Problem with switching application and focus - winapi

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.

Related

Toggle window visibility on tray icon click using WinAPI

How can I bring a window to the top if not there, and close it otherwise, when the tray icon is clicked, using the Windows API? That is, very similar to what the taskbar icon does. By bring to the top I mean fully visible to the user.
I cannot find a way to tell whether the window is on top or not, because when the tray icon is clicked, the taskbar is always on top. I tried inspecting the Z-order of the windows but it looks inconsistent. For example, when the application window is on top and tray icon is clicked, I would expect a constant number of taskbar/tray windows to be brought to top, and the window immediately following them being the one that was on top. But that's not the case, it seems.
I could mostly implement it, the problem is that the toggle doesn't care whether the window is open and fully visible to the user (on top). When the tray icon is clicked and the window is currently closed, it is opened and brought to top correctly. When the window is open and on top, it is also closed correctly. However, when the window is open but not on top, it will be closed instead of being brought to foreground.
To expand upon what Hans Passant said:
"On top" is not important, since some windows can be always on top; it's whether the window is the foreground window or not that you're concerned with.
Use GetForegroundWindow() to see if your window is the foreground window and if not, SetForegroundWindow() to make it so.
Thanks to Mike Gelfand who solved the problem! The following function will return:
-1 when window is closed
0 when window is fully visible
1 or above when window is open but not fully visible
int GetMyWindowLevel(HWND myWindow) {
WINDOWINFO myWindowInfo;
myWindowInfo.cbSize = sizeof(myWindowInfo);
if (!GetWindowInfo(myWindow, &myWindowInfo))
return -1;
int myWindowLevel = -1;
HWND currentWindow = GetTopWindow(NULL);
for (; currentWindow != NULL;
currentWindow = GetNextWindow(currentWindow, GW_HWNDNEXT)) {
WINDOWINFO currentWindowInfo;
currentWindowInfo.cbSize = sizeof(currentWindowInfo);
if (!GetWindowInfo(currentWindow, &currentWindowInfo))
continue;
if ((currentWindowInfo.dwExStyle & WS_EX_TOPMOST) !=
(myWindowInfo.dwExStyle & WS_EX_TOPMOST) ||
(currentWindowInfo.dwStyle & WS_POPUP) != 0)
continue;
++myWindowLevel;
if (currentWindow == myWindow)
break;
}
return currentWindow == myWindow ? myWindowLevel : -1;
}

Cocoa - go to foreground/background programmatically

