Итак, товарищи программисты, пишу сюда так как просто хочу поделиться решением. Недавно тоже терзала подобная мысль, толкового ответа не нашёл, решил разобраться сам. В предложениях я часто видел только учить PE, с чем не соглашусь. Ведь ресурсы использовать куда проще. Также на этом форуме наблюдал уже более близкие к истине ответы с генерацией иконки и замены её в ресурсе. Но такой метод был не полноценен. В итоге изучил структуру формата ICO, и его отличие от структуры ресурсов. Пример в основном выполнен на стандартном VB с минимальным использованием API для большего понимания сути. Собственно из него можно сделать полноценный редактор ресурсов.
Private Declare Function BeginUpdateResource Lib "kernel32" Alias "BeginUpdateResourceA" (ByVal pFileName As String, ByVal bDeleteExistingResources As Boolean) 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 Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
'Номера ресурсов
Private Const RT_ICON = 3&
Private Const RT_GROUP_ICON = 14
'Заголовок ICO либо CUR файлов
Private Type CursorOrIcon
Reserved As Integer
wType As Integer
Count As Integer
End Type
'Описание иконок в ICO файле
Private Type ICONDIRENTRY
bWidth As Byte 'Ширина иконки в байтах
bHeight As Byte 'Высота иконки в байтах
bColorCount As Byte 'Количество цветов (0 если >=8bpp)
bReserved As Byte
wPlanes As Integer
wBitCount As Integer
dwBytesInRes As Long
dwImageOffset As Long 'Байт с которого начинается иконка в ICO файле
End Type
'Инфа иконки тока под EXE
Private Type MEMICONDIRENTRY
bWidth As Byte
bHeight As Byte
bColorCount As Byte
bReserved As Byte
wPlanes As Integer
wBitCount As Integer
dwBytesInRes As Long
nID As Integer 'Номер иконки в группе (единственное отличие то ICO формата)
End Type
'полная информация о самой иконке
Private Type BITMAPINFOHEADER '40 bytes
a_Size As Long '=40
b_Width As Long
b_Height As Long
c_Planes As Integer
d_BitCount As Integer
e_Compression As Long
f_SizeImage As Long
g_XPelsPerMeter As Long
g_YPelsPerMeter As Long
h_ClrUsed As Long
i_ClrImportant As Long
End Type
Dim ICO As CursorOrIcon
Dim Bitm As BITMAPINFOHEADER
Dim IconR() As ICONDIRENTRY
Dim IconE() As MEMICONDIRENTRY
Dim Pic() As Byte
Dim mas() As Byte
Private Sub ReplaceIcon(sFileName As String, sIconName As String)
Dim h As Long
Dim FileName As String
'Имя файла
FileName = sFileName
'Открываем для записи ресурсов exe
h = BeginUpdateResource(FileName, False)
'Открываем иконку для бинарного чтения
Open sIconName For Binary As #1
'Читаем заголовок
Get #1, , ICO
'Подгоняем размер массива под количество иконок в файле
ReDim IconE(ICO.Count)
ReDim IconR(ICO.Count)
'Описание иконок и их структура в RT_ICON
'Структура иконок в ресурвах почти аналогична структуре в exe
'Различие только в том, что в ICO указан оффсет, а в ресурсе порядковый номер
For i = 0 To ICO.Count - 1
Get #1, , IconR(i)
IconE(i).bColorCount = IconR(i).bColorCount
IconE(i).bHeight = IconR(i).bHeight
IconE(i).bReserved = IconR(i).bReserved
IconE(i).bWidth = IconR(i).bWidth
IconE(i).dwBytesInRes = IconR(i).dwBytesInRes
IconE(i).wBitCount = IconR(i).wBitCount
IconE(i).wPlanes = IconR(i).wPlanes
IconE(i).nID = i + 1
Next i
'Подробное описание и сами иконки
For i = 0 To ICO.Count - 1
'Читаем структуру икокни
Get #1, IconR(i).dwImageOffset + 1, Bitm
'Чиатем картинку
ReDim Pic(IconR(i).dwBytesInRes)
Get #1, , Pic
'Оформляем массив, который будет содержать структуру и саму иконку
ReDim mas(IconR(i).dwBytesInRes + Len(Bitm))
'Вносим в массив структуру и картинку
CopyMemory mas(0), Bitm, Len(Bitm)
CopyMemory mas(Len(Bitm)), Pic(0), IconR(i).dwBytesInRes
'Записываем иконки в ресурсы
Call UpdateResource(h, ByVal RT_ICON, i + 1, 0, mas(0), IconR(i).dwBytesInRes + Len(Bitm)) '1252 - язык
Next i
'Итак, иконки теперь есть в ресурсах, теперь их нужно сгруппировать.
'Записываем Icon Group
ReDim mas(Len(ICO) + Len(IconE(1)) * ICO.Count)
CopyMemory mas(0), ICO, Len(ICO)
For i = 0 To ICO.Count - 1
offset = Len(ICO) + Len(IconE(1)) * i
CopyMemory mas(offset), IconE(i), Len(IconE(i))
Next i
'Обновляем ресурсы
'Сдесь в основном вместо 1 будет имя группы в ресурсах EXE который заменяем. 1 - стандартный у программ VB6
'В большинстве случаев может быть MAINICON. Только НЕ ЗАБУДЬТЕ поменять в деклейр функции UpdateResource параметр lpName с Long на String
Call UpdateResource(h, ByVal RT_GROUP_ICON, 1, 0, mas(0), Len(ICO) + Len(IconE(1)) * ICO.Count) '1252 - язык
'Закрываем
Call EndUpdateResource(h, 0)
Close #1
End Sub
Private Sub Command1_Click()
ReplaceIcon "file.exe", "icon.ico"
End Sub
Ответить
|