Need help with Windows Journal Record Hook - c

I want to build a software test automation software and I'm playing around with Windows Hooks for that.
So I built the following C code. Can anyone tell me how to correct it ?
#include "windows.h"
// the call back function
LRESULT CALLBACK JournalRecordProc(int code, WPARAM wParam, LPARAM lParam)
{
HHOOK hhk = 0;
if (code > 0)
{
// save Data in File
}
if (code < 0)
{
// work done: now pass on to the next one that does hooking
CallNextHookEx(hhk, code, wParam, lParam);
}
/*
if (code == )
{
// ESC button pressed -> finished recording
UnhookWindowsHookEx(hhk);
}
*/
}
int main()
{
int iRet = 0;
HHOOK hHook = 0;
HINSTANCE hMod = 0;
HOOKPROC (*hHookProc)(int, WPARAM, LPARAM);
hHookProc = &JournalRecordProc;
// type of hook, callback function handle, hinstance [dll ?], 0 for systemwide
hHook = SetWindowsHookEx(WH_JOURNALRECORD, hHookProc, hMod, 0);
return iRet;
}
When I compile this I get the compiler errors:
error C2440: '=': 'LRESULT (__stdcall
*)(int,WPARAM,LPARAM)' kann nicht in 'HOOKPROC (__cdecl
*)(int,WPARAM,LPARAM)' konvertiert werden (could not be converted)
error C2440: 'Funktion': 'HOOKPROC (__cdecl *)(int,WPARAM,LPARAM)' kann nicht in 'HOOKPROC' konvertiert werden (could not be converted)
warning C4024: 'SetWindowsHookExA': Unterschiedliche Typen für formalen und übergebenen Parameter 2

There's no need to declare a separate hHookProc variable - just pass your procedure to SetWindowsHookEx directly:
hHook = SetWindowsHookEx(WH_JOURNALRECORD, JournalRecordProc, hMod, 0);
You're also going to need a valid module handle:
HINSTANCE hMod = GetModuleHandle(NULL);
Having made those edits, and made your JournalRecordProc return a value, it all now compiles and works for me (in that SetWindowsHookEx succeeds, anyway).

Related

Why does CreateWindow in 64-bit Visual Studio C destroy itself on creation?

