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

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

assch 23-07-2010 03:17 1458933

Интересная проблема при выдирании иконки из exe
 
Не много раньше я открывал тему "Вытащить из .exe или .dll иконку "
Creat0R Предложил мне функцию.

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

Одним из недостатков этой функции был тот что иконки на выходе получаются на чёрном фоне.
Тогда beve предложил более сложную функцию которую впоследствии Creat0R оптимизировав её
убрал всё лишние, на выходе получилась функция которая нормально справлялась со своей работой.
До тех пор пока мне не попался случайно файл crack.exe и моя програмка которую я делаю при попытке
выдрать эту иконку тут же гаснет, я испытывал на многих файлах и 99 из 100 функция работает отлично
В SciTE при отладке этой функции пишет ошибку

Local $AGID = __GetIconData($hINST, Dec(__Rb(StringRight($AHDR[$I - 1], 4))))
Local $AGID = __GetIconData($hINST, Dec(__Rb(StringRight(^ ERROR

Кстати професиональная прога Articons Pro хоть и не гасла но тоже отказывалась вытаскивать эти иконки
(их кстати там две) А вот первая функция которую мне предложил Creat0R

FileExtractIcon("crack.exe", @DesktopDir & "\Icon.ico", -1)

Вытащила их без проблем только как я уже говорил на чёрном фоне.
Только прога Koda в которой есть фишка которая подставляет иконки в вашу программу и там можно эту иконку
вытащить, справилась с этим crack.exe без проблем.Но как узнать как она это сделала?
Всё таки интересно что за ошибка вылезает в этой функции

Local $AGID = __GetIconData($hINST, Dec(__Rb(StringRight($AHDR[$I - 1], 4))))
Local $AGID = __GetIconData($hINST, Dec(__Rb(StringRight(^ ERROR

И она напрочь отказывается работать с этим crack.exe
Ещё раз повторю 99 из 100 функция работает отлично.
Файл crack.exe Прилагаю.

Код:

#include <WinAPI.au3>

Global $aEN[1]

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

_FileExtractIcon($sSrc, -1, $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


Creat0R 23-07-2010 15:55 1459239

Цитата:

Цитата assch
интересно что за ошибка вылезает в этой функции »

Там должно быть описание ошибки. В любом случае это указывает на непредусмотреность числа элементов в масссиве.

Вот исправленная версия, ошибок не будет, но иконку не вытаскивает, мне кажется в этом случае можно использовать упрощонную версию, там всё ровно не заметно чёрного фона:

Код:

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

Global $a__EN[1]

$sSrc = @DesktopDir & "\crack.exe"
$sDest = @DesktopDir & "\crack.ico"

$iRet = _FileExtractIcon($sSrc, -1, $sDest)
If @error Then _FileExtractIconSimple($sSrc, $sDest, -1)

Func _FileExtractIcon($sInFile, $iIcon, $sOutIco, $iPath = 0)
        Local Const $LOAD_LIBRARY_AS_DATAFILE = 0x00000002
        Local Const $RT_ICON = 3
        Local Const $RT_GROUP_ICON = 14
        Local $hInst, $iGN = "", $sData, $sDByte, $sHdr, $aHdr, $iCnt, $Offset, $FO, $FW, $iCrt = 18
        If $iPath = 1 Then $iCrt = 26 ;+8, to create directory structure
        If Not FileExists($sInFile) Then Return SetError(1, 0, 0)
        If Not IsInt($iIcon) Then Return SetError(2, 0, 0)
        $hInst = _LoadLibraryEx($sInFile, $LOAD_LIBRARY_AS_DATAFILE)
        If Not $hInst Then Return SetError(3, 0, 0)
        _ResourceEnumNames($hInst, $RT_GROUP_ICON)
        For $i = 1 To $a__EN[0]
                If $i = StringReplace($iIcon, "-", "") Then
                        $iGN = $a__EN[$i]
                        ExitLoop
                EndIf
        Next
        Dim $a__EN[1]
        If $iGN = "" Then
                _FreeLibrary($hInst)
                Return SetError(4, 0, 0)
        EndIf
        $sData = _GetIconResource($hInst, $iGN, $RT_GROUP_ICON)
        If @error Then
                _FreeLibrary($hInst)
                Return SetError(5, 0, 0)
        EndIf
        $sHdr = BinaryMid($sData, 1, 6)
        $aHdr = StringRegExp(StringTrimLeft(BinaryMid($sData, 7), 2), "(.{28})", 3)
        $iCnt = UBound($aHdr)
        $Offset = ($iCnt * 16) + 6
        For $i = 0 To $iCnt - 1
                $sDByte = Dec(_StringReverseBytes(StringMid($aHdr[$i], 17, 8)))
                $sHdr &= StringTrimRight($aHdr[$i], 4) & _StringReverseBytes(Hex($Offset))
                $Offset += $sDByte
        Next
        For $i = 0 To $iCnt - 1
                $sData = _GetIconResource($hInst, "#" & Dec(_StringReverseBytes(StringRight($aHdr[$i], 4))), $RT_ICON)
                If @error Then
                        _FreeLibrary($hInst)
                        Return SetError(6, 0, 0)
                EndIf
                $sHdr &= StringTrimLeft($sData, 2)
        Next
        _FreeLibrary($hInst)
        $FO = FileOpen($sOutIco, $iCrt)
        If $FO = -1 Then Return SetError(7, 0, 0)
        $FW = FileWrite($FO, $sHdr)
        If $FW = 0 Then
                FileClose($FO)
                Return SetError(8, 0, 0)
        EndIf
        FileClose($FO)
        Return SetError(0, 0, 1)
EndFunc  ;==>_FileExtractIcon

Func _FileExtractIconSimple($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

; ========================================================================================================
; Internal Helper Functions from this point on
; ========================================================================================================
Func _GetIconResource($hModule, $sResName, $iResType)
        Local $hFind, $aSize, $hLoad, $hLock, $tRes, $sRet
        $hFind = DllCall("kernel32.dll", "int", "FindResource", "int", $hModule, "str", $sResName, "long", $iResType)
        If @error Or Not $hFind[0] Then Return SetError(1, 0, 0)
        $aSize = DllCall("kernel32.dll", "dword", "SizeofResource", "int", $hModule, "int", $hFind[0])
        If @error Or Not $aSize[0] Then Return SetError(2, 0, 0)
        $hLoad = DllCall("kernel32.dll", "int", "LoadResource", "int", $hModule, "int", $hFind[0])
        If @error Or Not $hLoad[0] Then Return SetError(3, 0, 0)
        $hLock = DllCall("kernel32.dll", "int", "LockResource", "int", $hLoad[0])
        If @error Or Not $hLock[0] Then
                _FreeResource($hLoad[0])
                Return SetError(4, 0, 0)
        EndIf
        $tRes = DllStructCreate("byte[" & $aSize[0] & "]", $hLock[0])
        If Not IsDllStruct($tRes) Then
                _FreeResource($hLoad[0])
                Return SetError(5, 0, 0)
        EndIf
        $sRet = DllStructGetData($tRes, 1)
        If $sRet = "" Then
                _FreeResource($hLoad[0])
                Return SetError(6, 0, 0)
        EndIf
        _FreeResource($hLoad[0])
        Return $sRet
EndFunc  ;==>_GetIconResource

Func _LoadLibraryEx($sFile, $iFlag)
        Local $aRet = DllCall("Kernel32.dll", "hwnd", "LoadLibraryExW", "wstr", $sFile, "hwnd", 0, "int", $iFlag)
        Return $aRet[0]
EndFunc  ;==>_LoadLibraryEx

Func _FreeLibrary($hModule)
        DllCall("Kernel32.dll", "hwnd", "FreeLibrary", "hwnd", $hModule)
EndFunc  ;==>_FreeLibrary

Func _FreeResource($hglbResource)
        DllCall("kernel32.dll", "int", "FreeResource", "int", $hglbResource)
EndFunc  ;==>_FreeResource

; Just a Reverse string byte function (smashly style..lol)
Func _StringReverseBytes($sByte)
        Local $aX = StringRegExp($sByte, "(.{2})", 3), $sX = ''
        For $i = UBound($aX) - 1 To 0 Step -1
                $sX &= $aX[$i]
        Next
        Return $sX
EndFunc  ;==>_StringReverseBytes

Func _ResourceEnumNames($hModule, $iType)
        Local $aRet, $xCB
        If Not $hModule Then Return SetError(1, 0, 0)
        $xCB = DllCallbackRegister('__ResourceEnumNamesProc', 'int', 'int_ptr;int_ptr;int_ptr;int_ptr')
        $aRet = DllCall('kernel32.dll', 'int', 'EnumResourceNamesW', 'ptr', $hModule, 'int', $iType, 'ptr', DllCallbackGetPtr($xCB), 'ptr', 0)
        DllCallbackFree($xCB)
        If $aRet[0] <> 1 Then Return SetError(2, 0, 0)
        Return SetError(0, 0, 1)
EndFunc  ;==>_ResourceEnumNames

Func __ResourceEnumNamesProc($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 $a__EN[UBound($a__EN) + 1]
                $a__EN[0] += 1
                $a__EN[UBound($a__EN) - 1] = DllStructGetData($tBuf, 1)
        Else
                ReDim $a__EN[UBound($a__EN) + 1]
                $a__EN[0] += 1
                $a__EN[UBound($a__EN) - 1] = "#" & $pName
        EndIf
        Return 1
EndFunc  ;==>__ResourceEnumNamesProc

и кстати как раз таки эту тему можно было продолжить обсуждать в первой, т.к оно напрямую связано.

assch 23-07-2010 16:08 1459251

описание ошибки

G:\Documents and Settings\assch\??????? ????\f33.au3 (91) : ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:
Local $AGID = __GetIconData($hINST, Dec(__Rb(StringRight($AHDR[$I - 1], 4))))
Local $AGID = __GetIconData($hINST, Dec(__Rb(StringRight(^ ERROR

Creat0R 23-07-2010 16:16 1459259

Цитата:

Цитата assch
описание ошибки »

В последнем примере этого нет.

assch 23-07-2010 17:06 1459298

Да в последнем примере этого нет
Просто я дополнил описание ошибки старого примера
Простите что ввёл в заблуждение
Если вы помните я писал что КОДА справилась без проблем
Простите за нескромность
А каким алгоритмом она это делает вы не знаете?

assch 23-07-2010 17:15 1459305

Помните я писал что собираю програмку по данной теме
Так вот с вашей помощью что вышло
Правда со старым кодом для выдирания
файл прилагаю

madmasles 23-07-2010 17:27 1459309

Цитата:

Цитата assch
Если вы помните я писал что КОДА справилась без проблем
Простите за нескромность
А каким алгоритмом она это делает вы не знаете? »

Вот здесь можно задать этот вопрос разработчику Koda Form Designer Loopback-у.


Время: 12:48.

Время: 12:48.
© OSzone.net 2001-