SetWindowsHookEx in C #
-
06-07-2019 - |
Frage
Ich versuche, einen 3rd-Party-App Haken, so dass ich auf seinen Bildschirm zu zeichnen. Zeichnung auf dem Bildschirm ist einfach, und ich brauche keine Hilfe mit ihm, aber ich zu sein scheinen Probleme mit mit der Verwendung von SetWindowsHookEx
WH_GETMESSAGE
zu behandeln. Ich kann nicht herausfinden, was in den letzten beiden Parameter zu übergeben.
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;
}
}
Lösung
SetWindowsHookEx Spezifika die beiden letzten Parameter thusly :
-
hMod
[in] an die DLL Handle die enthält Hookprozedur auf den durch den lpfn Parameter. Der hMod Parameter muss sein auf NULL gesetzt, wenn der dwThreadId Parameter gibt einen Thread erstellt durch den aktuellen Prozess, und wenn der Haken Verfahren ist innerhalb des Codes im Zusammenhang mit dem aktuellen Prozess.
-
dwThreadId
[in] Gibt die Kennung des Gewinde, mit dem das Verfahren hook assoziiert ist. Wenn diese Parameter die Hookprozedur Null ist, ist mit allen bestehenden Fäden zugeordnet in demselben Desktop wie der Lauf Aufruf-Thread.
Ich bin nicht sicher, ob Sie einen .NET-DLL in der Art und Weise verwenden können, erforderlich, aber man kann auf jeden Fall versuchen.
Schnappen hMod
über Marshal.GetHINSTANCE (typeof (Form1) .module) und dwThreadId
über Process.Threads . Alternativ setzen dwThreadId
auf 0, wenn Sie einen globalen Haken wollen (dh. Ein Haken für alle GetMessage()
Anrufe in der aktuellen Desktop), aber hüte dich vor den Leistungseinbußen.
Andere Tipps
Im Folgenden legt nahe, das wird nicht funktionieren:
"Globale Haken sind nicht im .NET Framework unterstützt. Mit Ausnahme des WH_KEYBOARD_LL Low-Level-Haken und dem WH_MOUSE_LL Low-Level-Haken, man kann nicht global Haken in dem Microsoft .NET Framework implementieren."
Ich glaube, Sie zu P benötigen / Invoke GetModuleHandle
und mit dem Griff es für den dritten Parameter von SetWindowsHookEx
zurückgibt. Ich glaube auch, 0
für den vierten Parameter korrekt ist, wie Sie wollen nicht irgendeinen bestimmten Thread in der Anwendung von Drittanbietern anschließen.
Wenn dies nicht für Sie arbeiten, SetWindowsHookEx
auf MSDN können Sie in die richtige Richtung zeigen.
Ich weiß nicht, aber wenn Sie Parameterwerte verwenden, die angeben, dass Sie möchten, wie die API sagt hilft, „eine DLL in einem anderen Prozess injizieren“, dann für alle weiß, dass ich es kann nur funktionieren, wenn Sie schreiben eine nicht verwaltete DLL aus dem sie nennen.
Ich weiß, dass dies ist eine alte Frage, aber ich bin der Hoffnung, dass es noch jemanden gibt, der dies nützlich finden. Ich denke, dass Sie vermischen int
und IntPtr
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
Diese Arbeit für mich 13 verwenden ...
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
}
Globale Haken sind nicht im .NET Framework unterstützt
Mit Ausnahme des WH_KEYBOARD_LL Low-Level-Haken und dem WH_MOUSE_LL Low-Level-Haken, man kann nicht global Haken in dem Microsoft .NET Framework implementieren.
Um einen globalen Hook zu installieren, muss ein Haken hat einen native DLL Export selbst in einem anderen Prozess zu injizieren, die eine gültige, konsistente Funktion erfordert ins Leben zu rufen. Dieses Verhalten erfordert eine DLL zu exportieren.
Das .NET Framework nicht DLL Exporte unterstützen. Managed Code hat kein Konzept für einen konsistenten Wert für einen Funktionszeiger, da diese Funktionszeiger sind Proxies, die dynamisch erstellt werden.
Low-Level-Hook-Prozeduren werden auf dem Thread aufgerufen, die den Hook installiert. Low-Level-Haken nicht verlangen, dass die Hook-Prozedur in einem DLL implementiert werden.
Siehe auch: Snoop - Die WPF Spy Dienstprogramm
oder meine WPF => WF => Win32 LL_Keyboard Proxy Haken w / Gestures