2011-05-10 38 views
6

我需要從EXE中提取所有圖標並將它們保存爲磁盤文件,但我無法使用最簡單的解決方案(ExtractIconEx),因爲我需要以某種方式提取ICO文件即使代碼在運行Windows XP的系統上運行,也可以保留大尺寸圖標。我將在稍後使用其他代碼提取想要的圖標(128x128和其他vista大小的圖標),但我需要一種方式來提取所有圖標及其所有資源,因爲它們出現在EXE中,而不管PC代碼是否運行正在運行XP,Vista或Win7。從EXE中提取所有圖標而不使用ExtractIconEx

到目前爲止,我知道圖標在RT_GROUP_ICONS

我知道有些人在Delphi中一定是做過這個,因爲像IcoFX和資源管理器這樣的工具似乎已經做到了。我曾經記得看到一個完全開源的Delphi工具,可以做到這一點,但那是幾年前。

要重申我用ExtractIconEx所遇到的問題 - 它不會訪問整個.ico文件,它只會提取支持的圖標資源格式,這是平臺支持的任何單個分辨率(大小)。因此,在XP上,它將提取32x32或48x48圖標,但不是Vista格式的128x128圖標。

更新:這是公認的答案,解決了我的面向未來的憂慮的修改版本。如果我們所調用的函數在未來的Windows版本中從User32.dll中消失,我希望它會更優雅地失敗,而不是加載我的整個應用程序。

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. 
+0

Vista圖標是256px PNG圖像,而不是128px,FWIW – 2011-05-10 19:28:56

+1

你試過'PrivateExtractIcons'功能嗎? http://msdn.microsoft.com/en-us/library/ms648075 – RRUZ 2011-05-10 19:33:55

+0

這是一個功能性的工作理念,但它讓我感到恐慌,它將在未來破裂(感謝MSDN!) – 2011-05-10 20:51:05

回答

9

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 ; 
+0

由於頁面頂部的警告,我會保持謹慎。 「[此功能不適用於一般用途,可能會在後續版本的Windows中更改或無法使用。]」 – 2011-05-10 20:09:56

+0

@Bruce,是的,您說得對,但我個人使用這個功能沒有問題,從Windows XP到Windows 7。 – RRUZ 2011-05-10 20:18:22

+0

哎。這在MSDN中是一個可怕的警告。 – 2011-05-10 20:29:34

1

這裏是一個working example on Delphi Praxis。它爲指定的可執行文件讀取默認的RT_GROUP_ICON和關聯的RT_ICON資源,並將它們保存爲完整的多圖像.ICO文件。

它似乎被256像素圖像(保存格式無效)弄糊塗,至少在XP上,所以它可能需要一點調整。

+0

看起來它可以提供一個原始解決方案,如果XP-256x256毛刺可以修復。 – 2011-05-11 01:58:38

+0

256像素圖像是PNG文件而不是位圖。它們是特殊的,因爲它們在圖標結構中具有高度和寬度值= 0! – 2011-05-11 10:12:09

相關問題