http://blog.sina.com.cn/s/blog_498c7cd50100mdjv.html
自己尝试做了一个获取窗口激活消息的钩子函数,能顺利编译运行,特将过程和代码贴在下面:
目的:有窗口被点击,钩子函数就能拦截到该消息,并通知给主程序。 钩子程序:使用全局钩子,建立dll。 主程序:使用控制台程序 环境:使用visual studio 2005 c++ 1.创建dll程序 文件->新建项目->visual c++->win32->win32 项目,输入dll文件名为:dlltest,点击下一步,在提示框中选择DLL,点击完成,建立了一个非mfc的dll项目。添加dlltext.h头文件,添加dlltest.def文件 a) 建立钩子 在dlltest.cpp中建立钩子启动函数BOOL startHOOK(HWND hwnd),和钩子卸载函数BOOL stopHOOK(),钩子回调函数LRESULT CALLBACK WindowsProc(int nCode,WPARAM wparam,LPARAM lparam)。 dlltest.cpp代码如下: #include "stdafx.h" #include "Log.h" #ifdef _MANAGED #pragma managed(push, off) #endif #pragma data_seg(".mydata") HHOOK hkb = NULL; //安装窗口钩子句柄; HWND hwndmain=NULL; //调用钩子的主窗体句柄 HINSTANCE hins = NULL;//DLL实例句柄 #pragma data_seg() #pragma comment(linker,"/SECTION:.mydata,RWS") // tell linker: make it shared #define WM_THREADFIREEVENT1 WM_APP+111 //自定义消息 BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: hins = (HINSTANCE)hModule; //给dll实例句柄赋值 break; case DLL_PROCESS_DETACH: break; } return TRUE; } #ifdef _MANAGED #pragma managed(pop) #endif LRESULT CALLBACK WindowsProc(int nCode,WPARAM wparam,LPARAM lparam) { if (HCBT_ACTIVATE==nCode) { PostMessageA(hwndmain,WM_THREADFIREEVENT1,wparam,lparam); } return CallNextHookEx(hkb,nCode,wparam,lparam); } extern "C" BOOL _declspec(dllexport) stopHOOK() { BOOL bResult = FALSE; if (hkb) { bResult = UnhookWindowsHookEx(hkb); if (bResult) { hkb = NULL; } } return bResult; } extern "C" BOOL _declspec(dllexport) startHOOK(HWND m_hwnd) { Log logger; BOOL bResult = FALSE; hwndmain = m_hwnd; hkb = SetWindowsHookExW(WH_CBT,(HOOKPROC)WindowsProc,hins,0); if (hkb!=NULL) { bResult = true; } return bResult; } 2.在dlltest.p中将startHOOK()和stopHOOK()设置为可供外部调用的函数,代码如下: #ifndef DLLTEST_H #define DLLTEST_H extern "C" BOOL _declspec(dllexport) startHOOK(HWND m_hwnd); extern "C" BOOL _declspec(dllexport) stopHOOK(); #endif 3.在dlltest.def中设置共享变量和外部调用函数,代码如下: LIBRARY "dlltest" EXPORTS startHOOK stopHOOK SECTIONS .mydata READ WRITE SHARED 以上是dll的部分,接下来是主程序的部分,主程序由于是非mfc程序,所以没有窗口,为了接收dll传过来的消息,在主程序中通过api函数建立了一个隐藏窗口,用以接收从dll中获取的消息。具体代码如下: // dllCall.cpp : 定义控制台应用程序的入口点。 #include "stdafx.h" #include <Windows.h> #include <iostream> #include <string> #include <WinUser.h> //#include <IMessage.h> #pragma comment(lib,"..\\Release\\dlltest.lib") //静态调用dll文件,必须将上面生成的dlltest.lib和dlltest.dll文件放到主程序的运行目录下 using namespace std; extern "C" BOOL _declspec(dllimport)startHOOK(HWND hwnd); extern "C" BOOL _declspec(dllimport)stopHOOK(); #define WM_THREADFIREEVENT1 WM_APP+111 //自定义用户接收消息类型,必须和dll中的消息类型一致,否则无法接收 LRESULT CALLBACK WndProc(HWND hwnd,UINT uMsg,WPARAM wparam,LPARAM lparam); //定义窗口过程函数 int _tmain(int argc, _TCHAR* argv[]) { { MSG msg; HINSTANCE hInstance = (HINSTANCE)GetModuleHandleW(0);//获取当前程序实例句柄 //创建窗口 HMENU hMenu = CreateMenu(); WNDCLASS wndclass; wndclass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH); wndclass.hCursor = LoadCursor(NULL,IDC_ARROW); wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION); wndclass.hInstance =hInstance; wndclass.lpfnWndProc = WndProc; wndclass.lpszClassName = L"HELLO"; wndclass.lpszMenuName=NULL; wndclass.style = CS_HREDRAW; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; RegisterClass(&wndclass); HWND hwnd_y = CreateWindowExW(WS_ACTIVECAPTION,L"hello",L"hello",WS_ACTIVECAPTION, 960,720,CW_USEDEFAULT,CW_USEDEFAULT,NULL,hMenu,hInstance,NULL); //隐藏窗口 ShowWindow(hwnd_y,SW_HIDE); startHOOK(hwnd_y); //启动钩子函数 //进行消息循环 while (GetMessageW(&msg,hwnd_y,0,0)) { if (msg.message == WM_THREADFIREEVENT1) { cout<<"收到消息"<<endl; //当有窗口激活消息收到,则打印该行 } } return 0; } LRESULT CALLBACK WndProc(HWND hwnd_y,UINT uMsg,WPARAM wparam,LPARAM lparam) { switch (uMsg) { case WM_QUIT: {stopHOOK();cout<<"停止钩子函数"<<endl;break;} //收到WM_QUIT消息则卸载钩子函数,这里用不到,但是以后如果换成线程来做,这个就需要 default: return DefWindowProc(hwnd_y,uMsg,wparam,lparam); } return 0; } 通过release方式进行编译,当用户点击任何一个窗口的时候都会在cmd.exe中出现提示消息。 总结: 1. sendmessage和postmessage区别 sendmessage是直接发送给窗口的,所以需要在窗口过程函数中取到该消息,不能用getmessage或peekmessage。而postmessage是发送到消息队列中的,可以上述两个函数获取消息。 2. 非mfc接收消息 在baidu上找了半天,也只找到说是用窗口接收,其他没有看到,所以只能建立一个隐藏窗口了。 3. dll共享 在程序中设置了一些句柄称为全局共享数据,但是我要在主程序中调用这些个数值,就不知道怎么做了,在baidu中找到的都是同一种方法,网上的方法如下: #pragma data_seg( "MYSEC ") char MySharedData[4096]={0}; #pragma data_seg() 然后在用户的DEF文件中为有名的数据区设定共享属性。 LIBRARY TEST DATA READ WRITE SECTIONS .MYSEC READ WRITE SHARED 在应用程序(进程)按外部变量引用共享数据。 extern _export "C "{char * MySharedData[];} 进程中使用该变量应注意间接引用。 m_pStatic=(CEdit*)GetDlgItem(IDC_SHARED); m_pStatic-> GetLine(0,*MySharedData,80); 但是也没有说m_pStatic是个什么类型的,所以最后没有用起来。