方法在3310次成功后失败

时间:2017-10-27 14:03:50

标签: c# icons pinvoke handle

我继承了以下扩展方法,该方法基于文件路径

创建ImageSource对象
public static class ImageSourceExtensions
{
    [StructLayout(LayoutKind.Sequential)]
    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 const uint SHGFI_ICON = 0x100;
    public const uint SHGFI_LARGEICON = 0x0;

    [DllImport("shell32.dll")]
    public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);

    public static ImageSource GetIconFromFolder(this string filePath)
    {
        SHFILEINFO shinfo = new SHFILEINFO();
        SHGetFileInfo(filePath, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo),
                SHGFI_ICON | SHGFI_LARGEICON);

        using (Icon i = Icon.FromHandle(shinfo.hIcon))
        {
            //Convert icon to a Bitmap source
            ImageSource img = Imaging.CreateBitmapSourceFromHIcon(
                                    i.Handle,
                                    new Int32Rect(0, 0, i.Width, i.Height),
                                    BitmapSizeOptions.FromEmptyOptions());

            return img;
        }
    }
}

此扩展方法适用于文件夹和文件3310次。在第3311个方法调用上,抛出以下异常:

  

'传递给Icon的Win32句柄无效或错误   类型“

使用 shinfo.hIcon 属性时会抛出此错误。

错误最初是在我的主应用程序中引发的,每次都在不同的文件上。我已经将这个类提取到一个新项目中,并且可以通过在单击按钮上执行此操作来获得相同的错误(在相同的次数之后):

String path = @"C:\Generic Folder\Generic Document.pdf";

        for (int i = 0; i <4000; i++)
        {
            ImageSource img = path.GetIconFromFolder();
        }

有人知道这个的明显原因吗?

1 个答案:

答案 0 :(得分:6)

你的HANDLE已经不多了。 Windows具有有限数量的句柄,当您获得一个句柄(在这种情况下是图标的句柄)时,您应该在不再使用它之后释放它。如果不这样做,Windows将耗尽免费句柄。

  

如果SHGetFileInfo在psfi指向的SHFILEINFO结构的hIcon成员中返回一个图标句柄,你负责在不再需要它时使用DestroyIcon释放它

因此,您需要PInvoke DestroyIcon并在功能结束时将shinfo.hIcon传递给它。

使用FromHandle创建的图标的处理不会破坏原始句柄:

  

使用此方法时,必须使用Win32 API中的DestroyIcon方法处置原始图标,以确保释放资源。