using System; using System.Text; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Diagnostics; namespace NaGet.InteropServices { /// /// ShellLinkの更新フラグ /// [Flags] public enum ShellLinkResolve : uint { // AnyMatch = 0x02, // winMe,win2k以降無効 /// /// MSIを呼ぶ /// InvokeMSI = 0x80, /// /// 追跡禁止 /// NoLinkInfo = 0x40, /// /// リンク先の解決ができないときダイアログを表示しない /// NoUi = 0x01, NoUiWithMsgPump = 0x101, /// /// リンク先のデータ更新を行わない /// NoUpdate = 0x07, /// /// 検索をしない /// NoSearch = 0x10, NoTrack = 0x20, /// /// リンク先を更新する /// Update = 0x04, } [ComImport()] [Guid("000214F9-0000-0000-C000-000000000046")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IShellLinkW { void GetPath([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, IntPtr pfd, uint fFlags); void GetIDList(out IntPtr ppidl); void SetIDList(IntPtr pidl); void GetDescription([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDesc, int cchMaxPath); void SetDescription(string pszDesc); void GetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); void SetWorkingDirectory(string pszDir); void GetArguments([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); void SetArguments(string pszArgs); void GetHotkey(out short pwHotkey); void SetHotkey(short pwHotkey); void GetShowCmd(out uint piShowCmd); void SetShowCmd(uint piShowCmd); void GetIconLocation([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchMaxPath, out int piIcon); void SetIconLocation(string pszIconPath, int iIcon); void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszPath, int cchMaxPath, uint dwReserved); void Resolve(IntPtr hWnd, ShellLinkResolve fFlag); void SetPath(string pszFile); } /// /// シェルリンク(ショートカット)のカプセルクラス /// public class ShellLink : IDisposable { /// /// シェルリンクのCOMオブジェクト /// protected IShellLinkW shellLink; /// /// シェルリンクのGUID /// public const string ShellLinkGuid = "00021401-0000-0000-C000-000000000046"; protected const int MAX_PATH = 260; /// /// 新しいシェルリンクを作成する形のコンストラクタ /// public ShellLink() { Type shellLinkType = Type.GetTypeFromCLSID(new Guid(ShellLinkGuid)); shellLink = (IShellLinkW) Activator.CreateInstance(shellLinkType); } /// /// 既存のシェルリンクを開くコンストラクタ /// /// 既存のシェルリンクのパス public ShellLink(string path) : this() { if (! System.IO.File.Exists(path)) { throw new System.IO.FileNotFoundException("File does not found", path); } ToPersistFile().Load(path, 0); Resolve(IntPtr.Zero, ShellLinkResolve.NoUpdate | ShellLinkResolve.NoUi); } /// /// シェルリンクの解析解決 /// /// 親フレームのハンドル /// 方法 public void Resolve(IntPtr? hWnd, ShellLinkResolve fFlags) { shellLink.Resolve(hWnd ?? IntPtr.Zero, fFlags); } /// /// IPersistFileとして取り出す /// /// IPersistFileにキャストされたCOMオブジェクト public IPersistFile ToPersistFile() { return (IPersistFile) shellLink; } /// /// リンク先パスを得る。コマンドラインを得るためにも /// /// パスのタイプ(1:8.3形式; 2:UNCパス; 4:環境変数変換なし) /// パス public string GetPath(uint fFlags) { StringBuilder sb = new StringBuilder(MAX_PATH); shellLink.GetPath(sb, sb.Capacity, IntPtr.Zero, fFlags); return sb.ToString(); } /// /// リンク先パス(取得時には環境変数は展開されません) /// public string Path { get { return GetPath(0x04); } set { shellLink.SetPath(value); } } /// /// リンク先(引数) /// public string Arguments { get { StringBuilder sb = new StringBuilder(MAX_PATH); shellLink.GetArguments(sb, sb.Capacity); return sb.ToString(); } set { shellLink.SetArguments(value); } } /// /// 作業フォルダ /// public string WorkingDirectory { get { StringBuilder sb = new StringBuilder(MAX_PATH); shellLink.GetWorkingDirectory(sb, sb.Capacity); return sb.ToString(); } set { shellLink.SetWorkingDirectory(value); } } /// /// ウィンドウスタイル(ShowCmdのワッパ) /// public ProcessWindowStyle WindowStyle { get { uint showcmd; shellLink.GetShowCmd(out showcmd); switch (showcmd) { case 3: return ProcessWindowStyle.Maximized; case 7: return ProcessWindowStyle.Minimized; case 1: default: return ProcessWindowStyle.Normal; } } set { switch (value) { case ProcessWindowStyle.Normal: shellLink.SetShowCmd(1); break; case ProcessWindowStyle.Maximized: shellLink.SetShowCmd(3); break; case ProcessWindowStyle.Minimized: case ProcessWindowStyle.Hidden: shellLink.SetShowCmd(7); break; } } } /// /// アイコンの場所を得る /// /// アイコンを含むファイルパス /// アイコンのインデックス public void GetIconLocation(out string iconPath, out int iconIndex) { StringBuilder sb = new StringBuilder(MAX_PATH); shellLink.GetIconLocation(sb, sb.Capacity, out iconIndex); iconPath = sb.ToString(); } /// /// アイコンの場所を設定する /// /// アイコンを含むファイルパス /// アイコンのインデックス public void SetIconLocation(string iconPath, int iconIndex) { shellLink.SetIconLocation(iconPath, iconIndex); } /// /// COMオブジェクトの開放 /// public void Dispose() { if (shellLink != null) { Marshal.ReleaseComObject(shellLink); shellLink = null; } } /// /// シェルリンクの中身をプロセス情報として取得する。起動の際に利用 /// /// プロセス起動情報化されたシェルリンクの情報 public ProcessStartInfo ToProcessStartInfo() { ProcessStartInfo procInfo = new ProcessStartInfo(); procInfo.FileName = GetPath(0); procInfo.Arguments = Arguments; procInfo.WorkingDirectory = WorkingDirectory; procInfo.WindowStyle = WindowStyle; return procInfo; } /// /// プロセス情報からシェルリンクオブジェクトを生成 /// /// プロセス情報 /// 生成されたシェルリンクオブジェクト public static ShellLink CreateFromProcessStartInfo(ProcessStartInfo procInfo) { ShellLink shelllink = new ShellLink(); shelllink.Path = procInfo.FileName; shelllink.Arguments = procInfo.Arguments; shelllink.WorkingDirectory = procInfo.WorkingDirectory; shelllink.WindowStyle = procInfo.WindowStyle; return shelllink; } /// /// ショートカット先のEXEファイルに対して適切な名前を生成する。 /// /// 具体的には、アセンブリの製品名をまず優先的に使い、 /// それがなければ、exeファイルのファイル名(拡張子を除いたもの)を返す。 /// /// 拡張子はつかないので、lnkファイル名に使う場合は、手動で /// ".lnk"を追加すること。 /// /// 拡張子を含まない、適切な名前 public string GetSuitableShellLinkNameFor() { string exeFile = GetPath(0); try { FileVersionInfo vInfo = FileVersionInfo.GetVersionInfo(exeFile); if (vInfo.ProductName != null && vInfo.ProductName != string.Empty && vInfo.ProductName.IndexOfAny(System.IO.Path.GetInvalidFileNameChars()) < 0) { // 原則、製品名を採用 return vInfo.ProductName; } } catch (Exception) {} // そのほかの場合は、*.exeファイルの名前をそのまま使用 return System.IO.Path.GetFileNameWithoutExtension(exeFile); } } }