DDE (Dynamic Data Exchange) is one Microsoft way of communicating between applications that support that (e.g. Word does, but Wordpad/Notepad don't). Messages are strings that express commands. It looks like for Word the commands have to be bracketed, so put braces around to prevent the Tcl parser from seeing them. Tcl (for Windows) of course has dde support - see the dde page in Tcl Help.
http://www.purl.org/tcl/home/man/tcl8.5/TclCmd/dde.htm
tclguy writes during March of 2002 on comp.lang.tcl:
"... I wanted to get time to answer this earlier, but you eventually hit on it yourself. DDE requires an event loop to be running to service requests. DDE is based on a serial request / response mechanism, which you can hang up when a process isn't responding. A Tcl process that sees no reason to have an event loop running will also not queue into the fact that DDE requests are waiting. This is why you see the problem in Tcl apps mostly, and not Tk apps (which need the event loop for the UI)."
BR 2003-10-28 - This leads directly to the biggest problem with DDE (IMO).
During connection setup, a straight-forward DDE client will send a broadcast (without a timeout) to all threads that have an event queue. (On Windows all threads that have ever processed events in the past have an event queue, all others don't have one.)
The problem: Any thread that has an event queue but is currently not servicing it for any reason will block the broadcast. This will block the client, and the effect can propagate to its clients. I have had very bad experiences with this in real life.
PT 11-Mar-2004: This issue has been resolved for Tcl 8.5 by using SendMessageTimeout to perform this step. This results in badly behaved applications not appearing in the list of available services but also not hanging the DDE client app.
More commentary: DDE's a funny creature. Deprecated since 199? [document], everyone knows it's preferable on all sorts of grounds to use a COM interface--but Tcl still, as of 2004, builds in the DDE package, but does not do the same for any COM facility.
From a posting by Bill Schongar, at http://groups.google.com/groups?oi=djq&ic=1&selm=an_490725194 , you can control Microsoft Word from the dde command. First: be sure Word is running, then try a command like the following to insert text into the current document:
package require dde
look at CWind:but it does the work."
dde execute -async Winword System {[Insert "Text from Tcl."]}
To quit Word, or close a document, use the following commands as a guide:
dde execute Winword System {[FileExit 2]} dde execute Winword System {[FileClose 2]}
In these examples, 2 = close without saving, 1 = save first, 0 = prompt.
For documentation on accessing Word, see the "wrdbasic.hlp" file, which you can choose to install when you install Word.
Adrian Davis adds that
dde execute Winword System {[AppMaximize 1]}
maximizes Word. - RS also found these to work:
% dde execute Winword System {[EndOfDocument]} % dde execute Winword System {[StartOfDocument]} % dde execute Winword System {[EditFind .Find="hello" .PatternMatch=1]}
See also Word Reaper.
Peter G. Baum presented this example for MATLAB:
dde execute Matlab Engine "s = ones(5);"
CL's favorite DDE baby steps are with IE, because it's even more ubiquitous than Word or Excel. Moreover, the simplest possible IE example also illustrates a significant difficulty in working with DDE.
To open a web page in Internet Explorer:
dde execute iexplore WWW_OpenURL "http://www.tcltk.com/"
See http://support.microsoft.com/support/kb/articles/Q160/9/57.ASP?LN=EN-US&SD=gn&FR=0 for various dde commands supported by internet explorer. It would be nice to transcribe some of them into Tcl for this page.
dde execute iexplore WWW_ShowFile C:/Program%20Files/....
will open a local file (note that spaces and other odd characters must be converted to valid '%' codes).
dde request iexplore WWW_GetWindowInfo 1
will return information about the current window which is open, although if multiple windows are open, I'm not sure how to control this more accurately.
dde request iexplore WWW_ListWindows 0
seems to do something...
Vince.
(any help with above? In particular, it would be useful to be able to grab the URL of the foremost window.-)
All of the above experiments should "work" reliably, in that, from the user perspective, IE indeed acts as described. However, back in the Tcl process, [dde] typically throws a "remote server cannot handle this command" exception. That's because, in KBK's analysis, DDE gives no "way to distinguish 'result expected, but the server failed to provide it' from 'no result is expected'." The only way not to receive a DMLERR_NOTPROCESSED is to invoke "dde exec -async ..."
Using dde to get browser info - A little Web kiosk
Finally, Eudora seems to have some support:
{Eudora DeleteMessageById} {Eudora PutMessageById} {Eudora GetMessageById} {Eudora GetNextMessageId} {Eudora ExpandNickname} {Eudora MAPI} {Eudora WWW_OpenURL}
But I'm not sure how to make use of them...
Controlling Windows explorer:
To open a folder on the desktop:
dde execute Folders AppProperties{[ViewFolder "C:\Temp","C:\Temp",5)]}
you can also use 'ExploreFolder' instead.
To open the Find Folder dialog:
dde execute Folders AppProperties {[FindFolder("","C:\Temp")]}
will open the Find Folder dialog.
Re MS Excel, George Petasis writes in comp.lang.tcl: Finally, I manage to find an example at msdn. My only problem now is how to select the chart type of the created chart. Acoording to the example:
dde execute Excel $Topic \ "\[Select(\"R1C1:R${rows}C1\;R1C5:R${rows}C$cols\")\]\[New(2,2)\]"
The chart is created with New(2,2), after the correct cells are selected. This chart is the vertical bars type and is placed in a new book. How can I select the scatter graph and place it in a new sheet of the first book (referenced by $Topic)? Where can I find documentation about this New dde function?
Helpful procedures (Vince) [Someone please annotate these]:
proc windowsDdeExecute {service topic name args} { set cmd "\[$name\(" set subcmds [list] foreach a $args { lappend subcmds "\"$a\"" } append cmd [join $subcmds ","] "\)\]" puts stderr "dde execute $service $topic $cmd" dde execute $service $topic $cmd } proc windowsProgmanExecute {name args} { eval [list windowsDdeExecute PROGMAN PROGMAN $name] $args }
A recent posting in news:comp.lang.tcl says:
Message-ID: <[email protected]> From: Bruce Hartweg <[email protected]> Newsgroups: comp.lang.tcl Subject: Re: Q: dde and Netscape References: <[email protected]> <[email protected]> <[email protected]> <[email protected]> Date: Wed, 23 May 2001 09:20:08 -0500 Organization: Raytheon Company Neil Madden wrote: > "Donal K. Fellows" wrote: > > > > Bruce Hartweg wrote: > > > change wrote: > > >> However, if I use > > >> dde execute -asynce netscape WWW_OpenURL http://www.yahoo.comm > > >> the netscape does nothing (no error message either). Could someone help me? > > [...] > > > It's been a while, so I am not sure (can't find my script where I used this) > > > but I think you need to use dde request instead of dde execute. > > > > > > For reference of what DDE Topics Netscape supports see > > > http://developer.netscape.com/docs/manuals/communicator/DDE/contents.htm > > > > Hmm. The following URL (hopefully not mangled by this newsreader) looks > > to be the key: > > http://developer.netscape.com/docs/manuals/communicator/DDE/ddevb.htm#www_openurl > > > > So, I *guess* that it should be something like this: > > > > dde request netscape WWW_OpenURL http://www.yahoo.com 0 0 > > Doesn't work for me on Win98, I get: > wrong # args: should be "dde request serviceName topicName value" > > Removing the "0 0" from the end and it works as expected. >
Yes, (it's coming back) the value has to be a single string, if you want to pass other args to the service separate by commas & keep as single arg (add commas to skip items) so
dde request netscape WWW_OpenURL "${url},,0"
will open the URL in a new window, and
dde request netscape WWW_OpenURL "${url},,0xFFFFFFFF"
will open it in the last active window
Bruce
How, though, does one use -ddename? How, in particular, can one Tk instance spawn and control another? Jeffrey Hobbs posted an example in August 2001:
exec wish83.exe myfile.tcl -ddename bar -mynameis foo & dde eval bar $command
Notice that the spawned interpreter can itself
dde eval foo $command2
in this context.
As Jeff writes, "Also, to find existing names, you just do:
dde services TclEval {}
and that is like 'winfo interps'."
Which applications are running?
dde services "" ""
can tell you.
From news:comp.lang.tcl , Oleg Oleinick writes:
To take control over DDE, application can start DDE server in the slave interpreter.
Following example prevents application to start twice:
package require Tk package require dde # dde dispatcher proc ddecommand {command} { switch -- $command { "raise" { raise . focus -force . } } } # Check for running instance if { [llength [dde services TclEval MYAPP]] } { # Application already run, raise it dde eval MYAPP catch raise exit 0 } # Create slave intepreter 'ddeagent' if { [lsearch -exact [info loaded] {{} Dde}] >= 0 } { # Statically linked dde, we can use safe interpreter interp create -safe ddeagent interp invokehidden ddeagent load {} dde } else { interp create ddeagent interp eval ddeagent package require dde } # Create new command raise in slave interpreter interp alias ddeagent raise {} ddecommand raise # Create dde server in slave interpreter interp eval ddeagent dde servername MYAPP focus -force .
Oleg
Netscape provides a list [L1 ] of DDE things known to Navigator.
Iain B. Findleton has coded a DDE 2.0 he's currently using, although not yet released. Also, Iain has found that it's safest to connect only to active services; Win* seems to misbehave uncontrollably when one tries to connect to an absent service.
It is often useful to be able and use a context menu option to either launch a Tcl application on a file, or if the Tcl application is running have it handle the launched file. An example of registering the handler is shown in regContextHandler - TFW
Applications inaccessible through DDE often can be reached by way of COM and SendKeys. For even more power and flexibility, Stefano Porici advises, "If you're interested in sending key sequences and exchanging data through the clipboard (a powerful combination anyway), you can give a
http://www.interq.or.jp/japan/s-imai/tcltk/cwind.html
this is a loadable DLL with a very simple Tcl interface. A more powerful interaction model (allowing mouse movements) is provided by WinTclSend ..."
See send for a Windows emulation with DDE.
[We need a comparison with tcom, OpTcl, ...]
How to Restrict The List of Exposed Commands
By default the dde package, when used as a server, exposed all of the commands and variables available in the interpreter. This is not always what is desired. One solution might be to load the package into a safe slave interpreter and use [interp alias] to expose the required commands. Unfortunately the package doesn't support safe interpreters. A second solution is to build a modified dde package - see dde restriction for more. PT
Associating a Windows file type with a Tcl application
With an implementation of TIP #120 [L2 ] it is possible to have Windows Explorer launch a Tcl application for a file type. See ddeexec
How get data in and out of Excel
# dde request Excel System SysItems # dde request Excel System Topics # # Create a new book # dde execute Excel System {[NEW(1)]} # dde poke Excel {[Book1]Sheet1} "R1C1" 4 # dde request Excel {[Book1]Sheet1} "R1C1" # # Select Row 1 Column1 to Row 20 Column 3 # dde execute Excel System {[select("r1c1:r20c3")]} # # Sort Row 1 Column 1 # dde execute Excel System {[sort(1,"R1C1",1)]} # # Quit # dde execute Excel System {[quit()]} # # Get a list of books and sheets # dde services Excel {} # To load an existing .xls file in the current directory set cwd [pwd] regsub "/" $cwd "\\" cwd exec {C:/Program Files/Microsoft Office/Office/Excel.exe} & catch {dde execute Excel {[Book1]Sheet1} "\[open(\"$pwd\\$fileName.xls\")\]"} package require dde # bookAndSheet like {[Book1]Sheet1}
Starting at Row=1 and Column=1 and assuming data is a list of rows and each row is a list of values.
proc excel_export {data bookAndSheet} { set row 1 set col 1 foreach d $data { foreach v $d { dde poke Excel $bookAndSheet "R${row}C${col}" $v incr col } incr row set col 1 } } # bookAndSheet like {[Book1]Sheet1}
Imports a square of values from r1 (row 1) to r2 (row 2) and from c1 (column 1) to c2 (column 2). Returns a list of rows. Each row is a list of values.
proc excel_import {r1 c1 r2 c2 bookAndSheet} { set ret {} set row $r1 set col $c1 for {} {$row <= $r2} {incr row} { for {set col $c1} {$col <= $c2} {incr col} { lappend rowData [string range [dde request Excel $bookAndSheet "R${row}C${col}"] 0 end-2] # puts "$row $col $rowData" } lappend ret $rowData set rowData {} } return $ret }
Earl Johnson ([email protected]) (Loading an existing xls file added by CF)
A little tip from Ro if you want to control Mozilla via DDE:
Mozilla registers the DDE application "Mozilla" and currently supports only (as of Sept 7th, 2002) the "WWW_OpenURL" topic.
Use the source @ http://lxr.mozilla.org/seamonkey/source/xpfe/bootstrap/nsNativeAppSupportWin.cpp
2012-09-18 hae Using Mozilla Firefox 14.0.1 the browser registers as 'FireFox'.
# Open a website in a new tab if firefox is already started. dde request FireFox WWW_OpenURL http://www.google.com # Always open a website in a new window dde request FireFox WWW_OpenURL http://www.google.com,0,0
package require dde puts "Currently displayed is '[lindex [dde request iexplore WWW_GetWindowInfo 0] 0]'."
Some examples of using dde with Microsoft Access - see also [L3 ]
dde request MSAccess {c:\samples\NWIND.MDB} tablelist
gives a list of available tables
-To access data in a table
dde request MSAccess {c:\samples\NWIND.MDB;TABLE tblBooks} All
gives all entries in table with field names
dde request MSAccess {c:\samples\NWIND.MDB;TABLE tblBooks} Data
gives entries without field names
dde request MSAccess {c:\samples\NWIND.MDB;TABLE tblBooks} FieldNames
gives just the field names
-To access data from a query
dde request MSAccess {c:\samples\NWIND.MDB;QUERY qryCatagories} All
gives all rows of a query
It is interesting to see all that you can do with DDE in other applications, but may I suggest a list of ideas of what kind of services a Tcl application can make available to other (Tcl or not) applications through dde: Serving dde
While DDE has a notion of "Advise" [document], Tcl's standard DDE package does not provide a correlative for Advise.
ALX: Howto open PDF with Adobe Acrobat or Reader using DDE
MG I've just experimented a little in setting up a DDE server (to make a Tcl program the default telnet client, in my case, but you can use it for handling any file extension). Couldn't find a whole lot of info on what settings were needed in Windows itself, to make it work with the Tcl script, but with a little trial and error I think I've got it figured out, and thought I'd share.
The first thing I did was set up a really simple script, using Tcl 8.5:
package require Tcl 8.5 package require dde 1.3 dde servername -handler myHandler -- myApp proc myHandler {args} { puts $args } console show
Then made it into a Starpack (see How to create my first Starpack) and placed it as c:\ddetest.exe
Then it's just a case of setting up the file extension settings in Windows. In any folder, go to Tools -> Folder Options -> File Types, select the file type/extension you want, and change it's "open" action to use:
Application used to perform the action: c:\ddetest.exe Use DDE: Yes DDE Message: %1 Application: TclEval DDE Application Not Running: (leave blank) Topic: myApp
That's all I did, and it worked for me. The first time I tried to access a Telnet url, it launched the exec and printed the URL to the console. Subsequent attempts printed the URL in the same console, without relaunching the app. You could probably avoid having to make a Starpack if you changed the "Application used to perform the action" to be something like
"c:\path\to\wish.exe" -- "c:\path\to\tclscript.tcl"
though I've not tried it.
Updated a bit later: it seems I didn't notice that Windows (XP, at least) sends the dde request immediately after launching the "Application used to perform the action", when it's not already running, so if you pass the info on the command line and check for it there, too, you end up processing it twice.
Using the Tcl DDE package on a PC with XP system ( having codepage 1252 ) for tranmitting 8 bit characters (e.g. c4) results in 2 hex values on the receiving side (e.g. c3 84) (it's a dymo labelprinter software) . Does the DDE package any code transformations by itself ? I believe cp1252 is unicode (?), there should be no need for converting anything. Is there any hind ? Thanks
RS cp1252 is almost the same as iso8859-1, an 8-bit encoding, with ASCII and Western European letters. Before you send out the string, convert it to cp1252 with
set string [encoding convertto cp1252 $string]