動態修改PE文件圖標(使用UpdateResource API函數)


PE文件的圖標存儲在資源文件中,而操作資源要用到的API函數就是UpdateResource
首先我們需要先了解一下ICO格式,參考資料:http://www.moon-soft.com/program/FORMAT/windows/icons.htm
ICO格式不復雜,就是由數據頭、數據目錄、數據三個部分組成

一個.ico文件中可能含有若干個圖標,我們需要將數據目錄和數據解析出來。簡單地寫了個單元

 

[delphi]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. unit Icons;  
  2.   
  3. interface  
  4.   
  5. uses  
  6.   Winapi.Windows, System.SysUtils, System.Classes;  
  7.   
  8. type  
  9.   
  10.   { 用於ICO圖標文件 }  
  11.   
  12.   TIconDirEntry = packed record  
  13.     bWidth: Byte;  
  14.     bHeight: Byte;  
  15.     bColorCount: Byte;  
  16.     bReserved: Byte;  
  17.     wPlanes: Word;  
  18.     wBitCount: Word;  
  19.     dwBytesInRes: DWORD;  
  20.     dwImageOffset: DWORD;  
  21.   end;  
  22.   PIconDirEntry = ^TIconDirEntry;  
  23.   
  24.   TIconDir = packed record  
  25.     idReserved: Word;  
  26.     idType: Word;  
  27.     idCount: Word;  
  28.     idEntries: array [0..0] of TIconDirEntry;  
  29.   end;  
  30.   PIconDir = ^TIconDir;  
  31.   
  32.   { 用於PE文件中的圖標 }  
  33.   
  34.   TGroupIconDirEntry = packed record  
  35.     bWidth: Byte;  
  36.     bHeight: Byte;  
  37.     bColorCount: Byte;  
  38.     bReserved: Byte;  
  39.     wPlanes: Word;  
  40.     wBitCount: Word;  
  41.     dwBytesInRes: DWORD;  
  42.     nID: Word;  
  43.   end;  
  44.   
  45.   TGroupIconDir = packed record  
  46.     idReserved: Word;  
  47.     idType: Word;  
  48.     idCount: Word;  
  49.     idEntries: array [0 .. 0] of TGroupIconDirEntry;  
  50.   end;  
  51.   PGroupIconDir = ^TGroupIconDir;  
  52.   
  53.   { ICO圖標文件 }  
  54.   TIcoFile = class  
  55.   public  
  56.     IconStream: TMemoryStream;  
  57.     IconDir: PIconDir;  
  58.     IconDirSize: DWORD;  
  59.   
  60.     constructor Create; overload;  
  61.     constructor Create(const FileName: string); overload;  
  62.     destructor Destroy; override;  
  63.   
  64.     // 加載ICO數據  
  65.     procedure LoadFromFile(const FileName: string);  
  66.     procedure LoadFromStream(Stream: TStream);  
  67.   end;  
  68.   
  69. implementation  
  70.   
  71. { TIcoFile }  
  72.   
  73. constructor TIcoFile.Create;  
  74. begin  
  75.   IconStream := TMemoryStream.Create;  
  76.   IconDir := nil;  
  77.   IconDirSize := 0;  
  78. end;  
  79.   
  80. constructor TIcoFile.Create(const FileName: string);  
  81. begin  
  82.   Create;  
  83.   LoadFromFile(FileName);  
  84. end;  
  85.   
  86. destructor TIcoFile.Destroy;  
  87. begin  
  88.   FreeMem(IconDir);  
  89.   FreeAndNil(IconStream);  
  90.   inherited;  
  91. end;  
  92.   
  93. procedure TIcoFile.LoadFromFile(const FileName: string);  
  94. var  
  95.   MS: TMemoryStream;  
  96. begin  
  97.   MS := TMemoryStream.Create;  
  98.   try  
  99.     MS.LoadFromFile(FileName);  
  100.     LoadFromStream(MS);  
  101.   finally  
  102.     FreeAndNil(MS);  
  103.   end;  
  104. end;  
  105.   
  106. procedure TIcoFile.LoadFromStream(Stream: TStream);  
  107. var  
  108.   Dir: TIconDir;  
  109. begin  
  110.   Stream.Position := 0;  
  111.   IconStream.Clear;  
  112.   IconStream.CopyFrom(Stream, Stream.Size);  
  113.   
  114.   IconStream.Position := 0;  
  115.   IconStream.ReadBuffer(Dir, SizeOf(Dir));  
  116.   
  117.   FreeMem(IconDir);  
  118.   IconDirSize := SizeOf(TIconDirEntry) * (Dir.idCount - 1) + SizeOf(TIconDir);  
  119.   IconDir := AllocMem(IconDirSize);  
  120.   IconStream.Position := 0;  
  121.   IconStream.ReadBuffer(IconDir^, IconDirSize);  
  122. end;  
  123.   
  124. end.  


