Тема: AHK: Извлечение иконок из dll и exe
Функция GetIconFromResource(dest, source, idx) извлекает иконку с порядковым номером idx из dll или exe файла, указанного в параметре source, и сохраняет её в файл, путь к которому указан в параметре dest. Если папка файла, указанного в dest, отсутствует, она будет создана скриптом, если это возможно. Чтобы извлечь из ресурса все иконки за раз, передайте idx равный 0. В этом случае к имени файла, указанного в dest, будет добавлен порядковый номер каждой из иконок.
GetIconFromResource(dest, source, idx)
{
; info: http://msdn.microsoft.com/en-us/library/ms997538.aspx
SetBatchLines, -1
if !hModule := Validation(dest, source, idx)
Return
for key, handle in FindGroup(source, idx, hModule)
{
pGroupInfo := GetResData(hModule, handle)
if !IsObject(DataArray := CreateDataArray(hModule, pGroupInfo, CountIcons, size, idx ? idx : A_Index))
{
if (DataArray = 6)
continue
else
break
}
pData := CreateDataBuff(DataArray, pGroupInfo, CountIcons, size)
res := Data2icoFile(pData, dest, size, idx)
} until !res
DllCall("FreeLibrary", Ptr, hModule)
}
Validation(dest, source, idx)
{
if !((idx + 1) > 0 && source := ValidateName(source))
Return
static dwFlags := (LOAD_LIBRARY_AS_DATAFILE := 0x2 | LOAD_LIBRARY_AS_IMAGE_RESOURCE := 0x20)
if !hModule := DllCall("LoadLibraryEx", Str, source, Ptr, 0, UInt, dwFlags, Ptr)
Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Невозможно загрузить указанный модуль!`nОшибка " A_LastError, Str, "", UInt, 0)
Return hModule
}
ValidateName(FilePath)
{
SplitPath, FilePath,,, ext
if !(ext ~= "i)exe|dll") && Error := "Допустимы только dll и exe файлы"
Return, 0, DllCall("MessageBox", Ptr, 0, Str, Error, Str, "", UInt, 0)
if !FileExist(FilePath)
{
EnvGet, PathVar, Path
Loop, parse, PathVar, `;
continue
until FileExist(p := RTrim(A_LoopField, "\") . "\" . FilePath) && (FilePath := p) && found := 1
if !found && Text := "Файл " FilePath " не найден"
Return, 0, DllCall("MessageBox", Ptr, 0, Str, Text, Str, "", UInt, 0)
}
Return FilePath
}
FindGroup(source, idx, hModule)
{
Names := [idx, 0]
DllCall("EnumResourceNames", Ptr, hModule, UInt, RT_GROUP_ICON := 14
, Ptr, RegisterCallback("EnumGroupIconProc", "Fast", 4), Ptr, pNames := Object(Names))
ObjRelease(pNames)
if (Names.3 = "") && Text := idx ? "Иконка " . idx . " в файле " . source . " не найдена"
: "Иконки в файле " . source . " не найдены"
Return, 0, DllCall("MessageBox", Ptr, 0, Str, Text, Str, "", UInt, 0)
Names.Remove(1, 2)
for i, Name in Names
Names[i] := DllCall("FindResource", Ptr, hModule, Name + 1 ? "UInt" : "Str", Name, UInt, RT_GROUP_ICON, Ptr)
Return Names
}
EnumGroupIconProc(hModule, Type, Name, lp)
{
(Name>>16) ? Name := LTrim(StrGet(Name+0), "#")
obj := Object(lp)
if !obj.1
obj.Insert(Name)
else if ((obj.2 += 1) = obj.1)
Return, 0, obj.3 := Name
Return 1
}
GetResData(hModule, hRes)
{
hData := DllCall("LoadResource", Ptr, hModule, Ptr, hRes, Ptr)
Return DllCall("LockResource", Ptr, hData, Ptr)
}
CreateDataArray(hModule, pIconGroup, ByRef CountIcons, ByRef offset, idx)
{
if NumGet(pIconGroup+0, 2, "UShort") != 1 && Text := "Ресурс " Idx " неправильного типа. Возможно, файл сжат или зашифрован`nПродолжить?"
Return DllCall("MessageBox", Ptr, 0, Str, Text, Str, "Неправильный ресурс", UInt, 4)
DataArray := [], RT_ICON := 3
CountIcons := NumGet(pIconGroup+0, 4, "UShort")
offset := 6 + CountIcons*16
Loop % CountIcons
{
id := NumGet(pIconGroup + 6 + 14*A_Index - 2, "UShort")
hRes := DllCall("FindResource", Ptr, hModule, UInt, id, UInt, RT_ICON, Ptr)
pIcon := GetResData(hModule, hRes)
DataArray[A_Index] := {ptr: pIcon
, size: s := NumGet(pIconGroup + 6 + 14*A_Index - 6, "UInt")
, offset: offset}
offset += s
}
Return DataArray
}
CreateDataBuff(DataArray, pIconGroup, CountIcons, size)
{
static IconData
VarSetCapacity(IconData, size)
DllCall("RtlMoveMemory", Ptr, &IconData, Ptr, pIconGroup, Ptr, 6)
offset := 6
Loop % CountIcons
{
DllCall("RtlMoveMemory", Ptr, &IconData + offset, Ptr, pIconGroup + offset - 2*(A_Index - 1), Ptr, 12)
NumPut(DataArray[A_Index].offset, &IconData + offset + 12, "UInt"), offset += 16
DllCall("RtlMoveMemory", Ptr, &IconData + DataArray[A_Index].offset, Ptr, DataArray[A_Index].ptr, Ptr, DataArray[A_Index].size)
}
Return &IconData
}
Data2icoFile(pData, Dest, size, idx)
{
static i = 0
SplitPath, Dest,, Dir, Ext, OutNameNoExt
if !FileExist(Dir)
{
FileCreateDir, % Dir
if ErrorLevel && Text := "Невозможно создать папку " Dir "`nОшибка " A_LastError
Return, 0, DllCall("MessageBox", Ptr, 0, Str, Text, Str, "", UInt, 0)
}
(!idx) ? Dest := (Ext ? SubStr(Dest, 1, -(StrLen(Ext) + 1)) : Dest) . "(" . ++i . ")" . (Ext ? "." . Ext : "")
if !(File := FileOpen(Dest, "w")) && Text := "Невозможно открыть файл " Dest "на запись`nОшибка " A_LastError
Return, 0, DllCall("MessageBox", Ptr, 0, Str, Text, Str, "", UInt, 0)
File.Seek(0), File.RawWrite(pData+0, size), File.Close()
Return 1
}
Пример использования:
GetIconFromResource(A_Desktop "\Icons\test.ico", "Shell32.dll", 0) ; извлекаем все иконки из Shell32.dll
GetIconFromResource(A_Desktop "\Icons2\test.ico", "Shell32.dll", 45) ; извлекаем иконку с порядковым индексом 45 (счёт от 1)
Return