2010-12-06 9 views
25

現在のアクティブウィンドウが変更されたときに、コールバックを呼び出す方法を教えてください。私はそれがCBTProcを使ってどのように行われるのか見てきました。しかし、グローバルなイベントは、管理されたコードにフックするのは容易ではありません。私はポーリングを必要としない方法を見つけることに興味があります。私はイベント駆動アプローチを好むだろう。ポーリングなしでC#を使用してアクティブなウィンドウを検出

よろしく

+0

「変更」を定義できますか? – Eric

+2

http://support.microsoft.com/kb/318804によると、.NETでグローバルフックを実行することはできません。グローバルフックはこれらのタイプのイベントを監視する方法であるため、唯一のオプションはポーリングですC#からアクセスできるインターフェイスを提供するアンマネージコード(たとえばC++など)を記述することもできます。 –

+0

ジム私はあなたに正しい答えがあると思います。 – Joe

答えて

47

新しいWindowsフォームプロジェクトを作成し、テキストボックスを追加して複数行にし、テキストボックスのDockプロパティを設定して名前を付けてログに貼り付け、次のコードに貼り付けます(System.Runtime.InteropServicesを追加する必要があります)。あなたのusings)...

WinEventDelegate dele = null; 

    public Form1() 
    { 
     InitializeComponent(); 
     dele = new WinEventDelegate(WinEventProc); 
     IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT); 
    } 

    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_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); 

    private string GetActiveWindowTitle() 
    { 
     const int nChars = 256; 
     IntPtr handle = IntPtr.Zero; 
     StringBuilder Buff = new StringBuilder(nChars); 
     handle = GetForegroundWindow(); 

     if (GetWindowText(handle, Buff, nChars) > 0) 
     { 
      return Buff.ToString(); 
     } 
     return null; 
    } 

    public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) 
    { 
     Log.Text += GetActiveWindowTitle() + "\r\n"; 
    } 
+3

、dele' 'の範囲があることが必要デリゲートが処分されるのを防ぐために広げられました。詳細については、[ドキュメントページ](http://msdn.microsoft.com/en-us/library/windows/desktop/dd373640(v = vs.85).aspx)のコメントを参照してください。 –

+0

これはコンソールアプリケーションではうまく動作しないようですが、その理由を知っていますか?私はInitializeComponent()を削除しました。 –

+1

@AnthonyRaimondo明らかに、Console.ReadLineをアクティブにしても起動しません。相互運用呼び出しを削減し、コードを少しクリーンアップするにはhttp://stackoverflow.com/questions/8840926/asynchronously-getforegroundwindow-via-sendmessage-or-something/11943387#11943387 –

7

あなたはSetWinEventHookを使用してEVENT_SYSTEM_FOREGROUNDイベントをリッスンすることができます。グローバルフックの問題を回避するには、WINEVENT_OUTOFCONTEXTフラグを使用します。

+0

いくつかの例を挙げてください。 –

+4

[あなたはstackoverflowを検索することができます](http://stackoverflow.com/questions/4407631/is-there-windows-system-event-on-active-window-changed)。 –

+1

追加情報:あなたのコンテキスト外機能は速くなければなりません。 (https://msdn.microsoft.com/en-us/library/windows/desktop/dd373611%28v=vs.85%29.aspx)サヴァスSopiadis'答えを1として –

16

私はこのスレッドを知っては古いですが、将来の使用のために: のコードを実行するときは、しばらく後にクラッシュに気付くでしょう。これは、フォームのコンストラクタでラインから発生している。今、期待通り

public Form1() 
     { 
      InitializeComponent(); 
      dele = new WinEventDelegate(WinEventProc); 
      IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT); 
     } 
WinEventDelegate dele = null; 

..works:代わりに、上記の

public Form1() 
    { 
     InitializeComponent(); 
     WinEventDelegate dele = new WinEventDelegate(WinEventProc);//<-causing ERROR 
     IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT); 
    } 

は、次のような変形を作ります!

関連する問題