我需要通过自动化接口(interface)(使用 C++/C# 编码)获取控制值/文本。我尝试使用 UI Automation API ,这是 Inspect 捕获的一些结果:
c++ - Visual Basic 6 ListView 的自动化支持-LMLPHP

c++ - Visual Basic 6 ListView 的自动化支持-LMLPHP
UI 自动化将这些控件识别为 pane,我无法正常获取 ListView 文本项或获取/设置滑块值。
尝试使用其他工具,如 MSAAAutomation Spy 给出相同的结果。
经过研究,我发现类名像 ListView20WndClassSlider20WndClass 等的控件属于 Visual Basic 6 控件。
那么,是否有任何 API 也可以支持这些类型的控件?

备注 1 :
有一个叫Ranorex的工具可以支持这些控制(可惜是3490欧元的商业许可),不知道用的是哪个底层API:
c++ - Visual Basic 6 ListView 的自动化支持-LMLPHP

c++ - Visual Basic 6 ListView 的自动化支持-LMLPHP

备注 2
在被测应用程序中使用了一些其他控件类型,UI 自动化仍然可以获得值(value):

  • ThunderRT6FormDC:识别为窗口
  • ThunderRT6CommandButton:识别为按钮
  • ThunderRT6CheckBox:识别为复选框
  • 等等...
  • 可悲的是,它们嵌入了 ListView20WndClass 和 Slider20WndClass 但都识别为 Pane

  • 更新 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 时,只需将鼠标悬停在屏幕上的某个元素上即可进行检查。
    但是当我将鼠标悬停在 ListView 上时:
  • VB6 ListView (ListView20WndClass):它返回一个空字符串(以 101 为例)
  • MFC/Winform ListView (SysListView32):鼠标下的应用程序停止工作(控制台应用程序仍在运行)
  • 最佳答案

    您可以使用 pywinauto,它可以在后台使用 Win32 API 自动化 VB6 应用程序(所有细节都隐藏起来,包括 LVM_GETITEM 消息等)。大多数控件都可以识别为按钮、复选框甚至 ListView !有关 ListView ,请参阅 supported class names。您的案例在这里。

    如果使用 flexible waits ,Win32 API 应该比 UI 自动化工作得更快。虽然 UI 自动化也受支持(如果有的话)。

    Getting Started Guide 将帮助您迈出第一步并学习高级概念。也可以随意提出带有标签 pywinauto 的问题。我是图书馆的维护者。

    关于c++ - Visual Basic 6 ListView 的自动化支持,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43083781/

    10-11 23:40