[英]WinApi message loop, Postmessage works like SendMessage
Hello can Somebody answer me why when I run this program the order of MessageBoxes is 1,2,4,3 instead of 1,2,3,4. 你好有人回答我为什么当我运行这个程序时,MessageBoxes的顺序是1,2,4,3而不是1,2,3,4。 In my opinion program should end executing WM_PAINT procedure before start WM_USER+11, why it isn't? 在我看来,程序应该在启动WM_USER + 11之前结束执行WM_PAINT程序,为什么不呢?
// Win32Project6.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "Win32Project6.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
DWORD thread(LPVOID lpdwThreadParam);
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WIN32PROJECT6, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT6));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX 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, MAKEINTRESOURCE(IDI_WIN32PROJECT6));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32PROJECT6);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
// PostMessage(hWnd, WM_USER + 11, 0, 0);
MessageBox(0,"1","Message",0);
MessageBox(0, "2", "Message", 0);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_USER+11:
MessageBox(hWnd,"4","Message",0);
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&thread, &hWnd, 0, 0);
MessageBox(hWnd, "3", "Message", 0);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
DWORD thread(LPVOID lpdwThreadParam)
{
PostMessage(*(HWND*)(lpdwThreadParam), WM_USER + 11, 0, 0);
return 0;
}
Some notes about this code: 关于此代码的一些注意事项
WM_PAINT
. 您不应该在WM_PAINT
创建线程。 Nor should you call MessageBox
in WM_PAINT
. 你也不应该在WM_PAINT
调用MessageBox
。 WM_PAINT
is only for painting your window; WM_PAINT
仅用于绘制窗口; no other logic should be executed here. 这里不应该执行其他逻辑。 The system optimizes WM_PAINT
calls and behavior can get really tricky when you start overstaying your welcome in this handler. 系统优化了WM_PAINT
调用,当您在此处理程序中开始过度使用欢迎时,行为会变得非常棘手。 (LPTHREAD_START_ROUTINE)&thread
. 你也不应该像使用(LPTHREAD_START_ROUTINE)&thread
一样进行函数调用。 If your function is not the right type, change the function prototype; 如果您的函数类型不正确,请更改函数原型; don't just try and hide the compiler's warnings. 不要只是尝试隐藏编译器的警告。 _beginthread
, because the CRT has some initialization to perform. 你应该使用_beginthread
,因为CRT有一些初始化要执行。 hWnd
as the thread parameter, not &hWnd
. 你应该传递hWnd
作为线程参数,而不是&hWnd
。 The pointer can go out of scope and become invalid. 指针可能超出范围并变为无效。 This is a critical bug. 这是一个严重的错误。 To really see what's going on, you should fix these errors first. 要真正了解正在发生的事情,您应该首先修复这些错误。
To answer your question, the different threads have no guarantee of speed. 要回答你的问题,不同的线程无法保证速度。 After you split off a thread, there is now no telling what will happen next. 拆分线程后,现在无法告诉接下来会发生什么。 They are asynchronous. 它们是异步的。 Maybe the thread code runs faster than your main thread, maybe vice-versa. 也许线程代码比你的主线程运行得更快,反之亦然。
Keep in mind that MessageBox
has its own internal message loop. 请记住, MessageBox
有自己的内部消息循环。 So the callstack at WM_USER+11
(MessageBox4) is going to look something like this: 所以WM_USER+11
(MessageBox4)的callstack看起来像这样:
MessageBox (4)
WndProc (WM_USER+11)
DispatchMessage
MessageBox (3), before it's actually shown
WndProc (WM_PAINT)
DispatchMessage
WinMain
So you can see that if the thread posts the message quickly enough, it will be processed before MessageBox(3)
will be shown. 所以你可以看到,如果线程足够快地发布消息,它将在MessageBox(3)
显示之前被处理。
My guess is if you use a lighter debugging technique ( OutputDebugString
for example), you'll observe more predictable behavior. 我的猜测是,如果你使用较轻的调试技术(例如OutputDebugString
),你会发现更可预测的行为。
WM_PAINT
is one of the special low-priority messages. WM_PAINT
是特殊的低优先级消息之一。
The
WM_PAINT
message, theWM_TIMER
message, and theWM_QUIT
message, [...] are kept in the queue and are forwarded to the window procedure only when the queue contains no other messages.WM_PAINT
消息,WM_TIMER
消息和WM_QUIT
消息[...]保留在队列中,仅当队列不包含其他消息时才转发到窗口过程。
MSDN - Queued Messages . MSDN - 排队的消息 。
See also The Old New Thing - Paint messages will come in as fast as you let them . 另请参阅The Old New Thing - Paint消息将以您允许的速度进入 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.