I want to create a shortcut pointing to some EXE file, on the desktop, using .NET Framework 3.5 and relying on an official Windows API. How can I do that?
-
1Using the Windows Script Host Object Model from Rustam Irzaev is the only reliable one for a proper shortcut. ayush: This technique misses a bunch of features like hot keys and descriptions. Thorarin: ShellLink works well in most cases, but notably it does not work in Windows XP and creates invalid shortcuts. Simon Mourier: This was very promising, but creates invalid shortcuts in Windows 8. – BrutalDev May 17 '13 at 19:07
-
2The answer from Simon Mourier is the best answer here. The only correct and bullet proof way to create shortcuts is using the same API that the operating system uses and this is the IShellLink interface. Do not use Windows Script Host or create Web links! Simon Mourier shows how to do this with 6 lines of code. Anybody who had problems with this method SURELY passed invalid paths. I tested his code on Windows XP, 7 and 10. Compile your app as "Any CPU" to avoid problems with 32/64 bit Windows which use different folders for Program Files, et al. – Elmue Mar 31 '20 at 15:50
-
I can attest that the reason Simon Mourier answer wasn't working for me was because my paths were invalid. Make sure to check for extra or missing "\\". Worked after fixing that mistake. – hallibut Jan 25 '22 at 22:35
15 Answers
With additional options such as hotkey, description etc.
At first, Project > Add Reference > COM > Windows Script Host Object Model.
using IWshRuntimeLibrary;
private void CreateShortcut()
{
object shDesktop = (object)"Desktop";
WshShell shell = new WshShell();
string shortcutAddress = (string)shell.SpecialFolders.Item(ref shDesktop) + @"\Notepad.lnk";
IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(shortcutAddress);
shortcut.Description = "New shortcut for a Notepad";
shortcut.Hotkey = "Ctrl+Shift+N";
shortcut.TargetPath = Environment.GetFolderPath(Environment.SpecialFolder.System) + @"\notepad.exe";
shortcut.Save();
}

- 20,522
- 15
- 48
- 66

