简体   繁体   English

Win32 API - HWND “{未使用 =???} 无法读取内存”错误

[英]Win32 API - HWND “{unused = ???} Unable to read memory” error

My project is C++ Windows Desktop Wizard AKA Win32 API project.我的项目是 C++ Windows 桌面向导 AKA Win32 API 项目。

In function WinMain(...) I'm creating my window:在 function WinMain(...) 我正在创建我的 window:

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

And after that for some reason my window has status "unable to read memory" (therefore I can't create GUIs without this issue).之后由于某种原因,我的 window 的状态为“无法读取内存”(因此我无法创建没有此问题的 GUI)。 I checked even 2nd page of Google to find a resolve of this problem.我什至检查了谷歌的第二页以找到解决此问题的方法。 Microsoft's documentation didn't help: I checked the implementation and it fits with mine.微软的文档没有帮助:我检查了实现,它与我的相符。 I can't fix it for a long time, mb I'm blind and I wrote smth wrong before, despite I've created 2 working projects before (comparison didn't give any results).尽管我之前创建了 2 个工作项目(比较没有给出任何结果),但我很长一段时间都无法修复它,我是盲人,我之前写错了。

Here goes the whole code:整个代码如下:

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

>how it looks in debugger< >它在调试器中的外观<

Thanks in advance for help.提前感谢您的帮助。

When STRICT Type Checking is enabled during compiling, HWND is a typedef for HWND__* , where HWND__ is a struct with an unused data member (only because a struct can't legally be empty in C, but it can in C++), eg:在编译期间启用STRICT Type Checking时, HWNDHWND__*的 typedef,其中HWND__是具有unused数据成员的结构(仅因为struct在 C 中不能合法为空,但在 C++ 中可以),例如:

winnt.h: 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);

So, when STRICT is defined, HWND is an alias for struct HWND__* , otherwise it is an alias for PVOID ( void* ).因此,当定义STRICT时, HWNDstruct HWND__*的别名,否则它是PVOID ( void* ) 的别名。 Same with MANY other handle types ( HHOOK , HEVENT , HGDIOBJ , HBITMAP , etc).与许多其他句柄类型( HHOOKHEVENTHGDIOBJHBITMAP等)相同。

For your debugger to be showing you the unused member when viewing an HWND , that means you are compiling with STRICT defined (which is a good thing, you should be).为了让您的调试器在查看HWND时向您显示unused的成员,这意味着您正在使用定义的STRICT进行编译(这是一件好事,您应该这样做)。 The debugger sees a pointer to a type, and tries to display the data that type contains.调试器看到指向类型的指针,并尝试显示该类型包含的数据。

However, an HWND is not REALLY a pointer to a struct HWND__ in memory.但是, HWND并不是真正指向 memory 中的struct HWND__的指针。 It is actually just an opaque value provided by the kernel.它实际上只是 kernel 提供的一个不透明值 What an HWND actually refers to is private to the kernel, a user-mode debugger has no way of knowing what that really is. HWND实际指的是 kernel 私有的,用户模式调试器无法知道它到底是什么。

STRICT handling is merely provided for compile-time type safety, so that user code can't accidentally pass other handle types where an HWND is expected, and vice versa. STRICT处理仅用于编译时类型安全,因此用户代码不会意外传递其他需要HWND的句柄类型,反之亦然。

In your case, your HWND has a value of 0x00170344 , which means CreateWindowEx() is not failing, the HWND itself is valid.在您的情况下,您的HWND的值为0x00170344 ,这意味着CreateWindowEx()没有失败, HWND本身是有效的。 But 0x00170344 is not a valid memory address in your app's address space, so when the debugger tries to access the unused member at that address, it fails with "unable to read memory".但是0x00170344在您的应用程序的地址空间中不是有效的 memory 地址,因此当调试器尝试访问该地址处unused的成员时,它会因“无法读取内存”而失败。 The unused member will NEVER be valid in a user-mode debugger (that is why it is "unused"). unused的成员在用户模式调试器中永远不会有效(这就是它“未使用”的原因)。 The only thing that is important is whether the value of the HWND itself is 0 or not.唯一重要的是HWND本身的是否为0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM