using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Diagnostics;
namespace NaGet.InteropServices
{
///
/// ShellLinkの更新フラグ
///
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;
}
GC.SuppressFinalize(this);
}
///
/// シェルリンクの中身をプロセス情報として取得する。起動の際に利用
///
/// プロセス起動情報化されたシェルリンクの情報
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 ( (!string.IsNullOrEmpty(vInfo.ProductName))
&& vInfo.ProductName.IndexOfAny(System.IO.Path.GetInvalidFileNameChars()) < 0) {
// 原則、製品名を採用
return vInfo.ProductName;
}
} catch (Exception) {}
// そのほかの場合は、*.exeファイルの名前をそのまま使用
return System.IO.Path.GetFileNameWithoutExtension(exeFile);
}
}
}