1.子线程中建立一个窗口
为了在后面比较这两个函数,先使用win32 windows程序中建立子线程,在子线程中建立一个窗口。
(1)新建一个 win32 windows应用程序
(2)定义子窗口的窗口响应函数
LRESULT CALLBACK SubWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_DESTROY: PostQuitMessage(0); break; case WM_LBUTTONDOWN: MessageBoxA(0,"","SubWndProc",0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } }
(3)定义子线程窗口函数
void CreateWndInThread(int nWidth, int nHeight) { WNDCLASSEX wcex2; wcex2.cbSize = sizeof(WNDCLASSEX); wcex2.style = CS_HREDRAW | CS_VREDRAW; wcex2.lpfnWndProc = SubWndProc; wcex2.cbClsExtra = 0; wcex2.cbWndExtra = 0; wcex2.hInstance = GetModuleHandle(nullptr); wcex2.hIcon = 0; wcex2.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex2.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex2.lpszMenuName = NULL; wcex2.lpszClassName = L"SubWindow"; wcex2.hIconSm = 0; RegisterClassEx(&wcex2); HWND g_hWnd = CreateWindowA("SubWindow", nullptr,WS_OVERLAPPEDWINDOW, 0, 0, nWidth, nHeight, NULL, NULL, wcex2.hInstance, 0); ShowWindow(g_hWnd, SW_SHOW); UpdateWindow(g_hWnd); MSG msg; while (GetMessage(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
(4)处理主线程的 WM_LBUTTONDOWN 消息
在里面开启一个子线程,调用 CreateWndInThread
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_LBUTTONDOWN: { std::thread t(CreateWndInThread, 960, 480); t.detach(); } break; //省略其他消息 default: return DefWindowProc(hWnd, message, wParam, lParam); } break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
(5)运行程序
在主窗口上鼠标左键点击,会创建一个子窗口,
然后在子窗口上鼠标左键点击,会弹出一个MessageBox。
可以发现两个窗口的消息处理互不影响。
2.PostMessage和SendMessage
PostMessage会将消息压入窗口所在线程的消息队列,然后立即返回,非阻塞
SendMessage则不经过消息队列,SendMessage可认为是直接调用了该窗口的窗口过程,阻塞
将上面的项目做如下修改:
(1)定义一个全局遍历来存储子窗体的句柄,定义子窗体自定义消息
#define WM_SUB_MSG (WM_USER+1) HWND subWinHwnd;//子窗口
(2)修改子窗口的窗口响应函数
void CreateWndInThread(int nWidth, int nHeight) { WNDCLASSEX wcex2; wcex2.cbSize = sizeof(WNDCLASSEX); wcex2.style = CS_HREDRAW | CS_VREDRAW; wcex2.lpfnWndProc = SubWndProc; wcex2.cbClsExtra = 0; wcex2.cbWndExtra = 0; wcex2.hInstance = GetModuleHandle(nullptr); wcex2.hIcon = 0; wcex2.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex2.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex2.lpszMenuName = NULL; wcex2.lpszClassName = L"SubWindow"; wcex2.hIconSm = 0; RegisterClassEx(&wcex2); subWinHwnd = CreateWindowA("SubWindow", nullptr,WS_OVERLAPPEDWINDOW, 0, 0, nWidth, nHeight, NULL, NULL, wcex2.hInstance, 0); ShowWindow(subWinHwnd, SW_SHOW); UpdateWindow(subWinHwnd); MSG msg; while (GetMessage(&msg, nullptr, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
(3)修改子线程窗口函数
LRESULT CALLBACK SubWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_SUB_MSG: MessageBoxA(0,"WM_SUB_MSG","子窗体",0); break; case WM_DESTROY: PostQuitMessage(0); break; case WM_LBUTTONDOWN: MessageBoxA(0,"左键消息","子窗体",0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } }
(4)修改主窗口的窗口函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_LBUTTONDOWN: { std::thread t(CreateWndInThread, 960, 480); t.detach(); } break; case WM_RBUTTONDOWN: { SendMessage(subWinHwnd,WM_SUB_MSG,0,0); //PostMessage(subWinHwnd,WM_SUB_MSG,0,0); MessageBoxA(0,"右键消息","主窗体",0); } break; case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // 分析菜单选择: 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_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: 在此添加任意绘图代码... EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
(5)运行程序
发现使用SendMessage(subWinHwnd,WM_SUB_MSG,0,0) ,
MessageBoxA(0,"右键消息","主窗体",0) 对话框在 MessageBoxA(0,"WM_SUB_MSG","子窗体",0) 后面出现
使用PostMessage(subWinHwnd,WM_SUB_MSG,0,0)
MessageBoxA(0,"右键消息","主窗体",0) 对话框在MessageBoxA(0,"WM_SUB_MSG","子窗体",0) 前面出现
(6)完整代码链接:https://www.aliyundrive.com/s/UtrYB42wyi3
总结:
PostMessage会将消息压入窗口所在线程的消息队列,然后立即返回,非阻塞
SendMessage则不经过消息队列,SendMessage可认为是直接调用了该窗口的窗口过程,阻塞