Added support for creating an IzPack installer.
This commit is contained in:
807
installer/lib/launch4j/head_src/head.c
Normal file
807
installer/lib/launch4j/head_src/head.c
Normal file
@ -0,0 +1,807 @@
|
||||
/*
|
||||
Launch4j (http://launch4j.sourceforge.net/)
|
||||
Cross-platform Java application wrapper for creating Windows native executables.
|
||||
|
||||
Copyright (c) 2004, 2008 Grzegorz Kowal,
|
||||
Ian Roberts (jdk preference patch)
|
||||
Sylvain Mina (single instance patch)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
Except as contained in this notice, the name(s) of the above copyright holders
|
||||
shall not be used in advertising or otherwise to promote the sale, use or other
|
||||
dealings in this Software without prior written authorization.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
#include "head.h"
|
||||
|
||||
HMODULE hModule;
|
||||
FILE* hLog;
|
||||
BOOL console = FALSE;
|
||||
BOOL wow64 = FALSE;
|
||||
int foundJava = NO_JAVA_FOUND;
|
||||
|
||||
struct _stat statBuf;
|
||||
PROCESS_INFORMATION pi;
|
||||
DWORD priority;
|
||||
|
||||
char mutexName[STR] = {0};
|
||||
|
||||
char errUrl[256] = {0};
|
||||
char errTitle[STR] = "Launch4j";
|
||||
char errMsg[BIG_STR] = {0};
|
||||
|
||||
char javaMinVer[STR] = {0};
|
||||
char javaMaxVer[STR] = {0};
|
||||
char foundJavaVer[STR] = {0};
|
||||
char foundJavaKey[_MAX_PATH] = {0};
|
||||
|
||||
char oldPwd[_MAX_PATH] = {0};
|
||||
char workingDir[_MAX_PATH] = {0};
|
||||
char cmd[_MAX_PATH] = {0};
|
||||
char args[MAX_ARGS] = {0};
|
||||
|
||||
FILE* openLogFile(const char* exePath, const int pathLen) {
|
||||
char path[_MAX_PATH] = {0};
|
||||
strncpy(path, exePath, pathLen);
|
||||
strcat(path, "\\launch4j.log");
|
||||
return fopen(path, "a");
|
||||
}
|
||||
|
||||
void closeLogFile() {
|
||||
if (hLog != NULL) {
|
||||
fclose(hLog);
|
||||
}
|
||||
}
|
||||
|
||||
void setWow64Flag() {
|
||||
LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
|
||||
GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
|
||||
|
||||
if (fnIsWow64Process != NULL) {
|
||||
fnIsWow64Process(GetCurrentProcess(), &wow64);
|
||||
}
|
||||
debug("WOW64:\t\t%s\n", wow64 ? "yes" : "no");
|
||||
}
|
||||
|
||||
void setConsoleFlag() {
|
||||
console = TRUE;
|
||||
}
|
||||
|
||||
void msgBox(const char* text) {
|
||||
if (console) {
|
||||
printf("%s: %s\n", errTitle, text);
|
||||
} else {
|
||||
MessageBox(NULL, text, errTitle, MB_OK);
|
||||
}
|
||||
}
|
||||
|
||||
void signalError() {
|
||||
DWORD err = GetLastError();
|
||||
if (err) {
|
||||
LPVOID lpMsgBuf;
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
||||
| FORMAT_MESSAGE_FROM_SYSTEM
|
||||
| FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
debug("Error:\t\t%s\n", (LPCTSTR) lpMsgBuf);
|
||||
strcat(errMsg, "\n\n");
|
||||
strcat(errMsg, (LPCTSTR) lpMsgBuf);
|
||||
msgBox(errMsg);
|
||||
LocalFree(lpMsgBuf);
|
||||
} else {
|
||||
msgBox(errMsg);
|
||||
}
|
||||
if (*errUrl) {
|
||||
debug("Open URL:\t%s\n", errUrl);
|
||||
ShellExecute(NULL, "open", errUrl, NULL, NULL, SW_SHOWNORMAL);
|
||||
}
|
||||
closeLogFile();
|
||||
}
|
||||
|
||||
BOOL loadString(const int resID, char* buffer) {
|
||||
HRSRC hResource;
|
||||
HGLOBAL hResourceLoaded;
|
||||
LPBYTE lpBuffer;
|
||||
|
||||
hResource = FindResourceEx(hModule, RT_RCDATA, MAKEINTRESOURCE(resID),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT));
|
||||
if (NULL != hResource) {
|
||||
hResourceLoaded = LoadResource(hModule, hResource);
|
||||
if (NULL != hResourceLoaded) {
|
||||
lpBuffer = (LPBYTE) LockResource(hResourceLoaded);
|
||||
if (NULL != lpBuffer) {
|
||||
int x = 0;
|
||||
do {
|
||||
buffer[x] = (char) lpBuffer[x];
|
||||
} while (buffer[x++] != 0);
|
||||
// debug("Resource %d:\t%s\n", resID, buffer);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SetLastError(0);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL loadBool(const int resID) {
|
||||
char boolStr[20] = {0};
|
||||
loadString(resID, boolStr);
|
||||
return strcmp(boolStr, TRUE_STR) == 0;
|
||||
}
|
||||
|
||||
int loadInt(const int resID) {
|
||||
char intStr[20] = {0};
|
||||
loadString(resID, intStr);
|
||||
return atoi(intStr);
|
||||
}
|
||||
|
||||
BOOL regQueryValue(const char* regPath, unsigned char* buffer,
|
||||
unsigned long bufferLength) {
|
||||
HKEY hRootKey;
|
||||
char* key;
|
||||
char* value;
|
||||
if (strstr(regPath, HKEY_CLASSES_ROOT_STR) == regPath) {
|
||||
hRootKey = HKEY_CLASSES_ROOT;
|
||||
} else if (strstr(regPath, HKEY_CURRENT_USER_STR) == regPath) {
|
||||
hRootKey = HKEY_CURRENT_USER;
|
||||
} else if (strstr(regPath, HKEY_LOCAL_MACHINE_STR) == regPath) {
|
||||
hRootKey = HKEY_LOCAL_MACHINE;
|
||||
} else if (strstr(regPath, HKEY_USERS_STR) == regPath) {
|
||||
hRootKey = HKEY_USERS;
|
||||
} else if (strstr(regPath, HKEY_CURRENT_CONFIG_STR) == regPath) {
|
||||
hRootKey = HKEY_CURRENT_CONFIG;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
key = strchr(regPath, '\\') + 1;
|
||||
value = strrchr(regPath, '\\') + 1;
|
||||
*(value - 1) = 0;
|
||||
|
||||
HKEY hKey;
|
||||
unsigned long datatype;
|
||||
BOOL result = FALSE;
|
||||
if ((wow64 && RegOpenKeyEx(hRootKey,
|
||||
key,
|
||||
0,
|
||||
KEY_READ | KEY_WOW64_64KEY,
|
||||
&hKey) == ERROR_SUCCESS)
|
||||
|| RegOpenKeyEx(hRootKey,
|
||||
key,
|
||||
0,
|
||||
KEY_READ,
|
||||
&hKey) == ERROR_SUCCESS) {
|
||||
result = RegQueryValueEx(hKey, value, NULL, &datatype, buffer, &bufferLength)
|
||||
== ERROR_SUCCESS;
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
*(value - 1) = '\\';
|
||||
return result;
|
||||
}
|
||||
|
||||
void regSearch(const HKEY hKey, const char* keyName, const int searchType) {
|
||||
DWORD x = 0;
|
||||
unsigned long size = BIG_STR;
|
||||
FILETIME time;
|
||||
char buffer[BIG_STR] = {0};
|
||||
while (RegEnumKeyEx(
|
||||
hKey, // handle to key to enumerate
|
||||
x++, // index of subkey to enumerate
|
||||
buffer, // address of buffer for subkey name
|
||||
&size, // address for size of subkey buffer
|
||||
NULL, // reserved
|
||||
NULL, // address of buffer for class string
|
||||
NULL, // address for size of class buffer
|
||||
&time) == ERROR_SUCCESS) {
|
||||
|
||||
if (strcmp(buffer, javaMinVer) >= 0
|
||||
&& (!*javaMaxVer || strcmp(buffer, javaMaxVer) <= 0)
|
||||
&& strcmp(buffer, foundJavaVer) > 0) {
|
||||
strcpy(foundJavaVer, buffer);
|
||||
strcpy(foundJavaKey, keyName);
|
||||
appendPath(foundJavaKey, buffer);
|
||||
foundJava = searchType;
|
||||
debug("Match:\t\t%s\\%s\n", keyName, buffer);
|
||||
} else {
|
||||
debug("Ignore:\t\t%s\\%s\n", keyName, buffer);
|
||||
}
|
||||
size = BIG_STR;
|
||||
}
|
||||
}
|
||||
|
||||
void regSearchWow(const char* keyName, const int searchType) {
|
||||
HKEY hKey;
|
||||
debug("64-bit search:\t%s...\n", keyName);
|
||||
if (wow64 && RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
keyName,
|
||||
0,
|
||||
KEY_READ | KEY_WOW64_64KEY,
|
||||
&hKey) == ERROR_SUCCESS) {
|
||||
|
||||
regSearch(hKey, keyName, searchType | KEY_WOW64_64KEY);
|
||||
RegCloseKey(hKey);
|
||||
if ((foundJava & KEY_WOW64_64KEY) != NO_JAVA_FOUND)
|
||||
{
|
||||
debug("Using 64-bit runtime.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
debug("32-bit search:\t%s...\n", keyName);
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
keyName,
|
||||
0,
|
||||
KEY_READ,
|
||||
&hKey) == ERROR_SUCCESS) {
|
||||
regSearch(hKey, keyName, searchType);
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
}
|
||||
|
||||
void regSearchJreSdk(const char* jreKeyName, const char* sdkKeyName,
|
||||
const int jdkPreference) {
|
||||
if (jdkPreference == JDK_ONLY || jdkPreference == PREFER_JDK) {
|
||||
regSearchWow(sdkKeyName, FOUND_SDK);
|
||||
if (jdkPreference != JDK_ONLY) {
|
||||
regSearchWow(jreKeyName, FOUND_JRE);
|
||||
}
|
||||
} else { // jdkPreference == JRE_ONLY or PREFER_JRE
|
||||
regSearchWow(jreKeyName, FOUND_JRE);
|
||||
if (jdkPreference != JRE_ONLY) {
|
||||
regSearchWow(sdkKeyName, FOUND_SDK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL findJavaHome(char* path, const int jdkPreference) {
|
||||
regSearchJreSdk("SOFTWARE\\JavaSoft\\Java Runtime Environment",
|
||||
"SOFTWARE\\JavaSoft\\Java Development Kit",
|
||||
jdkPreference);
|
||||
if (foundJava == NO_JAVA_FOUND) {
|
||||
regSearchJreSdk("SOFTWARE\\IBM\\Java2 Runtime Environment",
|
||||
"SOFTWARE\\IBM\\Java Development Kit",
|
||||
jdkPreference);
|
||||
}
|
||||
if (foundJava != NO_JAVA_FOUND) {
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
foundJavaKey,
|
||||
0,
|
||||
KEY_READ | (foundJava & KEY_WOW64_64KEY),
|
||||
&hKey) == ERROR_SUCCESS) {
|
||||
unsigned char buffer[BIG_STR] = {0};
|
||||
unsigned long bufferlength = BIG_STR;
|
||||
unsigned long datatype;
|
||||
if (RegQueryValueEx(hKey, "JavaHome", NULL, &datatype, buffer,
|
||||
&bufferlength) == ERROR_SUCCESS) {
|
||||
int i = 0;
|
||||
do {
|
||||
path[i] = buffer[i];
|
||||
} while (path[i++] != 0);
|
||||
if (foundJava & FOUND_SDK) {
|
||||
appendPath(path, "jre");
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
return TRUE;
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the executable name, returns path length.
|
||||
*/
|
||||
int getExePath(char* exePath) {
|
||||
if (GetModuleFileName(hModule, exePath, _MAX_PATH) == 0) {
|
||||
return -1;
|
||||
}
|
||||
return strrchr(exePath, '\\') - exePath;
|
||||
}
|
||||
|
||||
void appendPath(char* basepath, const char* path) {
|
||||
if (basepath[strlen(basepath) - 1] != '\\') {
|
||||
strcat(basepath, "\\");
|
||||
}
|
||||
strcat(basepath, path);
|
||||
}
|
||||
|
||||
void appendJavaw(char* jrePath) {
|
||||
if (console) {
|
||||
appendPath(jrePath, "bin\\java.exe");
|
||||
} else {
|
||||
appendPath(jrePath, "bin\\javaw.exe");
|
||||
}
|
||||
}
|
||||
|
||||
void appendLauncher(const BOOL setProcName, char* exePath,
|
||||
const int pathLen, char* cmd) {
|
||||
if (setProcName) {
|
||||
char tmpspec[_MAX_PATH];
|
||||
char tmpfile[_MAX_PATH];
|
||||
strcpy(tmpspec, cmd);
|
||||
strcat(tmpspec, LAUNCH4J_TMP_DIR);
|
||||
tmpspec[strlen(tmpspec) - 1] = 0;
|
||||
if (_stat(tmpspec, &statBuf) == 0) {
|
||||
// Remove temp launchers and manifests
|
||||
struct _finddata_t c_file;
|
||||
long hFile;
|
||||
appendPath(tmpspec, "*.exe");
|
||||
strcpy(tmpfile, cmd);
|
||||
strcat(tmpfile, LAUNCH4J_TMP_DIR);
|
||||
char* filename = tmpfile + strlen(tmpfile);
|
||||
if ((hFile = _findfirst(tmpspec, &c_file)) != -1L) {
|
||||
do {
|
||||
strcpy(filename, c_file.name);
|
||||
debug("Unlink:\t\t%s\n", tmpfile);
|
||||
_unlink(tmpfile);
|
||||
strcat(tmpfile, MANIFEST);
|
||||
debug("Unlink:\t\t%s\n", tmpfile);
|
||||
_unlink(tmpfile);
|
||||
} while (_findnext(hFile, &c_file) == 0);
|
||||
}
|
||||
_findclose(hFile);
|
||||
} else {
|
||||
if (_mkdir(tmpspec) != 0) {
|
||||
debug("Mkdir failed:\t%s\n", tmpspec);
|
||||
appendJavaw(cmd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
char javaw[_MAX_PATH];
|
||||
strcpy(javaw, cmd);
|
||||
appendJavaw(javaw);
|
||||
strcpy(tmpfile, cmd);
|
||||
strcat(tmpfile, LAUNCH4J_TMP_DIR);
|
||||
char* tmpfilename = tmpfile + strlen(tmpfile);
|
||||
char* exeFilePart = exePath + pathLen + 1;
|
||||
|
||||
// Copy manifest
|
||||
char manifest[_MAX_PATH] = {0};
|
||||
strcpy(manifest, exePath);
|
||||
strcat(manifest, MANIFEST);
|
||||
if (_stat(manifest, &statBuf) == 0) {
|
||||
strcat(tmpfile, exeFilePart);
|
||||
strcat(tmpfile, MANIFEST);
|
||||
debug("Copy:\t\t%s -> %s\n", manifest, tmpfile);
|
||||
CopyFile(manifest, tmpfile, FALSE);
|
||||
}
|
||||
|
||||
// Copy launcher
|
||||
strcpy(tmpfilename, exeFilePart);
|
||||
debug("Copy:\t\t%s -> %s\n", javaw, tmpfile);
|
||||
if (CopyFile(javaw, tmpfile, FALSE)) {
|
||||
strcpy(cmd, tmpfile);
|
||||
return;
|
||||
} else if (_stat(javaw, &statBuf) == 0) {
|
||||
long fs = statBuf.st_size;
|
||||
if (_stat(tmpfile, &statBuf) == 0 && fs == statBuf.st_size) {
|
||||
debug("Reusing:\t\t%s\n", tmpfile);
|
||||
strcpy(cmd, tmpfile);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
appendJavaw(cmd);
|
||||
}
|
||||
|
||||
void appendAppClasspath(char* dst, const char* src, const char* classpath) {
|
||||
strcat(dst, src);
|
||||
if (*classpath) {
|
||||
strcat(dst, ";");
|
||||
}
|
||||
}
|
||||
|
||||
BOOL isJrePathOk(const char* path) {
|
||||
char javaw[_MAX_PATH];
|
||||
BOOL result = FALSE;
|
||||
if (*path) {
|
||||
strcpy(javaw, path);
|
||||
appendJavaw(javaw);
|
||||
result = _stat(javaw, &statBuf) == 0;
|
||||
}
|
||||
debug("Check launcher:\t%s %s\n", javaw, result ? "(OK)" : "(n/a)");
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand environment %variables%
|
||||
*/
|
||||
BOOL expandVars(char *dst, const char *src, const char *exePath, const int pathLen) {
|
||||
char varName[STR];
|
||||
char varValue[MAX_VAR_SIZE];
|
||||
while (strlen(src) > 0) {
|
||||
char *start = strchr(src, '%');
|
||||
if (start != NULL) {
|
||||
char *end = strchr(start + 1, '%');
|
||||
if (end == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
// Copy content up to %VAR%
|
||||
strncat(dst, src, start - src);
|
||||
// Insert value of %VAR%
|
||||
*varName = 0;
|
||||
strncat(varName, start + 1, end - start - 1);
|
||||
// Remember value start for logging
|
||||
char *varValue = dst + strlen(dst);
|
||||
if (strcmp(varName, "EXEDIR") == 0) {
|
||||
strncat(dst, exePath, pathLen);
|
||||
} else if (strcmp(varName, "EXEFILE") == 0) {
|
||||
strcat(dst, exePath);
|
||||
} else if (strcmp(varName, "PWD") == 0) {
|
||||
GetCurrentDirectory(_MAX_PATH, dst + strlen(dst));
|
||||
} else if (strcmp(varName, "OLDPWD") == 0) {
|
||||
strcat(dst, oldPwd);
|
||||
} else if (strstr(varName, HKEY_STR) == varName) {
|
||||
regQueryValue(varName, dst + strlen(dst), BIG_STR);
|
||||
} else if (GetEnvironmentVariable(varName, varValue, MAX_VAR_SIZE) > 0) {
|
||||
strcat(dst, varValue);
|
||||
}
|
||||
debug("Substitute:\t%s = %s\n", varName, varValue);
|
||||
src = end + 1;
|
||||
} else {
|
||||
// Copy remaining content
|
||||
strcat(dst, src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void appendHeapSizes(char *dst) {
|
||||
MEMORYSTATUS m;
|
||||
memset(&m, 0, sizeof(m));
|
||||
GlobalMemoryStatus(&m);
|
||||
|
||||
appendHeapSize(dst, INITIAL_HEAP_SIZE, INITIAL_HEAP_PERCENT,
|
||||
m.dwAvailPhys, "-Xms");
|
||||
appendHeapSize(dst, MAX_HEAP_SIZE, MAX_HEAP_PERCENT,
|
||||
m.dwAvailPhys, "-Xmx");
|
||||
}
|
||||
|
||||
void appendHeapSize(char *dst, const int absID, const int percentID,
|
||||
const DWORD freeMemory, const char *option) {
|
||||
|
||||
const int mb = 1048576; // 1 MB
|
||||
int abs = loadInt(absID);
|
||||
int percent = loadInt(percentID);
|
||||
int free = (long long) freeMemory * percent / (100 * mb); // 100% * 1 MB
|
||||
int size = free > abs ? free : abs;
|
||||
if (size > 0) {
|
||||
debug("Heap %s:\t%d MB / %d%%, Free: %d MB, Heap size: %d MB\n",
|
||||
option, abs, percent, freeMemory / mb, size);
|
||||
strcat(dst, option);
|
||||
_itoa(size, dst + strlen(dst), 10); // 10 -- radix
|
||||
strcat(dst, "m ");
|
||||
}
|
||||
}
|
||||
|
||||
int prepare(const char *lpCmdLine) {
|
||||
char tmp[MAX_ARGS] = {0};
|
||||
hModule = GetModuleHandle(NULL);
|
||||
if (hModule == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Get executable path
|
||||
char exePath[_MAX_PATH] = {0};
|
||||
int pathLen = getExePath(exePath);
|
||||
if (pathLen == -1) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Initialize logging
|
||||
if (strstr(lpCmdLine, "--l4j-debug") != NULL) {
|
||||
hLog = openLogFile(exePath, pathLen);
|
||||
if (hLog == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
debug("\n\nCmdLine:\t%s %s\n", exePath, lpCmdLine);
|
||||
}
|
||||
|
||||
setWow64Flag();
|
||||
|
||||
// Set default error message, title and optional support web site url.
|
||||
loadString(SUPPORT_URL, errUrl);
|
||||
loadString(ERR_TITLE, errTitle);
|
||||
if (!loadString(STARTUP_ERR, errMsg)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Single instance
|
||||
loadString(MUTEX_NAME, mutexName);
|
||||
if (*mutexName) {
|
||||
SECURITY_ATTRIBUTES security;
|
||||
security.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
security.bInheritHandle = TRUE;
|
||||
security.lpSecurityDescriptor = NULL;
|
||||
CreateMutexA(&security, FALSE, mutexName);
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||
debug("Instance already exists.");
|
||||
return ERROR_ALREADY_EXISTS;
|
||||
}
|
||||
}
|
||||
|
||||
// Working dir
|
||||
char tmp_path[_MAX_PATH] = {0};
|
||||
GetCurrentDirectory(_MAX_PATH, oldPwd);
|
||||
if (loadString(CHDIR, tmp_path)) {
|
||||
strncpy(workingDir, exePath, pathLen);
|
||||
appendPath(workingDir, tmp_path);
|
||||
_chdir(workingDir);
|
||||
debug("Working dir:\t%s\n", workingDir);
|
||||
}
|
||||
|
||||
// Use bundled jre or find java
|
||||
if (loadString(JRE_PATH, tmp_path)) {
|
||||
char jrePath[MAX_ARGS] = {0};
|
||||
expandVars(jrePath, tmp_path, exePath, pathLen);
|
||||
debug("Bundled JRE:\t%s\n", jrePath);
|
||||
if (jrePath[0] == '\\' || jrePath[1] == ':') {
|
||||
// Absolute
|
||||
strcpy(cmd, jrePath);
|
||||
} else {
|
||||
// Relative
|
||||
strncpy(cmd, exePath, pathLen);
|
||||
appendPath(cmd, jrePath);
|
||||
}
|
||||
}
|
||||
if (!isJrePathOk(cmd)) {
|
||||
if (!loadString(JAVA_MIN_VER, javaMinVer)) {
|
||||
loadString(BUNDLED_JRE_ERR, errMsg);
|
||||
return FALSE;
|
||||
}
|
||||
loadString(JAVA_MAX_VER, javaMaxVer);
|
||||
if (!findJavaHome(cmd, loadInt(JDK_PREFERENCE))) {
|
||||
loadString(JRE_VERSION_ERR, errMsg);
|
||||
strcat(errMsg, " ");
|
||||
strcat(errMsg, javaMinVer);
|
||||
if (*javaMaxVer) {
|
||||
strcat(errMsg, " - ");
|
||||
strcat(errMsg, javaMaxVer);
|
||||
}
|
||||
loadString(DOWNLOAD_URL, errUrl);
|
||||
return FALSE;
|
||||
}
|
||||
if (!isJrePathOk(cmd)) {
|
||||
loadString(LAUNCHER_ERR, errMsg);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Append a path to the Path environment variable
|
||||
char jreBinPath[_MAX_PATH];
|
||||
strcpy(jreBinPath, cmd);
|
||||
strcat(jreBinPath, "\\bin");
|
||||
if (!appendToPathVar(jreBinPath)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Set environment variables
|
||||
char envVars[MAX_VAR_SIZE] = {0};
|
||||
loadString(ENV_VARIABLES, envVars);
|
||||
char *var = strtok(envVars, "\t");
|
||||
while (var != NULL) {
|
||||
char *varValue = strchr(var, '=');
|
||||
*varValue++ = 0;
|
||||
*tmp = 0;
|
||||
expandVars(tmp, varValue, exePath, pathLen);
|
||||
debug("Set var:\t%s = %s\n", var, tmp);
|
||||
SetEnvironmentVariable(var, tmp);
|
||||
var = strtok(NULL, "\t");
|
||||
}
|
||||
*tmp = 0;
|
||||
|
||||
// Process priority
|
||||
priority = loadInt(PRIORITY_CLASS);
|
||||
|
||||
// Custom process name
|
||||
const BOOL setProcName = loadBool(SET_PROC_NAME)
|
||||
&& strstr(lpCmdLine, "--l4j-default-proc") == NULL;
|
||||
const BOOL wrapper = loadBool(WRAPPER);
|
||||
|
||||
appendLauncher(setProcName, exePath, pathLen, cmd);
|
||||
|
||||
// Heap sizes
|
||||
appendHeapSizes(args);
|
||||
|
||||
// JVM options
|
||||
if (loadString(JVM_OPTIONS, tmp)) {
|
||||
strcat(tmp, " ");
|
||||
} else {
|
||||
*tmp = 0;
|
||||
}
|
||||
/*
|
||||
* Load additional JVM options from .l4j.ini file
|
||||
* Options are separated by spaces or CRLF
|
||||
* # starts an inline comment
|
||||
*/
|
||||
strncpy(tmp_path, exePath, strlen(exePath) - 3);
|
||||
strcat(tmp_path, "l4j.ini");
|
||||
long hFile;
|
||||
if ((hFile = _open(tmp_path, _O_RDONLY)) != -1) {
|
||||
const int jvmOptLen = strlen(tmp);
|
||||
char* src = tmp + jvmOptLen;
|
||||
char* dst = src;
|
||||
const int len = _read(hFile, src, MAX_ARGS - jvmOptLen - BIG_STR);
|
||||
BOOL copy = TRUE;
|
||||
int i;
|
||||
for (i = 0; i < len; i++, src++) {
|
||||
if (*src == '#') {
|
||||
copy = FALSE;
|
||||
} else if (*src == 13 || *src == 10) {
|
||||
copy = TRUE;
|
||||
if (dst > tmp && *(dst - 1) != ' ') {
|
||||
*dst++ = ' ';
|
||||
}
|
||||
} else if (copy) {
|
||||
*dst++ = *src;
|
||||
}
|
||||
}
|
||||
*dst = 0;
|
||||
if (len > 0 && *(dst - 1) != ' ') {
|
||||
strcat(tmp, " ");
|
||||
}
|
||||
_close(hFile);
|
||||
}
|
||||
|
||||
// Expand environment %variables%
|
||||
expandVars(args, tmp, exePath, pathLen);
|
||||
|
||||
// MainClass + Classpath or Jar
|
||||
char mainClass[STR] = {0};
|
||||
char jar[_MAX_PATH] = {0};
|
||||
loadString(JAR, jar);
|
||||
if (loadString(MAIN_CLASS, mainClass)) {
|
||||
if (!loadString(CLASSPATH, tmp)) {
|
||||
return FALSE;
|
||||
}
|
||||
char exp[MAX_ARGS] = {0};
|
||||
expandVars(exp, tmp, exePath, pathLen);
|
||||
strcat(args, "-classpath \"");
|
||||
if (wrapper) {
|
||||
appendAppClasspath(args, exePath, exp);
|
||||
} else if (*jar) {
|
||||
appendAppClasspath(args, jar, exp);
|
||||
}
|
||||
|
||||
// Deal with wildcards or >> strcat(args, exp); <<
|
||||
char* cp = strtok(exp, ";");
|
||||
while(cp != NULL) {
|
||||
debug("Add classpath:\t%s\n", cp);
|
||||
if (strpbrk(cp, "*?") != NULL) {
|
||||
int len = strrchr(cp, '\\') - cp + 1;
|
||||
strncpy(tmp_path, cp, len);
|
||||
char* filename = tmp_path + len;
|
||||
*filename = 0;
|
||||
struct _finddata_t c_file;
|
||||
long hFile;
|
||||
if ((hFile = _findfirst(cp, &c_file)) != -1L) {
|
||||
do {
|
||||
strcpy(filename, c_file.name);
|
||||
strcat(args, tmp_path);
|
||||
strcat(args, ";");
|
||||
debug(" \" :\t%s\n", tmp_path);
|
||||
} while (_findnext(hFile, &c_file) == 0);
|
||||
}
|
||||
_findclose(hFile);
|
||||
} else {
|
||||
strcat(args, cp);
|
||||
strcat(args, ";");
|
||||
}
|
||||
cp = strtok(NULL, ";");
|
||||
}
|
||||
*(args + strlen(args) - 1) = 0;
|
||||
|
||||
strcat(args, "\" ");
|
||||
strcat(args, mainClass);
|
||||
} else if (wrapper) {
|
||||
strcat(args, "-jar \"");
|
||||
strcat(args, exePath);
|
||||
strcat(args, "\"");
|
||||
} else {
|
||||
strcat(args, "-jar \"");
|
||||
strncat(args, exePath, pathLen);
|
||||
appendPath(args, jar);
|
||||
strcat(args, "\"");
|
||||
}
|
||||
|
||||
// Constant command line args
|
||||
if (loadString(CMD_LINE, tmp)) {
|
||||
strcat(args, " ");
|
||||
strcat(args, tmp);
|
||||
}
|
||||
|
||||
// Command line args
|
||||
if (*lpCmdLine) {
|
||||
strcpy(tmp, lpCmdLine);
|
||||
char* dst;
|
||||
while ((dst = strstr(tmp, "--l4j-")) != NULL) {
|
||||
char* src = strchr(dst, ' ');
|
||||
if (src == NULL || *(src + 1) == 0) {
|
||||
*dst = 0;
|
||||
} else {
|
||||
strcpy(dst, src + 1);
|
||||
}
|
||||
}
|
||||
if (*tmp) {
|
||||
strcat(args, " ");
|
||||
strcat(args, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
debug("Launcher:\t%s\n", cmd);
|
||||
debug("Launcher args:\t%s\n", args);
|
||||
debug("Args length:\t%d/32768 chars\n", strlen(args));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void closeHandles() {
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
closeLogFile();
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a path to the Path environment variable
|
||||
*/
|
||||
BOOL appendToPathVar(const char* path) {
|
||||
char chBuf[MAX_VAR_SIZE] = {0};
|
||||
|
||||
const int pathSize = GetEnvironmentVariable("Path", chBuf, MAX_VAR_SIZE);
|
||||
if (MAX_VAR_SIZE - pathSize - 1 < strlen(path)) {
|
||||
return FALSE;
|
||||
}
|
||||
strcat(chBuf, ";");
|
||||
strcat(chBuf, path);
|
||||
return SetEnvironmentVariable("Path", chBuf);
|
||||
}
|
||||
|
||||
DWORD execute(const BOOL wait) {
|
||||
STARTUPINFO si;
|
||||
memset(&pi, 0, sizeof(pi));
|
||||
memset(&si, 0, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
|
||||
DWORD dwExitCode = -1;
|
||||
char cmdline[MAX_ARGS];
|
||||
strcpy(cmdline, "\"");
|
||||
strcat(cmdline, cmd);
|
||||
strcat(cmdline, "\" ");
|
||||
strcat(cmdline, args);
|
||||
if (CreateProcess(NULL, cmdline, NULL, NULL,
|
||||
TRUE, priority, NULL, NULL, &si, &pi)) {
|
||||
if (wait) {
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
GetExitCodeProcess(pi.hProcess, &dwExitCode);
|
||||
debug("Exit code:\t%d\n", dwExitCode);
|
||||
closeHandles();
|
||||
} else {
|
||||
dwExitCode = 0;
|
||||
}
|
||||
}
|
||||
return dwExitCode;
|
||||
}
|
Reference in New Issue
Block a user