2011-08-02 37 views
7

Có ai biết làm thế nào để có được thông tin phiên bản cho một tập tin thực thi/thông qua Java. Kịch bản là tôi có một tệp trên hệ thống cục bộ của mình và nếu phiên bản trên máy chủ mới hơn thì phiên bản trên hệ thống của tôi tôi cần tải xuống tệp từ máy chủ.Nhận thông tin phiên bản cho .exe

+2

Phiên bản của bạn có ý nghĩa gì? –

+1

Tại sao bạn không thực hiện kiểm tra md5? – Zaffy

+0

Bạn có nghĩa là thông tin meta (nhấp chuột phải và thuộc tính trong cửa sổ) không? – dacwe

Trả lời

8

Sau khi chi tiêu giờ trực tuyến và mã hóa, tôi đã tìm thấy giải pháp bằng cách sử dụng JNA để lấy Thông tin phiên bản cho tệp.

import com.sun.jna.Library; 
import com.sun.jna.Memory; 
import com.sun.jna.Native; 
import com.sun.jna.Pointer; 
import com.sun.jna.ptr.IntByReference; 
import com.sun.jna.ptr.PointerByReference; 
import com.sun.jna.win32.W32APIOptions; 
import java.io.IOException; 


public class FileVersionInfo 
{ 
    interface Version extends Library { 

     Version INSTANCE = (Version) Native.loadLibrary("Version", Version.class, W32APIOptions.UNICODE_OPTIONS); 

     public int GetFileVersionInfoSizeW(String lptstrFilename, int dwDummy); 

     public boolean GetFileVersionInfoW(String lptstrFilename, int dwHandle, 
      int dwLen, Pointer lpData); 

     public int VerQueryValueW(Pointer pBlock, String lpSubBlock, 
      PointerByReference lplpBuffer, IntByReference puLen); 

    } 

    static class VS_FIXEDFILEINFO extends com.sun.jna.Structure { 
     public int dwSignature; 
     public int dwStrucVersion; 
     public int dwFileVersionMS; 
     public int dwFileVersionLS; 
     public int dwProductVersionMS; 
     public int dwProductVersionLS; 
     public int dwFileFlagsMask; 
     public int dwFileFlags; 
     public int dwFileOS; 
     public int dwFileType; 
     public int dwFileSubtype; 
     public int dwFileDateMS; 
     public int dwFileDateLS; 

      public VS_FIXEDFILEINFO(com.sun.jna.Pointer p){ 
       super(p); 
      } 
    } 
    public static void main(String[] args) throws IOException { 

     int dwDummy = 0; 
     int versionlength = Version.INSTANCE.GetFileVersionInfoSizeW(
       "C:\\Test\\chromeinstall.exe", dwDummy); 

     byte[] bufferarray = new byte[versionlength]; 
     Pointer lpData = new Memory(bufferarray.length);  

     PointerByReference lplpBuffer = new PointerByReference(); 
     IntByReference puLen = new IntByReference(); 
     boolean FileInfoResult = Version.INSTANCE.GetFileVersionInfoW(
       "C:\\Test\\chromeinstall.exe", 
       0, versionlength, lpData); 
     System.out.println(FileInfoResult); 
     int verQueryVal = Version.INSTANCE.VerQueryValueW(lpData, 
       "\\", lplpBuffer, 
       puLen); 

     VS_FIXEDFILEINFO lplpBufStructure = new VS_FIXEDFILEINFO(
       lplpBuffer.getValue()); 
     lplpBufStructure.read(); 

     short[] rtnData = new short[4]; 
     rtnData[0] = (short) (lplpBufStructure.dwFileVersionMS >> 16); 
     rtnData[1] = (short) (lplpBufStructure.dwFileVersionMS & 0xffff); 
     rtnData[2] = (short) (lplpBufStructure.dwFileVersionLS >> 16); 
     rtnData[3] = (short) (lplpBufStructure.dwFileVersionLS & 0xffff); 

     for (int i = 0; i < rtnData.length; i++) { 
      System.out.println(rtnData[i]); 
     } 

} 
+0

Cảm ơn mã hữu ích này! Chỉ cần một lưu ý phụ cho những người sử dụng nó: Nếu bạn sử dụng mã này bên trong một lớp với VS_FIXEDFILEINFO là một lớp bên trong, bạn có thể nhận được lỗi "Class com.sun.jna.Cấu trúc không thể truy cập vào một getfield thành viên ". Nếu vậy, chỉ cần thêm từ khóa' public' vào lớp bên trong VS_FIXEDFILEINFO để sửa nó. –

+1

Trong Java 8 (có thể thấp hơn nữa), bạn phải thực hiện phương thức getFieldOrder(). những gì để đặt ở đó mặc dù ... Câu trả lời dưới đây bởi Antonis Zafiropoulos hoạt động tuy nhiên. – Mgamerz

2

Do vấn đề về tính di động, tôi tin rằng loại thông tin này không thực sự có sẵn trong java trừ khi bạn truy cập nó bằng cách sử dụng phương pháp tiếp cận ít di động hơn.

Ví dụ bạn có thể viết trình bao bọc bằng JNI và C++ và sử dụng GetFileVersionInfo API (xem thêm this JavaWorld tip) của Windows để nhận loại thông tin đó từ exe. Một cách tiếp cận khác là sử dụng một ứng dụng hoàn toàn bên ngoài để xuất ra phiên bản của tệp và sử dụng lớp Runtime để tạo một quy trình và tương tác với ứng dụng đó.

cách tiếp cận khác sẽ yêu cầu có quyền truy cập vào máy chủ và cung cấp phiên bản kiểm tra từ phía máy chủ:

