diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/env.cpp | 160 | ||||
| -rw-r--r-- | src/env.h | 9 | ||||
| -rw-r--r-- | src/instancemanager.cpp | 31 | ||||
| -rw-r--r-- | src/instancemanager.h | 2 |
4 files changed, 196 insertions, 6 deletions
diff --git a/src/env.cpp b/src/env.cpp index 9f0acbbd..5bed84c1 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -846,6 +846,166 @@ Association getAssociation(const QFileInfo& targetInfo) } +struct RegistryKeyCloser +{ + using pointer = HKEY; + + void operator()(HKEY key) + { + if (key != 0) { + ::RegCloseKey(key); + } + } +}; + +using RegistryKeyPtr = std::unique_ptr<HKEY, RegistryKeyCloser>; + +RegistryKeyPtr openRegistryKey(HKEY parent, const wchar_t* name) +{ + HKEY subkey = 0; + + auto r = ::RegOpenKeyExW( + parent, name, + 0, KEY_SET_VALUE|KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE, + &subkey); + + if (r != ERROR_SUCCESS) { + return {}; + } + + return RegistryKeyPtr(subkey); +} + +bool keyHasValues(HKEY key) +{ + auto name = std::make_unique<wchar_t[]>(1000 + 1); + DWORD nameSize = 1000; + + // note that RegEnumValueW() also enumerates the default value if it exists + auto r = ::RegEnumValueW( + key, 0, name.get(), &nameSize, nullptr, nullptr, nullptr, nullptr); + + if (r != ERROR_NO_MORE_ITEMS) { + return true; + } + + // no values, no default, it's empty + return false; +} + +bool forEachSubKey(HKEY key, std::function<bool (const wchar_t* name)> f) +{ + auto name = std::make_unique<wchar_t[]>(1000 + 1); + DWORD nameSize = 1000; + + DWORD i = 0; + + // something would be really wrong if it had more than 100 keys + while (i < 100) + { + auto r = ::RegEnumKeyExW( + key, i, name.get(), &nameSize, nullptr, nullptr, nullptr, nullptr); + + if (r == ERROR_NO_MORE_ITEMS) { + // no more subkeys + break; + } + + if (r == ERROR_SUCCESS) { + // a subkey exists + auto subkey = openRegistryKey(key, name.get()); + + if (!subkey) { + // can't open it, stop + return false; + } + + // fire callback + if (!f(name.get())) { + return false; + } + } else { + // something went wrong, stop + return false; + } + + ++i; + } + + return true; +} + +bool isKeyEmpty(HKEY key) +{ + // check for any values + if (keyHasValues(key)) { + return false; + } + + auto r = forEachSubKey(key, [&](const wchar_t* name) { + // a subkey exists, recursively check if it's empty + auto subkey = openRegistryKey(key, name); + + if (!subkey) { + // can't open, stop + return false; + } + + if (!isKeyEmpty(subkey.get())) { + // not empty, stop + return false; + } + + // empty, go on + return true; + }); + + if (!r) { + // something went wrong or some subkey has values + return false; + } + + // key has no values and has either no subkeys or all subkeys are empty + return true; +} + +void deleteRegistryKeyIfEmpty(const QString& name) +{ + if (name.isEmpty()) { + return; + } + + auto key = openRegistryKey(HKEY_CURRENT_USER, name.toStdWString().c_str()); + if (!key) { + return; + } + + if (!isKeyEmpty(key.get())) { + return; + } + + ::RegDeleteTreeW(HKEY_CURRENT_USER, name.toStdWString().c_str()); +} + +bool registryValueExists(const QString& keyName, const QString& valueName) +{ + auto key = openRegistryKey( + HKEY_CURRENT_USER, keyName.toStdWString().c_str()); + + if (!key) { + return false; + } + + DWORD type = 0; + + auto r = ::RegQueryValueExW( + key.get(), valueName.toStdWString().c_str(), + nullptr, &type, nullptr, nullptr); + + return (r == ERROR_SUCCESS); +} + + // returns the filename of the given process or the current one // std::wstring processFilename(HANDLE process=INVALID_HANDLE_VALUE) @@ -301,6 +301,15 @@ struct Association Association getAssociation(const QFileInfo& file); +// returns whether the given value exists +// +bool registryValueExists(const QString& key, const QString& value); + +// deletes a registry key if it's empty or only contains empty keys +// +void deleteRegistryKeyIfEmpty(const QString& name); + + enum class CoreDumpTypes { Mini = 1, diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp index 9bcd0f3c..aa8f1d8c 100644 --- a/src/instancemanager.cpp +++ b/src/instancemanager.cpp @@ -23,6 +23,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "settings.h" #include "shared/appconfig.h" #include "plugincontainer.h" +#include "env.h" #include <report.h> #include <iplugingame.h> #include <utility.h> @@ -37,14 +38,15 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. using namespace MOBase; -static const char COMPANY_NAME[] = "Tannin"; -static const char APPLICATION_NAME[] = "Mod Organizer"; -static const char INSTANCE_KEY[] = "CurrentInstance"; +const QString Organization = "Mod Organizer Team"; +const QString Application = "Mod Organizer"; +const QString InstanceValue = "CurrentInstance"; InstanceManager::InstanceManager() - : m_AppSettings(COMPANY_NAME, APPLICATION_NAME) + : m_AppSettings(Organization, Application) { + updateRegistryKey(); } InstanceManager &InstanceManager::instance() @@ -53,6 +55,23 @@ InstanceManager &InstanceManager::instance() return s_Instance; } +void InstanceManager::updateRegistryKey() +{ + const QString OldOrganization = "Tannin"; + const QString OldApplication = "Mod Organizer"; + const QString OldInstanceValue = "CurrentInstance"; + + const QString OldRootKey = "Software\\" + OldOrganization; + + if (env::registryValueExists(OldRootKey + "\\" + OldApplication, OldInstanceValue)) { + QSettings old(OldOrganization, OldApplication); + setCurrentInstance(old.value(OldInstanceValue).toString()); + old.remove(OldInstanceValue); + } + + env::deleteRegistryKeyIfEmpty(OldRootKey); +} + void InstanceManager::overrideInstance(const QString& instanceName) { m_overrideInstanceName = instanceName; @@ -70,7 +89,7 @@ QString InstanceManager::currentInstance() const if (m_overrideInstance) return m_overrideInstanceName; else - return m_AppSettings.value(INSTANCE_KEY, "").toString(); + return m_AppSettings.value(InstanceValue, "").toString(); } void InstanceManager::clearCurrentInstance() @@ -82,7 +101,7 @@ void InstanceManager::clearCurrentInstance() void InstanceManager::setCurrentInstance(const QString &name) { - m_AppSettings.setValue(INSTANCE_KEY, name); + m_AppSettings.setValue(InstanceValue, name); } bool InstanceManager::deleteLocalInstance(const QString &instanceId) const diff --git a/src/instancemanager.h b/src/instancemanager.h index 2331ebfd..7f87045d 100644 --- a/src/instancemanager.h +++ b/src/instancemanager.h @@ -71,6 +71,8 @@ private: bool portableInstall() const; bool portableInstallIsLocked() const; + void updateRegistryKey(); + private: QSettings m_AppSettings; |
