71

How do you create an application shortcut (.lnk file) in C# or using the .NET framework?

The result would be a .lnk file to the specified application or URL.

Charley Rathkopf
  • 4,720
  • 7
  • 38
  • 57

6 Answers6

61

It's not as simple as I'd have liked, but there is a great class call ShellLink.cs at vbAccelerator

This code uses interop, but does not rely on WSH.

Using this class, the code to create the shortcut is:

private static void configStep_addShortcutToStartupGroup()
{
    using (ShellLink shortcut = new ShellLink())
    {
        shortcut.Target = Application.ExecutablePath;
        shortcut.WorkingDirectory = Path.GetDirectoryName(Application.ExecutablePath);
        shortcut.Description = "My Shorcut Name Here";
        shortcut.DisplayMode = ShellLink.LinkDisplayMode.edmNormal;
        shortcut.Save(STARTUP_SHORTCUT_FILEPATH);
    }
}
Tamas Szoke
  • 5,426
  • 4
  • 24
  • 39
Charley Rathkopf
  • 4,720
  • 7
  • 38
  • 57
  • Anyone tried ShellLink on Vista? Looks like the code was written in 2003. – blak3r Jun 24 '09 at 01:25
  • It worked on Windows Server 2008 Standard 64bit SP2. I see no reason it wouldn't on Vista. – David Boike Jan 07 '11 at 19:49
  • 9
    Works on Windows 7 and even in 64-bit applications :) – fparadis2 Jul 19 '11 at 14:25
  • @ryan. Download the schelllink class from the link and use the code above to create the link. How much more of a working class do you need? – Charley Rathkopf Jan 19 '12 at 18:02
  • @Chasler I can't make it work in Pocket-PC. Hope you could have version for it. Thanks – fiberOptics Jan 20 '12 at 03:17
  • @ryan. I had no need to use this on a pocket-PC. If you find the solution, feel free to add it below. – Charley Rathkopf Feb 29 '12 at 01:36
  • 1
    @Ryan - Make sure you get the FileIcon.cs file as well.... the two files work hand and hand – DJ Burb Mar 05 '12 at 20:30
  • Direct link to code: http://www.vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects/Creating_and_Modifying_Shortcuts/ShellLink_Code_zip_ShellLink/ShellLink_cs.asp – Peter Aug 18 '12 at 04:54
  • 1
    Maybe it's a stupid question, but how to add **ShellLink** to project? I've downloaded it and added to a new folder **Libraries**. But in the code **using (ShellLink shortcut = new ShellLink())** it can't find **ShellLink**. – Amazing User Apr 19 '14 at 18:53
  • Excuse my ignorance, but just out of curiosity, what is wrong with WSH? Or perhaps why is not relying on it a plus? – Tristan McPherson Sep 22 '14 at 06:02
  • 2
    I'd just like to point out that this method has limitations in .NET I ended up having to use the other answer below which uses dynamics and WSH. The problem appears to be related to UAC: http://stackoverflow.com/questions/2934420/why-do-i-get-e-accessdenied-when-reading-public-shortcuts-through-shell32 So the issues is that the COM interface requires admin access, which your end users may not have. If you know they have access then it's not an issue. However, in cases where your users do not have admin access, the WSH with Dyanmics approach below works. – SomeInternetGuy Oct 21 '14 at 16:00
59

Nice and clean. (.NET 4.0)

Type t = Type.GetTypeFromCLSID(new Guid("72C24DD5-D70A-438B-8A42-98424B88AFB8")); //Windows Script Host Shell Object
dynamic shell = Activator.CreateInstance(t);
try{
    var lnk = shell.CreateShortcut("sc.lnk");
    try{
        lnk.TargetPath = @"C:\something";
        lnk.IconLocation = "shell32.dll, 1";
        lnk.Save();
    }finally{
        Marshal.FinalReleaseComObject(lnk);
    }
}finally{
    Marshal.FinalReleaseComObject(shell);
}

That's it, no additional code needed. CreateShortcut can even load shortcut from file, so properties like TargetPath return existing information. Shortcut object properties.

Also possible this way for versions of .NET unsupporting dynamic types. (.NET 3.5)

