📄 024.htm
字号:
face="宋体" lang="ZH-CN">包含</font>win.com<font face="宋体" lang="ZH-CN">的目录</font>)<font
face="宋体" lang="ZH-CN">。函数</font>GetWindowDirectory<font face="宋体"
lang="ZH-CN">返回这一目录的路径;</p>
<p> </font>(3)Windows<font face="宋体" lang="ZH-CN">系统目录</font>(<font
face="宋体" lang="ZH-CN">包含系统文件如</font>gdi.exe<font face="宋体"
lang="ZH-CN">的目录</font>)<font face="宋体" lang="ZH-CN">。函数</font>GetSystemDirectory<font
face="宋体" lang="ZH-CN">返回这一目录的路径;</p>
<p> </font>(4)<font face="宋体" lang="ZH-CN">包含当前任务可执行文件的目录。利用函数</font>GetModuleFileName<font
face="宋体" lang="ZH-CN">可以返回这一目录的路径;</p>
<p> </font>(5)<font face="宋体" lang="ZH-CN">列在</font>PATH<font face="宋体"
lang="ZH-CN">环境变量中的目录;</p>
<p> </font>(6)<font face="宋体" lang="ZH-CN">网络的映象目录列表。</p>
<p> 如果函数执行成功,则返回装载库模块的实例句柄。否则,返回一个小于</font>HINSTANCE_ERROR<font
face="宋体" lang="ZH-CN">的错误代码。错误代码的意义如下表: </p>
<p> 表</font>10.2 Loadlibrary<font face="宋体" lang="ZH-CN">返回错误代码的意义</p>
<p>━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━</font></p>
<p><font face="宋体" lang="ZH-CN">错误代码 意 义</p>
<p>——————————————————————————————————————</p>
<p> </font> 0 <font face="宋体" lang="ZH-CN">系统内存不够,可执行文件被破坏或调用非法</p>
<p> </font> 2 <font face="宋体" lang="ZH-CN">文件没有被发现</p>
<p> </font> 3 <font face="宋体" lang="ZH-CN">路径没有被发现</p>
<p> </font> 5 <font face="宋体" lang="ZH-CN">企图动态链接一个任务或者有一个共享或网络保护错</p>
<p> </font> 6 <font face="宋体" lang="ZH-CN">库需要为每个任务建立分离的数据段</p>
<p> </font> <font face="宋体" lang="ZH-CN"> </font> 8 <font face="宋体"
lang="ZH-CN">没有足够的内存启动应用程序</p>
<p> </font> 10 Windows<font face="宋体" lang="ZH-CN">版本不正确</p>
<p> </font> 11 <font face="宋体" lang="ZH-CN">可执行文件非法。或者不是</font>Windows<font
face="宋体" lang="ZH-CN">应用程序,或者在</font>.EXE<font face="宋体"
lang="ZH-CN">映</p>
<p> </font> <font face="宋体" lang="ZH-CN"> 像中有错误</p>
<p> </font> 12 <font face="宋体" lang="ZH-CN">应用程序为一个不同的操作系统设计</font>(<font
face="宋体" lang="ZH-CN">如</font>OS/2<font face="宋体" lang="ZH-CN">程序</font>)</p>
<p>13 <font face="宋体" lang="ZH-CN">应用程序为</font>MS DOS4.0<font face="宋体"
lang="ZH-CN">设计</p>
<p> </font> 14 <font face="宋体" lang="ZH-CN">可执行文件的类型不知道</p>
<p> </font> 15 <font face="宋体" lang="ZH-CN">试图装载一个实模式应用程序</font>(<font
face="宋体" lang="ZH-CN">为早期</font>Windows<font face="宋体" lang="ZH-CN">版本设计</font>)</p>
<p>16 <font face="宋体" lang="ZH-CN">试图装载包含可写的多个数据段的可执行文件的第二个实例</p>
<p> </font> 19 <font face="宋体" lang="ZH-CN">试图装载一个压缩的可执行文件。文件必须被解压后才能被装裁</p>
<p> </font> 20 <font face="宋体" lang="ZH-CN">动态链接库文件非法</p>
<p> </font> 21 <font face="宋体" lang="ZH-CN">应用程序需要</font>32<font
face="宋体" lang="ZH-CN">位扩展</font></p>
<p><font face="宋体" lang="ZH-CN">━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━</font>
</p>
<font face="宋体" lang="ZH-CN"><p> 假如在应用程序用</font>Loadlibrary<font
face="宋体" lang="ZH-CN">调用某一模块前,其它应用程序已把该模块装入内存,则</font>Loadlibrary<font
face="宋体" lang="ZH-CN">并不会装载该模块的另一实例,而是使该模块的“引用计数”加</font>1<font
face="宋体" lang="ZH-CN">。 </p>
<p> </font>2.GetProcAddress<font face="宋体" lang="ZH-CN">:捡取给定模块中函数的地址</p>
<p> 语法为: </p>
<p> </font>function GetProcAddress(Module: THandle; ProcName: PChar): TFarProc; </p>
<p>Module<font face="宋体" lang="ZH-CN">包含被调用的函数库模块的句柄,这个值由</font>Loadlibrary<font
face="宋体" lang="ZH-CN">返回。如果把</font>Module<font face="宋体" lang="ZH-CN">设置为</font>nil<font
face="宋体" lang="ZH-CN">,则表示要引用当前模块。</p>
<p> </font>ProcName<font face="宋体" lang="ZH-CN">是指向含有函数名的以</font>nil<font
face="宋体" lang="ZH-CN">结尾的字符串的指针,或者也可以是函数的次序值。如果</font>ProcName<font
face="宋体" lang="ZH-CN">参数是次序值,则如果该次序值的函数在模块中并不存在时,</font>GetProcAddress<font
face="宋体" lang="ZH-CN">仍返回一个非</font>nil<font face="宋体" lang="ZH-CN">的值。这将引起混乱。因此大部分情况下用函数名是一种更好的选择。如果用函数名,则函数名的拼写必须与动态链接库文件</font>EXPORTS<font
face="宋体" lang="ZH-CN">节中的对应拼写相一致。</p>
<p> 如果</font>GetProcAddress<font face="宋体" lang="ZH-CN">执行成功,则返回模块中函数入口处的地址,否则返回</font>nil<font
face="宋体" lang="ZH-CN">。</font></p>
<p>3.Freelibrary<font face="宋体" lang="ZH-CN">:从内存中移出库模块</p>
<p> 语法为: </p>
<p> </font>procedure Freelibrary(Module : THandle); </p>
<p>Module<font face="宋体" lang="ZH-CN">为库模块的句柄。这个值由</font>Loadlibrary<font
face="宋体" lang="ZH-CN">返回。</p>
<p> 由于库模块在内存中只装载一次,因而调用</font>Freelibrary<font
face="宋体" lang="ZH-CN">首先使库模块的引用计数减一。如果引用计数减为</font>0<font
face="宋体" lang="ZH-CN">,则卸出该模块。</p>
<p> 每调用一次</font>Loadlibrary<font face="宋体" lang="ZH-CN">就应调用一次</font>FreeLibray<font
face="宋体" lang="ZH-CN">,以保证不会有多余的库模块在应用程序结束后仍留在内存中。 </p>
</font><p>10.2.4.2 <font face="宋体" lang="ZH-CN">动态调用举例 </p>
<p> 对于动态调用,我们举了如下的一个简单例子。系统一共包含两个编辑框。在第一个编辑框中输入一个字符串,而后在第二个编辑框中输入字符。如果该字符包含在第一个编辑框的字符串中,则标签框显示信息:“位于第</font>n<font
face="宋体" lang="ZH-CN">位。”,否则显示信息:“不包含这个字符。”。如图是程序的运行界面。</p>
<p>输入检查功能的实现在Edit2的OnKeyPress事件处理过程中,程序清单如下。 </p>
<p>procedure TForm1.Edit2KeyPress(Sender: TObject; var Key: Char);</p>
<p>var</p>
<p>order: Integer;</p>
<p>txt: PChar;</p>
<p>PFunc: TFarProc;</p>
<p>Moudle: THandle;</p>
<p>begin</p>
<p>Moudle := Loadlibrary('c:\dlls\example.dll');</p>
<p>if Moudle > 32 then</p>
<p>begin</p>
<p>Edit2.text := '';</p>
<p>Pfunc := GetProcAddress(Moudle,'Instr');</p>
<p>txt := StrAlloc(80);</p>
<p>txt := StrPCopy(txt,Edit1.text);</p>
<p>Order := TInstr(PFunc)(txt,Key);</p>
<p>if Order = -1 then</p>
<p>Label1.Caption := '不包含这个字符 '</p>
<p>else</p>
<p>Label1.Caption := '位于第'+IntToStr(Order+1)+'位';</p>
<p>end;</p>
<p>Freelibrary(Moudle);</p>
<p>end;</p>
<p> 在利用GetProcAddess返回的函数指针时,必须进行强制类型转换: </p>
<p>Order := TInstr(PFunc)(text,Key);</p>
<p> TInStr是一个定义好了的函数类型: </p>
<p>type</p>
<p>TInStr = function(Source: PChar;Check: Char): Integer; </p>
<p align="center">10.3 利用DLLs实现数据传输 </p>
<p>10.3.1 DLLs中的全局内存 </p>
<p> Windows规定:DLLs并不拥有它打开的任何文件或它分配的任何全局内存块。这些对象由直接或间接调用DLLs的应用程序拥有。这样,当应用程序中止时,它拥有的打开的文件自动关闭,它拥有的全局内存块自动释放。这就意味着保存在DLLs全局变量中的文件和全局内存块变量在DLLs没有被通知的情况下就变为非法。这将给其它使用该DLLs的应用程序造成困难。</p>
<p> 为了避免出现这种情况,文件和全局内存块句柄不应作为DLLs的全局变量,而是作为DLLs中过程或函数的参数传递给DLLs使用。调用DLLs的应用程序应该负责对它们的维护。</p>
<p> 但在特定情况下,DLLs也可以拥有自己的全局内存块。这些内存块必须用gmem_DDEShare属性进行分配。这样的内存块直到被DLLs显示释放或DLLs退出时都保持有效。</p>
<p> 由DLLs管理的全局内存块是应用程序间进行数据传输的又一途径,下面我们将专门讨论这一问题。 </p>
<p>10.3.2 利用DLLs实现应用程序间的数据传输 </p>
<p> 利用DLLs实现应用程序间的数据传输的步骤为:</p>
<p> 1. 编写一个DLLs程序,其中拥有一个用gmem_DDEShare属性分配的全局内存块;</p>
<p> 2. 服务器程序调用DLLs,向全局内存块写入数据;</p>
<p> 3. 客户程序调用DLLs,从全局内存块读取数据。 </p>
<p>10.3.2.1 用于实现数据传输的DLLs的编写 </p>
<p> 用于实现数据传输的DLLs与一般DLLs的编写基本相同,其中特别的地方是:</p>
<p> 1. 定义一个全局变量句柄: </p>
<p>var</p>
<p>hMem: THandle;</p>
<p> 2. 定义一个过程,返回该全局变量的句柄。该过程要包含在exports子句中。如: </p>
<p>function GetGlobalMem: THandle; export;</p>
<p>begin</p>
<p>Result := hMem;</p>
<p>end;</p>
<p> 3. 在初始化代码中分配全局内存块:</p>
<p>程序清单如下: </p>
<p>begin</p>
<p>hMem := GlobalAlloc(gmem_MOVEABLE and gmem_DDEShare,num);</p>
<p>if hMem = 0 then</p>
<p>MessageDlg('Could not allocate memory',mtWarning,[mbOK],0);</p>
<p>end.</p>
<p> num是一个预定义的常数。</p>
<p>Windows API函数GlobalAlloc用于从全局内存堆中分配一块内存,并返回该内存块的句柄。该函数包括两个参数,第一个参数用于设置内存块的分配标志。可以使用的分配标志如下表所示。</p>
<p>表10.3 全局内存块的分配标志</p>
<p>━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━</p>
<p>标 志 意 义</p>
<p>—————————————————————————————————</p>
<p>gmem_DDEShare 分配可由应用程序共享的内存</p>
<p>gmem_Discardable 分配可抛弃的内存(只与gmem_Moveable连用)</p>
<p>gmem_Fixed 分配固定内存</p>
<p>gmem_Moveable 分配可移动的内存</p>
<p>gmem_Nocompact 该全局堆中的内存不能被压缩或抛弃</p>
<p>gmem_Nodiscard 该全局堆中的内存不能被抛弃</p>
<p>gmem_NOT_Banked 分配不能被分段的内存</p>
<p>gmem_Notify 通知功能。当该内存被抛弃时调用GlobalNotify函数</p>
<p>gmem_Zeroinit 将所分配内存块的内容初始化为零</p>
<p>━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ </p>
<p> 有两个预定义的常用组合是:</p>
<p>GHND = gmem_Moveable and gmem_Zeroinit</p>
<p>GPTK = gmem_Fixed and gmem_Zeroinit</p>
<p> 第二个参数用于设置欲分配的字节数。分配的字节数必须是32的倍数,因而实际分配的字节数可能比所设置的要大。</p>
<p> 由于用gmem_DDEShare分配的内存在分配内存的模块终止时自动抛弃,因而不必调用GlobalFree显式释放内存。</p>
<p> </font></p>
<hr color="#EE9B73" size="1" width="94%">
</TD>
<TD CLASS="tt3" VALIGN="bottom" width="8%" background="bg.gif"><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>
<A HREF="../../../../../index.htm"><FONT style="FONT-SIZE: 9pt">回首页</font></A><BR>
</strong>
</TD>
</TR>
</table>
</BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -