Monday, July 11, 2005

 

Getting a shortcut's target in C#

The .NET Framework has a lot of handy classes but none that read a shortcut's target. Normally you can add a reference to Shell32, instantiate it, NameSpace over to the shell link hoo-hah and read the target. I couldn't get this to work for a UNC path in an ASP.NET application without changing the account listed in the application pool. I found a doc that has the file format and wrote a method for reading the data I need:

    
private string GetShortcutTarget(stringfile)
{
// Based on shortcut file format documentation by Jesse Hager.
// http://www.i2s-lab.com/Papers/The_Windows_Shortcut_File_Format.pdf
// This reads paths for local files. It would need tweaking if the shortcut
// pointed to a UNC.
if (System.IO.Path.GetExtension(file).ToLower() != ".lnk")
{
throw new Exception("Supplied file must be a .LNK file");
}
FileStream fileStream = File.Open(file,
FileMode.Open, FileAccess.Read);
using (System.IO.BinaryReader fileReader = new BinaryReader(fileStream))
{

// uint constant = fileReader.ReadUInt32(); // Reads the letter "L"
// byte[] guid = fileReader.ReadBytes(16); // Reads the GUID - another constant
fileStream.Seek(0x14, SeekOrigin.Begin); // Seek to flags
uint flags = fileReader.ReadUInt32(); // Read flags
//Results.Text += "<br>" + flags.ToString("x") + "<br>";
//Results.Text += "uflags & 1 = " + (uflags & 1) + "<br>";
if ((flags & 1) == 1) // Bit 1 set means we have to skip the shell item ID list
{
fileStream.Seek(0x4c,SeekOrigin.Begin);
// Seek to the end of the header
uint offset = fileReader.ReadUInt16(); // Read the length of the Shell item ID list
fileStream.Seek(offset, SeekOrigin.Current); // Seek past it (to the file locator info)
}
long fileInfoStartsAt = fileStream.Position; // Store the offset where the file info
// structure begins
uint totalStructLength = fileReader.ReadUInt32(); // read the length of the whole struct
fileStream.Seek(0xc, SeekOrigin.Current); // seek to offset to base pathname
uint fileOffset = fileReader.ReadUInt32(); // read offset to base pathname
// the offset is from the beginning of the file info struct (fileInfoStartsAt)
fileStream.Seek((fileInfoStartsAt + fileOffset), SeekOrigin.Begin); // Seek to beginning of
// base pathname (target)
long pathLength = (totalStructLength + fileInfoStartsAt) - fileStream.Position - 2; // read
// the base pathname. I don't need the 2 terminating nulls.
char [] linkTarget = fileReader.ReadChars((int)pathLength); // should be unicode safe
string target = new string(linkTarget); // convert the character array to a string
return target;
}
}
Edit: I'm glad this code is getting some use. Please consider it public domain, but bear in mind that I make no warranties about the fitness or merchantability of this code for any particular use or purpose. Apologies about the crazy formatting. If it works for you feel free to email me: jtatum@gmail.com.

Comments:
OMG! That's amazing!
 
Thanx a LOT!!! You made my day!! :-)
 
u just saved my life dude
 
It doesn't work with all .lnk files. On Windows 7, found the "Downloads" location worked great, as did various program shortcuts. However, the "Maintenance/Backup and Restore" shortcut caused the method to hang.
pathLength was a huge negative number for that shortcut.
 
Yes!! I can finally dump the iWSH Rutime! thx man!!
 
Post a Comment

Links to this post:

Create a Link



<< Home

This page is powered by Blogger. Isn't yours?