There is no easy way. Having said this, there is a way to get it via
image list, but it is not for meek.
Basically what you do is create an empty toolbar control and add it to
your form. Then you assign your imagelist to it. Then you use
SHFindMenuBar to get its handle, and then TB_GETIMAGELIST to get
hImageList. From there it is easy to call ImageList_GetIcon to get an
icon handle. Then you remove toolbar. Since this is all done in a single
call, toolbar does not have a chance to show up, nor would it, since it
does not have any buttons. The only problem is that adding/removing
control forces the for to repaint once , but I suspect it can be overcome
by doing this on a hidden form.
private int ExtractIcon(ImageList il, int index)
{
Capture = true;
IntPtr hWnd = GetCapture();
Capture = false;
ToolBar tb = new ToolBar();
tb.ImageList = il;
this.Controls.Add(tb);
IntPtr hWndTB = SHFindMenuBar(hWnd);
IntPtr hIL = SendMessage(hWndTB, TB_GETIMAGELIST, 0, 0);
IntPtr hIcon = ImageList_GetIcon(hIL, index, 0);
IntPtr hDC = GetDC(hWnd);
DrawIconEx(hDC, 20, 20, hIcon, 0, 0, 0, IntPtr.Zero, DI_NORMAL);
ReleaseDC(hWnd, hDC);
hIcon = IntPtr.Zero;
this.Controls.Remove(tb);
}
// P/Invokes
const int WM_USER = 0x400;
const int TB_GETIMAGELIST = WM_USER + 49;
const int DI_NORMAL = 3;
[DllImport("coredll")]
extern static IntPtr GetCapture();
[DllImport("coredll")]
extern static IntPtr ImageList_GetIcon(
IntPtr himl,
int i,
uint flags
);
[DllImport("aygshell")]
extern static IntPtr SHFindMenuBar(IntPtr hwnd);
[DllImport("coredll")]
extern static IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, int
lParam);
[DllImport("coredll")]
extern static IntPtr GetDC(IntPtr hWnd);
[DllImport("coredll")]
extern static IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("coredll")]
extern static int DrawIconEx(
IntPtr hDC,
int X,
int Y,
IntPtr hIcon,
int cxWidth,
int cyWidth,
int istepIfAniCur,
IntPtr hbrFlickerFreeDraw,
uint diFlags
);