Unable to create a shortcut in C# - c#

In my program I want to give the user the ability to create a shortcut.
I tried using the IWshRuntimeLibrary, but it doesn't support Unicode character, and therefore fails.
I have found this answer, and it works when I copy it exactly like it is, but doesn't work when I put it in a function and use variables.
This is the code I use:
public static void CreateShortcut(string shortcutName, string shortcutPath, string targetFileLocation, string description = "", string args = "")
{
// Create empty .lnk file
string path = System.IO.Path.Combine(shortcutPath, $"{shortcutName}.lnk");
System.IO.File.WriteAllBytes(path, new byte[0]);
// Create a ShellLinkObject that references the .lnk file
Shell32.Shell shl = new Shell32.Shell();
Shell32.Folder dir = shl.NameSpace(shortcutPath);
Shell32.FolderItem itm = dir.Items().Item(shortcutName);
Shell32.ShellLinkObject lnk = (Shell32.ShellLinkObject)itm.GetLink;
// Set the .lnk file properties
lnk.Path = targetFileLocation;
lnk.Description = description;
lnk.Arguments = args;
lnk.WorkingDirectory = Path.GetDirectoryName(targetFileLocation);
lnk.Save(path);
}
As you can see, it is the same exact code. The only difference is the use of variables instead of hard-coded values.
I call the function like so: Utils.CreateShortcut("Name", #"D:\Desktop", "notepad.exe", args: "Demo.txt");
And I get a System.NullReferenceException for the line Shell32.ShellLinkObject lnk = (Shell32.ShellLinkObject)itm.GetLink; because itm is null.

I have found the problem.
This line: System.IO.Path.Combine(shortcutPath, $"{shortcutName}.lnk");
I add the ".lnk" extension to the file name, but when I search for it with dir.Items().Item(shortcutName); it doesn't have the extension.
The solution: Write at the beginning of the function shortcutName += ".lnk";
And get the path like so: System.IO.Path.Combine(shortcutPath, shortcutName);

Related

File not relocating correctly c#

I have my program setup to rename and store a file according to checkbox input. I used another stackoverflow post for my template. Only problem is when I tried setting it up for sub-folders, it never puts it in the correct folder. I have a label folder with two sub folders called L-Labels and B-Labels. The user checks which label type it is and the file gets renamed and placed in the according sub-folder. When I used breakpoint my variables are getting the correct value so I don't see what's wrong I have provided my variables and code for relocating the file. What is causing this to not put it in my sub-folder?
Varibales:
string oldPath = lblBrowseName.Text;
string newpathB = #"C:\Users\Public\Labels\B_Labels";
string newpathL = #"C:\Users\Public\Labels\L_Labels";
Method:
if (rChkBoxBizerba.Checked == true)
{
string newFileName = rtxtBoxNewVersion.Text;
FileInfo f1 = new FileInfo(oldPath);
if (f1.Exists)
{
if (!Directory.Exists(newpathB))
{
Directory.CreateDirectory(newpathB);
}
f1.CopyTo(string.Format("{0}{1}{2}", newpathB, newFileName, f1.Extension));
if (System.IO.File.Exists(lblBrowseName.Text))
System.IO.File.Delete(lblBrowseName.Text);
}
I would say this is the problem:
f1.CopyTo(string.Format("{0}{1}{2}", newpathB, newFileName, f1.Extension));
You declare your path but it doesn't have a trailing directory separator, so when you combine all the parts, as above, the actual result is invalid.
You really should use Path.Combine() to combine parts of paths together, this uses the correct directory separator and makes additional checks.
Try something like this:
// Build actual filename
string filename = String.Format("{0}{1}",newFileName, f1.Extension));
// Now build the full path (directory + filename)
string full_path = Path.Combine(newpathB,filename);
// Copy file
f1.CopyTo(full_path);

Error Access to the path is denied when Rename a Directory

I want to rename the a folder with the new name inputed in a Textbox txtFilenFolderName:
protected void btnUpdate_Click(object sender, EventArgs e)
{
string[] values = EditValue;
string oldpath = values[0];// = "D:\\C#Projects\\website\\Lecturer\\giangvien\\New folder"
string oldName = values[2]; //= New Folder
string newName = txtFilenFolderName.Text; //= New Folder1
string newPath = string.Empty;
if (oldName != newName)
{
newPath = oldpath.Replace(oldName, newName);
Directory.Move(oldpath, newPath);
}
else
lblmessage2.Text = "New name must not be the same as the old ";
}
}
Try to debug:
oldpath = "D:\\C#Projects\\website\\Lecturer\\giangvien\\New folder"
oldName = New Folder
newName= New Folder1
newpath = "D:\\C#Projects\\website\\Lecturer\\giangvien\\New folder1"
Everything seems right, but I when I click on buton Edit ---> rename---> Update---> an error occur: Access to the path is denied D:\\C#Projects\\website\\Lecturer\\giangvien\\New folder
Help!
the path "D:\\C#Projects\\website\\Lecturer\\giangvien\\New folder" probably doesn't exist. I'm thinking you meant "D:\C#Projects\website\Lecturer\giangvien\New folder". I think what #CharmingInferno was trying to get at was that when you use # in front of a string you don't need to use escape characters as it takes the text as is like the following
string g = "\\\\server\\share\\file.txt"; // \\server\share\file.txt
string h = #"\\server\share\file.txt"; // \\server\share\file.txt
However you are putting your values in the EditValue string array should be corrected.
I had the same problem just now.
Using
Directory.Move(srcDirectory, dstDirectory);
sometimes caused the Access to the path /dstDirectory/ is denied exception, sometimes it don't.
The following solved for me.
new DirectoryInfo(srcDirectory).MoveTo(dstDirectory);

