This is an automated email from the ASF dual-hosted git repository.

skygo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans-native-launchers.git

commit 1d019a29da279c15b4c3adf98ee2e56b6380c0de
Author: Jaroslav Tulach <jaroslav.tul...@oracle.com>
AuthorDate: Sun May 6 07:27:25 2018 +0200

    Moving the platform modules into their own subdirectory to lower the 
clutter in the root
---
 .dep.inc                     |   5 +
 Makefile                     | 107 +++++++
 argnames.h                   |  41 +++
 jvmlauncher.cpp              | 455 +++++++++++++++++++++++++++
 jvmlauncher.h                | 123 ++++++++
 nbexec.cpp                   |  63 ++++
 nbexec.exe.manifest          |  51 +++
 nbexec.rc                    |  26 ++
 nbexec_exe.rc                |  29 ++
 nbexecexe.cpp                |  32 ++
 nbexecloader.h               |  66 ++++
 nbproject/configurations.xml | 210 +++++++++++++
 nbproject/project.properties |  17 +
 nbproject/project.xml        |  49 +++
 platformlauncher.cpp         | 724 +++++++++++++++++++++++++++++++++++++++++++
 platformlauncher.h           | 111 +++++++
 utilsfuncs.cpp               | 449 +++++++++++++++++++++++++++
 utilsfuncs.h                 |  52 ++++
 version.h                    |  28 ++
 version.rc                   |  63 ++++
 20 files changed, 2701 insertions(+)

