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