1

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.

Totte Karlsson
  • 1,261
  • 1
  • 20
  • 55
  • I guess one could write a library function like, getIdForMessage(string& msg_name) and do all RegisterWindowMessage calls in the DLL, but it does not seem right for some reason? – Totte Karlsson Aug 16 '16 at 23:26

1 Answers1

3

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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks for the instructions. I was to reproduce the RegisterWindowMessage call that gave me 0, but now it don't anymore, oddly enough! In any case, I went for using the initLib function as a way to register a bunch of messages. For a standalone app that need to process these messages, the list of strings defined will be needed (copy and pasted) for that apps own registration of messages purpose. – Totte Karlsson Aug 17 '16 at 17:45