Creating application shortcut in a directory - c#

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.

Related

Unable to create a shortcut in 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);

Creating shortcuts for a new user's desktop

This question explains how to create a shortcut in C#.
For example,
using System;
using IWshRuntimeLibrary;
using System.IO;
namespace TestCreateShortcut
{
class Program
{
static void Main(string[] args)
{
WshShell shell = new WshShell();
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string source = "C:\\foo\\hello.exe";
string dest = desktop + "\\hello.lnk";
IWshRuntimeLibrary.IWshShortcut shortcut =
(IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(dest);
shortcut.TargetPath = source;
shortcut.WorkingDirectory = new FileInfo(source).Directory.Name;
shortcut.Save();
}
}
}
The problem is that, as an Administrator user, I want to create this shortcut on another user's Desktop. I could change the desktop string to be their Desktop path instead of mine, but the catch is this user will have been created right before I want to call the code to make a Desktop shortcut, so there is no C:\Users\TheUser folder yet!
What are some ways to alleviate this situation or make it possible to put a shortcut on a newly-created user's desktop?
I preferably want to do this before the users actually log in for the first time. Thank you.

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.

How to get video duration from mp4, wmv, flv, mov videos

Alright. Actually i need mostly the mp4 format. But if it is possible to get for other types as well that would be nice. I just need to read the duration of the file. How can i do that with C# 4.0 ?
So the thing i need is like this video is like : 13 minutes 12 seconds
I can use 3 third party exes too. Like they save the information about the file to a text file. I can parse that text file.
Thank you.
This answer about P/Invoke for Shell32 reminded me of the Windows API Code Pack to access common Windows Vista/7/2008/2008R2 APIs.
It was very easy, using the PropertyEdit demo in the included samples, to figure out the Shell32 API to get various media file properties, like duration.
I assume the same prerequisite applies for having the proper demultiplexers installed, but it was quite simple, as it only required adding references to Microsoft.WindowsAPICodePack.dll and Microsoft.WindowsAPICodePack.Shell.dll and the following code:
using Microsoft.WindowsAPICodePack.Shell;
using Microsoft.WindowsAPICodePack.Shell.PropertySystem;
using (ShellObject shell = ShellObject.FromParsingName(filePath))
{
// alternatively: shell.Properties.GetProperty("System.Media.Duration");
IShellProperty prop = shell.Properties.System.Media.Duration;
// Duration will be formatted as 00:44:08
string duration = prop.FormatForDisplay(PropertyDescriptionFormatOptions.None);
}
Other stuff
Some common properties for an MPEG-4/AAC audio media file:
System.Audio.Format = {00001610-0000-0010-8000-00AA00389B71}
System.Media.Duration = 00:44:08
System.Audio.EncodingBitrate = ?56kbps
System.Audio.SampleRate = ?32 kHz
System.Audio.SampleSize = ?16 bit
System.Audio.ChannelCount = 2 (stereo)
System.Audio.StreamNumber = 1
System.DRM.IsProtected = No
System.KindText = Music
System.Kind = Music
It's easy to iterate through all properties if you're looking for the available metadata:
using (ShellPropertyCollection properties = new ShellPropertyCollection(filePath))
{
foreach (IShellProperty prop in properties)
{
string value = (prop.ValueAsObject == null) ? "" : prop.FormatForDisplay(PropertyDescriptionFormatOptions.None);
Console.WriteLine("{0} = {1}", prop.CanonicalName, value);
}
}
You could also use windows media player, although it don't support alle file types you requested
using WMPLib;
public Double Duration(String file)
{
WindowsMediaPlayer wmp = new WindowsMediaPlayerClass();
IWMPMedia mediainfo = wmp.newMedia(file);
return mediainfo.duration;
}
}
You can use DirectShow API MediaDet object, through DirectShow.NET wrapper library. See Getting length of video for code sample, get_StreamLength gets you the duration in seconds. This assumes Windows has MPEG-4 demultiplexer installed (requires third party components with Windows prior to 7, I believe the same applies to another answer by cezor, there are free to redistribute components though).
IMHO you could use MediaInfo which gives you a lot of information about media files.
There is a CLI for it so you can use it from your code and get info you need.
You can take a look at this link.
I think you are looking for FFMPEG - https://ffmpeg.org/
there are also some free alternatives that you can read about them in this question - Using FFmpeg in .net?
FFMpeg.NET
FFMpeg-Sharp
FFLib.NET
you can see this link for examples of using FFMPEG and finding the duration - http://jasonjano.wordpress.com/2010/02/09/a-simple-c-wrapper-for-ffmpeg/
public VideoFile GetVideoInfo(string inputPath)
{
VideoFile vf = null;
try
{
vf = new VideoFile(inputPath);
}
catch (Exception ex)
{
throw ex;
}
GetVideoInfo(vf);
return vf;
}
public void GetVideoInfo(VideoFile input)
{
//set up the parameters for video info
string Params = string.Format("-i {0}", input.Path);
string output = RunProcess(Params);
input.RawInfo = output;
//get duration
Regex re = new Regex("[D|d]uration:.((\\d|:|\\.)*)");
Match m = re.Match(input.RawInfo);
if (m.Success)
{
string duration = m.Groups[1].Value;
string[] timepieces = duration.Split(new char[] { ':', '.' });
if (timepieces.Length == 4)
{
input.Duration = new TimeSpan(0, Convert.ToInt16(timepieces[0]), Convert.ToInt16(timepieces[1]), Convert.ToInt16(timepieces[2]), Convert.ToInt16(timepieces[3]));
}
}
}
FFMPEG project has a tool, called ffprobe which can provide you the information you need about your multimedia files and ouput the information in a nicely formated JSON.
Take a look at this answer for an example.
Using Windows Media Player Component also, we can get the duration of the video.
Following code snippet may help you guys :
using WMPLib;
// ...
var player = new WindowsMediaPlayer();
var clip = player.newMedia(filePath);
Console.WriteLine(TimeSpan.FromSeconds(clip.duration));
and don't forget to add the reference of wmp.dll which will be
present in System32 folder.
I found the NReco.VideoInfo library to be the best option and far simpler than some of those above. It's a simple as giving the library a file path and it spits out the metadata:
var ffProbe = new FFProbe();
var videoInfo = ffProbe.GetMediaInfo(blob.Uri.AbsoluteUri);
return videoInfo.Duration.TotalMilliseconds;
I had the same problem and we built a wrapper for ffprobe Alturos.VideoInfo.
You can use it simply by installing the nuget package. Also the ffprobe binary is required.
PM> install-package Alturos.VideoInfo
Example
var videoFilePath = "myVideo.mp4";
var videoAnalyer = new VideoAnalyzer("ffprobe.exe");
var analyzeResult = videoAnalyer.GetVideoInfo(videoFilePath);
var duration = analyzeResult.VideoInfo.Format.Duration;
StreamReader errorreader;
string InterviewID = txtToolsInterviewID.Text;
Process ffmpeg = new Process();
ffmpeg.StartInfo.UseShellExecute = false;
ffmpeg.StartInfo.ErrorDialog = false;
ffmpeg.StartInfo.RedirectStandardError = true;
ffmpeg.StartInfo.FileName = Server.MapPath("ffmpeg.exe");
ffmpeg.StartInfo.Arguments = "-i " + Server.MapPath("videos") + "\\226.flv";
ffmpeg.Start();
errorreader = ffmpeg.StandardError;
ffmpeg.WaitForExit();
string result = errorreader.ReadToEnd();
string duration = result.Substring(result.IndexOf("Duration: ") + ("Duration: ").Length, ("00:00:00.00").Length);

