安装键盘钩子可以,卸载钩子不行,有代码

小小爬虾 2015-07-16 04:50:37
DLL代码
#include <Windows.h>
#include <tchar.h>

HHOOK g_HHook=NULL;//钩子句柄
HINSTANCE g_hInst=NULL;//DLL模块句柄
//导出函数
extern "C" _declspec(dllexport) VOID SetHookOn();
extern "C" _declspec(dllexport) VOID SetHookOff();
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
g_hInst=hinstDLL;
break;
}

return (TRUE);
}

LRESULT CALLBACK KeyBoardProc(int code,WPARAM wParam,LPARAM lParam)
{
if (code<0)
{
return CallNextHookEx(g_HHook,code,wParam,lParam);
}
if(code==HC_ACTION && lParam>0)
{
TCHAR szBuf[MAXBYTE]={0};
GetKeyNameText(lParam,szBuf,MAXBYTE);
MessageBox(NULL,szBuf,NULL,MB_OK);
}
return CallNextHookEx(g_HHook,code,wParam,lParam);
}
VOID SetHookOn()
{
g_HHook=SetWindowsHookEx(WH_KEYBOARD,KeyBoardProc,g_hInst,0);
}
VOID SetHookOff()
{
UnhookWindowsHookEx(g_HHook);
}


安装钩子的程序:MFC对话框,两个按钮,一个启动钩子,一个停止钩子。代码:
//接收Dll中导出函数的函数指针
typedef VOID (*SETHOOKON)();
typedef VOID (*SETHOOKOFF)();
HMODULE m_hInst;//DLL的模块句柄

void CInjectTheDllDlg::OnBnClickedStart()
{
// TODO: 在此添加控件通知处理程序代码
m_hInst=LoadLibrary(_T("firstdll.dll"));
SETHOOKON SetHookOn=(SETHOOKON)GetProcAddress(m_hInst,"SetHookOn");
SetHookOn();
FreeLibrary(m_hInst);
}
void CInjectTheDllDlg::OnBnClickedStop()
{
// TODO: 在此添加控件通知处理程序代码
m_hInst=LoadLibrary(_T("firstdll.dll"));
SETHOOKOFF SetHookOff=(SETHOOKOFF)GetProcAddress(m_hInst,"SetHookOff");
SetHookOff();
FreeLibrary(m_hInst);
}


点击启动按钮,钩子开始工作,能够记录键盘;但点击停止按钮,却仍能记录键盘。
请教问题出在了哪里呢?
...全文
224 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
小小爬虾 2015-07-17
  • 打赏
  • 举报
回复
引用 4 楼 dong364 的回复:
在CInjectTheDllDlg::OnBnClickedStop()中,SetHookOff()中的g_HHook是NULL,是NULL的原因就是你在OnBnClickedStart()中FreeLibrary在Stop()中又重新Load了,按道理你这代码调式一下就可以找到原因了
指教的极是。深层次的问题就是我不会调试DLL。
dong364 2015-07-17
  • 打赏
  • 举报
回复
在CInjectTheDllDlg::OnBnClickedStop()中,SetHookOff()中的g_HHook是NULL,是NULL的原因就是你在OnBnClickedStart()中FreeLibrary在Stop()中又重新Load了,按道理你这代码调式一下就可以找到原因了
孤客天涯 2015-07-17
  • 打赏
  • 举报
回复
那是因为你安装跟卸载分别都调用了LoadLibrary,你应该是只LoadLibrary一次就可以了,然后把函数地址取出来调用就可以
小小爬虾 2015-07-17
  • 打赏
  • 举报
回复
引用 1 楼 dong364 的回复:
LoadLibrary和FreeLibrary(m_hInst);在那两个函数里面调用感觉不妥,应该放在程序入口和程序出口处,这里我觉得可以放在dlg构造和析构中
另问:我构建Dlg的析构函数时,是否将析构函数定义为虚函数?
小小爬虾 2015-07-17
  • 打赏
  • 举报
回复
改好了,成功,给出代码

//接收Dll中导出函数的函数指针
typedef VOID (*SETHOOKON)();
typedef VOID (*SETHOOKOFF)();
//DLL的模块句柄
HMODULE m_hInst;
//构造函数中打开Dll句柄
CInjectTheDllDlg::CInjectTheDllDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CInjectTheDllDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_hInst=LoadLibrary(_T("firstdll.dll"));
}
//析构函数中释放Dll句柄
CInjectTheDllDlg::~CInjectTheDllDlg()
{
	FreeLibrary(m_hInst);
}
//Start Hook
void CInjectTheDllDlg::OnBnClickedButton1()
{
	SETHOOKON SetHookOn=(SETHOOKON)GetProcAddress(m_hInst,"SetHookOn");
	SetHookOn();
}
//Stop Hook
void CInjectTheDllDlg::OnBnClickedButton2()
{
	SETHOOKOFF SetHookOff=(SETHOOKOFF)GetProcAddress(m_hInst,"SetHookOff");
	SetHookOff();
}
小小爬虾 2015-07-17
  • 打赏
  • 举报
回复
改好了,成功,给出代码

