Только о двух вещах мы будем жалеть на смертном одре — что мало любили и мало путешествовали.
Марк Твен.
Человека делают счастливым три вещи: любовь, интересная работа и возможность путешествовать…
Иван Бунин

пятница, 7 мая 2010 г.

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

Столкнулась я с такой проблемкой - как получить версию файла (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.

Комментариев нет: