Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   AutoIt (http://forum.oszone.net/forumdisplay.php?f=103)
-   -   [решено] Вытащить из .exe или .dll иконку (http://forum.oszone.net/showthread.php?t=180004)

assch 06-07-2010 22:07 1448626

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

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

FlatX007 07-07-2010 01:19 1448712

Тут 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 1448715

Цитата:

Цитата assch
можно ли это сделать силами Autoit »

Можно:

Код:

#include <GDIPlus.au3>
#include <WinAPI.au3>

_FileExtractIcon("shell32.dll", @DesktopDir & "\Icon.ico", -20)

Func _FileExtractIcon($sSrcFileIcon, $sOutFileIcon, $iIndex = 0)
    Local $aRet, $hIcon, $pBitmapdll, $pBitmap

    If $iIndex < 0 Then
        $iIndex = ($iIndex * -1)
    EndIf

    $aRet = DllCall("shell32.dll", "long", "ExtractAssociatedIcon", "int", 0, "str", $sSrcFileIcon, "int*", $iIndex - 1)
    $hIcon = $aRet[0]

    _GDIPlus_Startup()

    $pBitmapdll = DllCall($ghGDIPDll, "int", "GdipCreateBitmapFromHICON", "ptr", $hIcon, "int*", 0)
    $pBitmap = $pBitmapdll[2]

    _WinAPI_DestroyIcon($hIcon)
    _GDIPlus_ImageSaveToFileEx($pBitmap, $sOutFileIcon, "{557CF400-1A04-11D3-9A73-0000F81EF32E}")
    _GDIPlus_ImageDispose($pBitmap)

    _GDIPlus_Shutdown()

    Return 1
Endfunc


beve 07-07-2010 02:22 1448725

Вложений: 1
Вот есть такой скрипт...

assch 07-07-2010 03:40 1448731

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

Creat0R 07-07-2010 05:11 1448735

Цитата:

Цитата assch
иконки на выходе получаются на чёрном фоне »

И это не единственный минус данной функции, также не все форматы иконки сохраняются, на самом деле только один формат.

Мне удалось выдрать код из примера в посте от beve (кстати этот код вроде взят отсюда), и привести его немного в порядок:

Код:

#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 1448945

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

madmasles 07-07-2010 14:22 1448971

assch,
Посмотрите здесь: Объявления и новости.
Там Creat0R подробно и по-русски расписал все изменения в версиях, начиная с AutoIt v3.3.1.2 (бета).

assch 07-07-2010 20:31 1449211

Спасибо madmasles
За быстрый ответ без лишнего этикета

Creat0R 07-07-2010 21:50 1449262

Цитата:

Цитата assch
Извиняюсь что не в тему »

Извинение не делает это лигитимным ;)
На будущее, если у вас возникают несколько вопросов, пишите в отдельные темы каждый из них, если конечно в поиске не нашли подобной темы.


Время: 00:27.

Время: 00:27.
© OSzone.net 2001-