C# ExtractIconEx nIconIndex参数的正确用法?

C# ExtractIconEx nIconIndex参数的正确用法?,c#,C#,我试图以编程方式从注册表中提取一些图标。然而,我注意到不一致的行为。我在这里做了一个基本测试: 如果我阅读了有关索引工作原理的说明: 如果此值为负数且phiconLarge或phiconSmall不为空,则函数首先提取其资源标识符等于nIconIndex绝对值的图标。例如,使用-3提取资源标识符为3的图标 然而,我不能在我的结果中重复这一点。我可以通过检查结果是否为0来解决这个问题,然后翻转值并再次运行它,但我觉得一定有更好的解决方案。如果您误解了函数的工作原理,您不能只翻转数字的符号 图标有

我试图以编程方式从注册表中提取一些图标。然而,我注意到不一致的行为。我在这里做了一个基本测试:

如果我阅读了有关索引工作原理的说明:

如果此值为负数且phiconLarge或phiconSmall不为空,则函数首先提取其资源标识符等于nIconIndex绝对值的图标。例如,使用-3提取资源标识符为3的图标


然而,我不能在我的结果中重复这一点。我可以通过检查结果是否为0来解决这个问题,然后翻转值并再次运行它,但我觉得一定有更好的解决方案。

如果您误解了函数的工作原理,您不能只翻转数字的符号

图标有一个资源ID,一个类似于100的数字。由创建资源文件的程序员选择。挑选数字没有标准,一切皆有可能

因此,如果你知道你想要的图标的资源ID,那么你传递一个负值,资源ID。你传递,比如说,-100

但是,如果您不知道程序员选择的资源ID,那么您必须(比如)选择资源表中的第一个图标。然后使用正数。0是第一个图标,1是第二个图标,等等。如果您想知道文件中有多少个图标,可以达到多高,那么传递-1,函数的返回值就会告诉您。如何获得资源ID为1的图标是一个问题


如果您有Visual Studio的零售版,则可以看到这些图标ID。文件+打开+文件并选择EXE或DLL文件。例如,选择c:\windows\system32\user32.dll,它有非常容易识别的图标。打开“图标”节点,您将看到图标列表,其资源ID可见。双击一个图标可以看到图标本身。

根据文档,这是向后的。负数是资源ID,正数是索引。但在我的测试中,telephon.cpl需要-100+100返回0。然而,它在properties=+100中的图标ID是正确的,更正了。是,-100起作用,Telephon.cpl有一个资源ID为100的图标。或者通过0来获得第一个(也是唯一的一个)。虽然您的订单被翻转了(谢谢RogerN),但这个解释确实帮助我更好地理解了它,我确实误解了它的工作原理,-1是一个不幸的特殊情况,它让我走错了方向。我在本地尝试了它,它似乎在工作,但nIconIndex=-1除外。正值对应于基于零的图标索引(0、1、2、3),负值对应于资源ID(这些是任意的)。但是,当传递nIconIndex=-1时,函数返回文件中图标的#,即使phiconLarge和phiconSmall不为NULL。除了C#之外,我还在纯C应用程序中尝试了它,以确保phiconLarge和phiconSmall不会以某种方式被编组为空指针。感谢测试,我假设类似的情况正在发生。然而,似乎所有带有-1参数的文件只有一个图标,所以现在我只添加一个特例来获得默认图标。
class Program
{
    [DllImport("Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    private static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons);

    static void Main(string[] args)
    {
        IntPtr largeIconPtr = IntPtr.Zero;
        IntPtr smallIconPtr = IntPtr.Zero;

        //HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{1206F5F1-0569-412C-8FEC-3204630DFB70}\DefaultIcon
        Console.WriteLine("Vault.dll");
        ExtractIconEx(@"%SystemRoot%\system32\Vault.dll", 1, out largeIconPtr, out smallIconPtr, 1);
        Console.WriteLine("Icon Index = 1");
        Console.WriteLine("Large: " + largeIconPtr.ToString());
        Console.WriteLine("Small: " + smallIconPtr.ToString());
        Console.WriteLine();

        Console.WriteLine("Icon Index = -1");
        ExtractIconEx(@"%SystemRoot%\system32\Vault.dll", -1, out largeIconPtr, out smallIconPtr, 1);            
        Console.WriteLine("Large: " + largeIconPtr.ToString());
        Console.WriteLine("Small: " + smallIconPtr.ToString());
        Console.WriteLine();

        //HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{40419485-C444-4567-851A-2DD7BFA1684D}\DefaultIcon
        Console.WriteLine("telephon.cpl");
        Console.WriteLine("Icon Index = 100");
        ExtractIconEx(@"%SystemRoot%\System32\telephon.cpl", 100, out largeIconPtr, out smallIconPtr, 1);
        Console.WriteLine("Large: " + largeIconPtr.ToString());
        Console.WriteLine("Small: " + smallIconPtr.ToString());
        Console.WriteLine();

        Console.WriteLine("Icon Index = -100");
        ExtractIconEx(@"%SystemRoot%\System32\telephon.cpl", -100, out largeIconPtr, out smallIconPtr, 1);
        Console.WriteLine("Large: " + largeIconPtr.ToString());
        Console.WriteLine("Small: " + smallIconPtr.ToString());
        Console.ReadLine();
    }
}