C++ 从DLL导入函数时出现错误LNK2019

C++ 从DLL导入函数时出现错误LNK2019,c++,dll,C++,Dll,我正在学习如何构建一个DLL并从另一个项目中调用它(我还希望DLL不仅可以被C/C++调用,还可以被Python调用)。以下是我构建DLL的代码: callbacktesetDLL.h: #ifdef CALLBACKTESTDLL_EXPORTS #define CALLBACKTESTDLL_API __declspec(dllexport) #else #define CALLBACKTESTDLL_API __declspec(dllimport) #endif typedef

我正在学习如何构建一个DLL并从另一个项目中调用它(我还希望DLL不仅可以被C/C++调用,还可以被Python调用)。以下是我构建DLL的代码:

callbacktesetDLL.h:

#ifdef CALLBACKTESTDLL_EXPORTS
#define CALLBACKTESTDLL_API __declspec(dllexport)    
#else
#define CALLBACKTESTDLL_API __declspec(dllimport)
#endif

typedef int(CALLBACK *p)(char*);   

CALLBACKTESTDLL_API int __stdcall StrToInt(char*);      

CALLBACKTESTDLL_API char* __stdcall NumCompare(p FuncP, char*, int b);      
#include "stdafx.h"
#include <stdio.h>
#include "callbacktestDLL.h"
#include <stdlib.h>

CALLBACKTESTDLL_API int __stdcall StrToInt(char* StrInput)
{
    int IntResult;
    IntResult = atoi(StrInput);
    return IntResult;
}


CALLBACKTESTDLL_API char* __stdcall NumCompare(p FuncP, char* StrInput, int b)          
{
    int a = FuncP(StrInput);
    if (a>b)
    {
        return "a is bigger than b";
    }
    else
    {
        return "b is bigger than a";
    }
}
LIBRARY

EXPORTS
StrToInt @1
NumCompare @2
#pragma comment(lib,"callbacktestDLL.lib")

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

typedef int(*p)(char*);

extern "C" _declspec(dllimport) int StrToInt(char* InpuString);
extern "C" _declspec(dllimport) char* NumCompare(p FuncP, char*, int b);
#include "stdafx.h"

int main()
{
    p FuncP_R = StrToInt;
    NumCompare(FuncP_R, "1234", 40);
    return 0;
}
typedef int(CALLBACK *p)(char*);   

extern "C" __declspec(dllexport) int __stdcall StrToInt(char* InputString);     

extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b); 
#include "stdafx.h"
#include <stdio.h>
#include "callbacktestDLL.h"
#include <stdlib.h>

extern "C" CALLBACKTESTDLL_API int __stdcall StrToInt(char* InputString)        
{
    int IntResult;
    IntResult = atoi(InputString);
    return IntResult;
}

extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b)  
{
    int a = FuncP(InputString);
    if (a>b)
    {
        return "a is bigger than b\n";
    }
    else
    {
        return "b is bigger than a\n";
    }
}
#pragma comment(lib,"callbacktestDLL")

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

typedef int(__stdcall *p)(char*); //same as typedef int(CALLBACK *p)(char*) in callbacktestDLL.h

extern "C" _declspec(dllimport) int __stdcall StrToInt(char* InputString); //exactly same as what's in callbacktestDLL.h apart from dllimport  
extern "C" _declspec(dllimport) char* __stdcall NumCompare(p FuncP, char* InputString, int b);  //exactly same as what's in callbacktestDLL.h apart from dllimport
#include "stdafx.h"
    int main()
    {
        p FuncP_R;
        char* a = "1234";
        FuncP_R = StrToInt;
        printf(NumCompare(FuncP_R, a, 42));
        return 0;
    }
callbacktestDLL.cpp:

#ifdef CALLBACKTESTDLL_EXPORTS
#define CALLBACKTESTDLL_API __declspec(dllexport)    
#else
#define CALLBACKTESTDLL_API __declspec(dllimport)
#endif

typedef int(CALLBACK *p)(char*);   

CALLBACKTESTDLL_API int __stdcall StrToInt(char*);      

CALLBACKTESTDLL_API char* __stdcall NumCompare(p FuncP, char*, int b);      
#include "stdafx.h"
#include <stdio.h>
#include "callbacktestDLL.h"
#include <stdlib.h>

