分享

VB中应用DDE

 nxhujiee 2019-11-14

【注意】在OLE和COM出现之前,DDE是两个windows程序之间通信的较好方式

动态数据交换(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.LinkExecute Cmd”   ‘触发本标程序的 Form_LinkExecute 事件

★接收方设置:

1.必须在设计状态下设置本程序的窗口:LinkMode = 1

2.在 Form_LinkExecute 事件中接收发送程序发出的 DDE 会话消息

二、DDE会话的事件 

▲LinkClose                      (事件)DDE 对话结束

▲LinkError(linkerr As Integer)  (事件)DDE 对话出错

▲LinkExecute(cmdstr As String, cancel As Integer)   (事件)

当一个 DDE 对话中的命令字符串由一个接收端应用程序发出时而发生的

▲LinkOpen(cancel As Integer)    (事件)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 会话的目标应用程序提供数据。

如果存在这种链接,Visual Basic 在控件内容改变时会自动提醒目标应用程序。另外,目标应用程序能够向窗体上的 Label、PictureBox、TextBox 控件存放数据。如果设计时LinkMode为 1(源),运行时可以将它改为 0(无)也可以再改回来。

返回一个代表包含该窗口的框架的 Window 对象,此属性为只读,只应用于Window 对象

四、DDE会话的有关方法

▲LinkSend         (方法)

在一次 DDE 对话中将 PictureBox 控件的内容传输到的接收端应用程序。

▲LinkExecute String (方法)

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.Print Application.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.本示例建立一个 Microsoft Excel 的 DDE 链接,将一些值放置到一个新工作单的第一行的单元里,并按照这些值画图。 LinkExecute 向 Microsoft Excel 发送激活工作单的命令,选择一些值并按照它们画图。

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

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 = "R1C1Then

            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 的工作单,在第一列中放入一些数据。

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

 

【例】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:\WINDOWS\CALC.EXE建立快捷方式

txtLnk.LinkExecute "[AddItem(""C:\WINDOWS\CALC.EXE"",""计算器"" )]"

将快捷方式移至桌面

sProgramsPath = sProgramsPath & "\计算器.lnk"

sDesktopPath = sDesktopPath & "\计算器.lnk"

FileCopy sProgramsPath, sDesktopPath

Kill sProgramsPath

End Sub

以上在Windows98ME + VB5VB6通过。

 

【例】用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  ‘CmdStrDDE程序传送过来的参数

  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

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多