在 MFC+ATL EXE 中使用带有未注册接口的 IDispatchImpl

Posted

技术标签:

【中文标题】在 MFC+ATL EXE 中使用带有未注册接口的 IDispatchImpl【英文标题】:Using IDispatchImpl with an Unregistered Interface in an MFC+ATL EXE 【发布时间】:2013-12-07 18:22:31 【问题描述】:

我将该项目作为 MFC 应用程序(用于 GUI..)开始,后来添加了对 ATL 的支持。

然后我编写了一个简单的 ATL-COM 对象,使用 IDispatchImpl 实现了一个未注册的双接口,其中 0xfff 表示主要和次要,以告诉 ATL 从 EXE 加载 TLB。

我跳过了一些细节,但最后,经过一些调试后,我发现 atlcom.h 中的 CComTypeInfoHolder::GetTI 实现并没有尝试从 EXE 加载 TLB,而是在注册表中搜索它。原因:m_plibid 变量与我的 ATL::CAtlMfcModule 声明中使用的 DECLARE_LIBID 宏不对应。

经过一番谷歌搜索,我找到了Bug: CAtlMfcModule::InitLibId() not called,并在我的模块 CTOR 中添加了对 InitLibId 的调用。

现在工作正常。

问题:这是一个已知的错误吗?有一个已知的修复?我对这样一个老错误的解决方法并不满意。有没有其他的处理方法?

更新:附加信息,作为答案,没有错误...

IDispatchImpl Class:

默认IDispatchImpl 类查找类型信息 T 在注册表中。要实现未注册的接口,您可以使用 IDispatchImpl 类无需访问注册表,使用 预定义的版本号。如果您创建一个 IDispatchImpl 对象 将 0xFFFF 作为 wMajor 的值,将 0xFFFF 作为 wMinor 的值, IDispatchImpl 类从 .dll 文件中检索类型库 而不是注册表。

摘自CComTypeInfoHolder::GetTIatlcom.h中的实现:

if (InlineIsEqualGUID( CAtlModule::m_libid, *m_plibid) &&
                       m_wMajor == 0xFFFF &&
                       m_wMinor == 0xFFFF ) 
    TCHAR szFilePath[MAX_PATH];
    DWORD dwFLen = ::GetModuleFileName(_AtlBaseModule.GetModuleInstance(), szFilePath, MAX_PATH);
    [...]
    hRes = LoadTypeLib(pszFile, &pTypeLib);
 else 
    [...]
    hRes = LoadRegTypeLib(*m_plibid, m_wMajor, m_wMinor, lcid, &pTypeLib);

所以,在我看来,有一个广告行为:对次要和主要使用 0xffff,ATL 将尝试从模块而不是注册表加载类型库,前提是您的 CAtlModule: :m_libid 是最新的。 CAtlModule::m_libid 如何保持最新?通过使用 DECLARE_LIBID 宏。该宏是如何工作的?通过定义一个静态的InitLibId 函数来设置CAtlModule::m_libid

错误:当您的模块派生自 ATL::CAtlMfcModule 时,未调用定义的 InitLibId 函数(因为 ATL::CAtlMfcModule 不是类模板)

【问题讨论】:

我看不出这是一个错误。接口未注册,需自行提示CComTypeInfoHolder。基类可以帮助您第二次尝试从私有未注册类型库加载,但他们不必这样做。 @RomanR。这是一个错误,恕我直言。 DECLARE_LIBID 宏正是用于提示 CComTypeInfoHolder,但如果生成的 InitLibId 函数从未被调用,则无用。 【参考方案1】:

您是对的,如果您将-1 用于主要/次要版本,则假定类型信息将从二进制文件中获取。但是,这不适用于 MFC 项目:DECLARE_LIBID 仅适用于 CAtlMfcModule 类,但不适用于其后代。

在 atlbase.h 中的快速修复可能是这样的:

//class CAtlMfcModule :
//  public ATL::CAtlModuleT<CAtlMfcModule>

template <typename T>
class CAtlMfcModuleT : 
    public ATL::CAtlModuleT<T>

然后在你的项目中:

//class CMFCApplication1Module :
//  public ATL::CAtlMfcModule

class CMFCApplication1Module :
    public ATL::CAtlMfcModuleT<CMFCApplication1Module>

如果您将其作为错误发布到 MS Connect,您可以在此处留下一个链接,以便其他人对错误进行投票。

【讨论】:

以上是关于在 MFC+ATL EXE 中使用带有未注册接口的 IDispatchImpl的主要内容,如果未能解决你的问题,请参考以下文章

静态或动态链接 CRT、MFC、ATL 等

向现有 mfc 应用程序添加 ATL 支持

ATL 如何将 BSTR* str 转换为注册表项。 SetValue(LPCTSTR str 类型

ATL“实现界面向导”

如何在 C++ ATL/MFC 中检索具有相同格式的刻度,如 DateTime.Ticks

创建带有连接点的简单 atl 对象 未生成火方法