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