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

时间:2013-11-22 18:42:01

标签: visual-c++ com mfc atl visual-c++-2010

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

然后我编写了一个简单的ATL-COM对象,它使用IDispatchImpl实现一个非注册的双接口,使用0xfff为Major和Minor,告诉ATL从EXE加载TLB。

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

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

现在工作正常。

问题:这是一个已知的错误吗?有一个已知的修复?我对这种旧bug的解决方法并不舒服。还有另一种处理方法吗?

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

IDispatchImpl Class

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

CComTypeInfoHolder::GetTI中的atlcom.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);

所以,我觉得有一个广告行为:对于minor和major使用0xffff,ATL将尝试从模块加载typelib,而不是从注册表加载,只要你的CAtlModule: :m_libid很高兴。 CAtlModule :: m_libid如何应该是最新的?使用DECLARE_LIBID宏。那个宏如何工作?通过定义静态InitLibId函数,设置CAtlModule::m_libid

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

1 个答案:

答案 0 :(得分:2)

你是对的,如果你使用-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上,则可以在此处留下链接,以便其他人提升该错误。