AnsweredAssumed Answered

VRF-VEE_DDE

Question asked by VRFuser on Jul 2, 1996
from: Greg Goebel / HP-MXD
      gvg@lvld.hp.com / 970-679-2305 / FAX 970-679-5971
to:   VRf
date: Wednesday, 03 July 1996 1406 MDT

Hi All:

This is all the notes on DDE I have for VEE.  Using VEE as a client is simple
enough, but trying to figure out what the remote server is doing is like
working on a ship in a bottle (and DDE was enough of a dud so that most
applications don't document it if they support it at all).

As experiences go, DDE has not been one of my favorites.

[%%] regards -- gvg


[X.3] DDE & VEE For Windows

* Dynamic Data Exchange, or DDE, is a scheme that allows different MS-Windows
applications to communicate with each other; it defines a protocol that allows
one application to open a "channel" or "link" to another application; transfer
data with that application; ask the application to execute a command; and then
close the link to that application.

In DDE, an application can act as either a "client" or a "server".  A client
application can open a link, send commands and data to another application, and
read data back from that application.   A server application, on the other
hand, passively receives the open link, accepts the commands sent to it and
interprets them, and accepts or provides data through the link.

You can think of a client and server as analogous to a "terminal" and a "host
computer".  A computer terminal can be used to connect ("log in") to a host
computer, send commands to that host, and transfer data to and from the host;
the terminal is a "client" to the host computer.  The host computer simply
accepts the terminal input and provides the appropriate output; the host is a
"server" to the terminal.

Of course, a terminal and a host computer are both hardware devices, while a
DDE client and server are simply Windows software applications; but the
concepts are similar, if the details are different.  An application may have
the capability of being both a client and a server, though it is unusual for
one to operate as both at the same time.

A standard DDE client supports five basic operations:

   Open:             Open the link to the server.
   Execute:          Send a command for the server to execute.
   Peek (Request):   Read a data item from the server.
   Poke:             Send a data item to the server.
   Close:            Close the link to the server.

Different client applications may have different names for these functions,
but the same functionality will still be there.

* However, to be able to use these five functions, you have to know some
things about the server application -- for example, it's very difficult to
open a link to a server application without knowing the name of the
application.  And that's where the problems with DDE arise.

To perform DDE communications -- or, in DDE terms, to have a "conversation" --
you need to have the following information about the server application:

   Application name   ! Just the name of the application.
   Data topic         ! Defines the item of interest in the application.
   Data item          ! The actual item of concern.

You will need the application name (usually just the executable file name of
the application) and the data topic (often a file name -- but data topic
definitions vary all over the map) to open a link to a server application; you
will then need the data item (which is often a variable name -- but can be also
defined in a wide variety of ways) to peek or poke data to it.  Data and
commands are generally transferred in text format by convention.

For example, if a client program wants to access an Excel spreadsheet, the
three parameters would be like:

   Application name   ! Always "Excel".
   Data topic         ! A worksheet name (like "Sheet1" or "Chart1").
   Data item          ! A spreadsheet cell (like "R3C4").

But these definitions are strictly for Excel.  The problem with DDE is not
setting up the link -- that's extremely simple; the problem is figuring out
what the server application uses for topics and items.  This is strictly up
to the application, and the application designers can implement it any way
they like -- or not implement it at all.  To put it bluntly:

% Not all applications have DDE capability.  For example, most of the
   standard Windows applications -- Paint, Clipboard, Terminal, and so on --
   cannot act as either DDE clients or servers.

% You cannot assume any particular DDE server commands or syntax; simply
   trying to guess commands and sending them to a server will get you nowhere.
   You must know what the server application thinks its data topics and data
   items are -- and this information must be provided by the application
   vendor.

   Attempting to set up a DDE conversation without knowing what commands the
   server understands is like trying to build a ship in a bottle -- using a
   black bottle.

The fact that if you get any error on the server side it simply breaks the
DDE connection makes debugging DDE conversations somewhat difficult.  It will
be less difficult if you have a good knowledge of the server's behavior.

* VEEWIN has DDE capabilities through its To/From DDE object.  Using DDE, a
user can, for example, let a VEEWIN program access another application -- in
which case VEEWIN is acting as a client; VEEWIN *cannot* act as a server.

This appendix discusses how to use VEEWIN's To/From DDE object.  However,
the operation of the client -- what commands are sent to it and how it
responds -- are the responsibility of those who make the client product; this
is the harder part of the task and its behavior is beyond our knowledge.

Unfortunately, DDE is now being phased out by Microsoft in favor of OLE
(object linking & embedding) and support for DDE by most vendors is being
swiftly abandoned.  For this fact and the unfortunate reality that DDE was
never a very robust protocol to begin with, we discourage its use:  it's not a
good solution and it has no future.

[%%]


[X3.1] USING THE VEEWIN DDE OBJECT -- PRINCIPLES 

* To perform DDE client operations in VEEWIN, you use a type of VEEWIN
"transaction object" called a "To/From DDE" object, or, more simply, a "DDE
object".  This section shows how to use the DDE object ... note that the
examples used are just to show you the basic techiniques involved for using
the object -- they're of no practical use whatsoever.  We'll get to more
practical details in the next section.

You select the DDE object from the VEEWIN "I/O" menu:

    Device  I/O  Data  Math
  -+----------------------------+-
   |  VXIplug&play Instruments >|
   |  Other Instruments         |
   |  Advanced I/O             >|
   |  Bus I/O Monitor           |
   |  ID Monitor                |
   +----------------------------+
   |  To                       >|
   |  From                     >|
   |  To/From Named Pipe (UNIX) |
   |  To/From Socket            |
   |  To/From DDE (PC)          |<-----
   |  HP BASIC/UX (UNIX)       >|
   |  Execute Program (UNIX)    |
   |  Execute Program (PC)      |
   +----------------------------+
   |  Print Screen              |
   +----------------------------+

-- and you get the object:

   +---------------------------------------------+
   |                  To/From DDE                |
   +---------------------------------------------+
   | Application:  [Excel                       ]|
   | Topic:        [Sheet1                      ]|
   +---------------------------------------------+
   |                                             |
   |                                             |
   |                                             |
   |                                             |
   |                                             |
   +---------------------------------------------+

Note that "Excel" and "Sheet1" are provided by default as a convenience -- DDE
to Excel is a common Windows application task.  Since you may not have Excel
on your system, we'll perform DDE to Windows Program Manager instead (since it
is standard with Windows and, unlike most of the standard Windows apps,
supports DDE).  So we enter the application name "Progman" and the data topic
name "progman":

   +---------------------------------------------+
   |                  To/From DDE                |
   +---------------------------------------------+
   | Application:  [ProgMan                     ]|
   | Topic:        [progman                     ]|
   +---------------------------------------------+
   |                                             |
   |                                             |
   |                                             |
   |                                             |
   |                                             |
   +---------------------------------------------+

