Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PostMessage to hidden form doesn't work the first time

I have a C# WinForms application that appears in the system tray. The application is hiding the main form on load:

private void MainForm_Load(object sender, System.EventArgs e)
{
    Hide();
}

For the same main form, I've overriden the WndProc to catch a custom window message (that message is registered to Windows with the RegisterWindowMessage Win32 API call).

protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_MYCUSTOM_MESSAGE)
    {
        // Handle custom message
    }
}

From an external C++ application I'm broadcasting the same custom window message with PostMessage.

UINT msg = RegisterWindowMessage(L"WM_MYCUSTOM_MESSAGE");
PostMessage(HWND_BROADCAST, msg, NULL, NULL);

When I execute the above code after the C# application was first started, it doesn't get into the WndProc. After the main form is shown (by a double click on the system tray icon, which in essence does a Show()), catching the broadcast message works and keeps working after hiding the form with Hide().

Can anyone explain me why it doesn't work after the first Hide() from the MainForm_Load event handler? Am I hiding the form too early?

EDIT1: It seems like it has nothing to do with the Hide on load. Even without the initial Hide, my main form WndProc will only start accepting broadcast posts after it is hidden and re-shown...

like image 515
huysentruitw Avatar asked Apr 17 '12 12:04

huysentruitw


3 Answers

After creating a small test application, I have found out that PostMessage() to HWND_BROADCAST doesn't arrive in Form.WndProc if Form.ShowInTaskbar is set to false while SendMessage() to HWND_BROADCAST does.

Even though the MSDN note about sending or posting messages to HWND_BROADCAST is exactly the same.

So it had nothing to do with the hiding or showing of the form and this seems like another undocumented feature of the Windows API.

like image 157
huysentruitw Avatar answered Sep 22 '22 17:09

huysentruitw


There's something else going on, calling Hide() in the form's Load event handler doesn't actually hide the window. Try it with a little test Winforms app to see this.

If you don't actually see the window then the simple explanation is that the window just wasn't created. Which entirely explains why the message isn't being received. Override OnHandleCreated() and set a breakpoint on it to double-check this theory. The Show() method must be called to create the native window, apparently your NotifyIcon event handler is the first one to do so. Which happens when you call Application.Run() but don't pass a form instance.

Check this answer for a way to ensure that that a form is created but not made visible.

like image 22
Hans Passant Avatar answered Sep 26 '22 17:09

Hans Passant


With Broadcast, the message is posted to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows. The message is not posted to child windows (according to MSDN). Use an application, like WinSpy to make sure your windows is a top level one right after the initial startup and hiding. Also this http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/ might (or might not) give some insights on how the OnLoad works... Seems it's a little bit more complicated. Try to hide the MainForm somewhere else, not on the OnLoad.

like image 32
Ferenc Deak Avatar answered Sep 22 '22 17:09

Ferenc Deak