求助, IAccessible 的问题
本帖最后由 hiroyukki 于 2013-05-30 17:16:20 编辑 有个需求是遍历某个 HWND 上的 IAccessible 对象,查文档拼凑如类似如下的代码,但似乎只能枚举到直接的一层子 IAccessible,孙子辈的就枚举不到了。
有做过的大牛指点一下吗,感激不尽
#include <windows.h>
#include <oleacc.h>
#include <stdio.h>
#include <comutil.h>
#include <Shlwapi.h>
#include <string>
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "oleacc.lib")
#pragma comment(lib, "comsuppw.lib")
#pragma comment(lib, "Shlwapi.lib")
using namespace std;
typedef BOOL (WINAPI* pfnAccHandler)(IAccessible*, void*);
#define _HRELEASE(p) \
if (p) \
{ \
p->Release(); \
p = NULL; \
} \
p \
string ToMultiByte(const wstring &str)
{
string ret;
int count = WideCharToMultiByte(CP_ACP, 0, str.c_str(), -1, NULL, 0, NULL, NULL);
if (count > 0)
{
char* buffer = (char*)malloc(count);
if (buffer)
{
WideCharToMultiByte(CP_ACP, 0, str.c_str(), -1, buffer, count, NULL, NULL);
ret = buffer;
free((void*)buffer);
}
}
return ret;
}
BOOL WINAPI AccGetRole(IAccessible* pAcc, LPWSTR wszRole, DWORD dwRoleSize)
{
BOOL bRet = FALSE;
VARIANT varRole;
VARIANT varSelf;
VariantInit(&varRole);
VariantInit(&varSelf);
varSelf.vt = VT_I4;
varSelf.lVal = CHILDID_SELF;
if (S_OK == (pAcc->get_accRole(varSelf, &varRole)))
{
if (VT_I4 == varRole.vt)
{
UINT nRole = varRole.lVal;
GetRoleTextW(nRole, wszRole, dwRoleSize);
bRet = TRUE;
}
else if (VT_BSTR == varRole.vt)
{
_bstr_t bRole(varRole.bstrVal, TRUE);
wnsprintfW(wszRole, dwRoleSize, L"%s", (wchar_t*)bRole);
bRet = TRUE;
}
}
VariantClear(&varRole);
VariantClear(&varSelf);
return bRet;
}
BOOL WINAPI AccGetName(IAccessible* pAcc, LPWSTR wszName, DWORD dwNameSize)
{
BOOL bRet = FALSE;
VARIANT varSelf;
VariantInit(&varSelf);
varSelf.vt = VT_I4;
varSelf.lVal = CHILDID_SELF;
BSTR bName;
if (S_OK == pAcc->get_accName(varSelf, &bName))
{
wnsprintfW(wszName, dwNameSize, L"%s", bName);
SysFreeString(bName);
bRet = TRUE;
}
VariantClear(&varSelf);
return bRet;
}
static BOOL WINAPI _AccEnumChild(IAccessible* pAccParent, pfnAccHandler pfnHandler, void* lpParam)
{
BOOL bRet = FALSE;
VARIANT varChild;
IEnumVARIANT* pEnum = NULL;
IAccessible* pAccChild = NULL;
VariantInit(&varChild);
do
{
if (!pAccParent || !pfnHandler)
{
break;
}
if (!pfnHandler(pAccParent, lpParam))
{
break;
}
pAccParent->QueryInterface(IID_IEnumVARIANT, (void**)(&pEnum));
if (pEnum)
{
pEnum->Reset();
}
long lChildCount = 0;
pAccParent->get_accChildCount(&lChildCount);
// 没有子就跳过
if (!lChildCount)
{
bRet = TRUE;
break;
}
printf("有子 %d 个\n", lChildCount);
BOOL bBreak = FALSE;
ULONG ulFetched = 0;
for (long index = 1; index <= lChildCount; ++index)
{
VariantClear(&varChild);
_HRELEASE(pAccChild);
if (pEnum)
{
if (!SUCCEEDED(pEnum->Next(1, &varChild, &ulFetched)))
{
continue;
}
}
else
{
varChild.vt = VT_I4;
varChild.lVal = index;
}
if (VT_I4 == varChild.vt)
{
pAccParent->get_accChild(varChild, (IDispatch**)(&pAccChild));
}
if (!pAccChild)
{
printf("!pAccChild\n");
continue;
}
if (!_AccEnumChild(pAccChild, pfnHandler, lpParam))
{
bBreak = TRUE;
break;
}
}
if (!bBreak)
{
bRet = TRUE;
}
} while (FALSE);
_HRELEASE(pAccChild);
_HRELEASE(pEnum);
VariantClear(&varChild);
return bRet;
}
BOOL WINAPI _AccIterator(IAccessible* pAcc, void* lpParam)
{
WCHAR wszRole[1024] = {0};
if (AccGetRole(pAcc, wszRole, RTL_NUMBER_OF(wszRole)))
{
printf("Role: %s\n", ToMultiByte(wszRole).c_str());
}
WCHAR wszName[1024] = {0};
if (AccGetName(pAcc, wszName, RTL_NUMBER_OF(wszName)))
{
printf("Name: %s\n", ToMultiByte(wszName).c_str());
}
return TRUE;
}
int main()
{
HWND hWnd = FindWindowA("Chrome_WidgetWin_1", NULL);
if (!IsWindow(hWnd))
{
printf("未找到窗口\n");
return 1;
}
IAccessible* pAccMain = NULL;
AccessibleObjectFromWindow(hWnd, OBJID_WINDOW, IID_IAccessible, (void**)(&pAccMain));
if (!pAccMain)
{
return 1;
}
_AccEnumChild(pAccMain, _AccIterator, NULL);
_HRELEASE(pAccMain);
return 0;
}
#undef _HRELEASE
[解决办法]
一般来说肯定是把当前的节点当做父节点再递归调用枚举函数哦...
[解决办法]
用VS自带的Spy++也只是看到这一层吧。不懂帮顶