Why does my Windows app get focus when by rules it should not? - winapi

By now everyone writing for Windows probably knows that applications cannot (officially) steal focus from foreground processes, and why. But I have just managed to steal focus, inadvertently, and don't understand how this is even possible.
I have a Delphi app that user brings up with a hotkey (or by a mouse click, or by Alt+Tab), selects a piece of text and hits Enter. My app then minimizes (hides to the tray, even), and pastes the text user just selected into the active window. Nothing new here, plenty of similar projects out there - clipboard extenders, glossaries, macro programs, etc.
What is puzzling to me is that after doing all the above and then sleeping for 1500 ms, I restore my main form and it gets the focus back! It becomes the foreground window, even though it wasn't 1500 ms ago (tested; Windows 7 32-bit.).
In fact, I don't want this at all, so before restoring my main form I record which window has foreground and I give it back to that window after it's been given to me. I'm just curious why my app gets to be in the foreground when by rules it should not. Maybe I don't understand the rules as fully as I thought I did?

If you look at the documentation for SetForegroundWindow you see a list of conditions for the call to succeed, one of them is "The process received the last input event." So if the user does not do anything after pressing enter in your app you still have the right to steal focus. I don't know if Delphi calls SetForegroundWindow for you when the window is restored but it might be something to look into.
I don't know how you restore your window but using SW_SHOWNOACTIVATE with ShowWindow might help...

Related

How to detect that my app is the top-most window

