DDEInitiate(), DDETerminate(), DDEAbortTrans(), DDEPoke(), DDERequest(), DDEExecute(), DDELastError(), DDESetOption(), DDEAdvise(), DDEEnabled(), DDESetService(), DDESetTopic()
Despite all the hoopla you've heard about the wonders of OLE, COM and ActiveX, Dynamic Data Exchange—one of COM's forebears—is not yet dead. Getting on in years, yes. Dead, no, not just yet.In most cases, we prefer to use the COM technologies when developing communications between applications. COM communications are more robust, support richer data types, and are more easily integrated into an OOP environment. But it takes two to tango. If the application on the other end of the phone speaks only DDE, then that is the language FoxPro must speak, too. Visual FoxPro supports the whole complement of DDE commands, providing capability as a client or a server.In case you're new to the DDE scene, let's do a brief overview of the ways in which DDE can be used. DDE is often described as similar to a phone conversation. One party initiates the phone call, the two parties exchange information, and the parties terminate the call.If VFP is the calling application—if we're driving the conversation—we first DDEInitiate() the conversation with the other party. This other application is commonly referred to as the server, confusing the situation with client-server database technology (as well as with Web technology). The client in DDE is the one running the show, running the code, and the server is the application that responds. DDERequest() and DDEPoke() provide the verbs to get and set variable values. DDEExecute() passes a command to the server. DDETerminate() completes the conversation. DDELastError() is the function used to get the details when things go wrong.It may be that we don't want to talk with the server as much as register an interest in the values it has in a particular document, and ask to be advised if these change. DDEAdvise() is the trick for this. Again, you DDEInitiate() and DDETerminate() a conversation, with the request for DDEAdvise() in the middle.Finally, if your application must play the server and be called upon by other applications, DDESetService() defines the services available, DDESetTopic() sets (surprise!) the topics of the conversations, and DDEEnable() allows the server to toggle on and off DDE services while processing. As we said before, DDE is never our first choice for interprocess communication mechanisms. But for those applications that support only DDE, or in situations of limited resources, Visual FoxPro is up to the task of communicating well using DDE. Visual FoxPro can carry on a variety of conversations, working as a client with cold, warm and hot links, as well as working as a DDE server.If you're really interested in the DDE server stuff, a trip down memory lane is required. The FoxPro development environment itself is not a DDE server, but rather the interface is in place for you to hook up your own application as a DDE server. Not much is documented in this version, but Mike Taylor of MicroMega wrote a cool application, FoxData, as a FoxPro DDE server. It was included with the sample code for FoxPro 2.x, and it demonstrated some neat little nooks and crannies in getting FoxPro to work. In addition, several excellent magazine articles and at least one book (listed in the references in the appendices) get into DDE in some depth.
Usage |
nChannel = DDEInitiate( cAppDDEName, cTopic ) lReturn = DDETerminate( nChannel | cAppDDEName ) |
Parameter |
Value |
Meaning |
cAppDDEName |
Character |
Also known as a "service name," this is the handle an application uses to identify itself via DDE, like a trucker's CB radio handle. Contrary to the Help file, Visual FoxPro uses "FoxPro." Excel uses "Excel." Word uses "WinWord." Ain't standards wonderful? If cAppDDEName is supplied with DDETerminate, all channels with this server are closed at once. |
cTopic |
Character |
The topic of your conversation. "System" is often a good icebreaker for speaking with an application you're trying to get acquainted with. |
nChannel |
-1 |
Indicates DDEInitiate could not establish a channel. Use DDELastError to determine why. |
Positive Integer |
The channel number that uniquely identifies this conversation for use with the other DDE functions. |
|
lReturn |
.F. |
Indicates DDETerminate could not close a channel. The other application may have already terminated, or an invalid channel number might have been passed. Use DDELastError to determine why. |
.T. |
Successful termination. |
Example |
? DDEInitiate("WinWord","Document1") = DDESetOption("Safety",.F.) && Turn off dialogs nChannel = -1 nTries = 0 DO WHILE nChannel = -1 and nTries < 3 nChannel = DDEINITIATE("WinWord","System") IF nChannel = -1 && Command failed IF DDELASTERROR() = 16 && Connect failure nTries = nTries + 1 * You'll need to fully qualify the path to * your server, below, or this will fail. RUN /N7 WINWORD.EXE ENDIF ENDIF ENDDO IF nTries = 3 && Three tries and you're out... WAIT WINDOW "Three strikes, you're out." ELSE WAIT WINDOW "Good to go!" ENDIF |
Usage |
lResult = DDEAbortTrans( nChannel ) uResult = DDEPoke( nChannel, cItemName, cData [ , cFormat [ , cAsynchUDF ] ] ) uValue = DDERequest( nChannel, cItemName [ , cFormat [ , cAsynchUDF ] ] ) |
Parameter |
Value |
Meaning |
nChannel |
Integer |
Identifies the particular DDE conversation, set by DDEInitiate(). |
lResult |
.T. |
The attempt to abort the transaction succeeded. |
.F. |
Unable to abort the transaction. We haven't been able to produce this at will, but we suspect it would occur only when connection with the other party in the DDE conversation was lost. |
|
cItemName |
Character |
The item whose data is either being requested or changed. For Excel, this could be a row/column address such as "R2C3". |
cData |
Character |
The data to be placed in cItemName. All data must be passed as a character string and the receiving application must translate it to numeric, if necessary. |
cFormat |
Character |
Dictates the format the data appears in, most often CF_TEXT, which is tab-separated fields. |
cASynchUDF |
Character |
If an asynchronous connection is desired (usually because the answer might take some time), this parameter supplies the name of the function to run when the data is ready. The six pieces of data this function receives are spelled out in the Help file. |
uResult |
Logical |
Reports whether the data was accepted by the application. Use DDELastError() to get information on the error if lResult is .F. |
Integer |
If an asynchronous transaction is selected, DDEPoke() returns the unique transaction number, which is the last parameter to the cAsynchUDF when the transaction is finished. |
|
uValue |
Character |
The result of querying cItemName. |
Integer |
The transaction number, which is the last parameter to the cAsynchUDF when the transaction is finished. |
Example |
* get the value of cell 2,3 nValue = VAL(DDERequest(nExcel,"R2C3")) |
Usage |
lResult = DDEExecute( nChannel, cCommand ) nResult = DDEExecute( nChannel, cCommand, cAsynchUDF ) |
Parameter |
Value |
Meaning |
nChannel |
Integer |
Identifies the particular DDE conversation, set by DDEInitiate(). |
cCommand |
Character |
The command for the server to execute. Each DDE server is unique in the commands, syntax and format it understands. |
cAsynchUDF |
Character |
If an asynchronous connection is desired (usually because the answer might take some time), this parameter supplies the name of the function to run when the data is ready. The six pieces of data this function receives are spelled out in the Help file. |
lResult |
.T. |
Synchronous command completed successfully. |
.F. |
Synchronous command failed. Test using DDELastError(). |
|
nResult |
-1 |
Asynchronous command failed. Test using DDELastError(). |
Integer |
The transaction number to be returned as the last parameter of the cAsynchUDF specified above. |
Example |
* Send the command to WinWord to print the current document =DDEExecute(nWord,"[FilePrint]") |
Usage |
nValue = DDELastError() |
Parameter |
Value |
Meaning |
nValue |
0 |
Last command did not generate an error. |
Integer |
See table of errors in Help. |
Example |
IF DDELastError() = 0 && no error, continue processing |
Usage |
lValue = DDESetOption( "Safety" [, lSafetyOn ] ) lValue | nValue = DDESetOption( "Timeout" [, nTimeout ] ) |
Parameter |
Value |
Meaning |
lSafetyOn |
Logical |
Determines whether warning dialogs appear (.T.) or not (.F.). See example in DDEInitiate(), above. |
Omitted |
Returns present setting of safety in lValue. |
|
lValue |
.T. |
Function completed successfully. |
.F. |
Function failed. |
|
nTimeout |
Numeric |
Amount of time FoxPro waits for a response from the other end of a DDE conversation, expressed in milliseconds. Default is 2 seconds. Legal values from 1 to 594 billion or so—too long for us to wait! |
Omitted |
Returns current timeout setting in nValue. |
|
nValue |
Numeric |
Current setting for timeout. |
Example |
? DDESetOption("Timeout") && Display the current timeout |
Usage |
lValue = DDEAdvise( nChannel, cItemName, cUDFName, nTypeLink ) |
Parameter |
Value |
Meaning |
nChannel |
Integer |
Identifies the particular DDE conversation, set by DDEInitiate(). |
cItemName |
Character |
The name of the item the application is to monitor. The server alerts Visual FoxPro if the data changes. For Excel, this might be a cell address. |
cUDFName |
Character |
The name of the routine to run when a change is made to the item identified above. |
nTypeLink |
0 |
Manual or "cold" link. Turns off a warm or hot link. |
1 |
Notify or "warm" link. |
|
2 |
Automatic or "hot" link. |
|
lValue |
.T. |
Function completed successfully. |
.F. |
Function failed. |
Example |
* This command sets up a hot link between an open Excel DDE * conversation and FoxPro. If the operator or a function * changes the value of the contents of row 2, column 2, the * FoxPro routine will run. = DDEAdvise(nExcel, "R2C2", "MyUDF", 2) |
Usage |
lValue = DDEEnabled( [ nChannel ] [ , lOnOff ] ) |
Parameter |
Value |
Meaning |
nChannel |
Integer |
Identifies the particular DDE conversation, set by DDEInitiate(). |
Omitted |
If no channel is specified, the command applies globally to all channels. |
|
lOnOff |
Logical |
Turns on or off either the specified channel or all channels of DDE while processing a time-critical function. |
Omitted |
Reports whether the specified channel or all channels currently have DDE enabled. |
|
lValue |
.T. |
Indicates either that a channel or global DDE processing is enabled, or that the last change to the status was accepted, depending on parameters supplied. |
.F. |
Channel or global DDE processing is disabled, or the function failed to complete successfully. |
Example |
=DDEEnable( 5, .T. ) && re-enable DDE channel 5 |
Usage |
lResult = DDESetService( cName, cAction [, cFormat | lSwitch ] ) |
Parameter |
Value |
Meaning |
cName |
Character |
Name of the service to maintain. |
cAction |
"Advise" |
Switch to set notification of changes on or off. The server side of warm and hot links, like DDEAdvise(). |
"Define" |
Defines the name of a new service. |
|
"Execute" |
Switch to enable or disable the execution of commands by the service. |
|
"Formats" |
Specifies which formats data may be transferred in. |
|
"Poke" |
Enables or disables a client's ability to poke data to this service. |
|
"Release" |
Releases this service name. |
|
"Request" |
Enables or disables DDERequest() messages. |
|
cFormat |
Character |
Specifies the format in which data can be transferred, using Microsoft shorthand like CF_TEXT (tab-delimited ASCII). |
lSwitch |
Logical |
For Advise, Execute, Poke and Request above, determines whether the feature should be enabled. |
Omitted |
If both cFormat and lSwitch are omitted, returns the current state of the specified action. |
|
lResult |
.T. |
If requesting the status of a feature, it's enabled. If attempting to change an item, the change was successful. |
.F. |
If requesting the status of a feature, it's disabled. If attempting to change an item, the change failed. |
Example |
* Create a new service, called Queries, which only * accepts requests, and transfers all data as tab-delimited text = DDESetService( "Queries", "Define" ) = DDESetService( "Queries", "Advise", .F. ) = DDESetService( "Queries", "Execute", .F. ) = DDESetService( "Queries", "Poke", .F. ) = DDESetService( "Queries", "Request", .T. ) = DDESetService( "Queries", "Formats", "CF_TEXT" ) |
Usage |
lValue = DDESetTopic( cService, cTopic [, cUDFtoRun ] ) |
Parameter |
Value |
Meaning |
cService |
Character |
A service name, defined with DDESetService(), above. |
cTopic |
Character |
A name for the individual topic. |
Empty string |
Indicates that the UDF name that follows should be run for all topic names that don't have a UDF defined for them. |
|
cUDFtoRun |
Character |
The name of the routine to be run when this service and topic are accessed. This UDF receives six parameters, as described in the Help, to indicate what it is to do. |
Omitted |
If no UDF is specified, the topic name is released. |
|
lValue |
.T. |
Topic name successfully created or released. |
.F. |
Command failed. Use DDELastError() to determine why. |
Example |
* Define a topic Tables under the Queries service name * which runs the procedure TablProc when called. =DDESetTopic( "Queries", "Tables", "TablProc" ) |
See Also |