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.
Related
When a focused window is closed, Windows will typically set focus to a different window when possible. I'm trying to figure out what exactly causes this to happen, and in what scenarios does this not occur.
I'm noticing that when some windows are closed, they do not cause the OS to set focus to a new window (eg. Discord, Slack). Discord and Slack are both hidden instead of destroyed on close, but then there are also other windows that when hidden will still cause the OS to set focus to a different window. One such example is with a fresh WPF app and changing the window's Visibility to Collapsed - this causes the window to be hidden, not destroyed, and yet the OS reassigns focus to another window.
What causes some windows when hidden to reassign focus (eg. WPF collapse)? As opposed to applications like Discord/Slack, which are hidden, yet do not reassign OS focus.
It's a multi-step dance of message exchanges, and I no longer have all the details cached in my head. So, generally speaking ...
There's a distinction between activating a window and setting the focus to a window. Windows can get activated in various ways, including a mouse click (either in the client or non-client areas, a keyboard operation, a window being created by a process that currently has "the foreground love", etc.)
A window that's activated can (in effect) accept the focus, reject the focus, or direct the focus to another window (such as a child window like an edit control or button).
A window that doesn't make the effort to direct the focus explicitly when its activated will (likely) end up with the focus by default. That's mostly an artifact of how DefWindowProc handles the relevant messages. But if it's using the dialog manager, then the dialog manager will (if I recall correctly) set the focus to one of the child windows that has the WS_TABSTOP window style.
Imagine a simple text editor application that has a top-level window and one child window that fill the top-level window's client area and hosts the actual editor functionality. In normal behavior, the child window would have the focus whenever the application is in the foreground. But if the top-level window is activated (for something other than a mouse click in the child window's client area), and the top-level window fails to redirect the focus to its child, then it may appear as though nothing has the focus because the window that does have the focus doesn't respond to most kinds of keyboard input.
Key messages involved include: WM_ACTIVATEAPP, WM_NCACTIVATE, WM_ACTIVATE, WM_MOUSEACTIVATE, WM_SETFOCUS, and WM_KILLFOCUS.
Edited to emphasize
what causes the OS to re-assign focus from a window?
In most cases, the OS does not assign focus. It activates and deactivates windows, and the affected applications respond to those events by setting the focus. Applications have a lot of flexibility in how to respond. So if there's an anomaly in where the focus is, it may be more of a question about the behavior of individual applications than about Windows.
It's also possible for a window to have focus but for it to seem as if no window has focus. One case is where the top-level window has focus but doesn't react to the keyboard itself because focus is normally supposed to be assigned to one if its child windows. It's also possible for a hidden window (at least a hidden child window) to have focus if it's not disabled.
Win32's DefWindowProc and dialog-specific APIs, MFC, WPF, and other frameworks generally provide "standard" behavior for handling focus and activation in common cases. But there's a lot of nuance, and there are inherently some differences. For example, WPF applications (if I recall correctly) use windowless child controls, so the traditional behaviors have to be implemented by the framework.
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.
What could prevent a dialog from being displayed modally in foreground in some circumstances?
A process (KeePass.exe) owns a hidden window. A global shortcut (CTRL+A) displays a dialog in foreground. This is done using the DoModal method. And it works.
However, in some circumstances which I do not know, the follwing happens: The window appears in the taskbar and only after clicking on it, it is shown. I created a plugin for KeePass which overwrites the WndProc and waits for a certain WM_COPYDATA message. If this message arrives, the dialog is shown using DoModal. However, in this case it is only displayed in the taskbar and not shown in foreground.
The WM_COPYDATA message is sent from a different process, but this should not matter right? What can be a reason for that?
I am struggling for so long on this, it's so weird that's even difficult to explain the problem.
I tried issuing SetForegroundWindow(hKeePassWindow) before showing the dialog but no change.
Is there a way to change the position of the popup menu. With top-level windows I can do it by CBTProc Callback Function and MoveWindow. Can I do the same with menus? Needs to be done so that the pop-up menu is located only in the area of its parent window. Something like a light window manager.
Yes, in a WH_CBT hook callback, you'll be notified with an 'nCode' of HCBT_CREATEWND whenever a menu window is created. Test for the class name, standard menu/submenu windows would have a class name of '#32768'. You can then send a MN_GETHMENU message to the window to find out which menu is about to be activated. But as documented, it is too early to move the window when the notification is received, the menu is not even visible yet, so you might need to sub-class the window and process additional messages.
Note that you don't need a hook to be notified when a menu window is shown, you can put a handler for the WM_ENTERIDLE message, test for 'wParam' to see if a menu caused the message, get the menu window from 'lParam' and again send a 'MN_GETHMENU' to find out the specific menu. It is possible to move the window at this point without further message handling. Just be aware that 'WM_ENTERIDLE' will be called multiple times so you need to keep track of you've already moved a particular window or not.
Normally when creating a sub window (WS_POPUP), the child window will become activate and the parent will become deactivated. However, with menus, both remain active. At least I am assuming the menu is active, it at least has focus.
Example: Click on the file menu in notepad, the menu appears, yet the notepad window still looks active.
Is it possible to mirror this behavior with either a window style or responding to a particular message?
Thanks
Another example: Combo boxes seem to show a subwindow, yet do not deactivate the window. And you can click on that subwindow, while still maintaining an activate main window. Any ideas on how to grab the class /style of that window?
The list dropdown in a combobox is a bit of a hack, it is both a popup and a child window, I can't recommend that approach (Undocumented style combination, and IIRC, it is a bit buggy to do this with a "normal" floating window/toolbar)
This leaves you with two options:
WS_EX_NOACTIVATE (Main window will stay active, floating window is not active)
Handle activate messages (Both windows will look active)
I am surprised that creating a new popup window activates it. Normally you'd need to call SetActiveWindow. However check out WM_ACTIVATE and WM_NCACTIVATE on how to stop the window becoming deactivated.
A fact that a lot of people miss is that windows does not have a separate window manager component :- most of the window management duties are performed by each window - usually in DefWindowProc.
Most window positioning and activation / de-activation is done - ultimately - via a call to SetWindowPos - which always sends a WM_WINDOWPOSCHANGING message allowing the window to have a final say on what happens.
DefWindowProc also activate its own window in response to mouse clicks and so on.
The result of all this is, it is quite possible to create windows that never accept activation - it does require an extensive understanding of what messages and situations might have led to an activation.
Ultimately I can say that it is VERY handy to have a debugging setup configured for remote debugging - so that you can interact with your debugger without effecting the activation state of the system - and hence drop a breakpoint into the window in questions WM_ACTIVATE handler and simply debug any situation leading to an unwanted activation.
If You want to handle keyboard focus as well, it might be trickier - normally focus is given to an activated window - but again its usually the DefWindowProc responsible for assigning both. I just see it dangerous as having one window, still obviously activated, and another with focus. This will confuse any assistive software greatly.
I'd be tempted to perform a message loop level message hook - Similar to IsDialogMessage - to filter keystrokes intended for the popup window.
If you create your popup window with WS_EX_NOACTIVATE it will not be activated by user input (You could still activate it programatically) and therefore your main application window will still remain active.