summaryrefslogtreecommitdiff
path: root/src/env.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/env.cpp')
-rw-r--r--src/env.cpp160
1 files changed, 160 insertions, 0 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)