How to follow a .lnk file programmatically

We have a network drive full of shortcuts (.lnk files) that point to folders and I need to traverse them programmatically in a C# Winforms app.
What practical options do I have?
Add IWshRuntimeLibrary as a reference to your project. Add Reference, COM tab, Windows Scripting Host Object Model.
Here is how I get the properties of a shortcut:
IWshRuntimeLibrary.IWshShell wsh = new IWshRuntimeLibrary.WshShellClass();
IWshRuntimeLibrary.IWshShortcut sc = (IWshRuntimeLibrary.IWshShortcut)wsh.CreateShortcut(filename);
The shortcut object "sc" has a TargetPath property.
If you do not wish to reference COM, and distribute the Interop.IWshRuntimeLibrary.dll with your product (remembering Jay Riggs "Embed Interop Types": False)
You can use the new dynamic COM instead.
private void Window_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
dynamic shortcut;
dynamic windowsShell;
try
{
var file = files[0];
if (Path.GetExtension(file)?.Equals(".lnk",StringComparison.OrdinalIgnoreCase) == true)
{
Type shellObjectType = Type.GetTypeFromProgID("WScript.Shell");
windowsShell = Activator.CreateInstance(shellObjectType);
shortcut = windowsShell.CreateShortcut(file);
file = shortcut.TargetPath;
// Release the COM objects
shortcut = null;
windowsShell = null;
}
//
// <use file>...
//
}
finally
{
// Release the COM objects
shortcut = null;
windowsShell = null;
}
}
}
I know it is not the correct way and that lnk file structures can change etc., but this is what I do:
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);
}
Load the file using the COM IPersistFile interface.
Do a QueryInterface on the result to turn it into an IShellLink interface.
Call IShellLink::GetPath
As far as I am aware you can have .NET generate classes conforming to each of these interfaces for you using the "Add Reference" dialog box.
The IShellLink interface lets you manipulate .lnk files, though it's a bit of a pain to use from C#.
This article has some code implementing the necessary interop gubbins.
Update
You can find the code from the article here but the page doesn't seem to work in Firefox. It does work in IE.

Categories

Resources