Extract all icons from EXE without using ExtractIconEx

I need to extract all the icons from EXE and save them as files on the disk, but I cannot use the simplest solution ( ExtractIconEx ), because I need to extract ICO files that save large icons, even if the code runs on Windows-based systems XP. I will then extract the necessary icons (128x128 and other Vista-sized icons) using different code, but I need a way to extract all the icons with all their resources, since they are in the EXE, regardless of whether my computer is running XP, Vista or win7.

So far I know that the icons are in RT_GROUP_ICONS .

I know that some people should have done this before in Delphi, because utilities like IcoFX and the resource finder seem to have done this. I once remember that I saw an open source Delphi tool that would do this, but that was many years ago.

To reformulate the problem with ExtractIconEx - it will not get access to the entire .ico file, it will extract only the supported icon resource formats, which always support the same resolution (size) supported by the platform. So, for example, on XP, the 32x32 or 48x48 icon will be extracted, but not the 128x128 icon in Vista format.

Update: This is a modified version of the accepted answer that solves the problem of the future. if some function that we call should disappear from User32.dll in a future version of Windows, I would like it to fail more elegantly than not loading my entire application.

unit ExtractIconUtils; interface uses Graphics,Forms,Windows; //---------------------------------------------------------------------------- // ExtractIcons // Call "private" MS Api to extract Icon file. This calls a publically // documented function marked as deprecated in the MSDN documentation. // It was no doubt Not Originally Intended to be documented, or publically // accessed, but it provides functionality that its hard to live without. // It exists on Windows 2000, XP, Vista, and Windows7, but might not exist // in some future Windows version (released after year 2011). // // uses global hUserDll : THandle; //---------------------------------------------------------------------------- function ExtractIcons(exeFilename,icoOutFileName:String;icoSize:Integer):Boolean; var hUserDll : THandle; implementation function ExtractIcons(exeFilename,icoOutFileName:String;icoSize:Integer):Boolean; const {$ifdef UNICODE} ExtractProcName='PrivateExtractIconsW'; {$else} ExtractProcName='PrivateExtractIconsA'; {$endif} type TExtractFunc = function(lpszFile: PChar; nIconIndex, cxIcon, cyIcon: integer; phicon: PHANDLE; piconid: PDWORD; nicon, flags: DWORD): DWORD; stdcall; var hIcon : THandle; nIconId : DWORD; Icon : TIcon; PrivateExtractIcons:TExtractFunc; begin result := false; if (hUserDll<4) then begin hUserDll := LoadLibrary('user32.dll'); if (hUserDll<4) then exit; end; { PrivateExtractIcons: MSDN documentation says that this function could go away in a future windows version, so we must try to load it, and if it fails, return false, rather than doing a static DLL import. } PrivateExtractIcons := GetProcAddress(hUserDll, ExtractProcName); if not Assigned(PrivateExtractIcons) then exit; //extract a icoSize x icoSize icon where icoSize is one of 256,128,64,48,32,16 if PrivateExtractIcons ( PWideChar(exeFilename), 0, icoSize, icoSize, @hIcon, @nIconId, 1, LR_LOADFROMFILE) <>0 then try Icon:=TIcon.Create; try Icon.Handle:=hIcon; Icon.SaveToFile(icoOutFileName); result := true; finally Icon.Free; end; finally DestroyIcon (hIcon); end; end ; initialization // none finalization if (hUserDll>4) then FreeLibrary(hUserDll); end. 
+6
source share
2 answers

PrivateExtractIcons can help you. You can specify the size of the icon you want to extract:

 {$IFDEF UNICODE} function PrivateExtractIcons(lpszFile: PChar; nIconIndex, cxIcon, cyIcon: integer; phicon: PHANDLE; piconid: PDWORD; nicon, flags: DWORD): DWORD; stdcall ; external 'user32.dll' name 'PrivateExtractIconsW'; {$ELSE} function PrivateExtractIcons(lpszFile: PChar; nIconIndex, cxIcon, cyIcon: integer; phicon: PHANDLE; piconid: PDWORD; nicon, flags: DWORD): DWORD; stdcall ; external 'user32.dll' name 'PrivateExtractIconsA'; {$ENDIF} procedure TMainForm.Button1Click(Sender: TObject); var hIcon : THandle; nIconId : DWORD; Icon : TIcon; begin //Extract a 128x128 icon if PrivateExtractIcons ('C:\Users\Public\Documents\RAD Studio\Projects\2010\Aero Colorizer\AeroColorizer.exe', 0, 128, 128, @hIcon, @nIconId, 1, LR_LOADFROMFILE) <>0 then try Icon:=TIcon.Create; try Icon.Handle:=hIcon; Icon.SaveToFile(ExtractFilePath(ParamStr(0))+'Aicon.ico'); finally Icon.Free; end; finally DestroyIcon (hIcon); end; end ; 
+9
source

Here is a working example on Delphi Praxis . It reads the default RT_GROUP_ICON and its associated RT_ICON resources for the specified executable file and saves them as a complete .ICO file with multiple images.

It seems to be confused by 256-pixel images (saved with an invalid format), at least on XP, so a little tweaking may be required.

+1
source

Source: https://habr.com/ru/post/887763/


All Articles