Version 16 of send

Updated 2003-07-25 11:11:35

send - Execute a command in a different application http://www.purl.org/tcl/home/man/tcl8.4/TkCmd/send.htm

 send ?options? app cmd ?arg arg ...?  

This command arranges for cmd (and args) to be executed in the application named by app. It returns the result or error from that command execution. App may be the name of any application whose main window is on the display containing the sender's main window; it need not be within the same process. If no arg arguments are present, then the command to be executed is contained entirely within the cmd argument. If one or more args are present, they are concatenated to form the command to be executed, just as for the eval command.

If the initial arguments of the command begin with "-" they are treated as options. The following options are currently defined:

-async : Requests asynchronous invocation. In this case the send command will complete immediately without waiting for cmd to complete in the target application; no result will be available and errors in the sent command will be ignored. If the target application is in the same process as the sending application then the -async option is ignored.

-displayof pathName : Specifies that the target application's main window is on the display of the window given by pathName, instead of the display containing the application's main window.

-- : Serves no purpose except to terminate the list of options. This option is needed only if app could contain a leading "-" character. (From: Tk help)


Send is a revelation. Many Tk (and even Tcl) programmers claim it as indispensable. Start by reading the distribution documentation mentioned above.


Can someone sketch up an example of how to use send - demonstrating some of the things one should be certain to consider when working with send?


Can different Tk bindings communicate through send? Yes--Perl/Tk, Tcl/Tk, and Tkinter are all happy sending messages to each other with built-in send. At some point, we need to present examples of this ... Steve Lidie devotes an entire chapter of his Perl/Tk book to send.


LV Back in the olden days, there was also an X Windows system library that allowed one to communicate between Xt based applications, with a Tcl interpreter, and Tk applications via send.

However, I don't know of any method for non-GUI applications to communicate via send to Tk applications, nor of a way for Java applications to communicate via send with Tk applications.


Start small with your send programming. Use a couple of simple Tk instances, to work out the security and application-name issues. Once those are properly settled, it's usually quick work to automate as much as you choose.


CAVEAT: The Tk send command depends on working with an X server and thus does not work normally on Windows or MacOS. Check out dde for Windows and Tcl's AppleScript support for Mac.


See also comm (a send look alike based on sockets which should work cross platform and cross machine), dde, and other methods listed in the Inventory of IPC methods.


PT writes on 29 March 2002:

I have released a preliminary version of a send for MS Windows systems that uses COM to do the work of registering interpreters and passing messages around. See http://tclsoap.sourceforge.net/winsend.html for more information and for the package. The source is in the CVS repository there (cvs -d:pserver:[email protected]:/cvsroot/tclsoap co winsend).

At the moment (Nov 2002) I'm not sure how successful the winsend package has been. However, there have been over 200 downloads so I imagine it's been of some use to someone :)


Pat Thoyts gave this example for a send substitute with DDE in the Tcl chatroom:

 # Emulate the 'send' command using the dde package if available. 
 if {[info command send] == {}} { 
    if {![catch {package require dde}]} { 
        dde servername TkInspect-[pid] 
        proc send {app args} { 
            eval dde eval [list $app] $args 
        } 
    } 
 } 

PT writes:

