views:

155

answers:

2

I am trying to call the standard Win32 API functions to get file version info, using the win32-api library.

The 3 version.dll functions are GetFileVersionInfoSize, GetFileVersionInfo, and VerQueryValue. Then I call RtlMoveMemory in kernel32.dll to get a copy of the VS_FIXEDFILEINFO struct (see Microsoft documentation: http://msdn.microsoft.com/en-us/library/ms646997%28VS.85%29.aspx).

I drew from an example I saw using VB: http://support.microsoft.com/kb/139491.

My problem is that the data that finally gets returned doesn't seem to match the expected struct, in fact it doesn't even return a consistent value. I suspect the data is getting mangled at some point, probably in VerQueryValue or RtlMoveMemory.

Here is the code:

GetFileVersionInfoSize = Win32::API.new('GetFileVersionInfoSize','PP','I','version.dll')
GetFileVersionInfo = Win32::API.new('GetFileVersionInfo','PIIP','I', 'version.dll')
VerQueryValue = Win32::API.new('VerQueryValue','PPPP','I', 'version.dll')
RtlMoveMemory = Win32::API.new('RtlMoveMemory', 'PPI', 'V', 'kernel32.dll')

buf = [0].pack('L')
version_size = GetFileVersionInfoSize.call(myfile + "\0", buf)
raise Exception.new  if version_size == 0 #TODO

version_info = 0.chr * version_size
version_ok = GetFileVersionInfo.call(file, 0, version_size, version_info)
raise Exception.new if version_ok == 0   #TODO

addr = [0].pack('L')
size = [0].pack('L')
query_ok = VerQueryValue.call(version_info, "\\\0", addr, size)
raise Exception.new if query_ok == 0        #TODO

# note that at this point, size == 4 -- is that right?

fixed_info = Array.new(13,0).pack('L*')
RtlMoveMemory.call(fixed_info, addr, fixed_info.length)

# fixed_info.unpack('L*')  #=> seemingly random data, usually only the first two dwords' worth and the rest 0.
A: 

This is the full code I got to work, in case others are looking for such a function.

Returns an array with four parts of product/file version number (i.e., what is called "File Version" in a dll file properties window):

def file_version ref, options = {}
  options = {:path => LIBDIR, :extension => 'dll'}.merge(options)
  begin
      file = File.join(ROOT, options[:path],"#{ref}.#{options[:extension]}").gsub(/\//,"\\")
      buf = [0].pack('L')
      version_size = GetFileVersionInfoSize.call(file + "\0", buf)
      raise Exception.new    if version_size == 0 #TODO

      version_info = 0.chr * version_size
      version_ok = GetFileVersionInfo.call(file, 0, version_size, version_info)
      raise Exception.new if version_ok == 0        #TODO

      addr = [0].pack('L')
      size = [0].pack('L')
      query_ok = VerQueryValue.call(version_info, "\\\0", addr, size)
      raise Exception.new if query_ok == 0        #TODO

      fixed_info = Array.new(18,0).pack('LSSSSSSSSSSLLLLLLL')
      RtlMoveMemory.call(fixed_info, addr.unpack('L')[0], fixed_info.length)

      fixed_info.unpack('LSSSSSSSSSSLLLLLLL')[5..8].reverse

  rescue
        []
  end
end
Eric G
A: 

This was very helpful, thanks!

krafty