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