用UpdateResource修改EXE文件图标的多源码(已修正) 注:转帖请包函作者信息.(作者:菜新)


微软官网UpdateResource 其它参考信息: https://msdn.microsoft.com/zh-cn/library/ms648008.aspx#_win32_Updating_Resources


一年前初学VB时我对这个API就特感兴趣,听说这个API可以更改图标资源,就更感兴趣了,后来试了试,发现修改其它资源貌似没多大问题,唯独修改图标时无果,我发现所修改的图虽说已经写入到资源文件中了,但是就是无法显示。后来到网上查了下,发现用UpdateResource修改EXE图标的没一个成功的,大致都是发生成功写入,无法正常显示的问题。罢矣,当时就琢磨着把该问题先放放,等日后有时间再好好折腾。

无奈时间过得太快,忽忽悠悠就过了一年了,前几天,在整理去年的一些源码时发现了这个遗留在硬盘中的代码,一年前无奈自己所学浅溥,啥都不知道,但现在已经对API有了较深厚的认识,再加上对汇编的一些了解,我想此时不解决更待何时。

在折腾这个API的期间也发生不少问题,最让我自责的就是差点被 CreateFile 这个API给Game Over,这个小伟知道(又是小伟?没办法啊,谁要咱和小伟太有缘了~)。还好自己最终醒悟,否则真的要好好鄙视鄙视自己。最初修改时还是和一年前一个样,这时我一直在回想一样年遇到这个问题的问题:所写图标的数据是不是完整的写到了资源文件中?想到此,我用eXeScope(一个PE资源文件查看工具)看了下写入到资源文件中的十六进制,又用UltraEdit-32以十六进制查看ico文件中的数据,发现没问题啊?一字节一字节都对得上,那问题出在哪了?没法,继续在Google游荡,终于找了一份有效的资料(网址现在不知扔哪去了),全E文,看得难受,不过大致的意思是说ICON是由一个结构组成,同PE那些什么NT头,DOS头的差不多,而所显示的图像数据包函于ICON类型结构的dwImageOffset偏移处。呵,这下总算搞明白为什么直接把ICON文件写入到资源文件中显示不了的问题了,也就是说在dwImageOffset偏移位置处才是咱所需要的图像数据,这不就啥都OK了么,爷爷的,原来咱从一开始就被ICON文件整得稀里糊涂,靠MS,当然也鄙视下自己的无知。另外还好找到的那份资料有点人性,把结构给咱标出来了,那么现在一切都顺理成章,不说多了,上代码:

===============================================

Delphi Code:

===============================================

//请自行添加到 Type 处
PICONDIRENTRY = ^ICONDIRENTRY;
ICONDIRENTRY = packed record
    bWidth: Byte;
    bHeight: Byte;
    bColorCount: Byte;
    bReserved: Byte;
    wPlanes: Word;
    wBitCount: Word;
    dwBytesInRes: DWORD;
    dwImageOffset: DWORD;
end;

PICONDIR = ^ICONDIR;
ICONDIR = packed record
    idReserved: Word;
    idType: Word;
    idCount: Word;
    idEntries: ICONDIRENTRY;
end;

PGRPICONDIRENTRY = ^GRPICONDIRENTRY;
GRPICONDIRENTRY = packed record
    bWidth: Byte;
    bHeight: Byte;
    bColorCount: Byte;
    bReserved: Byte;
    wPlanes: Word;
    wBitCount: Word;
    dwBytesInRes: DWORD;
    nID: Word;
end;

PGRPICONDIR = ^GRPICONDIR;
GRPICONDIR = packed record
    idReserved: Word;
    idType: Word;
    idCount: Word;
    idEntries: GRPICONDIRENTRY; 
end;

//
//函数说明:修改EXE图标
//
//参    数:IconFile 图标文件 
//              ExeFile 被修改的EXE文件
//
//返回值: 成功为True,否则False
/
function ChangeExeIcon(IcoFile, ExeFile: string): Boolean;
var
stID: ICONDIR;
stGID: GRPICONDIR;

pGrpIcon: PBYTE;
pIcon: PBYTE;
hUpdate: DWORD;
nSize, nGSize: DWORD; 
hFile: THandle;
dwReserved: DWORD; 
ret: Boolean;
begin
Result := False;

hFile := CreateFile(PChar(IcoFile), GENERIC_READ, 0, nil, OPEN_EXISTING,
                      FILE_ATTRIBUTE_NORMAL, 0);