這里要注意一個問題,ICO文件中的TIconDirEntry結構和PE文件中的TGroupIconDirEntry結構是不同的
不同處在最后一個參數,ICO文件中表示的是圖像數據偏移地址,是DWORD類型。而PE文件中表示的是圖像數據的索引,是WORD類型,少了2個字節
替換圖標需要寫入2個部分:RT_GROUP_ICON 和 RT_ICON
RT_GROUP_ICON也就是ICO的數據頭部分,RT_ICON就是圖像數據部分了
數據部分直接寫入即可,不用轉換什么的。但是數據頭需要稍微處理一下,因為前面說了,這個替換過程是把ICO文件寫到PE文件中
而他們數據頭部分結構略有不同(PE文件中每個數據頭比起ICO數據頭要少2字節),只用把這里處理下就行了
最后寫個函數就可以替換PE文件圖標了

 

 

[delphi]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
    1. function TMainForm.UpdatePeIcon(IcoFile, PeFile: string): Boolean;  
    2. var  
    3.   Ico: TIcoFile;  
    4.   I: Integer;  
    5.   hRes: THandle;  
    6.   GroupIconDir: PGroupIconDir;  
    7.   GroupIconDirSize: DWORD;  
    8.   Data: TBytes;  
    9. begin  
    10.   Result := False;  
    11.   hRes := BeginUpdateResource(PChar(PeFile), False);  
    12.   if hRes <> then  
    13.   begin  
    14.     Ico := TIcoFile.Create(IcoFile);  
    15.     // TGroupIconDirEntry結構要比TIconDirEntry結構少2字節  
    16.     GroupIconDirSize := Ico.IconDirSize - Ico.IconDir^.idCount * 2;  
    17.     GroupIconDir := AllocMem(GroupIconDirSize);  
    18.     GroupIconDir^.idReserved := 0;  
    19.     GroupIconDir^.idType := 1;  
    20.     GroupIconDir^.idCount := Ico.IconDir.idCount;  
    21.   
    22.     for I := to Ico.IconDir.idCount - do  
    23.     begin  
    24.       CopyMemory(@GroupIconDir^.idEntries[I], @Ico.IconDir^.idEntries[I],  
    25.         SizeOf(TGroupIconDirEntry));  
    26.       // 索引從1開始  
    27.       GroupIconDir^.idEntries[I].nID := I + 1;  
    28.   
    29.       // 寫入圖標數據  
    30.       SetLength(Data, Ico.IconDir^.idEntries[I].dwBytesInRes);  
    31.       Ico.IconStream.Position := Ico.IconDir^.idEntries[I].dwImageOffset;  
    32.       Ico.IconStream.ReadBuffer(Data[0], Length(Data));  
    33.   
    34.       UpdateResource(hRes, RT_ICON, MakeIntResource(I + 1), 0, @Data[0], Length(Data));  
    35.     end;  
    36.   
    37.     // 寫入 RT_GROUP_ICON  
    38.     UpdateResource(hRes, RT_GROUP_ICON, MakeIntResource('MAINICON'), 0, GroupIconDir, GroupIconDirSize);  
    39.   
    40.     FreeMem(GroupIconDir);  
    41.     FreeAndNil(Ico);  
    42.     EndUpdateResource(hRes, False);  
    43.     Result := True;  
    44.   end;  
    45. end;  

http://blog.csdn.net/aqtata/article/details/7710720


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM