仅一个函数的链接错误。相同 class 和 CPP 文件中具有相似签名的其他函数工作正常

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

以前有人问过类似的关于这种类型的链接错误的问题,我已经调查了其中的大部分(如果不是全部的话)。 这里有一些类似的问题,GitHub 和我调查过的 MSDN 来解决这个问题:

Github:

MSDN:

Whosebug 2

Whosebug 4

Whosebug 5

问题: 我有一个遗留产品,在 4 Visual Studio Solution 个文件中包含 400 多个 Visual Studio 项目。我面临的问题是一个 COM 组件项目,它应该使用从另一个项目创建的 dll(包含静态函数); dll 中的所有静态函数都工作正常,除了一个,我正在尝试添加它。 创建 dll 的项目构建正常,没有任何错误,包含静态函数的 header 文件和 cpp 文件如下。

文件: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 )

InvocationInterface.cpp文件:

#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);
}

使用这些函数的 COM 组件正在以下列方式使用它们: ComProxyFile.cpp

bool function(formal_parameters, ...)
{


    ...
    ...

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

    ...
    ...



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

函数 setNSMCSV 导致 LNK2019 错误,当我构建使用 dll 的 COM 组件时,声明了 20+ 这样的静态函数并以类似的方式定义,但除了我正在尝试实现的 setNSMCSV 之外,其他一切都工作正常。 如果我构建使用这些函数的项目,则会出现以下错误: 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)"

如果我注释掉 CUIInvocationInterface::setNSMCSV(pxModelSet, strCSVpath, true); 行,那么它编译得很好。

我尝试给出 setNSMCSV 函数定义 __declspec(dllexport) __cdeclextern "C",并使用 pragma comment,将 .lib 添加到 COM 组件使用函数,以及我能找到的其他类似问题中建议的其他内容。

为什么这个单一的函数会导致这个问题?其他函数具有相同的签名和类似的实现,但它们工作正常。

.cpp 文件中将 void setNSMCSV(GDMModelSetI* pModelSet, CString & sFilePath, bool bAppend) 更改为 void CUIInvocationInterface::setNSMCSV(GDMModelSetI* pModelSet, CString & sFilePath, bool bAppend)。您已将其声明为静态 class 函数,但定义为自由函数(而不是 class 成员)。

你的header:

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); // <-- Static class member function

};

您的 cpp:

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

在 InvocationInterface.cpp 中,您需要更改函数定义以包含 class 名称,即来自:

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

至:

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