当 WPF 应用程序的控件获得焦点时捕获活动 window 标题失败
Capturing active window title failed when WPF application's control focused
我正在尝试使用 SetWindowsHookEx
添加到我的时间跟踪器 window 字幕跟踪,但它只部分起作用。这是我用来为订阅者提供相应事件的代码:
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!");
}
}
我有主 ui WPF 应用程序和单个 Textbox
,我将 Hook 的事件绑定到文本框内容。当我 运行 它看起来工作正常,直到它自己聚焦。 IE。如果我单击 WPF window 的 texbox 变为活动挂钩,则会停止工作约 30-40 秒。在那之后事件捕获开始工作,但再次 - 直到主 WPF windows 变为活动状态。
知道它是什么以及如何解决它吗?
我使用标准 Visual Studio 模板(VS2012;.NET 4.5)创建了一个新的 WPF 应用程序。然后我替换了 XAML 和 code-behind 如下:
MainWindow.xaml
<Window x:Class="Whosebugtest.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
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
namespace Whosebugtest
{
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
}
}
对我来说,这很好用。我可以在不同的应用程序之间切换,它们的 window 标题反映在 WPF 应用程序的文本框中。即使文本框获得焦点也没有延迟。我添加了一个 do-nothing Button
控件只是为了证明无论 texbox 还是按钮被聚焦它都不会改变行为。
我只能假设您遇到的问题与您在事件处理程序中所做的事情有关,或者与某种线程问题有关。
可能的原因是委托被垃圾回收,因为它被分配到局部变量中。这就是它在 30-40 秒后停止工作的原因。
我正在尝试使用 SetWindowsHookEx
添加到我的时间跟踪器 window 字幕跟踪,但它只部分起作用。这是我用来为订阅者提供相应事件的代码:
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!");
}
}
我有主 ui WPF 应用程序和单个 Textbox
,我将 Hook 的事件绑定到文本框内容。当我 运行 它看起来工作正常,直到它自己聚焦。 IE。如果我单击 WPF window 的 texbox 变为活动挂钩,则会停止工作约 30-40 秒。在那之后事件捕获开始工作,但再次 - 直到主 WPF windows 变为活动状态。
知道它是什么以及如何解决它吗?
我使用标准 Visual Studio 模板(VS2012;.NET 4.5)创建了一个新的 WPF 应用程序。然后我替换了 XAML 和 code-behind 如下:
MainWindow.xaml
<Window x:Class="Whosebugtest.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
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
namespace Whosebugtest
{
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
}
}
对我来说,这很好用。我可以在不同的应用程序之间切换,它们的 window 标题反映在 WPF 应用程序的文本框中。即使文本框获得焦点也没有延迟。我添加了一个 do-nothing Button
控件只是为了证明无论 texbox 还是按钮被聚焦它都不会改变行为。
我只能假设您遇到的问题与您在事件处理程序中所做的事情有关,或者与某种线程问题有关。
可能的原因是委托被垃圾回收,因为它被分配到局部变量中。这就是它在 30-40 秒后停止工作的原因。