1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/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 // for compilers that support precompilation, includes "wx.h". 
  16 #include  "wx/wxprec.h" 
  23     #include "wx/msw/wrapwin.h" 
  24     #include "wx/string.h" 
  31 #include "wx/wfstream.h" 
  35 #include "wx/msw/private.h" 
  41 #include  <stdlib.h>      // for _MAX_PATH 
  48 #define   HKEY_DEFINED    // already defined in windows.h 
  49 #include  "wx/msw/registry.h" 
  51 // some registry functions don't like signed chars 
  52 typedef unsigned char *RegString
; 
  53 typedef BYTE
* RegBinary
; 
  55 #ifndef HKEY_PERFORMANCE_DATA 
  56     #define HKEY_PERFORMANCE_DATA ((HKEY)0x80000004) 
  59 #ifndef HKEY_CURRENT_CONFIG 
  60     #define HKEY_CURRENT_CONFIG ((HKEY)0x80000005) 
  64     #define HKEY_DYN_DATA ((HKEY)0x80000006) 
  67 // ---------------------------------------------------------------------------- 
  69 // ---------------------------------------------------------------------------- 
  71 // the standard key names, short names and handles all bundled together for 
  77   const wxChar 
*szShortName
; 
  81   { HKEY_CLASSES_ROOT
,      wxT("HKEY_CLASSES_ROOT"),      wxT("HKCR") }, 
  82   { HKEY_CURRENT_USER
,      wxT("HKEY_CURRENT_USER"),      wxT("HKCU") }, 
  83   { HKEY_LOCAL_MACHINE
,     wxT("HKEY_LOCAL_MACHINE"),     wxT("HKLM") }, 
  84   { HKEY_USERS
,             wxT("HKEY_USERS"),             wxT("HKU")  }, // short name? 
  85   { HKEY_PERFORMANCE_DATA
,  wxT("HKEY_PERFORMANCE_DATA"),  wxT("HKPD") }, 
  86   { HKEY_CURRENT_CONFIG
,    wxT("HKEY_CURRENT_CONFIG"),    wxT("HKCC") }, 
  87   { HKEY_DYN_DATA
,          wxT("HKEY_DYN_DATA"),          wxT("HKDD") }, // short name? 
  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 wxString
& szKey
); 
 117 // combines value and key name 
 118 static wxString 
GetFullName(const wxRegKey 
*pKey
); 
 119 static wxString 
GetFullName(const wxRegKey 
*pKey
, const wxString
& szValue
); 
 121 // returns "value" argument of wxRegKey methods converted into a value that can 
 122 // be passed to win32 registry functions; specifically, converts empty string 
 124 static inline const wxChar 
*RegValueStr(const wxString
& szValue
); 
 126 // ============================================================================ 
 127 // implementation of wxRegKey class 
 128 // ============================================================================ 
 130 // ---------------------------------------------------------------------------- 
 131 // static functions and variables 
 132 // ---------------------------------------------------------------------------- 
 134 const size_t wxRegKey::nStdKeys 
= WXSIZEOF(aStdKeys
); 
 136 // @@ should take a `StdKey key', but as it's often going to be used in loops 
 137 //    it would require casts in user code. 
 138 const wxChar 
*wxRegKey::GetStdKeyName(size_t key
) 
 140   // return empty string if key is invalid 
 141   wxCHECK_MSG( key 
< nStdKeys
, wxEmptyString
, wxT("invalid key in wxRegKey::GetStdKeyName") ); 
 143   return aStdKeys
[key
].szName
; 
 146 const wxChar 
*wxRegKey::GetStdKeyShortName(size_t key
) 
 148   // return empty string if key is invalid 
 149   wxCHECK( key 
< nStdKeys
, wxEmptyString 
); 
 151   return aStdKeys
[key
].szShortName
; 
 154 wxRegKey::StdKey 
wxRegKey::ExtractKeyName(wxString
& strKey
) 
 156   wxString strRoot 
