2017-03-29 66 views
4

我需要通過自動化接口(使用C++/C#編碼)獲取控制的值/文本。我試着用UI Automation API,這是一些結果由Inspect捕獲: Inspect ListviewVisual Basic 6自動化支持ListView

Inspect slider UI自動化識別這些控制爲pane,我不能讓列表視圖文本項目或獲取/設置滑塊值正常。
嘗試與其他工具如MSAAAutomation Spy給出了相同的結果。

經過研究,我發現類名控件如ListView20WndClassSlider20WndClass,...屬於Visual Basic 6控件。
那麼,有沒有任何API可以支持這些類型的控制?

備註1: 有一個名爲Ranorex可以支持這些控制工具(可悲的是,這是€3490商業授權),我不知道用哪個底層API:
enter image description here

enter image description here


注2 有被測應用程序中使用的一些其他控制類型的UI自動化仍然可以得到值:

  • ThunderRT6FormDC:承認窗口
  • ThunderRT6CommandButton:承認按鈕
  • ThunderRT6CheckBox:黯然承認複選框
  • 等...
  • ,它們嵌入ListView20WndClass and Slide r20WndClass但都承認窗格


更新1 我創建了一個簡單的程序,以獲取文本,但仍無法正常工作(編譯爲Unicode字符集):

#include <iostream> 
using namespace std; 

#include <UIAutomation.h> 
#include <atlstr.h> 
#include <Commctrl.h> 

CString getListViewItemText(HWND hwnd, int nItem, int nSubItem) { 
    LVITEM item; 
    memset(&item, 0, sizeof(LVITEM)); 
    item.iSubItem = nSubItem; 
    CString string; 
    int Length = 64; //initial reasonable string length 
    int ReturnCode; 

    do { 
     Length *= 2; //resize the string buffer 
     item.cchTextMax = Length; 
     item.pszText = string.GetBufferSetLength(Length); 

     ReturnCode = (int)::SendMessage(hwnd, LVM_GETITEMTEXT, 
      (WPARAM)nItem, (LPARAM)&item); 
     printf("len = %d \n", ReturnCode); 

    } while (ReturnCode == Length - 1); //if could not get all chars, try again 

    string.ReleaseBuffer(); 
    return string; 
} 

void UI_Spy() { 

    // Init COM 
    CoInitialize(NULL); 

    // Init UIAutomation instance 
    IUIAutomation *pAuto; 
    CoCreateInstance(CLSID_CUIAutomation, NULL, 
     CLSCTX_INPROC_SERVER, IID_IUIAutomation, reinterpret_cast<void**>(&pAuto)); 

    if (pAuto) { 

     IUIAutomationElement *pElm; 
     POINT p; 

     for (int i = 0; i < 10; i++) { 
      for (int j = 5; j > 0; j--) { 
       Sleep(1000); 
       printf("%d ", j); 
      } 
      GetCursorPos(&p); 
      if (pAuto->ElementFromPoint(p, &pElm) == S_OK) { 
       wprintf(L"\nPOSITION x = %d, y = %d\n", p.x, p.y); 

       BSTR str; 
       pElm->get_CurrentName(&str); 
       wprintf(L"-Name = %s\n", str); 
       SysFreeString(str); 

       pElm->get_CurrentLocalizedControlType(&str); 
       wprintf(L"-Type = %s\n", str); 
       SysFreeString(str); 

       CONTROLTYPEID typeId; 
       pElm->get_CurrentControlType(&typeId); 

       switch (typeId) { 

        // Process checkbox 
       case UIA_CheckBoxControlTypeId: 
        IUIAutomationTogglePattern *toggle; 
        pElm->GetCurrentPattern(UIA_TogglePatternId, (IUnknown**)&toggle); 
        ToggleState state; 
        toggle->get_CurrentToggleState(&state); 
        printf("-Checkbox = %s\n", state == ToggleState::ToggleState_On ? "TRUE" 
         : (state == ToggleState::ToggleState_Off ? "FALSE" : "INTER")); 
        break; 

        // Process VB6 listview 
       case UIA_PaneControlTypeId: 
        pElm->get_CurrentClassName(&str); 
        if (str != nullptr && wcscmp(str, L"ListView20WndClass") == 0) { 
         HWND hwnd; 
         pElm->get_CurrentNativeWindowHandle((UIA_HWND*)&hwnd); 
         printf("-VB6 Listview: %p\n", hwnd); 

         CString txt = getListViewItemText(hwnd, 0, 0); 
         //txt = "Test"; 
         printf("-[0,0] = %S\n", (const wchar_t*)txt); 
        } 
        SysFreeString(str); 
        break; 

        // Process normal listview 
       case UIA_ListControlTypeId: 
        HWND hwnd; 
        pElm->get_CurrentNativeWindowHandle((UIA_HWND*)&hwnd); 
        printf("-Normal Listview: %p\n", hwnd); 

        CString txt = getListViewItemText(hwnd, 0, 0); 
        //txt = "Test"; 
        printf("-[0,0] = %S\n", (const wchar_t*)txt); 
        break; 
       } 

       wprintf(L"\n"); 
       pElm->Release(); 
      } 
      printf("\n"); 
     } 

     // Release UIAutomation instance 
     pAuto->Release(); 
    } 

    // Release COM 
    CoUninitialize(); 
} 

int main() 
{ 
    UI_Spy(); 

    cin.get(); 
    return 0; 
} 


當它計數5..4..3..2..1時,只需將鼠標懸停在屏幕上的某個元素上即可進行檢查。
但是,當我將鼠標放在列表視圖:

  • VB6列表視圖(ListView20WndClass):它返回一個空字符串(預期爲101作爲我的例子)
  • MFC/WinForm的列表視圖(SysListView32) :鼠標下的應用程序停止工作(控制檯應用程序仍在運行)
+1

ListView20WndClass是VB6列表視圖,但它是由Microsoft編寫的自定義作業 - 不像以前的版本,它不基於公共控件列表視圖,因此早於UI自動化。它確實實現了相同的消息傳遞API,因此您可以跳過跨進程環節並使用LVM_GETITEMTEXT等進行閱讀。 –

+0

你能檢查我更新的問題嗎? – phibao37

回答

1

ListView.ListItem對象沒有hwnd。

你應該類名搜索的ListView,下次使用的SendMessage()來發送消息LVM_GETITEM並使用LVITEM結構,以獲取有關項目信息:

LVM_GETITEM消息(Windows)中

https://msdn.microsoft.com/en-us/library/windows/desktop/bb774953(v=vs.85).aspx

LVITEM結構(Windows)中

https://msdn.microsoft.com/en-us/library/windows/desktop/bb774760(v=vs.85).aspx

此引用頁面可以幫助你:

列表視圖控件參考指南(Windows)https://msdn.microsoft.com/en-us/library/windows/desktop/ff485973(v=vs.85).aspx

編輯 但是,你的問題是不相關的VB6語言編程。 因此,我認爲這是錯誤的論壇,您應該在與您的語言相關的論壇上使用。

+0

你能檢查我更新的問題嗎? – phibao37

1

可以使用pywinauto其可以使用在引擎蓋下的Win32 API(所有細節是隱藏的,包括LVM_GETITEM消息等)自動化VB6的應用程式。大多數控件可以被識別爲按鈕,複選框甚至列表視圖!有關列表視圖,請參閱supported class names。你的情況在這裏。

如果使用的是flexible waits,則Win32 API的運行速度應快於UI自動化。儘管如此,UI Automation也受到支持。

Getting Started Guide將幫助您完成第一步並學習高級概念。也可以隨時問標籤pywinauto。我是圖書館維護者。