There are seven ways in which a 'dormant' application can become the 'active' one, based upon the combinations of whether it is minimised or simply obscured, and whether it is re-activated via alt-tab, a mouse-click of its icon, re-activated by it being sent a windows message from another program, or is simply 'discovered' to be the top-most application on the desktop when the application obscuring it is closed (or minimised).
In all cases I need to know that my app is now the active (e.g. top-most on the desktop) application so that I can refresh its data from the database.
I do know that apps 'know' when they are the top-most, as I can see the border changing to the active colour as soon as they become top-most.
If I trap WM_ACTIVATE_APP messages, this works most of the time, but doesn't seem to when my app was minimised and is restored to the active state.
I need to be told that my app is now top-most and active before the user does anything.
Any suggestions? Thanks, Dave
Try the following:
After such a time has elapsed that the data from the database should be considered out of date, call InvalidateRect() on your window (or the WinForms equivalent). If your window is not obscured it will get an immediate WM_PAINT. But if the window is completely obscured, it shouldn't get the WM_PAINT until the OS actually needs to display it - i.e. when the obscuring window is moved. Refresh the data from the database in response to the WM_PAINT message.
It turns out Raymond Chen blogged about this back in 2003.
After investigating, I found the cause and solution to my problem.
I found out that the WM_ACTIVATEAPP message was being sent (and received) OK, but this happened while the app was still in it minimized state (i.e. before it was restored).
Because I had an if test to not do anything when the app is minimized ( which is pointless as the user wouldn't see the results!), no action was being taken.
The WM_ACTIVATEAPP message is sent when the app gets 'uncovered', and that is okay since the app isn't minimized.
I now also respond to the WM_WINDOWPOSCHANGED which gets fired upon restore,
and this combination seems to cover all seven ways in which my app can be re-activated.

Intercepting a window's attempt to steal global focus on Windows

I'm a developer and a long-time Windows user with an obsession about making my system as convenient to use as possible.
Yesterday I thought about something that has always annoyed me in Windows and that I've taken for granted, and I realized that I have a better idea for how it could work, and I'm now wondering whether it's possible to tweak Windows to work like that.
The thing that annoys me is when windows steal focus. For example, I could be running an installer for some program. While it's working, I'll switch to my browser and browse, maybe entering some text into an email in my browser. Then suddenly the installer finishes and its window steals the focus. Now I'm in the middle of writing an email, so I might press a key that happens to be bound to a button on that installer, and then that button gets invoked, doing some action that I never intended to happen!
This is doubly annoying to me because I'm using a multiple-desktop program called DexPot, and when a window steals focus, it also brings itself to the desktop I'm currently on, which can be really annoying, because then I have to put it back into its original desktop.
How my ideal solution to this problem would work: Every time a window tries to steal focus, we intercept that, and don't let it. We show something like a toaster message saying "Foobar installer wants focus, press Win-Whatever to switch to it". If and when you press the key combo, it switches to the window.
The question is: Is there an easy way to tweak Windows to make this happen? I know very little about Windows programming. I do know AHK and if it's possible with that, that'd be great.
No, there isn't an easy way to add this behavior, but Windows tries to do this automatically.
In theory apps shouldn't be able to steal the foreground while you're actively using another app. Unfortunatly there are some scenarios where Windows can't tell the difference between legitimate user actions that should change the foreground and unwanted foreground-theft. The window manager generally tightens up the holes a bit with each new version of Windows, but also needs to make sure that apps can come to the foreground when the user wants them to, even if that desire is expressed indirectly.
For example, a process launched by the current foreground process can put a window into the foreground. This is necessary so that when a user launches a window from Explorer the newly launched process can open its main window. This permission only lasts until the next user input, so if an application is slow to launch and you start working on an email the app may lose its foreground permissions before it can use them.
See the SetForegroundWindow function documentation for a list of requirements for a process to be able to set a window into the foreground.
There are also apps which specifically make use of these requirements to steal the permission (by joining the foreground queue or synthsising user input to themselves), but I suspect in your installer scenario it is accidental.
I'm not sure what exactly is going on, but I suspect that the problem comes from the installer running as a service and accidentally stealing the foreground permission when it tries to launch the app on your current desktop.
It would be theoretically possible for an external process to hook into the foreground system to override this and show your confirmation toast, but it would be tricky to get right and would require significant low level code (I'd probably start with a CbtHook). It would not be possible in a scripting package like AHK (assuming you mean AutoHotKey) but would need to be native C/C++ code injected into every running process.

Win32 C++ - Do something when window is restored, which message?

So, I have a dialog based application using pure WinAPI. There is a main dialog, and then multiple other dialogs that are toolwindows. These toolwindows are meant to free-float around, the user can drag them, hide them, and show them, but they have no taskbar entry. This is what I intended, but the problem is, when I switch from the main window to a different application, then click on the taskbar entry for the main window, the main window will show up, but the toolwindows will not. They stay hidden behind the main window and sometimes windows of other applications, and you cannot use them until you move all of the top-most windows and hunt down the toolwindow.
So, what I'm trying to do to work around this is, when the user restores the window from being minimized, I want to enumerate through all of the tool windows and bring them to the front, maybe by calling SetActiveWindow().
But what message gets sent when the window is restored? I was thinking WM_SHOW, or WM_RESTORE, but they don't exist.
Another question, and if you answer this the first question is irrelevant because I will no longer need to use that workaround: Is there a better method of bringing all tool-windows to the front?
Give the tool windows the WS_POPUP style (and not WS_OVERLAPPED), and make the main window their parent (strictly it is their owner window). That way the tool windows will remain on top of the main window. This may (or may not) be what you want.
The naive answer to the question is to listen to WM_SIZE and respond to a wParam value of SIZE_RESTORED.
The other obvious possibility is to make all the tool windows be owned by the main window. So long as you are happy for the tool windows always to be on top of the main window, this will solve your problem. The owned windows will be hidden when the owner is minimized, and re-shown when the owner is restored.
Learn more about ownership in the MSDN topic on Window Features.

Is it possible to create a sub window which will not deactivate the parent?

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.

How can I prevent focus stealing in Windows?

A quick Google search for solutions to Focus Stealing in Windows reveals two main result categories:
People suggesting incomplete solutions involving the
ForegroundLockTimeout registry entry (or TweakUI, which I believe simply changes the aforementioned registry entry),
which isn't very effective.
Incessant hordes of Windows users complaining about it.
It's particularly annoying in two common scenarios:
Something triggers a program to popup a dialog window in the background while a fullscreen app is focused, causing the fullscreen app to minimize.
A window steals focus while you are typing, stealing all of your keystrokes. If you happen to press Space, Enter, or trigger a keyboard shortcut (like Y for Yes), it can cause completely undesirable outcomes.
What creative solutions can be applied to fix this problem for either or both of these scenarios?
I have one suggestion for how it can be solved, but I cannot implement it completely since I lack the knowledge.
The focus change between windows have to be instigated by the offending program calling a Windows API function located most probably in shell32 or user32. Some progams, like Adobe Photoshop makes the call multiple times (at least twice) to force itself up on the user when it's starting. The idea is to hook into this API function (if possible) and check where the call originates from. If it's not from explorer.exe (i.e. Alt+Tabbing or clicking an icon on the taskbar), then call should be blocked by said hook.

Resources