如何在 VCL 应用程序中处理已发布、已注册的 windows 消息?
How to handle a posted, registered windows message within a VCL application?
我有一些低级库代码,我希望能够广播一些自定义 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 主窗体定义
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函数为return 0。您似乎不能在单个应用程序中对同一消息进行两次 RegisterWindowMessage 调用。
所以问题是如何处理这种情况?尽管主应用程序正在使用此 DLL,但还有其他应用程序可以处理库消息。
你的两个断言都是错误的:
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()
。
您还可以选择将函数导出到 return 已注册的消息 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);
}
}
It seems you cannot have two RegisterWindowMessage calls for the same message within a single application
这是完全不正确的。应用程序可以根据需要多次调用 RegisterWindowMessage()
。该函数将在全局资源中仅分配给定消息一次,并且每次任何模块请求相同的消息时 return 相同的注册 ID,无论它被调用多少次。
我有一些低级库代码,我希望能够广播一些自定义 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 主窗体定义
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函数为return 0。您似乎不能在单个应用程序中对同一消息进行两次 RegisterWindowMessage 调用。
所以问题是如何处理这种情况?尽管主应用程序正在使用此 DLL,但还有其他应用程序可以处理库消息。
你的两个断言都是错误的:
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()
。您还可以选择将函数导出到 return 已注册的消息 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); } }
It seems you cannot have two RegisterWindowMessage calls for the same message within a single application
这是完全不正确的。应用程序可以根据需要多次调用
RegisterWindowMessage()
。该函数将在全局资源中仅分配给定消息一次,并且每次任何模块请求相同的消息时 return 相同的注册 ID,无论它被调用多少次。