我正在尝试连接第 3 方应用程序,以便我可以在其屏幕上绘图。绘制到屏幕上很容易,我不需要任何帮助,但我似乎在使用时遇到问题 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;
    }
}
有帮助吗?

解决方案

设置WindowsHookEx 因此指定最后两个参数:

  • hMod

IN]将dll的句柄包含LPFN参数指向的挂钩过程。如果DWThreadID参数指定当前过程创建的线程,以及挂钩过程是否在与当前过程关联的代码中,则必须将HMOD参数设置为null。

  • dwThreadId

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

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

抓住 hMod 通过 Marshal.GetHINSTANCE(typeof(Form1).Module)dwThreadId 通过 进程.线程. 。或者,设置 dwThreadId 如果你想要一个全局钩子(即所有人的钩子 GetMessage() 在当前桌面中调用)但要注意性能损失。

其他提示

以下表明这不起作用:

  

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

来自“如何在Visual C#.NET中设置Windows挂钩”

我相信你需要P / Invoke < code> GetModuleHandle 并使用它为 SetWindowsHookEx 的第三个参数返回的句柄。我还认为 0 对于第四个参数是正确的,因为您不想挂钩第三方应用程序中的任何一个特定线程。

如果这对您不起作用,请 MSDN上的 SetWindowsHookEx 可能会指向正确的方向。

我不知道,但如果你正在使用指定你想要的参数值,就像API帮助说的那样,“将DLL注入另一个进程”,那么对于所有我知道它只有你可能才有效编写一个非托管DLL,从中调用它。

我知道这是一个老问题,但我希望还有人会发现这个有用。我认为你混淆了 int IntPtr

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

这项工作对我来说使用13 ...

 private static IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(13, proc,
                GetModuleHandle(curModule.ModuleName), 0);
            }
        }
  internal enum HookType : uint {
    WH_JOURNALRECORD = 0,
    WH_JOURNALPLAYBACK = 1,
    WH_KEYBOARD = 2,
    WH_GETMESSAGE = 3,
    WH_CALLWNDPROC = 4,
    WH_CBT = 5,
    WH_SYSMSGFILTER = 6,
    WH_MOUSE = 7,
    WH_HARDWARE = 8,
    WH_DEBUG = 9,
    WH_SHELL = 10,
    WH_FOREGROUNDIDLE = 11,
    WH_CALLWNDPROCRET = 12,
    WH_KEYBOARD_LL = 13,
    WH_MOUSE_LL = 14
  }

.NET Framework不支持全局挂钩

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

要安装全局钩子,钩子必须具有本机DLL导出,以将自身注入另一个需要有效,一致的函数调用的进程中。此行为需要DLL导出。

.NET Framework不支持DLL导出。托管代码没有函数指针的一致值的概念,因为这些函数指针是动态构建的代理。

在安装挂钩的线程上调用低级挂钩过程。低级挂钩不要求在DLL中实现挂钩过程。

另见: Snoop - WPF间谍实用程序

或者我的WPF =&gt; WF =&gt; Win32 LL_Keyboard Hook Proxy w / Gestures

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top