问题
I need to get value/text of control via automation interface (coding with C++/C#). I tried with UI Automation API and this is some result captured by the Inspect:
UI Automation recognize these control as pane
and I can't get list view text item or get/set slider value as normal.
Tried with other tool like MSAA, Automation Spy give the same result.
After researching, I found that control with class name like ListView20WndClass
, Slider20WndClass
, ... belong to Visual Basic 6 control.
So, Is there any API can support these type of control as well?
Remark 1:
There is a tool named Ranorex can support these control (sadly, it is €3490 commercial license), and I don't know which underlying API was used:
Remark 2
There are some other control type used in the application under test that UI Automation still can get value:
- ThunderRT6FormDC: recognize as window
- ThunderRT6CommandButton: recognize as button
- ThunderRT6CheckBox: recognize as checkbox
- etc...
- sadly, they embed ListView20WndClass and Slider20WndClass but both recognize as pane
Update 1
I create a simple program to get text but still not working (compile as Unicode Character Set):
#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;
}
When it count 5..4..3..2..1 just mouse over some element on the screen to check.
But when I mouse over the list view:
- VB6 list view (ListView20WndClass): it return an empty string (expected is
101
as my example) - MFC/Winform list view (SysListView32): the application under mouse stopped working (the console application still running)
回答1:
You can use pywinauto which can automate VB6 apps using Win32 API under the hood (all details are hidden including LVM_GETITEM
message etc.). Most of the controls can be recognized as buttons, check boxes and even list views! See supported class names for list views. Your cases are here.
And Win32 API should work faster than with UI Automation if using flexible waits. Though UI Automation is also supported under the hood if any.
The Getting Started Guide will help you to do first steps and to learn the high level concept. Also feel free to ask questions with tag pywinauto
. I'm the library maintainer.
回答2:
ListView.ListItem object has not hwnd.
You should search ListView by class name, next use SendMessage() to send the message LVM_GETITEM and using the LVITEM structure to get info about items:
LVM_GETITEM message (Windows)
https://msdn.microsoft.com/en-us/library/windows/desktop/bb774953(v=vs.85).aspx
LVITEM structure (Windows)
https://msdn.microsoft.com/en-us/library/windows/desktop/bb774760(v=vs.85).aspx
this reference page may help you:
List-View Control Reference (Windows) https://msdn.microsoft.com/en-us/library/windows/desktop/ff485973(v=vs.85).aspx
EDIT However, your problem is not related to VB6 language programming. So, I think that this is the wrong forum, you should ask on forum related to Your language to use for.
来源:https://stackoverflow.com/questions/43083781/automation-support-for-visual-basic-6-listview