C# 系统钩子怎么用

deyter 2009-01-07 04:06:51
上网找了许久,大部分都是转来转去的,我用了却不能实现全局hook,
是不是全局hook和局部hook就是SetWindowsHookEx函数的第四个参数不同,全局的是0?
还有什么要注意的啊!?搞了半天没有搞出全局hook,
谢谢指教!
3Q!
...全文
1828 29 打赏 收藏 转发到动态 举报
写回复
用AI写文章
29 条回复
切换为时间正序
请发表友善的回复…
发表回复
zj84604741 2012-01-10
  • 打赏
  • 举报
回复
牛贴, 一定顶
留个记号, 慢慢学习
wbd6572789 2010-08-27
  • 打赏
  • 举报
回复
真是牛人,学习中
jingzhongrong 2009-01-08
  • 打赏
  • 举报
回复
7楼那个不是全局钩子吧。

全局钩子需要dll,这样才能加载到其他进程的进程空间中。
可用C++写dll然后由C#来调用
yhy0611 2009-01-08
  • 打赏
  • 举报
回复
另外,借这个地方问个问题,不知道钩子是否可以用Windows服务来承载啊?

http://topic.csdn.net/u/20090108/10/00811ad9-af2c-47ac-9754-973e8b6d48da.html
yhy0611 2009-01-08
  • 打赏
  • 举报
回复

//以下是调用

