一、背景
一个进程的线程窗口(window1)如何在不知道另一个进程的线程窗口(window2)的情况下接收到window2发送的自定义消息呢?
二、自定义消息
Windows系统除了预定义一些系统的消息外,还为用户预留了自定义消息的范围(WM_USER~0x7FFF)。通过RegisterWindowMessage函数,我们可以注册一个系统唯一的新消息。两个不同的进程注册了相同的消息字符串,这些应用将会返回相同的消息。直到整个消息会话结束。
三、广播消息
SendMessage或PostMessage函数可以向指定的窗口句柄发送窗口消息。如果窗口句柄是HWND_BOARDCAST,就会向系统所有顶层窗口发生该广播消息。
四、代码验证
广播消息的代码:
1 #include <iostream> 2 #include <Windows.h> 3 4 int main() 5 { 6 // 注册窗口消息 7 UINT seewoDesktopProxyMsg = ::RegisterWindowMessageW(L"Seewo_Desktop_Proxy_Message"); 8 9 if (0 == seewoDesktopProxyMsg) 10 { 11 std::cout << "RegisterWindowMessageW fail. error code:" << ::GetLastError(); 12 return 1; 13 } 14 15 // 广播消息 16 HWND hDesktop = GetDesktopWindow(); 17 std::cout << "desktop window:" << hDesktop << std::endl; 18 ::PostMessageW(HWND_BROADCAST, seewoDesktopProxyMsg, reinterpret_cast<WPARAM>(hDesktop), 0); 19 system("pause"); 20 21 std::cout << "Hello World! "; 22 }
接收广播消息:
#include <iostream> #include <thread> #include <Windows.h> UINT seewoDesktopProxyMsg = 0; void ListenRegistryWindowMessage() { WNDCLASSEX wndClass; wndClass.cbSize = sizeof(WNDCLASSEX); wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; wndClass.hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(0)); wndClass.lpfnWndProc = reinterpret_cast<WNDPROC>(DefWindowProc); wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hIcon = NULL; wndClass.hbrBackground = NULL; wndClass.hCursor = LoadCursor(0, IDC_ARROW); std::wstring className(L"SeewoDesktopProxy_recevie"); wndClass.lpszClassName = className.c_str(); wndClass.lpszMenuName = NULL; wndClass.hIconSm = NULL; if (!RegisterClassEx(&wndClass)) { std::cout << "RegisterClassEx err:" << GetLastError() << std::endl; } HWND proxyHwnd = CreateWindowEx(WS_EX_NOACTIVATE, className.c_str(), NULL, WS_POPUP, 0, 0, 0, 0, NULL, NULL, 0, NULL); if (proxyHwnd == NULL) { std::cout << "CreateWindowEx err:" << GetLastError() << std::endl; } std::cout << "create proxy windows success hWnd :" << proxyHwnd << std::endl; MSG msg; while (GetMessage(&msg, nullptr, 0, 0)) { if (msg.message == seewoDesktopProxyMsg) { std::cout << "receive registry window message." << (HWND)(msg.wParam) << std::endl; } TranslateMessage(&msg); DispatchMessage(&msg); } } int main() { // 注册窗口消息 seewoDesktopProxyMsg = ::RegisterWindowMessageW(L"Seewo_Desktop_Proxy_Message"); if (0 == seewoDesktopProxyMsg) { std::cout << "RegisterWindowMessageW fail. error code:" << ::GetLastError(); return 1; } // 接收消息的窗口 std::thread listen(ListenRegistryWindowMessage); listen.join(); std::cout << "Hello World! "; }
运行效果:
如果使用Spy++监控窗口消息会更加详细:
五、注意事项
接收方必须在发送方发送广播消息窗口消息队列创建完成,否则创建前的所有广播消息都无法正常接收到。
参考:https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerwindowmessagea