├── .github └── FUNDING.yml ├── .gitignore ├── RegistryTest ├── RegistryTest.cpp ├── stdafx.cpp ├── targetver.h ├── stdafx.h └── RegistryTest.vcxproj ├── appveyor.yml ├── Registry ├── src │ └── Registry.cpp ├── Registry.vcxproj └── include │ └── Registry.hpp ├── Registry.sln └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: m4x1m1l14n 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /ipch/* 2 | /bin/* 3 | /obj/* 4 | *.suo 5 | *.vcxproj.* 6 | *.VC.* 7 | *.ipch 8 | -------------------------------------------------------------------------------- /RegistryTest/RegistryTest.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m4x1m1l14n/Registry/HEAD/RegistryTest/RegistryTest.cpp -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | image: Visual Studio 2015 3 | configuration: 4 | - Release 5 | platform: 6 | - x86 7 | - x64 8 | environment: 9 | COVERALLS_REPO_TOKEN: 10 | secure: ocnxlYNr/PjOwPdIMWmoyZ33fAQBnHhe/Vxcp1nPKn3Hb2xJkECtuQGe11J6NW5v 11 | build: 12 | parallel: true 13 | verbosity: normal 14 | -------------------------------------------------------------------------------- /RegistryTest/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // RegistryTest.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /RegistryTest/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /RegistryTest/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #pragma comment(lib, "Registry.lib") 9 | 10 | #include "targetver.h" 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | -------------------------------------------------------------------------------- /Registry/src/Registry.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace m4x1m1l14n 4 | { 5 | namespace Registry 6 | { 7 | RegistryKey_ptr ClassesRoot(new RegistryKey(HKEY_CLASSES_ROOT)); 8 | RegistryKey_ptr CurrentUser(new RegistryKey(HKEY_CURRENT_USER)); 9 | RegistryKey_ptr LocalMachine(new RegistryKey(HKEY_LOCAL_MACHINE)); 10 | RegistryKey_ptr Users(new RegistryKey(HKEY_USERS)); 11 | RegistryKey_ptr CurrentConfig(new RegistryKey(HKEY_CURRENT_CONFIG)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Registry.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Registry", "Registry\Registry.vcxproj", "{E96994EA-B0B0-44CA-8849-DB7F4E020833}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RegistryTest", "RegistryTest\RegistryTest.vcxproj", "{2AD90722-1496-4363-B9F2-C583D416EFDB}" 9 | ProjectSection(ProjectDependencies) = postProject 10 | {E96994EA-B0B0-44CA-8849-DB7F4E020833} = {E96994EA-B0B0-44CA-8849-DB7F4E020833} 11 | EndProjectSection 12 | EndProject 13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4573FEE7-492E-472A-8239-885FE8890C9B}" 14 | ProjectSection(SolutionItems) = preProject 15 | README.md = README.md 16 | EndProjectSection 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|x64 = Debug|x64 21 | Debug|x86 = Debug|x86 22 | Release|x64 = Release|x64 23 | Release|x86 = Release|x86 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {E96994EA-B0B0-44CA-8849-DB7F4E020833}.Debug|x64.ActiveCfg = Debug|x64 27 | {E96994EA-B0B0-44CA-8849-DB7F4E020833}.Debug|x64.Build.0 = Debug|x64 28 | {E96994EA-B0B0-44CA-8849-DB7F4E020833}.Debug|x86.ActiveCfg = Debug|Win32 29 | {E96994EA-B0B0-44CA-8849-DB7F4E020833}.Debug|x86.Build.0 = Debug|Win32 30 | {E96994EA-B0B0-44CA-8849-DB7F4E020833}.Release|x64.ActiveCfg = Release|x64 31 | {E96994EA-B0B0-44CA-8849-DB7F4E020833}.Release|x64.Build.0 = Release|x64 32 | {E96994EA-B0B0-44CA-8849-DB7F4E020833}.Release|x86.ActiveCfg = Release|Win32 33 | {E96994EA-B0B0-44CA-8849-DB7F4E020833}.Release|x86.Build.0 = Release|Win32 34 | {2AD90722-1496-4363-B9F2-C583D416EFDB}.Debug|x64.ActiveCfg = Debug|x64 35 | {2AD90722-1496-4363-B9F2-C583D416EFDB}.Debug|x64.Build.0 = Debug|x64 36 | {2AD90722-1496-4363-B9F2-C583D416EFDB}.Debug|x86.ActiveCfg = Debug|Win32 37 | {2AD90722-1496-4363-B9F2-C583D416EFDB}.Debug|x86.Build.0 = Debug|Win32 38 | {2AD90722-1496-4363-B9F2-C583D416EFDB}.Release|x64.ActiveCfg = Release|x64 39 | {2AD90722-1496-4363-B9F2-C583D416EFDB}.Release|x64.Build.0 = Release|x64 40 | {2AD90722-1496-4363-B9F2-C583D416EFDB}.Release|x86.ActiveCfg = Release|Win32 41 | {2AD90722-1496-4363-B9F2-C583D416EFDB}.Release|x86.Build.0 = Release|Win32 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | EndGlobal 47 | -------------------------------------------------------------------------------- /Registry/Registry.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {E96994EA-B0B0-44CA-8849-DB7F4E020833} 23 | Win32Proj 24 | Registry 25 | 10.0 26 | 27 | 28 | 29 | StaticLibrary 30 | true 31 | v143 32 | Unicode 33 | 34 | 35 | StaticLibrary 36 | false 37 | v143 38 | true 39 | Unicode 40 | 41 | 42 | StaticLibrary 43 | true 44 | v143 45 | Unicode 46 | 47 | 48 | StaticLibrary 49 | false 50 | v143 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | $(SolutionDir)bin\$(Configuration)_$(PlatformTarget)\ 75 | $(SolutionDir)obj\$(Configuration)_$(PlatformTarget)\$(ProjectName)\ 76 | 77 | 78 | true 79 | $(SolutionDir)bin\$(Configuration)_$(PlatformTarget)\ 80 | $(SolutionDir)obj\$(Configuration)_$(PlatformTarget)\$(ProjectName)\ 81 | 82 | 83 | false 84 | $(SolutionDir)bin\$(Configuration)_$(PlatformTarget)\ 85 | $(SolutionDir)obj\$(Configuration)_$(PlatformTarget)\$(ProjectName)\ 86 | 87 | 88 | false 89 | $(SolutionDir)bin\$(Configuration)_$(PlatformTarget)\ 90 | $(SolutionDir)obj\$(Configuration)_$(PlatformTarget)\$(ProjectName)\ 91 | 92 | 93 | 94 | Use 95 | Level3 96 | Disabled 97 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 98 | true 99 | $(ProjectDir)include;%(AdditionalIncludeDirectories) 100 | MultiThreadedDebug 101 | true 102 | stdcpplatest 103 | false 104 | 105 | 106 | Console 107 | true 108 | 109 | 110 | 111 | 112 | Use 113 | Level3 114 | Disabled 115 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 116 | true 117 | $(ProjectDir)include;%(AdditionalIncludeDirectories) 118 | MultiThreadedDebug 119 | true 120 | stdcpplatest 121 | false 122 | 123 | 124 | Console 125 | true 126 | 127 | 128 | 129 | 130 | Level3 131 | Use 132 | MaxSpeed 133 | true 134 | true 135 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 136 | true 137 | $(ProjectDir)include;%(AdditionalIncludeDirectories) 138 | MultiThreaded 139 | true 140 | stdcpplatest 141 | false 142 | 143 | 144 | Console 145 | true 146 | true 147 | true 148 | 149 | 150 | 151 | 152 | Level3 153 | Use 154 | MaxSpeed 155 | true 156 | true 157 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 158 | true 159 | $(ProjectDir)include;%(AdditionalIncludeDirectories) 160 | MultiThreaded 161 | true 162 | stdcpplatest 163 | false 164 | 165 | 166 | Console 167 | true 168 | true 169 | true 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | NotUsing 178 | NotUsing 179 | NotUsing 180 | NotUsing 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /RegistryTest/RegistryTest.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {2AD90722-1496-4363-B9F2-C583D416EFDB} 23 | Win32Proj 24 | RegistryTest 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v142 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v142 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v142 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v142 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | $(SolutionDir)bin\$(Configuration)_$(PlatformTarget)\ 75 | $(SolutionDir)obj\$(Configuration)_$(PlatformTarget)\$(ProjectName)\ 76 | 77 | 78 | true 79 | $(SolutionDir)bin\$(Configuration)_$(PlatformTarget)\ 80 | $(SolutionDir)obj\$(Configuration)_$(PlatformTarget)\$(ProjectName)\ 81 | 82 | 83 | false 84 | $(SolutionDir)bin\$(Configuration)_$(PlatformTarget)\ 85 | $(SolutionDir)obj\$(Configuration)_$(PlatformTarget)\$(ProjectName)\ 86 | 87 | 88 | false 89 | $(SolutionDir)bin\$(Configuration)_$(PlatformTarget)\ 90 | $(SolutionDir)obj\$(Configuration)_$(PlatformTarget)\$(ProjectName)\ 91 | 92 | 93 | 94 | Use 95 | Level3 96 | Disabled 97 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 98 | true 99 | $(ProjectDir)..\Registry\include;%(AdditionalIncludeDirectories) 100 | MultiThreadedDebug 101 | false 102 | true 103 | 104 | 105 | Console 106 | true 107 | $(SolutionDir)bin\$(Configuration)_$(PlatformTarget)\;%(AdditionalLibraryDirectories) 108 | 109 | 110 | 111 | 112 | Use 113 | Level3 114 | Disabled 115 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 116 | true 117 | $(ProjectDir)..\Registry\include;%(AdditionalIncludeDirectories) 118 | MultiThreadedDebug 119 | false 120 | true 121 | 122 | 123 | Console 124 | true 125 | $(SolutionDir)bin\$(Configuration)_$(PlatformTarget)\;%(AdditionalLibraryDirectories) 126 | 127 | 128 | 129 | 130 | Level3 131 | Use 132 | MaxSpeed 133 | true 134 | true 135 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 136 | true 137 | $(ProjectDir)..\Registry\include;%(AdditionalIncludeDirectories) 138 | MultiThreaded 139 | true 140 | 141 | 142 | Console 143 | true 144 | true 145 | true 146 | $(SolutionDir)bin\$(Configuration)_$(PlatformTarget)\;%(AdditionalLibraryDirectories) 147 | 148 | 149 | 150 | 151 | Level3 152 | Use 153 | MaxSpeed 154 | true 155 | true 156 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 157 | true 158 | $(ProjectDir)..\Registry\include;%(AdditionalIncludeDirectories) 159 | MultiThreaded 160 | true 161 | 162 | 163 | Console 164 | true 165 | true 166 | true 167 | $(SolutionDir)bin\$(Configuration)_$(PlatformTarget)\;%(AdditionalLibraryDirectories) 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | Create 178 | Create 179 | Create 180 | Create 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://ci.appveyor.com/api/projects/status/3nvam4ye0yhtt5kt?svg=true)](https://ci.appveyor.com/project/m4x1m1l14n/registry) 2 | [![Coverage Status](https://coveralls.io/repos/github/m4x1m1l14n/Registry/badge.svg?branch=master)](https://coveralls.io/github/m4x1m1l14n/Registry?branch=master) 3 | 4 | Saved a little time of your life? :beer::sunglasses::thumbsup: 5 | [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=WZ5UGW93SUEA8¤cy_code=EUR&amount=5&source=url) 6 | 7 | # Registry namespace 8 | 9 | C++ class for manipulating Windows Registry. 10 | Wraps & simplifies native Windows API and combines it with power of modern C++11. 11 | 12 | [//]: # "Source code documentation to whole namespace can be found on [http://www.nanosoft.sk](http://www.nanosoft.sk)" 13 | 14 | ## Table of contents 15 | * [Table of contents](#table-of-contents) 16 | * [Root registry keys](#root-registry-keys) 17 | * [Opening registry keys](#opening-registry-keys) 18 | * [Creating registry keys](#creating-registry-keys) 19 | * [Deleting registry key](#deleting-registry-key) 20 | * [Flush registry](#flush-registry) 21 | * [Save registry key to file](#save-registry-key-to-file) 22 | * [Check if registry key exists](#check-if-registry-key-exists) 23 | * [Check if registry value exists](#check-if-registry-value-exists) 24 | * [Save boolean value to registry](#save-boolean-value-to-registry) 25 | * [Read boolean value from registry](#read-boolean-value-from-registry) 26 | * [Save integer value to registry](#save-integer-value-to-registry) 27 | * [Read integer value from registry](#read-integer-value-from-registry) 28 | * [Save string value to registry](#save-string-value-to-registry) 29 | * [Read string value from registry](#read-string-value-from-registry) 30 | * [Enumerating registry subkeys](#enumerating-registry-subkeys) 31 | 32 | >**NOTE:** 33 | > All methods can throw exceptions, if system error occurs! 34 | > 35 | > All exceptions thrown are derived from std::exception class, so don't forget to wrap your code with try / catch block. 36 | 37 | ## Root registry keys 38 | 39 | Following windows registry root keys are predefined within Registry namespace, and can be accessed directly in your code 40 | 41 | ```C++ 42 | Registry::ClassesRoot 43 | Registry::CurrentUser 44 | Registry::LocalMachine 45 | Registry::Users 46 | Registry::CurrentConfig 47 | ``` 48 | 49 | ## Opening registry keys 50 | 51 | Existing windows registry key can be opened simply by call to RegistryKey\:\:Open() method specifying path to registry key. 52 | 53 | >**NOTE:** 54 | > Registry key is closed automatically when RegistryKey object goes out of scope. 55 | 56 | ```C++ 57 | #include 58 | 59 | using namespace m4x1m1l14n; 60 | 61 | int main() 62 | { 63 | try 64 | { 65 | auto key = Registry::LocalMachine->Open(L"SOFTWARE\\MyCompany\\MyApplication"); 66 | 67 | // do work needed 68 | } 69 | catch (const std::exception&) 70 | { 71 | // handle thrown exception 72 | } 73 | 74 | return 0; 75 | } 76 | ``` 77 | 78 | Registry key is by default opened with read access, same as if you open registry key as follows 79 | 80 | ```C++ 81 | auto access = Registry::DesiredAccess::Read; 82 | 83 | auto key = Registry::LocalMachine->Open(L"SOFTWARE\\MyCompany\\MyApplication", access); 84 | ``` 85 | 86 | Desired access for opening registry keys can be combined 87 | 88 | ```C++ 89 | auto access = Registry::DesiredAccess::Read | Registry::DesiredAccess::Write; 90 | 91 | auto key = Registry::LocalMachine->Open(L"SOFTWARE\\MyCompany\\MyApplication", access); 92 | ``` 93 | 94 | ## Creating registry keys 95 | 96 | Registry keys can be created in a same way as if they are opened. 97 | 98 | Simply by using RegistryKey::Create() method. Usage is same as when opening keys. 99 | 100 | > **NOTE:** 101 | > You must have sufficient privileges to create registry keys under specific root key. 102 | > In other case std::system_error exception will be thrown 103 | 104 | ```C++ 105 | #include 106 | 107 | using namespace m4x1m1l14n; 108 | 109 | int main() 110 | { 111 | try 112 | { 113 | auto access = Registry::DesiredAccess::Read | Registry::DesiredAccess::Write; 114 | 115 | auto key = Registry::LocalMachine->Create(L"SOFTWARE\\MyCompany\\MyApplication", access); 116 | 117 | // do work needed 118 | } 119 | catch (const std::exception&) 120 | { 121 | // handle thrown exception 122 | } 123 | 124 | return 0; 125 | } 126 | ``` 127 | 128 | RegistryKey can be created also from native windows registry key handle HKEY. 129 | 130 | > **NOTE:** 131 | > In case hKey is nullptr, std::invalid_argument is thrown 132 | 133 | ```C++ 134 | Registry::RegistryKey_ptr key = std::make_shared(hKey); 135 | ``` 136 | 137 | ## Using with native API 138 | 139 | RegistryKey has HKEY() operator overloaded, thus can be used with conjunction with native Windows registry API. 140 | 141 | Usage is as follows 142 | 143 | ```C++ 144 | auto key = Registry::LocalMachine->Open(L"SOFTWARE\\MyCompany\\MyApplication"); 145 | 146 | DWORD dwValue = 0; 147 | DWORD cbData = sizeof(dwValue); 148 | DWORD dwType; 149 | 150 | LSTATUS lStatus = RegQueryValueEx(*key, L"SomeDWORDValue", nullptr, &dwType, reinterpret_cast(&dwValue), &cbData); 151 | if (lStatus == ERROR_SUCCESS) 152 | { 153 | // DO SOMETHING 154 | } 155 | ``` 156 | 157 | ## Deleting registry key 158 | 159 | ## Flush registry 160 | 161 | ## Save registry key to file 162 | 163 | ## Check if registry key exists 164 | 165 | HasKey() or Exists() methods can be used to check, whether registry key contains specified subkey. 166 | 167 | ```C++ 168 | #include 169 | 170 | using namespace m4x1m1l14n; 171 | 172 | int main() 173 | { 174 | try 175 | { 176 | auto key = Registry::LocalMachine->Create(L"SOFTWARE\\MyCompany\\MyApplication"); 177 | if (key->HasKey(L"SomeSubKey")) 178 | { 179 | // TRUE 180 | } 181 | else 182 | { 183 | // FALSE 184 | } 185 | } 186 | catch (const std::exception&) 187 | { 188 | // handle thrown exception 189 | } 190 | 191 | return 0; 192 | } 193 | ``` 194 | 195 | ## Check if registry value exists 196 | 197 | To check if windows registry key contains specific value use HasValue() method as follows 198 | 199 | ```C++ 200 | #include 201 | 202 | using namespace m4x1m1l14n; 203 | 204 | int main() 205 | { 206 | try 207 | { 208 | auto key = Registry::LocalMachine->Create(L"SOFTWARE\\MyCompany\\MyApplication"); 209 | if (key->HasValue(L"Version")) 210 | { 211 | // TRUE 212 | } 213 | else 214 | { 215 | // FALSE 216 | } 217 | } 218 | catch (const std::exception&) 219 | { 220 | // handle thrown exception 221 | } 222 | 223 | return 0; 224 | } 225 | ``` 226 | 227 | ## Save boolean value to registry 228 | 229 | To save boolean value to registry, use SetBoolean() method as follows 230 | 231 | > **NOTE:** 232 | > Boolean value is stored in registry as REG_DWORD. 0 for false and 1 for true. 233 | 234 | ```C++ 235 | #include 236 | 237 | using namespace m4x1m1l14n; 238 | 239 | int main() 240 | { 241 | try 242 | { 243 | auto key = Registry::LocalMachine->Create(L"SOFTWARE\\MyCompany\\MyApplication"); 244 | 245 | key->SetBoolean(L"EnableLogger", true); 246 | } 247 | catch (const std::exception&) 248 | { 249 | // handle thrown exception 250 | } 251 | 252 | return 0; 253 | } 254 | ``` 255 | 256 | ## Read boolean value from registry 257 | 258 | To read boolean value from registry use GetBoolean() method as follows 259 | 260 | > **NOTE:** 261 | > RegistryKey class use REG_DWORD registry value data type to work with boolean value. 262 | > If registry value is 0, false is returned. If registry value is above 0, value of true is returned. 263 | 264 | ```C++ 265 | #include 266 | 267 | using namespace m4x1m1l14n; 268 | 269 | int main() 270 | { 271 | try 272 | { 273 | auto key = Registry::LocalMachine->Create(L"SOFTWARE\\MyCompany\\MyApplication"); 274 | auto enabled = key->GetBoolean(L"EnableLogger"); 275 | if (enabled) 276 | { 277 | // do work 278 | } 279 | } 280 | catch (const std::exception&) 281 | { 282 | // handle thrown exception 283 | } 284 | 285 | return 0; 286 | } 287 | ``` 288 | 289 | ## Save integer value to registry 290 | 291 | To save signed / unsigned integer values to registry, use one of methods 292 | 293 | * SetInt32() 294 | * SetUInt32() 295 | * SetInt64() 296 | * SetUInt64() 297 | 298 | as follows 299 | 300 | ```C++ 301 | #include 302 | 303 | using namespace m4x1m1l14n; 304 | 305 | int main() 306 | { 307 | try 308 | { 309 | auto access = Registry::DesiredAccess::Write; 310 | 311 | auto key = Registry::LocalMachine->Open(L"SOFTWARE\\MyCompany\\MyApplication\\Logger", access); 312 | 313 | key->SetInt32(L"Severity", -3); 314 | key->SetUInt32(L"Timeout", 10000); 315 | 316 | key->SetInt64(L"SomeBigNumber", -9223372036854775808); 317 | key->SetUInt64(L"Id", 0xf0f0f0f0f0f0f0f0); 318 | } 319 | catch (const std::exception&) 320 | { 321 | // handle thrown exception 322 | } 323 | 324 | return 0; 325 | } 326 | ``` 327 | 328 | ## Read integer value from registry 329 | 330 | To read signed / unsigned integer values from registry, use one of methods 331 | 332 | * GetInt32() 333 | * GetUInt32() 334 | * GetInt64() 335 | * GetUInt64() 336 | 337 | as follows 338 | 339 | ```C++ 340 | #include 341 | 342 | using namespace m4x1m1l14n; 343 | 344 | int main() 345 | { 346 | try 347 | { 348 | auto key = Registry::LocalMachine->Open(L"SOFTWARE\\MyCompany\\MyApplication\\Logger"); 349 | 350 | std::cout << key->GetInt32(L"Severity") << std::endl; 351 | std::cout << key->GetUInt32(L"Timeout") << std::endl; 352 | std::cout << key->GetInt64(L"SomeBigNumber") << std::endl; 353 | std::cout << key->GetUInt64(L"Id") << std::endl; 354 | } 355 | catch (const std::exception&) 356 | { 357 | // handle thrown exception 358 | } 359 | 360 | return 0; 361 | } 362 | ``` 363 | 364 | ## Save string value to registry 365 | 366 | To save string value to registry use SetString() method as follows 367 | 368 | ```C++ 369 | #include 370 | 371 | using namespace m4x1m1l14n; 372 | 373 | int main() 374 | { 375 | try 376 | { 377 | auto access = Registry::DesiredAccess::Write; 378 | 379 | auto key = Registry::LocalMachine->Open(L"SOFTWARE\\MyCompany\\MyApplication\\Logger", access); 380 | 381 | key->SetString(L"FileName", L"c:\\Program Files\\MyCompany\\MyApplication\\log.txt"); 382 | } 383 | catch (const std::exception&) 384 | { 385 | // handle thrown exception 386 | } 387 | 388 | return 0; 389 | } 390 | ``` 391 | 392 | ## Read string value from registry 393 | 394 | To read string value from windows registry use GetString() method as follows 395 | 396 | ```C++ 397 | #include 398 | 399 | using namespace m4x1m1l14n; 400 | 401 | int main() 402 | { 403 | try 404 | { 405 | auto key = Registry::LocalMachine->Open(L"SOFTWARE\\MyCompany\\MyApplication\\Logger"); 406 | 407 | auto logFileName = key->GetString(L"FileName"); 408 | 409 | // work with read value 410 | } 411 | catch (const std::exception&) 412 | { 413 | // handle thrown exception 414 | } 415 | 416 | return 0; 417 | } 418 | ``` 419 | 420 | ## Save expandable string value to registry 421 | 422 | To save string value to registry use SetExpandString() method in same manner as SetString(). 423 | 424 | 425 | ```C++ 426 | #include 427 | 428 | using namespace m4x1m1l14n; 429 | 430 | int main() 431 | { 432 | try 433 | { 434 | auto access = Registry::DesiredAccess::Write; 435 | 436 | auto key = Registry::LocalMachine->Open(L"SOFTWARE\\MyCompany\\MyApplication\\Logger", access); 437 | 438 | key->SetExpandString(L"InstallDir", L"%ProgramFiles%\\My Company\\My Product\\"); 439 | } 440 | catch (const std::exception&) 441 | { 442 | // handle thrown exception 443 | } 444 | 445 | return 0; 446 | } 447 | ``` 448 | 449 | ## Enumerating registry subkeys 450 | 451 | Eumerating registry key subkeys is done as follows, using lambda expression 452 | 453 | ```C++ 454 | #include 455 | 456 | using namespace m4x1m1l14n; 457 | 458 | int main() 459 | { 460 | try 461 | { 462 | auto key = Registry::LocalMachine->Open(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"); 463 | 464 | key->EnumerateSubKeys([](const std::wstring& name) -> bool 465 | { 466 | // Process subkey 467 | std::wcout << name << std::endl; 468 | 469 | // Return true to continue processing, false otherwise 470 | return true; 471 | }); 472 | } 473 | catch (const std::exception& ex) 474 | { 475 | // handle thrown exception 476 | } 477 | 478 | return 0; 479 | } 480 | ``` 481 | -------------------------------------------------------------------------------- /Registry/include/Registry.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace m4x1m1l14n 16 | { 17 | namespace Registry 18 | { 19 | /*enum class ValueType 20 | { 21 | NUL, 22 | BOOLEAN, 23 | INT32, 24 | INT64, 25 | STRING, 26 | BINARY 27 | };*/ 28 | 29 | enum class DesiredAccess : REGSAM 30 | { 31 | Delete = DELETE, 32 | ReadControl = READ_CONTROL, 33 | WriteDAC = WRITE_DAC, 34 | WriteOwner = WRITE_OWNER, 35 | AllAccess = KEY_ALL_ACCESS, 36 | CreateSubKey = KEY_CREATE_SUB_KEY, 37 | EnumerateSubKeys = KEY_ENUMERATE_SUB_KEYS, 38 | Execute = KEY_EXECUTE, 39 | Notify = KEY_NOTIFY, 40 | QueryValue = KEY_QUERY_VALUE, 41 | Read = KEY_READ, 42 | SetValue = KEY_SET_VALUE, 43 | Wow6432 = KEY_WOW64_32KEY, 44 | Wow6464 = KEY_WOW64_64KEY, 45 | Write = KEY_WRITE 46 | }; 47 | 48 | DEFINE_ENUM_FLAG_OPERATORS(DesiredAccess); 49 | 50 | enum class CreateKeyOptions : DWORD 51 | { 52 | BackupRestore = REG_OPTION_BACKUP_RESTORE, 53 | NonVolatile = REG_OPTION_NON_VOLATILE, 54 | Volatile = REG_OPTION_VOLATILE 55 | }; 56 | 57 | enum class NotifyFilter : DWORD 58 | { 59 | ChangeName = REG_NOTIFY_CHANGE_NAME, 60 | ChangeAttributes = REG_NOTIFY_CHANGE_ATTRIBUTES, 61 | ChangeLastSet = REG_NOTIFY_CHANGE_LAST_SET, 62 | ChangeSecurity = REG_NOTIFY_CHANGE_SECURITY, 63 | ThreadAgnostic = REG_NOTIFY_THREAD_AGNOSTIC 64 | }; 65 | 66 | DEFINE_ENUM_FLAG_OPERATORS(NotifyFilter); 67 | 68 | #if 0 69 | class RegistryValue 70 | { 71 | public: 72 | virtual Registry::ValueType GetType() const { return ValueType::NUL; } 73 | 74 | virtual bool IsNull() const { return true; } 75 | virtual bool IsNumber() const { return false; } 76 | virtual bool IsInt32() const { return false; } 77 | virtual bool IsInt64() const { return false; } 78 | virtual bool IsString() const { return false; } 79 | virtual bool IsBool() const { return false; } 80 | 81 | virtual bool GetBoolean() const { return false; } 82 | virtual long GetInt32() const { return 0; } 83 | virtual long long GetInt64() const { return 0; } 84 | virtual std::wstring GetString() const { return std::wstring(); } 85 | virtual std::shared_ptr GetBinary() const { return std::shared_ptr(); } 86 | }; 87 | 88 | template 89 | class Value : public RegistryValue { 90 | protected: 91 | explicit Value(const T& value) : m_value(value), m_type(tag) { } 92 | explicit Value(T&& value) : m_value(std::move(value)), m_type(tag) { } 93 | 94 | public: 95 | Registry::ValueType GetType() const override { return tag; } 96 | virtual bool IsNull() const override { return (m_type == Registry::ValueType::NUL); } 97 | virtual bool IsNumber() const override { return (m_type == Registry::ValueType::INT32 || m_type == Registry::ValueType::INT64); } 98 | virtual bool IsInt32() const override { return (m_type == Registry::ValueType::INT32); } 99 | virtual bool IsInt64() const override { return (m_type == Registry::ValueType::INT64); } 100 | virtual bool IsString() const override { return (m_type == Registry::ValueType::STRING); } 101 | virtual bool IsBool() const override { return (m_type == Registry::ValueType::BOOLEAN); } 102 | 103 | protected: 104 | T m_value; 105 | Registry::ValueType m_type; 106 | }; 107 | 108 | class RegistryBoolean final : public Value { 109 | public: 110 | RegistryBoolean(bool value) : Value(value) {} 111 | 112 | bool GetBoolean() const override { return m_value; } 113 | }; 114 | 115 | class RegistryInt32 final : public Value { 116 | public: 117 | RegistryInt32(long value) : Value(value) {} 118 | 119 | long GetInt32() const override { return m_value; } 120 | }; 121 | 122 | class RegistryInt64 final : public Value { 123 | public: 124 | RegistryInt64(long long value) : Value(value) {} 125 | 126 | long long GetInt64() const override { return m_value; } 127 | }; 128 | 129 | class RegistryString final : public Value { 130 | public: 131 | RegistryString(const std::wstring& value) : Value(value) {} 132 | 133 | std::wstring GetString() const override { return m_value; } 134 | }; 135 | 136 | class RegistryBinary final : public Value> { 137 | public: 138 | RegistryBinary(const std::shared_ptr& value) : Value(value) {} 139 | 140 | std::shared_ptr GetBinary() const override { return m_value; } 141 | }; 142 | #endif 143 | 144 | class RegistryKey; 145 | 146 | typedef std::shared_ptr RegistryKey_ptr; 147 | 148 | class RegistryKey 149 | { 150 | private: 151 | /// 152 | /// Deleted default constructor 153 | /// 154 | RegistryKey() = delete; 155 | 156 | public: 157 | RegistryKey(HKEY hKey) 158 | : m_hKey(hKey) 159 | { 160 | if (m_hKey == nullptr) 161 | { 162 | throw std::invalid_argument("Registry key handle cannot be nullptr"); 163 | } 164 | } 165 | 166 | // Disable copy ctor & copy assignment operator 167 | RegistryKey(const RegistryKey& other) = delete; 168 | RegistryKey& operator=(RegistryKey& other) = delete; 169 | 170 | // TODO Implement move logic 171 | // RegistryKey(RegistryKey&& other); 172 | // RegistryKey& operator=(RegistryKey&& other); 173 | 174 | ~RegistryKey() 175 | { 176 | if ((m_hKey != nullptr) && !( 177 | (m_hKey >= HKEY_CLASSES_ROOT) && 178 | #if (WINVER >= 0x0400) 179 | (m_hKey <= HKEY_CURRENT_USER_LOCAL_SETTINGS) 180 | #else 181 | (m_hKey <= HKEY_PERFORMANCE_DATA) 182 | #endif 183 | )) 184 | { 185 | RegCloseKey(m_hKey); 186 | } 187 | } 188 | 189 | operator HKEY() const 190 | { 191 | return m_hKey; 192 | } 193 | 194 | /// 195 | /// Member method to open registry key on specified path, with specified access rights 196 | /// 197 | /// Relative path to subkey of this registry key 198 | /// (access), &hKey); 215 | if (lStatus != ERROR_SUCCESS) 216 | { 217 | auto ec = std::error_code(lStatus, std::system_category()); 218 | 219 | throw std::system_error(ec, "RegOpenKeyEx() failed"); 220 | } 221 | 222 | assert(hKey != nullptr); 223 | 224 | return std::make_shared(hKey); 225 | } 226 | 227 | /// 228 | /// Creates registry key on specified path 229 | /// 230 | /// Relative path to subkey to create 231 | RegistryKey_ptr CreateVolatile(const std::wstring& path, DesiredAccess access = DesiredAccess::Read) 232 | { 233 | return Create(path, access, CreateKeyOptions::Volatile); 234 | } 235 | 236 | /// 237 | /// Creates registry key on specified path 238 | /// 239 | /// Relative path to subkey to create 240 | /// Relative path to subkey to create 241 | /// Relative path to subkey to create 242 | RegistryKey_ptr Create(const std::wstring& path, DesiredAccess access = DesiredAccess::Read, CreateKeyOptions options = CreateKeyOptions::NonVolatile) 243 | { 244 | if (path.empty()) 245 | { 246 | throw std::invalid_argument("Specified path to registry key cannot be empty"); 247 | } 248 | 249 | HKEY hKey = nullptr; 250 | 251 | DWORD dwReserved = 0; 252 | LPTSTR lpClass = nullptr; 253 | 254 | LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr; 255 | 256 | LSTATUS lStatus = 257 | RegCreateKeyEx( 258 | m_hKey, 259 | path.c_str(), 260 | dwReserved, 261 | lpClass, 262 | static_cast(options), 263 | static_cast(access), 264 | lpSecurityAttributes, 265 | &hKey, 266 | nullptr 267 | ); 268 | 269 | if (lStatus != ERROR_SUCCESS) 270 | { 271 | auto ec = std::error_code(lStatus, std::system_category()); 272 | 273 | throw std::system_error(ec, "RegOpenKeyEx() failed"); 274 | } 275 | 276 | assert(hKey != nullptr); 277 | 278 | return std::make_shared(hKey); 279 | } 280 | 281 | void Delete() 282 | { 283 | LPTSTR lpSubKey = nullptr; 284 | 285 | LSTATUS lStatus = RegDeleteTree(m_hKey, lpSubKey); 286 | if (lStatus != ERROR_SUCCESS) 287 | { 288 | auto ec = std::error_code(lStatus, std::system_category()); 289 | 290 | throw std::system_error(ec, "RegDeleteTree() failed"); 291 | } 292 | } 293 | 294 | void Delete(const std::wstring& name) 295 | { 296 | LSTATUS lStatus = RegDeleteValue(m_hKey, name.c_str()); 297 | // In case registry entry with specified name is not registry Value 298 | // RegDeleteValue() returns ERROR_FILE_NOT_FOUND, so we will try to 299 | // delete registry entry as if it is registry Key 300 | if (lStatus == ERROR_FILE_NOT_FOUND) 301 | { 302 | lStatus = RegDeleteTree(m_hKey, name.c_str()); 303 | } 304 | 305 | if (lStatus != ERROR_SUCCESS && lStatus != ERROR_FILE_NOT_FOUND) 306 | { 307 | auto ec = std::error_code(lStatus, std::system_category()); 308 | 309 | throw std::system_error(ec, "RegDeleteTree() failed"); 310 | } 311 | } 312 | 313 | void Flush() 314 | { 315 | LSTATUS lStatus = RegFlushKey(m_hKey); 316 | if (lStatus != ERROR_SUCCESS) 317 | { 318 | auto ec = std::error_code(lStatus, std::system_category()); 319 | 320 | throw std::system_error(ec, "RegFlushKey() failed"); 321 | } 322 | } 323 | 324 | void Save(const std::wstring& file) 325 | { 326 | LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr; 327 | 328 | LSTATUS lStatus = RegSaveKey(m_hKey, file.c_str(), lpSecurityAttributes); 329 | if (lStatus != ERROR_SUCCESS) 330 | { 331 | auto ec = std::error_code(lStatus, std::system_category()); 332 | 333 | throw std::system_error(ec, "RegFlushKey() failed"); 334 | } 335 | } 336 | 337 | 338 | 339 | /// 340 | /// Checks whether specified subkey exists or not 341 | /// 342 | /// Subkey relative path to be checked for existence 343 | bool HasKey(const std::wstring& path) 344 | { 345 | if (path.empty()) 346 | { 347 | throw std::invalid_argument("Specified path to registry key cannot be empty"); 348 | } 349 | 350 | auto hasKey = false; 351 | 352 | HKEY hKey = nullptr; 353 | 354 | LSTATUS lStatus = RegOpenKeyEx(m_hKey, path.c_str(), 0, KEY_READ, &hKey); 355 | 356 | if (lStatus == ERROR_SUCCESS) 357 | { 358 | assert(hKey != nullptr); 359 | RegCloseKey(hKey); 360 | 361 | hasKey = true; 362 | } 363 | else if (lStatus != ERROR_FILE_NOT_FOUND) 364 | { 365 | assert(hKey == nullptr); 366 | 367 | auto ec = std::error_code(lStatus, std::system_category()); 368 | 369 | throw std::system_error(ec, "RegOpenKeyEx() failed"); 370 | } 371 | 372 | return hasKey; 373 | } 374 | 375 | // For backward compatibility only 376 | bool Exists(const std::wstring& path) 377 | { 378 | return HasKey(path); 379 | } 380 | 381 | bool HasValue(const std::wstring& name) 382 | { 383 | if (name.empty()) 384 | { 385 | throw std::invalid_argument("Value name cannot be empty"); 386 | } 387 | 388 | auto hasValue = false; 389 | 390 | LSTATUS lStatus = RegQueryValueEx(m_hKey, name.c_str(), nullptr, nullptr, nullptr, nullptr); 391 | if (lStatus == ERROR_SUCCESS) 392 | { 393 | hasValue = true; 394 | } 395 | else if (lStatus != ERROR_FILE_NOT_FOUND) 396 | { 397 | auto ec = std::error_code(lStatus, std::system_category()); 398 | 399 | throw std::system_error(ec, "RegQueryValueEx() failed"); 400 | } 401 | 402 | return hasValue; 403 | } 404 | 405 | bool GetBoolean(const std::wstring& name) 406 | { 407 | DWORD dwType = 0; 408 | DWORD dwData = 0; 409 | DWORD cbData = sizeof(dwData); 410 | 411 | LPDWORD lpReserver = nullptr; 412 | 413 | LSTATUS lStatus = RegQueryValueEx(m_hKey, name.c_str(), lpReserver, &dwType, reinterpret_cast(&dwData), &cbData); 414 | if (lStatus != ERROR_SUCCESS) 415 | { 416 | auto ec = std::error_code(lStatus, std::system_category()); 417 | 418 | throw std::system_error(ec, "RegQueryValueEx() failed"); 419 | } 420 | 421 | if (dwType != REG_DWORD && dwType != REG_QWORD) 422 | { 423 | throw std::runtime_error("Wrong registry value type " + std::to_string(dwType) + " for boolean value."); 424 | } 425 | 426 | return (dwData == 0) ? false : true; 427 | } 428 | 429 | // Default registry value 430 | bool GetBoolean() 431 | { 432 | return GetBoolean(L""); 433 | } 434 | 435 | void SetBoolean(const std::wstring& name, bool value) 436 | { 437 | DWORD dwValue = value ? 1 : 0; 438 | DWORD cbData = sizeof(dwValue); 439 | 440 | LSTATUS lStatus = RegSetValueEx(m_hKey, name.c_str(), 0, REG_DWORD, reinterpret_cast(&dwValue), cbData); 441 | if (lStatus != ERROR_SUCCESS) 442 | { 443 | auto ec = std::error_code(lStatus, std::system_category()); 444 | 445 | throw std::system_error(ec, "RegSetValueEx() failed"); 446 | } 447 | } 448 | 449 | void SetBoolean(bool value) 450 | { 451 | SetBoolean(L"", value); 452 | } 453 | 454 | long GetInt32(const std::wstring& name) 455 | { 456 | long lData = 0; 457 | DWORD cbData = sizeof(lData); 458 | 459 | LSTATUS lStatus = RegQueryValueEx(m_hKey, name.c_str(), nullptr, nullptr, reinterpret_cast(&lData), &cbData); 460 | if (lStatus != ERROR_SUCCESS) 461 | { 462 | auto ec = std::error_code(lStatus, std::system_category()); 463 | 464 | throw std::system_error(ec, "RegQueryValueEx() failed"); 465 | } 466 | 467 | return lData; 468 | } 469 | 470 | long GetInt32() 471 | { 472 | return GetInt32(L""); 473 | } 474 | 475 | unsigned long GetUInt32(const std::wstring& name) 476 | { 477 | return static_cast(GetInt32(name)); 478 | } 479 | 480 | unsigned long GetUInt32() 481 | { 482 | return GetUInt32(L""); 483 | } 484 | 485 | void SetInt32(const std::wstring& name, long value) 486 | { 487 | DWORD cbData = sizeof(value); 488 | 489 | LSTATUS lStatus = RegSetValueEx(m_hKey, name.c_str(), 0, REG_DWORD, reinterpret_cast(&value), cbData); 490 | if (lStatus != ERROR_SUCCESS) 491 | { 492 | auto ec = std::error_code(lStatus, std::system_category()); 493 | 494 | throw std::system_error(ec, "RegSetValueEx() failed"); 495 | } 496 | } 497 | 498 | void SetInt32(long value) 499 | { 500 | return SetInt32(L"", value); 501 | } 502 | 503 | void SetUInt32(const std::wstring& name, unsigned long value) 504 | { 505 | return SetInt32(name, static_cast(value)); 506 | } 507 | 508 | void SetUInt32(unsigned long value) 509 | { 510 | return SetUInt32(L"", value); 511 | } 512 | 513 | long long GetInt64(const std::wstring& name) 514 | { 515 | long long llData = 0; 516 | DWORD cbData = sizeof(llData); 517 | 518 | LSTATUS lStatus = RegQueryValueEx(m_hKey, name.c_str(), nullptr, nullptr, reinterpret_cast(&llData), &cbData); 519 | if (lStatus != ERROR_SUCCESS) 520 | { 521 | auto ec = std::error_code(lStatus, std::system_category()); 522 | 523 | throw std::system_error(ec, "RegQueryValueEx() failed"); 524 | } 525 | 526 | return llData; 527 | } 528 | 529 | long long GetInt64() 530 | { 531 | return GetInt64(L""); 532 | } 533 | 534 | unsigned long long GetUInt64(const std::wstring& name) 535 | { 536 | return static_cast(GetInt64(name)); 537 | } 538 | 539 | unsigned long long GetUInt64() 540 | { 541 | return static_cast(GetUInt64(L"")); 542 | } 543 | 544 | void SetInt64(const std::wstring& name, long long value) 545 | { 546 | DWORD cbData = sizeof(value); 547 | 548 | LSTATUS lStatus = RegSetValueEx(m_hKey, name.c_str(), 0, REG_QWORD, reinterpret_cast(&value), cbData); 549 | if (lStatus != ERROR_SUCCESS) 550 | { 551 | auto ec = std::error_code(lStatus, std::system_category()); 552 | 553 | throw std::system_error(ec, "RegSetValueEx() failed"); 554 | } 555 | } 556 | 557 | void SetInt64(long long value) 558 | { 559 | return SetInt64(L"", value); 560 | } 561 | 562 | void SetUInt64(const std::wstring& name, unsigned long long value) 563 | { 564 | SetInt64(name, static_cast(value)); 565 | } 566 | 567 | void SetUInt64(unsigned long long value) 568 | { 569 | SetUInt64(L"", value); 570 | } 571 | 572 | std::wstring GetString(const std::wstring& name) 573 | { 574 | DWORD cbData = 0; 575 | DWORD dwType = 0; 576 | 577 | DWORD dwFlags = RRF_RT_REG_EXPAND_SZ | RRF_NOEXPAND | RRF_RT_REG_SZ; 578 | 579 | LSTATUS lStatus = RegGetValue(m_hKey, nullptr, name.c_str(), dwFlags, &dwType, nullptr, &cbData); 580 | if (lStatus != ERROR_SUCCESS) 581 | { 582 | auto ec = std::error_code(lStatus, std::system_category()); 583 | 584 | throw std::system_error(ec, "RegGetValue() failed"); 585 | } 586 | 587 | if (dwType != REG_SZ && dwType != REG_EXPAND_SZ) // ??? 588 | { 589 | throw std::runtime_error("Wrong registry value type " + std::to_string(dwType) + " for string value."); 590 | } 591 | 592 | std::wstring value; 593 | 594 | if (cbData) 595 | { 596 | assert((cbData % sizeof(TCHAR)) != 1); 597 | 598 | auto data = new TCHAR[cbData / sizeof(TCHAR)]; 599 | assert(data != nullptr); 600 | 601 | lStatus = RegGetValue(m_hKey, nullptr, name.c_str(), dwFlags, &dwType, reinterpret_cast(data), &cbData); 602 | 603 | std::exception_ptr pex; 604 | 605 | if (lStatus == ERROR_SUCCESS) 606 | { 607 | //assert(data[cbData / sizeof(TCHAR) - 1] == _T('\0')); 608 | 609 | value = std::wstring(data); 610 | } 611 | else 612 | { 613 | auto ec = std::error_code(lStatus, std::system_category()); 614 | 615 | pex = std::make_exception_ptr(std::system_error(ec, "RegGetValue() failed")); 616 | } 617 | 618 | delete[] data; 619 | 620 | if (pex) 621 | { 622 | std::rethrow_exception(pex); 623 | } 624 | } 625 | 626 | return value; 627 | } 628 | 629 | std::wstring GetString() 630 | { 631 | return GetString(L""); 632 | } 633 | 634 | void SetString(const std::wstring& name, const std::wstring& value) 635 | { 636 | auto cbData = static_cast(value.length()); 637 | 638 | LSTATUS lStatus = RegSetValueEx(m_hKey, name.c_str(), 0, REG_SZ, reinterpret_cast(value.c_str()), cbData * sizeof(TCHAR)); 639 | if (lStatus != ERROR_SUCCESS) 640 | { 641 | auto ec = std::error_code(lStatus, std::system_category()); 642 | 643 | throw std::system_error(ec, "RegSetValueEx() failed"); 644 | } 645 | } 646 | 647 | void SetString(const std::wstring& value) 648 | { 649 | SetString(L"", value); 650 | } 651 | 652 | /// 653 | /// Create registry value with specified name of type REG_EXPAND_SZ within this registry key 654 | /// 655 | /// Name of registry value (Empty string for default key value) 656 | /// Value to be set 657 | void SetExpandString(const std::wstring& name, const std::wstring& value) 658 | { 659 | auto cbData = static_cast(value.length()); 660 | 661 | LSTATUS lStatus = RegSetValueEx(m_hKey, name.c_str(), 0, REG_EXPAND_SZ, reinterpret_cast(value.c_str()), cbData * sizeof(TCHAR)); 662 | if (lStatus != ERROR_SUCCESS) 663 | { 664 | auto ec = std::error_code(lStatus, std::system_category()); 665 | 666 | throw std::system_error(ec, "RegSetValueEx() failed"); 667 | } 668 | } 669 | 670 | /// 671 | /// Create default registry value of type REG_EXPAND_SZ within this registry key 672 | /// 673 | /// Value to be set 674 | void SetExpandString(const std::wstring& value) 675 | { 676 | SetExpandString(L"", value); 677 | } 678 | 679 | template 680 | void EnumerateSubKeys(const __Function& callback) 681 | { 682 | DWORD dwSubKeys = 0; 683 | DWORD dwLongestSubKeyLen = 0; 684 | 685 | LSTATUS lStatus = RegQueryInfoKey 686 | ( 687 | m_hKey, // Key handle 688 | nullptr, // Buffer for registry ked class name 689 | nullptr, // Size of class string 690 | nullptr, // Reserved 691 | &dwSubKeys, // Number of key subkeys (this is what we want) 692 | &dwLongestSubKeyLen, // Longest subkey size 693 | nullptr, // Longest class string 694 | nullptr, // number of values for this key 695 | nullptr, // Longest value name 696 | nullptr, // Longest value data 697 | nullptr, // Security descriptor 698 | nullptr // Last key write time 699 | ); 700 | 701 | if (lStatus != ERROR_SUCCESS) 702 | { 703 | auto ec = std::error_code(lStatus, std::system_category()); 704 | 705 | throw std::system_error(ec, "RegQueryInfoKey() failed"); 706 | } 707 | 708 | // Add space fot terminating null character 709 | ++dwLongestSubKeyLen; 710 | 711 | std::exception_ptr pex; 712 | 713 | auto pszName = reinterpret_cast(LocalAlloc(LMEM_FIXED, dwLongestSubKeyLen * sizeof(TCHAR))); 714 | assert(pszName != nullptr); 715 | 716 | for (DWORD i = 0; i < dwSubKeys; ++i) 717 | { 718 | DWORD dwLen = dwLongestSubKeyLen; 719 | 720 | lStatus = RegEnumKeyEx 721 | ( 722 | m_hKey, // Key handle 723 | i, // Subkey index 724 | pszName, // Subkey name buffer 725 | &dwLen, // Subkey name string length 726 | nullptr, // Reserved 727 | nullptr, // Subkey class buffer 728 | nullptr, // Subkey class string length 729 | nullptr // Last subkey write time 730 | ); 731 | 732 | if (lStatus != ERROR_SUCCESS) 733 | { 734 | auto ec = std::error_code(lStatus, std::system_category()); 735 | 736 | pex = std::make_exception_ptr( 737 | std::system_error(ec, "RegQueryInfoKey() failed") 738 | ); 739 | 740 | break; 741 | } 742 | 743 | std::wstring subKeyName(pszName, dwLen); 744 | 745 | // Catch possible exception thrown by lambda callback 746 | try 747 | { 748 | if (!callback(subKeyName)) 749 | { 750 | // Break loop when callback returns false 751 | break; 752 | } 753 | } 754 | catch (const std::exception&) 755 | { 756 | pex = std::current_exception(); 757 | 758 | break; 759 | } 760 | } 761 | 762 | LocalFree(pszName); 763 | 764 | if (pex) 765 | { 766 | std::rethrow_exception(pex); 767 | } 768 | } 769 | 770 | /// 771 | /// Notifies the caller about changes to the attributes or contents of a specified registry key. 772 | /// 773 | /// 774 | /// If this parameter is true, the function reports changes in the specified key and its subkeys. 775 | /// Otherwise, the function reports changes only in the specified key. 776 | /// Default is false. 777 | /// 778 | /// 779 | /// A value that indicates the changes that should be reported. 780 | /// Default is ChangeName and ChangeAttributes. 781 | /// 782 | void Notify(bool watchSubtree = false, NotifyFilter notifyFilter = NotifyFilter::ChangeName | NotifyFilter::ChangeAttributes) 783 | { 784 | HANDLE hEvent = nullptr; 785 | BOOL fAsynchronous = FALSE; 786 | 787 | LSTATUS lStatus = RegNotifyChangeKeyValue 788 | ( 789 | m_hKey, 790 | watchSubtree ? TRUE : FALSE, 791 | static_cast(notifyFilter), 792 | hEvent, 793 | fAsynchronous 794 | ); 795 | 796 | if (lStatus != ERROR_SUCCESS) 797 | { 798 | auto ec = std::error_code(lStatus, std::system_category()); 799 | 800 | throw std::system_error(ec, "RegNotifyChangeKeyValue() failed"); 801 | } 802 | } 803 | 804 | /// 805 | /// Notifies the caller about changes to the attributes or contents of a specified registry key asynchonously via provided event object. 806 | /// 807 | /// 808 | /// A handle to an event. Call to this function returns immediately and changes are reported by signaling this event. 809 | /// 810 | /// 811 | /// If this parameter is true, the function reports changes in the specified key and its subkeys. 812 | /// Otherwise, the function reports changes only in the specified key. 813 | /// Default is false. 814 | /// 815 | /// 816 | /// A value that indicates the changes that should be reported. 817 | /// Default is ChangeName and ChangeAttributes. 818 | /// 819 | void NotifyAsync(HANDLE hEvent, bool watchSubtree = false, NotifyFilter notifyFilter = NotifyFilter::ChangeName | NotifyFilter::ChangeAttributes | NotifyFilter::ChangeLastSet) 820 | { 821 | if (hEvent == nullptr) 822 | { 823 | throw std::invalid_argument("Event handle cannot be null"); 824 | } 825 | 826 | BOOL fAsynchronous = TRUE; 827 | 828 | LSTATUS lStatus = RegNotifyChangeKeyValue 829 | ( 830 | m_hKey, 831 | watchSubtree ? TRUE : FALSE, 832 | static_cast(notifyFilter), 833 | hEvent, 834 | fAsynchronous 835 | ); 836 | 837 | if (lStatus != ERROR_SUCCESS) 838 | { 839 | auto ec = std::error_code(lStatus, std::system_category()); 840 | 841 | throw std::system_error(ec, "RegNotifyChangeKeyValue() failed"); 842 | } 843 | } 844 | 845 | #if 0 846 | std::shared_ptr GetBinary(const std::wstring& name, size_t len) 847 | { 848 | DWORD cbData = DWORD(len); 849 | BYTE *data = new BYTE[len]; 850 | std::shared_ptr ret; 851 | 852 | if (data != nullptr) 853 | { 854 | LSTATUS lStatus = RegQueryValueEx(m_hKey, name.c_str(), nullptr, nullptr, data, &cbData); 855 | if (lStatus == ERROR_SUCCESS) 856 | { 857 | ret = std::shared_ptr(data, std::default_delete()); 858 | } 859 | } 860 | 861 | return ret; 862 | } 863 | 864 | bool SetBinary(const std::wstring& name, const BYTE* pData, size_t len) 865 | { 866 | DWORD cbData = DWORD(len); 867 | 868 | LSTATUS lStatus = RegSetValueEx(m_hKey, name.c_str(), 0, REG_BINARY, pData, DWORD(len)); 869 | 870 | return (lStatus == ERROR_SUCCESS); 871 | } 872 | 873 | RegistryValue GetValue(const std::wstring& name) 874 | { 875 | assert(m_hKey != nullptr); 876 | DWORD dwType = 0; 877 | DWORD cbData = 0; 878 | 879 | RegistryValue ret; 880 | 881 | LSTATUS err = RegQueryValueEx(m_hKey, name.c_str(), nullptr, &dwType, nullptr, &cbData); 882 | if (err == ERROR_SUCCESS) 883 | { 884 | switch (dwType) 885 | { 886 | case REG_DWORD: 887 | { 888 | long value = 0; 889 | cbData = sizeof(value); 890 | 891 | if (RegQueryValueEx(m_hKey, name.c_str(), nullptr, nullptr, (LPBYTE)&value, &cbData) == ERROR_SUCCESS) 892 | { 893 | ret = RegistryInt32(value); 894 | } 895 | } 896 | break; 897 | 898 | case REG_QWORD: 899 | { 900 | long long value = 0; 901 | cbData = sizeof(value); 902 | 903 | if (RegQueryValueEx(m_hKey, name.c_str(), nullptr, nullptr, (LPBYTE)&value, &cbData) == ERROR_SUCCESS) 904 | { 905 | ret = RegistryInt64(value); 906 | } 907 | } 908 | break; 909 | 910 | case REG_SZ: 911 | { 912 | WCHAR *data = new WCHAR[cbData]; 913 | if (data != nullptr) 914 | { 915 | LSTATUS lStatus = RegQueryValueEx(m_hKey, name.c_str(), nullptr, nullptr, (LPBYTE)data, &cbData); 916 | if (lStatus == ERROR_SUCCESS) 917 | { 918 | std::wstring s(data, cbData); 919 | ret = RegistryString(s); 920 | } 921 | 922 | delete[] data; 923 | } 924 | } 925 | break; 926 | 927 | case REG_BINARY: 928 | { 929 | BYTE *data = new BYTE[cbData]; 930 | 931 | if (data != nullptr) 932 | { 933 | LSTATUS lStatus = RegQueryValueEx(m_hKey, name.c_str(), nullptr, nullptr, data, &cbData); 934 | if (lStatus == ERROR_SUCCESS) 935 | { 936 | ret = RegistryBinary( 937 | std::shared_ptr( 938 | data, 939 | std::default_delete() 940 | ) 941 | ); 942 | } 943 | } 944 | } 945 | break; 946 | 947 | default: 948 | break; 949 | } 950 | } 951 | 952 | return ret; 953 | } 954 | 955 | void SetValue(const std::wstring& valueName, const RegistryValue& value) 956 | { 957 | switch (value.GetType()) 958 | { 959 | case Registry::ValueType::BOOLEAN: { return this->SetBoolean(valueName, value.GetBoolean()); } break; 960 | case Registry::ValueType::INT32: { return this->SetInt32(valueName, value.GetInt32()); } break; 961 | case Registry::ValueType::INT64: { return this->SetInt64(valueName, value.GetInt64()); } break; 962 | case Registry::ValueType::STRING: { return this->SetString(valueName, value.GetString()); } break; 963 | //case Registry::Type::BINARY: { return this->SetBinary(valueName, *value.GetBinary(), ); } 964 | } 965 | } 966 | #endif 967 | 968 | #if 0 969 | std::vector GetSubKeys() 970 | { 971 | std::vector vecRet; 972 | DWORD dwSubKeys = 0; 973 | DWORD dwMaxSubKeyLen = 0; 974 | LSTATUS lStatus = RegQueryInfoKey(m_hKey, NULL, NULL, NULL, &dwSubKeys, NULL, NULL, NULL, &dwMaxSubKeyLen, NULL, NULL, NULL); 975 | if (lStatus == ERROR_SUCCESS && dwSubKeys > 0) 976 | { 977 | 978 | for (DWORD i = 0; i < dwSubKeys; i++) 979 | { 980 | WCHAR pwszName[255]; 981 | DWORD dwNameLen = 255; 982 | lStatus = RegEnumKeyEx(m_hKey, i, pwszName, &dwNameLen, NULL, NULL, NULL, NULL); 983 | if (lStatus == ERROR_SUCCESS) 984 | { 985 | vecRet.push_back(std::wstring(pwszName, dwNameLen)); 986 | } 987 | } 988 | } 989 | 990 | return vecRet; 991 | } 992 | #endif 993 | 994 | private: 995 | HKEY m_hKey; 996 | }; 997 | 998 | extern RegistryKey_ptr ClassesRoot; 999 | extern RegistryKey_ptr CurrentUser; 1000 | extern RegistryKey_ptr LocalMachine; 1001 | extern RegistryKey_ptr Users; 1002 | extern RegistryKey_ptr CurrentConfig; 1003 | } 1004 | } 1005 | --------------------------------------------------------------------------------