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.
24 #include "FormatMessageWrapper.h"
31 typedef unsigned __int64 QWORD
, *PQWORD
;
36 * Base class for the registry classes.
39 * - win98 or later, win2k or later, win95 with IE4 or later, winNT4 with IE4 or later
40 * - import library Shlwapi.lib
48 * String type specific operations.
51 virtual LPCWSTR
GetPlainString(const S
& s
) const = 0;
52 virtual DWORD
GetLength(const S
& s
) const = 0;
55 virtual ~CRegBaseCommon() = default;
58 /** Default 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.
68 CRegBaseCommon(const S
& key
, bool force
, HKEY base
= HKEY_CURRENT_USER
, REGSAM sam
= 0);
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.
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.
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
));
95 /// get failure info for last operation
97 LONG
GetLastError() const
102 /// used in subclass templates to specify the correct string type
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
122 CRegBaseCommon
<S
>::CRegBaseCommon()
123 : m_base(HKEY_CURRENT_USER
)
126 , m_lastError(ERROR_SUCCESS
)
135 CRegBaseCommon
<S
>::CRegBaseCommon(const S
& key
, bool force
, HKEY base
, REGSAM sam
)
139 , m_lastError(ERROR_SUCCESS
)
148 DWORD CRegBaseCommon
<S
>::removeKey()
154 RegOpenKeyEx(m_base
, GetPlainString(m_path
), 0, KEY_WRITE
| m_sam
, &hKey
);
155 auto ret
= SHDeleteKey(m_base
, GetPlainString(m_path
));
161 LONG CRegBaseCommon
<S
>::removeValue()
167 RegOpenKeyEx(m_base
, GetPlainString(m_path
), 0, KEY_WRITE
| m_sam
, &hKey
);
168 auto ret
= RegDeleteValue(hKey
, GetPlainString(m_key
));
175 * Base class for MFC type registry classes.
178 #ifdef __CSTRINGT_H__
179 class CRegBase
: public CRegBaseCommon
<CString
>
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(); }
190 /** Default 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
209 sTemp
.FormatMessage(IDS_REG_ERROR
, static_cast<LPCWSTR
>(m_key
), static_cast<LPCWSTR
>(error
));
220 * Base class for STL string type registry classes.
223 class CRegStdBase
: public CRegBaseCommon
<std::wstring
>
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()); }
234 /** Default 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.
244 CRegStdBase(const std::wstring
& key
, bool force
, HKEY base
= HKEY_CURRENT_USER
, REGSAM sam
= 0);
249 * DWORD value in registry. with this class you can use DWORD values in registry
250 * like normal DWORD variables in your program.
252 * in your header file, declare your registry DWORD variable:
254 * CRegDWORD regvalue;
256 * next initialize the variable e.g. in the constructor of your class:
258 * regvalue = CRegDWORD("Software\\Company\\SubKey\\MyValue", 100);
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:
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
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
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
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
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;
323 * Make the value type accessible to others.
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
);
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.
343 CRegTypedBase(const typename
Base::StringT
& key
, const T
& def
, bool force
= FALSE
, HKEY base
= HKEY_CURRENT_USER
, REGSAM sam
= 0);
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.
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
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
)
391 , m_defaultvalue(def
)
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
)
401 , m_defaultvalue(def
)
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
)
411 , m_defaultvalue(def
)
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;
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;
435 Base::m_lastError
= RegCloseKey(hKey
);
439 lastRead
= GetTickCount64();
442 template<class T
, class Base
>
443 void CRegTypedBase
<T
, Base
>::write()
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
)
453 InternalWrite(hKey
, m_value
);
454 if (Base::m_lastError
== ERROR_SUCCESS
)
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
))
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
&()
483 if ((Base::m_read
) && (!Base::m_force
))
485 Base::m_lastError
= ERROR_SUCCESS
;
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
;
511 * DWORD value in registry. with this class you can use DWORD values in registry
512 * like normal DWORD variables in your program.
514 * in your header file, declare your registry DWORD variable:
516 * CRegDWORD regvalue;
518 * next initialize the variable e.g. in the constructor of your class:
520 * regvalue = CRegDWORD("Software\\Company\\SubKey\\MyValue", 100);
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:
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
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
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.
548 class CRegDWORDCommon
: public CRegTypedBase
<DWORD
, Base
>
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
;
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.
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
);
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
591 CRegDWORDCommon
<Base
>::CRegDWORDCommon()
592 : CRegTypedBase
<DWORD
, Base
>(0)
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
)
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
)
609 void CRegDWORDCommon
<Base
>::InternalRead(HKEY hKey
, DWORD
& value
)
611 DWORD size
= sizeof(value
);
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
);
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
>
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
;
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.
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
);
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
);
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
));
705 * CString value in registry. with this class you can use CString values in registry
706 * almost like normal CString variables in your program.
708 * in your header file, declare your registry CString variable:
710 * CRegString regvalue;
712 * next initialize the variable e.g. in the constructor of your class:
714 * regvalue = CRegString("Software\\Company\\SubKey\\MyValue", "default");
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:
722 * regvalue = "some string"; //stores the value "some string" in the registry
723 * CString temp = regvalue + "!!"; //temp has value "some string!!" now
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:
728 * static_cast<CString>(regvalue).GetLength();
729 * static_cast<CString>(regvalue).Trim();
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
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.
750 class CRegStringCommon
: public CRegTypedBase
<typename
Base::StringT
, Base
>
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
;
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.
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
);
778 CRegStringCommon
& operator+=(const typename
Base::StringT
& s
) { return *this = (typename
Base::StringT
)*this + s
; }
781 // implement CRegDWORD<> methods
784 CRegStringCommon
<Base
>::CRegStringCommon()
785 : CRegTypedBase
<typename
Base::StringT
, Base
>(typename
Base::StringT())
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
)
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
)
802 void CRegStringCommon
<Base
>::InternalRead(HKEY hKey
, typename
Base::StringT
& value
)
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());
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));
827 * CRect value in registry. with this class you can use CRect values in registry
828 * almost like normal CRect variables in your program.
830 * in your header file, declare your registry CString variable:
834 * next initialize the variable e.g. in the constructor of your class:
836 * regvalue = CRegRect("Software\\Company\\SubKey\\MyValue", CRect(100,100,200,200));
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:
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);
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:
851 * static_cast<CRect>(regvalue).MoveToX(100);
852 * static_cast<CRect>(regvalue).DeflateRect(10, 10);
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
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
>
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
;
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
);
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; }
917 * CPoint value in registry. with this class you can use CPoint values in registry
918 * almost like normal CPoint variables in your program.
920 * in your header file, declare your registry CPoint variable:
922 * CRegPoint regvalue;
924 * next initialize the variable e.g. in the constructor of your class:
926 * regvalue = CRegPoint("Software\\Company\\SubKey\\MyValue", CPoint(100,100));
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:
934 * regvalue = CPoint(40,20); //stores the value in the registry
935 * CPoint temp = regvalue + CPoint(1,1);
936 * temp += CSize(5,5);
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:
941 * static_cast<CRect>(regvalue).Offset(100, 10);
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
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
>
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
;
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
);
990 CRegPoint
& operator+=(CPoint p
) { return *this = p
+ *this; }
991 CRegPoint
& operator-=(CPoint p
) { return *this = p
- *this; }
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
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);
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.
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.
1026 bool getValues(CStringList
& values
); ///< returns the list of values
1027 bool getSubKeys(CStringList
& subkeys
); ///< returns the list of sub keys
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
1042 /// constructor parameters
1044 typename
T::StringT key
;
1045 typename
T::ValueT defaultValue
;
1048 /// per-index defaults
1050 using TDefaults
= std::map
<int, typename
T::ValueT
>;
1053 /// the indices accessed so far
1055 using TElements
= std::map
<int, T
*>;
1056 mutable TElements elements
;
1060 const typename
T::ValueT
& GetDefault(int index
) const;
1061 T
& GetAt(int index
) const;
1066 CKeyList(const typename
T::StringT
& key
, const typename
T::ValueT
& defaultValue
, HKEY base
= HKEY_CURRENT_USER
)
1068 , defaultValue(defaultValue
)
1073 /// destruction: delete all elements
1077 for (auto iter
= elements
.begin(), end
= elements
.end(); iter
!= end
; ++iter
)
1079 delete iter
->second
;
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
1100 TDefaults
& GetDefaults()
1105 const typename
T::ValueT
& GetDefault() const
1107 return defaultValue
;
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
;
1121 T
& CKeyList
<T
>::GetAt(int index
) const
1123 auto iter
= elements
.find(index
);
1124 if (iter
== elements
.end())
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
;
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
>;
1149 using CRegDWORDList
= CKeyList
<CRegDWORD
>;
1150 using CRegQWORDList
= CKeyList
<CRegQWORD
>;
1151 using CRegStringList
= CKeyList
<CRegString
>;
1155 using CRegStdDWORD
= CRegDWORDCommon
<CRegStdBase
>;
1156 using CRegStdQWORD
= CRegQWORDCommon
<CRegStdBase
>;
1157 using CRegStdString
= CRegStringCommon
<CRegStdBase
>;
1160 using CRegStdDWORDList
= CKeyList
<CRegStdDWORD
>;
1161 using CRegStdQWORDList
= CKeyList
<CRegStdQWORD
>;
1162 using CRegStdStringList
= CKeyList
<CRegStdString
>;