Войти

Показать полную графическую версию : [решено] Интересная проблема при выдирании иконки из exe


assch
23-07-2010, 03:17
Не много раньше я открывал тему "Вытащить из .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
интересно что за ошибка вылезает в этой функции »
Там должно быть описание ошибки. В любом случае это указывает на непредусмотреность числа элементов в масссиве.

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

#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
описание ошибки

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
описание ошибки »
В последнем примере этого нет.

assch
23-07-2010, 17:06
Да в последнем примере этого нет
Просто я дополнил описание ошибки старого примера
Простите что ввёл в заблуждение
Если вы помните я писал что КОДА справилась без проблем
Простите за нескромность
А каким алгоритмом она это делает вы не знаете?

assch
23-07-2010, 17:15
Помните я писал что собираю програмку по данной теме
Так вот с вашей помощью что вышло
Правда со старым кодом для выдирания
файл прилагаю

madmasles
23-07-2010, 17:27
Если вы помните я писал что КОДА справилась без проблем
Простите за нескромность
А каким алгоритмом она это делает вы не знаете? »
Вот здесь (http://autoit-script.ru/index.php?topic=273.60) можно задать этот вопрос разработчику Koda Form Designer Loopback-у.




© OSzone.net 2001-2012