Извлечь все значки из EXE без использования ExtractIconEx - PullRequest
6 голосов
/ 10 мая 2011

Мне нужно извлечь все значки из EXE и сохранить их как файлы на диске, но я не могу использовать самое простое решение ( ExtractIconEx ), потому что мне нужно извлечь файлы ICO таким образом, чтобы сохранить большиезначки размера, даже если код работает на системах под управлением Windows XP.Позже я извлеку нужные значки (128x128 и другие значки размера Vista), используя другой код, но мне нужен способ извлечения всех значков со всеми их ресурсами, так как они присутствуют в EXE-файле, независимо от того, работает ли мой код на ПК.работает под управлением XP, Vista или Win7.

Пока я знаю, что значки находятся в RT_GROUP_ICONS .

Я знаю, что некоторые люди, должно быть, делали это раньше в Delphiпотому что утилиты вроде IcoFX и resource-explorer, кажется, сделали это.Однажды я помню, как видел полностью Delphi-инструмент с открытым исходным кодом, который бы это делал, но это было много лет назад.

Чтобы повторить проблему, возникшую у меня с ExtractIconEx - он не будет обращаться ко всему файлу .ico, он будет толькоизвлечь поддерживаемые форматы ресурсов значков, которые когда-либо одного разрешения (размера), поддерживаемого платформой.Так, например, в XP он извлекает значок 32x32 или 48x48, но не значок Vista в формате 128x128.

Обновление: Это измененная версия принятого ответа, которая решаетмоя забота о будущемесли каким-то образом функция, которую мы вызываем, должна была исчезнуть из User32.dll в будущей версии Windows, я бы хотел, чтобы она более аккуратно завершилась ошибкой, чем не загрузила все мое приложение.

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.

Ответы [ 2 ]

9 голосов
/ 10 мая 2011

Вам может помочь функция PrivateExtractIcons. Вы можете указать размер иконки, которую вы хотите извлечь:

{$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 ;
1 голос
/ 11 мая 2011

Вот рабочий пример Delphi Praxis . Он считывает RT_GROUP_ICON по умолчанию и связанные ресурсы RT_ICON для указанного исполняемого файла и сохраняет их как полный файл .ICO с несколькими образами.

Кажется, что он запутан 256-пиксельными изображениями (сохраняет в неверном формате), по крайней мере, в XP, поэтому может потребоваться небольшая настройка.

...