Что нового

Можно ли с помощью функции _WinAPI_SaveHICONToFile скопировать иконку из файла

assch

Новичок
Сообщения
166
Репутация
4
В этом коде функция _WinAPI_SaveHICONToFile вытаскивает иконку которая забита в системе под расширение .dll
А можно ли с помощью этой же функции _WinAPI_SaveHICONToFile
вытащить (скопировать) любую иконку которая находится просто по адресу - @SystemDir & '\shell32.dll'




Код:
#Include <WinAPIEx.au3>

Local $Ras = ".dll"

Local $Flags = $SHGFI_ICON+ $SHGFI_LARGEICON + $SHGFI_SHELLICONSIZE + $SHGFI_USEFILEATTRIBUTES
Local $tSHFILEINFO = DllStructCreate($tagSHFILEINFO)

If Not _WinAPI_ShellGetFileInfo($Ras, $Flags, 0, $tSHFILEINFO) Then
		Return SetError(1, 0, 0)
EndIf
	
Dim $aIcon[2]
$aIcon[0] = DllStructGetData($tSHFILEINFO, 'hIcon')

_WinAPI_SaveHICONToFile("dll.ico", $aIcon)

_WinAPI_DestroyIcon($aIcon[0])



Func _WinAPI_SaveHICONToFile($sFile, $aIcon, $iStart = 0, $iEnd = -1)

    Local $Icon, $Count = 1

    If IsArray($aIcon) Then
        If UBound($aIcon, 2) Then
            Return SetError(2, 0, 0)
        EndIf
        If $iStart < 0 Then
            $iStart = 0
        EndIf
        If ($iEnd < 0) Or ($iEnd > UBound($aIcon) - 1) Then
            $iEnd = UBound($aIcon) - 1
        EndIf
        $Count = $iEnd - $iStart + 1
        If $Count < 1 Then
            Return SetError(1, 0, 0)
        EndIf
        Dim $Icon[$Count]
        For $i = 0 To $Count - 1
            $Icon[$i] = $aIcon[$iStart + $i]
        Next
    Else
        Dim $Icon[1] = [$aIcon]
    EndIf

    Local $hFile = _WinAPI_CreateFileEx($sFile, 2, 0x40000000, 0)

    If @error Then
        Return SetError(1, 0, 0)
    EndIf

    Local $tData, $W, $H, $Info, $Bytes, $Error, $Result = 0
    Local $tIco = DllStructCreate('ushort Reserved;ushort Type;ushort Count;byte Data[' & (16 * $Count) & ']')
    Local $Lenght = DllStructGetSize($tIco)
    Local $pIco = DllStructGetPtr($tIco)
    Local $tBI = DllStructCreate($tagBITMAPINFOHEADER)
    Local $pBI = DllStructGetPtr($tBI)
    Local $tDIB = DllStructCreate($tagDIBSECTION)
    Local $Size = DllStructGetSize($tDIB)
    Local $pDIB = DllStructGetPtr($tDIB)
    Local $Offset = $Lenght

    DllStructSetData($tIco, 'Reserved', 0)
    DllStructSetData($tIco, 'Type', 1)
    DllStructSetData($tIco, 'Count', $Count)

    DllStructSetData($tBI, 'biSize', 40)
    DllStructSetData($tBI, 'biPlanes', 1)
    DllStructSetData($tBI, 'biBitCount', 32)
    DllStructSetData($tBI, 'biCompression', 0)
    DllStructSetData($tBI, 'biXPelsPerMeter', 0)
    DllStructSetData($tBI, 'biYPelsPerMeter', 0)
    DllStructSetData($tBI, 'biClrUsed', 0)
    DllStructSetData($tBI, 'biClrImportant', 0)

    Do
        If Not _WinAPI_WriteFile($hFile, $pIco, $Lenght, $Bytes) Then
            ExitLoop
        EndIf
        For $i = 0 To $Count - 1
            $Info = _WinAPI_GetIconInfo($Icon[$i])
            If Not IsArray($Info) Then
                ExitLoop 2
            EndIf
            For $j = 4 To 5
                $Info[$j] = _WinAPI_CopyImage($Info[$j], 0, 0, 0, BitOR(0x2000, 0x0008))
                If _WinAPI_GetObject($Info[$j], $Size, $pDIB) Then
                    $Info[$j - 4] = DllStructGetData($tDIB, 'biSizeImage')
                    $Info[$j - 2] = DllStructGetData($tDIB, 'bmBits')
                Else
                    $Info[$j - 4] = 0
                    $Info[$j - 2] = 0
                EndIf
            Next
            $W = DllStructGetData($tDIB, 'bmWidth')
            $H = DllStructGetData($tDIB, 'bmHeight')
            $tData = DllStructCreate('byte Width;byte Height;byte Colors;byte Reserved;word Planes;word BPP;long Size;long Offset', $pIco + 6 + 16 * $i)
            DllStructSetData($tData, 'Width', $W)
            DllStructSetData($tData, 'Height', $H)
            DllStructSetData($tData, 'Colors', 0)
            DllStructSetData($tData, 'Reserved', 0)
            DllStructSetData($tData, 'Planes', 1)
            DllStructSetData($tData, 'BPP', 32)
            DllStructSetData($tData, 'Size', 48 + $Info[0] + $Info[1])
            DllStructSetData($tData, 'Offset', $Offset)
            DllStructSetData($tBI, 'biWidth', $W)
            DllStructSetData($tBI, 'biHeight', 2 * $H)
            DllStructSetData($tBI, 'biSizeImage', $Info[0] + $Info[1])
            $Offset += 40 + $Info[0] + $Info[1]
            Do
                $Error = 1
                If Not _WinAPI_WriteFile($hFile, $pBI, 40, $Bytes) Then
                    ExitLoop
                EndIf
                For $j = 1 To 0 Step -1
                    If Not _WinAPI_WriteFile($hFile, $Info[$j + 2], $Info[$j], $Bytes) Then
                        ExitLoop 2
                    EndIf
                Next
                $Error = 0
            Until 1
            For $j = 4 To 5
                _WinAPI_DeleteObject($Info[$j])
            Next
            If $Error Then
                ExitLoop 2
            EndIf
        Next
        _WinAPI_SetFilePointer($hFile, 0)
        If Not _WinAPI_WriteFile($hFile, $pIco, $Lenght, $Bytes) Then
            ExitLoop
        EndIf
        $Result = 1
    Until 1
    _WinAPI_CloseHandle($hFile)
    If Not $Result Then
        FileDelete($sFile)
    EndIf
    Return SetError(Number(Not $Result), 0, $Result)

