Index: java/PlatformTools/.classpath
===================================================================
--- java/PlatformTools/.classpath	(revision 724)
+++ java/PlatformTools/.classpath	(revision 724)
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
Index: java/PlatformTools/.project
===================================================================
--- java/PlatformTools/.project	(revision 724)
+++ java/PlatformTools/.project	(revision 724)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>PlatformTools</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
Index: java/PlatformTools/.settings/org.eclipse.jdt.core.prefs
===================================================================
--- java/PlatformTools/.settings/org.eclipse.jdt.core.prefs	(revision 724)
+++ java/PlatformTools/.settings/org.eclipse.jdt.core.prefs	(revision 724)
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
Index: java/PlatformTools/src/net/oni2/platformtools/PlatformInformation.java
===================================================================
--- java/PlatformTools/src/net/oni2/platformtools/PlatformInformation.java	(revision 724)
+++ java/PlatformTools/src/net/oni2/platformtools/PlatformInformation.java	(revision 724)
@@ -0,0 +1,114 @@
+package net.oni2.platformtools;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Vector;
+
+import net.oni2.platformtools.applicationinvoker.ApplicationInvoker;
+import net.oni2.platformtools.applicationinvoker.ApplicationInvocationResult;
+import net.oni2.platformtools.applicationinvoker.EExeType;
+import net.oni2.platformtools.applicationinvoker.ERuntimeNotInstalledException;
+
+/**
+ * @author Christian Illy
+ */
+public class PlatformInformation {
+
+	/**
+	 * @author Christian Illy
+	 */
+	public enum Architecture {
+		/**
+		 * 32 bit
+		 */
+		X86,
+		/**
+		 * 64 bit
+		 */
+		AMD64
+	}
+
+	/**
+	 * @author Christian Illy
+	 */
+	public enum Platform {
+		/**
+		 * Running Windows
+		 */
+		WIN,
+		/**
+		 * Running MacOS
+		 */
+		MACOS,
+		/**
+		 * Running a Linux
+		 */
+		LINUX,
+		/**
+		 * Unknown OS
+		 */
+		UNKNOWN
+	}
+
+	private static Platform platform = null;
+	private static Architecture architecture = null;
+
+	/**
+	 * @return Processor architecture
+	 */
+	public static Architecture getArchitecture() {
+		if (architecture == null) {
+			switch (getPlatform()) {
+				case WIN:
+					String arch = System.getenv("PROCESSOR_ARCHITECTURE")
+							.toLowerCase();
+					if (arch.startsWith("x86"))
+						architecture = Architecture.X86;
+					architecture = Architecture.AMD64;
+					break;
+				case MACOS:
+				case LINUX:
+					Vector<String> params = new Vector<String>();
+					params.add("LONG_BIT");
+					ApplicationInvocationResult res = null;
+					try {
+						res = ApplicationInvoker.executeAndWait(
+								EExeType.OSBINARY, null, new File("getconf"),
+								params);
+					} catch (IOException e) {
+						e.printStackTrace();
+					} catch (ERuntimeNotInstalledException e) {
+						e.printStackTrace();
+					}
+					architecture = Architecture.X86;
+					if (res != null) {
+						if (res.output.get(0).equals("64"))
+							architecture = Architecture.AMD64;
+					}
+					break;
+				default:
+					architecture = null;
+			}
+		}
+		return architecture;
+	}
+
+	/**
+	 * @return The operating system running on
+	 */
+	public static Platform getPlatform() {
+		if (platform == null) {
+			String os = System.getProperty("os.name").toLowerCase();
+			if (os.startsWith("win"))
+				platform = Platform.WIN;
+			else if (os.startsWith("linux"))
+				platform = Platform.LINUX;
+			else if (os.startsWith("mac"))
+				platform = Platform.MACOS;
+			else
+				platform = Platform.UNKNOWN;
+		}
+		return platform;
+	}
+
+}
Index: java/PlatformTools/src/net/oni2/platformtools/WinRegistry.java
===================================================================
--- java/PlatformTools/src/net/oni2/platformtools/WinRegistry.java	(revision 724)
+++ java/PlatformTools/src/net/oni2/platformtools/WinRegistry.java	(revision 724)
@@ -0,0 +1,503 @@
+package net.oni2.platformtools;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.prefs.Preferences;
+
+/**
+ * @author Unknown
+ */
+public class WinRegistry {
+	/**
+	 * Constant for accessing HKCU
+	 */
+	public static final int HKEY_CURRENT_USER = 0x80000001;
+	/**
+	 * Constant for accessing HKLM
+	 */
+	public static final int HKEY_LOCAL_MACHINE = 0x80000002;
+	/**
+	 * Constant for successful accesses
+	 */
+	public static final int REG_SUCCESS = 0;
+	/**
+	 * Constant for not found
+	 */
+	public static final int REG_NOTFOUND = 2;
+	/**
+	 * Constant for access denied
+	 */
+	public static final int REG_ACCESSDENIED = 5;
+
+	/**
+	 * Access 32bit registry view when running as 64bit application
+	 */
+	public static final int KEY_WOW64_32KEY = 0x0200;
+	/**
+	 * Access 64bit registry view when running as 32bit application
+	 */
+	public static final int KEY_WOW64_64KEY = 0x0100;
+
+	private static final int KEY_ALL_ACCESS = 0xf003f;
+	private static final int KEY_READ = 0x20019;
+	private static Preferences userRoot = Preferences.userRoot();
+	private static Preferences systemRoot = Preferences.systemRoot();
+	private static Class<? extends Preferences> userClass = userRoot.getClass();
+	private static Method regOpenKey = null;
+	private static Method regCloseKey = null;
+	private static Method regQueryValueEx = null;
+	private static Method regEnumValue = null;
+	private static Method regQueryInfoKey = null;
+	private static Method regEnumKeyEx = null;
+	private static Method regCreateKeyEx = null;
+	private static Method regSetValueEx = null;
+	private static Method regDeleteKey = null;
+	private static Method regDeleteValue = null;
+
+	private static boolean usable = false;
+
+	static {
+		try {
+			regOpenKey = userClass.getDeclaredMethod("WindowsRegOpenKey",
+					new Class[] { int.class, byte[].class, int.class });
+			regOpenKey.setAccessible(true);
+			regCloseKey = userClass.getDeclaredMethod("WindowsRegCloseKey",
+					new Class[] { int.class });
+			regCloseKey.setAccessible(true);
+			regQueryValueEx = userClass.getDeclaredMethod(
+					"WindowsRegQueryValueEx", new Class[] { int.class,
+							byte[].class });
+			regQueryValueEx.setAccessible(true);
+			regEnumValue = userClass.getDeclaredMethod("WindowsRegEnumValue",
+					new Class[] { int.class, int.class, int.class });
+			regEnumValue.setAccessible(true);
+			regQueryInfoKey = userClass.getDeclaredMethod(
+					"WindowsRegQueryInfoKey1", new Class[] { int.class });
+			regQueryInfoKey.setAccessible(true);
+			regEnumKeyEx = userClass.getDeclaredMethod("WindowsRegEnumKeyEx",
+					new Class[] { int.class, int.class, int.class });
+			regEnumKeyEx.setAccessible(true);
+			regCreateKeyEx = userClass.getDeclaredMethod(
+					"WindowsRegCreateKeyEx", new Class[] { int.class,
+							byte[].class });
+			regCreateKeyEx.setAccessible(true);
+			regSetValueEx = userClass.getDeclaredMethod("WindowsRegSetValueEx",
+					new Class[] { int.class, byte[].class, byte[].class });
+			regSetValueEx.setAccessible(true);
+			regDeleteValue = userClass.getDeclaredMethod(
+					"WindowsRegDeleteValue", new Class[] { int.class,
+							byte[].class });
+			regDeleteValue.setAccessible(true);
+			regDeleteKey = userClass.getDeclaredMethod("WindowsRegDeleteKey",
+					new Class[] { int.class, byte[].class });
+			regDeleteKey.setAccessible(true);
+			usable = true;
+		} catch (Exception e) {
+			// e.printStackTrace();
+		}
+	}
+
+	private WinRegistry() {
+	}
+
+	/**
+	 * Read a value from key and value name
+	 * 
+	 * @param hkey
+	 *            HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
+	 * @param key
+	 *            Key to access
+	 * @param valueName
+	 *            Name of value to read
+	 * @param wow64
+	 *            0 for standard registry access (32-bits for 32-bit app,
+	 *            64-bits for 64-bits app) or KEY_WOW64_32KEY to force access to
+	 *            32-bit registry view, or KEY_WOW64_64KEY to force access to
+	 *            64-bit registry view
+	 * @return the value
+	 * @throws Exception
+	 *             If registry access impossible
+	 * @throws IllegalArgumentException
+	 *             On illegal arguments
+	 * @throws IllegalAccessException
+	 *             On illegal access
+	 * @throws InvocationTargetException
+	 *             On reflection problems
+	 */
+	public static String readString(int hkey, String key, String valueName,
+			int wow64) throws Exception, IllegalArgumentException,
+			IllegalAccessException, InvocationTargetException {
+		if (!usable)
+			throw new Exception(
+					"Registry access not supported (not a Windows OS?).");
+		if (hkey == HKEY_LOCAL_MACHINE) {
+			return readString(systemRoot, hkey, key, valueName, wow64);
+		} else if (hkey == HKEY_CURRENT_USER) {
+			return readString(userRoot, hkey, key, valueName, wow64);
+		} else {
+			throw new IllegalArgumentException("hkey=" + hkey);
+		}
+	}
+
+	/**
+	 * Read value(s) and value name(s) form given key
+	 * 
+	 * @param hkey
+	 *            HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
+	 * @param key
+	 *            Key to access
+	 * @param wow64
+	 *            0 for standard registry access (32-bits for 32-bit app,
+	 *            64-bits for 64-bits app) or KEY_WOW64_32KEY to force access to
+	 *            32-bit registry view, or KEY_WOW64_64KEY to force access to
+	 *            64-bit registry view
+	 * @return the value name(s) plus the value(s)
+	 * @throws Exception
+	 *             If registry access impossible
+	 * @throws IllegalArgumentException
+	 *             On illegal arguments
+	 * @throws IllegalAccessException
+	 *             On illegal access
+	 * @throws InvocationTargetException
+	 *             On reflection problems
+	 */
+	public static Map<String, String> readStringValues(int hkey, String key,
+			int wow64) throws Exception, IllegalArgumentException,
+			IllegalAccessException, InvocationTargetException {
+		if (!usable)
+			throw new Exception(
+					"Registry access not supported (not a Windows OS?).");
+		if (hkey == HKEY_LOCAL_MACHINE) {
+			return readStringValues(systemRoot, hkey, key, wow64);
+		} else if (hkey == HKEY_CURRENT_USER) {
+			return readStringValues(userRoot, hkey, key, wow64);
+		} else {
+			throw new IllegalArgumentException("hkey=" + hkey);
+		}
+	}
+
+	/**
+	 * Read the value name(s) from a given key
+	 * 
+	 * @param hkey
+	 *            HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
+	 * @param key
+	 *            Key to access
+	 * @param wow64
+	 *            0 for standard registry access (32-bits for 32-bit app,
+	 *            64-bits for 64-bits app) or KEY_WOW64_32KEY to force access to
+	 *            32-bit registry view, or KEY_WOW64_64KEY to force access to
+	 *            64-bit registry view
+	 * @return the value name(s)
+	 * @throws Exception
+	 *             If registry access impossible
+	 * @throws IllegalArgumentException
+	 *             On illegal arguments
+	 * @throws IllegalAccessException
+	 *             On illegal access
+	 * @throws InvocationTargetException
+	 *             On reflection problems
+	 */
+	public static List<String> readStringSubKeys(int hkey, String key, int wow64)
+			throws Exception, IllegalArgumentException, IllegalAccessException,
+			InvocationTargetException {
+		if (!usable)
+			throw new Exception(
+					"Registry access not supported (not a Windows OS?).");
+		if (hkey == HKEY_LOCAL_MACHINE) {
+			return readStringSubKeys(systemRoot, hkey, key, wow64);
+		} else if (hkey == HKEY_CURRENT_USER) {
+			return readStringSubKeys(userRoot, hkey, key, wow64);
+		} else {
+			throw new IllegalArgumentException("hkey=" + hkey);
+		}
+	}
+
+	/**
+	 * Create a key
+	 * 
+	 * @param hkey
+	 *            HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
+	 * @param key
+	 *            Key to access
+	 * @throws Exception
+	 *             If registry access impossible
+	 * @throws IllegalArgumentException
+	 *             On illegal arguments
+	 * @throws IllegalAccessException
+	 *             On illegal access
+	 * @throws InvocationTargetException
+	 *             On reflection problems
+	 */
+	public static void createKey(int hkey, String key) throws Exception,
+			IllegalArgumentException, IllegalAccessException,
+			InvocationTargetException {
+		int[] ret;
+		if (!usable)
+			throw new Exception(
+					"Registry access not supported (not a Windows OS?).");
+		if (hkey == HKEY_LOCAL_MACHINE) {
+			ret = createKey(systemRoot, hkey, key);
+			regCloseKey
+					.invoke(systemRoot, new Object[] { new Integer(ret[0]) });
+		} else if (hkey == HKEY_CURRENT_USER) {
+			ret = createKey(userRoot, hkey, key);
+			regCloseKey.invoke(userRoot, new Object[] { new Integer(ret[0]) });
+		} else {
+			throw new IllegalArgumentException("hkey=" + hkey);
+		}
+		if (ret[1] != REG_SUCCESS) {
+			throw new IllegalArgumentException("rc=" + ret[1] + "  key=" + key);
+		}
+	}
+
+	/**
+	 * Write a value in a given key/value name
+	 * 
+	 * @param hkey
+	 *            HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
+	 * @param key
+	 *            Key to access
+	 * @param valueName
+	 *            Name of value to write to
+	 * @param value
+	 *            String to write
+	 * @param wow64
+	 *            0 for standard registry access (32-bits for 32-bit app,
+	 *            64-bits for 64-bits app) or KEY_WOW64_32KEY to force access to
+	 *            32-bit registry view, or KEY_WOW64_64KEY to force access to
+	 *            64-bit registry view
+	 * @throws Exception
+	 *             If registry access impossible
+	 * @throws IllegalArgumentException
+	 *             On illegal arguments
+	 * @throws IllegalAccessException
+	 *             On illegal access
+	 * @throws InvocationTargetException
+	 *             On reflection problems
+	 */
+	public static void writeStringValue(int hkey, String key, String valueName,
+			String value, int wow64) throws Exception,
+			IllegalArgumentException, IllegalAccessException,
+			InvocationTargetException {
+		if (!usable)
+			throw new Exception(
+					"Registry access not supported (not a Windows OS?).");
+		if (hkey == HKEY_LOCAL_MACHINE) {
+			writeStringValue(systemRoot, hkey, key, valueName, value, wow64);
+		} else if (hkey == HKEY_CURRENT_USER) {
+			writeStringValue(userRoot, hkey, key, valueName, value, wow64);
+		} else {
+			throw new IllegalArgumentException("hkey=" + hkey);
+		}
+	}
+
+	/**
+	 * Delete a given key
+	 * 
+	 * @param hkey
+	 *            HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
+	 * @param key
+	 *            Key to delete
+	 * @throws Exception
+	 *             If registry access impossible
+	 * @throws IllegalArgumentException
+	 *             On illegal arguments
+	 * @throws IllegalAccessException
+	 *             On illegal access
+	 * @throws InvocationTargetException
+	 *             On reflection problems
+	 */
+	public static void deleteKey(int hkey, String key) throws Exception,
+			IllegalArgumentException, IllegalAccessException,
+			InvocationTargetException {
+		int rc = -1;
+		if (!usable)
+			throw new Exception(
+					"Registry access not supported (not a Windows OS?).");
+		if (hkey == HKEY_LOCAL_MACHINE) {
+			rc = deleteKey(systemRoot, hkey, key);
+		} else if (hkey == HKEY_CURRENT_USER) {
+			rc = deleteKey(userRoot, hkey, key);
+		}
+		if (rc != REG_SUCCESS) {
+			throw new IllegalArgumentException("rc=" + rc + "  key=" + key);
+		}
+	}
+
+	/**
+	 * delete a value from a given key/value name
+	 * 
+	 * @param hkey
+	 *            HKEY_CURRENT_USER/HKEY_LOCAL_MACHINE
+	 * @param key
+	 *            Key to access
+	 * @param value
+	 *            Name of value to delete
+	 * @param wow64
+	 *            0 for standard registry access (32-bits for 32-bit app,
+	 *            64-bits for 64-bits app) or KEY_WOW64_32KEY to force access to
+	 *            32-bit registry view, or KEY_WOW64_64KEY to force access to
+	 *            64-bit registry view
+	 * @throws Exception
+	 *             If registry access impossible
+	 * @throws IllegalArgumentException
+	 *             On illegal arguments
+	 * @throws IllegalAccessException
+	 *             On illegal access
+	 * @throws InvocationTargetException
+	 *             On reflection problems
+	 */
+	public static void deleteValue(int hkey, String key, String value, int wow64)
+			throws Exception, IllegalArgumentException, IllegalAccessException,
+			InvocationTargetException {
+		if (!usable)
+			throw new Exception(
+					"Registry access not supported (not a Windows OS?).");
+		int rc = -1;
+		if (hkey == HKEY_LOCAL_MACHINE) {
+			rc = deleteValue(systemRoot, hkey, key, value, wow64);
+		} else if (hkey == HKEY_CURRENT_USER) {
+			rc = deleteValue(userRoot, hkey, key, value, wow64);
+		}
+		if (rc != REG_SUCCESS) {
+			throw new IllegalArgumentException("rc=" + rc + "  key=" + key
+					+ "  value=" + value);
+		}
+	}
+
+	// ========================================================================
+	private static int deleteValue(Preferences root, int hkey, String key,
+			String value, int wow64) throws IllegalArgumentException,
+			IllegalAccessException, InvocationTargetException {
+		int[] handles = (int[]) regOpenKey.invoke(root, new Object[] {
+				new Integer(hkey), toCstr(key),
+				new Integer(KEY_ALL_ACCESS | wow64) });
+		if (handles[1] != REG_SUCCESS) {
+			return handles[1]; // can be REG_NOTFOUND, REG_ACCESSDENIED
+		}
+		int rc = ((Integer) regDeleteValue.invoke(root, new Object[] {
+				new Integer(handles[0]), toCstr(value) })).intValue();
+		regCloseKey.invoke(root, new Object[] { new Integer(handles[0]) });
+		return rc;
+	}
+
+	// ========================================================================
+	private static int deleteKey(Preferences root, int hkey, String key)
+			throws IllegalArgumentException, IllegalAccessException,
+			InvocationTargetException {
+		int rc = ((Integer) regDeleteKey.invoke(root, new Object[] {
+				new Integer(hkey), toCstr(key) })).intValue();
+		return rc; // can REG_NOTFOUND, REG_ACCESSDENIED, REG_SUCCESS
+	}
+
+	// ========================================================================
+	private static String readString(Preferences root, int hkey, String key,
+			String value, int wow64) throws IllegalArgumentException,
+			IllegalAccessException, InvocationTargetException {
+		int[] handles = (int[]) regOpenKey
+				.invoke(root, new Object[] { new Integer(hkey), toCstr(key),
+						new Integer(KEY_READ | wow64) });
+		if (handles[1] != REG_SUCCESS) {
+			return null;
+		}
+		byte[] valb = (byte[]) regQueryValueEx.invoke(root, new Object[] {
+				new Integer(handles[0]), toCstr(value) });
+		regCloseKey.invoke(root, new Object[] { new Integer(handles[0]) });
+		return (valb != null ? new String(valb).trim() : null);
+	}
+
+	// ========================================================================
+	private static Map<String, String> readStringValues(Preferences root,
+			int hkey, String key, int wow64) throws Exception,
+			IllegalArgumentException, IllegalAccessException,
+			InvocationTargetException {
+		HashMap<String, String> results = new HashMap<String, String>();
+		int[] handles = (int[]) regOpenKey
+				.invoke(root, new Object[] { new Integer(hkey), toCstr(key),
+						new Integer(KEY_READ | wow64) });
+		if (handles[1] != REG_SUCCESS) {
+			return null;
+		}
+		int[] info = (int[]) regQueryInfoKey.invoke(root,
+				new Object[] { new Integer(handles[0]) });
+
+		int count = info[2]; // count
+		int maxlen = info[4]; // value length max
+		for (int index = 0; index < count; index++) {
+			byte[] name = (byte[]) regEnumValue.invoke(root, new Object[] {
+					new Integer(handles[0]), new Integer(index),
+					new Integer(maxlen + 1) });
+			String value = readString(hkey, key, new String(name), wow64);
+			results.put(new String(name).trim(), value);
+		}
+		regCloseKey.invoke(root, new Object[] { new Integer(handles[0]) });
+		return results;
+	}
+
+	// ========================================================================
+	private static List<String> readStringSubKeys(Preferences root, int hkey,
+			String key, int wow64) throws IllegalArgumentException,
+			IllegalAccessException, InvocationTargetException {
+		List<String> results = new ArrayList<String>();
+		int[] handles = (int[]) regOpenKey
+				.invoke(root, new Object[] { new Integer(hkey), toCstr(key),
+						new Integer(KEY_READ | wow64) });
+		if (handles[1] != REG_SUCCESS) {
+			return null;
+		}
+		int[] info = (int[]) regQueryInfoKey.invoke(root,
+				new Object[] { new Integer(handles[0]) });
+
+		int count = info[0]; // Fix: info[2] was being used here with wrong
+								// results. Suggested by davenpcj, confirmed by
+								// Petrucio
+		int maxlen = info[3]; // value length max
+		for (int index = 0; index < count; index++) {
+			byte[] name = (byte[]) regEnumKeyEx.invoke(root, new Object[] {
+					new Integer(handles[0]), new Integer(index),
+					new Integer(maxlen + 1) });
+			results.add(new String(name).trim());
+		}
+		regCloseKey.invoke(root, new Object[] { new Integer(handles[0]) });
+		return results;
+	}
+
+	// ========================================================================
+	private static int[] createKey(Preferences root, int hkey, String key)
+			throws IllegalArgumentException, IllegalAccessException,
+			InvocationTargetException {
+		return (int[]) regCreateKeyEx.invoke(root, new Object[] {
+				new Integer(hkey), toCstr(key) });
+	}
+
+	// ========================================================================
+	private static void writeStringValue(Preferences root, int hkey,
+			String key, String valueName, String value, int wow64)
+			throws IllegalArgumentException, IllegalAccessException,
+			InvocationTargetException {
+		int[] handles = (int[]) regOpenKey.invoke(root, new Object[] {
+				new Integer(hkey), toCstr(key),
+				new Integer(KEY_ALL_ACCESS | wow64) });
+		regSetValueEx.invoke(root, new Object[] { new Integer(handles[0]),
+				toCstr(valueName), toCstr(value) });
+		regCloseKey.invoke(root, new Object[] { new Integer(handles[0]) });
+	}
+
+	// ========================================================================
+	// utility
+	private static byte[] toCstr(String str) {
+		byte[] result = new byte[str.length() + 1];
+
+		for (int i = 0; i < str.length(); i++) {
+			result[i] = (byte) str.charAt(i);
+		}
+		result[str.length()] = 0;
+		return result;
+	}
+}
Index: java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/ApplicationInvocationResult.java
===================================================================
--- java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/ApplicationInvocationResult.java	(revision 724)
+++ java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/ApplicationInvocationResult.java	(revision 724)
@@ -0,0 +1,43 @@
+package net.oni2.platformtools.applicationinvoker;
+
+import java.util.Vector;
+
+/**
+ * @author Christian Illy
+ */
+public class ApplicationInvocationResult {
+	/**
+	 * Returned error code
+	 */
+	public int errorCode;
+	/**
+	 * Call command line
+	 */
+	public Vector<String> cmdLine;
+	/**
+	 * Combined StdOut+ErrOut lines
+	 */
+	public Vector<String> output;
+	/**
+	 * Time the app was run for
+	 */
+	public int time;
+
+	/**
+	 * @param errorCode
+	 *            Error code from executed program
+	 * @param cmdLine
+	 *            Commandline of call
+	 * @param output
+	 *            Output of executed program
+	 * @param time
+	 *            Time of execution in ms
+	 */
+	public ApplicationInvocationResult(int errorCode, Vector<String> cmdLine,
+			Vector<String> output, int time) {
+		this.errorCode = errorCode;
+		this.cmdLine = cmdLine;
+		this.output = output;
+		this.time = time;
+	}
+}
Index: java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/ApplicationInvoker.java
===================================================================
--- java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/ApplicationInvoker.java	(revision 724)
+++ java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/ApplicationInvoker.java	(revision 724)
@@ -0,0 +1,181 @@
+package net.oni2.platformtools.applicationinvoker;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Date;
+import java.util.List;
+import java.util.Vector;
+
+import net.oni2.platformtools.PlatformInformation;
+import net.oni2.platformtools.PlatformInformation.Platform;
+
+/**
+ * @author Christian Illy
+ */
+public class ApplicationInvoker {
+	private static Vector<String> buildCommandLine(EExeType exeType,
+			File program, Vector<String> params)
+			throws ERuntimeNotInstalledException, FileNotFoundException {
+		if (program.getParentFile() != null && !program.exists())
+			throw new FileNotFoundException();
+		Vector<String> cmdLine = new Vector<String>();
+		switch (exeType) {
+			case DOTNET:
+				if (!DotNet.isInstalled())
+					throw new ERuntimeNotInstalledException(
+							"No .NET runtime found");
+				if (PlatformInformation.getPlatform() != Platform.WIN)
+					cmdLine.add(DotNet.getRuntimeExe().getPath());
+				cmdLine.add(program.getPath());
+				break;
+			case JAR:
+				if (!Java.isInstalled())
+					throw new ERuntimeNotInstalledException("JRE not found");
+				cmdLine.add(Java.getRuntimeExe().getPath());
+				cmdLine.add("-jar");
+				cmdLine.add(program.getPath());
+				break;
+			case OSBINARY:
+				cmdLine.add(program.getPath());
+				break;
+			case WINEXE:
+				switch (PlatformInformation.getPlatform()) {
+					case LINUX:
+						if (!Wine.isInstalled())
+							throw new ERuntimeNotInstalledException(
+									"Can not run Windows executable because Wine was not found");
+						cmdLine.add(Wine.getRuntimeExe().getPath());
+						cmdLine.add(program.getPath());
+						break;
+					case MACOS:
+						throw new ERuntimeNotInstalledException(
+								"Can not run a Windows executable on MacOS");
+					case WIN:
+						cmdLine.add(program.getPath());
+						break;
+					case UNKNOWN:
+						throw new ERuntimeNotInstalledException(
+								"Can not run a Windows executable on an unidentified system");
+				}
+				break;
+		}
+		if (params != null)
+			cmdLine.addAll(params);
+		return cmdLine;
+	}
+
+	/**
+	 * Execute a short running application and wait for termination
+	 * 
+	 * @param exeType
+	 *            Type of executable to be run
+	 * @param workingDirectory
+	 *            Working directory for executed process
+	 * @param program
+	 *            Executable path
+	 * @param params
+	 *            List of command and arguments
+	 * @return Error code and list of output lines
+	 * @throws IOException
+	 *             Exc
+	 * @throws ERuntimeNotInstalledException
+	 *             If the program to be executed requires a runtime which could
+	 *             not be found on the system
+	 * @throws FileNotFoundException
+	 *             Program to be executed not found
+	 */
+	public static ApplicationInvocationResult executeAndWait(EExeType exeType,
+			File workingDirectory, File program, Vector<String> params)
+			throws ERuntimeNotInstalledException, FileNotFoundException,
+			IOException {
+		return executeAndWait(workingDirectory,
+				buildCommandLine(exeType, program, params));
+	}
+
+	/**
+	 * Execute an app without waiting
+	 * 
+	 * @param exeType
+	 *            Type of executable to be run
+	 * @param workingDirectory
+	 *            Working directory for executed process
+	 * @param program
+	 *            Executable path
+	 * @param params
+	 *            List of command and arguments
+	 * @throws ERuntimeNotInstalledException
+	 *             If the program to be executed requires a runtime which could
+	 *             not be found on the system
+	 * @throws FileNotFoundException
+	 *             Program to be executed not found
+	 */
+	public static void execute(EExeType exeType, File workingDirectory,
+			File program, Vector<String> params)
+			throws ERuntimeNotInstalledException, FileNotFoundException {
+		execute(buildCommandLine(exeType, program, params), workingDirectory);
+	}
+
+	/**
+	 * Execute a short running application and wait for termination
+	 * 
+	 * @param workingDirectory
+	 *            Working directory for executed process
+	 * @param cmdLine
+	 *            List of command and arguments
+	 * @return Error code and list of output lines
+	 * @throws IOException
+	 *             Exc
+	 */
+	private static ApplicationInvocationResult executeAndWait(
+			File workingDirectory, Vector<String> cmdLine) throws IOException {
+		long start = new Date().getTime();
+		ProcessBuilder pb = new ProcessBuilder(cmdLine);
+		pb.redirectErrorStream(true);
+		Process proc = pb.start();
+		if (workingDirectory != null)
+			pb.directory(workingDirectory);
+
+		InputStream is = proc.getInputStream();
+		InputStreamReader isr = new InputStreamReader(is);
+		BufferedReader br = new BufferedReader(isr);
+
+		String line;
+		Vector<String> lines = new Vector<String>();
+
+		while ((line = br.readLine()) != null) {
+			lines.add(line);
+		}
+		try {
+			proc.waitFor();
+		} catch (InterruptedException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		return new ApplicationInvocationResult(proc.exitValue(), cmdLine,
+				lines, (int) (new Date().getTime() - start));
+	}
+
+	/**
+	 * Execute an app without waiting
+	 * 
+	 * @param cmd
+	 *            Command and parameters
+	 * @param workingDirectory
+	 *            Working directory of app
+	 */
+	private static void execute(List<String> cmd, File workingDirectory) {
+		try {
+			ProcessBuilder pb = new ProcessBuilder(cmd);
+			if (workingDirectory != null)
+				pb.directory(workingDirectory);
+			pb.start();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+}
Index: java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/DotNet.java
===================================================================
--- java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/DotNet.java	(revision 724)
+++ java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/DotNet.java	(revision 724)
@@ -0,0 +1,92 @@
+package net.oni2.platformtools.applicationinvoker;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+import java.util.Vector;
+
+import net.oni2.platformtools.PlatformInformation;
+import net.oni2.platformtools.PlatformInformation.Architecture;
+import net.oni2.platformtools.PlatformInformation.Platform;
+import net.oni2.platformtools.WinRegistry;
+import net.oni2.platformtools.applicationinvoker.ApplicationInvoker;
+import net.oni2.platformtools.applicationinvoker.ApplicationInvocationResult;
+
+/**
+ * @author Christian Illy
+ */
+public class DotNet {
+	private static File mono = null;
+	private static int isInst = -1;
+
+	/**
+	 * @return is a .NET implementation installed?
+	 */
+	public static boolean isInstalled() {
+		if (isInst < 0) {
+			isInst = 0;
+			switch (PlatformInformation.getPlatform()) {
+				case WIN:
+					try {
+						int view = WinRegistry.KEY_WOW64_32KEY;
+						if (PlatformInformation.getArchitecture() == Architecture.AMD64)
+							view = WinRegistry.KEY_WOW64_64KEY;
+
+						Map<String, String> m = WinRegistry
+								.readStringValues(
+										WinRegistry.HKEY_LOCAL_MACHINE,
+										"Software\\Microsoft\\NET Framework Setup\\NDP\\v2.0.50727",
+										view);
+						isInst = (m != null ? 1 : 0);
+					} catch (IllegalArgumentException e) {
+						e.printStackTrace();
+					} catch (IllegalAccessException e) {
+						e.printStackTrace();
+					} catch (InvocationTargetException e) {
+						e.printStackTrace();
+					} catch (Exception e) {
+						if (!e.getMessage()
+								.equals("Registry access not supported (not a Windows OS?)."))
+							e.printStackTrace();
+					}
+					break;
+				case MACOS:
+				case LINUX:
+					Vector<String> params = new Vector<String>();
+					params.add("mono");
+					ApplicationInvocationResult res = null;
+					try {
+						res = ApplicationInvoker.executeAndWait(EExeType.OSBINARY, null, new File("which"), params);
+					} catch (IOException e) {
+						e.printStackTrace();
+					} catch (ERuntimeNotInstalledException e) {
+						e.printStackTrace();
+					}
+					if (res != null) {
+						if (res.output.size() > 0) {
+							if (res.output.get(0).startsWith("/")
+									&& res.output.get(0).endsWith("mono")) {
+								isInst = 1;
+								mono = new File(res.output.get(0));
+							}
+						}
+					}
+					break;
+				default:
+					isInst = 0;
+			}
+		}
+		return isInst == 1;
+	}
+
+	/**
+	 * @return Get the .Net runtime executable name
+	 */
+	public static File getRuntimeExe() {
+		if (PlatformInformation.getPlatform() != Platform.WIN)
+			return mono;
+		return null;
+	}
+
+}
Index: java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/EExeType.java
===================================================================
--- java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/EExeType.java	(revision 724)
+++ java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/EExeType.java	(revision 724)
@@ -0,0 +1,23 @@
+package net.oni2.platformtools.applicationinvoker;
+
+/**
+ * @author Christian Illy
+ */
+public enum EExeType {
+	/**
+	 * Exe is an executable for the target platform
+	 */
+	OSBINARY,
+	/**
+	 * Exe is an Windows executable
+	 */
+	WINEXE,
+	/**
+	 * Exe is a .Net executable
+	 */
+	DOTNET,
+	/**
+	 * Exe is a Java .jar archive
+	 */
+	JAR
+}
Index: java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/ERuntimeNotInstalledException.java
===================================================================
--- java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/ERuntimeNotInstalledException.java	(revision 724)
+++ java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/ERuntimeNotInstalledException.java	(revision 724)
@@ -0,0 +1,16 @@
+package net.oni2.platformtools.applicationinvoker;
+
+/**
+ * @author Christian Illy
+ */
+public class ERuntimeNotInstalledException extends Exception {
+	/**
+	 * @param msg
+	 *            Cause
+	 */
+	public ERuntimeNotInstalledException(String msg) {
+		super(msg);
+	}
+
+	private static final long serialVersionUID = -7304001610863429671L;
+}
Index: java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/Java.java
===================================================================
--- java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/Java.java	(revision 724)
+++ java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/Java.java	(revision 724)
@@ -0,0 +1,45 @@
+package net.oni2.platformtools.applicationinvoker;
+
+import java.io.File;
+
+import net.oni2.platformtools.PlatformInformation;
+import net.oni2.platformtools.PlatformInformation.Platform;
+
+/**
+ * @author Christian Illy
+ */
+public class Java {
+	private static int isFound = -1;
+	private static File jre = null;
+
+	/**
+	 * @return Was a JRE found
+	 */
+	public static boolean isInstalled() {
+		if (isFound < 0) {
+			getRuntimeExe();
+		}
+		return isFound == 1;
+	}
+
+	/**
+	 * @return The JRE executable
+	 */
+	public static File getRuntimeExe() {
+		if (isFound < 0) {
+			File jrehome = new File(System.getProperties().getProperty(
+					"java.home"), "bin");
+			if (PlatformInformation.getPlatform() == Platform.WIN)
+				jre = new File(jrehome, "javaw.exe");
+			else
+				jre = new File(jrehome, "java");
+			if (!jre.exists()) {
+				isFound = 0;
+				jre = null;
+			} else {
+				isFound = 1;
+			}
+		}
+		return jre;
+	}
+}
Index: java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/Wine.java
===================================================================
--- java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/Wine.java	(revision 724)
+++ java/PlatformTools/src/net/oni2/platformtools/applicationinvoker/Wine.java	(revision 724)
@@ -0,0 +1,57 @@
+package net.oni2.platformtools.applicationinvoker;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Vector;
+
+import net.oni2.platformtools.PlatformInformation;
+import net.oni2.platformtools.PlatformInformation.Platform;
+
+/**
+ * @author Christian Illy
+ */
+public class Wine {
+	private static File winePath = null;
+	private static int isInst = -1;
+
+	/**
+	 * @return Is Wine installed?
+	 */
+	public static boolean isInstalled() {
+		if (isInst < 0)
+			getRuntimeExe();
+		return isInst == 1;
+	}
+
+	/**
+	 * @return path to wine, null if not found or not Linux
+	 */
+	public static File getRuntimeExe() {
+		if (isInst < 0) {
+			isInst = 0;
+			if (PlatformInformation.getPlatform() == Platform.LINUX) {
+				Vector<String> params = new Vector<String>();
+				params.add("wine");
+				ApplicationInvocationResult res = null;
+				try {
+					res = ApplicationInvoker.executeAndWait(EExeType.OSBINARY,
+							null, new File("which"), params);
+				} catch (IOException e) {
+					e.printStackTrace();
+				} catch (ERuntimeNotInstalledException e) {
+					e.printStackTrace();
+				}
+				if (res != null) {
+					if (res.output.size() > 0) {
+						if (res.output.get(0).startsWith("/")
+								&& res.output.get(0).endsWith("wine")) {
+							winePath = new File(res.output.get(0));
+							isInst = 1;
+						}
+					}
+				}
+			}
+		}
+		return winePath;
+	}
+}
