I'm trying to create a hook to a keyboard event but the hook is never called on a key stroke. I set the hook with:
HHOOK hookRes = SetWindowsHookEx( WH_KEYBOARD, &KeyStrokeHook, NULL, GetCurrentThreadId() );
And the callback function is:
LRESULT CALLBACK KeyStrokeHook( _In_ int code, _In_ WPARAM wParam, _In_ LPARAM lParam )
{
if( code < 0 )
return CallNextHookEx( NULL, code, wParam, lParam );
if( lParam & 0x80000000 == 0 ) // If key pressed, not released
{
keyStroke = wParam;
SetEvent( keyEvent );
}
return CallNextHookEx( NULL, code, wParam, lParam );
}
hookRes has a valid hook, but the hook function is never called.
Can the hook be triggered if the thread that set the hook is currently blocked on a mutex?
Related
I need to somehow set the cursor to the "Select Precision" pointer (the horizontal and vertical cross-over) for a C++ application.
Does anyone know how this would be integrated using the WinApi protocol?
Somewhere in initialization code:
HCURSOR precision_cursor = LoadCursor( NULL, IDC_CROSS );
And window procedure:
LRESULT CALLBACK YourWindowProc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
{
switch ( msg )
{
case WM_SETCURSOR:
// If you omit test below, you will change cursor also for scrollbars, frames, etc.
if ( LOWORD( lparam ) == HTCLIENT )
{
SetCursor( precision_cursor );
return TRUE;
}
break;
}
// This will also handle cursor for scrollbars and frames.
return DefWindowProc( hwnd, msg, wparam, lparam );
}
I created a DLL to hook some events using a CBT hook. It seems to work only for the windows created by the process launching the hook...
My system is Windows 7 x64, but the behaviour is the same also on the x32.
This is the code (sorry but I'm no C++ expert):
#include "windows.h"
extern "C"
{
static LRESULT CALLBACK CbtProcCb(int nCode, WPARAM wParam, LPARAM lParam);
HINSTANCE g_hDll = NULL;
HWND g_hNotifyWin = NULL;
DWORD g_uNotifyMsg = NULL;
HHOOK g_hHook = NULL;
__declspec(dllexport) HHOOK SetCbtHook(HWND hWnd, LPCWSTR lStrMsg, DWORD threadId)
{
g_hNotifyWin = hWnd;
g_uNotifyMsg = RegisterWindowMessage(lStrMsg);
g_hHook = SetWindowsHookEx(WH_CBT, (HOOKPROC)CbtProcCb, g_hDll, threadId);
return g_hHook;
}
__declspec(dllexport) int UnsetCbtHook()
{
if ( !g_hHook )
return 0;
return UnhookWindowsHookEx(g_hHook);
}
}
static LRESULT CALLBACK CbtProcCb(int nCode, WPARAM wParam, LPARAM lParam)
{
SendNotifyMessage(g_hNotifyWin, g_uNotifyMsg, nCode, wParam); // Send nCode to check the received event
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if ( fdwReason == DLL_PROCESS_ATTACH )
g_hDll = hinstDLL;
return true;
}
Any hints?
When Windows installs globals hook, the DLL implementing the hook function is often loaded in other processes. In those processes, the g_hNotifyWin and g_uNotifyMsg global variables are NULL. That global variables are only not NULL in the context of the process in which the SetCbtHook call took place.
You must have a way to retrieve the correct value for g_hNotifyWin and 'g_uNotifyMsg', in an arbitrary process.
Add:
const char * g_pszClassName = "MyClassName";
const char * g_pszRegisteredMsg = "MyMessage";
to your DLL, and replace "MyClassName" by the class name of the g_hNotifyWin window. See the RegisterClass call in your EXE. Update also "MyMessage".
Then, use the following CbtProcCb function:
static LRESULT CALLBACK CbtProcCb(int nCode, WPARAM wParam, LPARAM lParam)
{
if ( nCode >= 0 ) {
if ( g_hNotifyWin == NULL ) g_hNotifyWin = FindWindow( g_pszClassName, NULL );
if ( g_uNotifyMsg == 0) g_uNotifyMsg = RegisterWindowMessage(g_pszRegisteredMsg);
if ( g_hNotifyWin && g_uNotifyMsg )
SendNotifyMessage(g_hNotifyWin, g_uNotifyMsg, nCode, wParam); // Send nCode to check the received event
}
return CallNextHookEx(NULL, nCode, wParam, lParam); // first arg useless see MSDN
}
EDIT:
As you noted in comment, same problem for g_uNotifyMsg See updated function. You could set up those variables in DllMain, indeed.
The first argument to CallNextHookEx may be NULL.
I guess your ThreadId is not zero, so hook is attached only to the calling process / thread respectively. Read documentation:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
As the snippet below runs , each time a key is tapped,the function LowLevelKeyboardProc is called. But the problem is it is called both at the time of pressing a key and at the time of releasing a key.It means , per one tap the function is called two times.But I want the function be called only one when the key is pressed and not when the key is released.
Even if I can filter the pressing and releasing of keys inside the function LowLevelKeyboardProc,it will be fine. Is there any way I can do this.
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
// call the function only if the key is pressed,else ( i.e key released) do nothing
}
BOOL WINAPI installHook(HINSTANCE hinstDLL, DWORD fwdReason, LPVOID lpvReserved){
handleKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hinstDLL, 0);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fwdReason, LPVOID lpvReserved) { // ENTRY POINT
if(hookThreadHandle==NULL) {
LPTHREAD_START_ROUTINE lpStartAddress = &installHook;
hookThreadHandle = CreateThread(NULL, 0, lpStartAddress, NULL, 0, &hookThreadId);
}
return TRUE;
}
You cannot change the way LowLevelKeyboardProc is called, but inside the function you can know the reason of the call:
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if ( nCode < 0 )
{
return CallNextHookEx(handleKeyboardHook, nCode, wParam, lParam);
}
if ( wParam == WM_KEYDOWN ) // possibly you want also WM_SYSKEYDOWN
{
// do what you need
}
}
I have created a hook for mouse. I wanted to get mouse click coordinates, but the GET_X_LPARAM() gives me negative value (and always the same when clicking on different places). My problem becomes solved with GetCursorPos(), but I wonder why it is not working with GET_X_LPARAM/GET_Y_LPARAM. Here's the code:
LRESULT CALLBACK Recorder::mouseHook( int code, WPARAM wParam, LPARAM lParam ) {
if( code < 0 )
return CallNextHookEx( m_mouseHook, code, wParam, lParam );
switch( wParam ) {
case WM_LBUTTONDOWN:{
int _hereIsANegativeNumber = GET_X_LPARAM( lParam );
break;}
}
return CallNextHookEx( 0, code, wParam, lParam );
}
This is how I set the hook:
m_mouseHook = SetWindowsHookEx( WH_MOUSE_LL, &mouseHook, GetModuleHandle( NULL ), 0 );
In a WH_MOUSE_LL hook, lParam is not the mouse coordinates - instead it is a pointer to a MSLLHOOKSTRUCT.
So, to get coordinates:
POINT pt = reinterpret_cast<MSLLHOOKSTRUCT*>(lParam)->pt;
See LowLevelMouseProc for more details.
Because for the WH_MOUSE_LL in the LowLevelMouseProc procedure what you get as the LPARAM variable is a pointer to a MSLLHOOKSTRUCT structure and use the pt member of it for getting the mouse coordinates
This might be a dumb question, but can you register multiple WndProc functions in Win32? e.g. a framework catches some messages and my app is interested in other ones - how do I catch them without modifying the framework code?
If I understand your intention correctly, you can do that by setting a hook. Assuming you know the thread whose message loop you'd like to hook, you can do something along these lines (unchecked):
SetWindowsHookEx(WH_CALLWNDPROC, yourHOOKPROC, NULL, theThreadId);
You can chain multiple message handling functions by using the function CallWindowProc instead of DefWindowProc.
Here is an example:
pfOriginalProc = SetWindowLong( hwnd, GWL_WNDPROC, (long) wndproc1 ); // First WNDPROC
pfOriginalProc2 = SetWindowLong( hwnd, GWL_WNDPROC, (long) wndproc2); // Second WNDPROC, WILL EXECUTE FIRST!!
LRESULT wndproc1( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch ( uMsg )
{
...
default:
return CallWindowProc( pfOriginalProc, hwnd, uMsg, wParam, lParam );
}
}
LRESULT wndproc2( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch ( uMsg )
{
...
default:
return CallWindowProc( pfOriginalProc2, hwnd, uMsg, wParam, lParam );
}
}