⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 024.htm

📁 delphi教程
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<p>10.2.1.3 DLLs<font face="宋体" lang="ZH-CN">中的变量和段 </p></font><p><font face="宋体" lang="ZH-CN">一个</font>DLLs<font face="宋体"lang="ZH-CN">拥有自己的数据段</font>(DS)<font face="宋体" lang="ZH-CN">,因而它声明的任何变量都为自己所私有。调用它的模块不能直接使用它定义的变量。要使用必须通过过程或函数界面才能完成。而对</font>DLLs<fontface="宋体" lang="ZH-CN">来说,它永远都没有机会使用调用它的模块中声明的变量。</p><p>  一个</font>DLLs<font face="宋体" lang="ZH-CN">没有自己的堆栈段</font>(SS)<fontface="宋体" lang="ZH-CN">,它使用调用它的应用程序的堆栈。因此在</font>DLL<fontface="宋体" lang="ZH-CN">中的过程、函数绝对不要假定</font>DS = SS<fontface="宋体" lang="ZH-CN">。一些语言在小模式编译下有这种假设,但使用</font>Delphi<fontface="宋体" lang="ZH-CN">可以避免这种情况。</font>Delphi<font face="宋体"lang="ZH-CN">绝不会产生假定</font>DS = SS<font face="宋体" lang="ZH-CN">的代码,</font>Delphi<fontface="宋体" lang="ZH-CN">的任何运行时间库过程</font>/<font face="宋体"lang="ZH-CN">函数也都不作这种假定。需注意的是如果读者想嵌入汇编语言代码,绝不要使</font>SS<fontface="宋体" lang="ZH-CN">和</font>DS<font face="宋体" lang="ZH-CN">登录同一个值。 </p></font><p>10.2.1.4 DLLs<font face="宋体" lang="ZH-CN">中的运行时间错和处理 </p><p>  由于</font>DLLs<font face="宋体" lang="ZH-CN">无法控制应用程序的运行,导致很难进行异常处理,因此编写</font>DLLs<fontface="宋体" lang="ZH-CN">时要十分小心,以确保被调用时能正常执行</font><font face="宋体" lang="ZH-CN">。当</font>DLLs<font face="宋体" lang="ZH-CN">中发生一个运行时间错时,相应</font>DLLs<fontface="宋体" lang="ZH-CN">并不一定从内存中移去(因为此时其它应用程序可能正在用它),而调用</font>DLLs<fontface="宋体" lang="ZH-CN">的程序异常中止。这样造成的问题是当</font>DLLs<fontface="宋体" lang="ZH-CN">已被修改,重新进行调用时,内存中保留的仍然可能是以前的版本,修改后的程序并没有得到验证。对于这个问题,有以下两种解决方法:</p><p>  </font>1.<font face="宋体" lang="ZH-CN">在程序的异常处理部分显式将</font>DLL<fontface="宋体" lang="ZH-CN">卸出内存;</p><p>  </font>2.<font face="宋体" lang="ZH-CN">完全退出</font>Windows<fontface="宋体" lang="ZH-CN">,而后重新启动,运行相应的程序。</p><p>  同一般的应用程序相比,</font>DLL<font face="宋体" lang="ZH-CN">中运行时间错的处理是很困难的,而造成的后果也更为严重。因此要求程序设计者在编写代码时要有充分、周到的考虑。 </p></font><p>10.2.1.5 <font face="宋体" lang="ZH-CN">库初始化代码的编写 </p><p>  传统</font>Windows<font face="宋体" lang="ZH-CN">中动态链接库的编写,需要两个标准函数:</font>LibMain<fontface="宋体" lang="ZH-CN">和</font>WEP<font face="宋体" lang="ZH-CN">,用于启动和关闭</font>DLL<fontface="宋体" lang="ZH-CN">。在</font>LibMain<font face="宋体" lang="ZH-CN">中,可以执行开锁</font>DLL<fontface="宋体" lang="ZH-CN">数据段、分配内存、初始化变量等初始化工作;而</font>WEP<fontface="宋体" lang="ZH-CN">在从内存中移去</font>DLLs<font face="宋体"lang="ZH-CN">前被调用,一般用于进行必要的清理工作,如释放内存等。</font>Delphi<fontface="宋体" lang="ZH-CN">用自己特有的方式实现了这两个标准函数的功能。这就是在工程文件中的</font>begin...end<fontface="宋体" lang="ZH-CN">部分添加初始化代码。和传统</font>Windows<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.LibMain<font face="宋体" lang="ZH-CN">和</font>WEP<font face="宋体"lang="ZH-CN">对用户透明,由系统自动调用。</p><p>  初始化代码完成的主要工作是:</p><p>  </font>1.<font face="宋体" lang="ZH-CN">初始化变量、分配全局内存块、登录窗口对象等初始化工作。在</font>(10.3.2)<fontface="宋体" lang="ZH-CN">节“利用</font>DLLs<font face="宋体" lang="ZH-CN">实现应用程序间的数据传输”中,用于数据共享的全局内存块就是在初始化代码中分配的。</p><p>  </font>2.<font face="宋体" lang="ZH-CN">设置</font>DLLs<font face="宋体"lang="ZH-CN">退出时的执行过程。</font>Delphi<font face="宋体" lang="ZH-CN">有一个预定义变量</font>ExitProc<fontface="宋体" lang="ZH-CN">用于指向退出过程的地址。用户可以把自己的过程名赋给</font>ExitProc<fontface="宋体" lang="ZH-CN">。系统自动调用</font>WEP<font face="宋体" lang="ZH-CN">函数,把</font>ExitProc<fontface="宋体" lang="ZH-CN">指向的地址依次赋给</font>WEP<font face="宋体"lang="ZH-CN">执行,直到</font>ExitProc<font face="宋体" lang="ZH-CN">为</font>nil<fontface="宋体" lang="ZH-CN">。</p><p>  下边的一段程序包含一个退出过程和一段初始化代码,用来说明如何正确设置退出过程。 </p></font><p>library Test;</p><p>{$S-}</p><p>uses WinTypes, WinProcs;</p><p>var</p><p>SaveExit: Pointer; </p><p>procedure LibExit; far;</p><p>begin</p><p>if ExitCode = wep_System_Exit then</p><p>begin</p><p>{ <font face="宋体" lang="ZH-CN">系统关闭时的相应处理</font> } </p><p>end </p><p>else</p><p>begin</p><p>{ DLL<font face="宋体" lang="ZH-CN">卸出时的相应处理</font> }</p><p>end;</p><p>ExitProc := SaveExit; { <font face="宋体" lang="ZH-CN">恢复原来的退出过程指针</font>}</p><p>end; </p><p>begin</p><p>{DLL<font face="宋体" lang="ZH-CN">的初始化工作</font> }</p><p>SaveExit := ExitProc; { <font face="宋体" lang="ZH-CN">保存原来的退出过程指针</font>}</p><p>ExitProc := @LibExit; { <font face="宋体" lang="ZH-CN">安装新的退出过程</font>}</p><p>end.</p><font face="宋体" lang="ZH-CN"><p>  在初始化代码中,首先把原来的退出过程指针保存到一个变量中,而后再把新的退出过程地址赋给</font>ExitProc<fontface="宋体" lang="ZH-CN">。而在自定义退出过程</font>LibExit<font face="宋体"lang="ZH-CN">结束时再把</font>ExitProc<font face="宋体" lang="ZH-CN">的值恢复。由于</font>ExitProc<fontface="宋体" lang="ZH-CN">是一个系统全局变量,所以在结束时恢复原来的退出过程是必要的。</p><p>  退出过程</font>LibExit<font face="宋体" lang="ZH-CN">中使用了一个系统定义变量</font>ExitCode<fontface="宋体" lang="ZH-CN">,用于标志退出时的状态。</font> ExitCode<fontface="宋体" lang="ZH-CN">的取值与意义如下: </p></font><p><font face="宋体" lang="ZH-CN">表</font>10.1 ExitCode<font face="宋体"lang="ZH-CN">的取值与意义</font></p><p><font face="宋体" lang="ZH-CN">━━━━━━━━━━━━━━━━━━━━━</p><p>取 值 意 义</font></p><p><font face="宋体" lang="ZH-CN">—————————————————————</p><p>  </font>WEP_System_Exit Windows<font face="宋体" lang="ZH-CN">关闭 </p></font><p>WEP_Free_DLLx DLLs<font face="宋体" lang="ZH-CN">被卸出</font></p><p><font face="宋体" lang="ZH-CN">━━━━━━━━━━━━━━━━━━━━━ </p><p>  退出过程编译时必须关闭</font>stack_checking<font face="宋体"lang="ZH-CN">,因而需设置编译指示</font> {$S-} <font face="宋体" lang="ZH-CN">。 </p></font><p>10.2.1.6 <font face="宋体" lang="ZH-CN">编写一般</font>DLLs<fontface="宋体" lang="ZH-CN">的应用举例 </p><p>  在下面的程序中我们把一个字符串操作的函数储存到一个</font>DLLs<fontface="宋体" lang="ZH-CN">中,以便需要的时候调用它。应该注意的一点是:为了保证这个函数可以被其它语言编写的程序所调用,作为参数传递的字符串应该是无结束符的字符数组类型</font>(<fontface="宋体" lang="ZH-CN">即</font>PChar<font face="宋体" lang="ZH-CN">类型</font>)<fontface="宋体" lang="ZH-CN">,而不是</font>Object Pascal<font face="宋体"lang="ZH-CN">的带结束符的</font>Srting<font face="宋体" lang="ZH-CN">类型。程序清单如下:</p></font><p>library Example;</p><p>uses</p><p>SysUtils,</p><p>Classes;</p><p>{<font face="宋体" lang="ZH-CN">返回字符在字符串中的位置}</p></font><p>function InStr(SourceStr: PChar;Ch: Char): Integer; export;</p><p>var</p><p>Len,i: Integer;</p><p>begin</p><p>Len := strlen(SourceStr);</p><p>for i := 0 to Len-1 do</p><p>if SourceStr[i] = ch then</p><p>begin</p><p>Result := i;</p><p>Exit;</p><p>end;</p><p>Result := -1;</p><p>end;</p><p>exports</p><p>Instr Index 1 name 'MyInStr' resident;</p><p>begin</p><p>end. </p><p>10.2.2 <font face="宋体" lang="ZH-CN">调用</font>DLLs</p><font face="宋体" lang="ZH-CN"><p>  有两种方法可用于调用一个储存在</font>DLLs<fontface="宋体" lang="ZH-CN">中的过程。</p><p>  </font>1.<font face="宋体" lang="ZH-CN">静态调用或显示装载</p><p>  使用一个外部声明子句,使</font>DLLs<font face="宋体" lang="ZH-CN">在应用程序开始执行前即被装入。例如: </p><p>  </font>function Instr(SourceStr : PChar;Check : Char); Integer; far; external'UseStr';</p><font face="宋体" lang="ZH-CN"><p>  使用这种方法,程序无法在运行时间里决定</font>DLLs<fontface="宋体" lang="ZH-CN">的调用。假如一个特定的</font>DLLs<font face="宋体"lang="ZH-CN">在运行时无法使用,则应用程序将无法执行。</p><p>  </font>2.<font face="宋体" lang="ZH-CN">动态调用或隐式装载</p><p>  使用</font>Windows API<font face="宋体" lang="ZH-CN">函数</font>LoadLibray<fontface="宋体" lang="ZH-CN">和</font>GetProcAddress<font face="宋体" lang="ZH-CN">可以实现在运行时间里动态装载</font>DLLs<fontface="宋体" lang="ZH-CN">并调用其中的过程。</p><p>  若程序只在其中的一部分调用</font>DLLs<font face="宋体"lang="ZH-CN">的过程,或者程序使用哪个</font>DLLs<font face="宋体"lang="ZH-CN">,</font> <font face="宋体" lang="ZH-CN">调用其中的哪个过程需要根据程序运行的实际状态来判断,那么使用动态调用就是一个很好的选择。</p><p>  使用动态调用,即使装载一个</font>DLLs<font face="宋体"lang="ZH-CN">失败了,程序仍能继续运行。 </p></font><p>10.2.3 <font face="宋体" lang="ZH-CN">静态调用</p><p>  在静态调用一个</font>DLLs<font face="宋体" lang="ZH-CN">中的过程或函数时,</font>external<fontface="宋体" lang="ZH-CN">指示增加到过程或函数的声明语句中。被调用的过程或函数必须采用远调用模式。这可以使用</font>far<fontface="宋体" lang="ZH-CN">过程指示或一个{</font>$F +}<font face="宋体"lang="ZH-CN">编译指示。</p><p>  </font>Delphi<font face="宋体" lang="ZH-CN">全部支持传统</font>Windows<fontface="宋体" lang="ZH-CN">动态链接库编程中的三种调用方式,它们是:</p><p>  ●</font> <font face="宋体" lang="ZH-CN">通过过程</font>/<fontface="宋体" lang="ZH-CN">函数名</p><p>  ●</font> <font face="宋体" lang="ZH-CN">通过过程</font>/<fontface="宋体" lang="ZH-CN">函数的别名</p><p>  ●</font> <font face="宋体" lang="ZH-CN">通过过程</font>/<fontface="宋体" lang="ZH-CN">函数的顺序号 </p><p>  通过过程或函数的别名调用,给用户编程提供了灵活性,而通过顺序号</font>(Index)<fontface="宋体" lang="ZH-CN">调用可以提高相应</font>DLL<font face="宋体"lang="ZH-CN">的装载速度。 </p></font><p>10.2.4 <font face="宋体" lang="ZH-CN">动态调用 </p></font><p>10.2.4.1 <font face="宋体" lang="ZH-CN">动态调用中的</font>API<fontface="宋体" lang="ZH-CN">函数 </p><p>  动态调用中使用的</font>Windows API<font face="宋体" lang="ZH-CN">函数主要有三个</font>,<fontface="宋体" lang="ZH-CN">即:</font>Loadlibrary<font face="宋体" lang="ZH-CN">,</font>GetProcAddress<fontface="宋体" lang="ZH-CN">和</font>Freelibrary<font face="宋体" lang="ZH-CN">。</p><p>  </font> 1.Loadlibrary: <font face="宋体" lang="ZH-CN">把指定库模块装入内存</p><p>  语法为: </p><p>  </font>function Loadlibrary(LibFileName: PChar): THandle; </p><p>LibFileName<font face="宋体" lang="ZH-CN">指定了要装载</font>DLLs<fontface="宋体" lang="ZH-CN">的文件名,如果</font>LibFileName<font face="宋体"lang="ZH-CN">没有包含一个路径,则</font>Windows<font face="宋体" lang="ZH-CN">按下述顺序进行查找:</p>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -