/win32/shellext/registry.h

https://bitbucket.org/tortoisehg/hgtk/ · C Header · 1089 lines · 508 code · 159 blank · 422 comment · 25 complexity · fdd138c1810c150747ccaa33700462dd MD5 · raw file

  1. // TortoiseSVN - a Windows shell extension for easy version control
  2. // Copyright (C) 2003-2009 - TortoiseSVN
  3. // This program is free software; you can redistribute it and/or
  4. // modify it under the terms of the GNU General Public License
  5. // as published by the Free Software Foundation; either version 2
  6. // of the License, or (at your option) any later version.
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU General Public License for more details.
  11. // You should have received a copy of the GNU General Public License
  12. // along with this program; if not, write to the Free Software Foundation,
  13. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  14. //
  15. #pragma once
  16. #include <string>
  17. #include <memory>
  18. #include "shlwapi.h"
  19. #include "tstring.h"
  20. #include "auto_buffer.h"
  21. #ifndef ASSERT
  22. #define ASSERT(x)
  23. #endif
  24. /**
  25. * \ingroup Utils
  26. * Base class for the registry classes.
  27. *
  28. * \par requirements
  29. * - win98 or later, win2k or later, win95 with IE4 or later, winNT4 with IE4 or later
  30. * - import library Shlwapi.lib
  31. */
  32. template<class S>
  33. class CRegBaseCommon
  34. {
  35. protected:
  36. /**
  37. * String type specific operations.
  38. */
  39. virtual LPCTSTR GetPlainString (const S& s) const = 0;
  40. virtual DWORD GetLength (const S& s) const = 0;
  41. public: //methods
  42. /** Default constructor.
  43. */
  44. CRegBaseCommon();
  45. /**
  46. * Constructor.
  47. * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
  48. * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
  49. * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
  50. */
  51. CRegBaseCommon(const S& key, bool force, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
  52. /**
  53. * Removes the whole registry key including all values. So if you set the registry
  54. * entry to be HKCU\Software\Company\Product\key\value there will only be
  55. * HKCU\Software\Company\Product key in the registry.
  56. * \return ERROR_SUCCESS or an nonzero error code. Use FormatMessage() to get an error description.
  57. */
  58. DWORD removeKey();
  59. /**
  60. * Removes the value of the registry object. If you set the registry entry to
  61. * be HKCU\Software\Company\Product\key\value there will only be
  62. * HKCU\Software\Company\Product\key\ in the registry.
  63. * \return ERROR_SUCCESS or an nonzero error code. Use FormatMessage() to get an error description.
  64. */
  65. LONG removeValue();
  66. /**
  67. * Returns the string of the last error occurred.
  68. */
  69. virtual S getErrorString()
  70. {
  71. LPVOID lpMsgBuf;
  72. FormatMessage(
  73. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  74. FORMAT_MESSAGE_FROM_SYSTEM |
  75. FORMAT_MESSAGE_IGNORE_INSERTS,
  76. NULL,
  77. LastError,
  78. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  79. (LPTSTR) &lpMsgBuf,
  80. 0, NULL );
  81. return (LPCTSTR)lpMsgBuf;
  82. };
  83. /// get failure info for last operation
  84. LONG GetLastError() const
  85. {
  86. return LastError;
  87. }
  88. /// used in subclass templates to specify the correct string type
  89. typedef S StringT;
  90. protected:
  91. //members
  92. HKEY m_base; ///< handle to the registry base
  93. S m_key; ///< the name of the value
  94. S m_path; ///< the path to the key
  95. LONG LastError; ///< the value of the last error occurred
  96. REGSAM m_sam; ///< the security attributes to pass to the registry command
  97. bool m_read; ///< indicates if the value has already been read from the registry
  98. bool m_force; ///< indicates if no cache should be used, i.e. always read and write directly from registry
  99. bool m_exists; ///< true, if the registry actually exists
  100. };
  101. // implement CRegBaseCommon<> members
  102. template<class S>
  103. CRegBaseCommon<S>::CRegBaseCommon()
  104. : m_base (HKEY_CURRENT_USER)
  105. , m_key()
  106. , m_path()
  107. , LastError (ERROR_SUCCESS)
  108. , m_sam (0)
  109. , m_read (false)
  110. , m_force (false)
  111. , m_exists (false)
  112. {
  113. }
  114. template<class S>
  115. CRegBaseCommon<S>::CRegBaseCommon (const S& key, bool force, HKEY base, REGSAM sam)
  116. : m_base (base)
  117. , m_key (key)
  118. , m_path()
  119. , LastError (ERROR_SUCCESS)
  120. , m_sam (sam)
  121. , m_read (false)
  122. , m_force (force)
  123. , m_exists (false)
  124. {
  125. }
  126. template<class S>
  127. DWORD CRegBaseCommon<S>::removeKey()
  128. {
  129. m_exists = false;
  130. m_read = true;
  131. HKEY hKey = NULL;
  132. RegOpenKeyEx (m_base, GetPlainString (m_path), 0, KEY_WRITE|m_sam, &hKey);
  133. return SHDeleteKey(m_base, GetPlainString (m_path));
  134. }
  135. template<class S>
  136. LONG CRegBaseCommon<S>::removeValue()
  137. {
  138. m_exists = false;
  139. m_read = true;
  140. HKEY hKey = NULL;
  141. RegOpenKeyEx(m_base, GetPlainString (m_path), 0, KEY_WRITE|m_sam, &hKey);
  142. return RegDeleteValue(hKey, GetPlainString (m_key));
  143. }
  144. /**
  145. * \ingroup Utils
  146. * Base class for MFC type registry classes.
  147. */
  148. #ifdef __CSTRINGT_H__
  149. class CRegBase : public CRegBaseCommon<CString>
  150. {
  151. protected:
  152. /**
  153. * String type specific operations.
  154. */
  155. virtual LPCTSTR GetPlainString (const CString& s) const {return (LPCTSTR)s;}
  156. virtual DWORD GetLength (const CString& s) const {return s.GetLength();}
  157. public: //methods
  158. /** Default constructor.
  159. */
  160. CRegBase();
  161. /**
  162. * Constructor.
  163. * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
  164. * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
  165. * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
  166. */
  167. CRegBase(const CString& key, bool force, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
  168. /**
  169. * Returns the string of the last error occurred.
  170. */
  171. CString getErrorString()
  172. {
  173. CString error = CRegBaseCommon<CString>::getErrorString();
  174. #if defined IDS_REG_ERROR
  175. CString sTemp;
  176. sTemp.Format(IDS_REG_ERROR, (LPCTSTR)m_key, (LPCTSTR)error);
  177. return sTemp;
  178. #else
  179. return error;
  180. #endif
  181. };
  182. };
  183. #endif
  184. /**
  185. * \ingroup Utils
  186. * Base class for STL string type registry classes.
  187. */
  188. class CRegStdBase : public CRegBaseCommon<tstring>
  189. {
  190. protected:
  191. /**
  192. * String type specific operations.
  193. */
  194. virtual LPCTSTR GetPlainString (const tstring& s) const {return s.c_str();}
  195. virtual DWORD GetLength (const tstring& s) const {return static_cast<DWORD>(s.size());}
  196. public: //methods
  197. /** Default constructor.
  198. */
  199. CRegStdBase();
  200. /**
  201. * Constructor.
  202. * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
  203. * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
  204. * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
  205. */
  206. CRegStdBase(const tstring& key, bool force, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
  207. };
  208. /**
  209. * \ingroup Utils
  210. * DWORD value in registry. with this class you can use DWORD values in registry
  211. * like normal DWORD variables in your program.
  212. * Usage:
  213. * in your header file, declare your registry DWORD variable:
  214. * \code
  215. * CRegDWORD regvalue;
  216. * \endcode
  217. * next initialize the variable e.g. in the constructor of your class:
  218. * \code
  219. * regvalue = CRegDWORD("Software\\Company\\SubKey\\MyValue", 100);
  220. * \endcode
  221. * this will set the registry value "MyValue" under HKEY_CURRENT_USER with path
  222. * "Software\Company\SubKey" to the variable. If the key does not yet exist or
  223. * an error occurred during read from the registry, a default
  224. * value of 100 is used when accessing the variable.
  225. * now the variable can be used like any other DWORD variable:
  226. * \code
  227. * regvalue = 200; //stores the value 200 in the registry
  228. * int temp = regvalue + 300; //temp has value 500 now
  229. * regvalue += 300; //now the registry has the value 500 too
  230. * \endcode
  231. * to avoid too much access to the registry the value is cached inside the object.
  232. * once the value is read, no more read accesses to the registry will be made.
  233. * this means the variable will contain a wrong value if the corresponding registry
  234. * entry is changed by anything else than this variable! If you think that could happen
  235. * then use
  236. * \code
  237. * regvalue.read();
  238. * \endcode
  239. * to force a refresh of the variable with the registry.
  240. * a write to the registry is only made if the new value assigned with the variable
  241. * is different than the last assigned value.
  242. * to force a write use the method write();
  243. * another option to force reads and writes to the registry is to specify TRUE as the
  244. * third parameter in the constructor.
  245. */
  246. template<class T, class Base>
  247. class CRegTypedBase : public Base
  248. {
  249. private:
  250. T m_value; ///< the cached value of the registry
  251. T m_defaultvalue; ///< the default value to use
  252. /**
  253. * time stamp of the last registry lookup, i.e \ref read() call
  254. */
  255. DWORD lastRead;
  256. /**
  257. * \ref read() will be called, if \ref lastRead differs from the
  258. * current time stamp by more than this.
  259. * (DWORD)(-1) -> no automatic refresh.
  260. */
  261. DWORD lookupInterval;
  262. /**
  263. * Check time stamps etc.
  264. * If the current data is out-dated, reset the \ref m_read flag.
  265. */
  266. void HandleAutoRefresh();
  267. /**
  268. * sub-classes must provide type-specific code to extract data from
  269. * and write data to an open registry key.
  270. */
  271. virtual void InternalRead (HKEY hKey, T& value) = 0;
  272. virtual void InternalWrite (HKEY hKey, const T& value) = 0;
  273. public:
  274. /**
  275. * Make the value type accessible to others.
  276. */
  277. typedef T ValueT;
  278. /**
  279. * Constructor.
  280. * We use this instead of a default constructor because not all
  281. * data types may provide an adequate default constructor.
  282. */
  283. CRegTypedBase(const T& def);
  284. /**
  285. * Constructor.
  286. * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
  287. * \param def the default value used when the key does not exist or a read error occurred
  288. * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
  289. * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
  290. */
  291. CRegTypedBase(const typename Base::StringT& key, const T& def, bool force = FALSE, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
  292. /**
  293. * Constructor.
  294. * \param updateInterval time in msec between registry lookups caused by operator const T&
  295. * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
  296. * \param def the default value used when the key does not exist or a read error occurred
  297. * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
  298. * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
  299. */
  300. CRegTypedBase(DWORD updateInterval, const typename Base::StringT& key, const T& def, bool force = FALSE, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
  301. /**
  302. * reads the assigned value from the registry. Use this method only if you think the registry
  303. * value could have been altered without using the CRegDWORD object.
  304. * \return the read value
  305. */
  306. void read(); ///< reads the value from the registry
  307. void write(); ///< writes the value to the registry
  308. bool exists(); ///< test whether registry entry exits
  309. const T& defaultValue() const; ///< return the default passed to the constructor
  310. /**
  311. * Data access.
  312. */
  313. operator const T&();
  314. CRegTypedBase<T,Base>& operator=(const T& rhs);
  315. };
  316. // implement CRegTypedBase<> members
  317. template<class T, class Base>
  318. void CRegTypedBase<T, Base>::HandleAutoRefresh()
  319. {
  320. if (m_read && (lookupInterval != (DWORD)(-1)))
  321. {
  322. DWORD currentTime = GetTickCount();
  323. if ( (currentTime < lastRead)
  324. || (currentTime > lastRead + lookupInterval))
  325. {
  326. m_read = false;
  327. }
  328. }
  329. }
  330. template<class T, class Base>
  331. CRegTypedBase<T, Base>::CRegTypedBase (const T& def)
  332. : m_value (def)
  333. , m_defaultvalue (def)
  334. , lastRead (0)
  335. , lookupInterval ((DWORD)-1)
  336. {
  337. }
  338. template<class T, class Base>
  339. CRegTypedBase<T, Base>::CRegTypedBase (const typename Base::StringT& key, const T& def, bool force, HKEY base, REGSAM sam)
  340. : Base (key, force, base, sam)
  341. , m_value (def)
  342. , m_defaultvalue (def)
  343. , lastRead (0)
  344. , lookupInterval ((DWORD)-1)
  345. {
  346. }
  347. template<class T, class Base>
  348. CRegTypedBase<T, Base>::CRegTypedBase (DWORD lookupInterval, const typename Base::StringT& key, const T& def, bool force, HKEY base, REGSAM sam)
  349. : Base (key, force, base, sam)
  350. , m_value (def)
  351. , m_defaultvalue (def)
  352. , lastRead (0)
  353. , lookupInterval (lookupInterval)
  354. {
  355. }
  356. template<class T, class Base>
  357. void CRegTypedBase<T, Base>::read()
  358. {
  359. m_value = m_defaultvalue;
  360. m_exists = false;
  361. HKEY hKey = NULL;
  362. if ((LastError = RegOpenKeyEx (m_base, GetPlainString (m_path), 0, KEY_EXECUTE|m_sam, &hKey))==ERROR_SUCCESS)
  363. {
  364. m_read = true;
  365. T value = m_defaultvalue;
  366. InternalRead (hKey, value);
  367. if (LastError ==ERROR_SUCCESS)
  368. {
  369. m_exists = true;
  370. m_value = value;
  371. }
  372. LastError = RegCloseKey(hKey);
  373. }
  374. lastRead = GetTickCount();
  375. }
  376. template<class T, class Base>
  377. void CRegTypedBase<T, Base>::write()
  378. {
  379. HKEY hKey = NULL;
  380. DWORD disp = 0;
  381. if ((LastError = RegCreateKeyEx(m_base, GetPlainString (m_path), 0, _T(""), REG_OPTION_NON_VOLATILE, KEY_WRITE|m_sam, NULL, &hKey, &disp))!=ERROR_SUCCESS)
  382. {
  383. return;
  384. }
  385. InternalWrite (hKey, m_value);
  386. if (LastError ==ERROR_SUCCESS)
  387. {
  388. m_read = true;
  389. m_exists = true;
  390. }
  391. LastError = RegCloseKey(hKey);
  392. lastRead = GetTickCount();
  393. }
  394. template<class T, class Base>
  395. bool CRegTypedBase<T, Base>::exists()
  396. {
  397. if (!m_read && (LastError == ERROR_SUCCESS))
  398. read();
  399. return m_exists;
  400. }
  401. template<class T, class Base>
  402. const T& CRegTypedBase<T, Base>::defaultValue() const
  403. {
  404. return m_defaultvalue;
  405. }
  406. template<class T, class Base>
  407. CRegTypedBase<T, Base>::operator const T&()
  408. {
  409. HandleAutoRefresh();
  410. if ((m_read)&&(!m_force))
  411. {
  412. LastError = ERROR_SUCCESS;
  413. }
  414. else
  415. {
  416. read();
  417. }
  418. return m_value;
  419. }
  420. template<class T, class Base>
  421. CRegTypedBase<T, Base>& CRegTypedBase<T, Base>::operator =(const T& d)
  422. {
  423. if (m_read && (d == m_value) && !m_force)
  424. {
  425. //no write to the registry required, its the same value
  426. LastError = ERROR_SUCCESS;
  427. return *this;
  428. }
  429. m_value = d;
  430. write();
  431. return *this;
  432. }
  433. /**
  434. * \ingroup Utils
  435. * DWORD value in registry. with this class you can use DWORD values in registry
  436. * like normal DWORD variables in your program.
  437. * Usage:
  438. * in your header file, declare your registry DWORD variable:
  439. * \code
  440. * CRegDWORD regvalue;
  441. * \endcode
  442. * next initialize the variable e.g. in the constructor of your class:
  443. * \code
  444. * regvalue = CRegDWORD("Software\\Company\\SubKey\\MyValue", 100);
  445. * \endcode
  446. * this will set the registry value "MyValue" under HKEY_CURRENT_USER with path
  447. * "Software\Company\SubKey" to the variable. If the key does not yet exist or
  448. * an error occurred during read from the registry, a default
  449. * value of 100 is used when accessing the variable.
  450. * now the variable can be used like any other DWORD variable:
  451. * \code
  452. * regvalue = 200; //stores the value 200 in the registry
  453. * int temp = regvalue + 300; //temp has value 500 now
  454. * regvalue += 300; //now the registry has the value 500 too
  455. * \endcode
  456. * to avoid too much access to the registry the value is cached inside the object.
  457. * once the value is read, no more read accesses to the registry will be made.
  458. * this means the variable will contain a wrong value if the corresponding registry
  459. * entry is changed by anything else than this variable! If you think that could happen
  460. * then use
  461. * \code
  462. * regvalue.read();
  463. * \endcode
  464. * to force a refresh of the variable with the registry.
  465. * a write to the registry is only made if the new value assigned with the variable
  466. * is different than the last assigned value.
  467. * to force a write use the method write();
  468. * another option to force reads and writes to the registry is to specify TRUE as the
  469. * third parameter in the constructor.
  470. */
  471. template<class Base>
  472. class CRegDWORDCommon : public CRegTypedBase<DWORD,Base>
  473. {
  474. private:
  475. /**
  476. * provide type-specific code to extract data from and write data to an open registry key.
  477. */
  478. virtual void InternalRead (HKEY hKey, DWORD& value);
  479. virtual void InternalWrite (HKEY hKey, const DWORD& value);
  480. public:
  481. CRegDWORDCommon(void);
  482. /**
  483. * Constructor.
  484. * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
  485. * \param def the default value used when the key does not exist or a read error occurred
  486. * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
  487. * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
  488. */
  489. CRegDWORDCommon(const typename Base::StringT& key, DWORD def = 0, bool force = false, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
  490. CRegDWORDCommon(DWORD lookupInterval, const typename Base::StringT& key, DWORD def = 0, bool force = false, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
  491. CRegDWORDCommon& operator=(DWORD rhs) {CRegTypedBase<DWORD, Base>::operator =(rhs); return *this;}
  492. CRegDWORDCommon& operator+=(DWORD d) { return *this = *this + d;}
  493. CRegDWORDCommon& operator-=(DWORD d) { return *this = *this - d;}
  494. CRegDWORDCommon& operator*=(DWORD d) { return *this = *this * d;}
  495. CRegDWORDCommon& operator/=(DWORD d) { return *this = *this / d;}
  496. CRegDWORDCommon& operator%=(DWORD d) { return *this = *this % d;}
  497. CRegDWORDCommon& operator<<=(DWORD d) { return *this = *this << d;}
  498. CRegDWORDCommon& operator>>=(DWORD d) { return *this = *this >> d;}
  499. CRegDWORDCommon& operator&=(DWORD d) { return *this = *this & d;}
  500. CRegDWORDCommon& operator|=(DWORD d) { return *this = *this | d;}
  501. CRegDWORDCommon& operator^=(DWORD d) { return *this = *this ^ d;}
  502. };
  503. // implement CRegDWORDCommon<> methods
  504. template<class Base>
  505. CRegDWORDCommon<Base>::CRegDWORDCommon(void)
  506. : CRegTypedBase<DWORD, Base>(0)
  507. {
  508. }
  509. template<class Base>
  510. CRegDWORDCommon<Base>::CRegDWORDCommon(const typename Base::StringT& key, DWORD def, bool force, HKEY base, REGSAM sam)
  511. : CRegTypedBase<DWORD, Base> (key, def, force, base, sam)
  512. {
  513. }
  514. template<class Base>
  515. CRegDWORDCommon<Base>::CRegDWORDCommon(DWORD lookupInterval, const typename Base::StringT& key, DWORD def, bool force, HKEY base, REGSAM sam)
  516. : CRegTypedBase<DWORD, Base> (lookupInterval, key, def, force, base, sam)
  517. {
  518. }
  519. template<class Base>
  520. void CRegDWORDCommon<Base>::InternalRead (HKEY hKey, DWORD& value)
  521. {
  522. DWORD size = sizeof(value);
  523. DWORD type = 0;
  524. if ((LastError = RegQueryValueEx(hKey, GetPlainString (m_key), NULL, &type, (BYTE*) &value, &size))==ERROR_SUCCESS)
  525. {
  526. ASSERT(type==REG_DWORD);
  527. }
  528. }
  529. template<class Base>
  530. void CRegDWORDCommon<Base>::InternalWrite (HKEY hKey, const DWORD& value)
  531. {
  532. LastError = RegSetValueEx (hKey, GetPlainString (m_key), 0, REG_DWORD,(const BYTE*) &value, sizeof(value));
  533. }
  534. /**
  535. * \ingroup Utils
  536. * CString value in registry. with this class you can use CString values in registry
  537. * almost like normal CString variables in your program.
  538. * Usage:
  539. * in your header file, declare your registry CString variable:
  540. * \code
  541. * CRegString regvalue;
  542. * \endcode
  543. * next initialize the variable e.g. in the constructor of your class:
  544. * \code
  545. * regvalue = CRegString("Software\\Company\\SubKey\\MyValue", "default");
  546. * \endcode
  547. * this will set the registry value "MyValue" under HKEY_CURRENT_USER with path
  548. * "Software\Company\SubKey" to the variable. If the key does not yet exist or
  549. * an error occurred during read from the registry, a default
  550. * value of "default" is used when accessing the variable.
  551. * now the variable can be used like any other CString variable:
  552. * \code
  553. * regvalue = "some string"; //stores the value "some string" in the registry
  554. * CString temp = regvalue + "!!"; //temp has value "some string!!" now
  555. * \endcode
  556. * to use the normal methods of the CString class, just typecast the CRegString to a CString
  557. * and do whatever you want with the string:
  558. * \code
  559. * ((CString)regvalue).GetLength();
  560. * ((CString)regvalue).Trim();
  561. * \endcode
  562. * please be aware that in the second line the change in the string won't be written
  563. * to the registry! To force a write use the write() method. A write() is only needed
  564. * if you change the String with Methods not overloaded by CRegString.
  565. * to avoid too much access to the registry the value is cached inside the object.
  566. * once the value is read, no more read accesses to the registry will be made.
  567. * this means the variable will contain a wrong value if the corresponding registry
  568. * entry is changed by anything else than this variable! If you think that could happen
  569. * then use
  570. * \code
  571. * regvalue.read();
  572. * \endcode
  573. * to force a refresh of the variable with the registry.
  574. * a write to the registry is only made if the new value assigned with the variable
  575. * is different than the last assigned value.
  576. * to force a write use the method write();
  577. * another option to force reads and writes to the registry is to specify TRUE as the
  578. * third parameter in the constructor.
  579. */
  580. template<class Base>
  581. class CRegStringCommon : public CRegTypedBase<typename Base::StringT, Base>
  582. {
  583. private:
  584. /**
  585. * provide type-specific code to extract data from and write data to an open registry key.
  586. */
  587. virtual void InternalRead (HKEY hKey, typename Base::StringT& value);
  588. virtual void InternalWrite (HKEY hKey, const typename Base::StringT& value);
  589. public:
  590. CRegStringCommon();
  591. /**
  592. * Constructor.
  593. * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
  594. * \param def the default value used when the key does not exist or a read error occurred
  595. * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
  596. * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
  597. */
  598. CRegStringCommon(const typename Base::StringT& key, const typename Base::StringT& def = _T(""), bool force = false, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
  599. CRegStringCommon(DWORD lookupInterval, const typename Base::StringT& key, const typename Base::StringT& def = _T(""), bool force = false, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
  600. CRegStringCommon& operator=(const typename Base::StringT& rhs) {CRegTypedBase<StringT, Base>::operator =(rhs); return *this;}
  601. CRegStringCommon& operator+=(const typename Base::StringT& s) { return *this = (typename Base::StringT)*this + s; }
  602. };
  603. // implement CRegDWORD<> methods
  604. template<class Base>
  605. CRegStringCommon<Base>::CRegStringCommon(void)
  606. : CRegTypedBase<typename Base::StringT, Base>(typename Base::StringT())
  607. {
  608. }
  609. template<class Base>
  610. CRegStringCommon<Base>::CRegStringCommon(const typename Base::StringT& key, const typename Base::StringT& def, bool force, HKEY base, REGSAM sam)
  611. : CRegTypedBase<typename Base::StringT, Base> (key, def, force, base, sam)
  612. {
  613. }
  614. template<class Base>
  615. CRegStringCommon<Base>::CRegStringCommon(DWORD lookupInterval, const typename Base::StringT& key, const typename Base::StringT& def, bool force, HKEY base, REGSAM sam)
  616. : CRegTypedBase<typename Base::StringT, Base> (lookupInterval, key, def, force, base, sam)
  617. {
  618. }
  619. template<class Base>
  620. void CRegStringCommon<Base>::InternalRead (HKEY hKey, typename Base::StringT& value)
  621. {
  622. DWORD size = 0;
  623. DWORD type = 0;
  624. LastError = RegQueryValueEx(hKey, GetPlainString (m_key), NULL, &type, NULL, &size);
  625. auto_buffer<TCHAR> pStr (size);
  626. if ((LastError = RegQueryValueEx(hKey, GetPlainString (m_key), NULL, &type, (BYTE*) pStr.get(), &size))==ERROR_SUCCESS)
  627. {
  628. ASSERT(type==REG_SZ || type==REG_EXPAND_SZ);
  629. value = StringT (pStr.get());
  630. }
  631. }
  632. template<class Base>
  633. void CRegStringCommon<Base>::InternalWrite (HKEY hKey, const typename Base::StringT& value)
  634. {
  635. LastError = RegSetValueEx(hKey, GetPlainString (m_key), 0, REG_SZ, (BYTE *)GetPlainString (value), (GetLength(value)+1)*sizeof (TCHAR));
  636. }
  637. /**
  638. * \ingroup Utils
  639. * CRect value in registry. with this class you can use CRect values in registry
  640. * almost like normal CRect variables in your program.
  641. * Usage:
  642. * in your header file, declare your registry CString variable:
  643. * \code
  644. * CRegRect regvalue;
  645. * \endcode
  646. * next initialize the variable e.g. in the constructor of your class:
  647. * \code
  648. * regvalue = CRegRect("Software\\Company\\SubKey\\MyValue", CRect(100,100,200,200));
  649. * \endcode
  650. * this will set the registry value "MyValue" under HKEY_CURRENT_USER with path
  651. * "Software\Company\SubKey" to the variable. If the key does not yet exist or
  652. * an error occurred during read from the registry, a default
  653. * value of 100,100,200,200 is used when accessing the variable.
  654. * now the variable can be used like any other CRect variable:
  655. * \code
  656. * regvalue = CRect(40,20,300,500); //stores the value in the registry
  657. * CRect temp = regvalue + CPoint(1,1);
  658. * temp |= CSize(5,5);
  659. * \endcode
  660. * to use the normal methods of the CRect class, just typecast the CRegRect to a CRect
  661. * and do whatever you want with the rect:
  662. * \code
  663. * ((CRect)regvalue).MoveToX(100);
  664. * ((CRect)regvalue).DeflateRect(10,10);
  665. * \endcode
  666. * please be aware that in the second line the change in the CRect won't be written
  667. * to the registry! To force a write use the write() method. A write() is only needed
  668. * if you change the CRect with Methods not overloaded by CRegRect.
  669. * to avoid too much access to the registry the value is cached inside the object.
  670. * once the value is read, no more read accesses to the registry will be made.
  671. * this means the variable will contain a wrong value if the corresponding registry
  672. * entry is changed by anything else than this variable! If you think that could happen
  673. * then use
  674. * \code
  675. * regvalue.read();
  676. * \endcode
  677. * to force a refresh of the variable with the registry.
  678. * a write to the registry is only made if the new value assigned with the variable
  679. * is different than the last assigned value.
  680. * to force a write use the method write();
  681. * another option to force reads and writes to the registry is to specify TRUE as the
  682. * third parameter in the constructor.
  683. */
  684. #ifdef __ATLTYPES_H__ // defines CRect
  685. class CRegRect : public CRegTypedBase<CRect, CRegBase>
  686. {
  687. private:
  688. /**
  689. * provide type-specific code to extract data from and write data to an open registry key.
  690. */
  691. virtual void InternalRead (HKEY hKey, CRect& value);
  692. virtual void InternalWrite (HKEY hKey, const CRect& value);
  693. public:
  694. CRegRect();
  695. /**
  696. * Constructor.
  697. * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
  698. * \param def the default value used when the key does not exist or a read error occurred
  699. * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
  700. * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
  701. */
  702. CRegRect(const CString& key, const CRect& def = CRect(), bool force = false, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
  703. ~CRegRect(void);
  704. CRegRect& operator=(const CRect& rhs) {CRegTypedBase<CRect, CRegBase>::operator =(rhs); return *this;}
  705. operator LPCRECT() { return (LPCRECT)(CRect)*this; }
  706. operator LPRECT() { return (LPRECT)(CRect)*this; }
  707. CRegRect& operator+=(POINT r) { return *this = (CRect)*this + r;}
  708. CRegRect& operator+=(SIZE r) { return *this = (CRect)*this + r;}
  709. CRegRect& operator+=(LPCRECT r) { return *this = (CRect)*this + r;}
  710. CRegRect& operator-=(POINT r) { return *this = (CRect)*this - r;}
  711. CRegRect& operator-=(SIZE r) { return *this = (CRect)*this - r;}
  712. CRegRect& operator-=(LPCRECT r) { return *this = (CRect)*this - r;}
  713. CRegRect& operator&=(CRect r) { return *this = r & *this;}
  714. CRegRect& operator|=(CRect r) { return *this = r | *this;}
  715. };
  716. #endif
  717. /**
  718. * \ingroup Utils
  719. * CPoint value in registry. with this class you can use CPoint values in registry
  720. * almost like normal CPoint variables in your program.
  721. * Usage:
  722. * in your header file, declare your registry CPoint variable:
  723. * \code
  724. * CRegPoint regvalue;
  725. * \endcode
  726. * next initialize the variable e.g. in the constructor of your class:
  727. * \code
  728. * regvalue = CRegPoint("Software\\Company\\SubKey\\MyValue", CPoint(100,100));
  729. * \endcode
  730. * this will set the registry value "MyValue" under HKEY_CURRENT_USER with path
  731. * "Software\Company\SubKey" to the variable. If the key does not yet exist or
  732. * an error occurred during read from the registry, a default
  733. * value of 100,100 is used when accessing the variable.
  734. * now the variable can be used like any other CPoint variable:
  735. * \code
  736. * regvalue = CPoint(40,20); //stores the value in the registry
  737. * CPoint temp = regvalue + CPoint(1,1);
  738. * temp += CSize(5,5);
  739. * \endcode
  740. * to use the normal methods of the CPoint class, just typecast the CRegPoint to a CPoint
  741. * and do whatever you want with the point:
  742. * \code
  743. * ((CRect)regvalue).Offset(100,10);
  744. * \endcode
  745. * please be aware that in the above example the change in the CPoint won't be written
  746. * to the registry! To force a write use the write() method. A write() is only needed
  747. * if you change the CPoint with Methods not overloaded by CRegPoint.
  748. * to avoid too much access to the registry the value is cached inside the object.
  749. * once the value is read, no more read accesses to the registry will be made.
  750. * this means the variable will contain a wrong value if the corresponding registry
  751. * entry is changed by anything else than this variable! If you think that could happen
  752. * then use
  753. * \code
  754. * regvalue.read();
  755. * \endcode
  756. * to force a refresh of the variable with the registry.
  757. * a write to the registry is only made if the new value assigned with the variable
  758. * is different than the last assigned value.
  759. * to force a write use the method write();
  760. * another option to force reads and writes to the registry is to specify TRUE as the
  761. * third parameter in the constructor.
  762. */
  763. #ifdef __ATLTYPES_H__ // defines CPoint
  764. class CRegPoint : public CRegTypedBase<CPoint, CRegBase>
  765. {
  766. private:
  767. /**
  768. * provide type-specific code to extract data from and write data to an open registry key.
  769. */
  770. virtual void InternalRead (HKEY hKey, CPoint& value);
  771. virtual void InternalWrite (HKEY hKey, const CPoint& value);
  772. public:
  773. CRegPoint();
  774. /**
  775. * Constructor.
  776. * \param key the path to the key, including the key. example: "Software\\Company\\SubKey\\MyValue"
  777. * \param def the default value used when the key does not exist or a read error occurred
  778. * \param force set to TRUE if no cache should be used, i.e. always read and write directly from/to registry
  779. * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
  780. */
  781. CRegPoint(const CString& key, const CPoint& def = CPoint(), bool force = false, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
  782. ~CRegPoint(void);
  783. CRegPoint& operator=(const CPoint& rhs) {CRegTypedBase<CPoint, CRegBase>::operator =(rhs); return *this;}
  784. CRegPoint& operator+=(CPoint p) { return *this = p + *this; }
  785. CRegPoint& operator-=(CPoint p) { return *this = p - *this; }
  786. };
  787. #endif
  788. /**
  789. * \ingroup Utils
  790. * Manages a registry key (not a value). Provides methods to create and remove the
  791. * key and to query the list of values and sub keys.
  792. */
  793. #ifdef __AFXCOLL_H__ // defines CStringList
  794. class CRegistryKey
  795. {
  796. public: //methods
  797. /**
  798. * Constructor.
  799. * \param key the path to the key, including the key. example: "Software\\Company\\SubKey"
  800. * \param base a predefined base key like HKEY_LOCAL_MACHINE. see the SDK documentation for more information.
  801. */
  802. CRegistryKey(const CString& key, HKEY base = HKEY_CURRENT_USER, REGSAM sam = 0);
  803. ~CRegistryKey();
  804. /**
  805. * Creates the registry key if it does not already exist.
  806. * \return ERROR_SUCCESS or an nonzero error code. Use FormatMessage() to get an error description.
  807. */
  808. DWORD createKey();
  809. /**
  810. * Removes the whole registry key including all values. So if you set the registry
  811. * entry to be HKCU\Software\Company\Product\key there will only be
  812. * HKCU\Software\Company\Product key in the registry.
  813. * \return ERROR_SUCCESS or an nonzero error code. Use FormatMessage() to get an error description.
  814. */
  815. DWORD removeKey();
  816. bool getValues(CStringList& values); ///< returns the list of values
  817. bool getSubKeys(CStringList& subkeys); ///< returns the list of sub keys
  818. public: //members
  819. HKEY m_base; ///< handle to the registry base
  820. HKEY m_hKey; ///< handle to the open registry key
  821. REGSAM m_sam; ///< the security attributes to pass to the registry command
  822. CString m_path; ///< the path to the key
  823. };
  824. #endif
  825. #ifdef _MAP_
  826. template<class T>
  827. class CKeyList
  828. {
  829. private:
  830. /// constructor parameters
  831. typename T::StringT key;
  832. typename T::ValueT defaultValue;
  833. HKEY base;
  834. /// per-index defaults
  835. typedef std::map<int, typename T::ValueT> TDefaults;
  836. TDefaults defaults;
  837. /// the indices accessed so far
  838. typedef std::map<int, T*> TElements;
  839. mutable TElements elements;
  840. /// auto-insert
  841. const typename T::ValueT& GetDefault (int index) const;
  842. T& GetAt (int index) const;
  843. public:
  844. /// construction
  845. CKeyList (const typename T::StringT& key, const typename T::ValueT& defaultValue, HKEY base = HKEY_CURRENT_USER)
  846. : key (key)
  847. , defaultValue (defaultValue)
  848. , base (base)
  849. {
  850. }
  851. /// destruction: delete all elements
  852. ~CKeyList()
  853. {
  854. for ( TElements::iterator iter = elements.begin()
  855. , end = elements.end()
  856. ; iter != end
  857. ; ++iter)
  858. {
  859. delete iter->second;
  860. }
  861. }
  862. /// data access
  863. const T& operator[] (int index) const
  864. {
  865. return GetAt (index);
  866. }
  867. T& operator[] (int index)
  868. {
  869. return GetAt (index);
  870. }
  871. const TDefaults& GetDefaults() const
  872. {
  873. return defaults;
  874. }
  875. TDefaults& GetDefaults()
  876. {
  877. return defaults;
  878. }
  879. const typename T::ValueT& GetDefault() const
  880. {
  881. return defaultValue;
  882. }
  883. };
  884. /// auto-insert
  885. template<class T>
  886. const typename T::ValueT& CKeyList<T>::GetDefault (int index) const
  887. {
  888. TDefaults::const_iterator iter = defaults.find (index);
  889. return iter == defaults.end() ? defaultValue : iter->second;
  890. }
  891. template<class T>
  892. T& CKeyList<T>::GetAt (int index) const
  893. {
  894. TElements::iterator iter = elements.find (index);
  895. if (iter == elements.end())
  896. {
  897. TCHAR buffer [10];
  898. _itot_s (index, buffer, 10);
  899. typename T::StringT indexKey = key + _T ('\\') + buffer;
  900. T* newElement = new T (indexKey, GetDefault (index), false, base);
  901. iter = elements.insert (std::make_pair (index, newElement)).first;
  902. }
  903. return *iter->second;
  904. };
  905. #endif
  906. /**
  907. * Instantiate templates for common (data type, string type) combinations.
  908. */
  909. #ifdef __CSTRINGT_H__
  910. CRegDWORDCommon<CRegBase>;
  911. typedef CRegDWORDCommon<CRegBase> CRegDWORD;
  912. CRegStringCommon<CRegBase>;
  913. typedef CRegStringCommon<CRegBase> CRegString;
  914. #ifdef _MAP_
  915. CKeyList<CRegDWORD>;
  916. typedef CKeyList<CRegDWORD> CRegDWORDList;
  917. CKeyList<CRegString>;
  918. typedef CKeyList<CRegString> CRegStringList;
  919. #endif
  920. #endif
  921. CRegDWORDCommon<CRegStdBase>;
  922. typedef CRegDWORDCommon<CRegStdBase> CRegStdDWORD;
  923. CRegStringCommon<CRegStdBase>;
  924. typedef CRegStringCommon<CRegStdBase> CRegStdString;
  925. #ifdef _MAP_
  926. CKeyList<CRegStdDWORD>;
  927. typedef CKeyList<CRegStdDWORD> CRegStdDWORDList;
  928. CKeyList<CRegStdString>;
  929. typedef CKeyList<CRegStdString> CRegStdStringList;
  930. #endif