Skip to content

Commit

Permalink
Feature: Support scanning Java from HMCL_JAVA_HOME, JAVA_HOME, PATH a…
Browse files Browse the repository at this point in the history
…nd HKey. Support giving priority to Java above 11.
  • Loading branch information
burningtnt committed Apr 26, 2024
1 parent df953e5 commit 51b4108
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 118 deletions.
6 changes: 6 additions & 0 deletions HMCLauncher/HMCL/Version.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,10 @@ class Version {
if (ver[i] != other.ver[i]) return ver[i] < other.ver[i];
return true;
}

bool operator>=(const Version &other) const {
for (int i = 0; i < 4; ++i)
if (ver[i] != other.ver[i]) return ver[i] > other.ver[i];
return true;
}
};
194 changes: 166 additions & 28 deletions HMCLauncher/HMCL/java.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,102 @@
#include "os.h"
#include "version.h"

namespace JavaScanner {
const Version JAVA_8(L"1.8"), JAVA_11(L"11");

const LPCWSTR JDK_NEW = L"SOFTWARE\\JavaSoft\\JDK";
const LPCWSTR JRE_NEW = L"SOFTWARE\\JavaSoft\\JRE";
const LPCWSTR JDK_OLD = L"SOFTWARE\\JavaSoft\\Java Development Kit";
const LPCWSTR JRE_OLD = L"SOFTWARE\\JavaSoft\\Java Runtime Environment";
const LPCWSTR JDK_HKEYS[] = {L"SOFTWARE\\JavaSoft\\JDK",
L"SOFTWARE\\JavaSoft\\JRE",
L"SOFTWARE\\JavaSoft\\Java Development Kit",
L"SOFTWARE\\JavaSoft\\Java Runtime Environment"};

bool oldJavaFound = false;
const LPCWSTR VENDOR_DIRS[] = {L"Java", L"Microsoft", L"BellSoft",
L"Zulu", L"Eclipse Foundation", L"AdoptOpenJDK",
L"Semeru"};

bool FindJavaByRegistryKey(HKEY rootKey, LPCWSTR subKey, std::wstring& path) {
const LPCWSTR PROGRAM_DIRS[] = {L"ProgramFiles", L"ProgramFiles(x86)",
L"ProgramW6432"};

/* Here we find the java from Environment Variable and Registry, which is fast,
* and store the result to 'path'. */
void scan(std::wstring& result, int& status) {
status = JAVA_STATUS_NOT_FOUND;

/*
// If 'HMCL_JAVA_HOME' is settled, this value MUST be used without any check.
if (ERROR_SUCCESS == MyGetEnvironmentVariable(L"HMCL_JAVA_HOME", result)) {
MyPathNormalize(result);
status = JAVA_STATUS_BEST;
trace(result, status);
return;
}
std::wstring currentResult;
if (ERROR_SUCCESS == MyGetEnvironmentVariable(L"JAVA_HOME", currentResult)) {
MyPathNormalize(result);
if (determine(currentResult, result, status) &&
status == JAVA_STATUS_BEST) {
return;
}
}
for (LPCWSTR hkey : JDK_HKEYS) {
scanRegistry(HKEY_LOCAL_MACHINE, hkey, result, status);
if (status == JAVA_STATUS_BEST) {
return;
}
}
*/

std::wstring envPath;
if (ERROR_SUCCESS == MyGetEnvironmentVariable(L"PATH", envPath)) {
int length = envPath.size();
int lastI = 0;
for (int i = 0; i < length; i++) {
if (envPath[i] == L';') {
int partL = i - lastI;
if (partL > 0) {
std::wstring part = envPath.substr(lastI, partL);
MyPathNormalize(part);
MyPathAddBackslash(part);
int partL2 = part.size();
if (part[partL2 - 5] == L'\\' && part[partL2 - 4] == L'b' &&
part[partL2 - 3] == L'i' && part[partL2 - 2] == L'n' &&
part[partL2 - 1] == L'\\') {
part.resize(partL2 - 5);
if (determine(part, result, status) && status == JAVA_STATUS_BEST) {
return;
}
}
}

lastI = i + 1;
}
}
}

/*
std::wstring root;
for (LPCWSTR program : PROGRAM_DIRS) {
if (ERROR_SUCCESS != MyGetEnvironmentVariable(program, root)) {
continue;
}
MyPathNormalize(root);
for (LPCWSTR vender : VENDOR_DIRS) {
std::wstring currentRoot = root + L"";
MyPathAppend(currentRoot, vender);
MyPathAddBackslash(currentRoot);
scanFolder(currentRoot, result, status);
if (status == JAVA_STATUS_BEST) {
return;
}
}
}
*/
}

void scanRegistry(HKEY rootKey, LPCWSTR subKey, std::wstring& path,
int& status) {
WCHAR javaVer[MAX_KEY_LENGTH]; // buffer for subkey name, special for
// JavaVersion
DWORD cbName; // size of name string
Expand All @@ -25,9 +111,10 @@ bool FindJavaByRegistryKey(HKEY rootKey, LPCWSTR subKey, std::wstring& path) {

HKEY hKey;
if (ERROR_SUCCESS !=
(result =
RegOpenKeyEx(rootKey, subKey, 0, KEY_WOW64_64KEY | KEY_READ, &hKey)))
return false;
(result = RegOpenKeyEx(rootKey, subKey, 0, KEY_WOW64_64KEY | KEY_READ,
&hKey))) {
return;
}

RegQueryInfoKey(hKey, // key handle
NULL, // buffer for class name
Expand All @@ -42,9 +129,10 @@ bool FindJavaByRegistryKey(HKEY rootKey, LPCWSTR subKey, std::wstring& path) {
NULL, // security descriptor
NULL); // last write time

if (!cSubKeys) return false;
if (!cSubKeys) {
return;
}

bool flag = false;
for (DWORD i = 0; i < cSubKeys; ++i) {
cbName = MAX_KEY_LENGTH;
if (ERROR_SUCCESS != (result = RegEnumKeyEx(hKey, i, javaVer, &cbName, NULL,
Expand All @@ -55,30 +143,80 @@ bool FindJavaByRegistryKey(HKEY rootKey, LPCWSTR subKey, std::wstring& path) {
if (ERROR_SUCCESS != RegOpenKeyEx(hKey, javaVer, 0, KEY_READ, &javaKey))
continue;

if (ERROR_SUCCESS == MyRegQueryValue(javaKey, L"JavaHome", REG_SZ, path)) {
if (Version(javaVer) < JAVA_8)
oldJavaFound = true;
else
flag = true;
}
std::wstring currentPath;
if (ERROR_SUCCESS ==
MyRegQueryValue(javaKey, L"JavaHome", REG_SZ, currentPath)) {
MyPathNormalize(currentPath);
Version v = Version(javaVer);

if (flag) break;
if (status < JAVA_STATUS_BEST && v >= JAVA_11) {
path = currentPath;
status = JAVA_STATUS_BEST;
trace(path, status);
break;
} else if (status < JAVA_STATUS_USABLE && v >= JAVA_8) {
path = currentPath;
status = JAVA_STATUS_USABLE;
trace(path, status);
}
}
}

RegCloseKey(hKey);
}

return flag;
void scanFolder(std::wstring root, std::wstring& result, int& status) {
WIN32_FIND_DATA data;
HANDLE hFind =
FindFirstFile((root + L"*").c_str(), &data); // Search all subdirectory

if (hFind != INVALID_HANDLE_VALUE) {
do {
std::wstring javaHome = root + data.cFileName;
trace(javaHome);
if (determine(javaHome, result, status) && status == JAVA_STATUS_BEST) {
goto done;
}
} while (FindNextFile(hFind, &data));

done:
FindClose(hFind);
}
}

boolean determine(std::wstring target, std::wstring& result, int& status) {
Version version(L"");
std::wstring currentRoot = target + L"";
MyPathAppend(currentRoot, std::wstring(L"bin\\javaw.exe"));

if (!MyGetFileVersionInfo(currentRoot, version)) return false;

if (status < JAVA_STATUS_BEST && version >= JAVA_11) {
result = target;
status = JAVA_STATUS_BEST;
trace(result, status);
return true;
} else if (status < JAVA_STATUS_USABLE && version >= JAVA_8) {
result = target;
status = JAVA_STATUS_USABLE;
trace(result, status);
return true;
}
return false;
}

bool FindJavaInRegistry(std::wstring& path) {
return FindJavaByRegistryKey(HKEY_LOCAL_MACHINE, JDK_NEW, path) ||
FindJavaByRegistryKey(HKEY_LOCAL_MACHINE, JRE_NEW, path) ||
FindJavaByRegistryKey(HKEY_LOCAL_MACHINE, JDK_OLD, path) ||
FindJavaByRegistryKey(HKEY_LOCAL_MACHINE, JRE_OLD, path);
inline void trace(std::wstring result, int status) {
// MessageBox(
// NULL,
// (std::wstring(L"Java at ") + result +
// std::wstring(L" is detected with status ") + std::to_wstring(status))
// .c_str(),
// L"DEBUG INFO", MB_OK);
}

bool FindJava(std::wstring& path) {
return ERROR_SUCCESS == MyGetEnvironmentVariable(L"HMCL_JAVA_HOME", path) ||
ERROR_SUCCESS == MyGetEnvironmentVariable(L"JAVA_HOME", path) ||
FindJavaInRegistry(path);
inline void trace(std::wstring javaHome) {
// MessageBox(NULL, (std::wstring(L"Determining Java at ") +
// javaHome).c_str(),
// L"DEBUG INFO", MB_OK);
}
} // namespace JavaScanner
18 changes: 14 additions & 4 deletions HMCLauncher/HMCL/java.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,18 @@
#include <windows.h>
#include <string>

// Find Java installation in system registry
bool FindJavaInRegistry(std::wstring &path);
namespace JavaScanner {
// These increasing values represent the priority of the Java.
// Be careful while changing their values!
const int JAVA_STATUS_NOT_FOUND = 0;
const int JAVA_STATUS_USABLE = 1; // Java 8 - 11 (Exclude)
const int JAVA_STATUS_BEST = 2; // Java 11 (Include) - ++

// Find Java Installation in registry and environment variable
bool FindJava(std::wstring &path);
void scan(std::wstring& pathResult, int& status);
void scanRegistry(HKEY rootKey, LPCWSTR subKey, std::wstring& path,
int& status);
void scanFolder(std::wstring root, std::wstring& result, int& status);
boolean determine(std::wstring target, std::wstring& result, int& status);
inline void trace(std::wstring result, int status);
inline void trace(std::wstring javaHome);
} // namespace JavaScanner

0 comments on commit 51b4108

Please sign in to comment.