2015-01-14 8 views
0

SetWindowsHookEx을 사용하여 시간 추적기 창 캡션 추적에 추가하려고하지만 부분적으로 만 작동합니다.WPF 응용 프로그램의 컨트롤에 포커스가있을 때 활성 창 제목을 캡처하지 못했습니다.

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!"); 
    } 
} 

내가 하나의 Textbox와 메인 UI를 WPF 응용 프로그램이 내가 텍스트 상자의 내용에 후크의 이벤트를 바인딩 : 여기 풀어서 이벤트로 가입자를 제공하기 위해 사용하여 내 코드입니다. 그것을 실행할 때까지 잘 작동합니다. 나는. WPF 창의 texbox를 클릭하면 활성 훅이 약 30-40 초 동안 작동을 멈 춥니 다. 그 후에 이벤트 캡쳐가 작동하지만 메인 WPF 창이 활성화 될 때까지 다시 캡처됩니다.

어떤 아이디어입니까? 어떻게 수정합니까?

+0

자신 만의 WPF 응용 프로그램을 추적해야합니까? 그렇지 않다면'WINEVENT_SKIPOWNPROCESS'를'SetWinEventHook' 호출에 전달하거나 콜백 함수가받은'hwnd'를 자신의 윈도우 핸들과 비교함으로써 필터를 걸러 낼 수는 없습니다. –

+0

@Steven Rands 필자는 사용자가 지정한 플래그로 테스트했습니다. 그것은 아무것도 바뀌지 않았습니다. –

+0

플래그를 어떻게 설정하고 있습니까? 다음과 같이 그들을 전달해야합니다 :'WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS'. 나는 WPF 애플 리케이션을 시험해 보았고, 애플 리케이션 자체가 전경 윈도우가 될 때'EventCallback' 메소드가 호출되는 것을 막았다. –

답변

0

표준 Visual Studio 템플릿 (VS2012; .NET 4.5)을 사용하여 새 WPF 응용 프로그램을 만들었습니다. 나는 다음 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를

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 
    } 
} 

나를 위해,이 잘 작동합니다. 서로 다른 응용 프로그램간에 전환 할 수 있으며 창 제목은 WPF 응용 프로그램의 텍스트 상자에 반영됩니다. 텍스트 상자에 포커스가 있어도 지연이 없습니다. 나는 아무 것도하지 않고 Button 컨트롤을 추가하여 texbox 나 버튼에 포커스가 있는지 여부가 동작을 변경하지 않는다는 것을 증명했습니다.

당신이 가지고있는 문제는 당신이 이벤트 처리기에서하고있는 일과 관련이 있거나, 어떤 종류의 스레딩 문제가 있다고 가정 할 수 있습니다.

+0

예, 샘플이 작동합니다. 그것은 UI 및 코어에 대한 다른 어셈블리에 의해 문제가 발생하는 것처럼 보입니다. 후크 클래스는 코어 어셈블리에 배치됩니다. 그게 문제 야. –

0

아마 대리자가 로컬 변수에 할당되어 있기 때문에 가비지 수집 된 것 같습니다. 30 초에서 40 초가 지나면 작동이 멈췄습니다.