1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/registry.cpp
3 // Purpose:     implementation of registry classes and functions
4 // Author:      Vadim Zeitlin
5 // Modified by:
6 // Created:     03.04.98
7 // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Licence:     wxWindows licence
9 // TODO:        - parsing of registry key names
10 //              - support of other (than REG_SZ/REG_DWORD) registry types
11 //              - add high level functions (RegisterOleServer, ...)
12 ///////////////////////////////////////////////////////////////////////////////
13 
14 // for compilers that support precompilation, includes "wx.h".
15 #include  "wx/wxprec.h"
16 
17 #ifdef __BORLANDC__
18     #pragma hdrstop
19 #endif
20 
21 #if wxUSE_REGKEY
22 
23 #ifndef WX_PRECOMP
24     #include "wx/msw/wrapwin.h"
25     #include "wx/string.h"
26     #include "wx/intl.h"
27     #include "wx/log.h"
28     #include "wx/crt.h"
29     #include "wx/utils.h"
30 #endif
31 
32 #include "wx/dynlib.h"
33 #include "wx/file.h"
34 #include "wx/wfstream.h"
35 #include "wx/msw/private.h"
36 
37 // Windows headers
38 #ifdef __WXWINCE__
39 #include <winbase.h>
40 #include <winreg.h>
41 #endif
42 
43 // other std headers
44 #include  <stdlib.h>      // for _MAX_PATH
45 
46 #ifndef _MAX_PATH
47     #define _MAX_PATH 512
48 #endif
49 
50 // our header
51 #define   HKEY_DEFINED    // already defined in windows.h
52 #include  "wx/msw/registry.h"
53 
54 // some registry functions don't like signed chars
55 typedef unsigned char *RegString;
56 typedef BYTE* RegBinary;
57 
58 #ifndef HKEY_PERFORMANCE_DATA
59     #define HKEY_PERFORMANCE_DATA ((HKEY)0x80000004)
60 #endif
61 
62 #ifndef HKEY_CURRENT_CONFIG
63     #define HKEY_CURRENT_CONFIG ((HKEY)0x80000005)
64 #endif
65 
66 #ifndef HKEY_DYN_DATA
67     #define HKEY_DYN_DATA ((HKEY)0x80000006)
68 #endif
69 
70 #ifndef KEY_WOW64_64KEY
71     #define KEY_WOW64_64KEY 0x0100
72 #endif
73 
74 // ----------------------------------------------------------------------------
75 // constants
76 // ----------------------------------------------------------------------------
77 
78 // the standard key names, short names and handles all bundled together for
79 // convenient access
80 static struct
81 {
82   HKEY        hkey;
83   const wxChar *szName;
84   const wxChar *szShortName;
85 }
86 aStdKeys[] =
87 {
88   { HKEY_CLASSES_ROOT,      wxT("HKEY_CLASSES_ROOT"),      wxT("HKCR") },
89   { HKEY_CURRENT_USER,      wxT("HKEY_CURRENT_USER"),      wxT("HKCU") },
90   { HKEY_LOCAL_MACHINE,     wxT("HKEY_LOCAL_MACHINE"),     wxT("HKLM") },
91   { HKEY_USERS,             wxT("HKEY_USERS"),             wxT("HKU")  }, // short name?
92   { HKEY_PERFORMANCE_DATA,  wxT("HKEY_PERFORMANCE_DATA"),  wxT("HKPD") },
93   { HKEY_CURRENT_CONFIG,    wxT("HKEY_CURRENT_CONFIG"),    wxT("HKCC") },
94   { HKEY_DYN_DATA,          wxT("HKEY_DYN_DATA"),          wxT("HKDD") }, // short name?
95 };
96 
97 // the registry name separator (perhaps one day MS will change it to '/' ;-)
98 #define   REG_SEPARATOR     wxT('\\')
99 
100 // useful for Windows programmers: makes somewhat more clear all these zeroes
101 // being passed to Windows APIs
102 #define   RESERVED        (0)
103 
104 // ----------------------------------------------------------------------------
105 // macros
106 // ----------------------------------------------------------------------------
107 
108 // const_cast<> is not yet supported by all compilers
109 #define CONST_CAST    ((wxRegKey *)this)->
110 
111 // and neither is mutable which m_dwLastError should be
112 #define m_dwLastError   CONST_CAST m_dwLastError
113 
114 // ----------------------------------------------------------------------------
115 // non member functions
116 // ----------------------------------------------------------------------------
117 
118 // removes the trailing backslash from the string if it has one
119 static inline void RemoveTrailingSeparator(wxString& str);
120 
121 // returns true if given registry key exists
122 static bool KeyExists(
123     WXHKEY hRootKey,
124     const wxString& szKey,
125     wxRegKey::WOW64ViewMode viewMode = wxRegKey::WOW64ViewMode_Default);
126 
127 // return the WOW64 registry view flag which can be used with MSW registry
128 // functions for opening the key in the specified view
129 static long GetMSWViewFlags(wxRegKey::WOW64ViewMode viewMode);
130 
131 // return the access rights which can be used with MSW registry functions for
132 // opening the key in the specified mode
133 static long
134 GetMSWAccessFlags(wxRegKey::AccessMode mode, wxRegKey::WOW64ViewMode viewMode);
135 
136 // combines value and key name
137 static wxString GetFullName(const wxRegKey *pKey);
138 static wxString GetFullName(const wxRegKey *pKey, const wxString& szValue);
139 
140 // returns "value" argument of wxRegKey methods converted into a value that can
141 // be passed to win32 registry functions; specifically, converts empty string
142 // to NULL
143 static inline const wxChar *RegValueStr(const wxString& szValue);
144 
145 // ============================================================================
146 // implementation of wxRegKey class
147 // ============================================================================
148 
149 // ----------------------------------------------------------------------------
150 // static functions and variables
151 // ----------------------------------------------------------------------------
152 
153 const size_t wxRegKey::nStdKeys = WXSIZEOF(aStdKeys);
154 
155 // @@ should take a `StdKey key', but as it's often going to be used in loops
156 //    it would require casts in user code.
GetStdKeyName(size_t key)157 const wxChar *wxRegKey::GetStdKeyName(size_t key)
158 {
159   // return empty string if key is invalid
160   wxCHECK_MSG( key < nStdKeys, wxEmptyString, wxT("invalid key in wxRegKey::GetStdKeyName") );
161 
162   return aStdKeys[key].szName;
163 }
164 
GetStdKeyShortName(size_t key)165 const wxChar *wxRegKey::GetStdKeyShortName(size_t key)
166 {
167   // return empty string if key is invalid
168   wxCHECK( key < nStdKeys, wxEmptyString );
169 
170   return aStdKeys[key].szShortName;
171 }
172 
ExtractKeyName(wxString & strKey)173 wxRegKey::StdKey wxRegKey::ExtractKeyName(wxString& strKey)
174 {
175   wxString strRoot = strKey.BeforeFirst(REG_SEPARATOR);
176 
177   size_t ui;
178   for ( ui = 0; ui < nStdKeys; ui++ ) {
179     if ( strRoot.CmpNoCase(aStdKeys[ui].szName) == 0 ||
180          strRoot.CmpNoCase(aStdKeys[ui].szShortName) == 0 ) {
181       break;
182     }
183   }
184 
185   if ( ui == nStdKeys ) {
186     wxFAIL_MSG(wxT("invalid key prefix in wxRegKey::ExtractKeyName."));
187 
188     ui = HKCR;
189   }
190   else {
191     strKey = strKey.After(REG_SEPARATOR);
192     if ( !strKey.empty() && strKey.Last() == REG_SEPARATOR )
193       strKey.Truncate(strKey.Len() - 1);
194   }
195 
196   return (StdKey)ui;
197 }
198 
GetStdKeyFromHkey(WXHKEY hkey)199 wxRegKey::StdKey wxRegKey::GetStdKeyFromHkey(WXHKEY hkey)
200 {
201   for ( size_t ui = 0; ui < nStdKeys; ui++ ) {
202     if ( aStdKeys[ui].hkey == (HKEY)hkey )
203       return (StdKey)ui;
204   }
205 
206   wxFAIL_MSG(wxT("non root hkey passed to wxRegKey::GetStdKeyFromHkey."));
207 
208   return HKCR;
209 }
210 
211 // ----------------------------------------------------------------------------
212 // ctors and dtor
213 // ----------------------------------------------------------------------------
214 
wxRegKey(WOW64ViewMode viewMode)215 wxRegKey::wxRegKey(WOW64ViewMode viewMode) : m_viewMode(viewMode)
216 {
217   m_hRootKey = (WXHKEY) aStdKeys[HKCR].hkey;
218 
219   Init();
220 }
221 
wxRegKey(const wxString & strKey,WOW64ViewMode viewMode)222 wxRegKey::wxRegKey(const wxString& strKey, WOW64ViewMode viewMode)
223     : m_strKey(strKey), m_viewMode(viewMode)
224 {
225   m_hRootKey  = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey;
226 
227   Init();
228 }
229 
230 // parent is a predefined (and preopened) key
wxRegKey(StdKey keyParent,const wxString & strKey,WOW64ViewMode viewMode)231 wxRegKey::wxRegKey(StdKey keyParent,
232                    const wxString& strKey,
233                    WOW64ViewMode viewMode)
234     : m_strKey(strKey), m_viewMode(viewMode)
235 {
236   RemoveTrailingSeparator(m_strKey);
237   m_hRootKey  = (WXHKEY) aStdKeys[keyParent].hkey;
238 
239   Init();
240 }
241 
242 // parent is a normal regkey
wxRegKey(const wxRegKey & keyParent,const wxString & strKey)243 wxRegKey::wxRegKey(const wxRegKey& keyParent, const wxString& strKey)
244     : m_strKey(keyParent.m_strKey), m_viewMode(keyParent.GetView())
245 {
246   // combine our name with parent's to get the full name
247   if ( !m_strKey.empty() &&
248        (strKey.empty() || strKey[0] != REG_SEPARATOR) ) {
249       m_strKey += REG_SEPARATOR;
250   }
251 
252   m_strKey += strKey;
253   RemoveTrailingSeparator(m_strKey);
254 
255   m_hRootKey  = keyParent.m_hRootKey;
256 
257   Init();
258 }
259 
260 // dtor closes the key releasing system resource
~wxRegKey()261 wxRegKey::~wxRegKey()
262 {
263   Close();
264 }
265 
266 // ----------------------------------------------------------------------------
267 // change the key name/hkey
268 // ----------------------------------------------------------------------------
269 
270 // set the full key name
SetName(const wxString & strKey)271 void wxRegKey::SetName(const wxString& strKey)
272 {
273   Close();
274 
275   m_strKey = strKey;
276   m_hRootKey = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey;
277 }
278 
279 // the name is relative to the parent key
SetName(StdKey keyParent,const wxString & strKey)280 void wxRegKey::SetName(StdKey keyParent, const wxString& strKey)
281 {
282   Close();
283 
284   m_strKey = strKey;
285   RemoveTrailingSeparator(m_strKey);
286   m_hRootKey = (WXHKEY) aStdKeys[keyParent].hkey;
287 }
288 
289 // the name is relative to the parent key
SetName(const wxRegKey & keyParent,const wxString & strKey)290 void wxRegKey::SetName(const wxRegKey& keyParent, const wxString& strKey)
291 {
292   Close();
293 
294   // combine our name with parent's to get the full name
295 
296   // NB: this method is called by wxRegConfig::SetPath() which is a performance
297   //     critical function and so it preallocates space for our m_strKey to
298   //     gain some speed - this is why we only use += here and not = which
299   //     would just free the prealloc'd buffer and would have to realloc it the
300   //     next line!
301   m_strKey.clear();
302   m_strKey += keyParent.m_strKey;
303   if ( !strKey.empty() && strKey[0] != REG_SEPARATOR )
304     m_strKey += REG_SEPARATOR;
305   m_strKey += strKey;
306 
307   RemoveTrailingSeparator(m_strKey);
308 
309   m_hRootKey = keyParent.m_hRootKey;
310 }
311 
312 // hKey should be opened and will be closed in wxRegKey dtor
SetHkey(WXHKEY hKey)313 void wxRegKey::SetHkey(WXHKEY hKey)
314 {
315   Close();
316 
317   m_hKey = hKey;
318 
319   // we don't know the parent of this key, assume HKLM by default
320   m_hRootKey = HKEY_LOCAL_MACHINE;
321 
322   // we don't know in which mode was this key opened but we can't reopen it
323   // anyhow because we don't know its name, so the only thing we can is to hope
324   // that it allows all the operations which we're going to perform on it
325   m_mode = Write;
326 
327   // reset old data
328   m_strKey.clear();
329   m_dwLastError = 0;
330 }
331 
332 // ----------------------------------------------------------------------------
333 // info about the key
334 // ----------------------------------------------------------------------------
335 
336 // returns true if the key exists
Exists() const337 bool wxRegKey::Exists() const
338 {
339   // opened key has to exist, try to open it if not done yet
340   return IsOpened()
341       ? true
342       : KeyExists(m_hRootKey, m_strKey, m_viewMode);
343 }
344 
345 // returns the full name of the key (prefix is abbreviated if bShortPrefix)
GetName(bool bShortPrefix) const346 wxString wxRegKey::GetName(bool bShortPrefix) const
347 {
348   StdKey key = GetStdKeyFromHkey((WXHKEY) m_hRootKey);
349   wxString str = bShortPrefix ? aStdKeys[key].szShortName
350                               : aStdKeys[key].szName;
351   if ( !m_strKey.empty() )
352     str << wxT("\\") << m_strKey;
353 
354   return str;
355 }
356 
GetKeyInfo(size_t * pnSubKeys,size_t * pnMaxKeyLen,size_t * pnValues,size_t * pnMaxValueLen) const357 bool wxRegKey::GetKeyInfo(size_t *pnSubKeys,
358                           size_t *pnMaxKeyLen,
359                           size_t *pnValues,
360                           size_t *pnMaxValueLen) const
361 {
362   // it might be unexpected to some that this function doesn't open the key
363   wxASSERT_MSG( IsOpened(), wxT("key should be opened in GetKeyInfo") );
364 
365   // We need to use intermediate variables in 64 bit build as the function
366   // parameters must be 32 bit DWORDs and not 64 bit size_t values.
367 #ifdef __WIN64__
368   DWORD dwSubKeys = 0,
369         dwMaxKeyLen = 0,
370         dwValues = 0,
371         dwMaxValueLen = 0;
372 
373   #define REG_PARAM(name) &dw##name
374 #else // Win32
375   // Old gcc headers incorrectly prototype RegQueryInfoKey() as taking
376   // size_t but normally we need a cast, even when sizeof(size_t) is the same
377   // as sizeof(DWORD).
378   #if defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__)
379     #define REG_PARAM(name) pn##name
380   #else
381     #define REG_PARAM(name)   (LPDWORD)(pn##name)
382   #endif
383 #endif
384 
385 
386   m_dwLastError = ::RegQueryInfoKey
387                   (
388                     (HKEY) m_hKey,
389                     NULL,                   // class name
390                     NULL,                   // (ptr to) size of class name buffer
391                     RESERVED,
392                     REG_PARAM(SubKeys),     // [out] number of subkeys
393                     REG_PARAM(MaxKeyLen),   // [out] max length of a subkey name
394                     NULL,                   // longest subkey class name
395                     REG_PARAM(Values),      // [out] number of values
396                     REG_PARAM(MaxValueLen), // [out] max length of a value name
397                     NULL,                   // longest value data
398                     NULL,                   // security descriptor
399                     NULL                    // time of last modification
400                   );
401 
402 #ifdef __WIN64__
403   if ( pnSubKeys )
404     *pnSubKeys = dwSubKeys;
405   if ( pnMaxKeyLen )
406     *pnMaxKeyLen = dwMaxKeyLen;
407   if ( pnValues )
408     *pnValues = dwValues;
409   if ( pnMaxValueLen )
410     *pnMaxValueLen = dwMaxValueLen;
411 #endif // __WIN64__
412 
413 #undef REG_PARAM
414 
415   if ( m_dwLastError != ERROR_SUCCESS ) {
416     wxLogSysError(m_dwLastError, _("Can't get info about registry key '%s'"),
417                   GetName().c_str());
418     return false;
419   }
420 
421   return true;
422 }
423 
424 // ----------------------------------------------------------------------------
425 // operations
426 // ----------------------------------------------------------------------------
427 
428 // opens key (it's not an error to call Open() on an already opened key)
Open(AccessMode mode)429 bool wxRegKey::Open(AccessMode mode)
430 {
431     if ( IsOpened() )
432     {
433         if ( mode <= m_mode )
434             return true;
435 
436         // we had been opened in read mode but now must be reopened in write
437         Close();
438     }
439 
440     HKEY tmpKey;
441     m_dwLastError = ::RegOpenKeyEx
442                     (
443                         (HKEY) m_hRootKey,
444                         m_strKey.t_str(),
445                         RESERVED,
446                         GetMSWAccessFlags(mode, m_viewMode),
447                         &tmpKey
448                     );
449 
450     if ( m_dwLastError != ERROR_SUCCESS )
451     {
452         wxLogSysError(m_dwLastError, _("Can't open registry key '%s'"),
453                       GetName().c_str());
454         return false;
455     }
456 
457     m_hKey = (WXHKEY) tmpKey;
458     m_mode = mode;
459 
460     return true;
461 }
462 
463 // creates key, failing if it exists and !bOkIfExists
Create(bool bOkIfExists)464 bool wxRegKey::Create(bool bOkIfExists)
465 {
466   // check for existence only if asked (i.e. order is important!)
467   if ( !bOkIfExists && Exists() )
468     return false;
469 
470   if ( IsOpened() )
471     return true;
472 
473   HKEY tmpKey;
474   DWORD disposition;
475   // Minimum supported OS for RegCreateKeyEx: Win 95, Win NT 3.1, Win CE 1.0
476   m_dwLastError = RegCreateKeyEx((HKEY) m_hRootKey, m_strKey.t_str(),
477       0,    // reserved and must be 0
478       NULL, // The user-defined class type of this key.
479       REG_OPTION_NON_VOLATILE, // supports other values as well; see MS docs
480       GetMSWAccessFlags(wxRegKey::Write, m_viewMode),
481       NULL, // pointer to a SECURITY_ATTRIBUTES structure
482       &tmpKey,
483       &disposition);
484 
485   if ( m_dwLastError != ERROR_SUCCESS ) {
486     wxLogSysError(m_dwLastError, _("Can't create registry key '%s'"),
487                   GetName().c_str());
488     return false;
489   }
490   else
491   {
492     m_hKey = (WXHKEY) tmpKey;
493     return true;
494   }
495 }
496 
497 // close the key, it's not an error to call it when not opened
Close()498 bool wxRegKey::Close()
499 {
500   if ( IsOpened() ) {
501     m_dwLastError = RegCloseKey((HKEY) m_hKey);
502     m_hKey = 0;
503 
504     if ( m_dwLastError != ERROR_SUCCESS ) {
505       wxLogSysError(m_dwLastError, _("Can't close registry key '%s'"),
506                     GetName().c_str());
507 
508       return false;
509     }
510   }
511 
512   return true;
513 }
514 
515 bool
RenameValue(const wxString & szValueOld,const wxString & szValueNew)516 wxRegKey::RenameValue(const wxString& szValueOld, const wxString& szValueNew)
517 {
518     bool ok = true;
519     if ( HasValue(szValueNew) ) {
520         wxLogError(_("Registry value '%s' already exists."), szValueNew);
521 
522         ok = false;
523     }
524 
525     if ( !ok ||
526          !CopyValue(szValueOld, *this, szValueNew) ||
527          !DeleteValue(szValueOld) ) {
528         wxLogError(_("Failed to rename registry value '%s' to '%s'."),
529                    szValueOld, szValueNew);
530 
531         return false;
532     }
533 
534     return true;
535 }
536 
CopyValue(const wxString & szValue,wxRegKey & keyDst,const wxString & szValueNew)537 bool wxRegKey::CopyValue(const wxString& szValue,
538                          wxRegKey& keyDst,
539                          const wxString& szValueNew)
540 {
541     wxString valueNew(szValueNew);
542     if ( valueNew.empty() ) {
543         // by default, use the same name
544         valueNew = szValue;
545     }
546 
547     switch ( GetValueType(szValue) ) {
548         case Type_String:
549             {
550                 wxString strVal;
551                 return QueryValue(szValue, strVal) &&
552                        keyDst.SetValue(valueNew, strVal);
553             }
554 
555         case Type_Dword:
556         /* case Type_Dword_little_endian: == Type_Dword */
557             {
558                 long dwVal;
559                 return QueryValue(szValue, &dwVal) &&
560                        keyDst.SetValue(valueNew, dwVal);
561             }
562 
563         case Type_Binary:
564         {
565             wxMemoryBuffer buf;
566             return QueryValue(szValue,buf) &&
567                    keyDst.SetValue(valueNew,buf);
568         }
569 
570         // these types are unsupported because I am not sure about how
571         // exactly they should be copied and because they shouldn't
572         // occur among the application keys (supposedly created with
573         // this class)
574         case Type_None:
575         case Type_Expand_String:
576         case Type_Dword_big_endian:
577         case Type_Link:
578         case Type_Multi_String:
579         case Type_Resource_list:
580         case Type_Full_resource_descriptor:
581         case Type_Resource_requirements_list:
582         default:
583             wxLogError(_("Can't copy values of unsupported type %d."),
584                        GetValueType(szValue));
585             return false;
586     }
587 }
588 
Rename(const wxString & szNewName)589 bool wxRegKey::Rename(const wxString& szNewName)
590 {
591     wxCHECK_MSG( !m_strKey.empty(), false, wxT("registry hives can't be renamed") );
592 
593     if ( !Exists() ) {
594         wxLogError(_("Registry key '%s' does not exist, cannot rename it."),
595                    GetFullName(this));
596 
597         return false;
598     }
599 
600     // do we stay in the same hive?
601     bool inSameHive = !wxStrchr(szNewName, REG_SEPARATOR);
602 
603     // construct the full new name of the key
604     wxRegKey keyDst;
605 
606     if ( inSameHive ) {
607         // rename the key to the new name under the same parent
608         wxString strKey = m_strKey.BeforeLast(REG_SEPARATOR);
609         if ( !strKey.empty() ) {
610             // don't add '\\' in the start if strFullNewName is empty
611             strKey += REG_SEPARATOR;
612         }
613 
614         strKey += szNewName;
615 
616         keyDst.SetName(GetStdKeyFromHkey(m_hRootKey), strKey);
617     }
618     else {
619         // this is the full name already
620         keyDst.SetName(szNewName);
621     }
622 
623     bool ok = keyDst.Create(false /* fail if alredy exists */);
624     if ( !ok ) {
625         wxLogError(_("Registry key '%s' already exists."),
626                    GetFullName(&keyDst));
627     }
628     else {
629         ok = Copy(keyDst) && DeleteSelf();
630     }
631 
632     if ( !ok ) {
633         wxLogError(_("Failed to rename the registry key '%s' to '%s'."),
634                    GetFullName(this), GetFullName(&keyDst));
635     }
636     else {
637         m_hRootKey = keyDst.m_hRootKey;
638         m_strKey = keyDst.m_strKey;
639     }
640 
641     return ok;
642 }
643 
Copy(const wxString & szNewName)644 bool wxRegKey::Copy(const wxString& szNewName)
645 {
646     // create the new key first
647     wxRegKey keyDst(szNewName);
648     bool ok = keyDst.Create(false /* fail if alredy exists */);
649     if ( ok ) {
650         ok = Copy(keyDst);
651 
652         // we created the dest key but copying to it failed - delete it
653         if ( !ok ) {
654             (void)keyDst.DeleteSelf();
655         }
656     }
657 
658     return ok;
659 }
660 
Copy(wxRegKey & keyDst)661 bool wxRegKey::Copy(wxRegKey& keyDst)
662 {
663     bool ok = true;
664 
665     // copy all sub keys to the new location
666     wxString strKey;
667     long lIndex;
668     bool bCont = GetFirstKey(strKey, lIndex);
669     while ( ok && bCont ) {
670         wxRegKey key(*this, strKey);
671         wxString keyName;
672         keyName << GetFullName(&keyDst) << REG_SEPARATOR << strKey;
673         ok = key.Copy(keyName);
674 
675         if ( ok )
676             bCont = GetNextKey(strKey, lIndex);
677         else
678             wxLogError(_("Failed to copy the registry subkey '%s' to '%s'."),
679                    GetFullName(&key), keyName.c_str());
680 
681     }
682 
683     // copy all values
684     wxString strVal;
685     bCont = GetFirstValue(strVal, lIndex);
686     while ( ok && bCont ) {
687         ok = CopyValue(strVal, keyDst);
688 
689         if ( !ok ) {
690             wxLogSysError(m_dwLastError,
691                           _("Failed to copy registry value '%s'"),
692                           strVal.c_str());
693         }
694         else {
695             bCont = GetNextValue(strVal, lIndex);
696         }
697     }
698 
699     if ( !ok ) {
700         wxLogError(_("Failed to copy the contents of registry key '%s' to '%s'."),
701                    GetFullName(this), GetFullName(&keyDst));
702     }
703 
704     return ok;
705 }
706 
707 // ----------------------------------------------------------------------------
708 // delete keys/values
709 // ----------------------------------------------------------------------------
DeleteSelf()710 bool wxRegKey::DeleteSelf()
711 {
712   {
713     wxLogNull nolog;
714     if ( !Open() ) {
715       // it already doesn't exist - ok!
716       return true;
717     }
718   }
719 
720   // prevent a buggy program from erasing one of the root registry keys or an
721   // immediate subkey (i.e. one which doesn't have '\\' inside) of any other
722   // key except HKCR (HKCR has some "deleteable" subkeys)
723   if ( m_strKey.empty() ||
724        ((m_hRootKey != (WXHKEY) aStdKeys[HKCR].hkey) &&
725         (m_strKey.Find(REG_SEPARATOR) == wxNOT_FOUND)) ) {
726       wxLogError(_("Registry key '%s' is needed for normal system operation,\ndeleting it will leave your system in unusable state:\noperation aborted."),
727                  GetFullName(this));
728 
729       return false;
730   }
731 
732   // we can't delete keys while enumerating because it confuses GetNextKey, so
733   // we first save the key names and then delete them all
734   wxArrayString astrSubkeys;
735 
736   wxString strKey;
737   long lIndex;
738   bool bCont = GetFirstKey(strKey, lIndex);
739   while ( bCont ) {
740     astrSubkeys.Add(strKey);
741 
742     bCont = GetNextKey(strKey, lIndex);
743   }
744 
745   size_t nKeyCount = astrSubkeys.Count();
746   for ( size_t nKey = 0; nKey < nKeyCount; nKey++ ) {
747     wxRegKey key(*this, astrSubkeys[nKey]);
748     if ( !key.DeleteSelf() )
749       return false;
750   }
751 
752   // now delete this key itself
753   Close();
754 
755   // deleting a key which doesn't exist is not considered an error
756 #if wxUSE_DYNLIB_CLASS
757   wxDynamicLibrary dllAdvapi32(wxT("advapi32"));
758   // Minimum supported OS for RegDeleteKeyEx: Vista, XP Pro x64, Win Server 2008, Win Server 2003 SP1
759   if(dllAdvapi32.HasSymbol(wxT("RegDeleteKeyEx")))
760   {
761     typedef LONG (WINAPI *RegDeleteKeyEx_t)(HKEY, LPCTSTR, REGSAM, DWORD);
762     wxDYNLIB_FUNCTION(RegDeleteKeyEx_t, RegDeleteKeyEx, dllAdvapi32);
763 
764     m_dwLastError = (*pfnRegDeleteKeyEx)((HKEY) m_hRootKey, m_strKey.t_str(),
765         GetMSWViewFlags(m_viewMode),
766         0);    // This parameter is reserved and must be zero.
767   }
768   else
769 #endif // wxUSE_DYNLIB_CLASS
770   {
771     m_dwLastError = RegDeleteKey((HKEY) m_hRootKey, m_strKey.t_str());
772   }
773 
774   if ( m_dwLastError != ERROR_SUCCESS &&
775           m_dwLastError != ERROR_FILE_NOT_FOUND ) {
776     wxLogSysError(m_dwLastError, _("Can't delete key '%s'"),
777                   GetName().c_str());
778     return false;
779   }
780 
781   return true;
782 }
783 
DeleteKey(const wxString & szKey)784 bool wxRegKey::DeleteKey(const wxString& szKey)
785 {
786   if ( !Open() )
787     return false;
788 
789   wxRegKey key(*this, szKey);
790   return key.DeleteSelf();
791 }
792 
DeleteValue(const wxString & szValue)793 bool wxRegKey::DeleteValue(const wxString& szValue)
794 {
795     if ( !Open() )
796         return false;
797 
798     m_dwLastError = RegDeleteValue((HKEY) m_hKey, RegValueStr(szValue));
799 
800     // deleting a value which doesn't exist is not considered an error
801     if ( (m_dwLastError != ERROR_SUCCESS) &&
802          (m_dwLastError != ERROR_FILE_NOT_FOUND) )
803     {
804         wxLogSysError(m_dwLastError, _("Can't delete value '%s' from key '%s'"),
805                       szValue, GetName().c_str());
806         return false;
807     }
808 
809     return true;
810 }
811 
812 // ----------------------------------------------------------------------------
813 // access to values and subkeys
814 // ----------------------------------------------------------------------------
815 
816 // return true if value exists
HasValue(const wxString & szValue) const817 bool wxRegKey::HasValue(const wxString& szValue) const
818 {
819     // this function should be silent, so suppress possible messages from Open()
820     wxLogNull nolog;
821 
822     if ( !CONST_CAST Open(Read) )
823         return false;
824 
825     LONG dwRet = ::RegQueryValueEx((HKEY) m_hKey,
826                                    RegValueStr(szValue),
827                                    RESERVED,
828                                    NULL, NULL, NULL);
829     return dwRet == ERROR_SUCCESS;
830 }
831 
832 // returns true if this key has any values
HasValues() const833 bool wxRegKey::HasValues() const
834 {
835   // suppress possible messages from GetFirstValue()
836   wxLogNull nolog;
837 
838   // just call GetFirstValue with dummy parameters
839   wxString str;
840   long     l;
841   return CONST_CAST GetFirstValue(str, l);
842 }
843 
844 // returns true if this key has any subkeys
HasSubkeys() const845 bool wxRegKey::HasSubkeys() const
846 {
847   // suppress possible messages from GetFirstKey()
848   wxLogNull nolog;
849 
850   // just call GetFirstKey with dummy parameters
851   wxString str;
852   long     l;
853   return CONST_CAST GetFirstKey(str, l);
854 }
855 
856 // returns true if given subkey exists
HasSubKey(const wxString & szKey) const857 bool wxRegKey::HasSubKey(const wxString& szKey) const
858 {
859   // this function should be silent, so suppress possible messages from Open()
860   wxLogNull nolog;
861 
862   if ( !CONST_CAST Open(Read) )
863     return false;
864 
865   return KeyExists(m_hKey, szKey, m_viewMode);
866 }
867 
GetValueType(const wxString & szValue) const868 wxRegKey::ValueType wxRegKey::GetValueType(const wxString& szValue) const
869 {
870     if ( ! CONST_CAST Open(Read) )
871       return Type_None;
872 
873     DWORD dwType;
874     m_dwLastError = RegQueryValueEx((HKEY) m_hKey, RegValueStr(szValue), RESERVED,
875                                     &dwType, NULL, NULL);
876     if ( m_dwLastError != ERROR_SUCCESS ) {
877       wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"),
878                     GetName().c_str());
879       return Type_None;
880     }
881 
882     return (ValueType)dwType;
883 }
884 
SetValue(const wxString & szValue,long lValue)885 bool wxRegKey::SetValue(const wxString& szValue, long lValue)
886 {
887   if ( CONST_CAST Open() ) {
888     m_dwLastError = RegSetValueEx((HKEY) m_hKey, RegValueStr(szValue),
889                                   (DWORD) RESERVED, REG_DWORD,
890                                   (RegString)&lValue, sizeof(lValue));
891     if ( m_dwLastError == ERROR_SUCCESS )
892       return true;
893   }
894 
895   wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
896                 GetFullName(this, szValue));
897   return false;
898 }
899 
QueryValue(const wxString & szValue,long * plValue) const900 bool wxRegKey::QueryValue(const wxString& szValue, long *plValue) const
901 {
902   if ( CONST_CAST Open(Read) ) {
903     DWORD dwType, dwSize = sizeof(DWORD);
904     RegString pBuf = (RegString)plValue;
905     m_dwLastError = RegQueryValueEx((HKEY) m_hKey, RegValueStr(szValue),
906                                     RESERVED,
907                                     &dwType, pBuf, &dwSize);
908     if ( m_dwLastError != ERROR_SUCCESS ) {
909       wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"),
910                     GetName().c_str());
911       return false;
912     }
913     else {
914       // check that we read the value of right type
915       wxASSERT_MSG( IsNumericValue(szValue),
916                     wxT("Type mismatch in wxRegKey::QueryValue().")  );
917 
918       return true;
919     }
920   }
921   else
922     return false;
923 }
924 
SetValue(const wxString & szValue,const wxMemoryBuffer & buffer)925 bool wxRegKey::SetValue(const wxString& szValue, const wxMemoryBuffer& buffer)
926 {
927 #ifdef __TWIN32__
928   wxFAIL_MSG("RegSetValueEx not implemented by TWIN32");
929   return false;
930 #else
931   if ( CONST_CAST Open() ) {
932     m_dwLastError = RegSetValueEx((HKEY) m_hKey, RegValueStr(szValue),
933                                   (DWORD) RESERVED, REG_BINARY,
934                                   (RegBinary)buffer.GetData(),buffer.GetDataLen());
935     if ( m_dwLastError == ERROR_SUCCESS )
936       return true;
937   }
938 
939   wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
940                 GetFullName(this, szValue));
941   return false;
942 #endif
943 }
944 
QueryValue(const wxString & szValue,wxMemoryBuffer & buffer) const945 bool wxRegKey::QueryValue(const wxString& szValue, wxMemoryBuffer& buffer) const
946 {
947   if ( CONST_CAST Open(Read) ) {
948     // first get the type and size of the data
949     DWORD dwType, dwSize;
950     m_dwLastError = RegQueryValueEx((HKEY) m_hKey, RegValueStr(szValue),
951                                     RESERVED,
952                                     &dwType, NULL, &dwSize);
953 
954     if ( m_dwLastError == ERROR_SUCCESS ) {
955         if ( dwSize ) {
956             const RegBinary pBuf = (RegBinary)buffer.GetWriteBuf(dwSize);
957             m_dwLastError = RegQueryValueEx((HKEY) m_hKey,
958                                             RegValueStr(szValue),
959                                             RESERVED,
960                                             &dwType,
961                                             pBuf,
962                                             &dwSize);
963             buffer.UngetWriteBuf(dwSize);
964         } else {
965             buffer.SetDataLen(0);
966         }
967     }
968 
969 
970     if ( m_dwLastError != ERROR_SUCCESS ) {
971       wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"),
972                     GetName().c_str());
973       return false;
974     }
975     return true;
976   }
977   return false;
978 }
979 
980 
981 
QueryValue(const wxString & szValue,wxString & strValue,bool WXUNUSED_IN_WINCE (raw)) const982 bool wxRegKey::QueryValue(const wxString& szValue,
983                           wxString& strValue,
984                           bool WXUNUSED_IN_WINCE(raw)) const
985 {
986     if ( CONST_CAST Open(Read) )
987     {
988 
989         // first get the type and size of the data
990         DWORD dwType=REG_NONE, dwSize=0;
991         m_dwLastError = RegQueryValueEx((HKEY) m_hKey,
992                                         RegValueStr(szValue),
993                                         RESERVED,
994                                         &dwType, NULL, &dwSize);
995         if ( m_dwLastError == ERROR_SUCCESS )
996         {
997             if ( !dwSize )
998             {
999                 // must treat this case specially as GetWriteBuf() doesn't like
1000                 // being called with 0 size
1001                 strValue.Empty();
1002             }
1003             else
1004             {
1005                 m_dwLastError = RegQueryValueEx((HKEY) m_hKey,
1006                                                 RegValueStr(szValue),
1007                                                 RESERVED,
1008                                                 &dwType,
1009                                                 (RegString)(wxChar*)wxStringBuffer(strValue, dwSize),
1010                                                 &dwSize);
1011 
1012                 // expand the var expansions in the string unless disabled
1013 #ifndef __WXWINCE__
1014                 if ( (dwType == REG_EXPAND_SZ) && !raw )
1015                 {
1016                     DWORD dwExpSize = ::ExpandEnvironmentStrings(strValue.t_str(), NULL, 0);
1017                     bool ok = dwExpSize != 0;
1018                     if ( ok )
1019                     {
1020                         wxString strExpValue;
1021                         ok = ::ExpandEnvironmentStrings(strValue.t_str(),
1022                                                         wxStringBuffer(strExpValue, dwExpSize),
1023                                                         dwExpSize
1024                                                         ) != 0;
1025                         strValue = strExpValue;
1026                     }
1027 
1028                     if ( !ok )
1029                     {
1030                         wxLogLastError(wxT("ExpandEnvironmentStrings"));
1031                     }
1032                 }
1033 #endif
1034                 // __WXWINCE__
1035             }
1036 
1037             if ( m_dwLastError == ERROR_SUCCESS )
1038             {
1039                 // check that it was the right type
1040                 wxASSERT_MSG( !IsNumericValue(szValue),
1041                               wxT("Type mismatch in wxRegKey::QueryValue().") );
1042 
1043               return true;
1044             }
1045         }
1046     }
1047 
1048     wxLogSysError(m_dwLastError, _("Can't read value of '%s'"),
1049                   GetFullName(this, szValue));
1050     return false;
1051 }
1052 
SetValue(const wxString & szValue,const wxString & strValue)1053 bool wxRegKey::SetValue(const wxString& szValue, const wxString& strValue)
1054 {
1055   if ( CONST_CAST Open() ) {
1056       m_dwLastError = RegSetValueEx((HKEY) m_hKey,
1057                                     RegValueStr(szValue),
1058                                     (DWORD) RESERVED, REG_SZ,
1059                                     (RegString)wxMSW_CONV_LPCTSTR(strValue),
1060                                     (strValue.Len() + 1)*sizeof(wxChar));
1061       if ( m_dwLastError == ERROR_SUCCESS )
1062         return true;
1063   }
1064 
1065   wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
1066                 GetFullName(this, szValue));
1067   return false;
1068 }
1069 
QueryDefaultValue() const1070 wxString wxRegKey::QueryDefaultValue() const
1071 {
1072   wxString str;
1073   QueryValue(wxEmptyString, str, false);
1074   return str;
1075 }
1076 
1077 // ----------------------------------------------------------------------------
1078 // enumeration
1079 // NB: all these functions require an index variable which allows to have
1080 //     several concurrently running indexations on the same key
1081 // ----------------------------------------------------------------------------
1082 
GetFirstValue(wxString & strValueName,long & lIndex)1083 bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex)
1084 {
1085   if ( !Open(Read) )
1086     return false;
1087 
1088   lIndex = 0;
1089   return GetNextValue(strValueName, lIndex);
1090 }
1091 
GetNextValue(wxString & strValueName,long & lIndex) const1092 bool wxRegKey::GetNextValue(wxString& strValueName, long& lIndex) const
1093 {
1094   wxASSERT( IsOpened() );
1095 
1096   // are we already at the end of enumeration?
1097   if ( lIndex == -1 )
1098     return false;
1099 
1100     wxChar  szValueName[1024];                  // @@ use RegQueryInfoKey...
1101     DWORD dwValueLen = WXSIZEOF(szValueName);
1102 
1103     m_dwLastError = RegEnumValue((HKEY) m_hKey, lIndex++,
1104                                  szValueName, &dwValueLen,
1105                                  RESERVED,
1106                                  NULL,            // [out] type
1107                                  NULL,            // [out] buffer for value
1108                                  NULL);           // [i/o]  it's length
1109 
1110     if ( m_dwLastError != ERROR_SUCCESS ) {
1111       if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
1112         m_dwLastError = ERROR_SUCCESS;
1113         lIndex = -1;
1114       }
1115       else {
1116         wxLogSysError(m_dwLastError, _("Can't enumerate values of key '%s'"),
1117                       GetName().c_str());
1118       }
1119 
1120       return false;
1121     }
1122 
1123     strValueName = szValueName;
1124 
1125   return true;
1126 }
1127 
GetFirstKey(wxString & strKeyName,long & lIndex)1128 bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex)
1129 {
1130   if ( !Open(Read) )
1131     return false;
1132 
1133   lIndex = 0;
1134   return GetNextKey(strKeyName, lIndex);
1135 }
1136 
GetNextKey(wxString & strKeyName,long & lIndex) const1137 bool wxRegKey::GetNextKey(wxString& strKeyName, long& lIndex) const
1138 {
1139   wxASSERT( IsOpened() );
1140 
1141   // are we already at the end of enumeration?
1142   if ( lIndex == -1 )
1143     return false;
1144 
1145   wxChar szKeyName[_MAX_PATH + 1];
1146 
1147 #ifdef __WXWINCE__
1148   DWORD sizeName = WXSIZEOF(szKeyName);
1149   m_dwLastError = RegEnumKeyEx((HKEY) m_hKey, lIndex++, szKeyName, & sizeName,
1150       0, NULL, NULL, NULL);
1151 #else
1152   m_dwLastError = RegEnumKey((HKEY) m_hKey, lIndex++, szKeyName, WXSIZEOF(szKeyName));
1153 #endif
1154 
1155   if ( m_dwLastError != ERROR_SUCCESS ) {
1156     if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
1157       m_dwLastError = ERROR_SUCCESS;
1158       lIndex = -1;
1159     }
1160     else {
1161       wxLogSysError(m_dwLastError, _("Can't enumerate subkeys of key '%s'"),
1162                     GetName().c_str());
1163     }
1164 
1165     return false;
1166   }
1167 
1168   strKeyName = szKeyName;
1169   return true;
1170 }
1171 
1172 // returns true if the value contains a number (else it's some string)
IsNumericValue(const wxString & szValue) const1173 bool wxRegKey::IsNumericValue(const wxString& szValue) const
1174 {
1175     ValueType type = GetValueType(szValue);
1176     switch ( type ) {
1177         case Type_Dword:
1178         /* case Type_Dword_little_endian: == Type_Dword */
1179         case Type_Dword_big_endian:
1180             return true;
1181 
1182         default:
1183             return false;
1184     }
1185 }
1186 
1187 // ----------------------------------------------------------------------------
1188 // exporting registry keys to file
1189 // ----------------------------------------------------------------------------
1190 
1191 #if wxUSE_STREAMS
1192 
1193 // helper functions for writing ASCII strings (even in Unicode build)
WriteAsciiChar(wxOutputStream & ostr,char ch)1194 static inline bool WriteAsciiChar(wxOutputStream& ostr, char ch)
1195 {
1196     ostr.PutC(ch);
1197     return ostr.IsOk();
1198 }
1199 
WriteAsciiEOL(wxOutputStream & ostr)1200 static inline bool WriteAsciiEOL(wxOutputStream& ostr)
1201 {
1202     // as we open the file in text mode, it is enough to write LF without CR
1203     return WriteAsciiChar(ostr, '\n');
1204 }
1205 
WriteAsciiString(wxOutputStream & ostr,const char * p)1206 static inline bool WriteAsciiString(wxOutputStream& ostr, const char *p)
1207 {
1208     return ostr.Write(p, strlen(p)).IsOk();
1209 }
1210 
WriteAsciiString(wxOutputStream & ostr,const wxString & s)1211 static inline bool WriteAsciiString(wxOutputStream& ostr, const wxString& s)
1212 {
1213 #if wxUSE_UNICODE
1214     wxCharBuffer name(s.mb_str());
1215     ostr.Write(name, strlen(name));
1216 #else
1217     ostr.Write(s.mb_str(), s.length());
1218 #endif
1219 
1220     return ostr.IsOk();
1221 }
1222 
1223 #endif // wxUSE_STREAMS
1224 
Export(const wxString & filename) const1225 bool wxRegKey::Export(const wxString& filename) const
1226 {
1227 #if wxUSE_FFILE && wxUSE_STREAMS
1228     if ( wxFile::Exists(filename) )
1229     {
1230         wxLogError(_("Exporting registry key: file \"%s\" already exists and won't be overwritten."),
1231                    filename.c_str());
1232         return false;
1233     }
1234 
1235     wxFFileOutputStream ostr(filename, wxT("w"));
1236 
1237     return ostr.IsOk() && Export(ostr);
1238 #else
1239     wxUnusedVar(filename);
1240     return false;
1241 #endif
1242 }
1243 
1244 #if wxUSE_STREAMS
Export(wxOutputStream & ostr) const1245 bool wxRegKey::Export(wxOutputStream& ostr) const
1246 {
1247     // write out the header
1248     if ( !WriteAsciiString(ostr, "REGEDIT4\n\n") )
1249         return false;
1250 
1251     return DoExport(ostr);
1252 }
1253 #endif // wxUSE_STREAMS
1254 
1255 static
1256 wxString
FormatAsHex(const void * data,size_t size,wxRegKey::ValueType type=wxRegKey::Type_Binary)1257 FormatAsHex(const void *data,
1258             size_t size,
1259             wxRegKey::ValueType type = wxRegKey::Type_Binary)
1260 {
1261     wxString value(wxT("hex"));
1262 
1263     // binary values use just "hex:" prefix while the other ones must indicate
1264     // the real type
1265     if ( type != wxRegKey::Type_Binary )
1266         value << wxT('(') << type << wxT(')');
1267     value << wxT(':');
1268 
1269     // write all the rest as comma-separated bytes
1270     value.reserve(3*size + 10);
1271     const char * const p = static_cast<const char *>(data);
1272     for ( size_t n = 0; n < size; n++ )
1273     {
1274         // TODO: line wrapping: although not required by regedit, this makes
1275         //       the generated files easier to read and compare with the files
1276         //       produced by regedit
1277         if ( n )
1278             value << wxT(',');
1279 
1280         value << wxString::Format(wxT("%02x"), (unsigned char)p[n]);
1281     }
1282 
1283     return value;
1284 }
1285 
1286 static inline
FormatAsHex(const wxString & value,wxRegKey::ValueType type)1287 wxString FormatAsHex(const wxString& value, wxRegKey::ValueType type)
1288 {
1289     return FormatAsHex(value.c_str(), value.length() + 1, type);
1290 }
1291 
FormatValue(const wxString & name) const1292 wxString wxRegKey::FormatValue(const wxString& name) const
1293 {
1294     wxString rhs;
1295     const ValueType type = GetValueType(name);
1296     switch ( type )
1297     {
1298         case Type_String:
1299             {
1300                 wxString value;
1301                 if ( !QueryValue(name, value) )
1302                     break;
1303 
1304                 // quotes and backslashes must be quoted, linefeeds are not
1305                 // allowed in string values
1306                 rhs.reserve(value.length() + 2);
1307                 rhs = wxT('"');
1308 
1309                 // there can be no NULs here
1310                 bool useHex = false;
1311                 for ( wxString::const_iterator p = value.begin();
1312                       p != value.end() && !useHex; ++p )
1313                 {
1314                     switch ( (*p).GetValue() )
1315                     {
1316                         case wxT('\n'):
1317                             // we can only represent this string in hex
1318                             useHex = true;
1319                             break;
1320 
1321                         case wxT('"'):
1322                         case wxT('\\'):
1323                             // escape special symbol
1324                             rhs += wxT('\\');
1325                             // fall through
1326 
1327                         default:
1328                             rhs += *p;
1329                     }
1330                 }
1331 
1332                 if ( useHex )
1333                     rhs = FormatAsHex(value, Type_String);
1334                 else
1335                     rhs += wxT('"');
1336             }
1337             break;
1338 
1339         case Type_Dword:
1340         /* case Type_Dword_little_endian: == Type_Dword */
1341             {
1342                 long value;
1343                 if ( !QueryValue(name, &value) )
1344                     break;
1345 
1346                 rhs.Printf(wxT("dword:%08x"), (unsigned int)value);
1347             }
1348             break;
1349 
1350         case Type_Expand_String:
1351         case Type_Multi_String:
1352             {
1353                 wxString value;
1354                 if ( !QueryRawValue(name, value) )
1355                     break;
1356 
1357                 rhs = FormatAsHex(value, type);
1358             }
1359             break;
1360 
1361         case Type_Binary:
1362             {
1363                 wxMemoryBuffer buf;
1364                 if ( !QueryValue(name, buf) )
1365                     break;
1366 
1367                 rhs = FormatAsHex(buf.GetData(), buf.GetDataLen());
1368             }
1369             break;
1370 
1371         // no idea how those appear in REGEDIT4 files
1372         case Type_None:
1373         case Type_Dword_big_endian:
1374         case Type_Link:
1375         case Type_Resource_list:
1376         case Type_Full_resource_descriptor:
1377         case Type_Resource_requirements_list:
1378         default:
1379             wxLogWarning(_("Can't export value of unsupported type %d."), type);
1380     }
1381 
1382     return rhs;
1383 }
1384 
1385 #if wxUSE_STREAMS
1386 
DoExportValue(wxOutputStream & ostr,const wxString & name) const1387 bool wxRegKey::DoExportValue(wxOutputStream& ostr, const wxString& name) const
1388 {
1389     // first examine the value type: if it's unsupported, simply skip it
1390     // instead of aborting the entire export process because we failed to
1391     // export a single value
1392     wxString value = FormatValue(name);
1393     if ( value.empty() )
1394     {
1395         wxLogWarning(_("Ignoring value \"%s\" of the key \"%s\"."),
1396                      name.c_str(), GetName().c_str());
1397         return true;
1398     }
1399 
1400     // we do have the text representation of the value, now write everything
1401     // out
1402 
1403     // special case: unnamed/default value is represented as just "@"
1404     if ( name.empty() )
1405     {
1406         if ( !WriteAsciiChar(ostr, '@') )
1407             return false;
1408     }
1409     else // normal, named, value
1410     {
1411         if ( !WriteAsciiChar(ostr, '"') ||
1412                 !WriteAsciiString(ostr, name) ||
1413                     !WriteAsciiChar(ostr, '"') )
1414             return false;
1415     }
1416 
1417     if ( !WriteAsciiChar(ostr, '=') )
1418         return false;
1419 
1420     return WriteAsciiString(ostr, value) && WriteAsciiEOL(ostr);
1421 }
1422 
DoExport(wxOutputStream & ostr) const1423 bool wxRegKey::DoExport(wxOutputStream& ostr) const
1424 {
1425     // write out this key name
1426     if ( !WriteAsciiChar(ostr, '[') )
1427         return false;
1428 
1429     if ( !WriteAsciiString(ostr, GetName(false /* no short prefix */)) )
1430         return false;
1431 
1432     if ( !WriteAsciiChar(ostr, ']') || !WriteAsciiEOL(ostr) )
1433         return false;
1434 
1435     // dump all our values
1436     long dummy;
1437     wxString name;
1438     wxRegKey& self = const_cast<wxRegKey&>(*this);
1439     bool cont = self.GetFirstValue(name, dummy);
1440     while ( cont )
1441     {
1442         if ( !DoExportValue(ostr, name) )
1443             return false;
1444 
1445         cont = GetNextValue(name, dummy);
1446     }
1447 
1448     // always terminate values by blank line, even if there were no values
1449     if ( !WriteAsciiEOL(ostr) )
1450         return false;
1451 
1452     // recurse to subkeys
1453     cont = self.GetFirstKey(name, dummy);
1454     while ( cont )
1455     {
1456         wxRegKey subkey(*this, name);
1457         if ( !subkey.DoExport(ostr) )
1458             return false;
1459 
1460         cont = GetNextKey(name, dummy);
1461     }
1462 
1463     return true;
1464 }
1465 
1466 #endif // wxUSE_STREAMS
1467 
1468 // ============================================================================
1469 // implementation of global private functions
1470 // ============================================================================
1471 
KeyExists(WXHKEY hRootKey,const wxString & szKey,wxRegKey::WOW64ViewMode viewMode)1472 bool KeyExists(WXHKEY hRootKey,
1473                const wxString& szKey,
1474                wxRegKey::WOW64ViewMode viewMode)
1475 {
1476     // don't close this key itself for the case of empty szKey!
1477     if ( szKey.empty() )
1478         return true;
1479 
1480     HKEY hkeyDummy;
1481     if ( ::RegOpenKeyEx
1482          (
1483             (HKEY)hRootKey,
1484             szKey.t_str(),
1485             RESERVED,
1486             // we might not have enough rights for rw access
1487             GetMSWAccessFlags(wxRegKey::Read, viewMode),
1488             &hkeyDummy
1489          ) == ERROR_SUCCESS )
1490     {
1491         ::RegCloseKey(hkeyDummy);
1492 
1493         return true;
1494     }
1495 
1496     return false;
1497 }
1498 
GetMSWViewFlags(wxRegKey::WOW64ViewMode viewMode)1499 long GetMSWViewFlags(wxRegKey::WOW64ViewMode viewMode)
1500 {
1501     long samWOW64ViewMode = 0;
1502 
1503     switch ( viewMode )
1504     {
1505         case wxRegKey::WOW64ViewMode_32:
1506 #ifdef __WIN64__    // the flag is only needed by 64 bit apps
1507             samWOW64ViewMode = KEY_WOW64_32KEY;
1508 #endif // Win64
1509             break;
1510 
1511         case wxRegKey::WOW64ViewMode_64:
1512 #ifndef __WIN64__   // the flag is only needed by 32 bit apps
1513             // 64 bit registry can only be accessed under 64 bit platforms
1514             if ( wxIsPlatform64Bit() )
1515                 samWOW64ViewMode = KEY_WOW64_64KEY;
1516 #endif // Win32
1517             break;
1518 
1519         default:
1520             wxFAIL_MSG("Unknown registry view.");
1521             // fall through
1522 
1523         case wxRegKey::WOW64ViewMode_Default:
1524             // Use default registry view for the current application,
1525             // i.e. 32 bits for 32 bit ones and 64 bits for 64 bit apps
1526             ;
1527     }
1528 
1529     return samWOW64ViewMode;
1530 }
1531 
GetMSWAccessFlags(wxRegKey::AccessMode mode,wxRegKey::WOW64ViewMode viewMode)1532 long GetMSWAccessFlags(wxRegKey::AccessMode mode,
1533     wxRegKey::WOW64ViewMode viewMode)
1534 {
1535     long sam = mode == wxRegKey::Read ? KEY_READ : KEY_ALL_ACCESS;
1536 
1537     sam |= GetMSWViewFlags(viewMode);
1538 
1539     return sam;
1540 }
1541 
GetFullName(const wxRegKey * pKey,const wxString & szValue)1542 wxString GetFullName(const wxRegKey *pKey, const wxString& szValue)
1543 {
1544   wxString str(pKey->GetName());
1545   if ( !szValue.empty() )
1546     str << wxT("\\") << szValue;
1547 
1548   return str;
1549 }
1550 
GetFullName(const wxRegKey * pKey)1551 wxString GetFullName(const wxRegKey *pKey)
1552 {
1553   return pKey->GetName();
1554 }
1555 
RemoveTrailingSeparator(wxString & str)1556 inline void RemoveTrailingSeparator(wxString& str)
1557 {
1558   if ( !str.empty() && str.Last() == REG_SEPARATOR )
1559     str.Truncate(str.Len() - 1);
1560 }
1561 
RegValueStr(const wxString & szValue)1562 inline const wxChar *RegValueStr(const wxString& szValue)
1563 {
1564     return szValue.empty() ? (const wxChar*)NULL : szValue.t_str();
1565 }
1566 
1567 #endif // wxUSE_REGKEY
1568