我如何知道我的 MFC 应用程序是不是使用 COM / OLE?

Posted

技术标签:

【中文标题】我如何知道我的 MFC 应用程序是不是使用 COM / OLE?【英文标题】:How do I know if my MFC Application use COM / OLE?我如何知道我的 MFC 应用程序是否使用 COM / OLE? 【发布时间】:2020-10-15 09:09:51 【问题描述】:

我从 Win7 到 Win10,最近打开文件时遇到“不正确的参数错误”。 该错误非常罕见且随机发生。 没有提供进一步的信息或调用堆栈信息。我曾在 MFC 代码中进行过深入搜索。 DocManager 打开文档,然后调用CDocument::SetPathName(..,TRUE) 将当前文件也添加到最近文件列表中。

这个函数现在似乎使用了一个 OLE/COM 函数。

void CRecentFileList::Add(LPCTSTR lpszPathName, LPCTSTR lpszAppID)

  :
  :
  Add(lpszPathName);

  HRESULT hr = S_OK;
  CComPtr<IShellItem> psi = NULL;

  hr = _AfxSHCreateItemFromParsingName(lpszPathName, NULL, IID_IShellItem, reinterpret_cast<void**>(&psi));
  ENSURE(SUCCEEDED(hr));   // Remark Tom: This throws an AfxInvalidException()
 

hr ErrorCode 为 -2147221008,表示CoInitialize 未被调用。

我很惊讶,因为我从未使用过 COM / OLE 的东西。

一定要克服这个错误,我必须在InitInstance 中添加AfxOleInit()

我的问题是,我如何提前知道我的应用程序是否需要使用 OLE / COM?

附加问题,如果我在我的应用程序中使用 COM / OLE,我有什么缺点吗? (内存和速度)?

【问题讨论】:

由于通过 COM 公开了如此多的 Windows API 表面,因此可以合理猜测任何重要的 Windows 应用程序都会在某个时候使用 COM。将线程初始化为 COM 单元不是免费的。一旦完成,就没有任何运行时开销。为 COM 注册线程不太可能表现出任何可观察到的性能下降。请注意,COM 是按线程初始化的。 InitInstance 中的单个初始化调用只会注册您的 UI 线程。 P.S.:您的 MFC 应用程序可能一直使用 COM,但即使它应该使用它也没有失败(有关详细信息,请参阅 Why does CoCreateInstance work even though my thread never called CoInitialize? The curse of the implicit MTA)。也许在 Windows 10 中发生了一些变化。 【参考方案1】:

我的问题是,我如何提前知道我的应用程序是否需要使用 OLE / COM?

MFC 应用程序应该始终初始化 OLE/COM,特别是使用 STA(单线程单元)的并发模型。这是在向导生成的模板中自动完成的,否则必须在用户代码中明确完成。来自CWinApp 文档:

MFC 应用程序必须初始化为单线程单元 (STA)。

如果您在 InitInstance 覆盖中调用 CoInitializeEx,请指定 COINIT_APARTMENTTHREADED(而不是 COINIT_MULTITHREADED)。

始终将 OLE/COM 初始化为 STA 还可以避免 @IInspectable 在评论中提到的 the curse of the implicit MTA

【讨论】:

以上是关于我如何知道我的 MFC 应用程序是不是使用 COM / OLE?的主要内容,如果未能解决你的问题,请参考以下文章

实现 COM 接口 C++ / VC++ 6.0 / MFC

MFC 是不是有等效的 JPanel

MFC 中的动态菜单

如何使用消息访问 mfc 控件?

如何通过 mfc 应用程序中的编辑控制框更改窗口句柄?

如果我不使用 MFC,是不是需要 afxres.h?如何从 .RC 脚本中删除它?