ChangeVersionInfo() and VersionRes class standalone usage

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
gwarble
Posts: 524
Joined: 30 Sep 2013, 15:01

ChangeVersionInfo() and VersionRes class standalone usage

24 Sep 2018, 19:05

Hey all,

I'm trying to use ChangeVersionInfo() and VersionRes class, from HotkeyIt's rewrite of ahk2exe iirc, to create a standalone function to edit the VersionInfo of another PE binary, but haven't been successful in creating the verInfo object parameter to send to the function.

I've made some mod's to ChangeVersionInfo() to remove dependencies on other parts of ahk2exe, but I'm a total amateur with objects/classes so I was hoping one of you experts could help me out. Basically the goal would be to read the VersionInfo from a PE binary (AutoHotkeySC.bin specifically, or any compiled script), modify one or all of the values and/or add in missing values, and write it back to the resources of the binary.

Anyone done this or willing to point me in the right direction?
Thanks

Code: Select all

;ChangeVersionInfo.ahk
ChangeVersionInfo(ExeFile, hUpdate, verInfo)
{
	hModule := LoadLibraryEx(ExeFile, 0, 2)
	if !hModule
		Util_Error("Error: Error opening destination file.")
	
	hRsrc := DllCall("FindResource", "PTR", hModule, "PTR", 1, "PTR", 16) ; Version Info\1
	hMem := LoadResource(hModule, hRsrc)
	vi := new VersionRes(LockResource(hMem))
	FreeLibrary(hModule)
	
	ffi := vi.GetDataAddr()
	props := SafeGetViChild(SafeGetViChild(vi, "StringFileInfo"), "040904b0")
	for k,v in verInfo
	{
		if IsLabel(lbl := "_VerInfo_" k)
			gosub %lbl%
		continue
		_VerInfo_Name:
		SafeGetViChild(props, "ProductName").SetText(v)
		SafeGetViChild(props, "InternalName").SetText(v)
		return
		_VerInfo_Description:
		SafeGetViChild(props, "FileDescription").SetText(v)
		return
		_VerInfo_Version:
		SafeGetViChild(props, "FileVersion").SetText(v)
		SafeGetViChild(props, "ProductVersion").SetText(v)
		ver := VersionTextToNumber(v)
		hiPart := (ver >> 32)&0xFFFFFFFF, loPart := ver & 0xFFFFFFFF
		NumPut(hiPart, ffi+8, "UInt"), NumPut(loPart, ffi+12, "UInt")
		NumPut(hiPart, ffi+16, "UInt"), NumPut(loPart, ffi+20, "UInt")
		return
		_VerInfo_Copyright:
		SafeGetViChild(props, "LegalCopyright").SetText(v)
		return
		_VerInfo_OrigFilename:
		SafeGetViChild(props, "OriginalFilename").SetText(v)
		return
		_VerInfo_CompanyName:
		SafeGetViChild(props, "CompanyName").SetText(v)
		return
	}
	
	VarSetCapacity(newVI, 16384) ; Should be enough
	viSize := vi.Save(&newVI)
	if !DllCall("UpdateResource", "ptr", hUpdate, "ptr", 16, "ptr", 1
	          , "ushort", 0x409, "ptr", &newVI, "uint", viSize, "uint")
		Util_Error("Error changing the version information.")
}

VersionTextToNumber(v)
{
	r := 0, i := 0
	while i < 4 && RegExMatch(v, "O)^(\d+).?", o)
	{
		StringTrimLeft, v, v, % o.Len
		val := o[1] + 0
		r |= (val&0xFFFF) << ((3-i)*16)
		i ++
	}
	return r
}

SafeGetViChild(vi, name)
{
	c := vi.GetChild(name)
	if !c
	{
		c := new VersionRes()
		c.Name := name
		vi.AddChild(c)
	}
	return c
}

Util_ObjIsEmpty(obj)
{
	for _,__ in obj
		return false
	return true
}
#Include <VersionRes>

Code: Select all

;VersionRes.ahk
class VersionRes
{
	Name := ""
	,Data := ""
	,IsText := true
	,DataSize := 0
	,Children := []
	
	__New(addr := 0)
	{
		if !addr
			return this
		
		wLength := NumGet(addr+0, "UShort"), addrLimit := addr + wLength, addr += 2
		,wValueLength := NumGet(addr+0, "UShort"), addr += 2
		,wType := NumGet(addr+0, "UShort"), addr += 2
		,szKey := StrGet(addr, "UTF-16"), addr += 2*(StrLen(szKey)+1), addr := (addr+3)&~3
		,ObjSetCapacity(this, "Data", size := wValueLength*(wType+1))
		,this.Name := szKey
		,this.DataSize := wValueLength
		,this.IsText := wType
		,DllCall("msvcrt\memcpy", "ptr", this.GetDataAddr(), "ptr", addr, "ptr", size, "cdecl"), addr += size, addr := (addr+3)&~3
		; if wType
			; ObjSetCapacity(this, "Data", -1)
		while addr < addrLimit
		{
			size := (NumGet(addr+0, "UShort") + 3) & ~3
			,this.Children.Insert(new VersionRes(addr))
			,addr += size
		}
	}
	
