]> git.saurik.com Git - wxWidgets.git/blob - src/palmos/registry.cpp
fixed SaveDIB() crash with BW images (patch 1045884)
[wxWidgets.git] / src / palmos / registry.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: palmos/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 licence
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 // This really doesn't apply to the Palm OS platform. It would be better to
16 // support the Palm OS preference database instead.
17 #ifndef __PALMOS__
18
19 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
20 #pragma implementation "registry.h"
21 #endif
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 wxWidgets headers
31 #include "wx/string.h"
32 #include "wx/intl.h"
33 #include "wx/log.h"
34
35 #include "wx/palmos/wrapwin.h"
36
37 // other std headers
38 #include <stdlib.h> // for _MAX_PATH
39
40 #ifndef _MAX_PATH
41 #define _MAX_PATH 512
42 #endif
43
44 // our header
45 #define HKEY_DEFINED // already defined in windows.h
46 #include "wx/palmos/registry.h"
47
48 // some registry functions don't like signed chars
49 typedef unsigned char *RegString;
50
51 // ----------------------------------------------------------------------------
52 // constants
53 // ----------------------------------------------------------------------------
54
55 // the registry name separator (perhaps one day MS will change it to '/' ;-)
56 #define REG_SEPARATOR wxT('\\')
57
58 // useful for Windows programmers: makes somewhat more clear all these zeroes
59 // being passed to Windows APIs
60 #define RESERVED (0)
61
62 // ----------------------------------------------------------------------------
63 // macros
64 // ----------------------------------------------------------------------------
65
66 // const_cast<> is not yet supported by all compilers
67 #define CONST_CAST ((wxRegKey *)this)->
68
69 // and neither is mutable which m_dwLastError should be
70 #define m_dwLastError CONST_CAST m_dwLastError
71
72 // ----------------------------------------------------------------------------
73 // non member functions
74 // ----------------------------------------------------------------------------
75
76 // ============================================================================
77 // implementation of wxRegKey class
78 // ============================================================================
79
80 // ----------------------------------------------------------------------------
81 // static functions and variables
82 // ----------------------------------------------------------------------------
83
84 const size_t wxRegKey::nStdKeys = WXSIZEOF(aStdKeys);
85
86 // @@ should take a `StdKey key', but as it's often going to be used in loops
87 // it would require casts in user code.
88 const wxChar *wxRegKey::GetStdKeyName(size_t key)
89 {
90 // return empty string if key is invalid
91 wxCHECK_MSG( key < nStdKeys, wxEmptyString, wxT("invalid key in wxRegKey::GetStdKeyName") );
92
93 return aStdKeys[key].szName;
94 }
95
96 const wxChar *wxRegKey::GetStdKeyShortName(size_t key)
97 {
98 // return empty string if key is invalid
99 wxCHECK( key < nStdKeys, wxEmptyString );
100
101 return aStdKeys[key].szShortName;
102 }
103
104 wxRegKey::StdKey wxRegKey::ExtractKeyName(wxString& strKey)
105 {
106 wxString strRoot = strKey.BeforeFirst(REG_SEPARATOR);
107
108 HKEY hRootKey = 0;
109 size_t ui;
110 for ( ui = 0; ui < nStdKeys; ui++ ) {
111 if ( strRoot.CmpNoCase(aStdKeys[ui].szName) == 0 ||
112 strRoot.CmpNoCase(aStdKeys[ui].szShortName) == 0 ) {
113 hRootKey = aStdKeys[ui].hkey;
114 break;
115 }
116 }
117
118 if ( ui == nStdKeys ) {
119 wxFAIL_MSG(wxT("invalid key prefix in wxRegKey::ExtractKeyName."));
120
121 hRootKey = HKEY_CLASSES_ROOT;
122 }
123 else {
124 strKey = strKey.After(REG_SEPARATOR);
125 if ( !strKey.IsEmpty() && strKey.Last() == REG_SEPARATOR )
126 strKey.Truncate(strKey.Len() - 1);
127 }
128
129 return (wxRegKey::StdKey)(int)hRootKey;
130 }
131
132 wxRegKey::StdKey wxRegKey::GetStdKeyFromHkey(WXHKEY hkey)
133 {
134 for ( size_t ui = 0; ui < nStdKeys; ui++ ) {
135 if ( (int) aStdKeys[ui].hkey == (int) hkey )
136 return (StdKey)ui;
137 }
138
139 wxFAIL_MSG(wxT("non root hkey passed to wxRegKey::GetStdKeyFromHkey."));
140
141 return HKCR;
142 }
143
144 // ----------------------------------------------------------------------------
145 // ctors and dtor
146 // ----------------------------------------------------------------------------
147
148 wxRegKey::wxRegKey()
149 {
150 m_hRootKey = (WXHKEY) aStdKeys[HKCR].hkey;
151
152 Init();
153 }
154
155 wxRegKey::wxRegKey(const wxString& strKey) : m_strKey(strKey)
156 {
157 m_hRootKey = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey;
158
159 Init();
160 }
161
162 // parent is a predefined (and preopened) key
163 wxRegKey::wxRegKey(StdKey keyParent, const wxString& strKey) : m_strKey(strKey)
164 {
165 RemoveTrailingSeparator(m_strKey);
166 m_hRootKey = (WXHKEY) aStdKeys[keyParent].hkey;
167
168 Init();
169 }
170
171 // parent is a normal regkey
172 wxRegKey::wxRegKey(const wxRegKey& keyParent, const wxString& strKey)
173 : m_strKey(keyParent.m_strKey)
174 {
175 // combine our name with parent's to get the full name
176 if ( !m_strKey.IsEmpty() &&
177 (strKey.IsEmpty() || strKey[0] != REG_SEPARATOR) ) {
178 m_strKey += REG_SEPARATOR;
179 }
180
181 m_strKey += strKey;
182 RemoveTrailingSeparator(m_strKey);
183
184 m_hRootKey = keyParent.m_hRootKey;
185
186 Init();
187 }
188
189 // dtor closes the key releasing system resource
190 wxRegKey::~wxRegKey()
191 {
192 Close();
193 }
194
195 // ----------------------------------------------------------------------------
196 // change the key name/hkey
197 // ----------------------------------------------------------------------------
198
199 // set the full key name
200 void wxRegKey::SetName(const wxString& strKey)
201 {
202 Close();
203
204 m_strKey = strKey;
205 m_hRootKey = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey;
206 }
207
208 // the name is relative to the parent key
209 void wxRegKey::SetName(StdKey keyParent, const wxString& strKey)
210 {
211 Close();
212
213 m_strKey = strKey;
214 RemoveTrailingSeparator(m_strKey);
215 m_hRootKey = (WXHKEY) aStdKeys[keyParent].hkey;
216 }
217
218 // the name is relative to the parent key
219 void wxRegKey::SetName(const wxRegKey& keyParent, const wxString& strKey)
220 {
221 Close();
222
223 // combine our name with parent's to get the full name
224
225 // NB: this method is called by wxRegConfig::SetPath() which is a performance
226 // critical function and so it preallocates space for our m_strKey to
227 // gain some speed - this is why we only use += here and not = which
228 // would just free the prealloc'd buffer and would have to realloc it the
229 // next line!
230 m_strKey.clear();
231 m_strKey += keyParent.m_strKey;
232 if ( !strKey.IsEmpty() && strKey[0] != REG_SEPARATOR )
233 m_strKey += REG_SEPARATOR;
234 m_strKey += strKey;
235
236 RemoveTrailingSeparator(m_strKey);
237
238 m_hRootKey = keyParent.m_hRootKey;
239 }
240
241 // hKey should be opened and will be closed in wxRegKey dtor
242 void wxRegKey::SetHkey(WXHKEY hKey)
243 {
244 Close();
245
246 m_hKey = hKey;
247 }
248
249 // ----------------------------------------------------------------------------
250 // info about the key
251 // ----------------------------------------------------------------------------
252
253 // returns TRUE if the key exists
254 bool wxRegKey::Exists() const
255 {
256 // opened key has to exist, try to open it if not done yet
257 return IsOpened() ? TRUE : KeyExists(m_hRootKey, m_strKey);
258 }
259
260 // returns the full name of the key (prefix is abbreviated if bShortPrefix)
261 wxString wxRegKey::GetName(bool bShortPrefix) const
262 {
263 StdKey key = GetStdKeyFromHkey((WXHKEY) m_hRootKey);
264 wxString str = bShortPrefix ? aStdKeys[key].szShortName
265 : aStdKeys[key].szName;
266 if ( !m_strKey.IsEmpty() )
267 str << _T("\\") << m_strKey;
268
269 return str;
270 }
271
272 bool wxRegKey::GetKeyInfo(size_t *pnSubKeys,
273 size_t *pnMaxKeyLen,
274 size_t *pnValues,
275 size_t *pnMaxValueLen) const
276 {
277 // old gcc headers incorrectly prototype RegQueryInfoKey()
278 #if defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__)
279 #define REG_PARAM (size_t *)
280 #else
281 #define REG_PARAM (LPDWORD)
282 #endif
283
284 // it might be unexpected to some that this function doesn't open the key
285 wxASSERT_MSG( IsOpened(), _T("key should be opened in GetKeyInfo") );
286
287 m_dwLastError = ::RegQueryInfoKey
288 (
289 (HKEY) m_hKey,
290 NULL, // class name
291 NULL, // (ptr to) size of class name buffer
292 RESERVED,
293 REG_PARAM
294 pnSubKeys, // [out] number of subkeys
295 REG_PARAM
296 pnMaxKeyLen, // [out] max length of a subkey name
297 NULL, // longest subkey class name
298 REG_PARAM
299 pnValues, // [out] number of values
300 REG_PARAM
301 pnMaxValueLen, // [out] max length of a value name
302 NULL, // longest value data
303 NULL, // security descriptor
304 NULL // time of last modification
305 );
306
307 #undef REG_PARAM
308
309 if ( m_dwLastError != ERROR_SUCCESS ) {
310 wxLogSysError(m_dwLastError, _("Can't get info about registry key '%s'"),
311 GetName().c_str());
312 return FALSE;
313 }
314
315 return TRUE;
316 }
317
318 // ----------------------------------------------------------------------------
319 // operations
320 // ----------------------------------------------------------------------------
321
322 // opens key (it's not an error to call Open() on an already opened key)
323 bool wxRegKey::Open(AccessMode mode)
324 {
325 if ( IsOpened() )
326 return TRUE;
327
328 HKEY tmpKey;
329 m_dwLastError = ::RegOpenKeyEx
330 (
331 (HKEY) m_hRootKey,
332 m_strKey,
333 RESERVED,
334 mode == Read ? KEY_READ : KEY_ALL_ACCESS,
335 &tmpKey
336 );
337
338 if ( m_dwLastError != ERROR_SUCCESS )
339 {
340 wxLogSysError(m_dwLastError, _("Can't open registry key '%s'"),
341 GetName().c_str());
342 return FALSE;
343 }
344
345 m_hKey = (WXHKEY) tmpKey;
346 return TRUE;
347 }
348
349 // creates key, failing if it exists and !bOkIfExists
350 bool wxRegKey::Create(bool bOkIfExists)
351 {
352 // check for existence only if asked (i.e. order is important!)
353 if ( !bOkIfExists && Exists() )
354 return FALSE;
355
356 if ( IsOpened() )
357 return TRUE;
358
359 HKEY tmpKey;
360 #ifdef __WXWINCE__
361 DWORD disposition;
362 m_dwLastError = RegCreateKeyEx((HKEY) m_hRootKey, m_strKey,
363 NULL, // reserved
364 NULL, // class string
365 0,
366 0,
367 NULL,
368 &tmpKey,
369 &disposition);
370 #else
371 m_dwLastError = RegCreateKey((HKEY) m_hRootKey, m_strKey, &tmpKey);
372 #endif
373 if ( m_dwLastError != ERROR_SUCCESS ) {
374 wxLogSysError(m_dwLastError, _("Can't create registry key '%s'"),
375 GetName().c_str());
376 return FALSE;
377 }
378 else
379 {
380 m_hKey = (WXHKEY) tmpKey;
381 return TRUE;
382 }
383 }
384
385 // close the key, it's not an error to call it when not opened
386 bool wxRegKey::Close()
387 {
388 if ( IsOpened() ) {
389 m_dwLastError = RegCloseKey((HKEY) m_hKey);
390 m_hKey = 0;
391
392 if ( m_dwLastError != ERROR_SUCCESS ) {
393 wxLogSysError(m_dwLastError, _("Can't close registry key '%s'"),
394 GetName().c_str());
395
396 return FALSE;
397 }
398 }
399
400 return TRUE;
401 }
402
403 bool wxRegKey::RenameValue(const wxChar *szValueOld, const wxChar *szValueNew)
404 {
405 bool ok = TRUE;
406 if ( HasValue(szValueNew) ) {
407 wxLogError(_("Registry value '%s' already exists."), szValueNew);
408
409 ok = FALSE;
410 }
411
412 if ( !ok ||
413 !CopyValue(szValueOld, *this, szValueNew) ||
414 !DeleteValue(szValueOld) ) {
415 wxLogError(_("Failed to rename registry value '%s' to '%s'."),
416 szValueOld, szValueNew);
417
418 return FALSE;
419 }
420
421 return TRUE;
422 }
423
424 bool wxRegKey::CopyValue(const wxChar *szValue,
425 wxRegKey& keyDst,
426 const wxChar *szValueNew)
427 {
428 if ( !szValueNew ) {
429 // by default, use the same name
430 szValueNew = szValue;
431 }
432
433 switch ( GetValueType(szValue) ) {
434 case Type_String:
435 {
436 wxString strVal;
437 return QueryValue(szValue, strVal) &&
438 keyDst.SetValue(szValueNew, strVal);
439 }
440
441 case Type_Dword:
442 /* case Type_Dword_little_endian: == Type_Dword */
443 {
444 long dwVal;
445 return QueryValue(szValue, &dwVal) &&
446 keyDst.SetValue(szValueNew, dwVal);
447 }
448
449 // these types are unsupported because I am not sure about how
450 // exactly they should be copied and because they shouldn't
451 // occur among the application keys (supposedly created with
452 // this class)
453 #ifdef __WIN32__
454 case Type_None:
455 case Type_Expand_String:
456 case Type_Binary:
457 case Type_Dword_big_endian:
458 case Type_Link:
459 case Type_Multi_String:
460 case Type_Resource_list:
461 case Type_Full_resource_descriptor:
462 case Type_Resource_requirements_list:
463 #endif // Win32
464 default:
465 wxLogError(_("Can't copy values of unsupported type %d."),
466 GetValueType(szValue));
467 return FALSE;
468 }
469 }
470
471 bool wxRegKey::Rename(const wxChar *szNewName)
472 {
473 wxCHECK_MSG( !!m_strKey, FALSE, _T("registry hives can't be renamed") );
474
475 if ( !Exists() ) {
476 wxLogError(_("Registry key '%s' does not exist, cannot rename it."),
477 GetFullName(this));
478
479 return FALSE;
480 }
481
482 // do we stay in the same hive?
483 bool inSameHive = !wxStrchr(szNewName, REG_SEPARATOR);
484
485 // construct the full new name of the key
486 wxRegKey keyDst;
487
488 if ( inSameHive ) {
489 // rename the key to the new name under the same parent
490 wxString strKey = m_strKey.BeforeLast(REG_SEPARATOR);
491 if ( !!strKey ) {
492 // don't add '\\' in the start if strFullNewName is empty
493 strKey += REG_SEPARATOR;
494 }
495
496 strKey += szNewName;
497
498 keyDst.SetName(GetStdKeyFromHkey(m_hRootKey), strKey);
499 }
500 else {
501 // this is the full name already
502 keyDst.SetName(szNewName);
503 }
504
505 bool ok = keyDst.Create(FALSE /* fail if alredy exists */);
506 if ( !ok ) {
507 wxLogError(_("Registry key '%s' already exists."),
508 GetFullName(&keyDst));
509 }
510 else {
511 ok = Copy(keyDst) && DeleteSelf();
512 }
513
514 if ( !ok ) {
515 wxLogError(_("Failed to rename the registry key '%s' to '%s'."),
516 GetFullName(this), GetFullName(&keyDst));
517 }
518 else {
519 m_hRootKey = keyDst.m_hRootKey;
520 m_strKey = keyDst.m_strKey;
521 }
522
523 return ok;
524 }
525
526 bool wxRegKey::Copy(const wxChar *szNewName)
527 {
528 // create the new key first
529 wxRegKey keyDst(szNewName);
530 bool ok = keyDst.Create(FALSE /* fail if alredy exists */);
531 if ( ok ) {
532 ok = Copy(keyDst);
533
534 // we created the dest key but copying to it failed - delete it
535 if ( !ok ) {
536 (void)keyDst.DeleteSelf();
537 }
538 }
539
540 return ok;
541 }
542
543 bool wxRegKey::Copy(wxRegKey& keyDst)
544 {
545 bool ok = TRUE;
546
547 // copy all sub keys to the new location
548 wxString strKey;
549 long lIndex;
550 bool bCont = GetFirstKey(strKey, lIndex);
551 while ( ok && bCont ) {
552 wxRegKey key(*this, strKey);
553 wxString keyName;
554 keyName << GetFullName(&keyDst) << REG_SEPARATOR << strKey;
555 ok = key.Copy((const wxChar*) keyName);
556
557 if ( ok )
558 bCont = GetNextKey(strKey, lIndex);
559 }
560
561 // copy all values
562 wxString strVal;
563 bCont = GetFirstValue(strVal, lIndex);
564 while ( ok && bCont ) {
565 ok = CopyValue(strVal, keyDst);
566
567 if ( !ok ) {
568 wxLogSysError(m_dwLastError,
569 _("Failed to copy registry value '%s'"),
570 strVal.c_str());
571 }
572 else {
573 bCont = GetNextValue(strVal, lIndex);
574 }
575 }
576
577 if ( !ok ) {
578 wxLogError(_("Failed to copy the contents of registry key '%s' to '%s'."), GetFullName(this), GetFullName(&keyDst));
579 }
580
581 return ok;
582 }
583
584 // ----------------------------------------------------------------------------
585 // delete keys/values
586 // ----------------------------------------------------------------------------
587 bool wxRegKey::DeleteSelf()
588 {
589 {
590 wxLogNull nolog;
591 if ( !Open() ) {
592 // it already doesn't exist - ok!
593 return TRUE;
594 }
595 }
596
597 // prevent a buggy program from erasing one of the root registry keys or an
598 // immediate subkey (i.e. one which doesn't have '\\' inside) of any other
599 // key except HKCR (HKCR has some "deleteable" subkeys)
600 if ( m_strKey.IsEmpty() ||
601 ((m_hRootKey != (WXHKEY) aStdKeys[HKCR].hkey) &&
602 (m_strKey.Find(REG_SEPARATOR) == wxNOT_FOUND)) ) {
603 wxLogError(_("Registry key '%s' is needed for normal system operation,\ndeleting it will leave your system in unusable state:\noperation aborted."), GetFullName(this));
604
605 return FALSE;
606 }
607
608 // we can't delete keys while enumerating because it confuses GetNextKey, so
609 // we first save the key names and then delete them all
610 wxArrayString astrSubkeys;
611
612 wxString strKey;
613 long lIndex;
614 bool bCont = GetFirstKey(strKey, lIndex);
615 while ( bCont ) {
616 astrSubkeys.Add(strKey);
617
618 bCont = GetNextKey(strKey, lIndex);
619 }
620
621 size_t nKeyCount = astrSubkeys.Count();
622 for ( size_t nKey = 0; nKey < nKeyCount; nKey++ ) {
623 wxRegKey key(*this, astrSubkeys[nKey]);
624 if ( !key.DeleteSelf() )
625 return FALSE;
626 }
627
628 // now delete this key itself
629 Close();
630
631 m_dwLastError = RegDeleteKey((HKEY) m_hRootKey, m_strKey);
632 // deleting a key which doesn't exist is not considered an error
633 if ( m_dwLastError != ERROR_SUCCESS &&
634 m_dwLastError != ERROR_FILE_NOT_FOUND ) {
635 wxLogSysError(m_dwLastError, _("Can't delete key '%s'"),
636 GetName().c_str());
637 return FALSE;
638 }
639
640 return TRUE;
641 }
642
643 bool wxRegKey::DeleteKey(const wxChar *szKey)
644 {
645 if ( !Open() )
646 return FALSE;
647
648 wxRegKey key(*this, szKey);
649 return key.DeleteSelf();
650 }
651
652 bool wxRegKey::DeleteValue(const wxChar *szValue)
653 {
654 if ( !Open() )
655 return FALSE;
656
657 m_dwLastError = RegDeleteValue((HKEY) m_hKey, WXSTRINGCAST szValue);
658
659 // deleting a value which doesn't exist is not considered an error
660 if ( (m_dwLastError != ERROR_SUCCESS) &&
661 (m_dwLastError != ERROR_FILE_NOT_FOUND) ) {
662 wxLogSysError(m_dwLastError, _("Can't delete value '%s' from key '%s'"),
663 szValue, GetName().c_str());
664 return FALSE;
665 }
666
667 return TRUE;
668 }
669
670 // ----------------------------------------------------------------------------
671 // access to values and subkeys
672 // ----------------------------------------------------------------------------
673
674 // return TRUE if value exists
675 bool wxRegKey::HasValue(const wxChar *szValue) const
676 {
677 // this function should be silent, so suppress possible messages from Open()
678 wxLogNull nolog;
679
680 if ( !CONST_CAST Open() )
681 return FALSE;
682
683 LONG dwRet = ::RegQueryValueEx((HKEY) m_hKey,
684 WXSTRINGCAST szValue,
685 RESERVED,
686 NULL, NULL, NULL);
687 return dwRet == ERROR_SUCCESS;
688 }
689
690 // returns TRUE if this key has any values
691 bool wxRegKey::HasValues() const
692 {
693 // suppress possible messages from GetFirstValue()
694 wxLogNull nolog;
695
696 // just call GetFirstValue with dummy parameters
697 wxString str;
698 long l;
699 return CONST_CAST GetFirstValue(str, l);
700 }
701
702 // returns TRUE if this key has any subkeys
703 bool wxRegKey::HasSubkeys() const
704 {
705 // suppress possible messages from GetFirstKey()
706 wxLogNull nolog;
707
708 // just call GetFirstKey with dummy parameters
709 wxString str;
710 long l;
711 return CONST_CAST GetFirstKey(str, l);
712 }
713
714 // returns TRUE if given subkey exists
715 bool wxRegKey::HasSubKey(const wxChar *szKey) const
716 {
717 // this function should be silent, so suppress possible messages from Open()
718 wxLogNull nolog;
719
720 if ( !CONST_CAST Open() )
721 return FALSE;
722
723 return KeyExists(m_hKey, szKey);
724 }
725
726 wxRegKey::ValueType wxRegKey::GetValueType(const wxChar *szValue) const
727 {
728 if ( ! CONST_CAST Open() )
729 return Type_None;
730
731 DWORD dwType;
732 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, WXSTRINGCAST szValue, RESERVED,
733 &dwType, NULL, NULL);
734 if ( m_dwLastError != ERROR_SUCCESS ) {
735 wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"),
736 GetName().c_str());
737 return Type_None;
738 }
739
740 return (ValueType)dwType;
741 }
742
743 #ifdef __WIN32__
744 bool wxRegKey::SetValue(const wxChar *szValue, long lValue)
745 {
746 if ( CONST_CAST Open() ) {
747 m_dwLastError = RegSetValueEx((HKEY) m_hKey, szValue, (DWORD) RESERVED, REG_DWORD,
748 (RegString)&lValue, sizeof(lValue));
749 if ( m_dwLastError == ERROR_SUCCESS )
750 return TRUE;
751 }
752
753 wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
754 GetFullName(this, szValue));
755 return FALSE;
756 }
757
758 bool wxRegKey::QueryValue(const wxChar *szValue, long *plValue) const
759 {
760 if ( CONST_CAST Open() ) {
761 DWORD dwType, dwSize = sizeof(DWORD);
762 RegString pBuf = (RegString)plValue;
763 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, WXSTRINGCAST szValue, RESERVED,
764 &dwType, pBuf, &dwSize);
765 if ( m_dwLastError != ERROR_SUCCESS ) {
766 wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"),
767 GetName().c_str());
768 return FALSE;
769 }
770 else {
771 // check that we read the value of right type
772 wxASSERT_MSG( IsNumericValue(szValue),
773 wxT("Type mismatch in wxRegKey::QueryValue().") );
774
775 return TRUE;
776 }
777 }
778 else
779 return FALSE;
780 }
781
782 #endif //Win32
783
784 bool wxRegKey::QueryValue(const wxChar *szValue,
785 wxString& strValue,
786 bool raw) const
787 {
788 if ( CONST_CAST Open() ) {
789
790 // first get the type and size of the data
791 DWORD dwType, dwSize;
792 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, WXSTRINGCAST szValue, RESERVED,
793 &dwType, NULL, &dwSize);
794 if ( m_dwLastError == ERROR_SUCCESS ) {
795 if ( !dwSize ) {
796 // must treat this case specially as GetWriteBuf() doesn't like
797 // being called with 0 size
798 strValue.Empty();
799 }
800 else {
801 m_dwLastError = RegQueryValueEx((HKEY) m_hKey,
802 WXSTRINGCAST szValue,
803 RESERVED,
804 &dwType,
805 (RegString)(wxChar*)wxStringBuffer(strValue, dwSize),
806 &dwSize);
807
808 // expand the var expansions in the string unless disabled
809 #ifndef __WXWINCE__
810 if ( (dwType == REG_EXPAND_SZ) && !raw )
811 {
812 DWORD dwExpSize = ::ExpandEnvironmentStrings(strValue, NULL, 0);
813 bool ok = dwExpSize != 0;
814 if ( ok )
815 {
816 wxString strExpValue;
817 ok = ::ExpandEnvironmentStrings
818 (
819 strValue,
820 wxStringBuffer(strExpValue, dwExpSize),
821 dwExpSize
822 ) != 0;
823 strValue = strExpValue;
824 }
825
826 if ( !ok )
827 {
828 wxLogLastError(_T("ExpandEnvironmentStrings"));
829 }
830 }
831 #endif
832 // __WXWINCE__
833 }
834
835 if ( m_dwLastError == ERROR_SUCCESS ) {
836 // check that it was the right type
837 wxASSERT_MSG( !IsNumericValue(szValue),
838 wxT("Type mismatch in wxRegKey::QueryValue().") );
839
840 return TRUE;
841 }
842 }
843 }
844
845 wxLogSysError(m_dwLastError, _("Can't read value of '%s'"),
846 GetFullName(this, szValue));
847 return FALSE;
848 }
849
850 bool wxRegKey::SetValue(const wxChar *szValue, const wxString& strValue)
851 {
852 if ( CONST_CAST Open() ) {
853 m_dwLastError = RegSetValueEx((HKEY) m_hKey, szValue, (DWORD) RESERVED, REG_SZ,
854 (RegString)strValue.c_str(),
855 (strValue.Len() + 1)*sizeof(wxChar));
856 if ( m_dwLastError == ERROR_SUCCESS )
857 return TRUE;
858 }
859
860 wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
861 GetFullName(this, szValue));
862 return FALSE;
863 }
864
865 wxString wxRegKey::QueryDefaultValue() const
866 {
867 wxString str;
868 QueryValue(NULL, str);
869 return str;
870 }
871
872 // ----------------------------------------------------------------------------
873 // enumeration
874 // NB: all these functions require an index variable which allows to have
875 // several concurrently running indexations on the same key
876 // ----------------------------------------------------------------------------
877
878 bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex)
879 {
880 if ( !Open() )
881 return FALSE;
882
883 lIndex = 0;
884 return GetNextValue(strValueName, lIndex);
885 }
886
887 bool wxRegKey::GetNextValue(wxString& strValueName, long& lIndex) const
888 {
889 wxASSERT( IsOpened() );
890
891 // are we already at the end of enumeration?
892 if ( lIndex == -1 )
893 return FALSE;
894
895 wxChar szValueName[1024]; // @@ use RegQueryInfoKey...
896 DWORD dwValueLen = WXSIZEOF(szValueName);
897
898 m_dwLastError = RegEnumValue((HKEY) m_hKey, lIndex++,
899 szValueName, &dwValueLen,
900 RESERVED,
901 NULL, // [out] type
902 NULL, // [out] buffer for value
903 NULL); // [i/o] it's length
904
905 if ( m_dwLastError != ERROR_SUCCESS ) {
906 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
907 m_dwLastError = ERROR_SUCCESS;
908 lIndex = -1;
909 }
910 else {
911 wxLogSysError(m_dwLastError, _("Can't enumerate values of key '%s'"),
912 GetName().c_str());
913 }
914
915 return FALSE;
916 }
917
918 strValueName = szValueName;
919
920 return TRUE;
921 }
922
923 bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex)
924 {
925 if ( !Open() )
926 return FALSE;
927
928 lIndex = 0;
929 return GetNextKey(strKeyName, lIndex);
930 }
931
932 bool wxRegKey::GetNextKey(wxString& strKeyName, long& lIndex) const
933 {
934 wxASSERT( IsOpened() );
935
936 // are we already at the end of enumeration?
937 if ( lIndex == -1 )
938 return FALSE;
939
940 wxChar szKeyName[_MAX_PATH + 1];
941
942 #ifdef __WXWINCE__
943 DWORD sizeName = WXSIZEOF(szKeyName);
944 m_dwLastError = RegEnumKeyEx((HKEY) m_hKey, lIndex++, szKeyName, & sizeName,
945 0, NULL, NULL, NULL);
946 #else
947 m_dwLastError = RegEnumKey((HKEY) m_hKey, lIndex++, szKeyName, WXSIZEOF(szKeyName));
948 #endif
949
950 if ( m_dwLastError != ERROR_SUCCESS ) {
951 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
952 m_dwLastError = ERROR_SUCCESS;
953 lIndex = -1;
954 }
955 else {
956 wxLogSysError(m_dwLastError, _("Can't enumerate subkeys of key '%s'"),
957 GetName().c_str());
958 }
959
960 return FALSE;
961 }
962
963 strKeyName = szKeyName;
964 return TRUE;
965 }
966
967 // returns TRUE if the value contains a number (else it's some string)
968 bool wxRegKey::IsNumericValue(const wxChar *szValue) const
969 {
970 ValueType type = GetValueType(szValue);
971 switch ( type ) {
972 case Type_Dword:
973 /* case Type_Dword_little_endian: == Type_Dword */
974 case Type_Dword_big_endian:
975 return TRUE;
976
977 default:
978 return FALSE;
979 }
980 }
981
982 // ============================================================================
983 // implementation of global private functions
984 // ============================================================================
985
986 bool KeyExists(WXHKEY hRootKey, const wxChar *szKey)
987 {
988 // don't close this key itself for the case of empty szKey!
989 if ( wxIsEmpty(szKey) )
990 return TRUE;
991
992 HKEY hkeyDummy;
993 if ( ::RegOpenKeyEx
994 (
995 (HKEY)hRootKey,
996 szKey,
997 RESERVED,
998 KEY_READ, // we might not have enough rights for rw access
999 &hkeyDummy
1000 ) == ERROR_SUCCESS )
1001 {
1002 ::RegCloseKey(hkeyDummy);
1003
1004 return TRUE;
1005 }
1006
1007 return FALSE;
1008 }
1009
1010 const wxChar *GetFullName(const wxRegKey *pKey, const wxChar *szValue)
1011 {
1012 static wxString s_str;
1013 s_str = pKey->GetName();
1014 if ( !wxIsEmpty(szValue) )
1015 s_str << wxT("\\") << szValue;
1016
1017 return s_str.c_str();
1018 }
1019
1020 void RemoveTrailingSeparator(wxString& str)
1021 {
1022 if ( !str.IsEmpty() && str.Last() == REG_SEPARATOR )
1023 str.Truncate(str.Len() - 1);
1024 }
1025
1026 #endif //Palm OS
1027