Commit 93c50632 authored by jan.koester's avatar jan.koester
Browse files

inital support regedit

parent 1f65f919
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -55,6 +55,21 @@ if(INIPARSER_FOUND)
    )
endif()

if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
    set(regeditsrc regconf.cpp)
    
    add_library(regedit SHARED ${regeditsrc})

    set_target_properties(regedit PROPERTIES PREFIX "" OUTPUT_NAME "regedit.cfg")

    target_link_libraries(regedit PRIVATE confplus kernel32.lib Advapi32.lib)

    install(TARGETS regedit
        RUNTIME DESTINATION bin
    )
endif()


if(NOT YAML_FOUND AND NOT INIPARSER_FOUND)
    message(ERROR "No backends are found Fatal!")
endif()
+219 −0
Original line number Diff line number Diff line
/*******************************************************************************
 * Copyright (c) 2023, Jan Koester jan.koester@gmx.net
 * All rights reserved.
 *
 * (Lizenzblock beibehalten)
 *******************************************************************************/

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
#include <windows.h>
#include <winreg.h>

#include "regconf.h" // Angenommen: Dies ist der umbenannte yamlconf.h
#include "exception.h" // Angenommen: Ihre eigene Exception-Klasse

namespace confplus {
    
    // Basis-Schlüssel in der Registry. Wir verwenden HKEY_CURRENT_USER
    // und einen festen Pfad für die Anwendung.
    const char* REGISTRY_BASE_PATH = "SOFTWARE\\ConfPlus\\Config";
    
    // Hilfsfunktion zum Ersetzen aller Vorkommen eines Substrings (für Pfade)
    std::string replaceAll(std::string str, const std::string& from, const std::string& to) {
        size_t start_pos = 0;
        while((start_pos = str.find(from, start_pos)) != std::string::npos) {
            str.replace(start_pos, from.length(), to);
            start_pos += to.length(); 
        }
        return str;
    }

    // Die Klasse wird von Yaml zu Registry umbenannt.
    class Registry : public BackendApi{
    public:
        const char* getName();
        const char* getVersion();
        const char* getAuthor();

        void loadConfig(const char *path,Config *conf);
        void saveConfig(const char *path,const Config *conf);

        Registry();
        virtual ~Registry();
    };

    Registry::Registry(){}

    Registry::~Registry(){}

    const char* Registry::getName(){
        return "registry";
    }

    const char* Registry::getVersion(){
        return "0.1";
    }

    const char* Registry::getAuthor(){
        return "Jan Koester";
    }

    /**
     * @brief Speichert die Konfiguration in der Windows Registry.
     * * Da das Config-System Pfade wie /Abschnitt/Schlüssel verwendet,
     * verwenden wir diese als Value-Namen unter dem Basis-Schlüssel.
     * * @param path Der Pfad wird hier ignoriert oder als Subkey des Basis-Pfades verwendet.
     * @param conf Das Config-Objekt.
     */
    void Registry::saveConfig(const char *path, const Config *conf){
        HKEY hKey;
        DWORD dwDisposition;

        // Erstellt oder öffnet den Basis-Schlüssel für die Konfiguration
        LONG lRes = RegCreateKeyExA(
            HKEY_CURRENT_USER,      // Hauptschlüssel
            REGISTRY_BASE_PATH,     // Subkey-Pfad
            0, NULL, REG_OPTION_NON_VOLATILE, 
            KEY_ALL_ACCESS,         // KEY_WRITE
            NULL, &hKey, &dwDisposition
        );

        if (lRes != ERROR_SUCCESS) {
            throw Exception("Failed to create/open registry key.");
        }

        // --- Iteration über alle Schlüssel im Config-Objekt ---
        // Da die Config-API nicht direkt sichtbar ist, simulieren wir die Iteration
        // und speichern jeden Wert als REG_SZ (String).
        
        // Die Iterationslogik müsste hier implementiert werden, um alle 
        // ConfigData* Objekte im Config-Objekt zu erhalten. 
        // Hier ein konzeptionelles Beispiel:
        
        std::vector<Config::ConfigData*> allKeys = conf->getAllKeys();
        for (Config::ConfigData* ckey : allKeys) {
            std::string cname = ckey->getPath(); // Z.B. "/Server/Port"
            std::string cvalue = conf->getValue(ckey, 0); // Hole den 1. Wert
            
            // Entferne den führenden Schrägstrich für den Value-Namen
            if (cname.length() > 0 && cname[0] == '/') {
                cname = cname.substr(1); 
            }
            
            // Speichere den Wert
            lRes = RegSetValueExA(
                hKey, 
                cname.c_str(), // Z.B. "Server/Port"
                0, 
                REG_SZ, 
                (const BYTE*)cvalue.c_str(), 
                cvalue.length() + 1
            );
            
            if (lRes != ERROR_SUCCESS) {
                std::cerr << "Failed to set value for: " << cname << std::endl;
            }
        }

        // Da die tatsächliche Struktur des Config-Objekts unbekannt ist,
        // kann hier nur ein Stub eingefügt werden.

        RegCloseKey(hKey);
    }