	_NewEnum()
	{
		return this.Children._NewEnum()
	}
	
	AddChild(node)
	{
		this.Children.Insert(node)
	}
	
	GetChild(name)
	{
		for k,v in this
			if v.Name = name
				return v
	}
	
	GetText()
	{
		if this.IsText
			return this.Data
	}
	
	SetText(txt)
	{
		if A_IsUnicode
			this.Data := txt
		else
			ObjSetCapacity(this,"Data",StrLen(txt)*2+2),StrPut(txt,this.GetDataAddr(),"UTF-16")
		this.IsText := true
		,this.DataSize := StrLen(txt)+1
	}
	
	GetDataAddr()
	{
		return ObjGetAddress(this, "Data")
	}
	
	Save(addr)
	{
		orgAddr := addr
		,addr += 2
		,NumPut(ds:=this.DataSize, addr+0, "UShort"), addr += 2
		,NumPut(it:=this.IsText, addr+0, "UShort"), addr += 2
		,addr += 2*StrPut(this.Name, addr+0, "UTF-16")
		,addr := (addr+3)&~3
		,realSize := ds*(it+1)
		,DllCall("msvcrt\memcpy", "ptr", addr, "ptr", this.GetDataAddr(), "ptr", realSize, "cdecl"), addr += realSize
		,addr := (addr+3)&~3
		for k,v in this
			addr += v.Save(addr)
		size := addr - orgAddr
		,NumPut(size, orgAddr+0, "UShort")
		return size
	}
}
EitherMouse - Multiple mice, individual settings . . . . www.EitherMouse.com . . . . forum . . . .
User avatar
gwarble
Posts: 524
Joined: 30 Sep 2013, 15:01

Re: ChangeVersionInfo() and VersionRes class standalone usage

26 Sep 2018, 19:31

I guess what I'm trying to figure out is how to populate verInfo {} when something like this is used:

Code: Select all

ProcessDirectives(ExeFile, module, cmds, IcoFile, UseCompression, UsePassword)
{
state := { ExeFile: ExeFile, module: module, resLang: 0x409, verInfo: {}, IcoFile: IcoFile, PostExec: [] }
;...
https://github.com/HotKeyIt/ahkdll-v1-r ... ctives.ahk
EitherMouse - Multiple mice, individual settings . . . . www.EitherMouse.com . . . . forum . . . .
just me
Posts: 9453
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: ChangeVersionInfo() and VersionRes class standalone usage

27 Sep 2018, 03:08

Code: Select all

	for k,v in verInfo
	{
		if IsLabel(lbl := "_VerInfo_" k)
			gosub %lbl%
		continue
		_VerInfo_Name:
		SafeGetViChild(props, "ProductName").SetText(v)
		SafeGetViChild(props, "InternalName").SetText(v)
		return
		_VerInfo_Description:
		SafeGetViChild(props, "FileDescription").SetText(v)
		return
		_VerInfo_Version:
		SafeGetViChild(props, "FileVersion").SetText(v)
		SafeGetViChild(props, "ProductVersion").SetText(v)
		ver := VersionTextToNumber(v)
		hiPart := (ver >> 32)&0xFFFFFFFF, loPart := ver & 0xFFFFFFFF
		NumPut(hiPart, ffi+8, "UInt"), NumPut(loPart, ffi+12, "UInt")
		NumPut(hiPart, ffi+16, "UInt"), NumPut(loPart, ffi+20, "UInt")
		return
		_VerInfo_Copyright:
		SafeGetViChild(props, "LegalCopyright").SetText(v)
		return
		_VerInfo_OrigFilename:
		SafeGetViChild(props, "OriginalFilename").SetText(v)
		return
		_VerInfo_CompanyName:
		SafeGetViChild(props, "CompanyName").SetText(v)
		return
	}
Apparently the verInfo object may contain up to 6 keys:
  • Name
  • Description
  • Version
  • Copyright
  • OrigFilename
  • CompanyName
As is, the function expects a hUpdate handle passed in the second parameter. To get such a handle you have to call BeginUpdateResource() before (and EndUpdateResource() after) the update.
User avatar
gwarble
Posts: 524
Joined: 30 Sep 2013, 15:01

Re: ChangeVersionInfo() and VersionRes class standalone usage

22 Nov 2018, 14:09

Thanks for the insight, I missed this reply earlier...
I will try it out
EitherMouse - Multiple mice, individual settings . . . . www.EitherMouse.com . . . . forum . . . .

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Descolada and 234 guests