Okay, what next?  Well, if you're not familiar with VEE transaction objects,
they perform a series of I/O transactions as defined by a list of transaction
commands in the object.

Right now this DDE object doesn't have any list items defined, but we can
fix that in a hurry -- just double-click on the empty list item (just below the
"Topic" entry in the object) and you get a dialog:

   +---------------------------------------------------------------------+
   |                          I/O Transaction                            |
   +---------------------------------------------------------------------+
   | [ READ (REQUEST) ] [ ITEM  ] [""    ] [ TEXT ] [x                 ] |
   | [   STRING FORMAT   ] [ DEFAULT NUMBER CHARS ]                      |
   | [  SCALAR  ]                                                        |
   |                                                                     |
   |                                                                     |
   |      [  OK  ]               [  NOP  ]               [ Cancel ]      |
   +---------------------------------------------------------------------+

This dialog defines the type of I/O transaction; the data items that will be
involved in the transfer; and the data format used.  The field labeled "READ
(REQUEST)" in the upper-left corner gives the type of transaction; click on
it and you'll get a list of the available transactions:

   +---------------------------------------------+
   |            Select DDE Action                |
   +----------+----------------------+-----------+
   |          | READ (REQUEST)       |           |
   |          | WRITE (POKE)         |           |
   |          | EXECUTE              |           |
   |          | WAIT                 |           |
   |          |                      |           |
   |          |                      |           |
   |          |                      |           |
   +----------+----------------------+-----------+
   | READ (REQUEST)                              |
   +---------------------------------------------+
   |      [  OK  ]               [ Cancel ]      |
   +---------------------------------------------+

