【问题标题】:MFC or WIN32 UI Automation Client Sample?MFC 或 WIN32 UI 自动化客户端示例?
【发布时间】:2024-01-16 01:15:01
【问题描述】:

我一直在寻找在 MFC(或 Win32)中使用 UI 自动化作为客户端来滚动另一个应用程序窗口的示例。但我找不到任何样品?

有谁知道或者可以提供一个吗?

【问题讨论】:

标签: winapi ui-automation


【解决方案1】:

以下是在记事本窗口上垂直滚动的 Win32 C++ 示例:testWindow.txt - Notepad

主要步骤:

  1. 使用FindWindow查找目标应用程序的主窗口句柄。

    FindWindow(L"Notepad", L"testWindow.txt - Notepad");

  2. 从上面找到的窗口句柄中获取IUIAutomationElement对象。

    pClientUIA->ElementFromHandle(targetWindow, &pRootElement);

  3. 使用UIA_ScrollBarControlTypeIdNormalizeElement查找包含滚动条的窗口句柄。

  4. 向包含滚动条的窗口发送WM_VSCROLL 消息。

    PostMessage(foundHwnd, WM_VSCROLL, SB_LINEUP, 0);

这是你可以参考的完整代码:

#include <windows.h>
#include <uiautomation.h>

IUIAutomation *pClientUIA;
IUIAutomationElement *pRootElement;

HWND FindScrollbarContainerWindow(const long controlType)
{
    HRESULT hr;
    BSTR name;
    IUIAutomationCondition *pCondition;
    VARIANT varProp;
    varProp.vt = VT_I4;
    varProp.uintVal = controlType;
    hr = pClientUIA->CreatePropertyCondition(UIA_ControlTypePropertyId, varProp, &pCondition);
    if (S_OK != hr)
    {
        printf("CreatePropertyCondition error: %d\n", hr);
    }

    IUIAutomationElementArray *pElementFound;
    hr = pRootElement->FindAll(TreeScope_Subtree, pCondition, &pElementFound);
    if (S_OK != hr)
    {
        printf("CreatePropertyCondition error: %d\n", hr);
    }
    int eleCount;
    pElementFound->get_Length(&eleCount);
    if (eleCount == 0)
        return NULL;

    for (int i = 0; i <= eleCount; i++)
    {
        IUIAutomationElement *pElement;
        hr = pElementFound->GetElement(i, &pElement);
        if (S_OK != hr)
        {
            printf("CreatePropertyCondition error: %d\n", hr);
        }
        hr = pElement->get_CurrentName(&name);
        if (S_OK != hr)
        {
            printf("CreatePropertyCondition error: %d\n", hr);
        }
        wprintf(L"Control Name: %s\n", name);

        hr = pElement->get_CurrentClassName(&name);
        if (S_OK != hr)
        {
            printf("CreatePropertyCondition error: %d\n", hr);
        }
        wprintf(L"Class Name: %s\n", name);

        IUIAutomationTreeWalker* pContentWalker = NULL;

        hr = pClientUIA->get_ContentViewWalker(&pContentWalker);
        if (pContentWalker == NULL)
            return NULL;

        // Get ancestor element nearest to the scrollbar UI Automation element in the tree view
        IUIAutomationElement *ncestorElement;
        hr = pContentWalker->NormalizeElement(pElement, &ncestorElement);

        hr = ncestorElement->get_CurrentName(&name);
        wprintf(name);

        // Get window handle of ancestor element
        UIA_HWND controlContainerHwnd = NULL;
        hr = ncestorElement->get_CurrentNativeWindowHandle(&controlContainerHwnd);
        printf("");

        if (controlContainerHwnd)
        {
            return (HWND)controlContainerHwnd;
        }
    }

    return NULL;
}

int main()
{
    // Find target window
    HWND targetWindow = FindWindow(L"Notepad", L"testWindow.txt - Notepad");
    if (NULL == targetWindow)
    {
        printf("FindWindow fails with error: %d\n", GetLastError());
        return FALSE;
    }

    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    if (S_OK != hr)
    {
        printf("CoInitializeEx error: %d\n", hr);
        return 1;
    }

    hr = CoCreateInstance(CLSID_CUIAutomation, NULL, CLSCTX_INPROC_SERVER, IID_IUIAutomation, reinterpret_cast<void**>(&pClientUIA));
    if (S_OK != hr)
    {
        printf("CoCreateInstance error: %d\n", hr);
        return 1;
    }

    hr = pClientUIA->ElementFromHandle(targetWindow, &pRootElement);
    if (S_OK != hr)
    {
        printf("ElementFromHandle error: %d\n", hr);
        return 1;
    }

    // Find scroll bar and its containing window
    HWND foundHwnd = FindScrollbarContainerWindow(UIA_ScrollBarControlTypeId);
    if (NULL == foundHwnd)
        return 1;

    // Vertical scroll bar
    // Line up - Like click top arrow button to scroll up one line
    PostMessage(foundHwnd, WM_VSCROLL, SB_LINEUP, 0);
    Sleep(1000);

    // Line down
    PostMessage(foundHwnd, WM_VSCROLL, SB_LINEDOWN, 0);
    Sleep(1000);

    // Page up
    PostMessage(foundHwnd, WM_VSCROLL, SB_PAGEUP, 0);
    Sleep(1000);

    // Page down
    PostMessage(foundHwnd, WM_VSCROLL, SB_LINEDOWN, 0);
    Sleep(1000);
}

------------------------------------------ ------------------

更新:

另一种方法是使用IUIAutomationScrollPattern::Scroll()。更直接、更简单。 Similar thread.

【讨论】: