Moving the platform modules into their own subdirectory to lower the clutter in the root
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