Windows properly detect active window changed - c++

I write a DLL need to know current active window and detect when active window changed.
For detecting active window changed, I use SetWinEventHook and listen for the EVENT_SYSTEM_FOREGROUND event.
hEvent = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND , NULL, WinEventProcCallback,0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
I've found that this doesn't work consistently. Sometimes my callback is called, other times not, depending from what to what focus is switched. Perhaps another event...
Is there any Windows (WINAPI?) event which fires every time the active (focused) window changed? I'd like to subscribe with my callback function.
Thanks.

Related

What's the correct way to bring a window to the front

I've been trying multiple ways of bringing a window into focus and on top of other windows.
I've tried SetForegroundWindow(), BringWindowToTop(), SetActiveWindow(). None of these work consistently.
How can I simply make it so that a window that I want to be in focus, becomes on top of all other windows and is focused? Why is this so difficult?
SetForegroundWindow() is the correct way to change the foreground window, but the thread that calls SetForegroundWindow() has to meet certain criteria for it to "work". If it does not meet the criteria, the window's taskbar button is flashed instead. This is by design. This is to protect the user from applications stealing focus and you should respect that.
See also:
Foreground activation permission is like love: You can’t steal it, it has to be given to you
What if two programs did this?
Your process needs to satisfy a few conditions for it to be able to set the foreground window.
This is to prevent applications from stealing focus - which is a very bad user experience.
Imagine you're writing an email, and halfway through it your application decides now would be a good time to push a window into foreground. As you're typing suddenly the focused window would instantly change and your keypresses would now be sent to your program instead of the mail program. Not only could this cause all sorts of havoc (the keys you pressed are now sent to your program, so hotkeys might get triggered, dialogs dismissed, etc...) - but it would also be a really frustrating experience for the user (especially for less technically-inclined people).
That is the reason why SetForegroundWindow() & similar functions sometimes won't push your window to the foreground, but still report success. Your window will still flash in the task bar though, so users know that something happened in your application.
SetForegroundWindow
The exact list of conditions that need to be met for SetForegroundWindow() to work are detailed in the documentation:
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.
An application cannot force a window to the foreground while the user is working with another window ¹. Instead, Windows flashes the taskbar button of the window to notify the user.
1 this is what prevents the mail program example detailed above from happening.
A process that fulfills these criteria can also "share" its permission to set the foreground window with another process by calling AllowSetForegroundWindow()
SetActiveWindow
SetActiveWindow() only works if the targeted window is attached to your message queue and one of your application windows is currently the foreground window.
Activates a window. The window must be attached to the calling thread's message queue.
The window will be brought into the foreground (top of Z-Order) if its application is in the foreground when the system activates the window.
BringWindowToTop
BringWindowToTop() is a convenience function for SetWindowPos(), which again has the same restrictions:
If an application is not in the foreground, and should be in the foreground, it must call the SetForegroundWindow function.
To use SetWindowPos to bring a window to the top, the process that owns the window must have SetForegroundWindow permission.
Using UI Automation
Since you mentioned that you need this functionality for an accessibility tool, here's how you could accomplish this using UI Automation:
This example uses bare-bones COM for simplicity, but if you want you can of course use e.g. wil for a more C++-like API.
#include <uiautomation.h>
bool MoveWindowToForeground(IUIAutomation* pAutomation, HWND hWnd) {
// retrieve an ui automation handle for a given window
IUIAutomationElement* element = nullptr;
HRESULT result = pAutomation->ElementFromHandle(hWnd, &element);
if (FAILED(result))
return false;
// move the window into the foreground
result = element->SetFocus();
// cleanup
element->Release();
return SUCCEEDED(result);
}
int main()
{
// initialize COM, only needs to be done once per thread
CoInitialize(nullptr);
// create the UI automation object
IUIAutomation* pAutomation = nullptr;
HRESULT result = CoCreateInstance(CLSID_CUIAutomation, NULL, CLSCTX_INPROC_SERVER, IID_IUIAutomation, reinterpret_cast<LPVOID*>(&pAutomation));
if (FAILED(result))
return 1;
// move the given window into the foreground
HWND hWnd = FindWindowW(nullptr, L"Calculator");
MoveWindowToForeground(pAutomation, hWnd);
// cleanup
pAutomation->Release();
CoUninitialize();
return 0;
}

Prevent window movement

