; This code is based on Ahk2Exe's IconChanger.ahk
; This code is based on Ahk2Exe's changeicon.cpp

DeleteIcons(_module, _IconID, _LangID, _ExeFile)
{
	global _EI_HighestIconID
	ids := EnumIcons(_ExeFile, _IconID)
	if !IsObject(ids)
		return False
	
	; Delete all the images
	Loop, % ids._MaxIndex()
		DllCall("UpdateResource", Ptr, _module, Ptr, 3, Ptr, ids[A_Index], UInt, _LangID, Ptr, 0, UInt, 0, UInt)
	DllCall("UpdateResource", Ptr, _module, Ptr, 14, Ptr, _IconID, UInt, _LangID, Ptr, 0, UInt, 0, UInt)
	return True
}

ReplaceIcons(_module, _IcoFile, _IconID, _LangID, _ExeFile)
{
	global _EI_HighestIconID
	ids := EnumIcons(_ExeFile, _IconID)
	if !IsObject(ids)
		return false
	
	f := FileOpen(_IcoFile, "r")
	if !IsObject(f)
		return false
	
	VarSetCapacity(igh, 8), f.RawRead(igh, 6)
	if NumGet(igh, 0, "UShort") != 0 || NumGet(igh, 2, "UShort") != 1
		return false
	
	wCount := NumGet(igh, 4, "UShort")
	
	VarSetCapacity(rsrcIconGroup, rsrcIconGroupSize := 6 + wCount*14)
	NumPut(NumGet(igh, "Int64"), rsrcIconGroup, "Int64") ; fast copy
	
	ige := &rsrcIconGroup + 6
	
	; Delete all the images
	Loop, % ids._MaxIndex()
		DllCall("UpdateResource", Ptr, _module, Ptr, 3, Ptr, ids[A_Index], UInt, _LangID, Ptr, 0, UInt, 0, UInt)
	
	Loop, %wCount%
	{
		thisID := ids[A_Index]
		if !thisID
			thisID := ++ _EI_HighestIconID
		
		f.RawRead(ige+0, 12) ; read all but the offset
		NumPut(thisID, ige+12, "UShort")
		
		imgOffset := f.ReadUInt()
		oldPos := f.Pos
		f.Pos := imgOffset
		
		VarSetCapacity(iconData, iconDataSize := NumGet(ige+8, "UInt"))
		f.RawRead(iconData, iconDataSize)
		f.Pos := oldPos
		
		DllCall("UpdateResource", Ptr, _module, Ptr, 3, Ptr, thisID, UInt, _LangID, Ptr, &iconData, UInt, iconDataSize, UInt)
		
		ige += 14
	}
	
	DllCall("UpdateResource", Ptr, _module, Ptr, 14, Ptr, _IconID, UInt, _LangID, Ptr, &rsrcIconGroup, UInt, rsrcIconGroupSize, UInt)
	return true
}

EnumIcons(_ExeFile, _IconID)
{
	; RT_GROUP_ICON = 14
	global _EI_HighestIconID
	static pEnumFunc := RegisterCallback("EnumIcons_Enum")
	
	hModule := DllCall("LoadLibraryEx", Str, _ExeFile, Ptr, 0, Ptr, 2, Ptr)
	if !hModule
		return
	
	_EI_HighestIconID := 0
	if DllCall("EnumResourceNames", Ptr, hModule, Ptr, 3, Ptr, pEnumFunc, UInt, 0) = 0
	{
		DllCall("FreeLibrary", Ptr, hModule)
		return
	}
	
	pDirHeader := DllCall("LockResource", Ptr, DllCall("LoadResource", Ptr, hModule, Ptr, DllCall("FindResource", Ptr, hModule, Ptr, _IconID, Ptr, 14, Ptr), Ptr), Ptr)
	pResDir := pDirHeader + 6
	
	wCount := NumGet(pDirHeader+4, "UShort")
	iconIDs := []
	
	Loop, %wCount%
	{
		pResDirEntry := pResDir + (A_Index-1)*14
		iconIDs[A_Index] := NumGet(pResDirEntry+12, "UShort")
	}
	
	DllCall("FreeLibrary", Ptr, hModule)
	return iconIDs
}

EnumIcons_Enum(hModule, type, name, lParam)
{
	; RT_ICON = 3
	global _EI_HighestIconID
	_EI_HighestIconID := ( ( name > _EI_HighestIconID ) ? name : _EI_HighestIconID )
	return True
}