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

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)

Related

Is there a way to disable message boxes in MFC?

I have an MFC application (using a legacy library that I can't change). When the application starts, it loads a couple of drivers and shows message boxes if some drivers couldn't be loaded. The loading of the drivers and the showing of the message boxes is done by a method inside the library that can't be changed (let's call this method Init). I would like to disable those message boxes (preventing them from "popping"). Is there something I could call before calling Init to disable Message Boxes temporarily and then re-enable them after?
(Note that if it is impossible to re-enable them after, I can very well live with that, I mostly want to disable them)
Thanks to all,
Note: If someone wonders about why I would like to do that, it is because my application exposes a COM interface and will be used by other applications. The only reason it is an application is that the library I use is much more easy to use when creating an MFC application (and not a dll). When it is called by my other applications, I don't want the message boxes to show, I just want to get the errors if something goes wrong.
I am not sure whether this could work. I use it for subclassing some messageboxes not to preven them to popup and they are not from a dll.
I set a hook to capture message boxes before poping up:
HHOK hMessageBoxHook_ = SetWindowsHookEx(WH_CBT,
&CbtHookProc,
::GetModuleHandle(NULL),
GetCurrentThreadId());
The new hook procedure (CbtHookProc) would be like this:
LRESULT CALLBACK CbtHookProc( int nCode,
WPARAM wParam,
LPARAM lParam)
{
if(nCode < 0)
{
return ::CallNextHookEx( hMessageBoxHook_,
nCode,
wParam,
lParam);
}
switch(nCode)
{
case HCBT_CREATEWND: // a window is about to be created
return -1;
}
return ::CallNextHookEx( hMessageBoxHook_,
nCode,
wParam,
lParam);
}
From microsoft documentation for HCBT_CREATEWND:
If the hook procedure returns a
nonzero value, the system destroys the
window
Then after calling Init you can remove the hook and message boxes will pop up again:
::UnhookWindowsHookEx(hMessageBoxHook_);
hMessageBoxHook_ = 0;
As I told you I can't assure it works but give it a try.
One way to do this would be to hook/unhook the calls to MessageBox/MessageBoxEx/etc. and just do nothing when these calls are made. Check this guide for details on hooking API calls. In your case, I would specifically look at Import Address Table method, which is quite easy to implement and allows you to achieve the functionality you want.
You may also want to check Microsoft's own Detours library, but I'm not sure on whether it supports replacing API calls functionality.
Hope it helps.
I had the same problem when using ODBC with MFC. Everytime there was an error, a message box would pop up showing the error, which was fine if I wanted one.
However, if I didn't, I only needed to surround it with:
TRY
{
// Call error-prone method
}
CATCH ( CException, pEx )
{
// Free resources
}
END_CATCH
The message box comes from the framework not knowing how to handle the exception. Simply catch it and do as you wish with it.

How could I detect when my application is minimized?

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.

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

Notification when Windows Dialog is opened

I want to do some processing when a particular dialog is opened but I am not able to find any way to get notification when that dialog is opened.
Is there any way to get notification in application for opening of a particular windows dialog?
The only available information about the dialog is its title and its unique.
The general solution is to use windows hooks, filter to WH_CBT, filter to WM_CREATE, or something like that, get the window text and see if it is the one of your interest.
One more important point: in hook you should use SetWindowLongPtr() to set window process to your own function, that will actually receive WM_CREATE event. In all calls this function should call the original window procedure.
You can also use a CBT Hook to watch window creation messages. You'll have access to the CREATSTRUCT used to create the actual window, eg, the title and class name. You can prevent the window from being created in your hook, modify the size, etc.
EDIT: sorry didn't notice that you don't have the code yourself but only the title. So I think the other posts solution is what you need
The event handling in win32 applications is done via a so called windows procedure which is a callback function with the following signature:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
This callback gets called by windows every time there is a message for windows which are registered with this callback function. One of the first messages send to a new window is the WM_CREATE message.
If you are creating your windows "by hand" with win32 API, then there should be a static callback function like the one below where you can filter for the WM_CREATE message.
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch( message )
{
case WM_CREATE:
// do what ever you want
return 0;
case default:
return DefWndProc( hwnd, message, wParam, lParam );
}
}
If you use MFC dialogs (CDialog) then you can overwrite the function CDialog::OnInitDialog().
OK, the way to do this is to use SetWindowsHookEx(WH_SYSMSGFILTER,...)
You'll be getting a lot more callbacks than you really need. and global hooks are a real drain on system performance (they can force the system to serialize things that would normally run independently)
be sure to read the Remarks, especially this part:
SetWindowsHookEx can be used to inject a DLL into another process. A 32-bit DLL cannot be injected into a 64-bit process, and a 64-bit DLL cannot be injected into a 32-bit process. If an application requires the use of hooks in other processes, it is required that a 32-bit application call SetWindowsHookEx to inject a 32-bit DLL into 32-bit processes, and a 64-bit application call SetWindowsHookEx to inject a 64-bit DLL into 64-bit processes. The 32-bit and 64-bit DLLs must have different names.
Your hook must live in a dll, and the dll will end up loaded into other process's address space, so you won't it won't have access to your procees's address space, you will have to set up some sort of interprocess communication between your hook and your app.
On the whole I'd say this sounds like a really bad idea.

