Dynamic data exchange (DDE) is a mechanism supported by Microsoft applications in Windows and on the Macintosh that enables two applications to "talk" to each other. DDE automates the manual cutting and pasting of information between applications, providing a faster vehicle for updating information.
More specifically, DDE provides three capabilities:
Note
Not all applications support DDE. Consult the documentation for your other applications to see if they support DDE.
Two applications exchange information by engaging in a DDE conversation. In a DDE conversation, the application that initiates and controls the conversation is the client and the application that responds is the server. The client application requests information from the server and sends information and commands to it. The server application, as its name implies, serves the needs of the client application by returning information, accepting information, and carrying out commands. There is nothing special about an application that makes it a client or a server; these are simply roles an application can adopt. In fact, an application can be engaged in several DDE conversations at the same time, acting as the client in some and the server in others. Each conversation is identified by a separate channel number.
When a client application begins a DDE conversation, it must specify two things:
When a server application receives a request for a conversation concerning a topic it recognizes, it responds and the conversation is started. Once established, a conversation cannot change applications or topics. The combination of application and topic uniquely identifies the conversation, and the combination remains constant for the duration of the conversation. If either the client or the server changes the application or the topic, the conversation is terminated.
During the conversation, the client and server may exchange information concerning one or more items. An item is a reference to data that is meaningful to the server application. Either the client or the server can change the item during the conversation.
Together, the application name, topic, and item uniquely identify the information that is being passed between the applications. Each of these is discussed in detail in the sections that follow.
Every application that supports DDE has a unique DDE application name. The following are application names for some Microsoft applications.
Application | DDE application name |
Microsoft Access | MSAccess |
Microsoft Excel for Windows | Excel |
Microsoft Excel for the Macintosh | Excel |
Microsoft FoxPro® for Windows | FoxPro |
Microsoft Project for Windows | WinProj |
Microsoft Project for the Macintosh | MSProject |
Microsoft Word for Windows | WinWord |
Microsoft Word for the Macintosh | MSWord or WinWord |
Microsoft Windows 3.x Program Manager | ProgMan |
In Windows, the application name of an application is usually, but not always, the name of the executable file for that application without the .EXE filename extension. If you're not sure what the DDE application name for an application is, check the application's documentation. Application names are not case-sensitive.
Note
Visual FoxPro™ 3.0 can act as both a server and a client to send data to and receive data from other applications such as Word. For more information see "DDE Functions" in Microsoft Visual FoxPro Help.
Every DDE conversation is with both a server application and a topic the server application supports. Most applications support the names of open files as topics. Some possible topics are a Microsoft Excel worksheet (for example, "DAILYORD.XLS"), a Word document (for example, "SALESREP.DOC"), or an object in a Microsoft Access database (for example, "NORTHWIND.MDB;TABLE Shippers").
A special topic that many applications recognize is "System." Unlike other topics, which may or may not be available depending on whether a file is open, the System topic is always available and provides a list of the other topics that are currently available as well as other information about the application.
With the server's application name and a topic name, a client can initiate a DDE conversation. But for a client to exchange information with the server, one other essential piece of information is needed: the items available in the topic of the DDE conversation. An item is a kind of subtopic that identifies the information actually being exchanged during the DDE conversation. For example, Microsoft Excel recognizes cell references (such as R1C1) as items in a conversation. In Word, a bookmark is an item. Microsoft Access recognizes several items, including SQL statements.
A key requirement for a DDE conversation is that both applications be running. If an application isn't running, a client can't initiate a DDE conversation with it. For that reason, a macro that initiates a DDE conversation usually includes instructions that carry out the following three steps:
1. Determine whether the application you want to talk to is running
2. Start the application if it isn't already running
3. Initiate the DDE conversation
You can use the AppIsRunning() function to determine whether an application is running. Here is the syntax:
AppIsRunning(Title$)
In Windows, Title$ is the name of the application as it appears in the title bar of the application window (Title$ also appears in the Task List). For example, to determine if Microsoft Excel is running, you can use the following instruction:
status = AppIsRunning("Microsoft Excel")
Note that the Title$ is not the same as the DDE application name. Word does not generate an error if you specify the wrong name for an AppIsRunning() instruction, but the instruction will give unexpected results.
On the Macintosh, Title$ is the application name. You can also use the MacID$() function to specify an application's signature instead of the application name. For example:
status = AppIsRunning(MacID$("XCEL"))
Note
In Windows, when a document window is maximized, the document window name is included in the title bar of the application window, but you don't have to specify the document window part of the title. For example, if Microsoft Excel is running and "BUDGET.XLS" is opened in a maximized document window, the application window title is "Microsoft Excel - BUDGET.XLS." But you can specify just "Microsoft Excel" for Title$.
If the server application is not running, you can use the Shell statement to start it. Here is the syntax:
Shell Application$ [, WindowStyle]
Application$ must be the actual application filename. For example, "EXCEL.EXE" is acceptable in Windows; on the Macintosh, "Microsoft Excel" is accepted. In Windows, the optional WindowStyle argument specifies how the application window is displayed (for example, as an icon or a maximized window); on the Macintosh, WindowStyle specifies whether the application should be activated. If the application you want to start is not in the current folder, or not on a path recognized by the operating system, you must specify the path as well as the filename. Here is a Windows example:
Shell "C:\EXCEL\EXCEL.EXE", 0 'Start Excel minimized
Here is the same example on the Macintosh:
Shell "HD1:EXCEL:Microsoft Excel", 0 'Start Excel and activate
On the Macintosh, it's a good idea to use the MacID$() function to specify an application signature rather than a specific application filename, since it isn't uncommon for Macintosh users to change application filenames. The application signature provided by MacID$() ensures that the Shell statement will run the specified application, regardless of the filename. Here is an example:
Shell MacID$("XCEL"), 0
To open a document at the same time you start the application, you can specify a document filename with the application filename or just the document filename, assuming the operating system can associate the filename with the application you want to start. Here is a Windows example:
Shell "C:\EXCEL\EXAMPLES\BUDGET.XLS", 0
Here is the same example on the Macintosh:
Shell "HD1:EXCEL:My Budget", 0
Here's how you might use AppIsRunning() and Shell together in Windows:
If AppIsRunning("Microsoft Excel") = 0 Then Shell "EXCEL.EXE", 0
In Windows, the AppIsRunning() instruction is necessary because with most applications, Shell starts a second instance of the application if one instance is already running — not usually the effect you want. On the Macintosh, Shell does not start a second instance of an application. If the application is already running, Shell either activates it or has no effect, depending on the value of the WindowStyle argument. Here's an example:
Shell MacID$("XCEL"), 4
The WindowStyle argument of 4 specifies that Microsoft Excel is not to be activated; if Microsoft Excel is already running, this instruction has no effect.
Note
In Word version 6.0 for Windows NT and Word version 7.0, you cannot depend on a program started with Shell to be finished loading before the instructions following the Shell statement in your macro are run. A DDEInitiate instruction that tries to communicate with an application that has not finished loading will generate errors. To avoid this problem, you can use a For...Next loop to delay the DDEInitiate instruction until the other application is loaded. For example:
If AppIsRunning("Microsoft Access") = 0 Then
Shell "MSACCESS.EXE", 0 For i = 1 To 2000 x = i Next i End If chan = DDEInitiate("MSAccess", "System")
When you have established that the application you want to talk to is running, you are ready to initiate a DDE conversation with DDEInitiate(). Here is the syntax:
DDEInitiate(Application$, Topic$)
Application$ is the DDE application name of the application you want to initiate a conversation with. Topic$ is the name of a topic the application currently supports. For example, the following instruction initiates a conversation with Microsoft Excel for Windows or Microsoft Excel for the Macintosh on the System topic:
chan = DDEInitiate("Excel", "System")
If DDEInitiate() is successful in initiating a conversation with the specified server application and topic, it returns a channel number. You use this channel number as an argument in other DDE statements and functions to refer to this DDE conversation.
An error occurs if the application isn't running or if the application doesn't recognize the topic. For example, if you specify "SALES.XLS" as the topic, but SALES.XLS isn't open, an error is generated.
Once you have initiated a conversation with another application, you can use the DDERequest$() function to obtain information from an item within the specified topic. Here is the syntax:
DDERequest$(ChanNum, Item$)
ChanNum is the number of a channel returned by the DDEInitiate() instruction. Item$ is an item supported by the topic of the DDE conversation.
You can use DDERequest$() to query the System topic in Microsoft Excel to get a list of the currently supported topics, as shown in the following Windows example:
If AppIsRunning("Microsoft Excel") = 0 Then Shell "EXCEL.EXE", 4 chan = DDEInitiate("Excel", "System") topics$ = DDERequest$(chan, "Topics")
Here is the same example on the Macintosh:
If AppIsRunning(MacID$("XCEL")) = 0 Then Shell MacID$("XCEL"), 4 chan = DDEInitiate("Excel", "System") topics$ = DDERequest$(chan, "Topics")
"Topics" is an item in the System topic that lists all the topics currently available. You can add an Insert instruction such as the following:
Insert topics$
This instruction inserts the list of topics in a document.
Topic names are separated by tab marks. In this example, [SALES.XLS]Sales Report and [SAMPLES.XLS]Amortization Table are the names of Microsoft Excel worksheets that can be accessed as topics in DDE conversations.
If the specified channel number doesn't refer to an active DDE conversation, DDERequest$() generates an error. You'll also get an error if the specified item is not recognized by the other application.
Note that since DDERequest$() is a string function, information is always returned to the Word macro in the form of a string. For an example that retrieves information from a range of cells in Microsoft Excel, see "Using Microsoft Excel as a Server" later in this chapter.
You can use InStr() to determine whether a file is currently open. The following Windows example determines if SALES.XLS is an available DDE topic (the file is open):
If AppIsRunning("Microsoft Excel") = 0 Then Shell "EXCEL.EXE", 4 chan = DDEInitiate("Excel", "System") topics$ = DDERequest$(chan, "Topics") If InStr(topics$, "SALES.XLS") <> 0 Then Print "File is Open" End If
Although the client in a DDE conversation usually obtains information from the server, the client can supply information to the server as well. To do so, you use the DDEPoke statement. Here is the syntax:
DDEPoke ChanNum, Item$, Data$
ChanNum is the channel number returned by the DDEInitiate() instruction that began the DDE conversation. Item$ is the name of an item supported by the topic of the DDE conversation. Data$ is the information — in the form of a string — that you want to "poke" (or insert) into the item. To send a number, you must first convert it into a string.
The following example pokes the numeric value 100 into the first cell of the Microsoft Excel worksheet that is the topic of the DDE conversation. The Str$() function is used to convert the value into a string:
DDEPoke chan1, "R1C1", Str$(100)
You can use the DDEExecute statement to send a command recognized by the server application:
DDEExecute ChanNum, Command$
ChanNum is the channel number returned by the DDEInitiate() instruction that began the DDE conversation. In Microsoft Excel and many other applications that support DDE, Command$ is a statement or function in the application's macro language. For example, in Microsoft Excel the XLM macro statement that creates a new worksheet is NEW(1). (Microsoft Excel does not accept Visual Basic instructions through DDE.) To send the same command through a DDE channel, you would use the following instruction:
DDEExecute chan1, "[NEW(1)]"
Many applications, including Microsoft Excel, require that each command received through a DDE channel be enclosed in brackets. You can use a single DDEExecute instruction to send more than one command, with each command enclosed in brackets. For example, the following instruction tells Microsoft Excel to open and then close a worksheet:
DDEExecute chan1, "[NEW(1)][FILE.CLOSE(0)]"
Note that there must be no spaces between bracketed commands in a single DDEExecute instruction; otherwise, an error will occur. The preceding instruction is equivalent to the following two instructions:
DDEExecute chan1, "[NEW(1)]" DDEExecute chan1, "[FILE.CLOSE(0)]"
Many commands require arguments in the form of strings enclosed in quotation marks. Because the quotation mark indicates the beginning and end of a string in WordBasic, you must use Chr$(34) to include a quotation mark in a command string. For example, to send the Microsoft Excel macro instruction OPEN("SALES.XLS"), you would use the following instruction:
DDEExecute chan1, "[OPEN(" + Chr$(34) + "SALES.XLS" + Chr$(34) + ")]"
DDE channels are not closed automatically until you exit Word. If you don't close a channel, it remains open, even after the macro has ended. Because each channel uses some system resources, you should always close channels when you no longer need them. You terminate a DDE conversation with DDETerminate. Here is the syntax:
DDETerminate ChanNum
ChanNum is the channel number returned by the DDEInitiate() instruction that began the conversation.
When you close Word, it automatically terminates all active DDE conversations. However, you might want to terminate all conversations without closing Word. To do so, you could use several consecutive DDETerminate statements or a loop. However, WordBasic provides DDETerminateAll as a shortcut. DDETerminateAll terminates all active DDE conversations that Word has initiated (it does not terminate DDE conversations that another application may have initiated with Word as the server). If you are debugging a macro that performs DDE and are often interrupting and restarting the macro, it's a good idea to use DDETerminateAll periodically to close any channels you may have inadvertently left open.
Here are some points to keep in mind about DDE conversations with Microsoft Excel:
Item | Description |
SysItems | Provides a list of the items in the System topic |
Topics | Provides a list of the currently valid topics, including all open documents |
Item | Description |
Status | Indicates whether Microsoft Excel is ready to receive DDE messages ("Busy" or "Ready") |
Formats | Provides the list of formats supported |
Selection | Indicates the currently selected cell or range of cells |
Protocols | Not applicable |
EditEnvItems | Not applicable |
Microsoft Excel does not accept Visual Basic instructions through a DDE channel. However, you can send an XLM macro command to run an available XLM macro or Visual Basic procedure. For example, the following instruction runs a Visual Basic procedure called FormatCells stored in a module called VBAMacros:
DDEExecute chan, "[run(" + Chr$(34) + "VBAMacros!FormatCells" + \ Chr$(34) + ")]"
The following example initiates a DDE conversation with SALES.XLS (a sample workbook supplied with Microsoft Excel), requests some sales figures, and inserts them into a Word document:
chan = DDEInitiate("Excel", "[SALES.XLS]Sales Report") figures$ = DDERequest$(chan, "R4C2:R8C4") Insert figures$ DDETerminate chan
You could also use a name defined in Microsoft Excel to refer to the cell range R4C2:R8C3. For example, if the cells were defined with the name "JanuarySales," you could use the following instruction:
figures$ = DDERequest$(chan, "JanuarySales")
Note that when the figures are inserted into Word, each cell is delimited by a tab character and each row by a paragraph mark, as shown in the following illustration. A paragraph mark is inserted after the last row in Windows, but not on the Macintosh.
Since DDERequest() returns the figures as a string, they lose any formatting that was applied in Microsoft Excel. Instead, they acquire the formatting of the paragraph in which the insertion point is located in Word.
You can use the following instructions to have the preceding macro select the figures after it inserts them and convert them into a table. The first instruction creates a temporary bookmark at the location where the figures from Microsoft Excel will be inserted. The remaining instructions select the figures and convert them into a table.
CopyBookmark "\Sel", "temp" Insert figures$ ExtendSelection EditGoTo "temp" TableInsertTable .ConvertFrom = 1
Note that you cannot have the macro pour the figures into the selected cells of an existing table, as you can when you use the Paste command (Edit menu) to copy cells from Microsoft Excel using the Clipboard.
Microsoft Access version 7.0 provides a wide variety of topics to allow you to access tables and queries. You can also send SQL statements to a database and launch macros. For information on the topics and items supported, see the Microsoft Access Help topic "Using Microsoft Access as a DDE Server."
Here are some other points to keep in mind when using Microsoft Access as a server:
Item | Description |
SysItems | Provides a list of the items in the System topic |
Topics | Provides a list of all open databases |
Status | Indicates whether Microsoft Access is ready to receive DDE messages ("Busy" or "Ready") |
Formats | Provides a list of formats Microsoft Access can copy to the Clipboard |
The following example inserts the contents of the Shippers table into a Word document. The Shippers table is a table in the NORTHWIND.MDB sample database included with Microsoft Access version 7.0. Note that Microsoft Access has its own internal syntax for specifying a table in a database as a topic, and this differs from the syntax used to specify a worksheet in Microsoft Excel, for example. This syntax is described in the Microsoft Access Help topic "Using Microsoft Access as a DDE Server."
Sub MAIN chan1 = DDEInitiate("MSAccess", "System") DDEExecute chan1, "[OpenDatabase C:\MSOffice\Access\Samples\NORTHWIND.MDB]" chan2 = DDEInitiate("MSAccess", "NORTHWIND;TABLE Shippers ") figures$ = DDERequest$(chan2, "All") Insert figures$ DDETerminateAll End Sub
As with figures imported from Microsoft Excel worksheets, fields are separated by tab characters and records by paragraph marks (although the last record does not end with a paragraph mark).
You can also access queries in a Microsoft Access database using the Query topic. For example:
chan = DDEInitiate("MSAccess", "NORTHWIND;QUERY Ten Most Expensive Products")
The following example sends an SQL statement to the NORTHWIND database to return a list of customers stored in the database:
Sub MAIN chan1 = DDEInitiate("MSAccess", "System") DDEExecute chan1, "[OpenDatabase C:\MSOffice\Access\Samples\NORTHWIND.MDB]"chan2 = DDEInitiate("MSAccess", "NORTHWIND;SQL SELECT DISTINCTROW" + \ " Customers.CompanyName FROM Customers" + \ " ORDER BY Customers.CompanyName;") list$ = DDERequest$(chan2, "Data") Insert list$ DDETerminateAll End Sub
An easy way to create SQL statements is to first create the query in Microsoft Access, and then copy the SQL statement into your Word macro. To see the SQL statement for a query in Microsoft Access, open the query in Design mode and choose SQL from the View menu to display the SQL dialog box.
So far, this chapter has described Word as the client application, but Word can also be used as a DDE server. Here are some points to keep in mind when using Word as a server:
Item | Description |
SysItems | Provides a list of the items in the System topic |
Topics | Provides a list of the currently valid topics, including all open documents |
Formats | Provides a list of all the Clipboard formats supported by Word |
DDEExecute chan%, "[FileOpen ""JOE.DOC""][FileOpen ""REPORT.DOC""]"
Note that each WordBasic instruction is enclosed in brackets and that you can send more than one WordBasic instruction with a single Visual Basic DDEExecute instruction. Visual Basic uses a pair of quotation marks to indicate one quotation mark within a string.
You can also send macro names to have Word start a macro. For example, the following Visual Basic instruction runs the Word macro SortHeadings:
DDEExecute chan%, "[SortHeadings]"
Do not send instructions that display dialog boxes in Word — Word will not become the active application window, and the DDE conversation will time out, waiting for the user to respond to the dialog box.
The following Microsoft Excel procedure opens a Word document, retrieves the text marked by a bookmark, and places it in a series of cells in a worksheet. First it defines returnlist as an object variable equivalent to six cells. Then it opens a DDE channel to the Word System topic and uses the DDEExecute method to send the WordBasic instruction FileOpen "TEST.DOC". Note that the instruction is enclosed in brackets and that "TEST.DOC" is enclosed in pairs of quotation marks, which Visual Basic uses to indicate quotation marks within a string. Once TEST.DOC is open, the macro closes the DDE channel to the System topic and opens a new one to the TEST.DOC topic. Finally, it uses the DDERequest method to request the text marked by the bookmark "listitems," which is returned to the object variable returnlist.
Sub ReturnWordBookmarkText() Dim returnList As Object Set returnList = ActiveSheet.Range(Cells(1, 1), Cells(6, 1)) channelNumber = Application.DDEInitiate("WinWord", "System") Application.DDEExecute channelNumber, "[FileOpen ""TEST.DOC""]" Application.DDETerminate channelNumber channelNumber = Application.DDEInitiate("WinWord", "TEST.DOC") returnList.value = Application.DDERequest(channelNumber, "listitems") Application.DDETerminate channelNumber End Sub
The following WordBasic macro establishes a DDE conversation with the same instance of Word and displays a message box, such as the one that follows, showing the list of currently valid topics. The While¼Wend loop replaces the tab characters between topics with paragraph marks so that the list is easier to read. Note that a WordBasic message box cannot display more than 255 characters, so the macro displays a message if the list of topics is too long.
Sub MAIN chan = DDEInitiate("winword", "system") topics$ = DDERequest$(chan, "topics") tab$ = Chr$(9) para$ = Chr$(13) While InStr(topics$, tab$) tab = InStr(topics$, tab$) leftside$ = Left$(topics$, tab - 1) rightside$ = Right$(topics$, Len(topics$) - tab) topics$ = leftside$ + para$ + rightside$ Wend msg$ = "The topics available are: " + para$ + para$ + topics$ If Len(msg$) > 255 Then MsgBox "Sorry, the list of topics is too long to display " + \ "in a message box. (255 characters is the maximum.)" Else MsgBox msg$, "Word DDE Topics" End If DDETerminate chan End Sub