Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to retrieve the target of a Windows shortcut?

227 views
Skip to first unread message

Francois Vogel

unread,
Dec 11, 2006, 4:11:24 PM12/11/06
to
Hi,

On Windows the file explorer allows the user to create shortcuts that
target a file or a directory.

Such a shortcut is actually a small file with some name (usually the
target file name with its extension: target.ext), prepended with a
second extension .lnk (that you can't see in the windows explorer).

On Windows you can also create links (symlinks or hard links), but those
are different from shortcuts.

Question:

How, in pure Tcl, can I:

a) detect that some filename actually refers to a shortcut?
file isfile returns true, and file type returns "file", so how can
I distinguish a shortcut from a "regular file"?

b) extract the target filename or directory name from the shortcut?

If this is not possible, what would be the right Tcl extension or
package to do this?

Thanks,
Francois

Mark Janssen

unread,
Dec 11, 2006, 4:52:12 PM12/11/06
to

On Dec 11, 11:11 pm, Francois Vogel <fsvogelnew5NOS...@free.fr> wrote:
> Hi,
>

Hi Francois,

>
> Question:
>
> How, in pure Tcl, can I:
>
> a) detect that some filename actually refers to a shortcut?
> file isfile returns true, and file type returns "file", so how can
> I distinguish a shortcut from a "regular file"?

In windows extensions determine everything so your best bet would be to
test the extension:

expr {[file extension $file] eq ".lnk"}

>
> b) extract the target filename or directory name from the shortcut?
>
> If this is not possible, what would be the right Tcl extension or
> package to do this?
>

As the lnk files contain binary info, this will be a bit involved in
plain Tcl. The Twapi extension [http://wiki.tcl.tk/twapi] however
contains procedures to extract this information:

%package require twapi
%::twapi::read_shortcut Windows\ (C).lnk -path
-desc {} -hotkey 0 -args {} -iconindex 0 -idl {<some binary stuff>}
-path C:\\ -showcmd normal -iconpath {} -workdir {}

You can then use the path info to determine if it is linking to a file
or a directory.

Hope this helps.

Mark

> Thanks,
> Francois

Francois Vogel

unread,
Dec 11, 2006, 5:06:30 PM12/11/06
to
Mark Janssen a écrit :

> In windows extensions determine everything so your best bet would be to
> test the extension:
>
> expr {[file extension $file] eq ".lnk"}

Hmm, as a first order solution perhaps.

But I just tried in the explorer to create a text file named
"helloworld.lnk", which is allowed by windows, and guess what? it shows
up in the windows explorer as "helloworld".

Of course, this has no target file/directory, but windows really thinks
this is a shortcut, as opening its properties proves...


> The Twapi extension [http://wiki.tcl.tk/twapi] however
> contains procedures to extract this information:

I'll have a look, thanks a lot, despite I would have loved to be able to
do that just in plain Tcl.

Thanks again,
Francois

suchenwi

unread,
Dec 12, 2006, 7:07:28 AM12/12/06
to

Francois Vogel schrieb:

> > The Twapi extension [http://wiki.tcl.tk/twapi] however
> > contains procedures to extract this information:
>
> I'll have a look, thanks a lot, despite I would have loved to be able to
> do that just in plain Tcl.

http://wiki.tcl.tk/1844 has this plain-Tcl solution - see whether it
works for you:

proc readlnk {lnk} {
set res ""
set fp [open $lnk]
foreach snip [split [read $fp] \x00] {
if {[regexp {[A-Z]:\\} $snip] && [file exists $snip]} {
lappend res $snip
}
}
close $fp
join $res
}

Francois Vogel

unread,
Dec 12, 2006, 6:31:18 PM12/12/06
to
suchenwi a écrit :

> http://wiki.tcl.tk/1844 has this plain-Tcl solution - see whether it
> works for you:

Thanks a lot for that link, Richard!

The sad thing is that I couldn't make the plain Tcl solution work.

But there is a lot of others solutions on this page, and I have to look
at each of them carefully.

Thanks again,
Francois

Emmanuel Frecon

unread,
Dec 24, 2006, 6:10:22 PM12/24/06
to
I am coming back from vacation, so this is perhaps reaching you too
late. I have this piece of code that works most of the time for doing
this (it uses part of the information from the wiki):

proc ::argutil::__readlnk { lnk } {
if { ![file exists $lnk] } {
__log warn "'$lnk' is not an accessible file"
return -code error "'$lnk' is not an accessible file"
}

if { [catch {package require tcom} err] == 0 } {
__log debug "'tcom' available trying failsafe method first"
set sh [::tcom::ref createobject "WScript.Shell"]
set lobj [$sh CreateShortcut [file nativename $lnk]]
set tgt [$lobj TargetPath]
__log info "'$lnk' points to '$tgt'"
if { $tgt ne "" } {
return $tgt
}
} else {
__log debug "Could not find 'tcom' package: $err"
}

__log debug "'tcom' not available or failed, using link
introspection"
set fp [open $lnk]
fconfigure $fp -encoding binary -translation binary -eofchar {}


foreach snip [split [read $fp] \x00] {

set abssnip [file join [file dirname $lnk] $snip]
if { $snip ne "" && [file exists $abssnip]} {
__log info "'$abssnip' found in '$lnk', using it as the link!"
close $fp
return $snip
}
}
close $fp
return ""

Francois Vogel

unread,
Dec 25, 2006, 4:32:39 PM12/25/06
to
Emmanuel Frecon a écrit :

> I am coming back from vacation, so this is perhaps reaching you too
> late.

No that's not too late, thank you.

After much browsing and carefully reading the solutions proposed here
and in the wiki, I reached the conclusion that there is no reliable way
to extract the target of a shortcut in pure Tcl.

Since I'm very willing to avoid using external packages such as tcom or
twapi, the only remaining solution is to parse the shortcut file properly.

For that purpose the best (IMHO) information I found is:
http://www.i2s-lab.com/Papers/The_Windows_Shortcut_File_Format.pdf

I've added this link to the wiki page, and it already has code for
parsing the format partially. It is however quite complex.

For the time being, I've just given up. Maybe later...

Thanks again,
Francois

0 new messages