2011-06-14 131 views
1

我想知道是否按下了按鈕。這似乎不是按鈕的官方屬性(不是按鈕樣式的複選框!),但似乎可以訪問,例如BM_GETSTATE消息應該會得到期望的結果。如何通過UIAutomation確定按鈕是否被按下?

問題是,我經常沒有爲我的按鈕獲得窗口句柄(它們只是另一個工具欄的一部分,儘管它們可以由AutomationElement自動添加)。我需要這樣的SendMessage函數的句柄。

所以..有沒有辦法讓我訪問該屬性?我知道它是可訪問的,因爲我已經在其他自動化程序中看到過它,我只是不知道如何去實現它。

我打算使用C#,但任何C代碼都可以。

非常感謝

回答

1

(編輯:所以我終於成功地使代碼格式正確位置 - 只需插入4個空格開頭)

享受它,我花了相當長的時間來獲得它的工作..但現在我覺得已經達到了一個新的水平。 :)

(請告訴我如何讓它正確地格式化 - 無論是報價和代碼的失敗對我)

int res; 
#region direct method 
int hwnd = ae.Current.NativeWindowHandle; 
if (hwnd != 0) 
{ 
    const UInt32 BM_GETSTATE = 0x00F2; 
    res = SendMessage(hwnd, BM_GETSTATE, 0, 0); 
} 
#endregion 
else 
#region method via toolbar 
{ 
    AutomationElement parent = TreeWalker.RawViewWalker.GetParent(ae); 
    while ((parent != null) && (parent.Current.ControlType != ControlType.ToolBar)) 
     parent = TreeWalker.RawViewWalker.GetParent(ae); 
    if (parent != null) 
    { 
     int toolBarHandle = parent.Current.NativeWindowHandle; 
     #region defines 
     const int WM_USER = 0x400; 
     const int TB_GETSTATE = (WM_USER + 18); 
     const int TB_GETBUTTON = (WM_USER + 23); 
     const int TB_BUTTONCOUNT = (WM_USER + 24); 
     #endregion 

     #region get correct child number 
     int numButtons = SendMessage(toolBarHandle, TB_BUTTONCOUNT, 0, 0); 
     AutomationElement sibling = ae; 
     int cnt = -1; 
     while (sibling != null) 
     { 
      sibling = TreeWalker.RawViewWalker.GetPreviousSibling(sibling); 
      ++cnt; 
     } 
     if (cnt >= numButtons) 
      cnt = 0; // nonsense value, but pass a valid one 
     #endregion 

     #region get command id 
     TBBUTTON butInfo = new TBBUTTON(); 
     butInfo.idCommand = 1234; 
     uint pid; 
     GetWindowThreadProcessId((IntPtr)toolBarHandle, out pid); 
     IntPtr process = OpenProcess(ProcessAccessFlags.VMOperation | ProcessAccessFlags.VMRead | 
     ProcessAccessFlags.VMWrite | ProcessAccessFlags.QueryInformation, false, pid); 

     IntPtr p = VirtualAllocEx(process, IntPtr.Zero, (uint)Marshal.SizeOf(typeof(TBBUTTON)), AllocationType.Commit 
            , MemoryProtection.ReadWrite); 

     int _res = SendMessage(toolBarHandle, TB_GETBUTTON, cnt, p.ToInt32()); 

     #region getresult 
     int read; 
     IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(TBBUTTON))); 
     Marshal.StructureToPtr(butInfo, ptr, true); 
     bool __res = ReadProcessMemory(process, p, ptr, Marshal.SizeOf(typeof(TBBUTTON)), out read); 
     System.Diagnostics.Debug.Assert(read == Marshal.SizeOf(typeof(TBBUTTON))); 
     butInfo = (TBBUTTON)Marshal.PtrToStructure(ptr, typeof(TBBUTTON)); 
     #endregion 

     int commandId = butInfo.idCommand; 
     VirtualFreeEx(process, p, 0, FreeType.Release); 

     #endregion 

     //!define BST_UNCHECKED  0 
     //!define BST_CHECKED  1 
     //!define BST_INDETERMINATE 2 
     //!define BST_PUSHED   4 
     //!define BST_FOCUS   8 

     #region get state 
     res = SendMessage(toolBarHandle, TB_GETSTATE, commandId, 0); 
     #endregion 
    } 
} 
#endregion 

編輯: 這裏http://www.andreas-reiff.de/2011/06/c-speicher-anderen-prozess-befullen-lassen-checken-ob-ein-button-gedruckt/與可讀的代碼,並在一個陌生的,外語的解釋..但是代碼註釋是英語。希望你覺得它有用。 另外,如果沒有這裏的信息,我將無法解決這個問題How come some controls don't have a windows handle?