Search code examples
c++windowswinapiui-automationmicrosoft-ui-automation

Get caption of child window button on windows using uiautomation with c++


I want to get this Zoom Meeting's "Mute My Audio" caption on windows using uiautomation with C++

enter image description here

this is my calling current code:

// 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");
  }

OUTPUT:

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

GetTopLevelWindowByName Function definitions:

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 Function definitions:

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

Spy++ windows tree of Zoom Meeting window: enter image description here

How can I crawl to child window and get it's button caption

I have no prior experience with this library so please elaborate as much you can (Thanks)



Solution

  • here the code which worked...

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

    Particularly in my case zoom has this feature that it shows all control button when we mouseover on zoom window. That's the reason I was not getting each window and button listed. So I just focused and set cursor position to zoom window before calling above function osFocusZoomWindow()