PageRenderTime 61ms CodeModel.GetById 13ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 0ms

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