简体   繁体   中英

How to handle a posted, registered windows message within a VCL application?

I have some low level library code that I would like to be able to broadcast a few custom windows messages.

In the library code, the following is defined:

static UINT WM_MOTOR_WARNING_MESSAGE = 0;

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

and the library is sending the message like this:

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

The VCL Main form defines

UINT WM_MOTOR_WARNING_MESSAGE = RegisterWindowMessage(L"MOTOR_WARNING_MESSAGE");

and an over ridden WndProc function:

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);
    }
}

The current problem seem to be that the library code, residing in a DLL, is loaded by the main application, causing the RegisterWindowMessage function to return 0 in the library. It seems you cannot have two RegisterWindowMessage calls for the same message within a single application.

So question is how to deal with this scenario? Although the Main application is using this DLL, there are other applications that could handle the library message.

Both of your assertions are wrong:

  1. the library code, residing in a DLL, is loaded by the main application, causing the RegisterWindowMessage function to return 0 in the library

    That is not why it fails. Something else is causing the failure. Use GetLastError() to find the cause, like its documentation says to.

    The most likely culprit is the fact that RegisterWindowMessage() is in user32.dll . A DLL entry point should never call functions from other DLLs (except kernel32.dll ). See Dynamic-Link Library Best Practices , which even explicitly states not to call into 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.

    Instead, have your library export an initialization function that your app can call after loading the DLL. Call RegisterWindowMessage() from inside that function.

    You could also optionally export a function to return the registered message 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

    That is completely untrue. An app can call RegisterWindowMessage() as many times as it wants. The function will allocate a given message only one time in global resources and return the same registered ID each time that same message is requested by any module, however many times it is called.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM