Most Efficient Way for getting notified on window open

前端 未结 3 1528
孤独总比滥情好
孤独总比滥情好 2020-12-08 23:25

I am writing an app (C# and WPF in .NET 4.0) that needs to get open windows and close them if they are not in it\'s white-list.

So far, using EnumDesktopWindo

相关标签:
3条回答
  • 2020-12-09 00:14

    If you are accessing windows from other application,this is not going to be an easy task but you could try to use Hooks in windows.

    0 讨论(0)
  • 2020-12-09 00:16

    You can Hook on to Shell to receive messages by using RegisterWindowMessage and RegisterShellHookWindow API functions.

    You will need the following Interop imports:

    public static class Interop
    {
        public enum ShellEvents : int
        {
            HSHELL_WINDOWCREATED = 1,
            HSHELL_WINDOWDESTROYED = 2,
            HSHELL_ACTIVATESHELLWINDOW = 3,
            HSHELL_WINDOWACTIVATED = 4,
            HSHELL_GETMINRECT = 5,
            HSHELL_REDRAW = 6,
            HSHELL_TASKMAN = 7,
            HSHELL_LANGUAGE = 8,
            HSHELL_ACCESSIBILITYSTATE = 11,
            HSHELL_APPCOMMAND = 12
        }
        [DllImport("user32.dll", EntryPoint = "RegisterWindowMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int RegisterWindowMessage(string lpString);
        [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int DeregisterShellHookWindow(IntPtr hWnd);
        [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int RegisterShellHookWindow(IntPtr hWnd);
        [DllImport("user32", EntryPoint = "GetWindowTextA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int GetWindowText(IntPtr hwnd, System.Text.StringBuilder lpString, int cch);
        [DllImport("user32", EntryPoint = "GetWindowTextLengthA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int GetWindowTextLength(IntPtr hwnd);
    }
    

    To be able to hook on to the shell, you'll need a class that inherits from Form and overrides the WndProc function. You can make this Form to have an Event that will be raised when a Window change its state.

    public class SystemProcessHookForm : Form
    {
        private readonly int msgNotify;
        public delegate void EventHandler(object sender, string data);
        public event EventHandler WindowEvent;
        protected virtual void OnWindowEvent(string data)
        {
            var handler = WindowEvent;
            if (handler != null)
            {
                handler(this, data);
            }
        }
    
        public SystemProcessHookForm()
        {
            // Hook on to the shell
            msgNotify = Interop.RegisterWindowMessage("SHELLHOOK");
            Interop.RegisterShellHookWindow(this.Handle);
        }
    
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == msgNotify)
            {
                // Receive shell messages
                switch ((Interop.ShellEvents)m.WParam.ToInt32())
                {
                    case Interop.ShellEvents.HSHELL_WINDOWCREATED:
                    case Interop.ShellEvents.HSHELL_WINDOWDESTROYED:
                    case Interop.ShellEvents.HSHELL_WINDOWACTIVATED:
                        string wName = GetWindowName(m.LParam);
                        var action = (Interop.ShellEvents)m.WParam.ToInt32();
                        OnWindowEvent(string.Format("{0} - {1}: {2}", action, m.LParam, wName));
                        break;
                }
            }
            base.WndProc(ref m);
        }
    
        private string GetWindowName(IntPtr hwnd)
        {
            StringBuilder sb = new StringBuilder();
            int longi = Interop.GetWindowTextLength(hwnd) + 1;
            sb.Capacity = longi;
            Interop.GetWindowText(hwnd, sb, sb.Capacity);
            return sb.ToString();
        }
    
        protected override void Dispose(bool disposing)
        {
            try { Interop.DeregisterShellHookWindow(this.Handle); }
            catch { }
            base.Dispose(disposing);
        }
    }
    

    And then, in your Main function of your application, you can have for example:

    static void Main(string[] args)
    {
        var f = new SystemProcessHookForm();
        f.WindowEvent += (sender, data) => Console.WriteLine(data); 
        while (true)
        {
            Application.DoEvents();
        }
    }
    

    Output sample: enter image description here

    0 讨论(0)
  • 2020-12-09 00:22

    Use the System.Windows.Automation namespace.

    Example (taken from The Old New Thing) which waits for a specific process to open a dialog box, then dismisses it:

    using System;
    using System.Windows.Automation;
    using System.Diagnostics;
    using System.Threading;
    
    class Program
    {
        [STAThread]
        public static void Main(string[] args)
        {     
            Automation.AddAutomationEventHandler(
                WindowPattern.WindowOpenedEvent,
                AutomationElement.RootElement,
                TreeScope.Children,
                (sender, e) =>
                {
                    var element = sender as AutomationElement;
    
                    Console.WriteLine("new window opened");
                });
    
            Console.ReadLine();
    
            Automation.RemoveAllEventHandlers();
        }
    }
    
    0 讨论(0)
提交回复
热议问题