简体   繁体   中英

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

My project is C++ Windows Desktop Wizard AKA Win32 API project.

In function WinMain(...) I'm creating my 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). 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).

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:

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* ). Same with MANY other handle types ( HHOOK , HEVENT , HGDIOBJ , HBITMAP , etc).

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). 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. It is actually just an opaque value provided by the 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.

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.

In your case, your HWND has a value of 0x00170344 , which means CreateWindowEx() is not failing, the HWND itself is valid. 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". The unused member will NEVER be valid in a user-mode debugger (that is why it is "unused"). The only thing that is important is whether the value of the HWND itself is 0 or not.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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