]> git.saurik.com Git - wxWidgets.git/blame - src/palmos/registry.cpp
Better alphabetized the event handler macros
[wxWidgets.git] / src / palmos / registry.cpp
CommitLineData
ffecfa5a
JS
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
49typedef 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
84const 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.
88const 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
96const 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
104wxRegKey::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
132wxRegKey::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
148wxRegKey::wxRegKey()
149{
150 m_hRootKey = (WXHKEY) aStdKeys[HKCR].hkey;
151
152 Init();
153}
154
155wxRegKey::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
163wxRegKey::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
172wxRegKey::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
190wxRegKey::~wxRegKey()
191{
192 Close();
193}
194
195// ----------------------------------------------------------------------------
196// change the key name/hkey
197// ----------------------------------------------------------------------------
198
199// set the full key name
200void 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
209void 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
219void 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
242void 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
254bool 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)
261wxString 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
272bool 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)
323bool 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
350bool 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
386bool 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
403bool 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
424bool 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
471bool 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
526bool 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
543bool 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// ----------------------------------------------------------------------------
587bool 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
643bool wxRegKey::DeleteKey(const wxChar *szKey)
644{
645 if ( !Open() )
646 return FALSE;
647
648 wxRegKey key(*this, szKey);
649 return key.DeleteSelf();
650}
651
652bool 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
675bool 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
691bool 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
703bool 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
715bool 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
726wxRegKey::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__
744bool 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
758bool 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
784bool 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
850bool 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
865wxString 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
878bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex)
879{
880 if ( !Open() )
881 return FALSE;
882
883 lIndex = 0;
884 return GetNextValue(strValueName, lIndex);
885}
886
887bool 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
923bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex)
924{
925 if ( !Open() )
926 return FALSE;
927
928 lIndex = 0;
929 return GetNextKey(strKeyName, lIndex);
930}
931
932bool 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)
968bool 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
986bool 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
1010const 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
1020void 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