EndFunc ;==>_WinAPI_SaveHICONToFile

; #FUNCTION# ====================================================================================================================
; Name...........: _WinAPI_SaveHICONToFile
; Description....: Saves a 32 bits-per-pixel single or multiple icon (HICON) to the specified icon (.ico) file.
; Syntax.........: _WinAPI_SaveHICONToFile ( $sFile, $aIcon [, $iStart [, $iEnd]] )
; Parameters.....: $sFile  - The name of the icon file.
;                  $aIcon  - Handle to the icon or array of the icon handles to be save.
;                  $iStart - The index of array to start saving at.
;                  $iEnd   - The index of array to stop saving at.
; Return values..: Success - 1.
;                  Failure - 0 and sets the @error flag to non-zero.
; Author.........: Yashied
; Modified.......:
; Remarks........: This function only works with 32 bits-per-pixel (RGB + Alpha) icons. If you do not know exactly which color
;                  depth is there an icon, use the _WinAPI_Create32BitHICON() function to convert its.
; Related........:
; Link...........: None
; Example........: Yes
; ===============================================================================================================================
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
assch,
Посмотрите _WinAPI_LoadShell32Icon().
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Я так понимаю функция _WinAPI_LoadShell32Icon() вернула какое то значение указанной иконки.
А какой дальнейший алгоритм действий?
Как вытащить (скопировать) саму иконку?
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Я так понимаю приспособить функцию _WinAPI_SaveHICONToFile
для копирования иконок не получится
По этому тема закрывается
Всем спасибо
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
assch
Поковыряй это Icon_of_folder, там реализовано. И вроде я уже предлагаю второй раз это сделать...
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Функция _WinAPI_LoadShell32Icon(), как впрочем и _WinAPI_ShellExtractIcon(), загружает иконку в память и возвращает ее (иконки) указатель. Вот именно его (или массив из указателей для разных размеров иконок) и нужно подставлять в функцию _WinAPI_SaveHICONToFile(). В данном примере я сохраняю 3 иконки с размерами 16x16, 32x32 и 48x48.

