Updated 2016-02-13 16:58:11 by escargo

I thought it was time I tried to return something to this Wiki. I created this page for little Tcl/Tk utilities which make life under MS Windows easier.

  • SendTo utility to add the UNC for several files

Problem: You want to insert the network path (UNC) into an email message for file(s) rather than attaching the files. You can select those files in Windows Explorer and then right click and select SendTo. The full path of those files will be send on the command line to whatever application you place in the SendTo directory in your profile (depends on the version of Windows. EG: WinXP places it under "Documents and Settings\username\SendTo). I tried to create a simple Visual C++ utility to grab this command line and place it on the clipboard. I found out that Tcl/Tk makes it much easier:
 clipboard clear
 clipboard append [join $argv {
 }]
 update
 exit

Place this script somewhere, not necessarily in the the SendTo directory. In the SendTo directory, create a new shortcut to your wish executable and add to the command line the path to this simple script. That is all you need!

Now, a few years later...

As needs progressed, I discovered a more robust way to implement this was to create a one line Windows script (.BAT) file to call wish. In this BAT file put the line:
  @<Path to Wish> "<Path to your Tcl script>" %*

Where you substitute the expressions with the angle brackets with that which is appropriate for your installation. As LES discovered below in the discussion, pathnames that have spaces can lead to problems. The above seems more robust. Now, create a shortcut in your SendTo directory that points to the .BAT file you created above.

Now, a more full-featured version of the above script. It handles selection of multiple files. It includes a line to modify the backslashes to make a Unix compatible-pathname (took me a long time to get it right, hence documenting it here). If you don't want unix names, remove it.
  wm withdraw .
  
  package require twapi
  
  # map the drive letters to UNC
  set newpaths {}
  foreach path $argv {
      if { [regexp {^[A-Z]:} $path drive] } {
          if { ! [catch {twapi::get_mapped_share_info $drive -uncvolume} status]} {
              array set driveinfo [twapi::get_mapped_share_info $drive -uncvolume]            
              set newpath [regsub ${drive} $path \\$driveinfo(-uncvolume)]
          } else {
              set newpath $path
          }
      } else {
          set newpath $path
      }
      lappend newpaths $newpath
  }
  
  # Make it unix-friendly - change back to forward slashes
  set newpaths [regsub -all \\\\ $newpaths /]
  
  twapi::open_clipboard
  twapi::empty_clipboard
  twapi::write_clipboard_text [join $newpaths {
  }]
  twapi::close_clipboard
  
  exit

The trick with the four backslahses above took a lot of time to nail down. Since I didn't see any documentation here, I thought this might be the pinnacle of my contribution. buchs

DISCUSSION

LES on 2003 Dec 01: has anyone actually tried this? It doesn't work for me. The script is not even run.

JPT 2003-12-02: I tried it under WinME and it worked ok... after I re-read the instructions and put a shortcut to the script in the SendTo directory instead of the script itself as I first did.

LES: I am using the shortcut too, on Win98, and it doesn't work.

LES on 2005 Jan 06: This little trick still doesn't work for me. The script is not even run. I REALLY want to make it work this time, so let me try a very detailed step-by-step:

1. I write a script...
 wm withdraw .
 tk_messageBox -message [ join $argv {} ]
 exit

... and save it as C:\WINDOWS\Desktop\test.tcl

2. I browse to my SendTo folder and create a shortcut to my wish executable. I rename it to Show_path.

3. I open the properties of that shortcut and find this path: D:\Langs\Tcl\bin\wish.exe

4. I modify that path: D:\Langs\Tcl\bin\wish.exe C:\WINDOWS\Desktop\test.tcl

5. I write a new text file...
 hey
 mom
 howdy

... and save it as C:\WINDOWS\Desktop\hello.txt

6. I right-click hello.txt and select SendTo > Show_path.

Result: an error message:
 invalid command name "hey"
    while executing
 "hey"
    (file "C:\WINDOWS\DESKTOP\HELLO.TXT" line 1)

So it didn't capture the file's path and also gave me an error. Where did I go wrong?

anonymous: You did not go wrong. Windows is launching wish and your script, then passing the file data as part of dde. The word Hey hits your shell and TCL raises an error.

Your intent was to get the path of the file, which you did not pass to tcl. You passed the contents of the file. The "%1" flag in the shortcut would pass the path through the shortcut.

LES How? I tried changing the path in the shortcut to D:\Langs\Tcl\bin\wish.exe C:\WINDOWS\Desktop\test.tcl "%1" , and it doesn't work either.

anonymous: Interesting. It works fine for me, I even copy/pasted your code. I get the messagebox with the path. I am using XP Pro. Lets try a slightly different method and see if it works.

Assuming that all .tcl files are associated with wish (not tclsh or nothing). Right click on an empty area in your SendTo folder and select New Shortcut. In the target area type exactly: start "C:\WINDOWS\Desktop\test.tcl" "%1"

Just to see if perhaps that method works. In my experience it does.

LES No. A DOS box opens and closes all too quickly. Suddenly, hello.txt is open in my text editor. Damn! >:-(

anonymous: Very odd. Maybe someone else will have an idea we have overlooked. I am stumped.
 wm withdraw .
 clipboard clear
 clipboard append [join $argv {}] 
 update

with wish "sciptname.tcl" "%1" in the shortcut

seems to work for me - exit seems to clear the clipboard

Working with Windows Drives

I found it rather difficult, at least from my perspective, to deal with Windows disks, particularly removable media. Specifically when I want to know the file systems and availability of drives / etc. Windows makes it rather hard. The small script below builds a complete array of all disks on a system and the required information to work with them.
 proc MyDisks {} {
    set ::myDisk(Listing) [file volumes]
    foreach disk $::myDisk(Listing) {
        set ::myDisk($disk,Name) [file nativename $disk]
        if {[catch {file type $disk} blah]} {
            set ::myDisk($disk,Available) 0
        } else {
            set ::myDisk($disk,Available) 1
        }
        set ::myDisk($disk,Writable) [file writable $disk]
        set ::myDisk($disk,FS) [lindex [file system $disk] 1]
    }
 }

To explain all of these checks and the resulting array:

- myDisk(Listing) contains all found volumes (drives). It is the easiest way to continue with other drive operations.

- myDisk($disk,Name) contains the native name of the disk. This is the name such as c:\ rather than c:/. It is how end-users expect to see the drive name.

- myDisk($disk,Available) is 0 for no disk present or 1 if a disk is present. this lets you know whether the drive contains removable media or not.

- myDisk($disk,Writable) is 0 if readonly on 1 if writable. This is useful for determining the type of removable media separate from the device FS formatting.

- myDisk($disk,FS) returns the actual file system for that device. It will return "" if the disk is not present, or the true file system if present. (CDFS NTFS / etc)

The reason I use a global array is to make it easy to integrate with GUI operations and associate variables as needed for user interaction.

Hopefully this helps anyone looking to make a simple file explorer / etc.

APN 2006/07/04 The Disks and Volumes [1] module of TWAPI provides commands to retrieve the above as well as other disk and volume related information.

Integrating Tcl and Emacs on Windows shows a secret way to integrate Tcl on Windows Emacs.

windows icons holds the secret of icon manipulation with Tcl