gpt4 book ai didi

c++ - 在 MFC 应用程序中实现 IServiceProvider

转载 作者:行者123 更新时间:2023-11-28 04:39:16 25 4
gpt4 key购买 nike

我需要在开源MFC应用程序中实现IServiceProvider接口(interface);特别是我的 TTSApp申请。

我正在尝试添加对 IAccessibleApplication interface 的支持,屏幕阅读器使用它来获取有关应用程序名称和版本信息的信息。

Google Chrome 似乎通过 AXPlatformNodeWin 类实现 IServiceProvider 接口(interface),该类派生自 CComObjectRootEx 类和其他类和接口(interface)。问题是 MFC 应用程序不使用 CComObjectRootEx 类;它由 ATL 使用。

我找到了 IServiceProviderImpl Class .不幸的是,我找不到任何关于它如何适应应用程序上下文的信息。我的类层次结构中的哪个类需要派生自 IServiceProviderImpl 类;我的 CWinApp 派生类、我的 CDialogEx 派生类或其他一些类?

最佳答案

在寻找这个问题的答案的过程中,我学到了很多东西。在探索过程中,我掉进了兔子洞(Alice's Adventures in Wonderland 作者:Charles Lutwidge Dodgson,又名 Lewis Carroll),却发现克苏鲁(The Call of Cthulhu 作者:H. P. Lovecraft)正在等我。

我的初步研究使我找到了 afxwin.h 中定义的以下宏。

  • DECLARE_INTERFACE_MAP
  • BEGIN_INTERFACE_MAP
  • END_INTERFACE_MAP
  • BEGIN_INTERFACE_PART
  • END_INTERFACE_PART

我能找到的关于这些宏的最佳文档在 TN038: MFC/OLE IUnknown Implementation 中。技术说明。 TstCon 是一个很好的示例,演示了这些宏的使用和 QueryService 函数的实现。样本。

当然,这又引出了另一个问题,我需要针对什么窗口执行此操作?为了回答这个问题,我查看了某个屏幕阅读器的源代码,了解它如何使用 IAccessibleApplication 接口(interface)。

以下函数虽然不是实际使用的代码,但演示了该技术(我无法分享实际代码,因为屏幕阅读器不是开源的)。

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 接口(interface),并将必要的代码添加到我所有可聚焦的窗口中。令我惊恐的是,我的 QueryService 函数从未被调用过。当我调试屏幕阅读器以找出原因时,我发现以下代码行隐含的 QueryInterface 失败了。

    CComQIPtr<IServiceProvider> serviceProvider = acc;

这导致了对 QueryInterface 调用失败原因的长期艰巨探索。

起初我正在做一个个人项目,所以我无法调用我雇主的资源。然后,完全是偶然的,我被分配了一项任务,要求我向需要信息的客户提供有关如何在 C++ 应用程序中实现 IAccessible2 接口(interface)的信息,以帮助他们使他们的应用程序更易于访问。万岁,终于可以请同事帮忙了!

我的同事引导我走上了正确的道路。

  1. 使用从 atlacc.h 获得的源代码创建 IAccessibleProxyImpl 类和 CAccessibleProxy 类的自定义版本。
  2. 添加 COM_INTERFACE_ENTRY对于我的自定义 IAccessibleProxyImpl 类的 COM_MAP ( BEGIN_COM_MAP/END_COM_MAP) 中的 IAccessibleApplication。
  3. 使用BEGIN_SERVICE_MAP, END_SERVICE_MAP, and SERVICE_ENTRY macros提供 IServiceProvider 接口(interface)的实现。
  4. CWnd::CreateAccessibleProxy function 提供覆盖使我的窗口使用我自定义的可访问代理,从而使用我对 IAccessibleApplication 接口(interface)的实现。

现在屏幕阅读器使用我为我的应用程序的 IAccessibleApplication 接口(interface)提供的应用程序名称。

我这样做的应用程序是开源的。这是我的TTSApp应用。我还制作了一个示例,演示如何使用类似的技术来支持可用的 IAccessible2 接口(interface) here .

我分享此信息是希望这些信息对您有所帮助。

关于c++ - 在 MFC 应用程序中实现 IServiceProvider,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50614948/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com