ruby win32api & structs (VerQueryValue) - PullRequest
       18

ruby win32api & structs (VerQueryValue)

5 голосов
/ 08 февраля 2010

Я пытаюсь вызвать стандартные функции Win32 API для получения информации о версии файла, используя библиотеку win32-api .

3 функции version.dll: GetFileVersionInfoSize, GetFileVersionInfo и VerQueryValue. Затем я вызываю RtlMoveMemory в kernel32.dll, чтобы получить копию структуры VS_FIXEDFILEINFO (см. Документацию Microsoft: http://msdn.microsoft.com/en-us/library/ms646997%28VS.85%29.aspx).

Я использовал пример, который видел при использовании VB: http://support.microsoft.com/kb/139491.

Моя проблема в том, что возвращаемые данные, похоже, не соответствуют ожидаемой структуре, фактически даже не возвращают непротиворечивое значение. Я подозреваю, что в какой-то момент данные искажаются, возможно, в VerQueryValue или RtlMoveMemory.

Вот код:

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.

Ответы [ 2 ]

3 голосов
/ 08 февраля 2010

Это полный код, который я получил для работы, на случай, если другие ищут такую ​​функцию.

Возвращает массив с четырьмя частями номера версии продукта / файла (то есть то, что называется «Версия файла» в окне свойств файла DLL):

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
1 голос
/ 19 июня 2014

Ответ в https://stackoverflow.com/a/2224681/3730446 не совсем корректен: структура VS_FIXEDFILEINFO содержит отдельные FileVersion и ProductVersion. Этот код возвращает номер версии, состоящий из двух более значимых компонентов ProductVersion и двух менее значимых компонентов FileVersion. В большинстве случаев я видел, что это не имеет значения, потому что оба значения Product- и FileVersion имеют одинаковое значение, но вы никогда не знаете, что может встретиться в дикой природе.

Мы можем убедиться в этом, сравнив структуру VS_FIXEDFILEINFO из http://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx и строку формата, которую мы используем для упаковки и распаковки буфера:

typedef struct tagVS_FIXEDFILEINFO {
    DWORD dwSignature;        //  0: L
    DWORD dwStrucVersion;     //  1: S
                              //  2: S
    DWORD dwFileVersionMS;    //  3: S
                              //  4: S
    DWORD dwFileVersionLS;    //  5: S
                              //  6: S
    DWORD dwProductVersionMS; //  7: S
                              //  8: S
    DWORD dwProductVersionLS; //  9: S
                              // 10: S
    DWORD dwFileFlagsMask;    // 11: L
    DWORD dwFileFlags;        // 12: L
    DWORD dwFileOS;           // 13: L
    DWORD dwFileType;         // 14: L
    DWORD dwFileSubtype;      // 15: L
    DWORD dwFileDateMS;       // 16: L
    DWORD dwFileDateLS;       // 17: L
} VS_FIXEDFILEINFO;

Подписки с 5 по 8, таким образом, состоят из dwFileVersionLS и dwProductVersionMS. Получение FileVersion и ProductVersion правильно будет выглядеть так:

info = fixed_info.unpack('LSSSSSSSSSSLLLLLLL')
file_version = [ info[4], info[3], info[6], info[5] ]
product_version = [ info[8], info[7], info[10], info[9] ]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...