none
COM/ATL object with implementation in a .cpp, LNK2001 !! RRS feed

  • Question

  • Hello all,

     

    I'm writing a COM object using ATL, I have been writing both definition and implementation in  a single .h file and everythink went fine, but now i want to place implementation in a .cpp file and the linker complains with a LNK2001.

     

    //.h file with class definition

    template <typename T, typename Itf>

    class IMBaseImpl : public CMBaseImpl, public Itf

    {

    public:

    IMBaseImpl();

    ~IMBaseImpl();

    STDMETHOD(Init)(IMApplication** pApp, BSTR strName);

    STDMETHOD(get_Name)(BSTR* pVal);

    STDMETHOD(put_Name)(BSTR newVal);

    IMApplication* getApp();

    };

     

     

    //.cpp file with class implementation

    #include "stdafx.h"

    #include "IMBaseImpl.h"

    template <typename T, typename Itf>

    IMBaseImpl<T,Itf>::IMBaseImpl()

    {

    }

    template <typename T, typename Itf>

    IMBaseImpl<T,Itf>::~IMBaseImpl()

    {

    }

    template <typename T, typename Itf>

    STDMETHODIMP IMBaseImpl<T, Itf>::Init(IMApplication** pApp, BSTR strName)

    {

    ...

    }

    ...

     

    //Snipet from the Com object that derives from the previous class, CBase.h

    class ATL_NO_VTABLE CMBase :

    public CComObjectRootEx<CComSingleThreadModel>,

    public CComCoClass<CMBase, &CLSID_MBase>,

    public IConnectionPointContainerImpl<CMBase>,

    public CProxy_IMBaseEvents<CMBase>,

    public IDispatchImpl<IMBaseImpl<CMBase, IMBase>, &IID_IMBase, &LIBID_MIMLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,

    public CProxyIMBaseEvents<CMBase> //IMBase, &IID_IMBase, &LIBID_MIMLib, /*wMajor =*/ 1, /*wMinor =*/ 0>

    {  ...

     

    Linking...

    Creating library D:\Programacion\MIM\MIM\..\bin\\MIM.lib and object D:\Programacion\MIM\MIM\..\bin\\MIM.exp

    MBase.obj : error LNK2019: unresolved external symbol "public: virtual long __stdcall IMBaseImpl<class CMBase,struct IMBase>::get_Name(wchar_t * *)" (?get_Name@?$IMBaseImpl@VCMBase@@UIMBase@@@@UAGJPAPA_W@Z) referenced in function "public: virtual long __stdcall CMBase::get_Name(wchar_t * *)" (?get_Name@CMBase@@UAGJPAPA_W@Z)

    MBase.obj : error LNK2001: unresolved external symbol "public: virtual long __stdcall IMBaseImpl<class CMBase,struct IMBase>::put_Name(wchar_t *)" (?put_Name@?$IMBaseImpl@VCMBase@@UIMBase@@@@UAGJPA_W@Z)

    MBase.obj : error LNK2001: unresolved external symbol "public: virtual long __stdcall IMBaseImpl<class CMBase,struct IMBase>::Init(struct IMApplication * *,wchar_t *)" (?Init@?$IMBaseImpl@VCMBase@@UIMBase@@@@UAGJPAPAUIMApplication@@PA_W@Z)

    MBase.obj : error LNK2019: unresolved external symbol "public: __thiscall IMBaseImpl<class CMBase,struct IMBase>::IMBaseImpl<class CMBase,struct IMBase>(void)" (??0?$IMBaseImpl@VCMBase@@UIMBase@@@@QAE@XZ) referenced in function "public: __thiscall ATL::IDispatchImpl<class IMBaseImpl<class CMBase,struct IMBase>,&struct _GUID const IID_IMBase,&struct _GUID const LIBID_MIMLib,1,0,class ATL::CComTypeInfoHolder>::IDispatchImpl<class IMBaseImpl<class CMBase,struct IMBase>,&struct _GUID const IID_IMBase,&struct _GUID const LIBID_MIMLib,1,0,class ATL::CComTypeInfoHolder>(void)" (??0?$IDispatchImpl@V?$IMBaseImpl@VCMBase@@UIMBase@@@@$1?IID_IMBase@@3U_GUID@@B$1?LIBID_MIMLib@@3U3@B$00$0A@VCComTypeInfoHolder@ATL@@@ATL@@QAE@XZ)

    MBase.obj : error LNK2019: unresolved external symbol "public: __thiscall IMBaseImpl<class CMBase,struct IMBase>::~IMBaseImpl<class CMBase,struct IMBase>(void)" (??1?$IMBaseImpl@VCMBase@@UIMBase@@@@QAE@XZ) referenced in function "public: __thiscall ATL::IDispatchImpl<class IMBaseImpl<class CMBase,struct IMBase>,&struct _GUID const IID_IMBase,&struct _GUID const LIBID_MIMLib,1,0,class ATL::CComTypeInfoHolder>::~IDispatchImpl<class IMBaseImpl<class CMBase,struct IMBase>,&struct _GUID const IID_IMBase,&struct _GUID const LIBID_MIMLib,1,0,class ATL::CComTypeInfoHolder>(void)" (??1?$IDispatchImpl@V?$IMBaseImpl@VCMBase@@UIMBase@@@@$1?IID_IMBase@@3U_GUID@@B$1?LIBID_MIMLib@@3U3@B$00$0A@VCComTypeInfoHolder@ATL@@@ATL@@QAE@XZ)

    Friday, December 22, 2006 2:15 PM

Answers

  • It seems template classes cannot be exported from OBJ, LIB or DLL files, compiled from CPP source, since the work which has to be performed by the compiler, related to generic issues, cannot be done by the linker.

     

    I think you have to keep your template classes in header files.

     

    See, for example, the <string> or <vector> header files from STL -- they include both declarations and implementations and do not rely on separate CPP files.

     

    But you can split your single header files in two parts: the .H file which contains declarations only, and another file (for example with .INL extension) which contains implementation (currently in your .CPP file). Then add a line like #include "MyClass.inl" into your .H file.

     

    Only put in CPP files non-template things.

     

    I hope this makes sense.

    Friday, December 22, 2006 3:04 PM
  • I just want to confirm what Viorel is saying. The complete definition of template functions and classes must generally be present in the compiled project. The reason is simply that the function or class isn't complete until it's referenced with a specific type. Imagine a function

    template<typename T> void Foo();

    A version of that function with T=double is not the same as T=int: the machine code generated for the two is likely to be completely different. When the linker tries to find Foo<int>, but only Foo<double> is present, the operation will fail; and such is your case.

    Some compilers does support the export keyword, which allows you to just include the declaration -- but VC is not one of them.

    Friday, December 22, 2006 4:44 PM
    Moderator

All replies

  • It seems template classes cannot be exported from OBJ, LIB or DLL files, compiled from CPP source, since the work which has to be performed by the compiler, related to generic issues, cannot be done by the linker.

     

    I think you have to keep your template classes in header files.

     

    See, for example, the <string> or <vector> header files from STL -- they include both declarations and implementations and do not rely on separate CPP files.

     

    But you can split your single header files in two parts: the .H file which contains declarations only, and another file (for example with .INL extension) which contains implementation (currently in your .CPP file). Then add a line like #include "MyClass.inl" into your .H file.

     

    Only put in CPP files non-template things.

     

    I hope this makes sense.

    Friday, December 22, 2006 3:04 PM
  • I just want to confirm what Viorel is saying. The complete definition of template functions and classes must generally be present in the compiled project. The reason is simply that the function or class isn't complete until it's referenced with a specific type. Imagine a function

    template<typename T> void Foo();

    A version of that function with T=double is not the same as T=int: the machine code generated for the two is likely to be completely different. When the linker tries to find Foo<int>, but only Foo<double> is present, the operation will fail; and such is your case.

    Some compilers does support the export keyword, which allows you to just include the declaration -- but VC is not one of them.

    Friday, December 22, 2006 4:44 PM
    Moderator
  • Thank you guys, I think i will have to live with a messed .h, no problemo.
    Saturday, December 23, 2006 12:48 AM