如何在当前活动窗口更改时调用回调函数。我已经了解到使用CBTProc可以实现这一点。然而,使用托管代码并不容易钩入全局事件。我有兴趣找到一种不需要轮询的方法。我希望采用事件驱动的方法。
谢谢
如何在当前活动窗口更改时调用回调函数。我已经了解到使用CBTProc可以实现这一点。然而,使用托管代码并不容易钩入全局事件。我有兴趣找到一种不需要轮询的方法。我希望采用事件驱动的方法。
谢谢
创建一个新的Windows窗体项目,添加一个文本框,使其多行显示,并将文本框的Dock属性设置为填充,命名为Log,然后粘贴以下代码(您需要将System.Runtime.InteropServices添加到您的usings中)...
WinEventDelegate dele = null;
public Form1()
{
InitializeComponent();
dele = new WinEventDelegate(WinEventProc);
IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
}
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);
private const uint WINEVENT_OUTOFCONTEXT = 0;
private const uint EVENT_SYSTEM_FOREGROUND = 3;
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
private string GetActiveWindowTitle()
{
const int nChars = 256;
IntPtr handle = IntPtr.Zero;
StringBuilder Buff = new StringBuilder(nChars);
handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return null;
}
public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
Log.Text += GetActiveWindowTitle() + "\r\n";
}
我知道这个帖子已经有点旧了,但考虑到将来的使用,请注意:当运行代码一段时间后,你会注意到程序崩溃了。这是由于Form构造函数中的那一行代码引起的:
public Form1()
{
InitializeComponent();
WinEventDelegate dele = new WinEventDelegate(WinEventProc);//<-causing ERROR
IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
}
不要像上面那样,做出以下修改:
public Form1()
{
InitializeComponent();
dele = new WinEventDelegate(WinEventProc);
IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
}
WinEventDelegate dele = null;
现在按预期工作!
WinEventDelegate dele
在Form1
构造函数内作用域时,它是一个候选的垃圾收集对象,因为引用在构造函数结束后就丢失了。将其作用域提升至类级别将会保持该引用活动直到类实例被释放。 - Walter StaboszSetWinEventHook
并监听EVENT_SYSTEM_FOREGROUND
事件。使用WINEVENT_OUTOFCONTEXT
标志以避免全局挂钩问题。