代码之家  ›  专栏  ›  技术社区  ›  cweston Given

.def文件C/C++动态链接库

  •  28
  • cweston Given  · 技术社区  · 17 年前

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

    它似乎取代了在DLL代码中使用显式导出的需要(即显式__declspec(dllexport)),但我在不使用这些导出时无法生成库文件,这会在以后使用DLL时产生链接器问题。

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

    6 回复  |  直到 11 年前
        1
  •  25
  •   Duncan Fletcher Duncan Fletcher    17 年前

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

    只需在函数声明中添加__declspec(dllexport),就会导致这些函数被DLL“导出”(至少在Windows上),以便可以从DLL外部调用它们。

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

    void foo(int i);
    

    最终可能会以“_foo@4“如果你不小心调用约定和.def文件的用法。

    在运行时显式加载和挂接到DLL时,在符号表中保持导出的函数名没有这种名称装饰非常方便。也就是说,要在运行时获取指向上述函数foo()的指针(假设它已导出),理想情况下只需调用:

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

    当然,还要进行一些适当的错误案例检查!

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

        2
  •  21
  •   Cœur Gustavo Armenta    6 年前

    我的理解是,.def文件提供了__declspec(dllexport)语法的替代方案,其额外好处是能够显式指定导出函数的序号。如果您仅按序号导出某些函数,这可能会很有用,因为这不会显示有关函数本身的太多信息(例如:许多操作系统内部DLL的导出函数仅按序号)。

    请参阅 reference page .

    请注意,.def文件中的名称必须与二进制文件中的姓名匹配。因此,如果你用C或C++加上'extern“C”{…}',名字就不会被篡改;否则,您必须为用于生成DLL的特定版本的编译器使用正确的错误名称。__declspec()函数会自动完成这一切。

        3
  •  12
  •   cweston Given    17 年前

    对于那些仍然感兴趣的人。..为了能够链接到dll和def文件,您还需要一个lib文件。在windows中,可以使用“LIB”工具从def中进行此操作。请参阅下面的命令行方式示例。

    lib /machine:i386 /def:sqlite3.def
    

    希望这能帮助别人。

        4
  •  4
  •   Ferruccio    17 年前

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

        5
  •  3
  •   Hosam Aly    17 年前

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

    此外,它们还提供了一种按序号(@1、@2等)而不是按名称指定导出的方法。当性能非常重要时,例如在视频驱动程序中,会使用这种查找符号的方法。

        6
  •  3
  •   chappar    17 年前

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

    def文件的优点是,它可以帮助您保持与已经实现的dll的backword兼容性。即它维护api的序号。假设你在dll中添加了一个新的api,那么链接器会查看你的.def文件,为ne wapi生成序号,这样旧api的序号就不会改变。

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