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

标签 c++ windows ipc c++builder

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

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

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 主窗体定义

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. the library code, residing in a DLL, is loaded by the main application, causing the RegisterWindowMessage function to return 0 in the library

    这不是它失败的原因。其他原因导致失败。使用 GetLastError() 查找原因,如其文档所述。

    最有可能的罪魁祸首是 RegisterWindowMessage()user32.dll 中。 DLL 入口点应该绝不 调用来自其他 DLL 的函数(kernel32.dll 除外)。参见 Dynamic-Link Library Best Practices ,它甚至明确声明不要调用 user32.dll:

    You should never perform the following tasks from within DllMain:

    ...

    • Call functions in User32.dll or Gdi32.dll. Some functions load another DLL, which may not be initialized.

    相反,让您的库导出一个初始化函数,您的应用程序可以在加载 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. It seems you cannot have two RegisterWindowMessage calls for the same message within a single application

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

关于c++ - 如何在 VCL 应用程序中处理已发布、已注册的 Windows 消息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38985818/

相关文章:

c++ - 使用另一个文件夹中的源代码时 Unresolved external 问题

c++ - CPP 线程中的嵌入式 Ruby 崩溃

ruby-on-rails - 如何以 root 身份从 Rails 运行命令?

delphi - 如何跨进程管理前台窗口?

c - 任意双向UNIX套接字通信

c++ - 如何在qt中解码json

c++ - 在基数树/patricia trie 中进行前缀搜索

windows - 如何在 lua 中保存到剪贴板或从剪贴板保存(Windows)

javascript - 是否可以在 node.js 的帮助下在 Windows 中将 JSLint 作为命令行运行?

windows - 命令在命令提示符中有效,但在批处理文件中无效