Starting Explorer with UNC Path Argument That Contains Comma Fails To Open Folder

Passing in a value with a comma in the UNC path (e.g. "\servername\Smith,John\Documents\") causes the following to start windows explorer but it opens the My Documents instead of the folder path. If I paste in the path into windows explorer's address bar, the folder opens appropriately.
public void OpenWindowsExplorer(string path) {
var runExplorer = new ProcessStartInfo { FileName = "explorer.exe", Arguments = path };
Process.Start(runExplorer);
}
Any idea as to why this is happening/how to resolve the issue is greatly appreciated.
Put quotes around the path:
public void OpenWindowsExplorer(string path) {
path = string.Format("\"{0}\"", path);
var runExplorer = new ProcessStartInfo { FileName = "explorer.exe",
Arguments = path };
Process.Start(runExplorer);
}

How to create a shortcut for an app from an other app in c#?

I'm trying to make a window's form application with c# that can copy an other application's shortcut to an especial folder.I use this code to copy files but cannot make a short cut...
system.io.file.copy("what","where");
I use this but it doesn't work
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(".\\calc.exe");
string destination = #"C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\Startup";
System.IO.FileInfo[] files = dir.GetFiles("*.exe");
foreach (var shorcut in files)
{
System.IO.File.Move(shorcut.FullName, destination);
}
What is the easiest way?
The following code allows you to read the lnk file
It doesn't make a lot of sense, don't have an easy way to check it. I reckon the best approach is to read the .lnk file the way it is supposed to be read. You can use COM to do so, the ShellLinkObject class implements the IShellLink interface. Get started with Project + Add Reference, Browse tab and navigate to c:\windows\system32\shell32.dll. That generates an interop library. Write code like this:
public static string GetLnkTarget(string lnkPath) {
var shl = new Shell32.Shell(); // Move this to class scope
lnkPath = System.IO.Path.GetFullPath(lnkPath);
var dir = shl.NameSpace(System.IO.Path.GetDirectoryName(lnkPath));
var itm = dir.Items().Item(System.IO.Path.GetFileName(lnkPath));
var lnk = (Shell32.ShellLinkObject)itm.GetLink;
return lnk.Target.Path;
}
Then you simply save it in your own folder using the following code
First include a reference to C:\Windows\System32\wshom.ocx
Second, include the following using statement :-
using IWshRuntimeLibrary;
Third, Here is the code :-
// This creates a Folder Shortcut
IWshShell wsh = new WshShellClass();
IWshShortcut shortcut = (IWshShortcut) wsh.CreateShortcut (shortcutpathfilename);
shortcut.TargetPath = targetdir;
shortcut.Save();
shortcutpathfilename is a path & filename of the .lnk file.
targetdir is the directory the link points to.

Creating application shortcut in a directory

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.
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);
}
}
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);
}
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"
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).
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();
}
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.

Categories

Resources