- 1,792
- 2
- 18
- 18
-
2This was really close for me. I needed to add the .exe's directory to the "WorkingDirectory" property on shortcut. (shortcut.WorkingDirectory) +1 – samuelesque May 16 '14 at 19:11
-
4To specify an icon index (in IconLocation), use a value like "path_to_icon_file,#", where # is the icon index. See https://msdn.microsoft.com/en-us/library/xsy6k3ys(v=vs.84).aspx – Chris Mar 22 '16 at 21:15
-
1for argument: shortcut.Arguments = "Seta Map mp_crash"; https://stackoverflow.com/a/18491229/2155778 – Zolfaghari Aug 21 '17 at 16:11
-
7Environment.SpecialFolders.System -- doesn't exist... Environment.SpecialFolder.System -- works. – JSWulf Oct 27 '17 at 21:18
-
for must of the time you also need to add Microsoft.CSharp as reference. – l1nuxuser Aug 01 '18 at 09:43
-
1To use the link for StartMenu, use the code `object shStartMenu = (object)"StartMenu";`. Also there is the option to have the link for all users, using the keyword 'common' as prefix. – Nasenbaer Oct 09 '18 at 09:07
URL shortcut
private void urlShortcutToDesktop(string linkName, string linkUrl)
{
string deskDir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
using (StreamWriter writer = new StreamWriter(deskDir + "\\" + linkName + ".url"))
{
writer.WriteLine("[InternetShortcut]");
writer.WriteLine("URL=" + linkUrl);
}
}
Application shortcut
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);
}
}
Also check this example.
If you want to use some API specific functions then you will want to use the IShellLink interface
as well as the IPersistFile interface
(through COM interop).
Here is an article that goes into detail what you need to do it, as well as sample code.
-
1These above are working fine. But i want to create shortcut through some API functions like DllImport("coredll.dll")] public static extern int SHCreateShortcut(StringBuilder szShortcut, StringBuilder szTarget); – Vipin Arora Feb 04 '11 at 12:04
-
@Vipin why? Is there any reason why any of the above solutions are not good enough? – alex Feb 04 '11 at 12:19
-
8nitpicking : you could remove the flush() line as the Using block's termination should take care of it for you – Newtopian Jun 26 '12 at 15:49
-
5I have had a lot of problems with this method ... Windows tends to cache the shortcut definition somewhere ... create a shortcut like this, delete it, then create one with the same name but a different URL ... chances are windows will open the old deleted URL when you click the shortcut. Rustam's answer below (using .lnk instead of .url) solved this problem for me – TCC Sep 24 '13 at 17:13
-
1Awesome answer. Much better than the horrid COM plumbing you have to deal with when using .lnk files. – James Ko Nov 09 '15 at 03:34
-
I think it would be advisable to use 'string app = System.Reflection.Assembly.GetEntryAssembly().Location' otherwise this could pick up the library location, and not the EXE entry assembly. – Jon Barker Mar 04 '16 at 18:33
-
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:05
-
1Doesn't work if you have arguments. For example: myprogram.exe Param1 Param2 – Neal Bailey Sep 04 '17 at 14:16
-
Originally tried just the .lnk style but the .url was definitely needed for internet shortcuts. Internet shortcuts would still work in the .link but would look and act like system shortcuts. (win 7 64 bit) – JSWulf Nov 30 '17 at 23:38
-
-
-
You may get problems using this approach. I strongly recommend to use the simple code of Simon Mourier instead. This is the only bullet proof way. – Elmue Mar 31 '20 at 15:25
-
Here is a piece of code that has no dependency on an external COM object (WSH), and supports 32-bit and 64-bit programs:
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
namespace TestShortcut
{
class Program
{
static void Main(string[] args)
{
IShellLink link = (IShellLink)new ShellLink();
// setup shortcut information
link.SetDescription("My Description");
link.SetPath(@"c:\MyPath\MyProgram.exe");
// save it
IPersistFile file = (IPersistFile)link;
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
file.Save(Path.Combine(desktopPath, "MyLink.lnk"), false);
}
}
[ComImport]
[Guid("00021401-0000-0000-C000-000000000046")]
internal class ShellLink
{
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214F9-0000-0000-C000-000000000046")]
internal interface IShellLink
{
void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out IntPtr pfd, int fFlags);
void GetIDList(out IntPtr ppidl);
void SetIDList(IntPtr pidl);
void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
void GetHotkey(out short pwHotkey);
void SetHotkey(short wHotkey);
void GetShowCmd(out int piShowCmd);
void SetShowCmd(int iShowCmd);
void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon);
void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
void Resolve(IntPtr hwnd, int fFlags);
void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
}
}

