我本想通过鼠标钩子来将鼠标在屏幕上的坐标(鼠标可能不在本程序窗口中)显示在我的应用程序中的对话框中。原理是:在DLL中设置一个 HWND hwnd, 在DLL 中建立一函数SetWnd(HWND hWnd_p),应用程序通过此函数将应用程序的窗口句柄传给DLL,钩子函数通过 SendMessage(...)给应用程序发消息,程序负责显示。但我发现当鼠标移到别的窗口时,已被赋值的 hWnd 变为了NULL,后来用键盘钩子来试却不会,不知为什么,请大家一定要帮忙,我已被折摩好久了
说明:
1、MouseProc()函数中的代码是为了测试才这样写的
2、hIns 已被赋值,代码未写出来,
3、鼠标位于本程序窗口时正常,钩子函数也能钩到鼠标消息#pragma data_seg("_MyData")
HHOOK hook = NULL;
HWND hWnd = NULL;
HINSTANCE hIns = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:_MyData, RWS")//设置钩子
BOOL DLLEXPORT CALLBACK InstallHook()
{
hook = SetWindowsHookEx(WH_MOUSE, (HOOKPROC )MouseProc, hIns, 0);
return (hook != NULL);
}
//应用程序通过此函数将应用程序的窗口 HWND 传给钩子, hWnd在上面有定义
void DLLEXPORT CALLBACK SetWnd(HWND hWnd_p)
{
hWnd = hWnd_p;
}
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if( nCode < 0 )
return CallNextHookEx(hook, nCode, wParam, lParam); if ( nCode == HC_ACTION ){
CString str;
POINT pt;
pt.x = rand() % 800;
pt.y = rand() % 600;
str.Format("%d, %d", pt.x, pt.y);
if( hWnd == NULL){ //当设置鼠标钩子且鼠标移到应用程序窗口以外的窗口时就会
//显示下面的AfxMessageBox(),当设置键盘钩子且在别的
//窗口按下一个键时也不会显示,经过测试发现当设置鼠标钩
//子显鼠标不在本窗口时 hWnd == NULL,但键盘钩子却不会
AfxMessageBox(str);
}
} return CallNextHookEx(hook, nCode, wParam, lParam);
}
说明:
1、MouseProc()函数中的代码是为了测试才这样写的
2、hIns 已被赋值,代码未写出来,
3、鼠标位于本程序窗口时正常,钩子函数也能钩到鼠标消息#pragma data_seg("_MyData")
HHOOK hook = NULL;
HWND hWnd = NULL;
HINSTANCE hIns = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:_MyData, RWS")//设置钩子
BOOL DLLEXPORT CALLBACK InstallHook()
{
hook = SetWindowsHookEx(WH_MOUSE, (HOOKPROC )MouseProc, hIns, 0);
return (hook != NULL);
}
//应用程序通过此函数将应用程序的窗口 HWND 传给钩子, hWnd在上面有定义
void DLLEXPORT CALLBACK SetWnd(HWND hWnd_p)
{
hWnd = hWnd_p;
}
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if( nCode < 0 )
return CallNextHookEx(hook, nCode, wParam, lParam); if ( nCode == HC_ACTION ){
CString str;
POINT pt;
pt.x = rand() % 800;
pt.y = rand() % 600;
str.Format("%d, %d", pt.x, pt.y);
if( hWnd == NULL){ //当设置鼠标钩子且鼠标移到应用程序窗口以外的窗口时就会
//显示下面的AfxMessageBox(),当设置键盘钩子且在别的
//窗口按下一个键时也不会显示,经过测试发现当设置鼠标钩
//子显鼠标不在本窗口时 hWnd == NULL,但键盘钩子却不会
AfxMessageBox(str);
}
} return CallNextHookEx(hook, nCode, wParam, lParam);
}
//
//头文件:HOOK.h
//
//源文件:HOOK.CPP
//
//功能:钩子
//
//作者:徐怀移
//
//时间:2005年12月13日
//
//
//
//
////////////////////////////////////////////////////////////////////////////////////////// HOOK.cpp : 定义 DLL 的初始化例程。
//#include "stdafx.h"
#include "HOOK.h"#ifdef _DEBUG
#define new DEBUG_NEW
#endif//
// 注意!
//
// 如果此 DLL 动态链接到 MFC
// DLL,从此 DLL 导出并
// 调入 MFC 的任何函数在函数的最前面
// 都必须添加 AFX_MANAGE_STATE 宏。
//
// 例如:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // 此处为普通函数体
// }
//
// 此宏先于任何 MFC 调用
// 出现在每个函数中十分重要。这意味着
// 它必须作为函数中的第一个语句
// 出现,甚至先于所有对象变量声明,
// 这是因为它们的构造函数可能生成 MFC
// DLL 调用。
//
// 有关其他详细信息,
// 请参阅 MFC 技术说明 33 和 58。
//// CHOOKApp#pragma data_seg ("shared")
HWND hwnd=NULL; //接收窗口的指针KBDLLHOOKSTRUCT kbkey={0};MSLLHOOKSTRUCT mouse={0};#pragma data_seg () #pragma comment(linker,"/SECTION:shared,RWS")
BEGIN_MESSAGE_MAP(CHOOKApp, CWinApp)
END_MESSAGE_MAP()
// CHOOKApp 构造CHOOKApp::CHOOKApp()
{
// TODO: 在此处添加构造代码,
// 将所有重要的初始化放置在 InitInstance 中
}
// 唯一的一个 CHOOKApp 对象CHOOKApp theApp;
// CHOOKApp 初始化BOOL CHOOKApp::InitInstance()
{
CWinApp::InitInstance(); return TRUE;
}
HHOOK phook[2]={0,0};
LRESULT WINAPI LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) //钩子函数
{ if(nCode==HC_ACTION)
{ mouse=*(MSLLHOOKSTRUCT*)lParam;
PostMessage(hwnd,WM_MOUSEHOOK,(WPARAM)&mouse,wParam);
} return CallNextHookEx(phook[1],nCode, wParam,lParam);
}
LRESULT WINAPI LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) //钩子函数
{ kbkey = *(KBDLLHOOKSTRUCT *) lParam;
switch (nCode)
{
case HC_ACTION:
TRACE("%d\n",::GetFocus());
PostMessage(hwnd,WM_KEYHOOK,(WPARAM)&kbkey,wParam);// return 1;
// Check to see if the CTRL key is pressed
// bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1);
// Disable CTRL+ESC
// if (pkbhs->vkCode == VK_ESCAPE && bControlKeyDown)
// return 1; // Disable ALT+TAB
if (kbkey.vkCode == VK_TAB && kbkey.flags & LLKHF_ALTDOWN)
return 1;
if(kbkey.vkCode==91)
return 1;
// Disable ALT+ESC
//if (pkbhs->vkCode == VK_ESCAPE && pkbhs->flags & LLKHF_ALTDOWN)
// return 1;
default: break;
}
return CallNextHookEx(phook[0],nCode, wParam,lParam);}void WINAPI AddHook(HWND wnd) //安装钩子
{ hwnd=wnd; if(phook[0]!=NULL)
{
UnhookWindowsHookEx(phook[0]);
} if(phook[1]!=NULL)
{
UnhookWindowsHookEx(phook[1]);
}
phook[0]=SetWindowsHookEx(WH_KEYBOARD_LL,LowLevelKeyboardProc,theApp.m_hInstance,0);
phook[1]=SetWindowsHookEx(WH_MOUSE_LL,LowLevelMouseProc,theApp.m_hInstance,0);
/*
HHOOK SetWindowsHookEx(
int idHook, // 钩子的类型,即它处理的消息类型
HOOKPROC lpfn, // 钩子子程的地址指针。如果dwThreadId参数为0
// 或是一个由别的进程创建的线程的标识,
// lpfn必须指向DLL中的钩子子程。
// 除此以外,lpfn可以指向当前进程的一段钩子子程代码。
// 钩子函数的入口地址,当钩子钩到任何消息后便调用这个函数。
HINSTANCE hMod, // 应用程序实例的句柄。标识包含lpfn所指的子程的DLL。
// 如果dwThreadId 标识当前进程创建的一个线程,
// 而且子程代码位于当前进程,hMod必须为NULL。
// 可以很简单的设定其为本应用程序的实例句柄。
DWORD dwThreadId // 与安装的钩子子程相关联的线程的标识符。
// 如果为0,钩子子程与所有的线程关联,即为全局钩子。
);
*/}void WINAPI DelHook() //御载钩子
{
if(phook[0]!=NULL)
{ UnhookWindowsHookEx(phook[0]); phook[0]=NULL;
}
if(phook[1]!=NULL)
{ UnhookWindowsHookEx(phook[1]); phook[1]=NULL;
}
}
我在 XP 里是可以用的
你好,很感谢你的回复,但不知你的 hwnd 你是在哪里赋值的呢?
PostMessage(hwnd,WM_MOUSEHOOK,(WPARAM)&mouse,wParam);我的程序之所以不行,就是因为鼠标移动其它窗口时 hwnd 的值自动变为 NULL,而鼠标移到本窗口时却不会。对于键盘HOOK, 则无论在哪个窗口按键盘, hwnd 却不会变为 NULL。
我用的是WIN2000
不好意思,对于键盘消息 hwnd 也会变成 NULL,(之前不小心把if语句给删了)
AFX_MANAGE_STATE(AfxGetStaticModuleState());
如果实在不行的话,建议直接用win32 dll,不要用MFC dll
我的QQ现在用不了,我先记下你的,以后再向你们赐教!