.def文件C / C ++ DLL

我不明白使用DLL的.def文件的意义。

它似乎取代了在您的DLL代码中使用显式导出的需要(即显式__declspec(dllexport))但是我不能在不使用这些时生成lib文件,然后在使用DLL时会创建链接器问题。

那么在与客户端应用程序链接时如何使用.def,它们是否取代了使用头文件或.lib文件的需要?

我的理解是.def文件提供了__declspec(dllexport)语法的替代方法,还有一个额外的好处是能够显式指定导出函数的序数。 如果仅通过序数导出某些函数,这可能很有用,它不会显示有关函数本身的大量信息(例如:许多OS内部DLL的导出函数仅按顺序)。

请参阅参考页面 。

请注意,.def文件中的名称必须与二进制文件中的名称匹配。 因此,如果您使用带有’extern“C”{…}’的C或C ++,名称将不会被破坏; 否则,您必须为用于生成DLL的特定编译器版本使用正确的受损名称。 __declspec()函数自动完成所有操作。

我发现同时使用__declspec(dllexport)和.def文件在创建可移植DLL时很有用,即可以从使用不同编译器或不同编译器设置编译的代码调用的DLL。

将__declspec(dllexport)放在函数声明上将导致这些函数被DLL“导出”(至少在Windows上),以便可以从DLL外部调用它们。

但是,在构建中添加一个列出所有导出函数的.def文件,可以阻止Microsoft编译器(例如)将前导下划线和尾随参数宽度信息添加到导出的函数名中(至少与__stdcall结合使用时)指令,对可移植性也很有用)。 例如函数声明

void foo(int i); 

如果你不小心调用约定和.def文件使用,最终可能会导出为“_foo @ 4”。

将GetProcAddress()调用作为加载和在运行时显式挂钩到DLL的一部分时,保持符号表中没有这种名称修饰的导出函数名称非常方便。 即在运行时获取指向上述函数foo()的指针(假设它完全被导出),理想情况下你只想调用:

 HANDLE dllHandle = LoadLibrary("mydll.dll"); void* fooFcnPtr = GetProcAddress(dllHandle, "foo"); 

当然有一些适当的错误案例检查!

在构建DLL时,在函数声明中使用.def文件加__stdcall,__ declspec(dllexport)和extern“C”将确保上述客户端代码适用于各种编译器和编译器设置。

对于那些感兴趣的人……为了能够链接到dll和def文件,你还需要一个lib文件。 在Windows中,这可以使用’LIB’工具从def进行。 请参阅下面的命令行方式示例。

 lib /machine:i386 /def:sqlite3.def 

希望这有助于其他人。

我没有使用过很多DLL,但我的理解是,对于导出的C ++函数,你应该使用“__declspec(dllexport)”,对于导出的C函数,你应该编写.def文件。 这可能是因为C ++函数支持重载,但C函数不支持。

.DEF文件在16位窗口中更常见,它们通常是指定应导出哪些符号的唯一方法。

此外,它们提供了一种通过序数值(@ 1,@ 2等)而不是名称来指定出口的方法。 当性能非常重要时,例如在video驱动程序中,使用这种查找符号的方法。

我的理解是.def文件实际上并没有指定需要导出哪个api。 它只包含导出的api及其序数。 如果要实际导出特定的api,则需要在声明的api和__declspec(dllimport)的定义中指定__declspec(dllexport)。

def文件的优点是,它可以帮助您维护与已经实现的dll的后备兼容性。 即它保持apis的序数。 假设您在dll中添加了一个新api,然后链接器会查看您的.def文件,该文件会生成ne wapi的序号,以便旧api的序数完好无损。

因此,如果客户端代码使用最新的dll,它不会破坏现有的api。