KeyboardHook, FAQ bsp will nicht funktionieren
-
Hallo,
also ich will mich in ein anderes programm einhaken und die messages abgreifen. Als einstieg dachte ich mir gucke ich das KeyboardHook FAQ an.
Dann habe ich noch das Forum durchforstet und den Source angepasst, leider will gar nichts funktionieren obwohl die dll und die funktion geladen wird.
hier einmal der Source von "hookdll.h"
// hookdll.h #ifdef __cplusplus #define EXPORT extern "C" __declspec (dllexport) #else #define EXPORT __declspec (dllexport) #endif // Funktonalität sowohl unter C als auch unter C++ gegeben EXPORT BOOL SetupHook (HWND) ; EXPORT BOOL UninstallHook (void) ; // Die Prototypen der EXPORT Funktionen /////////////////////////////////////////////////////////////nun der "hookdll.cpp"
// hookdll.cpp // Der Keyboardhook wird beim aufruf die Funktion SetupHook (HWND) // vom Hauptprogramm aus gesetzt. Dabei wird das Fensterhandle des // aufrufendes Programms an die Funktion übergeben. Als Ergebnis // sendet die hookdll.dll über die Funktion KeyboardHookProc // jedes mal wenn eine Taste betätigt wird eine Nachricht // vom Typ (WM_USER + 2) an das Hauptprogramm. Dabaei steht der // Tastencode der gedrückten Taste in dem Paramter "wParam". // Wenn der Hook nicht mehr benötigt wird, löscht man ihn über die // Funkion UninstallHook () #include <windows.h> #include "hookdll.h" /* -> Siehe Oben */ // Weise den Compiler an, die Variable hWindow in einem // separaten Abschnitt namens Shared unterzubringen // Darüber hinaus ist dann auch noch dem Linker mitzuteilen, // dass die Daten in diesem Abschnitt von allen Instanzen // dieser Anwendung gemeinsam verwendet werden sollen. // Ganz wichtig dabei ist, dass die Variablen initialisiert // sein müssen. #define SHARED __attribute__((section(".shr"), shared)) HWND hWindow = 0 ; // Weise den Compilern, den Abschnitt Shared als lesbar, // beschreibbar und zur gemeinsamen Verwendung zu deklarieren - "RSW". #pragma comment (linker, "/section:Shared,RWS") LRESULT CALLBACK KeyboardHookProc (int, WPARAM, LPARAM) ; // Der Prototyp der Funktion KeyboardHookProc HHOOK hhkHook SHARED=0 ; HINSTANCE hDllInstance ; // Definition globaler Variablen /************************************************************************/ /* DllMain: wird automatisch aufgerufen, wenn die DLL mit LoadLibrary() */ /* geladen, oder mit FreeLibrary wieder freigegeben wird. */ /* Eingabe Parameter: Systemspezifische Daten */ /* Return-Wert: TRUE */ /************************************************************************/ int APIENTRY DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved){ switch (fdwReason){ case DLL_PROCESS_ATTACH : // Die DLL wird in den Adressraum des aktuellen Prozesses // eingeblendet. hDllInstance = hInstance ; // Initialisierung der globalen Variable break ; } return TRUE ; } /***********************************************************/ /* SetupHook: EXPORT Funktion, setzt den Keyboardhook */ /* Eingabe Parameter: HWND des aufrufenden Fensters */ /* Return-Wert: TRUE */ /***********************************************************/ EXPORT BOOL SetupHook (HWND hParent){ hWindow = hParent ; // Initialisierung der globalen Variable mit dem Eingabe Parameter hhkHook = SetWindowsHookEx (WH_KEYBOARD_LL, KeyboardHookProc, NULL, GetCurrentThreadId()) ; // Keyboardhook setzen und das Ergebnis in der globalen Variable // hhkHook speichern. return TRUE ; } /*******************************************************************/ /* KeyboardHookProc: wird jedes mal aufgerufen, wenn eine Taste */ /* betätigt wird */ /* Eingabe Parameter: Systemspezifische Daten */ /* Return-Wert: s. u. */ /*******************************************************************/ LRESULT CALLBACK KeyboardHookProc (int nCode, WPARAM wParam, LPARAM lParam){ if (nCode == HC_ACTION){ // Verhindern das eine Nachricht mehrmals verarbeitet wird. if ((lParam & 1073741824) != 1073741824){ // Überprüfen ab vor dem Aufruf dieser Funktion die Taste bereits gedrückt war SendMessage ((HWND) hWindow, (WM_USER + 2), (WPARAM) wParam, (LPARAM) lParam) ; // Senden der Nachricht (WM_USER + 2) und den Tastencode der gedrückten // Taste (gespeichert in "wParam") an das in der globalen Variable // hWindow gespeicherte Fensterhandle. MessageBox(HWND_DESKTOP,"blub\n","",IDOK); } } return CallNextHookEx (hhkHook, nCode, wParam, lParam) ; // Die Nachrichten an den nächsten Hook weiterreichen. } /*********************************************************************/ /* UninstalHook: EXPORT Funktion, löscht den über die Funktion */ /* SetupHook gesetzten Hook */ /* Eingabe Parameter: keine */ /* Return-Wert: TRUE */ /*********************************************************************/ EXPORT BOOL UninstallHook (void){ UnhookWindowsHookEx (hhkHook) ; // den in der globalen Variable hhkHook gespeicherten Hook löschen. return TRUE ; } /////////////////////////////////////////////////////////////////////das ganze wird als "hook2_faq_winapi.dll" kompiliert.
Nun zum Hauptprogramm:
#define _WIN32_WINNT 0x0500 #include <windows.h> #include "hookdll.h" #include <iostream> #include <string.h> #include <sstream> #include <stdlib.h> #include <stdio.h> using namespace std; typedef BOOL (*SetupHookDll)(HWND); typedef BOOL (*UninstallHookDll)(void); string int_to_str(int i) { ostringstream ret; ret << i; return ret.str(); } SetupHookDll m_pSetupHookDll = NULL; UninstallHookDll m_pUninstallHookDll = NULL; /* Declare Windows procedure */ LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); HINSTANCE hGlobalInst; /* Make the class name into a global variable */ char szClassName[ ] = "WindowsApp"; bool hookinit(HWND); int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) { HWND hwnd; /* This is the handle for our window */ MSG messages; /* Here messages to the application are saved */ WNDCLASSEX wincl; /* Data structure for the windowclass */ /* The Window structure */ wincl.hInstance = hThisInstance; wincl.lpszClassName = szClassName; wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */ wincl.style = CS_DBLCLKS; /* Catch double-clicks */ wincl.cbSize = sizeof (WNDCLASSEX); /* Use default icon and mouse-pointer */ wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); wincl.hCursor = LoadCursor (NULL, IDC_ARROW); wincl.lpszMenuName = NULL; /* No menu */ wincl.cbClsExtra = 0; /* No extra bytes after the window class */ wincl.cbWndExtra = 0; /* structure or the window instance */ /* Use Windows's default color as the background of the window */ wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; /* Register the window class, and if it fails quit the program */ if (!RegisterClassEx (&wincl)) return 0; /* The class is registered, let's create the program*/ hwnd = CreateWindowEx ( 0, /* Extended possibilites for variation */ szClassName, /* Classname */ "Windows App", /* Title Text */ WS_OVERLAPPEDWINDOW, /* default window */ CW_USEDEFAULT, /* Windows decides the position */ CW_USEDEFAULT, /* where the window ends up on the screen */ 544, /* The programs width */ 375, /* and height in pixels */ HWND_DESKTOP, /* The window is a child-window to desktop */ NULL, /* No menu */ hThisInstance, /* Program Instance handler */ NULL /* No Window Creation data */ ); /* Make the window visible on the screen */ ShowWindow (hwnd, nFunsterStil); hGlobalInst=hThisInstance; /* Run the message loop. It will run until GetMessage() returns 0 */ while (GetMessage (&messages, NULL, 0, 0)) { /* Translate virtual-key messages into character messages */ TranslateMessage(&messages); /* Send message to WindowProcedure */ DispatchMessage(&messages); } /* The program return-value is 0 - The value that PostQuitMessage() gave */ return messages.wParam; } /* This function is called by the Windows function DispatchMessage() */ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hEdit; switch (message) /* handle the messages */ { case WM_CREATE: { hEdit=CreateWindow("edit","", WS_CHILD|WS_VISIBLE, /* default window */ 0,0,100,20, /* Windows decides the position */ hwnd, /* The window is a child-window to desktop */ NULL, /* No menu */ hGlobalInst, /* Program Instance handler */ NULL /* No Window Creation data */ ); ShowWindow(hEdit,SW_SHOWNORMAL); hookinit(hwnd); break; } case (WM_USER+2): { char msg[10]; string temp=int_to_str(wParam); SendMessage(hEdit,WM_SETTEXT,(WPARAM)temp.c_str(),(LPARAM)temp.length()); MessageBox(HWND_DESKTOP,"blub","",IDOK); break; } case WM_DESTROY: //m_pUninstallHookDll(); PostQuitMessage (0); /* send a WM_QUIT to the message queue */ break; default: /* for messages that we don't deal with */ return DefWindowProc (hwnd, message, wParam, lParam); } return 0; } bool hookinit(HWND hWnd) { HMODULE hMyDll = NULL; hMyDll = LoadLibrary("C:\\hook2_faq_winapi.dll"); if(hMyDll == NULL) { MessageBox(HWND_DESKTOP,"Dll nicht gefunden!\n","",IDOK); return 0; } else{MessageBox(HWND_DESKTOP,"DLL gefunden!\n","",IDOK);}; m_pSetupHookDll = (SetupHookDll)GetProcAddress(hMyDll, "SetupHook"); if(m_pSetupHookDll == NULL) { MessageBox(0,"SetupHookDll Funktionen nicht gefunden!\n","",IDOK); return 0; } else{MessageBox(HWND_DESKTOP,"Funktion gefunden!\n","",IDOK);}; m_pSetupHookDll(hWnd); return 0; };Interresanter weise bekomme ich einen fehler wenn ich im WM_DESTROY Swtich m_pUninstallHook aufrufe. Daher hier wegegelassen.
Ich benutze den MinGW Compiler.
Es wird auch die MsgBox im KeyboardHookProc nicht aufgerufen.
Wär nett wenn mir einer helfen könnte.
-
Push (leicht dringend)
-
Jo,
habe auch festgestellt das der entrypoint in der dll "wohl" nicht angesprochen wird. Die msgbox meldet sich aus der dll nicht.hmmmm...
-
Moi, SetWindowsHookEx mit !hmodule und ThreadID!=0 ?
SetWindowsHookEx
[...]
WH_KEYBOARD_LL Global only
[...]Also
hhkHook = SetWindowsHookEx (WH_KEYBOARD_LL, KeyboardHookProc, hDllInstance, 0);
-
zeusosc schrieb:
// Weise den Compiler an, die Variable hWindow in einem // separaten Abschnitt namens Shared unterzubringen // Darüber hinaus ist dann auch noch dem Linker mitzuteilen, // dass die Daten in diesem Abschnitt von allen Instanzen // dieser Anwendung gemeinsam verwendet werden sollen. // Ganz wichtig dabei ist, dass die Variablen initialisiert // sein müssen. #define SHARED __attribute__((section(".shr"), shared)) HWND hWindow = 0 ; // Weise den Compilern, den Abschnitt Shared als lesbar, // beschreibbar und zur gemeinsamen Verwendung zu deklarieren - "RSW". #pragma comment (linker, "/section:Shared,RWS")Ich habe nicht alles gelesen, stolpere nur hier über den Kommentar und die folgenden Instruktionen:
Laut Kommentar soll hWindow in einem shared-Segment untergebracht werden, das tust Du aber nicht. Du definierst zwar ein entsprechendes Makro für den MinGW, aber benutzt es nicht bei Definition von hWindow.
Das
#pragma comment (linker, "/section:Shared,RWS")
kannst Du hingegen weglassen, das gehört zu den MS-Compilern.
-
Also ich habe das folgend geändert:
#define SHARED __attribute__((section(".shr"), shared)) HWND SHARED hWindow = 0 ; HHOOK SHARED hhkHook =0 ; HINSTANCE SHARED hDllInstance =0; ; // Weise den Compilern, den Abschnitt Shared als lesbar, // beschreibbar und zur gemeinsamen Verwendung zu deklarieren - "RSW". LRESULT CALLBACK KeyboardHookProc (int, WPARAM, LPARAM) ; // Der Prototyp der Funktion KeyboardHookProc // Definition globaler Variablen /************************************************************************/ /* DllMain: wird automatisch aufgerufen, wenn die DLL mit LoadLibrary() */ /* geladen, oder mit FreeLibrary wieder freigegeben wird. */ /* Eingabe Parameter: Systemspezifische Daten */ /* Return-Wert: TRUE */ /************************************************************************/ BOOL WINAPI DllMain (HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved){ MessageBox(HWND_DESKTOP,"blub\n","",IDOK); switch (fdwReason){ case DLL_PROCESS_ATTACH : // Die DLL wird in den Adressraum des aktuellen Prozesses // eingeblendet. hDllInstance = hInstance ; // Initialisierung der globalen Variable break ; } return TRUE ; }der entry point DllMain wird anscheinend immer noch nicht aufgerufen,...
hmmm solangsam weiß ich nicht mehr weiter...
gruß
-
Die keyboard hooking FAQ hier ist halt veraltet. Heutzutage (Win2000 und neuer) funktioniert es ganz einfach (ohne DLL, ohne Injection, ohne Exports):
#include <Windows.h> #include <tchar.h> // Forward declarations of functions included in this code module: LRESULT CALLBACK WindowProcedure(HWND window, UINT messageId, WPARAM wordParameter, LPARAM longParameter); LRESULT CALLBACK LowLevelKeyboardHookProcedure(int code, WPARAM wordParameter, LPARAM longParameter); // required for the hook procedure as the message recipient window HWND g_mainWindow = NULL; int APIENTRY _tWinMain ( HINSTANCE instance, HINSTANCE previousInstance, LPTSTR commandLine, int showWindowCommand ) { UNREFERENCED_PARAMETER(previousInstance); UNREFERENCED_PARAMETER(commandLine); // low level hooking requires us to have a window message processing loop { const TCHAR* const windowClassName = TEXT("LLHook"); { WNDCLASSEX windowClass = {0}; windowClass.cbSize = sizeof(windowClass); windowClass.style = 0; windowClass.lpfnWndProc = WindowProcedure; windowClass.cbClsExtra = 0; windowClass.cbWndExtra = 0; windowClass.hInstance = instance; windowClass.hIcon = NULL; windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); windowClass.hbrBackground = (HBRUSH)(INT_PTR)(COLOR_WINDOW + 1); windowClass.lpszMenuName = NULL; windowClass.lpszClassName = windowClassName; windowClass.hIconSm = NULL; { const ATOM registerClassResult = RegisterClassEx(&windowClass); if (registerClassResult == 0) // If the function terminates before entering the message loop, it should return zero. return 0; } } { const HWND mainWindow = CreateWindow ( windowClassName, NULL, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, instance, NULL ); if (mainWindow == NULL) return 0; g_mainWindow = mainWindow; ShowWindow(mainWindow, showWindowCommand); UpdateWindow(mainWindow); } } { MSG message; // Main message loop while (GetMessage(&message, NULL, 0, 0)) DispatchMessage(&message); return (int) message.wParam; } } LRESULT CALLBACK WindowProcedure (HWND window, UINT messageId, WPARAM wordParameter, LPARAM longParameter) { switch (messageId) { case WM_CREATE: { const HHOOK hook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardHookProcedure, NULL, 0); if (hook == NULL) return -1; SetLastError(0); SetWindowLongPtr(window, GWLP_USERDATA, (LONG_PTR)hook); { const DWORD setWindowLongPointerError = GetLastError(); if (setWindowLongPointerError != 0) return -1; } } break; case WM_USER: { MessageBeep(0); } break; case WM_PAINT: { PAINTSTRUCT paintStructure = {0}; BeginPaint(window, &paintStructure); EndPaint(window, &paintStructure); } break; case WM_DESTROY: { const HHOOK hook = (HHOOK)SetWindowLongPtr(window, GWLP_USERDATA, 0); if (hook != NULL) UnhookWindowsHookEx(hook); PostQuitMessage(0); } break; default: return DefWindowProc(window, messageId, wordParameter, longParameter); } return 0; } LRESULT CALLBACK LowLevelKeyboardHookProcedure (int code, WPARAM wordParameter, LPARAM longParameter) { if (code == HC_ACTION) SendMessage(g_mainWindow, WM_USER, 0, 0); return CallNextHookEx(NULL, code, wordParameter, longParameter); }
-
ok, thx erstmal. Da taucht beim call der SetWindowHookEx ein error auf,
und zwarERROR_HOOK_NEEDS_HMOD
1428 (0x594)Cannot set nonlocal hook without a module handle.
Ich habe überlegt wie ich das problem lösen kann, dabei habe ich aus msdn
msdn schrieb:
hMod
[in] Handle to the DLL containing the hook procedure pointed to by the lpfn parameter. The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process.mir überlegt einfache die instance des Progs zu nehmen, leider kommt dann die gleiche fehlermeldung,..
jemand eine idee?
gruß
-
*push*
-
hMod ist das Handle der DLL!
-
Jo Martin,
Wie du oben gelesen hast, habe ich schwierigkeiten mit der DLL, da der entrypoint nicht angesprochen wird.
(sonst würde ja die msg Box erscheinen).Deswegen habe ich aufgrund des vorletzten Post versucht inerhalb der eigenen instance den hook zu erzeugen...
dit will allet net so wie icke wil

