為msdn 明確的說過c#不能全局掛鉤,對於我這個學習面向對象的c#來說,無疑是有一定的難度的。鉤子分為全局鉤子和線程鉤子,全局鉤子掛鉤整個Windows操作系統體系內的甄別優先權,而線程鉤子則掛鉤某一特定的程序,例如外掛,QQ盜號技術等都是有線程來決定的。Windows鉤子三個數,SetWindowsHookExSetWindowsHookEx,CallNextHookEx。這些函數都有Windows提供,最奇怪的是後掛鉤的竟然先運行,有點類似於棧。
c++dll編寫,需要注意一以下幾點。頭文件中需要又導出函數,否則加載的時候會不識別: extern "C" __declspec(dllexport) BOOL Start(); extern "C" __declspec(dllexport) void Stop(); #if !defined(AFX_DLL_H__CC961918_48E3_4FDB_AFA5_679670A94349__INCLUDED_) #define AFX_DLL_H__CC961918_48E3_4FDB_AFA5_679670A94349__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class DLL { public: DLL(); virtual ~DLL(); }; #endif // !defined(AFX_DLL_H__CC961918_48E3_4FDB_AFA5_679670A94349__INCLUDED_)
例如:無參 start,無參stop 都為導出函數 菜單掛鉤和鍵盤按鍵響應都可以用GetMesage鉤子
1.菜單鉤子 if(msg->message==WM_COMMAND) { if (0 == HIWORD(msg->wParam)) { wmId=LOWORD(msg->wParam); if(wmId==IDM_ABOUT) MessageBoxA(0,"攔截到菜單消息","提示",64); else MessageBoxA(0,"沒有攔截到菜單消息","提示",64); } } 注意:此處msg為結構體必須在判斷IDM_ABOUT菜單ID號的時候用指針指向,如果按照鉤子回調函數的wparam來判斷,無疑是總是不正確。
2. 鍵盤響應鉤子 if (msg->message == WM_CHAR) { if (msg->wParam == '0') { MessageBoxA(0,"已經攔截到關閉消息","提示",64); return 0; } if (msg->wParam == '5') { MessageBoxA(0,"已經攔截","提示",64); } } 攔截0和5的一個鉤子程,此兩個鉤子通過GETMESSAGE掛鉤,前者無疑是可以WH_CALLWNDPROC掛鉤,後者更是可以通過鍵盤來掛鉤。鉤子安裝原型:mHook=::SetWindowsHookEx (WH_GETMESSAGE,KeyProc,hInstance,progID);
DLL寫好了之後下面可以加載了,在c# 中提供了最簡單的DLL 訪問,只要剛才所寫的DLL 拷貝到c#源文件DEBUG目錄下,然後通過地址尋址函數來加載DLL和尋訪函數入口地址,以及傳遞參數: bool k = false; try { _amDBRSetThermoModel amf = (_amDBRSetThermoModel)DLLWrapper.GetFunctionAddress(hModule(), "Start", typeof(_amDBRSetThermoModel)); k = amf(kk); } catch (Exception ex) { MessageBox.Show(ex.Message.ToString()); } 這樣基本上掛鉤到你所想要的任何線程程序上面。