Search code examples
c++visual-c++comdllexportlnk2019

Linkage error for one function only. Other functions with similar signature in same class and CPP file are working fine


The similar question for this type of linkage error has been asked before, and I have looked into most (if not all) of them. Some similar questions here, GitHub and MSDN that I looked into to solve this problem:

Github:

MSDN:

StackOverflow 1

StackOverflow 2

Stackoverflow 3

Stackoverflow 4

Stackoverflow 5

Problem: I have a legacy product with over 400+ Visual Studio projects in 4 Visual Studio Solution Files. I am facing the problem with a project that is a COM component, it is supposed to use a dll(that contains static functions) created from another project; all the static function from the dll are working fine, except one, that I am trying to add in it. The project that creates the dll is building fine without any error, the header file and cpp file that contain static functions are as follows.

file: InvocationInterface.h

using namespace some_namespace;

#ifdef _WIN64
#pragma pack(8)
#else
#pragma pack(1) // tag for search
#endif

typedef struct 
{

    long nDBMS;
    long nDBMSVersion;
    long nDBMSMinorVersion;
    LPSTR szCaption; 
    LPSTR szRepGroupName;
    std::vector<bool> xDBMSOptions;
    EouGdmIdList selectedEntityIds;
    BOOL bIsAlterScript;
    int nInvoke;
    LPSTR szConnectionInfo;
    LPSTR szPassword;
    LPSTR szOptionXML;
    LPSTR szDDLPath;
} EouFEPARAM;

class EOU_EXPORT CUIInvocationInterface
{ 
public:
    CUIInvocationInterface(void);
    ~CUIInvocationInterface(void);

    // A lot of other similar static functions
    static void SetIncludeSysTablesForRevEng(GDMModelSetI* pxModelSet,BOOL bShow);

    static void setNSMCSV(GDMModelSetI* pxModelSet, CString csPath, bool append);

};
#pragma pack( pop, EouUIInvocationInterface_H_pack )

The InvocationInterface.cpp file:

#include "Header_files"

//Constructor
CUIInvocationInterface::CUIInvocationInterface(void)
{
}
//Destructor
CUIInvocationInterface::~CUIInvocationInterface(void)
{
}

// Old legacy code working just fine if I remove the function that is casusing linking error
void SetIncludeSysTablesForRevEng(GDMModelSetI* pxModelSet, BOOL bShow)
{
    return SetIncludeSysTables(pxModelSet, bShow);
}

// Function that is causing Linking Error
void setNSMCSV(GDMModelSetI* pModelSet, CString & sFilePath, bool bAppend)
{
    CWnd * wnd = nullptr;
    EouRESetOptions ForRE(wnd);
    ForRE.ProcessCSV(sFilePath, true);
}

The COM componenet that is using these functions are using them in following way: ComProxyFile.cpp

bool function(formal_parameters, ...)
{


    ...
    ...

    CUIInvocationInterface::setNSMCSV(pxModelSet, strCSVpath, true);
    CUIInvocationInterface::SetIncludeSysTablesForRevEng(pxModelSet, bIncludeSystemTables);

    ...
    ...



    SOMECLASS::OnInvokeAFunction(args, ...);
    return bRet;
}

The function setNSMCSV is causing the LNK2019 error, when I am building the COM component that is using the dll, there are 20+ such static functions declared and defined in a similar way but all are working fine except setNSMCSV, that I am trying to implement. If I build the project that is using these functions then it gives me following error: error LNK2019: unresolved external symbol "__declspec(dllimport) public: static void __cdecl CUIInvocationInterface::setNSMCSV(class GDMModelSetI *,class ATL::CStringT<char,class StrTraitMFC_DLL<char,class ATL::ChTraitsCRT<char> > >,bool)"

If I comment out the CUIInvocationInterface::setNSMCSV(pxModelSet, strCSVpath, true); line then it compiles just fine.

I tried giving setNSMCSV function definition __declspec(dllexport) __cdecl, extern "C", and using pragma comment, adding .lib to COM component that is using the functions, and other things that I could find that has been suggested in other similar questions here.

Why is this single function causing this issue? Other functions have same signatures and similar implementation but those are working fine.


Solution

  • In InvocationInterface.cpp, you need to change your function definition to include the class name, i.e. from:

    void setNSMCSV(GDMModelSetI* pModelSet, CString & sFilePath, bool bAppend)
    {
        CWnd * wnd = nullptr;
        EouRESetOptions ForRE(wnd);
        ForRE.ProcessCSV(sFilePath, true);
    }
    

    to:

    void CUIInvocationInterface::setNSMCSV(GDMModelSetI* pModelSet, CString & sFilePath, bool bAppend)
    {
        CWnd * wnd = nullptr;
        EouRESetOptions ForRE(wnd);
        ForRE.ProcessCSV(sFilePath, true);
    }