Good afternoon. I'm writing a global mouse hook. Everything seems to work just fine except that the hook is called only for the first mouse event.
Some code:
// Dll defined function
extern "C" Q_DECL_EXPORT LRESULT MouseProc(int code, WPARAM wParam, LPARAM lParam)
{
qDebug() << "MouseProc";
return TRUE;
}
// Application code
...
hLib = LoadLibrary(TEXT("ServerHook.dll"));
HOOKPROC hookAddr = (HOOKPROC)GetProcAddress(hLib, "MouseProc");
if (!hookAddr) {
qDebug() << "Invalid hook proc " << GetLastError();
}
if ((WinInputHook::hookHandle = SetWindowsHookEx(
WH_MOUSE, hookAddr, hLib, 0))
== NULL) {
qDebug() << "Invalid hook handle " << GetLastError();
}
...
The hooking you'r installing (WH_KEYBOARD) "installs a hook procedure that monitors keystroke messages" and not the mouse
Related
I have 2 C++ applications, mouseEventCapture and mouseEventTrigger. The job of mouseEventTrigger is to trigger an mouse event and the job of mouseEventCapture is to capture all the mouse activities.
My mouseEventCapture is capturing the mouse events triggered by mouseEventTrigger.
Now the next step in my mouseEventCapture is to capture the pid of the process which is triggering the mouse event(ie I need to capture the PID of mouseEventTrigger in my mouseEventCapture application).
I'm unable to figure out how this can be done in C++. Can anyone please help me out with this?
mouseEventTrigger.cpp
#include <Windows.h>
int main()
{
int x = 3; int y = 4;
SetCursorPos(x, y); //set cursor position
mouse_event(MOUSEEVENTF_MOVE, x, y, 0, 0);
return 0;
}
mouseEventCapture.cpp
#include <iostream>
#include <Windows.h>
HINSTANCE hInst = NULL;
DWORD dwThreadId = 0;
HWND hwnd = NULL;
LRESULT CALLBACK MouseHook(int nCode, WPARAM wParam, LPARAM lParam)
{
switch (wParam)
{
case WM_MOUSEMOVE:
case WM_SETCURSOR:
std::cout << "Mouse moved !!" << " " << point.x << " " << point.y << std::endl ;
break;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
std::cout << "Mouse left button clicked !!" << std::endl;
break;
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
std::cout << "Mouse right button clicked !!" << std::endl;
break;
default:
break;
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int main()
{
std::cout << "Tracking mouse move!\n";
HHOOK mouse = SetWindowsHookEx(WH_MOUSE_LL, &MouseHook, hInst, dwThreadId);
MSG message;
while (GetMessage(&message, hwnd, NULL, NULL) > 0)
{
TranslateMessage(&message);
DispatchMessage(&message);
}
UnhookWindowsHookEx(mouse);
return 0;
}
initially i was able to print something when i pressed only right mouse button using
if (wParam == WM_RBUTTONDOWN)but now , i want the same effect, i want to print something when right mouse button + Ctrl key is pressed. how can i acheive that ?
i have tried this
LRESULT CALLBACK MainWindow::mouseProc(int Code, WPARAM wParam, LPARAM lParam)
{
auto& ms = *(const MSLLHOOKSTRUCT*)lParam;
MSLLHOOKSTRUCT* pMouseStruct = (MSLLHOOKSTRUCT*)lParam;
if (pMouseStruct != nullptr)
{
if (wParam == WM_RBUTTONDOWN & MK_CONTROL) // Here, i added MK_CONTROL but it doesn't work
{
qDebug() << "Print something when Right mouse button and Ctrl button is pressed togather";
}
}
return CallNextHookEx(NULL, Code, wParam, lParam);
}
UPDATE
when i want to try the case where only Ctrl is pressed and it should print something, it still doesn't work
LRESULT CALLBACK MainWindow::mouseProc(int Code, WPARAM wParam, LPARAM lParam)
{
auto& ms = *(const MSLLHOOKSTRUCT*)lParam;
MSLLHOOKSTRUCT* pMouseStruct = (MSLLHOOKSTRUCT*)lParam;
if (pMouseStruct != nullptr)
{
if (wParam == MK_CONTROL) // Here, i added only MK_CONTROL but it doesn't work
{
qDebug() << "Print something when Ctrl button is pressed ";
}
}
return CallNextHookEx(NULL, Code, wParam, lParam);
}
what am i missing here ?
First of all, if you want to capture the right button + ctrl, you can check the state of the Ctrl key (whether it is pressed) when WM_RBUTTONDOWN is detected.
LRESULT CALLBACK mouseProc(int Code, WPARAM wParam, LPARAM lParam)
{
auto& ms = *(const MSLLHOOKSTRUCT*)lParam;
MSLLHOOKSTRUCT* pMouseStruct = (MSLLHOOKSTRUCT*)lParam;
if (pMouseStruct != nullptr)
{
if (wParam == WM_RBUTTONDOWN && (GetAsyncKeyState(VK_LCONTROL)&0x8000)) //Left CONTROL key as example
{
std::cout << "ctrl + rbutton";
}
}
return CallNextHookEx(NULL, Code, wParam, lParam);
}
If you want to use a keyboard hook to hook only "Ctrl":
LRESULT CALLBACK keyboardProc(int Code, WPARAM wParam, LPARAM lParam)
{
KBDLLHOOKSTRUCT* pKeyboardStruct = (KBDLLHOOKSTRUCT*)lParam;
if (pKeyboardStruct != nullptr)
{
if (pKeyboardStruct->vkCode == VK_LCONTROL)
{
if(wParam == WM_KEYDOWN)
std::cout << " -ctrl- ";
}
}
return CallNextHookEx(NULL, Code, wParam, lParam);
}
void main(void)
{
HHOOK hmouse = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, hInstance, 0);
HHOOK hkeyboard = SetWindowsHookEx(WH_KEYBOARD_LL, keyboardProc, hInstance, 0);
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hmouse);
UnhookWindowsHookEx(hkeyboard);
return;
};
I need to find HWND for the context menu. I create a context menu as in this tutorial but without submenus.
I can use FindWindow function this way:
HWND hWndMenu = FindWindow(TEXT("#32768"), NULL);
I can also use the WH_CBT hook. Here is the hook procedure:
LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)
{
if (code == HCBT_CREATEWND)
{
HWND hwnd = (HWND)wParam;
WCHAR name[1024] = { 0 };
GetClassName(hwnd, name, sizeof(name));
if (wcscmp(name, L"#32768"))
{
HWND hwndMenu = FindWindow(TEXT("#32768"), NULL);
std::cout << "HCBT_CREATEWND hwnd: " << hwnd << std::endl;
std::cout << "FindWindow hwnd: " << hwndMenu << std::endl;
}
}
return code < 0 ? CallNextHookEx(myHook, code, wParam, lParam) : 0;
}
When I open context menu I get two different hwnd's. I don't understand why. Could you explain it ?
At the time the WH_CBT hook is called, the menu window is still in progress of being created but is not yet available to FindWindow(). So, you end up finding another unrelated menu window that exists elsewhere. That is why you are seeing different HWNDs.
I took this example code from here that hooks a function to intercept keyboard events, and it works:
#include <Windows.h>
// variable to store the HANDLE to the hook. Don't declare it anywhere else then globally
// or you will get problems since every function uses this variable.
HHOOK _hook;
// This struct contains the data received by the hook callback. As you see in the callback function
// it contains the thing you will need: vkCode = virtual key code.
KBDLLHOOKSTRUCT kbdStruct;
// This is the callback function. Consider it the event that is raised when, in this case,
// a key is pressed.
LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0)
{
// the action is valid: HC_ACTION.
if (wParam == WM_KEYDOWN)
{
// lParam is the pointer to the struct containing the data needed, so cast and assign it to kdbStruct.
kbdStruct = *((KBDLLHOOKSTRUCT*)lParam);
// a key (non-system) is pressed.
if (kbdStruct.vkCode == VK_F1)
{
// F1 is pressed!
MessageBox(NULL, "F1 is pressed!", "key pressed", MB_ICONINFORMATION);
}
}
}
// call the next hook in the hook chain. This is nessecary or your hook chain will break and the hook stops
return CallNextHookEx(_hook, nCode, wParam, lParam);
}
void SetHook()
{
// Set the hook and set it to use the callback function above
// WH_KEYBOARD_LL means it will set a low level keyboard hook. More information about it at MSDN.
// The last 2 parameters are NULL, 0 because the callback function is in the same thread and window as the
// function that sets and releases the hook. If you create a hack you will not need the callback function
// in another place then your own code file anyway. Read more about it at MSDN.
if (!(_hook = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, NULL, 0)))
{
MessageBox(NULL, "Failed to install hook!", "Error", MB_ICONERROR);
}
}
void ReleaseHook()
{
UnhookWindowsHookEx(_hook);
}
void main()
{
// Set the hook
SetHook();
// Don't mind this, it is a meaningless loop to keep a console application running.
// I used this to test the keyboard hook functionality. If you want to test it, keep it in ;)
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
}
}
I am trying to make the similar code works for WH_GETMESSAGE to intercept WH_CREATE and WH_DESTROY messages, but it didn't work:
#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <psapi.h>
#include <iostream>
HHOOK _hook;
LRESULT CALLBACK GetMsgProc(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
std::cout << "Enter hook\n";
if (nCode >= 0)
{
// the action is valid: HC_ACTION.
std::cout << "HC_ACtION\n";
if (wParam != PM_REMOVE) return NULL;
MSG m = *((MSG*)lParam);
std::cout << "Message received\n";
TCHAR Buffer[MAX_PATH];
if (GetModuleFileNameEx(m.hwnd, 0, Buffer, MAX_PATH))
{
// At this point, buffer contains the full path to the executable
MessageBox(NULL, Buffer, L"key pressed", MB_ICONINFORMATION);
}
else
{
// You better call GetLastError() here
}
//CloseHandle(Hand);
}
// call the next hook in the hook chain. This is nessecary or your hook chain will break and the hook stops
return CallNextHookEx(_hook, nCode, wParam, lParam);
}
void SetHook()
{
if (!(_hook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, NULL, 0)))
{
MessageBox(NULL, L"Failed to install hook!", L"Error", MB_ICONERROR);
}
}
void ReleaseHook()
{
UnhookWindowsHookEx(_hook);
}
void main()
{
// Set the hook
SetHook();
// Don't mind this, it is a meaningless loop to keep a console application running.
// I used this to test the keyboard hook functionality. If you want to test it, keep it in ;)
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
}
}
MSDN specifies to use the function GetMsgProc with a predefined signature, but I don't see it does anything.
This is the first time calling Sleep_Detection() which is a function that includes RegisterClass():
//some codes here...
Execute_Command(0);
Sleep_Detection(); **//First time calling, no problem**
This is the second time calling Sleep_Detection() but it's now calling from inside of the SleepDetectionProc() callback function, the error occurred here.
I used GetLastError() and here I got an error code of 1410 which means "ERROR_CLASS_ALREADY_EXISTS".
LRESULT _stdcall SleepDetectionProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_POWERBROADCAST)
{
if (wParam == PBT_APMRESUMESUSPEND)
{
cout << "System restored" << endl;
Execute_Command(0);
Sleep_Detection(); **//Second time calling, error code 1410**
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
This is the Sleep_Detection() function:
void Sleep_Detection(void)
{
WNDCLASS WindowClass = { 0 };
WindowClass.lpfnWndProc = SleepDetectionProc;
WindowClass.lpszClassName = (L"Sleep detection");
if (!GetClassInfo(WindowClass.hInstance, WindowClass.lpszClassName, &WindowClass))
{
if (!RegisterClass(&WindowClass))
{
cout << "Cannot register class (Error Code: " << GetLastError() << ")" << endl;
exit(EXIT_FAILURE);
}
else
cout << "registered" << endl;
}
else
cout << "Class already exists" << endl;
HWND WinHandle = NULL;
if (!FindWindow(WindowClass.lpszClassName, ConsoleTitle))
{
if ((WinHandle = CreateWindow(L"Sleep detection", L"", 0, 0, 0, 0, 0, NULL, NULL, NULL, 0)) == NULL)
{
cout << "Cannot create window (Error Code: " << GetLastError() << ")" << endl;
exit(EXIT_FAILURE);
}
else
cout << "window created" << endl;
}
else
cout << "Window already exists" << endl;
int upRes;
MSG Message;
while (upRes = GetMessage(&Message, WinHandle, 0, 0))
{
if (upRes == -1)
{
cout << "An error occurred when getting window messages (Error Code: " << GetLastError() << endl;
exit(EXIT_FAILURE);
}
else
{
cout << "Got Message!" << endl;
TranslateMessage(&Message);
DispatchMessage(&Message);
}
}
}
So I basically called Sleep_Detection() twice and it also called the RegisterClass() function inside. I guess the error could be related to overwritten the RegisterClass()?
WNDCLASS WindowClass = { 0 };
WindowClass.lpfnWndProc = SleepDetectionProc;
WindowClass.lpszClassName = (L"Sleep detection");
WindowClass.hInstance is zero, which will cause GetClassInfo() to fail even if the window class already exists, because the value of NULL for the parameter hInstance is reserved for classes defined by the system, which is stated at the MSDN page:
hInstance
A handle to the instance of the application that created the class. To
retrieve information about classes defined by the system (such as
buttons or list boxes), set this parameter to NULL.
So RegisterClass will always be attempted, which of course fails on the 2nd try.
To correct the error, initialize WindowClass.hInstance like this:
WindowClass.hInstance = GetModuleHandle(NULL); // get hInstance of current process
If the code is called from a DLL, replace GetModuleHandle(NULL) with the handle of that DLL. By the way, HMODULE is interchangeable with HINSTANCE, that is the base address of the module.