I have some example code that simply puts a window on the screen in Windows 10. The program runs fine under 32 bit: the window call back procedure gets sent messages in the creation of the window.
Under 32-bit, the first three messages are:
WM_GETMINMAXINFO
WM_NCCREATE
WM_NCCALCSIZE
and it proceeds from there until the window is built.
However, under 64-bit, this does not happen; instead, these are the messages sent:
WM_GETMINMAXINFO
WM_NCCREATE
WM_NCDESTROY
As you can see, right after the window is created, the OS sends a message to destroy it!
Here's the actual code:
/*****************************************************************************/
/* This sample demonstrates how to continuously acquire pictures */
#include <windows.h>
#include <stdio.h>
#define _NIWIN
#define PB_QUIT 101 /* id for quit application push button */
// Window proc
LRESULT CALLBACK ImaqSmplProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam);
// windows GUI globals
static HINSTANCE hInst;
static HWND ImaqSmplHwnd;
static HWND HStop, HGrab, HQuit, HIntfName, HFrameRate;
static long CanvasWidth = 512; // width of the display area
static long CanvasHeight = 384; // height of the display area
static long CanvasTop = 10; // top of the display area
static long CanvasLeft = 10; // left of the display area
static long AcqWinWidth;
static long AcqWinHeight;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
CHAR ImaqSmplClassName[] = "Imaq Sample";
WNDCLASS ImaqSmplClass;
MSG msg;
// register the main window
hInst = hInstance;
if (!hPrevInstance)
{
ImaqSmplClass.style = CS_HREDRAW | CS_VREDRAW;
ImaqSmplClass.lpfnWndProc = (WNDPROC) ImaqSmplProc;
ImaqSmplClass.cbClsExtra = 0;
ImaqSmplClass.cbWndExtra = 0;
ImaqSmplClass.hInstance = hInstance;
ImaqSmplClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
ImaqSmplClass.hCursor = LoadCursor (NULL, IDC_ARROW);
ImaqSmplClass.hbrBackground = GetStockObject(LTGRAY_BRUSH);
ImaqSmplClass.lpszMenuName = 0;
ImaqSmplClass.lpszClassName = ImaqSmplClassName;
if (!RegisterClass (&ImaqSmplClass))
return (0);
}
// creates the main window
ImaqSmplHwnd = CreateWindow(ImaqSmplClassName, "LLGrab", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 680, 440, NULL, NULL, hInstance, NULL);
// creates the quit application button
if (!(HQuit = CreateWindow("Button","Quit",BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE,
550,152,80,40,ImaqSmplHwnd,(HMENU)PB_QUIT,hInstance,NULL)))
return(FALSE);
// Display the main window
ShowWindow(ImaqSmplHwnd, SW_SHOW);
UpdateWindow(ImaqSmplHwnd);
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return (int)(msg.wParam);
}
// Message proc
LRESULT CALLBACK ImaqSmplProc(HWND hWnd, UINT iMessage, UINT wParam, LONG lParam)
{
WORD wmId;
LRESULT theResult;
switch (iMessage)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
switch (wmId)
{
case PB_QUIT:
PostQuitMessage(0);
break;
}
break;
case WM_NCDESTROY:
break;
case WM_DESTROY:
PostQuitMessage(0);
default:
theResult = DefWindowProc(hWnd, iMessage, wParam, lParam);
return theResult;
break;
}
return 0;
}
Your ImaqSmplProc() window procedure is declared incorrectly, causing you to pass bad data to DefWindowProc().
For WM_NCCREATE, the lParam holds a pointer, which you are truncating under 64bit to a 32bit value, so DefWindowProc() fails to process WM_NCCREATE correctly, which then causes CreateWindow() to destroy the window. If you debug the code, you will likely see DefWindowProc() returning FALSE when processing WM_NCCREATE with a bad lParam value.
If an application processes this message, it should return TRUE to continue creation of the window. If the application returns FALSE, the CreateWindow or CreateWindowEx function will return a NULL handle.
To fix this, the wParam and lParam parameters MUST be declared as WPARAM and LPARAM, respectively:
LRESULT CALLBACK ImaqSmplProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
This matches the actual signature of WNDPROC:
LRESULT CALLBACK WindowProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
WPARAM and LPARAM are declared as UINT_PTR and LONG_PTR, respectively. Which means they are pointer-sized integers, and so have different sizes under 32bit and 64bit. Whereas UINT and LONG have the same size on both 32bit and 64bit. See Windows Data Types. Your original code is not accounting for this difference.
You used a type-cast to silence the compiler from alerting you to your incorrect declaration. You need to get rid of the type-cast when assigning ImaqSmplProc to ImaqSmplClass.lpfnWndProc:
ImaqSmplClass.lpfnWndProc = ImaqSmplProc;
Any time you find yourself using a type-cast, question yourself as to why, you may be doing something wrong. Don't use a type-cast unless you absolutely need it. Don't use a type-cast just to keep the compiler silent, it complains about questionable/erroneous things for a reason.
The problem is in the types you have specified for the wParam and lParam arguments to your ImaqSmplProc function. These should be of types WPARAM and LPARAM, respectively.
Why? These are defined as UINT_PTR and LONG_PTR types - which are 64-bit integers on x64 builds; thus, your specified UINT and LONG types are the wrong sizes, so you have undefined behaviour (at best).
Change the definition/declaration to:
LRESULT CALLBACK ImaqSmplProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

Use WH_MOUSE globally without DLL

I have a code to display a part of screen when mouse moves. But the WH_MOUSE doesn't work. I need to change GetModuleHandle(0), 0 to hInst, GetCurrentThreadId().
But then the application will work only when the mouse is over the application itself.
I want it global and I tried WH_MOUSE_LL, it is slower then WH_MOUSE.
Is that possible to use WH_MOUSE globally without DLL?
void SetHook()
{
gMouseHook = SetWindowsHookEx(WH_MOUSE, MouseProc, GetModuleHandle(0), 0);
}
//================================================================================
// Mouse Hook
static LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0) {
return CallNextHookEx(gMouseHook, nCode, wParam, lParam);
}
if (wParam == WM_MOUSEMOVE) {
MOUSEHOOKSTRUCT *mouseInfo = (MOUSEHOOKSTRUCT*)lParam;
int x = mouseInfo->pt.x;
int y = mouseInfo->pt.y;
PrintScreen(x, y);
}
return CallNextHookEx(gMouseHook, nCode, wParam, lParam);
}
Is that possible to use WH_MOUSE globally without DLL?
No, the hook procedure needs to be in a DLL so that it can be injected into other processes.
I tried WH_MOUSE_LL, it is slower then WH_MOUSE.
That probably means your hook procedure is slow.

