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