This is a suggestion for a generalisation of the send functionality. This is derived from the tkinspect send handling and should help a little with the use of send in a cross-platform application.

 # send.tcl - Copyright (C) 2002 Pat Thoyts <[email protected]>
 #
 # General send command
 #
 # This provides an abstraction of send, appname and interps that works for
 # all available send mechanisms. This is especially useful for Windows where
 # the usual Tk send is not available.
 #
 # We attempt to use the most efficient transport available. If the normal Tk
 # send command is present then this will be used. Otherwise we try winsend,
 # then dde for windows before defaulting to use comm.
 #
 # The interps command will try and build a list from all available transports.
 #
 # The appname command will try to apply the new name to all transports and
 # will read it from them all as well.
 #

 namespace eval send {
     variable version 1.0
     variable rcsid {$Id: 1055,v 1.17 2003-07-26 08:00:12 jcw Exp $}

     namespace export send interps appname
 }

 # Try using Tk send first, then look for a winsend interp,
 # then try dde and finally have a go at comm
 proc send::send {args} {
     array set opts [list displayof {} async 0]
     while {[string match -* [lindex $args 0]]} {
         switch -exact -- [lindex $args 0] {
             -displayof { set opts(displayof) [Pop args 1] }
             -async     { set opts(async) 1 }
             -- { Pop args ; break }
             default {
                 return -code error "bad option \"[lindex $args 0]\":\
                     should be -displayof, -async or --"
             }
         }
         Pop args
     }    
     set app [Pop args]

     if {[info command ::winfo] != {} 
         && [lsearch -exact [::winfo interps] $app] > -1} {
         set cmd ::send
         if {$opts(async) == 1} {append cmd " -async"}
         if {$opts(displayof) != {}} {append cmd " -displayof $opts(displayof)" }
         eval $cmd [list $app] $args
     } elseif {[info command ::winsend] != {}
               && [lsearch -exact [::winsend interps] $app] > -1} {
         eval ::winsend send [list $app] $args
     } elseif {[info command ::dde] != {}
               && [lsearch -exact [dde services TclEval {}] \
                       [list TclEval $app]] > -1} {
         eval ::dde eval [list $app] $args
     } elseif {[package provide comm] != {} 
               && [string is integer [lindex $app 0]]} {
         if {$opts(displayof) != {} && [llength $app] == 1} {
             lappend app $opts(displayof)
         }
         eval ::comm::comm send [list $app] $args
     } else {
         return -code error "bad interp: \"$app\" could not be found"
     }
 }

 proc send::interps {args} {
     array set opts [list displayof {}]
     while {[string match -* [lindex $args 0]]} {
         switch -exact -- [lindex $args 0] {
             -displayof { set opts(displayof) [Pop args 1] }
             --         { Pop args ; break }
             default {
                 return -code error "bad option \"[lindex $args 0]\":\
                     should be -displayof or --"
             }
         }
         Pop args
     }

     set interps {}
     if {[info command ::winfo] != {}} {
         set cmd "::winfo interps"
         if {$opts(displayof) != {}} {           
             append cmd " -displayof $opts(displayof)"
         }
         set interps [concat $interps [eval $cmd]]
     }
     if {[info command ::winsend] != {}} {
         set interps [concat $interps [::winsend interps]]
     }
     if {[info command ::dde] != {}} {
         set servers {}
         foreach server [::dde services TclEval {}] {
             lappend servers [lindex $server 1]
         }
         set interps [concat $interps $servers]
     }
     if {[package provide comm] != {}} {
         set interps [concat $interps [::comm::comm interps]]
     }
     return $interps
 }

 proc send::appname {{newname {}}} {
     set appname {}
     if {[info command ::tk] != {}} {
         set appname [eval ::tk appname $newname]
     }
     if {[info command ::winsend] != {}} {
         set appname [concat $appname [eval ::winsend appname $newname]]
     }
     if {[info command ::dde] != {}} {
         set appname [concat $appname [eval ::dde servername $newname]]
     }
     # comm? can set port num and local/global interface.
     return [lsort -unique $appname]
 }

 proc send::Pop {varname {nth 0}} {
     upvar $varname args
     set r [lindex $args $nth]
     set args [lreplace $args $nth $nth]
     return $r
 }

 package provide send $send::version

 # Local variables:
 #   mode: tcl
 #   indent-tabs-mode: nil
 # End:

LV Has anyone investigated what would be necessary for non-Tk applications to send info to Tk apps in the same manner as the Tk send? For instance, if I have a Java application or some other language without a Tk binding... Well, one thing that could be done is to write a Tclblend wrapper for the Java code. Then write some code that talks to the Java code and then acts as a send manager.

