2

how to use SHExtractIconsW dll function in C#, I managed to do this in AutoIt,

Local $arResult = DllCall('shell32.dll', 'int', 'SHExtractIconsW', _
        'wstr', $sIcon, _
        'int', $aDetails[5], _
        'int', $iSize, _
        'int', $iSize, _
        'ptr*', 0, 'ptr*', 0, 'int', 1, 'int', 0)

this is a refference from microsoft site, http://msdn.microsoft.com/en-us/library/windows/desktop/bb762163(v=vs.85).aspx

basically I want to extract icons from exe files, but almost all the examples here can not do that, in autoit I can do this with SHExtractIconsW, so I wanted to try it in C#.

note: i want 64x64 up to 256x256 icon size, not under.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
nyongrand
  • 618
  • 10
  • 24
  • 1
    What, exactly, is the advantage of using SHExtractIconsW instead of, say, LoadImage or ExtractIcon[Ex]? – Cody Gray - on strike Apr 12 '13 at 21:30
  • use ExtractIcon i can only extract small(16x16) and large (32x32) icon, as for LoadImage i don't know if it's can load icon from executablee file. – nyongrand Apr 12 '13 at 21:45
  • Yes, LoadImage is designed to do that. It takes an HINSTANCE parameter and a resource identifier. – Cody Gray - on strike Apr 12 '13 at 21:47
  • thank you for your info, it sounds like a new alternative for me, I'll try it later, after deal with this SHExtractIconsW. – nyongrand Apr 12 '13 at 21:53
  • @cody you need to get anHINSTANCE which these convenience apis in shell32 aim to save you from doing – David Heffernan Apr 12 '13 at 21:55
  • Sooo, we save one call to `LoadLibraryEx`? Big deal. This is an object-oriented language. Wrap it all up in a class and forget about it. – Cody Gray - on strike Apr 12 '13 at 21:57
  • @cody Well I know that. There's a lot of duplication in the shell32 dll. I think ms added a lot of useful helpers for convenience and then got lawyered into making them public. With lame documentation written by some summer PFY of an intern. – David Heffernan Apr 12 '13 at 22:04

1 Answers1

3

This appears to be a very poorly documented function.

The documentation for phIcon says:

When this function returns, contains a pointer to the array of icon handles.

But since the parameter has type HICON*, the caller must provide the array.

The documentation for pIconId is also wrong. It turns out that it also is an array.

All the marshalling can be done using default settings. Since there is no ANSI version of this API, give it the full name, SHExtractIconsW and set the Charset to Unicode.

So far as the documentation goes, there's no mention of SetLastError being called.

[DllImport("Shell32.dll", CharSet=CharSet.Unicode, ExactSpelling=true)]
static extern uint SHExtractIconsW(
    string pszFileName,
    int nIconIndex,
    int cxIcon,
    int cyIcon,
    IntPtr[] phIcon,
    uint[] pIconId,
    uint nIcons,
    uint flags
);

To call this you'll need to allocate the arrays like this:

IntPtr[] Icons = new IntPtr[nIcons];
uint[] IconIDs = new uint[nIcons];

Finally, I echo @Cody's comment. Since this API is clearly documented incorrectly, I'd try to use an alternative API that is documented properly and that you can rely on for the future.


Since you seem to be struggling to get this all to work, here's a fun program that extracts and displays icons from shell32.dll. I've not attempted to do any error checking, not called DestroyIcon on the icons and so on.

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

namespace WindowsFormsApplication12
{
    public partial class Form1 : Form
    {
        [DllImport("Shell32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
        static extern uint SHExtractIconsW(
            string pszFileName,
            int nIconIndex,
            int cxIcon,
            int cyIcon,
            IntPtr[] phIcon,
            uint[] pIconId,
            uint nIcons,
            uint flags
        );

        public Form1()
        {
            InitializeComponent();
        }

        private IntPtr[] Icons;
        private int currentIcon = 0;
        uint iconsExtracted;

        private void Form1_Load(object sender, EventArgs e)
        {
            uint nIcons = 1000;
            Icons = new IntPtr[nIcons];
            uint[] IconIDs = new uint[nIcons];
            iconsExtracted = SHExtractIconsW(
                @"C:\Windows\System32\shell32.dll",
                0,
                256, 256,
                Icons,
                IconIDs,
                nIcons,
                0
            );
            if (iconsExtracted == 0)
                ;//handle error
            Text = string.Format("Icon count: {0:d}", iconsExtracted);
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            pictureBox1.Image = Bitmap.FromHicon(Icons[currentIcon]);
            currentIcon = (currentIcon + 1) % (int)iconsExtracted;
        }
    }
}
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490