Commit d29d7346 authored by jan.koester's avatar jan.koester
Browse files

inital support regedit

parent 61424840
Loading
Loading
Loading
Loading
+64 −60
Original line number Diff line number Diff line
// In regedit.cpp

/*******************************************************************************
 * Copyright (c) 2025, Jan Koester jan.koester@gmx.net
 * All rights reserved.
@@ -27,16 +29,16 @@


#include "regedit.h"
#include "exception.h"
#include "exception.h" // Angenommener Include
#include "conf.h"      // Angenommener Include

#include <iostream>
#include <string>
#include <sstream>
#include <algorithm> // Für std::replace
#include <algorithm>
#include <stdexcept>
#include <memory> // Für std::unique_ptr
#include <memory> 

// Spezifische Windows API Includes
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winreg.h>
@@ -47,18 +49,11 @@ namespace confplus {
    HKEY REGISTRY_ROOT_KEY = HKEY_CURRENT_USER;
    
    // -------------------------------------------------------------------------
    // HILFSFUNKTIONEN
    // HILFSFUNKTIONEN (unverändert)
    // -------------------------------------------------------------------------

    /**
     * @brief Splittet den Config-Pfad (/Abschnitt/Key) in den Registry Subkey-Pfad (Abschnitt\Key)
     * und den letzten Teil als Value-Namen.
     */
    void splitConfigPath(const std::string& configPath, std::string& registryKeyPath, std::string& valueName) {
        // Entferne den führenden '/'
        std::string path = configPath.length() > 0 && configPath[0] == '/' ? configPath.substr(1) : configPath;

        // Finde den letzten '/'
        size_t last_slash = path.rfind('/');

        if (last_slash == std::string::npos) {
@@ -67,10 +62,13 @@ namespace confplus {
        } else {
            registryKeyPath = path.substr(0, last_slash);
            valueName = path.substr(last_slash + 1);

            // Ersetze '/' durch '\' für die Registry-API
            std::replace(registryKeyPath.begin(), registryKeyPath.end(), '/', '\\');
        }
        
        if (path.find('\\') == std::string::npos) {
            registryKeyPath = "";
            valueName = path;
        }
    }

    bool isInteger(const std::string& s) {
@@ -81,14 +79,10 @@ namespace confplus {
        return it == s.end();
    }
    
    /**
     * @brief Rekursive Funktion zum Laden von Werten und Subkeys aus der Registry.
     */
    void loadKeyRecursiveA(Config* conf, HKEY hKey, const std::string& currentConfigPath) {
        
        DWORD dwValues, dwSubKeys, dwMaxValueNameLen, dwMaxValueLen, dwMaxSubKeyLen;
        
        // 1. Hole Infos über den aktuellen Schlüssel
        LONG lRes = RegQueryInfoKeyA(
            hKey, NULL, NULL, NULL, 
            &dwSubKeys, &dwMaxSubKeyLen, NULL, 
@@ -100,13 +94,10 @@ namespace confplus {
            return; 
        }
        
        // --- 2. Werte (Values) laden ---
        if (dwValues > 0) {
            // maxNameSize und maxDataSize müssen die Nullterminierung mit einbeziehen
            DWORD maxNameSize = dwMaxValueNameLen > 0 ? dwMaxValueNameLen + 1 : 1;
            DWORD maxDataSize = dwMaxValueLen > 0 ? dwMaxValueLen + 1 : 1;

            // Verwendung von std::unique_ptr für automatische Speicherverwaltung
            std::unique_ptr<char[]> valueNameBuffer(new char[maxNameSize]);
            std::unique_ptr<char[]> dataBuffer(new char[maxDataSize]); 
            DWORD dwSizeValueName, dwSizeData, dwType;
@@ -125,7 +116,6 @@ namespace confplus {

                if (lRes == ERROR_SUCCESS) {
                    std::string valueNameStr = std::string(valueNameBuffer.get());
                    // Überspringe den '(Standardwert)', wenn benannte Werte vorhanden sind
                    if (valueNameStr.empty() && dwValues > 1) {
                        continue;
                    }
@@ -144,7 +134,7 @@ namespace confplus {
                            continue;
                        }
                    } else {
                        continue; // Andere Typen ignorieren
                        continue;
                    }
                    
                    Config::ConfigData* ckey = conf->setKey(cname);
@@ -153,7 +143,6 @@ namespace confplus {
            }
        }

        // --- 3. Subkeys (Unterschlüssel) rekursiv laden ---
        if (dwSubKeys > 0) {
            DWORD maxSubKeySize = dwMaxSubKeyLen > 0 ? dwMaxSubKeyLen + 1 : 1;
            std::unique_ptr<char[]> subKeyNameBuffer(new char[maxSubKeySize]);
@@ -169,18 +158,13 @@ namespace confplus {
                );

                if (lRes == ERROR_SUCCESS) {
                    // Öffne den Subkey
                    lRes = RegOpenKeyExA(
                        hKey, subKeyNameBuffer.get(), 0, KEY_READ, &hSubKey
                    );

                    if (lRes == ERROR_SUCCESS) {
                        // Erzeuge den neuen Konfigurationspfad
                        std::string nextConfigPath = currentConfigPath + "/" + std::string(subKeyNameBuffer.get());
                        
                        // Rekursiver Aufruf
                        loadKeyRecursiveA(conf, hSubKey, nextConfigPath);
                        
                        RegCloseKey(hSubKey);
                    }
                }
@@ -208,32 +192,25 @@ namespace confplus {
        return "Jan Koester";
    }
    
    /**
     * @brief Traversiert die ConfigData-Struktur rekursiv und speichert die Werte.
     */
    void Registry::saveKeyRecursive(HKEY hRootKey, std::string currentPath,const Config::ConfigData* currentData, const Config *conf) {
    void Registry::saveKeyRecursive(HKEY hRootKey, std::string currentPath, Config::ConfigData* currentData, const Config *conf) {
        // ... (Die saveKeyRecursive Logik bleibt unverändert, da sie korrekt den globalen REGISTRY_ROOT_KEY verwendet)
        for (Config::ConfigData* key = currentData; key != nullptr; key = key->nextData.get()) {
            
        // Iteriere über die 'nextData'-Kette auf der aktuellen Hierarchie-Ebene
        for (const Config::ConfigData* key = currentData; key != nullptr; key = key->next()) {
            std::string localKeyName = key->Key;
            
            // ANNAHME: key->Key enthält den lokalen Schlüsselnamen (z.B. "Datenbank", "Port")
            std::string localKeyName = key->getKey();
            
            if (localKeyName.empty() && !key->childs()) {
            if (localKeyName.empty() && !key->haveChild) {
                continue;
            }

            std::string subKeyPath = currentPath;
            std::string valueName = localKeyName;
            
            if (key->childs()) {
                // Sektion/Subkey
            if (key->haveChild) {
                if (!subKeyPath.empty()) {
                    subKeyPath += "\\";
                }
                subKeyPath += localKeyName;
            } else {
                // Wert
                if (!subKeyPath.empty()) {
                    subKeyPath += "\\";
                }
@@ -261,7 +238,7 @@ namespace confplus {
                    if (elements > 1) {
                        currentRegValueName = (valueName.empty() ? "" : valueName + "_") + std::to_string(pos);
                    } else if (valueName.empty()) {
                        currentRegValueName = ""; // (Standardwert)
                        currentRegValueName = "";
                    }

                    if (isInteger(cvalue)) {
@@ -285,37 +262,31 @@ namespace confplus {
                    }
                }

                // Schließe den Schlüssel, wenn es nur ein Wert war
                if (!key->childs() ) {
                if (!key->haveChild) {
                    RegCloseKey(hSubKey);
                }
            } else {
                std::cerr << "Failed to create subkey: " << subKeyPath << std::endl;
            }
            
            // Rekursiver Aufruf für Child-Knoten
            if (key->childs()) { 
            if (key->haveChild && key->Child) { 
                std::string nextPath = subKeyPath;
                
                if (lRes == ERROR_SUCCESS) {
                    saveKeyRecursive(hRootKey, nextPath, key->getChild(), conf);
                    RegCloseKey(hSubKey); // Schließe nach der Rekursion
                    saveKeyRecursive(hRootKey, nextPath, key->Child.get(), conf);
                    RegCloseKey(hSubKey);
                }
            }
        }
    }
    
    /**
     * @brief Speichert die Konfiguration in der Windows Registry.
     */
    void Registry::saveConfig(const char *path, const Config *conf){
        
        HKEY hRootKey;
        DWORD dwDisposition;

        // Öffne/Erstelle den Hauptschlüssel
        LONG lRes = RegCreateKeyExA(
            REGISTRY_ROOT_KEY,
            REGISTRY_ROOT_KEY, // Nutzt den globalen Root-Key
            path,
            0, NULL, REG_OPTION_NON_VOLATILE,
            KEY_ALL_ACCESS,
@@ -327,9 +298,8 @@ namespace confplus {
            throw e[ConfException::Error] << "Failed to create/open root registry key: " << path;
        }

        // Starte die rekursive Traversierung
        if (conf->firstData) {
            saveKeyRecursive(hRootKey, "", conf->first(), conf);
            saveKeyRecursive(hRootKey, "", conf->firstData.get(), conf);
        }
        
        RegCloseKey(hRootKey);
@@ -337,21 +307,55 @@ namespace confplus {

    /**
     * @brief Lädt die Konfiguration aus der Windows Registry.
     * NEUE LOGIK: Parst den vollen Pfad (z.B. HKEY_LOCAL_MACHINE\SOFTWARE).
     */
    void Registry::loadConfig(const char* path, Config* conf) {
        
        std::string fullPath(path);
        HKEY hRootKey = HKEY_CURRENT_USER; // Standard-Root-Key
        std::string subKeyPath = fullPath;
        
        // 1. Root-Key und Subkey-Pfad parsen
        size_t slashPos = fullPath.find('\\');

        if (slashPos != std::string::npos) {
            std::string rootKeyName = fullPath.substr(0, slashPos);
            
            // Konvertierung der Root-Key-Namen
            if (rootKeyName == "HKEY_LOCAL_MACHINE" || rootKeyName == "HKLM") {
                hRootKey = HKEY_LOCAL_MACHINE;
            } else if (rootKeyName == "HKEY_CURRENT_USER" || rootKeyName == "HKCU") {
                hRootKey = HKEY_CURRENT_USER;
            } else if (rootKeyName == "HKEY_CLASSES_ROOT" || rootKeyName == "HKCR") {
                hRootKey = HKEY_CLASSES_ROOT;
            } else if (rootKeyName == "HKEY_USERS" || rootKeyName == "HKU") {
                hRootKey = HKEY_USERS;
            } else if (rootKeyName == "HKEY_CURRENT_CONFIG" || rootKeyName == "HKCC") {
                hRootKey = HKEY_CURRENT_CONFIG;
            } else {
                // Der Pfad beginnt nicht mit einem bekannten Root-Key. 
                // Behandle den gesamten Pfad als relativ zum Standard-Root-Key (HKEY_CURRENT_USER).
                goto OpenKey;
            }
            
            // Subkey-Pfad ist der Rest nach dem ersten '\'
            subKeyPath = fullPath.substr(slashPos + 1);
        }

    OpenKey:
        HKEY hKey;

        // Öffne den Hauptschlüssel
        LONG lRes = RegOpenKeyExA(
            REGISTRY_ROOT_KEY, 
            path, 
            hRootKey,          // Der ermittelte Root-Key
            subKeyPath.c_str(), // Der Subkey-Pfad relativ zum Root-Key
            0, 
            KEY_READ, 
            &hKey
        );

        if (lRes != ERROR_SUCCESS) {
            std::cerr << "Registry key not found: " << path << std::endl;
            std::cerr << "Registry key not found: " << fullPath << " (Error: " << lRes << ")" << std::endl;
            return;
        }