Arn*_* F. 1 c# winapi setwindowshookex
我正试图在我的C#应用程序中挂钩创建一个窗口.
static IntPtr hhook = IntPtr.Zero;
static NativeMethods.HookProc hhookProc;
static void Main(string[] args)
{
// Dummy.exe is a form with a button that opens a MessageBox when clicking on it.
Process dummy = Process.Start(@"Dummy.exe");
try
{
hhookProc = new NativeMethods.HookProc(Hook);
IntPtr hwndMod = NativeMethods.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
hhook = NativeMethods.SetWindowsHookEx(HookType.WH_CBT, hhookProc, hwndMod, (uint)AppDomain.GetCurrentThreadId());
Console.WriteLine("hhook valid? {0}", hhook != IntPtr.Zero);
while (!dummy.HasExited)
dummy.WaitForExit(500);
}
finally
{
if(hhook != IntPtr.Zero)
NativeMethods.UnhookWindowsHookEx(hhook);
}
}
static int Hook(int nCode, IntPtr wParam, IntPtr lParam)
{
Console.WriteLine("Hook()");
return NativeMethods.CallNextHookEx(hhook, nCode, wParam, lParam);
}
Run Code Online (Sandbox Code Playgroud)
问题是,当点击我的按钮(在Dummy.exe中)时,我从不进入我的Hook,我做错了什么?
谢谢.
编辑
Program.cs中
using System;
using System.Diagnostics;
namespace Hooker
{
class Program
{
static IntPtr hhook = IntPtr.Zero;
static NativeMethods.HookProc hhookProc;
static void Main(string[] args)
{
Process dummy = Process.Start(@"Dummy.exe");
try
{
hhookProc = new NativeMethods.HookProc(Hook);
hhook = NativeMethods.SetWindowsHookEx(HookType.WH_CBT, hhookProc, IntPtr.Zero, 0);
Console.WriteLine("hhook valid? {0}", hhook != IntPtr.Zero);
while (!dummy.HasExited)
dummy.WaitForExit(500);
}
finally
{
if(hhook != IntPtr.Zero)
NativeMethods.UnhookWindowsHookEx(hhook);
}
}
static int Hook(int nCode, IntPtr wParam, IntPtr lParam)
{
Console.WriteLine("Hook()");
return NativeMethods.CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
}
}
}
Run Code Online (Sandbox Code Playgroud)
NativeMethods.cs
namespace Hooker
{
using System;
using System.Runtime.InteropServices;
internal static class NativeMethods
{
public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(HookType hookType, HookProc lpfn, IntPtr hMod, int dwThreadId);
[DllImport("user32.dll")]
public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", SetLastError = true)]
public static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int pid);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
}
}
Run Code Online (Sandbox Code Playgroud)
对于虚拟,请执行以下新表格:
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("CONTENT", "TITLE");
}
Run Code Online (Sandbox Code Playgroud)
像大多数SetWindowsHookEx钩子一样,WH_CBT钩子要求钩子回调存在于一个单独的Win32 DLL中,该DLL将被加载到目标进程中.这基本上要求钩子是用C/C++编写的,C#在这里不起作用.
(低级鼠标和键盘挂钩是此规则的两个例外.也可能在C#中使用其他挂钩,但仅当您挂钩自己的一个线程时,所以dwThreadId是当前进程中线程的id但不是0.我还没有证实这一点.你需要确保你使用的是Win32 threadid,所以使用GetCurrentThreadId可能是最好的选择.)
如果你想要观察从另一个应用程序出现的新窗口,另一种C#友好的方法是使用SetWinEventHook API,指定WINEVENT_OUTOFCONTEXT(这是一个魔术标志,可以将事件传递给您自己的进程,无需使用DLL和使C#在这里可用)和钩子EVENT_OBJECT_CREATE和EVENT_OBJECT_SHOW事件.您可以侦听自己的进程/线程事件,也可以侦听当前桌面上的所有进程/线程.
这将为您提供各种"创建"和显示通知,包括对话框中的子HWND,甚至列表框和类似内容中的项目; 因此,您需要过滤以仅提取顶级HWND的那些:例如.检查idObject == OBJID_WINDOW和idChild == 0; 那个hwnd是可见的(IsVisible())并且是顶级的.
请注意,使用WinEvents要求调用SetWinEventHook的线程正在抽取消息 - 如果它是带有UI的线程,通常就是这种情况.如果没有,您可能需要手动添加消息循环(GetMessage/TranslateMessage).此外,您还希望将GC.KeepAlive()与回调一起使用,以防止在调用UnhookWinEvents之前收集它.
| 归档时间: |
|
| 查看次数: |
16684 次 |
| 最近记录: |