2010-02-08 10 views
5

win32-api library'u kullanarak dosya sürümü bilgilerini almak için standart Win32 API işlevlerini çağırmaya çalışıyorum.ruby ​​win32api & structs (VerQueryValue)

3 version.dll işlevleri GetFileVersionInfoSize, GetFileVersionInfo ve VerQueryValue'dir. Sonra VS_FIXEDFILEINFO yapısının bir kopyasını almak için kernel32.dll dosyasında RtlMoveMemory'yi çağırıyorum (bkz. Microsoft belgeleri: http://msdn.microsoft.com/en-us/library/ms646997%28VS.85%29.aspx).

VB: http://support.microsoft.com/kb/139491 kullanarak gördüm bir örnekten çizdim.

Sorunum, sonunda döndürülen verilerin beklenen yapıyla eşleşmiyor gibi görünmesi, aslında tutarlı bir değer bile getirmiyor olmasıdır. Veriler bir noktada, muhtemelen VerQueryValue veya RtlMoveMemory'de karıştırıldığından şüpheleniyorum.

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. 
+1

RtlMoveMemory bir işaretçi isterken temelde VerQueryValue o addr uzun yani, bir işaretçi (yukarıdaki değişken addr) bir gösterici ile döner: FileVersion ve doğru olarak ProductVersion Alma şu şekilde görünecektir Referanslar. RtlMoveMemory = Win32 :: API.new ('RtlMoveMemory', 'PLI', 'V', 'kernel32.dll') ve sonra çağırarak: RtlMoveMemory.call ( Yani deklarasyon değişti fixed_info, addr.unpack ('L') [0], sabit_info.length) –

cevap

3

Bu Böyle bir işlev için aradığınız durum diğerlerinde, çalışmak lazım tam kodudur: Burada

kodudur.

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

https://stackoverflow.com/a/2224681/3730446 yılında cevabı kesinlikle doğru değil:

(bir dll dosyası özellikleri penceresinde "Dosya Sürümü" denen yani) ürün/dosya sürümü numarasının dört bölümden içeren bir dizi döndürür : VS_FIXEDFILEINFO yapısında ayrı FileVersion ve ProductVersion bulunur. Bu kod, ProductVersion'un iki önemli bileşeninden ve FileVersion'un daha az önemli bileşenlerinden oluşan bir sürüm numarası döndürür. Gördüğüm çoğu zaman, bu farketmez, çünkü hem Product- hem de FileVersion aynı değere sahiptir, ama vahşi ortamda ne karşılaşabileceğinizi asla bilemezsiniz.

Biz http://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx den VS_FIXEDFILEINFO yapı ve biz paketi ve tampon açmak için kullandığınız biçim dizesi karşılaştırarak bunu görebilirsiniz:

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; 

indisler 5 ila 8, daha sonra, dwFileVersionLS ve dwProductVersionMS oluşur. .. Ben bunu anladım düşünüyorum

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