//构造函数中打开Dll句柄
CInjectTheDllDlg::CInjectTheDllDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CInjectTheDllDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_hInst=LoadLibrary(_T("firstdll.dll"));
}
//析构函数中释放Dll句柄
CInjectTheDllDlg::~CInjectTheDllDlg()
{
	FreeLibrary(m_hInst);
}
//Start Hook
void CInjectTheDllDlg::OnBnClickedButton1()
{
	SETHOOKON SetHookOn=(SETHOOKON)GetProcAddress(m_hInst,"SetHookOn");
	SetHookOn();
}
//Stop Hook
void CInjectTheDllDlg::OnBnClickedButton2()
{
	SETHOOKOFF SetHookOff=(SETHOOKOFF)GetProcAddress(m_hInst,"SetHookOff");
	SetHookOff();
}
赵4老师 2015-07-17
  • 打赏
  • 举报
回复
在MSDN里面搜“调试DLL”
小小爬虾 2015-07-16
  • 打赏
  • 举报
回复
引用 1 楼 dong364 的回复:
LoadLibrary和FreeLibrary(m_hInst);在那两个函数里面调用感觉不妥,应该放在程序入口和程序出口处,这里我觉得可以放在dlg构造和析构中
虽然感觉不妥,但具体原因是什么呢
dong364 2015-07-16
  • 打赏
  • 举报
回复
LoadLibrary和FreeLibrary(m_hInst);在那两个函数里面调用感觉不妥,应该放在程序入口和程序出口处,这里我觉得可以放在dlg构造和析构中
这几年越来越多的开发团队使用了Git,掌握Git的使用已经越来越重要,已经是一个开发者必备的一项技能;但很多人在刚开始学习Git的时候会遇到很多疑问,比如之前使用过SVN的开发者想不通Git提交代码为什么需要先commit然后再去push,而不是一条命令一次性搞定;更多的开发者对Git已经入门,不过在遇到一些代码冲突、需要恢复Git代码时候就不知所措,这个时候哪些对 Git掌握得比较好的少数人,就像团队中的神一样,在队友遇到 Git 相关的问题的时候用各种流利的操作来帮助队友于水火。我去年刚加入新团队,发现一些同事对Git的常规操作没太大问题,但对Git的理解还是比较生疏,比如说分支和分支之间的关联关系、合并代码时候的冲突解决、提交代码前未拉取新代码导致冲突问题的处理等,我在协助处理这些问题的时候也记录各种问题的解决办法,希望整理后通过教程帮助到更多对Git操作进阶的开发者。本期教程学习方法分为“掌握基础——稳步进阶——熟悉协作”三个层次。从掌握基础的 Git的推送和拉取开始,以案例进行演示,分析每一个步骤的操作方式和原理,从理解Git 工具的操作到学会代码存储结构、演示不同场景下Git遇到问题的不同处理方案。循序渐进让同学们掌握Git工具在团队协作中的整体协作流程。在教程中会通过大量案例进行分析,案例会模拟在工作中遇到的问题,从最基础的代码提交和拉取、代码冲突解决、代码仓库的数据维护、Git服务端搭建等。为了让同学们容易理解,对Git简单易懂,文章中详细记录了详细的操作步骤,提供大量演示截图和解析。在教程的最后部分,会从提升团队整体效率的角度对Git工具进行讲解,包括规范操作、Gitlab的搭建、钩子事件的应用等。为了让同学们可以利用碎片化时间来灵活学习,在教程文章中大程度降低了上下文的依赖,让大家可以在工作之余进行学习与实战,并同时掌握里面涉及的Git不常见操作的相关知识,理解Git工具在工作遇到的问题解决思路和方法,相信一定会对大家的前端技能进阶大有帮助。
又一个delphi键盘钩子用法及代码,可以截获几乎所有键值,例如:shift ?,ctrl ?,alt ?,F1~F12,shift或者ctrl或者alt F1~F12,单独的 shift、ctrl、alt 键值,特殊键ins、del、caps lock、num lock、小键盘数字 等等,你只要稍作修改,也可以截获 ctrl alt ?等键值,没有截获不到的键值,本程序不使用dll方式,使用常规方式,方便你编译调试修改,支持xp、vista、win7,是最强悍的键盘钩子控件, 在delphi7下通过。   myshiftchar:string;//返回shift状态 例如 ctrl   mypresschar:string;//返回整个键值 例如 ctrl g   dulictrl:string;//返回 ctrl 和 alt 单独状态, =ctrl or =alt   安装方法:   本控件的核心源代码在 unit2   首先 创建调用主窗体,假定是form1,在form1上放一个 memo控件(必须),然后创建一个新单元 如unit2,把我的unit2 单元的源代码全部复制过去,做以下修改,首先确保form1使用 新单元 如unit2,并且unit2也使用form1。   在新单元unit2中 ,找到 函数 function KeyBHkHandle 过程,在其中找到以下两条语句:    // 在这里根据自己的情况修改    form1.Memo1.Lines.Add(mypresschar);   // 在这里根据自己的情况修改    if mypresschar'' then form1.Memo1.Lines.Add(mypresschar);   如果你的调用主窗体就叫form1,则不用修改,否则把这两条语句的form1修改为你的调用主窗体的名字。   在 memo编辑框的onChange事件中编写自己的 键盘消息接受主控制过程,其中 字符串mypresschar 返回总键值,它跟memo编辑框中显示值是一样的 ,例如 g、shift g、ctrl 2、F9、alt F9、 等等,其中 字符串shiftstr 返回 控制键 shift ctrl alt 的状态,例如按下ctrl,则 shiftstr=‘ctrl’ ,否则=''。   最后不要忘记在程序退出时卸载键盘钩子

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