asynchronously GetForegroundWindow via SendMessage or something?

后端 未结 3 1340
一向
一向 2020-12-08 12:00

Is there a way to be notified of when focus changes from any window to another window(even between windows applications) such that I can just have my delegate called immedia

3条回答
  •  独厮守ぢ
    2020-12-08 12:16

    SetWinEventHook() is probably your best bet; you can listen to either the EVENT_SYSTEM_FOREGROUND to listen for foreground window changes - or even EVENT_OBJECT_FOCUS to listen for more fine-grain focus changes within apps and within controls.

    You'll need to use this with the WINEVENT_OUTOFCONTEXT flag; this means that the change notification will be delivered asynchronously to your own app, so you won't need a separate DLL - you'll still need to P/Invoke though. But the notification won't be instant - there may be a small delay - but that's implied with asynchronous. If you want to do something absolutely immediately with no delay whatsoever, you're going to need to use C++ and an in-process hook (either SetWinEventHook with WINEVENT_INCONTEXT or the SetSetWindowsHookEx-style hook.)

    Here's a sample that seems to do what you're looking for:

    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()); 
        }
    }
    

提交回复
热议问题