DELPHI程序设计讲座(七)
DELPHI对DDE的支持及其应用
董占山
(中国农科院棉花所,河南安阳,455112)
本讲主要讲解DELPHI提供的4个DDE组件、与Windows程序管理器通信的方法、如何用DELPHI提供的DDE组件创建DDE客户和服务器。
1 DDE概述
Windows是一个多任务操作系统,可以同时运行多个应用程序,而且应用程序之间可以相互通信。为了实现Windows应用程序之间的相互通信,Microsoft为Windows应用程序制定了各种协议,如动态数据交换(Dynamic Data Exchange,DDE)和对象的链接和嵌入(Object Linking & Embedding,OLE)等。本讲重点介绍DDE,下一讲介绍OLE。
事实上,DDE是Windows中最基本的进程间通讯的协议,它在应用程序之间架起一个发送或接收数据的桥梁,使用DDE协议,不仅可以在应用程序之间交换信息,而且也可以通过宏命令控制其他应用程序。
通过DDE协议连接起来的两个应用程序,其中发送信息的应用程序称为服务器(Server),接收信息的应用程序称为客户(Client);不仅如此,客户也可以通过DDE反过来向服务器发送信息和宏命令,以达到操纵DDE服务器的目的。
2 DELPHI的DDE组件
DELPHI在System组件页上提供了4个与开发DDE应用程序有关的组件,在上一讲已经概要地讲解了,这一讲将详细讲解如何使用它们来创建一个完整的DDE应用程序。表1~表4列出了这4个组件的关键成员和事件。
表1 DDEServerConv组件的关键成员和事件
|
成员或事件名称
|
说明
|
|
OnClose事件
|
一次DDE会话结束时产生该事件
|
|
OnExecuteMacro事件
|
当DDE客户发送宏命令给DDE服务器时发生该事件,因此OnExecuteMacro中应当有处理相应宏的程序代码。
|
|
OnOpen事件
|
一次DDE会话开始时激发该事件
|
表2 DDEServerItem组件的关键成员和事件
|
成员或事件名称
|
说明
|
|
ServerConv属性
|
将DDE服务器会话组件与DDE服务器项目组件联系起来,其值为DDE服务器会话组件的Name属性值
|
|
Lines、Text属性
|
其中包含与DDE客户交换的实际数据,Text存储小于255个字节的字符串,当文本数据大于255个字节时,将存储在Lines中
|
|
CopyToClipBoard方法
|
将属性Text(或Lines)中的文本和DDE连接信息复制到Windows剪贴板,以激活一个DDE客户程序
|
|
OnChange事件
|
当属性Text的内容改变时产生此事件。
|
|
OnPokeData事件
|
当DDE服务器收到DDE客户发来的数据时产生此事件
|
表3 DDEClientConv组件的关键成员和事件
|
成员或事件名称
|
说明
|
|
ConnectMode属性
|
有两个取值:ddeAutomatic和ddeManual,前者的DDE连接是自动完成的;后者的连接是在程序调用OpenLink方法时完成的
|
|
|
DDEService属性
|
赋予DDE服务器程序的文件名,不包含扩展名
|
|
|
DDETopic属性
|
赋予DDE连接的话题,一般为所连接DDE服务器的窗口标题或DDEServerConv组件的Name属性值
|
|
|
FormatChars属性
|
若取FALSE,则来自DDE服务器的所有数据均会在DDE客户中显示出来;若取TRUE,则ASCII字符#8(退格)、#9(TAB符)、#10(换行)、#13(回车)均被过滤掉。
|
|
|
OnClose事件
|
一次DDE会话结束时发生该事件
|
|
|
OnOpen事件
|
一次DDE会话开始时发生该事件
|
|
|
CloseLink方法
|
终止正在进行的DDE会话
|
|
|
ExecuteMacro方法
|
将一个宏命令发送给DDE服务器
|
|
|
ExecuteMacroLines方法
|
将宏命令列表发送给DDE服务器
|
|
|
OnpenLink方法
|
创建一次DDE会话
|
|
|
PokeData方法
|
向DDE服务器发送数据(Text属性中的数据)
|
|
|
PokeDataLines方法
|
向DDE服务器发送数据(Lines属性中的数据)
|
|
|
RequestData方法
|
向DDE服务器请求数据
|
|
|
SetLink方法
|
设置一次DDE会话的服务器和话题
|
|
表4 DDEClientItem组件的关键成员和事件
|
成员或事件名称
|
说明
|
|
DDEConv属性
|
将DDE客户会话组件和DDE客户项目组件联系起来
|
|
|
DDEItem属性
|
赋予DDE会话项目,其值依赖于所连接的DDE服务器
|
|
|
Lines属性
|
存储来自DDE服务器的大于255个字节的数据
|
|
|
Text属性
|
存储来自DDE服务器的小于255个字节的字符串
|
|
|
OnChange事件
|
当属性Text的内容改变时激发
|
|
3 与Windows程序管理器通讯
Windows的程序管理器是一个典型的DDE服务器,它提供了多个宏命令,以便其他应用程序通过DDE直接操纵程序管理器,来创建或删除程序组或程序项。
3.1 Windows程序管理器对DDE的支持
安装过Windows应用程序的读者都知道:当安装程序(典型的安装程序有SETUP.EXE或INSTALL.EXE)在完成安装之前,都要调用程序管理器,创建一个程序组和若干个程序项,以便用户可以从程序管理器中启动该应用程序。这些安装程序就是通过DDE向程序管理器发送了有关创建程序组和程序项的宏命令。表5列出了程序管理器支持的8个宏命令的名称和用法。
表5 Windows程序管理器的DDE宏命令
|
宏命令
|
参数
|
功能
|
|
ShowGroup
|
GroupName,Mode
|
将GroupName指定的程序组进行放大、缩小或恢复,Mode指定了操作类型,可取1至8之间的任一整数
|
|
CreateGroup
|
GroupName[,GroupPath]
|
创建一个新的程序组或者激活一个已存在的程序组。GroupName为程序组名字,GroupPath为组文件的路径名
|
|
DeleteGroup
|
GroupName[,GroupPath]
|
删除指定的程序组,参数意义同上
|
|
Reload
|
GroupName
|
重新加载指定的程序组,参数意义同上
|
|
AddItem
|
CmdLine[,
ItemName, IconSourceFile, IconIndex, xPos, yPos, WorkDir, Hotkey]
|
在当前程序组内添加一个新的程序项。CmdLine为执行程序所需要的完整命令行,ItemName为程序项图标下显示的字符串,IconSourceFile为程序项的完整图标文件名,IconIndex为程序项图标在图标文件中的索引,xPos和yPos为程序项图标在组窗口中的水平和垂直位置,WorkDir为工作目录,Hotkey为快捷键
|
|
DeleteItem
|
ItemName
|
删除一个程序项,参数意义同上
|
|
ReplaceItem
|
ItemName
|
替换一个程序项,参数意义同上
|
|
ExitProgram
|
无
|
退出程序管理器
|
3.2 创建一个操纵程序管理器的DDE演示程序
在上面讲解的基础上,现在动手创建一个可以操纵程序管理器的DDE客户程序。单击“File/New Application”菜单命令创建一个新项目,按图1所示向主窗体内添加4个Button组件和一个DDEClientConv组件。主窗体和4个按钮,除了将标题(Caption)属性改为图示中的汉字以外,均使用创建时的缺省属性;将DDEClientConv组件的DDEService属性设置为“Progman”,其余属性也使用缺省值。
|

