How could I detect when my application is minimized? - c++

I have a program with an option to enable minimizing to the taskbar's notification area. In order for this to work, I need a reliable way of detecting when the user has minimized the application.
How can I do that using the Windows API in a C++ application?

When the user minimizes the window (either using the box on the title bar, or by selecting the "Minimize" option from the system menu), your application will receive a WM_SYSCOMMAND message. The wParam parameter of that message will contain the value SC_MINIMIZE, which indicates the particular type of system command that is being requested. In this case, you don't care about the lParam.
So you need to set up a message map that listens for a WM_SYSCOMMAND message with the wParam set to SC_MINIMIZE. Upon receipt of such a message, you should execute your code to minimize your application to the taskbar notification area, and return 0 (indicating that you've processed the message).
I'm not sure what GUI framework you're using. The sample code could potentially look very different for different toolkits. Here's what you might use in a straight Win32 C application:
switch (message)
{
case WM_SYSCOMMAND:
if ((wParam & 0xFFF0) == SC_MINIMIZE)
{
// shrink the application to the notification area
// ...
return 0;
}
break;
}

I think you are looking for WM_SIZE. When you get this, check the wParam to get the specifics. Here is the MSDN page.
WM_SIZE

You can check the area size returned from GetClientRect - if zero it's minimised, works for me but may not work in all cases.

That's what IsIconic is supposed to determine, but it doesn't work consistently for me. (Oh, for a consistent way to determine this...)

For completeness, there's also GetWindowPlacement. The window state is revealed in the showCmd member of the WINDOWPLACEMENT structure, and if the window is minimized it has a value of 2, or SW_SHOWMINIMIZED.

Related

Blocking Keyboard Play/Pause Button in Win 8

I am writing an application that needs to temporarily disable the Play/Pause button that appears on multimedia keyboards.
Normally, a key can be blocked quite easily by installing a low level keyboard hook (WH_KEYBOARD_LL) where the KeyboardProc intercepts the key (in this case VK_MEDIA_PLAY_PAUSE) and returns 1 instead of calling CallNextHookEx. I have tried this with other keys (including the Windows key VK_LWIN) and this works perfectly. I also have no problems with this method under Windows 7 where all keys, including VK_MEDIA_PLAY_PAUSE get blocked.
Windows 8 is a different story. When my application has input focus, everything works as expected, meaning the VK_MEDIA_PLAY_PAUSE key gets blocked and no other application responds to it. However, when my application loses focus, my hook procedure gets called (this was verified by sending out a OutputDebugString) but other applications respond to key even though I return 1. As soon as my app gets focus again, everything is block as it should.
After some investigation, I found that the multimedia keys not only generate keystrokes but also generate WM_APPCOMMAND messages so I added ShellProc (WH_SHELL) hook with the following hook procedure:
LRESULT __declspec(dllexport)__stdcall CALLBACK ShellProc(int nCode,WPARAM wParam,LPARAM lParam)
{
// Do we have to handle this message?
if (nCode == HSHELL_APPCOMMAND)
{
OutputDebugStringX(">>>>> HSHELL_APPCOMMAND");
// Process the hook if the hNotifyWnd window handle is valid
short AppCommand = GET_APPCOMMAND_LPARAM(lParam);
switch (AppCommand)
{
case APPCOMMAND_MEDIA_NEXTTRACK:
case APPCOMMAND_MEDIA_PLAY_PAUSE:
case APPCOMMAND_MEDIA_PREVIOUSTRACK:
case APPCOMMAND_MEDIA_STOP:
OutputDebugString(">>>>>ShellProc got a media command");
return 1;
}
}
// Call the next handler in the chain
return CallNextHookEx (hsh, nCode, wParam, lParam);
}
This procedure is only getting called when my app has input focus. Whenever I have input focus and return 1 the Play/Pause command gets blocked. As soon as I lose focus the procedure does not get called/hooked.
Anyone have any idea as to what is going on? As I have mentioned, the code works for other keys, just not the multimedia keys. Everything works fine in Windows 7.
Alternatively, can anyone suggest another way of blocking the multimedia keyboards Play/Pause button?
From the MSDN documentation for ShellProc:
HSHELL_APPCOMMAND: The user completed an input event (for example, pressed an application command button on the mouse or an application command key on the keyboard), and the application did not handle the WM_APPCOMMAND message generated by that input. [Emphasis added.]
The emphasized portion suggests that your hook callback only gets called after an application ignores the WM_APPCOMMAND. In other words, you're too late.
To catch the message in flight, I think you need a different type of hook. Perhaps WH_GETMESSAGE or WH_CALLWNDPROC.
But why are you trying to prevent the users from interacting with their applications as they choose?

How do I stop Windows from blocking the program during a window drag or menu button being held down?

I am novice with Win32, and I have been pursuing a problem (if it can be called a problem at all) with Windows blocking your program's flow during the event when a user grabs the window title bar and moves it around the screen.
I have no legitimate reason to solve this problem, except that it bothers me. A few possibilities include removing the frame altogether, but it seems an inconvenient hack. Some games (single player) do not find this a problem at all. I have read however, that multiplayer games might experience problems when the program freezes as it expects continuous flow of information and can be overwhelmed after such a delay.
I have tried adding this to my WindowProc
switch (uMsg)
{
case WM_SYSCOMMAND:
if (wParam == SC_CLOSE)
PostQuitMessage(0);
return 0;
...
...
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
And this seems a quick hack, except that when I mousedown over the close icon I can pull the mouse away and let go without closing the program, and during that time, when the close icon is held down, the program once again is blocked.
Furthermore, I do not know how to manually include the code necessary to move the window when the user clicks the titlebar and drags the mouse. For starters I do not know which uMsg's and wParam's to handle.
My question is then, how do I disallow blocking during the case when the user clicks down the exit button (or minimize/maximize buttons) while still handling the case when the mouse is clicked and released over the button, and how do I allow the user to move/drag the window without it blocking the program (or what message is sent when the title bar is clicked without it being a button or menu)?
I am creating the window with WS_SYSMENU | WS_MINIMIZEBOX.
I still want the program to respond to minimize, maximize, and exit commands.
If multi-threading can fix it, then that is interesting, but I wonder if I can get it to work on single-core processors. And I have read about hooks, but the MSDN page is still hard for me to interpret.
Why Is My App Freezing?—An Introduction to Message Loops & Threads
This phenomenon is not isolated to any particular message. It's a fundamental property of the Windows message loop: when one message is being processed, no other message can be processed at the same time. It's not exactly implemented this way, but you can think of it as a queue, where your app pulls the messages out of the queue to process in the reverse order that they are inserted.
Therefore, spending too long processing any message is going to suspend the processing of other messages, effectively freezing your application (because it cannot process any input). The only way to solve this problem is the obvious one: don't spend too long processing any one message.
Often that will mean delegating the processing to a background thread. You will still need to handle all messages on the main thread, and the background worker threads need to report back to the main method when they are finished. All interaction with the GUI needs to happen on a single thread, and that is almost always the main thread in your application (which is why it is often called the UI thread).
(And to answer an objection raised in your question, yes, you can operate multiple threads on single processor machines. You won't necessarily see any performance improvements, but it will make the UI more responsive. The logic here is that a thread can only do one thing at a time, but a processor can switch between threads extremely rapidly, effectively simulating doing more than one thing at a time.)
More useful information is available here in this MSDN article: Preventing Hangs in Windows Applications
Special Cases: Modal Event Processing Loops
Certain window operations on Windows are modal operations. Modal is a common word in computing that basically refers to locking the user into a particular mode where they cannot do anything else until they change (i.e. get out of that) modes. Whenever a modal operation is begun, a separate new message processing loop is spun up and message handling happens there (instead of your main message loop) for the duration of the mode. Common examples of these modal operations are drag-and-drop, window resizing, and message boxes.
Considering the example here of window resizing, your window receives a WM_NCLBUTTONDOWN message, which you pass to DefWindowProc for default processing. DefWindowProc figures out that the user intends to start a move or resize operation, and entered a moving/sizing message loop located somewhere deep in the bowels of Windows' own code. Thus, your application's message loop is no longer running because you've entered into a new moving/sizing mode.
Windows runs this moving/sizing loop as long as the user is interactively moving/sizing the window. It does this so that it can intercept mouse messages and process them accordingly. When the moving/sizing operation completes (e.g., when the user releases the mouse button or presses the Esc key), control will return to your application code.
It is worth pointing out that you are notified that this mode change has occurred via the WM_ENTERSIZEMOVE message; the corresponding WM_EXITSIZEMOVE message indicates that the modal event-processing loop has exited. That allows you to create a timer that will continue to generate WM_TIMER messages that your application can process. The actual details of how this is implemented are relatively unimportant, but the quick explanation is that DefWindowProc continues to dispatch WM_TIMER messages to your application inside of its own modal event processing loop. Use the SetTimer function to create a timer in response to the WM_ENTERSIZEMOVE message, and the KillTimer function to destroy it in response to the WM_EXITSIZEMOVE message.
I only point that out for completeness, though. In the majority of Windows apps that I've written, I've never needed to do that.
So, What Is Wrong With My Code?
Aside from all of that, the behavior you describe in the question are unusual. If you create a new, blank Win32 application using the Visual Studio template, I doubt you will be able to replicate this behavior. Without seeing the rest of your window procedure, I can't tell if you're blocking on any messages (as discussed above), but the part I can see in the question is wrong. You must always call DefWindowProc for messages that you do not explicitly process yourself.
In this case, you might be fooled into thinking that you're doing that, but WM_SYSCOMMAND can have lots of different values for its wParam. You only handle one of those, SC_CLOSE. All of the rest of them just get ignored because you return 0. That includes all of the window moving and resizing functionality (e.g. SC_MOVE, SC_SIZE, SC_MINIMIZE, SC_RESTORE, SC_MAXIMIZE, etc. etc.).
And there's really no good reason to handle WM_SYSCOMMAND yourself; just let DefWindowProc take care of it for you. The only time you need to handle WM_SYSCOMMAND is when you've added custom items to the window menu, and even then, you should pass every command that you do not recognize on to DefWindowProc.
A basic window procedure should look like this:
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_CLOSE:
DestroyWindow(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
It is also possible that your message loop is wrong. The idiomatic Win32 message loop (located near the bottom of your WinMain function) looks like this:
BOOL ret;
MSG msg;
while ((ret = GetMessage(&msg, nullptr, 0, 0)) != 0)
{
if (ret != -1)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
// An error occurred! Handle it and bail out.
MessageBox(nullptr, L"Unexpected Error", nullptr, MB_OK | MB_ICONERROR);
return 1;
}
}
You do not need hooks of any kind. The MSDN documentation on these is very good, but you're right: they're complicated. Stay away until you have a better understanding of the Win32 programming model. It is a rare case indeed where you need the functionality provided by a hook.
If multi-threading can fix it, then that is interesting but I wonder
if I can get it to work on single-core processors. And I have read
about hooks, but the MSDN page is still hard for me to interpret.
You can use multiple threads on a single-core processor. Performance would be better on multi-core systems, but that shouldn't prevent you from writing multithreaded applications. Anyway, go for it.
By printing all messages sent to WindowProc it appears WM_NCLBUTTONDOWN is sent last before the block occurs. You could check the mouse location after this event occurs, but it seems an inconvenient way to solve a simple problem.

Intercept mouse input

I was wondering if there is a way to intercept and modify mouse input before it gets to windows?
What I'm wanting to do is intercept mouse motion events, apply some custom scaling and acceleration to the values, and then continue passing them along. I'd need something that can do this before the inputs get to the raw input API or DirectInput.
In order to affect all mouse input, including DirectInput, during logon and the SAS screen, etc., you'll need to load a filter driver into the mouse driver stack.
Other people have done it, for example http://www.maf-soft.de/mafmouse/
There should be a moufiltr sample in the Windows DDK which you can use as a starting point. You will most likely want to use a virtual machine for development since errors in a driver on your development machine could be difficult to recover from.
Have you seen this method of intercepting mouse and keyboard input without having to make a filter driver or hook?
http://oblita.com/Interception.html
There is a LowLevelMouseProc hook procedure that you can use to get information on any mouse input entering the system, although I doubt if you can actually change this information (and the docs are silent on this).
If this fails, GetMsgProc is an alternative that lets you intercept all messages posted to any window. Though this hook does let you modify the message, it's probably too late to have any effect on APIs such as DirectInput.
You could try a windows hook - which are functions you set to receive windows messages before they get passed through to the rest of the system - a CBT hook (for computer based training) is what might get you best results.
I don't know Whether this will work with DirectInput or the other new stuff MS has added to break all the old internal consistency. Its easy to set up though, so try it and see.
As far as I know the best way is to hook to windows message loop, In your case you should pass HWND 0 (If I remember correctly this the HWND of the desktop) so all the messages will pass though your function first.
http://msdn.microsoft.com/en-us/library/ms633591%28VS.85%29.aspx
More on hooks : http://msdn.microsoft.com/en-us/library/ms644959%28VS.85%29.aspx
Use it as follows:
m_nOldWindowProc = ::SetWindowLong(0 /I think.../, GWL_WNDPROC, (LPARAM)(WNDPROC)WindowProcCallback);
and the callback:
LRESULT CALLBACK CStubWindow::WindowProcCallback(HWND hwnd,
UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_WINDOWPOSCHANGING:
((WINDOWPOS*)lParam)->cx = STATUS_BAR_WIDTH;
((WINDOWPOS*)lParam)->flags = SWP_NOOWNERZORDER | SWP_NOMOVE;
break;
default:
break;
}
return ::CallWindowProc(m_nOldWindowProc, hwnd, message, wParam, lParam);
}

C++ - Dialog box question

This is a more concrete question that is connected with my previous one.
I have an application that uses a timer. The code is written the way the my WM_TIMER handler call a DialogBoxParam(...) with some custom message handler (let's call it DlgProc).
This is done somewhat the following way:
case WM_TIMER:
{
// Routine, that displays a special message box
DisplayMessageBox(...);
return 0;
}
Now, if I make DlgProc handle the messages like this (see the code), this would result in tons of dialog boxes (one per WM_TIMER call).
switch (msg)
{
case WM_INITDIALOG:
// (...)
return TRUE;
case WM_COMMAND:
// (...)
return TRUE;
return FALSE;
}
But if I add a dummy WM_PAINT handler (return TRUE;) to my DlgProc, this results in exactly one shown DialogBox and 100% CPU load (that's because I receive tons of WM_PAINT messages).
Q:
What can be done here if I want my application to show exactly ONE dialog box and have no CPU load for WM_PAINT processing? (I mean like, have behaviour similiar to draw unique dialog box and fully pause the parent window).
Also it would be great if someone explains what actually happens in this situation and why do I receive gazillions of WM_PAINT messages to my dialog box and why their processing (with return TRUE) results in preventing the other dialog boxes creation.
Thank you.
1) You should disable the timer after the first WM_TIMER signal is caught if you want to show only one single dialog box. You can do this using KillTimer().
2) Windows wants to keep the GUI up-to-date. Whenever a region on the screen should be updated, it is invalidated using InvalidateRect or InvalidateRgn. Now, for every "invalid" screen part, WM_PAINT is called in order to make in "valid" again.
If you don't do it (or just parts of it), Windows will call WM_PAINT again ... and again. One way is to call ValidateRect. In many cases BeginPaint() and EndPaint() are used to do the job.
3) Maybe most important: you should not just return FALSE! Try DefWindowProc() for windows and DefDlgProc() for dialogs. They will also take care of WM_PAINT appropriately.
It's not that you registered for WM_PAINT, something must cause it (even if you don't add WM_PAINT: handler), look for re/draw functions (like InvalidateRect())