if hFile = INVALID_HANDLE_VALUE then
    Exit;

try                      
    ReadFile(hFile, stID, Sizeof(ICONDIR), dwReserved, nil);

    nSize := stID.idEntries.dwBytesInRes;
    GetMem(pIcon, nSize);
    SetFilePointer(hFile, stID.idEntries.dwImageOffset, nil, FILE_BEGIN);
    ReadFile(hFile, pIcon^, nSize, dwReserved, nil);

    stGID.idType := 1;
    stGID.idCount := stID.idCount;
    stGID.idReserved := 0;
    CopyMemory(@stGID.idEntries.bWidth, @stID.idEntries.bWidth, 12);
    stGID.idEntries.nID := 0;

    nGSize := Sizeof(GRPICONDIR);
    GetMem(pGrpIcon, nGSize);
    CopyMemory(pGrpIcon, @stGID, nGSize);

    hUpdate := BeginUpdateResource(PChar(ExeFile), False);
    try
      ret := UpdateResource(hUpdate, RT_GROUP_ICON, MAKEINTRESOURCE(1), 0, pGrpIcon, nGSize);
      ret := UpdateResource(hUpdate, RT_ICON, MAKEINTRESOURCE(1), 0, pIcon, nSize);
    finally
      EndUpdateResource(hUpdate, False);
    end;
finally
    CloseHandle(hFile);
end;

Result := ret;
end;

===============================================

VB Code:

===============================================