I currently have a small game which runs in a win32 window. I just noticed that when I hold the top of the window (the bar which has the closing button) it freezes my application. I would like to disable this as it manages to completely destroy my application (timers continue to count).
It seems that with even the most minimalistic settings for creation of the window it still has this feature. How can I disable this? I currently have:
HWND hWnd = CreateWindowW( L"Game",L"Game",
0x00000000L | 0x00080000L,
wr.left,
wr.top,
wr.right-wr.left,
wr.bottom-wr.top,
NULL,
NULL,
wc.hInstance,
NULL );
I read that my thread is ignored while dragging, if I am forced into using 2 threads could someone please provide a small example of usage?
Or should I stop the timers? (what message should I catch, and would it even be catched?)
Update
I am using instances of my time class to handle timings which looks something like:
Timer::Timer() {
__int64 frequency;
QueryPerformanceFrequency( (LARGE_INTEGER*)&frequency );
invFreqMilli = 1.0f / (float)((double)frequency / 1000.0);
StartWatch();
}
void Timer::StartWatch() {
startCount = 0;
currentCount = 0;
watchStopped = false;
QueryPerformanceCounter( (LARGE_INTEGER*)&startCount );
}
My Win32 message loop contains: mousemove, keyup and keydown.
When DefWindowProc handles WM_SYSCOMMAND with either SC_MOVE or SC_SIZE in the wParam, it enters a loop until the user stops it by releasing the mouse button, or pressing either enter or escape. It does this because it allows the program to render both the client area (where your widgets or game or whatever is drawn) and the borders and caption area by handling WM_PAINT and WM_NCPAINT messages (you should still receive these events in your Window Procedure).
It works fine for normal Windows apps, which do most of their processing inside of their Window Procedure as a result of receiving messages. It only effects programs which do processing outside of the Window Procedure, such as games (which are usually fullscreen and not affected anyway).
However, there is a way around it: handle WM_SYSCOMMAND yourself, resize or move yourself. This requires a good deal of effort, but may prove to be worth it. Alternatively, you could use setjmp/longjmp to escape from the Window Procedure when WM_SIZING is sent, or Windows Fibers along the same lines; these are hackish solutions though.
I solved it (using the first method) this past weekend, if you're interested I have released the code to the public domain on sourceforge. Just make sure to read the README, especially the caveat section. Here it is: https://sourceforge.net/projects/win32loopl/
Since the title bar to the user that he/she can move the window, you could remove that title bar and borders altogether. See "opening a window that has no title bar with win32" for an example.
When the game launches or is paused, you could show your own UI elements to allow the user to move the game window in these specific situations but only then.
You can check for the size/move loop using the WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE messages.

How to use mouse hook so current window never sees specific mouse message?

I want some window to never receive mouse wheel up/downs, i can control this messages trough my mouse hook fine but is there a way to make a window never receive those messages?
I can validate the window trough mouse hook and check if its active then just never send that message to it.
I installed mouse hook globally so i believe i have everything needed.
AFAIK hooks may not block the message from reaching the wndproc of the appropriate window.
You may however achieve what you need by subclassing the appropriate windows. That is, replace the window procedure of the appropriate window (use SetWindowLongPtr with GWL_WNDPROC flag) by your wndproc. It should pass all the messages to the original wndproc, apart from those that you want to filter-out.

C++/Win32 API - SetFocus to button does not work

HWND button = CreateWindowEx(0, "BUTTON", ...);
SetFocus(button); // Button no get focus! :(
Also, I have other controls on my form that I am able to SetFocus() to.
Thanks, Martin
It has been FOREVER since I've had to do this, but...
Were this a dialog, I would tell you to send a WM_NEXTDLGCTL via PostMessage(). The default dialog item message handler would take care of the rest for you setting keyboard focus and selection activation. However, this is a different case if I read this correctly. You're creating both parent and child windows raw on the fly. If this is the case, SetFocus() to the parent window, and handle WM_SETFOCUS on the parent window by bringing it to top, then setting focus on the child window. WM_SETFOCUS, and WM_KILLFOCUS were designed to allow you to switch the 'activated' state of your controls, and most handle it for you (unless your window is an owner draw control or some such). But in a raw window, when your base parent window is sent the focus, you need to appropriately ensure the proper child has it if you're hosting any (think of it as managing your own 'dialog'). Again, normally this is done by the default dialog procedure for you if this were a dialog, but being raw windows you're kind of stuck managing it all yourself.
Though I can't imagine how, I hope that helped somewhat.
SetFocus is a function, not a procedure. Call it as a function and check its returned value. Either the retuned value is null because you made an error in the CreateWindowEx() call and "button" isn't a valid handle or it's a window not associated with your thread's message queue, or the return value is not null (it's now the prior focused window's handle) and you do have the focus (but are somehow failing to detect it).
Try setting the WS_TABSTOP style on the button.
If you create that button in respond of the WM_INITDIALOG message you should return FALSE to prevent dialog box procedure to change the focus.

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

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.
Andrew isn't completely correct. Windows does try really hard to stop you from stealing focus, but it is possible using the folowing method.
Attach to the thread of the window that currently has focus.
Bring your window into focus.
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.
You can't steal focus. Period.
See this Old New Thing article:
https://blogs.msdn.microsoft.com/oldnewthing/20090220-00/?p=19083
doesn't ShowWindow(youwindow,SW_SHOWNORMAL) work?
-don
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.
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.