VB中应用DDE
动态数据交换(dde)是windows应用程序间通讯的基本方法之一,在动态数据交换的过程中,提供数据和服务的应用程序称为服务器,请求数据或服务的应用程序则称为客户。 dde交谈是由客户程序启动的。如果得到服务器程序的响应便可在两个应用程序之间建立起一条数据通道,开始进行信息的动态交换和传递。一个windows应用程序可以是一个程序的客户,同时也可以是另一个程序的服务器。本文将介绍如何用visual basic来编写dde服务器和客户程序。 vb中的dde事件 当动态数据交换启动时,会产生若干事件。通过响应这些事件,我们可以编写代码来处理动态数据交换时产生的问题。 l linkopen事件 该事件在启动dde时产生,如果vb的窗体作为服务器,则该事件作用于窗体,响应该事件的过程为form—linkopen。如果是vb中的控件作为客户接收数据,则该事件作用于控件。通过响应linkopen事件可以在dde启动时作一些初始化的处理。 l linkclose事件 该事件在关闭dde链接时产生。通过响应该事件可在dde关闭时作一些善后处理工作。 l linkerror事件 该事件在进行动态数据交换中发生错误时产生。通过由事件处理过程的参数传递的错误代码,可以在事件过程中处理不同的故障。 l linkexecute事件 该事件通常是作为服务器的程序在收到客户程序发送的命令时产生。服务器程序通过响应该事件来执行客户程序发送的命令。 l linknotify事件 该事件发生在客户程序。只有dde链接是以通知链接方式进行时才会产生这个事件。在这种情况下,当服务器中的数据发生变化时,就会在客户程序中引发linknotify事件,告诉客户方源数据已经更新,客户方在响应linknotify事件时,可通过调用linkrequest方法请求将更新的数据发送过来。 vb中dde的方法 l linkrequest方法 该方法是客户程序用来请求服务器程序将更新了的数据发送过来。 l linkexecute方法 该方法是客户程序用于向服务器程序发送执行命令时调用。通常会以服务器程序规定的命令字符串作为调用参数。 l linkpoke方法 dde的交换可以是双向的。该方法用于由客户程序向服务器程序发送数据。 l linksend方法 当dde所交换的数据是图形时,如果建立的是自动链接,则只要源图形中有一个象素发生变化也会引起一次发送整个图形的操作,这样一来就会大大地降低系统的性能。为此,可以在图形更新完毕时使用该方法将图形信息发出。 vb中dde的属性 l linkmode属性 该属性用于vb的窗体时可以决定该窗体是否是一个dde服务器的数据源。可设置的值有两个:none表示不作为dde的数据源,source表示作为dde的数据源。该属性用于控件时,将指定启动/关闭dde链接。可设置的值有四个:none表示关闭dde链接,automat?ic表示用自动方式启动dde链接,manual表示用手动方式启动dde链接,notify表示用通知方式启动dde链接。 l linktopic属性 该属性用于客户程序中的控件,它指定dde服务器应用程序名及动态数据交换的主题。 l linkitem属性 该属性用于客户程序中的控件。它指定dde实际传送的数据,通常是服务器程序中作为数据源的窗体里的一个控件名。 l linktimeout属性 该属性用于客户程序中的控件。在dde中,服务器对于客户请求的响应时间是可变的。客户程序可以设置linktimeout属性来控制等待的时间,从而避免因服务器响应时间过长而产生错误。
一、DDE会话基本设计 ★发送方设置: ''注:Kj代表窗体中发送DDE会话的某控件,如TextBox、Label 1.加入代码: Kj.LinkMode=0 Kj.LinkTopic="收|Form1"‘文件名|窗体名 Kj.LinkItem="Text1"‘控件名 Kj.LinkMode=Mode‘0(断开)1(自动)2(手动)3(通知) 2.用“Kj.LinkPoke”‘发送源程序控件kj的字符到本程序的Text1中 3.用“Kj.LinkRequest”‘源程序将本程序Text1字符取回放入kj 4用“Kj.LinkExecuteCmd” ‘触发本标程序的Form_LinkExecute事件 ★接收方设置: 1.必须在设计状态下设置本程序的窗口:LinkMode = 1 2.在Form_LinkExecute事件中接收发送程序发出的DDE会话消息 二、DDE会话的事件 ▲LinkClose(事件)DDE对话结束 ▲LinkError(linkerrAsInteger)(事件)DDE对话出错 ▲LinkExecute(cmdstrAsString,cancelAsInteger)(事件) 当一个DDE对话中的命令字符串由一个接收端应用程序发出时而发生的 ▲LinkOpen(cancelAsInteger)(事件)DDE对话正在启动时 ▲LinkNotify(事件) 如果接收端控件的LinkMode属性被设置为3(通知),当发送端已经改变了由DDE链接定义的数据时,此事件发生。 三、DDE会话的有关属性 ▲LinkTimeout[ =Number]属性返回或设置等待DDE响应消息的时间。 缺省为50(相当于5秒), 最大等待时间长度为65,535个十分之一秒,或大约为1时49分钟 ▲LinkItem[ =String]属性返回或设置传给接收端的数据 ▲LinkTopic[ =value]属性对于接收端控件-返回或设置发送端应用程序和主题 ▲LinkMode[ =Number]属性DDE会话方式 ★对于DDE会话中用做目标的控件,Number的设置值为: 0vbLinkNone无无DDE交互。(缺省值) 1vbLinkAutomatic自动每次链接数据改变,目标控件都要更新 2vbLinkManual手动只有激活LinkRequest方法时,才更新目标控件。 3vbLinkNotify通知链接数据改变时,会产生LinkNotify事件,但是只有在LinkRequest方法激活时才会更新目标控件。 ★对作为DDE会话源的窗体,number的设置值为: 0vbLinkNone(缺省值)无没有DDE交互。 没有目标应用程序能够启动与源窗体的主题会话,没有应用程序能够向窗体放置数据。如果在设计时LinkMode为0(无),在运行时不能将其改变为1(源)。 1vbLinkSource源允许窗体上的任何Label、PictureBox或TextBox控件为与该窗体建立DDE会话的目标应用程序提供数据。 如果存在这种链接,VisualBasic在控件内容改变时会自动提醒目标应用程序。另外,目标应用程序能够向窗体上的Label、PictureBox、TextBox控件存放数据。如果设计时LinkMode为1(源),运行时可以将它改为0(无)也可以再改回来。 返回一个代表包含该窗口的框架的Window对象,此属性为只读,只应用于Window对象 四、DDE会话的有关方法 ▲LinkSend(方法) 在一次DDE对话中将PictureBox控件的内容传输到的接收端应用程序。 ▲LinkExecuteString(方法) DDE对话过程中将命令字符串发送给发送端应用程序 ▲LinkPoke(方法) DDE对话过程中将Label、PictureBox或TextBox控件的内容传送给发送端应用程序 ▲LinkRequest(方法) DDE对话中请求发送端应用程序更新Label、PictureBox或TextBox控件中的内容 ★如果object的LinkMode属性设置为自动(1或vbLinkAutomatic),则源应用程序自动更新object而不需要LinkRequest。 ★如果object的LinkMode属性设置为手工(2或vbLinkManual),则只有使用LinkRequest时源应用程序才更新object。 ★如果object的LinkMode属性设置为通知Notify(3或vbLinkNotify),则源端通过调用LinkNotify事件通知接收端已更改数据。然后接收端必须使用LinkRequest更新数据。设置一指示对象为可见或隐藏的值 五、DDE会话的集合 LinkedWindows集合 ▲Count(属性)集合内成员的个数,此属性为只读 ▲Parent(属性)返回包含另一对象或集合的对象或集合,此属性为只读 ▲VBE(属性)返回该VBE对象的根,此属性为只读。 例返回活动工程名称:Debug.PrintApplication.VBE.ActiveVBProject.Name ▲Add(component)(方法)将一个对象添加到集合。 component参数: vbext_ct_ClassModule将一个类模块添加到集合。 Vbext_ct_MSForm将窗体添加到集合。 vbext_ct_StdModule将标准模块添加到集合。 ▲Item(index)(方法)返回集合中所索引的成员。 index参数可以是数值或包含对象标题的字符串。字符串必须和集合的key参数匹配。 Key参数: Windows Caption属性设置 LinkedWindows Caption属性设置 CodePanes 无唯一字符串与此集合相关。 VBProjects Name属性设置 VBComponents Name属性设置 References Name属性设置 Properties Name属性设置 ▲Remove(component)(方法)从集合中删除一项 component参数是必需的。 对于LinkedWindows集合来说,是一个对象。 对于References集合来说,是一个对类型库,或者对工程的引用。 对于VBComponents集合来说,是一个枚举型的常数,它代表一个类模块、一个窗体,或者是一个标准模块。 【例】六、DDE会话的Link操作示例 1.本示例建立一个MicrosoftExcel的DDE链接,将一些值放置到一个新工作单的第一行的单元里,并按照这些值画图。LinkExecute向MicrosoftExcel发送激活工作单的命令,选择一些值并按照它们画图。 PrivateSubForm_Click() DimCmd,I,Q,Row,Z‘声明变量。 Q=Chr(34)‘定义引用标记。 ''创建一个含有MicrosoftExcel宏指令的字串。 Cmd="[ACTIVATE("&Q&"SHEET1"&Q&")]" Cmd=Cmd&"[SELECT("&Q&"R1C1:R5C2"&Q&")]" Cmd=Cmd&"[NEW(2,1)][ARRANGE.ALL()]" IfText1.LinkMode=vbNoneThen Z=Shell("C:ProgramFilesMicrosoftOfficeOfficeEXCEL.EXE",4)启动Excel。 Text1.LinkTopic="Excel|Sheet1"‘设置连接主题。 Text1.LinkItem="R1C1"‘设置连接项目。 Text1.LinkMode=vbLinkManual‘设置连接模式。 EndIf ForI=1To5 Row=I''定义行号。 Text1.LinkItem="R"&Row&"C1"''设置连接项目。 Text1.Text=Chr(64+I)''将值放置在Text中。 Text1.LinkPoke''将值放入单元。 Text1.LinkItem="R"&Row&"C2"''设置连接项目。 Text1.Text=Row''将值放置在Text中。 Text1.LinkPoke''将值放入单元。 NextI onErrorResumeNext Text1.LinkExecuteCmd‘执行MicrosoftExcel命令。 MsgBox"LinkExecuteDDEdemowithMicrosoftExcelfinished.",64 End EndSub
2.使用LinkRequest更新含有MicrosoftExcel工作单中值的正文框的内容,计算机上必需正在运行着MicrosoftExcel PrivateSubForm_Click() IfText1.LinkMode=vbNoneThen''测试连接模式。 Text1.LinkTopic="Excel|Sheet1"''设置连接主题。 Text1.LinkItem="R1C1"''设置连接项目。 Text1.LinkMode=vbLinkManual''设置连接模式。 Text1.LinkRequest''更新正文框内容。 Else IfText1.LinkItem="R1C1"Then Text1.LinkItem="R2C1" Else Text1.LinkItem="R1C1" Text1.LinkRequest''更新正文框内容。 EndIf EndIf EndSub
3.LinkItem、LinkMode、LinkTopic属性示例 在这个例子中,每一次敲击鼠标都会使MicrosoftExcel工作单中的单元更新VisualBasic的TextBox 先启动MicrosoftExcel,打开一个新的名叫Sheet1的工作单,在第一列中放入一些数据。 PrivateSubForm_Click() DimCurRowAsString StaticRow''工作单的行数. Row=Row+1''增加行. IfRow=1Then''只第一次. ''确保连接不是活动的. Text1.LinkMode=0 ''设置应用程序的名字和题目名. Text1.LinkTopic="Excel|Sheet1" Text1.LinkItem="R1C1"''设置LinkItem. Text1.LinkMode=1''设置LinkMode为自动. Else ''在数据项目中更新行. CurRow="R"&Row&"C1" Text1.LinkItem=CurRow''设置LinkItem. EndIf EndSub
【例】VB读DDE的简明例子。 第一.创建一个工程,名称:Child,窗体名称:FrmChild,添加Text1 Option Explicit Private Sub Form_LinkExecute(CmdStr As String,Cancel As Integer) Text1.Text = CmdStr Cancel = 0 End Sub 第二.创建新工程,名称:Main,窗体名称FrmMain,添加Text1 Option Explicit Private Sub Text1_Change() Dim t As Long Text1.LinkMode = 0 Text1.LinkTopic = "Child|frmChild" '注意此处的标题一定与连接的标题相同否则连接不成功 Text1.LinkMode = 2 Text1.LinkExecute Text1.Text t = Text1.LinkTimeout Text1.LinkTimeout = 1 Text1.LinkMode = 0 Text1.LinkTimeout = t End Sub
【例】用DDE创建桌面快捷方式 受"用DDE连接方法向开始菜单中添加快捷方式"一文的启发,我写了一个可以向桌面增加快捷方式的小程序。与调用Vb5stkit.dll或Vb6stkit.dll来建立快捷方式相比,最大的特点在于避免了对该DLL文件的依赖(并不是每一台Win9x的机上都有的这些文件的)。是不是很环保? 原理:利用Text控件的DDE在系统开始菜单中添加一个快捷方式,然后将该快捷方式剪切到桌面上来。 须解决的问题:取得系统开始菜单和桌面的路径。这其中当然免不了要调用到API的SHGetSpecialFolderLocation 和SHGetPathFromIDList 函数。 实现步骤: 1.新建工程; 2.在表单中增加一个文本框(txtLnk)及一个命令按钮(cmdMakeLnk); 3.加入以下代码: Option Explicit Const CSIDL_DESKTOP = &H0系统桌面 Const CSIDL_PROGRAMS = &H2系统"开始-$#@62;程序"菜单 Private Type SHITEMID cb As Long abID As Byte End Type Private Type ITEMIDLIST mkid As SHITEMID End Type
Private DeclareFunction SHGetSpecialFolderLocation Lib "shell32.dll" (ByVal hwndOwner As Long,_ ByVal nFolder As Long,pidl As ITEMIDLIST) As Long Private Declare Function SHGetPathFromIDList Lib "shell32.dll" Alias "SHGetPathFromIDListA" _ (ByVal pidl As Long,ByVal pszPath As String) As Long 定义取得系统特定文件夹的路径的函数。 Private Function GetSpecialfolder(CSIDL As Long) As String Dim lRet As Long Dim IDL As ITEMIDLIST Dim sPath As String lRet = SHGetSpecialFolderLocation(100,CSIDL,IDL) 错误时返回非0值 If lRet = 0 Then sPath = Space$(512) lRet = SHGetPathFromIDList(ByVal IDL.mkid.cb,ByVal sPath) 一定要删除末尾的 0字节。这在调用API时常常会遇到。 GetSpecialfolder = Left$(sPath,InStr(sPath,Chr$(0)) - 1) Exit Function End If GetSpecialfolder = "" End Function Private Sub cmdMakeLnk_Click() Dim sProgramsPath As String Dim sDesktopPath As String sProgramsPath = GetSpecialfolder(CSIDL_PROGRAMS) sDesktopPath = GetSpecialfolder(CSIDL_DESKTOP) txtLnk.LinkTopic = "Progman|Progman" txtLnk.LinkMode = 2 格式: "[AddItem($#@60;欲建立快捷方式的命令行(可以是文件夹)$#@62;,$#@60;快捷方式的名称$#@62;,[快捷方式的图标文件],[第几个图标])]" 注意: 1、由于文件名是字符串,所以必须加引号,也就是以下这行命令为什么们用了两个引号的原因 2、在"快捷方式的图标文件"中所出现的路径及文件必须是8.3格式,不支持长文件名。 下面假设为 C:WINDOWSCALC.EXE建立快捷方式 txtLnk.LinkExecute "[AddItem(""C:WINDOWSCALC.EXE"",""计算器"" )]" 将快捷方式移至桌面 sProgramsPath = sProgramsPath & "计算器.lnk" sDesktopPath = sDesktopPath & "计算器.lnk" FileCopy sProgramsPath,sDesktopPath Kill sProgramsPath End Sub 以上在Windows98、ME + VB5、VB6通过。
【例】用DDE实现窗体防止运行多个实例并传递命令 上网的朋友一定都用过网络蚂蚁(Net Ants)的吧?不知你在使用过程中有没有注意过,那就是如果你想调动两个“蚂蚁”为您效力是不可能的——它总会把新运行的关闭。这点在VB 中很容易实现: Private Sub Form_Load() If App.PrevInstance Then MsgBox "你已经运行这个应用程序了" End ‘退出新运行的程序 End If End Sub 这样如果你运行这个程序后在运行它,它会弹出一个消息框并拒绝再次运行。这非常容易。 而“蚂蚁”程序的妙处就在于:在重复运行“蚂蚁”时它不仅拒绝运行,而且能把已经运行的“蚂蚁”激活,这样用上面的程序就无能为力了。但事实上实现拒绝运行并激活已运行的程序有多种方法: 1、用FindWindow函数得到已经运行窗体的句柄(HWND),然后用SetActiveWindow等API函数将其激活。其缺点也很明显,那就是没法传递参数。 2、用FindWindow函数得到已运行窗体的句柄后用SendMessage的方法给窗体传送一个自定义消息(附带参数),然后在窗体中拦截并进行处理,但这样做要修改窗体的标准消息处理程序,用在VC,BC或DELPHI编写的程序中还行,但在VB中工作量太大,并且容易发生“一般保护行错误”使VB崩溃,不太可取(当然,如果你有足够的信心和不怕崩溃的精神,也可以试一下 ^_^ )。 3、使用DDE技术。 所谓DDE技术,就是动态数据交换技术。也许你很奇怪,这与本文所讨论的内容有什么相干的?且听我慢慢讲来。 为了实现拒绝运行并把已经运行的程序激活并实现各种功能,我们可以先用本文开头提到的方法,检测一下程序有没有被运行过,如果没有,就正常运行,如果已经被运行过,就打通与它的DDE通道,传给它一个(或一些)数据,然后由已经运行的程序对数据进行处理,再去实现各种“意想不到”的功能,这时也许就有人对这你的程序喊:“酷、酷……” 好了,耳听为虚,眼见为实,下面让我们动点真格的。 打开VB,新建一个工程,选择菜单中的“工程->工程1 属性”,把工程名称改为“P1”(我爱偷懒,能短则短 ^_^ ),把已有的一个窗体的“LinkTopic”属性改为“FormDDE”,把“LinkMode” 属性改为“1 - Source”,添加一个PictureBox控件作为DDE执行控件,命名为picDDE。然后添加一个 TextBox控件,命名为“txtInfo”,并把“MultiLine”属性设置为“True”,以便显示多行文本,作为 消息显示控件。 最后在窗体代码区输入以下代码: Const COMMANDLINE = "CommandLine=" ‘还是为了省事,定义一个常量 Private Sub Form_LinkExecute(CmdStr As String,Cancel As Integer) Static lngCount As Long Dim Info As String Info = txtInfo.Text‘保留原有信息 Select Case CmdStr‘CmdStr是DDE程序传送过来的参数 Case "Max" Me.WindowState = 2 Info = Info + vbNewLine + "窗体已被最大化" Case "ShowTime" Info = Info + vbNewLine + "最后一次运行这个程序的时间是:" + Str(Now) Case "Count" lngCount = lngCount + 1 Info = Info + vbNewLine + "你已经第" + Str(lngCount) + "次重复调用这个程序。" _ + vbNewLine + "但怕您不多给工资,所以只运行了一个 ^_^" End Select If Left(CmdStr,Len(COMMANDLINE)) = COMMANDLINE Then Info = Info + vbNewLine + "新程序曾以命令行形式运行" + vbNewLine + "命令行为:" _ + vbNewLine + Right(CmdStr,Len(CmdStr) - Len(COMMANDLINE)) End If txtInfo.Text = Info‘把信息显示出来 Cancel = False End Sub Private Sub LinkAndSendMessage(ByVal Msg As String) Dim t As Long picDDE.LinkMode = 0 注释:-- picDDE.LinkTopic = "P1|FormDDE" ‘连接DDE程序并发送数据/参数 picDDE.LinkMode = 2 ‘“|”为管道符,是“退格键”旁边的竖线, picDDE.LinkExecute Msg ‘不是字母或数字! t = picDDE.LinkTimeout 注释:-- picDDE.LinkTimeout = 1 ‘终止DDE通道。当然,也可以用别的方法 picDDE.LinkMode = 0 ‘这里用的是超时强制终止的方法 picDDE.LinkTimeout = t 注释:-- End Sub Private Sub Form_Load() If App.PrevInstance Then ‘程序是否已经运行 Me.LinkTopic = "" ‘这两行用于清除新运行的程序的DDE服务器属性, Me.LinkMode = 0 ‘否则在连接DDE程序时会出乱子的 LinkAndSendMessage "Max" 注释:-- LinkAndSendMessage "Count" ‘连接DDE接受程序并传送数据/参数 LinkAndSendMessage "ShowTime" 注释:-- If Command <> "" Then ‘如果有命令行参数,就传递过去 LinkAndSendMessage COMMANDLINE + Command End If End ‘束新程序的运行 End If End Sub 测试一下: 把工程“P1”编译成EXE文件(设名称为 P1.EXE ) 1、打开“我的电脑”,找到 P1.EXE 并执行。可以看到程序正常运行了。 2、再运行一次,这次新程序没有运行成功,而原来运行的程序却被最大化了,而且文本框中有以下字符: 窗体已被最大化 你已经第 1次重复调用这个程序。 但怕您不多给工资,所以只运行了一个 ^_^ 最后一次运行这个程序的时间是:00-2-6 7:11:01 3、打开 MS-DOS方式 ,用命令行方式再次运行程序,如 “P1 How Are You?” 这时原来运行的程序文本框中又多了几行字: 窗体已被最大化 你已经第 2次重复调用这个程序。 但怕您不多给工资,所以只运行了一个 ^_^ 最后一次运行这个程序的时间是:00-2-6 7:14:32 新程序曾以命令行形式运行 命令行为: How Are You? OK,运行完全正确,然后你就可以把它应用的你的程序中了。 dde及其在vb中的实现 http://blog.163.com/shuangfeng_521/blog/static/200177372013128103329414/ 两个VB程序之交换数据的DDE工程DDE Server VB6 实现程序间通信(下载) http://download.csdn.net/detail/mokton/570138 http://bbs.csdn.net/topics/40149928 VB 利用DDE进程间通信,5行代码搞定方法虽然简单,但是找得却不容易,特此于大家共享。 http://download.csdn.net/detail/sysdzw/1759069 http://www.doc88.com/p-371433855719.html (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |