C#中的SetWindowsHookEx

Dar*_*g8r 10 c# setwindowshookex wm-paint

我正试图挂钩第三方应用程序,以便我可以绘制到它的屏幕.在屏幕上绘图是容易的,我需要它没有帮助,但我似乎有使用问题SetWindowsHookEx来处理WH_GETMESSAGE.我无法弄清楚最后两个参数传递的内容.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowDrawer
{
    public partial class Form1 : Form
    {
        private delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
        static IntPtr hHook;
        IntPtr windowHandle;
        uint processHandle;

        HookProc PaintHookProcedure;     

        [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
        static extern System.IntPtr FindWindowByCaption(int ZeroOnly, string lpWindowName);

        [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SetWindowsHookEx", SetLastError = true)]
        static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        // When you don't want the ProcessId, use this overload and pass IntPtr.Zero for the second parameter
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

        [System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet =System.Runtime.InteropServices.CharSet.Auto)]
        public static extern IntPtr GetModuleHandle(string lpModuleName);

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        { 
            PaintHookProcedure = new HookProc(PaintHookProc);
            windowHandle = FindWindowByCaption(0, "Untitled - Notepad");
            uint threadID = GetWindowThreadProcessId(windowHandle, out processHandle);
            IntPtr hMod = System.Runtime.InteropServices.Marshal.GetHINSTANCE(typeof(Form1).Module);

            // HERE IS THE PROBLEM.  WHAT THE HECK DO I PASS INTO THE LAST 2 PARAMS?  I get a null pointer
            hHook = SetWindowsHookEx(WH_GETMESSAGE, PaintHookProcedure, hMod, threadID);
        }

        public int PaintHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
           // Do some painting here.
            return CallNextHookEx(hHook, nCode, wParam, lParam); 
        }

        private const int WM_PAINT = 15;
        private const int WH_GETMESSAGE = 3;
    }
}
Run Code Online (Sandbox Code Playgroud)

Kev*_*ose 15

SetWindowsHookEx具体地说明了最后两个参数:

  • hMod

[in]处理包含lpfn参数指向的钩子过程的DLL.如果dwThreadId参数指定当前进程创建的线程,并且钩子过程位于与当前进程关联的代码内,则必须将hMod参数设置为NULL.

  • dwThreadId

[in]指定与钩子过程关联的线程的标识符.如果此参数为零,则挂钩过程与在与调用线程相同的桌面中运行的所有现有线程关联.

我不确定您是否可以按照所需的方式使用.NET dll,但您当然可以尝试.

抓住hMod通过Marshal.GetHINSTANCE(typeof运算(Form1上).Module)dwThreadId通过Process.Threads.或者,dwThreadId如果您想要一个全局挂钩(即GetMessage()当前桌面中所有调用的挂钩),则设置为0,但要注意性能损失.

  • 并且通过GetLastError()我的意思是Marshal.GetLastWin32Error(); p /直接调用GetLastError()是不可靠的. (3认同)

Bil*_*lVo 9

以下表明这不起作用:

".NET Framework不支持全局挂钩.除了WH_KEYBOARD_LL低级别挂钩和WH_MOUSE_LL低级别挂钩之外,您无法在Microsoft .NET Framework中实现全局挂钩."

"如何在Visual C#.NET中设置Windows挂钩"