How to stop application from executing

I am working on a project to prevent applications from being launched from removable devices.
Does anyone out there know how i can do this? Preferrably in C++ on the Windows platform.
My aim is to prevent execution of the exe file even if the user double clicks it or even if he tries to launch it from the command line.
Assuming that you wish to stop ANY process launching from a removable drive, this seems to be an application for a shell hook. I wrote the following code over the last half-hour, and it seems to test out OK. Bear in mind that writing a hook is a non-trivial process, and a global hook requires that a DLL be written. This is the relevant guts of the hook DLL:
BOOL __declspec(dllexport) __stdcall InstallShellHook ()
{
lpfnHookProc = (HOOKPROC) ShellFunc ;
BOOL bRetVal = FALSE;
if (hShellHook == NULL)
{
hShellHook = SetWindowsHookEx (WH_SHELL,
lpfnHookProc,
hInstance,
NULL);
return TRUE;
}
return FALSE;
}
LRESULT CALLBACK ShellFunc(int nCode, WPARAM wParam, LPARAM lParam)
{
HWND hWndNew;
char szBuff [_MAX_PATH];
char szDrive [_MAX_DRIVE];
switch (nCode)
{
case HSHELL_WINDOWCREATED:
hWndNew = (HWND)wParam;
GetWindowModuleFileName (hWndNew, szBuff, _MAX_PATH);
_splitpath (szBuff, szDrive, NULL, NULL, NULL);
if (GetDriveType (szDrive) == DRIVE_REMOVABLE)
{
PostMessage (hWndNew, WM_CLOSE, 0, 0);
}
break;
default:
break;
}
return 0;
}
I have tested this code, installed from a simple dialog testbed, and it allows me to launch any windowed application from my hard drive, but immediately closes any I launch from a USB key.
Note that this solution works for all GUI processes (i.e. non-console), but requires that they respond to WM_CLOSE on a top-level window. A more aggressive general solution would probably require you to resolve the hwnd into a hprocess and call TerminateProcess: the solution I have provided is "kinder" (linked DLLs will get unloaded etc), but less general.
If you want to know the basics of writing a system-wide hook, you can find them on my website here. Note that the above isn't production-quality code, I hacked it into an old ANSI dll I had laying around, hence the lack of support for Unicode, or anything approaching decent debug capability. It shows the basic idea though.
Your network admin can take care of that without you needing to write any code. We implemented exactly that same thing here to prevent the possibility of employees copying customers private information to removable devices and the network admin implemented it himself without us here in the dev dept needing to do anything. I don't know if that would work in your situation but it's worth considering.
You can write snippet that returns from Main method if the current disk type is removable device.
Call GetCurrentDirectory split disk name and use WMI(this can help) or even better GetDriveType(this can help here) method to know is it on removable disk or not
Seems to me you are looking for a generic way to stop any app being launched off the device from an application that is already running.
So essentially three issues:
1. Detecting the new application has started
2. Checking what type of device it is running off
3. Forcing the app to die if you don't want it
Part 1: This is the difficult party I think you need to either poll on a regular basis using EnumProcess which isn't great or just check applications which generate a WM_ACTIVATEAPP
Part 2: ArsenMkrt's Solution seems appropriate for this
Part 3: TerminateProcess should do it for you