FW: http://www.cnblogs.com/michaelxu/archive/2006/09/22/511557.html
[DllImport(
"
user32.dll
"
, CharSet
=
CharSet.Auto,
CallingConvention
=
CallingConvention.StdCall, SetLastError
=
true
)]
private
static
extern
int
SetWindowsHookEx(
int
idHook,
HookProc lpfn,
IntPtr hMod,
int
dwThreadId);

[DllImport(
"
user32.dll
"
, CharSet
=
CharSet.Auto,
CallingConvention
=
CallingConvention.StdCall, SetLastError
=
true
)]
private
static
extern
int
UnhookWindowsHookEx(
int
idHook);

[DllImport(
"
user32.dll
"
, CharSet
=
CharSet.Auto,
CallingConvention
=
CallingConvention.StdCall)]
private
static
extern
int
CallNextHookEx(
int
idHook,
int
nCode,
int
wParam,
IntPtr lParam);
下面是有关这两个low-level hook在Winuser.h中的定义:
/// <summary>
/// Windows NT/2000/XP: Installs a hook procedure that monitors low-level mouse input events.
/// </summary>
private
const
int
WH_MOUSE_LL
=
14
;
/// <summary>
/// Windows NT/2000/XP: Installs a hook procedure that monitors low-level keyboard input events.
/// </summary>
private
const
int
WH_KEYBOARD_LL
=
13
;
在安装全局钩子的时候,我们就要做替换了,将WH_MOUSE和WH_KEYBORAD分别换成WH_MOUSE_LL和WH_KEYBORAD_LL:
//
install hook
hMouseHook
=
SetWindowsHookEx(
WH_MOUSE_LL,
//
原来是WH_MOUSE
MouseHookProcedure,
Marshal.GetHINSTANCE(
Assembly.GetExecutingAssembly().GetModules()[
0
]),
0
);

//
install hook
hKeyboardHook
=
SetWindowsHookEx(
WH_KEYBOARD_LL,
//
原来是WH_KEYBORAD
KeyboardHookProcedure,
Marshal.GetHINSTANCE(
Assembly.GetExecutingAssembly().GetModules()[
0
]),
0
);
下面是关于鼠标和键盘的两个Callback函数:
private
int
MouseHookProc(
int
nCode,
int
wParam, IntPtr lParam)
{
// if ok and someone listens to our events
if ((nCode >= 0) && (OnMouseActivity != null))
{
//Marshall the data from callback.
MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));

//detect button clicked
MouseButtons button = MouseButtons.None;
short mouseDelta = 0;
switch (wParam)
{
case WM_LBUTTONDOWN:
//case WM_LBUTTONUP:
//case WM_LBUTTONDBLCLK:
button = MouseButtons.Left;
break;
case WM_RBUTTONDOWN:
//case WM_RBUTTONUP:
//case WM_RBUTTONDBLCLK:
button = MouseButtons.Right;
break;
case WM_MOUSEWHEEL:
//If the message is WM_MOUSEWHEEL, the high-order word of mouseData member is the wheel delta.
//One wheel click is defined as WHEEL_DELTA, which is 120.
//(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value
mouseDelta = (short)((mouseHookStruct.mouseData >> 16) & 0xffff);
//TODO: X BUTTONS (I havent them so was unable to test)
//If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP,
//or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released,
//and the low-order word is reserved. This value can be one or more of the following values.
//Otherwise, mouseData is not used.
break;
}

//double clicks
int clickCount = 0;
if (button != MouseButtons.None)
if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK) clickCount = 2;
else clickCount = 1;

//generate event
MouseEventArgs e = new MouseEventArgs(
button,
clickCount,
mouseHookStruct.pt.x,
mouseHookStruct.pt.y,
mouseDelta);
//raise it
OnMouseActivity(this, e);
}
//call next hook
return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}
private
int
KeyboardHookProc(
int
nCode, Int32 wParam, IntPtr lParam)
{
//indicates if any of underlaing events set e.Handled flag
bool handled = false;
//it was ok and someone listens to events
if ((nCode >= 0) && (KeyDown != null || KeyUp != null || KeyPress != null))
{
//read structure KeyboardHookStruct at lParam
KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
//raise KeyDown
if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
{
Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
KeyEventArgs e = new KeyEventArgs(keyData);
KeyDown(this, e);
handled = handled || e.Handled;
}

// raise KeyPress
if (KeyPress != null && wParam == WM_KEYDOWN)
{
bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true : false);
bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);

byte[] keyState = new byte[256];
GetKeyboardState(keyState);
byte[] inBuffer = new byte[2];
if (ToAscii(MyKeyboardHookStruct.vkCode,
MyKeyboardHookStruct.scanCode,
keyState,
inBuffer,
MyKeyboardHookStruct.flags) == 1)
{
char key = (char)inBuffer[0];
if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);
KeyPressEventArgs e = new KeyPressEventArgs(key);
KeyPress(this, e);
handled = handled || e.Handled;
}
}

// raise KeyUp
if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
{
Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
KeyEventArgs e = new KeyEventArgs(keyData);
KeyUp(this, e);
handled = handled || e.Handled;
}

}

