12

We have a network drive full of shortcuts (.lnk files) that point to folders and I need to traverse them programmatically in a C# Winforms app.

What practical options do I have?

Nate
  • 30,286
  • 23
  • 113
  • 184
user1231231412
  • 1,659
  • 2
  • 26
  • 42
  • 1
    Use the shell link interface: http://msdn.microsoft.com/en-us/library/windows/desktop/bb776891(v=vs.85).aspx – David Heffernan Dec 28 '11 at 20:09
  • 1
    What if the shortcut doesn't point to a file? – vcsjones Dec 28 '11 at 20:13
  • @vcsjones It can be skipped if it doesn't. Fortunately it's locked down and only accessed by the network engineers. – user1231231412 Dec 28 '11 at 20:16
  • @DavidHeffernan Do you know of any free wrappers in C# for this? – user1231231412 Dec 28 '11 at 20:19
  • type c# ishelllink into google and take it from there – David Heffernan Dec 28 '11 at 20:22
  • Do you just need to traverse them ? I mean the all those names of .INK files. The question only says so and may be we are complicating with manipulation of .Ink files. Please describe better. Just getting some file names should be a problem with Directory services but we dont what you really need in this scenario. – King Dec 28 '11 at 20:28
  • @Dumb Not sure I completely understand your comment, but this is a system maintained by another dept. and cannot be changed to another format. – user1231231412 Dec 28 '11 at 20:32
  • possible duplicate of [.NET read binary contents of .lnk file](http://stackoverflow.com/questions/2565885/net-read-binary-contents-of-lnk-file) – Hans Passant Dec 28 '11 at 20:33
  • @HansPassant It could be a duplicate but his code won't compile because of the missing references so I can't tell. – user1231231412 Dec 28 '11 at 20:37
  • @JonC, If you want to read the contents of the .Ink file, you can do so as Hans Passant has suggest. If you want to validate whether the link really points to a valid file and get that path, there is an answer by Billy. That's what I was confused. What exactly traversing meant ? You need the path names of the original file that this short cut points to ? Is it ? – King Dec 28 '11 at 20:38
  • It is spelled out explicitly in the answer, use "Add Reference" as indicated. – Hans Passant Dec 28 '11 at 20:46
  • @HansPassant You're correct it is "spelled out explicitly". When I follow the steps I get the message "Could not load file or assembly 'Shell32.dll' ... This may not be a managed file." I am able to add it via COM. – user1231231412 Dec 28 '11 at 20:58
  • Out of interest, how do you intend to handle shortcuts to folders that are invalid on the machine that is reading them? (Say someone uses a mapped drive, or adds a shortcut to a user specific location) – Deanna Dec 29 '11 at 23:40

5 Answers5

16

Add IWshRuntimeLibrary as a reference to your project. Add Reference, COM tab, Windows Scripting Host Object Model.

Here is how I get the properties of a shortcut:

IWshRuntimeLibrary.IWshShell wsh = new IWshRuntimeLibrary.WshShellClass();
IWshRuntimeLibrary.IWshShortcut sc = (IWshRuntimeLibrary.IWshShortcut)wsh.CreateShortcut(filename);

The shortcut object "sc" has a TargetPath property.

djdanlib
  • 21,449
  • 1
  • 20
  • 29
  • 6
    Thanks for your **simple and practical** suggestion and example and didn't just give me more info to dig through. One thing I would suggest to add to your answer is that you add a reference to the COM object "Windows Script Host Object Model" to get the IWshRuntimeLibrary. – user1231231412 Dec 28 '11 at 21:22
  • Just so that no one else have to waste so much time on stupid mistakes: filename in above example should of course be file.FullName if reading FileInfo, not file.Name. – Alex May 30 '14 at 04:42
  • 6
    I'll add that if you get an '_Interop type 'IWshRuntimeLibrary.WshShellClass' cannot be embedded. Use the applicable interface instead._' error on compiling, select IWshRuntimeLibrary in your references and set the 'Embed Interop Types' property from True to False. – Jay Riggs May 19 '15 at 23:43
3

If you do not wish to reference COM, and distribute the Interop.IWshRuntimeLibrary.dll with your product (remembering Jay Riggs "Embed Interop Types": False)

You can use the new dynamic COM instead.

private void Window_Drop(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(DataFormats.FileDrop))
    {
        string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
        dynamic shortcut;
        dynamic windowsShell;
        try
        {
            var file = files[0];
            if (Path.GetExtension(file)?.Equals(".lnk",StringComparison.OrdinalIgnoreCase) == true)
            {
                Type shellObjectType = Type.GetTypeFromProgID("WScript.Shell");
                windowsShell = Activator.CreateInstance(shellObjectType);
                shortcut = windowsShell.CreateShortcut(file);
                file = shortcut.TargetPath;
                // Release the COM objects
                shortcut = null;
                windowsShell = null;
            }
            //
            // <use file>...
            //
        }
        finally
        {
            // Release the COM objects
            shortcut = null;
            windowsShell = null;
        }
    }
}
Michael
  • 86
  • 4
1

I know it is not the correct way and that lnk file structures can change etc., but this is what I do:

    private static string LnkToFile(string fileLink)
    {
        string link = File.ReadAllText(fileLink);
        int i1 = link.IndexOf("DATA\0");
        if (i1 < 0)
            return null;
        i1 += 5;
        int i2 = link.IndexOf("\0", i1);
        if (i2 < 0)
            return link.Substring(i1);
        else
            return link.Substring(i1, i2 - i1);
    }
Meine
  • 53
  • 8
0
  1. Load the file using the COM IPersistFile interface.
  2. Do a QueryInterface on the result to turn it into an IShellLink interface.
  3. Call IShellLink::GetPath

As far as I am aware you can have .NET generate classes conforming to each of these interfaces for you using the "Add Reference" dialog box.

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
0

The IShellLink interface lets you manipulate .lnk files, though it's a bit of a pain to use from C#.

This article has some code implementing the necessary interop gubbins.

Update

You can find the code from the article here but the page doesn't seem to work in Firefox. It does work in IE.

arx
  • 16,686
  • 2
  • 44
  • 61