通过SendMessage或其他东西异步GetForegroundWindow?

有没有办法通知焦点何时从任何窗口更改到另一个窗口(甚至在Windows应用程序之间),以便我可以在用户更改焦点时立即调用我的委托?

我一直在想我可能只需要进行民意调查:( :(每1秒钟调用一次GetForegroundWindow但我真的不想那样做)。

SetWinEventHook()可能是你最好的选择; 您可以收听EVENT_SYSTEM_FOREGROUND以收听前景窗口更改 – 甚至可以收听EVENT_OBJECT_FOCUS以在应用程序内和控件内侦听更细粒度的焦点更改。

您需要将其与WINEVENT_OUTOFCONTEXT标志一起使用; 这意味着更改通知将异步传递到您自己的应用程序,因此您不需要单独的DLL – 您仍然需要P / Invoke。 但通知不会是即时的 – 可能会有一个小延迟 – 但这是异步的暗示。 如果你想在没有任何延迟的情况下立即做一些事情,你将需要使用C ++和进程内挂钩(带有WINEVENT_INCONTEXT的SetWinEventHook或者SetSetWindowsHookEx样式的钩子。)

这是一个似乎正在寻找你想要的样本:

using System; using System.Windows; using System.Windows.Forms; using System.Runtime.InteropServices; class ForegroundTracker { // Delegate and imports from pinvoke.net: 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); // Constants from winuser.h const uint EVENT_SYSTEM_FOREGROUND = 3; 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 foreground changes across all processes/threads on current desktop... IntPtr hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, procDelegate, 0, 0, WINEVENT_OUTOFCONTEXT); // MessageBox provides the necessary mesage loop that SetWinEventHook requires. MessageBox.Show("Tracking focus, close message box to exit."); UnhookWinEvent(hhook); } static void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) { Console.WriteLine("Foreground changed to {0:x8}", hwnd.ToInt32()); } } 

上面的例子就像一个冠军。 我重构了一点,使一个可能有用的类。 我没有定义所有常量,所以如果你想捕获其他事件,你需要添加一些常量。

 using System; using System.Runtime.InteropServices; #pragma warning disable 1591 // ReSharper disable InconsistentNaming namespace MosaiqPerformanceMonitor { public class EventHook { public delegate void WinEventDelegate( IntPtr hWinEventHook, uint eventType, IntPtr hWnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime); [DllImport("user32.dll")] public static extern IntPtr SetWinEventHook( uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags); [DllImport("user32.dll")] public static extern bool UnhookWinEvent(IntPtr hWinEventHook); public const uint EVENT_SYSTEM_FOREGROUND = 3; public const uint WINEVENT_OUTOFCONTEXT = 0; public const uint EVENT_OBJECT_CREATE = 0x8000; readonly WinEventDelegate _procDelegate; readonly IntPtr _hWinEventHook; public EventHook(WinEventDelegate handler, uint eventMin, uint eventMax) { _procDelegate = handler; _hWinEventHook = SetWinEventHook(eventMin, eventMax, IntPtr.Zero, handler, 0, 0, WINEVENT_OUTOFCONTEXT); } public EventHook(WinEventDelegate handler, uint eventMin) : this(handler, eventMin, eventMin) { } public void Stop() { UnhookWinEvent(_hWinEventHook); } // Usage Example for EVENT_OBJECT_CREATE (http://msdn.microsoft.com/en-us/library/windows/desktop/dd318066%28v=vs.85%29.aspx) // var _objectCreateHook = new EventHook(OnObjectCreate, EventHook.EVENT_OBJECT_CREATE); // ... // static void OnObjectCreate(IntPtr hWinEventHook, uint eventType, IntPtr hWnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) { // if (!Win32.GetClassName(hWnd).StartsWith("ClassICareAbout")) // return; // Note - in Console program, doesn't fire if you have a Console.ReadLine active, so use a Form } } 

您可以安装Windows挂钩(需要一些P / Invoke)并监视发送到Windows的消息。 此问题列出了将窗口置于前台所涉及的消息。 这是用于安装钩子的MSDN文档