Windows ruby win32api&;结构(VerQueryValue)

Windows ruby win32api&;结构(VerQueryValue),windows,ruby,winapi,Windows,Ruby,Winapi,我正在尝试调用标准Win32 API函数,以使用获取文件版本信息 3个version.dll函数是GetFileVersionInfo、GetFileVersionInfo和VerQueryValue。然后调用kernel32.dll中的rtlmovemory来获取VS_FIXEDFILEINFO结构的副本(请参阅Microsoft文档:http://msdn.microsoft.com/en-us/library/ms646997%28VS.85%29.aspx) 我从使用VB看到的一个示例中

我正在尝试调用标准Win32 API函数,以使用获取文件版本信息

3个version.dll函数是GetFileVersionInfo、GetFileVersionInfo和VerQueryValue。然后调用kernel32.dll中的rtlmovemory来获取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.

这是我得到的完整代码,以防其他人正在寻找这样的函数

返回包含产品/文件版本号四部分的数组(即dll文件属性窗口中的“文件版本”):

中的答案并不完全正确:
VS_FIXEDFILEINFO
结构包含单独的
FileVersion
ProductVersion
。该代码返回一个版本号,该版本号由
ProductVersion
的两个更重要的组件和
FileVersion
的两个不太重要的组件组成。我见过的大多数情况下,这并不重要,因为
Product-
FileVersion
都有相同的值,但你永远不知道在野外会遇到什么

我们可以通过比较
VS_FIXEDFILEINFO
结构和用于打包和解包缓冲区的格式字符串来了解这一点:

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] ]

我想我知道了。。基本上,VerQueryValue返回指向指针(上面的变量addr)的指针,而RtlMoveMemory需要一个指针,即addr引用的长指针。所以我更改了声明:rtlmovemory=Win32::API.new('rtlmovemory','PLI','V','kernel32.dll'),然后调用它:rtlmovemory.call(fixed_info,addr.unpack('L')[0],fixed_info.length)
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] ]