可以运行窗口应用程序没有消息循环

我有一个非常古老的应用程序,我很惊讶。 此应用程序运行没有消息循环。 ( GetMessagePeekMessage )。

这怎么可能?

从Visual Studio编辑的例子:

HINSTANCE g_hInstance = NULL; LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); BOOL InitInstance(HINSTANCE hInstance, int nCmdShow); ATOM _RegisterClass(HINSTANCE hInstance); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); _RegisterClass(hInstance); InitInstance(hInstance, SW_NORMAL); return 0; } ATOM _RegisterClass(HINSTANCE hInstance) { WNDCLASSEXA wcex = {0}; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_SAVEBITS; wcex.lpfnWndProc = WndProc; wcex.hInstance = hInstance; wcex.lpszClassName = "TEST_CLASS"; ATOM a = 0; a = RegisterClassExA(&wcex); return a; } BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; g_hInstance = hInstance; // Store instance handle in our global variable hWnd = CreateWindowA("TEST_CLASS", "TEST_WINDOW", WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } SendMessageW(hWnd, WM_USER, 111, 0); return TRUE; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_CREATE: OutputDebugStringA("Create called.\n"); break; case WM_USER: { if (wParam == 111) { OutputDebugStringA("User called.\n"); } } break; case WM_DESTROY: OutputDebugStringA("Destroy called.\n"); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } 

debugging输出:

创build调用。 用户呼叫。 消灭叫。 程序“[2152] Test.exe:Native”已退出,代码为0(0x0)。

这是预期的行为。

CreateWindow调用SendMessageWM_NCCREATEWM_CREATE发送到正在创建的窗口。 SendMessage行为如下(引自MSDN):

如果指定的窗口是由调用线程创建的,则窗口过程将立即作为子例程调用。

你的程序调用CreateWindow ,随后调用你的窗口过程(在WM_CREATE输出“Create called”),然后返回。 它会验证窗口句柄是否为非空值,并返回0,而不是输入消息泵。
它不会输出“Destroy called”(因为你可能预料到),因为这没有发生。 这个窗口没有被破坏(好吧, 最后是操作系统),程序就退出了。

关于编辑的代码:
新的代码在调用SendMessageW不同,它直接调用窗口过程。 因此,尽管没有消息泵,但用户消息仍被接收。
现在看来,摧毁的信息也是如此,这当然有点令人惊讶。 不知道这是什么原因。

请注意,该窗口是用“A”函数创建的,所以调用“W”函数通常是不可取的(即使它似乎“在这里工作”)。