    /**
     * @brief Lädt die Konfiguration aus der Windows Registry.
     * * Liest alle Werte unter dem Basis-Schlüssel und speichert sie im Config-Objekt.
     * * @param path Der Pfad wird hier ignoriert oder als Subkey des Basis-Pfades verwendet.
     * @param conf Das Config-Objekt.
     */
    void Registry::loadConfig(const char* path, Config* conf) {
        HKEY hKey;

        // Öffne den Basis-Schlüssel
        LONG lRes = RegOpenKeyExA(
            HKEY_CURRENT_USER, 
            REGISTRY_BASE_PATH, 
            0, 
            KEY_READ, 
            &hKey
        );

        if (lRes != ERROR_SUCCESS) {
            // Wenn der Schlüssel nicht existiert, ist das keine Exception,
            // sondern eine leere Konfiguration.
            std::cerr << "Registry key not found: " << REGISTRY_BASE_PATH << std::endl;
            return;
        }

        DWORD dwValues;
        DWORD dwMaxValueNameLen;
        DWORD dwMaxValueLen;

        // Ermittelt die Anzahl der Werte und die maximale Länge
        lRes = RegQueryInfoKey(
            hKey, NULL, NULL, NULL, NULL, NULL, NULL, 
            &dwValues, &dwMaxValueNameLen, &dwMaxValueLen, 
            NULL, NULL
        );

        if (lRes != ERROR_SUCCESS) {
            RegCloseKey(hKey);
            throw Exception("Failed to query registry key info.");
        }

        char* valueNameBuffer = new char[dwMaxValueNameLen + 1];
        char* dataBuffer = new char[dwMaxValueLen + 1];
        
        // Fügt 1 für das Null-Terminierungszeichen hinzu
        DWORD dwSizeValueName = dwMaxValueNameLen + 1;
        DWORD dwSizeData = dwMaxValueLen + 1;

        // --- Iteration über alle Values unter dem Basis-Schlüssel ---
        for (DWORD i = 0; i < dwValues; ++i) {
            DWORD dwType = 0;
            dwSizeValueName = dwMaxValueNameLen + 1;
            dwSizeData = dwMaxValueLen + 1;

            lRes = RegEnumValueA(
                hKey, i, 
                valueNameBuffer, &dwSizeValueName, 
                NULL, &dwType, 
                (LPBYTE)dataBuffer, &dwSizeData
            );

            if (lRes == ERROR_SUCCESS) {
                std::string cname = "/";
                cname += std::string(valueNameBuffer); // Z.B. "/Server/Port"
                std::string cvalue = std::string(dataBuffer);

                // Unterstützt nur REG_SZ (String) und REG_DWORD (Zahl)
                if (dwType == REG_SZ) {
                    Config::ConfigData* ckey = conf->setKey(cname);
                    conf->setValue(ckey, 0, cvalue);
                    std::cout << "Loading key: " << cname << " Value: " << cvalue << std::endl;
                } else if (dwType == REG_DWORD) {
                    // Konvertiere DWORD zu String
                    std::stringstream ss;
                    ss << *((DWORD*)dataBuffer);
                    Config::ConfigData* ckey = conf->setKey(cname);
                    conf->setValue(ckey, 0, ss.str());
                    std::cout << "Loading key: " << cname << " Value: " << ss.str() << " (DWORD)" << std::endl;
                }
            } else if (lRes == ERROR_NO_MORE_ITEMS) {
                break; 
            } else {
                // Fehler beim Lesen des Wertes
                std::cerr << "Error reading registry value at index " << i << std::endl;
            }
        }

        delete[] valueNameBuffer;
        delete[] dataBuffer;
        RegCloseKey(hKey);
    }
}
 No newline at end of file