建立/更新 捷徑檔案 Shortcut File (*.lnk)
要透過程式來產生或更新捷徑檔的方式,一般來說可以加入COM的參考 Microsoft Shell Controls And Automation,或是使用 VBS 呼叫 WScript 方式產生批次文件來建立捷徑檔,但這都不是十分便利的方式。還有另一個方式可以來產生捷徑,就是透過 ComImport 方式。
1.使用COM的參考 Microsoft Shell Controls And Automation
Shell32.ShellClass objShell = new Shell32.ShellClass();
Shell32.ShellLinkObject objLinker;
objLinker = (Shell32.ShellLinkObject)objShell.NameSpace("捷徑檔所在路徑").ParseName(My.Computer.FileSystem.GetName("捷徑檔案名稱.lnk")).GetLink;
objLinker.Description = "捷徑檔案的註解說明";
objLinker.Path = "執行的檔案名稱";
objLinker.SetIconLocation("圖示檔案名稱", 0); //0 為圖示的 Index
objLinker.ShowCommand = 1; //視窗樣式。1=正常,2=最小化,3=最大化
objLinker.WorkingDirectory = "工作路徑";
objLinker.Save();
並沒有很困難,只不過編譯後會附帶一個DLL檔案,如果少了這個DLL檔就不能執行程式。
2.使用 VBS 呼叫 WScript
這個方式其實就是產生一個批次檔,檔案內容如下
set WshShell = WScript.CreateObject("WScript.Shell" )
strDesktop = WshShell.SpecialFolders("AllUsersDesktop" )
set oShellLink = WshShell.CreateShortcut(strDesktop & "\捷徑檔案名稱.lnk" )
oShellLink.TargetPath = "執行檔案名稱"
oShellLink.WindowStyle = 1
oShellLink.IconLocation = "圖示檔案"
oShellLink.Description = "捷徑的註解說明"
oShellLink.WorkingDirectory = "工作路徑"
oShellLink.Save
然後透過 Process.Start 來執行此批次程式,就可以產生捷徑檔了。這個方式也不是很困難,只是得要注意是不是可以正確的執行這個VBS。
3. 使用ComImport
這個方式並不是很多人曉得,因為要先寫一大段的程式才能達到目地。只不過這方式不需要額外的DLL,也不需要產生批次檔案來執行,在我來說是相當不錯的一個方式。將程式寫成一個類別或是編譯為DLL,以後要使用時,引用一下參考就行了。
ShellLink 類別
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using ComTypes = System.Runtime.InteropServices.ComTypes;
namespace ShellLink
{
public class ShellLink : IDisposable
{
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")]
private interface IShellLinkW
{
uint GetExecuteFile([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, ref WIN32_FIND_DATAW pfd, uint fFlags);
uint GetIDList(out IntPtr ppidl);
uint SetIDList(IntPtr pidl);
uint GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
uint SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
uint GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
uint SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
uint GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
uint SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
uint GetHotKey(out ushort pwHotkey);
uint SetHotKey(ushort wHotKey);
uint GetShowCmd(out int piShowCmd);
uint SetShowCmd(int iShowCmd);
uint GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon);
uint SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
uint SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved);
uint Resolve(IntPtr hwnd, uint fFlags);
uint SetExecuteFile([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
}
[ComImport, ClassInterface(ClassInterfaceType.None), Guid("00021401-0000-0000-C000-000000000046")]
private class CShellLink { }
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
private struct WIN32_FIND_DATAW
{
public uint dwFileAttributes;
public ComTypes.FILETIME ftCreationTime;
public ComTypes.FILETIME ftLastAccessTime;
public ComTypes.FILETIME ftLastWriteTime;
public uint nFileSizeHigh;
public uint nFileSizeLow;
public uint dwReserved0;
public uint dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternateFileName;
}
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99")]
private interface IPropertyStore
{
uint GetCount([Out] out uint cProps);
uint GetAt([In] uint iProp, out PropertyKey pkey);
uint GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
uint SetValue([In] ref PropertyKey key, [In] PropVariant pv);
uint Commit();
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
private struct PropertyKey
{
private Guid formatId;
private Int32 propertyId;
public Guid FormatId { get { return formatId; } }
public Int32 PropertyId { get { return propertyId; } }
public PropertyKey(Guid formatId, Int32 propertyId)
{
this.formatId = formatId;
this.propertyId = propertyId;
}
public PropertyKey(string formatId, Int32 propertyId)
{
this.formatId = new Guid(formatId);
this.propertyId = propertyId;
}
}
[StructLayout(LayoutKind.Explicit)]
private sealed class PropVariant : IDisposable
{
[FieldOffset(0)]
ushort valueType;
[FieldOffset(8)]
IntPtr ptr;
public VarEnum VarType
{
get { return (VarEnum)valueType; }
set { valueType = (ushort)value; }
}
public bool IsNullOrEmpty { get { return (valueType == (ushort)VarEnum.VT_EMPTY || valueType == (ushort)VarEnum.VT_NULL); } }
public string Value { get { return Marshal.PtrToStringUni(ptr); } }
public PropVariant() { }
public PropVariant(string value)
{
if (value == null) throw new ArgumentException("Failed to set value.");
valueType = (ushort)VarEnum.VT_LPWSTR;
ptr = Marshal.StringToCoTaskMemUni(value);
}
~PropVariant() { Dispose(); }
public void Dispose()
{
PropVariantClear(this);
GC.SuppressFinalize(this);
}
}
[DllImport("Ole32.dll", PreserveSig = false)]
private extern static void PropVariantClear([In, Out] PropVariant pvar);
private IShellLinkW shellLinkW = null;
private readonly PropertyKey AppUserModelIDKey = new PropertyKey("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}", 5);
private const int MAX_PATH = 260;
private const int INFOTIPSIZE = 1024;
private const int STGM_READ = 0x00000000;
private const uint SLGP_UNCPRIORITY = 0x0002;
private ComTypes.IPersistFile PersistFile
{
get
{
ComTypes.IPersistFile PersistFile = shellLinkW as ComTypes.IPersistFile;
if (PersistFile == null) throw new COMException("Failed to create IPersistFile.");
return PersistFile;
}
}
private IPropertyStore PropertyStore
{
get
{
IPropertyStore PropertyStore = shellLinkW as IPropertyStore;
if (PropertyStore == null) throw new COMException("Failed to create IPropertyStore.");
return PropertyStore;
}
}
/// <summary>
/// 讀取目前載入的捷徑檔案名稱
/// </summary>
public string CurrentShortcutFile
{
get
{
string strFileName;
PersistFile.GetCurFile(out strFileName);
return strFileName;
}
}
/// <summary>
/// 設定/讀取 執行的檔案
/// </summary>
public string ExecuteFile
{
get
{
StringBuilder FileName = new StringBuilder(MAX_PATH);
WIN32_FIND_DATAW data = new WIN32_FIND_DATAW();
VerifySucceeded(shellLinkW.GetExecuteFile(FileName, FileName.Capacity, ref data, SLGP_UNCPRIORITY));
return FileName.ToString();
}
set
{
VerifySucceeded(shellLinkW.SetExecuteFile(value));
}
}
/// <summary>
/// 設定/讀取 執行檔案的參數
/// </summary>
public string ExecuteArguments
{
get
{
StringBuilder ExecuteArgs = new StringBuilder(INFOTIPSIZE);
VerifySucceeded(shellLinkW.GetArguments(ExecuteArgs, ExecuteArgs.Capacity));
return ExecuteArgs.ToString();
}
set
{
VerifySucceeded(shellLinkW.SetArguments(value));
}
}
/// <summary>
/// 設定/讀取 工作路徑
/// </summary>
public string WorkPath
{
get
{
StringBuilder WorkDirectory = new StringBuilder(MAX_PATH);
VerifySucceeded(shellLinkW.GetWorkingDirectory(WorkDirectory, WorkDirectory.Capacity));
return WorkDirectory.ToString();
}
set
{
VerifySucceeded(shellLinkW.SetWorkingDirectory(value));
}
}
/// <summary>
/// 設定/讀取 檔案註解
/// </summary>
public string Descriptions
{
get
{
StringBuilder FileDescription = new StringBuilder(MAX_PATH);
VerifySucceeded(shellLinkW.GetDescription(FileDescription, FileDescription.Capacity));
return FileDescription.ToString();
}
set
{
VerifySucceeded(shellLinkW.SetDescription(value));
}
}
/// <summary>
/// 設定/讀取 圖示檔案
/// </summary>
public string IconLocation
{
get
{
StringBuilder IconConfig = new StringBuilder(MAX_PATH);
int IconIndex;
VerifySucceeded(shellLinkW.GetIconLocation(IconConfig, IconConfig.Capacity, out IconIndex));
return IconConfig.ToString() + "," + IconIndex.ToString();
}
set
{
if (value.Split(',').Length == 2)
{
VerifySucceeded(shellLinkW.SetIconLocation(value.Split(',')[0], Convert.ToInt32(value.Split(',')[1])));
}
}
}
/// <summary>
/// 設定/讀取 Application User Model IDs For Win7 以上作業系統
/// </summary>
public string AppUserModelID
{
get
{
using (PropVariant pv = new PropVariant())
{
VerifySucceeded(PropertyStore.GetValue(AppUserModelIDKey, pv));
if (pv.Value == null)
return "Null";
else
return pv.Value;
}
}
set
{
using (PropVariant pv = new PropVariant(value))
{
VerifySucceeded(PropertyStore.SetValue(AppUserModelIDKey, pv));
VerifySucceeded(PropertyStore.Commit());
}
}
}
public ShellLink() : this(null) { }
/// <summary>
/// 初始化後載入捷徑檔案
/// </summary>
/// <param name="FullLinkFileName">完整的捷徑檔案名稱</param>
public ShellLink(string FullLinkFileName)
{
try
{
shellLinkW = (IShellLinkW)new CShellLink();
}
catch
{
throw new COMException("Failed to create ShellLink object.");
}
if (FullLinkFileName != null) Load(FullLinkFileName);
}
~ShellLink() { Dispose(false); }
/// <summary>
/// 釋放 ShellLink 使用的資源
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (shellLinkW != null)
{
Marshal.FinalReleaseComObject(shellLinkW);
shellLinkW = null;
}
}
/// <summary>
/// 儲存捷徑檔案
/// </summary>
public void Save()
{
string SaveFileName = CurrentShortcutFile;
if (SaveFileName == null) throw new InvalidOperationException("File name is not given.");
Save(SaveFileName);
}
/// <summary>
/// 儲存捷徑檔案
/// </summary>
/// <param name="FullLinkFileName">完整的捷徑檔案名稱</param>
public void Save(string FullLinkFileName)
{
if (FullLinkFileName == null) throw new ArgumentNullException("File name is required.");
PersistFile.Save(FullLinkFileName, true);
}
/// <summary>
/// 讀取捷徑檔案
/// </summary>
/// <param name="FullLinkFileName">完整的捷徑檔案名稱</param>
public void Load(string FullLinkFileName)
{
if (!File.Exists(FullLinkFileName)) throw new FileNotFoundException("File is not found.", FullLinkFileName);
PersistFile.Load(FullLinkFileName, STGM_READ);
}
/// <summary>
/// 確認程式執行
/// </summary>
/// <param name="hresult">回傳值</param>
public static void VerifySucceeded(uint hresult)
{
if (hresult > 1) throw new InvalidOperationException("Failed with HRESULT: " + hresult.ToString("X"));
}
}
}
使用方式: 新增捷徑
ShellLink slLinkObject = new ShellLink();
slLinkObject.WorkPath = "工作路徑";
slLinkObject.IconLocation = "圖示檔案,0"; // 0 為圖示檔的 Index
slLinkObject.ExecuteFile = "執行的檔案";
slLinkObject.Save("捷徑檔案名稱(.lnk)");
slLinkObject.Dispose();
使用方式: 編輯捷徑
ShellLink slLinkObject = new ShellLink("捷徑檔案名稱(.lnk)");
slLinkObject.WorkPath = "工作路徑";
slLinkObject.IconLocation = "圖示檔案,0"; // 0 為圖示檔的 Index
slLinkObject.ExecuteFile = "執行的檔案";
slLinkObject.Save();
slLinkObject.Dispose();
程式是運氣與直覺堆砌而成的奇蹟。
若不具備這兩者,不可能以這樣的工時實現這樣的規格。
修改規格是對奇蹟吐槽的褻瀆行為。
而追加修改則是相信奇蹟還會重現的魯莽行動。