Windows/C++: detect when focus has changed between windows (globally)

I'm trying to find a way to detect when focus is changed to another window (without having to poll every X ms).
I've already figured out a way to detect when focus is switched between applications using WH_SHELL and HSHELL_ACTIVATESHELLWINDOW.
The problem is I want to detect when focus is switched between dialog/windows within the same app.
ie. In Notepad, I can determine when the app switches to Notepad, but I cannot detect when the "Open" or "Save" dialogs appear because the focus is still within the same application.
You can use SetWindowsHookEx with a WH_CBT hook type. If you just want to detect focus changes within an application, pass GetCurrentThreadId() as the last parameter, otherwise the hook will be for all threads on the current desktop.
Note that using windows hooks can have an adverse effect on system performance, so the hook should only be installed when necessary and you should do a minimum amount of work in the hook procedure.
Sorry for the delay, I don't have VS installed on this computer so it's a bit hard to find the code.
Use this to hook your code into the system.
HHOOK oldShellHook = SetWindowsHookEx(WH_SHELL, BCK_WndShellProc, hDll, NULL);
if (!info->oldShellHook) {
MessageBox(m_hwnd, L"Failed to load global hook.", strTitle, MB_OK | MB_ICONERROR);
return;
}
And this your hook. Depending on what you're doing, use nMsg to figure out when you want to apply your custom logic.
LRESULT CALLBACK BCK_WndShellProc(int nMsg, WPARAM wParam, LPARAM lParam) {
...
}
Read the MSDN docs for SetWindowsHookEx() to make sure you return the expected values, otherwise you can lock up the whole system.
I use code similar to this on my Breadcrumb Killer and Spasm (Show all programs on Start menu) programs and it seems to work fine.
How about the "Computer Based Training API"; SetWindowsHookEx with WH_CBT which will enable you to receive HCBT_SETFOCUS (among others)