This dialog gives the expected DDE transactions, plus a WAIT transaction --
which does just that:  it allows you to put a delay or WAIT in your list of
transactions.

* The astute reader will notice something's missing from the discussion up to
this point, however -- where are the transactions for opening and closing a
link?  Actually, they're missing for the simple reason that you don't need to
worry about them -- the DDE object opens the link when it's activated and
closes it again when it has completed its list of I/O transactions.

Anyway, to get started, let's use DDE to execute some Program Manager DDE
server command.  Select the EXECUTE transaction from the dialog above and you
get:

   +---------------------------------------------------------------------+
   |                          I/O Transaction                            |
   +---------------------------------------------------------------------+
   | [ EXECUTE ] [ COMMAND ] [""                                       ] |
   |                                                                     |
   |                                                                     |
   |                                                                     |
   |                                                                     |
   |      [  OK  ]               [  NOP  ]               [ Cancel ]      |
   +---------------------------------------------------------------------+

So now we can decide which Program Manager DDE server command we want to
execute ... which begs the question:  what commands does the Program Manager
DDE server support?

Microsoft documentation reveals the following Program Manager DDE server
commands:

   CreateGroup:          Create a Program Manager program group.
   ShowGroup:            Bring up a group in Program Manager.
   AddItem:              Add an item to the group.
   DeleteGroup:          Delete a Program Manager group.
   ExitProgram:          Exit Program manager.

Type the Program Manager server command to create a program group -- named,
say "DDETest" -- in the DDE output field of this dialog:

   | [ EXECUTE ] [ COMMAND ] ["[CreateGroup(DDE Test)]"                ] |

Remember -- "[CreateGroup(DDE Test)]" is a Program Manager DDE server command
and is understood only by Program Manager -- no other application is likely to
understand it.  VEEWIN doesn't know what it means; it's just a lousy string as
far as it's concerned.

Anyway, click on OK and you now have one entry in your DDE object:

   +---------------------------------------------+
   |                  To/From DDE                |
   +---------------------------------------------+
   | Application:  [ProgMan                     ]|
   | Topic:        [progman                     ]|
   +---------------------------------------------+
   |[EXECUTE CMND;"[CreateGroup(DDE Test)]"     ]|
   |                                             |
   |                                             |
   |                                             |
   |                                             |
   +---------------------------------------------+

* Next, Let's have Program Manager create a program item in this new group,
say the "sysedit" (system editor) application that is shipped with Windows.
Now you have to add another transaction to the list, so double-click on the
space below the first transaction to get a second one -- you get the
transaction dialog, so select EXECUTE again, and type in the Program Manager
server command "[AddItem(C:\windows\system\sysedit.exe)]".