//if event handled in application do not handoff to other listeners
if (handled)
return 1;
else
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
参考资料:MSDN
FW: http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b318804
<script type="text/javascript"> var sectionFilter = "type != 'notice' && type != 'securedata' && type != 'querywords'"; var tocArrow = "/library/images/support/kbgraphics/public/en-us/downarrow.gif"; var depthLimit = 10; var depth3Limit = 10; var depth4Limit = 5; var depth5Limit = 3; var tocEntryMinimum = 1; </script> <script type="text/javascript" src="/common/script/gsfx/kbtoc.js?9"></script>
To set a mouse hook and to monitor the mouse events, follow these steps:
Low-level hook procedures are called on the thread that installed the hook. Low-level hooks do not require that the hook procedure be implemented in a DLL.
今天,有个同事问我,怎样在C#中使用全局钩子?以前写的全局钩子都是用unmanaged C或C++写个DLL来实现,可大家都知道,C#是基于.Net Framework的,是managed,怎么实现全局钩子呢?于是开始到网上搜索,好不容易找到一篇,318804 - HOW TO: Set a Windows Hook in Visual C# .NET,里面详细的说明了如何使用鼠标钩子捕获鼠标的移动等,可是,它只能在Application里起作用,出了Application就没用了,就是说它还是没有实现全局钩子,而且文章结尾处说:“Global Hooks are not supported in the .NET Framework...”,这可怎么办呢?
别担心,办法总是有的,经过一番摸索以后,发现WH_KEYBORAD_LL和WH_MOUSE_LL这两个low-level的hook可以被安装成全局的,这就好办了,我们不妨用这两个low-level的hook替换掉WH_KEYBORAD和WH_MOUSE,于是开始测试。结果成功了,在C#里实现了全局钩子。
我们来看一下主要代码段。
首先倒入所需要的windows函数,主要有三个,SetWindowsHookEX用来安装钩子,UnhookWindowsHookEX用来卸载钩子以及CallNextHookEX用来将hook信息传递到链表中下一个hook处理过程。



















下面是有关这两个low-level hook在Winuser.h中的定义:








在安装全局钩子的时候,我们就要做替换了,将WH_MOUSE和WH_KEYBORAD分别换成WH_MOUSE_LL和WH_KEYBORAD_LL:















这样替换了之后,我们就可以实现全局钩子了,而且,不需要写DLL。看一下程序运行情况:

下面是关于鼠标和键盘的两个Callback函数:


















































































































参考资料:MSDN
FW: http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b318804
How to set a Windows hook in Visual C# .NET
<script type="text/javascript">function loadTOCNode(){}</script>Article ID | : | 318804 |
Last Review | : | December 11, 2006 |
Revision | : | 3.1 |
This article was previously published under Q318804
For a Microsoft Visual Basic version of this article, see
319524
(http://support.microsoft.com/kb/319524/).
On This Page
Introduction
<script type="text/javascript">loadTOCNode(1, 'summary');</script>
This article describes how to set a hook that is specific to a thread and to a hook procedure by using the mouse hook as an example. You can use hooks to monitor certain types of events. You can associate these events with a specific thread or with all the threads in the same desktop as a calling thread.
MORE INFORMATION
<script type="text/javascript">loadTOCNode(1, 'moreinformation');</script>Set a mouse hook
<script type="text/javascript">loadTOCNode(2, 'moreinformation');</script> To set a hook, call the SetWindowsHookEx function from the User32.dll file. This function installs an application-defined hook procedure in the hook chain that is associated with the hook.To set a mouse hook and to monitor the mouse events, follow these steps:
1. | Start Microsoft Visual Studio .NET. |
2. | On the File menu, point to New, and then click Project. |
3. | In the New Project dialog box, click Visual C# Projects under Project Types, and then click Windows Application under Templates. In the Name box, type ThreadSpecificMouseHook. By default, a form that is named Form1 is created. |
4. | Add the following line of code in the Form1.cs file after the other using statements. using System.Runtime.InteropServices; |
5. | Add following code in the Form1 class. public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam); |
6. | Add a Button control to the form, and then add the following code in the Button1_click procedure. private void button1_Click(object sender, System.EventArgs e) |
7. | Add the following code for the MouseHookProc function in the Form1 class. public static int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam) |
8. | Press F5 to run the project. Click the button on the form to set the hook. The mouse coordinates appear on the form caption bar when the pointer moves on the form. Click the button again to remove the hook. |
Global hooks are not supported in the .NET Framework
<script type="text/javascript">loadTOCNode(2, 'moreinformation');</script> Except for the WH_KEYBOARD_LL low-level hook and the WH_MOUSE_LL low-level hook, you cannot implement global hooks in the Microsoft .NET Framework. To install a global hook, a hook must have a native DLL export to inject itself in another process that requires a valid, consistent function to call into. This behavior requires a DLL export. The .NET Framework does not support DLL exports. Managed code has no concept of a consistent value for a function pointer because these function pointers are proxies that are built dynamically.Low-level hook procedures are called on the thread that installed the hook. Low-level hooks do not require that the hook procedure be implemented in a DLL.
REFERENCES
<script type="text/javascript">loadTOCNode(1, 'references');</script>
For more information about hooks, visit the following Microsoft Developer Network (MSDN) Web site:
http://msdn.microsoft.com/library/en-us/winui/WinUI/WindowsUserInterface/Windowing/Hooks/AboutHooks.asp
(http://msdn.microsoft.com/library/en-us/winui/WinUI/WindowsUserInterface/Windowing/Hooks/AboutHooks.asp)