OSDN Git Service

AppliStation-*,とりあえずの実装 of 「インストール先フォルダ」のところで実行ファイルを直接 実行できるように
[applistation/AppliStation.git] / na-get-lib / NaGet.InteropServices / ShellLink.cs
1 using System;\r
2 using System.Text;\r
3 using System.Runtime.InteropServices;\r
4 using System.Runtime.InteropServices.ComTypes;\r
5 using System.Diagnostics;\r
6 \r
7 namespace NaGet.InteropServices\r
8 {       \r
9         /// <summary>\r
10         /// ShellLinkの更新フラグ\r
11         /// </summary>\r
12         [Flags]\r
13         public enum ShellLinkResolve : uint\r
14         {\r
15                 // AnyMatch = 0x02, // winMe,win2k以降無効\r
16                 \r
17                 /// <summary>\r
18                 /// MSIを呼ぶ\r
19                 /// </summary>\r
20                 InvokeMSI = 0x80,\r
21                 /// <summary>\r
22                 /// 追跡禁止\r
23                 /// </summary>\r
24                 NoLinkInfo = 0x40,\r
25                 /// <summary>\r
26                 /// リンク先の解決ができないときダイアログを表示しない\r
27                 /// </summary>\r
28                 NoUi = 0x01,\r
29                 NoUiWithMsgPump = 0x101,\r
30                 /// <summary>\r
31                 /// リンク先のデータ更新を行わない\r
32                 /// </summary>\r
33                 NoUpdate = 0x07,\r
34                 /// <summary>\r
35                 /// 検索をしない\r
36                 /// </summary>\r
37                 NoSearch = 0x10,\r
38                 NoTrack = 0x20,\r
39                 /// <summary>\r
40                 /// リンク先を更新する\r
41                 /// </summary>\r
42                 Update = 0x04,\r
43         }\r
44         \r
45         [ComImport()]\r
46         [Guid("000214F9-0000-0000-C000-000000000046")]\r
47         [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\r
48         public interface IShellLinkW\r
49         {\r
50                 void GetPath([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,\r
51                              int cchMaxPath, IntPtr pfd, uint fFlags);\r
52                 \r
53                 void GetIDList(out IntPtr ppidl);\r
54                 void SetIDList(IntPtr pidl);\r
55                 \r
56                 void GetDescription([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDesc,\r
57                                          int cchMaxPath);\r
58                 void SetDescription(string pszDesc);\r
59                 \r
60                 void GetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,\r
61                                          int cchMaxPath);\r
62                 void SetWorkingDirectory(string pszDir);\r
63                 \r
64                 void GetArguments([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,\r
65                                          int cchMaxPath);\r
66                 void SetArguments(string pszArgs);\r
67                 \r
68                 void GetHotkey(out short pwHotkey);\r
69                 void SetHotkey(short pwHotkey);\r
70                 \r
71                 void GetShowCmd(out uint piShowCmd);\r
72                 void SetShowCmd(uint piShowCmd);\r
73                 \r
74                 void GetIconLocation([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,\r
75                                          int cchMaxPath, out int piIcon);\r
76                 void SetIconLocation(string pszIconPath, int iIcon);\r
77                 \r
78                 void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszPath,\r
79                                          int cchMaxPath, uint dwReserved);\r
80                 \r
81                 void Resolve(IntPtr hWnd, ShellLinkResolve fFlag);\r
82                                 \r
83                 void SetPath(string pszFile);\r
84         }\r
85 \r
86         /// <summary>\r
87         /// シェルリンク(ショートカット)のカプセルクラス\r
88         /// </summary>\r
89         public class ShellLink : IDisposable\r
90         {\r
91                 /// <summary>\r
92                 /// シェルリンクのCOMオブジェクト\r
93                 /// </summary>\r
94                 protected IShellLinkW shellLink;\r
95                 \r
96                 /// <summary>\r
97                 /// シェルリンクのGUID\r
98                 /// </summary>\r
99                 public const string ShellLinkGuid = "00021401-0000-0000-C000-000000000046";\r
100                 \r
101                 protected const int MAX_PATH = 260;\r
102                 \r
103                 /// <summary>\r
104                 /// 新しいシェルリンクを作成する形のコンストラクタ\r
105                 /// </summary>\r
106                 public ShellLink()\r
107                 {\r
108                         Type shellLinkType = Type.GetTypeFromCLSID(new Guid(ShellLinkGuid));\r
109                         shellLink = (IShellLinkW) Activator.CreateInstance(shellLinkType);\r
110                 }\r
111                 \r
112                 /// <summary>\r
113                 /// 既存のシェルリンクを開くコンストラクタ\r
114                 /// </summary>\r
115                 /// <param name="path">既存のシェルリンクのパス</param>\r
116                 public ShellLink(string path) : this()\r
117                 {\r
118                         if (! System.IO.File.Exists(path)) {\r
119                                 throw new System.IO.FileNotFoundException("File does not found", path);\r
120                         }\r
121                         \r
122                         ToPersistFile().Load(path, 0);\r
123                         Resolve(IntPtr.Zero, ShellLinkResolve.NoUpdate | ShellLinkResolve.NoUi);\r
124                 }\r
125                 \r
126                 /// <summary>\r
127                 /// シェルリンクの解析解決\r
128                 /// </summary>\r
129                 /// <param name="hWnd">親フレームのハンドル</param>\r
130                 /// <param name="fFlags">方法</param>\r
131                 public void Resolve(IntPtr? hWnd, ShellLinkResolve fFlags)\r
132                 {\r
133                         shellLink.Resolve(hWnd ?? IntPtr.Zero, fFlags);\r
134                 }\r
135                 \r
136                 /// <summary>\r
137                 /// IPersistFileとして取り出す\r
138                 /// </summary>\r
139                 /// <returns>IPersistFileにキャストされたCOMオブジェクト</returns>\r
140                 public IPersistFile ToPersistFile()\r
141                 {\r
142                         return (IPersistFile) shellLink;\r
143                 }\r
144                 \r
145                 /// <summary>\r
146                 /// リンク先パスを得る。コマンドラインを得るためにも\r
147                 /// </summary>\r
148                 /// <param name="fFlags">パスのタイプ(1:8.3形式; 2:UNCパス; 4:環境変数変換なし)</param>\r
149                 /// <returns>パス</returns>\r
150                 public string GetPath(uint fFlags)\r
151                 {\r
152                         StringBuilder sb = new StringBuilder(MAX_PATH);\r
153                         shellLink.GetPath(sb, sb.Capacity, IntPtr.Zero, fFlags);\r
154                         return sb.ToString();\r
155                 }\r
156                 \r
157                 /// <summary>\r
158                 /// リンク先パス(取得時には環境変数は展開されません)\r
159                 /// </summary>\r
160                 public string Path {\r
161                         get { return GetPath(0x04); }\r
162                         set { shellLink.SetPath(value); }\r
163                 }\r
164                 \r
165                 /// <summary>\r
166                 /// リンク先(引数)\r
167                 /// </summary>\r
168                 public string Arguments {\r
169                         get {\r
170                                 StringBuilder sb = new StringBuilder(MAX_PATH);\r
171                                 shellLink.GetArguments(sb, sb.Capacity);\r
172                                 return sb.ToString();\r
173                         }\r
174                         set { shellLink.SetArguments(value); }\r
175                 }\r
176                 \r
177                 /// <summary>\r
178                 /// 作業フォルダ\r
179                 /// </summary>\r
180                 public string WorkingDirectory {\r
181                         get {\r
182                                 StringBuilder sb = new StringBuilder(MAX_PATH);\r
183                                 shellLink.GetWorkingDirectory(sb, sb.Capacity);\r
184                                 return sb.ToString();\r
185                         }\r
186                         set { shellLink.SetWorkingDirectory(value); }\r
187                 }\r
188                 \r
189                 /// <summary>\r
190                 /// ウィンドウスタイル(ShowCmdのワッパ)\r
191                 /// </summary>\r
192                 public ProcessWindowStyle WindowStyle\r
193                 {\r
194                         get {\r
195                                 uint showcmd;\r
196                                 shellLink.GetShowCmd(out showcmd);\r
197                                 switch (showcmd) {\r
198                                         case 3:\r
199                                                 return ProcessWindowStyle.Maximized;\r
200                                         case 7:\r
201                                                 return ProcessWindowStyle.Minimized;\r
202                                         case 1:\r
203                                         default:\r
204                                                 return ProcessWindowStyle.Normal;\r
205                                 }\r
206                         }\r
207                         set {\r
208                                 switch (value) {\r
209                                         case ProcessWindowStyle.Normal:\r
210                                                 shellLink.SetShowCmd(1);\r
211                                                 break;\r
212                                         case ProcessWindowStyle.Maximized:\r
213                                                 shellLink.SetShowCmd(3);\r
214                                                 break;\r
215                                         case ProcessWindowStyle.Minimized:\r
216                                         case ProcessWindowStyle.Hidden:\r
217                                                 shellLink.SetShowCmd(7);\r
218                                                 break;\r
219                                 }\r
220                         }\r
221                 }\r
222                 \r
223                 /// <summary>\r
224                 /// アイコンの場所を得る\r
225                 /// </summary>\r
226                 /// <param name="iconPath">アイコンを含むファイルパス</param>\r
227                 /// <param name="iconIndex">アイコンのインデックス</param>\r
228                 public void GetIconLocation(out string iconPath, out int iconIndex)\r
229                 {\r
230                         StringBuilder sb = new StringBuilder(MAX_PATH);\r
231                         shellLink.GetIconLocation(sb, sb.Capacity, out iconIndex);\r
232                         iconPath = sb.ToString();\r
233                 }\r
234                 \r
235                 /// <summary>\r
236                 /// アイコンの場所を設定する\r
237                 /// </summary>\r
238                 /// <param name="iconPath">アイコンを含むファイルパス</param>\r
239                 /// <param name="iconIndex">アイコンのインデックス</param>\r
240                 public void SetIconLocation(string iconPath, int iconIndex)\r
241                 {\r
242                         shellLink.SetIconLocation(iconPath, iconIndex);\r
243                 }\r
244                 \r
245                 /// <summary>\r
246                 /// COMオブジェクトの開放\r
247                 /// </summary>\r
248                 public void Dispose()\r
249                 {\r
250                         if (shellLink != null) {\r
251                                 Marshal.ReleaseComObject(shellLink);\r
252                                 shellLink = null;\r
253                         }\r
254                 }\r
255 \r
256                 /// <summary>\r
257                 /// シェルリンクの中身をプロセス情報として取得する。起動の際に利用\r
258                 /// </summary>\r
259                 /// <returns>プロセス起動情報化されたシェルリンクの情報</returns>\r
260                 public ProcessStartInfo ToProcessStartInfo()\r
261                 {\r
262                         ProcessStartInfo procInfo = new ProcessStartInfo();\r
263                         procInfo.FileName = GetPath(0);\r
264                         procInfo.Arguments = Arguments;\r
265                         procInfo.WorkingDirectory = WorkingDirectory;\r
266                         procInfo.WindowStyle = WindowStyle;\r
267                         \r
268                         return procInfo;\r
269                 }\r
270                 \r
271                 /// <summary>\r
272                 /// プロセス情報からシェルリンクオブジェクトを生成\r
273                 /// </summary>\r
274                 /// <param name="procInfo">プロセス情報</param>\r
275                 /// <returns>生成されたシェルリンクオブジェクト</returns>\r
276                 public static ShellLink CreateFromProcessStartInfo(ProcessStartInfo procInfo)\r
277                 {\r
278                         ShellLink shelllink = new ShellLink();\r
279                         shelllink.Path = procInfo.FileName;\r
280                         shelllink.Arguments = procInfo.Arguments;\r
281                         shelllink.WorkingDirectory = procInfo.WorkingDirectory;\r
282                         shelllink.WindowStyle = procInfo.WindowStyle;\r
283                         \r
284                         return shelllink;\r
285                 }\r
286                 \r
287                 /// <summary>\r
288                 /// ショートカット先のEXEファイルに対して適切な名前を生成する。\r
289                 /// \r
290                 /// 具体的には、アセンブリの製品名をまず優先的に使い、\r
291                 /// それがなければ、exeファイルのファイル名(拡張子を除いたもの)を返す。\r
292                 /// \r
293                 /// 拡張子はつかないので、lnkファイル名に使う場合は、手動で\r
294                 /// <code>".lnk"</code>を追加すること。\r
295                 /// </summary>\r
296                 /// <returns>拡張子を含まない、適切な名前</returns>\r
297                 public string GetSuitableShellLinkNameFor()\r
298                 {\r
299                         string exeFile = GetPath(0);\r
300                         \r
301                         try {\r
302                                 FileVersionInfo vInfo = FileVersionInfo.GetVersionInfo(exeFile);\r
303                                 if (vInfo.ProductName != null && vInfo.ProductName != string.Empty\r
304                                     && vInfo.ProductName.IndexOfAny(System.IO.Path.GetInvalidFileNameChars()) < 0) {\r
305                                         // 原則、製品名を採用\r
306                                         return vInfo.ProductName;\r
307                                 }\r
308                         } catch (Exception) {}\r
309 \r
310                         // そのほかの場合は、*.exeファイルの名前をそのまま使用\r
311                         return System.IO.Path.GetFileNameWithoutExtension(exeFile);\r
312                 }\r
313         }\r
314 }\r