模块定义 (.def) 文件为链接器提供有关被链接程序的导出、特性及其他方面的信息。 生成 DLL 时,.def 文件最有用。 由于存在可代替模块定义语句使用的链接器选项,通常不需要 .def 文件。 也可以将 __declspec(dllexport) 用作指定导出函数的手段。
在链接器阶段可以使用 /DEF(指定模块定义文件)链接器选项调用 .def 文件。
如果生成的 .exe 文件没有导出,使用 .def 文件将使输出文件较大并降低加载速度。
有关示例,请参见使用 DEF 文件从 DLL 导出。
目录
模块定义语句的规则
下列语法规则适用于 .def 文件中的所有语句。 其他适用于特定语句的规则与各语句一起加以说明。
-
语句、特性关键字和用户指定的标识符区分大小写。
-
包含空格或分号 (;) 的长文件名必须用引号 (") 引起。
-
使用一个或多个空格、制表符或换行符,将语句关键字同其参数分开和将各语句分开。 指定参数的冒号 (:) 或等号 (=) 两旁有零个或多个空格、制表符或换行符。
-
如果使用 NAME 或 LIBRARY 语句,则这些语句必须位于所有其他语句之前。
-
在 .def 文件中,SECTIONS 和 EXPORTS 语句可以出现多次。 每个语句都可以采用多个规范,各规范间必须用一个或多个空格、制表符或换行符分开。 语句关键字必须在第一个规范的前面出现一次,并且可以在每个附加规范的前面重复。
-
许多语句都具有等效的 LINK 命令行选项。 有关其他详细信息,请参见相应的 LINK 选项说明。
-
.def 文件中的注释由每个注释行开始处的分号 (;) 指定。 注释不能与语句共享一行,但可以在多行语句的规范间出现。(SECTIONS 和 EXPORTS 为多行语句。)
-
以十进制或十六进制为基础指定数值参数。
-
如果字符串参数与保留字匹配,则必须用双引号 (") 将字符串参数引起。
EXPORTS
引入了一个由一个或多个导出定义组成的节,这些定义可指定函数或数据的导出名或序号。 每个定义必须在单独一行上。
EXPORTS
definition
备注
第一个 definition
可以和 EXPORTS
关键字在同一行或在下一行上。 .DEF 文件可以包含一个或多个 EXPORTS
语句。
导出 definition
的语法为:
entryname[=internalname] [@ordinal [NONAME]] [[PRIVATE] | [DATA]]
entryname
是要导出的函数名或变量名。 这是必选项。 如果导出的名称与 DLL 中的名称不同,则使用 internalname
指定 DLL 中导出的名称。 例如,如果 DLL 导出函数 func1
,并且你希望调用方将其用作 func2
,则应指定:
EXPORTS
func2=func1
由于 Visual C++ 编译器针对 C++ 函数使用名称修饰,因此你必须将修饰名用作 entryname
或 internalname
,或在源代码中使用 extern "C"
定义导出函数。 编译器还将修饰使用 __stdcall 调用约定的 C 函数,它带有下划线 (_) 前缀和由 at 符号 (@) 后跟参数列表中的字节数(采用十进制)所组成的后缀。
若要查找由编译器产生的修饰名,请使用 DUMPBIN 工具或链接器 /MAP 选项。 修饰名特定于编译器。 如果要将修饰名导出到 .DEF 文件中,则链接到 DLL 的可执行文件也必须通过使用同一版本的编译器生成。 这可确保调用方中的修饰名与 .DEF 文件中的导出名相匹配。
可以使用 @ordinal
指定序号而不是函数名将进入 DLL 的导出表。 许多 Windows DLL 将导出序号以支持旧版代码。 通常使用采用 16 位 Windows 编码的序号,因为这有助于最大程度地减小 DLL 的大小。 除非 DLL 的客户端需要按序号导出函数以支持旧版,否则我们不建议你执行此操作。 由于 .LIB 文件将包含序号与函数之间的映射,因此你可以像通常在使用 DLL 的项目中那样使用函数名。
通过使用可选 NONAME
关键字,你可以只按序号导出,并减小结果 DLL 中导出表的大小。 但是,如果你想要在 DLL 上使用 GetProcAddress,你必须要知道序号,因为函数名将无效。
可选 PRIVATE
关键字禁止将 entryname
包含在由 LINK 生成的导入库中。 它不会影响同样是由 LINK 生成的映像中的导出。
可选 DATA
关键字指定导出的是数据,而不是代码。 此示例显示如何导出名为 exported_global
的数据变量:
EXPORTS
exported_global DATA
可通过采用建议的顺序列出的四种方式导出定义:
-
源代码中的 __declspec(dllexport) 关键字
-
.DEF 文件中的
EXPORTS
语句 -
LINK 命令中的 /EXPORT 规范
-
源代码中的 comment 指令,形式为
#pragma comment(linker, "/export:``definition``")
所有这四种方法可以用在同一个程序中。 LINK 在生成包含导出的程序时还创建导入库,除非生成中使用了 .EXP 文件。
下面是 EXPORTS 节的一个示例:
EXPORTS
DllCanUnloadNow @1 PRIVATE
DllWindowName = WindowName DATA
DllGetClassObject @4 NONAME PRIVATE
DllRegisterServer @7
DllUnregisterServer
使用 .DEF 文件从 DLL 中导出变量时,不必在变量上指定 __declspec(dllexport)
。 但是,在任何使用 DLL 的文件中,必须仍在数据的声明上使用 __declspec(dllimport)
。
LIBRARY
告知 LINK 创建 DLL。 LINK 同时还创建导入库,除非生成中使用了 .exp 文件。
LIBRARY [library][BASE=address]
备注
library 参数指定 DLL 的名称。 也可以使用 /OUT 链接器选项指定 DLL 输出名。
BASE=address 参数设置操作系统用来加载 DLL 的基址。 该参数重写 0x10000000 的默认 DLL 位置。 有关基址的详细信息,请参见 /BASE 选项说明。
请记住,在生成 DLL 时使用 /DLL 链接器选项。
HEAPSIZE
HEAPSIZE 公开的功能与 /HEAP 链接器选项相同。
/HEAP:reserve[,commit]
NAME (C/C++)
指定主输出文件的名称。
NAME [application][BASE=address]
备注
另一种指定输出文件名的方法是使用 /OUT 链接器选项,而另一种设置基址的方法是使用 /BASE 链接器选项。 如果两种方法都指定了,则 /OUT 重写 NAME。
如果生成 DLL,NAME 将只影响 DLL 名。
SECTIONS (C/C++)
引入了一个由一个或多个 definitions
(关于项目输出文件各节的访问说明符)组成的节。
SECTIONS
definitions
备注
每个定义必须在单独一行上。 SECTIONS
关键字可以在第一个定义所在的同一行或前一行上。 .def 文件可以包含一个或多个 SECTIONS
语句。
该 SECTIONS
语句为图像文件中的一节或多节设置特性,并可用于重写每种节类型的默认特性。
definitions
的格式为:
.section_name specifier
此处,.section_name
为程序图像中的节名, specifier
为下列一个或多个访问修饰符:
修饰符 | 说明 |
---|---|
EXECUTE | 节是可执行的 |
READ | 允许对数据进行读取操作 |
SHARED | 在所有加载图像的进程中共享节 |
WRITE | 允许对数据进行写操作 |
用空格分开修饰符名。 例如:
SECTIONS
.rdata READ WRITE
SECTIONS
标记部分 definitions
列表的开头。 每个 definition
必须处于单独的一行。 SECTIONS
关键字可以和第一个 definition
关键字在同一行或在前一行。 .def 文件可以包含一个或多个 SECTIONS
语句。 SEGMENTS
关键字作为 SECTIONS
的同义词受到支持。
Visual C++ 的早期版本支持:
section [CLASS 'classname'] specifier
出于兼容性考虑,支持 CLASS
关键字,但忽略了它。
另一种指定节特性的方法是使用 /SECTION 选项。
STACKSIZE
设置堆栈的大小(以字节为单位)。
STACKSIZE reserve[,commit]
备注
另一种设置堆栈的方法是使用堆栈分配 (/STACK) 选项。 有关 reserve 和 commit
参数的详细信息,请参见关于该选项的文档。
该选项对 DLL 无效。
STUB
当用于生成虚拟设备驱动程序 (VxD) 的模块定义文件时,STUB 允许指定包含将在 VxD 中使用的 IMAGE_DOS_HEADER 结构(在 WINNT.H 中定义)而不是默认头的文件名。
STUB:filename
备注
另一种指定 filename 的方法是使用 /STUB 链接器选项。
在模块定义文件中,STUB 仅在生成 VxD 时有效。
VERSION (C/C++)
通知 LINK 将一个数字放到 .exe 文件或 DLL 的头中。
VERSION major[.minor]
备注
major 和 minor 参数为 0 到 65,535 范围之间的十进制数。 默认值为版本 0.0。
另一种指定版本号的方法是使用版本信息 (/VERSION) 选项。