]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/registry.cpp
Removed child frame CreateStatusBar from MDI sample; renamed config.h to confbase.h;
[wxWidgets.git] / src / msw / registry.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: 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$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// Licence: wxWindows license
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// ============================================================================
16// declarations
17// ============================================================================
18
19// ----------------------------------------------------------------------------
20// headers
21// ----------------------------------------------------------------------------
22
23// for compilers that support precompilation, includes "wx.h".
24#include "wx/wxprec.h"
25
26#ifdef __BORLANDC__
27#pragma hdrstop
28#endif
29
30// other wxWindows headers
31#include "wx/string.h"
32#include "wx/intl.h"
33#include "wx/log.h"
34
35// Windows headers
36/*
37#define STRICT
38#define WIN32_LEAN_AND_MEAN
39*/
40
41#include <windows.h>
42
43// other std headers
44#include <stdlib.h> // for _MAX_PATH
45
46#ifndef _MAX_PATH
47 #define _MAX_PATH 512
48#endif
49
50// our header
51#define HKEY_DEFINED // already defined in windows.h
52#include "wx/msw/registry.h"
53
54// some registry functions don't like signed chars
55typedef unsigned char *RegString;
56
57// ----------------------------------------------------------------------------
58// constants
59// ----------------------------------------------------------------------------
60
61// the standard key names, short names and handles all bundled together for
62// convenient access
63static struct
64{
65 HKEY hkey;
66 const char *szName;
67 const char *szShortName;
68}
69aStdKeys[] =
70{
71 { HKEY_CLASSES_ROOT, "HKEY_CLASSES_ROOT", "HKCR" },
72#ifdef __WIN32__
73 { HKEY_CURRENT_USER, "HKEY_CURRENT_USER", "HKCU" },
74 { HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE", "HKLM" },
75 { HKEY_USERS, "HKEY_USERS", "HKU" }, // short name?
76 { HKEY_PERFORMANCE_DATA, "HKEY_PERFORMANCE_DATA", "HKPD" },
77#if WINVER >= 0x0400
78 { HKEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG", "HKCC" },
79#ifndef __GNUWIN32__
80 { HKEY_DYN_DATA, "HKEY_DYN_DATA", "HKDD" }, // short name?
81#endif //GNUWIN32
82#endif //WINVER >= 4.0
83#endif //WIN32
84};
85
86// the registry name separator (perhaps one day MS will change it to '/' ;-)
87#define REG_SEPARATOR '\\'
88
89// useful for Windows programmers: makes somewhat more clear all these zeroes
90// being passed to Windows APIs
91#define RESERVED (NULL)
92
93// ----------------------------------------------------------------------------
94// macros
95// ----------------------------------------------------------------------------
96// @ const_cast<> is not yet supported by all compilers
97#define CONST_CAST ((wxRegKey *)this)->
98
99#if !USE_MUTABLE
100 #define m_dwLastError CONST_CAST m_dwLastError
101#endif
102
103// ----------------------------------------------------------------------------
104// non member functions
105// ----------------------------------------------------------------------------
106
107// removes the trailing backslash from the string if it has one
108static inline void RemoveTrailingSeparator(wxString& str);
109
110// returns TRUE if given registry key exists
111static bool KeyExists(HKEY hRootKey, const char *szKey);
112
113// combines value and key name (uses static buffer!)
114static const char *GetFullName(const wxRegKey *pKey,
115 const char *szValue = NULL);
116
117// ============================================================================
118// implementation of wxRegKey class
119// ============================================================================
120
121// ----------------------------------------------------------------------------
122// static functions and variables
123// ----------------------------------------------------------------------------
124
125const size_t wxRegKey::nStdKeys = WXSIZEOF(aStdKeys);
126
127// @@ should take a `StdKey key', but as it's often going to be used in loops
128// it would require casts in user code.
129const char *wxRegKey::GetStdKeyName(size_t key)
130{
131 // return empty string if key is invalid
132 wxCHECK_MSG( key < nStdKeys, "", "invalid key in wxRegKey::GetStdKeyName" );
133
134 return aStdKeys[key].szName;
135}
136
137const char *wxRegKey::GetStdKeyShortName(size_t key)
138{
139 // return empty string if key is invalid
140 wxCHECK( key < nStdKeys, "" );
141
142 return aStdKeys[key].szShortName;
143}
144
145wxRegKey::StdKey wxRegKey::ExtractKeyName(wxString& strKey)
146{
147 wxString strRoot = strKey.Left(REG_SEPARATOR);
148
149 HKEY hRootKey;
150 size_t ui;
151 for ( ui = 0; ui < nStdKeys; ui++ ) {
152 if ( strRoot.CmpNoCase(aStdKeys[ui].szName) == 0 ||
153 strRoot.CmpNoCase(aStdKeys[ui].szShortName) == 0 ) {
154 hRootKey = aStdKeys[ui].hkey;
155 break;
156 }
157 }
158
159 if ( ui == nStdKeys ) {
160 wxFAIL_MSG("invalid key prefix in wxRegKey::ExtractKeyName.");
161
162 hRootKey = HKEY_CLASSES_ROOT;
163 }
164 else {
165 strKey = strKey.After(REG_SEPARATOR);
166 if ( !strKey.IsEmpty() && strKey.Last() == REG_SEPARATOR )
167 strKey.Truncate(strKey.Len() - 1);
168 }
169
170 return (wxRegKey::StdKey)(int)hRootKey;
171}
172
173wxRegKey::StdKey wxRegKey::GetStdKeyFromHkey(HKEY hkey)
174{
175 for ( size_t ui = 0; ui < nStdKeys; ui++ ) {
176 if ( aStdKeys[ui].hkey == hkey )
177 return (StdKey)ui;
178 }
179
180 wxFAIL_MSG("non root hkey passed to wxRegKey::GetStdKeyFromHkey.");
181
182 return HKCR;
183}
184
185// ----------------------------------------------------------------------------
186// ctors and dtor
187// ----------------------------------------------------------------------------
188
189wxRegKey::wxRegKey()
190{
191 m_hKey = 0;
192 m_hRootKey = aStdKeys[HKCR].hkey;
193 m_dwLastError = 0;
194}
195
196wxRegKey::wxRegKey(const wxString& strKey) : m_strKey(strKey)
197{
198 m_hRootKey = aStdKeys[ExtractKeyName(m_strKey)].hkey;
199 m_hKey = NULL;
200 m_dwLastError = 0;
201}
202
203// parent is a predefined (and preopened) key
204wxRegKey::wxRegKey(StdKey keyParent, const wxString& strKey) : m_strKey(strKey)
205{
206 RemoveTrailingSeparator(m_strKey);
207 m_hRootKey = aStdKeys[keyParent].hkey;
208 m_hKey = NULL;
209 m_dwLastError = 0;
210}
211
212// parent is a normal regkey
213wxRegKey::wxRegKey(const wxRegKey& keyParent, const wxString& strKey)
214 : m_strKey(keyParent.m_strKey)
215{
216 // combine our name with parent's to get the full name
217 if ( !m_strKey.IsEmpty() &&
218 (strKey.IsEmpty() || strKey[0] != REG_SEPARATOR) ) {
219 m_strKey += REG_SEPARATOR;
220 }
221
222 m_strKey += strKey;
223 RemoveTrailingSeparator(m_strKey);
224
225 m_hRootKey = keyParent.m_hRootKey;
226 m_hKey = NULL;
227 m_dwLastError = 0;
228}
229
230// dtor closes the key releasing system resource
231wxRegKey::~wxRegKey()
232{
233 Close();
234}
235
236// ----------------------------------------------------------------------------
237// change the key name/hkey
238// ----------------------------------------------------------------------------
239
240// set the full key name
241void wxRegKey::SetName(const wxString& strKey)
242{
243 Close();
244
245 m_strKey = strKey;
246 m_hRootKey = aStdKeys[ExtractKeyName(m_strKey)].hkey;
247}
248
249// the name is relative to the parent key
250void wxRegKey::SetName(StdKey keyParent, const wxString& strKey)
251{
252 Close();
253
254 m_strKey = strKey;
255 RemoveTrailingSeparator(m_strKey);
256 m_hRootKey = aStdKeys[keyParent].hkey;
257}
258
259// the name is relative to the parent key
260void wxRegKey::SetName(const wxRegKey& keyParent, const wxString& strKey)
261{
262 Close();
263
264 // combine our name with parent's to get the full name
265 m_strKey = keyParent.m_strKey;
266 if ( !strKey.IsEmpty() && strKey[0] != REG_SEPARATOR )
267 m_strKey += REG_SEPARATOR;
268 m_strKey += strKey;
269
270 RemoveTrailingSeparator(m_strKey);
271
272 m_hRootKey = keyParent.m_hRootKey;
273}
274
275// hKey should be opened and will be closed in wxRegKey dtor
276void wxRegKey::SetHkey(HKEY hKey)
277{
278 Close();
279
280 m_hKey = hKey;
281}
282
283// ----------------------------------------------------------------------------
284// info about the key
285// ----------------------------------------------------------------------------
286
287// returns TRUE if the key exists
288bool wxRegKey::Exists() const
289{
290 // opened key has to exist, try to open it if not done yet
291 return IsOpened() ? TRUE : KeyExists(m_hRootKey, m_strKey);
292}
293
294// returns the full name of the key (prefix is abbreviated if bShortPrefix)
295wxString wxRegKey::GetName(bool bShortPrefix) const
296{
297 StdKey key = GetStdKeyFromHkey(m_hRootKey);
298 wxString str = bShortPrefix ? aStdKeys[key].szShortName
299 : aStdKeys[key].szName;
300 if ( !m_strKey.IsEmpty() )
301 str << "\\" << m_strKey;
302
303 return str;
304}
305
306#ifdef __GNUWIN32__
307bool wxRegKey::GetKeyInfo(size_t* pnSubKeys,
308 size_t* pnMaxKeyLen,
309 size_t* pnValues,
310 size_t* pnMaxValueLen) const
311#else
312bool wxRegKey::GetKeyInfo(ulong *pnSubKeys,
313 ulong *pnMaxKeyLen,
314 ulong *pnValues,
315 ulong *pnMaxValueLen) const
316#endif
317{
318#ifdef __WIN32__
319 m_dwLastError = ::RegQueryInfoKey
320 (
321 m_hKey,
322 NULL, // class name
323 NULL, // (ptr to) size of class name buffer
324 RESERVED,
325 pnSubKeys, // [out] number of subkeys
326 pnMaxKeyLen, // [out] max length of a subkey name
327 NULL, // longest subkey class name
328 pnValues, // [out] number of values
329 pnMaxValueLen, // [out] max length of a value name
330 NULL, // longest value data
331 NULL, // security descriptor
332 NULL // time of last modification
333 );
334
335 if ( m_dwLastError != ERROR_SUCCESS ) {
336 wxLogSysError(m_dwLastError, _("can't get info about registry key '%s'"),
337 GetName().c_str());
338 return FALSE;
339 }
340 else
341 return TRUE;
342#else // Win16
343 wxFAIL_MSG("GetKeyInfo() not implemented");
344
345 return FALSE;
346#endif
347}
348
349// ----------------------------------------------------------------------------
350// operations
351// ----------------------------------------------------------------------------
352
353// opens key (it's not an error to call Open() on an already opened key)
354bool wxRegKey::Open()
355{
356 if ( IsOpened() )
357 return TRUE;
358
359 m_dwLastError = RegOpenKey(m_hRootKey, m_strKey, &m_hKey);
360 if ( m_dwLastError != ERROR_SUCCESS ) {
361 wxLogSysError(m_dwLastError, _("can't open registry key '%s'"),
362 GetName().c_str());
363 return FALSE;
364 }
365 else
366 return TRUE;
367}
368
369// creates key, failing if it exists and !bOkIfExists
370bool wxRegKey::Create(bool bOkIfExists)
371{
372 // check for existence only if asked (i.e. order is important!)
373 if ( !bOkIfExists && Exists() ) {
374 return FALSE;
375 }
376
377 if ( IsOpened() )
378 return TRUE;
379
380 m_dwLastError = RegCreateKey(m_hRootKey, m_strKey, &m_hKey);
381 if ( m_dwLastError != ERROR_SUCCESS ) {
382 wxLogSysError(m_dwLastError, _("can't create registry key '%s'"),
383 GetName().c_str());
384 return FALSE;
385 }
386 else
387 return TRUE;
388}
389
390// close the key, it's not an error to call it when not opened
391bool wxRegKey::Close()
392{
393 if ( IsOpened() ) {
394 m_dwLastError = RegCloseKey(m_hKey);
395 if ( m_dwLastError != ERROR_SUCCESS ) {
396 wxLogSysError(m_dwLastError, _("can't close registry key '%s'"),
397 GetName().c_str());
398
399 m_hKey = 0;
400 return FALSE;
401 }
402 else {
403 m_hKey = 0;
404 }
405 }
406
407 return TRUE;
408}
409
410// ----------------------------------------------------------------------------
411// delete keys/values
412// ----------------------------------------------------------------------------
413bool wxRegKey::DeleteSelf()
414{
415 {
416 wxLogNull nolog;
417 if ( !Open() ) {
418 // it already doesn't exist - ok!
419 return TRUE;
420 }
421 }
422
423 // we can't delete keys while enumerating because it confuses GetNextKey, so
424 // we first save the key names and then delete them all
425 wxArrayString astrSubkeys;
426
427 wxString strKey;
428 long lIndex;
429 bool bCont = GetFirstKey(strKey, lIndex);
430 while ( bCont ) {
431 astrSubkeys.Add(strKey);
432
433 bCont = GetNextKey(strKey, lIndex);
434 }
435
436 size_t nKeyCount = astrSubkeys.Count();
437 for ( size_t nKey = 0; nKey < nKeyCount; nKey++ ) {
438 wxRegKey key(*this, astrSubkeys[nKey]);
439 if ( !key.DeleteSelf() )
440 return FALSE;
441 }
442
443 // now delete this key itself
444 Close();
445
446 m_dwLastError = RegDeleteKey(m_hRootKey, m_strKey);
447 if ( m_dwLastError != ERROR_SUCCESS ) {
448 wxLogSysError(m_dwLastError, _("can't delete key '%s'"),
449 GetName().c_str());
450 return FALSE;
451 }
452
453 return TRUE;
454}
455
456bool wxRegKey::DeleteKey(const char *szKey)
457{
458 if ( !Open() )
459 return FALSE;
460
461 wxRegKey key(*this, szKey);
462 return key.DeleteSelf();
463}
464
465bool wxRegKey::DeleteValue(const char *szValue)
466{
467 if ( !Open() )
468 return FALSE;
469
470 #ifdef __WIN32__
471 m_dwLastError = RegDeleteValue(m_hKey, szValue);
472 if ( m_dwLastError != ERROR_SUCCESS ) {
473 wxLogSysError(m_dwLastError, _("can't delete value '%s' from key '%s'"),
474 szValue, GetName().c_str());
475 return FALSE;
476 }
477 #else //WIN16
478 // named registry values don't exist in Win16 world
479 wxASSERT( IsEmpty(szValue) );
480
481 // just set the (default and unique) value of the key to ""
482 m_dwLastError = RegSetValue(m_hKey, NULL, REG_SZ, "", RESERVED);
483 if ( m_dwLastError != ERROR_SUCCESS ) {
484 wxLogSysError(m_dwLastError, _("can't delete value of key '%s'"),
485 GetName().c_str());
486 return FALSE;
487 }
488 #endif //WIN16/32
489
490 return TRUE;
491}
492
493// ----------------------------------------------------------------------------
494// access to values and subkeys
495// ----------------------------------------------------------------------------
496
497// return TRUE if value exists
498bool wxRegKey::HasValue(const char *szValue) const
499{
500 // this function should be silent, so suppress possible messages from Open()
501 wxLogNull nolog;
502
503 #ifdef __WIN32__
504 if ( CONST_CAST Open() ) {
505 return RegQueryValueEx(m_hKey, szValue, RESERVED,
506 NULL, NULL, NULL) == ERROR_SUCCESS;
507 }
508 else
509 return FALSE;
510 #else // WIN16
511 // only unnamed value exists
512 return IsEmpty(szValue);
513 #endif // WIN16/32
514}
515
516// returns TRUE if this key has any subkeys
517bool wxRegKey::HasSubkeys() const
518{
519 // just call GetFirstKey with dummy parameters
520 wxString str;
521 long l;
522 return CONST_CAST GetFirstKey(str, l);
523}
524
525// returns TRUE if given subkey exists
526bool wxRegKey::HasSubKey(const char *szKey) const
527{
528 if ( CONST_CAST Open() )
529 return KeyExists(m_hKey, szKey);
530 else
531 return FALSE;
532}
533
534wxRegKey::ValueType wxRegKey::GetValueType(const char *szValue)
535{
536 #ifdef __WIN32__
537 if ( !Open() )
538 return Type_None;
539
540 DWORD dwType;
541 m_dwLastError = RegQueryValueEx(m_hKey, szValue, RESERVED,
542 &dwType, NULL, NULL);
543 if ( m_dwLastError != ERROR_SUCCESS ) {
544 wxLogSysError(m_dwLastError, _("can't read value of key '%s'"),
545 GetName().c_str());
546 return Type_None;
547 }
548
549 return (ValueType)dwType;
550 #else //WIN16
551 return IsEmpty(szValue) ? Type_String : Type_None;
552 #endif //WIN16/32
553}
554
555#ifdef __WIN32__
556bool wxRegKey::SetValue(const char *szValue, long lValue)
557{
558 if ( CONST_CAST Open() ) {
559 m_dwLastError = RegSetValueEx(m_hKey, szValue, RESERVED, REG_DWORD,
560 (RegString)&lValue, sizeof(lValue));
561 if ( m_dwLastError == ERROR_SUCCESS )
562 return TRUE;
563 }
564
565 wxLogSysError(m_dwLastError, _("can't set value of '%s'"),
566 GetFullName(this, szValue));
567 return FALSE;
568}
569
570bool wxRegKey::QueryValue(const char *szValue, long *plValue) const
571{
572 if ( CONST_CAST Open() ) {
573 DWORD dwType, dwSize = sizeof(DWORD);
574 RegString pBuf = (RegString)plValue;
575 m_dwLastError = RegQueryValueEx(m_hKey, szValue, RESERVED,
576 &dwType, pBuf, &dwSize);
577 if ( m_dwLastError != ERROR_SUCCESS ) {
578 wxLogSysError(m_dwLastError, _("can't read value of key '%s'"),
579 GetName().c_str());
580 return FALSE;
581 }
582 else {
583 // check that we read the value of right type
584 wxASSERT_MSG( dwType == REG_DWORD,
585 "Type mismatch in wxRegKey::QueryValue()." );
586
587 return TRUE;
588 }
589 }
590 else
591 return FALSE;
592}
593
594#endif //Win32
595
596bool wxRegKey::QueryValue(const char *szValue, wxString& strValue) const
597{
598 if ( CONST_CAST Open() ) {
599 #ifdef __WIN32__
600 // first get the type and size of the data
601 DWORD dwType, dwSize;
602 m_dwLastError = RegQueryValueEx(m_hKey, szValue, RESERVED,
603 &dwType, NULL, &dwSize);
604 if ( m_dwLastError == ERROR_SUCCESS ) {
605 RegString pBuf = (RegString)strValue.GetWriteBuf(dwSize);
606 m_dwLastError = RegQueryValueEx(m_hKey, szValue, RESERVED,
607 &dwType, pBuf, &dwSize);
608 strValue.UngetWriteBuf();
609 if ( m_dwLastError == ERROR_SUCCESS ) {
610 // check that it was the right type
611 wxASSERT_MSG( dwType == REG_SZ,
612 "Type mismatch in wxRegKey::QueryValue()." );
613
614 return TRUE;
615 }
616 }
617 #else //WIN16
618 // named registry values don't exist in Win16
619 wxASSERT( IsEmpty(szValue) );
620
621 m_dwLastError = RegQueryValue(m_hKey, 0, strValue.GetWriteBuf(256), &l);
622 strValue.UngetWriteBuf();
623 if ( m_dwLastError == ERROR_SUCCESS )
624 return TRUE;
625 #endif //WIN16/32
626 }
627
628 wxLogSysError(m_dwLastError, _("can't read value of '%s'"),
629 GetFullName(this, szValue));
630 return FALSE;
631}
632
633bool wxRegKey::SetValue(const char *szValue, const wxString& strValue)
634{
635 if ( CONST_CAST Open() ) {
636 #ifdef __WIN32__
637 m_dwLastError = RegSetValueEx(m_hKey, szValue, RESERVED, REG_SZ,
638 (RegString)strValue.c_str(),
639 strValue.Len() + 1);
640 if ( m_dwLastError == ERROR_SUCCESS )
641 return TRUE;
642 #else //WIN16
643 // named registry values don't exist in Win16
644 wxASSERT( IsEmpty(szValue) );
645
646 m_dwLastError = RegSetValue(m_hKey, NULL, REG_SZ, strValue, NULL);
647 if ( m_dwLastError == ERROR_SUCCESS )
648 return TRUE;
649 #endif //WIN16/32
650 }
651
652 wxLogSysError(m_dwLastError, _("can't set value of '%s'"),
653 GetFullName(this, szValue));
654 return FALSE;
655}
656
657wxRegKey::operator wxString() const
658{
659 wxString str;
660 QueryValue(NULL, str);
661 return str;
662}
663
664// ----------------------------------------------------------------------------
665// enumeration
666// NB: all these functions require an index variable which allows to have
667// several concurrently running indexations on the same key
668// ----------------------------------------------------------------------------
669
670bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex)
671{
672 if ( !Open() )
673 return FALSE;
674
675 lIndex = 0;
676 return GetNextValue(strValueName, lIndex);
677}
678
679bool wxRegKey::GetNextValue(wxString& strValueName, long& lIndex) const
680{
681 wxASSERT( IsOpened() );
682
683 // are we already at the end of enumeration?
684 if ( lIndex == -1 )
685 return FALSE;
686
687 #ifdef __WIN32__
688 char szValueName[1024]; // @@ use RegQueryInfoKey...
689 DWORD dwValueLen = WXSIZEOF(szValueName);
690
691 lIndex++;
692 m_dwLastError = RegEnumValue(m_hKey, lIndex,
693 szValueName, &dwValueLen,
694 RESERVED,
695 NULL, // [out] type
696 NULL, // [out] buffer for value
697 NULL); // [i/o] it's length
698
699 if ( m_dwLastError != ERROR_SUCCESS ) {
700 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
701 m_dwLastError = ERROR_SUCCESS;
702 lIndex = -1;
703 }
704 else {
705 wxLogSysError(m_dwLastError, _("can't enumerate values of key '%s'"),
706 GetName().c_str());
707 }
708
709 return FALSE;
710 }
711
712 strValueName = szValueName;
713 #else //WIN16
714 // only one unnamed value
715 wxASSERT( lIndex == 0 );
716
717 lIndex = -1;
718 strValueName.Empty();
719 #endif
720
721 return TRUE;
722}
723
724bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex)
725{
726 if ( !Open() )
727 return FALSE;
728
729 lIndex = 0;
730 return GetNextKey(strKeyName, lIndex);
731}
732
733bool wxRegKey::GetNextKey(wxString& strKeyName, long& lIndex) const
734{
735 wxASSERT( IsOpened() );
736
737 // are we already at the end of enumeration?
738 if ( lIndex == -1 )
739 return FALSE;
740
741 char szKeyName[_MAX_PATH + 1];
742 m_dwLastError = RegEnumKey(m_hKey, lIndex++, szKeyName, WXSIZEOF(szKeyName));
743
744 if ( m_dwLastError != ERROR_SUCCESS ) {
745 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
746 m_dwLastError = ERROR_SUCCESS;
747 lIndex = -1;
748 }
749 else {
750 wxLogSysError(m_dwLastError, _("can't enumerate subkeys of key '%s'"),
751 GetName().c_str());
752 }
753
754 return FALSE;
755 }
756
757 strKeyName = szKeyName;
758 return TRUE;
759}
760
761// ============================================================================
762// implementation of global functions
763// ============================================================================
764bool KeyExists(HKEY hRootKey, const char *szKey)
765{
766 HKEY hkeyDummy;
767 if ( RegOpenKey(hRootKey, szKey, &hkeyDummy) == ERROR_SUCCESS ) {
768 RegCloseKey(hkeyDummy);
769 return TRUE;
770 }
771 else
772 return FALSE;
773}
774
775const char *GetFullName(const wxRegKey *pKey, const char *szValue)
776{
777 static wxString s_str;
778 s_str = pKey->GetName();
779 if ( !IsEmpty(szValue) )
780 s_str << "\\" << szValue;
781
782 return s_str.c_str();
783}
784
785void RemoveTrailingSeparator(wxString& str)
786{
787 if ( !str.IsEmpty() && str.Last() == REG_SEPARATOR )
788 str.Truncate(str.Len() - 1);
789}