DDE - Dynamic Data Exchange

by Ian Roberts

A requirement of a VB3 development I was working on recently was to set up an interface to allow another program, being developed interstate, to retrieve information and to invoke a form within my app. As it turned out the company responsible for creating the external app hired a talented VB programmer at their end, Peter Wone from GUI. Not surprisingly, we didn't have any trouble understanding each other and what we required, of course no one else understood us but as long as they got what they wanted they left us alone.

Peter and I discussed a number of approaches and finally decided on DDE, and setting up the interface to be almost API in appearance. We also convinced the two companies that it would be an advantage to have the two of us together to get the quickest and most reliable results. Once Peter arrived in Melbourne and we began to look at what was required we found that we had a problem, his app needed an information feed from yet another app that he had running in Sydney. Our clients, now thinking that they have just wasted one of the four remaining days of the project, were a little worried. "It's OK, we will just define an interface and build a test harness to test it. When I get back to Sydney I can implement the link via the defined interface. No problem.", was the cool response from Wone.

Setting up the DDE link in my app involved placing a label on the main form and setting the following properties of that form:

  LinkMode = 1 - Source
  LinkTopic = "frmMain"
We then placed a label on the form, set its name to lblDDELink, and placed the following call into the change event.
  Call BackChat(vsAWK, lblDDELink)
From the above call you may notice we used the Awk control from VS/VBX. This allowed us to set up painless expression parsing (i.e. we didn't need to code it ourselves).

In the DDECOMMS.BAS module we placed the BackChat routine. The following code is only an example skeleton.

  Sub BackChat (Awk As VideoSoftAwk, lbl As Label)
    Dim s As String
    Dim sAccnt As String
    Dim flgOK As Integer
    Dim OldFS As String
    Dim Verb As String
    Static OrderNumber As String
    Static flagGate%, i%

    If flagGate Then Exit Sub                     ' this flag is to avoid code re-entrance

    Let flagGate = True                 
    Let Awk.L = Trim$(lbl.Caption)
    Let OldFS = Awk.FS
    Let Awk.FS = "|"
    Let Verb = UCase$(Awk.F(1))
    Select Case Verb
      ' To retrieve information
      Case "GET DATA"                             ' The calling app passes this command 

        ' write Access username
        If trim$(gstrCliName) = "" then           ' Check to see if the data is valid
	  Let lbl.Caption = "NOT AVAILABLE"       ' return message to show no valid data
	  Let lbl.Caption = gstrCliName           ' then return valid data
        End If
      ' To pass a value
      Case "SET VALUE"                            ' passed as (SET VALUE|1234)
        Let OrderNumber = Trim$(Awk.F(2)) 
        Let lbl.Caption = "OK"
      ' this command allowed us to request a particular form to be shown
      Case "SHOW FORM"

        ' open order window
        ' preload form with passed data in OrderNumber
        ' do any validation and place result in the flgOK

	If flgOK Then
          Let glfShowForm = True
          Let lbl.Caption = "OK"
          Let lbl.Caption = "NOT OK"
        End If
        Case "GET COMMAND SET"

          ' write Access username
          Let lbl.Caption = "GET DATA| SET VALUE|SHOW FORM"
        Case Else
        ' No Action

    End Select
    Let Awk.FS = OldFS
    Let flagGate = False

  End Sub

While looking at the above code you may notice that we didn't do a show in the SHOW FORM command. We found that if we did this, the DDE link wouldn't return to the calling app and would cause an error. So we set up a global variable (glfShowForm) which by default is false. A timer control was already being used to update a clock so we added a test to see if our variable got set to true. This allowed the DDE link to complete its conversation and the timer to show the form. The code added to the timer was as simple as

  If glfShowOrder Then frmOrder.Show 1
All that remained was to build a DDE test app. First as with almost any VB app we started with a form then added some controls and code. The form and code are supplied below. To use the test app set the
  LinkTopic = {exe name off the application}|frmMain
  LinkItem = lblDDELink
  LinkTimeOut = 50
  Command=???                                     ' GET  DATA, SET VALUE or GET COMMAND SET 
The key press event of the command text box will fire the DDE link and the result will be displayed in lblReceived.

  Option Explicit

  Sub Form_Load ()

    awk.fs = "|"

  End Sub

  Sub lblReceived_Change ()

    Static flagGate%
    Dim nFields As Integer
    Dim i As Integer
    Dim sCaption As String

    If flagGate Then Exit Sub
    flagGate = True

    Awk.L = Trim$(lblReceived)
    nFields = Awk.NF

    sCaption = Trim$(Awk.F(1))
    If nFields > 1 Then
      For i = 2 To nFields
        sCaption = sCaption & Chr$(13) & Chr$(10) & Trim$(Awk.F(i))
      Next i

    End If
    lblReceived = sCaption
    flagGate = False
  End Sub

  Sub txtCommand_KeyPress (KeyAscii As Integer)
  On Error GoTo Err_txtCommand_KeyPress

    If KeyAscii = 13 Then
      Let lblReceived.LinkTopic = Trim$(txtLinkTopic.Text)
      Let lblReceived.LinkItem = Trim$(txtLinkItem.Text)
      Let lblReceived.LinkTimeout = CInt(txtTimeout.Text)
      Let lblReceived.LinkMode = 2 '- Manual
      Let lblSent.Caption = txtCommand.Text
      Let lblReceived.Caption = txtCommand.Text
    End If

    Exit Sub

    MsgBox Error$, 48, "DDE Test Harness"
    Resume Exit_txtCommand_KeyPress

  End Sub

  Sub txtTimeout_KeyPress (KeyAscii As Integer)
  Select Case KeyAscii
    Case 8, 9
      'No action
    Case 48 To 57 '0-9
      'No action

    Case Else
      Let KeyAscii = 0

  End Select
  End Sub

Written by: Ian Roberts
Feb 1996