Option Explicit

Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long
Private Declare Function SetFilePointer Lib "kernel32" (ByVal hFile As Long, ByVal lDistanceToMove As Long, lpDistanceToMoveHigh As Long, ByVal dwMoveMethod As Long) As Long
Private Declare Function BeginUpdateResource Lib "kernel32" Alias "BeginUpdateResourceA" (ByVal pFileName As String, ByVal bDeleteExistingResources As Long) As Long
Private Declare Function UpdateResource Lib "kernel32" Alias "UpdateResourceA" (ByVal hUpdate As Long, ByVal lpType As Long, ByVal lpName As Long, ByVal wLanguage As Long, lpData As Any, ByVal cbData As Long) As Long
Private Declare Function EndUpdateResource Lib "kernel32" Alias "EndUpdateResourceA" (ByVal hUpdate As Long, ByVal fDiscard As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetLastError Lib "kernel32" () As Long

Private Const INVALID_HANDLE_VALUE = -1
Private Const GENERIC_READ = &H80000000
Private Const FILE_ATTRIBUTE_NORMAL = &H80
Private Const FILE_BEGIN = 0
Private Const OPEN_EXISTING = 3
Private Const RT_ICON = 3&
Private Const DIFFERENCE As Long = 11
Private Const RT_GROUP_ICON As Long = (RT_ICON + DIFFERENCE)


Private Type ICONDIRENTRY
    bWidth As Byte
    bHeight As Byte
    bColorCount As Byte
    bReserved As Byte
    wPlanes As Integer
    wBitCount As Integer
    dwBytesInRes As Long
    dwImageOffset As Long
End Type

Private Type ICONDIR
    idReserved As Integer
    idType As Integer
    idCount As Integer
    'idEntries As ICONDIRENTRY
End Type

Private Type GRPICONDIRENTRY
    bWidth As Byte
    bHeight As Byte
    bColorCount As Byte
    bReserved As Byte
    wPlanes As Integer
    wBitCount As Integer
    dwBytesInRes As Long
    nID As Integer
End Type

Private Type GRPICONDIR
    idReserved As Integer
    idType As Integer
    idCount As Integer
    idEntries As GRPICONDIRENTRY
End Type

'//
'//函数说明:修改EXE图标
'//
'//参    数:IconFile 图标文件
'//              ExeFile 被修改的EXE文件
'//
'//返回值: 成功为True,否则False
'/
Private Function ChangeExeIcon(ByVal IconFile As String, ByVal ExeFile As String) As Boolean
    On Error GoTo cw
    
    Dim stID As ICONDIR
    Dim stIDE As ICONDIRENTRY
    Dim stGID As GRPICONDIR
    
    Dim hFile As Long
    Dim pIcon() As Byte, pGrpIcon() As Byte
    Dim nSize As Long, nGSize As Long
    Dim dwReserved As Long
    Dim hUpdate As Long
    Dim ret As Long
    
    hFile = CreateFile(IconFile, GENERIC_READ, 0, ByVal 0&, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
    If hFile = INVALID_HANDLE_VALUE Then Exit Function

    ret = ReadFile(hFile, stID, Len(stID), dwReserved, ByVal 0&)
    If ret = 0 Then GoTo cw
    
    ret = ReadFile(hFile, stIDE, Len(stIDE), dwReserved, ByVal 0&)

    nSize = stIDE.dwBytesInRes
    ReDim pIcon(nSize - 1)
    SetFilePointer hFile, stIDE.dwImageOffset, ByVal 0&, FILE_BEGIN
    ret = ReadFile(hFile, pIcon(0), nSize, dwReserved, ByVal 0&)
    If ret = 0 Then GoTo cw
    
    With stGID
        .idType = 1
        .idCount = stID.idCount
        .idReserved = 0
        CopyMemory stGID.idEntries, stIDE, 12
        .idEntries.nID = 0
    End With
    
    nGSize = Len(stGID)
    ReDim pGrpIcon(nGSize - 1)
    CopyMemory pGrpIcon(0), stGID, nGSize
    
        
    hUpdate = BeginUpdateResource(ExeFile, False)
    ret = UpdateResource(hUpdate, RT_GROUP_ICON, 1, 0, pGrpIcon(0), nGSize)
    ret = UpdateResource(hUpdate, RT_ICON, 1, 0, pIcon(0), nSize)
    EndUpdateResource hUpdate, False

    If ret = 0 Then GoTo cw
    ChangeExeIcon = True
    
cw:
    CloseHandle hFile
    
End Function

===============================================

VC++ Code:

===============================================

#include <stdio.h>
#include <windows.h>
#include <tchar.h>


struct ICONDIRENTRY
{
    BYTE bWidth;
    BYTE bHeight;
    BYTE bColorCount;
    BYTE bReserved;
    WORD wPlanes;
    WORD wBitCount;
    DWORD dwBytesInRes;
    DWORD dwImageOffset;
};


struct ICONDIR
{
    WORD idReserved;
    WORD idType;
    WORD idCount;
    //ICONDIRENTRY idEntries;
};


struct GRPICONDIRENTRY
{
    BYTE bWidth;
    BYTE bHeight;
    BYTE bColorCount;
    BYTE bReserved;
    WORD wPlanes;
    WORD wBitCount;
    DWORD dwBytesInRes;
    WORD nID;
};

struct GRPICONDIR
{
    WORD idReserved;
    WORD idType;
    WORD idCount;
    GRPICONDIRENTRY idEntries;
};


//
//函数说明:修改EXE图标
//
//参    数:IconFile 图标文件 
//              ExeFile 被修改的EXE文件
//
//返回值: 成功为True,否则False
/
bool ChangeExeIcon(LPWSTR IconFile, LPWSTR ExeFile)
{
    ICONDIR stID;
    ICONDIRENTRY stIDE;
    GRPICONDIR stGID;
    HANDLE hFile;
    DWORD nSize, nGSize, dwReserved;
    HANDLE hUpdate;
    PBYTE pIcon, pGrpIcon;
    BOOL ret;

    hFile = CreateFile(IconFile, GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
       return false;
    }

    ZeroMemory(&stID, sizeof(ICONDIR));
    ret = ReadFile(hFile, &stID, sizeof(ICONDIR), &dwReserved, NULL);

    ZeroMemory(&stIDE, sizeof(ICONDIRENTRY));
    ret = ReadFile(hFile, &stIDE, sizeof(ICONDIRENTRY), &dwReserved, NULL);

    nSize = stIDE.dwBytesInRes;
    pIcon = (PBYTE)malloc(nSize);
    SetFilePointer(hFile, stIDE.dwImageOffset, NULL, FILE_BEGIN);
    ret = ReadFile(hFile, (LPVOID)pIcon, nSize, &dwReserved, NULL);
    if (!ret)
    {
       CloseHandle(hFile);
       return false;
    }

    ZeroMemory(&stGID, sizeof(GRPICONDIR));
    stGID.idCount = stID.idCount;
    stGID.idReserved = 0;
    stGID.idType = 1;
    CopyMemory(&stGID.idEntries, &stIDE, 12);
    stGID.idEntries.nID = 0;

    nGSize = sizeof(GRPICONDIR);
    pGrpIcon = (PBYTE)malloc(nGSize);
    CopyMemory(pGrpIcon, &stGID, nGSize);


    hUpdate = BeginUpdateResource(ExeFile, false);
    ret = UpdateResource(hUpdate, RT_GROUP_ICON, MAKEINTRESOURCE(1), 0, (LPVOID)pGrpIcon, nGSize);
    ret = UpdateResource(hUpdate, RT_ICON, MAKEINTRESOURCE(1), 0, (LPVOID)pIcon, nSize);
EndUpdateResource(hUpdate, false);
    if (!ret)
    {
       CloseHandle(hFile);
       return false;
    }

    CloseHandle(hFile);
    return true;
}

===============================================

ASM Code:

===============================================


.386
.model flat,stdcall
option casemap:none

include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib

ICONDIRENTRY STRUCT
    bWidth BYTE ?
    bHeight BYTE ?
    bColorCount BYTE ?
    bReserved BYTE ?
    wPlanes WORD ?
    wBitCount WORD ?
    dwBytesInRes DWORD ?
    dwImageOffset DWORD ?
ICONDIRENTRY ENDS

ICONDIR STRUCT
    idReserved WORD ?
    idType WORD ?
    idCount WORD ?
    ;idEntries ICONDIRENTRY <>
ICONDIR ENDS

GRPICONDIRENTRY STRUCT
    bWidth BYTE ?
    bHeight BYTE ?
    bColorCount BYTE ?
    bReserved BYTE ?
    wPlanes WORD ?
    wBitCount WORD ?
    dwBytesInRes DWORD ?
    nID   WORD ?
GRPICONDIRENTRY ENDS

GRPICONDIR STRUCT
    idReserved WORD ?
    idType WORD ?
    idCount WORD ?
    idEntries GRPICONDIRENTRY <>
GRPICONDIR ENDS

.data

szIcon   db 'a.ico', 0
szFile   db 'a.exe', 0

.code

//
//函数说明:修改EXE图标
//
//参    数:IconFile 图标文件 
//              ExeFile 被修改的EXE文件
//
//返回值: 成功为True,否则False
/

_ChangeExeIcon proc IconFile, ExeFile

     local @stID:   ICONDIR
     local @stIDE:   ICONDIRENTRY
     local @stGID:   GRPICONDIR

     local @hFile:   DWORD
     local @dwReserved: DWORD
     local @nSize:   DWORD
     local @nGSize:   DWORD
     local @pIcon:   DWORD
     local @pGrpIcon: DWORD
     local @hUpdate:   DWORD
      local @ret:   DWORD

     invoke CreateFile, IconFile, GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
     mov @hFile, eax

     .if eax == INVALID_HANDLE_VALUE
          xor eax, eax
          ret
     .endif

     invoke RtlZeroMemory, addr @stID, sizeof @stID
     invoke ReadFile, @hFile, addr @stID, sizeof @stID, addr @dwReserved, NULL

     invoke RtlZeroMemory, addr @stIDE, sizeof @stIDE
     invoke ReadFile, @hFile, addr @stIDE, sizeof @stIDE, addr @dwReserved, NULL

     push @stIDE.dwBytesInRes
     pop @nSize

     invoke GlobalAlloc, GPTR, @nSize 
     mov @pIcon, eax

     invoke SetFilePointer, @hFile, @stIDE.dwImageOffset, NULL, FILE_BEGIN
     invoke ReadFile, @hFile, @pIcon, @nSize, addr @dwReserved, NULL
     cmp eax, 0
     je err

     invoke RtlZeroMemory, addr @stGID, sizeof @stGID
     push @stID.idCount
     pop @stGID.idCount
     mov @stGID.idReserved, 0
     mov @stGID.idType, 1
     invoke RtlMoveMemory, addr @stGID.idEntries, addr @stIDE, 12
     mov @stGID.idEntries.nID, 0

     mov @nGSize, sizeof @stGID
     invoke GlobalAlloc, GPTR, @nGSize
     mov @pGrpIcon, eax
     invoke RtlMoveMemory, @pGrpIcon, addr @stGID, @nGSize


     ;开始修改
     invoke BeginUpdateResource, ExeFile, FALSE
     mov @hUpdate, eax
     invoke UpdateResource, @hUpdate, RT_GROUP_ICON, 1, 0, @pGrpIcon, @nGSize
     invoke UpdateResource, @hUpdate, RT_ICON, 1, 0, @pIcon, @nSize
     mov @ret, eax
     invoke EndUpdateResource, @hUpdate, FALSE

     .if @ret == FALSE
          jmp err
     .endif

     ;成功后到此一日游
     invoke GlobalFree, @pIcon
     invoke CloseHandle, @hFile
     mov eax, 1
ret

err:
     ;失败后到此一日游
     invoke GlobalFree, @pIcon
     invoke CloseHandle, @hFile
     xor eax, eax
     ret

_ChangeExeIcon endp

;==========================程序入口=============================
start:

     invoke _ChangeExeIcon, offset szIcon, offset szFile
     invoke ExitProcess, NULL

end start

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更这些源码资源,以适应各平台技术的最发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
### 回答1: exe图标替换工具源码,其中exe代表“可执行文件”。这个工具源码的作用就是用于替换可执行文件图标。随着计算机应用的广泛,各种软件的可执行文件图标显得很重要,因为它是软件产品的标识之一。 执行源码的方法可以分为两种。一是使用现有工具直接打开执行;一是使用编译软件将源码编译成程序然后执行。 这个工具源码的实现理论比较简单,但实现上需要意一些细节。具体来说: - 首先,需要通过系统调用定位到要修改的可执行文件; - 其次,需要解析可执行文件的资源表(resource table); - 之后,检查存在的图标是否满足替换条件(例如图标大小、颜色等); - 最后,将要替换的图标写入可执行文件的资源表中。 以上步骤,最为关键的是解析资源表和写入图标数据。解析资源表需要根据可执行文件不同的格式进行不同的解析方式,需要针对不同的格式进行优化;写入图标数据时,需要非常小心防止出现数据格式错误等问题,需要进行一定的校验和错误检查。 总之,exe图标替换工具源码是一个比较实用的工具,其实现虽然简单,但要充分考虑到各种情况,因此考验编程人员的技术。 ### 回答2: exe 图标替换工具源码,首先需要了解 exe 文件的组成结构。exe 文件是一种可执行文件,通常由多个部分组成,包括头部信息、代码段、数据段、资源段等。其中,资源段包括了 exe 文件中所有的资源信息,如图标单、对话框、字符串等。因此,修改 exe 文件图标,实际上就是修改 exe 文件中的资源段信息。 为了实现 exe 图标替换的功能,可以使用 Windows API 函数来操作 exe 文件。首先需要用到的是 LoadLibrary 和 FindResource 函数,分别用于加载当前进程中的 exe 文件以及查找资源。接着可以使用 LockResource 和 SizeofResource 函数来获取资源的位置和大小。最后需要用 UpdateResource 函数来修改资源信息,并保存更后的 exe 文件。 以上是大致的流程,具体实现时需要考虑一些细节问题,比如如何找到 exe 文件、如何确定要替换的图标资源等。同时,需要意的是,替换 exe 图标的操作会影响 exe 文件的数字签名,因此需要重进行数字签名以保证 exe 文件的安全性。 综上所述,exe 图标替换工具源码的实现需要使用 Windows API 函数,并考虑到一些细节问题和安全性问题。同时,需要了解 exe 文件的组成结构以及资源段的相关知识。 ### 回答3: exe 图标替换工具源码是一个将可执行文件图标替换为自定义图标的程序。它可以帮助您在 Windows 操作系统中修改应用程序的图标,使其更加符合您的个人喜好或需要。 该工具的源码通常使用 C# 或 VB.NET 编写,因为这些编程语言可以直接访问 Windows API,进而实现更多的功能。具体实现流程如下: 首先,程序会遍历指定目录下的所有可执行文件,并读取它们的图标信息。这个过程通常使用 Windows API 中的 FindFirstFile 和 FindNextFile 函数实现。 接着,程序会使用 Windows API 中的 ExtractIconEx 函数提取自定义的图标文件中的图标,并将其保存到内存中。如果用户没有提供自定义图标,则使用默认图标。 最后,程序会使用 Windows API 中的 UpdateResource 函数将自定义图标替换可执行文件中的图标资源。如果替换成功,程序将会输出日志并提示用户操作成功。 整个替换过程相对简单,但其中涉及到的 Windows API 接口较多,需要有一定的编程经验和操作系统知识。如果您是一名程序员,可以尝试理解并修改源码来使其更加适合您的需求;如果您只是一般用户,建议慎重使用该工具,以免误操作导致程序无法正常运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值