图1 操纵程序管理器程序的窗体框架
|
下面编写几个按钮的OnClick事件处理程序和其他相关的事件处理程序。
为了在降低代码的冗余度,在TForm1类(缺省的主窗体类)的Private部分添加如下声明:
Macro : string;
Cmd : array[0..255] of char;
procedure ExecMacro;
在单元的实现部分,创建私有过程方法ExecMacro的代码如下:
procedure TForm1.ExecMacro;
begin
StrPCopy(Cmd,Macro);
if not
DDEClientConv1.ExecuteMacro(Cmd,False) then
MessageDlg('Unable to execute this operation.',mtInformation,[mbOk],0);
end;
在这段代码中,调用了DDEClientConv的ExecuteMacro方法,向程序管理器发送宏命令字符串。这是创建该演示程序的关键所在。
用鼠标双击4个按钮,分别完成其OnClick事件处理程序如下:
procedure TForm1.Button1Click(Sender: TObject);
begin
Macro :=
'[ShowGroup("附件",1)]'+#13#10;
ExecMacro;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Macro :=
'[CreateGroup("My Group","My Group 1.GRP")]'+#13#10;
ExecMacro;
Button3.Enabled := true;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
Macro :=
'[AddItem("c:\win95\command\edit.com",'+
'"My Item
1","c:\win95\progman.exe","2","1","1","c:\","")]'+#13#10;
ExecMacro;
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
DDEClientConv1.CloseLink;
Close;
end;
在上面的4个按钮的事件处理程序中,前三个按钮都是向程序管理器发送宏命令的,第四个按钮是用来关闭DDE连接和应用程序的。另外还需要为窗体的OnCreate事件编写一段代码,使创建窗体的同时打开一次DDE会话,另外使在新程序组未创建之前,不能使用Button3(创建一个新程序项),代码如下:
procedure TForm1.FormCreate(Sender: TObject);
begin
DDEClientConv1.OpenLink;
Button3.Enabled := False;
end;
如果你正确地完成了上述步骤,这时就可以按<F9>键或者单击工具栏上的运行按钮
,待程序编译运行后,分别单击4个按钮,可以在Windows 95的桌面上观察到程序执行的结果。
4 创建一个DDE服务器
|

