【问题标题】:Get caption of child window button on windows using uiautomation with c++使用 c++ 的 uiautomation 在 Windows 上获取子窗口按钮的标题
【发布时间】:2021-03-19 12:29:30
【问题描述】:

我想在 Windows 上使用带有 C++ 的 uiautomation 获取此 Zoom Meeting 的“静音我的音频”标题

这是我当前调用的代码:

// Get the handle of the Zoom Meetings window.
  zoomWnd = ::FindWindow(NULL, "Zoom Meeting");
  if (zoomWnd != NULL)
  {
    std::cout<<"zoom meeting"<<"\n";
    IUIAutomationElement *zoom = GetTopLevelWindowByName(L"Zoom Meeting");
    rawListDescendants(zoom, "Meeting");
  }

输出:

zoom meeting
sName: ContentLeftPanel
sName: VideoContainerWnd
sName: Video Content
sName:
sName:
sName:

GetTopLevelWindowByName 函数定义:

IUIAutomationElement *GetTopLevelWindowByName(LPWSTR windowName)
{
  if (windowName == NULL)
  {
    return NULL;
  }

  VARIANT varProp;
  varProp.vt = VT_BSTR;
  varProp.bstrVal = SysAllocString(windowName);
  if (varProp.bstrVal == NULL)
  {
    return NULL;
  }

  IUIAutomationElement *pRoot = NULL;
  IUIAutomationElement *pFound = NULL;

  // Get the desktop element.
  HRESULT hr = g_pAutomation->GetRootElement(&pRoot);
  if (FAILED(hr) || pRoot == NULL)
  {
    goto cleanup;
  }

  // Get a top-level element by name, such as "Program Manager"
  IUIAutomationCondition *pCondition = NULL;
  hr = g_pAutomation->CreatePropertyCondition(UIA_NamePropertyId, varProp, &pCondition);
  if (FAILED(hr))
  {
    goto cleanup;
  }

  pRoot->FindFirst(TreeScope_Children, pCondition, &pFound);

cleanup:
  if (pRoot != NULL)
    pRoot->Release();

  if (pCondition != NULL)
    pCondition->Release();

  VariantClear(&varProp);
  return pFound;
}

rawListDescendants 函数定义:

void rawListDescendants(IUIAutomationElement *pParent, std::string windowType)
{
  if (pParent == NULL)
    return;

  IUIAutomationTreeWalker *pControlWalker = NULL;
  IUIAutomationElement *pNode = NULL;

  g_pAutomation->get_RawViewWalker(&pControlWalker);
  if (pControlWalker == NULL)
  {
    goto cleanup;
  }

  pControlWalker->GetFirstChildElement(pParent, &pNode);
  if (pNode == NULL)
  {
    goto cleanup;
  }

  while (pNode)
  {
    BSTR desc;
    BSTR sName;

    pNode->get_CurrentLocalizedControlType(&desc);
    pNode->get_CurrentName(&sName);

    
    std::wcout<<"sName: "<<sName<<"\n";
    //std::wcout<<"desc: "<<desc<<"\n";

    // only go into windows and panes
    if (desc != NULL)
      if (0 == wcscmp(desc, L"window") || 0 == wcscmp(desc, L"pane"))
        rawListDescendants(pNode, windowType);

    if (desc != NULL)
      SysFreeString(desc);
    if (sName != NULL)
      SysFreeString(sName);

    // get the next element
    IUIAutomationElement *pNext;
    pControlWalker->GetNextSiblingElement(pNode, &pNext);
    pNode->Release();
    pNode = pNext;
  }

cleanup:
  if (pControlWalker != NULL)
    pControlWalker->Release();

  if (pNode != NULL)
    pNode->Release();

  return;
}

Zoom Meeting 窗口的 Spy++ windows 树:

如何爬到子窗口并获取它的按钮标题

我之前没有使用过这个库,所以请尽可能详细说明(谢谢)


【问题讨论】:

  • 由于您已经发现了包含源代码的文档部分(How to Find UI ElementsHow to Walk the UI Automation Tree),您需要向上导航左侧的树视图以了解您复制的代码的作用、为什么以及如何合并这些更改,以便它满足您的需要。
  • @llnspectable 谢谢人...但是你能帮我解决这个问题吗,已经花了 2 天时间解决这个问题..
  • 从使用正确的工具开始。 Spy++ 不会有帮助。 Inspect 将。
  • @llnspectable 感谢该工具,现在我可以看到其中的所有窗口和元素...imgur.com/a/tBXYqLM
  • @llnspectable 我已经创建了一个函数来列出所有具有递归功能的后代......但它没有列出所有窗口。这是代码:codepile.net/pile/xPJQXpeZ这是所有窗口:imgur.com/a/tBXYqLM

标签: c++ windows winapi ui-automation microsoft-ui-automation


【解决方案1】:

这里是有效的代码...

IUIAutomationElement *zoom = GetTopLevelWindowByName(L"Zoom Meeting");
ListDescendants(zoom, 2);

void ListDescendants(IUIAutomationElement* pParent, int indent)
{
  osFocusZoomWindow();
  if (pParent == NULL)
      return;

  IUIAutomationTreeWalker* pControlWalker = NULL;
  IUIAutomationElement* pNode = NULL;

  g_pAutomation->get_ControlViewWalker(&pControlWalker);
  if (pControlWalker == NULL)
      goto cleanup;

  pControlWalker->GetFirstChildElement(pParent, &pNode);
  if (pNode == NULL)
      goto cleanup;

  while (pNode)
  {
      BSTR sName;
      pNode->get_CurrentName(&sName);
      //std::wcout << sName << L"\n";
      std::wstring strName(sName, SysStringLen(sName));
      if (strName.find(L"currently unmuted") != std::string::npos)
      {
        std::cout<<"####### UNMUTE"<<"\n";
      }else if(strName.find(L"currently muted") != std::string::npos){
        std::cout<<"####### MUTE"<<"\n";
      }
      SysFreeString(sName);

      ListDescendants(pNode, indent+1);
      IUIAutomationElement* pNext;
      pControlWalker->GetNextSiblingElement(pNode, &pNext);
      pNode->Release();
      pNode = pNext;
  }

cleanup:
  if (pControlWalker != NULL)
      pControlWalker->Release();

  if (pNode != NULL)
      pNode->Release();

  return;
}

特别是在我的例子中,缩放具有这个功能,当我们将鼠标悬停在缩放窗口上时,它会显示所有控制按钮。这就是我没有列出每个窗口和按钮的原因。所以我只是在调用上面的函数osFocusZoomWindow()之前将光标位置设置为缩放窗口@

【讨论】:

  • 谢谢,我很难弄清楚为什么找不到静音/取消静音按钮。当我看到你的帖子时,我几乎放弃了。竖起大拇指!
【解决方案2】:

一种解决方案是您可以使用IUIAutomationElement::FindAll() 找到所有按钮,然后将名称与“静音我的音频”进行比较。

以下是您可以参考的示例(我假设您已经拥有按钮的父窗口句柄:hwnd):

IUIAutomation *pClientUIA;
IUIAutomationElement *pRootElement;

hr = pClientUIA->ElementFromHandle(hwnd, &pRootElement);
WCHAR controlName[] = L"Mute My Audio";
FindControl(UIA_ButtonControlTypeId, controlName);

查找控制功能:

void FindControl(const long controlType, BSTR controlName)
{
    HRESULT hr;
    BSTR name;
    IUIAutomationCondition *pCondition;
    VARIANT varProp;
    varProp.vt = VT_I4;
    varProp.uintVal = controlType;
    hr = pClientUIA->CreatePropertyCondition(UIA_ControlTypePropertyId, varProp, &pCondition);

    IUIAutomationElementArray *pElementFound;
    hr = pRootElement->FindAll(TreeScope_Subtree, pCondition, &pElementFound);

    int eleCount;
    pElementFound->get_Length(&eleCount);
    if (eleCount == 0)
        return;

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

        if (!lstrcmp(controlName, name))
        {
            printf("Found it!\n");    
        }
    }    
}

【讨论】:

  • 韩谢谢回复嘿我做了这两个变量 IUIAutomation *pClientUIA; IUIAutomationElement *pRootElement;全局所以 FindControl 可以使用它。但是有一些奇怪的行为代码返回 pClientUIA 并在它不执行后下一行...
  • 试过 std::cout
  • Rita Han - MSFT 我已经创建了一个函数来列出所有具有递归功能的后代......但它没有列出所有窗口。这是代码:codepile.net/pile/xPJQXpeZ 这是所有窗口:imgur.com/a/tBXYqLM
猜你喜欢
  • 2019-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多