如何维护资源管理器项目视图中当前可见的项目列表

How to maintain a list of the items currently visible in Explorer's items view

本文关键字:项目 列表 视图 维护 资源管理器 何维护      更新时间:2023-10-16

我正在尝试维护一个代表Explorer项目视图中项目的IUIAutomationElement列表(即向量或集合(。我已经为items视图本身获得了一个IUIAutomationElement,所以从那里我基本上是在尝试跟踪它的item子项。我还需要访问视图中每个项的索引(通过此处讨论的属性(。

我目前的方法是,每当用户滚动时,例如,我用UIA_ListItemControlTypeIdFindAll项目视图的子项。这种方法有效而且非常简单,但我想知道它是否效率太低了。因为在任何卷轴上,无论多小,都要做很多工作。

我的另一个想法是在items视图中为StructureChangedEvent设置一个事件处理程序,它可以在孩子们来来去去时跟踪他们。但在使用AccEvent后,在孩子离开后,被丢弃的孩子的属性似乎不可用,因此我将无法访问该元素(以前的(索引(该属性不适用于虚拟化项目(。所以我不知道从向量中删除什么元素。

那么,还有其他潜在的策略来监视项目视图的子项吗?还是FindAll是最好的选择,即使它效率低下?

Microsoft UI Automation允许客户端订阅感兴趣的事件。此功能无需持续轮询系统中的UI元素以查看是否有任何信息、结构或状态发生了更改,从而提高了性能

对于这种情况,我们可以通过AddStructureChangedEventHandler订阅结构更改事件。请参阅下面关于处理结构更改事件的代码示例:

// Defines an event handler for structure-changed events, and 
// listens for them on the element specifies by the user.
#include <windows.h>
#include <stdio.h>
#include <UIAutomation.h>
class EventHandler:
public IUIAutomationStructureChangedEventHandler
{
private:
LONG _refCount;
public:
int _eventCount;
// Constructor.
EventHandler(): _refCount(1), _eventCount(0) 
{
}
// IUnknown methods.
ULONG STDMETHODCALLTYPE AddRef() 
{
ULONG ret = InterlockedIncrement(&_refCount);
return ret;
}
ULONG STDMETHODCALLTYPE Release() 
{
ULONG ret = InterlockedDecrement(&_refCount);
if (ret == 0) 
{
delete this;
return 0;
}
return ret;
}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppInterface) 
{
if (riid == __uuidof(IUnknown))
*ppInterface=static_cast<IUIAutomationStructureChangedEventHandler*>(this);
else if (riid == __uuidof(IUIAutomationStructureChangedEventHandler)) 
*ppInterface=static_cast<IUIAutomationStructureChangedEventHandler*>(this);
else 
{
*ppInterface = NULL;
return E_NOINTERFACE;
}
this->AddRef();
return S_OK;
}
// IUIAutomationStructureChangedEventHandler methods
HRESULT STDMETHODCALLTYPE HandleStructureChangedEvent(IUIAutomationElement* pSender, StructureChangeType changeType, SAFEARRAY* pRuntimeID) {
_eventCount++;
switch (changeType) 
{
case StructureChangeType_ChildAdded:
wprintf(L">> Structure Changed: ChildAdded! (count: %d)n", _eventCount);
break;
case StructureChangeType_ChildRemoved:
wprintf(L">> Structure Changed: ChildRemoved! (count: %d)n", _eventCount);
break;
case StructureChangeType_ChildrenInvalidated:
wprintf(L">> Structure Changed: ChildrenInvalidated! (count: %d)n", _eventCount);
break;
case StructureChangeType_ChildrenBulkAdded:
wprintf(L">> Structure Changed: ChildrenBulkAdded! (count: %d)n", _eventCount);
break;
case StructureChangeType_ChildrenBulkRemoved:
wprintf(L">> Structure Changed: ChildrenBulkRemoved! (count: %d)n", _eventCount);
break;
case StructureChangeType_ChildrenReordered:
wprintf(L">> Structure Changed: ChildrenReordered! (count: %d)n", _eventCount);
break;
}
return S_OK;
}
};
int main(int argc, char* argv[]) 
{
HRESULT hr;
int ret = 0;
IUIAutomationElement* pTargetElement = NULL;
EventHandler* pEHTemp = NULL;
CoInitializeEx(NULL,COINIT_MULTITHREADED);
IUIAutomation* pAutomation=NULL;
hr = CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation), (void**)&pAutomation);
if (FAILED(hr) || pAutomation == NULL) 
{
ret = 1;
goto cleanup;
}
wprintf(L"-Use the mouse to point to the element you want to listen from.n");
Sleep(3000);
// Make this application dots-per-inch (DPI) aware.
SetProcessDPIAware();
// Get mouse cursor position and get element from point.
POINT pt;
GetPhysicalCursorPos(&pt);
hr = pAutomation->ElementFromPoint(pt, &pTargetElement);
if (FAILED(hr) || pTargetElement == NULL) 
{
ret = 1;
goto cleanup;
}
pEHTemp = new EventHandler();
if (pEHTemp == NULL) 
{
ret = 1;
goto cleanup;
}
wprintf(L"-Adding Event Handler.n");
hr = pAutomation->AddStructureChangedEventHandler(pTargetElement, TreeScope_Subtree, NULL, (IUIAutomationStructureChangedEventHandler*) pEHTemp);
if (FAILED(hr)) 
{
ret = 1;
goto cleanup;
}
wprintf(L"-Press any key to remove event handler and exitn");
getchar();
wprintf(L"-Removing Event Handler.n");
hr = pAutomation->RemoveStructureChangedEventHandler(pTargetElement, (IUIAutomationStructureChangedEventHandler*) pEHTemp);
if (FAILED(hr)) 
{
ret = 1;
goto cleanup;
}
// Release resources and terminate.
cleanup:
if (pEHTemp != NULL) 
pEHTemp->Release();
if (pTargetElement != NULL) 
pTargetElement->Release();
if (pAutomation != NULL) 
pAutomation->Release();
CoUninitialize();
return ret;
}

这是一份关于订阅UI自动化事件的有用文档。