GetProcAddress returns NULL

I have to use a simple function from a DLL; I am able to load the library but GetProcAddress returns NULL. I think I understood name mangling but maybe I'm doing something wrong. Thanks (Code follows, asap I'll add other information required):
mydll.h
#ifdef MYDLL_EXPORTS
#define MYDLL_API extern "C" __declspec(dllexport)
#else
#define MYDLL_API extern "C" __declspec(dllimport)
#endif
MYDLL_API void testFunction(void);
MYDLL_API LRESULT CALLBACK mouseProc(int nCode, WPARAM wParam, LPARAM lParam);
mydll.cpp
#include "stdafx.h"
#include "mydll.h"
// This is an example of an exported function.
MYDLL_API void testFunction(void)
{
MessageBox(NULL, (LPCWSTR)L"Test", (LPCWSTR)L"Test", MB_OK);
}
MYDLL_API LRESULT CALLBACK mouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
// processes the message
if(nCode >= 0)
{
if(wParam != NULL && wParam == MK_RBUTTON)
{
MessageBox(NULL, (LPCWSTR)L"Captured mouse right button", (LPCWSTR)L"Test", MB_OK);
}
}
// calls next hook in chain
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
code from main.cpp
...
case WM_CREATE:
{
// creates state for window
stateClassPointer = new stateClass();
// saves states pointer in a space reserved for user data
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) stateClassPointer);
// now it will load DLL and set up hook procedure for mouse events
// declares local variables
HOOKPROC hkprcMouseProc;
HINSTANCE hinstDLL;
HHOOK hhookMouseProc;
//FARPROC WINAPI test;
// loads DLL
if((hinstDLL = LoadLibrary(TEXT("C:\\Users\\Francesco\\Dropbox\\poli\\bi\\not\\pds\\sp\\wk5\\lsp5\\Debug\\mydll.dll"))) == NULL)
{
MessageBox(hWnd, (LPCWSTR)L"Error loading DLL", (LPCWSTR)L"Error", MB_OK | MB_ICONERROR);
break;
}
// saves DLL handle in the state class
stateClassPointer->setHInstance(hinstDLL);
// sets up hook procedure for mouse events
if((hkprcMouseProc = (HOOKPROC)GetProcAddress(hinstDLL, "mouseProc")) == NULL)
{
MessageBox(hWnd, (LPCWSTR)L"Error setting windows hook: GetProcAddress", (LPCWSTR)L"Error", MB_OK | MB_ICONERROR);
break;
}
if((hhookMouseProc = SetWindowsHookEx(WH_MOUSE, hkprcMouseProc, hinstDLL, 0)) == NULL)
{
MessageBox(hWnd, (LPCWSTR)L"Error setting windows hook: SetWindowsHookEx", (LPCWSTR)L"Error", MB_OK | MB_ICONERROR);
break;
}
// saves hook handle in the state class
stateClassPointer->setHHook(hhookMouseProc);
/*test = GetProcAddress(hinstDLL, "testFunction");
test();*/
}
break;
...
Yes, the MessageBox() call succeeded without errors. Move the GetLastError() call before it.
The error is otherwise predictable, it couldn't find "mouseProc". The name will be mangled in the DLL, most probably "_mouseProc#12". Use dumpbin.exe /exports on your DLL to be sure.
Fwiw: you can make this code less painful by not dynamically loading the DLL but just linking its import library. The fact that the DLL will be injected into other processes doesn't also mean you have to inject it in yours. All you need is the module handle so you can call SetWindowsHookEx(). Get that from the DllMain() entry point or by using GetModuleHandle().

WH_GETMESSAGE global hook not working