- 132,049
- 21
- 248
- 298
-
@BrutalDev - What doesn't work? I've tested it on Windows 8 x64 and it does works. – Simon Mourier May 28 '13 at 12:53
-
Also running Win8 x64, copied the code sample above exactly as is, it creates an icon on my desktop with no path. Executing the link just opens explorer to the desktop. This is a similar issue I had with ShellLink.cs but in Windows XP/2003. The only example that definitively works across all Windows versions was Rustam Irzaev's using WSHOM as I mentioned in my comment to the main question: "This was very promising, but creates invalid shortcuts in Windows 8" – BrutalDev May 31 '13 at 17:39
-
I got this to work on Windows 8.1 x64, but the code as given here right now doesn't have a definition for IPersistFile. I had to copy that over from the [ShellLink.cs](http://www.vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects/Creating_and_Modifying_Shortcuts/article.asp) post to get it to work. – Walter Wilfinger Feb 21 '14 at 21:58
-
2I don't see any tangible reason why this wouldn't work. Anyway, IPersistFile is available out-of-the-box in System.Runtime.InteropServices.ComTypes – Simon Mourier Feb 21 '14 at 22:21
-
-
2This solution does not set correct icon using `SetIconLocation` on 64-bit Windows 10 with 32-bit executable. Solution is described here: https://stackoverflow.com/a/39282861 and I also suspect, that it is the same problem with Windows 8 all other are reffering to. It may be related to 32-bit exe files on 64-bit Windows. – Maris B. Nov 20 '19 at 13:27
-
@MarisB. I have no problem setting an icon, on a 64-bit Windows with a 32-bit process, with this code and the SetIconLocation method. Can you provide a code that doesn't work (or possibly ask another question)? – Simon Mourier Nov 21 '19 at 08:02
-
@SimonMourier. If you use `SetIconLocation` on 64-bit Windows from 32-bit process, and then examine .lnk file, you will see that it points to wrong Program Files folder - to 64-bit folder, instead of 32-bit. Try your code with a single line added - SetIconLocation. More info here: https://stackoverflow.com/questions/2976489/ishelllinkseticonlocation-translates-my-icon-path-into-program-files-which-i – Maris B. Nov 21 '19 at 10:59
-
2@MarisB. Like I said, I've tested what you say SetIconLocation, 64 vs 32 with my code above and it works fine. If you have a problem with paths, this is another story. This question is not about Program Files. – Simon Mourier Nov 21 '19 at 11:05
-
For people missing the declaration of `IPersistFile`, it is located in System.Runtime.InteropServices.ComTypes in mscorlib.dll. – Doctor Jones Nov 29 '19 at 13:17
-
@ReinstateMonica - yep, it's in the using statements list. I rarely add needed usings because it's often useless, but here it's important to know. – Simon Mourier Nov 29 '19 at 16:25
-
Doesn't work in my environment. link.SetPath(LinkTarget) throws an exception (translated from German) "Interface not registered\r\n\r\nThe proxy registration for the IID {ADD8BA80-002B-11D0-8F0F-00C04FD7D062} was no found." Note that IShellLink works otherwise, if I comment out this single line of code, an (empty) shortcut file gets created in the target directory. I can also set other properties, like "SetWorkingDirectory", and the according property in the .lnk file get set to the value given. It's only the SetPath property which seems to fail. (VS 2019 on Windows 10 x64) – Nimral Aug 17 '20 at 11:01
-
ADD8BA80-002B-11D0-8F0F-00C04FD7D062 is IDelegateFolder. It's possible that you have a 3rd party extensions that messes with the shell. – Simon Mourier Aug 17 '20 at 11:59
-
may i ask if you could also add to the answer how to get the target path of existing shorcut file? – newbieguy Sep 17 '20 at 09:31
-
@newbieguy - this is an other question, but roughly: `link = (IShellLink)new ShellLink();file = (IPersistFile)link;file.Load(...);link.GetPath(...)` – Simon Mourier Sep 17 '20 at 15:44
You can use this ShellLink.cs class to create the shortcut.
To get the desktop directory, use:
var dir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
or use Environment.SpecialFolder.CommonDesktopDirectory
to create it for all users.

- 47,289
- 11
- 75
- 111
-
6@Vipin: if a solution works for you, it is customary to upvote it. Also, you should select the best solution and accept it as the answer to your problem. – Thorarin Feb 08 '11 at 10:46
-
-
1@zwcloud This code doesn't overwrite anything because it doesn't do anything. It's just telling you what classes and methods to use to work with shortcuts. If your code is overwriting the exe that's on you. I would look at how you actually create the lnk file to see why it's destroying your exe. – Cdaragorn Nov 14 '19 at 18:15
Without additional reference:
using System;
using System.Runtime.InteropServices;
public class Shortcut
{
private static Type m_type = Type.GetTypeFromProgID("WScript.Shell");
private static object m_shell = Activator.CreateInstance(m_type);
[ComImport, TypeLibType((short)0x1040), Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B")]
private interface IWshShortcut
{
[DispId(0)]
string FullName { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0)] get; }
[DispId(0x3e8)]
string Arguments { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3e8)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3e8)] set; }
[DispId(0x3e9)]
string Description { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3e9)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3e9)] set; }
[DispId(0x3ea)]
string Hotkey { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3ea)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3ea)] set; }
[DispId(0x3eb)]
string IconLocation { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3eb)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3eb)] set; }
[DispId(0x3ec)]
string RelativePath { [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3ec)] set; }
[DispId(0x3ed)]
string TargetPath { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3ed)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3ed)] set; }
[DispId(0x3ee)]
int WindowStyle { [DispId(0x3ee)] get; [param: In] [DispId(0x3ee)] set; }
[DispId(0x3ef)]
string WorkingDirectory { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3ef)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3ef)] set; }
[TypeLibFunc((short)0x40), DispId(0x7d0)]
void Load([In, MarshalAs(UnmanagedType.BStr)] string PathLink);
[DispId(0x7d1)]
void Save();
}
public static void Create(string fileName, string targetPath, string arguments, string workingDirectory, string description, string hotkey, string iconPath)
{
IWshShortcut shortcut = (IWshShortcut)m_type.InvokeMember("CreateShortcut", System.Reflection.BindingFlags.InvokeMethod, null, m_shell, new object[] { fileName });
shortcut.Description = description;
shortcut.Hotkey = hotkey;
shortcut.TargetPath = targetPath;
shortcut.WorkingDirectory = workingDirectory;
shortcut.Arguments = arguments;
if (!string.IsNullOrEmpty(iconPath))
shortcut.IconLocation = iconPath;
shortcut.Save();
}
}
To create Shortcut on Desktop:
string lnkFileName = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Notepad.lnk");
Shortcut.Create(lnkFileName,
System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "notepad.exe"),
null, null, "Open Notepad", "Ctrl+Shift+N", null);

