Что нового

Cохранение иконки (HICON) в .ico файл

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
Данная функция позволяет сохранить одну или несколько иконок, представленных указателями (хендлами), в указанный .ico файл. Иконки должны быть 32-битные (RGB+Alpha). Если вы точно не знаете, какой глубины цвета иконки, используйте функцию _WinAPI_Create32BitHICON() для их конвертации. Для запуска этого примера вам понадобится WinAPIEx.au3.

Код:
#Include <WinAPIEx.au3>

Opt('MustDeclareVars', 1)

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

For $i = 0 To 2
	$aIcon[$i] = _WinAPI_Create32BitHICON(_WinAPI_ShellExtractIcon(@SystemDir & '\shell32.dll', 32, $aIcon[$i], $aIcon[$i]), 1)
Next
_WinAPI_SaveHICONToFile(@ScriptDir & '\MyIcon.ico', $aIcon)
For $i = 0 To 2
	_WinAPI_DestroyIcon($aIcon[$i])
Next

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

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', 40 + $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
 
Верх