我正在尝试使用IAccessible2 API访问(仅限Windows)Firefox / Thunderbird中的信息:http://www.linuxfoundation.org/collaborate/workgroups/accessibility/iaccessible2 然而,我几乎在第一步就失败了。我可以为任一应用程序获取IAccessible接口,然后获取IServiceProvider接口。但是当我调用QueryService来获取IAccessible2接口时,如下所述:http://accessibility.linuxfoundation.org/a11yspecs/ia2/docs/html/_generalinfo.html#_dicoveringInterfaces它总是返回E_INVALIDARG。
AccProbe成功返回两个应用程序的IA2信息。 QueryService的MS文档未将E_INVALIDARG列为可能的返回值。但是,浏览mozilla源时,如果第一个参数(服务ID)是意外的,它会返回此值,否则会调用QueryInterface(这将返回E_NOINTERFACE以获取错误的接口ID)。所以...这意味着QueryService的第一个参数是错误的;但是我已经尝试了几乎所有我认为mozilla期望的价值而没有差别。
我从c#开始,然后在c ++中再次尝试,以防我在InterOp中丢失了一些东西。两种语言都有相同的结果。这是我目前的c ++测试代码:
HWND hw = GetForegroundWindow();
IAccessible *pIA;
HRESULT hr = AccessibleObjectFromWindow(hw, OBJID_WINDOW, IID_IAccessible, (void**)&pIA);
if (!SUCCEEDED(hr))
return -1;
// SNIP - calls pIA->get_accName to check correct window is being accessed. This works OK.
const IID IID_IAccessible2 = {0xE89F726E, 0xC4F4, 0x4c19, 0xbb, 0x19, 0xb6, 0x47, 0xd7, 0xfa, 0x84, 0x78};
::IServiceProvider *pService = NULL;
hr = pIA->QueryInterface(IID_IServiceProvider, (void **)&pService);
if(SUCCEEDED(hr))
{
IAccessible2 *pIA2 = NULL;
hr = pService->QueryService(IID_IAccessible2, IID_IAccessible2, (void**)&pIA2);
if (SUCCEEDED(hr) && pIA2)
{
// Always fails with E_INVALIDARG
pIA2->Release();
}
pService->Release();
}
这一切都在Win7上 - 使用32位和64位。 Firefox 3.6.24和Thunderbird 8.0。 Visual Studio 2005
我做错了吗?
答案 0 :(得分:1)
HRESULT hr = AccessibleObjectFromWindow(hw, OBJID_WINDOW, IID_IAccessible, (void**)&pIA);
if (!SUCCEEDED(hr))
return -1;
我认为问题出在这里 - 用OBJID_CLIENT替换OBJID_WINDOW,它似乎有效。 (我没有注册typelib,但我可以为IID_IAccessible和IUnknown接口进行QS,它似乎也可以工作。另外,一定要确保CoInitialize()。)
IAccessible有一个有趣的层次结构:每个HWND都有一个“窗口”部分和一个“客户端”部分。这部分是由于Win32如何在内部工作; Win32 HWND可以包含标题栏,菜单,滚动条等项目,它们共享相同的HWND - 以及实际控制内容所在的内容区域(客户区域)。为了允许这些项目有自己的表示,MSAA的设计者选择了一个两级结构,其中OBJID_WINDOW代表整个窗口,它有子项,然后代表滚动条,菜单栏,标题栏等等 - 如果它们是本。
然而,实现accessiblity的窗口部分通常是客户端部分,因此您通常需要请求OBJID_CLIENT来获取“真正的”IAccessible。