Type t = Type.GetTypeFromCLSID(new Guid("72C24DD5-D70A-438B-8A42-98424B88AFB8")); //Windows Script Host Shell Object
object shell = Activator.CreateInstance(t);
try{
    object lnk = t.InvokeMember("CreateShortcut", BindingFlags.InvokeMethod, null, shell, new object[]{"sc.lnk"});
    try{
        t.InvokeMember("TargetPath", BindingFlags.SetProperty, null, lnk, new object[]{@"C:\whatever"});
        t.InvokeMember("IconLocation", BindingFlags.SetProperty, null, lnk, new object[]{"shell32.dll, 5"});
        t.InvokeMember("Save", BindingFlags.InvokeMethod, null, lnk, null);
    }finally{
        Marshal.FinalReleaseComObject(lnk);
    }
}finally{
    Marshal.FinalReleaseComObject(shell);
}
IS4
  • 11,945
  • 2
  • 47
  • 86
  • 2
    Very clean. This would be the top answer if the question was asked again. – Damien Jan 08 '14 at 09:07
  • This will not be able to create a shortcut whose name has Unicode characters in it. Tested on Win7 with .NET 4.0. The COM object replaces the Unicode characters with question marks, which aren't valid in a file name. – Walter Wilfinger Feb 21 '14 at 21:54
  • Not a big deal, you can rename the file after `.Save` anyway, but thanks for notifying. – IS4 Feb 23 '14 at 10:32
  • Thank you, I was searching a long time for this. More parameters can be found here: http://msdn.microsoft.com/en-us/library/xsy6k3ys(v=vs.84).aspx – Justin Sep 08 '14 at 09:40
  • Thank you, I ended up using the 4.0 solution after discovering that the Shell COM method has limitations from my end users. This lead me to http://stackoverflow.com/questions/2934420/why-do-i-get-e-accessdenied-when-reading-public-shortcuts-through-shell32 which briefly lead me to think I had no solution. This Wsh solution worked exceptionally well and was a simple copy/paste. – SomeInternetGuy Oct 21 '14 at 16:02
  • it looks like your second example will work in .NET Core even though the dynamic way does not. – Dave Cousineau May 10 '23 at 21:30
  • 1
    @DaveCousineau `System.__ComObject` is the correct type, denoting a wrapper around a particular COM object. .NET is supposed to be able to use `dynamic` to query for `IDispatch` supported by the COM object and invoke its methods, but .NET Core did not implement it [until .NET 5](https://github.com/dotnet/runtime/pull/33060). – IS4 May 11 '23 at 14:19
13

I found something like this:

private void appShortcutToDesktop(string linkName)
{
    string deskDir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);

    using (StreamWriter writer = new StreamWriter(deskDir + "\\" + linkName + ".url"))
    {
        string app = System.Reflection.Assembly.GetExecutingAssembly().Location;
        writer.WriteLine("[InternetShortcut]");
        writer.WriteLine("URL=file:///" + app);
        writer.WriteLine("IconIndex=0");
        string icon = app.Replace('\\', '/');
        writer.WriteLine("IconFile=" + icon);
        writer.Flush();
    }
}

Original code at sorrowman's article "url-link-to-desktop"

p.campbell
  • 98,673
  • 67
  • 256
  • 322