diff --git a/.dep.inc b/.dep.inc
new file mode 100755
index 0000000..4560e55
--- /dev/null
+++ b/.dep.inc
@@ -0,0 +1,5 @@
+# This code depends on make tool being used
+DEPFILES=$(wildcard $(addsuffix .d, ${OBJECTFILES}))
+ifneq (${DEPFILES},)
+include ${DEPFILES}
+endif
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ee8f7c1
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,107 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+#  Main targets can be executed directly, and they are:
+#  
+#     build                    build a specific configuration
+#     clean                    remove built files from a configuration
+#     clobber                  remove all built files
+#     all                      build all configurations
+#     help                     print help mesage
+#  
+#  Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and
+#  .help-impl are implemented in nbproject/makefile-impl.mk.
+#
+# NOCDDL
+
+# Environment 
+MKDIR=mkdir
+CP=cp
+CCADMIN=CCadmin
+RANLIB=ranlib
+
+
+
+# build
+build: .build-post-$(CONF)
+
+.build-pre:
+# Add your pre 'build' code here...
+
+.build-post-nbexec: .build-impl nbexecexe.cpp nbexecloader.h utilsfuncs.cpp 
nbexec_exe.rc
+       windres.exe -Ocoff nbexec_exe.rc nbexec_exe.res
+       g++ -s -mno-cygwin -Wl,--nxcompat -Wl,--dynamicbase -Wl,--no-seh 
-DNBEXEC_DLL=\"nbexec.dll\" nbexecexe.cpp utilsfuncs.cpp nbexec_exe.res -o 
nbexec.exe
+       cp nbexec.exe ../../../nbbuild/netbeans/platform/lib/
+       cp nbexec.dll ../../../nbbuild/netbeans/platform/lib/
+       
+.build-post-nbexec64: .build-impl nbexecexe.cpp nbexecloader.h utilsfuncs.cpp 
nbexec_exe.rc
+       x86_64-w64-mingw32-windres.exe -Ocoff nbexec_exe.rc nbexec_exe64.res 
+       x86_64-w64-mingw32-g++.exe -m64 -s -mno-cygwin -Wl,--nxcompat 
-Wl,--dynamicbase -DNBEXEC_DLL=\"nbexec64.dll\" -static-libgcc 
-static-libstdc++ nbexecexe.cpp utilsfuncs.cpp nbexec_exe64.res -o nbexec64.exe 
+       cp nbexec64.exe ../../../nbbuild/netbeans/platform/lib/
+       cp nbexec64.dll ../../../nbbuild/netbeans/platform/lib/
+
+
+
+# clean
+clean: .clean-post-$(CONF)
+
+.clean-pre:
+# Add your pre 'clean' code here...
+
+.clean-post-nbexec: .clean-impl
+       rm -f nbexec_exe32.res nbexec32.exe
+       
+.clean-post-nbexec64: .clean-impl
+       rm -f nbexec_exe64.res nbexec64.exe
+
+
+
+# clobber
+clobber: .clobber-post
+
+.clobber-pre:
+# Add your pre 'clobber' code here...
+
+.clobber-post: .clobber-impl
+# Add your post 'clobber' code here...
+
+
+
+# all
+all: .all-post
+
+.all-pre:
+# Add your pre 'all' code here...
+
+.all-post: .all-impl
+# Add your post 'all' code here...
+
+
+
+# help
+help: .help-post
+
+.help-pre:
+# Add your pre 'help' code here...
+
+.help-post: .help-impl
+# Add your post 'help' code here...
+
+
+
+# include project implementation makefile
+include nbproject/Makefile-impl.mk
diff --git a/argnames.h b/argnames.h
new file mode 100644
index 0000000..c4bdaba
--- /dev/null
+++ b/argnames.h
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef _ARGNAMES_H
+#define        _ARGNAMES_H
+
+#define ARG_NAME_SEPAR_PROC "--fork-java"
+#define ARG_NAME_CONSOLE    "--console"
+#define ARG_NAME_LAUNCHER_LOG "--trace"
+#define ARG_NAME_LA_START_APP "--la_start_app"
+#define ARG_NAME_LA_START_AU "--la_start_au"
+#define ARG_NAME_LA_PPID "--la_ppid"
+#define ARG_NAME_USER_DIR "--userdir"
+#define ARG_DEFAULT_USER_DIR_ROOT "--default_userdir_root"
+#define ARG_NAME_CACHE_DIR "--cachedir"
+#define ARG_NAME_CLUSTERS "--clusters"
+#define ARG_NAME_BOOTCLASS "--bootclass"
+#define ARG_NAME_JDKHOME "--jdkhome"
+#define ARG_NAME_CP_PREPEND "--cp:p"
+#define ARG_NAME_CP_APPEND "--cp:a"
+#define ARG_NAME_NOSPLASH "--nosplash"
+
+
+#endif /* _ARGNAMES_H */
+
diff --git a/jvmlauncher.cpp b/jvmlauncher.cpp
new file mode 100644
index 0000000..7e297f1
--- /dev/null
+++ b/jvmlauncher.cpp
@@ -0,0 +1,455 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ /*
+ * Author: Tomas Holy
+ */
+
+#include "jvmlauncher.h"
+#include <cassert>
+#include <fstream>
+
+using namespace std;
+
+const char *JvmLauncher::JDK_KEY = "Software\\JavaSoft\\Java Development Kit";
+const char *JvmLauncher::JRE_KEY = "Software\\JavaSoft\\Java Runtime 
Environment";
+const char *JvmLauncher::JDK_POST9_KEY = "Software\\JavaSoft\\JDK";
+const char *JvmLauncher::JRE_POST9_KEY = "Software\\JavaSoft\\JRE";
+const char *JvmLauncher::CUR_VERSION_NAME = "CurrentVersion";
+const char *JvmLauncher::JAVA_HOME_NAME = "JavaHome";
+const char *JvmLauncher::JAVA_BIN_DIR = "\\bin";
+const char *JvmLauncher::JAVA_EXE_FILE = "\\bin\\java.exe";
+const char *JvmLauncher::JAVAW_EXE_FILE = "\\bin\\javaw.exe";
+const char *JvmLauncher::JAVA_CLIENT_DLL_FILE = "\\bin\\client\\jvm.dll";
+const char *JvmLauncher::JAVA_SERVER_DLL_FILE = "\\bin\\server\\jvm.dll";
+const char *JvmLauncher::JAVA_JRE_PREFIX = "\\jre";
+const char *JvmLauncher::JNI_CREATEVM_FUNC = "JNI_CreateJavaVM";
+
+extern void exitHook(int status);
+
+JvmLauncher::JvmLauncher()
+    : suppressConsole(false) {
+}
+
+JvmLauncher::JvmLauncher(const JvmLauncher& orig) {
+}
+
+JvmLauncher::~JvmLauncher() {
+}
+
+bool JvmLauncher::checkJava(const char *path, const char *prefix) {
+    assert(path);
+    assert(prefix);
+    logMsg("checkJava(%s)", path);
+    javaPath = path;
+    if (*javaPath.rbegin() == '\\') {
+        javaPath.erase(javaPath.length() - 1, 1);
+    }
+    javaExePath = javaPath + prefix + JAVA_EXE_FILE;
+    javawExePath = javaPath + prefix + JAVAW_EXE_FILE;
+    javaClientDllPath = javaPath + prefix + JAVA_CLIENT_DLL_FILE;
+    javaServerDllPath = javaPath + prefix + JAVA_SERVER_DLL_FILE;
+    if (!fileExists(javaClientDllPath.c_str())) {
+        javaClientDllPath = "";
+    }
+    if (!fileExists(javaServerDllPath.c_str())) {
+        javaServerDllPath = "";
+    }
+    javaBinPath = javaPath + prefix + JAVA_BIN_DIR;
+    if (fileExists(javaExePath.c_str()) || !javaClientDllPath.empty() || 
!javaServerDllPath.empty()) {
+        if (!fileExists(javawExePath.c_str())) {
+            logMsg("javaw.exe not exists, forcing java.exe");
+            javawExePath = javaExePath;
+        }        
+        return true;
+    }
+
+    javaPath.clear();
+    javaBinPath.clear();
+    javaExePath.clear();
+    javawExePath.clear();
+    javaClientDllPath.clear();
+    javaServerDllPath.clear();
+    return false;
+}
+
+bool JvmLauncher::initialize(const char *javaPathOrMinVersion) {
+    logMsg("JvmLauncher::initialize()\n\tjavaPathOrMinVersion: %s", 
javaPathOrMinVersion);
+    assert(javaPathOrMinVersion);
+    if (isVersionString(javaPathOrMinVersion)) {
+        return findJava(javaPathOrMinVersion);
+    } else {
+        return (checkJava(javaPathOrMinVersion, JAVA_JRE_PREFIX) || 
checkJava(javaPathOrMinVersion, ""));
+    }
+}
+
+bool JvmLauncher::getJavaPath(string &path) {
+    logMsg("JvmLauncher::getJavaPath()");
+    path = javaPath;
+    return !javaPath.empty();
+}
+
+bool JvmLauncher::start(const char *mainClassName, const list<string> &args, 
const list<string> &options, bool &separateProcess, DWORD *retCode) {
+    assert(mainClassName);
+    logMsg("JvmLauncher::start()\n\tmainClassName: %s\n\tseparateProcess: %s",
+            mainClassName, separateProcess ? "true" : "false");
+    logMsg("  args:");
+    for (list<string>::const_iterator it = args.begin(); it != args.end(); 
++it) {
+        logMsg("\t%s", it->c_str());
+    }
+    logMsg("  options:");
+    for (list<string>::const_iterator it = options.begin(); it != 
options.end(); ++it) {
+        logMsg("\t%s", it->c_str());
+    }
+
+    if (!javaExePath.empty() && javaClientDllPath.empty() && 
javaServerDllPath.empty()) {
+        logMsg("Found only java.exe at %s. No DLLs. Falling back to 
java.exe\n", javaExePath.c_str());
+        separateProcess = true;
+    } else {
+        if (javaExePath.empty() || (javaClientDllPath.empty() && 
javaServerDllPath.empty())) {
+            if (!initialize("")) {
+                return false;
+            }
+        }
+    }  
+
+    if (!separateProcess) {
+        // both client/server found, check option which should be used
+        if (!javaClientDllPath.empty() && !javaServerDllPath.empty()) {
+            javaDllPath = findClientOption(options) ? javaClientDllPath : 
javaServerDllPath;
+        } else {
+            javaDllPath = javaClientDllPath.empty() ? javaServerDllPath : 
javaClientDllPath;
+        }
+
+        // it is necessary to absolutize dll path because current dir has to be
+        // temporarily changed for dll loading
+        char absoluteJavaDllPath[MAX_PATH] = "";
+        strncpy(absoluteJavaDllPath, javaDllPath.c_str(), MAX_PATH);
+        normalizePath(absoluteJavaDllPath, MAX_PATH);
+        javaDllPath = absoluteJavaDllPath;
+
+        logMsg("Java DLL path: %s", javaDllPath.c_str());
+        if (!canLoadJavaDll()) {
+            logMsg("Falling back to running Java in a separate process; DLL 
cannot be loaded (64-bit DLL?).");
+            separateProcess = true;
+        }
+    }
+
+    return separateProcess ? startOutProcJvm(mainClassName, args, options, 
retCode)
+            : startInProcJvm(mainClassName, args, options);
+}
+
+bool JvmLauncher::findClientOption(const list<string> &options) {
+    for (list<string>::const_iterator it = options.begin(); it != 
options.end(); ++it) {
+        if (*it == "-client") {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool JvmLauncher::canLoadJavaDll() {
+    // be prepared for stupid placement of msvcr71.dll in java installation
+    // (in java 1.6/1.7 jvm.dll is dynamically linked to msvcr71.dll which si 
placed
+    // in bin directory)
+    PrepareDllPath prepare(javaBinPath.c_str());
+    HMODULE hDll = LoadLibrary(javaDllPath.c_str());
+    if (hDll) {
+        FreeLibrary(hDll);
+        return true;
+    }
+    logErr(true, false, "Cannot load %s.", javaDllPath.c_str());
+    return false;
+}
+
+bool JvmLauncher::isVersionString(const char *str) {
+    char *end = 0;
+    strtod(str, &end);
+    return *end == '\0';
+}
+
+bool JvmLauncher::startInProcJvm(const char *mainClassName, const 
std::list<std::string> &args, const std::list<std::string> &options) {
+    class Jvm {
+    public:
+
+        Jvm(JvmLauncher *jvmLauncher)
+            : hDll(0)
+            , hSplash(0)
+            , jvm(0)
+            , env(0)
+            , jvmOptions(0)
+            , jvmLauncher(jvmLauncher)
+        {
+        }
+
+        ~Jvm() {
+            if (env && env->ExceptionOccurred()) {
+                env->ExceptionDescribe();
+            }
+
+            if (jvm) {
+                logMsg("Destroying JVM");
+                jvm->DestroyJavaVM();
+            }
+
+            if (jvmOptions) {
+                delete[] jvmOptions;
+            }
+
+            if (hDll) {
+                FreeLibrary(hDll);
+            }
+            if (hSplash) {
+                FreeLibrary(hSplash);
+            }
+        }
+
+        bool init(const list<string> &options) {
+            logMsg("JvmLauncher::Jvm::init()");
+            logMsg("LoadLibrary(\"%s\")", jvmLauncher->javaDllPath.c_str());
+            {
+                PrepareDllPath prepare(jvmLauncher->javaBinPath.c_str());
+                hDll = LoadLibrary(jvmLauncher->javaDllPath.c_str());
+                if (!hDll) {
+                    logErr(true, true, "Cannot load %s.", 
jvmLauncher->javaDllPath.c_str());
+                    return false;
+                }
+                
+                string pref = jvmLauncher->javaBinPath;
+                pref += "\\splashscreen.dll";
+                const string splash = pref;
+                logMsg("Trying to load %s", splash.c_str());
+                hSplash = LoadLibrary(splash.c_str());
+                logMsg("Splash loaded as %d", hSplash);
+            }
+
+            CreateJavaVM createJavaVM = (CreateJavaVM) GetProcAddress(hDll, 
JNI_CREATEVM_FUNC);
+            if (!createJavaVM) {
+                logErr(true, true, "GetProcAddress for %s failed.", 
JNI_CREATEVM_FUNC);
+                return false;
+            }
+
+            logMsg("JVM options:");
+            jvmOptions = new JavaVMOption[options.size() + 1];
+            int i = 0;
+            for (list<string>::const_iterator it = options.begin(); it != 
options.end(); ++it, ++i) {
+                const string &option = *it;
+                logMsg("\t%s", option.c_str());
+                if (option.find("-splash:") == 0 && hSplash > 0) {
+                    const string splash = option.substr(8);
+                    logMsg("splash at %s", splash.c_str());
+                    
+                    SplashInit splashInit = 
(SplashInit)GetProcAddress(hSplash, "SplashInit");
+                    SplashLoadFile splashLoadFile = 
(SplashLoadFile)GetProcAddress(hSplash, "SplashLoadFile");
+                    
+                    logMsg("splash init %d and load %d", splashInit, 
splashLoadFile);
+                    if (splashInit && splashLoadFile) {
+                        splashInit();
+                        splashLoadFile(splash.c_str());
+                    }
+                }
+                jvmOptions[i].optionString = (char *) option.c_str();
+                jvmOptions[i].extraInfo = 0;
+            }
+            JavaVMInitArgs jvmArgs;
+            jvmOptions[options.size()].optionString = (char *) "exit";
+            jvmOptions[options.size()].extraInfo    = (void *) &exitHook;
+            
+            jvmArgs.options = jvmOptions;
+            jvmArgs.nOptions = options.size() + 1;
+            jvmArgs.version = JNI_VERSION_1_4;
+            jvmArgs.ignoreUnrecognized = JNI_TRUE;
+
+            logMsg("Creating JVM...");
+            if (createJavaVM(&jvm, &env, &jvmArgs) < 0) {
+                logErr(false, true, "JVM creation failed");
+                return false;
+            }
+            logMsg("JVM created.");
+            return true;
+        }
+        typedef jint (CALLBACK *CreateJavaVM)(JavaVM **jvm, JNIEnv **env, void 
*args);
+        typedef void (CALLBACK *SplashInit)();
+        typedef int (CALLBACK *SplashLoadFile)(const char* file);
+
+        HMODULE hDll;
+        HMODULE hSplash;
+        JavaVM *jvm;
+        JNIEnv *env;
+        JavaVMOption *jvmOptions;
+        JvmLauncher *jvmLauncher;
+    };
+
+    Jvm jvm(this);
+    if (!jvm.init(options)) {
+        return false;
+    }
+
+    jclass mainClass = jvm.env->FindClass(mainClassName);
+    if (!mainClass) {
+        logErr(false, true, "Cannot find class %s.", mainClassName);
+        return false;
+    }
+
+    jmethodID mainMethod = jvm.env->GetStaticMethodID(mainClass, "main", 
"([Ljava/lang/String;)V");
+    if (!mainMethod) {
+        logErr(false, true, "Cannot get main method.");
+        return false;
+    }
+    
+    jclass jclassString = jvm.env->FindClass("java/lang/String");
+    if (!jclassString) {
+        logErr(false, true, "Cannot find java/lang/String class");
+        return false;
+    }
+
+    jstring jstringArg = jvm.env->NewStringUTF("");
+    if (!jstringArg) {
+        logErr(false, true, "NewStringUTF() failed");
+        return false;
+    }
+
+    jobjectArray mainArgs = jvm.env->NewObjectArray(args.size(), jclassString, 
jstringArg);
+    if (!mainArgs) {
+        logErr(false, true, "NewObjectArray() failed");
+        return false;
+    }
+    int i = 0;
+    for (list<string>::const_iterator it = args.begin(); it != args.end(); 
++it, ++i) {
+        const string &arg = *it;
+        const int len = 32*1024;
+        char utf8[len] = "";
+        if (convertAnsiToUtf8(arg.c_str(), utf8, len))
+            logMsg("Conversion to UTF8 failed");
+        jstring jstringArg = jvm.env->NewStringUTF(utf8);
+        if (!jstringArg) {
+            logErr(false, true, "NewStringUTF() failed");
+            return false;
+        }
+        jvm.env->SetObjectArrayElement(mainArgs, i, jstringArg);
+    }
+
+    jvm.env->CallStaticVoidMethod(mainClass, mainMethod, mainArgs);
+    return true;
+}
+
+
+bool JvmLauncher::startOutProcJvm(const char *mainClassName, const 
std::list<std::string> &args, const std::list<std::string> &options, DWORD 
*retCode) {
+    string cmdLine = '\"' + (suppressConsole ? javawExePath : javaExePath) + 
'\"';
+    cmdLine.reserve(32*1024);
+    for (list<string>::const_iterator it = options.begin(); it != 
options.end(); ++it) {
+        cmdLine += " \"";
+        cmdLine += *it;
+        cmdLine += "\"";
+    }
+    
+    // mainClass and args
+    cmdLine += ' ';
+    cmdLine += mainClassName;
+    for (list<string>::const_iterator it = args.begin(); it != args.end(); 
++it) {
+        if (javaClientDllPath.empty() && *it == "-client") {
+            logMsg("Removing -client option, client java dll not found.");
+            // remove client parameter, no client java found
+            continue;
+        }
+        cmdLine += " \"";
+        cmdLine += *it;
+        cmdLine += "\"";
+    }
+
+    logMsg("Command line:\n%s", cmdLine.c_str());
+    if (cmdLine.size() >= 32*1024) {
+        logErr(false, true, "Command line is too long. Length: %u. Maximum 
length: %u.", cmdLine.c_str(), 32*1024);
+        return false;
+    }
+
+    STARTUPINFO si = {0};
+    si.cb = sizeof (STARTUPINFO);
+    PROCESS_INFORMATION pi = {0};
+
+    char cmdLineStr[32*1024] = "";
+    strcpy(cmdLineStr, cmdLine.c_str());
+    if (!CreateProcess(NULL, cmdLineStr, NULL, NULL, FALSE, CREATE_SUSPENDED, 
NULL, NULL, &si, &pi)) {
+        logErr(true, true, "Failed to create process");
+        return false;
+    }
+
+    disableFolderVirtualization(pi.hProcess);
+    ResumeThread(pi.hThread);
+    WaitForSingleObject(pi.hProcess, INFINITE);
+    if (retCode) {
+        GetExitCodeProcess(pi.hProcess, retCode);
+    }
+    CloseHandle(pi.hProcess);
+    CloseHandle(pi.hThread);
+    return true;
+}
+
+bool JvmLauncher::findJava(const char *minJavaVersion) {
+    // scan for registry for jdk/jre version 9
+    if (findJava(JDK_POST9_KEY, "", minJavaVersion)) {
+        return true;
+    }
+    if (findJava(JRE_POST9_KEY, "", minJavaVersion)) {
+        return true;
+    }
+    if (findJava(JDK_KEY, JAVA_JRE_PREFIX, minJavaVersion)) {
+        return true;
+    }
+    if (findJava(JRE_KEY, "", minJavaVersion)) {
+        return true;
+    }
+    javaPath = "";
+    javaExePath = "";
+    javaClientDllPath = "";
+    javaServerDllPath = "";
+    javaBinPath = "";
+    return false;  
+}
+
+bool JvmLauncher::findJava(const char *javaKey, const char *prefix, const char 
*minJavaVersion) {
+    logMsg("JvmLauncher::findJava()\n\tjavaKey: %s\n\tprefix: 
%s\n\tminJavaVersion: %s", javaKey, prefix, minJavaVersion);
+    string value;
+    bool result = false;
+    if (getStringFromRegistry(HKEY_LOCAL_MACHINE, javaKey, CUR_VERSION_NAME, 
value)) {
+        if (value >= minJavaVersion) {
+            string path;
+            if (getStringFromRegistry(HKEY_LOCAL_MACHINE, (string(javaKey) + 
"\\" + value).c_str(), JAVA_HOME_NAME, path)) {
+                if (*path.rbegin() == '\\') {
+                    path.erase(path.length() - 1, 1);
+                }                
+                result = checkJava(path.c_str(), prefix);
+            }
+        }
+    }
+    if(!result && isWow64()) {
+        if (getStringFromRegistry64bit(HKEY_LOCAL_MACHINE, javaKey, 
CUR_VERSION_NAME, value)) {
+            if (value >= minJavaVersion) {
+                string path;
+                if (getStringFromRegistry64bit(HKEY_LOCAL_MACHINE, 
(string(javaKey) + "\\" + value).c_str(), JAVA_HOME_NAME, path)) {
+                    if (*path.rbegin() == '\\') {
+                        path.erase(path.length() - 1, 1);
+                    }
+                    result = checkJava(path.c_str(), prefix);
+                }
+            }
+        }
+    } 
+    // probably also need to check 32bit registry when launcher becomes 64-bit 
but is not the case now.   
+    return result;    
+}
diff --git a/jvmlauncher.h b/jvmlauncher.h
new file mode 100644
index 0000000..01f4e34
--- /dev/null
+++ b/jvmlauncher.h
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ /*
+ * Author: Tomas Holy
+ */
+
+#ifndef _JVMLAUNCHER_H
+#define        _JVMLAUNCHER_H
+
+#include <windows.h>
+#include <string>
+#include <list>
+#include "jni.h"
+#include "utilsfuncs.h"
+
+class JvmLauncher {
+    static const int MAX_ARGS_LEN = 32*1024;
+
+    static const char *JDK_KEY;
+    static const char *JRE_KEY;
+    // registry key change starting with version 9 
+    static const char *JDK_POST9_KEY;
+    static const char *JRE_POST9_KEY;
+    static const char *CUR_VERSION_NAME;
+    static const char *JAVA_HOME_NAME;
+    static const char *JAVA_BIN_DIR;
+    static const char *JAVA_EXE_FILE;
+    static const char *JAVAW_EXE_FILE;
+    static const char *JAVA_CLIENT_DLL_FILE;
+    static const char *JAVA_SERVER_DLL_FILE;
+    static const char *JAVA_JRE_PREFIX;
+    static const char *JNI_CREATEVM_FUNC;
+
+public:
+    JvmLauncher();
+    virtual ~JvmLauncher();
+
+    bool initialize(const char *javaPathOrMinVersion);
+    bool getJavaPath(std::string &path);
+    bool start(const char *mainClassName, const std::list<std::string> &args, 
const std::list<std::string> &options, bool &separateProcess, DWORD *retCode);
+
+    void setSuppressConsole(bool val) {
+        suppressConsole = val;
+    }
+
+private:
+    JvmLauncher(const JvmLauncher& orig);
+
+    bool checkJava(const char *javaPath, const char *prefix);
+    bool findJava(const char *minJavaVersion);
+    bool findJava(const char *javaKey, const char *prefix, const char 
*minJavaVersion);
+    bool startOutProcJvm(const char *mainClassName, const 
std::list<std::string> &args, const std::list<std::string> &options, DWORD 
*retCode);
+    bool startInProcJvm(const char *mainClassName, const 
std::list<std::string> &args, const std::list<std::string> &options);
+    bool isVersionString(const char *str);
+    bool canLoadJavaDll();
+    bool findClientOption(const std::list<std::string> &options);
+
+private:
+    bool suppressConsole;
+    std::string javaExePath;
+    std::string javawExePath;
+    std::string javaDllPath;
+    std::string javaClientDllPath;
+    std::string javaServerDllPath;
+    std::string javaPath;
+    std::string javaBinPath;
+
+    class PrepareDllPath {
+    public:
+        PrepareDllPath(const char *dllDirectory)
+            : setDllDirectory(0) {
+            logMsg("PrepareDllPath: %s", dllDirectory);
+            oldCurDir[0] = '\0';
+
+            // SetDllDirectory is present since XP SP1, so we have to load it 
dynamically
+            HINSTANCE hKernel32 = GetModuleHandle("kernel32");
+            if (!hKernel32) {
+                logErr(true, false, "Cannot load kernel32.");
+                return;
+            }
+
+            LPFNSDD setDllDirectory = (LPFNSDD)GetProcAddress(hKernel32, 
"SetDllDirectoryA");
+            if (setDllDirectory) {
+                setDllDirectory(dllDirectory);
+            } else {
+                logErr(true, false, "Cannot find SetDllDirectoryA");
+            }
+            GetCurrentDirectory(MAX_PATH, oldCurDir);
+            SetCurrentDirectory(dllDirectory);
+        }
+        ~PrepareDllPath() {
+            if (setDllDirectory) {
+                setDllDirectory(NULL);
+            }
+            if (oldCurDir[0]) {
+                SetCurrentDirectory(oldCurDir);
+            }
+        }
+    private:
+        typedef BOOL (WINAPI *LPFNSDD)(LPCTSTR lpPathname);
+        LPFNSDD setDllDirectory;
+        char oldCurDir[MAX_PATH];
+    };
+};
+
+#endif /* _JVMLAUNCHER_H */
+
diff --git a/nbexec.cpp b/nbexec.cpp
new file mode 100644
index 0000000..2e63d02
--- /dev/null
+++ b/nbexec.cpp
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ /*
+ * Author: Tomas Holy
+ */
+
+#include "platformlauncher.h"
+#include "utilsfuncs.h"
+
+PlatformLauncher launcher;
+
+extern "C" BOOL APIENTRY DllMain(HANDLE hModule,
+        DWORD ul_reason_for_call,
+        LPVOID lpReserved
+        ) {
+    switch (ul_reason_for_call) {
+        case DLL_PROCESS_ATTACH:
+            break;
+        case DLL_THREAD_ATTACH:
+            break;
+        case DLL_THREAD_DETACH:
+            break;
+        case DLL_PROCESS_DETACH:
+            launcher.onExit();
+            break;
+    }
+    return TRUE;
+}
+
+void exitHook(int status) {
+    logMsg("Exit hook called with status %d", status);
+    launcher.onExit();
+}
+
+#define NBEXEC_EXPORT extern "C" __declspec(dllexport)
+
+NBEXEC_EXPORT int startPlatform(int argc, char *argv[], const char *helpMsg) {
+    DWORD retCode = 0;
+    launcher.appendToHelp(helpMsg);
+    launcher.setSuppressConsole(!isConsoleAttached());
+    if (!launcher.start(argv, argc, &retCode)) {
+        return -1;
+    }
+    return retCode;
+}
+
+
diff --git a/nbexec.exe.manifest b/nbexec.exe.manifest
new file mode 100644
index 0000000..da15223
--- /dev/null
+++ b/nbexec.exe.manifest
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<assemblyIdentity version="9.0.0.0"
+   processorArchitecture="X86"
+   name="nbexec.exe"
+   type="win32"/>
+
+<description>nbexec Process.</description>
+<dependency>
+  <dependentAssembly>
+    <assemblyIdentity
+      type="win32"
+      name="Microsoft.Windows.Common-Controls"
+      version="6.0.0.0"
+      processorArchitecture="*"
+      publicKeyToken="6595b64144ccf1df"
+      language="*"
+    />
+  </dependentAssembly>
+</dependency>
+<!-- Identify the application security requirements. -->
+<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+  <security>
+    <requestedPrivileges>
+      <requestedExecutionLevel
+        level="asInvoker"
+        uiAccess="false"/>
+      </requestedPrivileges>
+     </security>
+</trustInfo>
+</assembly>
diff --git a/nbexec.rc b/nbexec.rc
new file mode 100644
index 0000000..b0843af
--- /dev/null
+++ b/nbexec.rc
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <winuser.h>
+
+#define FNAME "nbexec.dll"
+#define FILETYPE_ID 0x2L
+
+#include "version.rc"
+
diff --git a/nbexec_exe.rc b/nbexec_exe.rc
new file mode 100644
index 0000000..598b6c0
--- /dev/null
+++ b/nbexec_exe.rc
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <winuser.h>
+
+#define FNAME "nbexec.exe"
+#define FILETYPE_ID 0x1L
+
+#include "version.rc"
+
+
+CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "nbexec.exe.manifest"
+
diff --git a/nbexecexe.cpp b/nbexecexe.cpp
new file mode 100644
index 0000000..181a365
--- /dev/null
+++ b/nbexecexe.cpp
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ /*
+ * Author: Tomas Holy
+ */
+
+#include <windows.h>
+#include "nbexecloader.h"
+
+int main(int argc, char *argv[]) {
+    checkLoggingArg(argc, argv, true);
+    NBExecLoader loader;
+    
+    // NBEXEC_DLL specified in preprocessor definitions
+    return loader.start(NBEXEC_DLL, argc - 1, argv + 1);  
+}
diff --git a/nbexecloader.h b/nbexecloader.h
new file mode 100644
index 0000000..221a557
--- /dev/null
+++ b/nbexecloader.h
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef _NBEXECLOADER_H
+#define        _NBEXECLOADER_H
+
+#include "utilsfuncs.h"
+
+#define HELP_MSG \
+"\
+  --console suppress    supppress console output\n\
+  --console new         open new console for output\n\
+\n"
+
+class NBExecLoader {
+    typedef int (*StartPlatform)(int argc, char *argv[], const char *help);
+
+public:
+    NBExecLoader()
+        : hLib(0) {
+    }
+    ~NBExecLoader() {
+        if (hLib) {
+            FreeLibrary(hLib);
+        }
+    }
+    int start(const char *path, int argc, char *argv[]) {
+        if (!hLib) {
+            hLib = LoadLibrary(path);
+            if (!hLib) {
+                logErr(true, true, "Cannot load \"%s\".", path);
+                return -1;
+            }
+        }
+
+        StartPlatform startPlatform = (StartPlatform) GetProcAddress(hLib, 
"startPlatform");
+        if (!startPlatform) {
+            logErr(true, true, "Cannot start platform, failed to find 
startPlatform() in %s", path);
+            return -1;
+        }
+        logMsg("Starting platform...\n");
+        return startPlatform(argc, argv, HELP_MSG);
+    }
+
+private:
+    HMODULE hLib;
+};
+
+#endif /* _NBEXECLOADER_H */
+
diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml
new file mode 100644
index 0000000..0121be8
--- /dev/null
+++ b/nbproject/configurations.xml
@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<configurationDescriptor version="100">
+  <logicalFolder name="root" displayName="root" projectFiles="true" 
kind="ROOT">
+    <logicalFolder name="HeaderFiles"
+                   displayName="Header Files"
+                   projectFiles="true">
+      <itemPath>argnames.h</itemPath>
+      <itemPath>jvmlauncher.h</itemPath>
+      <itemPath>platformlauncher.h</itemPath>
+      <itemPath>utilsfuncs.h</itemPath>
+      <itemPath>version.h</itemPath>
+    </logicalFolder>
+    <logicalFolder name="ResourceFiles"
+                   displayName="Resource Files"
+                   projectFiles="true">
+      <itemPath>nbexec.exe.manifest</itemPath>
+      <itemPath>nbexec.rc</itemPath>
+      <itemPath>nbexec_exe.rc</itemPath>
+      <itemPath>version.rc</itemPath>
+    </logicalFolder>
+    <logicalFolder name="SourceFiles"
+                   displayName="Source Files"
+                   projectFiles="true">
+      <itemPath>jvmlauncher.cpp</itemPath>
+      <itemPath>nbexec.cpp</itemPath>
+      <itemPath>nbexecexe.cpp</itemPath>
+      <itemPath>nbexecloader.h</itemPath>
+      <itemPath>platformlauncher.cpp</itemPath>
+      <itemPath>utilsfuncs.cpp</itemPath>
+    </logicalFolder>
+    <logicalFolder name="ExternalFiles"
+                   displayName="Important Files"
+                   projectFiles="false">
+      <itemPath>Makefile</itemPath>
+    </logicalFolder>
+    <logicalFolder name="ExternalFiles"
+                   displayName="Important Files"
+                   projectFiles="false">
+      <itemPath>Makefile</itemPath>
+    </logicalFolder>
+  </logicalFolder>
+  <projectmakefile>Makefile</projectmakefile>
+  <confs>
+    <conf name="nbexec" type="2">
+      <toolsSet>
+        <compilerSet>Cygwin|Cygwin</compilerSet>
+        <dependencyChecking>true</dependencyChecking>
+        <rebuildPropChanged>false</rebuildPropChanged>
+      </toolsSet>
+      <compileType>
+        <cTool>
+          <developmentMode>5</developmentMode>
+          <warningLevel>2</warningLevel>
+        </cTool>
+        <ccTool>
+          <developmentMode>5</developmentMode>
+          <stripSymbols>true</stripSymbols>
+          <architecture>1</architecture>
+          <incDir>
+            <pElem>C:/Program Files/Java/jdk1.8.0_77/include</pElem>
+            <pElem>C:/Program Files/Java/jdk1.8.0_77/include/win32</pElem>
+          </incDir>
+          <commandLine>-mno-cygwin</commandLine>
+          <preprocessorList>
+            <Elem>NBEXEC_DLL="nbexec.dll"</Elem>
+          </preprocessorList>
+        </ccTool>
+        <linkerTool>
+          <output>nbexec.dll</output>
+          <additionalDep>${OBJECTDIR}/nbexec.res</additionalDep>
+          <linkerLibItems>
+            <linkerOptionItem>${OBJECTDIR}/nbexec.res</linkerOptionItem>
+          </linkerLibItems>
+          <commandLine>-Wl,--nxcompat -Wl,--dynamicbase 
-Wl,--no-seh</commandLine>
+        </linkerTool>
+      </compileType>
+      <item path="argnames.h" ex="false" tool="3" flavor2="0">
+      </item>
+      <item path="jvmlauncher.cpp" ex="false" tool="1" flavor2="0">
+      </item>
+      <item path="jvmlauncher.h" ex="false" tool="3" flavor2="0">
+      </item>
+      <item path="nbexec.cpp" ex="false" tool="1" flavor2="0">
+      </item>
+      <item path="nbexec.exe.manifest" ex="false" tool="3" flavor2="0">
+      </item>
+      <item path="nbexec.rc" ex="false" tool="3" flavor2="0">
+        <customTool>
+          <customToolCommandline>windres.exe -Ocoff nbexec.rc 
${OBJECTDIR}/nbexec.res</customToolCommandline>
+          <customToolDescription>Compiling Resource 
files...</customToolDescription>
+          <customToolOutputs>${OBJECTDIR}/nbexec.res</customToolOutputs>
+          <customToolAdditionalDep>version.h</customToolAdditionalDep>
+        </customTool>
+      </item>
+      <item path="nbexec_exe.rc" ex="false" tool="3" flavor2="0">
+        <customTool>
+          <customToolDescription></customToolDescription>
+        </customTool>
+      </item>
+      <item path="nbexecexe.cpp" ex="false" tool="1" flavor2="0">
+      </item>
+      <item path="nbexecloader.h" ex="false" tool="3" flavor2="0">
+      </item>
+      <item path="platformlauncher.cpp" ex="false" tool="1" flavor2="0">
+      </item>
+      <item path="platformlauncher.h" ex="false" tool="3" flavor2="0">
+      </item>
+      <item path="utilsfuncs.cpp" ex="false" tool="1" flavor2="0">
+      </item>
+      <item path="utilsfuncs.h" ex="false" tool="3" flavor2="0">
+      </item>
+      <item path="version.h" ex="false" tool="3" flavor2="0">
+      </item>
+      <item path="version.rc" ex="false" tool="3" flavor2="0">
+      </item>
+    </conf>
+    <conf name="nbexec64" type="2">
+      <toolsSet>
+        <compilerSet>Cygwin64|Cygwin</compilerSet>
+        <dependencyChecking>true</dependencyChecking>
+        <rebuildPropChanged>false</rebuildPropChanged>
+      </toolsSet>
+      <compileType>
+        <cTool>
+          <developmentMode>5</developmentMode>
+        </cTool>
+        <ccTool>
+          <developmentMode>5</developmentMode>
+          <stripSymbols>true</stripSymbols>
+          <architecture>2</architecture>
+          <incDir>
+            <pElem>C:/Program Files/Java/jdk1.8.0_77/include</pElem>
+            <pElem>C:/Program Files/Java/jdk1.8.0_77/include/win32</pElem>
+          </incDir>
+          <commandLine>-mno-cygwin -static-libgcc 
-static-libstdc++</commandLine>
+          <preprocessorList>
+            <Elem>NBEXEC_DLL="nbexec64.dll"</Elem>
+          </preprocessorList>
+        </ccTool>
+        <linkerTool>
+          <output>nbexec64.dll</output>
+          <additionalDep>${OBJECTDIR}/nbexec64.res</additionalDep>
+          <linkerLibItems>
+            <linkerOptionItem>${OBJECTDIR}/nbexec64.res</linkerOptionItem>
+          </linkerLibItems>
+          <commandLine>-Wl,--nxcompat -Wl,--dynamicbase</commandLine>
+        </linkerTool>
+      </compileType>
+      <item path="argnames.h" ex="false" tool="3" flavor2="0">
+      </item>
+      <item path="jvmlauncher.cpp" ex="false" tool="1" flavor2="0">
+      </item>
+      <item path="jvmlauncher.h" ex="false" tool="3" flavor2="0">
+      </item>
+      <item path="nbexec.cpp" ex="false" tool="1" flavor2="0">
+      </item>
+      <item path="nbexec.exe.manifest" ex="false" tool="3" flavor2="0">
+      </item>
+      <item path="nbexec.rc" ex="false" tool="3" flavor2="0">
+        <customTool>
+          <customToolCommandline>x86_64-w64-mingw32-windres.exe -Ocoff 
nbexec.rc ${OBJECTDIR}/nbexec64.res</customToolCommandline>
+          <customToolDescription>Compiling Resource 
files...</customToolDescription>
+          <customToolOutputs>${OBJECTDIR}/nbexec64.res</customToolOutputs>
+          <customToolAdditionalDep>version.h</customToolAdditionalDep>
+        </customTool>
+      </item>
+      <item path="nbexec_exe.rc" ex="false" tool="3" flavor2="0">
+        <customTool>
+          <customToolDescription></customToolDescription>
+        </customTool>
+      </item>
+      <item path="nbexecexe.cpp" ex="false" tool="1" flavor2="0">
+      </item>
+      <item path="nbexecloader.h" ex="false" tool="3" flavor2="0">
+      </item>
+      <item path="platformlauncher.cpp" ex="false" tool="1" flavor2="0">
+      </item>
+      <item path="platformlauncher.h" ex="false" tool="3" flavor2="0">
+      </item>
+      <item path="utilsfuncs.cpp" ex="false" tool="1" flavor2="0">
+      </item>
+      <item path="utilsfuncs.h" ex="false" tool="3" flavor2="0">
+      </item>
+      <item path="version.h" ex="false" tool="3" flavor2="0">
+      </item>
+      <item path="version.rc" ex="false" tool="3" flavor2="0">
+      </item>
+    </conf>
+  </confs>
+</configurationDescriptor>
diff --git a/nbproject/project.properties b/nbproject/project.properties
new file mode 100644
index 0000000..2456923
--- /dev/null
+++ b/nbproject/project.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
diff --git a/nbproject/project.xml b/nbproject/project.xml
new file mode 100644
index 0000000..99f9274
--- /dev/null
+++ b/nbproject/project.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<project xmlns="http://www.netbeans.org/ns/project/1";>
+    <type>org.netbeans.modules.cnd.makeproject</type>
+    <configuration>
+        <data xmlns="http://www.netbeans.org/ns/make-project/1";>
+            <name>Platform Launcher Win</name>
+            <make-project-type>0</make-project-type>
+            <c-extensions/>
+            <cpp-extensions>cpp</cpp-extensions>
+            <header-extensions>h</header-extensions>
+            <sourceEncoding>UTF-8</sourceEncoding>
+            <make-dep-projects/>
+            <sourceRootList/>
+            <confList>
+                <confElem>
+                    <name>nbexec</name>
+                    <type>2</type>
+                </confElem>
+                <confElem>
+                    <name>nbexec64</name>
+                    <type>2</type>
+                </confElem>
+            </confList>
+            <formatting>
+                <project-formatting-style>false</project-formatting-style>
+            </formatting>
+        </data>
+    </configuration>
+</project>
diff --git a/platformlauncher.cpp b/platformlauncher.cpp
new file mode 100644
index 0000000..b29b309
--- /dev/null
+++ b/platformlauncher.cpp
@@ -0,0 +1,724 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ /*
+ * Author: Tomas Holy
+ */
+
+#include "utilsfuncs.h"
+#include "platformlauncher.h"
+#include "argnames.h"
+
+using namespace std;
+
+const char *PlatformLauncher::HELP_MSG =
+"\nUsage: launcher {options} arguments\n\
+\n\
+General options:\n\
+  --help                show this help\n\
+  --jdkhome <path>      path to JDK\n\
+  -J<jvm_option>        pass <jvm_option> to JVM\n\
+\n\
+  --cp:p <classpath>    prepend <classpath> to classpath\n\
+  --cp:a <classpath>    append <classpath> to classpath\n\
+\n\
+  --fork-java           run java in separate process\n\
+  --trace <path>        path for launcher log (for trouble shooting)\n\
+\n";
+
+const char *PlatformLauncher::REQ_JAVA_VERSION = "1.8";
+
+const char *PlatformLauncher::OPT_JDK_HOME = "-Djdk.home=";
+const char *PlatformLauncher::OPT_NB_PLATFORM_HOME = "-Dnetbeans.home=";
+const char *PlatformLauncher::OPT_NB_CLUSTERS = "-Dnetbeans.dirs=";
+const char *PlatformLauncher::OPT_NB_USERDIR = "-Dnetbeans.user=";
+const char *PlatformLauncher::OPT_DEFAULT_USERDIR_ROOT = 
"-Dnetbeans.default_userdir_root=";
+const char *PlatformLauncher::OPT_HEAP_DUMP = 
"-XX:+HeapDumpOnOutOfMemoryError";
+const char *PlatformLauncher::OPT_HEAP_DUMP_PATH = "-XX:HeapDumpPath=";
+const char *PlatformLauncher::OPT_KEEP_WORKING_SET_ON_MINIMIZE = 
"-Dsun.awt.keepWorkingSetOnMinimize=true";
+const char *PlatformLauncher::OPT_CLASS_PATH = "-Djava.class.path=";
+const char *PlatformLauncher::OPT_SPLASH = "-splash:";
+const char *PlatformLauncher::OPT_SPLASH_PATH = "\\var\\cache\\splash.png";
+
+const char *PlatformLauncher::HEAP_DUMP_PATH =  "\\var\\log\\heapdump.hprof";
+const char *PlatformLauncher::RESTART_FILE_PATH =  "\\var\\restart";
+
+const char *PlatformLauncher::UPDATER_MAIN_CLASS = 
"org/netbeans/updater/UpdaterFrame";
+const char *PlatformLauncher::IDE_MAIN_CLASS = "org/netbeans/Main";
+
+PlatformLauncher::PlatformLauncher()
+    : separateProcess(false)
+    , suppressConsole(false)
+    , heapDumpPathOptFound(false)
+    , nosplash(false)
+    , exiting(false) {
+}
+
+PlatformLauncher::PlatformLauncher(const PlatformLauncher& orig) {
+}
+
+PlatformLauncher::~PlatformLauncher() {
+}
+
+bool PlatformLauncher::start(char* argv[], int argc, DWORD *retCode) {
+    if (!checkLoggingArg(argc, argv, false) || !initPlatformDir() || 
!parseArgs(argc, argv)) {
+        return false;
+    }
+    disableFolderVirtualization(GetCurrentProcess());
+
+    if (jdkhome.empty()) {
+        if (!jvmLauncher.initialize(REQ_JAVA_VERSION)) {
+            logErr(false, true, "Cannot find Java %s or higher.", 
REQ_JAVA_VERSION);
+            return false;
+        }
+    }
+    jvmLauncher.getJavaPath(jdkhome);
+    
+    deleteNewClustersFile();
+    prepareOptions();
+
+    if (nextAction.empty()) {
+        if (shouldAutoUpdateClusters(true)) {
+            // run updater
+            if (!run(true, retCode)) {
+                return false;
+            }
+        }
+
+        while (true) {
+            // run app
+            if (!run(false, retCode)) {
+                return false;
+            }
+
+            if (shouldAutoUpdateClusters(false)) {
+                // run updater
+                if (!run(true, retCode)) {
+                    return false;
+                }
+            } else if (!restartRequested()) {
+                break;
+            }
+        }
+    } else {
+        if (nextAction == ARG_NAME_LA_START_APP) {
+            return run(false, retCode);
+        } else if (nextAction == ARG_NAME_LA_START_AU) {
+            if (shouldAutoUpdateClusters(false)) {
+                return run(true, retCode);
+            }
+        } else {
+            logErr(false, true, "We should not get here.");
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool PlatformLauncher::run(bool updater, DWORD *retCode) {
+    logMsg(updater ? "Starting updater..." : "Starting application...");
+    constructClassPath(updater);
+    const char *mainClass;
+    if (updater) {
+        mainClass = UPDATER_MAIN_CLASS;
+        nextAction = ARG_NAME_LA_START_APP;
+    } else {
+        DeleteFile((userDir + RESTART_FILE_PATH).c_str());
+        mainClass = bootclass.empty() ? IDE_MAIN_CLASS : bootclass.c_str();
+        nextAction = ARG_NAME_LA_START_AU;
+    }
+
+    string option = OPT_NB_CLUSTERS;
+    option += auClusters.empty() ? clusters : auClusters;
+    javaOptions.push_back(option);
+
+    option = OPT_CLASS_PATH;
+    option += classPath;
+    javaOptions.push_back(option);
+
+    jvmLauncher.setSuppressConsole(suppressConsole);
+    bool rc = jvmLauncher.start(mainClass, progArgs, javaOptions, 
separateProcess, retCode);
+    if (!separateProcess) {
+        exit(0);
+    }
+
+    javaOptions.pop_back();
+    javaOptions.pop_back();
+    return rc;
+}
+
+
+
+bool PlatformLauncher::initPlatformDir() {
+    char path[MAX_PATH] = "";
+    getCurrentModulePath(path, MAX_PATH);
+    logMsg("Module: %s", path);
+    char *bslash = strrchr(path, '\\');
+    if (!bslash) {
+        return false;
+    }
+    *bslash = '\0';
+    bslash = strrchr(path, '\\');
+    if (!bslash) {
+        return false;
+    }
+    *bslash = '\0';
+    clusters = platformDir = path;
+    logMsg("Platform dir: %s", platformDir.c_str());
+    return true;
+}
+
+bool PlatformLauncher::parseArgs(int argc, char *argv[]) {
+#define CHECK_ARG \
+    if (i+1 == argc) {\
+        logErr(false, true, "Argument is missing for \"%s\" option.", 
argv[i]);\
+        return false;\
+    }
+
+    logMsg("Parsing arguments:");
+    for (int i = 0; i < argc; i++) {
+        logMsg("\t%s", argv[i]);
+    }
+
+    for (int i = 0; i < argc; i++) {
+        if (strcmp(ARG_NAME_SEPAR_PROC, argv[i]) == 0) {
+            separateProcess = true;
+            logMsg("Run Java in separater process");
+        } else if (strcmp(ARG_NAME_LAUNCHER_LOG, argv[i]) == 0) {
+            CHECK_ARG;
+            i++;
+        } else if (strcmp(ARG_NAME_LA_START_APP, argv[i]) == 0
+                || strcmp(ARG_NAME_LA_START_AU, argv[i]) == 0) {
+            nextAction = argv[i];
+            logMsg("Next launcher action: %s", nextAction.c_str());
+        } else if (strcmp(ARG_NAME_LA_PPID, argv[i]) == 0) {
+            CHECK_ARG;
+            suppressConsole = false;
+            parentProcID = argv[++i];
+            logMsg("Parent process ID found: %s", parentProcID.c_str());
+        } else if (strcmp(ARG_NAME_USER_DIR, argv[i]) == 0) {
+            CHECK_ARG;
+            char tmp[MAX_PATH + 1] = {0};
+            strncpy(tmp, argv[++i], MAX_PATH);
+            if (strcmp(tmp, "memory") != 0 && !normalizePath(tmp, MAX_PATH)) {
+                logErr(false, true, "User directory path \"%s\" is not 
valid.", argv[i]);
+                return false;
+            }
+            userDir = tmp;
+            logMsg("User dir: %s", userDir.c_str());
+        } else if (strcmp(ARG_DEFAULT_USER_DIR_ROOT, argv[i]) == 0) {
+            CHECK_ARG;
+            char tmp[MAX_PATH + 1] = {0};
+            strncpy(tmp, argv[++i], MAX_PATH);
+            if (strcmp(tmp, "memory") != 0 && !normalizePath(tmp, MAX_PATH)) {
+                logErr(false, true, "Default User directory path \"%s\" is not 
valid.", argv[i]);
+                return false;
+            }
+            defaultUserDirRoot = tmp;
+            logMsg("Default Userdir root: %s", defaultUserDirRoot.c_str());
+        } else if (strcmp(ARG_NAME_CLUSTERS, argv[i]) == 0) {
+            CHECK_ARG;
+            clusters = argv[++i];
+        } else if (strcmp(ARG_NAME_BOOTCLASS, argv[i]) == 0) {
+            CHECK_ARG;
+            bootclass = argv[++i];
+        } else if (strcmp(ARG_NAME_JDKHOME, argv[i]) == 0) {
+            CHECK_ARG;            
+            if (jdkhome.empty()) {
+                jdkhome = argv[++i];
+                if (!jvmLauncher.initialize(jdkhome.c_str())) {
+                    logMsg("Cannot locate java installation in specified 
jdkhome: %s", jdkhome.c_str());
+                    string errMsg = "Cannot locate java installation in 
specified jdkhome:\n";
+                    errMsg += jdkhome;
+                    errMsg += "\nDo you want to try to use default version?";
+                    jdkhome = "";
+                    if (::MessageBox(NULL, errMsg.c_str(), "Invalid jdkhome 
specified", MB_ICONQUESTION | MB_YESNO) == IDNO) {
+                        return false;
+                    }
+                }
+            } else {
+                i++;
+            }
+        } else if (strcmp(ARG_NAME_CP_PREPEND, argv[i]) == 0
+                || strcmp(ARG_NAME_CP_PREPEND + 1, argv[i]) == 0) {
+            CHECK_ARG;
+            cpBefore += argv[++i];
+        } else if (strcmp(ARG_NAME_CP_APPEND, argv[i]) == 0
+                || strcmp(ARG_NAME_CP_APPEND + 1, argv[i]) == 0
+                || strncmp(ARG_NAME_CP_APPEND + 1, argv[i], 3) == 0
+                || strncmp(ARG_NAME_CP_APPEND, argv[i], 4) == 0) {
+            CHECK_ARG;
+            cpAfter += argv[++i];
+        } else if (strncmp("-J", argv[i], 2) == 0) {
+            javaOptions.push_back(argv[i] + 2);
+            if (strncmp(argv[i] + 2, OPT_HEAP_DUMP_PATH, 
strlen(OPT_HEAP_DUMP_PATH)) == 0) {
+                heapDumpPathOptFound = true;
+            }
+        } else {
+            if (strcmp(argv[i], "-h") == 0
+                    || strcmp(argv[i], "-help") == 0
+                    || strcmp(argv[i], "--help") == 0
+                    || strcmp(argv[i], "/?") == 0) {
+                printToConsole(HELP_MSG);
+                if (!appendHelp.empty()) {
+                    printToConsole(appendHelp.c_str());
+                }
+            } else if (strcmp(ARG_NAME_NOSPLASH, argv[i]) == 0) {
+                 nosplash = true;
+            }
+            progArgs.push_back(argv[i]);
+        }
+    }
+    return true;
+}
+
+bool PlatformLauncher::processAutoUpdateCL() {
+    logMsg("processAutoUpdateCL()...");
+    if (userDir.empty()) {
+        logMsg("\tuserdir empty, quiting");
+        return false;
+    }
+    string listPath = userDir;
+    listPath += "\\update\\download\\netbeans.dirs";
+
+    WIN32_FIND_DATA fd = {0};
+    HANDLE hFind = 0;
+    hFind = FindFirstFile(listPath.c_str(), &fd);
+    if (hFind == INVALID_HANDLE_VALUE) {
+        logMsg("File \"%s\" does not exist", listPath.c_str());
+        return false;
+    }
+    FindClose(hFind);
+
+    FILE *file = fopen(listPath.c_str(), "r");
+    if (!file) {
+        logErr(true, false, "Cannot open file %s", listPath.c_str());
+        return false;
+    }
+
+    int len = fd.nFileSizeLow + 1;
+    char *str = new char[len];
+    if (!fgets(str, len, file)) {
+        fclose(file);
+        delete[] str;
+        logErr(true, false, "Cannot read from file %s", listPath.c_str());
+        return false;
+    }
+    len = strlen(str) - 1;
+    if (str[len] == '\n') {
+        str[len] = '\0';
+    }
+
+    auClusters = str;
+    fclose(file);
+    delete[] str;
+    return true;
+}
+
+void PlatformLauncher::deleteNewClustersFile() {
+    logMsg("deleteNewClustersFile()...");
+    if (userDir.empty()) {
+        logMsg("\tuserdir empty, quiting");
+        return;
+    }
+    string listPath = userDir;
+    listPath += "\\update\\download\\netbeans.dirs";
+
+    if (fileExists(listPath.c_str())) {
+        DeleteFileA(listPath.c_str());
+        logMsg("%s file deleted.", listPath.c_str());
+    }
+}
+
+// check if new updater exists, if exists install it (replace old one) and 
remove ...\new_updater directory
+bool PlatformLauncher::checkForNewUpdater(const char *basePath) {
+    logMsg("checkForNewUpdater() at %s", basePath);
+    BOOL removeDir = false;
+    string srcPath = basePath;
+    srcPath += "\\update\\new_updater\\updater.jar";
+    WIN32_FIND_DATA fd = {0};
+    HANDLE hFind = FindFirstFile(srcPath.c_str(), &fd);
+    if (hFind != INVALID_HANDLE_VALUE) {
+        logMsg("New updater found: %s", srcPath.c_str());
+        FindClose(hFind);
+        string destPath = basePath;
+        destPath += "\\modules\\ext\\updater.jar";
+        createPath(destPath.c_str());
+
+        int i = 0;
+        while (true) {
+            if (MoveFileEx(srcPath.c_str(), destPath.c_str(), 
MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {
+                break;
+            }
+            if (exiting || ++i > 10) {
+                logErr(true, false, "Failed to move \"%s\" to \"%s\"", 
srcPath.c_str(), destPath.c_str());
+                return false;
+            }
+            logErr(true, false, "Failed to move \"%s\" to \"%s\", trying to 
wait", srcPath.c_str(), destPath.c_str());
+            Sleep(100);
+        }
+        logMsg("New updater successfully moved from \"%s\" to \"%s\"", 
srcPath.c_str(), destPath.c_str());
+        removeDir = true;
+    } else {
+        logMsg("No new updater at %s", srcPath.c_str());
+    }
+    string locPath = basePath;
+    locPath += "\\update\\new_updater\\updater_*.jar";
+    hFind = FindFirstFile(locPath.c_str(), &fd);
+    while (hFind != INVALID_HANDLE_VALUE) {
+        string destPath = basePath;
+        string name = fd.cFileName;
+        logMsg("New updater localization found: %s", name.c_str());
+        destPath += "\\modules\\ext\\locale\\";
+        destPath += name;
+
+        string fromPath = basePath;
+        fromPath += "\\update\\new_updater\\";
+        fromPath += name;
+
+        createPath(destPath.c_str());
+
+        int i = 0;
+        while (true) {
+            if (MoveFileEx(fromPath.c_str(), destPath.c_str(), 
MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {
+                break;
+            }
+            if (exiting || ++i > 10) {
+                logErr(true, false, "Failed to move \"%s\" to \"%s\"", 
fromPath.c_str(), destPath.c_str());
+                return false;
+            }
+            logErr(true, false, "Failed to move \"%s\" to \"%s\", trying to 
wait", fromPath.c_str(), destPath.c_str());
+            Sleep(100);
+        }
+        logMsg("New updater successfully moved from \"%s\" to \"%s\"", 
fromPath.c_str(), destPath.c_str());
+        removeDir = true;
+        
+        if (!FindNextFile(hFind, &fd)) {
+            break;
+        }
+    }
+    FindClose(hFind);
+
+    if (removeDir) {
+        srcPath.erase(srcPath.rfind('\\'));
+        logMsg("Removing directory \"%s\"", srcPath.c_str());
+        if (!RemoveDirectory(srcPath.c_str())) {
+            logErr(true, false, "Failed to remove directory \"%s\"", 
srcPath.c_str());
+        }
+    }
+    return true;
+}
+
+bool PlatformLauncher::shouldAutoUpdate(bool firstStart, const char *basePath) 
{
+    // The logic is following:
+    // if there is an NBM for installation then run updater
+    // unless it is not a first start and we asked to install later (on next 
start)
+
+    // then also check if last run left list of modules to disable/uninstall 
and
+    // did not mark them to be deactivated later (on next start)
+    string path = basePath;
+    path += "\\update\\download\\*.nbm";
+    logMsg("Checking for updates: %s", path.c_str());
+    WIN32_FIND_DATA fd;
+    HANDLE hFindNbms = FindFirstFile(path.c_str(), &fd);
+    if (hFindNbms != INVALID_HANDLE_VALUE) {
+        logMsg("Some updates found at %s", path.c_str());
+        FindClose(hFindNbms);
+    } else {
+        //also check for OSGi jars if *.nbm not found
+        path = basePath;
+        path += "\\update\\download\\*.jar";
+        hFindNbms = FindFirstFile(path.c_str(), &fd);
+        if (hFindNbms != INVALID_HANDLE_VALUE) {
+            logMsg("Some OSGi updates found at %s", path.c_str());
+            FindClose(hFindNbms);
+        }
+    }
+
+    path = basePath;
+    path += "\\update\\download\\install_later.xml";
+    HANDLE hFind = FindFirstFile(path.c_str(), &fd);
+    if (hFind != INVALID_HANDLE_VALUE) {
+        logMsg("install_later.xml found: %s", path.c_str());
+        FindClose(hFind);
+    }
+
+    if (hFindNbms != INVALID_HANDLE_VALUE && (firstStart || hFind == 
INVALID_HANDLE_VALUE)) {
+        return true;
+    }
+
+    path = basePath;
+    path += "\\update\\deactivate\\deactivate_later.txt";
+    hFind = FindFirstFile(path.c_str(), &fd);
+    if (hFind != INVALID_HANDLE_VALUE) {
+        logMsg("deactivate_later.txt found: %s", path.c_str());
+        FindClose(hFind);
+    }
+
+    if (firstStart || hFind == INVALID_HANDLE_VALUE) {
+        path = basePath;
+        path += "\\update\\deactivate\\to_disable.txt";
+        hFind = FindFirstFile(path.c_str(), &fd);
+        if (hFind != INVALID_HANDLE_VALUE) {
+            logMsg("to_disable.txt found: %s", path.c_str());
+            FindClose(hFind);
+            return true;
+        }
+
+        path = basePath;
+        path += "\\update\\deactivate\\to_uninstall.txt";
+        hFind = FindFirstFile(path.c_str(), &fd);
+        if (hFind != INVALID_HANDLE_VALUE) {
+            logMsg("to_uninstall.txt found: %s", path.c_str());
+            FindClose(hFind);
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool PlatformLauncher::shouldAutoUpdateClusters(bool firstStart) {
+    bool runUpdater = false;
+    string cl = processAutoUpdateCL() ? auClusters : clusters;
+    checkForNewUpdater(platformDir.c_str());
+    runUpdater = shouldAutoUpdate(firstStart, platformDir.c_str());
+
+    const char delim = ';';
+    string::size_type start = cl.find_first_not_of(delim, 0);
+    string::size_type end = cl.find_first_of(delim, start);
+    while (string::npos != end || string::npos != start) {
+        string cluster = cl.substr(start, end - start);
+        checkForNewUpdater(cluster.c_str());
+        if (!runUpdater) {
+            runUpdater = shouldAutoUpdate(firstStart, cluster.c_str());
+        }
+        start = cl.find_first_not_of(delim, end);
+        end = cl.find_first_of(delim, start);
+    }
+
+    checkForNewUpdater(userDir.c_str());
+    if (!runUpdater) {
+        runUpdater = shouldAutoUpdate(firstStart, userDir.c_str());
+    }
+    return runUpdater;
+}
+
+void PlatformLauncher::prepareOptions() {
+    string option = OPT_JDK_HOME;
+    option += jdkhome;
+    javaOptions.push_back(option);
+
+    if (!nosplash) {
+        string splashPath = userDir;
+        splashPath += OPT_SPLASH_PATH;
+        if (fileExists(splashPath.c_str())) {
+            javaOptions.push_back(OPT_SPLASH + splashPath);
+        }
+    }
+
+    option = OPT_NB_PLATFORM_HOME;
+    option += platformDir;
+    javaOptions.push_back(option);
+
+    option = OPT_NB_USERDIR;
+    option += userDir;
+    javaOptions.push_back(option);
+    
+    option = OPT_DEFAULT_USERDIR_ROOT;
+    option += defaultUserDirRoot;
+    javaOptions.push_back(option);
+
+    option = OPT_HEAP_DUMP;
+    javaOptions.push_back(option);
+
+    if (!heapDumpPathOptFound) {
+        option = OPT_HEAP_DUMP_PATH;
+        option += userDir;
+        option += HEAP_DUMP_PATH;
+        javaOptions.push_back(option);
+        // rename old heap dump to .old
+        string heapdumpfile = userDir + HEAP_DUMP_PATH;
+        if (fileExists(heapdumpfile.c_str())) {
+            string heapdumpfileold = heapdumpfile + ".old";
+            if (fileExists(heapdumpfileold.c_str())) {
+                DeleteFileA(heapdumpfileold.c_str());
+            }
+            MoveFile (heapdumpfile.c_str(), heapdumpfileold.c_str());
+        }
+    }
+    
+    option = OPT_KEEP_WORKING_SET_ON_MINIMIZE;
+    javaOptions.push_back(option);
+}
+
+string & PlatformLauncher::constructClassPath(bool runUpdater) {
+    logMsg("constructClassPath()");
+    addedToCP.clear();
+    classPath = cpBefore;
+
+    addJarsToClassPathFrom(userDir.c_str());
+    addJarsToClassPathFrom(platformDir.c_str());
+
+    if (runUpdater) {
+        const char *baseUpdaterPath = userDir.c_str();
+        string updaterPath = userDir + "\\modules\\ext\\updater.jar";
+
+        // if user updater does not exist, use updater from platform
+        if (!fileExists(updaterPath.c_str())) {
+            baseUpdaterPath = platformDir.c_str();
+            updaterPath = platformDir + "\\modules\\ext\\updater.jar";
+        }
+
+        addToClassPath(updaterPath.c_str(), false);
+        addFilesToClassPath(baseUpdaterPath, "\\modules\\ext\\locale", 
"updater_*.jar");
+    }
+
+    addToClassPath((jdkhome + "\\lib\\dt.jar").c_str(), true);
+    addToClassPath((jdkhome + "\\lib\\tools.jar").c_str(), true);
+
+    if (!cpAfter.empty()) {
+        addToClassPath(cpAfter.c_str(), false);
+    }
+    logMsg("ClassPath: %s", classPath.c_str());
+    return classPath;
+}
+
+void PlatformLauncher::addJarsToClassPathFrom(const char *dir) {
+    addFilesToClassPath(dir, "lib\\patches", "*.jar");
+    addFilesToClassPath(dir, "lib\\patches", "*.zip");
+
+    addFilesToClassPath(dir, "lib", "*.jar");
+    addFilesToClassPath(dir, "lib", "*.zip");
+
+    addFilesToClassPath(dir, "lib\\locale", "*.jar");
+    addFilesToClassPath(dir, "lib\\locale", "*.zip");
+}
+
+void PlatformLauncher::addFilesToClassPath(const char *dir, const char 
*subdir, const char *pattern) {
+    logMsg("addFilesToClassPath()\n\tdir: %s\n\tsubdir: %s\n\tpattern: %s", 
dir, subdir, pattern);
+    string path = dir;
+    path += '\\';
+    path += subdir;
+    path += '\\';
+
+    WIN32_FIND_DATA fd = {0};
+    string patternPath = path + pattern;
+    HANDLE hFind = FindFirstFile(patternPath.c_str(), &fd);
+    if (hFind == INVALID_HANDLE_VALUE) {
+        logMsg("Nothing found (%s)", patternPath.c_str());
+        return;
+    }
+    do {
+        string name = subdir;
+        name += fd.cFileName;
+        string fullName = path + fd.cFileName;
+        if (addedToCP.insert(name).second) {
+            addToClassPath(fullName.c_str());
+        } else {
+            logMsg("\"%s\" already added, skipping \"%s\"", name.c_str(), 
fullName.c_str());
+        }
+    } while (FindNextFile(hFind, &fd));
+    FindClose(hFind);
+}
+
+void PlatformLauncher::addToClassPath(const char *path, bool onlyIfExists) {
+    logMsg("addToClassPath()\n\tpath: %s\n\tonlyIfExists: %s", path, 
onlyIfExists ? "true" : "false");
+    if (onlyIfExists && !fileExists(path)) {
+        return;
+    }
+
+    if (!classPath.empty()) {
+        classPath += ';';
+    }
+    classPath += path;
+}
+
+void PlatformLauncher::appendToHelp(const char *msg) {
+    if (msg) {
+        appendHelp = msg;
+    }
+}
+
+bool PlatformLauncher::restartRequested() {
+    return fileExists((userDir + RESTART_FILE_PATH).c_str());
+}
+
+void PlatformLauncher::onExit() {
+    logMsg("onExit()");
+    
+    if (exiting) {
+        logMsg("Already exiting, no need to schedule restart");
+        return;
+    }
+    
+    exiting = true;
+
+    if (separateProcess) {
+        logMsg("JVM in separate process, no need to restart");
+        return;
+    }
+
+    bool restart = (nextAction == ARG_NAME_LA_START_APP || (nextAction == 
ARG_NAME_LA_START_AU && shouldAutoUpdateClusters(false)));
+    if (!restart && restartRequested()) {
+        restart = true;
+        nextAction = ARG_NAME_LA_START_APP;
+    }
+
+    if (restart) {
+        string cmdLine = GetCommandLine();
+        logMsg("Old command line: %s", cmdLine.c_str());
+        string::size_type bslashPos = cmdLine.find_last_of('\\');
+        string::size_type pos = cmdLine.find(ARG_NAME_LA_START_APP);
+        if ((bslashPos == string::npos || bslashPos < pos) && pos != 
string::npos) {
+            cmdLine.erase(pos, strlen(ARG_NAME_LA_START_APP));
+        }
+        pos = cmdLine.find(ARG_NAME_LA_START_AU);
+        if ((bslashPos == string::npos || bslashPos < pos) && pos != 
string::npos) {
+            cmdLine.erase(pos, strlen(ARG_NAME_LA_START_AU));
+        }
+
+        if (*cmdLine.rbegin() != ' ') {
+            cmdLine += ' ';
+        }
+        if (!parentProcID.empty() && cmdLine.find(ARG_NAME_LA_PPID) == 
string::npos) {
+            cmdLine += ARG_NAME_LA_PPID;
+            cmdLine += ' ';
+            cmdLine += parentProcID;
+        }
+
+        if (*cmdLine.rbegin() != ' ') {
+            cmdLine += ' ';
+        }
+        cmdLine += nextAction;
+
+        logMsg("New command line: %s", cmdLine.c_str());
+        char cmdLineStr[32 * 1024] = "";
+        strcpy(cmdLineStr, cmdLine.c_str());
+        STARTUPINFO si = {0};
+        PROCESS_INFORMATION pi = {0};
+        si.cb = sizeof(STARTUPINFO);
+        if (!CreateProcess(NULL, cmdLineStr, NULL, NULL, FALSE, 0, NULL, NULL, 
&si, &pi)) {
+            logErr(true, true, "Failed to create process.");
+            return;
+        }
+        CloseHandle(pi.hThread);
+        CloseHandle(pi.hProcess);
+    }
+}
diff --git a/platformlauncher.h b/platformlauncher.h
new file mode 100644
index 0000000..07fe4d8
--- /dev/null
+++ b/platformlauncher.h
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ /*
+ * Author: Tomas Holy
+ */
+
+#ifndef _PLATFORMLAUNCHER_H
+#define        _PLATFORMLAUNCHER_H
+
+#include "jvmlauncher.h"
+#include <string>
+#include <list>
+#include <set>
+
+class PlatformLauncher {
+    static const char *REQ_JAVA_VERSION;
+    static const char *HELP_MSG;
+
+    static const char *HEAP_DUMP_PATH;
+    static const char *RESTART_FILE_PATH;
+
+    static const char *OPT_JDK_HOME;
+    static const char *OPT_NB_PLATFORM_HOME;
+    static const char *OPT_NB_CLUSTERS;
+    static const char *OPT_NB_USERDIR;
+    static const char *OPT_DEFAULT_USERDIR_ROOT;
+    static const char *OPT_HEAP_DUMP;
+    static const char *OPT_HEAP_DUMP_PATH;
+    static const char *OPT_KEEP_WORKING_SET_ON_MINIMIZE;
+    static const char *OPT_CLASS_PATH;
+    static const char *OPT_SPLASH;
+    static const char *OPT_SPLASH_PATH;
+
+    static const char *UPDATER_MAIN_CLASS;
+    static const char *IDE_MAIN_CLASS;
+
+
+public:
+    PlatformLauncher();
+    virtual ~PlatformLauncher();
+
+    bool start(char* argv[], int argc, DWORD *retCode);
+    void appendToHelp(const char *msg);
+    void onExit();
+
+    void setSuppressConsole(bool val) {
+        suppressConsole = val;
+    }
+
+private:
+    PlatformLauncher(const PlatformLauncher& orig);
+    bool parseArgs(int argc, char *argv[]);
+    bool initPlatformDir();
+    bool processAutoUpdateCL();
+    void deleteNewClustersFile();
+    bool checkForNewUpdater(const char *basePath);
+    bool shouldAutoUpdate(bool firstStart, const char *basePath);
+    bool shouldAutoUpdateClusters(bool firstStart);
+    void prepareOptions();
+    std::string & constructClassPath(bool runUpdater);
+    void addFilesToClassPath(const char *dir, const char *subdir, const char 
*pattern);
+    void addToClassPath(const char *path, bool onlyIfExists = false);
+    void addJarsToClassPathFrom(const char *dir);
+    bool run(bool updater, DWORD *retCode);
+    bool restartRequested();
+
+private:
+    bool separateProcess;
+    bool suppressConsole;
+    bool heapDumpPathOptFound;
+    bool nosplash;
+    bool exiting;
+    std::string platformDir;
+    std::string userDir;
+    std::string defaultUserDirRoot;
+    std::string clusters;
+    std::string bootclass;
+    std::string jdkhome;
+    std::string cpBefore;
+    std::string cpAfter;
+    std::string auClusters;
+    std::string nextAction;
+    std::string parentProcID;
+
+    std::list<std::string> javaOptions;
+    std::list<std::string> launcherOptions;
+    std::list<std::string> progArgs;
+    JvmLauncher jvmLauncher;
+    std::set<std::string> addedToCP;
+    std::string classPath;
+    std::string appendHelp;
+};
+
+#endif /* _PLATFORMLAUNCHER_H */
+
diff --git a/utilsfuncs.cpp b/utilsfuncs.cpp
new file mode 100644
index 0000000..2902b1e
--- /dev/null
+++ b/utilsfuncs.cpp
@@ -0,0 +1,449 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ /*
+ * Author: Tomas Holy
+ */
+
+#ifndef KEY_WOW64_64KEY
+#define KEY_WOW64_64KEY 0x0100
+#endif
+
+#include "utilsfuncs.h"
+#include "argnames.h"
+#include <tlhelp32.h>
+#include <windows.h>
+
+using namespace std;
+
+bool disableFolderVirtualization(HANDLE hProcess) {
+    OSVERSIONINFO osvi = {0};
+    osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+    if (GetVersionEx(&osvi) && osvi.dwMajorVersion == 6) // check it is Win 
VISTA
+    {
+        HANDLE hToken;
+        if (OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken)) {
+            DWORD tokenInfoVal = 0;
+            if (!SetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS) 24, 
&tokenInfoVal, sizeof (DWORD))) {
+                // invalid token information class (24) is OK, it means there 
is no folder virtualization on current system
+                if (GetLastError() != ERROR_INVALID_PARAMETER) {
+                    logErr(true, true, "Failed to set token information.");
+                    return false;
+                }
+            }
+            CloseHandle(hToken);
+        } else {
+            logErr(true, true, "Failed to open process token.");
+            return false;
+        }
+    }
+    return true;
+}
+
+bool getStringFromRegistry(HKEY rootKey, const char *keyName, const char 
*valueName, string &value) {
+    return getStringFromRegistryEx(rootKey, keyName, valueName, value, false);
+}
+
+bool getStringFromRegistry64bit(HKEY rootKey, const char *keyName, const char 
*valueName, string &value) {
+    return getStringFromRegistryEx(rootKey, keyName, valueName, value, true);
+}
+
+
+
+bool getStringFromRegistryEx(HKEY rootKey, const char *keyName, const char 
*valueName, string &value, bool read64bit) {
+    logMsg("getStringFromRegistry()\n\tkeyName: %s\n\tvalueName: %s", keyName, 
valueName);
+    HKEY hKey = 0;
+    if (RegOpenKeyEx(rootKey, keyName, 0, KEY_READ | (read64bit ? 
KEY_WOW64_64KEY : 0), &hKey) == ERROR_SUCCESS) {
+        DWORD valSize = 4096;
+        DWORD type = 0;
+        char val[4096] = "";
+        if (RegQueryValueEx(hKey, valueName, 0, &type, (BYTE *) val, &valSize) 
== ERROR_SUCCESS
+                && type == REG_SZ) {
+            logMsg("%s: %s", valueName, val);
+            RegCloseKey(hKey);
+            value = val;
+            return true;
+        } else {
+            logErr(true, false, "RegQueryValueEx() failed.");
+        }
+        RegCloseKey(hKey);
+    } else {
+        logErr(true, false, "RegOpenKeyEx() failed.");
+    }
+    return false;
+}
+
+bool getDwordFromRegistry(HKEY rootKey, const char *keyName, const char 
*valueName, DWORD &value) {
+    logMsg("getDwordFromRegistry()\n\tkeyName: %s\n\tvalueName: %s", keyName, 
valueName);
+    HKEY hKey = 0;
+    if (RegOpenKeyEx(rootKey, keyName, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
+        DWORD valSize = sizeof(DWORD);
+        DWORD type = 0;
+        if (RegQueryValueEx(hKey, valueName, 0, &type, (BYTE *) &value, 
&valSize) == ERROR_SUCCESS
+                && type == REG_DWORD) {
+            logMsg("%s: %u", valueName, value);
+            RegCloseKey(hKey);
+            return true;
+        } else {
+            logErr(true, false, "RegQueryValueEx() failed.");
+        }
+        RegCloseKey(hKey);
+    } else {
+        logErr(true, false, "RegOpenKeyEx() failed.");
+    }
+    return false;
+}
+
+bool dirExists(const char *path) {
+    WIN32_FIND_DATA fd = {0};
+    HANDLE hFind = 0;
+    hFind = FindFirstFile(path, &fd);
+    if (hFind == INVALID_HANDLE_VALUE) {
+        logMsg("Dir \"%s\" does not exist", path);
+        return false;
+    }
+    logMsg("Dir \"%s\" exists", path);
+    FindClose(hFind);
+    return (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+}
+
+bool fileExists(const char *path) {
+    WIN32_FIND_DATA fd = {0};
+    HANDLE hFind = 0;
+    hFind = FindFirstFile(path, &fd);
+    if (hFind == INVALID_HANDLE_VALUE) {
+        logMsg("File \"%s\" does not exist", path);
+        return false;
+    }
+
+    logMsg("File \"%s\" exists", path);
+    FindClose(hFind);
+    return true;
+}
+
+bool normalizePath(char *path, int len) {
+    char tmp[MAX_PATH] = "";
+    int i = 0;
+    while (path[i] && i < MAX_PATH - 1) {
+        tmp[i] = path[i] == '/' ? '\\' : path[i];
+        i++;
+    }
+    tmp[i] = '\0';
+    return _fullpath(path, tmp, len) != NULL;
+}
+
+bool createPath(const char *path) {
+    logMsg("Creating directory \"%s\"", path);
+    char dir[MAX_PATH] = "";
+    const char *sep = strchr(path, '\\');
+    while (sep) {
+        strncpy(dir, path, sep - path);
+        if (!CreateDirectory(dir, 0) && GetLastError() != 
ERROR_ALREADY_EXISTS) {
+            logErr(true, false, "Failed to create directory %s", dir);
+            return false;
+        }
+        sep = strchr(sep + 1, '\\');
+    }
+    return true;
+}
+
+
+char * getCurrentModulePath(char *path, int pathLen) {
+    MEMORY_BASIC_INFORMATION mbi;
+    static int dummy;
+    VirtualQuery(&dummy, &mbi, sizeof (mbi));
+    HMODULE hModule = (HMODULE) mbi.AllocationBase;
+    GetModuleFileName(hModule, path, pathLen);
+    return path;
+}
+
+char * skipWhitespaces(char *str) {
+    while (*str != '\0' && (*str == ' ' || *str == '\t' || *str == '\n' || 
*str == '\r')) {
+        str++;
+    }
+    return str;
+}
+
+char * trimWhitespaces(char *str) {
+    char *end = str + strlen(str) - 1;
+    while (end >= str && (*end == ' ' || *end == '\t' || *end == '\n' || *end 
== '\r')) {
+        *end = '\0';
+        end--;
+    }
+    return end;
+}
+
+char* getSysError(char *str, int strSize) {
+    int err = GetLastError();
+    LPTSTR lpMsgBuf;
+    FormatMessage(
+            FORMAT_MESSAGE_ALLOCATE_BUFFER |
+            FORMAT_MESSAGE_FROM_SYSTEM |
+            FORMAT_MESSAGE_IGNORE_INSERTS,
+            NULL,
+            err,
+            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+            (LPTSTR) & lpMsgBuf,
+            0,
+            NULL
+            );
+    LPTSTR tmp = strchr(lpMsgBuf, '\r');
+    if (tmp != NULL) {
+        *tmp = '\0';
+    }
+
+    _snprintf(str, strSize, " %s (%u)", lpMsgBuf, err);
+    LocalFree(lpMsgBuf);
+    return str;
+}
+
+string gLogFileName;
+
+void logV(bool appendSysError, bool showMsgBox, const char *format, va_list 
args) {
+    char msg[4096] = "";
+    vsnprintf(msg, 4096, format, args);
+
+    if (appendSysError) {
+        char sysErr[512] = "";
+        getSysError(sysErr, 512);
+        strncat(msg, sysErr, 4096 - strlen(msg));
+    }
+
+    if (!gLogFileName.empty()) {
+        FILE *file = fopen(gLogFileName.c_str(), "a");
+        if (file) {
+            fprintf(file, "%s\n", msg);
+            fclose(file);
+        }
+    }
+
+    if (showMsgBox) {
+        ::MessageBox(NULL, msg, "Error", MB_OK | MB_ICONSTOP);
+    }
+}
+
+void logErr(bool appendSysError, bool showMsgBox, const char *format, ...) {
+    va_list args;
+    va_start(args, format);
+    logV(appendSysError, showMsgBox, format, args);
+}
+
+void logMsg(const char *format, ...) {
+    va_list args;
+    va_start(args, format);
+    logV(false, false, format, args);
+}
+
+bool restarting(int argc, char *argv[]) {
+    for (int i = 0; i < argc; i++) {
+        if (strcmp(ARG_NAME_LA_START_APP, argv[i]) == 0 || 
strcmp(ARG_NAME_LA_START_AU, argv[i]) == 0) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool checkLoggingArg(int argc, char *argv[], bool delFile) {
+    for (int i = 0; i < argc; i++) {
+        if (strcmp(ARG_NAME_LAUNCHER_LOG, argv[i]) == 0) {
+            if (i + 1 == argc) {
+                logErr(false, true, "Argument is missing for \"%s\" option.", 
argv[i]);
+                return false;
+            }
+            gLogFileName = argv[++i];
+            // if we are restarting, keep log file
+            if (delFile && !restarting(argc, argv)) {
+                DeleteFile(gLogFileName.c_str());
+            }
+            break;
+        }
+    }
+    return true;
+}
+
+bool setupProcess(int &argc, char *argv[], DWORD &parentProcID, const char 
*attachMsg) {
+#define CHECK_ARG \
+    if (i+1 == argc) {\
+        logErr(false, true, "Argument is missing for \"%s\" option.", 
argv[i]);\
+        return false;\
+    }
+
+    parentProcID = 0;
+    DWORD cmdLineArgPPID = 0;
+    for (int i = 0; i < argc; i++) {
+        if (strcmp(ARG_NAME_CONSOLE, argv[i]) == 0) {
+            CHECK_ARG;
+            if (strcmp("new", argv[i + 1]) == 0){
+                AllocConsole();
+            } else if (strcmp("suppress", argv[i + 1]) == 0) {
+                // nothing, no console should be attached
+            } else {
+                logErr(false, true, "Invalid argument for \"%s\" option.", 
argv[i]);
+                return false;
+            }
+            // remove options
+            for (int k = i + 2; k < argc; k++) {
+                argv[k-2] = argv[k];
+            }
+            argc -= 2;
+            return true;
+        } else if (strcmp(ARG_NAME_LA_PPID, argv[i]) == 0) {
+            CHECK_ARG;
+            char *end = 0;
+            cmdLineArgPPID = strtoul(argv[++i], &end, 10);
+            if (cmdLineArgPPID == 0 && *end != '\0') {
+                logErr(false, true, "Invalid parameter for option %s", 
ARG_NAME_LA_PPID);
+                return false;
+            }
+            logMsg("Command line arg PPID: %u", cmdLineArgPPID);
+            break;
+        }
+    }
+#undef CHECK_ARG
+
+    // default, attach to parent process console if exists
+    // AttachConsole exists since WinXP, so be nice and do it dynamically
+    typedef BOOL (WINAPI *LPFAC)(DWORD  dwProcessId);
+    HINSTANCE hKernel32 = GetModuleHandle("kernel32");
+    if (hKernel32) {
+        LPFAC attachConsole = (LPFAC) GetProcAddress(hKernel32, 
"AttachConsole");
+        if (attachConsole) {
+            if (cmdLineArgPPID) {
+                if (!attachConsole(cmdLineArgPPID)) {
+                    logErr(true, false, "AttachConsole of PPID: %u failed.", 
cmdLineArgPPID);
+                }
+            } else {
+                if (!attachConsole((DWORD) -1)) {
+                    logErr(true, false, "AttachConsole of PP failed.");
+                } else {
+                    getParentProcessID(parentProcID);
+                    if (attachMsg) {
+                        printToConsole(attachMsg);
+                    }
+                }
+            }
+        } else {
+            logErr(true, false, "GetProcAddress() for AttachConsole failed.");
+        }
+    }
+    return true;
+}
+
+bool isConsoleAttached() {
+    typedef HWND (WINAPI *GetConsoleWindowT)();
+    HINSTANCE hKernel32 = GetModuleHandle("kernel32");
+    if (hKernel32) {
+        GetConsoleWindowT getConsoleWindow = (GetConsoleWindowT) 
GetProcAddress(hKernel32, "GetConsoleWindow");
+        if (getConsoleWindow) {
+            if (getConsoleWindow() != NULL) {
+                logMsg("Console is attached.");
+                return true;
+            }
+        } else {
+            logErr(true, false, "GetProcAddress() for GetConsoleWindow 
failed.");
+        }
+    }
+    return false;
+}
+
+bool printToConsole(const char *msg) {
+    FILE *console = fopen("CON", "a");
+    if (!console) {
+        return false;
+    }
+    fprintf(console, "%s", msg);
+    fclose(console);
+    return false;
+}
+
+bool getParentProcessID(DWORD &id) {
+    typedef HANDLE (WINAPI * CreateToolhelp32SnapshotT)(DWORD, DWORD);
+    typedef BOOL (WINAPI * Process32FirstT)(HANDLE, LPPROCESSENTRY32);
+    typedef BOOL (WINAPI * Process32NextT)(HANDLE, LPPROCESSENTRY32);
+
+    HINSTANCE hKernel32 = GetModuleHandle("kernel32");
+    if (!hKernel32) {
+        return false;
+    }
+
+    CreateToolhelp32SnapshotT createToolhelp32Snapshot = 
(CreateToolhelp32SnapshotT) GetProcAddress(hKernel32, 
"CreateToolhelp32Snapshot");
+    Process32FirstT process32First = (Process32FirstT) 
GetProcAddress(hKernel32, "Process32First");
+    Process32NextT process32Next = (Process32NextT) GetProcAddress(hKernel32, 
"Process32Next");
+
+    if (createToolhelp32Snapshot == NULL || process32First == NULL || 
process32Next == NULL) {
+        logErr(true, false, "Failed to obtain Toolhelp32 functions.");
+        return false;
+    }
+
+    HANDLE hSnapshot = createToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+    if (hSnapshot == INVALID_HANDLE_VALUE) {
+        logErr(true, false, "Failed to obtain process snapshot.");
+        return false;
+    }
+
+    PROCESSENTRY32 entry = {0};
+    entry.dwSize = sizeof (PROCESSENTRY32);
+    if (!process32First(hSnapshot, &entry)) {
+        CloseHandle(hSnapshot);
+        return false;
+    }
+
+    DWORD curID = GetCurrentProcessId();
+    logMsg("Current process ID: %u", curID);
+
+    do {
+        if (entry.th32ProcessID == curID) {
+            id = entry.th32ParentProcessID;
+            logMsg("Parent process ID: %u", id);
+            CloseHandle(hSnapshot);
+            return true;
+        }
+    } while (process32Next(hSnapshot, &entry));
+
+    CloseHandle(hSnapshot);
+    return false;
+}
+
+bool isWow64()
+{
+    BOOL IsWow64 = FALSE;
+    typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
+    LPFN_ISWOW64PROCESS fnIsWow64Process;
+
+    fnIsWow64Process = (LPFN_ISWOW64PROCESS) 
GetProcAddress(GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
+  
+    if (NULL != fnIsWow64Process)
+    {
+        if (!fnIsWow64Process(GetCurrentProcess(),&IsWow64))
+        {
+            // handle error
+        }
+    }
+    return IsWow64;
+}
+
+int convertAnsiToUtf8(const char *ansi, char *utf8, int utf8Len) {
+    const int len = 32*1024;
+    WCHAR tmp[len] = L"";
+    if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ansi, -1, tmp, len) == 0)
+        return -1;
+    if (WideCharToMultiByte(CP_UTF8, 0, tmp, -1, utf8, utf8Len, NULL, NULL) == 
0)
+        return -1;
+    return 0;
+}
+
diff --git a/utilsfuncs.h b/utilsfuncs.h
new file mode 100644
index 0000000..6cf172a
--- /dev/null
+++ b/utilsfuncs.h
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ /*
+ * Author: Tomas Holy
+ */
+
+#ifndef _UTILSFUNCS_H
+#define        _UTILSFUNCS_H
+
+#include <windows.h>
+#include <string>
+
+bool isWow64();
+bool disableFolderVirtualization(HANDLE hProcess);
+bool getStringFromRegistry(HKEY rootKey, const char *keyName, const char 
*valueName, std::string &value);
+bool getStringFromRegistryEx(HKEY rootKey, const char *keyName, const char 
*valueName, std::string &value,bool read64bit);
+bool getStringFromRegistry64bit(HKEY rootKey, const char *keyName, const char 
*valueName, std::string &value);
+bool getDwordFromRegistry(HKEY rootKey, const char *keyName, const char 
*valueName, DWORD &value);
+bool dirExists(const char *path);
+bool fileExists(const char *path);
+bool normalizePath(char *path, int len);
+bool createPath(const char *path);
+char * getCurrentModulePath(char *path, int pathLen);
+char * skipWhitespaces(char *str);
+char * trimWhitespaces(char *str);
+void logMsg(const char *format, ...);
+void logErr(bool appendSysError, bool showMsgBox, const char *format, ...);
+bool checkLoggingArg(int argc, char *argv[], bool delFile);
+bool setupProcess(int &argc, char *argv[], DWORD &parentProcID, const char 
*attachMsg = 0);
+bool printToConsole(const char *msg);
+bool getParentProcessID(DWORD &id);
+bool isConsoleAttached();
+int convertAnsiToUtf8(const char *ansi, char *utf8, int utf8Len);
+
+#endif /* _UTILSFUNCS_H */
+
diff --git a/version.h b/version.h
new file mode 100644
index 0000000..b423ffc
--- /dev/null
+++ b/version.h
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#define COMPANY "Oracle Corporation"
+#define COMPONENT "NetBeans Platform Launcher"
+#define VER "9.0.0.0"
+#define FVER 9,0,0,0
+#define BUILD_ID "04012017"
+#define INTERNAL_NAME "nbexec"
+#define COPYRIGHT "\xA9 2007, 2017 Oracle and/or its affiliates. All rights 
reserved."
+#define NAME "NetBeans Platform Launcher"
+
diff --git a/version.rc b/version.rc
new file mode 100644
index 0000000..7a516a4
--- /dev/null
+++ b/version.rc
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <winuser.h>
+#include <winver.h>
+#include "version.h"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION    FVER
+ PRODUCTVERSION FVER
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ // FILEOS 0x4 is Win32, 0x40004 is Win32 NT only
+ FILEOS 0x4L
+ // FILETYPE should be 0x1 for .exe and 0x2 for .dll
+ FILETYPE FILETYPE_ID
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "000004b0"
+        BEGIN
+            VALUE "CompanyName",      COMPANY       "\0"
+            VALUE "FileDescription",  COMPONENT     "\0"
+            VALUE "FileVersion",      VER           "\0"
+            VALUE "Full Version",     BUILD_ID      "\0"
+            VALUE "InternalName",     INTERNAL_NAME "\0"
+            VALUE "LegalCopyright",   COPYRIGHT     "\0"
+            VALUE "OriginalFilename", FNAME         "\0"
+            VALUE "ProductName",      NAME          "\0"
+            VALUE "ProductVersion",   VER           "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x0, 1200
+    END
+END

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org
For additional commands, e-mail: commits-h...@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to