-2

我的项目是 C++ Windows 桌面向导 AKA 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)。我什至检查了谷歌的第二页以找到解决此问题的方法。微软的文档没有帮助:我检查了实现,它与我的相符。尽管我之前创建了 2 个工作项目(比较没有给出任何结果),但我很长一段时间都无法修复它,我是盲人,我之前写错了。

整个代码如下:

#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;
}

>它在调试器中的外观<

提前感谢您的帮助。

4

1 回答 1

1

STRICT Type Checking在编译期间启用时,HWND是一个 typedef for HWND__*,其中HWND__是一个带有unused数据成员的结构(只是因为 astruct在 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

风向:

DECLARE_HANDLE            (HWND);

因此,当STRICT定义时,HWND是 的别名struct HWND__*,否则是PVOID( void*) 的别名。与许多其他句柄类型(、、、、HHOOKHEVENTHGDIOBJ相同HBITMAP

为了让您的调试器unused在查看时向您显示成员HWND,这意味着您正在使用STRICT定义进行编译(这是一件好事,您应该这样做)。调试器看到指向类型的指针,并尝试显示该类型包含的数据。

但是,anHWND并不是真正的指向struct HWND__内存中的 a 的指针。它实际上只是内核提供的一个不透明的值。anHWND实际上指的是内核私有的,用户模式调试器无法知道它到底是什么。

STRICT处理只是为了编译时类型安全而提供的,因此用户代码不会意外地传递HWND预期的其他句柄类型,反之亦然。

在您的情况下,您HWND的值为0x00170344,这意味着CreateWindowEx()没有失败,它HWND本身是有效的。But0x00170344不是应用程序地址空间中的有效内存地址,因此当调试器尝试访问该unused地址的成员时,它会失败并显示“无法读取内存”。该unused成员在用户模式调试器中永远不会有效(这就是它“未使用”的原因)。唯一重要的是它本身的价值是否存在HWND0

于 2020-06-02T20:18:08.937 回答