2009-10-21 65 views
15

在Windows 7的文件夾圖標,我有以下代碼在Windows XP和Vista的作品 - 無論是32位和64位:如何抓使用Shell32.SHGetFileInfo

public static Icon GetFolderIcon(IconSize size, FolderType folderType) 
{ 
    // Need to add size check, although errors generated at present! 
    uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_USEFILEATTRIBUTES; 

    if (FolderType.Open == folderType) 
    { 
     flags += Shell32.SHGFI_OPENICON; 
    } 

    if (IconSize.Small == size) 
    { 
     flags += Shell32.SHGFI_SMALLICON; 
    } 
    else 
    { 
     flags += Shell32.SHGFI_LARGEICON; 
    } 

    // Get the folder icon 
    var shfi = new Shell32.SHFILEINFO(); 
    Shell32.SHGetFileInfo( null, 
          Shell32.FILE_ATTRIBUTE_DIRECTORY, 
          ref shfi, 
          (uint) Marshal.SizeOf(shfi), 
          flags); 

    Icon.FromHandle(shfi.hIcon); // Load the icon from an HICON handle 

    // Now clone the icon, so that it can be successfully stored in an ImageList 
    var icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone(); 

    User32Dll.DestroyIcon(shfi.hIcon);  // Cleanup 
    return icon; 
} 

的常量的定義方式如下:

alt text

public const uint SHGFI_ICON = 0x000000100; 
public const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; 
public const uint SHGFI_OPENICON = 0x000000002; 
public const uint SHGFI_SMALLICON = 0x000000001; 
public const uint SHGFI_LARGEICON = 0x000000000; 
public const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010; 

此獲取的文件夾圖標時,給出了在Windows 7下面的結果

雖然在Vista中 - 使用下面的文件夾圖標相同的方法結果:

alt text

我想「正確的」 Windows文件夾中的Windows 7圖標也 - 不是用來指示驅動器的圖標在哪裏安裝Windows。

我不知道win32 API,而我的非託管編程在Windows平臺上幾乎沒有。

+0

請澄清你的問題。「這會導致帶有以下圖標的Windows 7」是什麼意思? – 2009-10-21 07:27:40

回答

20

您不應指定null作爲第一個參數SHGeFileInfo。改爲使用文件夾路徑(請注意,某些文件夾具有不同(非標準)圖標)。例如,您可以使用臨時文件夾或應用程序的根文件夾。

最佳做法是爲每個文件夾獲取正確的圖標(換句話說:將GetFolderIcon的簽名更改爲public static Icon GetFolderIcon(string folderPath, IconSize size, FolderType folderType)並將其稱爲您顯示的每個文件夾)。

似乎有一個開源的庫,它已經有一個託管包裝器來獲取文件夾圖標。 上找到PInvoke.net(在對入境的SHGetFileInfo):

然而,這並沒有,如果你想有一個驅動器或文件夾的圖標工作。

在這種情況下,您可以使用由ManagedWindowsApi項目(http://mwinapi.sourceforge.net)提供的ExtendedFileInfo類。

如果你要堅持手工製作的解決方案,這對我的作品(X64 Win7的RTM,.NET 3.5 SP1):

using System; 
using System.Drawing; 
using System.Runtime.InteropServices; 
using System.Windows.Forms; 

namespace IconExtractor 
{ 
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
    public struct SHFILEINFO 
    { 
     public IntPtr hIcon; 
     public int iIcon; 
     public uint dwAttributes; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 
     public string szDisplayName; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] 
     public string szTypeName; 
    }; 

    public enum FolderType 
    { 
     Closed, 
     Open 
    } 

    public enum IconSize 
    { 
     Large, 
     Small 
    } 

    public partial class Form1 : Form 
    { 
     [DllImport("shell32.dll", CharSet = CharSet.Auto)] 
     public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, out SHFILEINFO psfi, uint cbFileInfo, uint uFlags); 

     [DllImport("user32.dll", SetLastError = true)] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     static extern bool DestroyIcon(IntPtr hIcon); 

     public const uint SHGFI_ICON = 0x000000100; 
     public const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; 
     public const uint SHGFI_OPENICON = 0x000000002; 
     public const uint SHGFI_SMALLICON = 0x000000001; 
     public const uint SHGFI_LARGEICON = 0x000000000; 
     public const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010; 

     public static Icon GetFolderIcon(IconSize size, FolderType folderType) 
     {  
      // Need to add size check, although errors generated at present!  
      uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES;  

      if (FolderType.Open == folderType)  
      {   
       flags += SHGFI_OPENICON;  
      }  
      if (IconSize.Small == size)  
      {  flags += SHGFI_SMALLICON;  
      }  
      else  
      {  
       flags += SHGFI_LARGEICON;  
      }  
      // Get the folder icon  
      var shfi = new SHFILEINFO();  

      var res = SHGetFileInfo(@"C:\Windows",        
       FILE_ATTRIBUTE_DIRECTORY,        
       out shfi,        
       (uint) Marshal.SizeOf(shfi),        
       flags); 

      if (res == IntPtr.Zero) 
       throw Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()); 

      // Load the icon from an HICON handle 
      Icon.FromHandle(shfi.hIcon);  

      // Now clone the icon, so that it can be successfully stored in an ImageList 
      var icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone();  

      DestroyIcon(shfi.hIcon);  // Cleanup  

      return icon;} 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      try 
      { 

       Icon icon = GetFolderIcon(IconSize.Large, FolderType.Open); 
       pictureBox1.Image = icon.ToBitmap(); 
       // Note: The image actually should be disposed somewhere 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message); 
      } 
     } 
    } 
} 
+0

因爲每個人在他們的系統上都有'C:\ Windows' – 2014-12-05 00:30:59

+0

即使您沒有'C:\ Windows',它也能正常工作,請參閱Tom的回答。無論如何,這就是爲什麼有關最佳實踐的評論和「這對我有用」。 – JPW 2014-12-06 11:15:49

9

不應指定null作爲尤爾SHGeFileInfo的第一個參數。

沒錯。

改爲使用文件夾路徑(請注意,某些文件夾具有不同的(非標準)圖標)。例如,您可以使用臨時文件夾或應用程序的根文件夾。

它不需要是真實的(現有的)文件夾路徑。任何非空字符串都可以。例如:

SHGetFileInfo("AnyNonEmptyStringWillDo", FILE_ATTRIBUTE_DIRECTORY, sfi, 
     SizeOf(sfi), SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX) 
+3

這是一個非常有用的工作答案。你不必嘗試尋找一個真正的文件夾通過。事實上,我實際上通過''AnyNonEmptyStringWillDo'''。 – 2012-04-11 22:42:20