第七章 剪贴板和动态数据交换二.docx
《第七章 剪贴板和动态数据交换二.docx》由会员分享,可在线阅读,更多相关《第七章 剪贴板和动态数据交换二.docx(18页珍藏版)》请在冰点文库上搜索。
第七章剪贴板和动态数据交换二
第七章 剪贴板和动态数据交换
(二)
7.3.5控制服务器应用程序的执行
客户程序控制服务器应用程序的一个方面是:
必要的时候客户程序可以启动服务器程序,并装载会话主题。
而客户程序控制服务器应用程序更重要的一点是向服务器发送服务器承认的宏命令,来完成对服务器应用程序的各种操作。
服务器到底支持哪些宏命令,可参阅服务器应用程序文档。
发送宏命令要使用DDEClientConv的两个方法ExecuteMacro和ExecuteMacroLines,它们的语法如下:
functionExecuteMacro(Cmd:
PChar;WaitFlag:
Boolean):
Boolean;
functionExecuteMacroLines(Cmd:
TStrings;WaitFlag:
Boolean):
Boolean;
Cmd是欲发送的宏命令字符串或宏命令字符串链表。
WaitFlag决定了在DDE服务器程序执行宏命令时客户程序的行为。
如果WaitFlag设置为True,则在服务器宏命令执行完毕前,不允许对ExecuteMacro、ExecuteMacroLines、PokeData、PokeDataLines这些方法的成功调用,它们都不向服务器发送数据并返回False。
如果WaitFlag设置为False,则调用的方法在第一个宏执行完毕前即试图向服务器发送数据。
WaitFalg的设置也取决于服务器应用程序。
一些应用程序当在第一个宏执行完之前就试图向它发送数据或命令时,可能导致第一个宏执行失败或导致不可预料的后果。
具体情况可查阅服务器应用程序文档。
函数返回值表示命令串是否被成功传输。
而宏命令执行是否成功客户是无法检测到的。
7.3.6格式化文本
DDEClientConv有一个布尔属性FormartChars,用于决定是否格式化文本。
所谓格式化文本是指从传输来的文本数据中过滤掉BackSpace(8)、Tab(7)、Linefeed(10)、Return(13)等字符。
括号内是字符的ASCII码。
许多时候这些字符将导致DDE客户数据显示的混乱。
FormatChars的缺省值是False。
7.3.7响应DDE事件
部件DDEClientConv有两个事件OnOpen和OnClose,分别在DDE会话建立和中止时触发。
部件DDEClientItem有一个OnChange事件。
这一事件常用于DDE项目数据的转储和显示,如(7.3.1)节所示。
在自动模式下,OnOpen事件在包含DDEClientConv部件的窗口创建时触发,或在调用SetLink方法时触发,OnClose事件在客户程序或服务器程序关闭时触发。
在人工模式下,OnOpen事件在调用OpenLink方法时触发,OnClose事件在调用ColseLink方法时触发。
7.3.8利用客户程序和Excel交换数据
下面我们建立一个DDE客户程序,并利用这一程序与Excel中的一个工作表交换数据。
程序设计界面
界面中包含一个DDE会话部件DDEClientConv1和DDE项目部件DDEClientItem1,用于建立和维护DDE联接;一个RadioGroup控件和其中的两个无线电按钮AutoRadio、ManualRadio,用于设置联接模式;一个GroupBox控件和其中的两个按钮RequestBtn和PokeBtn,用于控制数据的申请和发送,其中RequestBtn在自动模式下变灰;一个文本框Memo1用于保存DDE数据;一个按钮PasteBtn用于粘贴联接信息并建立DDE联接;另外一个按钮CloseBtn用于关闭系统。
设计时把DDEClientConv1的FormatChars属性置为True,这样可以保留服务器传来数据的显示格式;ConnectMode保留ddeAutomatic的缺省设置。
程序在类TForm1中定义了一个私有数据成员Automatic,用于标志联接模式;三个字符串数据成员DDEService、DDETopic、DDEItem用于记录联接信息。
窗口生成时进行变量和部件状态的初始化。
procedureTForm1.FormCreate(Sender:
TObject);
begin
RequestBtn.Enabled:
=False;
AutoRadio.Checked:
=True;
Automatic:
=True;
end;
当联接模式改变时,程序进行相应的处理。
自动模式转换为人工模式:
procedureTForm1.ManualRadioClick(Sender:
TObject);
begin
ifAutomaticthen
begin
RequestBtn.Enabled:
=ManualRadio.Checked;
DDEClientConv1.ConnectMode:
=ddeManual;
Automatic:
=False;
end;
end;
人工模式转换为自动模式:
procedureTForm1.AutoRadioClick(Sender:
TObject);
begin
ifnotAutomaticthen
begin
RequestBtn.Enabled:
=ManualRadio.Checked;
If(DDEService='')or(DDETopic='')then
begin
MessageDlg('CannotSetLink.',mtWarning,[mbOK],0);
Exit;
end;
DDEClientConv1.SetLink(DDEService,DDETopic);
DDEClientItem1.DdeConv:
=DDEClientConv1;
DDEClientItem1.DDEItem:
=DDEItem;
DDEClientConv1.ConnectMode:
=ddeAutomatic;
Automatic:
=True;
end;
end;
当从自动模式转换到人工模式,只需要简单修改相应属性即可;而从人工模式转换到自动模式,则需要调用SetLink重新建立联接,否则往往会引发一个DDE异常。
联接的建立采用从剪贴板粘贴联接信息的方式,这是最具有灵活性的一种方法。
procedureTForm1.PasteBtnClick(Sender:
TObject);
begin
ifGetPasteLinkInfo(DDEService,DDETopic,DDEItem)then
begin
DDEClientConv1.SetLink(DDEService,DDETopic);
ifAutomaticthen
begin
DDEClientItem1.DdeConv:
=DDEClientConv1;
DDEClientItem1.DDEItem:
=DDEItem;
end;
end;
end;
GetPasteInfo是DDEMan库单元中定义的一个函数,用于检测剪贴板上是否有联接信息并返回相应的DDE服务、主题和项目。
对于人工模式,必须由客户显式向服务器申请数据。
在这种模式下DDE项目部件是多余的,接收到的DDE联接信息用一个字符串来记录。
下面是实现代码。
procedureTForm1.RequestBtnClick(Sender:
TObject);
var
TheData:
PChar;
begin
IfDDEItem=''then
begin
MessageDlg('CannotRequestData',mtWarning,[mbOK],0);
Exit;
end;
TheData:
=StrAlloc(79);
DDEClientConv1.OpenLink;
TheData:
=DDEClientConv1.RequestData(DDEItem);
DDEClientConv1.CloseLink;
ifTheData<>nilthen
Memo1.Text:
=StrPas(TheData);
StrDisPose(TheData);
end;
OpenLink、CloseLink方法用于打开和关闭联接。
RequestData方法向服务器申请数据并返回到一个PChar字符串中。
字符串必须显式分配内存并在退出时释放。
数据发送在不同联接模式下是不同的。
对于人工模式,增加了联接的打开和关闭操作。
程序清单如下。
procedureTForm1.PokeBtnClick(Sender:
TObject);
begin
IfDDEItem=''then
begin
MessageDlg('CannotPokeData.',mtWarning,[mbOK],0);
Exit;
end;
ifAutomaticthen
DDEClientConv1.PokeDataLines(DDEItem,Memo1.Lines)
else
begin
DDEClientConv1.OpenLink;
DDEClientConv1.PokeDataLines(DDEItem,Memo1.Lines);
DDEClientConv1.CloseLink;
end;
end;
打开MicrosoftOffice中的Excel,装入一个文件,把相关的单元选中,拷贝到剪贴板上。
而后运行程序,按下PasteLink按钮,DDE联接就建立起来,相关单元中的数据显示在Memo1中。
之后可以进行模式转换、数据申请、申请发送等一系列工作。
运行后的屏幕显示如下图所示。
7.3.9用客户程序控制程序管理器
下面的例子用客户程序向程序管理器发送命令,用于创建程序组、程序项以及删除程序组。
程序管理器提供了应用程序的DDE接口命令字符串,应用程序利用这些命令字符串可以实现以下的功能:
1.创建程序组
命令格式为:
CreateGroup(程序组名[,程序组所在的路径])
程序组不存在时进行创建;如程序组存在则按照指定的路径激活。
2.删除程序组
命令格式为:
DeleteGroup(程序组名)
3.显示程序组
命令格式为;
ShowGroup(程序组名,显示标志)
显示标志用于控制程序组在程序管理器中以极大、极小或正常方式显示。
4.重新装入程序组
命令格式为:
ReLoadGroup(程序组名)
该命令使程序管理器先删除而后再重新装入一个已有的程序组。
5.向程序组中添加程序项
命令格式为:
AddItem(命令行[,描述[,图标路径[,图标序号[,图标横坐标,图标纵坐标[,工作区目录[,热键[,是否最小化显示标志]]]]]]])
命令行控制程序项的执行,可包括路径、参数等。
其它参数分别对应在程序管理器中添加一个程序项时需要设置的参数和选项。
它们都有缺省设置,因而是可选的。
6.替换程序组中的程序项
命令格式为:
ReplaceItem(程序项名)
该命令删除一个程序项,并将所删除程序项的位置记录下来,以后通过AddItem在这个所记录的位置增加新项目。
7.从程序组中删除程序项
命令格式为:
DeleteItem(程序项名)
从当前活动程序组中删除一个程序项。
8.关闭程序管理器
命令格式为:
ExitProgram(是否保存程序组信息标志)
从应用程序向程序管理器发送命令字符串的方法是基本一致的。
为简便起见,在例程中只实现了其中仅包含一个字符串参数的情形,读者可以很容易作进一步的扩展。
程序设计界面如图所示,包含一个DDE客户会话(DDEClientConv)部件和四个完成不同功能的按钮。
DDEClientConv在设计时和程序管理器建立一个DDE会话,其中DDE服务器和DDE主题都为PROGMAN。
联接模式ConnectMode设置为ddeManual。
我们把只有一个字符串参数的命令发送情况抽象出来,形成下面的SendMacro函数。
functionTForm1.SendMacro(Name:
String;Command:
String):
Boolean;
var
Macro:
String;
Cmd:
array[0..255]ofChar;
begin
Result:
=True;
ifName<>''then
begin
Macro:
=Format('['+Command+'(%s)]',[Name])+#13#10;
StrPCopy(Cmd,Macro);
DDEClient.OpenLink;
ifnotDDEClient.ExecuteMacro(Cmd,False)then
Result:
=False;
DDEClient.CloseLink;
end;
end;
过程首先利用Format函数形成宏字符串:
Macro:
=Format('['+Command+'(%s)]',[Name])+#13#10;
而后把Pascal类型的字符串拷贝到一个程序管理器可接受的PChar类型字符串中。
DDE联接采用人工模式。
首先调用OpenLink方法。
而后调用ExecuteMacro方法发送命令,如失败则返回False。
最后用CloseLink关闭联接。
三个按钮CreateButton、AddButton、DeleteButton分别用于创建程序组、添加程序项、删除程序组。
它们的程序实现大同小异,如下所示。
创建程序组:
procedureTForm1.CreateButtonClick(Sender:
TObject);
var
Name:
String;
begin
Name:
=InputBox('InputBox','InputGroupName','');
ifName=''then
MessageDlg('Groupnamecannotbeblank.',mtError,[mbOK],0)
else
ifSendMacro(Name,'CreateGroup')=Falsethen
MessageDlg('Unabletocreategroup.',mtInformation,[mbOK],0);
end;
添加程序项:
procedureTForm1.AddButtonClick(Sender:
TObject);
var
Name:
String;
begin
Name:
=InputBox('InputBox','InputApplicationfull_Pathname','');
ifName=''then
MessageDlg('Applicationnamecannotbeblank.',mtError,[mbOK],0)
else
ifSendMacro(Name,'AddItem')=Falsethen
MessageDlg('UnabletoAddItem.',mtInformation,[mbOK],0);
end;
删除程序组:
procedureTForm1.DeleteButtonClick(Sender:
TObject);
var
Name:
String;
begin
Name:
=InputBox('InputBox','InputGroupNametobeDeleted','');
ifName=''then
MessageDlg('Groupnamecannotbeblank.',mtError,[mbOK],0)
else
ifSendMacro(Name,'DeleteGroup')=Falsethen
MessageDlg('Unabletocreategroup.',mtInformation,[mbOK],0);
end;
7.4DDE服务器程序的实现
DDE服务器程序响应DDE客户的请求,一般地它包含了客户程序希望获取的数据。
创建一个DDE服务器程序,必须要把一个DDEServerItem部件添加到窗体中。
DDEServerItem的text或Lines属性包含了要联接的数据。
一般地DDEServerItem部件又和另一个文本控件相联系。
当文本控件中的内容变化时则更新DDEServerItem的text或Lines属性的值。
下面的一段程序把DDEServerItem和一个列表框相联系。
这一联系是在列表框的OnChange事件中实现。
procedureForm1.OnListBoxChange(Sender:
TObject);
begin
DDEServerItem1.Lines:
=ListBox1.Items;
end;
创建DDE服务器程序时也可以再加入一个DDEServerConv部件,并把两个部件利用DDEServerItem的ServerConv属性联系起来。
此时DDE主题成为部件DDEServerConv的名称,而不是拥有DDEServerItem部件窗体的标题。
在下列情况下使用DDEServerConv部件成为必要:
1.拥有DDEServerItem部件窗体的标题可能在运行时改变或可能有其它窗体拥有同样的标题。
在这种情况下DDE联接可能无法建立;
2.DDE客户程序可能会向你的服务器程序发送一条宏命令。
在这种情况下只有拥有一个DDEServerConv部件才能响应OnMacroExecute事件并执行相应的动作。
7.4.1和DDE客户程序建立联接
一般说来,建立DDE联接是客户程序的任务。
但服务器程序可以把一个联接拷贝到剪贴板上供客户程序粘贴并建立DDE会话。
步骤如下:
1.调用DDEServerItem部件的CopyToClipboard方法,把Text(或Lines)属性的值和DDE联接信息拷贝到剪贴板上;
2.DDE客户程序插入联接的数据。
一般地这是通过选择适当的命令(如Edit|PasteSpecial或Edit|PasteLink)来实现的。
7.4.2响应DDE事件
部件DDEServerConv有三个事件:
OnOpen、OnClose、OnExecuteMacro。
前两个事件在DDE会话建立和终止时触发。
同(7.3.7)中的介绍。
OnExecuteMacro事件用于响应客户程序发送过来的宏指令。
OnExecuteMacro事件处理过程有一个Msg参数,保存发送过来的指令串。
用户可以在该过程中决定如何响应这些宏指令。
DDEServerItem部件只有一个事件OnPokeData。
这一事件用于响应客户程序发送来的数据。
如果客户程序是Delphi程序,则客户程序调用了PokeData或PokeDataLines方法。
在这一事件的处理过程中用户可以把发送来的数据保存到一个合适的地方。
一般说来这应该就是DDEServerItem所联系的文本控件。
下面的程序把发送来的数据保存到ListBox中。
procedureForm1.OnDDEServerItemPokeData(Serder:
TObject);
begin
ListBox1.Items:
=DDEServerItem1.Lines;
end;
7.4.3DDE服务器应用例程
下面我们创建一个DDE服务器例程和一个相应的DDE客户例程。
DDE服务器例程可以完成的工作有:
1.把DDE联接信息拷贝到剪贴板上供其它程序使用;
2.利用一个TMemo部件为其它程序提供数据源;
3.接收客户程序发送来的数据;
4.根据客户程序发送来的宏指令改变自身的运行状态。
其中各部件的关键属性如下:
DDESrvrForm.ActiveControl=Memo1
DDESrvrForm.Menu=MainMenu1
Bevel1.Align=alTop
Memo1.Align=alClient
DDETestItem.ServerConv=DDETestTopic
通过设置Bevel1、Memo1的Align属性,可以保证窗口大小变化时仍能有较为美观的屏幕显示。
Memo1是服务器的数据源,DDE项目部件DDETestItem通过Memo1的OnChange事件与Memo1建立联系。
procedureTDdeSrvrForm.doOnChange(Sender:
TObject);
begin
ifnotFInPokethen
DDETestItem.Lines:
=Memo1.Lines;
end;
其中FInPoke是一个布尔类型的私有数据成员,用于标志程序是否在处理客户程序的数据发送。
当数据是由客户发送过来转存到数据源时,则没有必要再把数据传给DDE项目部件。
把联接信息拷贝到剪贴板,只需简单调用DDETestItem的CopyToClipboard方法。
procedureTDDESrvrForm.CopyClick(Sender:
TObject);
begin
DDETestItem.CopyToClipboard;
end;
这是通过菜单项Edit|Copy来调用的。
接收客户程序发送来的数据,是在DDETestItem的OnPokeData事件处理过程中。
在接收过程中改变FInPoke的值,以阻止数据的无效反送。
procedureTDDESrvrForm.doOnPoke(Sender:
TObject);
begin
FInPoke:
=True;
Memo1.Lines:
=DDETestItem.Lines;
FInPoke:
=False;
end;
在DDE会话部件DDETestTopic的OnExecuteMacro事件处理过程中处理客户发送来的宏指令。
我们共定义了五种可以响应的宏指令:
CopyDDE、Clear、WS_Normal、WS_MINIMIZED、WS_MAXIMIZED,分别用于拷贝联接信息、清除Memo1中的内容以及改变窗口显示状态。
procedureTDdeSrvrForm.doMacro(Sender:
TO