Код:
#Include <WinAPIEx.au3>

Dim $aIcon[3] = [16, 32, 48]

For $i = 0 To 2
	$aIcon[$i] = _WinAPI_ShellExtractIcon(@SystemDir & '\shell32.dll', 3, $aIcon[$i], $aIcon[$i])
Next
_WinAPI_SaveHICONToFile(@ScriptDir & '\3.ico', $aIcon)
For $i = 0 To 2
	_WinAPI_DestroyIcon($aIcon[$i])
Next
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Yashied
К сожелению это решение у меня не работает
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
И почему же?
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Иконка появляется пустая
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Я только что попробывал на Windows 7 и XP. Все отлично работает. Ищи проблему у себя. Попробуй еще так:

Код:
#Include <WinAPIEx.au3>

Dim $aIcon[3] = [16, 32, 48]

For $i = 0 To 2
    $aIcon[$i] = _WinAPI_Create32BitHICON(_WinAPI_ShellExtractIcon(@SystemDir & '\shell32.dll', 3, $aIcon[$i], $aIcon[$i]), 1)
Next
_WinAPI_SaveHICONToFile(@ScriptDir & '\3.ico', $aIcon)
For $i = 0 To 2
    _WinAPI_DestroyIcon($aIcon[$i])
Next
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Вышли мне свой код
только полный код ,вместе с функцией _WinAPI_SaveHICONToFile
А то может быть эта функция у нас отличается
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Функцию я скопировал из твоего первого поста. А система какая? 32 или 64?
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Удивительно но ни тот ни другой не срабатывает
У меня обычная XP 32
Попробую покопать
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
assch
У меня работает на XP SP3 32.
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Кажется наладил
вместо Dim $aIcon[3] = [16, 32, 48]

пришлось убрать [16, 32, 48]

стало просто Dim $aIcon[3]

И заработало
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
assch

А причем здесь 2.exe? Ты вообще спрашивал про shell32.dll... Что это за манера такая, спрашивать про одно, а писать про другое...
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Прошу прощения
Посты убрал
shell32.dll я привёл просто как пример в широком смысле меня интересуют все файлы
содержащие иконки "exe, dll, cpl, icl, ocx"
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Я вчера нашёл два кода которые вытаскивают иконки из файлов.

Код первый:


Код:
#include <WinAPI.au3>

Global $AEN[1]

$EIGH = _Exticongrouphdr(@SystemDir & '\shell32.dll', 131)

$EID = _Exticondata($EIGH)

_Createiconfile($EID, -1, "2.ico")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Func _Exticongrouphdr($SINFILE, $IICON)
	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
	Return $ARET
EndFunc   ;==>_Exticongrouphdr

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Func _Resourceenumnames($HMODULE, $ITYPE)
	Local $ARET, $XCB
	If Not IsPtr($HMODULE) Then Return SetError(1, 0, 0)
	$XCB = DllCallbackRegister("___EnumResNameProc", "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 ___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 $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   ;==>___EnumResNameProc

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Func _Freeresource($HGLBRESOURCE)
	Local $AFR = DllCall("kernel32.dll", "int", "FreeResource", "int", $HGLBRESOURCE)
EndFunc   ;==>_Freeresource

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Func _Exticondata($AID)
	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)
	Return $ARET
EndFunc   ;==>_Exticondata

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

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   ;==>_Geticondata

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

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   ;==>_Rb

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Func _Createiconfile($AID, $ASEL, $SOUTICO, $IPATH = 0)
	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
		Local $ASKPNG = MsgBox(4, "Detected single extract of PNG icon", "Would you like to save this icon as a PNG file instead?" & @CRLF & @CRLF & "Click Yes to save as .png file." & @CRLF & "Click No to save as .ico file", 0, $HGUI)
		If $ASKPNG = 6 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   ;==>_Createiconfile

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Код второй:

Код:
Global $aSad[1]

_FileExtractIcon(@SystemDir & '\shell32.dll', 131, "1.ico")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

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 $aSad[0]
		If $i = StringReplace($iIcon, "-", "") Then
			$iGN = $aSad[$i]
			ExitLoop
		EndIf
	Next
	Dim $aSad[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 _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

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

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

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Они вытаскивают иконки из "exe , dll ,cpl ,ocx" но почему то с форматом "icl" (в большенстве случаев не работают)
В принципи есть обходной манёвр. Сначала перегоняется в "png" потом в иконку.

Код третий:

Код:
#include <GDIPlus.au3>

Simple(@SystemDir & '\shell32.dll',"3.png", 2)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Func Simple($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, "{557CF406-1A04-11D3-9A73-0000F81EF32E}")
	_GDIPlus_ImageDispose($pBitmap)
	
	_GDIPlus_Shutdown()
	
	_ImageConvertToIco("3.png", "33.ico", 32, 32)
     FileDelete("3.png")
	Return 1
Endfunc

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Func _ImageConvertToIco($sImageFile, $sOutIconFile, $iWidth = -1, $iHeight = -1)
    Local $hImage, $hThumb, $HICON
   
    ; Start GDIPlus
    _GDIPlus_Startup()
   
    ; Load image
    $hImage = _GDIPlus_ImageLoadFromFile($sImageFile)
   
    If $iWidth = -1 Then
        $iWidth = _GDIPlus_ImageGetWidth($hImage)
    EndIf
   
    If $iHeight = -1 Then
        $iHeight = _GDIPlus_ImageGetHeight($hImage)
    EndIf
   
    ; Get Thumbnail (resize the image)
    $hThumb = __GDIPlus_ImageGetThumbnail($hImage, $iWidth, $iHeight)
   
    ; create a HICON from the image
    $HICON = __GDIPlus_BitmapCreateHICONFromBitmap($hThumb)
   
    ;Clean up and shutdown GDIPlus
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_ImageDispose($hThumb)
    _GDIPlus_Shutdown()
   
    ; create an ico file from the image
    __CreateIconFileFromHICON($HICON, $sOutIconFile)
   
    ; Destroy the HICON now I've finished with it.
    _WinAPI_DestroyIcon($HICON)
EndFunc ;==>_ImageConvertToIco

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Func __GDIPlus_ImageGetThumbnail($hImage, $iWidth, $iHeight)
    Local $aResult = DllCall($ghGDIPDll, 'uint', 'GdipGetImageThumbnail', 'ptr', $hImage, 'uint', $iWidth, 'uint', $iHeight, 'ptr*', 0, 'ptr', 0, 'ptr', 0)
    If @error Then
        Return SetError(1, 0, 0)
    Else
        If $aResult[0] Then
            Return SetError($aResult[0], 0, 0)
        EndIf
    EndIf
    Return $aResult[4]
EndFunc   ;==>_GDIPlus_ImageGetThumbnail

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Func __GDIPlus_BitmapCreateHICONFromBitmap($hBitmap)
    Local $HICON = DllCall($ghGDIPDll, "int", "GdipCreateHICONFromBitmap", "hwnd", $hBitmap, "int*", 0)
    If @error Then
        Return SetError(@error, 0, -1)
    EndIf
    Return SetError($HICON[0], 0, $HICON[2])
EndFunc   ;==>_GDIPlus_BitmapCreateHICONFromBitmap

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Func __CreateIconFileFromHICON($HICON, $sOutIcon)
    Local $aInfo, $sIco, $sBmp, $hCDC, $tBI, $tBits, $iSz, $sBD, $FO
    ; Start of single icon Header 3 x 2 bytes = 6 bytes: 0000 Reserved / 0100 icon / 0100 Numer of icons, total length will be 22 bytes for a single icon when finished
    $sIco = "0x000001000100"
    ; Start of the Bitmap data header 1 x 4bytes: length of the header will be 40 bytes when finished. Will be appended to the end of the icon header when finished
    $sBmp = "28000000"
    ; Get info about the HICON, this is mainly to get the pointers to the Color/Mask bitmaps data
    $aInfo = _WinAPI_GetIconInfo($HICON)
    ; create a memory Compatable DC
    $hCDC = _WinAPI_CreateCompatibleDC(0)
    ; create a BITMAPINFO Struct to store the Bitmap Info, it needs to be inilialized by setting the struct size.
    $tBI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBI, "Size", DllStructGetSize($tBI))
    ; Pass a bitmap data pointer to the BITMAPINFO struct so we can recieve the details of the color bitmap data, we use it to write the headers
    _WinAPI_GetDIBits($hCDC, $aInfo[5], 0, 0, 0, DllStructGetPtr($tBI), 0)
    ; Now we have some the basic info to add to the icon & Bitmap header so we'll add that to the headers.
    $sIco &= Hex(DllStructGetData($tBI, "Width"), 2) & Hex(DllStructGetData($tBI, "Height"), 2) & "00000100" & _
        __StringReverseBytes(Hex(DllStructGetData($tBI, "BitCount"), 4))
    $sBmp &= __StringReverseBytes(Hex(DllStructGetData($tBI, "Width"))) & __StringReverseBytes(Hex(DllStructGetData($tBI, "Height") * 2)) & "0100" & _
        __StringReverseBytes(Hex(DllStructGetData($tBI, "BitCount"), 4)) & "00000000"
    ; Get the size of the Bitmap data from the BITMAPINFO Struct, we'll use this in the headers further on.
    $iSz = DllStructGetData($tBI, "SizeImage")
    ; create a struct to store the Bitmap data Bits of the first bitmap, reset the BITMAPINFO struct
    $tBits = DllStructCreate("byte[" & DllStructGetData($tBI, "SizeImage") & "]")
    ; Get the color bitmap dib bits into the $tBits struct.
    DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $aInfo[5], 'int', $iSz, 'ptr', DllStructGetPtr($tBits))
    ; Get GetBitmapBits returns Bottom to Top dib, so I turn it to Top to Bottom dib ;)
    ; ATM I'm only assuming that GetBitmapBits returns a Bottom to Top dib, maybe the bitmap bits you use could be Top Down already?.
    For $i = DllStructGetData($tBI, "SizeImage") + 1 To 0 Step -(DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))
        $sBD &= StringTrimLeft(BinaryMid(DllStructGetData($tBits, 1), $i, (DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))), 2)
    Next
    ;Clear the BITMAPINFO & $tBits Struct as we'll use the same variables again for the mask bitmap data
    $tBits = 0
    $tBI = 0
    ; create a BITMAPINFO Struct to store the Bitmap Info again, it needs to be inilialized by setting the struct size.
    $tBI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBI, "Size", DllStructGetSize($tBI))
    ; Pass a bitmap data pointer to the BITMAPINFO struct so we can recieve the details of the bitmask bitmap data
    _WinAPI_GetDIBits($hCDC, $aInfo[4], 0, 0, 0, DllStructGetPtr($tBI), 0)
    ; We've finished with the Compatable DC, delete it.
    _WinAPI_DeleteDC($hCDC)
    ; Add the size of the of the color + bitmask bitmap data as we need this for both the icon & Bitmap header
    $iSz += DllStructGetData($tBI, "SizeImage")
    ; combine the bitmap data size with the bitmap header, I'm padding the rest of the 40 byte bitmap header with 0's., that's the Bitmap header done
    $sBmp &= __StringReverseBytes(Hex($iSz)) & "00000000000000000000000000000000"
    ; Now add the size of the Bitmap data + bitmap header size and combine the icon header together with the bitmap header and color bitmap data
    $sIco &= __StringReverseBytes(Hex($iSz + 40)) & __StringReverseBytes(Hex("22")) & $sBmp & $sBD
    ; create a struct to store the Bitmap dib Bits of the mask bitmap
    $tBits = DllStructCreate("byte[" & DllStructGetData($tBI, "SizeImage") & "]")
    ; Get the mask bitmap dib bits into the $tBits struct.
    DllCall('gdi32.dll', 'int', 'GetBitmapBits', 'ptr', $aInfo[4], 'int', DllStructGetData($tBI, "SizeImage"), 'ptr', DllStructGetPtr($tBits))
    ; Get GetBitmapBits returns Bottom to Top dib, so I turn it to a Top to Bottom dib and append the mask bitmap data to the icon
    For $i = DllStructGetData($tBI, "SizeImage") + 1 To 0 Step -(DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))
        $sIco &= StringTrimLeft(BinaryMid(DllStructGetData($tBits, 1), $i, (DllStructGetData($tBI, "SizeImage") / DllStructGetData($tBI, "Height"))), 2)
    Next
    ; Write the icon to a file.
    $FO = FileOpen($sOutIcon, 18)
    FileWrite($sOutIcon, Binary($sIco))
    FileClose($FO)
    ; Clear the structs
    $tBits = 0
    $tBI = 0
EndFunc   ;==>_CreateIconFileFromHICON

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

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

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Но это шаманство
Кто нибудь знает почему с форматом "icl" у этих двух первых кодов такие проблемы?
Поэтому я искал универсальный способ для всех форматов.
Функция с _WinAPI_SaveHICONToFile в принципи хорошая ,она одинаково работает со всеми форматами.
Только вот как назло попался один экзешник из которого эта функция первую (основную) иконку вытащила не корректно
(сильно смазана и нет некоторых элементов рисунка)
интересно то что в этом экзешнике есть вторая иконка (она точно такая же только у первой белый фон а у второй жёлтый)
так вот её функция вытащила хорошо. Кстати первые два кода у которых проблемы с "icl" с именно этим экзешником
вообще не работают. Вытащить (относительно) коректно из этого экзешника иконку у меня получается только обходным манёвром
(перегонкой в "png" потом в иконку). Правда способ с перегонкой в "png" потом в иконку
не всегда нормально выводит иконки из других форматов.
(но как ни странно с проблемным (для первых двух кодов) "icl" и с этим проблемным экзешником этот способ работает вполне сносно)


В примере с _WinAPI_SaveHICONToFile было написано что можно сохранить иконки разных размеров (16x16,32x32,48x48)
А как именно это сделать (например вытащить иконку только 48х48)?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Прочитай еще раз очень внимательно этот ответ. А по поводу "некорректной иконки", так она не 32-битная, и, соответственно, ее нужно перевести в 32-битную. См. предыдущий мой ответ.
 
Автор
A

assch

Новичок
Сообщения
166
Репутация
4
Спасибо
Не уверен что пойму но попробую почитать внимательно
 
Верх