2010-02-08 3 views
5

표준 Win32 API 함수를 호출하여 win32-api library을 사용하여 파일 버전 정보를 가져 오려고합니다.ruby ​​win32api & structs (VerQueryValue)

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

을 RtlMoveMemory에 포인터를 원하면서 기본적으로 VerQueryValue는 요지 긴 즉, 포인터 (위의 변수 요지)에 대한 포인터를 반환 : FileVersion 제대로 ProductVersion을 얻는 것은 같을 것이다 참조. RtlMoveMemory에 =는 Win32 :: API.new ('RtlMoveMemory에', 'PLI', 'V', 'KERNEL32.DLL') 다음이 전화 : RtlMoveMemory.call ( 그래서 나는 선언을 변경 fixed_info, addr.unpack ('L') [0], fixed_info.length) –

답변

3

이 나는 ​​그런 기능을 찾고있는 경우 다른 사람, 일을 가지고 전체 코드는 다음과 같습니다

는 코드입니다.

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의 대답은 엄격하게 정확하지 :

의 (a DLL 파일 등록 정보 창에서 "파일 버전"이라는 것이 예) 제품/파일 버전 번호의 네 부분을 배열로 반환 : VS_FIXEDFILEINFO 구조체는 과 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, 다음, dwFileVersionLSdwProductVersionMS로 구성되어 있습니다. .. 내가 그것을 알아 냈다고 생각

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] ] 
관련 문제