Reading Windows File Version Information in Ruby

I needed to read the resource version information from a windows executable file. I was hoping to find a nice Win32 wrapper library so I wouldn’t have to deal with the Windows API, but I couldn’t find anything beyond Win32API. Maybe I didn’t look hard enough. In any case, I decided to write this script.

Win32::VersionInfomation::API is a Ruby interface to the Windows API.
Win32::VersionInfomationHash uses Win32::VersionInfomation::API to load the version information into a Hash.

# Ruby interface for reading version information from a windows binary file
module Win32
    class VersionInfomation
    end
end

# Simple Ruby wrapper for Win32 API
class Win32::VersionInfomation::API
    require "Win32API"

    def self.get_file_version_info_size(filename)
        file = filename.dup
        s=""
        vsize=Win32API.new('version.dll', 'GetFileVersionInfoSize', ['P', 'P'], 'L').call(file, s)
        vsize
    end

    def self.get_file_version_info(filename)
        file = filename.dup
        vsize = get_file_version_info_size(filename)
        if (vsize > 0)
          result = ' '*vsize
          Win32API.new('version.dll', 'GetFileVersionInfo', ['P', 'L', 'L', 'P'], 'L').call(file, 0, vsize, result)
          rstring = result.unpack('v*').map{|s| s.chr if s<256}*''
          return rstring
        else
          return nil
        end
    end
end

# Loads the file version infomation into a Hash
class Win32::VersionInfomationHash < Hash

    # Default string information table names
    # These names are used for the hash keys
    # TODO: Dynamically read the table names from the file
    STRING_FILE_INFO = %w(Comments CompanyName FileDescription FileVersion InternalName 
    LegalCopyright LegalTrademarks OriginalFilename PrivateBuild ProductName ProductVersion SpecialBuild)

    def initialize(filename)
        @filename = filename
        init_file_version_info_hash
    end

    private
    # Converts the raw file version info into a Hash
    def init_file_version_info_hash()
        file_version_info = Win32::VersionInfomation::API.get_file_version_info(@filename)
        STRING_FILE_INFO.each do |key|
            file_version_info =~ /#{key}\W+(.*?)00/
            self[key] = $1
        end
    end
end

if __FILE__ == $0
    if ARGV[0]
        version_info_hash = Win32::VersionInfomationHash.new(ARGV[0])
        puts version_info_hash.to_yaml
    else
        puts "usage: #{__FILE__} filename"
    end
end
Advertisements
Tagged with: ,
Posted in ruby

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: