Icons extrahieren

  • Hi,
    ich habe mir vor langer Zeit mal dieses Skript gesichert.
    Es sollen alle Icons aus der exe extrahiert und als ico gespeichert werden.

    Leider funktioniert es nun nicht mehr.
    Ich denke es liegt an Win 7 64bit.
    Es wäre am besten, wenn es unter Win XP und Win 7 funktionieren würde.

    Spoiler anzeigen
    [autoit]

    #include <APIConstants.au3>
    #include <Constants.au3>
    #include <GDIPlus.au3>
    #include <GUIConstantsEx.au3>
    #include <GuiListView.au3>
    #include <GuiStatusBar.au3>
    #include <ListViewConstants.au3>
    #include <StatusBarConstants.au3>
    #include <StructureConstants.au3>
    #include <WinAPI.au3>
    #include <WindowsConstants.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Opt("GUIOnEventMode", 1)

    [/autoit] [autoit][/autoit] [autoit]

    ; notify messages
    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")

    [/autoit] [autoit][/autoit] [autoit]

    Global $sIn = @SystemDir & "\shell32.dll" ;; default icon file
    Global $hGui, $LV, $Extract, $LHT, $IHM

    [/autoit] [autoit][/autoit] [autoit]

    $hGui = GUICreate("", 500, 400, -1, -1, -1, $WS_EX_ACCEPTFILES)

    [/autoit] [autoit][/autoit] [autoit]

    GUISetOnEvent($GUI_EVENT_DROPPED, "GuiEvent", $hGui)
    GUISetOnEvent($GUI_EVENT_CLOSE, "GuiEvent", $hGui)

    [/autoit] [autoit][/autoit] [autoit]

    $LV = GUICtrlCreateListView("", 5, 5, 490, 350, $LVS_ICON)
    GUICtrlSetState(-1, $GUI_DROPACCEPTED)
    GUICtrlSetTip(-1, "Drop a supported file here to view it's icons." & @LF & "Double Click an icon to extract.")
    _GUICtrlListView_SetView($LV, 1)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; Build Menu
    $fil_mnu = GUICtrlCreateMenu("&extract")
    $menu_save_all_as_ico = GUICtrlCreateMenuItem("Save all as ICO", $fil_mnu)
    GUICtrlSetOnEvent(-1, "menu_save_all_as_ico")

    [/autoit] [autoit][/autoit] [autoit]

    $menu_save_all_as_png = GUICtrlCreateMenuItem("Save all as PNG", $fil_mnu)
    GUICtrlSetOnEvent(-1, "menu_save_all_as_png")

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; status bar ..
    Global $aStatusParts[2] = [400, -1]
    Global $aTempStatus[2] = ["", ""]

    [/autoit] [autoit][/autoit] [autoit]

    $StatusBar = _GUICtrlStatusBar_Create($hGui, $aStatusParts, $aTempStatus, $SBARS_SIZEGRIP)
    _GUICtrlStatusBar_SetMinHeight($StatusBar, 20)
    _GUICtrlStatusBar_SetText($StatusBar, "Icon Extractor")

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState(@SW_SHOW, $hGui)

    [/autoit] [autoit][/autoit] [autoit]

    Update()

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    While 1
    Sleep(100)
    ChkExtract()
    WEnd

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func GuiEvent()
    Switch @GUI_CtrlId
    Case $GUI_EVENT_CLOSE
    Exit

    [/autoit] [autoit][/autoit] [autoit]

    Case $GUI_EVENT_DROPPED
    If StringRegExp(@GUI_DragFile, "(?i)\.(cpl|dll|exe|icl|ocx)", 0) Then
    _GUICtrlListView_DeleteAllItems($LV)
    $sIn = @GUI_DragFile
    Update()
    EndIf
    EndSwitch
    EndFunc ;==>GuiEvent

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; function - save all as ico as
    Func menu_save_all_as_ico()
    ; all icons ?
    $IHM = _WinAPI_ExtractIconEx($sIn, -1, 0, 0, 0)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To $IHM
    $filename = @ScriptDir & "\icon_" & $i & ".ico";

    [/autoit] [autoit][/autoit] [autoit]

    _GUICtrlStatusBar_SetText($StatusBar, "extracting ICO icon " & $i & " of " & $IHM)

    [/autoit] [autoit][/autoit] [autoit]

    _ExtractIconToFile($sIn, $i, $filename)

    [/autoit] [autoit][/autoit] [autoit]

    Next
    _GUICtrlStatusBar_SetText($StatusBar, "")

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>menu_save_all_as_ico

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; function - save all as png files
    Func menu_save_all_as_png()
    ; all icons ?
    $IHM = _WinAPI_ExtractIconEx($sIn, -1, 0, 0, 0)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To $IHM
    $filename = @ScriptDir & "\icon_" & $i & ".png";

    [/autoit] [autoit][/autoit] [autoit]

    $Ret = DllCall("shell32", "long", "ExtractAssociatedIcon", "int", 0, "str", $sIn, "int*", $i)
    $hIcon = $Ret[0]

    [/autoit] [autoit][/autoit] [autoit]

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

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_ImageSaveToFile($pBitmap, $filename)
    _GDIPlus_ImageDispose($pBitmap)
    _GDIPlus_Shutdown()
    _WinAPI_DestroyIcon($Ret[0])
    _GUICtrlStatusBar_SetText($StatusBar, "extracting PNG icon " & $i & " of " & $IHM)
    Next
    _GUICtrlStatusBar_SetText($StatusBar, "")
    EndFunc ;==>menu_save_all_as_png

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func ChkExtract()
    If $Extract Then
    $Extract = 0

    [/autoit] [autoit][/autoit] [autoit]

    Local $FOD = FileSaveDialog("Save extracted icon as..", "", "Icon file (*.ico)")

    [/autoit] [autoit][/autoit] [autoit]

    If Not @error And $FOD <> "" Then
    WinSetTitle($hGui, "", "Extracting...")
    _ExtractIconToFile($sIn, $LHT, $FOD)

    [/autoit] [autoit][/autoit] [autoit]

    If @error Then
    WinSetTitle($hGui, "", "Error extracting icon - Error Code: " & @error)
    Else
    WinSetTitle($hGui, "", "Icons found in " & StringMid($sIn, StringInStr($sIn, "\", 0, -1) + 1) & ": " & $IHM)
    EndIf
    EndIf
    EndIf
    EndFunc ;==>ChkExtract

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func Update()
    $IHM = _WinAPI_ExtractIconEx($sIn, -1, 0, 0, 0)

    [/autoit] [autoit][/autoit] [autoit]

    WinSetTitle($hGui, "", "Icons found in " & StringMid($sIn, StringInStr($sIn, "\", 0, -1) + 1) & ": " & $IHM)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To $IHM
    GUICtrlCreateListViewItem($i, $LV)
    GUICtrlSetImage(-1, $sIn, -$i, 1)
    Next
    EndFunc ;==>Update

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func DefName()
    Local $FN = StringFormat("%0" & StringLen($IHM) & "d", $LHT)
    Return $FN & "_" & StringTrimRight(StringMid($sIn, StringInStr($sIn, "\", 0, -1) + 1), 3) & "ico"
    EndFunc ;==>DefName

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; double click on item -> extract as--.
    Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndLV, $tInfo
    $hWndLV = GUICtrlGetHandle($LV)

    [/autoit] [autoit][/autoit] [autoit]

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
    Case $hWndLV
    Switch $iCode
    Case $NM_DBLCLK
    Local $tPoint = _WinAPI_GetMousePos(True, $hGui)
    Local $LVHT = _GUICtrlListView_HitTest($hWndLV, DllStructGetData($tPoint, "X"), DllStructGetData($tPoint, "Y"))
    If $LVHT[0] <> -1 Then
    $Extract = 1
    $LHT = ($LVHT[0] + 1)
    EndIf
    EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_NOTIFY

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Global $aINM[1]

    [/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# =============================================================================================
    ; Name...........: _ExtractIconToFile
    ; Description ...: Extract an icon resource from a cpl, dll, exe, icl, ocx to a *.ico file
    ; Syntax.........: _ExtractIconToFile($sInFile, $iIcon, $sOutIco[, $iPath = 0])
    ; Parameters ....: $sInFile - Path to file that contains the icon to extract.
    ; $iIcon - Icon Number to extract, eg; -1 (The first icon starts at -1)
    ; $sOutIco - Full path where to save the extracted icon to, eg; "C:\My Icons\new.ico"
    ; $iPath - If set to 1 then the extraction path will be created if it doesn't exist.
    ; If left as 0 then if the extraction path doesn't exist it won't be created.
    ; Return values .: Success - Return 1 and @error 0
    ; Failure - Return 0 and @error 1 ~ 12
    ; @error 1 = Invalid $sInFile parameter
    ; @error 2 = Invalid $iIcon parameter
    ; @error 3 = LoadLibrary failed to return a valid ptr
    ; @error 4 = $iIcon does not exist in the $sInFile
    ; @error 5 = Failed to Find RT_GROUP_ICON Resource
    ; @error 6 = Returned RT_GROUP_ICON Resource as 0 bytes
    ; @error 7 = Failed to Load RT_GROUP_ICON Resource
    ; @error 8 = Failed to Lock RT_GROUP_ICON Resource
    ; @error 9 = Failed to create DLL Struct for RT_GROUP_ICON data
    ; @error 10 = Data in DLL Struct is null
    ; @error 11 = Failed to Open output file path
    ; @error 12 = Failed to write file at output path
    ; (Most the error returns were for my own debug purpose)
    ; Author ........: smashly
    ; Modified.......:
    ; Remarks .......: A big Thank You to Siao for the heads up on _ResourceEnumNames & ___EnumResNameProc
    ; Also Thank You to WeaponX for his _StringSplitRegExp
    ; Related .......:
    ; Link ..........;
    ; Example .......; _ExtractIconToFile(@SystemDir & "\shell32.dll", -42, @HomeDrive & "\Extracted.ico")
    ; ========================================================================================================
    Func _ExtractIconToFile($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 = "", $hFind, $aSize, $hLoad, $hLock, $tRes
    Local $sData, $sHdr, $iOrd, $aHtail, $iCnt, $Offset, $FO, $iCrt = 18

    [/autoit] [autoit][/autoit] [autoit]

    If $iPath = 1 Then $iCrt = 26
    If Not FileExists($sInFile) Then Return SetError(1, 0, 0)
    If Not IsInt($iIcon) Then Return SetError(2, 0, 0)

    [/autoit] [autoit][/autoit] [autoit]

    $hInst = _LoadLibraryEx($sInFile, $LOAD_LIBRARY_AS_DATAFILE)
    If Not IsPtr($hInst) Then Return SetError(3, 0, 0)
    _ResourceEnumNames($hInst, $RT_GROUP_ICON)
    For $i = 1 To $aINM[0]
    If $i = StringReplace($iIcon, "-", "") Then
    $iGN = $aINM[$i]
    ExitLoop
    EndIf
    Next
    If $iGN = "" Then
    _FreeLibrary($hInst)
    Return SetError(4, 0, 0)
    EndIf
    $hFind = DllCall("kernel32.dll", "int", "FindResourceA", "int", $hInst, "str", $iGN, "long", $RT_GROUP_ICON)
    If $hFind[0] = 0 Then
    _FreeLibrary($hInst)
    Return SetError(5, 0, 0)
    EndIf
    $aSize = DllCall("kernel32.dll", "dword", "SizeofResource", "int", $hInst, "int", $hFind[0])
    If $aSize[0] = 0 Then
    _FreeLibrary($hInst)
    Return SetError(6, 0, 0)
    EndIf
    $hLoad = DllCall("kernel32.dll", "int", "LoadResource", "int", $hInst, "int", $hFind[0])
    If $hLoad[0] = 0 Then
    _FreeLibrary($hInst)
    Return SetError(7, 0, 0)
    EndIf
    $hLock = DllCall("kernel32.dll", "int", "LockResource", "int", $hLoad[0])
    If $hLock[0] = 0 Then
    _FreeLibrary($hInst)
    Return SetError(8, 0, 0)
    EndIf
    $tRes = DllStructCreate("byte[" & $aSize[0] & "]", $hLock[0])
    If Not IsDllStruct($tRes) Then
    _FreeLibrary($hInst)
    Return SetError(9, 0, 0)
    EndIf
    $sData = DllStructGetData($tRes, 1)
    If $sData = "" Then
    _FreeLibrary($hInst)
    Return SetError(10, 0, 0)
    EndIf
    $sHdr = StringLeft($sData, 14)
    $iOrd = Dec(LTHR("0x" & StringRight(StringLeft($sData, 42), 4))) ;index start of icon in the library
    $aHtail = _StringSplitRegExp(StringTrimLeft($sData, 14), '(.){28}', True)
    $iCnt = $aHtail[0]
    $Offset = ($iCnt * 16) + 6
    For $r = 1 To $aHtail[0]
    $sDByte = Dec(Hex(BitRotate("0x" & StringLeft(StringRight($aHtail[$r], 12), 4), -8), 4))
    $aHtail[$r] = StringTrimRight($aHtail[$r], 4)
    $sHdr &= $aHtail[$r] & LTHR($Offset) & "0000"
    $Offset += $sDByte
    Next
    For $i = 1 To $iCnt
    $hFind = DllCall("kernel32.dll", "int", "FindResourceA", "int", $hInst, "str", "#" & $iOrd, "long", $RT_ICON)
    $aSize = DllCall("kernel32.dll", "dword", "SizeofResource", "int", $hInst, "int", $hFind[0])
    $hLoad = DllCall("kernel32.dll", "int", "LoadResource", "int", $hInst, "int", $hFind[0])
    $hLock = DllCall("kernel32.dll", "int", "LockResource", "int", $hLoad[0])
    $tRes = DllStructCreate("byte[" & $aSize[0] & "]", $hLock[0])
    $sHdr &= StringTrimLeft(DllStructGetData($tRes, 1), 2)
    $iOrd += 1
    Next
    _FreeLibrary($hInst)
    Dim $aINM[1]
    $FO = FileOpen($sOutIco, $iCrt)
    If $FO = -1 Then Return SetError(11, 0, 0)
    $FW = FileWrite($FO, $sHdr)
    If $FW = 0 Then Return SetError(12, 0, 0)
    FileClose($FO)
    Return SetError(0, 0, 1)
    EndFunc ;==>_ExtractIconToFile

    [/autoit] [autoit][/autoit] [autoit]

    ; Helper Functions beyond this point

    [/autoit] [autoit][/autoit] [autoit]

    Func LTHR($sNum)
    Return Hex(BitRotate($sNum, -8), 4)
    EndFunc ;==>LTHR

    [/autoit] [autoit][/autoit] [autoit]

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

    [/autoit] [autoit][/autoit] [autoit]

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

    [/autoit] [autoit][/autoit] [autoit]

    Func _StringSplitRegExp($sString, $sPattern, $sIncludeMatch = False, $iCount = 0)
    Local $sReservedPattern = Chr(0), $sTemp, $aResult
    Local $sReplacePattern = $sReservedPattern
    If $sIncludeMatch Then $sReplacePattern = "$0" & $sReplacePattern
    $sTemp = StringRegExpReplace($sString, $sPattern, $sReplacePattern, $iCount)
    If StringRight($sTemp, 1) = $sReservedPattern Then $sTemp = StringTrimRight($sTemp, 1)
    $aResult = StringSplit($sTemp, $sReservedPattern, 1)
    Return $aResult
    EndFunc ;==>_StringSplitRegExp

    [/autoit] [autoit][/autoit] [autoit]

    Func _ResourceEnumNames($hModule, $iType)
    Local $aRet, $IsPtr = IsPtr($hModule), $xCB
    If $IsPtr Then
    $xCB = DllCallbackRegister('___EnumResNameProc', 'int', 'int*;int*;int*;int*')
    MsgBox(0,0,"jetzt kommt der Fehler")
    $aRet = DllCall('kernel32.dll', 'int', 'EnumResourceNamesW', 'ptr', $hModule, 'int', $iType, 'ptr', DllCallbackGetPtr($xCB), 'ptr', 0) ;???????????????????????????????????????????
    MsgBox(0,0,"jetzt kommt der Fehler")
    DllCallbackFree($xCB)
    EndIf
    EndFunc ;==>_ResourceEnumNames

    [/autoit] [autoit][/autoit] [autoit]

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

    [/autoit]

    Bei dieser Zeile kommt der Fehler

    [autoit]

    $aRet = DllCall('kernel32.dll', 'int', 'EnumResourceNamesW', 'ptr', $hModule, 'int', $iType, 'ptr', DllCallbackGetPtr($xCB), 'ptr', 0)

    [/autoit]

    Hoffe ihr könnt mir helfen 8)

  • Um aus 32bit-Dateien die Icons zu extrahieren, musst du das Skript mit 32bit ausführen, für 64bit mit 64bit.

  • Ah, ok.
    Wenn es keine andere Möglichkeit gibt, dann muß ichs halt so machen.


    Du kannst die Resource-API wegwerfen und alles selbst schreiben, so wie der ResHacker denke ich. Ich könnte mich auch irren, aber so habe ich es in Erinnerung. Mein x64-System habe ich gerade nicht zur Verfügung.

  • Eine Idee habe ich. Eventuell liegt es am Callback, das sollte so aussehen:

    [autoit]

    $xCB = DllCallbackRegister('___EnumResNameProc', 'int', 'ptr;ptr;ptr;long_ptr')

    [/autoit]