我需要在开源MFC应用程序中实现IServiceProvider接口;特别是我的TTSApp申请。
我正在尝试添加对IAccessibleApplication interface的支持,屏幕阅读器使用该IServiceProviderImpl Class来获取有关应用程序名称和版本信息的信息。
Google Chrome似乎通过AXPlatformNodeWin类实现了IServiceProvider接口,该类派生自CComObjectRootEx类以及其他类和接口。问题是MFC应用程序不使用CComObjectRootEx类;它由ATL使用。
我找到了{{3}}。不幸的是,我无法找到有关它如何适合应用程序上下文的任何信息。我的类层次结构中的哪个类需要从IServiceProviderImpl类派生;我的CWinApp派生类,我的CDialogEx派生类,还是其他一些类?
答案 0 :(得分:0)
我在寻找这个问题答案的过程中学到了很多东西。在这个任务中,我堕下了兔子洞(Alice's Adventures in Wonderland,查尔斯·路特维奇·道奇森,a.k.a.刘易斯·卡罗尔),却发现Cthulhu(H. {Lovecraft The Call of Cthulhu)在等我。
我最初的研究使我得到了afxwin.h中定义的以下宏。
我可以在TN038: MFC/OLE IUnknown Implementation技术说明中找到这些宏的最佳文档。一个很好的示例演示了这些宏的使用以及QueryService函数的实现是TstCon示例。
当然,这导致了另一个问题,我需要在哪个窗口执行此操作?为了回答这个问题,我查看了某个屏幕阅读器的源代码,看看它是如何使用IAccessibleApplication接口的。
以下函数虽然不是实际使用的代码,但演示了该技术(由于屏幕阅读器不是开源的,我无法共享实际代码)。
std::wstring GetApplicationNameUsingTheIAccessibleApplicationInterface(
HWND hwnd, long idObject, long idChild)
{
CComPtr<IAccessible> acc;
CComVariant var;
auto hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &acc, &var);
if (hr != S_OK) return L"";
if (!acc) return L"";
CComQIPtr<IServiceProvider> serviceProvider = acc;
if (!serviceProvider) return L"";
CComQIPtr<IAccessibleApplication> application;
hr = serviceProvider->QueryService(
IID_IAccessible, __uuidof(IAccessibleApplication),
reinterpret_cast<void**>(&application));
if (FAILED(hr)) return L"";
if (!application) return L"";
CComBSTR appName;
hr = application->get_appName(&text);
if (FAILED(hr)) return L"";
return appName.m_str;
}
此函数或类似函数从我们的WinEventProc callback function调用,以响应EVENT_OBJECT_FOCUS事件。这表明我需要为每个可以获得焦点的窗口执行此操作。
我认为是我的问题的答案,我潜入并实现了IAccessibleApplication接口,并为我所有可关注的窗口添加了必要的代码。令我恐惧的是,我的QueryService函数从未被调用过。当我调试屏幕阅读器以找出原因时,我发现下面一行代码隐含的隐式QueryInterface失败了。
CComQIPtr<IServiceProvider> serviceProvider = acc;
这导致了一个漫长而艰巨的任务,即发现调用QueryInterface失败的原因。
我一开始就在做个人项目,所以我无法调用我雇主的资源。然后,完全偶然的,我被分配了一项任务,要求我提供有关如何在C ++应用程序中实现IAccessible2接口的信息给需要信息的客户端,以帮助他们使应用程序更易于访问。华友世纪,我终于可以联系同事寻求帮助了!
我的同事引导我走上正确的道路。
现在,屏幕阅读器使用我为我的应用程序提供的IAccessibleApplication接口的应用程序名称。
我这样做的应用程序是开源的。这是我的TTSApp申请。我还举了一个例子来演示如何使用类似的技术来支持可用的IAccessible2接口here。
我正在分享这一点,希望这些信息能够证明是有用的。