📄 024.htm
字号:
<HTML><HEAD><meta http-equiv="Content-Type" content="text/html; charset=GB2312"><TITLE>—DELPHI基础教程—第十章 动态链接库编程(一)</TITLE><META NAME="keywords" CONTENT=" DELPHI基础教程 第十章 动态链接库编程(一)"><META NAME="description" CONTENT=" - DELPHI基础教程 - 第十章 动态链接库编程(一)"><style><!--#page {position:absolute; z-index:0; left:0px; top:0px}.tt3 {font: 9pt/12pt "宋体"}.tt2 {font: 12pt/15pt "宋体"}a {text-decoration:none}a:hover {color: blue;text-decoration:underline}--></style></HEAD><body text="#000000" bgcolor="#FFFFFF" leftmargin="3" topmargin="3" marginheight="3" marginwidth="3"><TABLE WIDTH="100%" CELLPADDING=10 CELLSPACING=0 BORDER=0><TR><TD CLASS="tt3" VALIGN="top" width="8%" ><strong><A HREF="025.htm"><FONT style="FONT-SIZE: 9pt">后一页</font></A><BR><A HREF="023.htm"><FONT style="FONT-SIZE: 9pt">前一页</font></A><BR><A HREF="index.html"><FONT style="FONT-SIZE: 9pt">回目录</font></A><BR></strong></TD><TD class="tt2" width="84%"><center><B><FONT style="FONT-SIZE: 16.5pt" COLOR="#FF6666" FACE="隶书">第十章 动态链接库编程(一)</FONT></B></center><hr width="94%"><p align="center">10.1 Windows<font face="宋体" lang="ZH-CN">的动态链接库原理 </p><p> 动态链接库</font>(DLLs)<font face="宋体" lang="ZH-CN">是从</font>C<fontface="宋体" lang="ZH-CN">语言函数库和</font>Pascal<font face="宋体" lang="ZH-CN">库单元的概念发展而来的。所有的</font>C<fontface="宋体" lang="ZH-CN">语言标准库函数都存放在某一函数库中,同时用户也可以用</font>LIB<fontface="宋体" lang="ZH-CN">程序创建自己的函数库。在链接应用程序的过程中,链接器从库文件中拷贝程序调用的函数代码,并把这些函数代码添加到可执行文件中。这种方法同只把函数储存在已编译的</font>.OBJ<fontface="宋体" lang="ZH-CN">文件中相比更有利于代码的重用。</p><p> 但随着</font>Windows<font face="宋体" lang="ZH-CN">这样的多任务环境的出现,函数库的方法显得过于累赘。如果为了完成屏幕输出、消息处理、内存管理、对话框等操作,每个程序都不得不拥有自己的函数,那么</font>Windows<fontface="宋体" lang="ZH-CN">程序将变得非常庞大。</font>Windows<font face="宋体"lang="ZH-CN">的发展要求允许同时运行的几个程序共享一组函数的单一拷贝。动态链接库就是在这种情况下出现的。动态链接库不用重复编译或链接,一旦装入内存,</font>Dlls<fontface="宋体" lang="ZH-CN">函数可以被系统中的任何正在运行的应用程序软件所使用,而不必再将</font>DLLs<fontface="宋体" lang="ZH-CN">函数的另一拷贝装入内存。 </p></font><p>10.1.1 <font face="宋体" lang="ZH-CN">动态链接库的工作原理 </p><p> “动态链接”这几字指明了</font>DLLs<font face="宋体" lang="ZH-CN">是如何工作的。对于常规的函数库,链接器从中拷贝它需要的所有库函数,并把确切的函数地址传送给调用这些函数的程序。而对于</font>DLLs<fontface="宋体" lang="ZH-CN">,函数储存在一个独立的动态链接库文件中。在创建</font>Windows<fontface="宋体" lang="ZH-CN">程序时,链接过程并不把</font>DLLs<font face="宋体"lang="ZH-CN">文件链接到程序上。直到程序运行并调用一个</font>DLLs<fontface="宋体" lang="ZH-CN">中的函数时,该程序才要求这个函数的地址。此时</font>Windows<fontface="宋体" lang="ZH-CN">才在</font>DLLs<font face="宋体" lang="ZH-CN">中寻找被调用函数,并把它的地址传送给调用程序。采用这种方法,</font>DLLs<fontface="宋体" lang="ZH-CN">达到了复用代码的极限。</p><p> 动态链接库的另一个方便之处是对动态链接库中函数的修改可以自动传播到所有调用它的程序中,而不必对程序作任何改动或处理。</p><p> </font>DLLs<font face="宋体" lang="ZH-CN">不仅提供了函数重用的机制,而且提供了数据共享的机制。任何应用程序都可以共享由装入内存的</font>DLLs<fontface="宋体" lang="ZH-CN">管理的内存资源块。只包含共享数据的</font>DLLs<fontface="宋体" lang="ZH-CN">称为资源文件。如</font>Windows<font face="宋体"lang="ZH-CN">的字体文件等。 </p></font><p>10.1.2 Windows<font face="宋体" lang="ZH-CN">系统的动态链接库 </p><p> </font>Windows<font face="宋体" lang="ZH-CN">本身就是由大量的动态链接库支持的。这包括</font>WindowsAPI<font face="宋体" lang="ZH-CN">函数</font> ( KRNLx86.EXE<font face="宋体"lang="ZH-CN">,</font>USER.EXE<font face="宋体" lang="ZH-CN">,</font>GDI.EXE<fontface="宋体" lang="ZH-CN">,…</font>)<font face="宋体" lang="ZH-CN">,各种驱动程序文件,各种带有</font>.Fon<fontface="宋体" lang="ZH-CN">和</font>.Fot <font face="宋体" lang="ZH-CN">扩展名的字体资源文件等。</font>Windows<fontface="宋体" lang="ZH-CN">还提供了针对某一功能的专用</font>DLLs<fontface="宋体" lang="ZH-CN">,如进行</font>DDE<font face="宋体" lang="ZH-CN">编程的</font>ddeml.dll<fontface="宋体" lang="ZH-CN">,进行程序安装的</font>ver.dll<font face="宋体"lang="ZH-CN">等。</p><p> 虽然在编写</font>Windows<font face="宋体" lang="ZH-CN">程序时必然要涉及到</font>DLLs<fontface="宋体" lang="ZH-CN">,但利用</font>Delphi <font face="宋体" lang="ZH-CN">,用户在大部分时候并不会注意到这一点。这一方面是因为</font>Delphi<fontface="宋体" lang="ZH-CN">提供了丰富的函数使用户不必直接去使用</font>WindowsAPI;<font face="宋体" lang="ZH-CN">另一方面即使使用</font>Windows API<fontface="宋体" lang="ZH-CN">,由于</font>Delphi<font face="宋体" lang="ZH-CN">把</font>API<fontface="宋体" lang="ZH-CN">函数和其它</font>Windows DLLs<font face="宋体"lang="ZH-CN">函数重新组织到了几个库单元中,因而也不必使用特殊的调用格式。所以本章的重点放在编写和调用用户自定义的</font>DLLs<fontface="宋体" lang="ZH-CN">上。</p><p> 使用传统的</font>Windows<font face="宋体" lang="ZH-CN">编程方法来创建和使用一个</font>DLLs<fontface="宋体" lang="ZH-CN">是一件很令人头痛的事,正如传统的</font>Windows<fontface="宋体" lang="ZH-CN">编程方法本身就令人生畏一样。用户需要对定义文件、工程文件进行一系列的修改以适应创建和使用</font>DLLs<fontface="宋体" lang="ZH-CN">的需要。</font>Delphi<font face="宋体" lang="ZH-CN">的出现,在这一方面,正如在其它许多方面所做的那样,减轻了开发者的负担。更令人兴奋的是</font>Delphi<fontface="宋体" lang="ZH-CN">利用</font>DLLs <font face="宋体" lang="ZH-CN">实现了窗体的重用机制。用户可以将自己设计好的窗体储存在一个</font>DLLs<fontface="宋体" lang="ZH-CN">中,在需要的时候可随时调用它。 </p></font><p align="center">10.2 DLLs<font face="宋体" lang="ZH-CN">的编写和调用 </p></font><p>10.2.1 DLLs<font face="宋体" lang="ZH-CN">的编写 </p><p> 在</font>Delphi<font face="宋体" lang="ZH-CN">环境中,编写一个</font>DLLs<fontface="宋体" lang="ZH-CN">同编写一个一般的应用程序并没有太大的区别。事实上作为</font>DLLs<font face="宋体" lang="ZH-CN">主体的</font>DLL<font face="宋体" lang="ZH-CN">函数的编写,除了在内存、资源的管理上有所不同外,并不需要其它特别的手段。真正的区别在工程文件上。</p><p> 在绝大多数情况下,用户几乎意识不到工程文件的存在,因为它一般不显示在屏幕上。如果想查看工程文件,则可以打开</font>View<fontface="宋体" lang="ZH-CN">菜单选择</font>Project Source<font face="宋体"lang="ZH-CN">项,此时工程文件的代码就会出现在屏幕的</font>Code Editor(<fontface="宋体" lang="ZH-CN">代码编辑器</font>)<font face="宋体" lang="ZH-CN">中。</p><p> 一般工程文件的格式为: </p><p> </font>program<font face="宋体" lang="ZH-CN"> </font> <font face="宋体"lang="ZH-CN">工程标题</font>;</p><font face="宋体" lang="ZH-CN"><p> </font>uses<font face="宋体" lang="ZH-CN"> </font><font face="宋体" lang="ZH-CN">子句</font>;</p><font face="宋体" lang="ZH-CN"><p> 程序体 </p><p> 而</font>DLLs<font face="宋体" lang="ZH-CN">工程文件的格式为: </p><p> </font>library <font face="宋体" lang="ZH-CN">工程标题</font>;</p><font face="宋体" lang="ZH-CN"><p> </font>uses <font face="宋体" lang="ZH-CN">子句</font>;</p><font face="宋体" lang="ZH-CN"><p> </font>exprots <font face="宋体" lang="ZH-CN">子句</font>;</p><font face="宋体" lang="ZH-CN"><p> 程序体 </p><p> 它们主要的区别有两点:</p><p> </font>1.<font face="宋体" lang="ZH-CN">一般工程文件的头标用</font>program<fontface="宋体" lang="ZH-CN">关键字,而</font>DLLs<font face="宋体" lang="ZH-CN">工程文件头标用</font>library<font face="宋体" lang="ZH-CN">关键字。不同的关键字通知编译器生成不同的可执行文件。用</font>program<fontface="宋体" lang="ZH-CN">关键字生成的是</font>.exe<font face="宋体"lang="ZH-CN">文件,而用</font>library<font face="宋体" lang="ZH-CN">关键字生成的是</font>.dll<fontface="宋体" lang="ZH-CN">文件;</p><p> 2.假如DLLs要输出供其它应用程序使用的函数或过程,则必须将这些函数或过程列在exports子句中。而这些函数或过程本身必须用export编译指令进行编译。</p><p> 根据</font>DLLs<font face="宋体" lang="ZH-CN">完成的功能,我们把</font>DLLs<fontface="宋体" lang="ZH-CN">分为如下的三类:</font></p><p>1.<font face="宋体" lang="ZH-CN">完成一般功能的</font>DLLs<font face="宋体"lang="ZH-CN">;</font></p><p>2.<font face="宋体" lang="ZH-CN">用于数据交换的</font>DLLs<font face="宋体"lang="ZH-CN">;</font></p><p>3.<font face="宋体" lang="ZH-CN">用于窗体重用的</font>DLLs<font face="宋体"lang="ZH-CN">。</p><p> 这一节我们只讨论完成一般功能的</font>DLLs<font face="宋体"lang="ZH-CN">,其它内容将在后边的两节中讨论。 </p></font><p>10.2.1.1 <font face="宋体" lang="ZH-CN">编写一般</font>DLLs<fontface="宋体" lang="ZH-CN">的步骤 </p><p> 编写一般</font>DLLs<font face="宋体" lang="ZH-CN">的步骤如下:</p><p> </font>1.<font face="宋体" lang="ZH-CN">利用</font>Delphi<font face="宋体"lang="ZH-CN">的应用程序模板,建立一个</font>DLLs<font face="宋体"lang="ZH-CN">程序框架。</p><p> 对于</font>Delphi 1.0<font face="宋体" lang="ZH-CN">的用户,由于没有</font>DLLs<fontface="宋体" lang="ZH-CN">模板,因此:</p><p> </font>(1).<font face="宋体" lang="ZH-CN">建立一个一般的应用程序,并打开工程文件;</p><p> </font>(2).<font face="宋体" lang="ZH-CN">移去窗体和相应的代码单元;</p><p> </font>(3).<font face="宋体" lang="ZH-CN">在工程文件中,把</font>program<fontface="宋体" lang="ZH-CN">改成</font>library<font face="宋体" lang="ZH-CN">,移去</font>Uses<fontface="宋体" lang="ZH-CN">子句中的</font>Forms<font face="宋体" lang="ZH-CN">,并添加适当的库单元(一般</font>SysUtils<fontface="宋体" lang="ZH-CN">、</font>Classes<font face="宋体" lang="ZH-CN">是需要的),删去</font>begin...end<fontface="宋体" lang="ZH-CN">之间的所有代码。</p><p> </font>2.<font face="宋体" lang="ZH-CN">以适当的文件名保持文件,此时</font>library<fontface="宋体" lang="ZH-CN">后跟的库名自动修改;</p><p> </font>3.<font face="宋体" lang="ZH-CN">输入过程、函数代码。如果过程、函数准备供其它应用程序调用,则在过程、函数头后加上</font>export<font face="宋体" lang="ZH-CN">编译指示;</p><p> </font>4.<font face="宋体" lang="ZH-CN">建立</font>exports<font face="宋体"lang="ZH-CN">子句,包含供其它应用程序调用的函数和过程名。可以利用标准指示</font>name <font face="宋体" lang="ZH-CN">、</font>Index<font face="宋体" lang="ZH-CN">、</font>resident<fontface="宋体" lang="ZH-CN">以方便和加速过程</font>/<font face="宋体"lang="ZH-CN">函数的调用;</p><p> </font>5.<font face="宋体" lang="ZH-CN">输入库初始化代码。这一步是可选的;</p><p> </font>6.<font face="宋体" lang="ZH-CN">编译程序,生成动态链接库文件。 </p></font><p>10.2.1.2 <font face="宋体" lang="ZH-CN">动态链接库中的标准指示 </p><p> 在动态链接库的输出部分,用到了三个标准指示:</font>name<fontface="宋体" lang="ZH-CN">、</font>Index<font face="宋体" lang="ZH-CN">、</font>resident<fontface="宋体" lang="ZH-CN">。</p><p> </font>1.name</p><font face="宋体" lang="ZH-CN"><p> </font>name<font face="宋体" lang="ZH-CN">后面接一个字符串常量,作为该过程或函数的输出名。如: </p></font><p>exports</p><p>InStr name MyInstr;</p><font face="宋体" lang="ZH-CN"><p> 其它应用程序将用新名字</font>(MyInstr)<fontface="宋体" lang="ZH-CN">调用该过程或函数。如果仍利用原来的名字</font>(InStr)<fontface="宋体" lang="ZH-CN">,则在程序执行到引用点时会引发一个系统错误。</p><p> </font>2.Index</p><font face="宋体" lang="ZH-CN"><p> </font>Index<font face="宋体" lang="ZH-CN">指示为过程或函数分配一个顺序号。如果不使用</font>Index<fontface="宋体" lang="ZH-CN">指示,则由编译器按顺序进行分配。</p><p> </font>Index<font face="宋体" lang="ZH-CN">后所接数字的范围为</font>1...32767<fontface="宋体" lang="ZH-CN">。使用</font>Index<font face="宋体" lang="ZH-CN">可以加速调用过程。</p><p> </font>3.resident</p><font face="宋体" lang="ZH-CN"><p> 使用</font>resident<font face="宋体"lang="ZH-CN">,则当</font>DLLs<font face="宋体" lang="ZH-CN">装入时特定的输出信息始终保持在内存中。这样当其它应用程序调用该过程时,可以比利用名字扫描</font>DLL<fontface="宋体" lang="ZH-CN">入口降低时间开销。</p><p> 对于那些其它应用程序常常要调用的过程或函数,使用</font>resident<fontface="宋体" lang="ZH-CN">指示是合适的。例如: </p></font><p>exports</p><p>InStr name MyInStr resident; </p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -