在 windows 上使用 uiautomation 和 c++ 获取 child window 按钮的标题
Get caption of child window button on windows using uiautomation with c++
我想在 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;
}
Spy++ windows Zoom Meeting 树 window:
如何抓取 child window 并获取它的按钮标题
我之前没有使用过这个库,所以请尽可能详细说明(谢谢)
一个解决方案是您可以使用 IUIAutomationElement::FindAll()
找到所有按钮,然后将名称与“Mute My Audio”进行比较。
以下是您可以参考的示例(我假设您已经拥有按钮的父 window 句柄: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");
}
}
}
这里是有效的代码...
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;
}
特别是在我的案例中,zoom 具有此功能,当我们将鼠标悬停在 zoom window 上时,它会显示所有控制按钮。这就是我没有列出每个 window 和按钮的原因。所以我只是在调用上面的函数 osFocusZoomWindow()
之前聚焦并将光标位置设置为缩放 window
我想在 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;
}
Spy++ windows Zoom Meeting 树 window:
如何抓取 child window 并获取它的按钮标题
我之前没有使用过这个库,所以请尽可能详细说明(谢谢)
一个解决方案是您可以使用 IUIAutomationElement::FindAll()
找到所有按钮,然后将名称与“Mute My Audio”进行比较。
以下是您可以参考的示例(我假设您已经拥有按钮的父 window 句柄: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");
}
}
}
这里是有效的代码...
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;
}
特别是在我的案例中,zoom 具有此功能,当我们将鼠标悬停在 zoom window 上时,它会显示所有控制按钮。这就是我没有列出每个 window 和按钮的原因。所以我只是在调用上面的函数 osFocusZoomWindow()