我需要通過自動化接口(使用C++/C#編碼)獲取控制的值/文本。我試着用UI Automation API,這是一些結果由Inspect捕獲: Visual Basic 6自動化支持ListView
UI自動化識別這些控制爲pane
,我不能讓列表視圖文本項目或獲取/設置滑塊值正常。
嘗試與其他工具如MSAA,Automation Spy給出了相同的結果。
經過研究,我發現類名控件如ListView20WndClass
,Slider20WndClass
,...屬於Visual Basic 6控件。
那麼,有沒有任何API可以支持這些類型的控制?
備註1: 有一個名爲Ranorex可以支持這些控制工具(可悲的是,這是€3490商業授權),我不知道用哪個底層API:
注2 有被測應用程序中使用的一些其他控制類型的UI自動化仍然可以得到值:
- ThunderRT6FormDC:承認窗口
- ThunderRT6CommandButton:承認按鈕
- ThunderRT6CheckBox:黯然承認複選框
- 等...
- ,它們嵌入ListView20WndClass and Slide r20WndClass但都承認窗格
更新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時,只需將鼠標懸停在屏幕上的某個元素上即可進行檢查。
但是,當我將鼠標放在列表視圖:
- VB6列表視圖(ListView20WndClass):它返回一個空字符串(預期爲
101
作爲我的例子) - MFC/WinForm的列表視圖(SysListView32) :鼠標下的應用程序停止工作(控制檯應用程序仍在運行)
ListView20WndClass是VB6列表視圖,但它是由Microsoft編寫的自定義作業 - 不像以前的版本,它不基於公共控件列表視圖,因此早於UI自動化。它確實實現了相同的消息傳遞API,因此您可以跳過跨進程環節並使用LVM_GETITEMTEXT等進行閱讀。 –
你能檢查我更新的問題嗎? – phibao37