我需要通过自动化界面获取控制值/文本(用C ++ / C#编码)。我尝试使用UI Automation API,这是Inspect捕获的一些结果:
UI自动化将这些控件识别为pane
,我无法获得列表视图文本项或获取/设置滑块值。
尝试使用其他工具,例如MSAA,Automation Spy会得到相同的结果。
经过研究,我发现类名为ListView20WndClass
,Slider20WndClass
,...的控件属于Visual Basic 6控件。
那么,有没有API可以支持这些类型的控制呢?
备注1 :
有一个名为Ranorex的工具可以支持这些控制(遗憾的是,它是3490欧元的商业许可证),而且我不知道使用了哪种底层API:
备注2
在测试的应用程序中使用了一些其他控件类型,UI Automation仍然可以获得价值:
更新1
我创建了一个简单的程序来获取文本但仍然无法正常工作(编译为Unicode字符集):
#include <iostream>
using namespace std;
#include <UIAutomation.h>
#include <atlstr.h>
#include <Commctrl.h>
CString getListViewItemText(HWND hwnd, int nItem, int nSubItem) {
LVITEM item;
memset(&item, 0, sizeof(LVITEM));
item.iSubItem = nSubItem;
CString string;
int Length = 64; //initial reasonable string length
int ReturnCode;
do {
Length *= 2; //resize the string buffer
item.cchTextMax = Length;
item.pszText = string.GetBufferSetLength(Length);
ReturnCode = (int)::SendMessage(hwnd, LVM_GETITEMTEXT,
(WPARAM)nItem, (LPARAM)&item);
printf("len = %d \n", ReturnCode);
} while (ReturnCode == Length - 1); //if could not get all chars, try again
string.ReleaseBuffer();
return string;
}
void UI_Spy() {
// Init COM
CoInitialize(NULL);
// Init UIAutomation instance
IUIAutomation *pAuto;
CoCreateInstance(CLSID_CUIAutomation, NULL,
CLSCTX_INPROC_SERVER, IID_IUIAutomation, reinterpret_cast<void**>(&pAuto));
if (pAuto) {
IUIAutomationElement *pElm;
POINT p;
for (int i = 0; i < 10; i++) {
for (int j = 5; j > 0; j--) {
Sleep(1000);
printf("%d ", j);
}
GetCursorPos(&p);
if (pAuto->ElementFromPoint(p, &pElm) == S_OK) {
wprintf(L"\nPOSITION x = %d, y = %d\n", p.x, p.y);
BSTR str;
pElm->get_CurrentName(&str);
wprintf(L"-Name = %s\n", str);
SysFreeString(str);
pElm->get_CurrentLocalizedControlType(&str);
wprintf(L"-Type = %s\n", str);
SysFreeString(str);
CONTROLTYPEID typeId;
pElm->get_CurrentControlType(&typeId);
switch (typeId) {
// Process checkbox
case UIA_CheckBoxControlTypeId:
IUIAutomationTogglePattern *toggle;
pElm->GetCurrentPattern(UIA_TogglePatternId, (IUnknown**)&toggle);
ToggleState state;
toggle->get_CurrentToggleState(&state);
printf("-Checkbox = %s\n", state == ToggleState::ToggleState_On ? "TRUE"
: (state == ToggleState::ToggleState_Off ? "FALSE" : "INTER"));
break;
// Process VB6 listview
case UIA_PaneControlTypeId:
pElm->get_CurrentClassName(&str);
if (str != nullptr && wcscmp(str, L"ListView20WndClass") == 0) {
HWND hwnd;
pElm->get_CurrentNativeWindowHandle((UIA_HWND*)&hwnd);
printf("-VB6 Listview: %p\n", hwnd);
CString txt = getListViewItemText(hwnd, 0, 0);
//txt = "Test";
printf("-[0,0] = %S\n", (const wchar_t*)txt);
}
SysFreeString(str);
break;
// Process normal listview
case UIA_ListControlTypeId:
HWND hwnd;
pElm->get_CurrentNativeWindowHandle((UIA_HWND*)&hwnd);
printf("-Normal Listview: %p\n", hwnd);
CString txt = getListViewItemText(hwnd, 0, 0);
//txt = "Test";
printf("-[0,0] = %S\n", (const wchar_t*)txt);
break;
}
wprintf(L"\n");
pElm->Release();
}
printf("\n");
}
// Release UIAutomation instance
pAuto->Release();
}
// Release COM
CoUninitialize();
}
int main()
{
UI_Spy();
cin.get();
return 0;
}
当它计数5..4..3..2..1时,只需将鼠标悬停在屏幕上的某个元素上即可查看
但是当我将鼠标悬停在列表视图上时:
101
作为我的例子)答案 0 :(得分:1)
ListView.ListItem对象没有hwnd。
您应该通过类名搜索ListView,然后使用SendMessage()发送消息LVM_GETITEM并使用LVITEM结构获取有关项目的信息:
LVM_GETITEM消息(Windows)
https://msdn.microsoft.com/en-us/library/windows/desktop/bb774953(v=vs.85).aspx
LVITEM结构(Windows)
https://msdn.microsoft.com/en-us/library/windows/desktop/bb774760(v=vs.85).aspx
此参考页面可以帮助您:
列表视图控件参考(Windows)https://msdn.microsoft.com/en-us/library/windows/desktop/ff485973(v=vs.85).aspx
修改强> 但是,您的问题与VB6语言编程无关。 所以,我认为这是一个错误的论坛,你应该在与你的语言相关的论坛上询问。
答案 1 :(得分:1)
您可以使用pywinauto,它可以使用Win32 API自动化VB6应用程序(隐藏所有详细信息,包括LVM_GETITEM
消息等)。大多数控件可以被识别为按钮,复选框甚至列表视图!有关列表视图,请参阅supported class names。你的案子在这里。
如果使用flexible waits,Win32 API应该比使用UI Automation更快。虽然UI Automation也受到支持,但如果有的话。
Getting Started Guide将帮助您完成第一步并学习高级概念。也可以随意使用标记pywinauto
提问。我是图书馆维护者。