PDA

Показать полную графическую версию : [решено] Вытащить из .exe или .dll иконку


assch
06-07-2010, 22:07
Пытаюсь сделать небольшую програмку которая меняет иконки у папок. В Windows такая утилитка есть ,только работает она
с файлами .ico а информацию записывает в .ini файл , и соответственно при разрыве путей (Например файл .ico перешёл в другое место
или папку вообще перенесли на другой компьютер) Вид папки примет обычный вид. Смысл програмки такой - Файл .ico копируется в папку назначения
и в ней же создаётся файл .ini где прописывается путь к этой иконке ,эти два файла можно сделать не видимыми. Поэтому при переносе этой папки
на другой компьютер она будет иметь вид той иконки которая вшита в ней. Проектик сами понимаете не комерческий а просто ради интереса что-то
сделать самому.
С простыми файлами .ico это сделать просто, а вот если кому-то пондравится иконка зашитая в .exe или .dll. Я понимаю что можно
вытащить эту иконку с помощью какой нибудь програмки но хочется чтобы работало всё в одном флаконе. Скажем при выборе иконки для папки
выбираешь файл .exe или .dll в окне отображаются все иконки зашитые в ней ( Сделать это просто, пример даже есть в Autoit ) дальше при выборе самой иконки из этого списка
нужно вытащить её из этих файлов в формате .ico ну а дальше всё просто.
По информации которую я пытаюсь найти вертится это около функции API ExtractIconExW хотя могу и ошибатся.

Вопрос - можно ли это сделать силами Autoit или нет?
Буду признателен любой инфрмации.

FlatX007
07-07-2010, 01:19
Тут http://bogdan.at.ua/reshack/index.html

ResHack pаботает через командную строку, следовательно им можно управлять по средствам AUTOIT

Или тут http://autoit-script.ru/index.php?topic=47.0

Смотреть функции:
_WinAPI_LoadResource _WinAPI_LoadLibrary

Creat0R
07-07-2010, 01:22
можно ли это сделать силами Autoit »
Можно:

#include (http://www.autoitscript.com/autoit3/docs/keywords.htm##include) <GDIPlus.au3>
#include (http://www.autoitscript.com/autoit3/docs/keywords.htm##include) <WinAPI.au3>

