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