  • file chứa số phiên bản trong tên của họ,
  • lưu một tập tin riêng biệt tiếp cận java mà có thể cung cấp phiên bản hiện tại
  • lưu ngày tải xuống ở phía máy chủ và kiểm tra xem phiên bản hiện tại có mới hơn ngày cuối cùng được tải xuống
  • kiểm tra md5 để xem phiên bản có khác hay không, trong trường hợp máy chủ chỉ có thể chứa các phiên bản mới hơn hoặc bằng nhau như phiên bản mới của khách hàng
+0

Tôi thích cách tiếp cận đó. Im sử dụng JNA trong các phần khác của dự án của tôi và nó đẹp hơn rất nhiều sau đó JNI vì vậy tôi sẽ làm điều tương tự bằng cách sử dụng JNA. cảm ơn – GEverding

1

Nếu bạn có nghĩa là thông tin bạn nhận được trong Thuộc tính-> Chi tiết trên Windows, hãy nhớ rằng tùy thuộc nền tảng của nó! Điều đó đang được nói SIGAR có các ràng buộc Java và một lớp học FileVersionInfo có vẻ gần với những gì bạn cần.

5

Để tham khảo, một phiên bản sửa đổi của mã bởi GEverding, với JNA 4, sử dụng com.sun.jna.platform.win32

package examples; 

import java.io.IOException; 

import com.sun.jna.Memory; 
import com.sun.jna.Pointer; 
import com.sun.jna.platform.win32.VerRsrc.VS_FIXEDFILEINFO; 
import com.sun.jna.ptr.IntByReference; 
import com.sun.jna.ptr.PointerByReference; 

public class FileVersion { 

