I'm writing a small Windows application in Visual C++ without MVC. Its really small, it just contains one textfield, an OK-Button and an Cancel-Button.
The application is started by a background-process when user starts printing. When opening the application doesn't get focus, isn't even visible.
For the user it's importend that the application is directly in focus, so they have as lease clicks as possible to use it.
I tried many many things to get the application in focus:
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
SetForegroundWindow(hWnd);
ShowWindow(hWnd, SW_RESTORE);
SetFocus(hWnd);
I even repeated this calls in a timer. All of this doesn't work. Now I found some remarks on MSDN:
The system restricts which processes can set the foreground window. A
process can set the foreground window only if one of the following
conditions is true:
The process is the foreground process.
The process was started by the foreground process.
The process received the last input event.
There is no foreground process.
The foreground process is being debugged.
The foreground is not locked (see LockSetForegroundWindow).
The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
No menus are active.
Anybody knows a workaround for this?
There is no workaround for this. The whole point of this new Windows behavior is to prevent applications from bringing themselves to the foreground on their own and being a nuisance. In your case, I would suggest using a notification icon and showing a balloon message when necessary instead of a window. However, even in this case your notification icon can be hidden by the user and there is no workaround, for the same reason as above.
Now, this is coming from a Java developer and not a Visual C++ developer, but can you maybe set the frame/window/whatever-its-called-in-visual-c to be always on top? In Java, if you have a JFrame, say myJFrame, you can call myJFrame.setAlwaysOnTop(true) and it stays on top of all other windows. This seems to be a simple workaround to your problem, however it may not be desirable for the user if it's blocking something of theirs on screen.
http://www.thescarms.com/vbasic/alttab.aspx seems to do the job
void forceToFront(HWND hWnd) {
HWND foregroundWindow = GetForegroundWindow();
if (foregroundWindow == hWnd) {
// Window is already Foreground-window
return;
}
if (SetForegroundWindow(hWnd)) {
// could set window to foreground without any tricks
return;
}
// attach thread of foreground-window to this window
DWORD foregroundThread = GetWindowThreadProcessId(foregroundWindow, NULL);
DWORD myThread = GetWindowThreadProcessId(hWnd, NULL);
AttachThreadInput(foregroundThread, myThread, true);
SetForegroundWindow(hWnd);
AttachThreadInput(foregroundThread, myThread, false);
}
Related
I have to put a window to foreground using its name, for example "images".
With
findWindowW(NULL, stringName)
I get the handle to the process (HWND).
Then with
SetForegroundWindow(windowHandle);
I think that I put it into the foreground automatically, but I have to press 'Enter'. Am I doing something wrong or there's another way to do that? I can use also the PID of the process.
My final purpose is to send shortcuts like CTRL+V to the process after put it into the foreground. Thank you.
From MSDN
The system restricts which processes can set the foreground window. A process can set the foreground window only if one of the following conditions is true:
The process is the foreground process.
The process was started by the foreground process.
The process received the last input event.
There is no foreground process.
The process is being debugged.
The foreground process is not a Modern Application or the Start Screen.
The foreground is not locked (see LockSetForegroundWindow).
The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
No menus are active.
So, if your program does not correspond to the above, you can not set foreground automatically.
I think you can use below code for your case and this link can be help as well.
void SetForegroundWindowForce(HWND hWnd)
{
HWND hWndForeground = ::GetForegroundWindow();
if(hWndForeground == hWnd) return;
DWORD Strange = ::GetWindowThreadProcessId(hWndForeground, NULL);
DWORD My = ::GetWindowThreadProcessId(hWnd, NULL);
if( !::AttachThreadInput(My, Strange, TRUE) )
{
ASSERT(0);
}
::SetForegroundWindow(hWnd);
::BringWindowToTop(hWnd);
if( !::AttachThreadInput(My, Strange, FALSE) )
{
ASSERT(0);
}
}
I know this sounds evil but my intention is not this at all.
A user has clicked "delay shot" and a countdown starts, during that time they go focus another application, then after countdown user expects my app to take back focus.
SetForegroundWindow fails when it runs from appliction with PID X while application with PID Y is focused.
This worked to bring my window forward, but it doesn't get focus:
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
It sets the window to be always on top. However focus is not put into my window. And then setting it back to HWND_NOTOPMOST leaves it there, even though its not top most, but it still doesnt have focus. Running SetForegroundWindow won't do the trick after these calls to SetWindowPos Is there anyway to steal focus?
I have tried a combination of:
SwitchToThisWindow
SetWindowPos
ShowWindow
SetForegroundWindow
But can't seem to figure it out.
Another reason I think this has to be possible is because Mac OSX allows it with NSApplication activateIgnoringOtherApps: and Linux's allow it too. I'd like to get this cross platform.
As a last resort I was going to use the HWND_TOPMOST method, then GetWindowRect then SetCursorPos and send single click to my window at pos 0,0, I really don't want to though as there might be something at 0,0 and it shouldn't be auto clicked on.
This always works, no matter what app is in foreground (like Task Manager, etc.):
AllocConsole();
auto hWndConsole = GetConsoleWindow();
SetWindowPos(hWndConsole, 0, 0, 0, 0, 0, SWP_NOZORDER);
FreeConsole();
SetForegroundWindow(hWnd);
As the comment says, SetForegroundWindow is sometimes useless intentionally. Basically, two ways are used to bypass restrictions:
Simulate keyboards / mouses
Get privileges
There is some smarter magic to achieve the goal without directly clicking the window you are going to activate. Since I'm not familiar with GUI, I would suggest inject code directly into current foreground window and hand over the foreground right.
Besides there're some examples on simulating.
http://www.codeproject.com/Tips/76427/How-to-bring-window-to-top-with-SetForegroundWindo.aspx
Is it possible create MFC form that cold stay on the top of all applications on PC not allowing to do anything else without entering required information.
Win32 doesn't support system-modal dialogs any more, as far as I'm aware. This is a relic from 16 bit Windows versions.
You can try yourself with a MB_SYSTEMMODAL type MessageBox.
Closest thing would be to utilize a screen-sized window to display a dimmed desktop background while your dialog is shown. This simulates the behaviour of the user account control -- except that you still can switch tasks.
You can obtain something similar setting your window on "TopMost". You can do it on property sheet in design mode, or programmatically with this line:
SetWindowPos( pWnd->m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE );
Hope this will fit your needs.
I am having trouble with SetWindowPos failing to bring windows of external processes to the top of the z-order reliably. I am able to bring windows to the front like:
NativeMethods.SetWindowPos(hwnd, new IntPtr(-1), Left, Top, Width, Height, 0x10);
NativeMethods.SetWindowPos(hwnd, new IntPtr(-2), Left, Top, Width, Height, 0x10);
It doesn't work 100% of the time though. After some reading, I found a few things.
SetWindowPos documentation states:
To use SetWindowPos to bring a window to the top, the process that owns the window must have SetForegroundWindow permission.
An article on MSDN then states
A process that is started with UIAccess rights has the following abilities:
* Set the foreground window.
AllowSetForeground mentions
The calling process must already be able to set the foreground window
I have signed my .exe and enabled UIAccess so that I can set the foreground window like so in my manifest:
<requestedExecutionLevel level="highestAvailable" uiAccess="true" />
My program starts and I get the UAC prompt asking for permission. I then test for UIAccess, admin rights, and TokenElevationType. The first 2 return true, and the 3rd returns TokenElevationTypeFull. I still run into the same problems though with my new code though.
My code is:
uint processid=0;
NativeMethods.GetWindowThreadProcessId(hwnd, out processid);
NativeMethods.AllowSetForegroundWindow((int)processid);
NativeMethods.SetWindowPos(hwnd, IntPtr.Zero, Left, Top, Width, Height, 0x10);
NativeMethods.RedrawWindow(hwnd, IntPtr.Zero, IntPtr.Zero, NativeMethods.RedrawWindowFlags.Erase | NativeMethods.RedrawWindowFlags.Invalidate | NativeMethods.RedrawWindowFlags.NoChildren);
NativeMethods.RedrawWindow(hwnd, IntPtr.Zero, IntPtr.Zero, NativeMethods.RedrawWindowFlags.Erase | NativeMethods.RedrawWindowFlags.Invalidate | NativeMethods.RedrawWindowFlags.UpdateNow | NativeMethods.RedrawWindowFlags.AllChildren);
What you want to do is contrary to the (complicated) rules Windows has in place to prevent badly-behaved programs from wresting control away from the user. (Control doesn't just mean input focus, but also control of what's visible and what's not.) Although your intentions may be aligned with the user's, what you're asking for is indistinguishable from what disruptive programs often try to do.
There are alternative ways to signal the user that non-foreground windows need attention. Check out FlashWindowEx, for example. You might also consider a tray icon that pops notification balloons. These seem like they'd be appropriate and effective solutions.
Sorry but my english is very bad.
I am writing a winapi program in c and I have a problem. The program has a main window and NO DIALOG child windows (controls). The controls are directly attached to the main window. When I switch the application to another application and back again, the focus is set to the main window and not to the control that owns the focus before switching.
My message loop is:
while ((rGetMessage = GetMessage(&msg, NULL, 0, 0)) != 0 && rGetMessage != -1)
{
if(!IsDialogMessage(hwnd_principal, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
What is my error?
I use the IsDialogMessage function for that various keys work on (like TAB key in the controls).
When you switch back to your application, Windows will by default set the keyboard focus to its main window, regardless of which window had the focus when it was deactivated. If you want to do something different you need to handle WM_ACTIVATE and use SetFocus() to restore the focus to the control.