]> git.saurik.com Git - wxWidgets.git/blame - src/msw/regconf.cpp
wxProcess-related code now works
[wxWidgets.git] / src / msw / regconf.cpp
CommitLineData
19454fa0
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: msw/regconf.cpp
6d833566 3// Purpose:
19454fa0 4// Author: Vadim Zeitlin
6d833566 5// Modified by:
19454fa0
VZ
6// Created: 27.04.98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// Licence: wxWindows license
10///////////////////////////////////////////////////////////////////////////////
11
cfe780fb
JS
12#ifdef __GNUG__
13#pragma implementation "regconf.h"
14#endif
15
a3b46648
UU
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
19454fa0 18
a3b46648
UU
19#ifdef __BORLANDC__
20#pragma hdrstop
82cf4761
VZ
21#endif
22
82cf4761
VZ
23#ifndef WX_PRECOMP
24 #include <wx/string.h>
25#endif //WX_PRECOMP
26
2432b92d 27#include <wx/event.h>
18244936 28#include <wx/app.h>
82cf4761 29#include <wx/log.h>
19454fa0 30#include <wx/config.h>
3d05544e
JS
31
32#ifndef __WIN16__
33
6d833566 34#include <wx/msw/registry.h>
82cf4761 35#include <wx/msw/regconf.h>
19454fa0
VZ
36
37// ----------------------------------------------------------------------------
38// constants
39// ----------------------------------------------------------------------------
40
41// we put our data in HKLM\SOFTWARE_KEY\appname
c19a8a9a 42#define SOFTWARE_KEY wxString("Software\\")
19454fa0
VZ
43
44// ----------------------------------------------------------------------------
45// global functions
46// ----------------------------------------------------------------------------
47
48// get the value if the key is opened and it exists
49bool TryGetValue(const wxRegKey& key, const wxString& str, wxString& strVal)
50{
51 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, strVal);
52}
53
54bool TryGetValue(const wxRegKey& key, const wxString& str, long *plVal)
55{
56 return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, plVal);
57}
58
59// ============================================================================
60// implementation
61// ============================================================================
62
63// ----------------------------------------------------------------------------
64// ctor/dtor
65// ----------------------------------------------------------------------------
18244936 66
040f0110
VZ
67// create the config object which stores its data under HKCU\vendor\app and, if
68// style & wxCONFIG_USE_GLOBAL_FILE, under HKLM\vendor\app
69wxRegConfig::wxRegConfig(const wxString& appName, const wxString& vendorName,
70 const wxString& strLocal, const wxString& strGlobal,
71 long style)
72 : wxConfigBase(appName, vendorName, strLocal, strGlobal, style)
19454fa0 73{
040f0110 74 wxString strRoot;
19454fa0 75
040f0110 76 bool bDoUseGlobal = (style & wxCONFIG_USE_GLOBAL_FILE) != 0;
41286812 77
040f0110
VZ
78 // the convention is to put the programs keys under <vendor>\<appname>
79 // (but it can be overriden by specifying the pathes explicitly in strLocal
80 // and/or strGlobal)
81 if ( strLocal.IsEmpty() || (strGlobal.IsEmpty() && bDoUseGlobal) )
82 {
83 if ( vendorName.IsEmpty() )
84 {
85 if ( wxTheApp )
86 strRoot = wxTheApp->GetVendorName();
87 }
88 else
89 {
90 strRoot = vendorName;
91 }
18244936 92
040f0110
VZ
93 // no '\\' needed if no vendor name
94 if ( !strRoot.IsEmpty() )
18244936 95 {
040f0110 96 strRoot += '\\';
18244936 97 }
18244936 98
040f0110
VZ
99 if ( appName.IsEmpty() )
100 {
101 wxCHECK_RET( wxTheApp, "No application name in wxRegConfig ctor!" );
102 strRoot << wxTheApp->GetAppName();
103 }
104 else
18244936 105 {
040f0110 106 strRoot << appName;
18244936 107 }
040f0110
VZ
108 }
109 //else: we don't need to do all the complicated stuff above
18244936 110
040f0110
VZ
111 wxString str = strLocal.IsEmpty() ? strRoot : strLocal;
112 m_keyLocalRoot.SetName(wxRegKey::HKCU, SOFTWARE_KEY + str);
113 m_keyLocal.SetName(m_keyLocalRoot, "");
18244936 114
040f0110
VZ
115 if ( bDoUseGlobal )
116 {
117 str = strGlobal.IsEmpty() ? strRoot : strGlobal;
118 m_keyGlobalRoot.SetName(wxRegKey::HKLM, SOFTWARE_KEY + str);
119 m_keyGlobal.SetName(m_keyGlobalRoot, "");
120 }
18244936
JS
121
122 // Create() will Open() if key already exists
123 m_keyLocalRoot.Create();
124
125 // as it's the same key, Open() shouldn't fail (i.e. no need for Create())
126 m_keyLocal.Open();
127
040f0110
VZ
128 // OTOH, this key may perfectly not exist, so suppress error messages the call
129 // to Open() might generate
130 if ( bDoUseGlobal )
131 {
132 wxLogNull nolog;
133 m_keyGlobalRoot.Open();
134 }
18244936 135}
19454fa0
VZ
136
137wxRegConfig::~wxRegConfig()
138{
139 // nothing to do - key will be closed in their dtors
140}
141
142// ----------------------------------------------------------------------------
143// path management
144// ----------------------------------------------------------------------------
145void wxRegConfig::SetPath(const wxString& strPath)
146{
82cf4761 147 wxArrayString aParts;
19454fa0 148
41286812
VZ
149 // because GetPath() returns "" when we're at root, we must understand
150 // empty string as "/"
151 if ( strPath.IsEmpty() || (strPath[0] == wxCONFIG_PATH_SEPARATOR) ) {
19454fa0 152 // absolute path
82cf4761 153 wxSplitPath(aParts, strPath);
19454fa0
VZ
154 }
155 else {
156 // relative path, combine with current one
157 wxString strFullPath = GetPath();
4d0c0756 158 strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
82cf4761 159 wxSplitPath(aParts, strFullPath);
19454fa0
VZ
160 }
161
162 // recombine path parts in one variable
163 wxString strRegPath;
164 m_strPath.Empty();
c86f1403 165 for ( size_t n = 0; n < aParts.Count(); n++ ) {
19454fa0 166 strRegPath << '\\' << aParts[n];
4d0c0756 167 m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n];
19454fa0
VZ
168 }
169
170 // change current key(s)
171 m_keyLocal.SetName(m_keyLocalRoot, strRegPath);
172 m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath);
173 m_keyLocal.Create();
174
175 wxLogNull nolog;
176 m_keyGlobal.Open();
177}
178
179// ----------------------------------------------------------------------------
180// enumeration (works only with current group)
181// ----------------------------------------------------------------------------
182
183/*
6d833566 184 We want to enumerate all local keys/values after the global ones, but, of
19454fa0
VZ
185 course, we don't want to repeat a key which appears locally as well as
186 globally twice.
187
188 We use the 15th bit of lIndex for distinction between global and local.
189 */
190
191#define LOCAL_MASK 0x8000
192#define IS_LOCAL_INDEX(l) (((l) & LOCAL_MASK) != 0)
193
02569ba8 194bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) const
19454fa0
VZ
195{
196 lIndex = 0;
197 return GetNextGroup(str, lIndex);
198}
199
02569ba8 200bool wxRegConfig::GetNextGroup(wxString& str, long& lIndex) const
19454fa0
VZ
201{
202 // are we already enumerating local entries?
203 if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
204 // try to find a global entry which doesn't appear locally
205 do {
206 if ( !m_keyGlobal.GetNextKey(str, lIndex) ) {
207 // no more global entries
208 lIndex |= LOCAL_MASK;
209 break;
210 }
211 } while( m_keyLocal.HasSubKey(str) );
212 }
213
214 // much easier with local entries: get the next one we find
215 // (don't forget to clear our flag bit and set it again later)
216 lIndex &= ~LOCAL_MASK;
217 bool bOk = m_keyLocal.GetNextKey(str, lIndex);
218 lIndex |= LOCAL_MASK;
219
220 return bOk;
221}
222
02569ba8 223bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) const
19454fa0
VZ
224{
225 lIndex = 0;
82cf4761 226 return GetNextEntry(str, lIndex);
19454fa0
VZ
227}
228
02569ba8 229bool wxRegConfig::GetNextEntry(wxString& str, long& lIndex) const
19454fa0
VZ
230{
231 // are we already enumerating local entries?
232 if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
233 // try to find a global entry which doesn't appear locally
234 do {
82cf4761 235 if ( !m_keyGlobal.GetNextValue(str, lIndex) ) {
19454fa0
VZ
236 // no more global entries
237 lIndex |= LOCAL_MASK;
238 break;
239 }
82cf4761 240 } while( m_keyLocal.HasValue(str) );
19454fa0
VZ
241 }
242
243 // much easier with local entries: get the next one we find
244 // (don't forget to clear our flag bit and set it again later)
245 lIndex &= ~LOCAL_MASK;
82cf4761 246 bool bOk = m_keyLocal.GetNextValue(str, lIndex);
19454fa0
VZ
247 lIndex |= LOCAL_MASK;
248
249 return bOk;
250}
251
c86f1403 252size_t wxRegConfig::GetNumberOfEntries(bool bRecursive) const
82cf4761 253{
c86f1403 254 size_t nEntries = 0;
82cf4761
VZ
255
256 // dummy vars
257 wxString str;
258 long l;
6a23cbce 259 bool bCont = ((wxRegConfig*)this)->GetFirstEntry(str, l);
82cf4761
VZ
260 while ( bCont ) {
261 nEntries++;
262
6a23cbce 263 bCont = ((wxRegConfig*)this)->GetNextEntry(str, l);
82cf4761
VZ
264 }
265
266 return nEntries;
267}
268
c86f1403 269size_t wxRegConfig::GetNumberOfGroups(bool bRecursive) const
82cf4761 270{
c86f1403 271 size_t nGroups = 0;
82cf4761
VZ
272
273 // dummy vars
274 wxString str;
275 long l;
6a23cbce 276 bool bCont = ((wxRegConfig*)this)->GetFirstGroup(str, l);
82cf4761
VZ
277 while ( bCont ) {
278 nGroups++;
279
6a23cbce 280 bCont = ((wxRegConfig*)this)->GetNextGroup(str, l);
82cf4761
VZ
281 }
282
283 return nGroups;
284}
285
6d833566
VZ
286// ----------------------------------------------------------------------------
287// tests for existence
288// ----------------------------------------------------------------------------
289
290bool wxRegConfig::HasGroup(const wxString& strName) const
291{
292 return m_keyLocal.HasSubKey(strName) || m_keyGlobal.HasSubKey(strName);
293}
294
295bool wxRegConfig::HasEntry(const wxString& strName) const
296{
297 return m_keyLocal.HasValue(strName) || m_keyGlobal.HasValue(strName);
298}
299
19454fa0
VZ
300// ----------------------------------------------------------------------------
301// reading/writing
302// ----------------------------------------------------------------------------
303
18244936 304bool wxRegConfig::Read(const wxString& key, wxString *pStr) const
19454fa0 305{
18244936 306 wxConfigPathChanger path(this, key);
19454fa0 307
cf447356 308 bool bQueryGlobal = TRUE;
19454fa0
VZ
309
310 // if immutable key exists in global key we must check that it's not
311 // overriden by the local key with the same name
312 if ( IsImmutable(path.Name()) ) {
02569ba8 313 if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
19454fa0 314 if ( m_keyLocal.HasValue(path.Name()) ) {
6d833566 315 wxLogWarning("User value for immutable key '%s' ignored.",
19454fa0
VZ
316 path.Name().c_str());
317 }
18244936 318 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
cf447356 319 return TRUE;
19454fa0
VZ
320 }
321 else {
322 // don't waste time - it's not there anyhow
cf447356 323 bQueryGlobal = FALSE;
19454fa0
VZ
324 }
325 }
326
327 // first try local key
02569ba8
VZ
328 if ( TryGetValue(m_keyLocal, path.Name(), *pStr) ||
329 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
41286812 330 // nothing to do
18244936
JS
331
332 // TODO: do we return TRUE? Not in original implementation,
333 // but I don't see why not. -- JACS
334 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
335 return TRUE;
336 }
337
338 return FALSE;
339}
340
341bool wxRegConfig::Read(const wxString& key, wxString *pStr,
342 const wxString& szDefault) const
343{
344 wxConfigPathChanger path(this, key);
345
346 bool bQueryGlobal = TRUE;
347
348 // if immutable key exists in global key we must check that it's not
349 // overriden by the local key with the same name
350 if ( IsImmutable(path.Name()) ) {
351 if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
352 if ( m_keyLocal.HasValue(path.Name()) ) {
353 wxLogWarning("User value for immutable key '%s' ignored.",
354 path.Name().c_str());
355 }
356
357 return TRUE;
358 }
359 else {
360 // don't waste time - it's not there anyhow
361 bQueryGlobal = FALSE;
362 }
363 }
364
365 // first try local key
366 if ( TryGetValue(m_keyLocal, path.Name(), *pStr) ||
367 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
368 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
369 return TRUE;
41286812
VZ
370 }
371 else {
372 if ( IsRecordingDefaults() ) {
18244936 373 ((wxRegConfig*)this)->Write(key, szDefault);
41286812
VZ
374 }
375
376 // default value
377 *pStr = szDefault;
19454fa0
VZ
378 }
379
41286812 380 *pStr = wxConfigBase::ExpandEnvVars(*pStr);
baeed289 381
cf447356 382 return FALSE;
19454fa0
VZ
383}
384
18244936 385bool wxRegConfig::Read(const wxString& key, long *plResult) const
19454fa0 386{
18244936 387 wxConfigPathChanger path(this, key);
19454fa0 388
cf447356 389 bool bQueryGlobal = TRUE;
19454fa0
VZ
390
391 // if immutable key exists in global key we must check that it's not
392 // overriden by the local key with the same name
393 if ( IsImmutable(path.Name()) ) {
02569ba8 394 if ( TryGetValue(m_keyGlobal, path.Name(), plResult) ) {
19454fa0 395 if ( m_keyLocal.HasValue(path.Name()) ) {
6d833566 396 wxLogWarning("User value for immutable key '%s' ignored.",
19454fa0
VZ
397 path.Name().c_str());
398 }
399
cf447356 400 return TRUE;
19454fa0
VZ
401 }
402 else {
403 // don't waste time - it's not there anyhow
cf447356 404 bQueryGlobal = FALSE;
19454fa0
VZ
405 }
406 }
407
408 // first try local key
02569ba8
VZ
409 if ( TryGetValue(m_keyLocal, path.Name(), plResult) ||
410 (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), plResult)) ) {
cf447356 411 return TRUE;
19454fa0 412 }
cf447356 413 return FALSE;
19454fa0
VZ
414}
415
18244936 416bool wxRegConfig::Write(const wxString& key, const wxString& szValue)
19454fa0 417{
18244936 418 wxConfigPathChanger path(this, key);
19454fa0
VZ
419
420 if ( IsImmutable(path.Name()) ) {
421 wxLogError("Can't change immutable entry '%s'.", path.Name().c_str());
cf447356 422 return FALSE;
19454fa0
VZ
423 }
424
425 return m_keyLocal.SetValue(path.Name(), szValue);
426}
427
18244936 428bool wxRegConfig::Write(const wxString& key, long lValue)
19454fa0 429{
18244936 430 wxConfigPathChanger path(this, key);
19454fa0
VZ
431
432 if ( IsImmutable(path.Name()) ) {
433 wxLogError("Can't change immutable entry '%s'.", path.Name().c_str());
cf447356 434 return FALSE;
19454fa0
VZ
435 }
436
437 return m_keyLocal.SetValue(path.Name(), lValue);
438}
439
440// ----------------------------------------------------------------------------
89077ebc
VZ
441// renaming
442// ----------------------------------------------------------------------------
443
444bool wxRegConfig::RenameEntry(const wxString& oldName, const wxString& newName)
445{
446 // check that the old entry exists...
447 if ( !HasEntry(oldName) )
448 return FALSE;
449
450 // and that the new one doesn't
451 if ( HasEntry(newName) )
452 return FALSE;
453
454 // delete the old entry and create the new one - but do in the reverse
455 // order to not lose the data if Create() fails
456
457 bool ok;
458 if ( m_keyLocal.IsNumericValue(oldName) )
459 {
460 long val;
461 ok = m_keyLocal.QueryValue(oldName, &val) &&
462 m_keyLocal.SetValue(newName, val);
463 }
464 else
465 {
466 wxString val;
467 ok = m_keyLocal.QueryValue(oldName, val) &&
468 m_keyLocal.SetValue(newName, val);
469 }
470
471 if ( !ok )
472 return FALSE;
473
474 if ( !m_keyLocal.DeleteValue(oldName) )
475 {
476 m_keyLocal.DeleteValue(newName);
477
478 return FALSE;
479 }
480
481 return TRUE;
482}
483
484bool wxRegConfig::RenameGroup(const wxString& oldName, const wxString& newName)
485{
486 // check that the old group exists...
487 if ( !HasGroup(oldName) )
488 return FALSE;
489
490 // and that the new one doesn't
491 if ( HasGroup(newName) )
492 return FALSE;
493
494 // TODO there is no way to rename a registry key - we must do a deep copy
495 // ourselves
496 wxFAIL_MSG("Registry key renaming not implemented");
497
498 return FALSE;
499}
500
501// ----------------------------------------------------------------------------
19454fa0
VZ
502// deleting
503// ----------------------------------------------------------------------------
18244936 504bool wxRegConfig::DeleteEntry(const wxString& value, bool bGroupIfEmptyAlso)
19454fa0 505{
18244936 506 wxConfigPathChanger path(this, value);
19454fa0
VZ
507
508 if ( !m_keyLocal.DeleteValue(path.Name()) )
cf447356 509 return FALSE;
19454fa0 510
82cf4761 511 if ( !m_keyLocal.HasSubkeys() ) {
08159082 512 wxString strKey = GetPath().AfterLast(wxCONFIG_PATH_SEPARATOR);
19454fa0
VZ
513 SetPath(".."); // changes m_keyLocal
514 return m_keyLocal.DeleteKey(strKey);
515 }
516
cf447356 517 return TRUE;
19454fa0
VZ
518}
519
18244936 520bool wxRegConfig::DeleteGroup(const wxString& key)
19454fa0 521{
18244936 522 wxConfigPathChanger path(this, key);
19454fa0
VZ
523
524 return m_keyLocal.DeleteKey(path.Name());
525}
526
527bool wxRegConfig::DeleteAll()
528{
19454fa0
VZ
529 m_keyLocal.Close();
530 m_keyGlobal.Close();
90186e52 531
19454fa0 532 bool bOk = m_keyLocalRoot.DeleteSelf();
90186e52
VZ
533
534 // make sure that we opened m_keyGlobalRoot and so it has a reasonable name:
535 // otherwise we will delete HKEY_CLASSES_ROOT recursively
536 if ( bOk && m_keyGlobalRoot.IsOpened() )
19454fa0
VZ
537 bOk = m_keyGlobalRoot.DeleteSelf();
538
539 return bOk;
540}
3d05544e
JS
541
542#endif
543 // __WIN16__
544