C# 中的 SetWindowsHookEx
-
06-07-2019 - |
题
我正在尝试连接第 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中实现全局挂钩。“
我相信你需要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