private KeyboardHook k_hook;
private void HookForm_Load(object sender, EventArgs e)
{
try
{
if (this.buttonKeyHook.Text == "安装键盘钩子")
{
k_hook = new KeyboardHook();
k_hook.KeyDownEvent += new KeyEventHandler(hook_KeyDown);
k_hook.Start();
this.buttonKeyHook.Text = "卸载键盘钩子";
}else if(k_hook!=null)
{
k_hook.Stop();
this.buttonKeyHook.Text = "安装键盘钩子";
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

private void hook_KeyDown(object sender, KeyEventArgs e)
{
//自己写吧
}
yhy0611 2009-01-08
  • 打赏
  • 举报
回复
我也是在网上找的,可以实现全局钩子


/// <summary>
///键盘钩子
/// </summary>
public class KeyboardHook {

public event KeyEventHandler KeyDownEvent;
public event KeyPressEventHandler KeyPressEvent;
public event KeyEventHandler KeyUpEvent;

public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);


static int hKeyboardHook = 0; //声明键盘钩子处理的初始值。

//值在Microsoft SDK的Winuser.h里查询
public const int WH_KEYBOARD_LL = 13; //线程键盘钩子监听鼠标消息设为2,全局键盘监听鼠标消息设为13。

HookProc KeyboardHookProcedure; //声明KeyboardHookProcedure作为HookProc类型。



//键盘结构
[StructLayout(LayoutKind.Sequential)]
public class KeyboardHookStruct
{
public int vkCode; //定一个虚拟键码。该代码必须有一个价值的范围1至254 。
public int scanCode; // 指定的硬件扫描码的关键。
public int flags; // 键标志
public int time; // 指定的时间戳记的这个讯息。
public int dwExtraInfo; // 指定额外信息相关的信息。
}


//使用此功能,安装了一个钩子。
[DllImport("user32.dll",CharSet=CharSet.Auto,
CallingConvention=CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn,
IntPtr hInstance, int threadId);


//调用此函数卸载钩子。
[DllImport("user32.dll",CharSet=CharSet.Auto,
CallingConvention=CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);


//使用此功能,通过信息钩子继续下一个钩子
[DllImport("user32.dll",CharSet=CharSet.Auto,
CallingConvention=CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode,
Int32 wParam, IntPtr lParam);

// 取得当前线程编号(线程钩子需要用到)
[DllImport("kernel32.dll")]
static extern int GetCurrentThreadId();


public void Start()
{
// 安装键盘钩子
if(hKeyboardHook == 0)
{
KeyboardHookProcedure = new HookProc(KeyboardHookProc);
hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL,KeyboardHookProcedure, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),0);
//************************************
//键盘线程钩子
//SetWindowsHookEx( 2,KeyboardHookProcedure, IntPtr.Zero, GetCurrentThreadId());//指定要监听的线程idGetCurrentThreadId(),
//键盘全局钩子,需要引用空间(using System.Reflection;)
//SetWindowsHookEx( 13,MouseHookProcedure,Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),0);
//
//关于SetWindowsHookEx (int idHook, HookProc lpfn, IntPtr hInstance, int threadId)函数将钩子加入到钩子链表中,说明一下四个参数:
//idHook 钩子类型,即确定钩子监听何种消息,上面的代码中设为2,即监听键盘消息并且是线程钩子,如果是全局钩子监听键盘消息应设为13,
//线程钩子监听鼠标消息设为7,全局钩子监听鼠标消息设为14。lpfn 钩子子程的地址指针。如果dwThreadId参数为0 或是一个由别的进程创建的
//线程的标识,lpfn必须指向DLL中的钩子子程。 除此以外,lpfn可以指向当前进程的一段钩子子程代码。钩子函数的入口地址,当钩子钩到任何
//消息后便调用这个函数。hInstance应用程序实例的句柄。标识包含lpfn所指的子程的DLL。如果threadId 标识当前进程创建的一个线程,而且子
//程代码位于当前进程,hInstance必须为NULL。可以很简单的设定其为本应用程序的实例句柄。threaded 与安装的钩子子程相关联的线程的标识符。
//如果为0,钩子子程与所有的线程关联,即为全局钩子。
//************************************


//如果SetWindowsHookEx失败。
if(hKeyboardHook == 0 ) {
Stop();
throw new Exception("安装键盘钩子失败");
}
}
}

public void Stop()
{
bool retKeyboard = true;


if(hKeyboardHook != 0)
{
retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
hKeyboardHook = 0;
}

if (!(retKeyboard)) throw new Exception("卸载钩子失败!");
}



//ToAscii职能的转换指定的虚拟键码和键盘状态的相应字符或字符。
[DllImport("user32")]
public static extern int ToAscii(int uVirtKey, //[in] 指定虚拟关键代码进行翻译。
int uScanCode, // [in] 指定的硬件扫描码的关键须翻译成英文。高阶位的这个值设定的关键,如果是(不压) 。
byte[] lpbKeyState, // [in] 指针,以256字节数组,包含当前键盘的状态。每个元素(字节)的数组包含状态的一个关键。如果高阶位的字节是一套,关键是下跌(按下)。在低比特,如果设置表明,关键是对切换。在此功能,只有肘位的CAPS LOCK键是相关的。在切换状态的NUM个锁和滚动锁定键被忽略。
byte[] lpwTransKey, // [out] 指针的缓冲区收到翻译字符或字符。
int fuState); // [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise.

//获取按键的状态
[DllImport("user32")]
public static extern int GetKeyboardState(byte[] pbKeyState);

private const int WM_KEYDOWN = 0x100;//KEYDOWN
private const int WM_KEYUP = 0x101;//KEYUP
private const int WM_SYSKEYDOWN = 0x104;//SYSKEYDOWN
private const int WM_SYSKEYUP = 0x105;//SYSKEYUP

private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
// 侦听键盘事件
if ((nCode >= 0) && (KeyDownEvent != null || KeyUpEvent != null || KeyPressEvent != null))
{
KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct) Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
// raise KeyDown
if (KeyDownEvent != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
{
Keys keyData=(Keys)MyKeyboardHookStruct.vkCode;
KeyEventArgs e = new KeyEventArgs(keyData);
KeyDownEvent(this, e);
}

//键盘按下
if (KeyPressEvent != null && wParam == WM_KEYDOWN)
{
byte[] keyState = new byte[256];
GetKeyboardState(keyState);

byte[] inBuffer= new byte[2];
if (ToAscii(MyKeyboardHookStruct.vkCode,
MyKeyboardHookStruct.scanCode,
keyState,
inBuffer,
MyKeyboardHookStruct.flags)==1)
{
KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer[0]);
KeyPressEvent(this, e);
}
}

// 键盘抬起
if (KeyUpEvent != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
{
Keys keyData=(Keys)MyKeyboardHookStruct.vkCode;
KeyEventArgs e = new KeyEventArgs(keyData);
KeyUpEvent(this, e);
}

}

//如果返回1,则结束消息,这个消息到此为止,不再传递。
//如果返回0或调用CallNextHookEx函数则消息出了这个钩子继续往下传递,也就是传给消息真正的接受者
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}



~KeyboardHook()
{
Stop();
}

}

Deathsign 2009-01-08
  • 打赏
  • 举报
回复
C#只能做键盘和鼠标的全局钩子……
其他钩子都无法实现

但是可以手写C++的DLL然后C#调用也是可以的
tiger999 2009-01-08
  • 打赏
  • 举报
回复
http://www.codeproject.com/KB/cs/globalhook.aspx
lunat 2009-01-08
  • 打赏
  • 举报
回复
c#不能做全局钩子吧
据我所知,做全局钩子或者其它进程的线程钩子需要把钩子函数放在一个c++的dll里面

哦 在http://www.bitscn.com/dotnet/c/200806/142681.html 看到一篇 貌似真的实现了全局钩子

仔细看了下 你这个Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0])写的跟他写的不一样,
他是这样写的:
Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().ManifestModule)
journeydj 2009-01-08
  • 打赏
  • 举报
