]> git.saurik.com Git - wxWidgets.git/blob - src/palmos/registry.cpp
Only filter out duplicate -libraries. Let other constructs
[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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
16 #pragma implementation "registry.h"
17 #endif
18
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 // This really doesn't apply to the Palm OS platform. It would be better to
27 // support the Palm OS preference database instead.
28 #ifndef __WXPALMOS__
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.empty() && 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.empty() &&
177 (strKey.empty() || 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.empty() && 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.empty() )
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 default:
454 wxLogError(_("Can't copy values of unsupported type %d."),
455 GetValueType(szValue));
456 return false;
457 }
458 }
459
460 bool wxRegKey::Rename(const wxChar *szNewName)
461 {
462 wxCHECK_MSG( !!m_strKey, false, _T("registry hives can't be renamed") );
463
464 if ( !Exists() ) {
465 wxLogError(_("Registry key '%s' does not exist, cannot rename it."),
466 GetFullName(this));
467
468 return false;
469 }
470
471 // do we stay in the same hive?
472 bool inSameHive = !wxStrchr(szNewName, REG_SEPARATOR);
473
474 // construct the full new name of the key
475 wxRegKey keyDst;
476
477 if ( inSameHive ) {
478 // rename the key to the new name under the same parent
479 wxString strKey = m_strKey.BeforeLast(REG_SEPARATOR);
480 if ( !!strKey ) {
481 // don't add '\\' in the start if strFullNewName is empty
482 strKey += REG_SEPARATOR;
483 }
484
485 strKey += szNewName;
486
487 keyDst.SetName(GetStdKeyFromHkey(m_hRootKey), strKey);
488 }
489 else {
490 // this is the full name already
491 keyDst.SetName(szNewName);
492 }
493
494 bool ok = keyDst.Create(false /* fail if alredy exists */);
495 if ( !ok ) {
496 wxLogError(_("Registry key '%s' already exists."),
497 GetFullName(&keyDst));
498 }
499 else {
500 ok = Copy(keyDst) && DeleteSelf();
501 }
502
503 if ( !ok ) {
504 wxLogError(_("Failed to rename the registry key '%s' to '%s'."),
505 GetFullName(this), GetFullName(&keyDst));
506 }
507 else {
508 m_hRootKey = keyDst.m_hRootKey;
509 m_strKey = keyDst.m_strKey;
510 }
511
512 return ok;
513 }
514
515 bool wxRegKey::Copy(const wxChar *szNewName)
516 {
517 // create the new key first
518 wxRegKey keyDst(szNewName);
519 bool ok = keyDst.Create(false /* fail if alredy exists */);
520 if ( ok ) {
521 ok = Copy(keyDst);
522
523 // we created the dest key but copying to it failed - delete it
524 if ( !ok ) {
525 (void)keyDst.DeleteSelf();
526 }
527 }
528
529 return ok;
530 }
531
532 bool wxRegKey::Copy(wxRegKey& keyDst)
533 {
534 bool ok = true;
535
536 // copy all sub keys to the new location
537 wxString strKey;
538 long lIndex;
539 bool bCont = GetFirstKey(strKey, lIndex);
540 while ( ok && bCont ) {
541 wxRegKey key(*this, strKey);
542 wxString keyName;
543 keyName << GetFullName(&keyDst) << REG_SEPARATOR << strKey;
544 ok = key.Copy((const wxChar*) keyName);
545
546 if ( ok )
547 bCont = GetNextKey(strKey, lIndex);
548 }
549
550 // copy all values
551 wxString strVal;
552 bCont = GetFirstValue(strVal, lIndex);
553 while ( ok && bCont ) {
554 ok = CopyValue(strVal, keyDst);
555
556 if ( !ok ) {
557 wxLogSysError(m_dwLastError,
558 _("Failed to copy registry value '%s'"),
559 strVal.c_str());
560 }
561 else {
562 bCont = GetNextValue(strVal, lIndex);
563 }
564 }
565
566 if ( !ok ) {
567 wxLogError(_("Failed to copy the contents of registry key '%s' to '%s'."), GetFullName(this), GetFullName(&keyDst));
568 }
569
570 return ok;
571 }
572
573 // ----------------------------------------------------------------------------
574 // delete keys/values
575 // ----------------------------------------------------------------------------
576 bool wxRegKey::DeleteSelf()
577 {
578 {
579 wxLogNull nolog;
580 if ( !Open() ) {
581 // it already doesn't exist - ok!
582 return true;
583 }
584 }
585
586 // prevent a buggy program from erasing one of the root registry keys or an
587 // immediate subkey (i.e. one which doesn't have '\\' inside) of any other
588 // key except HKCR (HKCR has some "deleteable" subkeys)
589 if ( m_strKey.empty() ||
590 ((m_hRootKey != (WXHKEY) aStdKeys[HKCR].hkey) &&
591 (m_strKey.Find(REG_SEPARATOR) == wxNOT_FOUND)) ) {
592 wxLogError(_("Registry key '%s' is needed for normal system operation,\ndeleting it will leave your system in unusable state:\noperation aborted."), GetFullName(this));
593
594 return false;
595 }
596
597 // we can't delete keys while enumerating because it confuses GetNextKey, so
598 // we first save the key names and then delete them all
599 wxArrayString astrSubkeys;
600
601 wxString strKey;
602 long lIndex;
603 bool bCont = GetFirstKey(strKey, lIndex);
604 while ( bCont ) {
605 astrSubkeys.Add(strKey);
606
607 bCont = GetNextKey(strKey, lIndex);
608 }
609
610 size_t nKeyCount = astrSubkeys.Count();
611 for ( size_t nKey = 0; nKey < nKeyCount; nKey++ ) {
612 wxRegKey key(*this, astrSubkeys[nKey]);
613 if ( !key.DeleteSelf() )
614 return false;
615 }
616
617 // now delete this key itself
618 Close();
619
620 m_dwLastError = RegDeleteKey((HKEY) m_hRootKey, m_strKey);
621 // deleting a key which doesn't exist is not considered an error
622 if ( m_dwLastError != ERROR_SUCCESS &&
623 m_dwLastError != ERROR_FILE_NOT_FOUND ) {
624 wxLogSysError(m_dwLastError, _("Can't delete key '%s'"),
625 GetName().c_str());
626 return false;
627 }
628
629 return true;
630 }
631
632 bool wxRegKey::DeleteKey(const wxChar *szKey)
633 {
634 if ( !Open() )
635 return false;
636
637 wxRegKey key(*this, szKey);
638 return key.DeleteSelf();
639 }
640
641 bool wxRegKey::DeleteValue(const wxChar *szValue)
642 {
643 if ( !Open() )
644 return false;
645
646 m_dwLastError = RegDeleteValue((HKEY) m_hKey, WXSTRINGCAST szValue);
647
648 // deleting a value which doesn't exist is not considered an error
649 if ( (m_dwLastError != ERROR_SUCCESS) &&
650 (m_dwLastError != ERROR_FILE_NOT_FOUND) ) {
651 wxLogSysError(m_dwLastError, _("Can't delete value '%s' from key '%s'"),
652 szValue, GetName().c_str());
653 return false;
654 }
655
656 return true;
657 }
658
659 // ----------------------------------------------------------------------------
660 // access to values and subkeys
661 // ----------------------------------------------------------------------------
662
663 // return true if value exists
664 bool wxRegKey::HasValue(const wxChar *szValue) const
665 {
666 // this function should be silent, so suppress possible messages from Open()
667 wxLogNull nolog;
668
669 if ( !CONST_CAST Open() )
670 return false;
671
672 LONG dwRet = ::RegQueryValueEx((HKEY) m_hKey,
673 WXSTRINGCAST szValue,
674 RESERVED,
675 NULL, NULL, NULL);
676 return dwRet == ERROR_SUCCESS;
677 }
678
679 // returns true if this key has any values
680 bool wxRegKey::HasValues() const
681 {
682 // suppress possible messages from GetFirstValue()
683 wxLogNull nolog;
684
685 // just call GetFirstValue with dummy parameters
686 wxString str;
687 long l;
688 return CONST_CAST GetFirstValue(str, l);
689 }
690
691 // returns true if this key has any subkeys
692 bool wxRegKey::HasSubkeys() const
693 {
694 // suppress possible messages from GetFirstKey()
695 wxLogNull nolog;
696
697 // just call GetFirstKey with dummy parameters
698 wxString str;
699 long l;
700 return CONST_CAST GetFirstKey(str, l);
701 }
702
703 // returns true if given subkey exists
704 bool wxRegKey::HasSubKey(const wxChar *szKey) const
705 {
706 // this function should be silent, so suppress possible messages from Open()
707 wxLogNull nolog;
708
709 if ( !CONST_CAST Open() )
710 return false;
711
712 return KeyExists(m_hKey, szKey);
713 }
714
715 wxRegKey::ValueType wxRegKey::GetValueType(const wxChar *szValue) const
716 {
717 if ( ! CONST_CAST Open() )
718 return Type_None;
719
720 DWORD dwType;
721 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, WXSTRINGCAST szValue, RESERVED,
722 &dwType, NULL, NULL);
723 if ( m_dwLastError != ERROR_SUCCESS ) {
724 wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"),
725 GetName().c_str());
726 return Type_None;
727 }
728
729 return (ValueType)dwType;
730 }
731
732 bool wxRegKey::QueryValue(const wxChar *szValue,
733 wxString& strValue,
734 bool raw) const
735 {
736 if ( CONST_CAST Open() ) {
737
738 // first get the type and size of the data
739 DWORD dwType, dwSize;
740 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, WXSTRINGCAST szValue, RESERVED,
741 &dwType, NULL, &dwSize);
742 if ( m_dwLastError == ERROR_SUCCESS ) {
743 if ( !dwSize ) {
744 // must treat this case specially as GetWriteBuf() doesn't like
745 // being called with 0 size
746 strValue.Empty();
747 }
748 else {
749 m_dwLastError = RegQueryValueEx((HKEY) m_hKey,
750 WXSTRINGCAST szValue,
751 RESERVED,
752 &dwType,
753 (RegString)(wxChar*)wxStringBuffer(strValue, dwSize),
754 &dwSize);
755
756 // expand the var expansions in the string unless disabled
757 #ifndef __WXWINCE__
758 if ( (dwType == REG_EXPAND_SZ) && !raw )
759 {
760 DWORD dwExpSize = ::ExpandEnvironmentStrings(strValue, NULL, 0);
761 bool ok = dwExpSize != 0;
762 if ( ok )
763 {
764 wxString strExpValue;
765 ok = ::ExpandEnvironmentStrings
766 (
767 strValue,
768 wxStringBuffer(strExpValue, dwExpSize),
769 dwExpSize
770 ) != 0;
771 strValue = strExpValue;
772 }
773
774 if ( !ok )
775 {
776 wxLogLastError(_T("ExpandEnvironmentStrings"));
777 }
778 }
779 #endif
780 // __WXWINCE__
781 }
782
783 if ( m_dwLastError == ERROR_SUCCESS ) {
784 // check that it was the right type
785 wxASSERT_MSG( !IsNumericValue(szValue),
786 wxT("Type mismatch in wxRegKey::QueryValue().") );
787
788 return true;
789 }
790 }
791 }
792
793 wxLogSysError(m_dwLastError, _("Can't read value of '%s'"),
794 GetFullName(this, szValue));
795 return false;
796 }
797
798 bool wxRegKey::SetValue(const wxChar *szValue, const wxString& strValue)
799 {
800 if ( CONST_CAST Open() ) {
801 m_dwLastError = RegSetValueEx((HKEY) m_hKey, szValue, (DWORD) RESERVED, REG_SZ,
802 (RegString)strValue.c_str(),
803 (strValue.Len() + 1)*sizeof(wxChar));
804 if ( m_dwLastError == ERROR_SUCCESS )
805 return true;
806 }
807
808 wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
809 GetFullName(this, szValue));
810 return false;
811 }
812
813 wxString wxRegKey::QueryDefaultValue() const
814 {
815 wxString str;
816 QueryValue(NULL, str);
817 return str;
818 }
819
820 // ----------------------------------------------------------------------------
821 // enumeration
822 // NB: all these functions require an index variable which allows to have
823 // several concurrently running indexations on the same key
824 // ----------------------------------------------------------------------------
825
826 bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex)
827 {
828 if ( !Open() )
829 return false;
830
831 lIndex = 0;
832 return GetNextValue(strValueName, lIndex);
833 }
834
835 bool wxRegKey::GetNextValue(wxString& strValueName, long& lIndex) const
836 {
837 wxASSERT( IsOpened() );
838
839 // are we already at the end of enumeration?
840 if ( lIndex == -1 )
841 return false;
842
843 wxChar szValueName[1024]; // @@ use RegQueryInfoKey...
844 DWORD dwValueLen = WXSIZEOF(szValueName);
845
846 m_dwLastError = RegEnumValue((HKEY) m_hKey, lIndex++,
847 szValueName, &dwValueLen,
848 RESERVED,
849 NULL, // [out] type
850 NULL, // [out] buffer for value
851 NULL); // [i/o] it's length
852
853 if ( m_dwLastError != ERROR_SUCCESS ) {
854 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
855 m_dwLastError = ERROR_SUCCESS;
856 lIndex = -1;
857 }
858 else {
859 wxLogSysError(m_dwLastError, _("Can't enumerate values of key '%s'"),
860 GetName().c_str());
861 }
862
863 return false;
864 }
865
866 strValueName = szValueName;
867
868 return true;
869 }
870
871 bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex)
872 {
873 if ( !Open() )
874 return false;
875
876 lIndex = 0;
877 return GetNextKey(strKeyName, lIndex);
878 }
879
880 bool wxRegKey::GetNextKey(wxString& strKeyName, long& lIndex) const
881 {
882 wxASSERT( IsOpened() );
883
884 // are we already at the end of enumeration?
885 if ( lIndex == -1 )
886 return false;
887
888 wxChar szKeyName[_MAX_PATH + 1];
889
890 #ifdef __WXWINCE__
891 DWORD sizeName = WXSIZEOF(szKeyName);
892 m_dwLastError = RegEnumKeyEx((HKEY) m_hKey, lIndex++, szKeyName, & sizeName,
893 0, NULL, NULL, NULL);
894 #else
895 m_dwLastError = RegEnumKey((HKEY) m_hKey, lIndex++, szKeyName, WXSIZEOF(szKeyName));
896 #endif
897
898 if ( m_dwLastError != ERROR_SUCCESS ) {
899 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
900 m_dwLastError = ERROR_SUCCESS;
901 lIndex = -1;
902 }
903 else {
904 wxLogSysError(m_dwLastError, _("Can't enumerate subkeys of key '%s'"),
905 GetName().c_str());
906 }
907
908 return false;
909 }
910
911 strKeyName = szKeyName;
912 return true;
913 }
914
915 // returns true if the value contains a number (else it's some string)
916 bool wxRegKey::IsNumericValue(const wxChar *szValue) const
917 {
918 ValueType type = GetValueType(szValue);
919 switch ( type ) {
920 case Type_Dword:
921 /* case Type_Dword_little_endian: == Type_Dword */
922 case Type_Dword_big_endian:
923 return true;
924
925 default:
926 return false;
927 }
928 }
929
930 // ============================================================================
931 // implementation of global private functions
932 // ============================================================================
933
934 bool KeyExists(WXHKEY hRootKey, const wxChar *szKey)
935 {
936 // don't close this key itself for the case of empty szKey!
937 if ( wxIsEmpty(szKey) )
938 return true;
939
940 HKEY hkeyDummy;
941 if ( ::RegOpenKeyEx
942 (
943 (HKEY)hRootKey,
944 szKey,
945 RESERVED,
946 KEY_READ, // we might not have enough rights for rw access
947 &hkeyDummy
948 ) == ERROR_SUCCESS )
949 {
950 ::RegCloseKey(hkeyDummy);
951
952 return true;
953 }
954
955 return false;
956 }
957
958 const wxChar *GetFullName(const wxRegKey *pKey, const wxChar *szValue)
959 {
960 static wxString s_str;
961 s_str = pKey->GetName();
962 if ( !wxIsEmpty(szValue) )
963 s_str << wxT("\\") << szValue;
964
965 return s_str.c_str();
966 }
967
968 void RemoveTrailingSeparator(wxString& str)
969 {
970 if ( !str.empty() && str.Last() == REG_SEPARATOR )
971 str.Truncate(str.Len() - 1);
972 }
973
974 #endif //Palm OS
975