]> git.saurik.com Git - wxWidgets.git/blob - src/msw/regconf.cpp
don't overwrite the existing local file if we failed to open it but it does exist
[wxWidgets.git] / src / msw / regconf.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/regconf.cpp
3 // Purpose:
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 27.04.98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_CONFIG && wxUSE_REGKEY
20
21 #include "wx/config.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/string.h"
25 #include "wx/intl.h"
26 #include "wx/log.h"
27 #include "wx/event.h"
28 #include "wx/app.h"
29 #endif //WX_PRECOMP
30
31 #include "wx/msw/registry.h"
32 #include "wx/msw/regconf.h"
33
34 // ----------------------------------------------------------------------------
35 // constants
36 // ----------------------------------------------------------------------------
37
38 // we put our data in HKLM\SOFTWARE_KEY\appname
39 #define SOFTWARE_KEY wxString(wxT("Software\\"))
40
41 // ----------------------------------------------------------------------------
42 // global functions
43 // ----------------------------------------------------------------------------
44
45 // get the value if the key is opened and it exists
46 bool TryGetValue(const wxRegKey& key, const wxString& str, wxString& strVal)
47 {
48 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, strVal);
49 }
50
51 bool TryGetValue(const wxRegKey& key, const wxString& str, long *plVal)
52 {
53 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, plVal);
54 }
55
56 bool TryGetValue(const wxRegKey& key, const wxString& str, wxMemoryBuffer &plVal)
57 {
58 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, plVal);
59 }
60
61 // ============================================================================
62 // implementation
63 // ============================================================================
64
65 // ----------------------------------------------------------------------------
66 // ctor/dtor
67 // ----------------------------------------------------------------------------
68 IMPLEMENT_ABSTRACT_CLASS(wxRegConfig, wxConfigBase)
69
70 // create the config object which stores its data under HKCU\vendor\app and, if
71 // style & wxCONFIG_USE_GLOBAL_FILE, under HKLM\vendor\app
72 wxRegConfig::wxRegConfig(const wxString& appName, const wxString& vendorName,
73 const wxString& strLocal, const wxString& strGlobal,
74 long style)
75 : wxConfigBase(appName, vendorName, strLocal, strGlobal, style)
76 {
77 wxString strRoot;
78
79 bool bDoUseGlobal = (style & wxCONFIG_USE_GLOBAL_FILE) != 0;
80
81 // the convention is to put the programs keys under <vendor>\<appname>
82 // (but it can be overriden by specifying the pathes explicitly in strLocal
83 // and/or strGlobal)
84 if ( strLocal.empty() || (strGlobal.empty() && bDoUseGlobal) )
85 {
86 if ( vendorName.empty() )
87 {
88 if ( wxTheApp )
89 strRoot = wxTheApp->GetVendorName();
90 }
91 else
92 {
93 strRoot = vendorName;
94 }
95
96 // no '\\' needed if no vendor name
97 if ( !strRoot.empty() )
98 {
99 strRoot += '\\';
100 }
101
102 if ( appName.empty() )
103 {
104 wxCHECK_RET( wxTheApp, wxT("No application name in wxRegConfig ctor!") );
105 strRoot << wxTheApp->GetAppName();
106 }
107 else
108 {
109 strRoot << appName;
110 }
111 }
112 //else: we don't need to do all the complicated stuff above
113
114 wxString str = strLocal.empty() ? strRoot : strLocal;
115
116 // as we're going to change the name of these keys fairly often and as
117 // there are only few of wxRegConfig objects (usually 1), we can allow
118 // ourselves to be generous and spend some memory to significantly improve
119 // performance of SetPath()
120 static const size_t MEMORY_PREALLOC = 512;
121
122 m_keyLocalRoot.ReserveMemoryForName(MEMORY_PREALLOC);
123 m_keyLocal.ReserveMemoryForName(MEMORY_PREALLOC);
124
125 m_keyLocalRoot.SetName(wxRegKey::HKCU, SOFTWARE_KEY + str);
126 m_keyLocal.SetName(m_keyLocalRoot, wxEmptyString);
127
128 if ( bDoUseGlobal )
129 {
130 str = strGlobal.empty() ? strRoot : strGlobal;
131
132 m_keyGlobalRoot.ReserveMemoryForName(MEMORY_PREALLOC);
133 m_keyGlobal.ReserveMemoryForName(MEMORY_PREALLOC);
134
135 m_keyGlobalRoot.SetName(wxRegKey::HKLM, SOFTWARE_KEY + str);
136 m_keyGlobal.SetName(m_keyGlobalRoot, wxEmptyString);
137 }
138
139 // Create() will Open() if key already exists
140 m_keyLocalRoot.Create();
141
142 // as it's the same key, Open() shouldn't fail (i.e. no need for Create())
143 m_keyLocal.Open();
144
145 // OTOH, this key may perfectly not exist, so suppress error messages the call
146 // to Open() might generate
147 if ( bDoUseGlobal )
148 {
149 wxLogNull nolog;
150 m_keyGlobalRoot.Open(wxRegKey::Read);
151 m_keyGlobal.Open(wxRegKey::Read);
152 }
153 }
154
155 // ----------------------------------------------------------------------------
156 // path management
157 // ----------------------------------------------------------------------------
158
159 // this function is called a *lot* of times (as I learned after seeing from
160 // profiler output that it is called ~12000 times from Mahogany start up code!)
161 // so it is important to optimize it - in particular, avoid using generic
162 // string functions here and do everything manually because it is faster
163 //
164 // I still kept the old version to be able to check that the optimized code has
165 // the same output as the non optimized version.
166 void wxRegConfig::SetPath(const wxString& strPath)
167 {
168 // remember the old path
169 wxString strOldPath = m_strPath;
170
171 #ifdef WX_DEBUG_SET_PATH // non optimized version kept here for testing
172 wxString m_strPathAlt;
173
174 {
175 wxArrayString aParts;
176
177 // because GetPath() returns "" when we're at root, we must understand
178 // empty string as "/"
179 if ( strPath.empty() || (strPath[0] == wxCONFIG_PATH_SEPARATOR) ) {
180 // absolute path
181 wxSplitPath(aParts, strPath);
182 }
183 else {
184 // relative path, combine with current one
185 wxString strFullPath = GetPath();
186 strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
187 wxSplitPath(aParts, strFullPath);
188 }
189
190 // recombine path parts in one variable
191 wxString strRegPath;
192 m_strPathAlt.Empty();
193 for ( size_t n = 0; n < aParts.Count(); n++ ) {
194 strRegPath << '\\' << aParts[n];
195 m_strPathAlt << wxCONFIG_PATH_SEPARATOR << aParts[n];
196 }
197 }
198 #endif // 0
199
200 // check for the most common case first
201 if ( strPath.empty() )
202 {
203 m_strPath = wxCONFIG_PATH_SEPARATOR;
204 }
205 else // not root
206 {
207 // construct the full path
208 wxString strFullPath;
209 if ( strPath[0u] == wxCONFIG_PATH_SEPARATOR )
210 {
211 // absolute path
212 strFullPath = strPath;
213 }
214 else // relative path
215 {
216 strFullPath.reserve(2*m_strPath.length());
217
218 strFullPath << m_strPath;
219 if ( strFullPath.Len() == 0 ||
220 strFullPath.Last() != wxCONFIG_PATH_SEPARATOR )
221 strFullPath << wxCONFIG_PATH_SEPARATOR;
222 strFullPath << strPath;
223 }
224
225 // simplify it: we need to handle ".." here
226
227 // count the total number of slashes we have to know if we can go upper
228 size_t totalSlashes = 0;
229
230 // position of the last slash to be able to backtrack to it quickly if
231 // needed, but we set it to -1 if we don't have a valid position
232 //
233 // we only remember the last position which means that we handle ".."
234 // quite efficiently but not "../.." - however the latter should be
235 // much more rare, so it is probably ok
236 int posLastSlash = -1;
237
238 const wxChar *src = strFullPath.c_str();
239 size_t len = strFullPath.length();
240 const wxChar *end = src + len;
241
242 wxStringBufferLength buf(m_strPath, len);
243 wxChar *dst = buf;
244 wxChar *start = dst;
245
246 for ( ; src < end; src++, dst++ )
247 {
248 if ( *src == wxCONFIG_PATH_SEPARATOR )
249 {
250 // check for "/.."
251
252 // note that we don't have to check for src < end here as
253 // *end == 0 so can't be '.'
254 if ( src[1] == _T('.') && src[2] == _T('.') &&
255 (src + 3 == end || src[3] == wxCONFIG_PATH_SEPARATOR) )
256 {
257 if ( !totalSlashes )
258 {
259 wxLogWarning(_("'%s' has extra '..', ignored."),
260 strFullPath.c_str());
261 }
262 else // return to the previous path component
263 {
264 // do we already have its position?
265 if ( posLastSlash == -1 )
266 {
267 // no, find it: note that we are sure to have one
268 // because totalSlashes > 0 so we don't have to
269 // check the boundary condition below
270
271 // this is more efficient than strrchr()
272 dst--;
273 while ( *dst != wxCONFIG_PATH_SEPARATOR )
274 {
275 dst--;
276 }
277 }
278 else // the position of last slash was stored
279 {
280 // go directly there
281 dst = start + posLastSlash;
282
283 // invalidate posLastSlash
284 posLastSlash = -1;
285 }
286
287 // we must have found a slash one way or another!
288 wxASSERT_MSG( *dst == wxCONFIG_PATH_SEPARATOR,
289 _T("error in wxRegConfig::SetPath") );
290
291 // stay at the same position
292 dst--;
293
294 // we killed one
295 totalSlashes--;
296 }
297
298 // skip both dots
299 src += 2;
300 }
301 else // not "/.."
302 {
303 if ( (dst == start) || (dst[-1] != wxCONFIG_PATH_SEPARATOR) )
304 {
305 *dst = wxCONFIG_PATH_SEPARATOR;
306
307 posLastSlash = dst - start;
308
309 totalSlashes++;
310 }
311 else // previous char was a slash too
312 {
313 // squeeze several subsequent slashes into one: i.e.
314 // just ignore this one
315 dst--;
316 }
317 }
318 }
319 else // normal character
320 {
321 // just copy
322 *dst = *src;
323 }
324 }
325
326 // NUL terminate the string
327 if ( dst[-1] == wxCONFIG_PATH_SEPARATOR && (dst != start + 1) )
328 {
329 // if it has a trailing slash we remove it unless it is the only
330 // string character
331 dst--;
332 }
333
334 *dst = _T('\0');
335 buf.SetLength(dst - start);
336 }
337
338 #ifdef WX_DEBUG_SET_PATH
339 wxASSERT( m_strPath == m_strPathAlt );
340 #endif
341
342 if ( m_strPath == strOldPath )
343 return;
344
345 // registry APIs want backslashes instead of slashes
346 wxString strRegPath;
347 if ( !m_strPath.empty() )
348 {
349 size_t len = m_strPath.length();
350
351 const wxChar *src = m_strPath.c_str();
352 wxStringBufferLength buf(strRegPath, len);
353 wxChar *dst = buf;
354
355 const wxChar *end = src + len;
356 for ( ; src < end; src++, dst++ )
357 {
358 if ( *src == wxCONFIG_PATH_SEPARATOR )
359 *dst = _T('\\');
360 else
361 *dst = *src;
362 }
363
364 buf.SetLength(len);
365 }
366
367 // this is not needed any longer as we don't create keys unnecessarily any
368 // more (now it is done on demand, i.e. only when they're going to contain
369 // something)
370 #if 0
371 // as we create the registry key when SetPath(key) is done, we can be left
372 // with plenty of empty keys if this was only done to try to read some
373 // value which, in fact, doesn't exist - to prevent this from happening we
374 // automatically delete the old key if it was empty
375 if ( m_keyLocal.Exists() && LocalKey().IsEmpty() )
376 {
377 m_keyLocal.DeleteSelf();
378 }
379 #endif // 0
380
381 // change current key(s)
382 m_keyLocal.SetName(m_keyLocalRoot, strRegPath);
383
384 if ( GetStyle() & wxCONFIG_USE_GLOBAL_FILE )
385 {
386 m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath);
387
388 wxLogNull nolog;
389 m_keyGlobal.Open(wxRegKey::Read);
390 }
391 }
392
393 // ----------------------------------------------------------------------------
394 // enumeration (works only with current group)
395 // ----------------------------------------------------------------------------
396
397 /*
398 We want to enumerate all local keys/values after the global ones, but, of
399 course, we don't want to repeat a key which appears locally as well as
400 globally twice.
401
402 We use the 15th bit of lIndex for distinction between global and local.
403 */
404
405 #define LOCAL_MASK 0x8000
406 #define IS_LOCAL_INDEX(l) (((l) & LOCAL_MASK) != 0)
407
408 bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) const
409 {
410 lIndex = 0;
411 return GetNextGroup(str, lIndex);
412 }
413
414 bool wxRegConfig::GetNextGroup(wxString& str, long& lIndex) const
415 {
416 // are we already enumerating local entries?
417 if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
418 // try to find a global entry which doesn't appear locally
419 while ( m_keyGlobal.GetNextKey(str, lIndex) ) {
420 if ( !m_keyLocal.Exists() || !LocalKey().HasSubKey(str) ) {
421 // ok, found one - return it
422 return true;
423 }
424 }
425
426 // no more global entries
427 lIndex |= LOCAL_MASK;
428 }
429
430 // if we don't have the key at all, don't try to enumerate anything under it
431 if ( !m_keyLocal.Exists() )
432 return false;
433
434 // much easier with local entries: get the next one we find
435 // (don't forget to clear our flag bit and set it again later)
436 lIndex &= ~LOCAL_MASK;
437 bool bOk = LocalKey().GetNextKey(str, lIndex);
438 lIndex |= LOCAL_MASK;
439
440 return bOk;
441 }
442
443 bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) const
444 {
445 lIndex = 0;
446 return GetNextEntry(str, lIndex);
447 }
448
449 bool wxRegConfig::GetNextEntry(wxString& str, long& lIndex) const
450 {
451 // are we already enumerating local entries?
452 if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
453 // try to find a global entry which doesn't appear locally
454 while ( m_keyGlobal.GetNextValue(str, lIndex) ) {
455 if ( !m_keyLocal.Exists() || !LocalKey().HasValue(str) ) {
456 // ok, found one - return it
457 return true;
458 }
459 }
460
461 // no more global entries
462 lIndex |= LOCAL_MASK;
463 }
464
465 // if we don't have the key at all, don't try to enumerate anything under it
466 if ( !m_keyLocal.Exists() )
467 return false;
468
469 // much easier with local entries: get the next one we find
470 // (don't forget to clear our flag bit and set it again later)
471 lIndex &= ~LOCAL_MASK;
472 bool bOk = LocalKey().GetNextValue(str, lIndex);
473 lIndex |= LOCAL_MASK;
474
475 return bOk;
476 }
477
478 size_t wxRegConfig::GetNumberOfEntries(bool WXUNUSED(bRecursive)) const
479 {
480 size_t nEntries = 0;
481
482 // dummy vars
483 wxString str;
484 long l;
485 bool bCont = ((wxRegConfig*)this)->GetFirstEntry(str, l);
486 while ( bCont ) {
487 nEntries++;
488
489 bCont = ((wxRegConfig*)this)->GetNextEntry(str, l);
490 }
491
492 return nEntries;
493 }
494
495 size_t wxRegConfig::GetNumberOfGroups(bool WXUNUSED(bRecursive)) const
496 {
497 size_t nGroups = 0;
498
499 // dummy vars
500 wxString str;
501 long l;
502 bool bCont = ((wxRegConfig*)this)->GetFirstGroup(str, l);
503 while ( bCont ) {
504 nGroups++;
505
506 bCont = ((wxRegConfig*)this)->GetNextGroup(str, l);
507 }
508
509 return nGroups;
510 }
511
512 // ----------------------------------------------------------------------------
513 // tests for existence
514 // ----------------------------------------------------------------------------
515
516 bool wxRegConfig::HasGroup(const wxString& key) const
517 {
518 wxConfigPathChanger path(this, key);
519
520 wxString strName(path.Name());
521
522 return (m_keyLocal.Exists() && LocalKey().HasSubKey(strName)) ||
523 m_keyGlobal.HasSubKey(strName);
524 }
525
526 bool wxRegConfig::HasEntry(const wxString& key) const
527 {
528 wxConfigPathChanger path(this, key);
529
530 wxString strName(path.Name());
531
532 return (m_keyLocal.Exists() && LocalKey().HasValue(strName)) ||
533 m_keyGlobal.HasValue(strName);
534 }
535
536 wxConfigBase::EntryType wxRegConfig::GetEntryType(const wxString& key) const
537 {
538 wxConfigPathChanger path(this, key);
539
540 wxString strName(path.Name());
541
542 bool isNumeric;
543 if ( m_keyLocal.Exists() && LocalKey().HasValue(strName) )
544 isNumeric = m_keyLocal.IsNumericValue(strName);
545 else if ( m_keyGlobal.HasValue(strName) )
546 isNumeric = m_keyGlobal.IsNumericValue(strName);
547 else
548 return wxConfigBase::Type_Unknown;
549
550 return isNumeric ? wxConfigBase::Type_Integer : wxConfigBase::Type_String;
551 }
552
553 // ----------------------------------------------------------------------------
554 // reading/writing
555 // ----------------------------------------------------------------------------
556
557 bool wxRegConfig::DoReadString(const wxString& key, wxString *pStr) const
558 {
559 wxCHECK_MSG( pStr, false, _T("wxRegConfig::Read(): NULL param") );
560
561 wxConfigPathChanger path(this, key);
562
563 bool bQueryGlobal = true;
564
565 // if immutable key exists in global key we must check that it's not
566 // overriden by the local key with the same name
567 if ( IsImmutable(path.Name()) ) {
568 if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
569 if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) {
570 wxLogWarning(wxT("User value for immutable key '%s' ignored."),
571 path.Name().c_str());
572 }
573
574 return true;
575 }
576 else {
577 // don't waste time - it's not there anyhow
578 bQueryGlobal = false;
579 }
580 }
581
582 // first try local key
583 if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), *pStr)) ||
584 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
585 return true;
586 }
587
588 return false;
589 }
590
591 // this exactly reproduces the string version above except for ExpandEnvVars(),
592 // we really should avoid this code duplication somehow...
593
594 bool wxRegConfig::DoReadLong(const wxString& key, long *plResult) const
595 {
596 wxCHECK_MSG( plResult, false, _T("wxRegConfig::Read(): NULL param") );
597
598 wxConfigPathChanger path(this, key);
599
600 bool bQueryGlobal = true;
601
602 // if immutable key exists in global key we must check that it's not
603 // overriden by the local key with the same name
604 if ( IsImmutable(path.Name()) ) {
605 if ( TryGetValue(m_keyGlobal, path.Name(), plResult) ) {
606 if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) {
607 wxLogWarning(wxT("User value for immutable key '%s' ignored."),
608 path.Name().c_str());
609 }
610
611 return true;
612 }
613 else {
614 // don't waste time - it's not there anyhow
615 bQueryGlobal = false;
616 }
617 }
618
619 // first try local key
620 if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), plResult)) ||
621 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), plResult)) ) {
622 return true;
623 }
624
625 return false;
626 }
627
628 bool wxRegConfig::DoReadBinary(const wxString& key, wxMemoryBuffer *buf) const
629 {
630 wxCHECK_MSG( buf, false, _T("wxRegConfig::Read(): NULL param") );
631
632 wxConfigPathChanger path(this, key);
633
634 bool bQueryGlobal = true;
635
636 // if immutable key exists in global key we must check that it's not
637 // overriden by the local key with the same name
638 if ( IsImmutable(path.Name()) ) {
639 if ( TryGetValue(m_keyGlobal, path.Name(), *buf) ) {
640 if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) {
641 wxLogWarning(wxT("User value for immutable key '%s' ignored."),
642 path.Name().c_str());
643 }
644
645 return true;
646 }
647 else {
648 // don't waste time - it's not there anyhow
649 bQueryGlobal = false;
650 }
651 }
652
653 // first try local key
654 if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), *buf)) ||
655 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *buf)) ) {
656 return true;
657 }
658
659 return false;
660 }
661
662 bool wxRegConfig::DoWriteString(const wxString& key, const wxString& szValue)
663 {
664 wxConfigPathChanger path(this, key);
665
666 if ( IsImmutable(path.Name()) ) {
667 wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str());
668 return false;
669 }
670
671 return LocalKey().SetValue(path.Name(), szValue);
672 }
673
674 bool wxRegConfig::DoWriteLong(const wxString& key, long lValue)
675 {
676 wxConfigPathChanger path(this, key);
677
678 if ( IsImmutable(path.Name()) ) {
679 wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str());
680 return false;
681 }
682
683 return LocalKey().SetValue(path.Name(), lValue);
684 }
685
686 bool wxRegConfig::DoWriteBinary(const wxString& key, const wxMemoryBuffer& buf)
687 {
688 wxConfigPathChanger path(this, key);
689
690 if ( IsImmutable(path.Name()) ) {
691 wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str());
692 return false;
693 }
694
695 return LocalKey().SetValue(path.Name(), buf);
696 }
697
698 // ----------------------------------------------------------------------------
699 // renaming
700 // ----------------------------------------------------------------------------
701
702 bool wxRegConfig::RenameEntry(const wxString& oldName, const wxString& newName)
703 {
704 // check that the old entry exists...
705 if ( !HasEntry(oldName) )
706 return false;
707
708 // and that the new one doesn't
709 if ( HasEntry(newName) )
710 return false;
711
712 return m_keyLocal.RenameValue(oldName, newName);
713 }
714
715 bool wxRegConfig::RenameGroup(const wxString& oldName, const wxString& newName)
716 {
717 // check that the old group exists...
718 if ( !HasGroup(oldName) )
719 return false;
720
721 // and that the new one doesn't
722 if ( HasGroup(newName) )
723 return false;
724
725 return wxRegKey(m_keyLocal, oldName).Rename(newName);
726 }
727
728 // ----------------------------------------------------------------------------
729 // deleting
730 // ----------------------------------------------------------------------------
731
732 bool wxRegConfig::DeleteEntry(const wxString& value, bool bGroupIfEmptyAlso)
733 {
734 wxConfigPathChanger path(this, value);
735
736 if ( m_keyLocal.Exists() ) {
737 if ( !m_keyLocal.DeleteValue(path.Name()) )
738 return false;
739
740 if ( bGroupIfEmptyAlso && m_keyLocal.IsEmpty() ) {
741 wxString strKey = GetPath().AfterLast(wxCONFIG_PATH_SEPARATOR);
742 SetPath(_T("..")); // changes m_keyLocal
743 return LocalKey().DeleteKey(strKey);
744 }
745 }
746
747 return true;
748 }
749
750 bool wxRegConfig::DeleteGroup(const wxString& key)
751 {
752 wxConfigPathChanger path(this, RemoveTrailingSeparator(key));
753
754 if ( !m_keyLocal.Exists() )
755 {
756 // nothing to do
757 return true;
758 }
759
760 if ( !LocalKey().DeleteKey(path.Name()) )
761 return false;
762
763 path.UpdateIfDeleted();
764
765 return true;
766 }
767
768 bool wxRegConfig::DeleteAll()
769 {
770 m_keyLocal.Close();
771 m_keyGlobal.Close();
772
773 bool bOk = m_keyLocalRoot.DeleteSelf();
774
775 // make sure that we opened m_keyGlobalRoot and so it has a reasonable name:
776 // otherwise we will delete HKEY_CLASSES_ROOT recursively
777 if ( bOk && m_keyGlobalRoot.IsOpened() )
778 bOk = m_keyGlobalRoot.DeleteSelf();
779
780 return bOk;
781 }
782
783 #endif // wxUSE_CONFIG && wxUSE_REGKEY