SetWindowsHookEx Help on Host Machine - windows

I've written a program which wires up a keyboard hook to listen out for F12 to be pressed, on receipt of F12 being pressed I fire an event to start a separate process in my main program.
This works beautifully on my host computer and and while any other app on the machine has focus, but the keyboard hook stops working when a full screen RDP session is focused or virtual machine running in VMWare is focused.
I use SetWindowsHookEx to set up the keyboard hook as follows:
public static int KeyboardHook;
public void AwaitKeyboard(IntPtr handle)
{
_keyboardHookProcedure = new HookProc(KeyboardHookProc);
KeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, _keyboardHookProcedure, handle, 0);
}
Then inside the KeyboardHookProc method I can add code to do something with the main window
public static int KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode < 0)
{
return CallNextHookEx(KeyboardHook, nCode, wParam, lParam);
}
MainWindow mainWindow = (MainWindow)Application.Current.MainWindow;
if (mainWindow != null)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
if (vkCode == mainWindow.KeyboardShortcutCode) // Keyboard shortcut pressed
{
mainWindow.KeyboardShortcutPressed();
}
}
return CallNextHookEx(KeyboardHook, nCode, wParam, lParam);
}
else
{
return CallNextHookEx(KeyboardHook, nCode, wParam, lParam);
}
}
This all works fine for apps on my host machine. But the moment a VM or full screen RDP window is activated, the KeyboardHookProc method is never invoked.
I've read suggestions that I could clear the hook and re-set it whenever the active window changes in Windows. I have tried that and got that working, but re-setting up the hook didn't fix the problem as KeyboardHookProc is still not invoked when in a VM or RDP.
The moment I return to the host machine and press F12 my keyboard hook springs to life and operates as I need it to.
Does anyone have any suggestions?
Thanks

Most likely a kernel driver or something before you in the hook chain is eating the key. This is probably by design as far as those other products are concerned.
I see the same issue on my machine, VirtualBox is eating my Foobar2000 hotkeys when it has focus.
WH_KEYBOARD_LL is pretty much as low as you can go in usermode. You could try raw input but I doubt that is going to work.

Related

How to detect mouse hovering in a non-client section of a window?

I have a program that paints to the client area about 60hz using Direct3D 9, and the mouse is interfering, so I want to get rid of it only when it moves across the client area.
I thought that calling ShowCursor(false) in WM_MOUSEMOVE and calling ShowCursor(true) when WM_NCMOUSEMOVE is called by the system would work, but it results in a poor behavior.
So I found that TrackMouseEvent() would make the job, but I'm calling it in the following way:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static bool g_fMouseTracking = false;
switch (message)
{
case WM_MOUSEMOVE:
if (!g_fMouseTracking)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.dwFlags = TME_NONCLIENT;
tme.dwHoverTime = HOVER_DEFAULT;
tme.hwndTrack = hWnd;
g_fMouseTracking = TrackMouseEvent(&tme);
}
break;
case WM_NCMOUSEHOVER:
ShowCursor(true);
break;
...
and WM_NCMOUSEHOVER is never called. I don't know why.
Anyway, this is only one piece of code, to do what I want I know I need more code, but if it's not calling WM_NCMOUSEMOVE I can't start doing more advanced mouse hovering tricks.
When you want to track WM_NCMOUSEHOVER you must use TrackMouseEvent in WM_NCMOUSEMOVE.

Detecting BLE device in range on Win32