PT 26Jun2003: There is an Xt based library - tclXtSend [L1 ] [L2 ] which permits non-Tk applications to use send. It may be out of date though.


LV Sometimes a Tk application dies and its interpreter is left registered with the window manager. When this happens, one can see things like this:

 $ wish 
 % send Display.tcl puts $args
 can't read "args": no such variable
 % send Display.tcl info vars
 no application named "Display.tcl"
 % winfo interps
 wish Driver.tcl pilotManager xfilewatch.tcl
 % send Driver.tcl puts abc
 target application died or uses a Tk version before 4.0
 % winfo interps
 wish Driver.tcl pilotManager xfilewatch.tcl

Has anyone a tip on how to clear out that interpreter name?


Pre-TIP

I'm working on this slowly. Currently synchronous send works very nicely but I want to sort out async as well. In the meantime TIP preparation goes on - I'd welcome any comments, additions etc before I sumbit it to the TIP process.

 Title:          Implement the Tk send command for windows.
 Author:         Pat Thoyts <[email protected]>
 Type:           Project
 Tcl-Version:    8.5
 Keywords:       tk, send
 Created:        25-Jul-2003

 ~ Abstract

 This TIP proposes to provide an implementation of the send mechanism
 for Tk under Windows.

 ~ Rationale

 The Tk send command is used to provide an X server based mechanism for
 transmitting information between Tk applications. This provides the
 basis for remote introspection (tkinspect) and remote control
 (tkcon). This subsystem has never been implemented under Windows
 although there are means to emulate this using Tcl's dde package or
 the comm library. By providing a win32 implementation we help to
 standardise the Tk command set across platforms and will make it
 simpler to use this feature from Perl/Tk and Python Tkinter.

 ~ Reference Implementation

 This implementation is based upon an integrated version of the winsend
 package currently at http://tclsoap.sf.net/winsend/. This uses the
 Windows Running Object Table to maintain interpreter registration
 information. This is a global system COM object that is provided as
 part of the Windows COM automation framework. Its purpose is to
 provide a single registry for maintaining references to active COM
 componets.

 When tk appname is called a COM component is created which contains a
 reference to the Tcl interpreter. This is then registered with the
 Running Object Table with the registration name containing the Tk
 appname. To find available interpreters we use the winfo interps
 command. This iterates over all the registered objects looking for Tk
 registered names and can then return a list of registered
 interpreters.

 The Tk send command is then provided as a COM method call. To perform
 a send, the client interpreter (or indeed any automation capable COM
 client) obtains the interpreter reference from the running object
 table and calls the Send method on this object, passing in the command
 as a string. For the synchronous version this is sufficient. The
 result is returned using the standard COM method calling and error
 information can be returned the same way.

 Support for the asynchronous send is currently underway but will be
 modelled closely on the X-based send.

 There are some advantages in using COM over DDE for the transport
 mechanism. DDEML has a tendancy to use broadcast window messages. If
 there are any toplevel windows that are not processing their message
 queues, then DDE gets hung. While a fix has been applied to the Tcl
 dde package, there remain problems. In contrast the COM-based system
 never broadcasts. We initiate a conversation with the Running Object
 Table first and then with the specific application requested. If this
 application fails to process it's message queue then we will get stuck
 - but no other poorly behaved application can affect our
 communication.

 A second advantage is than non-Tcl automation capable clients can also
 call our method. This means that Windows Scripting code (vbscript or
 jscript) can make use of the send command.

 Finally, given a suitable DCOM environment it should also be possible
 to implement the -displayof feature via Distributed COM. However, I
 don't see much call for this - network sockets are a lot simpler to
 use than DCOM.

 ~ Copyright

 This document is placed in the public domain.

Tk syntax help - Arts and crafts of Tcl-Tk programming - Category Command, part of the Tk package