OCNYang 2012-08-24
为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()); } 这样基本上挂钩到你所想要的任何线程程序上面。