CALLBACKTESTDLL_API int __stdcall StrToInt(char* StrInput)
{
    int IntResult;
    IntResult = atoi(StrInput);
    return IntResult;
}


CALLBACKTESTDLL_API char* __stdcall NumCompare(p FuncP, char* StrInput, int b)          
{
    int a = FuncP(StrInput);
    if (a>b)
    {
        return "a is bigger than b";
    }
    else
    {
        return "b is bigger than a";
    }
}
LIBRARY

EXPORTS
StrToInt @1
NumCompare @2
#pragma comment(lib,"callbacktestDLL.lib")

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

typedef int(*p)(char*);

extern "C" _declspec(dllimport) int StrToInt(char* InpuString);
extern "C" _declspec(dllimport) char* NumCompare(p FuncP, char*, int b);
#include "stdafx.h"

int main()
{
    p FuncP_R = StrToInt;
    NumCompare(FuncP_R, "1234", 40);
    return 0;
}
typedef int(CALLBACK *p)(char*);   

extern "C" __declspec(dllexport) int __stdcall StrToInt(char* InputString);     

extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b); 
#include "stdafx.h"
#include <stdio.h>
#include "callbacktestDLL.h"
#include <stdlib.h>

extern "C" CALLBACKTESTDLL_API int __stdcall StrToInt(char* InputString)        
{
    int IntResult;
    IntResult = atoi(InputString);
    return IntResult;
}

extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b)  
{
    int a = FuncP(InputString);
    if (a>b)
    {
        return "a is bigger than b\n";
    }
    else
    {
        return "b is bigger than a\n";
    }
}
#pragma comment(lib,"callbacktestDLL")

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

typedef int(__stdcall *p)(char*); //same as typedef int(CALLBACK *p)(char*) in callbacktestDLL.h

extern "C" _declspec(dllimport) int __stdcall StrToInt(char* InputString); //exactly same as what's in callbacktestDLL.h apart from dllimport  
extern "C" _declspec(dllimport) char* __stdcall NumCompare(p FuncP, char* InputString, int b);  //exactly same as what's in callbacktestDLL.h apart from dllimport
#include "stdafx.h"
    int main()
    {
        p FuncP_R;
        char* a = "1234";
        FuncP_R = StrToInt;
        printf(NumCompare(FuncP_R, a, 42));
        return 0;
    }
通过上面的代码,我得到了
callbacktestDLL.dll
callbacktestDLL.lib
。使用dependens,可以显示DLL中函数的名称:

现在我想从另一个项目调用DLL中的函数:

CallDLL.h:

#ifdef CALLBACKTESTDLL_EXPORTS
#define CALLBACKTESTDLL_API __declspec(dllexport)    
#else
#define CALLBACKTESTDLL_API __declspec(dllimport)
#endif

typedef int(CALLBACK *p)(char*);   

CALLBACKTESTDLL_API int __stdcall StrToInt(char*);      

CALLBACKTESTDLL_API char* __stdcall NumCompare(p FuncP, char*, int b);      
#include "stdafx.h"
#include <stdio.h>
#include "callbacktestDLL.h"
#include <stdlib.h>

CALLBACKTESTDLL_API int __stdcall StrToInt(char* StrInput)
{
    int IntResult;
    IntResult = atoi(StrInput);
    return IntResult;
}


CALLBACKTESTDLL_API char* __stdcall NumCompare(p FuncP, char* StrInput, int b)          
{
    int a = FuncP(StrInput);
    if (a>b)
    {
        return "a is bigger than b";
    }
    else
    {
        return "b is bigger than a";
    }
}
LIBRARY

EXPORTS
StrToInt @1
NumCompare @2
#pragma comment(lib,"callbacktestDLL.lib")

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

typedef int(*p)(char*);

extern "C" _declspec(dllimport) int StrToInt(char* InpuString);
extern "C" _declspec(dllimport) char* NumCompare(p FuncP, char*, int b);
#include "stdafx.h"

int main()
{
    p FuncP_R = StrToInt;
    NumCompare(FuncP_R, "1234", 40);
    return 0;
}
typedef int(CALLBACK *p)(char*);   

extern "C" __declspec(dllexport) int __stdcall StrToInt(char* InputString);     

extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b); 
#include "stdafx.h"
#include <stdio.h>
#include "callbacktestDLL.h"
#include <stdlib.h>

extern "C" CALLBACKTESTDLL_API int __stdcall StrToInt(char* InputString)        
{
    int IntResult;
    IntResult = atoi(InputString);
    return IntResult;
}

extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b)  
{
    int a = FuncP(InputString);
    if (a>b)
    {
        return "a is bigger than b\n";
    }
    else
    {
        return "b is bigger than a\n";
    }
}
#pragma comment(lib,"callbacktestDLL")

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

typedef int(__stdcall *p)(char*); //same as typedef int(CALLBACK *p)(char*) in callbacktestDLL.h

extern "C" _declspec(dllimport) int __stdcall StrToInt(char* InputString); //exactly same as what's in callbacktestDLL.h apart from dllimport  
extern "C" _declspec(dllimport) char* __stdcall NumCompare(p FuncP, char* InputString, int b);  //exactly same as what's in callbacktestDLL.h apart from dllimport
#include "stdafx.h"
    int main()
    {
        p FuncP_R;
        char* a = "1234";
        FuncP_R = StrToInt;
        printf(NumCompare(FuncP_R, a, 42));
        return 0;
    }

然而,当我运行该项目时,它告诉我:
错误LNK2019:未解析的外部符号\uuuu imp\uu strott
错误LNK2019:未解析的外部符号\uuu imp\uu NumCompare
。我已经在CallDLL项目的根文件夹下复制了
.lib
.dll
文件。为什么会发生这种情况?我怎样才能解决它?谢谢你的关注。

我终于来了。详情如下: 生成DLL的文件包括:

callbacktestDLL.h:

#ifdef CALLBACKTESTDLL_EXPORTS
#define CALLBACKTESTDLL_API __declspec(dllexport)    
#else
#define CALLBACKTESTDLL_API __declspec(dllimport)
#endif

typedef int(CALLBACK *p)(char*);   

CALLBACKTESTDLL_API int __stdcall StrToInt(char*);      

CALLBACKTESTDLL_API char* __stdcall NumCompare(p FuncP, char*, int b);      
#include "stdafx.h"
#include <stdio.h>
#include "callbacktestDLL.h"
#include <stdlib.h>

CALLBACKTESTDLL_API int __stdcall StrToInt(char* StrInput)
{
    int IntResult;
    IntResult = atoi(StrInput);
    return IntResult;
}


CALLBACKTESTDLL_API char* __stdcall NumCompare(p FuncP, char* StrInput, int b)          
{
    int a = FuncP(StrInput);
    if (a>b)
    {
        return "a is bigger than b";
    }
    else
    {
        return "b is bigger than a";
    }
}
LIBRARY

EXPORTS
StrToInt @1
NumCompare @2
#pragma comment(lib,"callbacktestDLL.lib")

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

typedef int(*p)(char*);

extern "C" _declspec(dllimport) int StrToInt(char* InpuString);
extern "C" _declspec(dllimport) char* NumCompare(p FuncP, char*, int b);
#include "stdafx.h"

int main()
{
    p FuncP_R = StrToInt;
    NumCompare(FuncP_R, "1234", 40);
    return 0;
}
typedef int(CALLBACK *p)(char*);   

extern "C" __declspec(dllexport) int __stdcall StrToInt(char* InputString);     

extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b); 
#include "stdafx.h"
#include <stdio.h>
#include "callbacktestDLL.h"
#include <stdlib.h>

extern "C" CALLBACKTESTDLL_API int __stdcall StrToInt(char* InputString)        
{
    int IntResult;
    IntResult = atoi(InputString);
    return IntResult;
}

extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b)  
{
    int a = FuncP(InputString);
    if (a>b)
    {
        return "a is bigger than b\n";
    }
    else
    {
        return "b is bigger than a\n";
    }
}
#pragma comment(lib,"callbacktestDLL")

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

typedef int(__stdcall *p)(char*); //same as typedef int(CALLBACK *p)(char*) in callbacktestDLL.h

extern "C" _declspec(dllimport) int __stdcall StrToInt(char* InputString); //exactly same as what's in callbacktestDLL.h apart from dllimport  
extern "C" _declspec(dllimport) char* __stdcall NumCompare(p FuncP, char* InputString, int b);  //exactly same as what's in callbacktestDLL.h apart from dllimport
#include "stdafx.h"
    int main()
    {
        p FuncP_R;
        char* a = "1234";
        FuncP_R = StrToInt;
        printf(NumCompare(FuncP_R, a, 42));
        return 0;
    }
callbacktestDLL.cpp:

#ifdef CALLBACKTESTDLL_EXPORTS
#define CALLBACKTESTDLL_API __declspec(dllexport)    
#else
#define CALLBACKTESTDLL_API __declspec(dllimport)
#endif

typedef int(CALLBACK *p)(char*);   

CALLBACKTESTDLL_API int __stdcall StrToInt(char*);      

CALLBACKTESTDLL_API char* __stdcall NumCompare(p FuncP, char*, int b);      
#include "stdafx.h"
#include <stdio.h>
#include "callbacktestDLL.h"
#include <stdlib.h>

CALLBACKTESTDLL_API int __stdcall StrToInt(char* StrInput)
{
    int IntResult;
    IntResult = atoi(StrInput);
    return IntResult;
}


CALLBACKTESTDLL_API char* __stdcall NumCompare(p FuncP, char* StrInput, int b)          
{
    int a = FuncP(StrInput);
    if (a>b)
    {
        return "a is bigger than b";
    }
    else
    {
        return "b is bigger than a";
    }
}
LIBRARY

EXPORTS
StrToInt @1
NumCompare @2
#pragma comment(lib,"callbacktestDLL.lib")

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

typedef int(*p)(char*);

extern "C" _declspec(dllimport) int StrToInt(char* InpuString);
extern "C" _declspec(dllimport) char* NumCompare(p FuncP, char*, int b);
#include "stdafx.h"

int main()
{
    p FuncP_R = StrToInt;
    NumCompare(FuncP_R, "1234", 40);
    return 0;
}
typedef int(CALLBACK *p)(char*);   

extern "C" __declspec(dllexport) int __stdcall StrToInt(char* InputString);     

extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b); 
#include "stdafx.h"
#include <stdio.h>
#include "callbacktestDLL.h"
#include <stdlib.h>

extern "C" CALLBACKTESTDLL_API int __stdcall StrToInt(char* InputString)        
{
    int IntResult;
    IntResult = atoi(InputString);
    return IntResult;
}

extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b)  
{
    int a = FuncP(InputString);
    if (a>b)
    {
        return "a is bigger than b\n";
    }
    else
    {
        return "b is bigger than a\n";
    }
}
#pragma comment(lib,"callbacktestDLL")

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

typedef int(__stdcall *p)(char*); //same as typedef int(CALLBACK *p)(char*) in callbacktestDLL.h

extern "C" _declspec(dllimport) int __stdcall StrToInt(char* InputString); //exactly same as what's in callbacktestDLL.h apart from dllimport  
extern "C" _declspec(dllimport) char* __stdcall NumCompare(p FuncP, char* InputString, int b);  //exactly same as what's in callbacktestDLL.h apart from dllimport
#include "stdafx.h"
    int main()
    {
        p FuncP_R;
        char* a = "1234";
        FuncP_R = StrToInt;
        printf(NumCompare(FuncP_R, a, 42));
        return 0;
    }
CallDLL.cpp:

#ifdef CALLBACKTESTDLL_EXPORTS
#define CALLBACKTESTDLL_API __declspec(dllexport)    
#else
#define CALLBACKTESTDLL_API __declspec(dllimport)
#endif

typedef int(CALLBACK *p)(char*);   

CALLBACKTESTDLL_API int __stdcall StrToInt(char*);      

CALLBACKTESTDLL_API char* __stdcall NumCompare(p FuncP, char*, int b);      
#include "stdafx.h"
#include <stdio.h>
#include "callbacktestDLL.h"
#include <stdlib.h>

CALLBACKTESTDLL_API int __stdcall StrToInt(char* StrInput)
{
    int IntResult;
    IntResult = atoi(StrInput);
    return IntResult;
}


CALLBACKTESTDLL_API char* __stdcall NumCompare(p FuncP, char* StrInput, int b)          
{
    int a = FuncP(StrInput);
    if (a>b)
    {
        return "a is bigger than b";
    }
    else
    {
        return "b is bigger than a";
    }
}
LIBRARY

EXPORTS
StrToInt @1
NumCompare @2
#pragma comment(lib,"callbacktestDLL.lib")

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

typedef int(*p)(char*);

extern "C" _declspec(dllimport) int StrToInt(char* InpuString);
extern "C" _declspec(dllimport) char* NumCompare(p FuncP, char*, int b);
#include "stdafx.h"

int main()
{
    p FuncP_R = StrToInt;
    NumCompare(FuncP_R, "1234", 40);
    return 0;
}
typedef int(CALLBACK *p)(char*);   

extern "C" __declspec(dllexport) int __stdcall StrToInt(char* InputString);     

extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b); 
#include "stdafx.h"
#include <stdio.h>
#include "callbacktestDLL.h"
#include <stdlib.h>

extern "C" CALLBACKTESTDLL_API int __stdcall StrToInt(char* InputString)        
{
    int IntResult;
    IntResult = atoi(InputString);
    return IntResult;
}

extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b)  
{
    int a = FuncP(InputString);
    if (a>b)
    {
        return "a is bigger than b\n";
    }
    else
    {
        return "b is bigger than a\n";
    }
}
#pragma comment(lib,"callbacktestDLL")

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

typedef int(__stdcall *p)(char*); //same as typedef int(CALLBACK *p)(char*) in callbacktestDLL.h

extern "C" _declspec(dllimport) int __stdcall StrToInt(char* InputString); //exactly same as what's in callbacktestDLL.h apart from dllimport  
extern "C" _declspec(dllimport) char* __stdcall NumCompare(p FuncP, char* InputString, int b);  //exactly same as what's in callbacktestDLL.h apart from dllimport
#include "stdafx.h"
    int main()
    {
        p FuncP_R;
        char* a = "1234";
        FuncP_R = StrToInt;
        printf(NumCompare(FuncP_R, a, 42));
        return 0;
    }

它像预期的那样工作。我认为我犯的一个错误是导入时缺少
\uu stdcall
。也许这个名字也有错误。我将继续测试它。

您应该始终包含相同的头文件以定义一致的接口。创建不同的头文件容易出错。对接口的下一次更改可能会使接口不兼容

实现函数的模块与使用函数的模块之间存在细微差异。区别在于
\u declspec(dllimport)
\u declspec(dllexport)
。这就是为什么头文件包含

# ifdef CALLBACKTESTDLL_EXPORTS
实现这些函数的模块也会导出这些函数。因此,必须在项目设置中定义符号。如果在命令行编译,则必须将
/D CALLBACKTESTDLL\u EXPORT
添加到编译器参数中


顺便说一句:如果您定义了
CALLBACKTESTDLL\u EXPORT
CALLBACKTESTDLL\u API
包含
\u declspec(dllexport)
。这将导致链接器创建DLL导出表。
.DEF
不是必需的。您应该删除它,因为。。。。。它再次定义了接口(在不同的级别)。

是否与库链接?并且DLL应该与可执行文件位于同一目录中。您是否为DLL定义了
CALLBACKTESTDLL\u EXPORTS
?(顺便说一句,您只需要在函数声明之前设置导出声明。)
extern“C”
防止名称损坏,而库仍然导出损坏的名称。该.def文件没有用处,因为它没有列出正确(损坏)的名称。在客户端代码中不使用.h文件是一个非常糟糕的主意。重新键入函数名时,您忘记了u stdcall属性。这将更改修饰的函数名。不要这样做,请使用
#在客户端代码中也包括“callbacktestDLL.h”
。不太明显这是怎么回事,如果有必要,请仔细检查您没有在客户端项目中定义CALLBACKTESTDLL导出。该.h文件不是秘密,需要正确使用DLL。用于构建DLL的其他文件(如.cpp文件)与客户端程序员无关。因此,在极不可能的情况下,有人这样做,一定要扔掉DLL。如果你不这样做,那么你就有可能侵犯版权,这可能是相当昂贵的。这种方法可能会给你一个DLL,你可以使用。但它也有一些退步。有关详细信息,请参阅我的答案。谢谢您告诉我这些详细信息。您能告诉我什么时候使用
.DEF
?另一个问题,在我自己的回答中,虽然
CallDLL.h
中的函数名称与
中的函数名称不同,但为什么我仍然可以导入它们?