From 17c98655f86f8ea41c4528e3fc25d12388a36861 Mon Sep 17 00:00:00 2001 From: Sky Date: Sun, 6 Oct 2013 19:54:52 +0100 Subject: [PATCH] First draft of multiple Java installation detection on Windows --- gui/settingsdialog.cpp | 4 +- gui/settingsdialog.ui | 18 +++++- logic/JavaUtils.cpp | 131 +++++++++++++++++++++++++++-------------- logic/JavaUtils.h | 20 ++++++- 4 files changed, 123 insertions(+), 50 deletions(-) diff --git a/gui/settingsdialog.cpp b/gui/settingsdialog.cpp index c6fe893d..011925b7 100644 --- a/gui/settingsdialog.cpp +++ b/gui/settingsdialog.cpp @@ -185,9 +185,9 @@ void SettingsDialog::loadSettings(SettingsObject *s) void SettingsDialog::on_pushButton_clicked() { JavaUtils jut; - QStringList paths = jut.FindJavaPath(); + auto javas = jut.FindJavaPaths(); - ui->javaPathTextBox->setText(paths.at(0)); + ui->javaPathTextBox->setText(std::get(javas.at(0))); } void SettingsDialog::on_btnBrowse_clicked() diff --git a/gui/settingsdialog.ui b/gui/settingsdialog.ui index d7a134fb..8fa5e96e 100644 --- a/gui/settingsdialog.ui +++ b/gui/settingsdialog.ui @@ -374,6 +374,12 @@ + + + 0 + 0 + + Java path: @@ -381,6 +387,12 @@ + + + 0 + 0 + + JVM arguments: @@ -402,9 +414,6 @@ - - - @@ -418,6 +427,9 @@ + + + diff --git a/logic/JavaUtils.cpp b/logic/JavaUtils.cpp index 1cfd0a77..91fa271c 100644 --- a/logic/JavaUtils.cpp +++ b/logic/JavaUtils.cpp @@ -14,7 +14,6 @@ */ #include "JavaUtils.h" -#include "osutils.h" #include "pathutils.h" #include @@ -22,27 +21,33 @@ #include #include -#if WINDOWS -#include - -#endif - JavaUtils::JavaUtils() { } -#if WINDOWS -QStringList JavaUtils::FindJavaPath() +std::vector JavaUtils::GetDefaultJava() { - QStringList paths; + std::vector javas; + javas.push_back(std::make_tuple("java", "unknown", "java", false)); + + return javas; +} + +#if WINDOWS +std::vector JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString keyName) +{ + std::vector javas; + + QString archType = "unknown"; + if(keyType == KEY_WOW64_64KEY) archType = "64"; + else if(keyType == KEY_WOW64_32KEY) archType = "32"; HKEY jreKey; - QString jreKeyName = "SOFTWARE\\JavaSoft\\Java Runtime Environment"; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, jreKeyName.toStdString().c_str(), 0, KEY_READ | KEY_WOW64_64KEY, &jreKey) == ERROR_SUCCESS) + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName.toStdString().c_str(), 0, KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) == ERROR_SUCCESS) { - // Read the current JRE version from the registry. - // This will be used to find the key that contains the JavaHome value. + // Read the current type version from the registry. + // This will be used to find any key that contains the JavaHome value. char *value = new char[0]; DWORD valueSz = 0; if (RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE*)value, &valueSz) == ERROR_MORE_DATA) @@ -51,64 +56,102 @@ QStringList JavaUtils::FindJavaPath() RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE*)value, &valueSz); } - RegCloseKey(jreKey); + QString recommended = value; - // Now open the registry key for the JRE version that we just got. - jreKeyName.append("\\").append(value); - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, jreKeyName.toStdString().c_str(), 0, KEY_READ | KEY_WOW64_64KEY, &jreKey) == ERROR_SUCCESS) + TCHAR subKeyName[255]; + DWORD subKeyNameSize, numSubKeys, retCode; + + // Get the number of subkeys + RegQueryInfoKey(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + + // Iterate until RegEnumKeyEx fails + if(numSubKeys > 0) { - // Read the JavaHome value to find where Java is installed. - value = new char[0]; - valueSz = 0; - if (RegQueryValueExA(jreKey, "JavaHome", NULL, NULL, (BYTE*)value, &valueSz) == ERROR_MORE_DATA) + for(int i = 0; i < numSubKeys; i++) { - value = new char[valueSz]; - RegQueryValueExA(jreKey, "JavaHome", NULL, NULL, (BYTE*)value, &valueSz); + subKeyNameSize = 255; + retCode = RegEnumKeyEx(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL, NULL); + if(retCode == ERROR_SUCCESS) + { + // Now open the registry key for the version that we just got. + QString newKeyName = keyName + "\\" + subKeyName; - paths << QDir(PathCombine(value, "bin")).absoluteFilePath("java.exe"); + HKEY newKey; + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, newKeyName.toStdString().c_str(), 0, KEY_READ | KEY_WOW64_64KEY, &newKey) == ERROR_SUCCESS) + { + // Read the JavaHome value to find where Java is installed. + value = new char[0]; + valueSz = 0; + if (RegQueryValueEx(newKey, "JavaHome", NULL, NULL, (BYTE*)value, &valueSz) == ERROR_MORE_DATA) + { + value = new char[valueSz]; + RegQueryValueEx(newKey, "JavaHome", NULL, NULL, (BYTE*)value, &valueSz); + + javas.push_back(std::make_tuple(subKeyName, archType, QDir(PathCombine(value, "bin")).absoluteFilePath("java.exe"), (recommended == subKeyName))); + } + + RegCloseKey(newKey); + } + } } - - RegCloseKey(jreKey); } + + RegCloseKey(jreKey); } - if(paths.length() <= 0) + return javas; +} + +std::vector JavaUtils::FindJavaPaths() +{ + std::vector JRE64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment"); + std::vector JDK64s = this->FindJavaFromRegistryKey(KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Development Kit"); + std::vector JRE32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment"); + std::vector JDK32s = this->FindJavaFromRegistryKey(KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Development Kit"); + + std::vector javas; + javas.insert(javas.end(), JRE64s.begin(), JRE64s.end()); + javas.insert(javas.end(), JDK64s.begin(), JDK64s.end()); + javas.insert(javas.end(), JRE32s.begin(), JRE32s.end()); + javas.insert(javas.end(), JDK32s.begin(), JDK32s.end()); + + if(javas.size() <= 0) { QLOG_WARN() << "Failed to find Java in the Windows registry - defaulting to \"java\""; - paths << "java"; + return this->GetDefaultJava(); } - return paths; + QLOG_INFO() << "Found the following Java installations (64 -> 32, JRE -> JDK): "; + + for(auto &java : javas) + { + QString sRec; + if(std::get(java)) sRec = "(Recommended)"; + QLOG_INFO() << std::get(java) << std::get(java) << " at " << std::get(java) << sRec; + } + + return javas; } #elif OSX -QStringList JavaUtils::FindJavaPath() +std::vector JavaUtils::FindJavaPath() { QLOG_INFO() << "OS X Java detection incomplete - defaulting to \"java\""; - QStringList paths; - paths << "java"; - - return paths; + return this->GetDefaultPath(); } #elif LINUX -QStringList JavaUtils::FindJavaPath() +std::vector JavaUtils::FindJavaPath() { QLOG_INFO() << "Linux Java detection incomplete - defaulting to \"java\""; - QStringList paths; - paths << "java"; - - return paths; + return this->GetDefaultPath(); } #else -QStringList JavaUtils::FindJavaPath() +std::vector JavaUtils::FindJavaPath() { QLOG_INFO() << "Unknown operating system build - defaulting to \"java\""; - QStringList paths; - paths << "java"; - - return paths; + return this->GetDefaultPath(); } #endif diff --git a/logic/JavaUtils.h b/logic/JavaUtils.h index fef2a1bf..63daac12 100644 --- a/logic/JavaUtils.h +++ b/logic/JavaUtils.h @@ -17,10 +17,28 @@ #include +#include "osutils.h" + +#if WINDOWS + #include +#endif + +#define JI_ID 0 +#define JI_ARCH 1 +#define JI_PATH 2 +#define JI_REC 3 +typedef std::tuple java_install; + class JavaUtils { public: JavaUtils(); - QStringList FindJavaPath(); + std::vector FindJavaPaths(); + +private: + std::vector GetDefaultJava(); +#if WINDOWS + std::vector FindJavaFromRegistryKey(DWORD keyType, QString keyName); +#endif };