I'm trying to create a shortcut (.lnk) on my windows filesystem.
The code I have is working fine. However, when I run the same console application on a Windows 2008R2 Server, it acts differently.
So I have my console application and here is what happens:
My program simply creates a shortcut on the desktop with a .docx extension and all goes fine on my local machine. When I run the same console application on my Server, it creates the same shortcut but the target got modified... it changed the target to a .doc file.
In other words, when I run the console app:
LocalMachine
Creates MyWordFile.lnk pointing to U:\test.docx
Server
Creates MyWordFile.lnk pointing to U:\test.doc
This is strange behaviour. Here is the code
Code
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)
{
//ShortcutTarget
var sTarget = @"U:\test.docx";
//ShortCutName
var sName = @"MyWordFile.lnk";
IShellLink link = (IShellLink)new ShellLink();
link.SetPath(sTarget);
IPersistFile file = (IPersistFile)link;
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
file.Save(Path.Combine(desktopPath, sName), 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);
}
}
Update
I noticed that the 4th character gets removed from the target's extension. So, when i have a file "file.abcdef", the link points at "file.abc". Also spaces get replaced for underscores, so "my file.abcd" pointer becomes "my_file.abc"
Navigate to the file or folder on your computer. Right click the file or folder and a menu will appear. Left click the Desktop (create shortcut) item on the list. This action creates a desktop shortcut to the file or folder on your desktop.
Under most circumstances, shortcut targets are applications or batch files. You simply provide the full path to the application or batch file in the Target property. However, after entering the target, if you leave the Shortcuts view and then return to it, you find that the target has changed.
Creating a shortcut does not modify the name of the target.
You are seeing something else, "my_file.abc" is the short name of "my file.abcd". Such names are always created on a file system that still has the short name generation feature turned on. Almost all of them still do, even though it is very rarely necessary anymore today. Keeping "my file.abcd" compatible with programs that can only handle MS-Dos names does require that the space is replaced and the extension shortened to 3 letters. You also often see "~1" in such names, used to truncate the filename to 8 letters.
You can see the short names with DIR /x
.
Exactly how you got to see the short name for this file is not obvious from the question. But the IShellLink interface declaration is certainly wrong, the methods are not listed in the correct order. That has pretty grave consequences for an ComInterfaceType.InterfaceIsIUnknown interface, you will call the wrong method at runtime. The Path property setter is actually the 2nd method. You are now calling the 18th method, it is not declared so very hard to guess what it might do. Well, something very surprising if it doesn't throw an exception, this qualifies :) It is not entirely implausible btw, the 17th method that was added was the getter for the Target property, added in a later version of the interface. You might accidentally hit the undocumented setter. Intentionally undocumented.
Just don't declare the interface yourself. Best way to do it is to use Project > Add Reference > Browse button > select C:\Windows\System32\Shell32.dll. Described in more detail in this post.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With