Reputation: 33
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;
}
Upvotes: 2
Views: 669
Reputation: 596632
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.
Upvotes: 7
Reputation: 51845
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)
Upvotes: 4