Что нового

Замена значка в exe файле по его идентификатору (индексу)

_script_

Новичок
Сообщения
3
Репутация
0
День добрый. Стоит следущая задача - заменить иконку требуемого индекса (идентификатора) на другую имеющуюся иконку средствами AutoIt, без использования редакторов ресурсов и Wrapper'а:

http://autoit-script.ru/index.php?action=downloads;sa=downfile&id=516
http://autoit-script.ru/index.php?action=downloads;sa=downfile&id=517

Я пробовал выполнить замену бинарных данных найденной иконки бинарными данными имеющейся, но ничего не вышло :(.

Есть код, позволяющий извлекать значок произвольного индекса (взято отсюда forum.oszone.net/nextnewesttothread-179923.html):

Код:
#NoTrayIcon

_ExtractIcon("notepad.exe", 1, @DesktopCommonDir & "\notepad.ico")

Func _ExtractIcon($sFileInput, $iIndex, $sFileOutput)
   Local $hInst, $aResNames, $iGroupName = 0, $IconData, $iID, $aData, $sHDR, $iOffset, $iMIcon, $hFileOpen
   Global $__g_vEnum

   $hInst = DllCall("kernel32.dll", "handle", "LoadLibraryExW", "wstr", $sFileInput, "ptr", 0, "dword", 2)
   If $hInst[0] = 0 Then
	  Return SetError(-1, 0, "")
   EndIf

   $aResNames = _WinAPI_EnumResourceNames($hInst[0], 14)
   If @error Then
	  DllCall("kernel32.dll", "bool", "FreeLibrary", "handle", $hInst[0])
	  Return SetError(-2, 0, "")
   EndIf
   For $i = 1 To $aResNames[0]
	  If $i = $iIndex Then
		 $iGroupName = $aResNames[$i]
		 ExitLoop
	  EndIf
   Next
   If $iGroupName = 0 Then
	  DllCall("kernel32.dll", "bool", "FreeLibrary", "handle", $hInst[0])
	  Return SetError(-3, 0, "")
   EndIf

   $IconData = __IconData($hInst[0], 14, $iGroupName)
   If Not $IconData Then
	  DllCall("kernel32.dll", "bool", "FreeLibrary", "handle", $hInst[0])
	  Return SetError(-4, 0, "")
   EndIf
   $iID = Dec(__Rb(StringMid($IconData, 11, 4)))
   $aData = StringRegExp(StringTrimLeft(BinaryMid($IconData, 7), 2), "(.{28})", 3)

   Local $aIcon[$iID][2]
   DllCall("kernel32.dll", "bool", "FreeLibrary", "handle", $hInst[0])
   $hInst = DllCall("kernel32.dll", "handle", "LoadLibraryExW", "wstr", $sFileInput, "ptr", 0, "dword", 2)
   For $i = 0 To $iID-1
	  $IconData = __IconData($hInst[0], 3, Dec(__Rb(StringRight($aData[$i], 4))))
	  If Not $IconData Then
		 DllCall("kernel32.dll", "bool", "FreeLibrary", "handle", $hInst[0])
		 Return SetError(-4, 0, "")
	  EndIf
	  $aIcon[$i][0] = StringTrimRight($aData[$i], 4)
	  $aIcon[$i][1] = $IconData
   Next
   DllCall("kernel32.dll", "bool", "FreeLibrary", "handle", $hInst[0])

   $sHDR = "0x00000100" & __Rb(Hex($iID, 4))
   $iOffset = 16*$iID+6
   For $i = 0 To $iID-1
	  $sHDR = $sHDR & $aIcon[$i][0] & __Rb(Hex($iOffset))
	  $iOffset = $iOffset+Dec(__Rb(StringMid($aIcon[$i][0], 17, 8)))
	  $iMIcon = $iMIcon & StringTrimLeft($aIcon[$i][1], 2)
   Next

   $hFileOpen = FileOpen($sFileOutput, 2+8+16)
   If Not FileWrite($hFileOpen, $sHDR & $iMIcon) Then
	  FileClose($hFileOpen)
	  Return SetError(-5, 0, "")
   EndIf
   FileClose($hFileOpen)

   Return True
EndFunc

Func _WinAPI_EnumResourceNames($hModule, $sType)
   Local $aRet, $hEnumProc
   Dim $__g_vEnum[101] = [0]
   $hEnumProc = DllCallbackRegister("__EnumResNamesProc", "bool", "handle;ptr;ptr;long_ptr")
   $aRet = DllCall("kernel32.dll", "bool", "EnumResourceNamesW", "handle", $hModule, "int", $sType, _
		 "ptr", DllCallbackGetPtr($hEnumProc), "long_ptr", 0)
   If @error Or Not $aRet[0] Or Not $__g_vEnum[0] Then $__g_vEnum = @error + 10
   DllCallbackFree($hEnumProc)
   If $__g_vEnum Then Return SetError($__g_vEnum, 0, 0)

   __Inc($__g_vEnum, -1)
   Return $__g_vEnum
EndFunc

Func __EnumResNamesProc($hModule, $iType, $iName, $lParam)
   #forceref $hModule, $iType, $lParam

   Local $iLength = _WinAPI_StrLen($iName)
   __Inc($__g_vEnum)
   If $iLength Then
	  $__g_vEnum[$__g_vEnum[0]] = DllStructGetData(DllStructCreate("wchar[" & ($iLength + 1) & "]", $iName), 1)
   Else
	  $__g_vEnum[$__g_vEnum[0]] = Number($iName)
   EndIf
   Return 1
EndFunc

Func _WinAPI_StrLen($pString)
   Local $aRet = DllCall("kernel32.dll", "int", "lstrlenW", "ptr", $pString)
   If @error Then Return SetError(@error, @extended, 0)

   Return $aRet[0]
EndFunc

Func __Inc(ByRef $aData, $iIncrement = 100)
   Select
	  Case UBound($aData, 2)
		 If $iIncrement < 0 Then
			ReDim $aData[$aData[0][0] + 1][UBound($aData, 2)]
		 Else
			$aData[0][0] += 1
			If $aData[0][0] > UBound($aData) - 1 Then
			   ReDim $aData[$aData[0][0] + $iIncrement][UBound($aData, 2)]
			EndIf
		 EndIf
	  Case UBound($aData, 1)
		 If $iIncrement < 0 Then
			ReDim $aData[$aData[0] + 1]
		 Else
			$aData[0] += 1
			If $aData[0] > UBound($aData) - 1 Then
			   ReDim $aData[$aData[0] + $iIncrement]
			EndIf
		 EndIf
	  Case Else
		 Return 0
   EndSelect
   Return 1
EndFunc

Func __IconData($hInstance, $sType, $sName)
   Local $hResource, $hData, $pData, $iSize, $tResource, $tData

   $hResource = DllCall("kernel32.dll", "handle", "FindResourceA", "handle", $hInstance, "int", $sName, "int", $sType)
   If @error Then Return SetError(@error, @extended, 0)

   $iSize = DllCall("kernel32.dll", "dword", "SizeofResource", "handle", $hInstance, "handle", $hResource[0])
   If @error Then Return SetError(@error, @extended, 0)

   $hData = DllCall("kernel32.dll", "handle", "LoadResource", "handle", $hInstance, "handle", $hResource[0])
   If @error Then Return SetError(@error, @extended, 0)

   $pData = DllCall("kernel32.dll", "ptr", "LockResource", "handle", $hData[0])
   If @error Then Return SetError(@error, @extended, 0)

   $tResource = DllStructCreate("byte[" & $iSize[0] & "]", $pData[0])
   $tData = DllStructGetData($tResource, 1)

   Return $tData
EndFunc

Func __Rb($sBYTE)
   Local $AX = StringRegExp($SBYTE, "(.{2})", 3), $SX = ""
   For $i = UBound($AX) - 1 To 0 Step -1
	  $SX = $SX & $AX[$i]
   Next
   Return $SX
EndFunc


Может его удастся как-то модифицировать для решения поставленной задачи?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Если необходимо изменить ресурсы .exe файла, то я советую использовать командную строку Resource Hacker'а.
 
Автор
S

_script_

Новичок
Сообщения
3
Репутация
0
Yashied сказал(а):
Если необходимо изменить ресурсы .exe файла, то я советую использовать командную строку Resource Hacker'а.

Я знаю про Resource Hacker, но это не совсем то что нужно. Хочется выполнить замену значка именно с помощью Autoit'а. Если с помощью Autoit'а удается извлечь иконку, то думается и с заменой не должно быть никаких проблем. Или замена значка принципиально иная операция, не доступная Autoit'у?

Простая операция замены бинарных данных, а-ля StringReplace(), не приводит к желаемому результату, а других идей не возникает :(.

Посоветуйте хотя бы какую-нибудь литературу, где можно почерпнуть необходимые сведения.

P.S. Хотя Resource Hacker и не написан на Autoit (скорее всего, исходников в сети что-то не видно), он как-то справляется с заменой
ресурса.
 

Prog

Продвинутый
Сообщения
537
Репутация
65
_script_ [?]
Посоветуйте хотя бы какую-нибудь литературу, где можно почерпнуть необходимые сведения.
Изучайте. http://purebasic.ucoz.ru/publ/uchebnye_materialy/start/zamena_znachkov_v_ispolnjaemom_fajle/4-1-0-6
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
_script_ сказал(а):
Или замена значка принципиально иная операция, не доступная Autoit'у?
Я вам дал самый оптимальный способ, но если не устраивает, то курите пиример к функции _WinAPI_UpdateResource(). Тупо заменить бинарные данные одной иконки на другую нельзя, т.к. иконка в ресурсах находится в виде .bmp, а не .ico.




Добавлено:
Сообщение автоматически объединено:

Prog, большая к вам просьба, т.к. этот форум посвящен AutoIt, то выкладывайте решения на AutoIt, а не на другом ЯП, особенно в этом разделе.
 
Автор
S

_script_

Новичок
Сообщения
3
Репутация
0
Спасибо, Yashied! Пример в английской справке к функции _WinAPI_UpdateResource() ровно то, что нужно и даже больше. :beer:
 

Prog

Продвинутый
Сообщения
537
Репутация
65
OffTopic:
Yashied [?]
большая к вам просьба, т.к. этот форум посвящен AutoIt, то выкладывайте решения на AutoIt
Автор темы попросил дать хоть что-то, я и дал. :smile: Лучше было вообще ничего не давать? :whistle:
 
Верх