How do I force my app to come to the front and take focus?
Asked Answered
P

5

10

I'm working on an application that happens to be the bootstrap for an installer that I'm also working on. The application makes a few MSI calls to get information that I need for putting together the wizard that is my application's main window, which causes a progress window to open while the info is being gathered and then go away once that's done. Then the wizard is set up and launched. My problem is that the wizard (derived from CPropertySheet) does not want to come to the front and be the active application without me adding in some calls to do so.

I've solved the problem of bringing it to the front with the following code in my OnInitDialog() method:

SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); // force window to top
SetWindowPos(&wndNoTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); // lose the topmost status that the previous line gave us

My problem is that I still haven't figured out how to make the window self-activate (i.e., make itself be the one that has the focus). SetFocus() won't work in this context. I need something that will force the window to the top of the Z-order and activate it, preferably in as few calls as possible.

My guess is that the progress window opened at the beginning by the MSI calls is causing the main window to screw up, but I have no way to prevent that window from appearing. Also, it wouldn't make sense to hide it, because it lets the user know what's going on before the main window arrives.

Pervasive answered 27/3, 2009 at 2:44 Comment(0)
D
14

Andrew isn't completely correct. Windows does try really hard to stop you from stealing focus, but it is possible using the folowing method.

  1. Attach to the thread of the window that currently has focus.
  2. Bring your window into focus.
  3. Detach from the thread.

And the code for that would go something like this:

DWORD dwCurrentThread = GetCurrentThreadId();
DWORD dwFGThread      = GetWindowThreadProcessId(GetForegroundWindow(), NULL);


AttachThreadInput(dwCurrentThread, dwFGThread, TRUE);

// Possible actions you may wan to bring the window into focus.
SetForegroundWindow(hwnd);
SetCapture(hwnd);
SetFocus(hwnd);
SetActiveWindow(hwnd);
EnableWindow(hwnd, TRUE);

AttachThreadInput(dwCurrentThread, dwFGThread, FALSE);

You may or may not need to have to run your program with administrative privileges for this to work, but I've used this code personally and it has go the job done.

Drava answered 19/12, 2013 at 21:15 Comment(2)
This does not work in Windows 10 1703 (Creators update)Bagnio
Man, you literally saved me! I was making custom keyboard shortcut engine based on low level hook. When launching regedit it was always in the background, because my engine has no window at all, so it can't create process on-top of active window. I spawned fake invisible window, but I couldn't make it foreground still. Only your method helped achieve this! BTW I'm on Windows 10 21H2 and it works perfectly! Even though, my "fake" window that I switch focus to is not even visible!Heard
R
6

You can't steal focus. Period.

See this Old New Thing article:

https://blogs.msdn.microsoft.com/oldnewthing/20090220-00/?p=19083

Rolle answered 27/3, 2009 at 3:17 Comment(9)
Thank you, I was looking for this article as the answer to this question. Please everyone that reads this, internalise it and fix the virus meme that tries to steal foreground activation. But my app is special! Your app is user hostile. Don't do it!Compartment
I agree and although in all likely hood this applies to the author, he (or somebody else) may have a good reason to need this functionality (closed system, private or home computer only). Make a recommendation on usage but don't hide the information.Vitiligo
I hope that Microsoft will - some day - finally fix all focus-stealing once and for all. Programmers doing focus-stealing should be sent to Siberia. Naked.Sima
My reason for stealing focus is that the user just launched the application, it launches a window that does get focus, that window goes away, and the app launches another window, which doesn't get focus. That leaves the user scratching his head if I don't fix that.Pervasive
That article is of no use to me, because I'm not running a second instance of the same application. My application (or, rather, the MSI calls that my application is calling) is launching a window and then closing it, and my app then launches its main window. It's not taking focus, but it should.Pervasive
It sounds like it applies exactly to your situation. You have process A launching process B and you want process B to get focus. The solution, as the article explains, is that process A must give process B focus - process B can't take focus by itself.Rolle
No, my program calls MSI functions that end up opening a progress window (which gets focus). The last MSI function call closes the window, and my app then opens its main window (which doesn't get focus). It's all happening in the same process.Pervasive
For those that follow: RobH's situation is EXACTLY why you shouldn't steal focus. If I launch an app that starts some process you can bet that I'm typing an email while waiting for it to load. Now comes your focus stealing app that most likely is asking if it's okay to do something at the same time I'm hitting enter.. Just don't do it.Wits
I laughed pretty hard at this post when I thought about the number of times I've had applications steal focus. Yeah. Totally impossible, "period".Aponeurosis
A
1

There ARE good reasons for an app to 'steal' focus. My application is a server loading many driver DLLs. Another application, connecting to the server, has a button that sends a message to the server to show detail information in one of those DLLs (owned by the server, not the client app) for convenience. Unfortunately, this popped open window is usually buried under multiple windows.

Aretino answered 19/2, 2021 at 14:22 Comment(0)
L
0

doesn't ShowWindow(youwindow,SW_SHOWNORMAL) work? -don

Lucais answered 27/3, 2009 at 2:50 Comment(1)
Haven't tried it, but I'm guessing that it's no more effective than BringWindowToTop(). (See my comment on Mitch Wheat's reply.)Pervasive
V
0

You will find that BringWindowToTop or SetForegroundWindow have requirements that must be met before the window will actually be forced to the front over all other windows (applications). If these aren't met, Windows will only flash the application's icon in the taskbar. This article presents a way around that but as 1800 INFORMATION points out, it is not recommended. I guess you'll just have to accept it.

Vitiligo answered 27/3, 2009 at 3:5 Comment(1)
Don't do this. Raymond Chen explains why this often causes your app to hang: blogs.msdn.com/oldnewthing/archive/2008/08/01/8795860.aspxCompartment

© 2022 - 2024 — McMap. All rights reserved.