WindowsAPI钩子程序入门

C#钩子程序入门

简介

现在网络上涉及到钩子程序入门,基本都是以三个基础概念:装载钩子程序,卸载钩子程序,以及回调。但是,本文却不会以这些为出发点,前面的三个概念确实是钩子程序中的重要部分,但对于入门而言,有时是难以理解的(至少本人之前很长时间在这个上面一直是糊里糊涂的,还是后来突然有所明悟 —— 这个看个人,可能有些人一开始就明白了,就像大学里学C语言一样。)。所以本文以个人入门时,最早接触的几个概念来进行描述。

主要函数/API接口

本文主要涉及三个函数/API接口:FindWindow、FindWindowEx、SendMessage。前两个是查找窗体,并返回句柄;最后一个则是消息发送。

注,进行下面内容时,可以利用SPY++工具辅助理解。

FindWindow

FindWindow查找最顶层的窗口句柄,即父窗口为null。并且如果有多个匹配结果,则它只返回最先查找到的结果。

用法 —— 以记事本为例:

[DllImport("user32.dll", EntryPoint = "FindWindow")]
private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);

IntPtr ParenthWnd = FindWindow(null,"无标题 - 记事本"); //方法1
ParentWnd = FindWindow("Notepad", null); //方法2

参数:第一个参数为待查找的窗口类;第二个参数为窗口标题。如果查找到窗口,则返回窗口句柄,否则返回0。上述代码中的方法1和方法2在本示例中效果是一样的。

注意:在函数中的两个参数关系是同时匹配。如果你只需要匹配类或者窗体名称,则另一个参数需设置为null。

FindWindowEx

用于查找窗口中的子窗口句柄,如窗口内部的各种控件。

引入:

[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

参数:第一个参数为父级窗口,第二个参数为同级窗口的前一个窗口句柄,第三个为窗口类,第四个为窗口标题。

注:如果第一个和第二个参数均设置为IntPtr.Zero,则其效果等同于FindWindow。

SendMessage

用于向指定的窗体句柄上发送消息,如设置文本、鼠标按下等消息。

引入:

[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(IntPtr hWnd, int Msg, string wParam, string lParam);

参数:第一个参数为待发送消息的窗口句柄,第二个为待发送的消息类型,后两个为附加参数,其设置与第二个参数相关联。上述引入时,后两个参数为string类型,但其并不固定,你可以将其处理为object类型。具体内容在遇到时,在进行说明。

另有一个与SendMessage相似的函数 —— PostMessage,不过相对来说SendMessage使用的更多,因为它看起来比较负责任。从比较专业(网络协议)的方面来解释就像:PostMessage像UDP协议,TCP像TCP协议;而比较通俗的讲,以送快递为例,PostMessage是送到代理点就表示送到了,而SendMessage则表示送到家并且要明确签收才行,所以在这上面就可以看出,SendMessage更加负责任。

关于第二个参数,有很多消息类型,具体可以查看:https://msdn.microsoft.com/zh-cn/library/ms644927.aspx
或者查看:http://git.oschina.net/huaxia283611/codes/mtgvh1q4ero7uwk38c25b84 —— 注释不完整,逐步完善

上述函数使用操作步骤

本小节简要介绍如何使用上述函数。

添加相关引用

在使用windows api的类中添加如下引用:

using System.Runtime.InteropServices;

即添加DllImport相关的引用。

函数导入

使用DllImport导入相关函数,如导入FindWindow:

[DllImport("user32.dll", EntryPoint = "FindWindow")]
private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);

其中导入函数修饰符使用extern static。另使用特性(Attribute)修饰 —— DllImport。第一个参数为相关的dll,此处使用user32.dll,但在某些平台上需要使用coredll.dll;第二个参数EntryPoint为相关dll中的函数签名,如果你的函数定义与其一致,则此参数可以省略,不一致则必须,如下面两句导入,均可使用 —— 不过为了维护管理方便,常常保持一致:

[DllImport("user32.dll")]
private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll", EntryPoint = "FindWindow")]
private extern static IntPtr MyFindWindow(string lpClassName, string lpWindowName);

上面完成后,即可调用,方式如调用其他静态方法一样。

至此,入门内容介绍完了,其中主要包含了查找窗体后设置子窗体内容的基本操作。

参考

以下为微软官方相关文档参考: