; Original script from w0xx0m at http://www.autohotkey.com/forum/topic8618.html

; changelog :
; modified to support AutoHotkey_L (Unicode version)
; numeric info modified to extract X.X.X.X even if last is null
; added FileVersion and ProductVersion extraction formatted as X,X,X,X (for direct use in RC file)
; added BuildID extraction

oldErrMode:=DllCall("SetErrorMode", UInt,1) ; SEM_FAILCRITICALERRORS=0x0001

FileGetFullVer(file,verFlags=1,delim="")
{
	If !delim
		delim=|
	{
	; FLAGS:
	;	0x00001 - numeric info
	;	0x00002 - file type
	;	0x10000 - numeric info (FileVersion) formatted as X,X,X,X
	;	0x20000 - numeric info (ProductVersion) formatted as X,X,X,X
	;	0x00004 - file description
	;	0x00008 - company name
	;	0x00010 - FileVersion
	;	0x00020 - Comments
	;	0x00040 - InternalName
	;	0x00080 - LegalCopyright
	;	0x00100 - LegalTrademarks
	;	0x00200 - OriginalFilename
	;	0x00400 - ProductName
	;	0x00800 - ProductVersion
	;	0x01000 - PrivateBuild
	;	0x02000 - SpecialBuild
	;	0x04000 - LegalTrademarks1
	;	0x08000 - clean-up empty fields
	;	0x40000 - BuildID

	; VersionInfoStrings
	;	viPredefinedFirst = 0
	;	viLanguage = 0
	;	viComments = 1
	;	viCompanyName = 2
	;	viFileDescription = 3
	;	viFileVersion = 4
	;	viInternalName = 5
	;	viLegalCopyright = 6
	;	viLegalTrademarks = 7
	;	viOriginalFilename = 8
	;	viProductName = 9
	;	viProductVersion = 10
	;	viPrivateBuild = 11
	;	viSpecialBuild = 12
	;	viLegalTrademarks1 = 13  'Used by Office apps only?
	;	viLegalTrademarks2 = 14  'Used by Office apps only?
	;	viPredefinedLast = 14

	;typedef struct tagVS_FIXEDFILEINFO
	;	0  DWORD dwSignature;
	;	4  DWORD dwStrucVersion;
	;	8  DWORD dwFileVersionMS;
	;	12 DWORD dwFileVersionLS;
	;	16 DWORD dwProductVersionMS;
	;	20 DWORD dwProductVersionLS;
	;	24 DWORD dwFileFlagsMask;
	;	28 DWORD dwFileFlags;
	;	32 DWORD dwFileOS;
	;	36 DWORD dwFileType;
	;	40 DWORD dwFileSubtype;
	;	44 DWORD dwFileDateMS;
	;	48 DWORD dwFileDateLS;

	;	MAX_PATH = 260
	;	; ----- VS_VERSION.dwFileFlags -----
	;	VS_FFI_SIGNATURE = 0xFEEF04BD
	;	VS_FFI_STRUCVERSION = 0x10000
	;	VS_FFI_FILEFLAGSMASK = 0x3F
	;	; ----- VS_VERSION.dwFileFlags -----
	;	VS_FF_DEBUG = 0x1
	;	VS_FF_PRERELEASE = 0x2
	;	VS_FF_PATCHED = 0x4
	;	VS_FF_PRIVATEBUILD = 0x8
	;	VS_FF_INFOINFERRED = 0x10
	;	VS_FF_SPECIALBUILD = 0x20
	;	; ----- VS_VERSION.dwFileOS -----
	;	VOS_UNKNOWN = 0x0
	;	VOS_DOS = 0x10000
	;	VOS_OS216 = 0x20000
	;	VOS_OS232 = 0x30000
	;	VOS_NT = 0x40000
	;	VOS_DOS_WINDOWS16 = 0x10001
	;	VOS_DOS_WINDOWS32 = 0x10004
	;	VOS_OS216_PM16 = 0x20002
	;	VOS_OS232_PM32 = 0x30003
	;	VOS_NT_WINDOWS32 = 0x40004
	;	; ----- VS_VERSION.dwFileType -----
	;	VFT_UNKNOWN = 0x0
	;	VFT_APP = 0x1
	;	VFT_DLL = 0x2
	;	VFT_DRV = 0x3
	;	VFT_FONT = 0x4
	;	VFT_VXD = 0x5
	;	VFT_STATIC_LIB = 0x7
	;	; **** VS_VERSION.dwFileSubtype for VFT_WINDOWS_FONT ****
	;	VFT2_FONT_RASTER = 0x1
	;	VFT2_FONT_VECTOR = 0x2
	;	VFT2_FONT_TRUETYPE = 0x3
	;	; ----- VS_VERSION.dwFileSubtype for VFT_WINDOWS_DRV -----
	;	VFT2_UNKNOWN = 0x0
	;	VFT2_DRV_PRINTER = 0x1
	;	VFT2_DRV_KEYBOARD = 0x2
	;	VFT2_DRV_LANGUAGE = 0x3
	;	VFT2_DRV_DISPLAY = 0x4
	;	VFT2_DRV_MOUSE = 0x5
	;	VFT2_DRV_NETWORK = 0x6
	;	VFT2_DRV_SYSTEM = 0x7
	;	VFT2_DRV_INSTALLABLE = 0x8
	;	VFT2_DRV_SOUND = 0x9
	;	VFT2_DRV_COMM = 0xA
	}

	version=
	dummy:=1
	fiSize:=DllCall("version\GetFileVersionInfoSizeW", Str, file, UInt, &dummy)
	varSetCapacity(fi,fiSize,0)
	loop,1
		{
		if !DllCall("version\GetFileVersionInfoW", Str, file, Int,0, UInt,fiSize, UInt, &fi)
			Break
		if !DllCall("version\VerQueryValueW", UInt,&fi, Str,"\", UIntp,fiFFI#, UIntp,dummy)
			Break

		varSetCapacity(fiFFI,13*8)
		DllCall("RtlMoveMemory", UInt,&fiFFI, UInt,fiFFI#, UInt,13*8)  
		version:=iif(verFlags & 1=0,"","v" extractInteger(fiFFI,10,0,2) "." extractInteger(fiFFI,8,0,2) "." extractInteger(fiFFI,14,0,2) "." extractInteger(fiFFI,12,0,2))
				. iif(verFlags & 2=0,"","|" switch(extractInteger(fiFFI,36)+1,"","Application","DLL","|" switch(extractInteger(fiFFI,40)+1,"","Printer ","Keyboard ","Language ","Display ","Mouse ","Network ","System ","Installable ", "Sound ","Comm. ") "driver","|" switch(extractInteger(fiFFI,40),"Raster","Vector","TrueType") " font","|VxD driver", "|Static Lib"))
				. iif(verFlags & 0x10000,"|"  extractInteger(fiFFI,10,0,2) "," extractInteger(fiFFI,8,0,2) "," extractInteger(fiFFI,14,0,2) "," extractInteger(fiFFI,12,0,2),"")
				. iif(verFlags & 0x20000,"|"  extractInteger(fiFFI,18,0,2) "," extractInteger(fiFFI,16,0,2) "," extractInteger(fiFFI,22,0,2) "," extractInteger(fiFFI,20,0,2),"")
		if (verFlags & 0xFFFE)
			{
			If !DllCall("version\VerQueryValueW", UInt,&fi, str,"\VarFileInfo\Translation", UIntp,fiTrans#, UIntp,dummy)
				Break
			If !dummy
				Break

			fiTrans:=0
			VarSetCapacity(Trans,16 )
			If !DllCall( "msvcrt\swprintf", Str,Trans, Str,"%08X", UInt,NumGet(fiTrans#+0) )
				Break
			DllCall("version\VerQueryValueW", UInt,&fi, str,"\StringFileInfo\" SubStr(Trans,-3) SubStr(Trans,1,4) "\CompanyName", UIntp,fiValue#, UIntp,dummy)
			Company := StrGet( fiValue#, DllCall( "lstrlenW", UInt,fiValue# ) )
			If !Company
				sSubBlock := "\StringFileInfo\0409" SubStr(Trans,1,4) "\"
			Else
				sSubBlock := "\StringFileInfo\" SubStr(Trans,-3) SubStr(Trans,1,4) "\"

			version:=version
				. iif(verFlags & 4=0,"","|" verGetStdValue(fi,sSubBlock "FileDescription"))
				. iif(verFlags & 8=0,"","|" verGetStdValue(fi,sSubBlock "CompanyName"))
				. iif(verFlags & 0x00010,"|" verGetStdValue(fi,sSubBlock "FileVersion"),"")
				. iif(verFlags & 0x00020,"|" verGetStdValue(fi,sSubBlock "Comments"),"")
				. iif(verFlags & 0x00040,"|" verGetStdValue(fi,sSubBlock "InternalName"),"")
				. iif(verFlags & 0x00080,"|" verGetStdValue(fi,sSubBlock "LegalCopyright"),"")
				. iif(verFlags & 0x00100,"|" verGetStdValue(fi,sSubBlock "LegalTrademarks"),"")
				. iif(verFlags & 0x00200,"|" verGetStdValue(fi,sSubBlock "OriginalFilename"),"")
				. iif(verFlags & 0x00400,"|" verGetStdValue(fi,sSubBlock "ProductName"),"")
				. iif(verFlags & 0x00800,"|" verGetStdValue(fi,sSubBlock "ProductVersion"),"")
				. iif(verFlags & 0x01000,"|" verGetStdValue(fi,sSubBlock "PrivateBuild"),"")
				. iif(verFlags & 0x02000,"|" verGetStdValue(fi,sSubBlock "SpecialBuild"),"")
				. iif(verFlags & 0x04000,"|" verGetStdValue(fi,sSubBlock "LegalTrademarks1") . "|" verGetStdValue(fi,sSubBlock "LegalTrademarks2"),"")
				. iif(verFlags & 0x40000,"|" verGetStdValue(fi,sSubBlock "BuildID"),"")
			}
		}


	if (verFlags & 0x08000)
		{
		dummy=
		version=|%version%|
		stringReplace,version,version,|v0.0|
		loop,parse,version,|
			if (A_LoopField)
				dummy:=dummy . delim . A_LoopField
		return strMid(dummy,2)
		}

	if (delim<>"|")
		stringReplace,version,version,|,%delim%,all

Return version
}

verGetStdValue(byref fi, value)
{
	fiValue#:=0
	dummy:=0
	If !DllCall("version\VerQueryValueW", UInt,&fi, str,value, UIntp,fiValue#, UIntp,dummy)
		Return
	If !dummy
		Return

Return StrGet( fiValue#, DllCall( "lstrlenW", UInt,fiValue# ) )
}

iif(expr, a, b)
{
if (expr)
	Return a
else
	Return b
}

strLeft(s, n)
{
stringLeft,s,s,%n%
Return s
}

strRight(s, n)
{
stringRight,s,s,%n%
Return s
}

strMid(s, begin, n=0x7FFF, Left=0) ; if L<>0 then mid to the left  ;;
{
if Left=0
	stringMid,s,s,%begin%,%n%
else
	stringMid,s,s,%begin%,%n%,L
Return s
}

ExtractInteger(ByRef pSource, pOffset = 0, pIsSigned = false, pSize = 4)
{
; pSource is a string (buffer) whose memory area contains a raw/binary integer at pOffset.
; The caller should pass true for pSigned to interpret the result as signed vs. unsigned.
; pSize is the size of PSource's integer in bytes (e.g. 4 bytes for a DWORD or Int).
; pSource must be ByRef to avoid corruption during the formal-to-actual copying process
; (since pSource might contain valid data beyond its first binary zero).

	Loop %pSize%  ; Build the integer by adding up its bytes.
		result += *(&pSource + pOffset + A_Index-1) << 8*(A_Index-1)
	if (!pIsSigned OR pSize > 4 OR result < 0x80000000)
		Return result  ; Signed vs. unsigned doesn't matter in these cases.
	; Otherwise, convert the value (now known to be 32-bit) to its signed counterpart:
	
Return -(0xFFFFFFFF - result + 1)
}

InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
{
; The caller must ensure that pDest has sufficient capacity.  To preserve any existing contents in pDest,
; only pSize number of bytes starting at pOffset are altered in it.

	Loop %pSize%  ; Copy each byte in the integer into the structure as raw binary data.
		DllCall("RtlFillMemory", UInt, &pDest + pOffset + A_Index-1, UInt, 1, UChar, pInteger >> 8*(A_Index-1) & 0xFF)

}

switch(idx,val1="",val2="",val3="",val4="",val5="",val6="",val7="",val8="",val9="",val10="",val11="",val12="",val13="",val14="",val15="",val16="")
{
Return val%idx%
} 