- 218
- 2
- 7
I Use simply for my app:
using IWshRuntimeLibrary; // > Ref > COM > Windows Script Host Object
...
private static void CreateShortcut()
{
string link = Environment.GetFolderPath( Environment.SpecialFolder.Desktop )
+ Path.DirectorySeparatorChar + Application.ProductName + ".lnk";
var shell = new WshShell();
var shortcut = shell.CreateShortcut( link ) as IWshShortcut;
shortcut.TargetPath = Application.ExecutablePath;
shortcut.WorkingDirectory = Application.StartupPath;
//shortcut...
shortcut.Save();
}

- 349
- 3
- 6
Use ShellLink.cs at vbAccelerator to create your shortcut easily !
private static void AddShortCut()
{
using (ShellLink shortcut = new ShellLink())
{
shortcut.Target = Application.ExecutablePath;
shortcut.WorkingDirectory = Path.GetDirectoryName(Application.ExecutablePath);
shortcut.Description = "My Shorcut";
shortcut.DisplayMode = ShellLink.LinkDisplayMode.edmNormal;
shortcut.Save(SHORTCUT_FILEPATH);
}
}

- 11,849
- 2
- 36
- 54
-
3That link is now dead, but you can find an archived version of it [here](https://web.archive.org/web/20150414052035/http://www.vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects/Creating_and_Modifying_Shortcuts/article.asp). – p.s.w.g Dec 17 '15 at 18:29
Here's my code:
public static class ShortcutHelper
{
#region Constants
/// <summary>
/// Default shortcut extension
/// </summary>
public const string DEFAULT_SHORTCUT_EXTENSION = ".lnk";
private const string WSCRIPT_SHELL_NAME = "WScript.Shell";
#endregion
/// <summary>
/// Create shortcut in current path.
/// </summary>
/// <param name="linkFileName">shortcut name(include .lnk extension.)</param>
/// <param name="targetPath">target path</param>
/// <param name="workingDirectory">working path</param>
/// <param name="arguments">arguments</param>
/// <param name="hotkey">hot key(ex: Ctrl+Shift+Alt+A)</param>
/// <param name="shortcutWindowStyle">window style</param>
/// <param name="description">shortcut description</param>
/// <param name="iconNumber">icon index(start of 0)</param>
/// <returns>shortcut file path.</returns>
/// <exception cref="System.IO.FileNotFoundException"></exception>
public static string CreateShortcut(
string linkFileName,
string targetPath,
string workingDirectory = "",
string arguments = "",
string hotkey = "",
ShortcutWindowStyles shortcutWindowStyle = ShortcutWindowStyles.WshNormalFocus,
string description = "",
int iconNumber = 0)
{
if (linkFileName.Contains(DEFAULT_SHORTCUT_EXTENSION) == false)
{
linkFileName = string.Format("{0}{1}", linkFileName, DEFAULT_SHORTCUT_EXTENSION);
}
if (File.Exists(targetPath) == false)
{
throw new FileNotFoundException(targetPath);
}
if (workingDirectory == string.Empty)
{
workingDirectory = Path.GetDirectoryName(targetPath);
}
string iconLocation = string.Format("{0},{1}", targetPath, iconNumber);
if (Environment.Version.Major >= 4)
{
Type shellType = Type.GetTypeFromProgID(WSCRIPT_SHELL_NAME);
dynamic shell = Activator.CreateInstance(shellType);
dynamic shortcut = shell.CreateShortcut(linkFileName);
shortcut.TargetPath = targetPath;
shortcut.WorkingDirectory = workingDirectory;
shortcut.Arguments = arguments;
shortcut.Hotkey = hotkey;
shortcut.WindowStyle = shortcutWindowStyle;
shortcut.Description = description;
shortcut.IconLocation = iconLocation;
shortcut.Save();
}
else
{
Type shellType = Type.GetTypeFromProgID(WSCRIPT_SHELL_NAME);
object shell = Activator.CreateInstance(shellType);
object shortcut = shellType.InvokeMethod("CreateShortcut", shell, linkFileName);
Type shortcutType = shortcut.GetType();
shortcutType.InvokeSetMember("TargetPath", shortcut, targetPath);
shortcutType.InvokeSetMember("WorkingDirectory", shortcut, workingDirectory);
shortcutType.InvokeSetMember("Arguments", shortcut, arguments);
shortcutType.InvokeSetMember("Hotkey", shortcut, hotkey);
shortcutType.InvokeSetMember("WindowStyle", shortcut, shortcutWindowStyle);
shortcutType.InvokeSetMember("Description", shortcut, description);
shortcutType.InvokeSetMember("IconLocation", shortcut, iconLocation);
shortcutType.InvokeMethod("Save", shortcut);
}
return Path.Combine(System.Windows.Forms.Application.StartupPath, linkFileName);
}
private static object InvokeSetMember(this Type type, string methodName, object targetInstance, params object[] arguments)
{
return type.InvokeMember(
methodName,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty,
null,
targetInstance,
arguments);
}
private static object InvokeMethod(this Type type, string methodName, object targetInstance, params object[] arguments)
{
return type.InvokeMember(
methodName,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod,
null,
targetInstance,
arguments);
}
/// <summary>
/// windows styles
/// </summary>
public enum ShortcutWindowStyles
{
/// <summary>
/// Hide
/// </summary>
WshHide = 0,
/// <summary>
/// NormalFocus
/// </summary>
WshNormalFocus = 1,
/// <summary>
/// MinimizedFocus
/// </summary>
WshMinimizedFocus = 2,
/// <summary>
/// MaximizedFocus
/// </summary>
WshMaximizedFocus = 3,
/// <summary>
/// NormalNoFocus
/// </summary>
WshNormalNoFocus = 4,
/// <summary>
/// MinimizedNoFocus
/// </summary>
WshMinimizedNoFocus = 6,
}
}

- 1,023
- 15
- 24

- 1,795
- 1
- 22
- 22
Here's a (Tested) Extension Method, with comments to help you out.
using IWshRuntimeLibrary;
using System;
namespace Extensions
{
public static class XShortCut
{
/// <summary>
/// Creates a shortcut in the startup folder from a exe as found in the current directory.
/// </summary>
/// <param name="exeName">The exe name e.g. test.exe as found in the current directory</param>
/// <param name="startIn">The shortcut's "Start In" folder</param>
/// <param name="description">The shortcut's description</param>
/// <returns>The folder path where created</returns>
public static string CreateShortCutInStartUpFolder(string exeName, string startIn, string description)
{
var startupFolderPath = Environment.SpecialFolder.Startup.GetFolderPath();
var linkPath = startupFolderPath + @"\" + exeName + "-Shortcut.lnk";
var targetPath = Environment.CurrentDirectory + @"\" + exeName;
XFile.Delete(linkPath);
Create(linkPath, targetPath, startIn, description);
return startupFolderPath;
}
/// <summary>
/// Create a shortcut
/// </summary>
/// <param name="fullPathToLink">the full path to the shortcut to be created</param>
/// <param name="fullPathToTargetExe">the full path to the exe to 'really execute'</param>
/// <param name="startIn">Start in this folder</param>
/// <param name="description">Description for the link</param>
public static void Create(string fullPathToLink, string fullPathToTargetExe, string startIn, string description)
{
var shell = new WshShell();
var link = (IWshShortcut)shell.CreateShortcut(fullPathToLink);
link.IconLocation = fullPathToTargetExe;
link.TargetPath = fullPathToTargetExe;
link.Description = description;
link.WorkingDirectory = startIn;
link.Save();
}
}
}
And an example of use:
XShortCut.CreateShortCutInStartUpFolder(THEEXENAME,
Environment.CurrentDirectory,
"Starts some executable in the current directory of application");
1st parm sets the exe name (found in the current directory) 2nd parm is the "Start In" folder and 3rd parm is the shortcut description.
The naming convention of the link leaves no ambiguity as to what it will do. To test the link just double click it.
Final Note: the application itself (target) must have an ICON image associated with it. The link is easily able to locate the ICON within the exe. If the target application has more than one icon, you may open the link's properties and change the icon to any other found in the exe.
-
I'm getting a error msg that .GetFolderPath() does not exists. Same for XFile.Delete. What am I missing? – RalphF Sep 18 '17 at 04:22
-
Does error happen here? Environment.SpecialFolder.Startup.GetFolderPath(); – JWP Sep 18 '17 at 16:24
I use "Windows Script Host Object Model" reference to create shortcut.
and to create shortcut on specific location:
void CreateShortcut(string linkPath, string filename)
{
// Create shortcut dir if not exists
if (!Directory.Exists(linkPath))
Directory.CreateDirectory(linkPath);
// shortcut file name
string linkName = Path.ChangeExtension(Path.GetFileName(filename), ".lnk");
// COM object instance/props
IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell();
IWshRuntimeLibrary.IWshShortcut sc = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(linkName);
sc.Description = "some desc";
//shortcut.IconLocation = @"C:\...";
sc.TargetPath = linkPath;
// save shortcut to target
sc.Save();
}

- 456
- 4
- 5
I have created a wrapper class based on Rustam Irzaev's answer with use of IWshRuntimeLibrary.
IWshRuntimeLibrary -> References -> COM > Windows Script Host Object Model
using System;
using System.IO;
using IWshRuntimeLibrary;
using File = System.IO.File;
public static class Shortcut
{
public static void CreateShortcut(string originalFilePathAndName, string destinationSavePath)
{
string fileName = Path.GetFileNameWithoutExtension(originalFilePathAndName);
string originalFilePath = Path.GetDirectoryName(originalFilePathAndName);
string link = destinationSavePath + Path.DirectorySeparatorChar + fileName + ".lnk";
var shell = new WshShell();
var shortcut = shell.CreateShortcut(link) as IWshShortcut;
if (shortcut != null)
{
shortcut.TargetPath = originalFilePathAndName;
shortcut.WorkingDirectory = originalFilePath;
shortcut.Save();
}
}
public static void CreateStartupShortcut()
{
CreateShortcut(System.Reflection.Assembly.GetEntryAssembly()?.Location, Environment.GetFolderPath(Environment.SpecialFolder.Startup));
}
public static void DeleteShortcut(string originalFilePathAndName, string destinationSavePath)
{
string fileName = Path.GetFileNameWithoutExtension(originalFilePathAndName);
string originalFilePath = Path.GetDirectoryName(originalFilePathAndName);
string link = destinationSavePath + Path.DirectorySeparatorChar + fileName + ".lnk";
if (File.Exists(link)) File.Delete(link);
}
public static void DeleteStartupShortcut()
{
DeleteShortcut(System.Reflection.Assembly.GetEntryAssembly()?.Location, Environment.GetFolderPath(Environment.SpecialFolder.Startup));
}
}

- 1,461
- 15
- 31
If you want a simple code to put on other location, take this:
using IWshRuntimeLibrary;
WshShell shell = new WshShell();
IWshShortcut shortcut = shell.CreateShortcut(@"C:\FOLDER\SOFTWARENAME.lnk");
shortcut.TargetPath = @"C:\FOLDER\SOFTWARE.exe";
shortcut.Save();

- 135
- 1
- 4
-
1isn't this just the same as the code in 5? 6? of the existing answers? – Marc Gravell Jan 21 '21 at 09:59
-
@MarcGravell Just read again. I said "If you want a SIMPLE code". Few lines than others. – Helio Passarelli Mar 25 '21 at 17:41
-
1I like this terse one. Others are too noisy. Are you c# guys always so noisy? – caoanan Jul 19 '21 at 15:31
VB rewrite of the Windows API IShellLink interface:
<ComImport(), Guid("00021401-0000-0000-C000-000000000046")>
Private Class ShellLink
End Class
<ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")>
Private Interface IShellLink
Sub GetPath(<Out, MarshalAs(UnmanagedType.LPWStr)> ByVal pszFile As StringBuilder, ByVal cchMaxPath As Integer, <Out> ByRef pfd As IntPtr, ByVal fFlags As Integer)
Sub GetIDList(<Out> ByRef ppidl As IntPtr)
Sub SetIDList(ByVal pidl As IntPtr)
Sub GetDescription(<Out, MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As StringBuilder, ByVal cchMaxName As Integer)
Sub SetDescription(<MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As String)
Sub GetWorkingDirectory(<Out, MarshalAs(UnmanagedType.LPWStr)> ByVal pszDir As StringBuilder, ByVal cchMaxPath As Integer)
Sub SetWorkingDirectory(<MarshalAs(UnmanagedType.LPWStr)> ByVal pszDir As String)
Sub GetArguments(<Out, MarshalAs(UnmanagedType.LPWStr)> ByVal pszArgs As StringBuilder, ByVal cchMaxPath As Integer)
Sub SetArguments(<MarshalAs(UnmanagedType.LPWStr)> ByVal pszArgs As String)
Sub GetHotkey(<Out> ByRef pwHotkey As Short)
Sub SetHotkey(ByVal wHotkey As Short)
Sub GetShowCmd(<Out> ByRef piShowCmd As Integer)
Sub SetShowCmd(ByVal iShowCmd As Integer)
Sub GetIconLocation(<Out, MarshalAs(UnmanagedType.LPWStr)> ByVal pszIconPath As StringBuilder, ByVal cchIconPath As Integer, <Out> ByRef piIcon As Integer)
Sub SetIconLocation(<MarshalAs(UnmanagedType.LPWStr)> ByVal pszIconPath As String, ByVal iIcon As Integer)
Sub SetRelativePath(<MarshalAs(UnmanagedType.LPWStr)> ByVal pszPathRel As String, ByVal dwReserved As Integer)
Sub Resolve(ByVal hwnd As IntPtr, ByVal fFlags As Integer)
Sub SetPath(<MarshalAs(UnmanagedType.LPWStr)> ByVal pszFile As String)
End Interface
'How to use:
Public Shared Sub CreateNewShortcut(LNKLocation As String, LNKTarget As String, Optional TargetArgs As String = Nothing, Optional StartFolder As String = Nothing,Optional Description As String = Nothing, Optional IconFile As String = "c:\windows\System32\SHELL32.dll", Optional IconIndex As Integer = 21)
Dim link As IShellLink = CType(New ShellLink(), IShellLink)
If Description <> Nothing Then link.SetDescription(Description)
If TargetArgs <> Nothing Then link.SetArguments(TargetArgs)
If IconFile <> Nothing Then link.SetIconLocation(IconFile, IconIndex)
link.SetPath(LNKTarget)
Dim file As System.Runtime.InteropServices.ComTypes.IPersistFile = CType(link, System.Runtime.InteropServices.ComTypes.IPersistFile)
file.Save(LNKLocation, False)
End Sub

- 1,675
- 1
- 19
- 27
For Windows Vista/7/8/10, you can create a symlink instead via mklink
.
Process.Start("cmd.exe", $"/c mklink {linkName} {applicationPath}");
Alternatively, call CreateSymbolicLink
via P/Invoke.

- 4,546
- 3
- 40
- 69
private void CreateShortcut(string executablePath, string name)
{
CMDexec("echo Set oWS = WScript.CreateObject('WScript.Shell') > CreateShortcut.vbs");
CMDexec("echo sLinkFile = '" + Environment.GetEnvironmentVariable("homedrive") + "\\users\\" + Environment.GetEnvironmentVariable("username") + "\\desktop\\" + name + ".ink' >> CreateShortcut.vbs");
CMDexec("echo Set oLink = oWS.CreateShortcut(sLinkFile) >> CreateShortcut.vbs");
CMDexec("echo oLink.TargetPath = '" + executablePath + "' >> CreateShortcut.vbs");
CMDexec("echo oLink.Save >> CreateShortcut.vbs");
CMDexec("cscript CreateShortcut.vbs");
CMDexec("del CreateShortcut.vbs");
}

- 1,273
- 10
- 14