博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#强化系列文章二:在C#中使用钩子
阅读量:5774 次
发布时间:2019-06-18

本文共 3100 字,大约阅读时间需要 10 分钟。

相信以前用过VB、Delphi,特别是VC的程序员应该对钩子程序都不陌生。在C#中我们同样可以使用钩子程序来实现特殊效果,比如当用户按下某个特殊键时提示,比如关闭应用程序前提示等。

当然使用方法相对VC来说要稍微复杂一点,有的地方还不太方便,下面的例子中实现两个基本功能:
1、按下Alt+F4时使窗口最小化
2、关闭应用程序前提示
不过目前只能捕获消息,不能屏蔽消息,我正在实验,也希望知道的高手能多多指教
一、加入winuser.h中的定义
因为钩子程序一般情况下都是在vc下使用的,在c#里面并没有对应的方法、结构等的定义,我们首先需要把winuser.h中的相关定义加入自己的类

钩子类型的枚举
具体的说明在msdn中都可以查到,主要的比如WH_KEYBOARD是监控按键事件,WH_CALLWNDPROC是在消息触发时执行


虚键值的定义
这个不用说明了,对应ALT、CTRL等键


消息结构体
这个是windows内部传递过来的消息的结构


二、加入自己定义的委托和事件参数

钩子委托
HokkProc是
SetWindowsHookEx
调用时的委托事件,HookEventHandler是自己的委托事件

钩子事件参数
是自己的委托事件中接受的事件参数


三、实现自己的钩子类

这一步是最重要的,要使用钩子,我们需要引用
user32.dll
中的相应方法:

        [DllImport(
"
user32.dll
"
)]
        
static
 
extern
 IntPtr SetWindowsHookEx(HookType hook, HookProc callback, IntPtr hMod, 
uint
 dwThreadId);
        [DllImport(
"
user32.dll
"
)]
        
static
 
extern
 
bool
 UnhookWindowsHookEx(IntPtr hhk);
        [DllImport(
"
user32.dll
"
)]
        
static
 
extern
 
int
 CallNextHookEx(IntPtr hhk, 
int
 nCode, IntPtr wParam, IntPtr lParam);
        [DllImport(
"
user32.dll
"
)]
        
static
 
extern
 
short
 GetKeyState(VirtualKeys nVirtKey);
SetWindowsHookEx
是注册一个钩子程序,
UnhookWindowsHookEx
是释放钩子程序,
CallNextHookEx
调用钩子的后续事件处理,
GetKeyState
得到所按的虚键


然后就可以调用这些方法来实现钩子程序,比如注册一个钩子可以调用:

            m_hook 
=
 SetWindowsHookEx(m_hooktype, m_hookproc, IntPtr.Zero, (
uint
)AppDomain.GetCurrentThreadId());
其中m_hooktype就是
HookType
中定义的类型,m_hookproc就是实际的钩子处理程序:

m_hookproc 
=
 
new
 HookProc(KeyHookProcedure);

最关键的就是
KeyHookProcedure
等钩子处理程序:

        
protected
 
int
 KeyHookProcedure(
int
 code, IntPtr wParam, IntPtr lParam)
        
{
            
if
 (code 
!=
 
0
)
            
{
                
return
 CallNextHookEx(m_hook, code, wParam, lParam);
            }
            
if
 (HookInvoked 
!=
 
null
)
            
{
                Keys key 
=
 (Keys)wParam.ToInt32();
                HookEventArgs eventArgs 
=
 
new
 HookEventArgs();
                eventArgs.key 
=
 key;
                eventArgs.lParam 
=
 lParam;
                eventArgs.wParam 
=
 wParam;
                eventArgs.HookCode 
=
 code;
                eventArgs.bAltKey 
=
 GetKeyState(VirtualKeys.VK_MENU) 
<=
 
-
127
;
                eventArgs.bCtrlKey 
=
 GetKeyState(VirtualKeys.VK_CONTROL) 
<=
 
-
127
;
                HookInvoked(this, eventArgs);
            }
            
return
 CallNextHookEx(m_hook, code, wParam, lParam);
        }
在这个事件中可以取得消息的参数,特别是按键的值,然后通过HookInvoked委托调用事件实际的处理程序


四、在应用程序中调用钩子类
我们可以在自己的form中声明两个钩子对象

        
private
 MyHook callProcHook 
=
 
new
 MyHook(HookType.WH_CALLWNDPROC);
        
private
 MyHook keyHook 
=
 
new
 MyHook(HookType.WH_KEYBOARD);
然后在初始化时注册钩子:

        
private
 
void
 Form1_Load(
object
 sender, EventArgs e)
        
{
            keyHook.HookInvoked 
+=
 
new
 HookEventHandler(keyHook_HookInvoked);
            keyHook.Install();
            callProcHook.HookInvoked 
+=
 
new
 HookEventHandler(callProcHook_HookInvoked);
            callProcHook.Install();
        }

然后就是实际的钩子事件:

        
private
 
void
 keyHook_HookInvoked(
object
 sender, HookEventArgs e)
        
{
            
if
 (e.key 
==
 Keys.F4 
&&
 e.bAltKey) 
//
Alt + F4
            
{
                
this
.WindowState 
=
 FormWindowState.Minimized;
            }
        }
        
private
 
void
 callProcHook_HookInvoked(
object
 sender, HookEventArgs e)
        
{
            
unsafe
            
{
                CWPSTRUCT
*
 message 
=
 (CWPSTRUCT
*
)e.lParam;
                
if
 (message 
!=
 
null
)
                
{
                    
if
 (message
->
message 
==
 WM_CLOSE)
                    
{
                        (sender 
as
 MyHook).CallNextProc 
=
 
false
;
                        MessageBox.Show(
"
程序即将关闭!
"
);
                    }
                }
            }
        }

这样我们就可以通过钩子实现一些相对底层的应用。

代码说的有点乱,我就把最主要的代码直接列在下面供大家参考:

例子代码

以上的钩子只对当前应用程序起作用,如果想控制其他的所有程序,需要使用全局钩子。原则上全局钩子在C#中是不支持的,在 中的代码可以参照来实现全局钩子

    本文转自永春博客园博客,原文链接:http://www.cnblogs.com/firstyi/archive/2008/01/08/1030761.html,如需转载请自行联系原作者

你可能感兴趣的文章
java工程师linux命令,这篇文章就够了
查看>>
关于React生命周期的学习
查看>>
webpack雪碧图生成
查看>>
搭建智能合约开发环境Remix IDE及使用
查看>>
Spring Cloud构建微服务架构—服务消费基础
查看>>
RAC实践采坑指北
查看>>
runtime运行时 isa指针 SEL方法选择器 IMP函数指针 Method方法 runtime消息机制 runtime的使用...
查看>>
LeetCode36.有效的数独 JavaScript
查看>>
Scrapy基本用法
查看>>
PAT A1030 动态规划
查看>>
自制一个 elasticsearch-spring-boot-starter
查看>>
软件开发学习的5大技巧,你知道吗?
查看>>
java入门第二季--封装--什么是java中的封装
查看>>
【人物志】美团前端通道主席洪磊:一位产品出身、爱焊电路板的工程师
查看>>
一份关于数据科学家应该具备的技能清单
查看>>
机器学习实战_一个完整的程序(一)
查看>>
Web框架的常用架构模式(JavaScript语言)
查看>>
如何用UPA优化性能?先读懂这份报告!
查看>>
这些Java面试题必须会-----鲁迅
查看>>
Linux 常用命令
查看>>