2013-07-14 145 views
0

我目前正在編寫一個應用程序,需要捕捉用戶在其窗口句柄上完成的每個動作。捕捉最小化,最大化,調整大小,鍵盤焦點變化等

我需要的是提出了以下事件:

  • 窗口調整大小,最大化,最小化或移動
  • 用戶更改活動窗口
  • 用戶更改窗口句柄的鍵盤集中

爲此,我嘗試了很多解決方案,但徒勞無功。首先,我使用了一個定時器,每100ms輪詢前景窗口(使用GetForegroundWindow())和鍵盤集中處理,使用AttachThreadInput()加上GetFocus()函數。

但是這個解決方案不是很方便,我更喜歡使用.NET Framework提供的UIAutomation的更乾淨的解決方案。但是我意識到它使用了很多CPU,並且對於我的目的來說太慢了,並且當我切換到另一個窗口句柄時,事件有時會被調用3到4次。

關於窗口調整大小,最大化等我做了一個計時器(但不是很真實),並試圖讓一些掛鉤工藝,如CBT鉤子和殼鉤。不幸的是,我發現這種鉤子(全局鉤子)不被C#支持。

我正在爲我的程序的這一部分尋找穩定可靠的代碼。提前致謝。

+0

[WND_PROC(http://msdn.microsoft.com/en-us/library/system.windows.forms.control.wndproc.aspx) - 我不知道那是什麼您使用的,但這是Windows用來處理幾乎所有消息的東西 – Sayse

+0

不,我想暫時避開Winform。我確切地說我想監視其他窗口的句柄,而不是我的應用程序。 關於WND_PROC:我想這隻適用於應用程序本身,不是嗎?我查找使用AttachThreadInput()傳遞消息到我的應用程序,但它需要一個Form對象 – Louisbob

+0

是的,它是我相信的應用程序..(窗口) – Sayse

回答

0

BrendanMcK奇妙的回答我的問題在這個帖子:

Setting up Hook on Windows messages

我抄他的答案正下方。它比計時器更方便,因爲它比我更快,並且它比UIAutomation的CPU-eater更少。感謝大家!

using System; 
using System.Windows; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

class NameChangeTracker 
{ 
    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); 

    [DllImport("user32.dll")] 
    static extern bool UnhookWinEvent(IntPtr hWinEventHook); 

    const uint EVENT_OBJECT_NAMECHANGE = 0x800C; 
    const uint WINEVENT_OUTOFCONTEXT = 0; 

    // Need to ensure delegate is not collected while we're using it, 
    // storing it in a class field is simplest way to do this. 
    static WinEventDelegate procDelegate = new WinEventDelegate(WinEventProc); 

    public static void Main() 
    { 
     // Listen for name change changes across all processes/threads on current desktop... 
     IntPtr hhook = SetWinEventHook(EVENT_OBJECT_NAMECHANGE, EVENT_OBJECT_NAMECHANGE, IntPtr.Zero, 
       procDelegate, 0, 0, WINEVENT_OUTOFCONTEXT); 

     // MessageBox provides the necessary mesage loop that SetWinEventHook requires. 
     // In real-world code, use a regular message loop (GetMessage/TranslateMessage/ 
     // DispatchMessage etc or equivalent.) 
     MessageBox.Show("Tracking name changes on HWNDs, close message box to exit."); 

     UnhookWinEvent(hhook); 
    } 

    static void WinEventProc(IntPtr hWinEventHook, uint eventType, 
     IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) 
    { 
     // filter out non-HWND namechanges... (eg. items within a listbox) 
     if(idObject != 0 || idChild != 0) 
     { 
      return; 
     } 
     Console.WriteLine("Text of hwnd changed {0:x8}", hwnd.ToInt32()); 
    } 
}