Code : Tout sélectionner
#include <array.au3>
Global $Fichier = "C:\Windows\twunk_32.exe"
Global $AReturn, $props[1]
_GetVersionInfo($Fichier, $AReturn)
If IsArray($AReturn) Then
MsgBox(64, "Info :", "Description = " & $AReturn[1])
EndIf
Func _GetVersionInfo($sFilePath, ByRef $ARet2) ;-- return array(5)
Local $ARet, $s1, $sB, $Pt1, $sRes, $A1, $A4[4], $A2[4], $LocRes, $VLocRes, $SizeRes, $iOff, $Boo, $sVerString, $sMarker
Local $iNum1, $iNum2, $iReadPt, $iNum3, $LocAspack, $VLocAspack, $VIOffset, $ReadOffset, $BooAspack
; On Error Resume Next
If Not FileExists($sFilePath) Then
Return 1 ;bad path.
EndIf
$sRes = ".rsrc"
$sVerString = "VS_VER"
$BooAspack = False
$file = FileOpen($sFilePath, 0)
$s1 = FileRead($sFilePath, 2048)
FileClose($file)
$file = 0
;ConsoleWrite($s1)
$A1 = _GetArray(StringMid($s1, 61, 2)) ;-- get number value at offset 60 that points to PE signature address.
$iNum1 = (_GetNumFromBytes($A1) + 1) ;-- get offset of "PE00"
$sB = _GetByteString($s1, False) ;-- get a workable string with Chr(0) replaced by "*".
$sMarker = StringMid($sB, $iNum1, 4)
;~ ConsoleWrite("$sMarker ="&$sMarker&@LF)
If ($sMarker <> "PE**") Then
If StringLeft($sMarker, 2) = "NE" Then
Return 5 ;-- 16 bit.
Else
Return 4 ;-- no PE signature found.
EndIf
EndIf
$Pt1 = StringInStr($sB, $sRes) ;-- find .rsrc table.
If ($Pt1 = 0) Then
Return 2 ;no resource table header found.
EndIf
$Pt1 = $Pt1 + 12 ;-- size of raw data is 4 bytes at offset of 16 into the .rsrc table.
$A1 = _GetArray(StringMid($s1, $Pt1, 12)) ;-- get the same string as a numeric array to Read offset numbers.
For $iOff = 0 To 3
;ConsoleWrite("$iOff ="&$iOff&@LF)
$A4[$iOff] = $A1[$iOff]
Next
$VLocRes = _GetNumFromBytes($A4)
For $iOff = 0 To 3
$A4[$iOff] = $A1[$iOff + 4]
Next
$SizeRes = _GetNumFromBytes($A4) ;--size of resource section in bytes.
For $iOff = 0 To 3
$A4[$iOff] = $A1[$iOff + 8]
Next
$LocRes = _GetNumFromBytes($A4) ;-- offset location of resource section.
$Pt1 = StringInStr(1, $sB, ".aspack") ;-- find .rsrc table.
If ($Pt1 > 0) Then
$BooAspack = True
$Pt1 = $Pt1 + 12 ;-- virtual offset is first 4 bytes; raw offset is bytes 9-12.
$A1 = _GetArray(StringMid($s1, $Pt1, 12))
For $iOff = 0 To 3
$A4[$iOff] = $A1[$iOff]
Next
$VLocAspack = _GetNumFromBytes($A4)
For $iOff = 0 To 3
$A4[$iOff] = $A1[$iOff + 8]
Next
$LocAspack = _GetNumFromBytes($A4)
EndIf
$Boo = False
$file = FileOpen($sFilePath, 0)
;MsgBox(0, "$LocRes", "$LocRes+12 =" & $LocRes + 12)
;~ ConsoleWrite("$LocRes+12 =" & $LocRes + 12 & @CRLF)
_Skip($file, $LocRes + 12)
$s1 = FileRead($file, 2) ;-- Read bytes 13,14 to get number of named resource types.
$iNum1 = Asc($s1) ;-- number of names.
; ConsoleWrite("$iNum1 =" & $iNum1 & @LF)
$s2 = FileRead($file, 2) ;-- Read bytes 15,16 to get number of numbered resource types.
$iNum2 = Asc($s2);-- number of nums.
; ConsoleWrite("$iNum2 =" & $iNum2 & @LF)
If $iNum2 = 0 Then ;-- no numbered entries. have to quit here.
Return 3
EndIf
If ($iNum1 > 0) Then _Skip($file, $iNum1 * 8) ;-- Skip past named entries.
$iReadPt = $LocRes + 16 + ($iNum1 * 8) ;-- update file offset variable because this will be needed.
;ConsoleWrite("$iReadPt ="& $iReadPt&@LF)
$Boo = False
For $iOff = 1 To $iNum2
$s1 = FileRead($file, 8)
$iReadPt = $iReadPt + 8
If (Asc($s1) = 16) Then ;-- this is version info. entry.
$Boo = True
ExitLoop
EndIf
Next
If ($Boo = False) Then ;-- have to quit. no version info. entry found.
;ConsoleWrite("Return point 1" & @LF)
Return 3 ;failed to find version info in resource table.
EndIf
$A1 = _GetArray($s1) ;-- get a byte array for version info entry at top level.
;ConsoleWrite("Ubound>>"&UBound($A1))
$iOff = 0
$iNum3 = 1
;Do
While 1
For $iNum1 = 0 To 2 ;-- get offset number to next level from 2nd 4 bytes of entry structure.
$A4[$iNum1] = $A1[$iNum1 + 4]
Next
$A4[3] = 0
$iNum2 = _GetNumFromBytes($A4)
If ($A1[7] > 127) Then ;-- high bit was set in entry offset value, so it;s just a pointer to another pointer.
$iNum2 = $LocRes + $iNum2 + 16
_Skip($file, $iNum2 - $iReadPt) ;- 1)
$s1 = FileRead($file, 8)
$iReadPt = $iReadPt + (($iNum2 - $iReadPt) + 8)
$A1 = _GetArray($s1)
Else ;-- this is the offset of version info offset info.!
$iOff = ($iNum2 + $LocRes)
;ExitLoop
ExitLoop
EndIf
$iNum3 = $iNum3 + 1
If ($iNum3 > 10) Then ExitLoop
WEnd
;Loop
If ($iOff = 0) Then ;-- have to quit. no final offset found.
;ConsoleWrite("Return point 2" & @LF)
Return 3 ;failed to find version info in resource table.
EndIf
_Skip($file, $iOff - $iReadPt)
$s1 = FileRead($file, 8)
$iReadPt = $iReadPt + (($iOff - $iReadPt) + 8)
$A1 = _GetArray($s1)
For $iNum1 = 0 To 3
$A4[$iNum1] = $A1[$iNum1]
Next
$VIOffset = _GetNumFromBytes($A4) ;--offset of version info. given in .rsrc section.
$ReadOffset = (($VIOffset - $VLocRes) + $LocRes)
For $iNum1 = 0 To 3
$A4[$iNum1] = $A1[$iNum1 + 4]
Next
$SizeRes = _GetNumFromBytes($A4)
_Skip($file, $ReadOffset - $iReadPt)
$s1 = FileRead($file, $SizeRes) ;-- read out the entire FileVersionInfo data area.
FileClose($file)
$file = 0
$sB = _GetByteString($s1, True) ;-- snip unicode.
$Pt1 = StringInStr($sB, $sVerString)
If ($Pt1 > 0) Then ;-- "VS_VER" was found, so process the string and quit.
$ARet = _ProcessRes($sB)
$ARet2 = $ARet
Return 0 ; ok
ElseIf ($BooAspack = True) Then ;-- if "VS_VER" was not found but there is an "aspack" section then try that.
$ReadOffset = (($VIOffset - $VLocAspack) + $LocAspack) ;-- calculate a new file version info data offset.
$file = FileOpen($sFilePath, 0) ;-- The file was closed and is now re-opened here. Keeping the file
_Skip($file, $ReadOffset) ;-- open "just in case" wouldn;t have helped because the file pointer
$s1 = FileRead($file, $SizeRes) ;-- for this read may be further back thean the pointer was when the file
FileClose($file) ;-- was closed. So rather than try to sort out the read point, the file is just
$file = 0;-- opened fresh and Skip is used.
$sB = _GetByteString($s1, True)
$Pt1 = StringInStr($sB, $sVerString)
If ($Pt1 > 0) Then
$ARet = _ProcessRes($sB)
$ARet2 = $ARet
Return 0 ; ok
Else
;ConsoleWrite("Return point 3" & @LF)
Return 3 ;failed to find version info in resource table.
EndIf
Else
;ConsoleWrite("Return point 4" & @LF)
Return 3 ;failed to find version info in resource table.
EndIf
EndFunc ;==>_GetVersionInfo
Func _ProcessRes($sDat)
; find where the resource info starts
Local $info_ptr = StringInStr($sDat, "StringFileInfo") + StringLen("StringFileInfo")
Local $s_props = StringMid($sDat, $info_ptr)
Local $occurance = 2
While 1
$info_ptr = StringInStr($s_props, Chr(1), 0, $occurance) + 1 ; find the beginning of a property name
$s_prop = StringMid($s_props, $info_ptr)
$prop_ptr = StringInStr($s_prop, "*") ; find the end of a property name
If @error Then ExitLoop
$s_prop = StringMid($s_prop, 1, $prop_ptr - 1)
If Not StringLen($s_prop) Then ExitLoop ; no more resources
If $s_prop = "VarFileInfo" Then ExitLoop ; no more resources
$occurance += 1
ReDim $props[$occurance - 2]
$props[$occurance - 3] = $s_prop ; resize and populate array with resource names
WEnd
Dim $AInfo[UBound($props) ]
; On Error Resume Next
For $x = 0 To UBound($props) - 1
$AInfo[$x] = _GetInfo($sDat, $props[$x])
Next
Return $AInfo
EndFunc ;==>_ProcessRes
Func _GetInfo($sStr, $sVal)
; had to rewrite this function because of incompatiblities
;between AutoIt3 and Vb string functions.
Dim $Pta, $Ptb, $LenVal, $s4, $occurance = 1
$LenVal = StringLen($sVal) + 1 ;-- length of info string: "CompanyName" = 11
$Pta = StringInStr($sStr, $sVal) ;-- find string name.
;~ ConsoleWrite(String(StringMid($sStr, $Pta - 1, 1)) & @LF)
If ($Pta > 0) Then
$Pta = $Pta + $LenVal
$Ptb = $Pta + StringInStr(StringMid($sStr, $Pta + 1), "*")
;~ ConsoleWrite(StringMid($sStr, $Pta + 1) & @LF)
;~ ConsoleWrite(StringMid($sStr, $Pta, ($Ptb - $Pta)) & @LF)
If $Ptb > ($Pta + 2) And $sVal <> "FileVersion" Then
$s4 = StringMid($sStr, $Pta, ($Ptb - $Pta))
$s4 = StringReplace($s4, "*", "")
If StringInStr($s4, Chr(1), 1) = 0 Then Return $s4
ElseIf $sVal = "FileVersion" Then ; deal with file version
$s4 = StringMid($sStr, $Pta, ($Ptb - $Pta))
If $Ptb = ($Pta + 2) Then
$s4 &= '.0.0.0'
EndIf
$s4 = StringReplace($s4, "*", "")
$s4 = StringReplace($s4, ",", ".")
$s4 = StringStripWS($s4, 8)
If StringInStr($s4, Chr(1), 1) = 0 Then Return $s4 ;-- check for Chr(1) which seems to be found
EndIf
EndIf
Return ""
EndFunc ;==>_GetInfo
;-------------- simplified version of _GetByteString For this Class. ---------------------
Func _GetByteString($sStr, $SnipUnicode)
Local $sRet, $iLen, $iA, $iLen2, $A2[2]
; On Error Resume Next
$iLen2 = 0
If ($SnipUnicode = False) Then
ReDim $A2[StringLen($sStr) ]
For $iLen = 1 To StringLen($sStr)
$iA = Asc(StringMid($sStr, $iLen, 1))
If $iA = 0 Then $iA = 42 ;-- converts 0-byte to *
;If UBound($A2) > $iLen - 1 Then
$A2[$iLen - 1] = Chr($iA)
Next
Else
ReDim $A2[ (StringLen($sStr) / 2) ]
For $iLen = 1 To StringLen($sStr) Step 2
$iA = Asc(StringMid($sStr, $iLen, 1))
If $iA = 0 Then $iA = 42 ;-- converts 0-byte to *
$A2[$iLen2] = Chr($iA)
$iLen2 = $iLen2 + 1
Next
EndIf
Return _Join($A2, "")
EndFunc ;==>_GetByteString
;-------------------------------- Simplified version of _GetArray. -----------------------
Func _GetArray($sStr)
Dim $iA, $Len1, $Len2, $AStr[2]
; On Error Resume Next
$Len1 = StringLen($sStr)
If $Len1 > 1 Then ReDim $AStr[ ($Len1) ]
For $iA = 1 To $Len1
$AStr[$iA - 1] = Asc(StringMid($sStr, $iA, 1))
Next
Return $AStr
EndFunc ;==>_GetArray
;-------------------- return a number from 2 or 4 bytes. ---------------
Func _GetNumFromBytes($ABytes)
Dim $Num1
; Err.Clear
; On Error Resume Next
;_GetNumFromBytes = -1
If UBound($ABytes) > 1 Then
$Num1 = ($ABytes[0] + $ABytes[1] * 256)
If (UBound($ABytes) > 3) Then
$Num1 = $Num1 + ($ABytes[2] * 65536) + ($ABytes[3] * 16777216)
EndIf
Return $Num1
EndIf
EndFunc ;==>_GetNumFromBytes
Func _Join($aStrJ, $sDelim = "")
;mimic VB Join command (array to string with delimiter)
Local $sTemp
If IsArray($aStrJ) Then
For $x = 0 To UBound($aStrJ) - 1
$sTemp = $sTemp & $aStrJ[$x] & $sDelim
Next
;ConsoleWrite("Join $sTemp =" & $sTemp & @LF)
Return $sTemp
EndIf
SetError(1)
Return ""
EndFunc ;==>_Join
Func _Skip($hfile, $bytes)
;mimic FSO.skip
Local $temp = FileRead($hfile, $bytes)
If @error Then Return 0
Return 1
EndFunc ;==>_Skip