图2 DDEsvr的主窗体
|
欲使一个DELPHI程序具备DDE服务器功能,需要在窗体内加入DDEServerConv和DDEServerItem组件。下面给出一个最简单的DDE服务器框架,供读者参考。
单击File/New
Application菜单项,开始一个新项目,按图2所示向窗体内加入Memo、Button、Label、DDEServerConv、DDEServerItem组件各一个,按表6设置窗体和各个组件的创建属性。以DDESvr为项目名和DDEServerMain为单元名保存项目到工作目录下。
表6 DDESvr有关组件的创建属性
|
组件名
|
属性名
|
取值
|
|
Form
|
BorderIcons
|
[biSystemMenu,biMinimize]
|
|
|
BorderStyle
|
bsSingle
|
|
|
Caption
|
DDE服务器
|
|
|
Name
|
frmDDEServer
|
|
|
Position
|
poDefaultPosOnly
|
|
Memo
|
Name
|
DDEMemo
|
|
Button
|
Caption
|
复制
|
|
|
Name
|
btnCopy
|
|
Label
|
Caption
|
Press [复制] button to copy the DDE information to
clipboard.
|
|
|
Name
|
lblNotification
|
|
DDEServerConv
|
Name
|
DdeServerConv1
|
|
DDEServerItem
|
Name
|
DdeServerItem1
|
|
|
ServerConv
|
DdeServerConv1
|
作为DDE服务器,在进行连接之前,需要将有关的DDE信息(如服务器名、会话的话题、会话的项目)复制到系统剪贴板,以便激活DDE客户。本程序使用“复制”按钮(当然也可以使用菜单命令项)来完成此功能,其OnClick事件处理程序如下:
procedure TfrmDDEServer.btnCopyClick(Sender: TObject);
begin
DDEServerItem1.CopyToClipboard;
lblNotification.Caption := '';
end;
在该事件处理程序中调用了DDEServerItem的关键方法之一CopyToClipBoard,来完成DDE服务器信息的复制工作。为了在DDE连接建立之后,能够动态地看到服务器向客户发送数据,本程序使用一个Memo组件编辑数据,并实时地发送给DDE客户,其OnChange事件处理程序如下:
procedure TfrmDDEServer.DDEMemoChange(Sender: TObject);
begin
if not
InPoking then begin
DDEServerItem1.Lines := DDEMemo.Lines;
lblNotification.Caption := 'Editing...';
end;
end;
在该事件处理程序中使用了一个InPoking的变量,它是类的私有数据成员,声明如下:
InPoking : Boolean;
其作用是防止在DDE服务器接收客户发来的数据时,循环改变DDE服务器醒目(DDEServerItem1)的Lines属性。上面的代码可以完成数据从DDE服务器到DDE客户的传送工作,下面的代码用来完成数据从DDE客户到DDE服务器的传送工作。
要完成数据从DDE客户到DDE服务器的传送,需要为DDEServerConv组件的OnPokeData和OnExecuteMacro事件编写处理程序,本例中的事件处理程序如下:
procedure TfrmDDEServer.DdeServerItem1PokeData(Sender:
TObject);
begin
InPoking :=
True;
DDEMemo.Lines
:= DDEServerItem1.Lines;
InPoking :=
False;
lblNotification.Caption := 'Receive text from the DDE client.';
end;
procedure TfrmDDEServer.DdeServerConv1ExecuteMacro(Sender:
TObject;
Msg:
TStrings);
var
TempText :
string;
begin
TempText :=
'';
if Msg.Count
> 0 then TempText := Msg.Strings[0];
MessageDlg('Executing Macro -'+TempText,mtInformation,[mbOk],0);
end;
至此,DDE服务器的基本框架已经完成,它具备与DDE客户双向交流数据的基本功能。
5 创建一个DDE客户
|

图3
DDEClnt的主窗体
|
与创建DDE服务器相仿,欲使DELPHI程序具有DDE客户的功能,需要向窗体内添加DDEClientConv和DDEClientItem两个组件。
创建一个新项目,命名其项目名为DDEClnt、单元名为ClntMain,保存项目。按图3所示向主窗体内添加Memo和Button组件各两个,MainMenu、Bevel、DDEClientConv和DDEClientItem组件各1个,它们的创建属性见表7。对MainMenu组件,使用菜单设计器设计一个“编辑”菜单项,在该菜单中添加一个“粘贴链接”菜单条目。
表7 DDEClnt关键组件的主要创建属性
|
组件名
|
属性名
|
取值
|
|
Form
|
BorderIcons
|
[biSystemMenu,biMinimize]
|
|
|
BorderStyle
|
bsSingle
|
|
|
Caption
|
DDE客户
|
|
|
Name
|
frmDDEClient
|
|
|
Position
|
poDefaultPosOnly
|
|
Memo
|
Name
|
ReceivingMemo
|
|
Memo
|
Name
|
SendingMemo
|
|
Button
|
Caption
|
发送数据
|
|
|
Name
|
btnPoking
|
|
Button
|
Caption
|
发送宏命令
|
|
|
Name
|
|