2009-10-21 30 views
15

Tôi có đoạn mã sau đó hoạt động trên Windows XP và Vista - cả 32 và 64 bit:Làm thế nào để lấy biểu tượng thư mục trên Windows 7 sử dụng 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; 
} 

Các hằng số được định nghĩa theo cách sau :

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; 

này cho kết quả như sau trong cửa sổ 7 khi lấy biểu tượng thư mục:

alt text

.210

Trong khi tại Vista - sử dụng kết quả phương pháp tương tự trong biểu tượng thư mục sau:

alt text

Tôi muốn vào biểu tượng thư mục Windows "đúng" cho Windows 7 cũng - không phải là biểu tượng dùng để biểu thị các ổ đĩa nơi Windows được cài đặt.

Tôi không biết API win32 và chương trình không được quản lý của tôi không nằm cạnh nền tảng Windows.

+0

Hãy làm rõ câu hỏi của bạn."Điều này dẫn đến các cửa sổ 7 với các biểu tượng sau" nghĩa là gì? –

Trả lời

20

Bạn không nên chỉ định null làm thông số đầu tiên yur thành SHGeFileInfo. Thay vào đó, hãy sử dụng đường dẫn đến thư mục (xin lưu ý rằng một số thư mục có biểu tượng khác (không chuẩn). Bạn có thể sử dụng thư mục tạm thời hoặc thư mục gốc của ứng dụng của bạn chẳng hạn.

Thực hành tốt nhất là lấy biểu tượng đúng cho mỗi thư mục (nói cách khác: Thay đổi chữ ký GetFolderIcon thành public static Icon GetFolderIcon(string folderPath, IconSize size, FolderType folderType) và gọi nó cho mỗi thư mục bạn hiển thị).

Dường như có một thư viện nguồn mở đã có trình bao bọc được quản lý để tìm nạp các biểu tượng thư mục. Tìm thấy trên PInvoke.net (mục nhập cho SHGetFileInfo):

Tuy nhiên, điều này không có tác dụng nếu bạn muốn biểu tượng ổ đĩa hoặc thư mục.

Trong trường hợp đó, bạn có thể sử dụng lớp ExtendedFileInfo do dự án ManagedWindowsApi cung cấp (http://mwinapi.sourceforge.net).

Nếu bạn muốn dính vào một giải pháp thủ công bằng tay, điều này làm việc cho tôi (Win7 x64 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

vì mọi người đều có 'C: \ Windows' trên hệ thống của họ –

+0

Nó hoạt động ngay cả khi bạn không có 'C: \ Windows', hãy xem câu trả lời của Tom. Dù sao, đó là lý do tại sao có một nhận xét về thực hành tốt nhất và một "điều này làm việc cho tôi". – JPW

9

Bạn không nên chỉ định null như yur tham số đầu tiên cho SHGeFileInfo.

Đúng vậy.

Sử dụng đường dẫn đến thư mục thay thế (xin lưu ý rằng một số thư mục có biểu tượng khác (không chuẩn). Bạn có thể sử dụng thư mục tạm thời hoặc thư mục gốc của ứng dụng của bạn chẳng hạn.

Nó không cần phải là đường dẫn thư mục thực (hiện có). Bất kỳ chuỗi không trống nào cũng sẽ làm. ví dụ:

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

Đây là một câu trả lời rất hữu ích và hiệu quả. Bạn không cần phải cố gắng tìm kiếm một thư mục thực sự để vượt qua. Trong thực tế, tôi theo nghĩa đen vượt qua '" AnyNonEmptyStringWillDo "'. –

Các vấn đề liên quan