From f6405e08fc4f12129c85d1a8088a9f7104edc6ac Mon Sep 17 00:00:00 2001 From: Michael Freeman Date: Fri, 11 Dec 2015 20:34:21 -0500 Subject: [PATCH] added VersionUtil class and utility method for obtaining file version information --- CHANGES.md | 1 + .../com/sun/jna/platform/win32/VerRsrc.java | 32 ++++++++ .../sun/jna/platform/win32/VersionUtil.java | 77 +++++++++++++++++++ .../jna/platform/win32/VersionUtilTest.java | 43 +++++++++++ 4 files changed, 153 insertions(+) create mode 100644 contrib/platform/src/com/sun/jna/platform/win32/VersionUtil.java create mode 100644 contrib/platform/test/com/sun/jna/platform/win32/VersionUtilTest.java diff --git a/CHANGES.md b/CHANGES.md index 27e103741b..bca64c6c90 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -26,6 +26,7 @@ Features * [#554](https://github.com/java-native-access/jna/pull/554): Initial code for a few Unix 'libc' API(s) [@lgoldstein](https://github.com/lgoldstein) * [#552](https://github.com/java-native-access/jna/pull/552): Added `Module32FirstW` and `Module32NextW` to `com.sun.jna.platform.win32.Kernel32` (and helper to `com.sun.jna.platform.win32.Kernel32Util`) and `MODULEENTRY32W` structure to `com.sun.jna.platform.win32.Tlhelp32` - [@mlfreeman2](https://github.com/mlfreeman2). * [#564](https://github.com/java-native-access/jna/pull/564): Use generic definition of Native#loadLibrary [@lgoldstein](https://github.com/lgoldstein) +* [#562](https://github.com/java-native-access/jna/pull/562): Added `com.sun.jna.platform.win32.VersionUtil` with `getFileVersionInfo` utility method to get file major, minor, revision, and build version parts - [@mlfreeman2](https://github.com/mlfreeman2). Bug Fixes --------- diff --git a/contrib/platform/src/com/sun/jna/platform/win32/VerRsrc.java b/contrib/platform/src/com/sun/jna/platform/win32/VerRsrc.java index 2b69e978a7..8431a9f8be 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/VerRsrc.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/VerRsrc.java @@ -116,6 +116,38 @@ public VS_FIXEDFILEINFO(Pointer memory) { */ public WinDef.DWORD dwFileDateLS; + public int getFileVersionMajor() { + return dwFileVersionMS.intValue() >>> 16; + } + + public int getFileVersionMinor() { + return dwFileVersionMS.intValue() & 0xffff; + } + + public int getFileVersionRevision() { + return dwFileVersionLS.intValue() >>> 16; + } + + public int getFileVersionBuild() { + return dwFileVersionLS.intValue() & 0xffff; + } + + public int getProductVersionMajor() { + return dwProductVersionMS.intValue() >>> 16; + } + + public int getProductVersionMinor() { + return dwProductVersionMS.intValue() & 0xffff; + } + + public int getProductVersionRevision() { + return dwProductVersionLS.intValue() >>> 16; + } + + public int getProductVersionBuild() { + return dwProductVersionLS.intValue() & 0xffff; + } + protected List getFieldOrder() { return Arrays.asList(new String[] { "dwSignature", "dwStrucVersion", "dwFileVersionMS", "dwFileVersionLS", "dwProductVersionMS", "dwProductVersionLS", "dwFileFlagsMask", "dwFileFlags", "dwFileOS", "dwFileType", "dwFileSubtype", "dwFileDateMS", "dwFileDateLS" }); } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/VersionUtil.java b/contrib/platform/src/com/sun/jna/platform/win32/VersionUtil.java new file mode 100644 index 0000000000..bdfa1f618c --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/win32/VersionUtil.java @@ -0,0 +1,77 @@ +/* Copyright (c) 2015 Michael Freeman, All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ +package com.sun.jna.platform.win32; + +import com.sun.jna.Memory; +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.VerRsrc.VS_FIXEDFILEINFO; +import com.sun.jna.platform.win32.Version; +import com.sun.jna.platform.win32.Win32Exception; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.PointerByReference; + +/** + * Reads Windows Version info from files (the version details you can see by + * right-clicking and choosing properties) + * + * @author mlfreeman[at]gmail.com + */ +public class VersionUtil { + + /** + * Gets the file's version number info + * + * @param filePath + * The path to the file + * @return The VS_FIXEDFILEINFO structure read from the file.
+ * Use the getFileVersionMajor(), getFileVersionMinor(), + * getFileVersionRevision(), and getFileVersionBuild() + * @throws UnsupportedOperationException + * if VerQueryValue fails to get version info from the file. + */ + public static VS_FIXEDFILEINFO getFileVersionInfo(String filePath) { + IntByReference dwDummy = new IntByReference(); + + int versionLength = Version.INSTANCE.GetFileVersionInfoSize(filePath, dwDummy); + + // Reading version info failed. + // throw a Win32Exception with GetLastError() + if (versionLength == 0) { + throw new Win32Exception(Native.getLastError()); + } + + // buffer to hold version info + Pointer lpData = new Memory(versionLength); + + // pointer to pointer to location in aforementioned buffer + PointerByReference lplpBuffer = new PointerByReference(); + + if (!Version.INSTANCE.GetFileVersionInfo(filePath, 0, versionLength, lpData)) { + throw new Win32Exception(Native.getLastError()); + } + + // here to make VerQueryValue happy. + IntByReference puLen = new IntByReference(); + + // this does not set GetLastError, so no need to throw a Win32Exception + if (!Version.INSTANCE.VerQueryValue(lpData, "\\", lplpBuffer, puLen)) { + throw new UnsupportedOperationException("Unable to extract version info from the file: \"" + filePath + "\""); + } + + VS_FIXEDFILEINFO fileInfo = new VS_FIXEDFILEINFO(lplpBuffer.getValue()); + fileInfo.read(); + return fileInfo; + } + +} diff --git a/contrib/platform/test/com/sun/jna/platform/win32/VersionUtilTest.java b/contrib/platform/test/com/sun/jna/platform/win32/VersionUtilTest.java new file mode 100644 index 0000000000..eb8b397d8c --- /dev/null +++ b/contrib/platform/test/com/sun/jna/platform/win32/VersionUtilTest.java @@ -0,0 +1,43 @@ +/* This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ +package com.sun.jna.platform.win32; + +import java.io.File; + +import com.sun.jna.platform.win32.VerRsrc.VS_FIXEDFILEINFO; + +import junit.framework.TestCase; + +public class VersionUtilTest extends TestCase { + + public static void main(String[] args) { + junit.textui.TestRunner.run(VersionUtilTest.class); + } + + public void testGetFileVersionNumbers() { + String testFileName = "regedit.exe"; + File file = new File(System.getenv("SystemRoot"), testFileName); + assertTrue("Test file with version info in it should exist.", file.exists()); + + VS_FIXEDFILEINFO version = VersionUtil.getFileVersionInfo(file.getAbsolutePath()); + assertNotNull("Version info should have been returned.", version); + + assertTrue("The major file version number should be greater than 0 when pulling version from \"" + testFileName + "\"", version.getFileVersionMajor() > 0); + assertTrue("The minor file version number should be greater than or equal to 0 when pulling version from \"" + testFileName + "\"", version.getFileVersionMinor() >= 0); + assertTrue("The revision file version number should be greater than or equal to 0 when pulling version from \"" + testFileName + "\"", version.getFileVersionRevision() >= 0); + assertTrue("The build file version number should be greater than or equal to 0 when pulling version from \"" + testFileName + "\"", version.getFileVersionBuild() > 0); + + assertTrue("The major product version number should be greater than 0 when pulling version from \"" + testFileName + "\"", version.getProductVersionMajor() > 0); + assertTrue("The minor product version number should be greater than or equal to 0 when pulling version from \"" + testFileName + "\"", version.getProductVersionMinor() >= 0); + assertTrue("The revision product version number should be greater than or equal to 0 when pulling version from \"" + testFileName + "\"", version.getProductVersionRevision() >= 0); + assertTrue("The build product version number should be greater than or equal to 0 when pulling version from \"" + testFileName + "\"", version.getProductVersionBuild() > 0); + } +}