Как стать автором
Обновить

Получаем версию файла (exe, dll) с помощью java

Время на прочтение4 мин
Количество просмотров4K
Столкнулась я с такой проблемкой — как получить версию файла (exe и dll) на java. Ведь обычными стандартными средствами определить это нельзя, а только лишь можно узнать размер, дату последней модификации и некоторые другие свойства файла. Это описано тут.
Покопавшись на форумах и всё хорошенько прогуглив — нашла два таких выхода — JNI и JNA. Остановилась на втором варианте, так как на С++ писать специальную dll ну уж очень не хотелось, хотелось всё решить с помощью java и обращаться напрямую к version.dll (C:\WINDOWS\system32).
В итоге решение сводится к такой связке GetFileVersionInfo GetFileVersionInfoSize VerQueryValue. Долго пришлось поразбираться с функцией VerQueryValue — сложность была в том, что версии файлы зависят от языка и необходимо было хитрым способом получить LANGANDCODEPAGE. В итоге получился такой класс:



package upload;

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.StdCallLibrary;
import java.io.IOException;

/**
*
* @author samozvanka
*/
public class Win32GetFileInformation
{
 //+ declare before using
 private static byte[] Hexhars = "«0123456789abcdef".getBytes();
 
 public String FileVersion;
 private String LanguageCodePage;
 private PointerByReference InfoData;
 
 public interface Win32VersionDLL extends StdCallLibrary
 {
  Win32VersionDLL INSTANCE = (Win32VersionDLL) Native.loadLibrary(
    "Version", Win32VersionDLL.class);
  
  Integer GetFileVersionInfoSizeA(String FilePath, IntByReference Handle);

  Boolean GetFileVersionInfoA(String FilePath, int Handle, int InfoSize,
    PointerByReference InfoData);

  Boolean VerQueryValueA(PointerByReference InfoData,
    String VersionInformation, PointerByReference VersionData,
    IntByReference DataSize);
 }

 public void Win32GetFileInformation(String FilePath) throws IOException
 {
  IntByReference unusedParam = new IntByReference();
  
  int infoSize = Win32VersionDLL.INSTANCE.GetFileVersionInfoSizeA(FilePath, unusedParam);
  if (infoSize == 0)
  {
   throw new IOException("File does not exist or has no information.");
  }

  this.InfoData = new PointerByReference();
  
  Boolean success = Win32VersionDLL.INSTANCE.GetFileVersionInfoA
  (
    FilePath,
    unusedParam.getValue(),
    infoSize,
    this.InfoData
  );
  
  //+ Assert(success, "GetFileVersionInfoA in Win32GetFileInformation is failed")
  
  PointerByReference versionDataByRef = new PointerByReference();
  IntByReference dataSize = new IntByReference();
  Pointer versionDataPointer = null;
  
  // Retrieve the language information
  success = Win32VersionDLL.INSTANCE.VerQueryValueA
  (
    this.InfoData,
    "\\VarFileInfo\\Translation",
    versionDataByRef,
    dataSize
  );
  
  //+ Assert(success, "VerQueryValueA in Win32GetFileInformation is failed")
  
  System.out.println("DataSize.getValue() = " + dataSize.getValue());
  
  versionDataPointer = versionDataByRef.getValue();
  byte[] codePageBytes = versionDataPointer.getByteArray(0, dataSize.getValue());
  byte BSwap;
  // swap 0<->1 and 2<->3
  BSwap = codePageBytes[1];
  codePageBytes[1] = codePageBytes[0];
  codePageBytes[0] = BSwap;
  BSwap = codePageBytes[3];
  codePageBytes[3] = codePageBytes[2];
  codePageBytes[2] = BSwap;
  // got 1,0,3,2
  
  this.LanguageCodePage = decode(codePageBytes).toUpperCase();
  
  //// Retrieve file information
  this.FileVersion = QueryValue("FileVersion");
  
  System.out.println("FileVersion = " + this.FileVersion);

 }

 private String QueryValue(String ValueName)
 {
  IntByReference dataSize = new IntByReference();
  PointerByReference versionDataByRef = new PointerByReference();
  Pointer versionDataPointer = null;
  Boolean success = Win32VersionDLL.INSTANCE.VerQueryValueA
  (
    this.InfoData,
    "\\StringFileInfo\\" + this.LanguageCodePage + "\\" + ValueName, //"
    versionDataByRef,
    dataSize
  );
  
  //+ Assert(success, "VerQueryValueA in Win32GetFileInformation is failed")
  
  versionDataPointer = versionDataByRef.getValue();
  if (versionDataPointer == null)
  {
   return "";
  }
  else
  {
   versionDataPointer = versionDataByRef.getValue();
   return versionDataPointer.getString();
  }
 }

 private static String decode(byte[] encodedString)
 {
  StringBuilder result = new StringBuilder(2 * encodedString.length);
  
  for (int i = 0; i < encodedString.length; i++)
  {
   int v = encodedString[i] & 0xff;
  
   result.append((char) Hexhars[v >> 4]);
   result.append((char) Hexhars[v & 0xf]);
  }
  
  return result.toString();
 }
}

* This source code was highlighted with Source Code Highlighter.


Вдруг кому пригодится. И если есть другие какие то несложные реализации этого, то хотелось бы их узнать.
Теги:
Хабы:
Всего голосов 41: ↑29 и ↓12+17
Комментарии30

Публикации

Истории

Работа

Java разработчик
355 вакансий

Ближайшие события