SetWindowsHookEx в C#
Я пытаюсь подключить стороннее приложение, чтобы рисовать на его экране. Рисовать на экране легко, и мне не нужна помощь, но у меня, похоже, возникают проблемы с использованием 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;
}
}
6 ответов
SetWindowsHookEx специфицирует последние два параметра таким образом:
hMod
[in] Дескриптор библиотеки DLL, содержащей процедуру подключения, на которую указывает параметр lpfn. Параметр hMod должен быть установлен в NULL, если параметр dwThreadId указывает поток, созданный текущим процессом, и если подключаемая процедура находится в коде, связанном с текущим процессом.
dwThreadId
[in] Определяет идентификатор потока, с которым должна быть связана подключаемая процедура. Если этот параметр равен нулю, процедура подключения связана со всеми существующими потоками, работающими на том же рабочем столе, что и вызывающий поток.
Я не уверен, что вы можете использовать.NET DLL требуемым образом, но вы, безусловно, можете попробовать.
грейфер hMod
через Marshal.GetHINSTANCE(typeof(Form1).Module) и dwThreadId
через Process.Threads. В качестве альтернативы, установите dwThreadId
в 0, если вы хотите глобальный хук (т.е. хук для всех GetMessage()
звонки в текущем рабочем столе), но остерегайтесь штрафов за производительность.
Следующее предполагает, что это не будет работать:
"Глобальные хуки не поддерживаются в.NET Framework. За исключением низкоуровневого хука WH_KEYBOARD_LL и низкоуровневого хука WH_MOUSE_LL, вы не можете реализовать глобальные хуки в Microsoft .NET Framework".
Я знаю, что это старый вопрос, но я надеюсь, что есть кто-то, кто найдет это полезным. Я думаю, что вы путаете int
а также IntPtr
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
Я считаю, что вам нужно P/Invoke GetModuleHandle
и использовать дескриптор, который он возвращает для третьего параметра SetWindowsHookEx
, Я тоже верю 0
верно для четвертого параметра, так как вы не хотите подключать какой-либо конкретный поток в стороннем приложении.
Если это не работает для вас, SetWindowsHookEx
на MSDN может указать вам в правильном направлении.
Я не знаю, но если вы используете значения параметров, которые указывают, что вы хотите, как подсказывает API, "внедрить DLL в другой процесс", то, насколько я знаю, это может сработать, только если вы пишете неуправляемую DLL из которого это назвать.
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 Spy
Или мой WPF => WF => Win32 LL_Keyboard Hook Proxy с жестами
Эта работа для меня использовать 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);
}
}