我正在编写一个应用程序,需要捕获用户在其窗口句柄上完成的每个操作。
我需要提出以下事件:
要做到这一点,我尝试了很多解决方案,但是徒劳无功。首先,我使用了一个Timer,每隔100ms轮询一次前景窗口(使用GetForegroundWindow())和使用AttachThreadInput()加上GetFocus()函数的键盘聚焦句柄。
但是这个解决方案不是很方便,我更喜欢使用.NET Framework提供的UIAutomation更清晰的解决方案。但是我意识到它使用了很多CPU并且对我的目的而言太慢了,当我切换到另一个窗口句柄时,事件有时会被调用3到4次。
关于窗口调整大小,最大化等等。我也做了一个计时器(但不是很真实),并试图使用一些钩子技术,如CBT钩子和Shell钩子。不幸的是,我发现C#不支持这种钩子(全局钩子)。
我正在为我的程序的这一部分寻找稳定可靠的代码。提前谢谢。
答案 0 :(得分:0)
BrendanMcK在这篇文章中回答了我的问题:
Setting up Hook on Windows messages
我在下面复制了他的答案。比起我提出的方法,它比Timer更方便,并且它比UIAutomation更少的CPU吃。谢谢大家!
using System;
using System.Windows;
using System.Windows.Forms;
using System.Runtime.InteropServices;
class NameChangeTracker
{
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr
hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess,
uint idThread, uint dwFlags);
[DllImport("user32.dll")]
static extern bool UnhookWinEvent(IntPtr hWinEventHook);
const uint EVENT_OBJECT_NAMECHANGE = 0x800C;
const uint WINEVENT_OUTOFCONTEXT = 0;
// Need to ensure delegate is not collected while we're using it,
// storing it in a class field is simplest way to do this.
static WinEventDelegate procDelegate = new WinEventDelegate(WinEventProc);
public static void Main()
{
// Listen for name change changes across all processes/threads on current desktop...
IntPtr hhook = SetWinEventHook(EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_NAMECHANGE, IntPtr.Zero,
procDelegate, 0, 0, WINEVENT_OUTOFCONTEXT);
// MessageBox provides the necessary mesage loop that SetWinEventHook requires.
// In real-world code, use a regular message loop (GetMessage/TranslateMessage/
// DispatchMessage etc or equivalent.)
MessageBox.Show("Tracking name changes on HWNDs, close message box to exit.");
UnhookWinEvent(hhook);
}
static void WinEventProc(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
// filter out non-HWND namechanges... (eg. items within a listbox)
if(idObject != 0 || idChild != 0)
{
return;
}
Console.WriteLine("Text of hwnd changed {0:x8}", hwnd.ToInt32());
}
}