Windows ruby win32api&;结构(VerQueryValue)
我正在尝试调用标准Win32 API函数,以使用获取文件版本信息 3个version.dll函数是GetFileVersionInfo、GetFileVersionInfo和VerQueryValue。然后调用kernel32.dll中的rtlmovemory来获取VS_FIXEDFILEINFO结构的副本(请参阅Microsoft文档: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看到的一个示例中
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] ]