Note the double backslashes ("\") in this command ... this isn't a typo,
the double backslashes must be used so that VEEWIN will not try to interpret
the backslash as part of a control code (since transaction objects interpret
"
" as a "newline", "e" as an "escape" code, and so on).

This done, you have your second transaction:

   +---------------------------------------------+
   |                 To/From DDE                 |
   +---------------------------------------------+
   | Application:  [ProgMan                     ]|
   | Topic:        [progman                     ]|
   +---------------------------------------------+
   | EXECUTE CMND;"[CreateGroup(DDE Test)]"      |
   |[EXECUTE CMND;"[AddItem(C:windowssyste  ]|
   |                                             |
   |                                             |
   |                                             |
   +---------------------------------------------+

* Now add another transaction -- this time, select a WAIT:

   +---------------------------------------------------------------------+
   |                          I/O Transaction                            |
   +---------------------------------------------------------------------+
   | [    WAIT    ] [ FOR INTERVAL (sec): ] [  3  ]                      |
   |                                                                     |
   |                                                                     |
   |                                                                     |
   |                                                                     |
   |      [  OK  ]               [  NOP  ]               [ Cancel ]      |
   +---------------------------------------------------------------------+

Set the WAIT to 3 seconds as shown, and click on OK; this gives you the next
transaction:

   +---------------------------------------------+
   |                  To/From DDE                |
   +---------------------------------------------+
   | Application:  [ProgMan                     ]|
   | Topic:        [progman                     ]|
   +---------------------------------------------+
   | EXECUTE CMND;"[CreateGroup(DDE Test)]"      |
   | EXECUTE CMND;"[AddItem(C:windowssyste   |
   | WAIT 3                                      |
   |                                             |
   |                                             |
   +---------------------------------------------+

* Finally, add another EXECUTE transaction to execute the Program Manager
server command "[DeleteGroup(DDE Test)"].  This completes our list of
transactions:

   +---------------------------------------------+
   |                  To/From DDE                |
   +---------------------------------------------+
   | Application:  [ProgMan                     ]|
   | Topic:        [progman                     ]|
   +---------------------------------------------+
   | EXECUTE CMND;"[CreateGroup(DDE Test)]"      |
   | EXECUTE CMND;"[AddItem(C:windowssyste   |
   | WAIT 3                                      |
   | EXECUTE CMND;"[DeleteGroup(DDE Test)]"      |
   |                                             |
   +---------------------------------------------+

* Now we can run our DDE test program.  First, make sure you set up the
Program Manager and VEEWIN windows so you can see them both at the same time;
then click on the VEEWIN RUN button.  The group "DDE Test" will appear in
Program Manager, with the "Sysedit" icon in it, survive for three seconds, and
then die.

Note that if you have an error -- say you spelled "DDE Test" in the last
transaction as "DDETest" -- VEEWIN will toss an error dialog in your face like
so:

   +-----------------------------+
   |        Error Message        |
   +-----------------------------+
   |                             |
   |     DDE EXECUTE failed      |
   |                             |
   |   In transaction number 4   |
   |  Object Title: To/From DDE  |
   |  Object Type:  To/From DDE  |
   |                             |
   |      Error number: 833      |
   +-----------------------------+
   |          [  OK  ]           |
   +-----------------------------+

Like I said before, don't expect to get much better error information than
this out of a DDE conversation ... send something to a server it doesn't
understand, it won't send back an error message, it just breaks the
conversation.

[%%]


[X3.2] USING THE VEEWIN DDE OBJECT -- IN PRACTICE 

* As noted, the example shown in the previous section is just to show how to
use the object ... it is of very little practical use.

In practice, you will want to use DDE to send information to another
application or to take information from that other application.  A popular
application for DDE is Microsoft Excel, so an example that communicates with
Excel should prove useful.  Let's write a VEEWIN program to, say:

% Write random data to a grid of spreadsheet cells.
% Take the sum of the random data.
% Create a graph of one column of the data.

This example assumes use of Excel 3.0.

The overall structure of the example program is shown below:

            +-------+
            | Start |
            +---+---+
                |
           +----+----+
           | formula |  <-- seed random-number generator
           +----+----+
                |
      +---------+---------+
      |     For Range     | <-- count spreadsheet rows
      +-------------------+
      | From [ 1        ] |         +---------------+      +-----------------+
      | Thru [ 16       ] +--+----->|r  To String   +----->|rc  To/From DDE  |
      | Step [ 1        ] |  |  +-->|c              |  +-->|rn               |
      +---------+---------+  |  |   +---------------+  |   +-----------------+
                |            |  |    convert row &     |    write random data
   +------------+            |  |    column numbers    |  to a spreadsheet cell
   |                         |  |   into spreadsheet   |
   |            +------------+  |     cell address     |
   |            |               |                      |
   |  +---------+---------+     +------------+         |
   |  |     For Range     |     |            |         |
   |  +-------------------+     |    +-------+-------+ |
   |  | From [ 1        ] |     |    | Random Number +-+
   |  | Thru [ 16       ] +-----+    +---------------+
   |  | Step [ 1        ] |           generate random
   |  +-------------------+           spreadsheet data
   |    count spreadsheet
   |     column address
   |
   +----------+              +----------------------+
              |              |     AlphaNumeric     |
      +-------+-------+      +----------------------+
      |  To/From DDE  +----->|                      |
      +---------------+      +----------------------+
     set up SUM formula      display spreadsheet sum
     in spreadsheet, get
     back sum, select a
    column and graphs it

Let's take a look at the overall functioning of this program before we get into
nitty-gritty details.

* The control flow through this program is straightfoward.  When you press the
Start button, the Formula object is first executed to seed the random-number
generator.  This Formula object contains the following formula:

   +---------------------------------------------------+
   |                     Formula                       |
   +------------------------------------------+--------+
   | [randomseed((10^9)*fracPart(now()/100))] | result |
   +------------------------------------------+--------+

Note that by default a Formula object is created with an input pin labeled
"A Any" ... this input pin is not needed and will cause a runtime error if
it's not connected to something, so when you create this formula object, just
move the mouse cursor over the input pin and press Ctrl-D to kill it off.

As mentioned elsewhere in this tutorial, this Formula object generates a
"randomseed" to allow generation of unpredictable random numbers, derived
from the current time in such a way that it varies widely between runs of the
program.

The Formula object sequence-out pin then triggers a For Range counter that
counts the number of spreadsheet rows; and each output of this row counter in
turn triggers another For Range counter that counts the number of spreadsheet
columns.

With each row-column count, a random number is generated and pumped, along
with the row-column number, into the To/From DDE object; the To/From DDE
object then uses DDE to write the random number to the appropriate spreadsheet
cell.  Note that the row-column column counts are processed through a To
String object ... why this is done will be explained presently.

Note also that the To/From DDE object only writes *one* random number at a
time, under the control of the row-column counters; it does not write the
entire grid of numbers at once.  Writing each of the numbers constitutes a
complete DDE transaction from Open to Close.  This is a somewhat slow way of
doing things, but then, DDE is slow to begin with.

* When the row-column count is completed, the row counter's sequence-out pin
fires and then triggers the second To/From DDE object -- which performs the
final DDE transactions.

% Write a SUM formula to the spreadsheet.
% Get the sum back.
% Select a column of data.
% Have the spreadsheet graph it.

An AlphaNumeric display object is used to display the spreadsheet sum.

* It may not be immediately obvious that the row counter's sequence-out pin
will fire only after the last column count has been completed ... it wasn't
obvious to me, until I talked to a pal in the lab who reminded me that an
object's sequence-out pin fires only after all the objects downstream of
it have done their thing.

* Okay, that describes the overall operation of the program; now for details.
Let's examine the critical elements of the program as though we were building
them from the ground up.

The To/From DDE object that writes random numbers to spreadsheet cells only
uses one transaction, a WRITE (POKE) transaction.  To make this object, you
create a To/From DDE object to get, as in the previous section:

   +---------------------------------------------+
   |                  To/From DDE                |
   +---------------------------------------------+
   | Application:  [Excel                       ]|
   | Topic:        [Sheet1                      ]|
   +---------------------------------------------+
   |                                             |
   |                                             |
   |                                             |
   |                                             |
   |                                             |
   +---------------------------------------------+

The application and data topic entries are just fine in this case; so now
you can click on the transaction field and selecte a WRITE (POKE) transaction:

   +---------------------------------------------------------------------+
   |                          I/O Transaction                            |
   +---------------------------------------------------------------------+
   | [ WRITE (POKE) ] [ ITEM ] [""   ] [ TEXT ] [x                     ] |
   | [     REAL FORMAT    ] [   FIELD WIDTH   ] [20  ] [ RIGHT JUSTIFY ] |
   | [ /- ] [ STANDARD ] [ ALL SIG DIGITS ] [ EOL ON ]                   |
   |                                                                     |
   |                                                                     |
   |      [  OK  ]               [  NOP  ]               [ Cancel ]      |
   +---------------------------------------------------------------------+

The ITEM field in this case tells Excel which cell (by row and column) to
write the random number to -- it will specify a string like "R1C3" or "R10C7".
In principle, you should be able to specify this cell address directly in the
ITEM parameter field, as follows:

   [ ITEM ] ["R",r,"C",c]

-- where the small "r" and "c" are input pins set up on the object that
provide the row and column number; if "r" had an input value of 5 and C had an
input value of 13, for example, you would get an ITEM value of "R5C13".

Unfortunately, this won't work, since (as of time of writing) there is a bug
in the ITEM parameter field of the To/From DDE object that prevents it from
correctly parsing its parameters.  No great problem -- you can just set up a
input pin called, say, "rc" and specify it as the ITEM parameter:

   [ ITEM ] [rc        ]

-- and then create the appropriate ITEM string with another object ... the To
String object performs this function in the program, as we'll show presently.

As far as the random number to be sent to the spreadsheet goes, you can set up
an input pin named, say, "rn" to accept the random number and specify that in
the output parameter field (which is tagged as a TEXT-type output):

   [ TEXT ] [rn                    ]

The other fields after that are correct -- we do want to send a REAL FORMAT
number -- except for the EOL ON field; click on that to toggle it to EOL OFF,
since we don't want to send a newline (line-feed character) after the string.
And then click on OK to get the transaction:

   [ WRITE ITEM:rc TEXT rn REAL STD     ]

Now this transaction uses the "rc" and "rn" input pins to generate its DDE
output.  There's a slight problem, however:  these pins don't exist by
default.

No problem; just move the mouse over the left margin of the To/From DDE object
and press Ctrl-A twice to add two pins; you get two input pins labeled "A Any"
and "B Any".  Then double-click on the "A Any" pin to get the dialog:

   +------------------------------------------------+
   |            Input Terminal Information          |
   +------------------------------------------------+
   | Name:  [   A   ]    Required Type:   [  Any  ] |
   | Mode:  [  Data ]    Required Shape:  [  Any  ] |
   |                                                |
   |              Container Information             |
   |                                                |
   | No data on input pin                           |
   |                                                |
   |        [   OK   ]             [ Cancel ]       |
   +------------------------------------------------+

Change the "name" field to "rc" and click on OK.  Change the "B Any" pin to
"rn" using the same technique and you get:

   +-------------------------------------------------+
   |                      To/From DDE                |
   +-----+-------------------------------------------+
   |     | Application:  [Excel                     ]|
   | rc  | Topic:        [Sheet1                    ]|
   | Any +-------------------------------------------+
   |     |[ WRITE ITEM:rc TEXT rn REAL STD          ]|
   |     |                                           |
   | rn  |                                           |
   | Any |                                           |
   |     |                                           |
   +-----+-------------------------------------------+

* This done -- now to handle creating the row-column address ITEM.  You can
synthesize the address string using a To String object; you select this off
the "I/O" menu's "To >" submenu, and get:

   +-----------------------------------------------------+
   |                      To String                      |
   +-----+--------------------------------------+--------+
   |     |[ WRITE TEXT a EOL                   ]|        |
   |     |                                      |        |
   |  A  |                                      | result |
   | Any |                                      |        |
   |     |                                      |        |
   |     |                                      |        |
   +-----+--------------------------------------+--------+

Click on the transaction field to get:

   +--------------------------------------------------------+
   |                   I/O Transaction                      |
   +--------------------------------------------------------+
   | [ WRITE ] [   TEXT   ] [a                       ]      |
   | [   DEFAULT FORMAT   ] [ EOL ON ]                      |
   |                                                        |
   |                                                        |
   |                                                        |
   |    [  OK  ]          [  NOP  ]           [ Cancel ]    |
   +--------------------------------------------------------+

OK, you should be able to figure out the drill by now:  change the parameter
field from "a" to:

   "R",r,"C",c

This splices the row and column counts (as given by the "r" and "c" input
pins) with the characters "R" and "C" to give the proper cell address field
required by Excel.  (As noted earlier ... you could have actually done this in
the To/From DDE object, except there was a bug in an earlier release.)

Next, change DEFAULT FORMAT to STRING FORMAT, and set DEFAULT FIELD WIDTH;
change EOL ON to EOL OFF, since you don't want to have newline characters on
the end of the cell address string, either.  This gives the transaction field:

   [WRITE TEXT "R",r,"C",c STR          ]

Of course, you need to set up the "r" and "c" input pins as well -- you do
this in exactly the same way that you set up the input pins on the To/From
DDE object; and once you do that, you end up with:

   +-----------------------------------------------------+
   |                      To String                      |
   +-----+--------------------------------------+--------+
   |     |[ WRITE TEXT "R",r,"C",c STR         ]|        |
   |  r  |                                      |        |
   | Any |                                      |        |
   |     |                                      | result |
   |     |                                      |        |
   |  c  |                                      |        |
   | Any |                                      |        |
   |     |                                      |        |
   +-----+--------------------------------------+--------+

Now you can use this object to take the row-column count from the counters
and feed the appropriate cell address string into the To/From DDE object.

* The last component to set up is a To/From DDE object to perform the
remaining DDE operations; bypassing a lot of arm-waving, the object ends up
looking like this:

   +-------------------------------------------------+
   |                  To/From DDE                    |
   +---------------------------------------------+---+
   | Application:  [Excel                       ]|   |
   | Topic:        [Sheet1                      ]|   |
   +---------------------------------------------+   |
   | WRITE ITEM:"R18C1" TEXT "=SUM(A1:H16)" STR  | s |
   | READ ITEM:"R18C1" TEXT s REAL               |   |
   | EXECUTE CMND;"[SELECT("R1C1:R16C1")]"     |   |
   | EXECUTE CMND;"[NEW(2)]"                     |   |
   |                                             |   |
   +---------------------------------------------+---+

These four transactions perform the following functions:

% The first puts the Excel formula "=SUM(A1:H16)" in cell R18C1 to sum all
   the numbers in the grid set up by the other part of the VEEWIN program.

% The second reads the sum value back from cell R18C1 and sends it
   to output pin "s" for display by the Alphanumeric object.  (You create an
   output pin by moving the mouse cursor over the right margin and pressing
   Ctrl-A; you can then modify the default name to "s" by double-clicking on
   it.)

% The third executes the Excel macro command "[SELECT("R1C1:R16C1"]" to
   select the cells in the first column of the grid.  (Note how """ is used
   to embed double-quotes inside a double-quoted string.)

% Finally, the fourth executes the Excel macro command "[NEW(2)]" to create
   a graph.

Note that Excel macro commands are documented as part of the Excel command
language and are not part of DDE as such, and are certainly not part of
VEEWIN.

* With the entire program fleshed out, you should (if you have Excel) try to
arrange both the Excel and VEEWIN user interfaces on the display so you can
see them simultaneously, set up a spreadsheet named "Sheet1" in Excel, and
then run the VEEWIN program.  It can be very amusing to watch the numbers
magically appear in the spreadsheet.

You can put some simple extensions in the program -- for example, suppose you
want to save the spreadsheet to a file -- in both normal and text format --
and save the graph to a file as well.

Let's say you want to save the spreadsheet as TEST.XLS, save its data in text
format as TEST.TXT, and save the graph as CHART.  All you have to do is add a
few transactions to the last To/From DDE object:

   +-------------------------------------------------+
   |                  To/From DDE                    |
   +---------------------------------------------+---+
   | Application:  [Excel                       ]|   |
   | Topic:        [Sheet1                      ]|   |
   +---------------------------------------------+   |
   | WRITE ITEM:"R18C1" TEXT "=SUM(A1:H16)" STR  | s |
   | READ ITEM:"R18C1" TEXT s REAL               |   |
   | EXECUTE CMND;"[SELECT("R1C1:R16C1")]"     |   |
   |[EXECUTE CMND;"[NEW(2)]"                  ]  |   |
   | EXECUTE CMND;"[ACTIVATE("Sheet1")]"       |   |
   | EXECUTE CMND;"[SAVE.AS("C:TEST",3)]"    |   |
   | EXECUTE CMND;"[SAVE.AS("C:TEST",1)]"    |   |
   | EXECUTE CMND;"[ACTIVATE("Chart1")]"       |   |
   | EXECUTE CMND;"[SAVE AS("J:CHART"]"      |   |
   |                                             |   |
   +---------------------------------------------+---+

The five added transactions perform the following actions:

  % The Excel macro command "[ACTIVATE("Sheet1")]" selects the
    spreadsheet.  Creating the chart leaves a graphics sheet and worksheet in
    Excel, so you have to make sure you activate the proper sheet before
    trying to save it.

  % The macro command "[SAVE.AS("C:\TEST",3)]" saves the spreadsheet
    as text (format 3) in the file TEST.TXT.  (The command automatically
    appends the proper extension.)

  % The macro command "[SAVE.AS("C:\TEST",1)]" saves the spreadsheet
    as a normal spreadsheet file (format 1) in the file TEST.XLS.

  % The macro command "[ACTIVATE("Chart1")]" selects the graph.

  % The macro command "[SAVE AS("J:\CHART"]" saves the graph in
    default format in the file CHART.XLC.

* As a realistic example, this is still somewhat limited, but it should be
enough to get you started, and a more complex example would be too big to
explain in a short article like this.

* A final reminder ... if you want to perform DDE to another Windows app,
remember that the app *must* have DDE server capability, and you *must*
know what commands the app supports as a DDE server.  It is very easy to use
VEEWIN as a DDE client; the problems you will have will be figuring out what's
happening on the server end, and the fact that you don't get much error
feedback other than what amounts to "It Didn't Work" doesn't help.

[<>]

Outcomes