Automation support for Visual Basic 6 ListView

我是研究僧i 提交于 2021-01-27 08:20:18

问题


I need to get value/text of control via automation interface (coding with C++/C#). I tried with UI Automation API and this is some result captured by the Inspect:

UI Automation recognize these control as pane and I can't get list view text item or get/set slider value as normal.
Tried with other tool like MSAA, Automation Spy give the same result.

After researching, I found that control with class name like ListView20WndClass, Slider20WndClass, ... belong to Visual Basic 6 control.
So, Is there any API can support these type of control as well?

Remark 1: There is a tool named Ranorex can support these control (sadly, it is €3490 commercial license), and I don't know which underlying API was used:


Remark 2 There are some other control type used in the application under test that UI Automation still can get value:

  • ThunderRT6FormDC: recognize as window
  • ThunderRT6CommandButton: recognize as button
  • ThunderRT6CheckBox: recognize as checkbox
  • etc...
  • sadly, they embed ListView20WndClass and Slider20WndClass but both recognize as pane


Update 1 I create a simple program to get text but still not working (compile as Unicode Character Set):

#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;
}


When it count 5..4..3..2..1 just mouse over some element on the screen to check.
But when I mouse over the list view:

  • VB6 list view (ListView20WndClass): it return an empty string (expected is 101 as my example)
  • MFC/Winform list view (SysListView32): the application under mouse stopped working (the console application still running)

回答1:


You can use pywinauto which can automate VB6 apps using Win32 API under the hood (all details are hidden including LVM_GETITEM message etc.). Most of the controls can be recognized as buttons, check boxes and even list views! See supported class names for list views. Your cases are here.

And Win32 API should work faster than with UI Automation if using flexible waits. Though UI Automation is also supported under the hood if any.

The Getting Started Guide will help you to do first steps and to learn the high level concept. Also feel free to ask questions with tag pywinauto. I'm the library maintainer.




回答2:


ListView.ListItem object has not hwnd.

You should search ListView by class name, next use SendMessage() to send the message LVM_GETITEM and using the LVITEM structure to get info about items:

LVM_GETITEM message (Windows)

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

LVITEM structure (Windows)

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

this reference page may help you:

List-View Control Reference (Windows) https://msdn.microsoft.com/en-us/library/windows/desktop/ff485973(v=vs.85).aspx

EDIT However, your problem is not related to VB6 language programming. So, I think that this is the wrong forum, you should ask on forum related to Your language to use for.



来源:https://stackoverflow.com/questions/43083781/automation-support-for-visual-basic-6-listview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!