我正在尝试使用IAccessible2 API: http://www.linuxfoundation.org/collaborate/workgroups/accessibility/iaccessible2访问(仅限Windows) Firefox/Thunderbird中的信息然而我几乎在第一步就失败了。我可以获得两个应用程序的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)是意外的,则返回this,否则调用QueryInterface(对于错误的接口ID将返回E_NOINTERFACE)。所以…这意味着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
我做错了什么吗?
HRESULT hr = AccessibleObjectFromWindow(hw, OBJID_WINDOW, IID_IAccessible, (void**)&pIA);
if (!SUCCEEDED(hr))
return -1;
我认为问题在这里-用OBJID_CLIENT替换OBJID_WINDOW,它似乎起作用了。(我没有注册typelib,但我可以QS IID_IAccessible和IUnknown接口,它似乎起作用了。此外,请确保CoInitialize() Also。)
IAccessible有一个有趣的层次结构:每个HWND都有一个"窗口"部分和一个"客户端"部分。这部分是由于Win32的内部工作方式;Win32 HWND可以拥有标题栏、菜单、滚动条等项目,它们都共享相同的HWND -以及实际控件内容所在的内容区域(即客户端区域)。为了让这些项目有自己的表示,MSAA的设计者选择了一个两层结构,其中OBJID_WINDOW代表整个窗口,它的子结构代表滚动条、菜单栏、标题栏等——如果它们存在的话。
实现可访问性的窗口部分,然而,通常是客户端部分,所以你通常需要请求OBJID_CLIENT来获得'真正的' IAccessible。