在PB中利用DDE
华中科技大学电子与信息工程系 郭小兵
PowerBuilder(以下称PB)是一种强有力的企业级数据库应用系统开发工具,利用它可以方便地开发出数据库系统的前台应用软件。但由于用PB所开发的报表具有一定的局限性:报表的表头、列宽等都不能在应用程序中由用户来进行调整,所以若用户报表的格式有所变动,则必须在原程序中对报表进行调整,这在很大程度上降低了软件的灵活性。
Excel是Microsoft公司的表格处理软件,由于其简单易用,近年来在各单位的报表处理中得到广泛的应用。那么,在应用程序中是否可以调用Excel,让用户在用PB开发的应用程序中管理数据库中的数据,而在用户熟悉的Excel表格处理软件中调整并打印报表呢?
答案是肯定的,本文介绍如何利用动态数据交换DDE(Dynamic Data Exchange)技术,在PB中把数据库中的数据传送到Excel应用程序中,以便由用户在Excel中调整打印报表。
DDE用于在Windows平台上的两个正在运行的应用程序之间动态交换数据,它是一种在Windows操作系统中基于消息的协议。动态数据交换总是发生在两个正在运行的程序之间,在这两个应用程序之间相互发送和接收命令及数据。这两个正在运行的程序分别称为客户程序和服务器程序,客户程序就是请求服务的程序,而提供服务的程序称为服务器程序。
实现方法
DDE应用程序在开始交换数据以前必须由客户端发出初始请求,建立与服务器端的DDE连接(又称为通道或会话)。在建立连接后客户端可以连续向服务器发送数据请求和命令请求。
在本文的应用程序中,我们用Excel做DDE应用服务器程序,在PB中进行DDE连接。
1.启动DDE服务器应用程序
Excel.exe可以在Windows环境下单独启动,也可以在PB中用run函数启动。
PB中run函数的语法格式为:
run(string{,windowstate})
●string:字符型,要执行的程序文件名;
●windowstate:枚举型,程序启动后的窗口状态,可以是最小化(minimized!)、最大化(maxized!)或原尺寸(normal!)。
在本文中,我们从客户程序PB中启动服务器应用程序Excel.exe,并假设Excel.exe的路径为:
c:\program files\Microsoft office\office\Excel .exe
在PB中启动服务器应用程序的命令为:
run(“c:\program files\Microsoft office\office\Excel.exe”, minimized!)
2.建立DDE连接
在客户程序和服务器程序均启动之后,就必须建立客户程序和服务器程序之间的连接。在客户程序PB中,可以使用OpenChannel函数建立这种连接,打开一个从客户程序到服务器程序的通道。
PB中OpenChannel函数的格式为:
OpenChannel(appname,topicname{,windowhandle }))
●appname:服务器程序的应用程序名;
●topicname:主题名,即客户端要使用的实例,如Word文档或Excel文档;
●windowhandle:客户端的窗口句柄,如果客户端程序打开了多个窗口,需要指定其中一个作为客户端窗口。
建立DDE连接的方式分为冷连接、暖连接和热连接:
●冷连接:是指运行中的客户程序和服务器程序进行直接的数据交换,不需要建立通道或连接,每次操作都要指定应用程序名和项目名;
●暖连接:是指用OpenChannel函数建立的连接,它可以利用OpenChannel函数返回的句柄对指定的应用进行操作;
●热连接:是指用StartHotLink建立的连接。
无论是冷连接还是暖连接都无法在客户端知道服务器端是否修改了数据,同样,在服务器端也无法知道客户端的数据修改情况。而用热连接就可以使服务器端和客户端彼此知道数据是否被修改。
在本文中,只是在PB中调用Excel报表,并向其中传递数据库数据,并不需要知道Excel中对数据的修改处理情况,所以选用暖连接方式比较合适。
3.从客户端向服务器端发送数据
在建立起客户程序和服务器程序的连接之后,就可以在客户程序PB中用SetRemote函数向服务器应用程序的报表中发送数据库数据,以生成完整的报表。
根据DDE连接方式的不同,SetRemote函数有两种格式分别用于冷连接和暖连接。
冷连接:
SetRemote(location,value,applname,topicname)
暖连接:
SetRemote(location,value,handle{,windowhandle})
我们可以利用该函数读取数据库中的数据并写入到Excel的报表文件中以待打印。
4.通过客户端执行服务器端命令
在客户程序向服务器Excel发送完数据后,用户可以在Excel中对报表做适当的调整,然后打印调整过的报表,并且关闭Excel。
在应用程序的客户端中可以以远程方式执行服务器应用程序(Excel.exe)中的命令,执行远程命令的函数为ExecRemote。该函数也是根据DDE连接方式的不同有冷连接和暖连接两种格式。
冷连接:
ExecRemote ( command , appname, topicname)
暖连接:
ExecRemote (command ,handle,{ windowhandle })
利用这个命令可以在PB客户端执行Excel程序的保存、打印和关闭等操作。
5.结束DDE连接
当完成DDE的数据处理后,使用CloseChannel函数关闭DDE连接。该函数的语法格式为:
CloseChannel ( handle, { windowhandle } )
编程实例
假设有某学校的成绩管理系统,学生的成绩报表格式如图1。
XX班级考试成绩一览表
2000年XX月
姓名
语文
数学
英语
物理
化学
总分
平均
全班平均
首先在Excel中按照上述格式做好报表grade1.xls,并且把全班的平均成绩和表头之间空余100行(假设班级的学生人数不超过100人)。然后在Excel中设计好全班平均成绩、个人总成绩和个人平均成绩的计算公式,以自动计算所需要的数值。最后从数据库中检索出数据并填充在数据窗口控件dw_1中。
部分源代码如下:
int I,handle,n
string excel,road_excel
//得到Excel的路径
registryget(“HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\8.0\”+&“Excel\microsoft Excel ”,“GalleryPath”,Regstring!, road_excel)
Excel=road_excel+“\Excel.exe”
//启动服务器程序,并打开报表grade1.xls
run(Excel+“ grade1.xls ”)
//建立到服务器程序的连接通道
handle=OpenChannel(“Excel”,“ grade1.xls ”)
n= dw_1.count()
//向Excel报表传递数据
for I= 1 to n
handle=OpenChannel(“Excel”,“ grade1.xls”)
SetRemote(“r”+string(I+1)+“c1”,string(dw_1.getitemnumber(I+1)),handle)
SetRemote(“r”+string(I+2)+“c1”,string(dw_1.getitemnumber(I+2)),handle)
SetRemote(“r”+string(I+3)+“c1”,string(dw_1.getitemnumber(I+3)),handle)
SetRemote(“r”+string(I+4)+“c1”,string(dw_1.getitemnumber(I+4)),handle)
SetRemote(“r”+string(I+5)+“c1”,string(dw_1.getitemnumber(I+5)),handle)
next
//在客户程序中打印Excel报表
ExecRemote(“[print()]”,“Excel”,“grade1.xls”)
//关闭并不保存grade.xls
ExecRemote(“[close(false)]”,“Excel”,“grade1.xls”)
//退出Excel
ExecRemote(“[quit()]”,“Excel”,“system”)
//关闭连接通道,结束DDE会话
Close(handle)
注意:从客户程序中启动Excel服务器程序与建立连接和传递数据之间必须要有一定的时间间隔,最好把启动Excel放在一个事件中,把建立连接和传递数据放在另一个事件中,避免由于在建立连接和传递数据时Excel还没有完全启动,造成建立连接和传递数据不正常。