Fix typos
[TortoiseGit.git] / src / Utils / registry.h
blob61502a27a1be82ff505518e9b8a32ef391f9d885
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2011-2019, 2021, 2023 - TortoiseGit
4 // Copyright (C) 2003-2014 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #pragma once
21 #include <string>
22 #include <memory>
23 #include <Shlwapi.h>
24 #include "FormatMessageWrapper.h"
26 #ifndef ASSERT
27 #define ASSERT(x)
28 #endif
30 #ifndef QWORD
31 typedef unsigned __int64 QWORD, *PQWORD;
32 #endif
34 /**
35 * \ingroup Utils
36 * Base class for the registry classes.
38 * \par requirements
39 * - win98 or later, win2k or later, win95 with IE4 or later, winNT4 with IE4 or later
40 * - import library Shlwapi.lib
43 template<class S>
44 class CRegBaseCommon
46 protected:
47 /**
48 * String type specific operations.
51 virtual LPCWSTR GetPlainString(const S& s) const = 0;
52 virtual DWORD GetLength(const S& s) const = 0;
54 public:
55 virtual ~CRegBaseCommon() = default;
56 //methods
58 /** Default constructor.
60 CRegBaseCommon();
61 /**
62 * Constructor.
63 * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
64 * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
65 * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
66 * \param sam
68 CRegBaseCommon(const S& key, bool force, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
70 /**
71 * Removes the whole registry key including all values. So if you set the registry
72 * entry to be HKCU\Software\Company\Product\key\value there will only be
73 * HKCU\Software\Company\Product key in the registry.
74 * \return ERROR_SUCCESS or an nonzero error code. Use FormatMessage() to get an error description.
76 DWORD removeKey();
77 /**
78 * Removes the value of the registry object. If you set the registry entry to
79 * be HKCU\Software\Company\Product\key\value there will only be
80 * HKCU\Software\Company\Product\key\ in the registry.
81 * \return ERROR_SUCCESS or an nonzero error code. Use FormatMessage() to get an error description.
83 LONG removeValue();
85 /**
86 * Returns the string of the last error occurred.
88 virtual S getErrorString()
90 CFormatMessageWrapper errorMessage(m_lastError);
91 S result(static_cast<LPCWSTR>(errorMessage));
92 return result;
95 /// get failure info for last operation
97 LONG GetLastError() const
99 return m_lastError;
102 /// used in subclass templates to specify the correct string type
104 using StringT = S;
106 protected:
107 //members
108 HKEY m_base; ///< handle to the registry base
109 S m_key; ///< the name of the value
110 S m_path; ///< the path to the key
111 LONG m_lastError; ///< the value of the last error occurred
112 REGSAM m_sam; ///< the security attributes to pass to the registry command
114 bool m_read; ///< indicates if the value has already been attempted read from the registry
115 bool m_force; ///< indicates if no cache should be used, i.e. always read and write directly from registry
116 bool m_exists; ///< true, if the registry value actually exists
119 // implement CRegBaseCommon<> members
121 template<class S>
122 CRegBaseCommon<S>::CRegBaseCommon()
123 : m_base(HKEY_CURRENT_USER)
124 , m_key()
125 , m_path()
126 , m_lastError(ERROR_SUCCESS)
127 , m_sam(0)
128 , m_read(false)
129 , m_force(false)
130 , m_exists(false)
134 template<class S>
135 CRegBaseCommon<S>::CRegBaseCommon(const S& key, bool force, HKEY base, REGSAM sam)
136 : m_base(base)
137 , m_key(key)
138 , m_path()
139 , m_lastError(ERROR_SUCCESS)
140 , m_sam(sam)
141 , m_read(false)
142 , m_force(force)
143 , m_exists(false)
147 template<class S>
148 DWORD CRegBaseCommon<S>::removeKey()
150 m_exists = false;
151 m_read = true;
153 HKEY hKey = nullptr;
154 RegOpenKeyEx(m_base, GetPlainString(m_path), 0, KEY_WRITE | m_sam, &hKey);
155 auto ret = SHDeleteKey(m_base, GetPlainString(m_path));
156 RegCloseKey(hKey);
157 return ret;
160 template<class S>
161 LONG CRegBaseCommon<S>::removeValue()
163 m_exists = false;
164 m_read = true;
166 HKEY hKey = nullptr;
167 RegOpenKeyEx(m_base, GetPlainString(m_path), 0, KEY_WRITE | m_sam, &hKey);
168 auto ret = RegDeleteValue(hKey, GetPlainString(m_key));
169 RegCloseKey(hKey);
170 return ret;
174 * \ingroup Utils
175 * Base class for MFC type registry classes.
178 #ifdef __CSTRINGT_H__
179 class CRegBase : public CRegBaseCommon<CString>
181 protected:
183 * String type specific operations.
186 LPCWSTR GetPlainString(const CString& s) const override { return static_cast<LPCWSTR>(s); }
187 virtual DWORD GetLength(const CString& s) const override { return s.GetLength(); }
189 public: //methods
190 /** Default constructor.
192 CRegBase();
194 * Constructor.
195 * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
196 * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
197 * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
199 CRegBase(const CString& key, bool force, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
202 * Returns the string of the last error occurred.
204 CString getErrorString() override
206 CString error = CRegBaseCommon<CString>::getErrorString();
207 #if defined IDS_REG_ERROR
208 CString sTemp;
209 sTemp.FormatMessage(IDS_REG_ERROR, static_cast<LPCWSTR>(m_key), static_cast<LPCWSTR>(error));
210 return sTemp;
211 #else
212 return error;
213 #endif
216 #endif
219 * \ingroup Utils
220 * Base class for STL string type registry classes.
223 class CRegStdBase : public CRegBaseCommon<std::wstring>
225 protected:
227 * String type specific operations.
230 LPCWSTR GetPlainString(const std::wstring& s) const override { return s.c_str(); }
231 DWORD GetLength(const std::wstring& s) const override { return static_cast<DWORD>(s.size()); }
233 public: //methods
234 /** Default constructor.
236 CRegStdBase();
238 * Constructor.
239 * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
240 * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
241 * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
242 * \param sam
244 CRegStdBase(const std::wstring& key, bool force, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
248 * \ingroup Utils
249 * DWORD value in registry. with this class you can use DWORD values in registry
250 * like normal DWORD variables in your program.
251 * Usage:
252 * in your header file, declare your registry DWORD variable:
253 * \code
254 * CRegDWORD regvalue;
255 * \endcode
256 * next initialize the variable e.g. in the constructor of your class:
257 * \code
258 * regvalue = CRegDWORD("Software\\Company\\SubKey\\MyValue", 100);
259 * \endcode
260 * this will set the registry value "MyValue" under HKEY_CURRENT_USER with path
261 * "Software\Company\SubKey" to the variable. If the key does not yet exist or
262 * an error occurred during read from the registry, a default
263 * value of 100 is used when accessing the variable.
264 * now the variable can be used like any other DWORD variable:
265 * \code
266 * regvalue = 200; //stores the value 200 in the registry
267 * int temp = regvalue + 300; //temp has value 500 now
268 * regvalue += 300; //now the registry has the value 500 too
269 * \endcode
270 * to avoid too much access to the registry the value is cached inside the object.
271 * once the value is read, no more read accesses to the registry will be made.
272 * this means the variable will contain a wrong value if the corresponding registry
273 * entry is changed by anything else than this variable! If you think that could happen
274 * then use
275 * \code
276 * regvalue.read();
277 * \endcode
278 * to force a refresh of the variable with the registry.
279 * a write to the registry is only made if the new value assigned with the variable
280 * is different than the last assigned value.
281 * to force a write use the method write();
282 * another option to force reads and writes to the registry is to specify TRUE as the
283 * third parameter in the constructor.
285 template<class T, class Base>
286 class CRegTypedBase : public Base
288 private:
289 T m_value; ///< the cached value of the registry
290 T m_defaultvalue; ///< the default value to use
293 * time stamp of the last registry lookup, i.e \ref read() call
296 ULONGLONG lastRead;
299 * \ref read() will be called, if \ref lastRead differs from the
300 * current time stamp by more than this.
301 * ULONGLONG(-1) -> no automatic refresh.
304 ULONGLONG lookupInterval;
307 * Check time stamps etc.
308 * If the current data is out-dated, reset the \ref m_read flag.
311 void HandleAutoRefresh();
314 * sub-classes must provide type-specific code to extract data from
315 * and write data to an open registry key.
318 virtual void InternalRead(HKEY hKey, T& value) = 0;
319 virtual void InternalWrite(HKEY hKey, const T& value) = 0;
321 public:
323 * Make the value type accessible to others.
326 using ValueT = T;
329 * Constructor.
330 * We use this instead of a default constructor because not all
331 * data types may provide an adequate default constructor.
333 CRegTypedBase(const T& def);
336 * Constructor.
337 * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
338 * \param def the default value used when the key does not exist or a read error occurred
339 * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
340 * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
341 * \param sam
343 CRegTypedBase(const typename Base::StringT& key, const T& def, bool force = FALSE, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
346 * Constructor.
347 * \param updateInterval time in msec between registry lookups caused by operator const T&
348 * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
349 * \param def the default value used when the key does not exist or a read error occurred
350 * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
351 * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
352 * \param sam
354 CRegTypedBase(DWORD updateInterval, const typename Base::StringT& key, const T& def, bool force = FALSE, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
357 * reads the assigned value from the registry. Use this method only if you think the registry
358 * value could have been altered without using the CRegDWORD object.
359 * \return the read value
361 void read(); ///< reads the value from the registry
362 void write(); ///< writes the value to the registry
364 bool exists(); ///< test whether registry entry exits
365 const T& defaultValue() const; ///< return the default passed to the constructor
368 * Data access.
371 operator const T&();
372 CRegTypedBase<T, Base>& operator=(const T& rhs);
375 // implement CRegTypedBase<> members
377 template<class T, class Base>
378 void CRegTypedBase<T, Base>::HandleAutoRefresh()
380 if (Base::m_read && (lookupInterval != DWORD(-1)))
382 ULONGLONG currentTime = GetTickCount64();
383 if ((currentTime < lastRead) || (currentTime > lastRead + lookupInterval))
384 Base::m_read = false;
388 template<class T, class Base>
389 CRegTypedBase<T, Base>::CRegTypedBase(const T& def)
390 : m_value(def)
391 , m_defaultvalue(def)
392 , lastRead(0)
393 , lookupInterval(static_cast<ULONGLONG>(-1))
397 template<class T, class Base>
398 CRegTypedBase<T, Base>::CRegTypedBase(const typename Base::StringT& key, const T& def, bool force, HKEY base, REGSAM sam)
399 : Base(key, force, base, sam)
400 , m_value(def)
401 , m_defaultvalue(def)
402 , lastRead(0)
403 , lookupInterval(static_cast<DWORD>(-1))
407 template<class T, class Base>
408 CRegTypedBase<T, Base>::CRegTypedBase(DWORD lookupInterval, const typename Base::StringT& key, const T& def, bool force, HKEY base, REGSAM sam)
409 : Base(key, force, base, sam)
410 , m_value(def)
411 , m_defaultvalue(def)
412 , lastRead(0)
413 , lookupInterval(lookupInterval)
417 template<class T, class Base>
418 void CRegTypedBase<T, Base>::read()
420 m_value = m_defaultvalue;
421 Base::m_exists = false;
423 HKEY hKey = nullptr;
424 if ((Base::m_lastError = RegOpenKeyEx(Base::m_base, Base::GetPlainString(Base::m_path), 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | Base::m_sam, &hKey)) == ERROR_SUCCESS)
426 T value = m_defaultvalue;
427 InternalRead(hKey, value);
429 if (Base::m_lastError == ERROR_SUCCESS)
431 Base::m_exists = true;
432 m_value = value;
435 Base::m_lastError = RegCloseKey(hKey);
438 Base::m_read = true;
439 lastRead = GetTickCount64();
442 template<class T, class Base>
443 void CRegTypedBase<T, Base>::write()
445 HKEY hKey = nullptr;
447 DWORD disp = 0;
448 if ((Base::m_lastError = RegCreateKeyEx(Base::m_base, Base::GetPlainString(Base::m_path), 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE | Base::m_sam, NULL, &hKey, &disp)) != ERROR_SUCCESS)
450 return;
453 InternalWrite(hKey, m_value);
454 if (Base::m_lastError == ERROR_SUCCESS)
456 Base::m_read = true;
457 Base::m_exists = true;
459 Base::m_lastError = RegCloseKey(hKey);
461 lastRead = GetTickCount64();
464 template<class T, class Base>
465 bool CRegTypedBase<T, Base>::exists()
467 if (!Base::m_read && (Base::m_lastError == ERROR_SUCCESS))
468 read();
470 return Base::m_exists;
473 template<class T, class Base>
474 const T& CRegTypedBase<T, Base>::defaultValue() const
476 return m_defaultvalue;
479 template<class T, class Base>
480 CRegTypedBase<T, Base>::operator const T&()
482 HandleAutoRefresh();
483 if ((Base::m_read) && (!Base::m_force))
485 Base::m_lastError = ERROR_SUCCESS;
487 else
489 read();
492 return m_value;
495 template<class T, class Base>
496 CRegTypedBase<T, Base>& CRegTypedBase<T, Base>::operator=(const T& d)
498 if (Base::m_read && (d == m_value) && !Base::m_force)
500 //no write to the registry required, its the same value
501 Base::m_lastError = ERROR_SUCCESS;
502 return *this;
504 m_value = d;
505 write();
506 return *this;
510 * \ingroup Utils
511 * DWORD value in registry. with this class you can use DWORD values in registry
512 * like normal DWORD variables in your program.
513 * Usage:
514 * in your header file, declare your registry DWORD variable:
515 * \code
516 * CRegDWORD regvalue;
517 * \endcode
518 * next initialize the variable e.g. in the constructor of your class:
519 * \code
520 * regvalue = CRegDWORD("Software\\Company\\SubKey\\MyValue", 100);
521 * \endcode
522 * this will set the registry value "MyValue" under HKEY_CURRENT_USER with path
523 * "Software\Company\SubKey" to the variable. If the key does not yet exist or
524 * an error occurred during read from the registry, a default
525 * value of 100 is used when accessing the variable.
526 * now the variable can be used like any other DWORD variable:
527 * \code
528 * regvalue = 200; //stores the value 200 in the registry
529 * int temp = regvalue + 300; //temp has value 500 now
530 * regvalue += 300; //now the registry has the value 500 too
531 * \endcode
532 * to avoid too much access to the registry the value is cached inside the object.
533 * once the value is read, no more read accesses to the registry will be made.
534 * this means the variable will contain a wrong value if the corresponding registry
535 * entry is changed by anything else than this variable! If you think that could happen
536 * then use
537 * \code
538 * regvalue.read();
539 * \endcode
540 * to force a refresh of the variable with the registry.
541 * a write to the registry is only made if the new value assigned with the variable
542 * is different than the last assigned value.
543 * to force a write use the method write();
544 * another option to force reads and writes to the registry is to specify TRUE as the
545 * third parameter in the constructor.
547 template<class Base>
548 class CRegDWORDCommon : public CRegTypedBase<DWORD, Base>
550 private:
552 * provide type-specific code to extract data from and write data to an open registry key.
555 void InternalRead(HKEY hKey, DWORD& value) override;
556 void InternalWrite(HKEY hKey, const DWORD& value) override;
558 public:
559 CRegDWORDCommon();
561 * Constructor.
562 * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
563 * \param def the default value used when the key does not exist or a read error occurred
564 * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
565 * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
566 * \param sam
568 CRegDWORDCommon(const typename Base::StringT& key, DWORD def = 0, bool force = false, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
569 CRegDWORDCommon(DWORD lookupInterval, const typename Base::StringT& key, DWORD def = 0, bool force = false, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
571 CRegDWORDCommon& operator=(DWORD rhs)
573 CRegTypedBase<DWORD, Base>::operator=(rhs);
574 return *this;
576 CRegDWORDCommon& operator+=(DWORD d) { return *this = *this + d; }
577 CRegDWORDCommon& operator-=(DWORD d) { return *this = *this - d; }
578 CRegDWORDCommon& operator*=(DWORD d) { return *this = *this * d; }
579 CRegDWORDCommon& operator/=(DWORD d) { return *this = *this / d; }
580 CRegDWORDCommon& operator%=(DWORD d) { return *this = *this % d; }
581 CRegDWORDCommon& operator<<=(DWORD d) { return *this = *this << d; }
582 CRegDWORDCommon& operator>>=(DWORD d) { return *this = *this >> d; }
583 CRegDWORDCommon& operator&=(DWORD d) { return *this = *this & d; }
584 CRegDWORDCommon& operator|=(DWORD d) { return *this = *this | d; }
585 CRegDWORDCommon& operator^=(DWORD d) { return *this = *this ^ d; }
588 // implement CRegDWORDCommon<> methods
590 template<class Base>
591 CRegDWORDCommon<Base>::CRegDWORDCommon()
592 : CRegTypedBase<DWORD, Base>(0)
596 template<class Base>
597 CRegDWORDCommon<Base>::CRegDWORDCommon(const typename Base::StringT& key, DWORD def, bool force, HKEY base, REGSAM sam)
598 : CRegTypedBase<DWORD, Base>(key, def, force, base, sam)
602 template<class Base>
603 CRegDWORDCommon<Base>::CRegDWORDCommon(DWORD lookupInterval, const typename Base::StringT& key, DWORD def, bool force, HKEY base, REGSAM sam)
604 : CRegTypedBase<DWORD, Base>(lookupInterval, key, def, force, base, sam)
608 template<class Base>
609 void CRegDWORDCommon<Base>::InternalRead(HKEY hKey, DWORD& value)
611 DWORD size = sizeof(value);
612 DWORD type = 0;
613 if ((Base::m_lastError = RegQueryValueEx(hKey, Base::GetPlainString(Base::m_key), nullptr, &type, reinterpret_cast<BYTE*>(&value), &size)) == ERROR_SUCCESS)
615 ASSERT(type == REG_DWORD);
619 template<class Base>
620 void CRegDWORDCommon<Base>::InternalWrite(HKEY hKey, const DWORD& value)
622 Base::m_lastError = RegSetValueEx(hKey, Base::GetPlainString(Base::m_key), 0, REG_DWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
625 template <class Base>
626 class CRegQWORDCommon : public CRegTypedBase<QWORD, Base>
628 private:
630 * provide type-specific code to extract data from and write data to an open registry key.
633 void InternalRead(HKEY hKey, QWORD& value) override;
634 void InternalWrite(HKEY hKey, const QWORD& value) override;
636 public:
637 CRegQWORDCommon();
639 * Constructor.
640 * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
641 * \param def the default value used when the key does not exist or a read error occurred
642 * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
643 * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
644 * \param sam
646 CRegQWORDCommon(const typename Base::StringT& key, QWORD def = 0, bool force = false, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
647 CRegQWORDCommon(QWORD lookupInterval, const typename Base::StringT& key, QWORD def = 0, bool force = false, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
649 CRegQWORDCommon& operator=(QWORD rhs)
651 CRegTypedBase<QWORD, Base>::operator=(rhs);
652 return *this;
654 CRegQWORDCommon& operator+=(QWORD d) { return *this = *this + d; }
655 CRegQWORDCommon& operator-=(QWORD d) { return *this = *this - d; }
656 CRegQWORDCommon& operator*=(QWORD d) { return *this = *this * d; }
657 CRegQWORDCommon& operator/=(QWORD d) { return *this = *this / d; }
658 CRegQWORDCommon& operator%=(QWORD d) { return *this = *this % d; }
659 CRegQWORDCommon& operator<<=(QWORD d) { return *this = *this << d; }
660 CRegQWORDCommon& operator>>=(QWORD d) { return *this = *this >> d; }
661 CRegQWORDCommon& operator&=(QWORD d) { return *this = *this & d; }
662 CRegQWORDCommon& operator|=(QWORD d) { return *this = *this | d; }
663 CRegQWORDCommon& operator^=(QWORD d) { return *this = *this ^ d; }
666 // implement CRegQWORDCommon<> methods
668 template <class Base>
669 CRegQWORDCommon<Base>::CRegQWORDCommon()
670 : CRegTypedBase<QWORD, Base>(0)
674 template <class Base>
675 CRegQWORDCommon<Base>::CRegQWORDCommon(const typename Base::StringT& key, QWORD def, bool force, HKEY base, REGSAM sam)
676 : CRegTypedBase<QWORD, Base>(key, def, force, base, sam)
680 template <class Base>
681 CRegQWORDCommon<Base>::CRegQWORDCommon(QWORD lookupInterval, const typename Base::StringT& key, QWORD def, bool force, HKEY base, REGSAM sam)
682 : CRegTypedBase<QWORD, Base>(lookupInterval, key, def, force, base, sam)
686 template <class Base>
687 void CRegQWORDCommon<Base>::InternalRead(HKEY hKey, QWORD& value)
689 DWORD size = sizeof(value);
690 DWORD type = 0;
691 if ((Base::m_lastError = RegQueryValueEx(hKey, Base::GetPlainString(Base::m_key), nullptr, &type, reinterpret_cast<BYTE*>(&value), &size)) == ERROR_SUCCESS)
693 ASSERT(type == REG_QWORD);
697 template <class Base>
698 void CRegQWORDCommon<Base>::InternalWrite(HKEY hKey, const QWORD& value)
700 Base::m_lastError = RegSetValueEx(hKey, Base::GetPlainString(Base::m_key), 0, REG_QWORD, reinterpret_cast<const BYTE*>(&value), sizeof(value));
704 * \ingroup Utils
705 * CString value in registry. with this class you can use CString values in registry
706 * almost like normal CString variables in your program.
707 * Usage:
708 * in your header file, declare your registry CString variable:
709 * \code
710 * CRegString regvalue;
711 * \endcode
712 * next initialize the variable e.g. in the constructor of your class:
713 * \code
714 * regvalue = CRegString("Software\\Company\\SubKey\\MyValue", "default");
715 * \endcode
716 * this will set the registry value "MyValue" under HKEY_CURRENT_USER with path
717 * "Software\Company\SubKey" to the variable. If the key does not yet exist or
718 * an error occurred during read from the registry, a default
719 * value of "default" is used when accessing the variable.
720 * now the variable can be used like any other CString variable:
721 * \code
722 * regvalue = "some string"; //stores the value "some string" in the registry
723 * CString temp = regvalue + "!!"; //temp has value "some string!!" now
724 * \endcode
725 * to use the normal methods of the CString class, just typecast the CRegString to a CString
726 * and do whatever you want with the string:
727 * \code
728 * static_cast<CString>(regvalue).GetLength();
729 * static_cast<CString>(regvalue).Trim();
730 * \endcode
731 * please be aware that in the second line the change in the string won't be written
732 * to the registry! To force a write use the write() method. A write() is only needed
733 * if you change the String with Methods not overloaded by CRegString.
734 * to avoid too much access to the registry the value is cached inside the object.
735 * once the value is read, no more read accesses to the registry will be made.
736 * this means the variable will contain a wrong value if the corresponding registry
737 * entry is changed by anything else than this variable! If you think that could happen
738 * then use
739 * \code
740 * regvalue.read();
741 * \endcode
742 * to force a refresh of the variable with the registry.
743 * a write to the registry is only made if the new value assigned with the variable
744 * is different than the last assigned value.
745 * to force a write use the method write();
746 * another option to force reads and writes to the registry is to specify TRUE as the
747 * third parameter in the constructor.
749 template<class Base>
750 class CRegStringCommon : public CRegTypedBase<typename Base::StringT, Base>
752 private:
754 * provide type-specific code to extract data from and write data to an open registry key.
757 void InternalRead(HKEY hKey, typename Base::StringT& value) override;
758 void InternalWrite(HKEY hKey, const typename Base::StringT& value) override;
760 public:
761 CRegStringCommon();
763 * Constructor.
764 * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
765 * \param def the default value used when the key does not exist or a read error occurred
766 * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
767 * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
768 * \param sam
770 CRegStringCommon(const typename Base::StringT& key, const typename Base::StringT& def = L"", bool force = false, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
771 CRegStringCommon(DWORD lookupInterval, const typename Base::StringT& key, const typename Base::StringT& def = L"", bool force = false, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
773 CRegStringCommon& operator=(const typename Base::StringT& rhs)
775 CRegTypedBase<Base::StringT, Base>::operator=(rhs);
776 return *this;
778 CRegStringCommon& operator+=(const typename Base::StringT& s) { return *this = (typename Base::StringT)*this + s; }
781 // implement CRegDWORD<> methods
783 template<class Base>
784 CRegStringCommon<Base>::CRegStringCommon()
785 : CRegTypedBase<typename Base::StringT, Base>(typename Base::StringT())
789 template<class Base>
790 CRegStringCommon<Base>::CRegStringCommon(const typename Base::StringT& key, const typename Base::StringT& def, bool force, HKEY base, REGSAM sam)
791 : CRegTypedBase<typename Base::StringT, Base>(key, def, force, base, sam)
795 template<class Base>
796 CRegStringCommon<Base>::CRegStringCommon(DWORD lookupInterval, const typename Base::StringT& key, const typename Base::StringT& def, bool force, HKEY base, REGSAM sam)
797 : CRegTypedBase<typename Base::StringT, Base>(lookupInterval, key, def, force, base, sam)
801 template<class Base>
802 void CRegStringCommon<Base>::InternalRead(HKEY hKey, typename Base::StringT& value)
804 DWORD size = 0;
805 DWORD type = 0;
806 Base::m_lastError = RegQueryValueEx(hKey, Base::GetPlainString(Base::m_key), nullptr, &type, nullptr, &size);
808 if (Base::m_lastError == ERROR_SUCCESS)
810 auto pStr = std::make_unique<wchar_t[]>(size);
811 if ((Base::m_lastError = RegQueryValueEx(hKey, Base::GetPlainString(Base::m_key), nullptr, &type, reinterpret_cast<BYTE*>(pStr.get()), &size)) == ERROR_SUCCESS)
813 ASSERT(type == REG_SZ || type == REG_EXPAND_SZ);
814 value = Base::StringT(pStr.get());
819 template<class Base>
820 void CRegStringCommon<Base>::InternalWrite(HKEY hKey, const typename Base::StringT& value)
822 Base::m_lastError = RegSetValueEx(hKey, Base::GetPlainString(Base::m_key), 0, REG_SZ, reinterpret_cast<const BYTE*>(static_cast<LPCWSTR>(Base::GetPlainString(value))), (Base::GetLength(value) + 1) * sizeof (wchar_t));
826 * \ingroup Utils
827 * CRect value in registry. with this class you can use CRect values in registry
828 * almost like normal CRect variables in your program.
829 * Usage:
830 * in your header file, declare your registry CString variable:
831 * \code
832 * CRegRect regvalue;
833 * \endcode
834 * next initialize the variable e.g. in the constructor of your class:
835 * \code
836 * regvalue = CRegRect("Software\\Company\\SubKey\\MyValue", CRect(100,100,200,200));
837 * \endcode
838 * this will set the registry value "MyValue" under HKEY_CURRENT_USER with path
839 * "Software\Company\SubKey" to the variable. If the key does not yet exist or
840 * an error occurred during read from the registry, a default
841 * value of 100,100,200,200 is used when accessing the variable.
842 * now the variable can be used like any other CRect variable:
843 * \code
844 * regvalue = CRect(40,20,300,500); //stores the value in the registry
845 * CRect temp = regvalue + CPoint(1,1);
846 * temp |= CSize(5,5);
847 * \endcode
848 * to use the normal methods of the CRect class, just typecast the CRegRect to a CRect
849 * and do whatever you want with the rect:
850 * \code
851 * static_cast<CRect>(regvalue).MoveToX(100);
852 * static_cast<CRect>(regvalue).DeflateRect(10, 10);
853 * \endcode
854 * please be aware that in the second line the change in the CRect won't be written
855 * to the registry! To force a write use the write() method. A write() is only needed
856 * if you change the CRect with Methods not overloaded by CRegRect.
857 * to avoid too much access to the registry the value is cached inside the object.
858 * once the value is read, no more read accesses to the registry will be made.
859 * this means the variable will contain a wrong value if the corresponding registry
860 * entry is changed by anything else than this variable! If you think that could happen
861 * then use
862 * \code
863 * regvalue.read();
864 * \endcode
865 * to force a refresh of the variable with the registry.
866 * a write to the registry is only made if the new value assigned with the variable
867 * is different than the last assigned value.
868 * to force a write use the method write();
869 * another option to force reads and writes to the registry is to specify TRUE as the
870 * third parameter in the constructor.
873 #ifdef __ATLTYPES_H__ // defines CRect
874 class CRegRect : public CRegTypedBase<CRect, CRegBase>
876 private:
878 * provide type-specific code to extract data from and write data to an open registry key.
881 void InternalRead(HKEY hKey, CRect& value) override;
882 void InternalWrite(HKEY hKey, const CRect& value) override;
884 public:
885 CRegRect();
887 * Constructor.
888 * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
889 * \param def the default value used when the key does not exist or a read error occurred
890 * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
891 * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
893 CRegRect(const CString& key, const CRect& def = CRect(), bool force = false, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
894 ~CRegRect() = default;
896 CRegRect& operator=(const CRect& rhs)
898 CRegTypedBase<CRect, CRegBase>::operator=(rhs);
899 return *this;
901 operator LPCRECT() { return (LPCRECT)(CRect) * this; }
902 operator LPRECT() { return (LPRECT)(CRect) * this; }
903 CRegRect& operator+=(POINT r) { return *this = (CRect) * this + r; }
904 CRegRect& operator+=(SIZE r) { return *this = (CRect) * this + r; }
905 CRegRect& operator+=(LPCRECT r) { return *this = (CRect) * this + r; }
906 CRegRect& operator-=(POINT r) { return *this = (CRect) * this - r; }
907 CRegRect& operator-=(SIZE r) { return *this = (CRect) * this - r; }
908 CRegRect& operator-=(LPCRECT r) { return *this = (CRect) * this - r; }
910 CRegRect& operator&=(const CRect& r) { return *this = r & *this; }
911 CRegRect& operator|=(const CRect& r) { return *this = r | *this; }
913 #endif
916 * \ingroup Utils
917 * CPoint value in registry. with this class you can use CPoint values in registry
918 * almost like normal CPoint variables in your program.
919 * Usage:
920 * in your header file, declare your registry CPoint variable:
921 * \code
922 * CRegPoint regvalue;
923 * \endcode
924 * next initialize the variable e.g. in the constructor of your class:
925 * \code
926 * regvalue = CRegPoint("Software\\Company\\SubKey\\MyValue", CPoint(100,100));
927 * \endcode
928 * this will set the registry value "MyValue" under HKEY_CURRENT_USER with path
929 * "Software\Company\SubKey" to the variable. If the key does not yet exist or
930 * an error occurred during read from the registry, a default
931 * value of 100,100 is used when accessing the variable.
932 * now the variable can be used like any other CPoint variable:
933 * \code
934 * regvalue = CPoint(40,20); //stores the value in the registry
935 * CPoint temp = regvalue + CPoint(1,1);
936 * temp += CSize(5,5);
937 * \endcode
938 * to use the normal methods of the CPoint class, just typecast the CRegPoint to a CPoint
939 * and do whatever you want with the point:
940 * \code
941 * static_cast<CRect>(regvalue).Offset(100, 10);
942 * \endcode
943 * please be aware that in the above example the change in the CPoint won't be written
944 * to the registry! To force a write use the write() method. A write() is only needed
945 * if you change the CPoint with Methods not overloaded by CRegPoint.
946 * to avoid too much access to the registry the value is cached inside the object.
947 * once the value is read, no more read accesses to the registry will be made.
948 * this means the variable will contain a wrong value if the corresponding registry
949 * entry is changed by anything else than this variable! If you think that could happen
950 * then use
951 * \code
952 * regvalue.read();
953 * \endcode
954 * to force a refresh of the variable with the registry.
955 * a write to the registry is only made if the new value assigned with the variable
956 * is different than the last assigned value.
957 * to force a write use the method write();
958 * another option to force reads and writes to the registry is to specify TRUE as the
959 * third parameter in the constructor.
962 #ifdef __ATLTYPES_H__ // defines CPoint
963 class CRegPoint : public CRegTypedBase<CPoint, CRegBase>
965 private:
967 * provide type-specific code to extract data from and write data to an open registry key.
970 void InternalRead(HKEY hKey, CPoint& value) override;
971 void InternalWrite(HKEY hKey, const CPoint& value) override;
973 public:
974 CRegPoint();
976 * Constructor.
977 * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
978 * \param def the default value used when the key does not exist or a read error occurred
979 * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
980 * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
982 CRegPoint(const CString& key, const CPoint& def = CPoint(), bool force = false, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
983 ~CRegPoint() = default;
985 CRegPoint& operator=(const CPoint& rhs)
987 CRegTypedBase<CPoint, CRegBase>::operator=(rhs);
988 return *this;
990 CRegPoint& operator+=(CPoint p) { return *this = p + *this; }
991 CRegPoint& operator-=(CPoint p) { return *this = p - *this; }
993 #endif
996 * \ingroup Utils
997 * Manages a registry key (not a value). Provides methods to create and remove the
998 * key and to query the list of values and sub keys.
1001 #ifdef __AFXCOLL_H__ // defines CStringList
1002 class CRegistryKey
1004 public: //methods
1006 * Constructor.
1007 * \param key the path to the key, including the key. example: "Software\\Company\\SubKey"
1008 * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
1010 CRegistryKey(const CString& key, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
1011 ~CRegistryKey();
1014 * Creates the registry key if it does not already exist.
1015 * \return ERROR_SUCCESS or an nonzero error code. Use FormatMessage() to get an error description.
1017 DWORD createKey();
1019 * Removes the whole registry key including all values. So if you set the registry
1020 * entry to be HKCU\Software\Company\Product\key there will only be
1021 * HKCU\Software\Company\Product key in the registry.
1022 * \return ERROR_SUCCESS or an nonzero error code. Use FormatMessage() to get an error description.
1024 DWORD removeKey();
1026 bool getValues(CStringList& values); ///< returns the list of values
1027 bool getSubKeys(CStringList& subkeys); ///< returns the list of sub keys
1029 public: //members
1030 HKEY m_base = nullptr; ///< handle to the registry base
1031 HKEY m_hKey = nullptr; ///< handle to the open registry key
1032 REGSAM m_sam = 0; ///< the security attributes to pass to the registry command
1033 CString m_path; ///< the path to the key
1035 #endif
1037 #ifdef _MAP_
1038 template<class T>
1039 class CKeyList
1041 private:
1042 /// constructor parameters
1044 typename T::StringT key;
1045 typename T::ValueT defaultValue;
1046 HKEY base;
1048 /// per-index defaults
1050 using TDefaults = std::map<int, typename T::ValueT>;
1051 TDefaults defaults;
1053 /// the indices accessed so far
1055 using TElements = std::map<int, T*>;
1056 mutable TElements elements;
1058 /// auto-insert
1060 const typename T::ValueT& GetDefault(int index) const;
1061 T& GetAt(int index) const;
1063 public:
1064 /// construction
1066 CKeyList(const typename T::StringT& key, const typename T::ValueT& defaultValue, HKEY base = HKEY_CURRENT_USER)
1067 : key(key)
1068 , defaultValue(defaultValue)
1069 , base(base)
1073 /// destruction: delete all elements
1075 ~CKeyList()
1077 for (auto iter = elements.begin(), end = elements.end(); iter != end; ++iter)
1079 delete iter->second;
1083 /// data access
1085 const T& operator[](int index) const
1087 return GetAt(index);
1090 T& operator[](int index)
1092 return GetAt(index);
1095 const TDefaults& GetDefaults() const
1097 return defaults;
1100 TDefaults& GetDefaults()
1102 return defaults;
1105 const typename T::ValueT& GetDefault() const
1107 return defaultValue;
1111 /// auto-insert
1113 template<class T>
1114 const typename T::ValueT& CKeyList<T>::GetDefault(int index) const
1116 auto iter = defaults.find(index);
1117 return iter == defaults.end() ? defaultValue : iter->second;
1120 template<class T>
1121 T& CKeyList<T>::GetAt(int index) const
1123 auto iter = elements.find(index);
1124 if (iter == elements.end())
1126 wchar_t buffer[10];
1127 _itow_s(index, buffer, 10);
1128 typename T::StringT indexKey = key + L'\\' + buffer;
1130 T* newElement = new T(indexKey, GetDefault(index), false, base);
1131 iter = elements.emplace(index, newElement).first;
1134 return *iter->second;
1137 #endif
1140 * Instantiate templates for common (data type, string type) combinations.
1143 #ifdef __CSTRINGT_H__
1144 using CRegDWORD = CRegDWORDCommon<CRegBase>;
1145 using CRegQWORD = CRegQWORDCommon<CRegBase>;
1146 using CRegString = CRegStringCommon<CRegBase>;
1148 #ifdef _MAP_
1149 using CRegDWORDList = CKeyList<CRegDWORD>;
1150 using CRegQWORDList = CKeyList<CRegQWORD>;
1151 using CRegStringList = CKeyList<CRegString>;
1152 #endif
1153 #endif
1155 using CRegStdDWORD = CRegDWORDCommon<CRegStdBase>;
1156 using CRegStdQWORD = CRegQWORDCommon<CRegStdBase>;
1157 using CRegStdString = CRegStringCommon<CRegStdBase>;
1159 #ifdef _MAP_
1160 using CRegStdDWORDList = CKeyList<CRegStdDWORD>;
1161 using CRegStdQWORDList = CKeyList<CRegStdQWORD>;
1162 using CRegStdStringList = CKeyList<CRegStdString>;
1163 #endif