• 广播自定义消息实现进程间的通信问题


    一、背景

      一个进程的线程窗口(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

  • 相关阅读:
    JSON Web Token
    Centos 7下编译安装PHP7.2(与Nginx搭配的安装方式)
    Nginx配置详解
    Centos 7下编译安装Nginx
    PHP常用正则验证
    拼手气红包函数
    获取汉字首字母大写
    根据生日计算年龄
    ffmpeg获取视频封面图片
    对象脑图总结
  • 原文地址:https://www.cnblogs.com/smartNeo/p/12489824.html
Copyright © 2020-2023  润新知