Anuraj
  • 18,859
  • 7
  • 53
  • 79
  • 12
    Given the choice between interop / wsh or reverse engineering the file format i would choose the latter. I think it is a pretty safe bet they won't change the format anytime soon. – chrisortman Apr 06 '11 at 13:29
  • 18
    Anuraj: You are cheating - this does not create a LNK but a URL file. – Helge Klein Aug 26 '11 at 11:46
  • @HelgeKlein Its OK if you [Registered your Application to use a URI Scheme](http://msdn.microsoft.com/en-us/library/aa767914(VS.85).aspx) – Jeremy Thompson Jan 07 '14 at 04:20
  • This is so simple. I don't care that it is a .url file instead of a .lnk assuming it ends up doing the same thing. Why wouldn't I use the simplest solution? I tested it for my purposes and it seems to work just fine. I find the only line that is really needed is "URL=" for my purposes. – Frank T. Clark Jun 03 '15 at 20:57
  • Not working on Windows 10 x64:"The target "" of this Internet Shortcut is not valid ..." . I created internet link to a web resource and changed it to my exe path in Properties->Web Document->Url - it launche the app. Also, i've checked the format of windows created internet link and it is different (e.g. has some GUID field). Thus, this is not a valid format. P.S. It is better to use Uri and Uri.AbsoluteUri rather than strings in this case. – aderesh Dec 16 '16 at 20:02
1

Donwload IWshRuntimeLibrary

You also need to import of COM library IWshRuntimeLibrary. Right click on your project -> add reference -> COM -> IWshRuntimeLibrary -> add and then use the following code snippet.

private void createShortcutOnDesktop(String executablePath)
{
    // Create a new instance of WshShellClass

    WshShell lib = new WshShellClass();
    // Create the shortcut

    IWshRuntimeLibrary.IWshShortcut MyShortcut;


    // Choose the path for the shortcut
    string deskDir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
    MyShortcut = (IWshRuntimeLibrary.IWshShortcut)lib.CreateShortcut(@deskDir+"\\AZ.lnk");


    // Where the shortcut should point to

    //MyShortcut.TargetPath = Application.ExecutablePath;
    MyShortcut.TargetPath = @executablePath;


    // Description for the shortcut

    MyShortcut.Description = "Launch AZ Client";

    StreamWriter writer = new StreamWriter(@"D:\AZ\logo.ico");
    Properties.Resources.system.Save(writer.BaseStream);
    writer.Flush();
    writer.Close();
    // Location for the shortcut's icon           

    MyShortcut.IconLocation = @"D:\AZ\logo.ico";


    // Create the shortcut at the given path

    MyShortcut.Save();

}
imsome1
  • 1,182
  • 4
  • 22
  • 37
AZ_
  • 21,688
  • 25
  • 143
  • 191
  • I don't have that COM library on my Windows 8 PC. – Damien Jan 08 '14 at 09:10
  • @Damien There is something called Google.. lolx :D just kidding dear you can download it from here. I am also updating my question. Thanks for pointing it out http://originaldll.com/file/interop.iwshruntimelibrary.dll/20842.html – AZ_ Jan 08 '14 at 10:28
1

After surveying all possibilities I found on SO I've settled on ShellLink:

//Create new shortcut
using (var shellShortcut = new ShellShortcut(newShortcutPath)
{
     Path = path
     WorkingDirectory = workingDir,
     Arguments = args,
     IconPath = iconPath,
     IconIndex = iconIndex,
     Description = description,
})
{
    shellShortcut.Save();
}

//Read existing shortcut
using (var shellShortcut = new ShellShortcut(existingShortcut))
{
    path = shellShortcut.Path;
    args = shellShortcut.Arguments;
    workingDir = shellShortcut.WorkingDirectory;
    ...
}

Apart of being simple and effective, the author (Mattias Sjögren, MS MVP) is some sort of COM/PInvoke/Interop guru, and perusing his code I believe it is more robust than the alternatives.

It should be mentioned that shortcut files can also be created by several commandline utilities (which in turn can be easily invoked from C#/.NET). I never tried any of them, but I'd start with NirCmd (NirSoft have SysInternals-like quality tools).

Unfortunately NirCmd can't parse shortcut files (only create them), but for that purpose TZWorks lp seems capable. It can even format its output as csv. lnk-parser looks good too (it can output both HTML and CSV).

Ohad Schneider
  • 36,600
  • 15
  • 168
  • 198
  • 1
    Somewhat ironic given that link contains the text "webhost4life" but that ShellLink link is 404 :-( – noonand Jan 26 '15 at 12:09
  • @noonand indeed, and it seems the library wasn't cached on the Wayback Machine either. Fortunately I've kept a copy: https://onedrive.live.com/redir?resid=DED6DB63D5309C3D!98150&authkey=!AFaK2w3dATW3U7E&ithint=file%2czip – Ohad Schneider Jan 26 '15 at 21:05
  • What is it with people posting code as a zip? I can't find a copy of this library anywhere on the internet :) – caesay Apr 25 '22 at 16:54
  • @caesay here it is in a git repo (of the project where I used it) :) https://sourceforge.net/p/tvgamelauncher/code/ci/master/tree/TvGameLauncher/TvGameLauncherGUI/Interop/ShellLink/ – Ohad Schneider Apr 25 '22 at 23:24
0

Similar to IllidanS4's answer, using the Windows Script Host proved the be the easiest solution for me (tested on Windows 8 64 bit).

However, rather than importing the COM type manually through code, it is easier to just add the COM type library as a reference. Choose References->Add Reference..., COM->Type Libraries and find and add "Windows Script Host Object Model".

This imports the namespace IWshRuntimeLibrary, from which you can access:

WshShell shell = new WshShell();
IWshShortcut link = (IWshShortcut)shell.CreateShortcut(LinkPathName);
link.TargetPath=TargetPathName;
link.Save();

Credit goes to Jim Hollenhorst.

Community
  • 1
  • 1
Steven Jeuris
  • 18,274
  • 9
  • 70
  • 161