简体   繁体   English

WPF应用程序的控件为焦点时,捕获活动窗口标题失败

[英]Capturing active window title failed when WPF application's control focused

I am trying to add to my time tracker window caption tracking using SetWindowsHookEx , but it is works only partially. 我正在尝试使用SetWindowsHookEx将其添加到我的时间跟踪器窗口标题跟踪中,但这仅部分起作用。 Here is my code I using to provide subscribers with coresponding event: 这是我用来为订阅者提供coresponding事件的代码:

public class Hooks
{
    #region DllImport

    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_SKIPOWNPROCESS = 2;
    private const uint WINEVENT_SKIPOWNTHREAD = 1;
    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); 

    #endregion DllImport

    public static event EventHandler<EventArgs<string>> WindowActivated;

    public void Bind()
    {
        var listener = new WinEventDelegate(EventCallback);
        var result = SetWinEventHook(EVENT_SYSTEM_FOREGROUND,
                        EVENT_SYSTEM_FOREGROUND,
                        IntPtr.Zero,
                        listener,
                        0,
                        0,
                        (WINEVENT_OUTOFCONTEXT));
    }

    private static void EventCallback(IntPtr hWinEventHook, uint eventType, IntPtr hwnd,
                                      int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
    {
        System.Diagnostics.Debug.Write("EventCallback enter!");

        if (eventType == EVENT_SYSTEM_FOREGROUND)
        {
            var buffer = new StringBuilder(300);
            var handle = GetForegroundWindow();

            System.Diagnostics.Debug.Write(string.Format("EventCallback GetWindowText: {0}, '{1}'",
                GetWindowText(handle, buffer, 300),
                buffer));

            if (GetWindowText(handle, buffer, 300) > 0 && WindowActivated != null)
            {
                System.Diagnostics.Debug.Write(string.Format(
                    "Calling handlers for WindowActivated with buffer='{0}'",
                    buffer));
                WindowActivated(handle, new EventArgs<string>(buffer.ToString()));
            } 
        }

        System.Diagnostics.Debug.Write("EventCallback leave!");
    }
}

I have main ui WPF application with single Textbox and I bind Hook's event to text box content. 我有带有单个Textbox主要ui WPF应用程序,并将Hook的事件绑定到文本框内容。 When I run it it looks work fine, until itself focused. 当我运行它时,它看起来工作正常,直到它本身专注为止。 Ie if I clicked texbox of WPF window becomes active hook stops working for about 30-40 seconds. 即,如果我单击WPF窗口的texbox变为活动状态,挂钩将停止工作约30-40秒。 After that events capturing becomes work, but again - until main WPF windows becomes active. 之后,事件捕获开始起作用,但是又恢复了-直到主要的WPF窗口变为活动状态。

Any ideas what is it and how to fix it? 任何想法是什么以及如何解决?

I created a new WPF application using the standard Visual Studio template (VS2012; .NET 4.5). 我使用标准Visual Studio模板(VS2012; .NET 4.5)创建了一个新的WPF应用程序。 I then replaced the XAML and code-behind as follows: 然后,我替换了XAML并进行了如下代码隐藏:

MainWindow.xaml MainWindow.xaml

<Window x:Class="stackoverflowtest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow">
    <Grid>
        <StackPanel VerticalAlignment="Top" Margin="15">
            <TextBox x:Name="_tb" />
            <Button Content="Does Nothing" HorizontalAlignment="Left" Margin="0,15" />
        </StackPanel>
    </Grid>
</Window>

MainWindow.xaml.cs MainWindow.xaml.cs

using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;

namespace stackoverflowtest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            _hooks = new Hooks(_tb);
            _hooks.Bind();
        }

        readonly Hooks _hooks;
    }

    public class Hooks
    {
        public Hooks(TextBox textbox)
        {
            _listener = EventCallback;
            _textbox = textbox;
        }

        readonly WinEventDelegate _listener;
        readonly TextBox _textbox;
        IntPtr _result;

        public void Bind()
        {
            _result = SetWinEventHook(
                EVENT_SYSTEM_FOREGROUND,
                EVENT_SYSTEM_FOREGROUND,
                IntPtr.Zero,
                _listener,
                0,
                0,
                WINEVENT_OUTOFCONTEXT
                );
        }

        void EventCallback(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild,
            uint dwEventThread, uint dwmsEventTime)
        {
            var windowTitle = new StringBuilder(300);
            GetWindowText(hwnd, windowTitle, 300);
            _textbox.Text = windowTitle.ToString();
        }

        #region P/Invoke
        const uint WINEVENT_OUTOFCONTEXT = 0;
        const uint EVENT_SYSTEM_FOREGROUND = 3;

        [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 int GetWindowText(IntPtr hWnd, StringBuilder text, int count);

        delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject,
            int idChild, uint dwEventThread, uint dwmsEventTime);
        #endregion
    }
}

For me, this works fine. 对我来说,这很好。 I can switch between different applications and their window titles are reflected in the textbox of the WPF app. 我可以在不同的应用程序之间切换,它们的窗口标题反映在WPF应用程序的文本框中。 There is no delay even when the textbox is focused. 即使文本框处于焦点状态,也没有延迟。 I added a do-nothing Button control just to prove that whether the texbox or the button is focused it does not change the behaviour. 我添加了什么都不做的Button控件,只是为了证明无论是texbox还是按钮处于焦点状态,它都不会改变其行为。

I can only assume the problem you are having is related to something you are doing in your event handler, or failing that some kind of threading issue. 我只能假设您遇到的问题与您在事件处理程序中所做的事情有关,或者与某种线程问题有关。

Probably the reason is that the delegate was garbage collected since it is assigned into a local variable. 可能的原因是该委托已被垃圾回收,因为它已被分配给局部变量。 That's why it stopped to work after 30-40 sec. 这就是为什么它在30-40秒后停止工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM