C#のSetWindowsHookEx
-
06-07-2019 - |
質問
サードパーティのアプリをフックして、画面に描画できるようにします。画面への描画は簡単で、私はそれを助けを必要としませんが、 WH_GETMESSAGE
を処理するために SetWindowsHookEx
を使用することに問題があるようです。最後の2つのパラメーターに何を渡すかわかりません。
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;
}
}
解決
SetWindowsHookEx は、このように最後の2つのパラメーターを指定します:
-
hMod
[in]を含むDLLへのハンドル lpfnが指すフックプロシージャ パラメータ。 hModパラメーターは dwThreadIdの場合、NULLに設定 パラメーターは作成されたスレッドを指定します 現在のプロセスによって、フックの場合 手順はコード内にあります 現在のプロセスに関連付けられています。
-
dwThreadId
[in]の識別子を指定します フックプロシージャのスレッド 関連付けられます。このパラメータが ゼロ、フック手順は すべての既存のスレッドに関連付けられています と同じデスクトップで実行 呼び出しスレッド。
必要な方法で.NET dllを使用できるかどうかはわかりませんが、確かに試すことができます。
Marshal.GetHINSTANCE(typeof(Form1).Module)および dwThreadId
( Process.Threads 。または、グローバルフック(つまり、現在のデスクトップ内のすべての GetMessage()
呼び出しのフック)が必要であるが、パフォーマンスのペナルティに注意する場合は、 dwThreadId
を0に設定します。
他のヒント
以下は、これが機能しないことを示唆しています:
"グローバルフックは.NET Frameworkではサポートされていません。 WH_KEYBOARD_LL低レベルフックとWH_MOUSE_LL低レベルフックを除き、Microsoft .NET Frameworkにグローバルフックを実装することはできません。
P / Invokeする必要があると思います < code> GetModuleHandle を返し、 SetWindowsHookEx
の3番目のパラメーターに返されるハンドルを使用します。また、サードパーティアプリケーションの特定の1つのスレッドをフックしたくないため、4番目のパラメーターには 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に実装する必要はありません。
参照: スヌープ-WPFスパイユーティリティ
または私のWPF =&gt; WF =&gt; Win32 LL_Keyboard Hook Proxy w / Gestures