VB6中不同进程之间交换数据的方法(DDE)
一、简介
动态数据交换(DDE)是windows应用程序间通讯的基本方法之一,在动态数据交换的过程中,提供数据和服务的应用程序称为服务器,请求数据或服务的应用程序则称为客户。
DDE对话连接是由客户程序启动的。如果得到服务器程序的响应便可在两个应用程序之间建立起一条数据通道,开始进行信息的动态交换和传递。一个windows应用程序可以是一个程序的客户,同时也可以是另一个程序的服务器。
在实际开发中,如果项目没有特殊的兼容性要求或不需要与一些较旧的系统进行集成,可根据具体需求考虑使用其他更高效的进程间通信方式,如:
- Sockets(套接字) :适用于网络通信,也可以用于本地进程间通信,支持高并发和大数据量传输,但实现相对复杂,需要处理网络连接、数据包拆分和重组等问题。
- Named Pipes(命名管道) :在 Windows 系统中,命名管道是一种高效的进程间通信机制,适用于本地或网络中计算机之间的通信,具有较好的安全性和数据传输能力,适合传输大量数据。
- .NET Remoting :在.NET 框架下,.NET Remoting 提供了一种灵活的远程对象通信机制,可以实现跨进程、跨网络的对象调用,适合构建分布式应用程序,但主要适用于.NET 环境下的应用程序通信。
- WCF(Windows Communication Foundation) :也是.NET 框架下的通信技术,功能更加强大和全面,支持多种通信协议和数据格式,适合构建复杂的企业级分布式系统,但学习曲线较陡。
二、对象三要素
2.1 DDE的属性
linkmode属性
该属性用于窗体时,可以决定该窗体是否是一个DDE服务器的数据源。可设置的值有两个:
- [0] none表示不作为DDE的数据源。发送方设置为0
- [1] source表示作为DDE的数据源。接收方(数据源)设置为1,这表示该窗体作为 DDE 服务器的数据源,能够响应来自客户端的 DDE 请求。
该属性用于控件时,将指定启动/关闭DDE链接。可设置的值有四个:
- [0] none表示关闭DDE链接
- [1] automatic表示用自动方式启动DDE链接
- [2] manual表示用手动方式启动DDE链接
- [3] notify表示用通知方式启动DDE链接
linktopic属性
该属性用于客户程序中的控件,它指定DDE服务器应用程序名及动态数据交换的主题。
linkitem属性
该属性用于客户程序中的控件。它指定DDE实际传送的数据,通常是服务器程序中作为数据源的窗体里的一个控件名。
linktimeout属性
该属性用于客户程序中的控件。在DDE中,服务器对于客户请求的响应时间是可变的。客户程序可以设置linktimeout属性来控制等待的时间,从而避免因服务器响应时间过长而产生错误。
2.2 DDE的方法
linkrequest方法
该方法是客户程序用来请求服务器程序将更新了的数据发送过来。
DDE 对话中请求发送端应用程序更新 Label、PictureBox 或 TextBox 控件中的内容
★如果 object 的 LinkMode 属性设置为自动( 1 或 vbLinkAutomatic),则源应用程序自动更新 object 而不需要 LinkRequest。
★如果 object 的 LinkMode 属性设置为手工(2 或 vbLinkManual),则只有使用LinkRequest 时源应用程序才更新 object。
★如果 object 的 LinkMode 属性设置为通知 Notify( 3 或 vbLinkNotify),则源端通过调用 LinkNotify 事件通知接收端已更改数据。然后接收端必须使用 LinkRequest 更新数据。设置一指示对象为可见或隐藏的值
linkexecute方法
该方法是客户程序用于向服务器程序发送执行命令时调用。通常会以服务器程序规定的命令字符串作为调用参数。
linkpoke方法
DDE的交换可以是双向的。该方法用于由客户程序向服务器程序发送数据。
linksend方法
当DDE所交换的数据是图形时,如果建立的是自动链接,则只要源图形中有一个象素发生变化也会引起一次发送整个图形的操作,这样一来就会大大地降低系统的性能。为此,可以在图形更新完毕时使用该方法将图形信息发出。
2.3 DDE的事件
vb中的DDE事件当动态数据交换启动时,会产生若干事件。通过响应这些事件,我们可以编写代码来处理动态数据交换时产生的问题。
linkopen事件
该事件在启动DDE时产生,如果vb的窗体作为服务器,则该事件作用于窗体,响应该事件的过程为form_linkopen。如果是vb中的控件作为客户接收数据,则该事件作用于控件。通过响应linkopen事件可以在DDE启动时作一些初始化的处理。
linkclose事件
该事件在关闭DDE链接时产生。通过响应该事件可在DDE关闭时作一些善后处理工作。
linkerror事件
该事件在进行动态数据交换中发生错误时产生。通过由事件处理过程的参数传递的错误代码,可以在事件过程中处理不同的故障。
linkexecute事件
该事件通常是作为服务器的程序在收到客户程序发送的命令时产生。服务器程序通过响应该事件来执行客户程序发送的命令。接收方在Form_LinkExecute 事件中接收发送程序发出的 DDE 会话消息。
linknotify事件
该事件发生在客户程序。只有DDE链接是以通知链接方式进行时才会产生这个事件。在这种情况下,当服务器中的数据发生变化时,就会在客户程序中引发linknotify事件,告诉客户方源数据已经更新,客户方在响应linknotify事件时,可通过调用linkrequest方法请求将更新的数据发送过来。
三、DDE会话基本设计
以下是对 VB6 中使用 DDE 在两个 exe 之间传输数据的更详细解释:
3.1 数据源服务器端详细设置
创建 DDE 服务器项目
新建一个标准 EXE 工程,假设工程名为 “DDEServer”。
在窗体(假设为 Form1)的属性窗口中,将 LinkMode 属性设为 1(vbLinkSource),这表示该窗体作为 DDE 服务器的数据源,能够响应来自客户端的 DDE 请求。
设置 LinkTopic 属性
在 Form1 的 Form_Load 事件中设置 LinkTopic 属性,代码如下:
1 2 3 |
Private Sub Form_Load() Me.LinkTopic = "DDEServerExample|Form1" End Sub |
* 这里的 “DDEServerExample” 是自定义的应用程序名(可以根据需要命名),用于标识这个 DDE 服务器应用程序;“Form1” 是提供数据的窗体名。这个设置告诉系统,该窗体是 DDE 通信的主题(topic)为 “DDEServerExample|Form1” 的数据源。
处理 LinkExecute 事件
编写 Form_LinkExecute 事件过程,用于接收并处理客户端发送的命令。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Private Sub Form_LinkExecute(CmdStr As String, Cancel As Integer) ' CmdStr 是客户端发送的命令字符串 ' 根据命令执行不同的操作 If CmdStr = "ShowMessage" Then MsgBox "服务器收到命令:显示消息", vbInformation ElseIf CmdStr = "GetData" Then ' 假设 Text1 是服务器端用于提供数据的控件 Text1.Text = "这是服务器返回的数据" Else MsgBox "收到未知命令:" & CmdStr, vbExclamation End If Cancel = 0' 表示继续处理该命令,让 DDE 通信继续进行 End Sub |
* 当客户端调用 LinkExecute 方法发送命令时,这个事件会被触发,根据命令字符串执行相应的操作,如弹出消息框或准备数据供客户端读取。
3.2 客户端详细设置
创建 DDE 客户端项目
新建另一个标准 EXE 工程,假设工程名为 “DDEClient”。
在窗体(假设为 Form1)上添加一个 TextBox 控件(Text1),用于发送 DDE 命令和接收数据。
设置 LinkTopic 和 LinkItem 属性
在客户端代码中设置 Text1 的 LinkTopic 属性为服务器应用程序名及窗体名,即 “DDEServerExample|Form1”,与服务器端设置的 LinkTopic 对应。同时设置 LinkItem 属性为服务器端用于数据传输的控件名,例如服务器端的 Text1 控件,代码如下:
1 2 |
Text1.LinkTopic = "DDEServerExample|Form1" Text1.LinkItem = "Text1" |
客户端的 Text1 控件就与服务器端的 Text1 控件建立了 DDE 链接关系。
发送 DDE 命令和数据
发送命令
使用 Text1 的 LinkExecute 方法发送命令字符串,触发服务器端的 LinkExecute 事件。例如,添加一个命令按钮(Command1),其 Click 事件代码如下:
1 2 3 |
Private Sub Command1_Click() Text1.LinkExecute "ShowMessage" End Sub |
当点击这个按钮时,客户端会向服务器发送 “ShowMessage” 命令,服务器端收到后会弹出消息框。
发送数据
使用 LinkPoke 方法发送数据到服务器端的指定控件。例如,添加另一个命令按钮(Command2),其 Click 事件代码如下:
1 2 3 4 |
Private Sub Command2_Click() Text1.Text = "客户端发送的数据" Text1.LinkPoke End Sub |
客户端 Text1 的内容会被发送到服务器端的 Text1 控件中。
请求数据
如果客户端想要从服务器获取数据,可以使用 LinkRequest 方法。例如,添加第三个命令按钮(Command3),其 Click 事件代码如下:
1 2 3 4 |
Private Sub Command3_Click() Text1.LinkRequest MsgBox "从服务器获取的数据:" & Text1.Text, vbInformation End Sub |
调用 LinkRequest 方法后,客户端会向服务器请求数据更新,服务器端如果设置了相应的数据提供逻辑(如前面提到的 “GetData” 命令),客户端就可以获取到服务器返回的数据并显示出来。
3.3 示例代码详细说明
服务器端完整代码示例
Form1 上有一个 TextBox 控件(Text1)和以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Private Sub Form_LinkExecute(CmdStr As String, Cancel As Integer) Select Case CmdStr Case "ShowMessage" MsgBox "服务器收到命令:显示消息", vbInformation Case "GetData" Text1.Text = "服务器返回的数据:" & Now' 返回当前时间作为数据示例 Case Else MsgBox "未知命令:" & CmdStr, vbExclamation End Select Cancel = 0 End Sub Private Sub Form_Load() Me.LinkMode = vbLinkSource' 设置为 DDE 服务器 Me.LinkTopic = "DDEServerExample|Form1" End Sub |
当客户端发送 “ShowMessage” 命令时,服务器弹出消息框;发送 “GetData” 命令时,服务器将当前时间作为数据填充到 Text1 中,供客户端读取。
3.4 客户端完整代码示例
Form1 上有三个命令按钮(Command1、Command2、Command3)和一个 TextBox 控件(Text1),代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Private Sub Command1_Click() ' 发送命令到服务器 Text1.LinkTopic = "DDEServerExample|Form1" Text1.LinkItem = "Text1" Text1.LinkExecute "ShowMessage" End Sub Private Sub Command2_Click() ' 发送数据到服务器 Text1.LinkTopic = "DDEServerExample|Form1" Text1.LinkItem = "Text1" Text1.Text = "客户端在" & Now & "发送的数据" Text1.LinkPoke End Sub Private Sub Command3_Click() ' 从服务器获取数据 Text1.LinkTopic = "DDEServerExample|Form1" Text1.LinkItem = "Text1" Text1.LinkExecute "GetData" Text1.LinkRequest' 请求数据更新 MsgBox "从服务器获取的数据:" & Text1.Text, vbInformation End Sub |
* Command1 用于发送命令;Command2 用于发送数据;Command3 先发送 “GetData” 命令让服务器准备数据,然后请求数据更新并显示。
四、其他示例
4.1 DDE操作Excel示例
1.本示例建立一个 Microsoft Excel 的 DDE 链接,将一些值放置到一个新工作单的第一行的单元里,并按照这些值画图。 LinkExecute 向 Microsoft Excel 发送激活工作单的命令,选择一些值并按照它们画图。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
Private Sub Form_Click() Dim Cmd, I, Q, Row, Z ‘声明变量。 Q = Chr(34) ‘定义引用标记。 '' 创建一个含有 Microsoft Excel 宏指令的字串。 Cmd = "[ACTIVATE(" & Q & "SHEET1" & Q & ")]" Cmd = Cmd & "[SELECT(" & Q & "R1C1:R5C2" & Q & ")]" Cmd = Cmd & "[NEW(2,1)][ARRANGE.ALL()]" If Text1.LinkMode = vbNone Then Z = Shell("C:\Program Files\Microsoft Office\Office\EXCEL.EXE", 4)启动Excel。 Text1.LinkTopic = "Excel|Sheet1" ‘设置连接主题。 Text1.LinkItem = "R1C1" ‘设置连接项目。 Text1.LinkMode = vbLinkManual ‘设置连接模式。 End If For I = 1 To 5 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 '' 将值放入单元。 Next I on Error Resume Next Text1.LinkExecute Cmd ‘执行 Microsoft Excel 命令。 MsgBox "LinkExecute DDE demo with Microsoft Excel finished.", 64 End End Sub |
2.使用 LinkRequest 更新含有 Microsoft Excel 工作单中值的正文框的内容,计算机上必需正在运行着 Microsoft Excel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Private Sub Form_Click() If Text1.LinkMode = vbNone Then '' 测试连接模式。 Text1.LinkTopic = "Excel|Sheet1" '' 设置连接主题。 Text1.LinkItem = "R1C1" '' 设置连接项目。 Text1.LinkMode = vbLinkManual '' 设置连接模式。 Text1.LinkRequest '' 更新正文框内容。 Else If Text1.LinkItem = "R1C1" Then Text1.LinkItem = "R2C1" Text1.LinkRequest '' 更新正文框内容。 Else Text1.LinkItem = "R1C1" Text1.LinkRequest '' 更新正文框内容。 End If End If End Sub |
3.LinkItem、LinkMode、LinkTopic 属性示例
在这个例子中,每一次敲击鼠标都会使 Microsoft Excel 工作单中的单元更新 Visual Basic的 TextBox
先启动 Microsoft Excel,打开一个新的名叫 Sheet1 的工作单,在第一列中放入一些数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Private Sub Form_Click() Dim CurRow As String Static Row '' 工作单的行数. Row = Row + 1 '' 增加行. If Row = 1 Then '' 只第一次. '' 确保连接不是活动的. Text1.LinkMode = 0 '' 设置应用程序的名字和题目名. Text1.LinkTopic = "Excel|Sheet1" Text1.LinkItem = "R1C1" '' 设置 LinkItem. Text1.LinkMode = 1 '' 设置 LinkMode 为自动. Else ''在数据项目中更新行. CurRow = "R" & Row & "C1" Text1.LinkItem = CurRow '' 设置 LinkItem. End If End Sub |
4.2 VB读DDE的简明例子
第一.创建一个工程,名称:Child,窗体名称:FrmChild,添加Text1
1 2 3 4 5 |
Option Explicit Private Sub Form_LinkExecute(CmdStr As String, Cancel As Integer) Text1.Text = CmdStr Cancel = 0 End Sub |
第二.创建新工程,名称:Main,窗体名称FrmMain,添加Text1
1 2 3 4 5 6 7 8 9 10 11 12 |
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 |
4.3 用DDE创建桌面快捷方式
受"用DDE连接方法向开始菜单中添加快捷方式"一文的启发,我写了一个可以向桌面增加快捷方式的小程序。与调用Vb5stkit.dll或Vb6stkit.dll来建立快捷方式相比,最大的特点在于避免了对该DLL文件的依赖(并不是每一台Win9x的机上都有的这些文件的)。是不是很环保?
原理:利用Text控件的DDE在系统开始菜单中添加一个快捷方式,然后将该快捷方式剪切到桌面上来。
须解决的问题:取得系统开始菜单和桌面的路径。这其中当然免不了要调用到API的SHGetSpecialFolderLocation 和SHGetPathFromIDList 函数。
实现步骤:
1.新建工程;
2.在表单中增加一个文本框(txtLnk)及一个命令按钮(cmdMakeLnk);
3.加入以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
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 ‘下面假设为 C:\WINDOWS\CALC.EXE建立快捷方式 txtLnk.LinkExecute "[AddItem(""C:\WINDOWS\CALC.EXE"",""计算器"" )]" ‘将快捷方式移至桌面 sProgramsPath = sProgramsPath & "\计算器.lnk" sDesktopPath = sDesktopPath & "\计算器.lnk" FileCopy sProgramsPath, sDesktopPath Kill sProgramsPath End Sub |
格式:
"[AddItem(欲建立快捷方式的命令行(可以是文件夹),快捷方式的名称,[快捷方式的图标文件],[第几个图标])]"
注意:
1、由于文件名是字符串,所以必须加引号,也就是这行命令为什么们用了两个引号的原因
2、在"快捷方式的图标文件"中所出现的路径及文件必须是8.3格式,不支持长文件名。
以上在Windows98、ME + VB5、VB6通过。
4.4 用DDE实现窗体防止运行多个实例并传递命令
如果你不想允许调动两个相同的程序为您效力,检测到相同的实例时,把新运行实例的关闭。这点在VB 中很容易实现:
1 2 3 4 5 6 |
Private Sub Form_Load() If App.PrevInstance Then MsgBox "你已经运行这个应用程序了" End ‘退出新运行的程序 End If End Sub |
这样如果你运行这个程序后在运行它,它会弹出一个消息框并拒绝再次运行。
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