There are a couple of ways to do this. The most reliable, and potentially most time consuming (provided you can't find an existing library), is to parse the PE File (i.e. .exe, .dll) and extract the relevant Icon group data yourself. Here's a good resource for the format: https://msdn.microsoft.com/en-us/library/ms809762.aspx
The second way, can be done easily enough with Windows functions, however there is one caveat. It will only work on PE files that are of the same bit-type as your application. So, for example, if your application is 64-bit, it will only work on 64-bit PE files.
Here's a function I just wrote - based off this: https://msdn.microsoft.com/en-us/library/windows/desktop/ms648051(v=vs.85).aspx#_win32_Sharing_Icon_Resources, that takes a file name, group number, and desired icon size, and returns a System.Drawing.Icon
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)] static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName); [DllImport("kernel32.dll")] static extern IntPtr FindResource(IntPtr hModule, int lpName, int lpType); [DllImport("kernel32.dll", SetLastError = true)] static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo); [DllImport("kernel32.dll")] static extern IntPtr LockResource(IntPtr hResData); [DllImport("user32.dll")] static extern int LookupIconIdFromDirectoryEx(byte[] presbits, bool fIcon, int cxDesired, int cyDesired, uint Flags); [DllImport("user32.dll")] static extern IntPtr CreateIconFromResourceEx(byte[] pbIconBits, uint cbIconBits, bool fIcon, uint dwVersion, int cxDesired, int cyDesired, uint uFlags); [DllImport("kernel32.dll", SetLastError = true)] static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo); const int RT_GROUP_ICON = 14; const int RT_ICON = 0x00000003; private System.Drawing.Icon GetIconFromGroup(string file, int groupId, int size) { IntPtr hExe = LoadLibrary(file); if(hExe != IntPtr.Zero) { IntPtr hResource = FindResource(hExe, groupId, RT_GROUP_ICON); IntPtr hMem = LoadResource(hExe, hResource); IntPtr lpResourcePtr = LockResource(hMem); uint sz = SizeofResource(hExe, hResource); byte[] lpResource = new byte[sz]; Marshal.Copy(lpResourcePtr, lpResource, 0, (int)sz); int nID = LookupIconIdFromDirectoryEx(lpResource, true, size, size, 0x0000); hResource = FindResource(hExe, nID, RT_ICON); hMem = LoadResource(hExe, hResource); lpResourcePtr = LockResource(hMem); sz = SizeofResource(hExe, hResource); lpResource = new byte[sz]; Marshal.Copy(lpResourcePtr, lpResource, 0, (int)sz); IntPtr hIcon = CreateIconFromResourceEx(lpResource, sz, true, 0x00030000, size, size, 0); System.Drawing.Icon testIco = System.Drawing.Icon.FromHandle(hIcon); return testIco; } return null; }
The process basically works like this:
- use
LoadLibrary to load up the .exe or .dll file - Get the handle & data of the
RT_GROUP_ICON resource - Pass the data, along with the desired size to
LookupIconIdFromDirectoryEx, to get the icon index - From there, you can either use
ExtractIconEx, or just repeat step 2 with the icon index, and RT_ICON instead, followed by using CreateIconFromResourceEx to get your icon handle.