OSDN Git Service

Merge branch 'mustard'
[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         public enum ShellLinkResolve : uint\r
13         {\r
14                 // AnyMatch = 0x02, // winMe,win2k以降無効\r
15                 \r
16                 /// <summary>\r
17                 /// MSIを呼ぶ\r
18                 /// </summary>\r
19                 InvokeMSI = 0x80,\r
20                 /// <summary>\r
21                 /// 追跡禁止\r
22                 /// </summary>\r
23                 NoLinkInfo = 0x40,\r
24                 /// <summary>\r
25                 /// リンク先の解決ができないときダイアログを表示しない\r
26                 /// </summary>\r
27                 NoUi = 0x01,\r
28                 NoUiWithMsgPump = 0x101,\r
29                 /// <summary>\r
30                 /// リンク先のデータ更新を行わない\r
31                 /// </summary>\r
32                 NoUpdate = 0x07,\r
33                 /// <summary>\r
34                 /// 検索をしない\r
35                 /// </summary>\r
36                 NoSearch = 0x10,\r
37                 NoTrack = 0x20,\r
38                 /// <summary>\r
39                 /// リンク先を更新する\r
40                 /// </summary>\r
41                 Update = 0x04,\r
42         }\r
43         \r
44         [ComImport()]\r
45         [Guid("000214F9-0000-0000-C000-000000000046")]\r
46         [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\r
47         public interface IShellLinkW\r
48         {\r
49                 void GetPath([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile,\r
50                              int cchMaxPath, IntPtr pfd, uint fFlags);\r
51                 \r
52                 void GetIDList(out IntPtr ppidl);\r
53                 void SetIDList(IntPtr pidl);\r
54                 \r
55                 void GetDescription([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDesc,\r
56                                          int cchMaxPath);\r
57                 void SetDescription(string pszDesc);\r
58                 \r
59                 void GetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir,\r
60                                          int cchMaxPath);\r
61                 void SetWorkingDirectory(string pszDir);\r
62                 \r
63                 void GetArguments([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs,\r
64                                          int cchMaxPath);\r
65                 void SetArguments(string pszArgs);\r
66                 \r
67                 void GetHotkey(out short pwHotkey);\r
68                 void SetHotkey(short pwHotkey);\r
69                 \r
70                 void GetShowCmd(out uint piShowCmd);\r
71                 void SetShowCmd(uint piShowCmd);\r
72                 \r
73                 void GetIconLocation([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,\r
74                                          int cchMaxPath, out int piIcon);\r
75                 void SetIconLocation(string pszIconPath, int iIcon);\r
76                 \r
77                 void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszPath,\r
78                                          int cchMaxPath, uint dwReserved);\r
79                 \r
80                 void Resolve(IntPtr hWnd, ShellLinkResolve fFlag);\r
81                                 \r
82                 void SetPath(string pszFile);\r
83         }\r
84 \r
85         /// <summary>\r
86         /// シェルリンク(ショートカット)のカプセルクラス\r
87         /// </summary>\r
88         public class ShellLink : IDisposable\r
89         {\r
90                 /// <summary>\r
91                 /// シェルリンクのCOMオブジェクト\r
92                 /// </summary>\r
93                 protected IShellLinkW shellLink;\r
94                 \r
95                 /// <summary>\r
96                 /// シェルリンクのGUID\r
97                 /// </summary>\r
98                 public const string ShellLinkGuid = "00021401-0000-0000-C000-000000000046";\r
99                 \r
100                 protected const int MAX_PATH = 260;\r
101                 \r
102                 /// <summary>\r
103                 /// 新しいシェルリンクを作成する形のコンストラクタ\r
104                 /// </summary>\r
105                 public ShellLink()\r
106                 {\r
107                         Type shellLinkType = Type.GetTypeFromCLSID(new Guid(ShellLinkGuid));\r
108                         shellLink = (IShellLinkW) Activator.CreateInstance(shellLinkType);\r
109                 }\r
110                 \r
111                 /// <summary>\r
112                 /// 既存のシェルリンクを開くコンストラクタ\r
113                 /// </summary>\r
114                 /// <param name="path">既存のシェルリンクのパス</param>\r
115                 public ShellLink(string path) : this()\r
116                 {\r
117                         if (! System.IO.File.Exists(path)) {\r
118                                 throw new System.IO.FileNotFoundException("File does not found", path);\r
119                         }\r
120                         \r
121                         ToPersistFile().Load(path, 0);\r
122                         Resolve(IntPtr.Zero, ShellLinkResolve.NoUpdate | ShellLinkResolve.NoUi);\r
123                 }\r
124                 \r
125                 /// <summary>\r
126                 /// シェルリンクの解析解決\r
127                 /// </summary>\r
128                 /// <param name="hWnd">親フレームのハンドル</param>\r
129                 /// <param name="fFlags">方法</param>\r
130                 public void Resolve(IntPtr? hWnd, ShellLinkResolve fFlags)\r
131                 {\r
132                         shellLink.Resolve(hWnd ?? IntPtr.Zero, fFlags);\r
133                 }\r
134                 \r
135                 /// <summary>\r
136                 /// IPersistFileとして取り出す\r
137                 /// </summary>\r
138                 /// <returns>IPersistFileにキャストされたCOMオブジェクト</returns>\r
139                 public IPersistFile ToPersistFile()\r
140                 {\r
141                         return (IPersistFile) shellLink;\r
142                 }\r
143                 \r
144                 /// <summary>\r
145                 /// リンク先パスを得る。コマンドラインを得るためにも\r
146                 /// </summary>\r
147                 /// <param name="fFlags">パスのタイプ(1:8.3形式; 2:UNCパス; 4:環境変数変換なし)</param>\r
148                 /// <returns>パス</returns>\r
149                 public string GetPath(uint fFlags)\r
150                 {\r
151                         StringBuilder sb = new StringBuilder(MAX_PATH);\r
152                         shellLink.GetPath(sb, sb.Capacity, IntPtr.Zero, fFlags);\r
153                         return sb.ToString();\r
154                 }\r
155                 \r
156                 /// <summary>\r
157                 /// リンク先パス(取得時には環境変数は展開されません)\r
158                 /// </summary>\r
159                 public string Path {\r
160                         get { return GetPath(0x04); }\r
161                         set { shellLink.SetPath(value); }\r
162                 }\r
163                 \r
164                 /// <summary>\r
165                 /// リンク先(引数)\r
166                 /// </summary>\r
167                 public string Arguments {\r
168                         get {\r
169                                 StringBuilder sb = new StringBuilder(MAX_PATH);\r
170                                 shellLink.GetArguments(sb, sb.Capacity);\r
171                                 return sb.ToString();\r
172                         }\r
173                         set { shellLink.SetArguments(value); }\r
174                 }\r
175                 \r
176                 /// <summary>\r
177                 /// 作業フォルダー\r
178                 /// </summary>\r
179                 public string WorkingDirectory {\r
180                         get {\r
181                                 StringBuilder sb = new StringBuilder(MAX_PATH);\r
182                                 shellLink.GetWorkingDirectory(sb, sb.Capacity);\r
183                                 return sb.ToString();\r
184                         }\r
185                         set { shellLink.SetWorkingDirectory(value); }\r
186                 }\r
187                 \r
188                 /// <summary>\r
189                 /// ウィンドウスタイル(ShowCmdのワッパ)\r
190                 /// </summary>\r
191                 public ProcessWindowStyle WindowStyle\r
192                 {\r
193                         get {\r
194                                 uint showcmd;\r
195                                 shellLink.GetShowCmd(out showcmd);\r
196                                 switch (showcmd) {\r
197                                         case 3:\r
198                                                 return ProcessWindowStyle.Maximized;\r
199                                         case 7:\r
200                                                 return ProcessWindowStyle.Minimized;\r
201                                         case 1:\r
202                                         default:\r
203                                                 return ProcessWindowStyle.Normal;\r
204                                 }\r
205                         }\r
206                         set {\r
207                                 switch (value) {\r
208                                         case ProcessWindowStyle.Normal:\r
209                                                 shellLink.SetShowCmd(1);\r
210                                                 break;\r
211                                         case ProcessWindowStyle.Maximized:\r
212                                                 shellLink.SetShowCmd(3);\r
213                                                 break;\r
214                                         case ProcessWindowStyle.Minimized:\r
215                                         case ProcessWindowStyle.Hidden:\r
216                                                 shellLink.SetShowCmd(7);\r
217                                                 break;\r
218                                 }\r
219                         }\r
220                 }\r
221                 \r
222                 /// <summary>\r
223                 /// アイコンの場所を得る\r
224                 /// </summary>\r
225                 /// <param name="iconPath">アイコンを含むファイルパス</param>\r
226                 /// <param name="iconIndex">アイコンのインデックス</param>\r
227                 public void GetIconLocation(out string iconPath, out int iconIndex)\r
228                 {\r
229                         StringBuilder sb = new StringBuilder(MAX_PATH);\r
230                         shellLink.GetIconLocation(sb, sb.Capacity, out iconIndex);\r
231                         iconPath = sb.ToString();\r
232                 }\r
233                 \r
234                 /// <summary>\r
235                 /// アイコンの場所を設定する\r
236                 /// </summary>\r
237                 /// <param name="iconPath">アイコンを含むファイルパス</param>\r
238                 /// <param name="iconIndex">アイコンのインデックス</param>\r
239                 public void SetIconLocation(string iconPath, int iconIndex)\r
240                 {\r
241                         shellLink.SetIconLocation(iconPath, iconIndex);\r
242                 }\r
243                 \r
244                 /// <summary>\r
245                 /// COMオブジェクトの開放\r
246                 /// </summary>\r
247                 public void Dispose()\r
248                 {\r
249                         if (shellLink != null) {\r
250                                 Marshal.ReleaseComObject(shellLink);\r
251                                 shellLink = null;\r
252                         }\r
253                         GC.SuppressFinalize(this);\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 ( (!string.IsNullOrEmpty(vInfo.ProductName))\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