/* | |
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); | |
// (foundJava & FOUND_SDK) { // removed by fry | |
// 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); | |
char jdk_path[_MAX_PATH] = {0}; // fry | |
strcpy(jdk_path, cmd); | |
//msgBox(jdk_path); | |
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); | |
} | |
// add tools.jar for JDK [fry] | |
char tools[_MAX_PATH] = { 0 }; | |
sprintf(tools, "%s\\lib\\tools.jar", jdk_path); | |
appendAppClasspath(args, tools, 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); | |
} | |
// may need to ignore STILL_ACTIVE (error code 259) here | |
// http://msdn.microsoft.com/en-us/library/ms683189(VS.85).aspx | |
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; | |
} |