简体   繁体   中英

Why does CreateWindow in 64-bit Visual Studio C destroy itself on creation?

I have some example code that simply puts a window on the screen in Windows 10. The program runs fine under 32 bit: the window call back procedure gets sent messages in the creation of the window.

Under 32-bit, the first three messages are:

WM_GETMINMAXINFO
WM_NCCREATE
WM_NCCALCSIZE

and it proceeds from there until the window is built.

However, under 64-bit, this does not happen; instead, these are the messages sent:

WM_GETMINMAXINFO
WM_NCCREATE
WM_NCDESTROY

As you can see, right after the window is created, the OS sends a message to destroy it!

Here's the actual code:

/*****************************************************************************/
/*      This sample demonstrates how to continuously acquire pictures        */
#include <windows.h>
#include <stdio.h>
#define _NIWIN 

#define PB_QUIT     101       /* id for quit application push button */

// Window proc
LRESULT CALLBACK ImaqSmplProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam);

// windows GUI globals
static HINSTANCE    hInst;
static HWND         ImaqSmplHwnd;
static HWND         HStop, HGrab, HQuit, HIntfName, HFrameRate;


static long        CanvasWidth = 512;  // width of the display area
static long        CanvasHeight = 384; // height of the display area
static long        CanvasTop = 10;     // top of the display area
static long        CanvasLeft = 10;    // left of the display area
static long        AcqWinWidth;
static long        AcqWinHeight;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                       LPSTR lpszCmdLine, int nCmdShow)
{
    CHAR        ImaqSmplClassName[] = "Imaq Sample";
    WNDCLASS    ImaqSmplClass;
    MSG         msg;
   

    // register the main window
    hInst = hInstance;
    if (!hPrevInstance)
    {
        ImaqSmplClass.style         = CS_HREDRAW | CS_VREDRAW;
        ImaqSmplClass.lpfnWndProc   = (WNDPROC) ImaqSmplProc;
        ImaqSmplClass.cbClsExtra    = 0;
        ImaqSmplClass.cbWndExtra    = 0;
        ImaqSmplClass.hInstance     = hInstance;
        ImaqSmplClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
        ImaqSmplClass.hCursor       = LoadCursor (NULL, IDC_ARROW);
        ImaqSmplClass.hbrBackground = GetStockObject(LTGRAY_BRUSH);
        ImaqSmplClass.lpszMenuName  = 0;
        ImaqSmplClass.lpszClassName = ImaqSmplClassName;
    
        if (!RegisterClass (&ImaqSmplClass))
            return (0);
    }

    // creates the main window
    ImaqSmplHwnd = CreateWindow(ImaqSmplClassName, "LLGrab", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                            CW_USEDEFAULT, CW_USEDEFAULT, 680, 440, NULL, NULL, hInstance, NULL);

    // creates the quit application button
    if (!(HQuit = CreateWindow("Button","Quit",BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE,
                                550,152,80,40,ImaqSmplHwnd,(HMENU)PB_QUIT,hInstance,NULL)))
      return(FALSE);
    
    // Display the main window
    ShowWindow(ImaqSmplHwnd, SW_SHOW);
    UpdateWindow(ImaqSmplHwnd);
        
    while (GetMessage (&msg, NULL, 0, 0))
    {
        TranslateMessage (&msg) ;
        DispatchMessage (&msg) ;
    }

    return (int)(msg.wParam);
}

// Message proc
LRESULT CALLBACK ImaqSmplProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam)
{
    WORD            wmId;   
    LRESULT theResult;
    
    switch (iMessage)
    {
        case WM_COMMAND:
            wmId    = LOWORD(wParam);
            switch (wmId)
            {
                case PB_QUIT:
                    PostQuitMessage(0);
                    break;
            }
            break;
        case WM_NCDESTROY:
            break;
        case WM_DESTROY:
            PostQuitMessage(0);

        default:
            theResult = DefWindowProc(hWnd, iMessage, wParam, lParam);
            return theResult;
            break;
    }
    return 0;
}

Your ImaqSmplProc() window procedure is declared incorrectly, causing you to pass bad data to DefWindowProc() .

For WM_NCCREATE , the lParam holds a pointer, which you are truncating under 64bit to a 32bit value, so DefWindowProc() fails to process WM_NCCREATE correctly, which then causes CreateWindow() to destroy the window. If you debug the code, you will likely see DefWindowProc() returning FALSE when processing WM_NCCREATE with a bad lParam value.

If an application processes this message, it should return TRUE to continue creation of the window. If the application returns FALSE, the CreateWindow or CreateWindowEx function will return a NULL handle.

To fix this, the wParam and lParam parameters MUST be declared as WPARAM and LPARAM , respectively:

LRESULT CALLBACK ImaqSmplProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

This matches the actual signature of WNDPROC :

LRESULT CALLBACK WindowProc(
  _In_ HWND   hwnd,
  _In_ UINT   uMsg,
  _In_ WPARAM wParam,
  _In_ LPARAM lParam
);

WPARAM and LPARAM are declared as UINT_PTR and LONG_PTR , respectively. Which means they are pointer-sized integers, and so have different sizes under 32bit and 64bit. Whereas UINT and LONG have the same size on both 32bit and 64bit. See Windows Data Types . Your original code is not accounting for this difference.

You used a type-cast to silence the compiler from alerting you to your incorrect declaration. You need to get rid of the type-cast when assigning ImaqSmplProc to ImaqSmplClass.lpfnWndProc :

ImaqSmplClass.lpfnWndProc   = ImaqSmplProc;

Any time you find yourself using a type-cast, question yourself as to why, you may be doing something wrong. Don't use a type-cast unless you absolutely need it. Don't use a type-cast just to keep the compiler silent, it complains about questionable/erroneous things for a reason.

The problem is in the types you have specified for the wParam and lParam arguments to your ImaqSmplProc function. These should be of types WPARAM and LPARAM , respectively.

Why? These are defined as UINT_PTR and LONG_PTR types - which are 64-bit integers on x64 builds; thus, your specified UINT and LONG types are the wrong sizes, so you have undefined behaviour (at best).

Change the definition/declaration to:

LRESULT CALLBACK ImaqSmplProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

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