Loading backends/regedit/regedit.cpp +176 −10 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ #include <stdexcept> #include <memory> #include <stack> #include <vector> #define WIN32_LEAN_AND_MEAN #include <windows.h> Loading Loading @@ -230,6 +231,15 @@ namespace confplus { DWORD maxSubKeySize = dwMaxSubKeyLen > 0 ? dwMaxSubKeyLen + 1 : 1; std::unique_ptr<char[]> subKeyNameBuffer(new char[maxSubKeySize]); // Erst alle Subkeys sammeln, um zu prüfen ob alle numerisch sind (sequence-of-mappings) struct SubKeyInfo { HKEY hKey; std::string name; size_t index; }; std::vector<SubKeyInfo> subKeys; bool allNumeric = true; for (DWORD i = 0; ; ++i) { DWORD dwSizeSubKeyName = maxSubKeySize; Loading @@ -247,25 +257,122 @@ namespace confplus { break; } // Guaranteed ERROR_SUCCESS HKEY hSubKey; std::string subKeyNameStr(subKeyNameBuffer.get()); // Prüfe ob der Subkey-Name rein numerisch ist bool isNumeric = !subKeyNameStr.empty(); for (char c : subKeyNameStr) { if (!std::isdigit(c)) { isNumeric = false; break; } } size_t idx = 0; if (isNumeric) { try { idx = std::stoul(subKeyNameStr); } catch (...) { isNumeric = false; } } // RegOpenKeyExA erfordert keinen KEY_WOW64_64KEY hier, da der Handle hKey bereits die richtige Ansicht hat. if (!isNumeric) { allNumeric = false; } HKEY hSubKey; lRes = RegOpenKeyExA(hKey, subKeyNameBuffer.get(), 0, KEY_READ, &hSubKey); if (lRes == ERROR_SUCCESS) { std::string subKeyNameStr(subKeyNameBuffer.get()); subKeys.push_back({hSubKey, subKeyNameStr, idx}); } else { std::cerr << "[DEBUG] RegOpenKeyExA failed for subkey: " << subKeyNameBuffer.get() << " in " << currentConfigPath << ". Error: " << lRes << std::endl; } } if (!subKeys.empty() && allNumeric) { // Sequence-of-mappings: numerische Subkeys (0, 1, 2...) enthalten // benannte Werte. Transponiere zu parallelen Arrays: // PARENT/0/URL="a", PARENT/1/URL="b" -> PARENT/URL[0]="a", PARENT/URL[1]="b" for (auto& sk : subKeys) { DWORD skValues, skMaxNameLen, skMaxDataLen; lRes = RegQueryInfoKeyA( sk.hKey, NULL, NULL, NULL, NULL, NULL, NULL, &skValues, &skMaxNameLen, &skMaxDataLen, NULL, NULL ); if (lRes != ERROR_SUCCESS) { RegCloseKey(sk.hKey); continue; } DWORD skNameSize = skMaxNameLen > 0 ? skMaxNameLen + 1 : 1; DWORD skDataSize = skMaxDataLen > 0 ? skMaxDataLen + 1 : 1; std::unique_ptr<char[]> skNameBuf(new char[skNameSize]); std::unique_ptr<char[]> skDataBuf(new char[skDataSize]); for (DWORD v = 0; ; ++v) { DWORD skNameLen = skNameSize; DWORD skDataLen = skDataSize; DWORD skType = 0; lRes = RegEnumValueA( sk.hKey, v, skNameBuf.get(), &skNameLen, NULL, &skType, (LPBYTE)skDataBuf.get(), &skDataLen ); if (lRes == ERROR_NO_MORE_ITEMS) break; if (lRes != ERROR_SUCCESS) break; std::string valName(skNameBuf.get()); if (valName.empty()) continue; std::transform( subKeyNameStr.begin(), subKeyNameStr.end(), subKeyNameStr.begin(), valName.begin(), valName.end(), valName.begin(), [](unsigned char c){ return std::toupper(c); } ); std::string nextConfigPath = currentConfigPath + "/" + subKeyNameStr; std::string cvalue; if (skType == REG_SZ || skType == REG_EXPAND_SZ) { cvalue = std::string(skDataBuf.get()); } else if (skType == REG_DWORD) { if (skDataLen >= sizeof(DWORD)) { DWORD dwVal = *reinterpret_cast<DWORD*>(skDataBuf.get()); cvalue = std::to_string(dwVal); } else { continue; } } else { continue; } if (cvalue.empty()) continue; // Speichere als paralleles Array: currentConfigPath/VALUENAME[index] std::string cname = currentConfigPath + "/" + valName; Config::ConfigData* ckey = conf->setKey(cname); conf->setValue(ckey, sk.index, cvalue); } keyStack.push({hSubKey, nextConfigPath, true}); RegCloseKey(sk.hKey); } } else { std::cerr << "[DEBUG] RegOpenKeyExA failed for subkey: " << subKeyNameBuffer.get() << " in " << currentConfigPath << ". Error: " << lRes << std::endl; // Normale Subkeys: wie bisher zur Stack hinzufügen for (auto& sk : subKeys) { std::string subKeyNameStr = sk.name; std::transform( subKeyNameStr.begin(), subKeyNameStr.end(), subKeyNameStr.begin(), [](unsigned char c){ return std::toupper(c); } ); std::string nextConfigPath = currentConfigPath + "/" + subKeyNameStr; keyStack.push({sk.hKey, nextConfigPath, true}); } } Loading Loading @@ -297,7 +404,6 @@ namespace confplus { } void Registry::saveKeyRecursive(HKEY hRootKey, std::string currentPath,const Config::ConfigData* currentData, const Config *conf) { // ... (Die saveKeyRecursive Logik bleibt unverändert, da sie korrekt den globalen REGISTRY_ROOT_KEY verwendet) for (const Config::ConfigData* key = currentData; key != nullptr; key = key->next()) { std::string localKeyName = key->getKey(); Loading @@ -314,6 +420,66 @@ namespace confplus { subKeyPath += "\\"; } subKeyPath += localKeyName; // Prüfe ob alle Kinder parallele Arrays sind (sequence-of-mappings). // Wenn ja: alle haben Elements > 1 und keine Kinder. bool isSeqOfMappings = true; size_t maxElements = 0; for (const Config::ConfigData* child = key->getChild(); child; child = child->next()) { if (child->childs() || child->getElements() <= 1) { isSeqOfMappings = false; break; } if (child->getElements() > maxElements) { maxElements = child->getElements(); } } if (isSeqOfMappings && maxElements > 1) { // Schreibe als numerische Subkeys: PARENT\0\KEY=val, PARENT\1\KEY=val for (size_t idx = 0; idx < maxElements; ++idx) { std::string idxSubKey = subKeyPath + "\\" + std::to_string(idx); HKEY hIdxKey; LONG lRes = RegCreateKeyExA(hRootKey, idxSubKey.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hIdxKey, NULL); if (lRes != ERROR_SUCCESS) { std::cerr << "Failed to create subkey: " << idxSubKey << std::endl; continue; } for (const Config::ConfigData* child = key->getChild(); child; child = child->next()) { if (idx >= child->getElements()) continue; std::string cvalue = conf->getValue(child, idx); std::string childName = child->getKey(); if (isInteger(cvalue)) { try { DWORD dwValue = std::stoul(cvalue); RegSetValueExA(hIdxKey, childName.c_str(), 0, REG_DWORD, (const BYTE*)&dwValue, sizeof(dwValue)); } catch (...) { RegSetValueExA(hIdxKey, childName.c_str(), 0, REG_SZ, (const BYTE*)cvalue.c_str(), cvalue.length() + 1); } } else { RegSetValueExA(hIdxKey, childName.c_str(), 0, REG_SZ, (const BYTE*)cvalue.c_str(), cvalue.length() + 1); } } RegCloseKey(hIdxKey); } } else { // Normale Rekursion für Kinder HKEY hSubKey; LONG lRes = RegCreateKeyExA(hRootKey, subKeyPath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hSubKey, NULL); if (lRes == ERROR_SUCCESS) { saveKeyRecursive(hRootKey, subKeyPath, key->getChild(), conf); RegCloseKey(hSubKey); } } } else { if (!subKeyPath.empty()) { subKeyPath += "\\"; Loading Loading
backends/regedit/regedit.cpp +176 −10 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ #include <stdexcept> #include <memory> #include <stack> #include <vector> #define WIN32_LEAN_AND_MEAN #include <windows.h> Loading Loading @@ -230,6 +231,15 @@ namespace confplus { DWORD maxSubKeySize = dwMaxSubKeyLen > 0 ? dwMaxSubKeyLen + 1 : 1; std::unique_ptr<char[]> subKeyNameBuffer(new char[maxSubKeySize]); // Erst alle Subkeys sammeln, um zu prüfen ob alle numerisch sind (sequence-of-mappings) struct SubKeyInfo { HKEY hKey; std::string name; size_t index; }; std::vector<SubKeyInfo> subKeys; bool allNumeric = true; for (DWORD i = 0; ; ++i) { DWORD dwSizeSubKeyName = maxSubKeySize; Loading @@ -247,25 +257,122 @@ namespace confplus { break; } // Guaranteed ERROR_SUCCESS HKEY hSubKey; std::string subKeyNameStr(subKeyNameBuffer.get()); // Prüfe ob der Subkey-Name rein numerisch ist bool isNumeric = !subKeyNameStr.empty(); for (char c : subKeyNameStr) { if (!std::isdigit(c)) { isNumeric = false; break; } } size_t idx = 0; if (isNumeric) { try { idx = std::stoul(subKeyNameStr); } catch (...) { isNumeric = false; } } // RegOpenKeyExA erfordert keinen KEY_WOW64_64KEY hier, da der Handle hKey bereits die richtige Ansicht hat. if (!isNumeric) { allNumeric = false; } HKEY hSubKey; lRes = RegOpenKeyExA(hKey, subKeyNameBuffer.get(), 0, KEY_READ, &hSubKey); if (lRes == ERROR_SUCCESS) { std::string subKeyNameStr(subKeyNameBuffer.get()); subKeys.push_back({hSubKey, subKeyNameStr, idx}); } else { std::cerr << "[DEBUG] RegOpenKeyExA failed for subkey: " << subKeyNameBuffer.get() << " in " << currentConfigPath << ". Error: " << lRes << std::endl; } } if (!subKeys.empty() && allNumeric) { // Sequence-of-mappings: numerische Subkeys (0, 1, 2...) enthalten // benannte Werte. Transponiere zu parallelen Arrays: // PARENT/0/URL="a", PARENT/1/URL="b" -> PARENT/URL[0]="a", PARENT/URL[1]="b" for (auto& sk : subKeys) { DWORD skValues, skMaxNameLen, skMaxDataLen; lRes = RegQueryInfoKeyA( sk.hKey, NULL, NULL, NULL, NULL, NULL, NULL, &skValues, &skMaxNameLen, &skMaxDataLen, NULL, NULL ); if (lRes != ERROR_SUCCESS) { RegCloseKey(sk.hKey); continue; } DWORD skNameSize = skMaxNameLen > 0 ? skMaxNameLen + 1 : 1; DWORD skDataSize = skMaxDataLen > 0 ? skMaxDataLen + 1 : 1; std::unique_ptr<char[]> skNameBuf(new char[skNameSize]); std::unique_ptr<char[]> skDataBuf(new char[skDataSize]); for (DWORD v = 0; ; ++v) { DWORD skNameLen = skNameSize; DWORD skDataLen = skDataSize; DWORD skType = 0; lRes = RegEnumValueA( sk.hKey, v, skNameBuf.get(), &skNameLen, NULL, &skType, (LPBYTE)skDataBuf.get(), &skDataLen ); if (lRes == ERROR_NO_MORE_ITEMS) break; if (lRes != ERROR_SUCCESS) break; std::string valName(skNameBuf.get()); if (valName.empty()) continue; std::transform( subKeyNameStr.begin(), subKeyNameStr.end(), subKeyNameStr.begin(), valName.begin(), valName.end(), valName.begin(), [](unsigned char c){ return std::toupper(c); } ); std::string nextConfigPath = currentConfigPath + "/" + subKeyNameStr; std::string cvalue; if (skType == REG_SZ || skType == REG_EXPAND_SZ) { cvalue = std::string(skDataBuf.get()); } else if (skType == REG_DWORD) { if (skDataLen >= sizeof(DWORD)) { DWORD dwVal = *reinterpret_cast<DWORD*>(skDataBuf.get()); cvalue = std::to_string(dwVal); } else { continue; } } else { continue; } if (cvalue.empty()) continue; // Speichere als paralleles Array: currentConfigPath/VALUENAME[index] std::string cname = currentConfigPath + "/" + valName; Config::ConfigData* ckey = conf->setKey(cname); conf->setValue(ckey, sk.index, cvalue); } keyStack.push({hSubKey, nextConfigPath, true}); RegCloseKey(sk.hKey); } } else { std::cerr << "[DEBUG] RegOpenKeyExA failed for subkey: " << subKeyNameBuffer.get() << " in " << currentConfigPath << ". Error: " << lRes << std::endl; // Normale Subkeys: wie bisher zur Stack hinzufügen for (auto& sk : subKeys) { std::string subKeyNameStr = sk.name; std::transform( subKeyNameStr.begin(), subKeyNameStr.end(), subKeyNameStr.begin(), [](unsigned char c){ return std::toupper(c); } ); std::string nextConfigPath = currentConfigPath + "/" + subKeyNameStr; keyStack.push({sk.hKey, nextConfigPath, true}); } } Loading Loading @@ -297,7 +404,6 @@ namespace confplus { } void Registry::saveKeyRecursive(HKEY hRootKey, std::string currentPath,const Config::ConfigData* currentData, const Config *conf) { // ... (Die saveKeyRecursive Logik bleibt unverändert, da sie korrekt den globalen REGISTRY_ROOT_KEY verwendet) for (const Config::ConfigData* key = currentData; key != nullptr; key = key->next()) { std::string localKeyName = key->getKey(); Loading @@ -314,6 +420,66 @@ namespace confplus { subKeyPath += "\\"; } subKeyPath += localKeyName; // Prüfe ob alle Kinder parallele Arrays sind (sequence-of-mappings). // Wenn ja: alle haben Elements > 1 und keine Kinder. bool isSeqOfMappings = true; size_t maxElements = 0; for (const Config::ConfigData* child = key->getChild(); child; child = child->next()) { if (child->childs() || child->getElements() <= 1) { isSeqOfMappings = false; break; } if (child->getElements() > maxElements) { maxElements = child->getElements(); } } if (isSeqOfMappings && maxElements > 1) { // Schreibe als numerische Subkeys: PARENT\0\KEY=val, PARENT\1\KEY=val for (size_t idx = 0; idx < maxElements; ++idx) { std::string idxSubKey = subKeyPath + "\\" + std::to_string(idx); HKEY hIdxKey; LONG lRes = RegCreateKeyExA(hRootKey, idxSubKey.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hIdxKey, NULL); if (lRes != ERROR_SUCCESS) { std::cerr << "Failed to create subkey: " << idxSubKey << std::endl; continue; } for (const Config::ConfigData* child = key->getChild(); child; child = child->next()) { if (idx >= child->getElements()) continue; std::string cvalue = conf->getValue(child, idx); std::string childName = child->getKey(); if (isInteger(cvalue)) { try { DWORD dwValue = std::stoul(cvalue); RegSetValueExA(hIdxKey, childName.c_str(), 0, REG_DWORD, (const BYTE*)&dwValue, sizeof(dwValue)); } catch (...) { RegSetValueExA(hIdxKey, childName.c_str(), 0, REG_SZ, (const BYTE*)cvalue.c_str(), cvalue.length() + 1); } } else { RegSetValueExA(hIdxKey, childName.c_str(), 0, REG_SZ, (const BYTE*)cvalue.c_str(), cvalue.length() + 1); } } RegCloseKey(hIdxKey); } } else { // Normale Rekursion für Kinder HKEY hSubKey; LONG lRes = RegCreateKeyExA(hRootKey, subKeyPath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hSubKey, NULL); if (lRes == ERROR_SUCCESS) { saveKeyRecursive(hRootKey, subKeyPath, key->getChild(), conf); RegCloseKey(hSubKey); } } } else { if (!subKeyPath.empty()) { subKeyPath += "\\"; Loading