Why is my property bar shown in the system tray icon blocking the taskbar?
Note: The code examples have been simplified, but the general structure remains intact.
I am working on a Win32 application whose main interface is the system tray icon. I am creating a dummy window using HWND_MESSAGE
as parent to receive icon messages:
WNDCLASSEX wndClass;
wndClass.lpfnWndProc = &iconWindowProc;
// ...
iconWindowHandle = CreateWindow(wndClass.lpszClassName, _T(""), 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_MESSAGE, NULL, GetModuleHandle(NULL), 0);
Then the icon is created by referencing this message-only window:
NOTIFYICONDATA iconData;
iconData.hWnd = iconWindowHandle;
iconData.uCallbackMessage = TRAYICON_MESSAGE;
// ...
Shell_NotifyIcon(NIM_ADD, &iconData)
When the tray icon is double clicked, I create and show a property sheet (from comctl32.dll
):
LRESULT CALLBACK iconWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case TRAYICON_MESSAGE:
switch (lParam) { // that contains the "real" message
case WM_LBUTTONDBLCLK:
showPropertySheet();
return 0;
// ...
}
break;
// ...
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
There is no parent window in the property sheet. The function PropertySheet
is called from a message-only window procedure. The flag is PSH_MODELESS
not set; thus, it PropertySheet
only returns after the properties window is closed:
void showPropertySheet() {
PROPSHEETPAGE pages[NUM_PAGES];
pages[0].pfnDlgProc = &firstPageDialogProc;
// ...
PROPSHEETHEADER header;
header.hwndParent = NULL;
header.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK;
header.ppsp = pages;
// ...
PropertySheet(&header);
}
This all works fine now, until I set a breakpoint in a dialog routine of one of the property sheet pages:
BOOL CALLBACK firstPageDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
return FALSE; // breakpoint here
}
When the program stops at a breakpoint, the entire taskbar is locked !
The call table is completely useless; it shows that the dialog procedure is being called somewhere inside comctl32.dll
through some calls inside user32.dll
. No window procedure is in between.
Creating a model of modelessness doesn't help. Also, I would prefer not to do this, because it makes the code more complex.
As long as my dialog routine returns quickly enough this shouldn't be a problem. But it seems strange that a longer operation within the dialogue procedure will not only close the dialogue itself, but also the entire shell. I can imagine that the message-only window routine has the power to invoke this behavior as it is more closely related to the tray icon ... but this function does not appear on the call stack.
Am I doing something fundamentally wrong? Can anyone shed some light on this issue?
source to share
Actually, this is pretty obvious, and the confusion must have been due to the lack of coffee.
The taskbar is probably using SendMessage
to send a message to my app, which causes it to block until the message is processed. SendMessageTimeout
is apparently not used.
It still seems strange to me that my function doesn't appear on the call stack. Surely such a message must go through my message loop for processing? Perhaps the warning that "the frame stack below this line may be incomplete or missing" was indeed correct.
source to share