spurious error messages from wxRegKey::HasValue() suppressed
[wxWidgets.git] / src / msw / registry.cpp
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
55 typedef 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
63 static struct
64 {
65 HKEY hkey;
66 const char *szName;
67 const char *szShortName;
68 }
69 aStdKeys[] =
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
108 static inline void RemoveTrailingSeparator(wxString& str);
109
110 // returns TRUE if given registry key exists
111 static bool KeyExists(HKEY hRootKey, const char *szKey);
112
113 // combines value and key name (uses static buffer!)
114 static 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
125 const 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.
129 const 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
137 const 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
145 wxRegKey::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
173 wxRegKey::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
189 wxRegKey::wxRegKey()
190 {
191 m_hKey = 0;
192 m_hRootKey = aStdKeys[HKCR].hkey;
193 m_dwLastError = 0;
194 }
195
196 wxRegKey::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
204 wxRegKey::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
213 wxRegKey::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
231 wxRegKey::~wxRegKey()
232 {
233 Close();
234 }
235
236 // ----------------------------------------------------------------------------
237 // change the key name/hkey
238 // ----------------------------------------------------------------------------
239
240 // set the full key name
241 void 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
250 void 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
260 void 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
276 void 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
288 bool 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)
295 wxString 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__
307 bool wxRegKey::GetKeyInfo(size_t* pnSubKeys,
308 size_t* pnMaxKeyLen,
309 size_t* pnValues,
310 size_t* pnMaxValueLen) const
311 #else
312 bool 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)
354 bool 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
370 bool 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
391 bool 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 // ----------------------------------------------------------------------------
413 bool 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
456 bool wxRegKey::DeleteKey(const char *szKey)
457 {
458 if ( !Open() )
459 return FALSE;
460
461 wxRegKey key(*this, szKey);
462 return key.DeleteSelf();
463 }
464
465 bool 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
498 bool 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
517 bool 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
526 bool 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
534 wxRegKey::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__
556 bool 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
570 bool 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
596 bool 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
633 bool 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
657 wxRegKey::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
670 bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex)
671 {
672 if ( !Open() )
673 return FALSE;
674
675 lIndex = 0;
676 return GetNextValue(strValueName, lIndex);
677 }
678
679 bool 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
724 bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex)
725 {
726 if ( !Open() )
727 return FALSE;
728
729 lIndex = 0;
730 return GetNextKey(strKeyName, lIndex);
731 }
732
733 bool 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 // ============================================================================
764 bool 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
775 const 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
785 void RemoveTrailingSeparator(wxString& str)
786 {
787 if ( !str.IsEmpty() && str.Last() == REG_SEPARATOR )
788 str.Truncate(str.Len() - 1);
789 }