Как я могу получить поле «Описание» inspect.exe в моем скрипте автоматизации на основе pywinauto? - PullRequest
0 голосов
/ 25 октября 2019

У меня есть следующий элемент SysTreeView32, из которого я хотел бы получить поле «Описание»:

The description bield is highlighted

В моем скрипте pywinauto (основан наWin32 Backend), я могу довольно легко получить элемент TreeViewWrapper, ища тип класса и в конечном итоге просматривая текст элементов, но некоторая информация, которая мне нужна, доступна только в поле Description этого элемента.

Iне удалось найти способ получить эту информацию.

Я также пытался в режиме МАУ:

enter image description here

Но в этомВ этом случае он даже не отображается в информации.

Поэтому я попытался использовать элемент TreeItemWrapper с бэкэндом UIA в pywinauto, но не смог найти соответствующее описание даже в UIAElementInfo. Хотя что-то выглядело примерно так в следующей строке:

impl = uia_defs.get_elem_interface(elem, "LegacyIAccessible").

Когда я вызываю legacy_properties из uia_controls.TreeItemWrapper, я получаю:

{'ChildId': 0,
 'DefaultAction': '',
 'Description': '',
 'Help': '',
 'KeyboardShortcut': '',
 'Name': 'Execute multiple tasks(MultiTask_ImportSysD)',
 'Role': 36,
 'State': 3145730,
 'Value': ''}

И там, Описаниепусто.

Ответы [ 2 ]

1 голос
/ 25 октября 2019

Я предполагаю, что свойство взято из IAccessible::get_accDescription.

MSDN говорит, что свойство устарело, но если вы все еще хотите его использовать, вызовите AccessibleObjectFromWindow, чтобы получить IAccessible для окна.

0 голосов
/ 29 октября 2019

Наконец, я не смог найти эту возможность через API, представленный pywinauto.

Хотя pywniauto предоставляет свойство Description через legacy_properties экземпляра uia_controls.TreeItemWrapper, но возвращает пустую строку. Это соответствует примечанию в документации Windows SDK, в котором говорится:

Примечание. Свойство Description часто используется неправильно и не поддерживается Microsoft UI Automation. Разработчики сервера Microsoft Active Accessibility не должны использовать это свойство. Если для сценариев доступности и автоматизации требуется больше информации, используйте свойства, поддерживаемые элементами UI Automation и шаблонами управления.

В конце я наконец разработал небольшой фрагмент кода для поиска элемента, которыйМне нужно описание, и я мог бы получить описание оттуда. Вот код:

# for OleAcc access
import ctypes
import comtypes, comtypes.automation, comtypes.client

comtypes.client.GetModule('oleacc.dll')

def accDescription(iaccessible, cid):
    objChildId = comtypes.automation.VARIANT()
    objChildId.vt = comtypes.automation.VT_I4
    objChildId.value = cid
    objDescription = comtypes.automation.BSTR()
    iaccessible._IAccessible__com__get_accDescription(objChildId, ctypes.byref(objDescription))
    return objDescription.value

def accRole(iaccessible, cid):
    objChildId = comtypes.automation.VARIANT()
    objChildId.vt = comtypes.automation.VT_I4
    objChildId.value = cid
    objRole = comtypes.automation.VARIANT()
    objRole.vt = comtypes.automation.VT_BSTR
    iaccessible._IAccessible__com__get_accRole(objChildId, objRole)
    return AccRoleNameMap[objRole.value]

def accState(iaccessible, cid):
    '''Get Element State'''
    objChildId = comtypes.automation.VARIANT()
    objChildId.vt = comtypes.automation.VT_I4
    objChildId.value = cid
    objState = comtypes.automation.VARIANT()
    iaccessible._IAccessible__com__get_accState(objChildId, ctypes.byref(objState))
    return objState.value

def accName(iaccessible, cid):
    '''Get Element Name'''
    objChildId = comtypes.automation.VARIANT()
    objChildId.vt = comtypes.automation.VT_I4
    objChildId.value = cid
    objName = comtypes.automation.BSTR()
    iaccessible._IAccessible__com__get_accName(objChildId, ctypes.byref(objName))
    return objName.value

def accDescendants(iaccessible):
    """Iterate all desencendants of an object iaccessible, including the current one.

    Arguments:
    iaccessible -- the IAccessible element to start from

    Yields:
    (IAcessible instance, Child id)
    """
    yield (iaccessible, 0)
    objAccChildArray = (comtypes.automation.VARIANT * iaccessible.accChildCount)()
    objAccChildCount = ctypes.c_long()
    ctypes.oledll.oleacc.AccessibleChildren(iaccessible, 0, iaccessible.accChildCount, objAccChildArray, ctypes.byref(objAccChildCount))
    for i in range(objAccChildCount.value):
        objAccChild = objAccChildArray[i]
        if objAccChild.vt == comtypes.automation.VT_DISPATCH:
            # query the sub element accessible interface
            newiaccessible = objAccChild.value.QueryInterface(comtypes.gen.Accessibility.IAccessible)
            # then loop over its descendants
            for (__i, __c) in accDescendants(newiaccessible):
                yield (__i, __c)
        else: #if objAccChild.vt == comtypes.automation.VT_I4:
            yield (iaccessible, objAccChild.value)


def findObjIAccessible(handle, text):
    """Find the IAccessible based on the name, starting from a specific window handle

    Arguments:
    handle -- the window handle from which to search for the element
    text -- text that should be contained in the name of the IAccessible instance

    Return:
    (None, 0) if not found
    (IAccessible instance, child id) of the first element whose name contains the text
    """
    iacc = ctypes.POINTER(comtypes.gen.Accessibility.IAccessible)()

    ctypes.oledll.oleacc.AccessibleObjectFromWindow(handle, 0, ctypes.byref(comtypes.gen.Accessibility.IAccessible._iid_), ctypes.byref(iacc))

    for (ia, ch) in accDescendants(iacc):
        n = accName(ia, ch)
        if n != None and text in n:
            return (ia, ch)
    else:
        return (None, 0)
...