gruß
-
Ok, ich habe mir jetzt VC++2008 Express runtergeladen um die dll zu erzeugen, diesmal bekomme ich eine meldung des entrypoints DllMain ich werde mal in einem seperaten thread nachfragen wo das problem mit dem MinGW , bzw bei mir, liegt.
Ich werde mich jetzt nochmal am hooking probieren,..
grüüße
-
Sooo ich nochmal:
Wenn ich nur WH_KEYBOARD benutzte, funktioniert lokal alles einwandfrei, ich will mich aber in ein anderes programm hooken, das heisst WH_KEYBOARD_LL, das funktioniert nicht nur seeehhhr träge, sondern schmeisst mir immer egal welche taste die werte 256 und 257 raus, ich nehme mal an das das sooo nicht gedacht war,...
daher habe ich zwei fragen:
a) woran kann das liegen und wie kann ich das problem beheben
b) wie kann ich die dll nur auf spezielles programm anwenden und in meinen anderen programm die messages abfangen.Freue mich auf eure antworten, werde mich in der zwischenzeit belesen,.. gruuuß
-------------------------------------------------------------------------------
Edit:
Ok das Problem habe ich nun gelöst.
Nun habe ich mit WH_CALLWNDPROC versucht die Messages für einen bestimmten Thread zu bekommen.Ich bekomme die Message das der Hook instaliert wurde, und ich bekomme ein bzw. zweimal eine nachricht das MsgProc aufgerufen wurde. Wenn ich das Window des Thread aber mit dem Mauszeiger berühre (eine andere Application ist vorher als actives fenster gekennzeichnet), was ja eine Message auslöst, bekomme ich eine Exception,
Funktion der Adresse 0x7a4...... verweist auf den Speicher 0xffffffff (oder auch 0x000000..). "read" konnte nicht durchgeführt werden.
Leider will mein debugger nicht, daher weiß ich nicht ganz wie ich herausbekomme ob das ein verweis aus der dll oder aus meinen hauptprogramm ist das diesen Fehler verursacht.
Prinzipiell müsste ich die Adressen aller funktionen mit deren funktionszeiger auflisten, leider weiß ich net wie ich die adressen ohne einen 30zeiler als Hex im string darstellen kann. Wisst Ihr da vlt. Weiter?
( GetProcAddr(hMyDll,irgendeineFkt") gibt mir leider die vals:00 raus)
Grüüüße und *push*