    public static void main(String[] args) throws IOException { 

     String filePath = "C:\\Test\\chromeinstall.exe"; 

     IntByReference dwDummy = new IntByReference(); 
     dwDummy.setValue(0); 

     int versionlength = 
       com.sun.jna.platform.win32.Version.INSTANCE.GetFileVersionInfoSize(
         filePath, dwDummy); 

     byte[] bufferarray = new byte[versionlength]; 
     Pointer lpData = new Memory(bufferarray.length); 
     PointerByReference lplpBuffer = new PointerByReference(); 
     IntByReference puLen = new IntByReference(); 

     boolean fileInfoResult = 
       com.sun.jna.platform.win32.Version.INSTANCE.GetFileVersionInfo(
         filePath, 0, versionlength, lpData); 

     boolean verQueryVal = 
       com.sun.jna.platform.win32.Version.INSTANCE.VerQueryValue(
         lpData, "\\", lplpBuffer, puLen); 

     VS_FIXEDFILEINFO lplpBufStructure = new VS_FIXEDFILEINFO(lplpBuffer.getValue()); 
     lplpBufStructure.read(); 

     int v1 = (lplpBufStructure.dwFileVersionMS).intValue() >> 16; 
     int v2 = (lplpBufStructure.dwFileVersionMS).intValue() & 0xffff; 
     int v3 = (lplpBufStructure.dwFileVersionLS).intValue() >> 16; 
     int v4 = (lplpBufStructure.dwFileVersionLS).intValue() & 0xffff; 

     System.out.println(
       String.valueOf(v1) + "." + 
         String.valueOf(v2) + "." + 
         String.valueOf(v3) + "." + 
         String.valueOf(v4)); 
    } 
} 
1

tôi sửa đổi câu trả lời Antonis Zafiropoulos và tạo ra một lớp tiện dụng bạn có thể chỉ cần thả vào dự án của bạn. Lưu ý rằng các dòng fileInfoResult và verQueryVal phải tồn tại mặc dù chúng dường như không làm bất cứ điều gì.

package yourpackage; 

import com.sun.jna.Memory; 
import com.sun.jna.Pointer; 
import com.sun.jna.platform.win32.VerRsrc.VS_FIXEDFILEINFO; 
import com.sun.jna.ptr.IntByReference; 
import com.sun.jna.ptr.PointerByReference; 

public class EXEFileInfo { 
    public static int MAJOR = 0; 
    public static int MINOR = 1; 
    public static int BUILD = 2; 
    public static int REVISION = 3; 

    public static int getMajorVersionOfProgram(String path) { 
     return getVersionInfo(path)[MAJOR]; 
    } 

    public static int getMinorVersionOfProgram(String path) { 
     return getVersionInfo(path)[MINOR]; 
    } 

    public static int getBuildOfProgram(String path) { 
     return getVersionInfo(path)[BUILD]; 
    } 

    public static int getRevisionOfProgram(String path) { 
     return getVersionInfo(path)[REVISION]; 
    } 

    public static int[] getVersionInfo(String path) { 
     IntByReference dwDummy = new IntByReference(); 
     dwDummy.setValue(0); 

     int versionlength = com.sun.jna.platform.win32.Version.INSTANCE.GetFileVersionInfoSize(path, dwDummy); 

     byte[] bufferarray = new byte[versionlength]; 
     Pointer lpData = new Memory(bufferarray.length); 
     PointerByReference lplpBuffer = new PointerByReference(); 
     IntByReference puLen = new IntByReference(); 
     boolean fileInfoResult = com.sun.jna.platform.win32.Version.INSTANCE.GetFileVersionInfo(path, 0, versionlength, lpData); 
     boolean verQueryVal = com.sun.jna.platform.win32.Version.INSTANCE.VerQueryValue(lpData, "\\", lplpBuffer, puLen); 

     VS_FIXEDFILEINFO lplpBufStructure = new VS_FIXEDFILEINFO(lplpBuffer.getValue()); 
     lplpBufStructure.read(); 

     int v1 = (lplpBufStructure.dwFileVersionMS).intValue() >> 16; 
     int v2 = (lplpBufStructure.dwFileVersionMS).intValue() & 0xffff; 
     int v3 = (lplpBufStructure.dwFileVersionLS).intValue() >> 16; 
     int v4 = (lplpBufStructure.dwFileVersionLS).intValue() & 0xffff; 
     System.out.println("Version: " + v1 + "." + v2 + "." + v3 + "." + v4); 
     return new int[] { v1, v2, v3, v4 }; 
    } 
} 
0

Có giải pháp di động explained here (và câu hỏi này ít nhiều trùng lặp).

Về cơ bản, các cửa sổ có thể thực thi sử dụng định dạng PE (và các định dạng ELF của Linux) và bạn có thể sử dụng the pecoff4j library để đọc thông tin này theo cách di động.

Các vấn đề liên quan