= strKey
.BeforeFirst(REG_SEPARATOR
); 
 159   for ( ui 
= 0; ui 
< nStdKeys
; ui
++ ) { 
 160     if ( strRoot
.CmpNoCase(aStdKeys
[ui
].szName
) == 0 || 
 161          strRoot
.CmpNoCase(aStdKeys
[ui
].szShortName
) == 0 ) { 
 166   if ( ui 
== nStdKeys 
) { 
 167     wxFAIL_MSG(wxT("invalid key prefix in wxRegKey::ExtractKeyName.")); 
 172     strKey 
= strKey
.After(REG_SEPARATOR
); 
 173     if ( !strKey
.empty() && strKey
.Last() == REG_SEPARATOR 
) 
 174       strKey
.Truncate(strKey
.Len() - 1); 
 180 wxRegKey::StdKey 
wxRegKey::GetStdKeyFromHkey(WXHKEY hkey
) 
 182   for ( size_t ui 
= 0; ui 
< nStdKeys
; ui
++ ) { 
 183     if ( aStdKeys
[ui
].hkey 
== (HKEY
)hkey 
) 
 187   wxFAIL_MSG(wxT("non root hkey passed to wxRegKey::GetStdKeyFromHkey.")); 
 192 // ---------------------------------------------------------------------------- 
 194 // ---------------------------------------------------------------------------- 
 198   m_hRootKey 
= (WXHKEY
) aStdKeys
[HKCR
].hkey
; 
 203 wxRegKey::wxRegKey(const wxString
& strKey
) : m_strKey(strKey
) 
 205   m_hRootKey  
= (WXHKEY
) aStdKeys
[ExtractKeyName(m_strKey
)].hkey
; 
 210 // parent is a predefined (and preopened) key 
 211 wxRegKey::wxRegKey(StdKey keyParent
, const wxString
& strKey
) : m_strKey(strKey
) 
 213   RemoveTrailingSeparator(m_strKey
); 
 214   m_hRootKey  
= (WXHKEY
) aStdKeys
[keyParent
].hkey
; 
 219 // parent is a normal regkey 
 220 wxRegKey::wxRegKey(const wxRegKey
& keyParent
, const wxString
& strKey
) 
 221         : m_strKey(keyParent
.m_strKey
) 
 223   // combine our name with parent's to get the full name 
 224   if ( !m_strKey
.empty() && 
 225        (strKey
.empty() || strKey
[0] != REG_SEPARATOR
) ) { 
 226       m_strKey 
+= REG_SEPARATOR
; 
 230   RemoveTrailingSeparator(m_strKey
); 
 232   m_hRootKey  
= keyParent
.m_hRootKey
; 
 237 // dtor closes the key releasing system resource 
 238 wxRegKey::~wxRegKey() 
 243 // ---------------------------------------------------------------------------- 
 244 // change the key name/hkey 
 245 // ---------------------------------------------------------------------------- 
 247 // set the full key name 
 248 void wxRegKey::SetName(const wxString
& strKey
) 
 253   m_hRootKey 
= (WXHKEY
) aStdKeys
[ExtractKeyName(m_strKey
)].hkey
; 
 256 // the name is relative to the parent key 
 257 void wxRegKey::SetName(StdKey keyParent
, const wxString
& strKey
) 
 262   RemoveTrailingSeparator(m_strKey
); 
 263   m_hRootKey 
= (WXHKEY
) aStdKeys
[keyParent
].hkey
; 
 266 // the name is relative to the parent key 
 267 void wxRegKey::SetName(const wxRegKey
& keyParent
, const wxString
& strKey
) 
 271   // combine our name with parent's to get the full name 
 273   // NB: this method is called by wxRegConfig::SetPath() which is a performance 
 274   //     critical function and so it preallocates space for our m_strKey to 
 275   //     gain some speed - this is why we only use += here and not = which 
 276   //     would just free the prealloc'd buffer and would have to realloc it the 
 279   m_strKey 
+= keyParent
.m_strKey
; 
 280   if ( !strKey
.empty() && strKey
[0] != REG_SEPARATOR 
) 
 281     m_strKey 
+= REG_SEPARATOR
; 
 284   RemoveTrailingSeparator(m_strKey
); 
 286   m_hRootKey 
= keyParent
.m_hRootKey
; 
 289 // hKey should be opened and will be closed in wxRegKey dtor 
 290 void wxRegKey::SetHkey(WXHKEY hKey
) 
 297 // ---------------------------------------------------------------------------- 
 298 // info about the key 
 299 // ---------------------------------------------------------------------------- 
 301 // returns true if the key exists 
 302 bool wxRegKey::Exists() const 
 304   // opened key has to exist, try to open it if not done yet 
 305   return IsOpened() ? true : KeyExists(m_hRootKey
, m_strKey
.wx_str()); 
 308 // returns the full name of the key (prefix is abbreviated if bShortPrefix) 
 309 wxString 
wxRegKey::GetName(bool bShortPrefix
) const 
 311   StdKey key 
= GetStdKeyFromHkey((WXHKEY
) m_hRootKey
); 
 312   wxString str 
= bShortPrefix 
? aStdKeys
[key
].szShortName
 
 313                               : aStdKeys
[key
].szName
; 
 314   if ( !m_strKey
.empty() ) 
 315     str 
<< _T("\\") << m_strKey
; 
 320 bool wxRegKey::GetKeyInfo(size_t *pnSubKeys
, 
 323                           size_t *pnMaxValueLen
) const 
 325     // old gcc headers incorrectly prototype RegQueryInfoKey() 
 326 #if defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__) 
 327     #define REG_PARAM   (size_t *) 
 329     #define REG_PARAM   (LPDWORD) 
 332   // it might be unexpected to some that this function doesn't open the key 
 333   wxASSERT_MSG( IsOpened(), _T("key should be opened in GetKeyInfo") ); 
 335   m_dwLastError 
= ::RegQueryInfoKey
 
 339                     NULL
,           // (ptr to) size of class name buffer 
 342                     pnSubKeys
,      // [out] number of subkeys 
 344                     pnMaxKeyLen
,    // [out] max length of a subkey name 
 345                     NULL
,           // longest subkey class name 
 347                     pnValues
,       // [out] number of values 
 349                     pnMaxValueLen
,  // [out] max length of a value name 
 350                     NULL
,           // longest value data 
 351                     NULL
,           // security descriptor 
 352                     NULL            
// time of last modification 
 357   if ( m_dwLastError 
!= ERROR_SUCCESS 
) { 
 358     wxLogSysError(m_dwLastError
, _("Can't get info about registry key '%s'"), 
 366 // ---------------------------------------------------------------------------- 
 368 // ---------------------------------------------------------------------------- 
 370 // opens key (it's not an error to call Open() on an already opened key) 
 371 bool wxRegKey::Open(AccessMode mode
) 
 375         if ( mode 
<= m_mode 
) 
 378         // we had been opened in read mode but now must be reopened in write 
 383     m_dwLastError 
= ::RegOpenKeyEx
 
 388                         mode 
== Read 
? KEY_READ 
: KEY_ALL_ACCESS
, 
 392     if ( m_dwLastError 
!= ERROR_SUCCESS 
) 
 394         wxLogSysError(m_dwLastError
, _("Can't open registry key '%s'"), 
 399     m_hKey 
= (WXHKEY
) tmpKey
; 
 405 // creates key, failing if it exists and !bOkIfExists 
 406 bool wxRegKey::Create(bool bOkIfExists
) 
 408   // check for existence only if asked (i.e. order is important!) 
 409   if ( !bOkIfExists 
&& Exists() ) 
 418   m_dwLastError 
= RegCreateKeyEx((HKEY
) m_hRootKey
, m_strKey
.wx_str(), 
 420       NULL
, // class string 
 427   m_dwLastError 
= RegCreateKey((HKEY
) m_hRootKey
, m_strKey
.wx_str(), &tmpKey
); 
 429   if ( m_dwLastError 
!= ERROR_SUCCESS 
) { 
 430     wxLogSysError(m_dwLastError
, _("Can't create registry key '%s'"), 
 436     m_hKey 
= (WXHKEY
) tmpKey
; 
 441 // close the key, it's not an error to call it when not opened 
 442 bool wxRegKey::Close() 
 445     m_dwLastError 
= RegCloseKey((HKEY
) m_hKey
); 
 448     if ( m_dwLastError 
!= ERROR_SUCCESS 
) { 
 449       wxLogSysError(m_dwLastError
, _("Can't close registry key '%s'"), 
 460 wxRegKey::RenameValue(const wxString
& szValueOld
, const wxString
& szValueNew
) 
 463     if ( HasValue(szValueNew
) ) { 
 464         wxLogError(_("Registry value '%s' already exists."), szValueNew
); 
 470          !CopyValue(szValueOld
, *this, szValueNew
) || 
 471          !DeleteValue(szValueOld
) ) { 
 472         wxLogError(_("Failed to rename registry value '%s' to '%s'."), 
 473                    szValueOld
, szValueNew
); 
 481 bool wxRegKey::CopyValue(const wxString
& szValue
, 
 483                          const wxString
& szValueNew
) 
 485     wxString 
valueNew(szValueNew
); 
 486     if ( valueNew
.empty() ) { 
 487         // by default, use the same name 
 491     switch ( GetValueType(szValue
) ) { 
 495                 return QueryValue(szValue
, strVal
) && 
 496                        keyDst
.SetValue(valueNew
, strVal
); 
 500         /* case Type_Dword_little_endian: == Type_Dword */ 
 503                 return QueryValue(szValue
, &dwVal
) && 
 504                        keyDst
.SetValue(valueNew
, dwVal
); 
 510             return QueryValue(szValue
,buf
) && 
 511                    keyDst
.SetValue(valueNew
,buf
); 
 514         // these types are unsupported because I am not sure about how 
 515         // exactly they should be copied and because they shouldn't 
 516         // occur among the application keys (supposedly created with 
 519         case Type_Expand_String
: 
 520         case Type_Dword_big_endian
: 
 522         case Type_Multi_String
: 
 523         case Type_Resource_list
: 
 524         case Type_Full_resource_descriptor
: 
 525         case Type_Resource_requirements_list
: 
 527             wxLogError(_("Can't copy values of unsupported type %d."), 
 528                        GetValueType(szValue
)); 
 533 bool wxRegKey::Rename(const wxString
& szNewName
) 
 535     wxCHECK_MSG( !m_strKey
.empty(), false, _T("registry hives can't be renamed") ); 
 538         wxLogError(_("Registry key '%s' does not exist, cannot rename it."), 
 544     // do we stay in the same hive? 
 545     bool inSameHive 
= !wxStrchr(szNewName
, REG_SEPARATOR
); 
 547     // construct the full new name of the key 
 551         // rename the key to the new name under the same parent 
 552         wxString strKey 
= m_strKey
.BeforeLast(REG_SEPARATOR
); 
 553         if ( !strKey
.empty() ) { 
 554             // don't add '\\' in the start if strFullNewName is empty 
 555             strKey 
+= REG_SEPARATOR
; 
 560         keyDst
.SetName(GetStdKeyFromHkey(m_hRootKey
), strKey
); 
 563         // this is the full name already 
 564         keyDst
.SetName(szNewName
); 
 567     bool ok 
= keyDst
.Create(false /* fail if alredy exists */); 
 569         wxLogError(_("Registry key '%s' already exists."), 
 570                    GetFullName(&keyDst
)); 
 573         ok 
= Copy(keyDst
) && DeleteSelf(); 
 577         wxLogError(_("Failed to rename the registry key '%s' to '%s'."), 
 578                    GetFullName(this), GetFullName(&keyDst
)); 
 581         m_hRootKey 
= keyDst
.m_hRootKey
; 
 582         m_strKey 
= keyDst
.m_strKey
; 
 588 bool wxRegKey::Copy(const wxString
& szNewName
) 
 590     // create the new key first 
 591     wxRegKey 
keyDst(szNewName
); 
 592     bool ok 
= keyDst
.Create(false /* fail if alredy exists */); 
 596         // we created the dest key but copying to it failed - delete it 
 598             (void)keyDst
.DeleteSelf(); 
 605 bool wxRegKey::Copy(wxRegKey
& keyDst
) 
 609     // copy all sub keys to the new location 
 612     bool bCont 
= GetFirstKey(strKey
, lIndex
); 
 613     while ( ok 
&& bCont 
) { 
 614         wxRegKey 
key(*this, strKey
); 
 616         keyName 
<< GetFullName(&keyDst
) << REG_SEPARATOR 
<< strKey
; 
 617         ok 
= key
.Copy(keyName
); 
 620             bCont 
= GetNextKey(strKey
, lIndex
); 
 622             wxLogError(_("Failed to copy the registry subkey '%s' to '%s'."), 
 623                    GetFullName(&key
), keyName
.c_str()); 
 629     bCont 
= GetFirstValue(strVal
, lIndex
); 
 630     while ( ok 
&& bCont 
) { 
 631         ok 
= CopyValue(strVal
, keyDst
); 
 634             wxLogSysError(m_dwLastError
, 
 635                           _("Failed to copy registry value '%s'"), 
 639             bCont 
= GetNextValue(strVal
, lIndex
); 
 644         wxLogError(_("Failed to copy the contents of registry key '%s' to '%s'."), 
 645                    GetFullName(this), GetFullName(&keyDst
)); 
 651 // ---------------------------------------------------------------------------- 
 652 // delete keys/values 
 653 // ---------------------------------------------------------------------------- 
 654 bool wxRegKey::DeleteSelf() 
 659       // it already doesn't exist - ok! 
 664   // prevent a buggy program from erasing one of the root registry keys or an 
 665   // immediate subkey (i.e. one which doesn't have '\\' inside) of any other 
 666   // key except HKCR (HKCR has some "deleteable" subkeys) 
 667   if ( m_strKey
.empty() || 
 668        ((m_hRootKey 
!= (WXHKEY
) aStdKeys
[HKCR
].hkey
) && 
 669         (m_strKey
.Find(REG_SEPARATOR
) == wxNOT_FOUND
)) ) { 
 670       wxLogError(_("Registry key '%s' is needed for normal system operation,\ndeleting it will leave your system in unusable state:\noperation aborted."), 
 676   // we can't delete keys while enumerating because it confuses GetNextKey, so 
 677   // we first save the key names and then delete them all 
 678   wxArrayString astrSubkeys
; 
 682   bool bCont 
= GetFirstKey(strKey
, lIndex
); 
 684     astrSubkeys
.Add(strKey
); 
 686     bCont 
= GetNextKey(strKey
, lIndex
); 
 689   size_t nKeyCount 
= astrSubkeys
.Count(); 
 690   for ( size_t nKey 
= 0; nKey 
< nKeyCount
; nKey
++ ) { 
 691     wxRegKey 
key(*this, astrSubkeys
[nKey
]); 
 692     if ( !key
.DeleteSelf() ) 
 696   // now delete this key itself 
 699   m_dwLastError 
= RegDeleteKey((HKEY
) m_hRootKey
, m_strKey
.wx_str()); 
 700   // deleting a key which doesn't exist is not considered an error 
 701   if ( m_dwLastError 
!= ERROR_SUCCESS 
&& 
 702           m_dwLastError 
!= ERROR_FILE_NOT_FOUND 
) { 
 703     wxLogSysError(m_dwLastError
, _("Can't delete key '%s'"), 
 711 bool wxRegKey::DeleteKey(const wxString
& szKey
) 
 716   wxRegKey 
key(*this, szKey
); 
 717   return key
.DeleteSelf(); 
 720 bool wxRegKey::DeleteValue(const wxString
& szValue
) 
 725     m_dwLastError 
= RegDeleteValue((HKEY
) m_hKey
, RegValueStr(szValue
)); 
 727     // deleting a value which doesn't exist is not considered an error 
 728     if ( (m_dwLastError 
!= ERROR_SUCCESS
) && 
 729          (m_dwLastError 
!= ERROR_FILE_NOT_FOUND
) ) 
 731         wxLogSysError(m_dwLastError
, _("Can't delete value '%s' from key '%s'"), 
 732                       szValue
, GetName().c_str()); 
 739 // ---------------------------------------------------------------------------- 
 740 // access to values and subkeys 
 741 // ---------------------------------------------------------------------------- 
 743 // return true if value exists 
 744 bool wxRegKey::HasValue(const wxString
& szValue
) const 
 746     // this function should be silent, so suppress possible messages from Open() 
 749     if ( !CONST_CAST 
Open(Read
) ) 
 752     LONG dwRet 
= ::RegQueryValueEx((HKEY
) m_hKey
, 
 753                                    RegValueStr(szValue
), 
 756     return dwRet 
== ERROR_SUCCESS
; 
 759 // returns true if this key has any values 
 760 bool wxRegKey::HasValues() const 
 762   // suppress possible messages from GetFirstValue() 
 765   // just call GetFirstValue with dummy parameters 
 768   return CONST_CAST 
GetFirstValue(str
, l
); 
 771 // returns true if this key has any subkeys 
 772 bool wxRegKey::HasSubkeys() const 
 774   // suppress possible messages from GetFirstKey() 
 777   // just call GetFirstKey with dummy parameters 
 780   return CONST_CAST 
GetFirstKey(str
, l
); 
 783 // returns true if given subkey exists 
 784 bool wxRegKey::HasSubKey(const wxString
& szKey
) const 
 786   // this function should be silent, so suppress possible messages from Open() 
 789   if ( !CONST_CAST 
Open(Read
) ) 
 792   return KeyExists(m_hKey
, szKey
); 
 795 wxRegKey::ValueType 
wxRegKey::GetValueType(const wxString
& szValue
) const 
 797     if ( ! CONST_CAST 
Open(Read
) ) 
 801     m_dwLastError 
= RegQueryValueEx((HKEY
) m_hKey
, RegValueStr(szValue
), RESERVED
, 
 802                                     &dwType
, NULL
, NULL
); 
 803     if ( m_dwLastError 
!= ERROR_SUCCESS 
) { 
 804       wxLogSysError(m_dwLastError
, _("Can't read value of key '%s'"), 
 809     return (ValueType
)dwType
; 
 812 bool wxRegKey::SetValue(const wxString
& szValue
, long lValue
) 
 814   if ( CONST_CAST 
Open() ) { 
 815     m_dwLastError 
= RegSetValueEx((HKEY
) m_hKey
, RegValueStr(szValue
), 
 816                                   (DWORD
) RESERVED
, REG_DWORD
, 
 817                                   (RegString
)&lValue
, sizeof(lValue
)); 
 818     if ( m_dwLastError 
== ERROR_SUCCESS 
) 
 822   wxLogSysError(m_dwLastError
, _("Can't set value of '%s'"), 
 823                 GetFullName(this, szValue
)); 
 827 bool wxRegKey::QueryValue(const wxString
& szValue
, long *plValue
) const 
 829   if ( CONST_CAST 
Open(Read
) ) { 
 830     DWORD dwType
, dwSize 
= sizeof(DWORD
); 
 831     RegString pBuf 
= (RegString
)plValue
; 
 832     m_dwLastError 
= RegQueryValueEx((HKEY
) m_hKey
, RegValueStr(szValue
), 
 834                                     &dwType
, pBuf
, &dwSize
); 
 835     if ( m_dwLastError 
!= ERROR_SUCCESS 
) { 
 836       wxLogSysError(m_dwLastError
, _("Can't read value of key '%s'"), 
 841       // check that we read the value of right type 
 842       wxASSERT_MSG( IsNumericValue(szValue
), 
 843                     wxT("Type mismatch in wxRegKey::QueryValue().")  ); 
 852 bool wxRegKey::SetValue(const wxString
& szValue
, const wxMemoryBuffer
& buffer
) 
 855   wxFAIL_MSG("RegSetValueEx not implemented by TWIN32"); 
 858   if ( CONST_CAST 
Open() ) { 
 859     m_dwLastError 
= RegSetValueEx((HKEY
) m_hKey
, RegValueStr(szValue
), 
 860                                   (DWORD
) RESERVED
, REG_BINARY
, 
 861                                   (RegBinary
)buffer
.GetData(),buffer
.GetDataLen()); 
 862     if ( m_dwLastError 
== ERROR_SUCCESS 
) 
 866   wxLogSysError(m_dwLastError
, _("Can't set value of '%s'"), 
 867                 GetFullName(this, szValue
)); 
 872 bool wxRegKey::QueryValue(const wxString
& szValue
, wxMemoryBuffer
& buffer
) const 
 874   if ( CONST_CAST 
Open(Read
) ) { 
 875     // first get the type and size of the data 
 876     DWORD dwType
, dwSize
; 
 877     m_dwLastError 
= RegQueryValueEx((HKEY
) m_hKey
, RegValueStr(szValue
), 
 879                                     &dwType
, NULL
, &dwSize
); 
 881     if ( m_dwLastError 
== ERROR_SUCCESS 
) { 
 883             const RegBinary pBuf 
= (RegBinary
)buffer
.GetWriteBuf(dwSize
); 
 884             m_dwLastError 
= RegQueryValueEx((HKEY
) m_hKey
, 
 885                                             RegValueStr(szValue
), 
 890             buffer
.UngetWriteBuf(dwSize
); 
 892             buffer
.SetDataLen(0); 
 897     if ( m_dwLastError 
!= ERROR_SUCCESS 
) { 
 898       wxLogSysError(m_dwLastError
, _("Can't read value of key '%s'"), 
 909 bool wxRegKey::QueryValue(const wxString
& szValue
, 
 911                           bool WXUNUSED_IN_WINCE(raw
)) const 
 913     if ( CONST_CAST 
Open(Read
) ) 
 916         // first get the type and size of the data 
 917         DWORD dwType
=REG_NONE
, dwSize
=0; 
 918         m_dwLastError 
= RegQueryValueEx((HKEY
) m_hKey
, 
 919                                         RegValueStr(szValue
), 
 921                                         &dwType
, NULL
, &dwSize
); 
 922         if ( m_dwLastError 
== ERROR_SUCCESS 
) 
 926                 // must treat this case specially as GetWriteBuf() doesn't like 
 927                 // being called with 0 size 
 932                 m_dwLastError 
= RegQueryValueEx((HKEY
) m_hKey
, 
 933                                                 RegValueStr(szValue
), 
 936                                                 (RegString
)(wxChar
*)wxStringBuffer(strValue
, dwSize
), 
 939                 // expand the var expansions in the string unless disabled 
 941                 if ( (dwType 
== REG_EXPAND_SZ
) && !raw 
) 
 943                     DWORD dwExpSize 
= ::ExpandEnvironmentStrings(strValue
.wx_str(), NULL
, 0); 
 944                     bool ok 
= dwExpSize 
!= 0; 
 947                         wxString strExpValue
; 
 948                         ok 
= ::ExpandEnvironmentStrings(strValue
.wx_str(), 
 949                                                         wxStringBuffer(strExpValue
, dwExpSize
), 
 952                         strValue 
= strExpValue
; 
 957                         wxLogLastError(_T("ExpandEnvironmentStrings")); 
 964             if ( m_dwLastError 
== ERROR_SUCCESS 
) 
 966                 // check that it was the right type 
 967                 wxASSERT_MSG( !IsNumericValue(szValue
), 
 968                               wxT("Type mismatch in wxRegKey::QueryValue().") ); 
 975     wxLogSysError(m_dwLastError
, _("Can't read value of '%s'"), 
 976                   GetFullName(this, szValue
)); 
 980 bool wxRegKey::SetValue(const wxString
& szValue
, const wxString
& strValue
) 
 982   if ( CONST_CAST 
Open() ) { 
 983       m_dwLastError 
= RegSetValueEx((HKEY
) m_hKey
, 
 984                                     RegValueStr(szValue
), 
 985                                     (DWORD
) RESERVED
, REG_SZ
, 
 986                                     (RegString
)strValue
.wx_str(), 
 987                                     (strValue
.Len() + 1)*sizeof(wxChar
)); 
 988       if ( m_dwLastError 
== ERROR_SUCCESS 
) 
 992   wxLogSysError(m_dwLastError
, _("Can't set value of '%s'"), 
 993                 GetFullName(this, szValue
)); 
 997 wxString 
wxRegKey::QueryDefaultValue() const 
1000   QueryValue(wxEmptyString
, str
, false); 
1004 // ---------------------------------------------------------------------------- 
1006 // NB: all these functions require an index variable which allows to have 
1007 //     several concurrently running indexations on the same key 
1008 // ---------------------------------------------------------------------------- 
1010 bool wxRegKey::GetFirstValue(wxString
& strValueName
, long& lIndex
) 
1016   return GetNextValue(strValueName
, lIndex
); 
1019 bool wxRegKey::GetNextValue(wxString
& strValueName
, long& lIndex
) const 
1021   wxASSERT( IsOpened() ); 
1023   // are we already at the end of enumeration? 
1027     wxChar  szValueName
[1024];                  // @@ use RegQueryInfoKey... 
1028     DWORD dwValueLen 
= WXSIZEOF(szValueName
); 
1030     m_dwLastError 
= RegEnumValue((HKEY
) m_hKey
, lIndex
++, 
1031                                  szValueName
, &dwValueLen
, 
1034                                  NULL
,            // [out] buffer for value 
1035                                  NULL
);           // [i/o]  it's length 
1037     if ( m_dwLastError 
!= ERROR_SUCCESS 
) { 
1038       if ( m_dwLastError 
== ERROR_NO_MORE_ITEMS 
) { 
1039         m_dwLastError 
= ERROR_SUCCESS
; 
1043         wxLogSysError(m_dwLastError
, _("Can't enumerate values of key '%s'"), 
1050     strValueName 
= szValueName
; 
1055 bool wxRegKey::GetFirstKey(wxString
& strKeyName
, long& lIndex
) 
1061   return GetNextKey(strKeyName
, lIndex
); 
1064 bool wxRegKey::GetNextKey(wxString
& strKeyName
, long& lIndex
) const 
1066   wxASSERT( IsOpened() ); 
1068   // are we already at the end of enumeration? 
1072   wxChar szKeyName
[_MAX_PATH 
+ 1]; 
1075   DWORD sizeName 
= WXSIZEOF(szKeyName
); 
1076   m_dwLastError 
= RegEnumKeyEx((HKEY
) m_hKey
, lIndex
++, szKeyName
, & sizeName
, 
1077       0, NULL
, NULL
, NULL
); 
1079   m_dwLastError 
= RegEnumKey((HKEY
) m_hKey
, lIndex
++, szKeyName
, WXSIZEOF(szKeyName
)); 
1082   if ( m_dwLastError 
!= ERROR_SUCCESS 
) { 
1083     if ( m_dwLastError 
== ERROR_NO_MORE_ITEMS 
) { 
1084       m_dwLastError 
= ERROR_SUCCESS
; 
1088       wxLogSysError(m_dwLastError
, _("Can't enumerate subkeys of key '%s'"), 
1095   strKeyName 
= szKeyName
; 
1099 // returns true if the value contains a number (else it's some string) 
1100 bool wxRegKey::IsNumericValue(const wxString
& szValue
) const 
1102     ValueType type 
= GetValueType(szValue
); 
1105         /* case Type_Dword_little_endian: == Type_Dword */ 
1106         case Type_Dword_big_endian
: 
1114 // ---------------------------------------------------------------------------- 
1115 // exporting registry keys to file 
1116 // ---------------------------------------------------------------------------- 
1120 // helper functions for writing ASCII strings (even in Unicode build) 
1121 static inline bool WriteAsciiChar(wxOutputStream
& ostr
, char ch
) 
1127 static inline bool WriteAsciiEOL(wxOutputStream
& ostr
) 
1129     // as we open the file in text mode, it is enough to write LF without CR 
1130     return WriteAsciiChar(ostr
, '\n'); 
1133 static inline bool WriteAsciiString(wxOutputStream
& ostr
, const char *p
) 
1135     return ostr
.Write(p
, strlen(p
)).IsOk(); 
1138 static inline bool WriteAsciiString(wxOutputStream
& ostr
, const wxString
& s
) 
1141     wxCharBuffer 
name(s
.mb_str()); 
1142     ostr
.Write(name
, strlen(name
)); 
1144     ostr
.Write(s
.mb_str(), s
.length()); 
1150 #endif // wxUSE_STREAMS 
1152 bool wxRegKey::Export(const wxString
& filename
) const 
1154 #if wxUSE_FFILE && wxUSE_STREAMS 
1155     if ( wxFile::Exists(filename
) ) 
1157         wxLogError(_("Exporting registry key: file \"%s\" already exists and won't be overwritten."), 
1162     wxFFileOutputStream 
ostr(filename
, _T("w")); 
1164     return ostr
.Ok() && Export(ostr
); 
1166     wxUnusedVar(filename
); 
1172 bool wxRegKey::Export(wxOutputStream
& ostr
) const 
1174     // write out the header 
1175     if ( !WriteAsciiString(ostr
, "REGEDIT4\n\n") ) 
1178     return DoExport(ostr
); 
1180 #endif // wxUSE_STREAMS 
1184 FormatAsHex(const void *data
, 
1186             wxRegKey::ValueType type 
= wxRegKey::Type_Binary
) 
1188     wxString 
value(_T("hex")); 
1190     // binary values use just "hex:" prefix while the other ones must indicate 
1192     if ( type 
!= wxRegKey::Type_Binary 
) 
1193         value 
<< _T('(') << type 
<< _T(')'); 
1196     // write all the rest as comma-separated bytes 
1197     value
.reserve(3*size 
+ 10); 
1198     const char * const p 
= wx_static_cast(const char *, data
); 
1199     for ( size_t n 
= 0; n 
< size
; n
++ ) 
1201         // TODO: line wrapping: although not required by regedit, this makes 
1202         //       the generated files easier to read and compare with the files 
1203         //       produced by regedit 
1207         value 
<< wxString::Format(_T("%02x"), (unsigned char)p
[n
]); 
1214 wxString 
FormatAsHex(const wxString
& value
, wxRegKey::ValueType type
) 
1216     return FormatAsHex(value
.c_str(), value
.length() + 1, type
); 
1219 wxString 
wxRegKey::FormatValue(const wxString
& name
) const 
1222     const ValueType type 
= GetValueType(name
); 
1228                 if ( !QueryValue(name
, value
) ) 
1231                 // quotes and backslashes must be quoted, linefeeds are not 
1232                 // allowed in string values 
1233                 rhs
.reserve(value
.length() + 2); 
1236                 // there can be no NULs here 
1237                 bool useHex 
= false; 
1238                 for ( wxString::const_iterator p 
= value
.begin(); 
1239                       p 
!= value
.end() && !useHex
; ++p 
) 
1241                     switch ( (*p
).GetValue() ) 
1244                             // we can only represent this string in hex 
1250                             // escape special symbol 
1260                     rhs 
= FormatAsHex(value
, Type_String
); 
1267         /* case Type_Dword_little_endian: == Type_Dword */ 
1270                 if ( !QueryValue(name
, &value
) ) 
1273                 rhs
.Printf(_T("dword:%08x"), (unsigned int)value
); 
1277         case Type_Expand_String
: 
1278         case Type_Multi_String
: 
1281                 if ( !QueryRawValue(name
, value
) ) 
1284                 rhs 
= FormatAsHex(value
, type
); 
1291                 if ( !QueryValue(name
, buf
) ) 
1294                 rhs 
= FormatAsHex(buf
.GetData(), buf
.GetDataLen()); 
1298         // no idea how those appear in REGEDIT4 files 
1300         case Type_Dword_big_endian
: 
1302         case Type_Resource_list
: 
1303         case Type_Full_resource_descriptor
: 
1304         case Type_Resource_requirements_list
: 
1306             wxLogWarning(_("Can't export value of unsupported type %d."), type
); 
1314 bool wxRegKey::DoExportValue(wxOutputStream
& ostr
, const wxString
& name
) const 
1316     // first examine the value type: if it's unsupported, simply skip it 
1317     // instead of aborting the entire export process because we failed to 
1318     // export a single value 
1319     wxString value 
= FormatValue(name
); 
1320     if ( value
.empty() ) 
1322         wxLogWarning(_("Ignoring value \"%s\" of the key \"%s\"."), 
1323                      name
.c_str(), GetName().c_str()); 
1327     // we do have the text representation of the value, now write everything 
1330     // special case: unnamed/default value is represented as just "@" 
1333         if ( !WriteAsciiChar(ostr
, '@') ) 
1336     else // normal, named, value 
1338         if ( !WriteAsciiChar(ostr
, '"') || 
1339                 !WriteAsciiString(ostr
, name
) || 
1340                     !WriteAsciiChar(ostr
, '"') ) 
1344     if ( !WriteAsciiChar(ostr
, '=') ) 
1347     return WriteAsciiString(ostr
, value
) && WriteAsciiEOL(ostr
); 
1350 bool wxRegKey::DoExport(wxOutputStream
& ostr
) const 
1352     // write out this key name 
1353     if ( !WriteAsciiChar(ostr
, '[') ) 
1356     if ( !WriteAsciiString(ostr
, GetName(false /* no short prefix */)) ) 
1359     if ( !WriteAsciiChar(ostr
, ']') || !WriteAsciiEOL(ostr
) ) 
1362     // dump all our values 
1365     wxRegKey
& self 
= wx_const_cast(wxRegKey
&, *this); 
1366     bool cont 
= self
.GetFirstValue(name
, dummy
); 
1369         if ( !DoExportValue(ostr
, name
) ) 
1372         cont 
= GetNextValue(name
, dummy
); 
1375     // always terminate values by blank line, even if there were no values 
1376     if ( !WriteAsciiEOL(ostr
) ) 
1379     // recurse to subkeys 
1380     cont 
= self
.GetFirstKey(name
, dummy
); 
1383         wxRegKey 
subkey(*this, name
); 
1384         if ( !subkey
.DoExport(ostr
) ) 
1387         cont 
= GetNextKey(name
, dummy
); 
1393 #endif // wxUSE_STREAMS 
1395 // ============================================================================ 
1396 // implementation of global private functions 
1397 // ============================================================================ 
1399 bool KeyExists(WXHKEY hRootKey
, const wxString
& szKey
) 
1401     // don't close this key itself for the case of empty szKey! 
1402     if ( szKey
.empty() ) 
1411             KEY_READ
,        // we might not have enough rights for rw access 
1413          ) == ERROR_SUCCESS 
) 
1415         ::RegCloseKey(hkeyDummy
); 
1423 wxString 
GetFullName(const wxRegKey 
*pKey
, const wxString
& szValue
) 
1425   wxString 
str(pKey
->GetName()); 
1426   if ( !szValue
.empty() ) 
1427     str 
<< wxT("\\") << szValue
; 
1432 wxString 
GetFullName(const wxRegKey 
*pKey
) 
1434   return pKey
->GetName(); 
1437 inline void RemoveTrailingSeparator(wxString
& str
) 
1439   if ( !str
.empty() && str
.Last() == REG_SEPARATOR 
) 
1440     str
.Truncate(str
.Len() - 1); 
1443 inline const wxChar 
*RegValueStr(const wxString
& szValue
) 
1445     return szValue
.empty() ? (const wxChar
*)NULL 
: szValue
.wx_str();