📄 024.htm
字号:
<p> </font>(1)<font face="宋体" lang="ZH-CN">当前目录;</p><p> </font>(2)Windows<font face="宋体" lang="ZH-CN">目录</font>(<fontface="宋体" lang="ZH-CN">包含</font>win.com<font face="宋体" lang="ZH-CN">的目录</font>)<fontface="宋体" lang="ZH-CN">。函数</font>GetWindowDirectory<font face="宋体"lang="ZH-CN">返回这一目录的路径;</p><p> </font>(3)Windows<font face="宋体" lang="ZH-CN">系统目录</font>(<fontface="宋体" lang="ZH-CN">包含系统文件如</font>gdi.exe<font face="宋体"lang="ZH-CN">的目录</font>)<font face="宋体" lang="ZH-CN">。函数</font>GetSystemDirectory<fontface="宋体" lang="ZH-CN">返回这一目录的路径;</p><p> </font>(4)<font face="宋体" lang="ZH-CN">包含当前任务可执行文件的目录。利用函数</font>GetModuleFileName<fontface="宋体" 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<fontface="宋体" 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<fontface="宋体" 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>(<fontface="宋体" 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>(<fontface="宋体" 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<fontface="宋体" lang="ZH-CN">位扩展</font></p><p><font face="宋体" lang="ZH-CN">━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━</font></p><font face="宋体" lang="ZH-CN"><p> 假如在应用程序用</font>Loadlibrary<fontface="宋体" lang="ZH-CN">调用某一模块前,其它应用程序已把该模块装入内存,则</font>Loadlibrary<fontface="宋体" lang="ZH-CN">并不会装载该模块的另一实例,而是使该模块的“引用计数”加</font>1<fontface="宋体" 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<fontface="宋体" lang="ZH-CN">返回。如果把</font>Module<font face="宋体" lang="ZH-CN">设置为</font>nil<fontface="宋体" lang="ZH-CN">,则表示要引用当前模块。</p><p> </font>ProcName<font face="宋体" lang="ZH-CN">是指向含有函数名的以</font>nil<fontface="宋体" lang="ZH-CN">结尾的字符串的指针,或者也可以是函数的次序值。如果</font>ProcName<fontface="宋体" lang="ZH-CN">参数是次序值,则如果该次序值的函数在模块中并不存在时,</font>GetProcAddress<fontface="宋体" lang="ZH-CN">仍返回一个非</font>nil<font face="宋体" lang="ZH-CN">的值。这将引起混乱。因此大部分情况下用函数名是一种更好的选择。如果用函数名,则函数名的拼写必须与动态链接库文件</font>EXPORTS<fontface="宋体" lang="ZH-CN">节中的对应拼写相一致。</p><p> 如果</font>GetProcAddress<font face="宋体" lang="ZH-CN">执行成功,则返回模块中函数入口处的地址,否则返回</font>nil<fontface="宋体" 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<fontface="宋体" lang="ZH-CN">返回。</p><p> 由于库模块在内存中只装载一次,因而调用</font>Freelibrary<fontface="宋体" lang="ZH-CN">首先使库模块的引用计数减一。如果引用计数减为</font>0<fontface="宋体" lang="ZH-CN">,则卸出该模块。</p><p> 每调用一次</font>Loadlibrary<font face="宋体" lang="ZH-CN">就应调用一次</font>FreeLibray<fontface="宋体" lang="ZH-CN">,以保证不会有多余的库模块在应用程序结束后仍留在内存中。 </p></font><p>10.2.4.2 <font face="宋体" lang="ZH-CN">动态调用举例 </p><p> 对于动态调用,我们举了如下的一个简单例子。系统一共包含两个编辑框。在第一个编辑框中输入一个字符串,而后在第二个编辑框中输入字符。如果该字符包含在第一个编辑框的字符串中,则标签框显示信息:“位于第</font>n<fontface="宋体" 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 width="94%"></TD><TD CLASS="tt3" VALIGN="bottom" 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></TR></table></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -