将 DLL 链接到 Visual C++ 时未定义的外部

use*_*890 5 c++ dll visual-studio-2012

我从供应商那里获得了一个 dll,我想在 C++ Visual Studio 2012 项目中使用它。它带有一个.lib文件。

链接时我得到:

Error   1   error LNK2019: unresolved external symbol __imp__FT_CreateDeviceInfoList referenced in function "int __cdecl Ftexam(void)" (?Ftexam@@YAHXZ) C:\Users\Terry\Documents\Visual Studio 2012\Projects\Win32Project1\Win32Project1\ftexam.obj ftexample
Run Code Online (Sandbox Code Playgroud)

我读过类似的帖子,但我一无所获。我认为我正在根据这些答案做所有事情,但在链接时我仍然收到未定义的参考错误。

  1. 我已将 dll.lib 文件添加到 /Linker/Addional Dependencies 列表中。
  2. 我已确保 dll.h 文件包含在我的源代码中
  3. 我已将dll.lib文件放入我的项目目录中,并确保如果我从那里删除它,我会cannot find dll.lib在链接时得到(即,它是“在构建中”)

在我提供的dll.h头文件中,我有这个:

#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
.
.
#ifdef __cplusplus
extern "C" {
#endif

typedef ULONG   FT_STATUS;
.
.
DLL_API FT_STATUS FT_CreateDeviceInfoList(
    LPDWORD lpdwNumDevs
);
Run Code Online (Sandbox Code Playgroud)

我的调用代码是:

#include dll.h

int Ftexam(){
    FT_STATUS ftStatus=0; 
    DWORD numDevs = 0;

    // create the device information list 
    ftStatus = FT_CreateDeviceInfoList(&numDevs); 
}
Run Code Online (Sandbox Code Playgroud)

我意识到可能存在一些名称损坏,因此我使用depends 查看了DLL 符号。它列出了这些禁用“Undecorate C++ 函数”选项的导出(因此,这些是未损坏的导出):

FT_Open
FT_Close
FT_Read
....
FT_CyclePort
FT_CreateDeviceInfoList<  <<<<<this reference!!!!
FT_GetDeviceInfoList
Run Code Online (Sandbox Code Playgroud)

上面识别的导出明显不匹配__imp__FT_CreateDeviceInfoList

是否有工具可以查看 .lib 文件中的定义,或者 Visual Studio 是否可以通过某种方式显示该定义?

更新:

通过使用 dumpbin,我可以看到 .lib 中的符号是

__imp_FT_CreateDeviceInfoList 

instead of 

__imp__FT_CreateDeviceInfoList
Run Code Online (Sandbox Code Playgroud)

我跟踪到了 DLL 的 64 位版本而不是 32 位版本的 .lib。(我首先尝试解决这个问题的组合之一)。

为了简化帖子,我指出标题包含:

DLL_API FT_STATUS FT_CreateDeviceInfoList(LPDWORD lpdwNumDevs);

When in fact, it actually contains:

DLL_API FT_STATUS WINAPI FT_CreateDeviceInfoList(LPDWORD lpdwNumDevs);
Run Code Online (Sandbox Code Playgroud)

因为 WINAPI 是#define

如此改变

#define WINAPI
to
#define WINAPI __stdcall 
Run Code Online (Sandbox Code Playgroud)

随着正确的 .lib 解决了这个问题。

Rem*_*eau 1

FT_CreateDeviceInfoList()未在 .h 文件中声明任何调用约定,因此它使用编译器的默认调用约定。您的编译器默认为__cdecl,这对于大多数 C++ 编译器来说是正常行为。有可能创建 DLL 的编译器实际上使用的是不同的默认调用约定。__stdcall例如,尝试编辑 .h 文件以指定,并查看它是否有任何区别,例如:

DLL_API FT_STATUS __stdcall FT_CreateDeviceInfoList(LPDWORD lpdwNumDevs);
Run Code Online (Sandbox Code Playgroud)

大多数 DLL 供应商使用它是__stdcall为了与最广泛的编译器选择兼容,而不仅仅是 C/C++ 编译器,尽管有些供应商确实使用__cdecl或 甚至__fastcall(不同编译器供应商的实现方式不同,因此请注意)。

最糟糕的情况是,您可以使用反汇编程序(例如 IDA 或 WinDASM),或者仅使用 IDE 自己的调试器来查看FT_CreateDeviceInfoList()DLL 内部的实际汇编代码,并了解它在访问参数lpdwNumDevs和返回FT_STATUS价值。这将准确地告诉您它实际使用的调用约定。

更新:进行一些在线搜索,我看到许多 .NET 代码的示例,这些代码使用FT_CreateDeviceInfoList()应用于__stdcall其声明的调用约定进行调用,因此这是一个很好的起点。如果有效,那么您应该联系 DLL 供应商并要求他们相应地修复其 .h 文件。