The windows shell uses the ddeexec
registry key to try and open file type using a running
dde service. You can specify both
application and
topic and the command (in dde parlance - the
item) to be called.
The following is a sample application that runs a dde server and associates with files with a
.z_t extension. You can open a file in this application by running either
wish dde-edit.tcl <filename> or once you have run
wish dde-edit.tcl -install to setup the file association, you can just do
start xyzzy.z_t and the Windows Shell will open the file in your tcl app for you.
# dde-edit.tcl - Copyright (C) 2003 Pat Thoyts <patthoyts@users.sf.net>
#
# Illustrate launching tcl applications via dde. This code requires a DDE
# package that implements TIP 120 - such as the one in Tcl 8.5a0
#
# $Id: 8940,v 1.9 2006-01-25 07:00:30 jcw Exp $
package require dde 1.2.4
namespace eval ::DdeEdit {
variable uid
if {![info exists uid]} {set uid 0}
variable dialogs
variable console 0
}
# -------------------------------------------------------------------------
# Description:
# Begin the dde service.
#
proc ::DdeEdit::DdeEdit {args} {
dde servername -handler [namespace origin DdeHandler] DdeEdit
menu .menu
menu .menu.file -tearoff 0
.menu add cascade -label "File" -underline 0 -menu .menu.file
.menu.file add checkbutton -label "Console" -underline 0 \
-command [namespace origin ShowConsole] \
-variable [namespace current]::console
.menu.file add command -label "Exit" -underline 1 -accel "Ctrl-W" \
-command {destroy .}
bind . <Control-w> {destroy .}
. configure -menu .menu
set t [text .t -yscrollcommand {.s set}]
set s [scrollbar .s -command [list $t yview]]
$t insert end $args
grid $t $s -sticky news
grid columnconfigure . 0 -weight 1
grid rowconfigure . 0 -weight 1
tkwait window .
}
# -------------------------------------------------------------------------
# We expect to receive commands in fairly standard DDE style.
# eg: Open("<filename>"), etc.
# If it doesn't match up - reject it.
#
proc ::DdeEdit::DdeHandler {cmd} {
set bits [split $cmd ()]
switch -exact -- [set verb [lindex $bits 0]] {
Open { return [DdeHandleOpen [lindex $bits 1]] }
Run { return [DdeHandleRun [lindex $bits 1]] }
Exit { return [DdehandleExit] }
default {
return -code error "invalid dde command:\
\"$verb\" must be one of Open, Run or Exit."
}
}
return
}
proc ::DdeEdit::DdeHandleOpen {filename} {
set filename [string trim $filename "\""]
if {![file readable $filename]} {
return -code error "file \"$filename\" is not readable: \
[llength $filename]\
[llength [lindex $filename 0]]"
}
set f [open $filename r]
set d [read $f]
close $f
ShowDialog $d
}
proc ::DdeEdit::DdeHandleExit {} {
after 100 {destroy .}
}
# -------------------------------------------------------------------------
# Description:
# Show a simple dialog without locking up the application.
# DDE calls need to return within a reasonable amount of time or the calling
# application raises an error - this means we cannot use tk_messageBox here.
#
proc ::DdeEdit::ShowDialog {text} {
variable uid
variable dialogs
set dlg [toplevel .t[incr uid]]
set m [menu ${dlg}.menu -tearoff 0]
$dlg configure -menu $m
$m add cascade -label "File" -underline 0 -menu [menu $m.file]
$m.file add command -label "Exit" -underline 1 -accel Ctrl-W \
-command [list destroy $dlg]
bind $dlg <Control-w> [list destroy $dlg]
set t [text $dlg.t -yscrollcommand [list $dlg.s set]]
set s [scrollbar $dlg.s -command [list $t yview]]
$t insert end $text
grid $t $s -sticky news
grid columnconfigure $dlg 0 -weight 1
grid rowconfigure $dlg 0 -weight 1
lappend dialogs $dlg
}
# -------------------------------------------------------------------------
# Description:
# Pop the nth element off a list. Used in options processing.
#
proc ::DdeEdit::Pop {varname {nth 0}} {
upvar $varname args
set r [lindex $args $nth]
set args [lreplace $args $nth $nth]
return $r
}
# -------------------------------------------------------------------------
# Description:
# Toggle display of the Tk console.
#
proc ::DdeEdit::ShowConsole {} {
variable console
if {$console == 0} {
console hide
} else {
console show
}
}
# -------------------------------------------------------------------------
# Description:
# Called to register the ".z_t" file suffix with Windows.
#
proc ::DdeEdit::install {} {
package require registry
set HKCR HKEY_CLASSES_ROOT
registry set "$HKCR\\.z_t" {} z_tfile
registry set $HKCR\\z_tfile {} "DDE Test File"
registry set $HKCR\\z_tfile\\shell {} {}
registry set $HKCR\\z_tfile\\shell\\&Open {} "&Open"
registry set $HKCR\\z_tfile\\shell\\&Open\\ddeexec {} "Open(\"%1\")"
registry set $HKCR\\z_tfile\\shell\\&Open\\ddeexec\\application {} "TclEval"
registry set $HKCR\\z_tfile\\shell\\&Open\\ddeexec\\topic {} "DdeEdit"
registry set $HKCR\\z_tfile\\shell\\&Open\\command {} \
"[file nativename [info nameofexecutable]]\
[file nativename [file normalize [info script]]] \"%1\""
}
# -------------------------------------------------------------------------
if {$tcl_interactive} {
puts "loaded"
} else {
if {[llength $argv] == 1 && [string match "-install" [lindex $argv 0]]} {
::DdeEdit::install
puts "install done"
exit 0
}
# See if we already have a running app.
package require Tk
if {[dde services TclEval DdeEdit] != {}} {
wm withdraw .
set filename [file normalize [lindex $argv 0]]
dde eval DdeEdit "Open(\"$filename\")"
exit 0
} else {
eval DdeEdit::DdeEdit $argv
}
}