We have a set of modeless dialogs that are children of a modal dialog. Only one of the modeless dialogs appears at a time; the others are hidden. This is controlled by elements in the modal dialog. If you think of a Windows property sheet you'll have the idea.
It all works fine except for the Tab key and the Alt+char hotkeys. They don't do what they're supposed to do, i.e., navigate the controls in the active modeless dialog. They just beep.
In a normal scenario, i.e., a modeless dialog owned by the application window, this is handled by calling IsDialogMessage() in the application's message loop. We can't do that because it's not our message loop--Windows is running the message loop to service the modal dialog, and all we get are messages sent to the dialog proc.
We're trying to think of ways to handle this without having to resort to doing all of the navigation ourselves via WM_GETDLGCODE.
Any ideas? Straight C++ Win32 API, none of that newfangled stuff the kids are all using these days.
TIA
ADDITIONAL INFO: Further investigation reveals that Windows is applying the navigation keys to the host modal dialog, not to the child modeless dialogs. We need them to go to the modeless dialogs.
The answer, found by a colleague, turns out to be adding the DS_CONTROL style to the modeless dialogs.
Raymond Chen discusses DS_CONTROL here.
It's amazing that you can work with Windows every day for 20 years and still run across stuff that you've absolutely never heard of.
Related
My MFC application has multiple top level (parented to the desktop) windows, any one of which can host an external application which can launch a modal dialog. Is there a way for one the other top level windows to get a notification when any of the others becomes modal?
My specific problem is that one of the my windows is hosting an embedded PDF viewer and when the user clicks print, only the window hosting the viewer is locked, not the others.
When a modal dialog is shown EnableWindow(FALSE) is called for the parent. It is deactivated now and will not accept any mouse input. Also it will not receive the keyboard focus.
When EnableWindow(FALSE) is called WM_ENABLE with wParam==FALSE is sent to the window.
When your parent receives this message you can call EnableWindow(FALSE) for all your other windows too. Recursion might be a problem here, but you can use a private window message or flags to prevent this.
Before the modal dialog closes EnableWndow(TRUE) is called again and WM_ENABLE with wParam==TRUE is sent again.
I have a set of modeless dialog boxes open, but I can't for the life of me click on one of them get it to appear in the foreground. It gets focus, but the dialog boxes forever remain in the order on the screen that they were created. The last one created is always in the foreground, obscuring (or partially obscuring) the others.
I have tried:
SetActiveWindow(hDlg);
SetForegroundWindow(hDlg);
SwitchToThisWindow(hDlg, FALSE);
in response to a WM_LBUTTONUP message, but though they get called they do nothing. I have tried different configurations in the dialog box properties like playing with the 'SetForground' or 'Topmost' parameters and they do nothing.
Am I trying to do an impossible task?
What is causing this is window ownership. An owned window is always shown above its owner. This is described in the documentation.
Clearly you have ownership relationships between your modeless dialogs. You can resolve this by making each of the modeless dialogs be owned by the same window.
Exactly how you do about controlling ownership depends on how you are creating these dialogs. If you are using CreateDialog then the third parameter is used to specify the dialog's owner.
In my Win32 app, I had a modal dialog that displays settings that I had to add more settings to. In order to fit the new settings, I dropped a TabCtrl in the dialog and implemented two modeless dialogs. The UI is working switching between them but the modeless dialogs don't respond to the keyboard. In a regular app, IsDialogMessage (hWndCurModelessDialog) would be called. How would I do this for my Modal dialog containing a modeless dialog?
You dont. The modal dialog box function calls IsDialogMessage from its own message loop automatically.
The modeless dialogs are the 'pages' ? Make sure they are parented to the main dialog (rather than the tab control) and have the DS_CONTROL style. This style allows IsDialogMessage to recurse into a child dialogs controls when tabbing.
In a Win32 API C++ project, I have a dialog with a tab control (3 tabs) and 3 dialogs that are children of the tab control. I load the main dialog with tab control using DialogBoxParam, and the child dialogs from resources with CreateDialogParam. The main dialog appears with the child dialogs. Clicking the tabs shows/hides the correct child dialog, everything working fine.
After searching around about tab orders I found the WS_EX_CONTROLPARENT style to set on the tab control to get tabbing working into the child dialog windows. This works great, except for one problem: The tab control itself never gets focus, so I can't tab to the tab control to change to a different tab with the keyboard. Keyboard focus goes through the child dialog, to the buttons on the main dialog, then directly back to the child dialog, and never stops on the tab control itself, so I have to click on the tab control to change tabs. It's driving me crazy. Any suggestions?
Update: I managed to work around the problem by forgetting about WS_EX_CONTROLPARENT completely, and making the child dialogs siblings of the tab control. Only side effect seems to be more flashing of controls during a repaint, but would still like an answer, since making the child dialogs children of the tab seems cleaner.
Its not cleaner. The recommended way to create tabbed dialogs is to make the tab pages children of the dialog. The tab control simply controls which of the pages is visible, but is not their parent.
This is especially important when you might try to get XP themeing working on the dialog.
WS_EX_CONTROLPARENT is a style intended to be set on the actual 'tab' dialogs.
I presume you have set WS_TABSTOP on the tab control itself? I imagine that WS_TABSTOP and WS_EX_CONTROLPARENT conflict when simultaneously set as they tell the dialog manager to do two entirely different and conflicting - things when the tab cycle reaches the control.
Lastly, I cannot see any reason at all that flickering should increase because the dialog pages are children of the dialog rather than the tab control.
You can't AFAIK because tabbing cycles through the child controls of a dialog by design. Best you could do is preprocess the tab keydown event and if its after the focus is on the last control in the dialog, focus the tab page and discard the event. Not cleaner than the solution you already have it seems to me.
Even when BorderStyle is set to 0, it is possible to force a window to show up on the taskbar either by turning on the ShowInTaskbar property or by using the windows api directly: SetWindowLong Me.hwnd, GWL_EXSTYLE, GetWindowLong(Me.hwnd, Win.GWL_EXSTYLE) Or Win.WS_EX_APPWINDOW. However, such taskbar entries lack a right-click menu in their taskbar entry. Right-clicking them does nothing instead of bringing up a context menu. Is there a way, to attach a standard or custom handler to it?
Without a hack, I think you're going to be stuck here, I'm sorry to say. When you set the VB6 borderless properties, you inherently disable the control menu. The control menu (typically activated by right-clicking the title bar of a window or left-clicking the icon in the upper left) is what's displayed when you right-click a window in the task bar.
Now, if you're in the mood to hack, you might be able to "simulate" the behavior in such a way that the user doesn't know the difference. I got the idea from this message thread on usenet.
Basically, it sounds like you may be able to hack it by using two forms. One form is minimized right away, and becomes your "stub" in the task bar. The other form is the one you're currently designing (which we'll call the "main" form). The stub form is what actually loads and displays your main form.
The stub form isn't borderless, and must not deactivate the control menu. It is positioned off screen and at the smallest possible size. You'll respond to its form-level events, and then use those to communicate the appropriate behaviors to the borderless form.
That's the general gist of the hack. If I wasn't at work right now, I'd whip up a simple VB6 project and see if I could get it to work for you.