If a device has an HID over GATT service, Windows will automatically connect to it. So, it clearly is paying attention to when the device is in range.
For a non-HID device, Win32 only connects to the BLE device when I make a request to it, such as setting a characteristic or registering for a notification. How can I detect when the device can be connected to successfully (is in range)? I'm tempted to just run a loop attempting to connect, but surely that cannot be the best solution.
If you must use Win32/WinAPI (as opposed BluetoothLeAdvertisementWatcher, which is a UWP class), you can use methods from bluetoothapis.h.
You basically need to create a message-pumping window, and handle incoming WM_DEVICECHANGE event. Something like this:
INT_PTR BleListener::EventLoopHandler(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 1;
DEBUG_PRINT(TEXT("Message: 0x%04x\n"), message);
switch (message)
{
case WM_DEVICECHANGE:
{
DEV_BROADCAST_HDR* hdr;
DEV_BROADCAST_HANDLE* bhandle;
if (wParam == DBT_CUSTOMEVENT)
{
hdr = (DEV_BROADCAST_HDR*)lParam;
if (hdr->dbch_devicetype == DBT_DEVTYP_HANDLE)
{
bhandle = (DEV_BROADCAST_HANDLE*)lParam;
if (bhandle->dbch_eventguid == GUID_BLUETOOTH_RADIO_IN_RANGE)
{
BTH_DEVICE_INFO* info = (BTH_DEVICE_INFO*)bhandle->dbch_data;
DEBUG_PRINT(TEXT("GUID_BLUETOOTH_RADIO_IN_RANGE. Address = 0x%llx\n"), info->address);
}
}
else if (bhandle->dbch_eventguid == GUID_BLUETOOTH_HCI_EVENT)
{
...
}
};
break;
...
}
}
You might also wanna take a look here and here for some gotchas.

SetWindowsHookEx to block 64-bit WM_HOTKEY from 32-bit

Our application requires running in a "secure kiosk mode" on Windows. We have a variety of ways we block various actions. One thing that we do is listen for the use of hotkeys using SetWindowsHookEx to register a WH_GETMESSAGE hook, then when a WM_HOTKEY message comes through we change it to WM_NULL (see code below). This works great in most cases but we recently uncovered an issue. On a 64-bit machine, if the application listening and responding to the hotkey is a 64-bit application we cannot block it with our 32-bit application.
We're trying to find ways to solve this and the only option I can think of is spawning a background 64-bit process to handle this hook for 64-bit applications. Are there other (more simple) alternatives?
Setting up the hook:
HHOOK getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, GetMessageProc, hInst, 0);
GetMsgProc:
LRESULT CALLBACK GetMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
{
switch (nCode)
{
case HC_ACTION:
{
MSG *msg = (MSG *) lParam;
if (msg->message == WM_HOTKEY)
{
// A hotkey was pressed, changed the message to WM_NULL
msg->message = WM_NULL;
}
break;
}
default:
break;
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}

Why does this window subclassing code crash?

I am trying to subclass the window that currently has focus. I do this by monitoring for HCBT_ACTIVATE events using a CBT hook, and set and unset the WndProc of the focused and previously focused windows.
The problem is that it only works whenever I have a breakpoint set somewhere in the code.
If there is no breakpoint, once my application exits, all the windows that I have subclassed crashes in order, even though I have removed the subclassing and restored the original WndProc.
I have verified that Unsubclass() is called whenever my application shuts down.
// code extracts
HINSTANCE hInst;
HHOOK hHook;
#pragma data_seg(".shared")
HWND hWndSubclass = 0;
FARPROC lpfnOldWndProc = NULL;
#pragma data_seg()
#pragma comment(linker, "/section:.shared,rws")
void Unsubclass()
{
// if the window still exists
if (hWndSubclass != 0 && IsWindow(hWndSubclass))
{
SetWindowLongPtr(hWndSubclass, GWLP_WNDPROC, (LPARAM)lpfnOldWndProc);
hWndSubclass = 0;
}
}
static LRESULT CALLBACK SubClassFunc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_MOVING)
{
// this is just test code so I can see it works (it does)
RECT* r = (RECT*)lParam;
r->right = r->left + 500;
r->bottom = r->top + 500;
return TRUE;
}
else if (message == WM_DESTROY)
{
Unsubclass();
}
return CallWindowProc((WNDPROC)lpfnOldWndProc, hWndSubclass, message, wParam, lParam);
}
void SubclassWindow(HWND hWnd)
{
// remove the subclassing for the old window
Unsubclass();
// subclass the new window
lpfnOldWndProc = (FARPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LPARAM)SubClassFunc);
hWndSubclass = hWnd;
}
static LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_ACTIVATE)
{
SubclassWindow((HWND)wParam);
}
return 0;
}
// ... code that initializes the CBT proc
__declspec(dllexport) BOOL Setup()
{
hHook = SetWindowsHookEx(WH_CBT, CBTProc, hInst, 0);
}
__declspec(dllexport) BOOL Teardown()
{
UnhookWindowsHookEx(hHook);
Unsubclass();
}
BOOL APIENTRY DllMain( HINSTANCE hInstance,
DWORD Reason,
LPVOID Reserved
)
{
switch(Reason)
{
case DLL_PROCESS_ATTACH:
hInst = hInstance;
return TRUE;
case DLL_PROCESS_DETACH:
Unsubclass();
return TRUE;
}
return TRUE;
}
Your problems hinge on several fronts:
UnHookWindowsHook does not unload injected dlls, all it does is remove the hook proc. If the dlls need to be unloaded its up to them to invent some kind of unloading mechanism.
SetWindowLongPtr typically fails when called from a process other than the process that owns the window.
The nett result of this is, its very difficult to safely remove windows hooks. First thing, your OldWindowProc pointer should not be stored in the shared data area. Next, in order to remove the subclass, you need to be able to co-erce the (currently) subclassed process to perform the un-subclassing.
What you could do is, first, register a new unique message id and place it in your shared area using RegisterWindowMessage. WM_REMOVE_HOOK.
UINT idWM_REMOVE_HOOK = RegisterWindowMessage("WM_REMOVE_HOOK");
Now, whenever you need to remove a hook,
SendMessage(hWndSubClass,idWM_REMOVE_HOOK,0,0);
In your subclass proc:
if(uMsg == WM_DESTROY || uMsg == idWM_REMOVE_HOOK)
{
Unsubclass(hwnd);
}
Remove the call to UnSubClass in DLL_PROCESS_DETATCH. Its a dangerous race condition thats going to cause your dll being unloaded in some random process to trash the hook data of a potentially valid hook in another process.
lpfnOldWndProc and hWndSubclass are global pointers. Seems like you've got only one per process. What if a process creates more than one window?
Then you will unsubclass only the last one.
EDIT: Also, why do you tear down in Process DETACH?
You are creating a global system-wide hook in a DLL. You need to store the HHOOK handle and your subclassing information in a block of shared memory so all instances of your DLL in all running processes can have access to them. Your variables are declared global in code, but each individual instance of the DLL will have its own local copy of them, and thus they will not be not initialized in all but 1 of your DLL instances (the one that calls Setup()). They need to be shared globally within the entire system instead.
You also should not be calling TearDown() in DLL_PROCESS_DETACH, either. Every instance of the DLL is going to call TearDown() when their respective processes terminate, but only the single instance that actually called Setup() should be the one to call Teardown().
If the debugger will cause the process to succeed by adding a breakpoint then most likely, this is a timing issue.
What possibly happens is that your main application is closing itself and freeing resources just before the subclassed windows get the messages they need to remove the subclass again. You might want to give them a few processing cycles to handle their own messages between the unhooking and the unsubclassing. (In Delphi you could do this by calling Application.ProcessMessages but in your C++ version? Don't know the answer to that.

Win32 WH_CBT Hook - close window before it is created

I´m a currently running a global hook that watches for a certain window and then closes it with PostMessage(hWnd,WM_CLOSE,0,0);
The DLL containing the hook:
LRESULT CALLBACK MyFunc(int code, WPARAM wParam, LPARAM lParam)
{
switch(code)
{
case HCBT_CREATEWND:
{
HWND hWnd = (HWND)wParam;
//GetWindowText(hWnd, wintext, 80) returns nothing
//if ( strcmp(wintext, ("Kaspersky Internet Security: license notification")) == 0 )
// {
// Beep(70,100);
// PostMessage(hWnd,WM_CLOSE,0,0);
// }
break;
}
case HCBT_ACTIVATE:
{
HWND hWnd = (HWND)wParam;
GetWindowText(hWnd, wintext, 80);
if ( strcmp(wintext, ("Kaspersky Internet Security: license notification")) == 0 )
{
Beep(70,100);
PostMessage(hWnd,WM_CLOSE,0,0);
}
break;
}
}
...
As you can see i´m using GetWindowText(hWnd, wintext, 80) to determine by window title if the currently activated window is the one to be closed. i´m
closing the window when it is being activated and not when it is created. I would like to close the window when it is being created, that is when HCBT_CREATEWND is true.
The thing is that I can´t use GetWindowText(hWnd, wintext, 80) to get the window title and thereby determine if the window should be closed because when HCBT_CREATEWND is called the window hasn't been fully created and has no title, GetWindowText(hWnd, wintext, 80) returns nothing.
To summarize my question: is it possible to get the title of the window or in any other way determine what kind of window it is, when HCBT_CREATEWND is true?
Could you try GetClassName instead of reading the window text?
It's probably more reliable the reading the window text (internationalization). An easy way to discover a window's class name is to use the spy++ utility - a handy tutorial is described here.
The window isn't created yet. Which means you won't be able to call ::GetWindowText(). Instead use the lParam as an LPCBT_CREATEWND. This gives you access to the CREATESTRUCT via a pointer. You can use the lpszName to get access to the window name.
Something like this --
CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
switch(nCode)
{
case HCBT_CREATEWND:
{
LPCBT_CREATEWND lpCreate = (LPCBT_CREATEWND)lParam;
lpCreate->lpcs->lpszName; // this is the name
break;
}
}
}

Resources