更换可执行文件的图标

如何更换可执行文件的图标_C++源码

VC 2008-09-26 21:39:41 阅读595 评论0   字号: 订阅

 

翻译: vivi

日期: 2008-9-26

原文: http://www.codeguru.com/cpp/w-p/win32/tutorials/article.php/c12873__1/

环境:  C++, WinAPI

偶的E文不好,翻译不对的地方,请见谅。如需转载请注明出处

http://afxvivi.blog.163.com/blog/static/93474001200882693941937/

导言

在这篇教程中,我将向你展示如何用一个给定的图标文件替换一个应用程序的图标。 为了简单化,你需要准备一个32x32的图标文件(同时,我将给出完成这些工作的完整源代码),我还会提供一般理论,来支持所有类型的图标,让您扩展例子。

周围有很多图标编辑器,用你喜欢的做一个32x32, 256色的图标。

事有先后: 先说图标文件在磁盘上的结构

图标文件结构如下:

ICON HEADER:

   WORD Reserved             - reserved

   WORD Type                 - 1 means icon, 2 means cursor

   WORD ImageCount           - number of images stored inside the file

 

   ICON DIRECTORY ENTRY      - there are ImageCount directory entries

      BYTE Width             - width of image

      BYTE Height            - height of image

      BYTE Colors            - 0 means 256 or more

      BYTE Reserved          - reserved

      WORD Planes            - number of planes

      WORD BitsPerPixel      - bits per pixel

      DWORD ImageSize        - size of image data

      DWORD ImageOffset      - offset of image data inside file

   ICON DIRECTORY ENTRY

   ...

   ICON DIRECTORY ENTRY

 

   ICON IMAGE                - the actual image data (which has the

                               structure of ICON IMAGE a bitmap) found

                               at the location specified by ImageOffset

   ...

   ICON IMAGE

正如您所看到的,一个图标文件可以包含一个以上的图像。

秘密

读取一个图标文件到内存中,并把它作为一个RC_ICON资源插入,因为由此产生的资源会被损坏。在资源中, 图标是被分成许多RC_ICON资源和一个RC_GROUP_ICON。一个RC_ICON入口基本上就是图标图像。RC_GROUP_ICON 包含ICON HEADER和 DIRECTORY ENTRIES ,还有一点改变: DWORD ImageOffset变成了WORD ResourceID。这是因为实际的图像数据已不再跟随其头部,因此可以用其资源ID来识别 。

一个应用程序可以在其资源中包含许多图标。通常,要显示的图标资源ID等于1,但也不是必然的。Windows通过一个叫做'MAINICON' 的RC_GROUP_ICON 来选择显示的图标。你可以用一个工具,例如PE Explorer,来看一看已编译的可执行模块的资源 (.EXE和.DLL文件)。

你要做的

把一个图标文件的ICON IMAGE 装入缓存,生成包含RC_GROUP_ICON资源的数据,然后把它们插入到一个给定的可执行文件中。

下面是一些结构声明:

// Make sure structures are packed the same way as Windows packs them

#pragma pack(push, 2)

 

typedef struct    // This is the Directory Entry stored in resources

{

   BYTE Width;

   BYTE Height;

   BYTE Colors;

   BYTE Reserved;

   WORD Planes;

   WORD BitsPerPixel;

   DWORD ImageSize;

   WORD ResourceID

} IconDirResEntry, *PIconDirResEntry;

 

typedef struct    // This is the actual RT_GROUP_ICON structure

{

   WORD Reserved;

   WORD ResourceType;

   WORD ImageCount;

   PIconDirResEntry Enries;    // The number of entries is ImageCount

} GroupIcon;

 

// Restore default packing

#pragma pack(pop)

在这个例子中,你可以声明一个较简单的结构因为你用的图标文件只包含一幅图像。 你还可以把头部和目录项组合到一个简单的结构中。

#pragma pack(push, 2)

 

typedef struct {

  WORD Reserved1;       // reserved, must be 0

  WORD ResourceType;    // type is 1 for icons

  WORD ImageCount;      // number of icons in structure (1)

  BYTE Width;           // icon width (32)

  BYTE Height;          // icon height (32)

  BYTE Colors;          // colors (0 means more than 8 bits per pixel)

  BYTE Reserved2;       // reserved, must be 0

  WORD Planes;          // color planes

  WORD BitsPerPixel;    // bit depth

  DWORD ImageSize;      // size of structure

  WORD ResourceID;      // resource ID

} GROUPICON;

 

#pragma pack(pop)

