Commits

Kaya Kupferschmidt  committed 9c35dfe

Improved win32 Registry class

  • Participants
  • Parent commits 1802c48

Comments (0)

Files changed (3)

File source/libs/magnum_core/source/magnum/system/win32/Registry.cpp

 #include "magnum/system/win32/Exception.h"
 #include "magnum/system/win32/Registry.h"
 
+#define MAX_REG_KEYNAME_LENGTH 255
+#define MAX_REG_VALUENAME_LENGTH 16384
 
 namespace magnum { namespace system { namespace win32 {
 using magnum::types::WString;
 
 
+static Registry::ValueType mapValueType(DWORD type)
+{
+    switch(type) {
+        case REG_BINARY:
+            return Registry::BinaryType;
+        //case REG_DWORD:
+        case REG_DWORD_LITTLE_ENDIAN:
+        case REG_DWORD_BIG_ENDIAN:
+            return Registry::DwordType;
+        //case REG_QWORD:
+        case REG_QWORD_LITTLE_ENDIAN:
+        //case REG_QWORD_BIG_ENDIAN:
+            return Registry::QwordType;
+        case REG_EXPAND_SZ:
+        case REG_SZ:
+            return Registry::StringType;
+        case REG_MULTI_SZ:
+            return Registry::StringArrayType;
+        default:
+            return Registry::UnknownType;
+    }
+}
+
+
 static HKEY getRootKey(Registry::Root root)
 {
     switch(root) {
 /*--------------------------------------------------------------------------*/
 /**
  */
-String Registry::getString(const String& node ,const String& value)
+bool Registry::removeNode(const String& node)
+{
+    WString wnode(node);
+    DWORD result = RegDeleteKeyW(m_RootKey, wnode.getConstData());
+
+    if (result == ERROR_FILE_NOT_FOUND)
+        return false;
+    if (result != ERROR_SUCCESS)
+        throw RegistryKeyNotFoundException();
+
+    return true;
+}
+
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
+bool Registry::removeValue(const String& node,const String& value)
+{
+    WString wnode(node);
+    HKEY handle;
+    LONG result = RegOpenKeyExW(m_RootKey, wnode.getConstData(), 0, KEY_SET_VALUE, &handle);
+    if (result != ERROR_SUCCESS)
+        throw RegistryKeyNotFoundException();
+
+    WString wvalue(value);
+    result = RegDeleteValueW(handle, wvalue.getConstData());
+    RegCloseKey(handle);
+
+    if (result == ERROR_FILE_NOT_FOUND)
+        return false;
+    if (result != ERROR_SUCCESS)
+        throw RegistryValueNotFoundException();
+
+    return true;
+}
+
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
+Registry::ValueType Registry::getValueType(const String& node ,const String& value) const
+{
+    WString wnode(node);
+    HKEY handle;
+    LONG result = RegOpenKeyExW(m_RootKey, wnode.getConstData(), 0, KEY_QUERY_VALUE, &handle);
+    if (result != ERROR_SUCCESS)
+        throw RegistryKeyNotFoundException();
+
+    WString wvalue(value);
+    DWORD type;
+    result = RegQueryValueExW(handle, wvalue.getConstData(), 0, &type, NULL, NULL);
+    if (result != ERROR_SUCCESS) {
+        RegCloseKey(handle);
+        throw RegistryValueNotFoundException();
+    }
+    RegCloseKey(handle);
+
+    return mapValueType(type);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
+String Registry::getString(const String& node ,const String& value) const
 {
     WString wnode(node);
     HKEY handle;
 /*--------------------------------------------------------------------------*/
 /**
  */
-ByteArray Registry::getByteArray(const String& node, const String& value)
+ByteArray Registry::getByteArray(const String& node, const String& value) const
 {
     WString wnode(node);
     HKEY handle;
 /*--------------------------------------------------------------------------*/
 /**
  */
-qword Registry::getQword(const String& node, const String& value)
+qword Registry::getQword(const String& node, const String& value) const
 {
     WString wnode(node);
     HKEY handle;
 /*--------------------------------------------------------------------------*/
 /**
  */
-dword Registry::getDword(const String& node, const String& value)
+dword Registry::getDword(const String& node, const String& value) const
 {
     WString wnode(node);
     HKEY handle;
 /*--------------------------------------------------------------------------*/
 /**
  */
+Array<String> Registry::getNodeNames(const String& node) const
+{
+    WString wnode(node);
+    HKEY handle;
+    LONG result = RegOpenKeyExW(m_RootKey, wnode.getConstData(), 0, KEY_ENUMERATE_SUB_KEYS, &handle);
+    if (result != ERROR_SUCCESS)
+        throw RegistryKeyNotFoundException();
+
+    Array<String> nodeNames;
+    for (int i=0; true; i++) {
+        DWORD cbName = MAX_REG_KEYNAME_LENGTH;
+        wchar_t achKey[MAX_REG_KEYNAME_LENGTH];   // buffer for subkey name
+        FILETIME ftLastWriteTime;
+        DWORD retCode = RegEnumKeyExW(handle, i, achKey, &cbName, NULL, NULL, NULL, &ftLastWriteTime);
+        if (retCode != ERROR_SUCCESS)
+            break;
+        if (cbName > 0)
+            nodeNames.insert(String(achKey, cbName));
+    }
+
+    RegCloseKey(handle);
+
+    return nodeNames;
+}
+
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
+Array<String> Registry::getValueNames(const String& node) const
+{
+    WString wnode(node);
+    HKEY handle;
+    LONG result = RegOpenKeyExW(m_RootKey, wnode.getConstData(), 0, KEY_QUERY_VALUE, &handle);
+    if (result != ERROR_SUCCESS)
+        throw RegistryKeyNotFoundException();
+
+    Array<String> valueNames;
+    for (int i=0; true; i++) {
+        DWORD cbName = MAX_REG_VALUENAME_LENGTH;
+        wchar_t achKey[MAX_REG_VALUENAME_LENGTH];   // buffer for subkey name
+        DWORD retCode = RegEnumValueW(handle, i, achKey, &cbName, NULL, NULL, NULL, NULL);
+        if (retCode != ERROR_SUCCESS)
+            break;
+        if (cbName > 0)
+            valueNames.insert(String(achKey, cbName));
+    }
+
+    RegCloseKey(handle);
+
+    return valueNames;
+}
+
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
 void Registry::setString(const String& node, const String& value ,const String& data)
 {
     WString wnode(node);
 /*--------------------------------------------------------------------------*/
 /**
  */
+Registry::ValueType RegistryNode::getValueType(const String& value) const
+{
+    WString wvalue(value);
+    DWORD type;
+    LONG result = RegQueryValueExW(m_Key, wvalue.getConstData(), 0, &type, NULL, NULL);
+    if (result != ERROR_SUCCESS) {
+        throw RegistryValueNotFoundException();
+    }
+
+    return mapValueType(type);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
+Array<String> RegistryNode::getNodeNames() const
+{
+    Array<String> nodeNames;
+    for (int i=0; true; i++) {
+        DWORD cbName = MAX_REG_KEYNAME_LENGTH;
+        wchar_t achKey[MAX_REG_KEYNAME_LENGTH];   // buffer for subkey name
+        FILETIME ftLastWriteTime;
+        DWORD retCode = RegEnumKeyExW(m_Key, i, achKey, &cbName, NULL, NULL, NULL, &ftLastWriteTime);
+        if (retCode != ERROR_SUCCESS)
+            break;
+        if (cbName > 0)
+            nodeNames.insert(String(achKey, cbName));
+    }
+
+    return nodeNames;
+}
+
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
+Array<String> RegistryNode::getValueNames() const
+{
+    Array<String> valueNames;
+    for (int i=0; true; i++) {
+        DWORD cbName = MAX_REG_VALUENAME_LENGTH;
+        wchar_t achKey[MAX_REG_VALUENAME_LENGTH];   // buffer for subkey name
+        DWORD retCode = RegEnumValueW(m_Key, i, achKey, &cbName, NULL, NULL, NULL, NULL);
+        if (retCode != ERROR_SUCCESS)
+            break;
+        if (cbName > 0)
+            valueNames.insert(String(achKey, cbName));
+    }
+
+    return valueNames;
+}
+
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
 String RegistryNode::getString(const String& value) const
 {
     WString wvalue(value);
         throw RegistryKeyNotFoundException();
 }
 
+
+/*--------------------------------------------------------------------------*/
+/**
+ */
+bool RegistryNode::removeValue(const String& value)
+{
+    WString wvalue(value);
+    DWORD result = RegDeleteValueW(m_Key, wvalue.getConstData());
+
+    if (result == ERROR_FILE_NOT_FOUND)
+        return false;
+    if (result != ERROR_SUCCESS)
+        throw RegistryValueNotFoundException();
+
+    return true;
+}
+
 } } }

File source/libs/magnum_core/source/magnum/system/win32/Registry.h

 #define __MAGNUM_SYSTEM_WIN32_REGISTRY_H
 
 #include "magnum/object/Object.h"
+#include "magnum/object/Array.h"
 #include "magnum/io/Closeable.h"
 
+#include "magnum/object/Array.inl"
+
 
 namespace magnum { namespace system { namespace win32 {
 using magnum::object::Object;
+using magnum::object::Array;
 using magnum::io::Closeable;
 using magnum::types::String;
 using magnum::types::ByteArray;
         LocalMachine,
         Users
     };
+    enum ValueType {
+        UnknownType,
+        StringType,
+        BinaryType,
+        DwordType,
+        QwordType,
+        StringArrayType
+    };
 
 public:
     explicit Registry(Root );
 
     RegistryNode* openNode(const String& );
     RegistryNode* createNode(const String& );
-    void removeNode(const String& );
 
-    String getString(const String& ,const String& );
-    ByteArray getByteArray(const String& ,const String& );
-    qword getQword(const String& ,const String& );
-    dword getDword(const String& ,const String& );
+    bool removeNode(const String& );
+    bool removeValue(const String& ,const String& );
+
+    ValueType getValueType(const String& ,const String& ) const;
+    String getString(const String& ,const String& ) const;
+    ByteArray getByteArray(const String& ,const String& ) const;
+    qword getQword(const String& ,const String& ) const;
+    dword getDword(const String& ,const String& ) const;
 
     void setString(const String& ,const String& ,const String& );
     void setByteArray(const String& ,const String& ,const ByteArray& );
     void setQword(const String& ,const String& ,qword );
     void setDword(const String& ,const String& ,dword );
 
-    void removeValue(const String& ,const String& );
+    Array<String> getValueNames(const String& ) const;
+    Array<String> getNodeNames(const String& ) const;
 
 private:
     Root m_Root;
     inline String getNode() const
         { return m_Node; }
 
+    Registry::ValueType getValueType(const String& ) const;
     String getString(const String& ) const;
     ByteArray getByteArray(const String& ) const;
     qword getQword(const String& ) const;
     void setQword(const String& ,qword );
     void setDword(const String& ,dword );
 
-    void removeValue(const String& );
+    bool removeValue(const String& );
+
+    Array<String> getValueNames() const;
+    Array<String> getNodeNames() const;
 
 private:
     RegistryNode(HKEY key, Registry::Root root, const String& node);

File source/unittest/system/Test_Registry.h

 /*
   Magnum
-  Copyright (C) 2002-2012 Kaya Kupferschmidt. All Rights Reserved.
+  Copyright (C) 2002-2013 Kaya Kupferschmidt. All Rights Reserved.
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
 #include "magnum/system/win32/Registry.h"
 
 using magnum::object::Reference;
+using magnum::object::Array;
 using magnum::system::win32::Registry;
 using magnum::system::win32::RegistryNode;
 using magnum::types::String;
 
 class Test_Registry : public magnum::test::StdTestSuite {
 public:
-void test1()
+void test_registry()
 {
     Registry reg(Registry::CurrentUser);
+    Array<String> names;
+
+    TEST_EXCEPTION( reg.getValueNames("Software\\dimajix\\Magnum\\unittest"), magnum::object::RuntimeException );
+    TEST_EXCEPTION( reg.getNodeNames("Software\\dimajix\\Magnum\\unittest"), magnum::object::RuntimeException );
+    Reference<RegistryNode> node = reg.createNode("Software\\dimajix\\Magnum\\unittest");
+    TEST_THROWS_NOTHING( names = reg.getValueNames("Software\\dimajix\\Magnum\\unittest") );
+    TEST_ASSERT( names.getSize() == 0);
+    TEST_THROWS_NOTHING( names = reg.getNodeNames("Software\\dimajix\\Magnum\\unittest") );
+    TEST_ASSERT( names.getSize() == 0);
+
     TEST_THROWS_NOTHING( reg.setString("Software\\dimajix\\Magnum\\unittest", "stringdata", "stringvalue") );
     TEST_ASSERT( reg.getString("Software\\dimajix\\Magnum\\unittest", "stringdata") == "stringvalue" );
+    TEST_ASSERT( reg.getValueType("Software\\dimajix\\Magnum\\unittest", "stringdata") == Registry::StringType );
     TEST_EXCEPTION( reg.getByteArray("Software\\dimajix\\Magnum\\unittest", "stringdata"), magnum::object::RuntimeException );
     TEST_EXCEPTION( reg.getDword("Software\\dimajix\\Magnum\\unittest", "stringdata"), magnum::object::RuntimeException );
     TEST_EXCEPTION( reg.getQword("Software\\dimajix\\Magnum\\unittest", "stringdata"), magnum::object::RuntimeException );
 
     TEST_THROWS_NOTHING( reg.setDword("Software\\dimajix\\Magnum\\unittest", "dworddata", 17) );
     TEST_ASSERT( reg.getDword("Software\\dimajix\\Magnum\\unittest", "dworddata") == 17 );
+    TEST_ASSERT( reg.getValueType("Software\\dimajix\\Magnum\\unittest", "dworddata") == Registry::DwordType );
     TEST_EXCEPTION( reg.getByteArray("Software\\dimajix\\Magnum\\unittest", "dworddata"), magnum::object::RuntimeException );
     TEST_EXCEPTION( reg.getString("Software\\dimajix\\Magnum\\unittest", "dworddata"), magnum::object::RuntimeException );
     TEST_EXCEPTION( reg.getQword("Software\\dimajix\\Magnum\\unittest", "dworddata"), magnum::object::RuntimeException );
 
     TEST_THROWS_NOTHING( reg.setString("Software\\dimajix\\Magnum\\unittest", "variantdata", "stringvalue") );
     TEST_ASSERT( reg.getString("Software\\dimajix\\Magnum\\unittest", "variantdata") == "stringvalue" );
+    TEST_ASSERT( reg.getValueType("Software\\dimajix\\Magnum\\unittest", "variantdata") == Registry::StringType );
     TEST_THROWS_NOTHING( reg.setDword("Software\\dimajix\\Magnum\\unittest", "variantdata", 27) );
     TEST_ASSERT( reg.getDword("Software\\dimajix\\Magnum\\unittest", "variantdata") == 27 );
+    TEST_ASSERT( reg.getValueType("Software\\dimajix\\Magnum\\unittest", "variantdata") == Registry::DwordType );
+
+    TEST_THROWS_NOTHING( names = reg.getValueNames("Software\\dimajix\\Magnum\\unittest") );
+    TEST_ASSERT( names.getSize() == 3);
+    TEST_THROWS_NOTHING( names = reg.getNodeNames("Software\\dimajix\\Magnum\\unittest") );
+    TEST_ASSERT( names.getSize() == 0);
+
+    TEST_ASSERT( reg.removeValue("Software\\dimajix\\Magnum\\unittest", "variantdata") );
+    TEST_THROWS_NOTHING( names = reg.getValueNames("Software\\dimajix\\Magnum\\unittest") );
+    TEST_ASSERT( names.getSize() == 2);
+    TEST_THROWS_NOTHING( names = reg.getNodeNames("Software\\dimajix\\Magnum\\unittest") );
+    TEST_ASSERT( names.getSize() == 0);
+    TEST_ASSERT( !reg.removeValue("Software\\dimajix\\Magnum\\unittest", "variantdata") );
+
+    TEST_ASSERT( reg.removeNode("Software\\dimajix\\Magnum\\unittest") );
+    TEST_ASSERT( !reg.removeNode("Software\\dimajix\\Magnum\\unittest") );
 }
 
 
-void test2()
+void test_nodes()
 {
     Registry reg(Registry::CurrentUser);
+    Array<String> names;
+
+    TEST_EXCEPTION( reg.getValueNames("Software\\dimajix\\Magnum\\unittest"), magnum::object::RuntimeException );
+    TEST_EXCEPTION( reg.getNodeNames("Software\\dimajix\\Magnum\\unittest"), magnum::object::RuntimeException );
     Reference<RegistryNode> node = reg.createNode("Software\\dimajix\\Magnum\\unittest");
 
+    TEST_THROWS_NOTHING( names = node->getValueNames() );
+    TEST_ASSERT( names.getSize() == 0);
+    TEST_THROWS_NOTHING( names = node->getNodeNames() );
+    TEST_ASSERT( names.getSize() == 0);
+
     TEST_THROWS_NOTHING( node->setString("stringdata", "stringvalue") );
     TEST_ASSERT( node->getString("stringdata") == "stringvalue" );
+    TEST_ASSERT( node->getValueType("stringdata") == Registry::StringType );
     TEST_EXCEPTION( node->getByteArray("stringdata"), magnum::object::RuntimeException );
     TEST_EXCEPTION( node->getDword("stringdata"), magnum::object::RuntimeException );
     TEST_EXCEPTION( node->getQword("stringdata"), magnum::object::RuntimeException );
 
     TEST_THROWS_NOTHING( node->setDword("dworddata", 17) );
     TEST_ASSERT( node->getDword("dworddata") == 17 );
+    TEST_ASSERT( node->getValueType("dworddata") == Registry::DwordType );
     TEST_EXCEPTION( node->getByteArray("dworddata"), magnum::object::RuntimeException );
     TEST_EXCEPTION( node->getString("dworddata"), magnum::object::RuntimeException );
     TEST_EXCEPTION( node->getQword("dworddata"), magnum::object::RuntimeException );
 
     TEST_THROWS_NOTHING( node->setString("variantdata", "stringvalue") );
     TEST_ASSERT( node->getString("variantdata") == "stringvalue" );
+    TEST_ASSERT( node->getValueType("variantdata") == Registry::StringType );
     TEST_THROWS_NOTHING( node->setDword("variantdata", 27) );
     TEST_ASSERT( node->getDword("variantdata") == 27 );
+    TEST_ASSERT( node->getValueType("variantdata") == Registry::DwordType );
+
+    TEST_THROWS_NOTHING( names = node->getValueNames() );
+    TEST_ASSERT( names.getSize() == 3 );
+    TEST_THROWS_NOTHING( names = node->getNodeNames() );
+    TEST_ASSERT( names.getSize() == 0 );
+
+    TEST_ASSERT( node->removeValue("variantdata") );
+    TEST_THROWS_NOTHING( names = node->getValueNames() );
+    TEST_ASSERT( names.getSize() == 2 );
+    TEST_THROWS_NOTHING( names = node->getNodeNames() );
+    TEST_ASSERT( names.getSize() == 0 );
+    TEST_ASSERT( !node->removeValue("variantdata") );
+
+    TEST_ASSERT( reg.removeNode("Software\\dimajix\\Magnum\\unittest") );
+    TEST_ASSERT( !reg.removeNode("Software\\dimajix\\Magnum\\unittest") );
 }
 
 
 Test_Registry() {
-    TEST_ADD( Test_Registry::test1 );
-    TEST_ADD( Test_Registry::test2 );
+    TEST_ADD( Test_Registry::test_registry );
+    TEST_ADD( Test_Registry::test_nodes );
 }
 };