zoukankan      html  css  js  c++  java
  • 动态修改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

  • 相关阅读:
    网站微信登录-python 实现
    最终还是迁移到github
    理解 python 装饰器
    Git 学习之 Git Basics
    haskell 常用 函数
    jinja 2 filter 使用
    目标的牵引作用
    姨妈去世了
    OKR的理解
    无法证明的事情,和梦又有什么区别呢
  • 原文地址:https://www.cnblogs.com/findumars/p/5277414.html
Copyright © 2011-2022 走看看