一、DLL的生成方式 VS2005使用DEF文件来生成DLL与Lib VS2005使用DEF文件来生成DLL与Lib时,与VC6的设置是不一样的,VC6工程中,只要有DEF文件并将其添加到工程中,VC6就可以自动地生成DLL与其相应的Lib文件了。 但是VS2005不一样,需要指定DEF文件,方法如下:
选择 工程 > 属性中的链接器,然后找到"输入"这一项. 在 "模块定义文件" 中输入 注意: 你需要在 Debug 和 Release 中都输入该项才行.
若要输出类的所有成员:数据or函数,__declspec(dllexport)要放在类名左边声明:
二、def文件 def文件中PRIVTATE的作用 The optional keyword PRIVATE prevents entryname from being placed in the import library generated by LINK. It has no 使用 .DEF 文件的优缺点(zz) 使用 .def 文件的另一个优点是:可以使用 NONAME 属性导出函数,该属性仅将序号放到 DLL 的导出表中。对具有大量导出函数的 DLL,使用NONAME 属性可以减小 DLL 文件的大小。有关编写模块定义语句的信息,请参见模块定义语句的规则。有关序号导出的更多信息,请参见按序号而不是按名称从 DLL 导出函数。 使用 .def 文件的主要缺点是:在 C++ 文件中导出函数时,必须将修饰名放到 .def 文件中,或者通过使用外部“C”用标准 C 链接定义导出函数,以避免编译器进行名称修饰。如果需要将修饰名放到 .def 文件中,则可以通过使用 DUMPBIN 工具或 /MAP 链接器选项来获取修饰名。请注意,编译器产生的修饰名是编译器特定的。如果将 Visual C++ 编译器产生的修饰名放到 .def 文件中,则链接到 DLL 的应用程序必须也是用相同版本的 Visual C++ 生成的,这样调用应用程序中的修饰名才能与 DLL 的 .def 文件中的导出名相匹配。 调用DLL,首先需要将DLL文件映像到用户进程的地址空间中,然后才能进行函数调用,这个函数和进程内部一般函数的调用方法相同。Windows提供了两种将DLL映像到进程地址空间的方法: ——在应用程序中要首先装入dll后才能调用导出表中的函数,例如用mfc 创建基于对话框的工程test,并在对话框上放置"load"按钮,先添加装载代码。 //设置全局变量glibsample用于存储dll句柄 HINSTANCE //第二个变量showme是指向dll typedef int(* Showme)(void); Showme showme; 2.利用classwizard为"load"按钮添加装载dll的代码 void ctestdlg::onloadbutton() { //要添加的代码如下 if(glibsample!=NULL) { AfxMessageBox("the sample.dll has already been load."); return; } //装载sample.dll,未加路径,将在三个默认路径中寻找 (1)windows的系统目录:\windows\system; //(2)dos中path所指出的任何目录; //(3)程序所在的目录;
//返回dll中showme()函数的地址 showme=(Showme)GetProcAddress(glibsample,"showme"); 先看看EXPORTS语法规则:
entryname[=internalname] [@ordinal [NONAME]] [PRIVATE] [DATA] 1.entryname是要导出的函数名或变量名。这是必选项。如果导出的名称与 DLL 中的名称不同,则通过internalname指定 DLL 中导出的名称。例如,如果 DLL 导出函数 EXPORTS func2=func1 此时用Dependency工具查看dll看到的函数名就是func2了,这个很好理解。 可选的 NONAME参数导出的dll和lib函数名测试如下: 用Dependency工具查看dll:
dumpbin -exports use_def_create_dll.lib命令查看lib导入库文件函数名如下:
可选的
可以看出NONAME参数导出的dll中就只有序号了,什么含义也不知道,一般情况下就只有开发人员自己知道到底这个方法有什么用,同样,调用时用GetProcAddress调用也必须得知道序号,而真正的函数名写进了lib导入库中,所以如果隐式调用dll,把导入库加到附加依赖项中就可以不用管了,直接按照头文件调用;而PRIVATE参数就刚好相反,函数名写到dll里面去了,lib中就连个序号都没有,这时带着头文件,用GetProcAddress显式调用dll中的函数也是很方便的。 至于DATA参数,测试的时候发现用了跟没用并没有什么区别,暂时等待高手解决…… 3. 有三种导出定义的方法,按照建议的使用顺序依次为: 1.代码中的 2.def 文件中的 3LINK 命令的 /EXPORT规范 所有这三种方法可以用在同一个程序中。LINK 在生成包含导出的程序时还创建导入库,除非生成中使用了 .exp 文件。 如何从__declspec(dllexport)和def两种导出函数方法中作出选择,可以从以下的几个方面考虑: 如果需要使用导出顺序值(export ordinal value),那么应该使用DEF文件来导出函数。只在使用DEF文件导出函数才能指定导出函数的顺序值。使用顺序值的一个好处是当向DLL中添加新的函数时,只要新的导出函数的顺序值大于原有的导出函数,就没有必要重新链接使用隐含链接的应用程序。相反,如果使用__declspec(dllexport)来导出函数,如果想DLL中添加了新的函数,使用隐含链接的应用程序有可能需要重新编译和链接。 使用DEF文件从C++文件导出函数,应该在定义函数是使用extern "C"或者在DEF文件中指定导出函数的decorated name,否则,由于编译器所产生的decorated name是基于特定编译器的,链接到该DLL的应用程序也必须使用创建DLL的同一版本的Visual C++来编译和链接。 由于使用__declspec(dllexport)关键字导出函数不需要编写DEF文件,因此,如果编写的DLL只供自己使用,使用__declspec(dllexport)较为简单。 |
|
来自: Qin Hantang > 《工作、技术》