回复
不会这个,帮顶
deyter 2009-01-08
  • 打赏
  • 举报
回复
怎么没有人回答我啊,我问的太白痴了吗?
确实搞不懂啊!
yhy0611 2009-01-08
  • 打赏
  • 举报
回复
我的代码也是D的,感谢作者^_^
jingzhongrong 2009-01-08
  • 打赏
  • 举报
回复
MSDN:
The keyboard input can come from the local keyboard driver or from calls to the keybd_event function. If the input comes from a call to keybd_event, the input was "injected". However, the WH_KEYBOARD_LL hook is not injected into another process. Instead, the context switches back to the process that installed the hook and it is called in its original context. Then the context switches back to the application that generated the event.
deyter 2009-01-08
  • 打赏
  • 举报
回复
谢谢大家了,7楼的确实可行!
whitechololate 2009-01-08
  • 打赏
  • 举报
回复
Mark!~

up
mawering 2009-01-08
  • 打赏
  • 举报
回复
帮顶了,跟着学一下!
qq289014458 2009-01-08
  • 打赏
  • 举报
回复
up!~!
yhy0611 2009-01-08
  • 打赏
  • 举报
回复
为什么我的贴子就没有这个火呀。。。。。。。

再做一次广告!

http://topic.csdn.net/u/20090108/10/00811ad9-af2c-47ac-9754-973e8b6d48da.html
yhy0611 2009-01-08
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 deyter 的回复:]
引用 15 楼 yhy0611 的回复:
引用 11 楼 jingzhongrong 的回复:
7楼那个不是全局钩子吧。

全局钩子需要dll,这样才能加载到其他进程的进程空间中。
可用C++写dll然后由C#来调用


全局钩子是不是指能捕获到其它进程的消息?如果是的话,这个就是全局的了,我试过了

7楼的跟我在网上找的全局钩子差不多,就是某人写的软键盘。
但是我参照写的就死不能捕获到其他进程,yhy0611 你怎么实现的啊?
把前部分弄成…
[/Quote]

这个确实是在网上找的,但我确实可以捕获到其它进程的消息。我自己试着改了一下,也完全可以,如果你要代码就加我QQ103630333

我现在正在找资料,想把钩子放到Windows服务中,试了半天也不行,不知道jingzhongrong 有没有什么办法?
deyter 2009-01-08
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 yhy0611 的回复:]
引用 11 楼 jingzhongrong 的回复:
7楼那个不是全局钩子吧。

全局钩子需要dll,这样才能加载到其他进程的进程空间中。
可用C++写dll然后由C#来调用


全局钩子是不是指能捕获到其它进程的消息?如果是的话,这个就是全局的了,我试过了
[/Quote]
7楼的跟我在网上找的全局钩子差不多,就是某人写的软键盘。
但是我参照写的就死不能捕获到其他进程,yhy0611 你怎么实现的啊?
把前部分弄成dll,然后在应用程序里调用dll里的KeyDownEvent 事件,是吗?
为什么我的不可以?
加载更多回复(8)

110,925

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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