I have an application with LSUIElement set to 1. It has a built-in editor, so I want the application to appear in Cmd+Tab cycle when the editor is open.
-(void)stepIntoForeground
{
if (NSAppKitVersionNumber < NSAppKitVersionNumber10_7) return;
if (counter == 0) {
ProcessSerialNumber psn = {0, kCurrentProcess};
OSStatus osstatus = TransformProcessType(&psn, kProcessTransformToForegroundApplication);
if (osstatus == 0) {
++counter;
} else {
//...
}
}
}
-(void)stepIntoBackground
{
if (NSAppKitVersionNumber < NSAppKitVersionNumber10_7) return;
if (counter == 0) return;
if (counter == 1) {
ProcessSerialNumber psn = {0, kCurrentProcess};
OSStatus osstatus = TransformProcessType(&psn, kProcessTransformToUIElementApplication);
if (osstatus == 0) {
--counter;
} else {
//..
}
}
}
The problems are:
there's also a Dock icon (not a big deal);
there's also Menu, that is not a big deal too, but they appear not always.
Is there any way to disable menu at all or to make it appear always in foreground? Thanks in advance.
This is how we do it.
(Works 10.7+)
DO NOT USE LSBackgroundOnly NOR LSUIElement in the app plist
Add and init your menu and NSStatusBar menu
After app initialized but not yet shown any window take a place where you might want to show the first window if any. We use applicationDidFinishLaunching.
If you do not want to show any window yet after app initialized use
[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
on 10.9 you can use at last the otherwise much correct
[NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
If you should open any window after app init finished than simply show the main window
Maintain your list of windows
If last window closed, call
[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
on 10.9 you can use at last the otherwise much correct
[NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
When your first window shown next time, call
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[NSApp activateIgnoringOtherApps:YES];
[[self window] makeKeyAndOrderFront:nil];
This should do the trick, if at least one app window is visible you will have menu, dock icon with state signaled, and cmd+tab element with your app, if last app window closed only your NSStatusBar element stays.
Known issues:
The first step is important because without that if a system modal dialog suspends your startup (f.e. your app is downloaded from the net and become quarantined a confirmation dialog might appear at first startup depending on your security settings) your menubar might not be owned by your app after your first app window shown.
Workaround: Starting as normal app (step 1.) would solve this problem, but will cause another small one, your app icon might appear for a moment in the dock at startup even if you would like to startup without any window shown. (but we can deal with this, not owning the menubar was a bigger problem for us, so we chose this instead)
Changing between NSApplicationActivationPolicyRegular and NSApplicationActivationPolicyAccessory (or NSApplicationActivationPolicyProhibited on OSes bellow 10.9) will kill your tooltip of status bar menu element, the tooltip will be shown initially but will not ever after the second call of NSApplicationActivationPolicyAccessory -> NSApplicationActivationPolicyProhibited
Workaround: We could not find a working workaround for this and reported to Apple as a bug.
Changing from NSApplicationActivationPolicyRegular to NSApplicationActivationPolicyAccessory has other problems on some OS versions like there might be no more mouse events in visible app windows sometimes
Workaround: switch first to NSApplicationActivationPolicyProhibited (take care this leads to unwanted app messages, like NSApplicationWillResignActiveNotification, NSWindowDidResignMainNotification, etc. !)
Changing from NSApplicationActivationPolicyAccessory to NSApplicationActivationPolicyRegular is bogus as on some OS versions
the app main menu is frozen till the first app front status change
the app activated after this policy not always get placed front in the application order
Workaround: switch first to NSApplicationActivationPolicyProhibited, take care the final switch to the desired NSApplicationActivationPolicyRegular should be made delayed, use f.e. dispatch_async or similar
With swift 4, in applicationDidfinishLaunching(_:Notification)
NSApplication.shared.setActivationPolicy(.regular)
did the trick for me, but I was only trying to get keyboard focus to my programmatically created window. Thanks.
You can set App "Application is agent (UIElement)" to YES in your plist file.
EDIT:
I think there are some hacks to do this.
But it's really not the way it's meant to be.
Cmd+tab is for getting an application to foreground, but if you don't have a menu bar, it doesn't look like foreground to the user.
I'd rather make a menu bar to access the app.

windows application showing behind the taskbar on vista

I have an MFC application. In my application if I run on Windows XP it's working fine. But if I run in Windows Vista the MFC dialog hides behind the taskbar.
bool bHide=true;
CRect rectWorkArea = CRect(0,0,0,0);
CRect rectTaskBar = CRect(0,0,0,0);
CWnd* pWnd = CWnd::FindWindow("Shell_TrayWnd", "");
pWnd->ShowWindow(SW_SHOW);
if( bHide )
{ // Code to Hide the System Task Bar
SystemParametersInfo(SPI_GETWORKAREA,0,(LPVOID)&rectWorkArea,0);
if( pWnd )
{
pWnd->GetWindowRect(rectTaskBar);
// rectWorkArea.bottom -= rectTaskBar.Height();
rectWorkArea.bottom += rectTaskBar.Height();//-----to hide taskbar
SystemParametersInfo(SPI_SETWORKAREA,0,(LPVOID)&rectWorkArea,0);
// pWnd->ShowWindow(SW_SHOW);
pWnd->ShowWindow(SW_HIDE); //--to hide taskbar
}
}
I used this code but it hides the taskbar. But I want to show the application above the task bar.
You don't own the taskbar, so you are not supposed to hide it. You have the option to auto-minimize it by the way. You have another option of using secondary monitor without taskbar there.
On the primary monitor your app is given work area, you are being able to locate (judging from the code snippet provided above). It is the best to position your window within this area without interfering with the taskbar, whether it is above or beyond.
If you still feel like making it more like a competition "who is on top" with the task bar, you might want to take a look at SetWindowPos API and window Z-Order.
finally i found the solution , what we want to do is we should add the below code in our oninitdialog,
SetWindowPos(&this->wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
the above line is enough to show the mfc dialog on above the taskbar . but sometimes the focus of the dialog get changed looks hanged(no response in dialog) the application.if it occurs put the below code.
SetWindowPos(&this->wndBottom,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);

Starting a windows-application with focus

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);
}

How can I tell if a window has focus? (Win32 API)

Using the Win32 API (in C, but that's inconsequential), how can I tell if a given window (identified by HWND) has focus?
I'm hooking an application watching for an event, and when that event occurs I want to check if the application already has focus. If it doesn't, I want to flash the window until they give focus to it.
Alternately, does the FlashWindowEx struct flag FLASHW_TIMERNOFG that flashes until the window has focus just not flash if the window already has focus?
I cannot test this now since I am not in my development environment, but I was under the impression that it would flash anyways, which is what I'm trying to avoid.
Also, if it matters, the application uses DirectX in this window.
GetActiveWindow will return the top-level window that is associated with the input focus. GetFocus will return the handle of the window that has the input focus.
This article might help:
http://www.microsoft.com/msj/0397/Win32/Win320397.aspx
Besides gkrogers answer using GetActiveWindow, you can also maintain a boolean variable for the window you want to know if it has focus or not by trapping the WM_SETFOCUS and WM_KILLFOCUS events, or WM_ACTIVATE:
WndProc() ..
case WM_SETFOCUS:
puts( "Got the focus" ) ;
break ;
case WM_KILLFOCUS:
puts( "Lost the focus" ) ;
break;
case WM_ACTIVATE:
if( LOWORD(wparam) == WA_INACTIVE )
puts( "I AM NOW INACTIVE." ) ;
else // WA_ACTIVE or WA_CLICKACTIVE
puts( "MEGAZORD ACTIVATED kew kew kew (flashy-eyes)" ) ;
break ;
Do you really mean "focus" or do you mean "active?"
One window has the focus -- the one that's first in line to get keyboard events. The outer window (that the user can drag around the screen) is "active" if one of its subwindows has the focus, but it might or might not have focus itself.
Use GetForegroundWindow function to get the Hwnd that you are focusing right now. Then you just need to compare it to the window of your application to check whether it contains focus or not.
For multiple modeless children:
Within the child you could save the focus, 13/08/2019 Visual Studio 2017.
You can save the focus so the parent knows which modeless child was clicked on.
In the child's callback handler:
case WM_CHILDACTIVATE: // Only gets called when the child border is click on.
//CurrentFocus = hDlg; // Example: can save the focus globally for parent usage.
//Beep(2000, 250); // So you can test
break;
case WM_GETMINMAXINFO: // Gets called when child window is being moved or sized.
//Beep(2000, 250);
break;
case WM_LBUTTONDOWN: // Only called when cursor is inside the child client area
//CurrentFocus = hDlg; // Following the focus.
//Beep(2000, 250);
break;

Resources