DELPHI基础教程
第七章 剪贴板和动态数据交换(一) 应用程序间的数据交换是象 Windows 这样的多任务环境的重要特性。作为一种基于 Windows 的开发工具, Delphi 支持如下四种数据交换方式:剪贴板、动态数据交换 ( DDE) 、对象联接与嵌入 (OLE) 以及动态联接库 (DLLs) 。这中间前三种方式最为常用, OLE 功能最为强大, DDE 次之。而剪贴板使用最为方便。在本章,我们只讨论剪贴板和动态数据交换。利用 OLE 实现数据交换见下一章,利用动态联接库 (DLLs) 进行数据交换将在第十章中介绍。 7.1 剪贴板及其应用 本质上,剪贴板只是一个全局内存块。当一个应用程序将数据传送给剪贴板后,通过修改内存块分配标志,把相关内存块的所有权从应用程序移交给 Windows 自身。其它应用程序可以通过一个句柄找到这个内存块,从而能够从内存块中读取数据。这样就实现了数据在不同应用程序间的传输。 剪贴板虽然功能较为简单,且不能实现实时传输,但却是更为复杂的 DDE 和 OLE 的基础。对于一些只是偶尔需要使用其它应用程序数据的程序来说,使用剪贴板不失为一种方便、快捷的方式。 Delphi 把剪贴板的大部分功能封装到一个 TClipboard 类中,同时把使用频度最高的文本传输功能 ( 包括 DBImage 的图像传输功能 ) 置入相应部件作为部件的方法,从而使用户可以十分方便地使用剪贴板进行编程。 7.1.1 使用剪贴板传输文本 剪贴板传输文本主要是应用如下的三个方法 :CopyToClipboard 、 CutToClipboard 和 PasteFromClipboard 。包含这些方法的部件如下表所示。 表 7.1 包含剪贴板方法的部件 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 方 法 部 件 ——————————————————————————— TDBEdit TDBMemo TDBImage CopyToClipboard TEdit TMemo TMaskEdit TOLEContainer TDDEServerItem ——————————————————————————— TDBEdit TDBMemo CutToClipboard TDBImage TEdit TMemo TMaskEdit ——————————————————————————— TDBEdit TDBMemo PasteFromClipboard TDBImage TEdit TMemo TMaskEdit ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 除 TDBImage 外,其余全是有关文本的控件。 在把文本传输到剪贴板之前,文本必须被选中。 若选 TMaskEdit 的 AutoSelect 属性为 True ,则当 MaskEdit 获得输入焦点时文本自动被选中;若选 TEdit 、 TMemo 的 HideSelection 属性为 True ,则失去焦点时,文本选中状态自动隐藏,重新获得焦点时再显示。 下面的语句把 MaskEdit 中选中的文本剪切到剪贴板: MaskEdit .CutToClipboard; 下面的语句把剪贴板中的文本粘贴到 Memo 的当前光标处: Memo.PasteFromClipboard ; 利用剪贴板类也可以实现文本的传输,见 (7.1.2) 中的介绍。 7.1.2 剪贴板类 为方便剪贴板的操作, Delphi 在 Clipbrd 库单元中定义了一个 TClipboard 类,并且预定义了一个变量 Clipboard 作为类 TClipboard 的实例,从而使用户在绝大多数场合不必自己去定义一个 TClipboard 的实例。 利用剪贴板类可以进行文本、图像和部件的传输,剪贴板类为实现这些方法提供了相应的属性和方法。表 7.2 、表 7.3 列出了 TClipboard 属性和方法的意义。 表 7.2 TClipboard 的属性 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 属 性 意 义 ─────────────────────────── AsText 保存剪贴板的文本,只有运行时才可设置 FormatCount 可用剪贴板格式的数目 Formats 可用剪贴板格式链 ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 表 7.3 TClipboard 的方法 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 方 法 参 数 意 义 ───────────────────────────────────── Clear 无 清除剪贴板的内容 Assign Source:TPersistent 把 Source 参数指定的对象拷贝到剪贴板,常 用于图形、图像对象 Open 无 打开剪贴板,阻止其它应用程序改变它的内容 Close 无 关闭打开的剪贴板 SetComponent Source:TPersistent 把部件拷贝到剪贴板 GetComponent Owner 从剪贴板取回一个部件并放置 Parent :TPersistent SetAsHandle Format:Word 把指定格式数据的句柄交给剪贴板 返回类型: THandle GetAsHandle Format:Word 返回剪贴板指定格式数据的句柄 返回类型: THandle HasFormat Format:Word 判断剪贴板是否拥有给定的格式 返回类型: Boolean SetTextBuf Buffer:PChar 设置剪贴板的文本内容 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 剪贴板中可能的数据格式如下表。 表 7.4 剪贴板数据格式及其意义 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 数据格式 意 义 ────────────────────────────── CF_TEXT 文本。每行以 CF_LF 结束, nil 标志文本结束 CF_BITMAP Windows 位图 CF_METAFILE Windows 元文件 CF_PICTURE TPicture 类型的对象 CF_OBJECT 任何 TPersistent 类型的对象 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 利用 TClipboard 实现文本的传输使用 AsText 属性和 SetTextBuf 方法。 AsText 属性为非控件部件的剪贴板操作提供了方便。如: Clipboard. AsText := Form1.Caption ; 把 Form1 的标题拷贝到剪贴板。 Label1.Caption := Clipboard.AsText; 把剪贴板中的文本写入 Label1 。 SetTextBuf 用于把超过 255 个字符的字符串拷入剪贴板。 7.1.3 利用剪贴板传输图像 7.1.3.1 拷贝 Image 部件上的内容和窗体上的图形可以直接拷贝到剪贴板。图像拷贝利用 Clipboard 的 Assign 方法。 例如: Clipboard.Assign(Image1.Picture); 把 Image1 上的图像拷贝到剪贴板。 7.1.3.2 剪切 图像的剪切是首先把图像拷贝到剪贴板,而后在原位置用空白图像进行覆盖。 下面一段程序表示了图像的剪切。 procedure TForm1.Cut1Click(Sender: TObject); var ARect: TRect; begin Clipboard.Assign(Image1.Picture); with Image.Canvas do begin CopyMode := cmWhiteness; ARect := Rect(0, 0, Image.Width, Image.Height); CopyRect(ARect, Image.Canvas, ARect); CopyMode := cmSrcCopy; end; end; 7.1.3.3 粘贴 从剪贴板上粘贴图像,首先检测剪贴板上的数据格式。如果格式为 CF_BITMAP ,则调用目标位图的 Assign 方法粘贴图像。 程序清单如下。 procedure TForm1.PasteButtonClick(Sender: TObject); var Bitmap: TBitmap; begin if Clipboard.HasFormat(CF_BITMAP) then begin Bitmap := TBitmap.Create; try Bitmap.Assign(Clipboard); Image.Canvas.Draw(0, 0, Bitmap); finally Bitmap.Free; end; end; end; try...finally 为资源保护块,参第十二章。 7.1.4 建立自己的剪贴板观察程序 在这一节中我们要建立一个自己的剪贴板观察程序,用来保存截获到剪贴板中的位图。 Windows 允许用户建立自己的剪贴板观察程序,并把该程序添加到一个剪贴板观察器链中。在链中,位置靠前的程序有义务把有关剪贴板的消息传递到紧随其后的观察程序。而处于链首的程序由 Windows 的消息循环机制直接把剪贴板消息发送过来。 建立一个剪贴板观察程序,首先该程序必须能响应相应的 Windows 消息。对于那些熟悉 Microsoft 公司 Visual Basic 的读者来说,这是令他们头疼而束手无策的地方。但 Delphi 在这方面却有良好的表现:利用关键字 message ,用户可以将一个过程定义为响应特定的 Windows 消息。如: procedure WMDrawClipboard(var Msg:TWMDrawClipboard); message WM_DRAWCLIPBOARD; 可以响应 WM_DRAWCLIPBOARD 消息。类 TWMDrawClipboard 是消息类 Message 的子类。 Delphi 把所有的消息都重新进行了定义,使用户在使用时可以直接引用其便于记忆的数据成员,而不必再自己动手去分解消息。虽然这并不能算作是一个重大的改进,但却体现了 Delphi 处处为用户方便着想的特点。 我们将要建立的程序目的是把截获到剪贴板上的位图保存下来。在本书的写作过程中,这一工作是大量存在的。虽然利用 Windows 工具 PaintBrush( 画笔),通过粘贴、保存等操作可以实现这一功能,但却存在以下一些问题: 1. 程序频繁切换影响效率,当有大量位图存在时更是如此; 2. 画笔有一个很讨厌的缺陷:当剪贴板上的位图比画笔界面的客户区大时,客户区外的位图被截断。因而往往需要根据所截获位图的大小来调整画笔客户区的大小,并重新进行粘贴。而如果开始就把画笔客户区调整到足够大,又会覆盖掉屏幕上一些有用的信息。 为解决这些问题,我开发了下面的程序。程序启动时,以极小化方式运行。此时只要剪贴板中存入位图,则自动弹出一个对话框请求用户保存。如果用户希望查看确认,则可以双击运行程序图标,选择相应按钮,剪贴板中的位图就会显示在屏幕上。 部件关键属性设计如下: ClipSaveForm : Caption =‘ Save Bitmap in Clipboard ' Panel1: Align = ' Top ' Image1: Align = ' Client ' SaveDialog1: FileEditStyle = fsEdit FileName = '*.bmp' Filter = 'Bitmap Files(*.bmp)|*.bmp|Any Files(*.*)|*.*' InitialDir = 'c:\bmp' Title = 'Save Bitmap' 程序主窗口是 TForm 派生类 TClipSaveForm 的实例。 TClipSaveForm 通过定义一些私有数据成员和过程,使响应和处理 Windows 的相应消息成为可能。下面是 TClipSaveForm 的类定义: type TClipSaveForm = class(TForm) SaveDialog1: TSaveDialog; Image1: TImage; Panel1: TPanel; Button1: TButton; SpeedButton1: TSpeedButton; SpeedButton2: TSpeedButton; Button2: TButton; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure SpeedButton1Click(Sender: TObject); procedure SpeedButton2Click(Sender: TObject); private { Private declarations } MyBitmap: TBitmap; { 保存截获的位图 } View: Boolean; { 判断是否显示 } NextViewerHandle: HWND; { 下一剪贴板观察器的句柄 } procedure WMDrawClipboard(var Msg:TWMDrawClipboard); message WM_DRAWCLIPBOARD; procedure WMChangeCBChain(var Msg:TWMChangeCBChain); message WM_CHANGECBCHAIN; { 响应 Windows 的剪贴板消息 } public { Public declarations } end; 窗口创建时,把该窗口登录为剪贴板观察器,添加到剪贴板观察器链中,同时进行变量、部件和剪贴板的初始化。 procedure TClipSaveForm.FormCreate(Sender: TObject); begin View := False; SpeedButton2.Down := True; MyBitmap := TBitmap.create; try MyBitmap.Width := 0; MyBitmap.Height := 0 ; except Application.terminate; end; Clipboard.Clear; NextViewerHandle := SetClipboardViewer(Handle); end; 窗口关闭时,退出剪贴板观察器链,并释放内存: procedure TClipSaveForm.FormDestroy(Sender: TObject); begin ChangeClipboardChain(Handle,NextViewerHandle); MyBitmap.Free; end; 在以上两段程序中用到的两个 Windows API 函数 SetClipboardViewer 和 ChangeClipboardChain 分别用于登录和退出剪贴板观察器链。 程序保存位图的功能是在消息响应过程WMDrawClipboard中实现的。该过程在剪贴板内容有变化时被调用。 procedure TClipSaveForm.WMDrawClipboard(var Msg: TWMDrawClipboard); var FileName: String; begin If NextViewerHandle <> 0 then SendMessage(NextViewerHandle,msg.Msg,0,0); If ClipBoard.HasFormat(CF_BITMAP) then begin MyBitmap.Assign(Clipboard); If SaveDialog1.Execute then begin FileName := SaveDialog1.FileName; MyBitmap.SaveToFile(FileName); end; If View then begin WindowState := wsNormal; Image1.Picture.Bitmap := MyBitmap; end; end; Msg.Result := 0; end; 程序首先判断在剪贴板观察器链中是否还存在下一个观察器。如果有,则把消息传递下去,这是剪贴板观察器程序的义务。而后判断剪贴板上内容的格式是否为位图。如是,则首先把剪贴板上内容保存到数据成员 MyBitmap 中,并激活一个文件保存对话框把位图保存到文件中。如果 View=True ,则把窗口状态 (WindowState) 设置为 wsNormal ,并把 MyBitmap 赋给 Image 部件的相应值,使用户可以对剪贴板上的位图进行观察。 消息响应过程 WMChangeCBChain 在剪贴板观察器链上其它观察器退出时被调用。根据被移出观察器的不同位置决定了不同的处理方法。 procedure TClipSaveForm.WMChangeCBChain(var Msg: TWMChangeCBChain); begin if Msg.Remove = NextViewerHandle then NextViewerHandle := Msg.Next else if NextViewerHandle <> 0 then SendMessage(NextViewerHandle,Msg.Msg,Msg.Remove,Msg.Next); Msg.Result := 0; end; 窗口上有两个加速按钮,两个按钮。它们击键 (click) 事件处理过程如下。每一程序段的意义是非常显然的。 procedure TClipSaveForm.Button1Click(Sender: TObject); begin Close; end; procedure TClipSaveForm.Button2Click(Sender: TObject); begin WindowState := wsMinimized; end; procedure TClipSaveForm.SpeedButton1Click(Sender: TObject); begin View := True; Image1.Picture.Bitmap := MyBitmap; end; procedure TClipSaveForm.SpeedButton2Click(Sender: TObject); begin View := False; Image1.Picture.Bitmap := nil; end; 通过对这个程序的介绍,以下几点是应该注意的: 1. 提供了一种自己截获和处理剪贴板上内容的方法。读者可以根据需要进一步扩充; 2. 提供了响应 Windows 消息的方法。在第三篇有关自定义部件开发的内容中,这一问题还要详细论述; 3. 最后的一点启示是:在 Delphi 程序开发中巧妙应用传统的 Windows 方法 ( 如消息处理、 API 函数等 ) 仍是很有必要的。而在应用这些方法中所体现的方便之处,正是 Delphi 胜过其它可视化开发工具的一个重要方面。 7.2 Windows 的 DDE 原理和 Dephi 的 DDE 实现机制 7.2.1 Windows 的 DDE 原理 Windows 的 DDE 机制基于 Windows 的消息机制。两个 Windows 应用程序通过相互之间传递 DDE 消息进行 DDE 会话 (Conversation) ,从而完成数据的请求、应答、传输。这两个应用程序分别称为服务器 (Server) 和客户 (Client) 。服务器是数据的提供者,客户是数据的请求和接受者。 DDE 会话由客户程序启动。客户程序把一条消息 (WM_DDE_INITIATE) 传播给当前运行的所有 Windows 程序。这条消息指明了客户程序所需要的一般数据 ( 应用程序、主题 ) 。拥有这些数据的 DDE 服务器可以响应这条被传播的消息。此时, DDE 会话就开始了。 由于在每个主题中, DDE 服务器可以支持一个或多个数据项,所以在客户请求数据时应同时指明应用程序名、主题名和项目名。应用程序、主题、项目是 DDE 中三个最基本的概念。 利用 Windows 本身提供的 DDE 消息和 API 进行 DDE 编程是一件相当棘手的问题。 虽然使用 DDE 管理库 (ddeml.dll) 可以一定程度上减轻开发者的工作负担,但开发 DDE 程序仍不是一件轻松的事情。 此时 Delphi 出现了! Delphi 通过其自身巧妙的设计使开发一个 DDE 应用程序同开发一个普通程序一样地快捷、方便。 7.2.2 Delphi 的 DDE 实现机制简介 Delphi 把所有的 DDE 功能做到四个部件中,它们是 : ● TDDEClientConv : 用于客户程序建立和维护一个 DDE 会话 ● TDDEClientItem : 用于客户程序建立和维护数据交换通道 ● TDDEServerConv : 用于服务器程序响应 DDE 会话 ● TDDEServerItem : 用于服务器程序维护数据交换通道 前两个部件用于生成一个 DDE 客户程序,后两个部件用于生成一个 DDE 服务器程序。如果一个应用程序同时拥有这些部件,则这一程序既可以充当 DDE 客户,也可以充当 DDE 服务器。 会话部件 TDDEClientConv 、 TDDEServerConv 用于建立和维护一个 DDE 会话。 DDE 会话包括 DDE 服务和 DDE 主题两部分。 DDE 服务是 DDE 服务器的名称,即在一般的 Windows DDE 机制中所讲的应用程序名。一般说来这一名称是 DDE 服务器应用程序执行文件名去掉 .EXE 后缀。比如你的应用程序要和 Word 6.0 建立会话,则 DDE 服务为 WINWORD 。但也不尽然。比如你的应用程序要和 Borland ReportSmith ( RPTSMITH.EXE ) 建立会话,则 DDE 服务为 Report Smith 。 DDE 服务到底如何,读者可参看相关的 DDE 服务器应用程序文档。 DDE 主题是一个包含了联接信息的数据单元。一般说来 DDE 主题是一个包括扩展名的完整文件名。例如和 Excel 中的一个文件建立 DDE 会话,则主题可能是 Topic = 'c:\excel\Example\sale.xls' 如果服务器是一个 Delphi 应用程序,缺省情况下主题是包含欲联接数据窗体的标题。如果服务器使用了 DDEServerConv 部件,则要求使用部件 DDEServerConv 的名称作为 DDE 主题。 项目部件 TDDEclientItem 、 TDDEServerItem 用于建立和维护 DDE 数据的传输通道。 DDE 项目中包含着实际欲传输的数据。 DDE 项目的格式取决于 DDE 服务器应用程序。一个可能的 DDE 项目例子是电子表格中的单元和数据库表中的域。如果服务器是 Delphi 应用程序,则项目是连接的 DDEServerItem 部件的名称。 Delphi 的 DDE 实现机制方便、实用,但也有一个令人遗憾的缺陷:只能传输文本数据以及命令、宏,而不能传输图像数据。在这一点上微软公司推出的 Visual Basic 要略胜一筹。不过在目前文本数据的使用仍是最广泛的,而且图像传输可以利用剪贴板和 OLE 来实现,则这一缺陷也并无很大的影响 7.3 DDE 客户程序的实现 DDE 客户程序启动 DDE 会话,向服务器请求并从服务器接收数据。同时还可以向服务器发送数据、命令、宏,改变服务器的状态并控制服务器的运行。 7.3.1 联接模式 (ConnectMode) Delphi 的 DDE 提供了两种联接模式:自动和人工。这可以通过 DDEClinetConv 部件的 ConnectMode 属性进行设置。如下表所示。 表 7.5 DDE 的联接模式 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 值 意 义 ─────────────────────────────── ddeAutomatic 在运行中当包含 TDDEClientConv 部件的窗口创建时 联接自动建立 ddeManual 只有当调用 OpenLink 方法时联接才建立 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 不同联接模式, DDE 客户程序的实现方式不同。 对于自动模式: 1. 向窗体中加入 DDEClientConv 和 DDEClientItem 部件并命名; 2. 把 DDEClientItem 部件的 DdeConv 属性设置为 DDEClientConv 部件的名称; 如果在设计时建立,则通过对象观察器进行选择;如果在运行时建立联系, 则通过如下的一条语句设置属性的值: DDEClientItem1.DdeConv := 'DDEClientConv1' ; 3. 和服务器建立联系,实现数据共享。 对于人工模式: 1. 向窗体中加入 DDEClientConv 部件; 2. 和服务器建立联系; 3. 数据更新时调用 RequestData 方法申请并获得数据。 7.3.2 和 DDE 服务器建立联系 和 DDE 服务器建立联系,既可以在设计时进行,也可以在运行时进行。 在设计时, DDE 联接可以通过剪贴板进行粘贴。具体步骤如下: 1. 激活服务器程序,并选中你的客户程序欲联接的数据; 2. 把数据和 DDE 联接信息拷贝到剪贴板上。一般说来这只需要选择服务器应用程序的 Edit|Copy 菜单; 3. 在 Delphi IDE 的设计窗体中选中 DDEClientConv 部件; 4. 在 Object Inspector( 对象观察器 ) 中单击 DDEService 属性或 DDETopic 属性,然后再单击 Ellipsis 按钮,打开 DDE Info 对话框; 5. 选择 Paste Link 按钮。此时 App 编辑框和 Topic 编辑框被自动填充。如果 Paste Link 按钮变灰,说明你准备用作服务器的应用程序不支持 DDE 或者 DDE 信息没有被成功地拷贝到剪贴板上; 6. 选择 OK 按钮。此时 Object Inspector 中的 DDEService 、 DDETopic 属性包含了建立一个 DDE 联接的正确值。 对于人工模式以下步骤是不需要的。 7. 选中 DDEClientItem 部件,并在 Object Inspector 中设置 DdeConv 属性为已完成联接的 DDEClientConv 部件名称; 8. 假如剪贴板上的 DDE 联接信息仍保留的话,从 Object Inspector 的下拉列表框中选择 DDEItem 属性的值。否则输入正确的值。 在运行时,调用 SetLink 方法来建立 DDE 联接。 SetLink 有两个 String 类型的参数,分别用来接受 DDEService 和 DDETopic 的值。过程执行后 DDEClientConv 部件的 DDEService 和 DDeTopic 属性被设置。要注意的是:在运行时直接设置 DDEService 和 DDETopic 的值并不能建立一个 DDE 联接,而必须调用 SetLink 方法进行初始化。 比如,下面的语句和 Excel 的 System 主题建立联接: DDEClietnConv. SetLink('Excel','System') ; 调用 SetLink 方法后,还需要设置 DDEClientItem 部件的 DDEItem 属性。 比如,下面的语句联接 Excel 的 Topics 项目,用以获取当前活跃文件的文件名: DDEClietnItem.DDEItem := 'Topics'; 当 DDE 联接建立后,联接的数据保存在 DDEClientItem 部件的 Text 和 Lines 属性中, Text 用于保存一个字符串 (String) , Lines 用于保存一个字符串链表 (TStrings) 对象。 为了显示联接数据,可以在 DDEClientItem 的 OnChange 事件中把数值赋给一个可视部件。 下面的事件过程把联接数据实时地显示在一个编辑框中。 procedure Form1.DDEClientItemChange(Sender: Tobject); begin Edit1.Text := DDEClientItem1.Text; end; 运行状态下也可以从剪贴板上粘贴 DDE 联接信息,并调用 SetLink 建立 DDE 会话。下面的例子显示了当用户按下应用程序中的 Paste Link 按钮时,动态建立 DDE 会话的过程。 procedure Form1.OnPasteLink(Sender: Tobject) ; var Service, Topic, Item: String; begin if GetPasteLinkInfo (Service, Topic, Item) then begin AppName.Text := Service; TopicName.Text := Topic; ItemName.Text := Item; DDEClient.SetLink (Service, Topic); DDEClientItem.DdeConv := DDEClient; DDEClientItem.DDEItem := ItemName.Text; end; end; GetPasteLinkInfo 是 DDEMan 库单元中定义的一个过程。如果返回 True ,则 DDE 联接信息保存在三个参数中;如果返回 False ,说明剪贴板上没有正确格式的 DDE 联接信息。 7.3.3 数据申请 虽然自动模式快捷、方便,但仍有一些理由使用 DDE 的人工模式: 1. 服务器程序可能不支持自动数据传输,客户必须显式申请服务器更新一个特定的项目; 2. 节省通信费用。假如没有实时传输的要求,则人工模式可以大幅度降低通信的开销; 3. 若客户程序只用于控制服务器的运行,则往往没有必要使用自动模式。 人工模式下客户程序的数据更新需要采用数据申请的方式。数据申请需要调用 DDEClientConv 部件的 RequestData 方法。 RequestData 有一个参数,指向要申请的 DDE 项目。 RequestData 返回一个 Pchar 类型的无结束符字符串,包含了申请到的文本。返回字符串占用的内存必须在程序终止前显式释放。 在人工模式下,即使存在一个 DDEClientItem 部件且与 DDEClientConv 相联接,数据更新后 DDEClientItem 部件的 Text 、 Lines 属性的值也不会改变。 7.3.4 数据发送 数据发送与一般的 DDE 数据流向正好相反,是把数据从 DDE 客户应用程序发送到 DDE 服务器应用程序。 数据发送使用 DDEClientConv 部件的两个方法 PokeData 和 PokeDataLines , 它们的语法是: function PokeData (Item: String ; Data: PChar): Boolean; function PokeDataLines (Item: String ; Data: TStrings): Boolean; 参数 Item 是 DDE 服务器中被联接的项目, Data 是要发送的数据。如果数据是一个字符串,则把它转化为 PChar 类型并调用 PokeData 方法;如果数据是一个字符串链表对象,可调用 PokeDataLines 方法。 方法的返回值标志数据传送是否成功。因为有一些 DDE 服务器应用程序并不接收发送的数据。 下面的语句把编辑框中的内容发送给服务器: StrPCopy(TheText , Edit1.text); DDEClientConv1.PokeData(DDEClientItem1.DDEItem , TheText); 过程 StrPCopy 把一个 Pascal 类型的字符串拷贝到一个无结束符的 PChar 类型字符串中。 |