globale Windows Botschaft eines Mausklicks abfangen
-
OK, hab das jetzt auskommentiert und noch ein wenig daran rumgebastelt. Ich hab da noch ein Problem: Ich würde der LIB gerne mein WindowHandle mitgeben, damit FindWindow() in der HookProcedure nicht verwendet werden muss. Das gefällt mir nicht. Dazu hatte ich eine globale Variable ghWnd deklariert und sie bei SetHook() gesetzt mit dem Parameter von SetHook(HWND). Leider klappt das nicht, d.h. die Message wird nicht an mein Fenster gesendet, außer, wenn ich über einem Fenster meines eigenen Prozesses mit der Mouse bin. Ich denke, das liegt daran, dass beim Start des Hooks jeder Prozess die DLL in seinen Adressraum aufnimmt und der Wert von hWnd dann verschwunden ist, weil hWnd ja nur in MEINEM PROZESS initialisiert wird. Irgendwie so muss das laufen. Ich würde der DLL/LIB trotzdem gerne das Handle mitgeben. Weiß jemand, wie man das realisieren könnte?
-
-
Hmm, das Problem ist, dass das mit dem Pragma Comment bei mir nicht funktioniert. "linker" gibt's beim BCB nicht als erstem Parameter.
-
Original erstellt von WebFritzi:
Was hättest du denn gerne kommentiert?Also wenn ich mir die geänderte Version so ansehe sieht das doch viel besser und erklärender aus als vorher meinst du nicht? (-;
Aber vielleicht noch ein klärendes Wort: Man soll auch nicht jede einzelne Funktion kommentieren. Was ich viel eher meinte - und as hast du ja jetzt auch gemacht - ist, dass du einzelne Blöcke noch kommentieren solltest was du beabsichtigst das sie tun sollen.
Zum Beispiel sowas hier:// Das Instanz-Handle der DLL speichern // Wird unten in SetHook() benötigt
Ist doch wunderbar erklärend, so muss keiner nachsehen was denn gInst oder wie die Variable hiess denn für eine Verwendung hat.
Gute Arbeit, Fritzi.
-junix
-
Danke junix.
So, ich hab das mit dem Window-Handle jetzt hinbekommen. Das hat mich vieeel Arbeit gekostet. Aber ich war froh, als es dann lief. Das Problem im BCB ist, dass dieses #pragma comment(linker, ...) nicht geht. Ist wohl ein Manko im Linker des BCB. Nachdem ich die google Groups von oben bis unten durchgewühlt hatte, bin ich zu dem Schluss gekommen, dass es wohl nur mit WinAPI geht. Leider gab es auch keinen fertigen Code, und ich musste mir alles selber zusammenfriemeln. Hier die fertige DLL:
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #pragma argsused // Wie in der cpp-Datei der Form-Klasse eine neue Message-ID erstellen #define WM_MOUSEHOOK WM_USER+100 #define SHMEMSIZE 4096 //--------------------------------------------------------------------------- // Funktionen deklarieren extern "C" __declspec(dllexport) __stdcall void SetHook(HWND); extern "C" __declspec(dllexport) __stdcall void RemoveHook(void); LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam); //--------------------------------------------------------------------------- // Globale Variablen HHOOK ghHook = NULL; // Hook-Handle HINSTANCE ghInst; // Instanz-Handle HWND ghWnd = NULL; // Fenster-Handle (shared memory) LPVOID lpvMem = NULL; // pointer to shared memory //--------------------------------------------------------------------------- BOOL WINAPI DllEntryPoint(HINSTANCE hinst, DWORD reason, LPVOID lpvReserved) { HANDLE hMapFile = NULL; // handle to file mapping BOOL bFirstProcess; // Das Instanz-Handle der DLL speichern // Wird unten in SetHook() benötigt ghInst = hinst; switch(reason) { // Die DLL wird in den Adressraum eines Prozesses geladen case DLL_PROCESS_ATTACH: { // Ein File-Mapping-Objekt erstellen (mit Name) hMapFile = CreateFileMapping( (HANDLE)0xFFFFFFFF, // use paging file NULL, // no security attributes PAGE_READWRITE, // read/write access 0, // size: high 32-bits sizeof(DWORD), // size: low 32-bits "DLLMemFileMap"); // name of map object if(hMapFile == NULL) return FALSE; // bFirstProcess == true nur im ersten ladenden Prozess bFirstProcess = (GetLastError() != ERROR_ALREADY_EXISTS); if(!bFirstProcess) { hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, // Read/write permission. FALSE, // Do not inherit the name "DLLMemFileMap"); // of the mapping object. if(hMapFile == NULL) return FALSE; } // Einen Zeiger auf das file-mapped shared memory bekommen lpvMem = MapViewOfFile( hMapFile, // object to map view of FILE_MAP_ALL_ACCESS, // read/write access 0, // high offset: map from 0, // low offset: beginning 0); // default: map entire file if(lpvMem == NULL) return FALSE; if(bFirstProcess) // Den Speicher initialisieren memset(lpvMem, '\0', SHMEMSIZE); else // ghWnd setzen auf das erste Byte im shared Memory // Dort ist das Hande gespeichert (siehe SetHook()) ghWnd = *(HWND*)lpvMem; } break; // Neuer Thread im Prozess case DLL_THREAD_ATTACH: break; // Beenden eines Threads im Prozess case DLL_THREAD_DETACH: break; // Die DLL wird aus dem Adressraum eines Prozesses freigegeben case DLL_PROCESS_DETACH: { // Den Speicher aus dem Adressraum des Prozesses "rausmappen" UnmapViewOfFile(lpvMem); // Das Handle des Prozesses auf das File-Mapping-Objekt schließen CloseHandle(hMapFile); } break; } return TRUE; } //--------------------------------------------------------------------------- void __stdcall SetHook(HWND hWnd) { // Hier wird hWnd in das shared Memory geschrieben // und ghWnd (im aufrufenden Prozess) gesetzt HWND* hTempWnd = (HWND*)lpvMem; *hTempWnd = hWnd; ghWnd = hWnd; if(!ghHook) { // Starten des Mouse-Hooks ghHook = SetWindowsHookEx(WH_MOUSE, (HOOKPROC)MouseHookProc, ghInst, 0); if(!ghHook) MessageBox(NULL, "Hook kann nicht erstellt werden", "ERROR", MB_OK|MB_ICONERROR); } else MessageBox(NULL, "Hook ist bereits erstellt", "MouseHook", MB_OK); } //--------------------------------------------------------------------------- void __stdcall RemoveHook(void) { // Beenden des Hooks UnhookWindowsHookEx(ghHook); } //--------------------------------------------------------------------------- LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) { if(nCode >= 0) // means: nCode==HC_ACTION or nCode==HC_NOREMOVE // Die Message an die Form senden SendMessage(ghWnd, WM_MOUSEHOOK, wParam, lParam); // Die nächste Hook-Prozedur aufrufen (optional) return CallNextHookEx(ghHook, nCode, wParam, lParam); } //---------------------------------------------------------------------------
Da ich das Prinzip der DLL noch nicht so GANZ verstanden habe, musste ich am Ende viel ausprobieren. Daher habe ich jetzt nochmal eine Frage: Wie läuft das eigentlich mit ner DLL? Wenn ich sie per LIB meinem Projekt hinzufüge und dieses dann starte, dann geht er doch irgendwann (Wann?) in den DllEntryPoint und führt den Code dort aus, nicht wahr? Dort werden dann ein paar globale Variablen gesetzt. Was passiert aber jetzt danach?
Ich hatte die Variable bFirstProcess (im EntryPoint) zuerst als global definiert gehabt. Dann fragte ich ganz am Anfang von SetHook() ab, ob bFirstProcess == true ist. Das war aber nicht der Fall. Wieso?ÜBRIGENS: Man kann diese DLL (auch die erste in diesem Thread) auch in WinAPI schreiben. Dann wird sie kleiner. Man includiert dann aber natürlich nicht vcl.h sondern windows.h.
[ Dieser Beitrag wurde am 13.01.2003 um 00:28 Uhr von WebFritzi editiert. ]
-
Selbst wenn das mit diesem #pragma ... nicht geht. Beim BCB gibt es auf jeden Fall einen anderen Weg eine Shared Section in der DLL einzurichten.
-
Original erstellt von <hmm>:
Selbst wenn das mit diesem #pragma ... nicht geht. Beim BCB gibt es auf jeden Fall einen anderen Weg eine Shared Section in der DLL einzurichten.Wie schön. Wie wär's dann mal damit, dass du sagst, wie?!
-
Ja, das weiß ich auch nicht, sonst hätte ich es auch geschrieben.
Sorry.
-
Guck dir mal das an: http://world.std.com/~lword/work/dllhint.html (.DEF Datei).
Ich hoffe das "pragma data_seg" funktioniert wenigstens.
-
Nein. Hast du denn hier nichts gelesen, oder was?! Ich sagte #pragma comment(linker,...) geht nicht im BCB-Linker. Das #pragma data_seg(...) geht zwar - bringt aber nichts ohne eine weitere Linker-Anweisung über shared Sections. Wie gesagt, da #pragma comment(linker,...) nicht funzt, muss ein DEF-File ran. Wenn ich dieses meinem DLL-Projekt hinzufüge, bekomme ich den
[LinkerFehler] Section .MYSEC defined in .def file is empty.
Und ich sach dir: Es gibt im BCB keine Möglichkeit, mit shared sections zu arbeiten!
-
Ich hatte es schon ganz durchgelesen, aber es hätte ja sein können, das du uns die Information einfach verschwiegen hast.
Original erstellt von WebFritzi:
Und ich sach dir: Es gibt im BCB keine Möglichkeit, mit shared sections zu arbeiten!Und ich bin immer noch der Meinung das geht 100 %ig.
Jeder Windows-Compiler unterstützt DEF Dateien und normalerweise auch Shared Sections. Vielleicht hast du beim Einbinden dieser Datei nur irgendeinen Fehler gemacht?
Oder es liegt an deinem uralten BCB. :p
-
Das ganz bestimmt nicht! Wie gesagt, ich habe die Google Groups gestern durchwühlt und habe immer wieder die Antwort erhalten, dass das im BCB nicht geht. Man MUSS mit mapped Files arbeiten. Anders geht's nicht!
-
-
Du meinst den letzten Beitrag? Jo, das wusste ich. Aber das "shared" ALLE globalen Variablen, was auch in einem anderen Groups-Thread (mit Referenz auf diesen da) diskutiert wird. Keine Chance!
-
Ok, ich habe den BCB nicht, aber ich war mir eigentlich sicher das sowas jeder vernünftige Compiler kann.
Es tut mir leid, wenn ich was falsches behauptet hab. Sorry.
-
Hi,
erstmal super DLL!!!Nur zu meiner Frage: Kann man irgendwie verhindern, dass die Bootschaft an Windows gesendet wird. Ich hab mir so gedacht ich drüche eine Tastenkombination dann läuft der Hook und ich bestimme, was mit dem Bootschaften gemacht wird, bis ich wieder die Tastenkombination vom Anfang drücke! Geht das?
Danke
Alexander Sulfrian
-
Ne, IMHO geht das nicht. Allerdings kannst du das CallNextHookEx() am Ende der Callback-Funktion weglassen. Ich hab das mal getestet und habe festgestellt, dass z.B. kein PopupMenu mehr aufgeklappt wird, wenn man aufs Desktop klickt oder im IE. Ansonsten habe ich keine Veränderungen festgestellt.
-
Meine allgemeine Frage zu einer DLL ist noch nicht geklärt. Ich wiederhole sie nochmal klarer. Also, wer sich den letzten Code nochmal durchliest, der entdeckt im DllEntryPoint eine BOOLsche Variable bFirstProcess. Diese wird einmal auf TRUE gesetzt - nämlich, wenn das Memory Mapped File erstellt wird (unter CreateFileMapping()). Da ja mein eigener Prozess die DLL zuerst "aufruft", ist die Variable nur dann TRUE. In allen anderen Prozessen, in die sich die DLL einlinkt, ist sie FALSE. Nun, wenn ich aber diese Variable global definiere und in SetHook() (welches ja auch nur mein eigener Prozess aufruft) nur dann den Parameter hWnd in das shared Memory schreibe, wenn der Wert von bFirstProcess TRUE ist, dann funzt der Hook nicht. Das heißt, dass der Wert von bFirstProcess an dieser Stelle FALSE ist. Aber warum???
Ich hatte die Möglichkeit in Betracht gezogen, dass mein Prozess beim Starten einmal die DLL "aufruft" und dann nochmal, wenn SetHook() aufgerufen wird. Dann wäre natürlich bFirstProcess wieder FALSE. Aber das glaube ich nicht. Woran liegt es also, dass bFirstProcess (als globale Variable) beim Aufruf von SetHook() FALSE ist?
-
<*push*>
-
<*push*>