]> git.saurik.com Git - wxWidgets.git/blob - src/msw/registry.cpp
wxIniConfig added (pre-alpha quality, many functions not implemented), some
[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 if ( m_dwLastError == ERROR_SUCCESS ) {
593 // check that it was the right type
594 wxASSERT_MSG( dwType == REG_SZ,
595 "Type mismatch in wxRegKey::QueryValue()." );
596
597 return TRUE;
598 }
599 }
600 #else //WIN16
601 // named registry values don't exist in Win16
602 wxASSERT( IsEmpty(szValue) );
603
604 m_dwLastError = RegQueryValue(m_hKey, 0, strValue.GetWriteBuf(256), &l);
605 if ( m_dwLastError == ERROR_SUCCESS )
606 return TRUE;
607 #endif //WIN16/32
608 }
609
610 wxLogSysError(m_dwLastError, _("can't read value of '%s'"),
611 GetFullName(this, szValue));
612 return FALSE;
613 }
614
615 bool wxRegKey::SetValue(const char *szValue, const wxString& strValue)
616 {
617 if ( CONST_CAST Open() ) {
618 #ifdef __WIN32__
619 m_dwLastError = RegSetValueEx(m_hKey, szValue, RESERVED, REG_SZ,
620 (RegString)strValue.c_str(),
621 strValue.Len() + 1);
622 if ( m_dwLastError == ERROR_SUCCESS )
623 return TRUE;
624 #else //WIN16
625 // named registry values don't exist in Win16
626 wxASSERT( IsEmpty(szValue) );
627
628 m_dwLastError = RegSetValue(m_hKey, NULL, REG_SZ, strValue, NULL);
629 if ( m_dwLastError == ERROR_SUCCESS )
630 return TRUE;
631 #endif //WIN16/32
632 }
633
634 wxLogSysError(m_dwLastError, _("can't set value of '%s'"),
635 GetFullName(this, szValue));
636 return FALSE;
637 }
638
639 wxRegKey::operator wxString() const
640 {
641 wxString str;
642 QueryValue(NULL, str);
643 return str;
644 }
645
646 // ----------------------------------------------------------------------------
647 // enumeration
648 // NB: all these functions require an index variable which allows to have
649 // several concurrently running indexations on the same key
650 // ----------------------------------------------------------------------------
651
652 bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex)
653 {
654 if ( !Open() )
655 return FALSE;
656
657 lIndex = 0;
658 return GetNextValue(strValueName, lIndex);
659 }
660
661 bool wxRegKey::GetNextValue(wxString& strValueName, long& lIndex) const
662 {
663 wxASSERT( IsOpened() );
664
665 // are we already at the end of enumeration?
666 if ( lIndex == -1 )
667 return FALSE;
668
669 #ifdef __WIN32__
670 char szValueName[1024]; // @@ use RegQueryInfoKey...
671 DWORD dwValueLen = WXSIZEOF(szValueName);
672
673 lIndex++;
674 m_dwLastError = RegEnumValue(m_hKey, lIndex,
675 szValueName, &dwValueLen,
676 RESERVED,
677 NULL, // [out] type
678 NULL, // [out] buffer for value
679 NULL); // [i/o] it's length
680
681 if ( m_dwLastError != ERROR_SUCCESS ) {
682 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
683 m_dwLastError = ERROR_SUCCESS;
684 lIndex = -1;
685 }
686 else {
687 wxLogSysError(m_dwLastError, _("can't enumerate values of key '%s'"),
688 GetName().c_str());
689 }
690
691 return FALSE;
692 }
693
694 strValueName = szValueName;
695 #else //WIN16
696 // only one unnamed value
697 wxASSERT( lIndex == 0 );
698
699 lIndex = -1;
700 strValueName.Empty();
701 #endif
702
703 return TRUE;
704 }
705
706 bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex)
707 {
708 if ( !Open() )
709 return FALSE;
710
711 lIndex = 0;
712 return GetNextKey(strKeyName, lIndex);
713 }
714
715 bool wxRegKey::GetNextKey(wxString& strKeyName, long& lIndex) const
716 {
717 wxASSERT( IsOpened() );
718
719 // are we already at the end of enumeration?
720 if ( lIndex == -1 )
721 return FALSE;
722
723 char szKeyName[_MAX_PATH + 1];
724 m_dwLastError = RegEnumKey(m_hKey, lIndex++, szKeyName, WXSIZEOF(szKeyName));
725
726 if ( m_dwLastError != ERROR_SUCCESS ) {
727 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
728 m_dwLastError = ERROR_SUCCESS;
729 lIndex = -1;
730 }
731 else {
732 wxLogSysError(m_dwLastError, _("can't enumerate subkeys of key '%s'"),
733 GetName().c_str());
734 }
735
736 return FALSE;
737 }
738
739 strKeyName = szKeyName;
740 return TRUE;
741 }
742
743 // ============================================================================
744 // implementation of global functions
745 // ============================================================================
746 bool KeyExists(HKEY hRootKey, const char *szKey)
747 {
748 HKEY hkeyDummy;
749 if ( RegOpenKey(hRootKey, szKey, &hkeyDummy) == ERROR_SUCCESS ) {
750 RegCloseKey(hkeyDummy);
751 return TRUE;
752 }
753 else
754 return FALSE;
755 }
756
757 const char *GetFullName(const wxRegKey *pKey, const char *szValue)
758 {
759 static wxString s_str;
760 s_str = pKey->GetName();
761 if ( !IsEmpty(szValue) )
762 s_str << "\\" << szValue;
763
764 return s_str.c_str();
765 }
766
767 void RemoveTrailingSeparator(wxString& str)
768 {
769 if ( !str.IsEmpty() && str.Last() == REG_SEPARATOR )
770 str.Truncate(str.Len() - 1);
771 }