我有一些低级库代码,我希望能够广播一些自定义的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,但还有其他应用程序可以处理库消息。
答案 0 :(得分:2)
你的两个断言都是错误的:
驻留在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);
}
}
在单个应用程序中,您似乎无法对同一条消息进行两次RegisterWindowMessage调用
这完全是不真实的。应用可以根据需要多次拨打RegisterWindowMessage()
。该函数将在全局资源中仅分配给定消息一次,并在每次任何模块请求相同消息时返回相同的注册ID,但多次调用它。