I am trying to set a global GetMessage hook on all threads. This is my DLL:
#include <windows.h>
__declspec(dllexport) LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
MessageBeep(0);
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
As you can see, it's not much. I just want it to call MessageBeep whenever it's called.
#include <windows.h>
typedef LRESULT (CALLBACK *LPGetMsgProc)(int nCode, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nCmdShow)
{
if(!(HMODULE hDll = LoadLibrary("library.dll")))
return 1;
if(!(LPGetMsgProc pfnProc = (LPGetMsgProc)GetProcAddress(hDll, "GetMsgProc#12")))
return 2;
HHOOK hMsgHook = SetWindowsHookEx(WH_GETMESSAGE, pfnProc, hInstance, 0);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0) {}
UnhookWindowsHookEx(hMsgHook);
return 0;
}
My WinMain loads the library, gets the procedure and sets the hook. However, MessageBeep is never being called. Is there something I'm doing wrong here?
Also, one other thing has been bothering me. In this call:
if(!(LPGetMsgProc pfnProc = (LPGetMsgProc)GetProcAddress(hDll, "GetMsgProc#12")))
I was forced to use "GetMsgProc#12" because I couldn't get it right any other way. Can somebody please tell me how I'm supposed to use a .def file or something else so I can just have it as "GetMsgProc"? Though MSDN stated that since I have __declspec(dllexport) in my declaration I wouldn't need it...
My IDE is Code::Blocks with MinGW. Thanks in advance.
The third parameter...
HHOOK hMsgHook = SetWindowsHookEx(WH_GETMESSAGE, pfnProc, hInstance, 0);
...is the handle passed into your WinMain function. But it needs to refer to the DLL where the callback function resides - in your case, that'd be hDLL.

How can I access a variable in a calling application from a dll?

I'm trying a little concept test to change one of the features of the logitech MS3200 keyboard (the zoom feature). I've got the keys that are sent from the zoom control. So, I have a main app, and a dll that contains a hook procedure.
Here's the main app:
#include <stdio.h>
#include <windows.h>
HANDLE hHook;
int main()
{
HINSTANCE hMod = GetModuleHandle(NULL);
hHook = SetWindowsHookEx(WH_KEYBOARD, HookProc,0,0);
if(hHook == NULL)
printf("Unable to set hook! Error: %d", GetLastError());
else
printf("Hook set successfully!");
while(TRUE)
{
Sleep(1000);
}
return 0;
}
And here is the hook procedure dll:
#include <windows.h>
int __declspec (dllexport) HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode < 0)
{
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
if(wParam == VK_ADD || wParam == VK_SUBTRACT)
{
short status = GetKeyState(VK_CONTROL);
if(status == 1)
{
if(wParam == VK_ADD)
wParam = VK_UP;
else
wParam = VK_DOWN;
}
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
int WINAPI dllmain(HINSTANCE hMod, DWORD data, LPVOID lpVOid)
{
return 0;
}
I need to be able to access what's returned by SetWindowsHookEx (hHook) from the dll, in order to call CallNextHookEx().
It's probably possible, but it's not worth your time to investigate.
Instead, move the hook setting code to the DLL.
Oh, and I think you need to pass the DLL module handle to the hook setting function, not a NULL
One possible way to handle this would be to have another exported function in your DLL to pass the hHook to, and save that in a variable local within the DLL for use in the HookProc.
HANDLE dllHook;
void __declspec (dllexport) HookHandle(HANDLE hHook)
{
dllHook = hHook;
}
int __declspec (dllexport) HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode < 0 && dllHook!= NULL)
{
return CallNextHookEx(dllHook, nCode, wParam, lParam);
}
//....
}
int WINAPI dllmain(HINSTANCE hMod, DWORD data, LPVOID lpVOid)
{
dllHook = NULL; //initialize
return 0;
}
Code in a DLL can't directly access variables in the calling app, because there's no guarantee that the app that loads the DLL will have those variables defined, and even if it did, the DLL has no way to know where it would be stored.
You could have a global variable in the DLL and an extra entry point to set it, which you call after calling SetWindowsHookEx. The DLL would need to wait until this entry point is called before calling CallNextHookEx.
On NT/XP/2003 etc the first param to CallNextHookEx is ignored. See the documentation for CallNextHookEx:
http://msdn.microsoft.com/en-us/library/ms644974%28VS.85%29.aspx
hth

Resources