23

How do you get the directory target of a shortcut folder? I've search everywhere and only finds target of shortcut file.

H.B.
  • 166,899
  • 29
  • 327
  • 400
Phu Minh Pham
  • 1,025
  • 7
  • 21
  • 38

7 Answers7

32

I think you will need to use COM and add a reference to "Microsoft Shell Control And Automation", as described in this blog post:

Here's an example using the code provided there:

namespace Shortcut
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using Shell32;

    class Program
    {
        public static string GetShortcutTargetFile(string shortcutFilename)
        {
            string pathOnly = System.IO.Path.GetDirectoryName(shortcutFilename);
            string filenameOnly = System.IO.Path.GetFileName(shortcutFilename);

            Shell shell = new Shell();
            Folder folder = shell.NameSpace(pathOnly);
            FolderItem folderItem = folder.ParseName(filenameOnly);
            if (folderItem != null)
            {
                Shell32.ShellLinkObject link = (Shell32.ShellLinkObject)folderItem.GetLink;
                return link.Path;
            }

            return string.Empty;
        }

        static void Main(string[] args)
        {
            const string path = @"C:\link to foobar.lnk";
            Console.WriteLine(GetShortcutTargetFile(path));
        }
    }
}
jordanhill123
  • 4,142
  • 2
  • 31
  • 40
Luke Girvin
  • 13,221
  • 9
  • 64
  • 84
  • Thanks! Now I just need to find out how to look for a shortcuf folder programmaticaly :) – Phu Minh Pham Feb 24 '12 at 12:11
  • 3
    I work on Windows 7 64 bit, and it fails in finding shortcut to VirtualBox installed in `C:\Program Files\Oracle\VirtualBoxOSX`. It kept returning the target to be in `C:\Program Files (x86)\Oracle\VirtualBoxOSX\VirtualBox.exe`. Any explanation on this behaviour? – swdev Mar 11 '14 at 01:08
  • 2
    Using Shell32 with this method only allow in single thread application. You have to include [STAThread] in main entry point. You will get exception in unit testing with this code because unit testing is not allow STAThread. see [answer](http://stackoverflow.com/questions/14543340/calling-shell32-dll-from-net-windows-service). There is also solution to run this code in unit testing see http://haacked.com/archive/2014/11/20/xunit-and-sta/ – yancyn Aug 19 '16 at 05:50
7

In windows 10 it needs to be done like this, first add COM reference to "Microsoft Shell Control And Automation"

// new way for windows 10
string targetname;
string pathOnly = System.IO.Path.GetDirectoryName(LnkFileName);
string filenameOnly = System.IO.Path.GetFileName(LnkFileName);

Shell shell = new Shell();
Shell32.Folder folder = shell.NameSpace(pathOnly);
FolderItem folderItem = folder.ParseName(filenameOnly);
if (folderItem != null) {
  Shell32.ShellLinkObject link = (Shell32.ShellLinkObject)folderItem.GetLink;
  targetname = link.Target.Path;  // <-- main difference
  if (targetname.StartsWith("{")) { // it is prefixed with {54A35DE2-guid-for-program-files-x86-QZ32BP4}
    int endguid = targetname.IndexOf("}");
    if (endguid > 0) {
      targetname = "C:\\program files (x86)" + targetname.Substring(endguid + 1);
  }
}
EJ Thayer
  • 151
  • 2
  • 3
0

An even simpler way to get the linked path that I use is:

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);
}

But it will of course break if the lnk-file format changes.

Meine
  • 53
  • 8
  • 1
    This only works for trivial `*.lnk` files - it won't work for `*.lnk` files created by Windows Installer (which don't point to files anyway) as well as certain other kinds of `*.lnk` files that don't store the path as a single string - unfortunately the binary file format is kinda complex: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/16cb4ca1-9339-4d0c-a68d-bf1d6cc0f943 – Dai Feb 25 '20 at 11:31
  • Didn't work in my case, the function already return null on my .lnk files. – Zyo Aug 27 '21 at 18:47
0
public static string GetLnkTarget(string lnkPath)
{
    var shl = new Shell();
    var dir = shl.NameSpace(Path.GetDirectoryName(lnkPath));
    var itm = dir.Items().Item(Path.GetFileName(lnkPath));
    var lnk = (ShellLinkObject)itm.GetLink;

    if (!File.Exists(lnk.Path)){
       return lnk.Path.Replace("Program Files (x86)", "Program Files");
    }
    else{
       return lnk.Path;
    }
}
M1zHu0
  • 1
  • 1
  • Please explain your solution. Answers which do not have an explanation and are only code get flagged as low effort. – cursorrux Sep 05 '21 at 11:09
  • Please add further details to expand on your answer, such as working code or documentation citations. – Community Sep 05 '21 at 11:09
-1

if you want find your application path that has shortcut on desktop, an easy way that i use, is the following:

Process.GetCurrentProcess().MainModule.FileName.Substring(0, Process.GetCurrentProcess().MainModule.FileName.LastIndexOf("\\")

this code return any exe path that is running,Regardless that who requested file

Mohsen.Sharify
  • 259
  • 4
  • 11
-1

Thanks to Mohsen.Sharify's answer I got more neat piece of code:

var fileName = Process.GetCurrentProcess().MainModule.FileName;
var folderName = Path.Combine(fileName, ".."); //origin folder
Barabas
  • 912
  • 8
  • 19
  • This does not answer the question as such, but is "just" a way of getting to the folder were the currently running executable file is placed, I think. – peSHIr Jul 20 '22 at 07:50
-3

All file shortcuts have a .lnk file extension you can check for. Using a string for example, you could use string.EndsWith(".lnk") as a filter.

All URL shortcuts have a .url file extension, so you will need to account for those as well if needed.

  • 2
    OP asked how to get the target directory of the shortcut, not how to check if it is a shortcut. –  Jan 25 '17 at 02:47