AF 10-07-03 proc getFixedInfo {file array} { set fh [open $file r] fconfigure $fh -encoding unicode -eofchar {} set data [read $fh] set s [string first "VS_VERSION_INFO" $data] if {$s < 0} {close $fh; error "no version information found"} unset data fconfigure $fh -encoding binary seek $fh [expr {($s * 2) - 6}] start seek $fh [expr {[tell $fh] % 4}] current binary scan [read $fh 6] sss len vlen type seek $fh 34 current if {[getdword $fh] != 4277077181} {close $fh; error "version information corrupt"} upvar $array ret array set ret {} seek $fh 4 current binary scan [read $fh 8] ssss b a d c set ret(FileVer) $a.$b.$c.$d binary scan [read $fh 8] ssss b a d c set ret(ProductVer) $a.$b.$c.$d seek $fh 4 current #binary scan [read $fh 4] B32 flagmask set ret(Flags) [getdword $fh] set ret(OS) [getdword $fh] set ret(FileType) [getdword $fh] set ret(FileSubType) [getdword $fh] binary scan [read $fh 8] w ret(Date) close $fh } proc getStringInfo {file array} { upvar $array ret array set ret {} set fh [open $file r] fconfigure $fh -encoding unicode -eofchar {} set data [read $fh] close $fh if {[set s [string first "StringFileInfo\000" $data]] < 0} {error "no string information found"} incr s -3 if {![regexp {(.)\000(.)StringFileInfo\000(.)\000(.)(....)(....)\000} [string range $data $s end] --> len type len2 type2 lang code]} { error "string information corrupt" } array set ret [list Language $lang CodePage $code] set len [expr [scan $len %c] / 2] set len2 [expr [scan $len2 %c] / 2] set data [string range $data $s [expr {$s + $len}]] set s 30 while {$s < $len2} { scan [string range $data $s end] %c%c%c slen vlen type if {$slen == 0} return set slen [expr {$slen / 2}] set name [string range $data [expr {$s + 3}] [expr {$s + $slen - $vlen - 1}]] set value [string range $data [expr {$s + $slen - $vlen}] [expr {$s + $slen - 2}]] set s [expr {$s + $slen + ($slen % 2)}] set ret([string trimright $name \000]) $value } } proc writeStringInfo {file array} { upvar $array val set fh [open $file r+] fconfigure $fh -encoding unicode -eofchar {} set data [read $fh] set s [string first "StringFileInfo\000" $data] if {$s < 0} { close $fh; error "no stringfileinfo found" } if {![info exists val(CodePage)]} { set val(CodePage) 04b0 } if {![info exists val(Language)]} { set val(Language) 0409 } incr s -3 set len [scan [string index $data $s] %c] seek $fh [expr {$s * 2}] start puts -nonewline $fh [format "%c\000\001StringFileInfo\000%c\000\001%s%s\000" $len [expr {$len - 36}] $val(Language) $val(CodePage)] unset val(CodePage) val(Language) set olen $len set len [expr {($len / 2) - 30}] foreach x [array names val] { set vlen [expr {[string length $val($x)] + 1}] set nlen [string length $x] set npad [expr {$nlen % 2}] set tlen [expr {$vlen + $nlen + $npad + 4}] set tpad [expr {$tlen % 2}] if {($tlen + $tpad) > $len} { set error "too long" ; break } puts -nonewline $fh [format "%c%c\001%s\000%s%s\000%s" [expr {$tlen * 2}] $vlen $x [string repeat \000 $npad] $val($x) [string repeat \000 $tpad]] set len [expr {$len - $tlen - $tpad}] } puts -nonewline $fh [string repeat \000 $len] puts -nonewline $fh [string range $data [expr {$s + ($olen / 2)}] end] close $fh if {[info exists error]} { error $error } } ---- output: getFixedInfo tclkit.exe test test(Date) = 0 test(FileSubType) = 0 test(FileType) = 2 test(FileVer) = 8.4.2.2 test(Flags) = 0 test(OS) = 4 test(ProductVer) = 8.4.2.2 getStringInfo tclkit.exe test parray test test(CodePage) = 04b0 test(CompanyName) = Equi4 Software test(FileDescription) = Tclkit, a standalone runtime for Tcl/Tk test(FileVersion) = 8.4.2 test(Language) = 0409 test(LegalCopyright) = Copyright © 1989-2003 by J.Ousterhout et al. test(OriginalFilename) = tclkit.exe test(ProductName) = Tclkit 8.4 for Windows test(ProductVersion) = 8.4.2 ---- i support writing any values to the file but here is a list of the ones normally used. Comments CompanyName FileDescription FileVersion InternalName LegalCopyright LegalTrademarks OriginalFilename PrivateBuild ProductName ProductVersion SpecialBuild in addition i use CodePage and Language you can only write to files that already have a stringfileinfo block and you are limited to the same or less total length so as not to corrupt the file. ---- some relevant links http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/resources/versioninformation/versioninformationreference/versioninformationstructures/stringfileinfo.asp http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/resources/versioninformation/versioninformationreference/versioninformationstructures/stringtable.asp http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/resources/versioninformation/versioninformationreference/versioninformationstructures/string.asp