Search code examples
windowsdelphimessage-queuec++builderpostmessage

Stop WndProc processing during shutdown of the app


I have defined a WndProc which looks similar to below (the code is written in C++Builder, but it applies in similar form to Delphi as well):

#define WM_SETTINGS_UPDATE WM_APP + 1234
#define WM_GUI_UPDATE      WM_APP + 1235

void __fastcall TForm1::WndProc(TMessage &fMessage)
{
switch (fMessage.Msg)
    {
    default:                 break;

    case WM_SETTINGS_UPDATE: ProcessMySettingsUpdate();
                             fMessage.Result = 1;
                             return;
                             break; // I know this is not needed, I do this purely for aesthetics

    case WM_GUI_UPDATE:      ProcessMyGUIUpdate();
                             fMessage.Result = 1;
                             return;
                             break; // I know this is not needed, I do this purely for aesthetics
    }

TForm::WndProc(fMessage);
}

So in essence this:

  1. checks for my custom WM_APP range messages (WM_SETTINGS_UPDATE and WM_GUI_UPDATE) in this case.

  2. processes those messages and then sets fMessage.Result to 1 indicating message was processed and returns (avoiding TForm:WndProc(fMessage), which I understand is the same as inherited in Delphi, and not needed if the message is processed).

  3. if my messages are not processed, it just calls TForm:WndProc(fMessage) (or inherited) to do the default processing.

My concern is this - what if there is a situation where the application is shutting down, and there are still some messages being unprocessed (left in the message queue by PostMessage())?

What I'd like to do in such a situation is to avoid calling my own processing, as it might result in some uninitialized memory Access Violations or similar. Is this basically enough, or do I need to apply some special processing to avoid that kind of situation, or process some "application shutting down" code?

And also - do I need to call inherited / TForm:WndProc(fMessage) after I am done with my processing, or is it safe to do it like above (set Result to 1 and return)?

Note - this does not necessarily apply to the MainForm (the first Form being created).


Solution

  • what if there is a situation where the application is shutting down, and there are still some messages being unprocessed (left in the message queue by PostMessage())?

    That is perfectly OK. Once a Form's HWND is destroyed, any remaining messages that were posted for that window will simply be discarded when dispatched by the main message loop. Your WndProc will not be called for them.

    What I'd like to do in such a situation is to avoid calling my own processing, as it might result in some uninitialized memory Access Violations or similar.

    That should not be a concern. One, because messages won't be dispatched to your Form's HWND after it is destroyed, and two, when the MainForm is closed, the main message loop is signaled to stop running, before any active Form HWNDs are destroyed. So, there won't be any further message dispatching anyway.

    Is this basically enough, or do I need to apply some special processing to avoid that kind of situation

    It should be enough. You typically do not need to handle this special (unless your custom messages are carrying pointers to objects that have to be freed).

    or process some "application shutting down" code?

    If you really want to detect when the app is being shut down, try having your WndProc handle the WM_CLOSE message (or you can use the Form's OnClose/Query events).

    do I need to call inherited / TForm:WndProc(fMessage) after I am done with my processing, or is it safe to do it like above (set Result to 1 and return)?

    That is perfectly OK for custom messages.