Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
227 views
in Technique[技术] by (71.8m points)

c# - asynchronously GetForegroundWindow via SendMessage or something?

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 immediately when the user changes focus??

I keep thinking I may just have to do polling :( :( every 1 second and call GetForegroundWindow but I really don't want to do that.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...