_FileExtractIcon("shell32.dll", @DesktopDir (http://www.autoitscript.com/autoit3/docs/macros.htm#@desktopdir) & "\Icon.ico", -20)

Func (http://www.autoitscript.com/autoit3/docs/keywords.htm#Func) _FileExtractIcon($sSrcFileIcon, $sOutFileIcon, $iIndex = 0)
Local (http://www.autoitscript.com/autoit3/docs/keywords.htm#Local) $aRet, $hIcon, $pBitmapdll, $pBitmap

If (http://www.autoitscript.com/autoit3/docs/keywords.htm#If) $iIndex < 0 Then (http://www.autoitscript.com/autoit3/docs/keywords.htm#Then)
$iIndex = ($iIndex * -1)
EndIf (http://www.autoitscript.com/autoit3/docs/keywords.htm#EndIf)

$aRet = DllCall (http://www.autoitscript.com/autoit3/docs/functions/DllCall.htm)("shell32.dll", "long", "ExtractAssociatedIcon", "int", 0, "str", $sSrcFileIcon, "int*", $iIndex - 1)
$hIcon = $aRet[0]

_GDIPlus_Startup (http://dundats.mvps.org/help/html/libfunctions/_gdiplus_startup.htm)()

$pBitmapdll = DllCall (http://www.autoitscript.com/autoit3/docs/functions/DllCall.htm)($ghGDIPDll, "int", "GdipCreateBitmapFromHICON", "ptr", $hIcon, "int*", 0)
$pBitmap = $pBitmapdll[2]

_WinAPI_DestroyIcon (http://dundats.mvps.org/help/html/libfunctions/_winapi_destroyicon.htm)($hIcon)
_GDIPlus_ImageSaveToFileEx (http://dundats.mvps.org/help/html/libfunctions/_gdiplus_imagesavetofileex.htm)($pBitmap, $sOutFileIcon, "{557CF400-1A04-11D3-9A73-0000F81EF32E}")
_GDIPlus_ImageDispose (http://dundats.mvps.org/help/html/libfunctions/_gdiplus_imagedispose.htm)($pBitmap)

_GDIPlus_Shutdown (http://dundats.mvps.org/help/html/libfunctions/_gdiplus_shutdown.htm)()

Return (http://www.autoitscript.com/autoit3/docs/keywords.htm#Return) 1
Endfunc (http://www.autoitscript.com/autoit3/docs/keywords.htm#EndFunc)

beve
07-07-2010, 02:22
Вот есть такой скрипт...

assch
07-07-2010, 03:40
Большое всем спасибо, жалко только что функция _FileExtractIcon делает это хорошо, и код довольно компактный ,только иконки на выходе получаются на чёрном фоне .
Всё равно всем большое спасибо за информацию .
Старожилу beve особенно за подарок.
Уважаемому Creat0R за интересный код , попробую понять почему получаются такие иконки.

Creat0R
07-07-2010, 05:11
иконки на выходе получаются на чёрном фоне »
И это не единственный минус данной функции, также не все форматы иконки сохраняются, на самом деле только один формат.

Мне удалось выдрать код из примера в посте от beve (кстати этот код вроде взят отсюда (http://www.autoitscript.com/forum/index.php?showtopic=78084)), и привести его немного в порядок:

#include <WinAPI.au3>

Global $aEN[1]

$sSrc = @SystemDir & "\shell32.dll"
$sOut = @DesktopDir & "\MyIcon.ico"

_FileExtractIcon($sSrc, -20, $sOut)

Func _FileExtractIcon($sINFILE, $iICON, $sOUTICO, $iPATH = 0, $iSaveAsPng = 0)
Local Const $RT_GROUP_ICON = 14
Local $hINST, $iGN = "", $HFIND, $aSIZE, $hLOAD, $HLOCK, $TRES, $sDATA, $aRet[2]
If Not FileExists($sINFILE) And Not IsPtr($sINFILE) Then Return SetError(1, 0, 0)
If Not IsInt($iICON) Then Return SetError(2, 0, 0)
If IsPtr($sINFILE) Then
$hINST = $sINFILE
Else
$hINST = _WinAPI_LoadLibraryEx($sINFILE, 2)
If Not $hINST Then Return SetError(3, 0, 0)
EndIf
If Not IsPtr($hINST) Then Return SetError(3, 0, 0)
__ResourceEnumNames($hINST, $RT_GROUP_ICON)
If @error Then
_WinAPI_FreeLibrary($hINST)
Return SetError(4, 0, 0)
EndIf
For $I = 1 To $aEN[0]
If $I = StringReplace($iICON, "-", "") Then
$iGN = $aEN[$I]
ExitLoop
EndIf
Next
If $iGN = "" Then
_WinAPI_FreeLibrary($hINST)
Return SetError(5, 0, 0)
EndIf
$HFIND = DllCall("kernel32.dll", "int", "FindResourceA", "int", $hINST, "str", $iGN, "long", $RT_GROUP_ICON)
If $HFIND[0] = 0 Then
_WinAPI_FreeLibrary($hINST)
Return SetError(6, 0, 0)
EndIf
$aSIZE = DllCall("kernel32.dll", "dword", "SizeofResource", "int", $hINST, "int", $HFIND[0])
If $aSIZE[0] = 0 Then
_WinAPI_FreeLibrary($hINST)
Return SetError(7, 0, 0)
EndIf
$hLOAD = DllCall("kernel32.dll", "int", "LoadResource", "int", $hINST, "int", $HFIND[0])
If $hLOAD[0] = 0 Then
_WinAPI_FreeLibrary($hINST)
Return SetError(8, 0, 0)
EndIf
$HLOCK = DllCall("kernel32.dll", "int", "LockResource", "int", $hLOAD[0])
If $HLOCK[0] = 0 Then
_WinAPI_FreeLibrary($hINST)
Return SetError(9, 0, 0)
EndIf
$TRES = DllStructCreate("byte[" & $aSIZE[0] & "]", $HLOCK[0])
If Not IsDllStruct($TRES) Then
_WinAPI_FreeLibrary($hINST)
Return SetError(10, 0, 0)
EndIf
$sDATA = DllStructGetData($TRES, 1)
If $sDATA = "" Then
_WinAPI_FreeLibrary($hINST)
Return SetError(11, 0, 0)
EndIf
__FreeResource($hLOAD[0])
If Not IsPtr($sINFILE) Then _WinAPI_FreeLibrary($hINST)
Dim $aEN[1]
$aRet[0] = $sINFILE
$aRet[1] = $sDATA

;_Exticondata()
Local $aID = $aRet

Local Const $RT_ICON = 3
Local $hINST, $AHDR, $aRet[1][2]
If Not IsArray($aID) Then Return SetError(1, 0, 0)
If Not FileExists($aID[0]) And Not IsPtr($aID[0]) Then Return SetError(2, 0, 0)
If IsPtr($aID[0]) Then
$hINST = $aID[0]
Else
$hINST = _WinAPI_LoadLibraryEx($aID[0], 2)
If Not $hINST Then Return SetError(3, 0, 0)
EndIf
If Not IsPtr($hINST) Then Return SetError(3, 0, 0)
$aRet[0][0] = Dec(__Rb(StringMid($aID[1], 11, 4)))
ReDim $aRet[$aRet[0][0] + 1][2]
$AHDR = StringRegExp(StringTrimLeft(BinaryMid($aID[1], 7), 2), "(.{28})", 3)
For $I = 1 To $aRet[0][0]
Local $AGID = __GetIconData($hINST, Dec(__Rb(StringRight($AHDR[$I - 1], 4))))
$aRet[$I][0] = StringTrimRight($AHDR[$I - 1], 4)
$aRet[$I][1] = $AGID[1]
__FreeResource($AGID[0])
Next
If Not IsPtr($aID[0]) Then _WinAPI_FreeLibrary($hINST)

;_Createiconfile($aID, $aSEL, $sOUTICO, $iPATH = 0, $iSaveAsPng = 0)
Local $aSEL = $iICON
$aID = $aRet
If Not IsArray($aID) Then Return SetError(1, 0, 0)
Local $iCNT, $sHDR, $OFFSET, $sDBYTE, $iMICON = "", $FO, $FW, $eSEL[$aID[0][0]], $iCRT = 18
If $iPATH <> 0 Then $iCRT = 26
If Not IsArray($aSEL) Then
For $I = 0 To UBound($eSEL) - 1
$eSEL[$I] = $I + 1
Next
$aSEL = $eSEL
EndIf
If UBound($aSEL) = 1 And StringInStr(StringTrimLeft($aID[$aSEL[0]][1], 2), "504E47") Then
If $iSaveAsPng Then $sOUTICO = StringReplace($sOUTICO, ".ico", ".png")
EndIf
$iCNT = UBound($aSEL)
$sHDR = "0x00000100" & __Rb(Hex($iCNT, 4))
$OFFSET = ($iCNT * 16) + 6
For $I = 0 To UBound($aSEL) - 1
$sDBYTE = Dec(__Rb(StringMid($aID[$aSEL[$I]][0], 17, 8)))
$sHDR &= $aID[$aSEL[$I]][0] & __Rb(Hex($OFFSET))
$OFFSET += $sDBYTE
If StringRight($sOUTICO, 4) = ".png" Then
$sHDR = ""
$iMICON &= $aID[$aSEL[$I]][1]
Else
$iMICON &= StringTrimLeft($aID[$aSEL[$I]][1], 2)
EndIf
Next
$FO = FileOpen($sOUTICO, $iCRT)
If $FO = -1 Then Return SetError(2, 0, 0)
$FW = FileWrite($FO, $sHDR & $iMICON)
If $FW = 0 Then
FileClose($FO)
Return SetError(3, 0, 0)
EndIf
FileClose($FO)
Return SetError(0, 0, 1)
EndFunc

Func __FreeResource($HGLBRESOURCE)
DllCall("kernel32.dll", "int", "FreeResource", "int", $HGLBRESOURCE)
EndFunc

Func __GetIconData($hMODULE, $iON)
Local Const $RT_ICON = 3
Local $HFIND, $aSIZE, $hLOAD, $HLOCK, $TRES, $aRet[2]
$HFIND = DllCall("kernel32.dll", "int", "FindResourceA", "int", $hMODULE, "str", "#" & $iON, "long", $RT_ICON)
$aSIZE = DllCall("kernel32.dll", "dword", "SizeofResource", "int", $hMODULE, "int", $HFIND[0])
$hLOAD = DllCall("kernel32.dll", "int", "LoadResource", "int", $hMODULE, "int", $HFIND[0])
$HLOCK = DllCall("kernel32.dll", "int", "LockResource", "int", $hLOAD[0])
$TRES = DllStructCreate("byte[" & $aSIZE[0] & "]", $HLOCK[0])
$aRet[0] = $HLOCK[0]
$aRet[1] = DllStructGetData($TRES, 1)
Return $aRet
EndFunc

Func __Rb($sBYTE)
Local $AX = StringRegExp($SBYTE, "(.{2})", 3), $SX = ""
For $I = UBound($AX) - 1 To 0 Step -1
$SX &= $AX[$I]
Next
Return $SX
EndFunc

Func __ResourceEnumNames($hMODULE, $iTYPE)
Local $aRet, $stCB
If Not IsPtr($hMODULE) Then Return SetError(1, 0, 0)
$stCB = DllCallbackRegister("__ResourceEnumNames_Proc", "int", "int_ptr;int_ptr;int_ptr;int_ptr")
$aRet = DllCall("kernel32.dll", "int", "EnumResourceNamesW", "ptr", $hMODULE, "int", $iTYPE, "ptr", DllCallbackGetPtr($stCB), "ptr", 0)
DllCallbackFree($stCB)
If $aRet[0] <> 1 Then Return SetError(2, 0, 0)
Return SetError(0, 0, 1)
EndFunc

Func __ResourceEnumNames_Proc($hMODULE, $pTYPE, $pNAME, $lPARAM)
Local $aSIZE = DllCall("kernel32.dll", "int", "GlobalSize", "ptr", $pNAME), $tBUF
If $aSIZE[0] Then
$tBUF = DllStructCreate("wchar[" & $aSIZE[0] & "]", $pNAME)
ReDim $aEN[UBound($aEN) + 1]
$aEN[0] += 1
$aEN[UBound($aEN) - 1] = DllStructGetData($tBUF, 1)
Else
ReDim $aEN[UBound($aEN) + 1]
$aEN[0] += 1
$aEN[UBound($aEN) - 1] = "#" & $pNAME
EndIf
Return 1
EndFunc

assch
07-07-2010, 13:45
Да этот код хоть и по обьёмней но гораздо лучше справляется со своей задачей
Большое спасибо Creat0R
Извиняюсь что не в тему
Не подскажете в чём проблема у меня стояла старая версия - autoit-v3.2.4.9 - А недавно обновил до версии autoit-v3.3.6.1 и мои старые файлы
не открываются выскакивает ошибка
Не посоветуйте оптимальную версию или проблема не в этом?

madmasles
07-07-2010, 14:22
assch,
Посмотрите здесь: Объявления и новости (http://autoit-script.ru/index.php?board=1.0).
Там Creat0R подробно и по-русски расписал все изменения в версиях, начиная с AutoIt v3.3.1.2 (бета).

assch
07-07-2010, 20:31
Спасибо madmasles
За быстрый ответ без лишнего этикета

Creat0R
07-07-2010, 21:50
Извиняюсь что не в тему »
Извинение не делает это лигитимным ;)
На будущее, если у вас возникают несколько вопросов, пишите в отдельные темы каждый из них, если конечно в поиске не нашли подобной темы.




© OSzone.net 2001-2012