HOW TO:在 Visual C# .NET 中设置窗口挂钩(转载)

本文以鼠标挂钩为例,介绍如何设置特定于某个线程的挂钩和特定于某个挂钩过程的挂钩。您可以使用挂钩监视特定类型的事件。您可以将这些事件作为一个调用线程与一个特定的线程或同一桌面中的所有的线程关联起来。



设置鼠标挂钩

若要设置挂钩,请从 User32.dll 文件中调用 SetWindowsHookEx 函数。此函数可将一个应用程序定义的挂钩过程安装到与此挂钩关联的挂钩链中。

若要设置一个鼠标挂钩并监视鼠标事件,请按照以下步骤操作:
  1. 启动 Microsoft Visual Studio .NET。
  2. 文件菜单上,指向新建,然后单击项目
  3. 新建项目对话框中,单击项目类型下的 Visual C# 项目,然后单击模板下的 Windows 应用程序。在名称框中键入 ThreadSpecificMouseHook。默认情况下将 Form1 添加到项目中。
  4. 将下面的代码行添加到 Form1.cs 文件中的其他 using 语句后面。
    using System.Runtime.InteropServices;
  5. Form1 类中添加以下代码:
    public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

    //Declare hook handle as int.
    static int hHook = 0;

    //Declare mouse hook constant.
    //For other hook types, you can obtain these values from Winuser.h in Microsoft SDK.
    public const int WH_MOUSE = 7;
    private System.Windows.Forms.Button button1;

    //Declare MouseHookProcedure as HookProc type.
    HookProc MouseHookProcedure;

    //Declare wrapper managed POINT class.
    [StructLayout(LayoutKind.Sequential)]
    public class POINT
    {
    public int x;
    public int y;
    }

    //Declare wrapper managed MouseHookStruct class.
    [StructLayout(LayoutKind.Sequential)]
    public class MouseHookStruct
    {
    public POINT pt;
    public int hwnd;
    public int wHitTestCode;
    public int dwExtraInfo;
    }

    //Import for SetWindowsHookEx function.
    //Use this function to install thread-specific hook.
    [DllImport("user32.dll",CharSet=CharSet.Auto,
    CallingConvention=CallingConvention.StdCall)]
    public static extern int SetWindowsHookEx(int idHook, HookProc lpfn,
    IntPtr hInstance, int threadId);

    //Import for UnhookWindowsHookEx.
    //Call this function to uninstall the hook.
    [DllImport("user32.dll",CharSet=CharSet.Auto,
    CallingConvention=CallingConvention.StdCall)]
    public static extern bool UnhookWindowsHookEx(int idHook);

    //Import for CallNextHookEx.
    //Use this function to pass the hook information to next hook procedure in chain.
    [DllImport("user32.dll",CharSet=CharSet.Auto,
    CallingConvention=CallingConvention.StdCall)]
    public static extern int CallNextHookEx(int idHook, int nCode,
    IntPtr wParam, IntPtr lParam);
  6. 向窗体添加 Button 控件,然后将下面的代码添加到 Button1_click 过程:
    private void button1_Click(object sender, System.EventArgs e)
    {
    if(hHook == 0)
    {
    // Create an instance of HookProc.
    MouseHookProcedure = new HookProc(Form1.MouseHookProc);

    hHook = SetWindowsHookEx(WH_MOUSE,
    MouseHookProcedure,
    (IntPtr)0,
    AppDomain.GetCurrentThreadId());
    //If SetWindowsHookEx fails.
    if(hHook == 0 )
    {
    MessageBox.Show("SetWindowsHookEx Failed");
    return;
    }
    button1.Text = "UnHook Windows Hook";
    }
    else
    {
    bool ret = UnhookWindowsHookEx(hHook);
    //If UnhookWindowsHookEx fails.
    if(ret == false )
    {
    MessageBox.Show("UnhookWindowsHookEx Failed");
    return;
    }
    hHook = 0;
    button1.Text = "Set Windows Hook";
    this.Text = "Mouse Hook";
    }
    }
  7. Form1 类中为 MouseHookProc 函数添加下面的代码:
    public static int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
    {
    //Marshall the data from callback.
    MouseHookStruct MyMouseHookStruct = (MouseHookStruct) Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));

    if (nCode < 0)
    {
    return CallNextHookEx(hHook, nCode, wParam, lParam);
    }
    else
    {
    //Create a string variable with shows current mouse. coordinates
    String strCaption = "x = " +
    MyMouseHookStruct.pt.x.ToString("d") +
    " y = " +
    MyMouseHookStruct.pt.y.ToString("d");
    //Need to get the active form because it is a static function.
    Form tempForm = Form.ActiveForm;

    //Set the caption of the form.
    tempForm.Text = strCaption;
    return CallNextHookEx(hHook, nCode, wParam, lParam);
    }
    }
  8. 按 F5 键运行此项目,然后单击窗体上的按钮以设置此挂钩。当指针在窗体上移动时,鼠标坐标将出现在窗体标题栏上。再次单击此按钮可删除此挂钩。

在 .NET 框架中不支持全局挂钩

您无法在 Microsoft .NET 框架中实现全局挂钩。若要安装全局挂钩,挂钩必须有一个本机动态链接库 (DLL) 导出以便将其本身插入到另一个需要调入一个有效而且一致的函数的进程中。这需要一个 DLL 导出,而 .NET 框架不支持这一点。托管代码没有让函数指针具有统一的值这一概念,因为这些函数是动态构建的代理。

 

 有关窗口挂钩的更多信息,请参见下面的 MSDN 文档:

About Hooks
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/hooks_9rg3.asp (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/hooks_9rg3.asp)

 

 原文:http://support.microsoft.com/kb/318804/

posted @ 2009-07-17 09:50  Alexander  阅读(442)  评论(0编辑  收藏  举报