我正在尝试使用win32-api library调用标准的Win32 API函数来获取文件版本信息。
3个version.dll函数是GetFileVersionInfoSize,GetFileVersionInfo和VerQueryValue。然后我调用kernel32.dll中的RtlMoveMemory来获取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.
答案 0 :(得分:3)
这是我开始工作的完整代码,以防其他人正在寻找这样的功能。
返回一个包含四个产品/文件版本号部分的数组(即,在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 :(得分:1)
https://stackoverflow.com/a/2224681/3730446中的答案并不完全正确:VS_FIXEDFILEINFO
结构包含单独的FileVersion
和ProductVersion
。该代码返回的版本号由ProductVersion
的两个更重要的组件和FileVersion
的两个不太重要的组件组成。我见过的大部分时间都没关系,因为Product-
和FileVersion
都有相同的价值,但你永远不会知道你在野外会遇到什么。
我们可以通过比较来自http://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx的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] ]