2011-08-02 29 views
7

¿Alguien sabe cómo consiguió obtener la información de la versión de un archivo ejecutable a través de Java. El caso es que tengo un archivo en mi sistema local y si la versión en el servidor es más nueva que la de mi sistema, necesito descargar el archivo del servidor.Obtenga información de la versión para .exe

+2

¿Qué quiere decir con la versión? –

+1

¿Por qué simplemente no hace una suma de comprobación md5? – Zaffy

+0

¿Te refieres a la metainformación (clic derecho y propiedades en Windows)? – dacwe

Respuesta

8

Después de pasar horas en línea y codificación encontré una solución usando JNA para obtener la información de la versión de un archivo.

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

Gracias por este código útil! Otra nota al margen para las personas que lo usan: si usa este código dentro de una clase con VS_FIXEDFILEINFO como una clase interna, puede obtener el error "Class com.sun.jna".La estructura no puede acceder a un getfield de miembro ". Si es así, simplemente agregue la palabra clave' public' a la clase interna VS_FIXEDFILEINFO para repararlo. –

+1

En Java 8 (quizás también más bajo), debe implementar un método getFieldOrder(). sin embargo, qué hay que poner ahí ... Sin embargo, la respuesta a continuación de Antonis Zafiropoulos funciona. – Mgamerz

2

Debido a problemas de portabilidad, creo que este tipo de información no está realmente disponible en Java a menos que acceda a ella utilizando un enfoque menos portátil.

Por ejemplo, podría escribir un contenedor utilizando JNI y C++ y usar el GetFileVersionInfo API (vea también this JavaWorld tip) de Windows para obtener ese tipo de información del exe. Otro enfoque sería usar una aplicación totalmente externa que muestre la versión del archivo y use la clase Runtime para crear un proceso e interactuar con esa aplicación.

Otros enfoques exigirán tener acceso al servidor y la disponibilidad para la comprobación de versión del lado del servidor:

  • archivos contienen el número de versión en su nombre,
  • guardar un archivo separado accesible para Java que puede proporcionar el versión actual
  • guarde la fecha de la descarga en el servidor y verifique si la versión actual es más nueva que la fecha en que se descargó la última
  • md5 para ver si la versión es diferente, en caso de que el servidor puede contener solo versiones más nuevas o igualmente nuevas que las del cliente
+0

Me gusta ese enfoque. Estoy usando JNA en otras partes de mi proyecto y es mucho mejor que JNI entonces haré lo mismo usando JNA. gracias – GEverding

1

Si se refiere a la información que obtiene en Propiedad-> Detalles en Windows, tenga en cuenta que depende de la plataforma. Dicho esto, SIGAR tiene enlaces Java y una clase FileVersionInfo que parece cercana a lo que necesita.

5

Como referencia, una versión modificada del código por GEverding, con JNA 4, usando 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

he modificado la respuesta de Antonis Zafiropoulos e hice una clase práctica puedes simplemente entrar en tu proyecto. Tenga en cuenta que las líneas fileInfoResult y verQueryVal deben existir aunque parezcan no hacer nada.

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

Hay una solución portátil explained here (y esta pregunta es más o menos un duplicado).

Básicamente, Windows ejecutable usa el formato PE (y Linux ELF) y puede usar the pecoff4j library para leer esta información de manera portátil.

Cuestiones relacionadas