最后一个结构是你将要插入到可执行文件的RC_GROUP_ICON 资源。

用WinAPI

你可以用WinAPI's BeginUpdateResource, UpdateResource, 和 EndUpdateResource来更新资源。 声明一个InjectMainIcon方法来接收图标文件和图标文件的文件名。

快速总览: BeginUpdateResource接收可执行模块的名字和一个布尔参数,如果这个布尔参数被设为真,将移除在可执行文件中找到的所有资源 (你不想那么做)。

UpdateResource接收用来更新模块的句柄 (BeginUpdateResource返回的句柄)。 它接收到资源类型的名称和资源名称,你可以用MAKEINTRESOURCE。(例如,类型是RC_ICON而且名称是MAKEINTRESOURCE(1),这将插入一个ID为1的图标资源。) 它还需要接收语言标识符。你需要用MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)把资源的语言设为默认值。最后,UpdateResource接收到一个包含资源的缓存指针和这个缓存的长度。

你要用到的最后一个方法是EndUpdateResource。他接收到BeginUpdateResource提供的的句柄和一个布尔参数,如果这个布尔参数被设为真,将将丢弃所有对资源所做的更改。

源于Windows SDK文档:

   HANDLE BeginUpdateResource(

      LPCTSTR pFileName,    // pointer to file in which to update

                            // resources

      BOOL bDeleteExistingResources    // deletion option

     );

 

   BOOL UpdateResource(

      HANDLE hUpdate,    // update-file handle

      LPCTSTR lpType,    // address of resource type to update

      LPCTSTR lpName,    // address of resource name to update

      WORD wLanguage,    // language identifier of resource

      LPVOID lpData,     // address of resource data

      DWORD cbData       // length of resource data, in bytes

     );

 

   BOOL EndUpdateResource(

      HANDLE hUpdate,    // update-file handle

      BOOL fDiscard      // write flag

     );

放到一起

你的InjectMainIcon方法是什么样子的?

void InjectMainIcon(char *Where, char *What)

{

   HANDLE hWhere = BeginUpdateResource(Where, FALSE);

 

   char *buffer;       // buffer to store raw icon data

   long buffersize;    // length of buffer

   int hFile;          // file handle

 

   hFile = open(What, O_RDONLY | O_BINARY);

   if (hFile == -1)

      return;          // if file doesn't exist, can't be opened etc.

 

   // calculate buffer length and load file into buffer

   buffersize = filelength(hFile);

   buffer     = (char *)malloc(buffersize);

   read(hFile, buffer, buffersize);

   close(hFile);

 

   UpdateResource(

      hWhere,                         // Handle to executable

      RT_ICON,                        // Resource type - icon

      MAKEINTRESOURCE(1),             // Make the id 1

      MAKELANGID(LANG_ENGLISH,        // Default language

                 SUBLANG_DEFAULT),

      (buffer+22),

      // skip the first 22 bytes because this is the  icon header

      // and directory entry (if the file  contains multiple

      // images, the directory entries will be larger than 22 bytes)

      buffersize-22    // length of buffer

     );

 

   // Again, we use this structure for educational purposes.

   // The icon header and directory entries can be read from the

   // file.

   GROUPICON grData;

 

   // This is the header

   grData.Reserved1 = 0;     // reserved, must be 0

   grData.ResourceType = 1;  // type is 1 for icons

   grData.ImageCount = 1;    // number of icons in structure (1)

 

   // This is the directory entry

   grData.Width        = 32;                 // icon width (32)

   grData.Height       = 32;                 // icon height (32)

   grData.Colors       = 0;                  // colors (256)

   grData.Reserved2    = 0;                  // reserved, must be 0

   grData.Planes       = 2;                  // color planes

   grData.BitsPerPixel = 32;                 // bit depth

   grData.ImageSize    = buffersize - 22;    // size of image

   grData.ResourceID   = 1;                  // resource ID is 1

 

   UpdateResource(

      hWhere,

      RT_GROUP_ICON,

      // RT_GROUP_ICON resources contain information about

      // stored icons

      "MAINICON",

      // MAINICON contains information about the application's

     // displayed icon

      MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),

      &grData,

      // Pointer to this structure

      sizeof(GROUPICON)

     );

 

 

   free(buffer);    // free memory

 

   // Perform the update, don't discard changes

   EndUpdateResource(hWhere, FALSE);

}

总结

系统显示的16x16的图标能够从32x32的图标资源中自动计算出,所以你没必要添加小图标。然而,可以修改这里的代码使它能够在运行时通过读取和分割图标文件的头部和目录项来插入所有的图标文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值