📄 chap13.html
字号:
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">DESCRIPTION</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>语句是可选的,它简单的说明了</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的用途。</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">4.	</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>下一步是向工程中添加一个头文件,它定义了</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>中的函数的返回值的类型和参数的个数、顺序和类型。</P>
<P ALIGN="JUSTIFY">单击菜单项</FONT><FONT SIZE=3>Project|Add To Project|New...</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,在</FONT><FONT SIZE=3>Files</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>选项卡下选择</FONT><FONT SIZE=3>C/C++ Header File</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,在</FONT><FONT SIZE=3>File</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>文本框中指定头文件名,如</FONT><FONT SIZE=3>msgbox.h</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>(可以省略后缀名</FONT><FONT SIZE=3>.h</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>)。</P>
<P ALIGN="JUSTIFY">在头文件中输入如下的内容:</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>#include <windows.h></P>
<P>extern "C" int MsgBox(</P>
<P>	// 消息框的文本</P>
<P>	LPCTSTR lpText="虽然这个例子有一些幼稚,但它工作得非常的好!",</P>
<P>	// 消息框的标题</P>
<P>	LPCTSTR lpCaption="一个简单的例子",</P>
<P>	// 消息框的样式</P>
<P>	UINT uType=MB_OK);</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">请注意函数定义前的关键字</FONT><FONT SIZE=3>extern "C"</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,这是由于我们使用了</FONT><FONT SIZE=3>C++</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>语言来开发</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,为了使</FONT><FONT SIZE=3>C</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>语言模块能够访问该导出函数,我们应该使用</FONT><FONT SIZE=3>C</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>链接来代替</FONT><FONT SIZE=3>C++</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>链接。否则,</FONT><FONT SIZE=3>C++</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>编译器将使用</FONT><FONT SIZE=3>C++</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的类型安全命名和调用协议,这在使用</FONT><FONT SIZE=3>C</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>调用该函数时就会遇上问题。在本例中并不需要考虑到这个问题,因为我们在开发</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>和应用程序时都是使用</FONT><FONT SIZE=3>C++</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,但我们仍然强烈建议使用</FONT><FONT SIZE=3>extern "C"</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,以保证在使用</FONT><FONT SIZE=3>C</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>编写的程序调用该</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的导出函数不会遇上麻烦,在本章后面的内容中我们还会讨论到这个问题。</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">5.	</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>下面要做的事是向工程中添加一个</FONT><FONT SIZE=3>C++</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>源文件,在该文件中实现函数</FONT><FONT SIZE=3>MsgBox()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。</P>
<P ALIGN="JUSTIFY">仿照上面的过程,单击菜单项</FONT><FONT SIZE=3>Project|Add To Project|New...</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,在</FONT><FONT SIZE=3>Files</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>选项卡下选择</FONT><FONT SIZE=3>C++ Source File</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>,在</FONT><FONT SIZE=3>File</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>文本框中指定源文件名,如</FONT><FONT SIZE=3>msgbox.cpp</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。</P>
<P ALIGN="JUSTIFY">在</FONT><FONT SIZE=3>msgbox.cpp</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>文件中添加如下的代码:</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>#include "test1.h"</P>
<P>int MsgBox(LPCTSTR lpText,</P>
<P>	 LPCTSTR lpCaption,</P>
<P> UINT uType)</P>
<P>{</P>
<P>	return MessageBox(NULL,lpText,lpCaption,uType);</P>
<P>}</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">编译该工程,在</FONT><FONT SIZE=3>Debug</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>目录下生成文件</FONT><FONT SIZE=3>msgbox.lib</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>和</FONT><FONT SIZE=3>msgbox.dll</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。</P>
<P ALIGN="JUSTIFY">在“</FONT><FONT SIZE=3>13.2.2 </FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>链接应用程序到</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>”小节中将讲述如何使用在本节中所创建的</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>:</FONT><FONT SIZE=3>msgbox.dll</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。</P><DIR>
</FONT><FONT FACE="Arial" SIZE=3><P>(2)	</FONT><FONT FACE="黑体" LANG="ZH-CN" SIZE=3>使用关键字</FONT><FONT FACE="Arial" SIZE=3>__declspec(dllexport)</P></DIR>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY">从</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>中导出文件的另一种方法是在定义函数时使用</FONT><FONT SIZE=3>__declspec(dllexport)</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>关键字。这种方法不需要使用</FONT><FONT SIZE=3>DEF</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>文件。</P>
<P ALIGN="JUSTIFY">仍使用前面的例子,在工程中删除</FONT><FONT SIZE=3>msgbox.def</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>文件,将</FONT><FONT SIZE=3>msgbox.h</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>文件修改如下:</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>#include <windows.h></P>
<P>extern "C" __declspec(dllexport) int MsgBox(</P>
<P>	// 消息框的文本</P>
<P>	LPCTSTR lpText="虽然这个例子有一些幼稚,但它工作得非常的好!",</P>
<P>	// 消息框的标题</P>
<P>	LPCTSTR lpCaption="一个简单的例子",</P>
<P>	// 消息框的样式</P>
<P>	UINT uType=MB_OK);</P>
</FONT><FONT SIZE=3><P ALIGN="JUSTIFY">msgbox.cpp</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>文件并不需要做任何修改,重新编译该工程,在</FONT><FONT SIZE=3>Debug</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>目录下仍生成两个文件</FONT><FONT SIZE=3>msgbox.lib</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>和</FONT><FONT SIZE=3>msgbox.dll</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。</P>
<P ALIGN="JUSTIFY">在下一小节“</FONT><FONT SIZE=3>13.2.2 </FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>链接应用程序到</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>”中讲述了如何在应用程序中使用所创建的</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>:</FONT><FONT SIZE=3>msgbox.dll</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的导出函数</FONT><FONT SIZE=3>MsgBox()</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。</P>
<P ALIGN="JUSTIFY">使用</FONT><FONT SIZE=3>__declspec(dllexport)</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>从</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>中导出类的语法如下:</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P>class __declspec(dllexport) CDemoClass</P>
<P>{</P>
<P>	...</P>
<P>}</P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"> </P>
<UL>
</FONT><FONT FACE="黑体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"><LI>注意:</LI></P>
</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"><LI>如果在使用</FONT><FONT SIZE=3>__declspec(dllexport)</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>的同时指定了调用协议关键字,则必须将</FONT><FONT SIZE=3>__declspec(dllexport)</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>关键字放在调用协议关键字的左边。如:</LI></P>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=1><P ALIGN="JUSTIFY"><LI>int __declspec(dllexport) __cdacl MyFunc();</LI></P>
</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"><LI>在</FONT><FONT SIZE=3>32</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>位版本的</FONT><FONT SIZE=3>Visual C++</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>中,</FONT><FONT SIZE=3>__declspec(dllexport)</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>和</FONT><FONT SIZE=3>__declspec(dllimport)</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>代替了</FONT><FONT SIZE=3>16</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>版本中使用的</FONT><FONT SIZE=3>__export</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>关键字。因此,在将</FONT><FONT SIZE=3>16</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>位的</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>源代码移植到</FONT><FONT SIZE=3>Win32</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>平台时,需要把每一处</FONT><FONT SIZE=3>__export</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>替换为</FONT><FONT SIZE=3>__declsped(dllexport)</FONT><FONT FACE="楷体_GB2312" LANG="ZH-CN" SIZE=3>。</LI></P></UL>
</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3><P ALIGN="JUSTIFY"></P>
<P ALIGN="JUSTIFY">如何从这两种导出函数的方法中作出选择,可以从下面的几个方面考虑:</P>
<UL>
<P ALIGN="JUSTIFY"><LI>如果需要使用导出顺序值(</FONT><FONT SIZE=3>export ordinal value</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>),那么应该使用</FONT><FONT SIZE=3>DEF</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>文件来导出函数。只在使用</FONT><FONT SIZE=3>DEF</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>文件导出函数才能指定导出函数的顺序值。使用顺序值的一个好处是当向</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>中添加新的函数时,只要新的导出函数的顺序值大于原有的导出函数,就没有必要重新链接使用隐含链接的应用程序。相反,如果使用</FONT><FONT SIZE=3>__declspec(dllexport)</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>来导出函数,如果向</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>中添加了新的函数,使用隐含链接的应用程序有可以需要重新编译和链接。</LI></P>
<P ALIGN="JUSTIFY"><LI>使用</FONT><FONT SIZE=3>DEF</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>文件来导出函数,可以创建具有</FONT><FONT SIZE=3>NONAME</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>属性的</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。具有</FONT><FONT SIZE=3>NONAME</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>属性的</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>在导出表中仅包含了导出函数的顺序值,这种类型的</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>在包括有大量的导出函数时,其文件长度要小于通常的</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。</LI></P>
<P ALIGN="JUSTIFY"><LI>使用</FONT><FONT SIZE=3>DEF</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>文件从</FONT><FONT SIZE=3>C++</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>文件导出函数,应该在定义函数时使用</FONT><FONT SIZE=3>extern "C"</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>或者在</FONT><FONT SIZE=3>DEF</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>文件中指定导出函数的</FONT><FONT SIZE=3>decorated name</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>。否则,由于编译器所产生的</FONT><FONT SIZE=3>decorated name</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>是基于特定编译器的,链接到该</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的应用程序也必须使用创建</FONT><FONT SIZE=3>DLL</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>的同一版本的</FONT><FONT SIZE=3>Visual C++</FONT><FONT FACE="宋体" LANG="ZH-CN" SIZE=3>来编译和链接。</LI></P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -