如何在VCL应用程序中处理已发布,已注册的Windows消息?

时间:2016-08-16 23:10:29

标签: c++ windows ipc c++builder

我有一些低级库代码,我希望能够广播一些自定义的Windows消息。

在库代码中,定义了以下内容:

static UINT WM_MOTOR_WARNING_MESSAGE = 0;

extern "C" int _libmain(unsigned long reason)
{
  WM_MOTOR_WARNING_MESSAGE = RegisterWindowMessage("MOTOR_WARNING_MESSAGE");
....

并且库正在发送如下消息:

        //Send windows message
        int ret = PostMessage(HWND_BROADCAST, WM_MOTOR_WARNING_MESSAGE, 0, 0);
        if(!ret)
        {
            Log(lError) << "Post message failed..";
        }

VCL Main表单定义

UINT WM_MOTOR_WARNING_MESSAGE = RegisterWindowMessage(L"MOTOR_WARNING_MESSAGE");

和过度的WndProc功能:

void __fastcall TMain::WndProc(TMessage& Message)
{
    if (Message.Msg == WM_MOTOR_WARNING_MESSAGE)
    {
        MessageDlg("Turn off motor", mtInformation, TMsgDlgButtons() << mbOK, 0);
    }
    else
    {
        TForm::WndProc(Message);
    }
}

当前的问题似乎是驻留在DLL中的库代码由主应用程序加载,导致RegisterWindowMessage函数在库中返回0。在单个应用程序中,您似乎无法对同一消息进行两次RegisterWindowMessage调用。

所以问题是如何处理这种情况?虽然主应用程序正在使用此DLL,但还有其他应用程序可以处理库消息。

1 个答案:

答案 0 :(得分:2)

你的两个断言都是错误的:

  1.   

    驻留在DLL中的库代码由主应用程序加载,导致RegisterWindowMessage函数在库中返回0

    这不是它失败的原因。其他因素导致失败。使用GetLastError()查找原因,就像文档中所说的那样。

    最可能的罪魁祸首是RegisterWindowMessage()位于user32.dll。 DLL入口点永远不会从其他DLL调用函数(kernel32.dll除外)。请参阅Dynamic-Link Library Best Practices,它甚至明确声明不会调用user32.dll

      

    您永远不应该在DllMain中执行以下任务:

         

    ...

         
        
    • 调用User32.dll 或Gdi32.dll中的函数。某些函数会加载另一个DLL,但可能无法初始化。
    •   

    相反,让您的库导出一个初始化函数,您的应用程序可以在加载DLL后调用该函数。从该函数内部调用RegisterWindowMessage()

    您也可以选择导出一个函数以返回已注册的消息ID。

    static UINT WM_MOTOR_WARNING_MESSAGE = 0;
    
    extern "C" int _libmain(unsigned long reason)
    {
    }
    
    void __stdcall initMyLib()
    {
        WM_MOTOR_WARNING_MESSAGE = RegisterWindowMessage("MOTOR_WARNING_MESSAGE");
        ....
    }
    
    UINT __stdcall getMotorWarningMsgID()
    {
        return WM_MOTOR_WARNING_MESSAGE;
    }
    

    static UINT WM_MOTOR_WARNING_MESSAGE = 0;
    
    __fastcall TMain::TMain(TComponent *Owner)
        : TForm(Owner)
    {
        initMyLib();
        WM_MOTOR_WARNING_MESSAGE = getMotorWarningMsgID();
    }
    
    void __fastcall TMain::WndProc(TMessage& Message)
    {
        if ((Message.Msg == WM_MOTOR_WARNING_MESSAGE) && (WM_MOTOR_WARNING_MESSAGE == 0))
        {
            MessageDlg("Turn off motor", mtInformation, TMsgDlgButtons() << mbOK, 0);
        }
        else
        {
            TForm::WndProc(Message);
        }
    }
    
  2.   

    在单个应用程序中,您似乎无法对同一条消息进行两次RegisterWindowMessage调用

    这完全是不真实的。应用可以根据需要多次拨打RegisterWindowMessage()。该函数将在全局资源中仅分配给定消息一次,并在每次任何模块请求相同消息时返回相同的注册ID,但多次调用它。