using System;\r
using System.IO;\r
+using System.Runtime.InteropServices;\r
using System.Drawing;\r
using System.Drawing.Imaging;\r
using NaGet.Packages;\r
/// </summary>\r
public sealed class GUIUtils\r
{\r
+ #region ExtraIcon関連\r
+ \r
+ [DllImport("shell32.dll")]\r
+ private static extern IntPtr ExtractIcon(IntPtr hInst, string lpszExeFileName, int nIconIndex);\r
+ \r
+ [DllImport("user32.dll", SetLastError=true)]\r
+ [return: MarshalAs(UnmanagedType.Bool)]\r
+ private static extern bool DestroyIcon(IntPtr hIcon);\r
+ \r
+ /// <summary>\r
+ /// アイコンファイル(実行ファイル・DLL)を開いてアイコンを作る\r
+ /// </summary>\r
+ /// <remarks>内部でコピーされるのでWin32APIのDestroyIconを使わないでいいが、やや遅い動作</remarks>\r
+ /// <param name="form">ハンドラ</param>\r
+ /// <param name="lpszExeFileName">対象ファイル</param>\r
+ /// <param name="nIconIndex">アイコンインデックス</param>\r
+ /// <returns>生成されたアイコン</returns>\r
+ public static Icon ExtractIcon(System.Windows.Forms.Form form, string lpszExeFileName, uint nIconIndex)\r
+ {\r
+ Icon ico = null;\r
+ \r
+ if (! File.Exists(lpszExeFileName)) {\r
+ ico = Icon.ExtractAssociatedIcon(lpszExeFileName); // ExtractAssociatedIconに例外を吐いてもらう\r
+ } else {\r
+ IntPtr hInst = (form != null)? form.Handle : IntPtr.Zero;\r
+ IntPtr hIcon = IntPtr.Zero;\r
+ \r
+ try {\r
+ hIcon = ExtractIcon(hInst, lpszExeFileName, (int) nIconIndex);\r
+ if ((hIcon != IntPtr.Zero) && (hIcon.ToInt32() != 2)) {\r
+ ico = (Icon) Icon.FromHandle(hIcon).Clone();\r
+ DestroyIcon(hIcon);\r
+ }\r
+ } catch (System.Runtime.InteropServices.COMException) {\r
+ // ExtraIconのP/Invoke失敗時用\r
+ }\r
+ }\r
+ return ico;\r
+ }\r
+ \r
+ /// <summary>\r
+ /// アイコンファイル(実行ファイル・DLL)を開いてアイコンを作る\r
+ /// </summary>\r
+ /// <param name="form">ハンドラ</param>\r
+ /// <param name="lpszExeFileNameAndIndex">対象ファイルとアイコンインデックスの文字列表現</param>\r
+ /// <returns>生成されたアイコン。</returns>\r
+ public static Icon ExtractIcon(System.Windows.Forms.Form form, string lpszExeFileNameAndIndex)\r
+ {\r
+ int index = lpszExeFileNameAndIndex.LastIndexOf(',');\r
+ if (index >= 0) {\r
+ uint nIconIndex = uint.Parse(lpszExeFileNameAndIndex.Substring(index+1));\r
+ return ExtractIcon(form, lpszExeFileNameAndIndex.Substring(0, index), nIconIndex);\r
+ } else {\r
+ return Icon.ExtractAssociatedIcon(lpszExeFileNameAndIndex);\r
+ }\r
+ }\r
+ \r
+ /// <summary>\r
+ /// シェルからフォルダアイコンを生成して返す\r
+ /// </summary>\r
+ /// <returns>フォルダアイコン</returns>\r
+ public static Icon GetShellIconForFolder()\r
+ {\r
+ // Vista以降ならば、SHGetStockIconInfo(SIID_FOLDER, SHGSI_ICON, &sInfo); をP/Invoke呼び出しするのが王道かと\r
+ string windir = Environment.GetEnvironmentVariable("windir");\r
+ return ExtractIcon(null, Path.Combine(windir, @"system32\shell32.dll"), 3);\r
+ }\r
+ \r
+ #endregion\r
+ \r
/// <summary>\r
/// パッケージに対応するアイコンを返す\r
/// </summary>\r
/// <returns>対応するアイコン。検出できなかった場合はnull。</returns>\r
public static Icon GetIconForPackage(InstalledPackage pkg)\r
{\r
+ Icon ico = null;\r
string iconPath = pkg.UninstallInfo.IconPath;\r
if (! string.IsNullOrEmpty(iconPath)) {\r
- if (iconPath.EndsWith(",0") || iconPath.EndsWith(",-0")) {\r
- iconPath = iconPath.Substring(0, iconPath.LastIndexOf(','));\r
- }\r
- if (File.Exists(iconPath)) {\r
- return Icon.ExtractAssociatedIcon(iconPath);\r
- }\r
+ ico = ExtractIcon(null, iconPath);\r
} else if (pkg.Type == InstallerType.ARCHIVE) {\r
string progGrp = Path.Combine(NaGet.Env.ArchiveProgramGroup, pkg.Name);\r
if (Directory.Exists(progGrp)) {\r
try {\r
using (NaGet.InteropServices.ShellLink link = new NaGet.InteropServices.ShellLink(lnkFiles[0])) {\r
if (File.Exists(link.GetPath(0))) {\r
- return Icon.ExtractAssociatedIcon(link.GetPath(0));\r
+ ico = Icon.ExtractAssociatedIcon(link.GetPath(0));\r
}\r
}\r
} catch (System.Runtime.InteropServices.COMException) {\r
}\r
}\r
}\r
- return null;\r
+ return ico;\r
}\r
\r
/// <summary>\r
public void BuildItems()\r
{\r
if (thread != null) {\r
- if (! thread.Join(1000)) {\r
+ if (! thread.Join(500)) {\r
thread.Interrupt();\r
}\r
thread = null;\r
}\r
}\r
\r
+ private void _insertItemFor(string filepath, ref bool cmdIsAdded)\r
+ {\r
+ string extension = Path.GetExtension(filepath).ToLower();\r
+ if (extension == ".exe") {\r
+ switch (NaGet.InteropServices.PEFileInfoUtils.GetPEFileType(filepath)) {\r
+ case NaGet.InteropServices.PEFileInfoUtils.PEFileType.WinGUI:\r
+ _addToItemsInv(CreateMenuItemForFile(filepath));\r
+ break;\r
+ case NaGet.InteropServices.PEFileInfoUtils.PEFileType.WinConsole:\r
+ case NaGet.InteropServices.PEFileInfoUtils.PEFileType.MSDosCom:\r
+ if (! cmdIsAdded) {\r
+ _insertToItemsInv(0, CreateMenuItemForCmdAt(Path.GetDirectoryName(filepath)));\r
+ cmdIsAdded = true;\r
+ }\r
+ break;\r
+ }\r
+ } else if ((extension == ".bat") || (extension == ".lnk")) {\r
+ _addToItemsInv(CreateMenuItemForFile(filepath));\r
+ }\r
+ }\r
+ \r
\r
private void buildItems()\r
{\r
_addToItemsInv(CreateMenuItemForFolder(folderPath));\r
_addToItemsInv(sep);\r
\r
- if (Directory.Exists(folderPath)) {\r
- foreach (string exeFile in Directory.GetFiles(folderPath, "*.exe")) {\r
+ if (Directory.Exists(folderPath)) { \r
+ foreach (string filepath in Directory.GetFiles(folderPath)) {\r
if (baseFolderPath != folderPath) return; // 途中でなんか操作されているならば終了\r
\r
- switch (NaGet.InteropServices.PEFileInfoUtils.GetPEFileType(exeFile)) {\r
- case NaGet.InteropServices.PEFileInfoUtils.PEFileType.WinGUI:\r
- _addToItemsInv(CreateMenuItemForFile(exeFile));\r
- break;\r
- case NaGet.InteropServices.PEFileInfoUtils.PEFileType.WinConsole:\r
- if (! cmdIsAdded) {\r
- _insertToItemsInv(0, CreateMenuItemForCmdAt(folderPath));\r
- cmdIsAdded = true;\r
- }\r
- break;\r
- }\r
+ _insertItemFor(filepath, ref cmdIsAdded);\r
}\r
}\r
} catch (ThreadInterruptedException) {}\r
public static ToolStripMenuItem CreateMenuItemForFolder(string folderPath)\r
{\r
ToolStripMenuItem item = CreateMenuItemForFile(folderPath);\r
+ item.Image = GUIUtils.GetShellIconForFolder().ToBitmap();\r
item.Text = "フォルダを開く(&O)";\r
return item;\r
}\r