在 C# 中设置 WindowsHookEx
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1811383/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
SetWindowsHookEx in C#
提问by Darthg8r
I'm trying to hook a 3rd party app so that I can draw to its screen. Drawing to the screen is easy, and I need no help with it, but I seem to be having issues with using SetWindowsHookEx
to handle WH_GETMESSAGE
. I can't figure out what to pass for the last two parameters.
我正在尝试挂钩 3rd 方应用程序,以便我可以在其屏幕上进行绘制。在屏幕上绘图是容易的,我需要它没有帮助,但我似乎有使用问题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;
}
}
采纳答案by Kevin Montrose
SetWindowsHookExspecifics the last two parameters thusly:
SetWindowsHookEx详细说明了最后两个参数:
hMod
hMod
[in] Handle to the DLL containing the hook procedure pointed to by the lpfn parameter. The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process.
[in] 包含 lpfn 参数指向的钩子过程的 DLL 句柄。如果 dwThreadId 参数指定由当前进程创建的线程,并且钩子过程在与当前进程关联的代码中,则 hMod 参数必须设置为 NULL。
dwThreadId
dwThreadId
[in] Specifies the identifier of the thread with which the hook procedure is to be associated. If this parameter is zero, the hook procedure is associated with all existing threads running in the same desktop as the calling thread.
[in] 指定与挂钩过程关联的线程的标识符。如果此参数为零,则挂钩过程与与调用线程在同一桌面上运行的所有现有线程相关联。
I'm not sure you can use a .NET dll in the manner required, but you can certainly try.
我不确定您是否可以以所需的方式使用 .NET dll,但您当然可以尝试。
Grab hMod
via Marshal.GetHINSTANCE(typeof(Form1).Module)and dwThreadId
via Process.Threads. Alternatively, set dwThreadId
to 0 if you want a global hook (ie. a hook for all GetMessage()
calls in the current desktop) but beware of the performance penalties.
抓斗hMod
通过Marshal.GetHINSTANCE(typeof运算).Module(Form 1中),并dwThreadId
通过Process.Threads。或者,dwThreadId
如果您想要全局挂钩(即GetMessage()
当前桌面中所有调用的挂钩),请设置为 0,但要注意性能损失。
回答by Adam Maras
I believe you need to P/Invoke GetModuleHandle
and use the handle it returns for the third parameter of SetWindowsHookEx
. I also believe 0
is correct for the fourth parameter, as you don't want to hook any one specific thread in the third-party application.
我相信您需要 P/InvokeGetModuleHandle
并使用它为SetWindowsHookEx
. 我也认为0
第四个参数是正确的,因为您不想在第三方应用程序中挂钩任何一个特定线程。
If this doesn't work for you, SetWindowsHookEx
on MSDN might point you in the right direction.
如果这对您不起作用,SetWindowsHookEx
MSDN 上可能会为您指明正确的方向。
回答by ChrisW
I don't know but if you're using parameter values which specify that you want to, as the API helps says, "inject a DLL into another process", then for all I know it might work only if you write an unmanaged DLL from which to call it.
我不知道,但如果您使用指定您想要的参数值,正如 API 帮助所说的那样,“将 DLL 注入另一个进程”,那么据我所知,只有在您编写非托管 DLL 时它才可能工作从中调用它。
回答by gumenimeda
I know that this is an old question but I'm hoping that there is still someone who will find this useful. I think that you are mixing up int
and IntPtr
我知道这是一个老问题,但我希望仍然有人会发现这很有用。我认为你正在混淆int
和IntPtr
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
回答by BillVo
The following suggests this won't work:
以下表明这行不通:
"Global hooks are not supported in the .NET Framework. 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."
“.NET Framework 不支持全局钩子。除了 WH_KEYBOARD_LL 低级钩子和 WH_MOUSE_LL 低级钩子,您不能在 Microsoft .NET Framework 中实现全局钩子。”
回答by Kirk Patrick Brown
This work for me use 13...
这项工作对我来说使用 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);
}
}
回答by Latency
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
}
Global hooks are not supported in the .NET Framework
.NET Framework 不支持全局钩子
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.
除了 WH_KEYBOARD_LL 低级挂钩和 WH_MOUSE_LL 低级挂钩之外,您无法在 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.
要安装全局钩子,钩子必须具有本机 DLL 导出以将自身注入另一个需要有效、一致的函数来调用的进程。此行为需要 DLL 导出。
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.
.NET Framework 不支持 DLL 导出。托管代码没有函数指针的一致值的概念,因为这些函数指针是动态构建的代理。
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.
在安装钩子的线程上调用低级钩子过程。低级挂钩不需要在 DLL 中实现挂钩过程。
See also: Snoop- The WPF Spy Utility
另请参阅: Snoop- WPF 间谍实用程序
Or my WPF => WF => Win32 LL_Keyboard Hook Proxy w/ Gestures
或者我的 WPF => WF => Win32 LL_Keyboard Hook Proxy w/ Gestures