Version 0 of Windows binary resources

Updated 2004-08-05 00:23:53

AF 2004-08-04 This is a series of procs for reading information from the resource tree compiled into windows executable files. The resource tree holds such information as the menus, icons, cursors, version information, and accelerator keys for the program.


 proc FindWindowsHeader {file sig} {
    set fh [open $file r]
    fconfigure $fh -encoding binary -eofchar {} -translation lf
    if {[read $fh 2] != "MZ"} {close $fh; error "not an DOS executable"}
    seek $fh 60 start
    seek $fh [getword $fh] start
    if {[read $fh 2] != $sig} {close $fh; error "windows header not found"}
    seek $fh -2 current
    return $fh
 }

 proc EnumNEResources {file} {
    set fh [FindWindowsHeader $file NE]
    seek $fh 36 current
    seek $fh [expr {[getword $fh] - 36}] current
    set base [tell $fh]

    set ret {}
    while {[set type [getNEResName $fh $base [getushort $fh]]] != 0} {
        set num [getushort $fh]
        seek $fh [expr {$num * 12 + 4}] current
        lappend ret $type $num
    }
    return $ret
 }

 proc getNEResource {file restype {resid {}}} {
    set fh [FindWindowsHeader $file NE]
    seek $fh 36 current
    seek $fh [expr {[getword $fh] - 38}] current
    set base [tell $fh]

    set shift [expr {int(pow(2, [getushort $fh]))}]
    while {[set type [getNEResName $fh $base [getushort $fh]]] != 0} {
        set num [getushort $fh]
        if {$type != $restype} {
            seek $fh [expr {$num * 12 + 4}] current
            continue
        }
        seek $fh 4 current
        set ret {}
        for {set i 0} {$i < $num} {incr i} {
            set offset [expr {[getushort $fh] * $shift}]
            set len [getushort $fh]
            seek $fh 2 current
            lappend ret[getNEResName $fh $base [getushort $fh]] $offset $len
            seek $fh 4 current
        }
        close $fh
        return $ret
    }
    return {}
 }


 proc getNEResName {fh base data} {
    if {$data == 0} {
        return 0
    } elseif {[getbit $data 0] == 0} {
        set cur [tell $fh]
        seek $fh [expr {$data + $base}] start
        set len [getchar $fh]
        set name [read $fh $len]
        seek $fh $cur start
        return $name
    } else {
        return [expr {$data & 0x7fff}]
    }
 }

 proc getdword {fh} {
    binary scan [read $fh 4] i tmp
    return $tmp
 }

 proc getulong {fh} {
    binary scan [read $fh 4] i tmp
    return [format %u $tmp]
 }

 proc getushort {fh} {
    binary scan [read $fh 2] s tmp
    return [expr {$tmp & 0x0000FFFF}]
 }

 proc getword {fh} {
    binary scan [read $fh 2] s tmp
    return $tmp
 }

 proc getchar {fh} {
    binary scan [read $fh 1] c tmp
    return $tmp
 }

usage:

 EnumNEResources ''file''
 getNEResource ''file'' ''res type''
 EnumPEResources ''file''
 getPEResource ''file'' ''res type''

more to come soon