4

我从供应商那里获得了一个我想在 C++ Visual Studio 2012 项目中使用的 dll。它带有一个.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

我读过类似的帖子,但我没有得到任何地方。我想我正在根据这些答案做所有事情,但是在链接时我仍然得到一个未定义的参考错误。

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

我的调用代码是:

#include dll.h

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

    // create the device information list 
    ftStatus = FT_CreateDeviceInfoList(&numDevs); 
}

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

FT_Open
FT_Close
FT_Read
....
FT_CyclePort
FT_CreateDeviceInfoList<  <<<<<this reference!!!!
FT_GetDeviceInfoList

上面标识的导出显然不匹配__imp__FT_CreateDeviceInfoList

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

更新:

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

__imp_FT_CreateDeviceInfoList 

instead of 

__imp__FT_CreateDeviceInfoList

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

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

DLL_API FT_STATUS FT_CreateDeviceInfoList(LPDWORD lpdwNumDevs);

When in fact, it actually contains:

DLL_API FT_STATUS WINAPI FT_CreateDeviceInfoList(LPDWORD lpdwNumDevs);

因为 WINAPI 是#defined

如此变化

#define WINAPI
to
#define WINAPI __stdcall 

连同正确的 .lib 一起解决了这个问题。

4

3 回答 3

1

打开 Visual Studio 命令提示符。触发以下命令以列出 lib 文件中的符号:

垃圾箱/所有 dll.lib

将以上内容重定向到文本文件,因为输出会快速滚动

于 2013-01-11T02:58:41.457 回答
1

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

DLL_API FT_STATUS __stdcall FT_CreateDeviceInfoList(LPDWORD lpdwNumDevs);

大多数 DLL 供应商使用__stdcall与最广泛选择的编译器兼容,而不仅仅是 C/C++ 编译器,尽管有些供应商确实使用__cdecl甚至__fastcall(不同编译器供应商的实现方式不同,所以要小心那个)。

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

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

于 2013-01-11T03:06:13.357 回答
-1

据我所知,您正在做的事情应该有效。但是您总是可以忘记 .lib 文件并直接使用 DLL,使用 LoadLibrary 加载它并使用 GetProcAddress 获取要使用的函数的地址。

于 2013-01-11T01:54:51.277 回答