1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        msw/registry.cpp 
   3 // Purpose:     implementation of registry classes and functions 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 
   9 // Licence:     wxWindows licence 
  10 // TODO:        - parsing of registry key names 
  11 //              - support of other (than REG_SZ/REG_DWORD) registry types 
  12 //              - add high level functions (RegisterOleServer, ...) 
  13 /////////////////////////////////////////////////////////////////////////////// 
  15 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  16 #pragma implementation "registry.h" 
  19 // for compilers that support precompilation, includes "wx.h". 
  20 #include  "wx/wxprec.h" 
  26 // other wxWindows headers 
  27 #include  "wx/string.h" 
  34 #define   WIN32_LEAN_AND_MEAN 
  37 #include  "wx/msw/wrapwin.h" 
  40 #include "wx/msw/private.h" 
  46 #include  <stdlib.h>      // for _MAX_PATH 
  53 #define   HKEY_DEFINED    // already defined in windows.h 
  54 #include  "wx/msw/registry.h" 
  56 // some registry functions don't like signed chars 
  57 typedef unsigned char *RegString
; 
  59 // ---------------------------------------------------------------------------- 
  61 // ---------------------------------------------------------------------------- 
  63 // the standard key names, short names and handles all bundled together for 
  69   const wxChar 
*szShortName
; 
  73   { HKEY_CLASSES_ROOT
,      wxT("HKEY_CLASSES_ROOT"),      wxT("HKCR") }, 
  75   { HKEY_CURRENT_USER
,      wxT("HKEY_CURRENT_USER"),      wxT("HKCU") }, 
  76   { HKEY_LOCAL_MACHINE
,     wxT("HKEY_LOCAL_MACHINE"),     wxT("HKLM") }, 
  77   { HKEY_USERS
,             wxT("HKEY_USERS"),             wxT("HKU")  }, // short name? 
  79   { HKEY_PERFORMANCE_DATA
,  wxT("HKEY_PERFORMANCE_DATA"),  wxT("HKPD") }, 
  81 #if WINVER >= 0x0400 && !defined(__WXWINCE__) 
  82   { HKEY_CURRENT_CONFIG
,    wxT("HKEY_CURRENT_CONFIG"),    wxT("HKCC") }, 
  83 #if !defined(__GNUWIN32__) && !defined(__WXWINCE__) 
  84   { HKEY_DYN_DATA
,          wxT("HKEY_DYN_DATA"),          wxT("HKDD") }, // short name? 
  86 #endif  //WINVER >= 4.0 
  90 // the registry name separator (perhaps one day MS will change it to '/' ;-) 
  91 #define   REG_SEPARATOR     wxT('\\') 
  93 // useful for Windows programmers: makes somewhat more clear all these zeroes 
  94 // being passed to Windows APIs 
  97 // ---------------------------------------------------------------------------- 
  99 // ---------------------------------------------------------------------------- 
 101 // const_cast<> is not yet supported by all compilers 
 102 #define CONST_CAST    ((wxRegKey *)this)-> 
 104 // and neither is mutable which m_dwLastError should be 
 105 #define m_dwLastError   CONST_CAST m_dwLastError 
 107 // ---------------------------------------------------------------------------- 
 108 // non member functions 
 109 // ---------------------------------------------------------------------------- 
 111 // removes the trailing backslash from the string if it has one 
 112 static inline void RemoveTrailingSeparator(wxString
& str
); 
 114 // returns TRUE if given registry key exists 
 115 static bool KeyExists(WXHKEY hRootKey
, const wxChar 
*szKey
); 
 117 // combines value and key name (uses static buffer!) 
 118 static const wxChar 
*GetFullName(const wxRegKey 
*pKey
, 
 119                                const wxChar 
*szValue 
= NULL
); 
 121 // ============================================================================ 
 122 // implementation of wxRegKey class 
 123 // ============================================================================ 
 125 // ---------------------------------------------------------------------------- 
 126 // static functions and variables 
 127 // ---------------------------------------------------------------------------- 
 129 const size_t wxRegKey::nStdKeys 
= WXSIZEOF(aStdKeys
); 
 131 // @@ should take a `StdKey key', but as it's often going to be used in loops 
 132 //    it would require casts in user code. 
 133 const wxChar 
*wxRegKey::GetStdKeyName(size_t key
) 
 135   // return empty string if key is invalid 
 136   wxCHECK_MSG( key 
< nStdKeys
, wxEmptyString
, wxT("invalid key in wxRegKey::GetStdKeyName") ); 
 138   return aStdKeys
[key
].szName
; 
 141 const wxChar 
*wxRegKey::GetStdKeyShortName(size_t key
) 
 143   // return empty string if key is invalid 
 144   wxCHECK( key 
< nStdKeys
, wxEmptyString 
); 
 146   return aStdKeys
[key
].szShortName
; 
 149 wxRegKey::StdKey 
wxRegKey::ExtractKeyName(wxString
& strKey
) 
 151   wxString strRoot 
= strKey
.BeforeFirst(REG_SEPARATOR
); 
 155   for ( ui 
= 0; ui 
< nStdKeys
; ui
++ ) { 
 156     if ( strRoot
.CmpNoCase(aStdKeys
[ui
].szName
) == 0 || 
 157          strRoot
.CmpNoCase(aStdKeys
[ui
].szShortName
) == 0 ) { 
 158       hRootKey 
= aStdKeys
[ui
].hkey
; 
 163   if ( ui 
== nStdKeys 
) { 
 164     wxFAIL_MSG(wxT("invalid key prefix in wxRegKey::ExtractKeyName.")); 
 166     hRootKey 
= HKEY_CLASSES_ROOT
; 
 169     strKey 
= strKey
.After(REG_SEPARATOR
); 
 170     if ( !strKey
.IsEmpty() && strKey
.Last() == REG_SEPARATOR 
) 
 171       strKey
.Truncate(strKey
.Len() - 1); 
 174   return (wxRegKey::StdKey
)(int)hRootKey
; 
 177 wxRegKey::StdKey 
wxRegKey::GetStdKeyFromHkey(WXHKEY hkey
) 
 179   for ( size_t ui 
= 0; ui 
< nStdKeys
; ui
++ ) { 
 180     if ( (int) aStdKeys
[ui
].hkey 
== (int) hkey 
) 
 184   wxFAIL_MSG(wxT("non root hkey passed to wxRegKey::GetStdKeyFromHkey.")); 
 189 // ---------------------------------------------------------------------------- 
 191 // ---------------------------------------------------------------------------- 
 195   m_hRootKey 
= (WXHKEY
) aStdKeys
[HKCR
].hkey
; 
 200 wxRegKey::wxRegKey(const wxString
& strKey
) : m_strKey(strKey
) 
 202   m_hRootKey  
= (WXHKEY
) aStdKeys
[ExtractKeyName(m_strKey
)].hkey
; 
 207 // parent is a predefined (and preopened) key 
 208 wxRegKey::wxRegKey(StdKey keyParent
, const wxString
& strKey
) : m_strKey(strKey
) 
 210   RemoveTrailingSeparator(m_strKey
); 
 211   m_hRootKey  
= (WXHKEY
) aStdKeys
[keyParent
].hkey
; 
 216 // parent is a normal regkey 
 217 wxRegKey::wxRegKey(const wxRegKey
& keyParent
, const wxString
& strKey
) 
 218         : m_strKey(keyParent
.m_strKey
) 
 220   // combine our name with parent's to get the full name 
 221   if ( !m_strKey
.IsEmpty() && 
 222        (strKey
.IsEmpty() || strKey
[0] != REG_SEPARATOR
) ) { 
 223       m_strKey 
+= REG_SEPARATOR
; 
 227   RemoveTrailingSeparator(m_strKey
); 
 229   m_hRootKey  
= keyParent
.m_hRootKey
; 
 234 // dtor closes the key releasing system resource 
 235 wxRegKey::~wxRegKey() 
 240 // ---------------------------------------------------------------------------- 
 241 // change the key name/hkey 
 242 // ---------------------------------------------------------------------------- 
 244 // set the full key name 
 245 void wxRegKey::SetName(const wxString
& strKey
) 
 250   m_hRootKey 
= (WXHKEY
) aStdKeys
[ExtractKeyName(m_strKey
)].hkey
; 
 253 // the name is relative to the parent key 
 254 void wxRegKey::SetName(StdKey keyParent
, const wxString
& strKey
) 
 259   RemoveTrailingSeparator(m_strKey
); 
 260   m_hRootKey 
= (WXHKEY
) aStdKeys
[keyParent
].hkey
; 
 263 // the name is relative to the parent key 
 264 void wxRegKey::SetName(const wxRegKey
& keyParent
, const wxString
& strKey
) 
 268   // combine our name with parent's to get the full name 
 270   // NB: this method is called by wxRegConfig::SetPath() which is a performance 
 271   //     critical function and so it preallocates space for our m_strKey to 
 272   //     gain some speed - this is why we only use += here and not = which 
 273   //     would just free the prealloc'd buffer and would have to realloc it the 
 276   m_strKey 
+= keyParent
.m_strKey
; 
 277   if ( !strKey
.IsEmpty() && strKey
[0] != REG_SEPARATOR 
) 
 278     m_strKey 
+= REG_SEPARATOR
; 
 281   RemoveTrailingSeparator(m_strKey
); 
 283   m_hRootKey 
= keyParent
.m_hRootKey
; 
 286 // hKey should be opened and will be closed in wxRegKey dtor 
 287 void wxRegKey::SetHkey(WXHKEY hKey
) 
 294 // ---------------------------------------------------------------------------- 
 295 // info about the key 
 296 // ---------------------------------------------------------------------------- 
 298 // returns TRUE if the key exists 
 299 bool wxRegKey::Exists() const 
 301   // opened key has to exist, try to open it if not done yet 
 302   return IsOpened() ? TRUE 
: KeyExists(m_hRootKey
, m_strKey
); 
 305 // returns the full name of the key (prefix is abbreviated if bShortPrefix) 
 306 wxString 
wxRegKey::GetName(bool bShortPrefix
) const 
 308   StdKey key 
= GetStdKeyFromHkey((WXHKEY
) m_hRootKey
); 
 309   wxString str 
= bShortPrefix 
? aStdKeys
[key
].szShortName
 
 310                               : aStdKeys
[key
].szName
; 
 311   if ( !m_strKey
.IsEmpty() ) 
 312     str 
<< _T("\\") << m_strKey
; 
 317 bool wxRegKey::GetKeyInfo(size_t *pnSubKeys
, 
 320                           size_t *pnMaxValueLen
) const 
 322     // old gcc headers incorrectly prototype RegQueryInfoKey() 
 323 #if defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__) 
 324     #define REG_PARAM   (size_t *) 
 326     #define REG_PARAM   (LPDWORD) 
 329   // it might be unexpected to some that this function doesn't open the key 
 330   wxASSERT_MSG( IsOpened(), _T("key should be opened in GetKeyInfo") ); 
 332   m_dwLastError 
= ::RegQueryInfoKey
 
 336                     NULL
,           // (ptr to) size of class name buffer 
 339                     pnSubKeys
,      // [out] number of subkeys 
 341                     pnMaxKeyLen
,    // [out] max length of a subkey name 
 342                     NULL
,           // longest subkey class name 
 344                     pnValues
,       // [out] number of values 
 346                     pnMaxValueLen
,  // [out] max length of a value name 
 347                     NULL
,           // longest value data 
 348                     NULL
,           // security descriptor 
 349                     NULL            
// time of last modification 
 354   if ( m_dwLastError 
!= ERROR_SUCCESS 
) { 
 355     wxLogSysError(m_dwLastError
, _("Can't get info about registry key '%s'"), 
 363 // ---------------------------------------------------------------------------- 
 365 // ---------------------------------------------------------------------------- 
 367 // opens key (it's not an error to call Open() on an already opened key) 
 368 bool wxRegKey::Open(AccessMode mode
) 
 374     m_dwLastError 
= ::RegOpenKeyEx
 
 379                         mode 
== Read 
? KEY_READ 
: KEY_ALL_ACCESS
, 
 383     if ( m_dwLastError 
!= ERROR_SUCCESS 
) 
 385         wxLogSysError(m_dwLastError
, _("Can't open registry key '%s'"), 
 390     m_hKey 
= (WXHKEY
) tmpKey
; 
 394 // creates key, failing if it exists and !bOkIfExists 
 395 bool wxRegKey::Create(bool bOkIfExists
) 
 397   // check for existence only if asked (i.e. order is important!) 
 398   if ( !bOkIfExists 
&& Exists() ) 
 407   m_dwLastError 
= RegCreateKeyEx((HKEY
) m_hRootKey
, m_strKey
, 
 409       NULL
, // class string 
 416   m_dwLastError 
= RegCreateKey((HKEY
) m_hRootKey
, m_strKey
, &tmpKey
); 
 418   if ( m_dwLastError 
!= ERROR_SUCCESS 
) { 
 419     wxLogSysError(m_dwLastError
, _("Can't create registry key '%s'"), 
 425     m_hKey 
= (WXHKEY
) tmpKey
; 
 430 // close the key, it's not an error to call it when not opened 
 431 bool wxRegKey::Close() 
 434     m_dwLastError 
= RegCloseKey((HKEY
) m_hKey
); 
 437     if ( m_dwLastError 
!= ERROR_SUCCESS 
) { 
 438       wxLogSysError(m_dwLastError
, _("Can't close registry key '%s'"), 
 448 bool wxRegKey::RenameValue(const wxChar 
*szValueOld
, const wxChar 
*szValueNew
) 
 451     if ( HasValue(szValueNew
) ) { 
 452         wxLogError(_("Registry value '%s' already exists."), szValueNew
); 
 458          !CopyValue(szValueOld
, *this, szValueNew
) || 
 459          !DeleteValue(szValueOld
) ) { 
 460         wxLogError(_("Failed to rename registry value '%s' to '%s'."), 
 461                    szValueOld
, szValueNew
); 
 469 bool wxRegKey::CopyValue(const wxChar 
*szValue
, 
 471                          const wxChar 
*szValueNew
) 
 474         // by default, use the same name 
 475         szValueNew 
= szValue
; 
 478     switch ( GetValueType(szValue
) ) { 
 482                 return QueryValue(szValue
, strVal
) && 
 483                        keyDst
.SetValue(szValueNew
, strVal
); 
 487         /* case Type_Dword_little_endian: == Type_Dword */ 
 490                 return QueryValue(szValue
, &dwVal
) && 
 491                        keyDst
.SetValue(szValueNew
, dwVal
); 
 494         // these types are unsupported because I am not sure about how 
 495         // exactly they should be copied and because they shouldn't 
 496         // occur among the application keys (supposedly created with 
 500         case Type_Expand_String
: 
 502         case Type_Dword_big_endian
: 
 504         case Type_Multi_String
: 
 505         case Type_Resource_list
: 
 506         case Type_Full_resource_descriptor
: 
 507         case Type_Resource_requirements_list
: 
 510             wxLogError(_("Can't copy values of unsupported type %d."), 
 511                        GetValueType(szValue
)); 
 516 bool wxRegKey::Rename(const wxChar 
*szNewName
) 
 518     wxCHECK_MSG( !!m_strKey
, FALSE
, _T("registry hives can't be renamed") ); 
 521         wxLogError(_("Registry key '%s' does not exist, cannot rename it."), 
 527     // do we stay in the same hive? 
 528     bool inSameHive 
= !wxStrchr(szNewName
, REG_SEPARATOR
); 
 530     // construct the full new name of the key 
 534         // rename the key to the new name under the same parent 
 535         wxString strKey 
= m_strKey
.BeforeLast(REG_SEPARATOR
); 
 537             // don't add '\\' in the start if strFullNewName is empty 
 538             strKey 
+= REG_SEPARATOR
; 
 543         keyDst
.SetName(GetStdKeyFromHkey(m_hRootKey
), strKey
); 
 546         // this is the full name already 
 547         keyDst
.SetName(szNewName
); 
 550     bool ok 
= keyDst
.Create(FALSE 
/* fail if alredy exists */); 
 552         wxLogError(_("Registry key '%s' already exists."), 
 553                    GetFullName(&keyDst
)); 
 556         ok 
= Copy(keyDst
) && DeleteSelf(); 
 560         wxLogError(_("Failed to rename the registry key '%s' to '%s'."), 
 561                    GetFullName(this), GetFullName(&keyDst
)); 
 564         m_hRootKey 
= keyDst
.m_hRootKey
; 
 565         m_strKey 
= keyDst
.m_strKey
; 
 571 bool wxRegKey::Copy(const wxChar 
*szNewName
) 
 573     // create the new key first 
 574     wxRegKey 
keyDst(szNewName
); 
 575     bool ok 
= keyDst
.Create(FALSE 
/* fail if alredy exists */); 
 579         // we created the dest key but copying to it failed - delete it 
 581             (void)keyDst
.DeleteSelf(); 
 588 bool wxRegKey::Copy(wxRegKey
& keyDst
) 
 592     // copy all sub keys to the new location 
 595     bool bCont 
= GetFirstKey(strKey
, lIndex
); 
 596     while ( ok 
&& bCont 
) { 
 597         wxRegKey 
key(*this, strKey
); 
 599         keyName 
<< GetFullName(&keyDst
) << REG_SEPARATOR 
<< strKey
; 
 600         ok 
= key
.Copy((const wxChar
*) keyName
); 
 603             bCont 
= GetNextKey(strKey
, lIndex
); 
 608     bCont 
= GetFirstValue(strVal
, lIndex
); 
 609     while ( ok 
&& bCont 
) { 
 610         ok 
= CopyValue(strVal
, keyDst
); 
 613             wxLogSysError(m_dwLastError
, 
 614                           _("Failed to copy registry value '%s'"), 
 618             bCont 
= GetNextValue(strVal
, lIndex
); 
 623         wxLogError(_("Failed to copy the contents of registry key '%s' to '%s'."), GetFullName(this), GetFullName(&keyDst
)); 
 629 // ---------------------------------------------------------------------------- 
 630 // delete keys/values 
 631 // ---------------------------------------------------------------------------- 
 632 bool wxRegKey::DeleteSelf() 
 637       // it already doesn't exist - ok! 
 642   // prevent a buggy program from erasing one of the root registry keys or an 
 643   // immediate subkey (i.e. one which doesn't have '\\' inside) of any other 
 644   // key except HKCR (HKCR has some "deleteable" subkeys) 
 645   if ( m_strKey
.IsEmpty() || 
 646        ((m_hRootKey 
!= (WXHKEY
) aStdKeys
[HKCR
].hkey
) && 
 647         (m_strKey
.Find(REG_SEPARATOR
) == wxNOT_FOUND
)) ) { 
 648       wxLogError(_("Registry key '%s' is needed for normal system operation,\ndeleting it will leave your system in unusable state:\noperation aborted."), GetFullName(this)); 
 653   // we can't delete keys while enumerating because it confuses GetNextKey, so 
 654   // we first save the key names and then delete them all 
 655   wxArrayString astrSubkeys
; 
 659   bool bCont 
= GetFirstKey(strKey
, lIndex
); 
 661     astrSubkeys
.Add(strKey
); 
 663     bCont 
= GetNextKey(strKey
, lIndex
); 
 666   size_t nKeyCount 
= astrSubkeys
.Count(); 
 667   for ( size_t nKey 
= 0; nKey 
< nKeyCount
; nKey
++ ) { 
 668     wxRegKey 
key(*this, astrSubkeys
[nKey
]); 
 669     if ( !key
.DeleteSelf() ) 
 673   // now delete this key itself 
 676   m_dwLastError 
= RegDeleteKey((HKEY
) m_hRootKey
, m_strKey
); 
 677   // deleting a key which doesn't exist is not considered an error 
 678   if ( m_dwLastError 
!= ERROR_SUCCESS 
&& 
 679           m_dwLastError 
!= ERROR_FILE_NOT_FOUND 
) { 
 680     wxLogSysError(m_dwLastError
, _("Can't delete key '%s'"), 
 688 bool wxRegKey::DeleteKey(const wxChar 
*szKey
) 
 693   wxRegKey 
key(*this, szKey
); 
 694   return key
.DeleteSelf(); 
 697 bool wxRegKey::DeleteValue(const wxChar 
*szValue
) 
 702     m_dwLastError 
= RegDeleteValue((HKEY
) m_hKey
, WXSTRINGCAST szValue
); 
 704     // deleting a value which doesn't exist is not considered an error 
 705     if ( (m_dwLastError 
!= ERROR_SUCCESS
) && 
 706          (m_dwLastError 
!= ERROR_FILE_NOT_FOUND
) ) { 
 707       wxLogSysError(m_dwLastError
, _("Can't delete value '%s' from key '%s'"), 
 708                     szValue
, GetName().c_str()); 
 715 // ---------------------------------------------------------------------------- 
 716 // access to values and subkeys 
 717 // ---------------------------------------------------------------------------- 
 719 // return TRUE if value exists 
 720 bool wxRegKey::HasValue(const wxChar 
*szValue
) const 
 722   // this function should be silent, so suppress possible messages from Open() 
 725     if ( !CONST_CAST 
Open() ) 
 728     LONG dwRet 
= ::RegQueryValueEx((HKEY
) m_hKey
, 
 729                                    WXSTRINGCAST szValue
, 
 732     return dwRet 
== ERROR_SUCCESS
; 
 735 // returns TRUE if this key has any values 
 736 bool wxRegKey::HasValues() const 
 738   // suppress possible messages from GetFirstValue() 
 741   // just call GetFirstValue with dummy parameters 
 744   return CONST_CAST 
GetFirstValue(str
, l
); 
 747 // returns TRUE if this key has any subkeys 
 748 bool wxRegKey::HasSubkeys() const 
 750   // suppress possible messages from GetFirstKey() 
 753   // just call GetFirstKey with dummy parameters 
 756   return CONST_CAST 
GetFirstKey(str
, l
); 
 759 // returns TRUE if given subkey exists 
 760 bool wxRegKey::HasSubKey(const wxChar 
*szKey
) const 
 762   // this function should be silent, so suppress possible messages from Open() 
 765   if ( !CONST_CAST 
Open() ) 
 768   return KeyExists(m_hKey
, szKey
); 
 771 wxRegKey::ValueType 
wxRegKey::GetValueType(const wxChar 
*szValue
) const 
 773     if ( ! CONST_CAST 
Open() ) 
 777     m_dwLastError 
= RegQueryValueEx((HKEY
) m_hKey
, WXSTRINGCAST szValue
, RESERVED
, 
 778                                     &dwType
, NULL
, NULL
); 
 779     if ( m_dwLastError 
!= ERROR_SUCCESS 
) { 
 780       wxLogSysError(m_dwLastError
, _("Can't read value of key '%s'"), 
 785     return (ValueType
)dwType
; 
 789 bool wxRegKey::SetValue(const wxChar 
*szValue
, long lValue
) 
 791   if ( CONST_CAST 
Open() ) { 
 792     m_dwLastError 
= RegSetValueEx((HKEY
) m_hKey
, szValue
, (DWORD
) RESERVED
, REG_DWORD
, 
 793                                   (RegString
)&lValue
, sizeof(lValue
)); 
 794     if ( m_dwLastError 
== ERROR_SUCCESS 
) 
 798   wxLogSysError(m_dwLastError
, _("Can't set value of '%s'"), 
 799                 GetFullName(this, szValue
)); 
 803 bool wxRegKey::QueryValue(const wxChar 
*szValue
, long *plValue
) const 
 805   if ( CONST_CAST 
Open() ) { 
 806     DWORD dwType
, dwSize 
= sizeof(DWORD
); 
 807     RegString pBuf 
= (RegString
)plValue
; 
 808     m_dwLastError 
= RegQueryValueEx((HKEY
) m_hKey
, WXSTRINGCAST szValue
, RESERVED
, 
 809                                     &dwType
, pBuf
, &dwSize
); 
 810     if ( m_dwLastError 
!= ERROR_SUCCESS 
) { 
 811       wxLogSysError(m_dwLastError
, _("Can't read value of key '%s'"), 
 816       // check that we read the value of right type 
 817       wxASSERT_MSG( IsNumericValue(szValue
), 
 818                     wxT("Type mismatch in wxRegKey::QueryValue().")  ); 
 829 bool wxRegKey::QueryValue(const wxChar 
*szValue
, 
 833   if ( CONST_CAST 
Open() ) { 
 835       // first get the type and size of the data 
 836       DWORD dwType
, dwSize
; 
 837       m_dwLastError 
= RegQueryValueEx((HKEY
) m_hKey
, WXSTRINGCAST szValue
, RESERVED
, 
 838                                       &dwType
, NULL
, &dwSize
); 
 839       if ( m_dwLastError 
== ERROR_SUCCESS 
) { 
 841             // must treat this case specially as GetWriteBuf() doesn't like 
 842             // being called with 0 size 
 846             m_dwLastError 
= RegQueryValueEx((HKEY
) m_hKey
, 
 847                                             WXSTRINGCAST szValue
, 
 850                                             (RegString
)(wxChar
*)wxStringBuffer(strValue
, dwSize
), 
 853             // expand the var expansions in the string unless disabled 
 855             if ( (dwType 
== REG_EXPAND_SZ
) && !raw 
) 
 857                 DWORD dwExpSize 
= ::ExpandEnvironmentStrings(strValue
, NULL
, 0); 
 858                 bool ok 
= dwExpSize 
!= 0; 
 861                     wxString strExpValue
; 
 862                     ok 
= ::ExpandEnvironmentStrings
 
 865                             wxStringBuffer(strExpValue
, dwExpSize
), 
 868                     strValue 
= strExpValue
; 
 873                     wxLogLastError(_T("ExpandEnvironmentStrings")); 
 880         if ( m_dwLastError 
== ERROR_SUCCESS 
) { 
 881           // check that it was the right type 
 882           wxASSERT_MSG( !IsNumericValue(szValue
), 
 883                         wxT("Type mismatch in wxRegKey::QueryValue().") ); 
 890   wxLogSysError(m_dwLastError
, _("Can't read value of '%s'"), 
 891                 GetFullName(this, szValue
)); 
 895 bool wxRegKey::SetValue(const wxChar 
*szValue
, const wxString
& strValue
) 
 897   if ( CONST_CAST 
Open() ) { 
 898       m_dwLastError 
= RegSetValueEx((HKEY
) m_hKey
, szValue
, (DWORD
) RESERVED
, REG_SZ
, 
 899                                     (RegString
)strValue
.c_str(), 
 900                                     (strValue
.Len() + 1)*sizeof(wxChar
)); 
 901       if ( m_dwLastError 
== ERROR_SUCCESS 
) 
 905   wxLogSysError(m_dwLastError
, _("Can't set value of '%s'"), 
 906                 GetFullName(this, szValue
)); 
 910 wxString 
wxRegKey::QueryDefaultValue() const 
 913   QueryValue(NULL
, str
); 
 917 // ---------------------------------------------------------------------------- 
 919 // NB: all these functions require an index variable which allows to have 
 920 //     several concurrently running indexations on the same key 
 921 // ---------------------------------------------------------------------------- 
 923 bool wxRegKey::GetFirstValue(wxString
& strValueName
, long& lIndex
) 
 929   return GetNextValue(strValueName
, lIndex
); 
 932 bool wxRegKey::GetNextValue(wxString
& strValueName
, long& lIndex
) const 
 934   wxASSERT( IsOpened() ); 
 936   // are we already at the end of enumeration? 
 940     wxChar  szValueName
[1024];                  // @@ use RegQueryInfoKey... 
 941     DWORD dwValueLen 
= WXSIZEOF(szValueName
); 
 943     m_dwLastError 
= RegEnumValue((HKEY
) m_hKey
, lIndex
++, 
 944                                  szValueName
, &dwValueLen
, 
 947                                  NULL
,            // [out] buffer for value 
 948                                  NULL
);           // [i/o]  it's length 
 950     if ( m_dwLastError 
!= ERROR_SUCCESS 
) { 
 951       if ( m_dwLastError 
== ERROR_NO_MORE_ITEMS 
) { 
 952         m_dwLastError 
= ERROR_SUCCESS
; 
 956         wxLogSysError(m_dwLastError
, _("Can't enumerate values of key '%s'"), 
 963     strValueName 
= szValueName
; 
 968 bool wxRegKey::GetFirstKey(wxString
& strKeyName
, long& lIndex
) 
 974   return GetNextKey(strKeyName
, lIndex
); 
 977 bool wxRegKey::GetNextKey(wxString
& strKeyName
, long& lIndex
) const 
 979   wxASSERT( IsOpened() ); 
 981   // are we already at the end of enumeration? 
 985   wxChar szKeyName
[_MAX_PATH 
+ 1]; 
 988   DWORD sizeName 
= WXSIZEOF(szKeyName
); 
 989   m_dwLastError 
= RegEnumKeyEx((HKEY
) m_hKey
, lIndex
++, szKeyName
, & sizeName
, 
 990       0, NULL
, NULL
, NULL
); 
 992   m_dwLastError 
= RegEnumKey((HKEY
) m_hKey
, lIndex
++, szKeyName
, WXSIZEOF(szKeyName
)); 
 995   if ( m_dwLastError 
!= ERROR_SUCCESS 
) { 
 996     if ( m_dwLastError 
== ERROR_NO_MORE_ITEMS 
) { 
 997       m_dwLastError 
= ERROR_SUCCESS
; 
1001       wxLogSysError(m_dwLastError
, _("Can't enumerate subkeys of key '%s'"), 
1008   strKeyName 
= szKeyName
; 
1012 // returns TRUE if the value contains a number (else it's some string) 
1013 bool wxRegKey::IsNumericValue(const wxChar 
*szValue
) const 
1015       ValueType type 
= GetValueType(szValue
); 
1018         /* case Type_Dword_little_endian: == Type_Dword */ 
1019         case Type_Dword_big_endian
: 
1027 // ============================================================================ 
1028 // implementation of global private functions 
1029 // ============================================================================ 
1031 bool KeyExists(WXHKEY hRootKey
, const wxChar 
*szKey
) 
1033     // don't close this key itself for the case of empty szKey! 
1034     if ( wxIsEmpty(szKey
) ) 
1043             KEY_READ
,        // we might not have enough rights for rw access 
1045          ) == ERROR_SUCCESS 
) 
1047         ::RegCloseKey(hkeyDummy
); 
1055 const wxChar 
*GetFullName(const wxRegKey 
*pKey
, const wxChar 
*szValue
) 
1057   static wxString s_str
; 
1058   s_str 
= pKey
->GetName(); 
1059   if ( !wxIsEmpty(szValue
) ) 
1060     s_str 
<< wxT("\\") << szValue
; 
1062   return s_str
.c_str(); 
1065 void RemoveTrailingSeparator(wxString
& str
) 
1067   if ( !str
.IsEmpty() && str
.Last() == REG_SEPARATOR 
) 
1068     str
.Truncate(str
.Len() - 1);