Win32 API - HWND "{unused =??}? 无法读取内存 "错误

问题描述 投票:-2回答:1

我的项目是C++ Windows Desktop Wizard又称Win32 API项目。

在函数WinMain(...)中,我正在创建我的窗口。

hWnd = CreateWindowEx(NULL, _T("DesktopApp"), _T("Hi, I'm window"), WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hInstance, NULL);

之后由于某种原因,我的窗口出现了 "无法读取内存 "的状态(因此我无法在没有这个问题的情况下创建GUI)。我甚至检查了Google的第二页来寻找解决这个问题的方法。微软的文档也没有帮助。我检查了它的实现,它和我的是一致的. 我很长时间都无法解决这个问题,因为我是个瞎子,而且我之前写错了一些东西,尽管我之前已经创建了两个工作项目(比较没有给出任何结果)。

下面是整个代码。

#include <windows.h>
#include <stdlib.h>
#include <string>
#include <tchar.h>
#include <shellapi.h>
#include <ctime>

HWND hWnd;
HINSTANCE hInst;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow)
{
    WNDCLASSEX wcex;

    ZeroMemory(&wcex, sizeof(wcex));
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = szWindowClass;
    wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);

    if (!RegisterClassEx(&wcex))
    {
        MessageBox(NULL,
            _T("Call to RegisterClassEx failed!"),
            _T("Windows Desktop Guided Tour"),
            NULL);
        return 1;
    }

    hInst = hInstance;

    hWnd = CreateWindowEx(NULL, _T("DesktopApp"), _T("Hi, I'm window"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hInstance, NULL);
    if (!hWnd)
    {
        MessageBox(NULL,
            _T("Call to CreateWindow failed!"),
            _T("Windows Desktop Guided Tour"),
            NULL);
        return 1;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

>它在调试器中的样子<

先谢谢你的帮助。

c++ windows winapi createwindowex
1个回答
1
投票

STRICT Type Checking 在编译过程中启用。HWND 是一个类型定义,用于 HWND__*,其中 HWND__ 是一个结构,有一个 unused 数据成员(只因为 struct 在C语言中不能合法地为空,但在C++中可以),如

winnt.h:

#ifdef STRICT
typedef void *HANDLE;
#if 0 && (_MSC_VER > 1000)
#define DECLARE_HANDLE(name) struct name##__; typedef struct name##__ *name
#else
#define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name
#endif
#else
typedef PVOID HANDLE;
#define DECLARE_HANDLE(name) typedef HANDLE name
#endif

windef:

DECLARE_HANDLE            (HWND);

所以,当 STRICT 被定义为。HWND 的别称。struct HWND__*的别称,否则就是 PVOID (void*). 和其他许多手柄类型一样 (HHOOK, HEVENT, HGDIOBJ, HBITMAP等)。)

为了让你的调试器向你显示出 unused 成员在查看 HWND,这意味着你正在用 STRICT 定义的(这是件好事,你应该是)。 调试器看到一个指向类型的指针,并试图显示该类型所包含的数据。

然而,一个 HWND 并不是真正的指向一个 struct HWND__ 在记忆中。 其实这只是一个 不透明值 内核提供的。 什么是 HWND 实际上指的是内核的隐私,用户模式的调试器无法知道那到底是什么。

STRICT 句柄只是为了编译时的类型安全而提供的,这样用户代码就不会意外地传递其他句柄类型,而在这些句柄类型中,有一个叫做 HWND 是预期,反之亦然。

在你的情况下,你的 HWND 价值为 0x00170344这意味着 CreateWindowEx() 没有失败, HWND 本身是有效的。 但是 0x00170344 在你的应用程序的地址空间中不是一个有效的内存地址,所以当调试器试图访问到 unused 该地址的成员,它以 "无法读取内存 "失败。该 unused 成员在用户模式调试器中永远不会有效(这就是为什么它是 "未使用 "的)。 唯一重要的是 价值HWND 本身就是 0 或不。

© www.soinside.com 2019 - 2024. All rights reserved.