0

我编写了以下代码,旨在返回一个List<Icon>文件中找到的所有图标的列表。

private List<Icon> GetIconsFromFile(string file)
{
    List<Icon> icons = new List<Icon>();
    IntPtr[] large = new IntPtr[999];
    IntPtr[] small = new IntPtr[999];
    Icon ico;
    try
    {
        int count = ExtractIconEx(file, -1, large, small, 999);
        if (count > 0)
        {
            large = new IntPtr[count - 1];
            small = new IntPtr[count - 1];

            ExtractIconEx(file, 0, large, small, count);
            for (int x = 0; x < count; x++)
            {
                ico = (Icon)Icon.FromHandle(large[x]).Clone();
                icons.Add(ico);
            }
        }
    }
    catch (Exception e)
    {
        System.Diagnostics.Debug.WriteLine(e.Message);
    } finally
    {
        foreach (IntPtr ptr in large) {
            if (ptr != IntPtr.Zero) {
                DestroyIcon(ptr);
            }
        }
        foreach (IntPtr ptr in small) {
            if (ptr != IntPtr.Zero) {
                DestroyIcon(ptr);
            }
        }
    }
    return icons;
}

当我使用如下代码时:

var icons = GetIconsFromFile(@"c:\windows\explorer.exe");

这是我单步执行代码时得到的结果:

int count = ExtractIconEx(file, -1, large, small, 999);

count是 29

for (int x = 0; x < count; x++)
{
    ico = (Icon)Icon.FromHandle(large[x]).Clone();
    icons.Add(ico);
}

x达到 28 时,抛出异常。x 的值跳到 39

这没有意义,因为这意味着当返回 29 的计数时,实际上有 27 个图标使第一个图标的值为 -1。如果计数从 0 开始,则 29 - 1 = 28,并且由于 28 小于count(29),因此不应引发异常,因为它在边界内。

当 api 返回(可能)此文件中正确数量的图标时,为什么此代码会导致越界错误?——除了改变我还能做x < count什么x < (count - 1)

4

1 回答 1

0

虽然根据 api 文档,关于为什么检索到的图标 ptr 的具体原因与图标计数不匹配,但我有一个解决该问题的方法,通过将for(int x; x < count; x++)循环更改为有条件检查的foreach(var x in large)循环。if(x != IntPtr.Zero)改写的方法如下:

private List<Icon> GetIconsFromFile(string file)
{
    List<Icon> icons = new List<Icon>();
    IntPtr[] large = new IntPtr[999];
    IntPtr[] small = new IntPtr[999];
    Icon ico;
    try
    {
        int count = ExtractIconEx(file, -1, large, small, 999);
        if (count > 0)
        {
            large = new IntPtr[count - 1];
            small = new IntPtr[count - 1];

            ExtractIconEx(file, 0, large, small, count);
            foreach(var x in large)
            {
                if(x != IntPtr.Zero) {
                   ico = (Icon)Icon.FromHandle(x).Clone();
                   icons.Add(ico);
                }
            }
        }
    }
    catch (Exception e)
    {
        System.Diagnostics.Debug.WriteLine(e.Message);
    } finally
    {
        foreach (IntPtr ptr in large) {
            if (ptr != IntPtr.Zero) {
                DestroyIcon(ptr);
            }
        }
        foreach (IntPtr ptr in small) {
            if (ptr != IntPtr.Zero) {
                DestroyIcon(ptr);
            }
        }
    }
    return icons;
}

仍然对为什么计数不正确或没有 IntPtr 值的想法持开放态度,这些值应该位于large数组的尾端。

于 2016-08-05T01:59:59.810 回答