]> git.saurik.com Git - wxWidgets.git/blob - src/msw/registry.cpp
OS X compilation fix
[wxWidgets.git] / src / msw / registry.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/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 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 // for compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
17
18 #ifdef __BORLANDC__
19 #pragma hdrstop
20 #endif
21
22 #ifndef WX_PRECOMP
23 #include "wx/msw/wrapwin.h"
24 #include "wx/string.h"
25 #include "wx/intl.h"
26 #include "wx/log.h"
27 #include "wx/crt.h"
28 #endif
29
30 #include "wx/file.h"
31 #include "wx/wfstream.h"
32
33 // Windows headers
34 #ifdef __WXWINCE__
35 #include "wx/msw/private.h"
36 #include <winbase.h>
37 #include <winreg.h>
38 #endif
39
40 // other std headers
41 #include <stdlib.h> // for _MAX_PATH
42
43 #ifndef _MAX_PATH
44 #define _MAX_PATH 512
45 #endif
46
47 // our header
48 #define HKEY_DEFINED // already defined in windows.h
49 #include "wx/msw/registry.h"
50
51 // some registry functions don't like signed chars
52 typedef unsigned char *RegString;
53 typedef BYTE* RegBinary;
54
55 #ifndef HKEY_PERFORMANCE_DATA
56 #define HKEY_PERFORMANCE_DATA ((HKEY)0x80000004)
57 #endif
58
59 #ifndef HKEY_CURRENT_CONFIG
60 #define HKEY_CURRENT_CONFIG ((HKEY)0x80000005)
61 #endif
62
63 #ifndef HKEY_DYN_DATA
64 #define HKEY_DYN_DATA ((HKEY)0x80000006)
65 #endif
66
67 // ----------------------------------------------------------------------------
68 // constants
69 // ----------------------------------------------------------------------------
70
71 // the standard key names, short names and handles all bundled together for
72 // convenient access
73 static struct
74 {
75 HKEY hkey;
76 const wxChar *szName;
77 const wxChar *szShortName;
78 }
79 aStdKeys[] =
80 {
81 { HKEY_CLASSES_ROOT, wxT("HKEY_CLASSES_ROOT"), wxT("HKCR") },
82 { HKEY_CURRENT_USER, wxT("HKEY_CURRENT_USER"), wxT("HKCU") },
83 { HKEY_LOCAL_MACHINE, wxT("HKEY_LOCAL_MACHINE"), wxT("HKLM") },
84 { HKEY_USERS, wxT("HKEY_USERS"), wxT("HKU") }, // short name?
85 { HKEY_PERFORMANCE_DATA, wxT("HKEY_PERFORMANCE_DATA"), wxT("HKPD") },
86 { HKEY_CURRENT_CONFIG, wxT("HKEY_CURRENT_CONFIG"), wxT("HKCC") },
87 { HKEY_DYN_DATA, wxT("HKEY_DYN_DATA"), wxT("HKDD") }, // short name?
88 };
89
90 // the registry name separator (perhaps one day MS will change it to '/' ;-)
91 #define REG_SEPARATOR wxT('\\')
92
93 // useful for Windows programmers: makes somewhat more clear all these zeroes
94 // being passed to Windows APIs
95 #define RESERVED (0)
96
97 // ----------------------------------------------------------------------------
98 // macros
99 // ----------------------------------------------------------------------------
100
101 // const_cast<> is not yet supported by all compilers
102 #define CONST_CAST ((wxRegKey *)this)->
103
104 // and neither is mutable which m_dwLastError should be
105 #define m_dwLastError CONST_CAST m_dwLastError
106
107 // ----------------------------------------------------------------------------
108 // non member functions
109 // ----------------------------------------------------------------------------
110
111 // removes the trailing backslash from the string if it has one
112 static inline void RemoveTrailingSeparator(wxString& str);
113
114 // returns true if given registry key exists
115 static bool KeyExists(WXHKEY hRootKey, const wxChar *szKey);
116
117 // combines value and key name (uses static buffer!)
118 static const wxChar *GetFullName(const wxRegKey *pKey,
119 const wxChar *szValue = NULL);
120
121 // ============================================================================
122 // implementation of wxRegKey class
123 // ============================================================================
124
125 // ----------------------------------------------------------------------------
126 // static functions and variables
127 // ----------------------------------------------------------------------------
128
129 const size_t wxRegKey::nStdKeys = WXSIZEOF(aStdKeys);
130
131 // @@ should take a `StdKey key', but as it's often going to be used in loops
132 // it would require casts in user code.
133 const wxChar *wxRegKey::GetStdKeyName(size_t key)
134 {
135 // return empty string if key is invalid
136 wxCHECK_MSG( key < nStdKeys, wxEmptyString, wxT("invalid key in wxRegKey::GetStdKeyName") );
137
138 return aStdKeys[key].szName;
139 }
140
141 const wxChar *wxRegKey::GetStdKeyShortName(size_t key)
142 {
143 // return empty string if key is invalid
144 wxCHECK( key < nStdKeys, wxEmptyString );
145
146 return aStdKeys[key].szShortName;
147 }
148
149 wxRegKey::StdKey wxRegKey::ExtractKeyName(wxString& strKey)
150 {
151 wxString strRoot = strKey.BeforeFirst(REG_SEPARATOR);
152
153 size_t ui;
154 for ( ui = 0; ui < nStdKeys; ui++ ) {
155 if ( strRoot.CmpNoCase(aStdKeys[ui].szName) == 0 ||
156 strRoot.CmpNoCase(aStdKeys[ui].szShortName) == 0 ) {
157 break;
158 }
159 }
160
161 if ( ui == nStdKeys ) {
162 wxFAIL_MSG(wxT("invalid key prefix in wxRegKey::ExtractKeyName."));
163
164 ui = HKCR;
165 }
166 else {
167 strKey = strKey.After(REG_SEPARATOR);
168 if ( !strKey.empty() && strKey.Last() == REG_SEPARATOR )
169 strKey.Truncate(strKey.Len() - 1);
170 }
171
172 return (StdKey)ui;
173 }
174
175 wxRegKey::StdKey wxRegKey::GetStdKeyFromHkey(WXHKEY hkey)
176 {
177 for ( size_t ui = 0; ui < nStdKeys; ui++ ) {
178 if ( aStdKeys[ui].hkey == (HKEY)hkey )
179 return (StdKey)ui;
180 }
181
182 wxFAIL_MSG(wxT("non root hkey passed to wxRegKey::GetStdKeyFromHkey."));
183
184 return HKCR;
185 }
186
187 // ----------------------------------------------------------------------------
188 // ctors and dtor
189 // ----------------------------------------------------------------------------
190
191 wxRegKey::wxRegKey()
192 {
193 m_hRootKey = (WXHKEY) aStdKeys[HKCR].hkey;
194
195 Init();
196 }
197
198 wxRegKey::wxRegKey(const wxString& strKey) : m_strKey(strKey)
199 {
200 m_hRootKey = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey;
201
202 Init();
203 }
204
205 // parent is a predefined (and preopened) key
206 wxRegKey::wxRegKey(StdKey keyParent, const wxString& strKey) : m_strKey(strKey)
207 {
208 RemoveTrailingSeparator(m_strKey);
209 m_hRootKey = (WXHKEY) aStdKeys[keyParent].hkey;
210
211 Init();
212 }
213
214 // parent is a normal regkey
215 wxRegKey::wxRegKey(const wxRegKey& keyParent, const wxString& strKey)
216 : m_strKey(keyParent.m_strKey)
217 {
218 // combine our name with parent's to get the full name
219 if ( !m_strKey.empty() &&
220 (strKey.empty() || strKey[0] != REG_SEPARATOR) ) {
221 m_strKey += REG_SEPARATOR;
222 }
223
224 m_strKey += strKey;
225 RemoveTrailingSeparator(m_strKey);
226
227 m_hRootKey = keyParent.m_hRootKey;
228
229 Init();
230 }
231
232 // dtor closes the key releasing system resource
233 wxRegKey::~wxRegKey()
234 {
235 Close();
236 }
237
238 // ----------------------------------------------------------------------------
239 // change the key name/hkey
240 // ----------------------------------------------------------------------------
241
242 // set the full key name
243 void wxRegKey::SetName(const wxString& strKey)
244 {
245 Close();
246
247 m_strKey = strKey;
248 m_hRootKey = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey;
249 }
250
251 // the name is relative to the parent key
252 void wxRegKey::SetName(StdKey keyParent, const wxString& strKey)
253 {
254 Close();
255
256 m_strKey = strKey;
257 RemoveTrailingSeparator(m_strKey);
258 m_hRootKey = (WXHKEY) aStdKeys[keyParent].hkey;
259 }
260
261 // the name is relative to the parent key
262 void wxRegKey::SetName(const wxRegKey& keyParent, const wxString& strKey)
263 {
264 Close();
265
266 // combine our name with parent's to get the full name
267
268 // NB: this method is called by wxRegConfig::SetPath() which is a performance
269 // critical function and so it preallocates space for our m_strKey to
270 // gain some speed - this is why we only use += here and not = which
271 // would just free the prealloc'd buffer and would have to realloc it the
272 // next line!
273 m_strKey.clear();
274 m_strKey += keyParent.m_strKey;
275 if ( !strKey.empty() && strKey[0] != REG_SEPARATOR )
276 m_strKey += REG_SEPARATOR;
277 m_strKey += strKey;
278
279 RemoveTrailingSeparator(m_strKey);
280
281 m_hRootKey = keyParent.m_hRootKey;
282 }
283
284 // hKey should be opened and will be closed in wxRegKey dtor
285 void wxRegKey::SetHkey(WXHKEY hKey)
286 {
287 Close();
288
289 m_hKey = hKey;
290 }
291
292 // ----------------------------------------------------------------------------
293 // info about the key
294 // ----------------------------------------------------------------------------
295
296 // returns true if the key exists
297 bool wxRegKey::Exists() const
298 {
299 // opened key has to exist, try to open it if not done yet
300 return IsOpened() ? true : KeyExists(m_hRootKey, m_strKey);
301 }
302
303 // returns the full name of the key (prefix is abbreviated if bShortPrefix)
304 wxString wxRegKey::GetName(bool bShortPrefix) const
305 {
306 StdKey key = GetStdKeyFromHkey((WXHKEY) m_hRootKey);
307 wxString str = bShortPrefix ? aStdKeys[key].szShortName
308 : aStdKeys[key].szName;
309 if ( !m_strKey.empty() )
310 str << _T("\\") << m_strKey;
311
312 return str;
313 }
314
315 bool wxRegKey::GetKeyInfo(size_t *pnSubKeys,
316 size_t *pnMaxKeyLen,
317 size_t *pnValues,
318 size_t *pnMaxValueLen) const
319 {
320 // old gcc headers incorrectly prototype RegQueryInfoKey()
321 #if defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__)
322 #define REG_PARAM (size_t *)
323 #else
324 #define REG_PARAM (LPDWORD)
325 #endif
326
327 // it might be unexpected to some that this function doesn't open the key
328 wxASSERT_MSG( IsOpened(), _T("key should be opened in GetKeyInfo") );
329
330 m_dwLastError = ::RegQueryInfoKey
331 (
332 (HKEY) m_hKey,
333 NULL, // class name
334 NULL, // (ptr to) size of class name buffer
335 RESERVED,
336 REG_PARAM
337 pnSubKeys, // [out] number of subkeys
338 REG_PARAM
339 pnMaxKeyLen, // [out] max length of a subkey name
340 NULL, // longest subkey class name
341 REG_PARAM
342 pnValues, // [out] number of values
343 REG_PARAM
344 pnMaxValueLen, // [out] max length of a value name
345 NULL, // longest value data
346 NULL, // security descriptor
347 NULL // time of last modification
348 );
349
350 #undef REG_PARAM
351
352 if ( m_dwLastError != ERROR_SUCCESS ) {
353 wxLogSysError(m_dwLastError, _("Can't get info about registry key '%s'"),
354 GetName().c_str());
355 return false;
356 }
357
358 return true;
359 }
360
361 // ----------------------------------------------------------------------------
362 // operations
363 // ----------------------------------------------------------------------------
364
365 // opens key (it's not an error to call Open() on an already opened key)
366 bool wxRegKey::Open(AccessMode mode)
367 {
368 if ( IsOpened() )
369 {
370 if ( mode <= m_mode )
371 return true;
372
373 // we had been opened in read mode but now must be reopened in write
374 Close();
375 }
376
377 HKEY tmpKey;
378 m_dwLastError = ::RegOpenKeyEx
379 (
380 (HKEY) m_hRootKey,
381 m_strKey,
382 RESERVED,
383 mode == Read ? KEY_READ : KEY_ALL_ACCESS,
384 &tmpKey
385 );
386
387 if ( m_dwLastError != ERROR_SUCCESS )
388 {
389 wxLogSysError(m_dwLastError, _("Can't open registry key '%s'"),
390 GetName().c_str());
391 return false;
392 }
393
394 m_hKey = (WXHKEY) tmpKey;
395 m_mode = mode;
396
397 return true;
398 }
399
400 // creates key, failing if it exists and !bOkIfExists
401 bool wxRegKey::Create(bool bOkIfExists)
402 {
403 // check for existence only if asked (i.e. order is important!)
404 if ( !bOkIfExists && Exists() )
405 return false;
406
407 if ( IsOpened() )
408 return true;
409
410 HKEY tmpKey;
411 #ifdef __WXWINCE__
412 DWORD disposition;
413 m_dwLastError = RegCreateKeyEx((HKEY) m_hRootKey, m_strKey,
414 NULL, // reserved
415 NULL, // class string
416 0,
417 0,
418 NULL,
419 &tmpKey,
420 &disposition);
421 #else
422 m_dwLastError = RegCreateKey((HKEY) m_hRootKey, m_strKey, &tmpKey);
423 #endif
424 if ( m_dwLastError != ERROR_SUCCESS ) {
425 wxLogSysError(m_dwLastError, _("Can't create registry key '%s'"),
426 GetName().c_str());
427 return false;
428 }
429 else
430 {
431 m_hKey = (WXHKEY) tmpKey;
432 return true;
433 }
434 }
435
436 // close the key, it's not an error to call it when not opened
437 bool wxRegKey::Close()
438 {
439 if ( IsOpened() ) {
440 m_dwLastError = RegCloseKey((HKEY) m_hKey);
441 m_hKey = 0;
442
443 if ( m_dwLastError != ERROR_SUCCESS ) {
444 wxLogSysError(m_dwLastError, _("Can't close registry key '%s'"),
445 GetName().c_str());
446
447 return false;
448 }
449 }
450
451 return true;
452 }
453
454 bool wxRegKey::RenameValue(const wxChar *szValueOld, const wxChar *szValueNew)
455 {
456 bool ok = true;
457 if ( HasValue(szValueNew) ) {
458 wxLogError(_("Registry value '%s' already exists."), szValueNew);
459
460 ok = false;
461 }
462
463 if ( !ok ||
464 !CopyValue(szValueOld, *this, szValueNew) ||
465 !DeleteValue(szValueOld) ) {
466 wxLogError(_("Failed to rename registry value '%s' to '%s'."),
467 szValueOld, szValueNew);
468
469 return false;
470 }
471
472 return true;
473 }
474
475 bool wxRegKey::CopyValue(const wxChar *szValue,
476 wxRegKey& keyDst,
477 const wxChar *szValueNew)
478 {
479 if ( !szValueNew ) {
480 // by default, use the same name
481 szValueNew = szValue;
482 }
483
484 switch ( GetValueType(szValue) ) {
485 case Type_String:
486 {
487 wxString strVal;
488 return QueryValue(szValue, strVal) &&
489 keyDst.SetValue(szValueNew, strVal);
490 }
491
492 case Type_Dword:
493 /* case Type_Dword_little_endian: == Type_Dword */
494 {
495 long dwVal;
496 return QueryValue(szValue, &dwVal) &&
497 keyDst.SetValue(szValueNew, dwVal);
498 }
499
500 case Type_Binary:
501 {
502 wxMemoryBuffer buf;
503 return QueryValue(szValue,buf) &&
504 keyDst.SetValue(szValueNew,buf);
505 }
506
507 // these types are unsupported because I am not sure about how
508 // exactly they should be copied and because they shouldn't
509 // occur among the application keys (supposedly created with
510 // this class)
511 case Type_None:
512 case Type_Expand_String:
513 case Type_Dword_big_endian:
514 case Type_Link:
515 case Type_Multi_String:
516 case Type_Resource_list:
517 case Type_Full_resource_descriptor:
518 case Type_Resource_requirements_list:
519 default:
520 wxLogError(_("Can't copy values of unsupported type %d."),
521 GetValueType(szValue));
522 return false;
523 }
524 }
525
526 bool wxRegKey::Rename(const wxChar *szNewName)
527 {
528 wxCHECK_MSG( !m_strKey.empty(), false, _T("registry hives can't be renamed") );
529
530 if ( !Exists() ) {
531 wxLogError(_("Registry key '%s' does not exist, cannot rename it."),
532 GetFullName(this));
533
534 return false;
535 }
536
537 // do we stay in the same hive?
538 bool inSameHive = !wxStrchr(szNewName, REG_SEPARATOR);
539
540 // construct the full new name of the key
541 wxRegKey keyDst;
542
543 if ( inSameHive ) {
544 // rename the key to the new name under the same parent
545 wxString strKey = m_strKey.BeforeLast(REG_SEPARATOR);
546 if ( !strKey.empty() ) {
547 // don't add '\\' in the start if strFullNewName is empty
548 strKey += REG_SEPARATOR;
549 }
550
551 strKey += szNewName;
552
553 keyDst.SetName(GetStdKeyFromHkey(m_hRootKey), strKey);
554 }
555 else {
556 // this is the full name already
557 keyDst.SetName(szNewName);
558 }
559
560 bool ok = keyDst.Create(false /* fail if alredy exists */);
561 if ( !ok ) {
562 wxLogError(_("Registry key '%s' already exists."),
563 GetFullName(&keyDst));
564 }
565 else {
566 ok = Copy(keyDst) && DeleteSelf();
567 }
568
569 if ( !ok ) {
570 wxLogError(_("Failed to rename the registry key '%s' to '%s'."),
571 GetFullName(this), GetFullName(&keyDst));
572 }
573 else {
574 m_hRootKey = keyDst.m_hRootKey;
575 m_strKey = keyDst.m_strKey;
576 }
577
578 return ok;
579 }
580
581 bool wxRegKey::Copy(const wxChar *szNewName)
582 {
583 // create the new key first
584 wxRegKey keyDst(szNewName);
585 bool ok = keyDst.Create(false /* fail if alredy exists */);
586 if ( ok ) {
587 ok = Copy(keyDst);
588
589 // we created the dest key but copying to it failed - delete it
590 if ( !ok ) {
591 (void)keyDst.DeleteSelf();
592 }
593 }
594
595 return ok;
596 }
597
598 bool wxRegKey::Copy(wxRegKey& keyDst)
599 {
600 bool ok = true;
601
602 // copy all sub keys to the new location
603 wxString strKey;
604 long lIndex;
605 bool bCont = GetFirstKey(strKey, lIndex);
606 while ( ok && bCont ) {
607 wxRegKey key(*this, strKey);
608 wxString keyName;
609 keyName << GetFullName(&keyDst) << REG_SEPARATOR << strKey;
610 ok = key.Copy((const wxChar*) keyName);
611
612 if ( ok )
613 bCont = GetNextKey(strKey, lIndex);
614 else
615 wxLogError(_("Failed to copy the registry subkey '%s' to '%s'."),
616 GetFullName(&key), keyName.c_str());
617
618 }
619
620 // copy all values
621 wxString strVal;
622 bCont = GetFirstValue(strVal, lIndex);
623 while ( ok && bCont ) {
624 ok = CopyValue(strVal, keyDst);
625
626 if ( !ok ) {
627 wxLogSysError(m_dwLastError,
628 _("Failed to copy registry value '%s'"),
629 strVal.c_str());
630 }
631 else {
632 bCont = GetNextValue(strVal, lIndex);
633 }
634 }
635
636 if ( !ok ) {
637 wxLogError(_("Failed to copy the contents of registry key '%s' to '%s'."),
638 GetFullName(this), GetFullName(&keyDst));
639 }
640
641 return ok;
642 }
643
644 // ----------------------------------------------------------------------------
645 // delete keys/values
646 // ----------------------------------------------------------------------------
647 bool wxRegKey::DeleteSelf()
648 {
649 {
650 wxLogNull nolog;
651 if ( !Open() ) {
652 // it already doesn't exist - ok!
653 return true;
654 }
655 }
656
657 // prevent a buggy program from erasing one of the root registry keys or an
658 // immediate subkey (i.e. one which doesn't have '\\' inside) of any other
659 // key except HKCR (HKCR has some "deleteable" subkeys)
660 if ( m_strKey.empty() ||
661 ((m_hRootKey != (WXHKEY) aStdKeys[HKCR].hkey) &&
662 (m_strKey.Find(REG_SEPARATOR) == wxNOT_FOUND)) ) {
663 wxLogError(_("Registry key '%s' is needed for normal system operation,\ndeleting it will leave your system in unusable state:\noperation aborted."),
664 GetFullName(this));
665
666 return false;
667 }
668
669 // we can't delete keys while enumerating because it confuses GetNextKey, so
670 // we first save the key names and then delete them all
671 wxArrayString astrSubkeys;
672
673 wxString strKey;
674 long lIndex;
675 bool bCont = GetFirstKey(strKey, lIndex);
676 while ( bCont ) {
677 astrSubkeys.Add(strKey);
678
679 bCont = GetNextKey(strKey, lIndex);
680 }
681
682 size_t nKeyCount = astrSubkeys.Count();
683 for ( size_t nKey = 0; nKey < nKeyCount; nKey++ ) {
684 wxRegKey key(*this, astrSubkeys[nKey]);
685 if ( !key.DeleteSelf() )
686 return false;
687 }
688
689 // now delete this key itself
690 Close();
691
692 m_dwLastError = RegDeleteKey((HKEY) m_hRootKey, m_strKey);
693 // deleting a key which doesn't exist is not considered an error
694 if ( m_dwLastError != ERROR_SUCCESS &&
695 m_dwLastError != ERROR_FILE_NOT_FOUND ) {
696 wxLogSysError(m_dwLastError, _("Can't delete key '%s'"),
697 GetName().c_str());
698 return false;
699 }
700
701 return true;
702 }
703
704 bool wxRegKey::DeleteKey(const wxChar *szKey)
705 {
706 if ( !Open() )
707 return false;
708
709 wxRegKey key(*this, szKey);
710 return key.DeleteSelf();
711 }
712
713 bool wxRegKey::DeleteValue(const wxChar *szValue)
714 {
715 if ( !Open() )
716 return false;
717
718 m_dwLastError = RegDeleteValue((HKEY) m_hKey, WXSTRINGCAST szValue);
719
720 // deleting a value which doesn't exist is not considered an error
721 if ( (m_dwLastError != ERROR_SUCCESS) &&
722 (m_dwLastError != ERROR_FILE_NOT_FOUND) )
723 {
724 wxLogSysError(m_dwLastError, _("Can't delete value '%s' from key '%s'"),
725 szValue, GetName().c_str());
726 return false;
727 }
728
729 return true;
730 }
731
732 // ----------------------------------------------------------------------------
733 // access to values and subkeys
734 // ----------------------------------------------------------------------------
735
736 // return true if value exists
737 bool wxRegKey::HasValue(const wxChar *szValue) const
738 {
739 // this function should be silent, so suppress possible messages from Open()
740 wxLogNull nolog;
741
742 if ( !CONST_CAST Open(Read) )
743 return false;
744
745 LONG dwRet = ::RegQueryValueEx((HKEY) m_hKey,
746 WXSTRINGCAST szValue,
747 RESERVED,
748 NULL, NULL, NULL);
749 return dwRet == ERROR_SUCCESS;
750 }
751
752 // returns true if this key has any values
753 bool wxRegKey::HasValues() const
754 {
755 // suppress possible messages from GetFirstValue()
756 wxLogNull nolog;
757
758 // just call GetFirstValue with dummy parameters
759 wxString str;
760 long l;
761 return CONST_CAST GetFirstValue(str, l);
762 }
763
764 // returns true if this key has any subkeys
765 bool wxRegKey::HasSubkeys() const
766 {
767 // suppress possible messages from GetFirstKey()
768 wxLogNull nolog;
769
770 // just call GetFirstKey with dummy parameters
771 wxString str;
772 long l;
773 return CONST_CAST GetFirstKey(str, l);
774 }
775
776 // returns true if given subkey exists
777 bool wxRegKey::HasSubKey(const wxChar *szKey) const
778 {
779 // this function should be silent, so suppress possible messages from Open()
780 wxLogNull nolog;
781
782 if ( !CONST_CAST Open(Read) )
783 return false;
784
785 return KeyExists(m_hKey, szKey);
786 }
787
788 wxRegKey::ValueType wxRegKey::GetValueType(const wxChar *szValue) const
789 {
790 if ( ! CONST_CAST Open(Read) )
791 return Type_None;
792
793 DWORD dwType;
794 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, WXSTRINGCAST szValue, RESERVED,
795 &dwType, NULL, NULL);
796 if ( m_dwLastError != ERROR_SUCCESS ) {
797 wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"),
798 GetName().c_str());
799 return Type_None;
800 }
801
802 return (ValueType)dwType;
803 }
804
805 bool wxRegKey::SetValue(const wxChar *szValue, long lValue)
806 {
807 if ( CONST_CAST Open() ) {
808 m_dwLastError = RegSetValueEx((HKEY) m_hKey, szValue, (DWORD) RESERVED, REG_DWORD,
809 (RegString)&lValue, sizeof(lValue));
810 if ( m_dwLastError == ERROR_SUCCESS )
811 return true;
812 }
813
814 wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
815 GetFullName(this, szValue));
816 return false;
817 }
818
819 bool wxRegKey::QueryValue(const wxChar *szValue, long *plValue) const
820 {
821 if ( CONST_CAST Open(Read) ) {
822 DWORD dwType, dwSize = sizeof(DWORD);
823 RegString pBuf = (RegString)plValue;
824 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, WXSTRINGCAST szValue, RESERVED,
825 &dwType, pBuf, &dwSize);
826 if ( m_dwLastError != ERROR_SUCCESS ) {
827 wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"),
828 GetName().c_str());
829 return false;
830 }
831 else {
832 // check that we read the value of right type
833 wxASSERT_MSG( IsNumericValue(szValue),
834 wxT("Type mismatch in wxRegKey::QueryValue().") );
835
836 return true;
837 }
838 }
839 else
840 return false;
841 }
842
843 bool wxRegKey::SetValue(const wxChar *szValue,const wxMemoryBuffer& buffer)
844 {
845 #ifdef __TWIN32__
846 wxFAIL_MSG("RegSetValueEx not implemented by TWIN32");
847 return false;
848 #else
849 if ( CONST_CAST Open() ) {
850 m_dwLastError = RegSetValueEx((HKEY) m_hKey, szValue, (DWORD) RESERVED, REG_BINARY,
851 (RegBinary)buffer.GetData(),buffer.GetDataLen());
852 if ( m_dwLastError == ERROR_SUCCESS )
853 return true;
854 }
855
856 wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
857 GetFullName(this, szValue));
858 return false;
859 #endif
860 }
861
862 bool wxRegKey::QueryValue(const wxChar *szValue, wxMemoryBuffer& buffer) const
863 {
864 if ( CONST_CAST Open(Read) ) {
865 // first get the type and size of the data
866 DWORD dwType, dwSize;
867 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, WXSTRINGCAST szValue, RESERVED,
868 &dwType, NULL, &dwSize);
869
870 if ( m_dwLastError == ERROR_SUCCESS ) {
871 if ( dwSize ) {
872 const RegBinary pBuf = (RegBinary)buffer.GetWriteBuf(dwSize);
873 m_dwLastError = RegQueryValueEx((HKEY) m_hKey,
874 WXSTRINGCAST szValue,
875 RESERVED,
876 &dwType,
877 pBuf,
878 &dwSize);
879 buffer.UngetWriteBuf(dwSize);
880 } else {
881 buffer.SetDataLen(0);
882 }
883 }
884
885
886 if ( m_dwLastError != ERROR_SUCCESS ) {
887 wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"),
888 GetName().c_str());
889 return false;
890 }
891 return true;
892 }
893 return false;
894 }
895
896
897
898 bool wxRegKey::QueryValue(const wxChar *szValue,
899 wxString& strValue,
900 bool WXUNUSED_IN_WINCE(raw)) const
901 {
902 if ( CONST_CAST Open(Read) )
903 {
904
905 // first get the type and size of the data
906 DWORD dwType=REG_NONE, dwSize=0;
907 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, WXSTRINGCAST szValue, RESERVED,
908 &dwType, NULL, &dwSize);
909 if ( m_dwLastError == ERROR_SUCCESS )
910 {
911 if ( !dwSize )
912 {
913 // must treat this case specially as GetWriteBuf() doesn't like
914 // being called with 0 size
915 strValue.Empty();
916 }
917 else
918 {
919 m_dwLastError = RegQueryValueEx((HKEY) m_hKey,
920 WXSTRINGCAST szValue,
921 RESERVED,
922 &dwType,
923 (RegString)(wxChar*)wxStringBuffer(strValue, dwSize),
924 &dwSize);
925
926 // expand the var expansions in the string unless disabled
927 #ifndef __WXWINCE__
928 if ( (dwType == REG_EXPAND_SZ) && !raw )
929 {
930 DWORD dwExpSize = ::ExpandEnvironmentStrings(strValue, NULL, 0);
931 bool ok = dwExpSize != 0;
932 if ( ok )
933 {
934 wxString strExpValue;
935 ok = ::ExpandEnvironmentStrings(strValue,
936 wxStringBuffer(strExpValue, dwExpSize),
937 dwExpSize
938 ) != 0;
939 strValue = strExpValue;
940 }
941
942 if ( !ok )
943 {
944 wxLogLastError(_T("ExpandEnvironmentStrings"));
945 }
946 }
947 #endif
948 // __WXWINCE__
949 }
950
951 if ( m_dwLastError == ERROR_SUCCESS )
952 {
953 // check that it was the right type
954 wxASSERT_MSG( !IsNumericValue(szValue),
955 wxT("Type mismatch in wxRegKey::QueryValue().") );
956
957 return true;
958 }
959 }
960 }
961
962 wxLogSysError(m_dwLastError, _("Can't read value of '%s'"),
963 GetFullName(this, szValue));
964 return false;
965 }
966
967 bool wxRegKey::SetValue(const wxChar *szValue, const wxString& strValue)
968 {
969 if ( CONST_CAST Open() ) {
970 m_dwLastError = RegSetValueEx((HKEY) m_hKey, szValue, (DWORD) RESERVED, REG_SZ,
971 (RegString)strValue.wx_str(),
972 (strValue.Len() + 1)*sizeof(wxChar));
973 if ( m_dwLastError == ERROR_SUCCESS )
974 return true;
975 }
976
977 wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
978 GetFullName(this, szValue));
979 return false;
980 }
981
982 wxString wxRegKey::QueryDefaultValue() const
983 {
984 wxString str;
985 QueryValue(NULL, str);
986 return str;
987 }
988
989 // ----------------------------------------------------------------------------
990 // enumeration
991 // NB: all these functions require an index variable which allows to have
992 // several concurrently running indexations on the same key
993 // ----------------------------------------------------------------------------
994
995 bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex)
996 {
997 if ( !Open(Read) )
998 return false;
999
1000 lIndex = 0;
1001 return GetNextValue(strValueName, lIndex);
1002 }
1003
1004 bool wxRegKey::GetNextValue(wxString& strValueName, long& lIndex) const
1005 {
1006 wxASSERT( IsOpened() );
1007
1008 // are we already at the end of enumeration?
1009 if ( lIndex == -1 )
1010 return false;
1011
1012 wxChar szValueName[1024]; // @@ use RegQueryInfoKey...
1013 DWORD dwValueLen = WXSIZEOF(szValueName);
1014
1015 m_dwLastError = RegEnumValue((HKEY) m_hKey, lIndex++,
1016 szValueName, &dwValueLen,
1017 RESERVED,
1018 NULL, // [out] type
1019 NULL, // [out] buffer for value
1020 NULL); // [i/o] it's length
1021
1022 if ( m_dwLastError != ERROR_SUCCESS ) {
1023 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
1024 m_dwLastError = ERROR_SUCCESS;
1025 lIndex = -1;
1026 }
1027 else {
1028 wxLogSysError(m_dwLastError, _("Can't enumerate values of key '%s'"),
1029 GetName().c_str());
1030 }
1031
1032 return false;
1033 }
1034
1035 strValueName = szValueName;
1036
1037 return true;
1038 }
1039
1040 bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex)
1041 {
1042 if ( !Open(Read) )
1043 return false;
1044
1045 lIndex = 0;
1046 return GetNextKey(strKeyName, lIndex);
1047 }
1048
1049 bool wxRegKey::GetNextKey(wxString& strKeyName, long& lIndex) const
1050 {
1051 wxASSERT( IsOpened() );
1052
1053 // are we already at the end of enumeration?
1054 if ( lIndex == -1 )
1055 return false;
1056
1057 wxChar szKeyName[_MAX_PATH + 1];
1058
1059 #ifdef __WXWINCE__
1060 DWORD sizeName = WXSIZEOF(szKeyName);
1061 m_dwLastError = RegEnumKeyEx((HKEY) m_hKey, lIndex++, szKeyName, & sizeName,
1062 0, NULL, NULL, NULL);
1063 #else
1064 m_dwLastError = RegEnumKey((HKEY) m_hKey, lIndex++, szKeyName, WXSIZEOF(szKeyName));
1065 #endif
1066
1067 if ( m_dwLastError != ERROR_SUCCESS ) {
1068 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
1069 m_dwLastError = ERROR_SUCCESS;
1070 lIndex = -1;
1071 }
1072 else {
1073 wxLogSysError(m_dwLastError, _("Can't enumerate subkeys of key '%s'"),
1074 GetName().c_str());
1075 }
1076
1077 return false;
1078 }
1079
1080 strKeyName = szKeyName;
1081 return true;
1082 }
1083
1084 // returns true if the value contains a number (else it's some string)
1085 bool wxRegKey::IsNumericValue(const wxChar *szValue) const
1086 {
1087 ValueType type = GetValueType(szValue);
1088 switch ( type ) {
1089 case Type_Dword:
1090 /* case Type_Dword_little_endian: == Type_Dword */
1091 case Type_Dword_big_endian:
1092 return true;
1093
1094 default:
1095 return false;
1096 }
1097 }
1098
1099 // ----------------------------------------------------------------------------
1100 // exporting registry keys to file
1101 // ----------------------------------------------------------------------------
1102
1103 #if wxUSE_STREAMS
1104
1105 // helper functions for writing ASCII strings (even in Unicode build)
1106 static inline bool WriteAsciiChar(wxOutputStream& ostr, char ch)
1107 {
1108 ostr.PutC(ch);
1109 return ostr.IsOk();
1110 }
1111
1112 static inline bool WriteAsciiEOL(wxOutputStream& ostr)
1113 {
1114 // as we open the file in text mode, it is enough to write LF without CR
1115 return WriteAsciiChar(ostr, '\n');
1116 }
1117
1118 static inline bool WriteAsciiString(wxOutputStream& ostr, const char *p)
1119 {
1120 return ostr.Write(p, strlen(p)).IsOk();
1121 }
1122
1123 static inline bool WriteAsciiString(wxOutputStream& ostr, const wxString& s)
1124 {
1125 #if wxUSE_UNICODE
1126 wxCharBuffer name(s.mb_str());
1127 ostr.Write(name, strlen(name));
1128 #else
1129 ostr.Write(s.mb_str(), s.length());
1130 #endif
1131
1132 return ostr.IsOk();
1133 }
1134
1135 #endif // wxUSE_STREAMS
1136
1137 bool wxRegKey::Export(const wxString& filename) const
1138 {
1139 #if wxUSE_FFILE && wxUSE_STREAMS
1140 if ( wxFile::Exists(filename) )
1141 {
1142 wxLogError(_("Exporting registry key: file \"%s\" already exists and won't be overwritten."),
1143 filename.c_str());
1144 return false;
1145 }
1146
1147 wxFFileOutputStream ostr(filename, _T("w"));
1148
1149 return ostr.Ok() && Export(ostr);
1150 #else
1151 wxUnusedVar(filename);
1152 return false;
1153 #endif
1154 }
1155
1156 #if wxUSE_STREAMS
1157 bool wxRegKey::Export(wxOutputStream& ostr) const
1158 {
1159 // write out the header
1160 if ( !WriteAsciiString(ostr, "REGEDIT4\n\n") )
1161 return false;
1162
1163 return DoExport(ostr);
1164 }
1165 #endif // wxUSE_STREAMS
1166
1167 static
1168 wxString
1169 FormatAsHex(const void *data,
1170 size_t size,
1171 wxRegKey::ValueType type = wxRegKey::Type_Binary)
1172 {
1173 wxString value(_T("hex"));
1174
1175 // binary values use just "hex:" prefix while the other ones must indicate
1176 // the real type
1177 if ( type != wxRegKey::Type_Binary )
1178 value << _T('(') << type << _T(')');
1179 value << _T(':');
1180
1181 // write all the rest as comma-separated bytes
1182 value.reserve(3*size + 10);
1183 const char * const p = wx_static_cast(const char *, data);
1184 for ( size_t n = 0; n < size; n++ )
1185 {
1186 // TODO: line wrapping: although not required by regedit, this makes
1187 // the generated files easier to read and compare with the files
1188 // produced by regedit
1189 if ( n )
1190 value << _T(',');
1191
1192 value << wxString::Format(_T("%02x"), (unsigned char)p[n]);
1193 }
1194
1195 return value;
1196 }
1197
1198 static inline
1199 wxString FormatAsHex(const wxString& value, wxRegKey::ValueType type)
1200 {
1201 return FormatAsHex(value.c_str(), value.length() + 1, type);
1202 }
1203
1204 wxString wxRegKey::FormatValue(const wxString& name) const
1205 {
1206 wxString rhs;
1207 const ValueType type = GetValueType(name);
1208 switch ( type )
1209 {
1210 case Type_String:
1211 {
1212 wxString value;
1213 if ( !QueryValue(name, value) )
1214 break;
1215
1216 // quotes and backslashes must be quoted, linefeeds are not
1217 // allowed in string values
1218 rhs.reserve(value.length() + 2);
1219 rhs = _T('"');
1220
1221 // there can be no NULs here
1222 bool useHex = false;
1223 for ( const wxChar *p = value.c_str(); *p && !useHex; p++ )
1224 {
1225 switch ( *p )
1226 {
1227 case _T('\n'):
1228 // we can only represent this string in hex
1229 useHex = true;
1230 break;
1231
1232 case _T('"'):
1233 case _T('\\'):
1234 // escape special symbol
1235 rhs += _T('\\');
1236 // fall through
1237
1238 default:
1239 rhs += *p;
1240 }
1241 }
1242
1243 if ( useHex )
1244 rhs = FormatAsHex(value, Type_String);
1245 else
1246 rhs += _T('"');
1247 }
1248 break;
1249
1250 case Type_Dword:
1251 /* case Type_Dword_little_endian: == Type_Dword */
1252 {
1253 long value;
1254 if ( !QueryValue(name, &value) )
1255 break;
1256
1257 rhs.Printf(_T("dword:%08x"), (unsigned int)value);
1258 }
1259 break;
1260
1261 case Type_Expand_String:
1262 case Type_Multi_String:
1263 {
1264 wxString value;
1265 if ( !QueryRawValue(name, value) )
1266 break;
1267
1268 rhs = FormatAsHex(value, type);
1269 }
1270 break;
1271
1272 case Type_Binary:
1273 {
1274 wxMemoryBuffer buf;
1275 if ( !QueryValue(name, buf) )
1276 break;
1277
1278 rhs = FormatAsHex(buf.GetData(), buf.GetDataLen());
1279 }
1280 break;
1281
1282 // no idea how those appear in REGEDIT4 files
1283 case Type_None:
1284 case Type_Dword_big_endian:
1285 case Type_Link:
1286 case Type_Resource_list:
1287 case Type_Full_resource_descriptor:
1288 case Type_Resource_requirements_list:
1289 default:
1290 wxLogWarning(_("Can't export value of unsupported type %d."), type);
1291 }
1292
1293 return rhs;
1294 }
1295
1296 #if wxUSE_STREAMS
1297
1298 bool wxRegKey::DoExportValue(wxOutputStream& ostr, const wxString& name) const
1299 {
1300 // first examine the value type: if it's unsupported, simply skip it
1301 // instead of aborting the entire export process because we failed to
1302 // export a single value
1303 wxString value = FormatValue(name);
1304 if ( value.empty() )
1305 {
1306 wxLogWarning(_("Ignoring value \"%s\" of the key \"%s\"."),
1307 name.c_str(), GetName().c_str());
1308 return true;
1309 }
1310
1311 // we do have the text representation of the value, now write everything
1312 // out
1313
1314 // special case: unnamed/default value is represented as just "@"
1315 if ( name.empty() )
1316 {
1317 if ( !WriteAsciiChar(ostr, '@') )
1318 return false;
1319 }
1320 else // normal, named, value
1321 {
1322 if ( !WriteAsciiChar(ostr, '"') ||
1323 !WriteAsciiString(ostr, name) ||
1324 !WriteAsciiChar(ostr, '"') )
1325 return false;
1326 }
1327
1328 if ( !WriteAsciiChar(ostr, '=') )
1329 return false;
1330
1331 return WriteAsciiString(ostr, value) && WriteAsciiEOL(ostr);
1332 }
1333
1334 bool wxRegKey::DoExport(wxOutputStream& ostr) const
1335 {
1336 // write out this key name
1337 if ( !WriteAsciiChar(ostr, '[') )
1338 return false;
1339
1340 if ( !WriteAsciiString(ostr, GetName(false /* no short prefix */)) )
1341 return false;
1342
1343 if ( !WriteAsciiChar(ostr, ']') || !WriteAsciiEOL(ostr) )
1344 return false;
1345
1346 // dump all our values
1347 long dummy;
1348 wxString name;
1349 wxRegKey& self = wx_const_cast(wxRegKey&, *this);
1350 bool cont = self.GetFirstValue(name, dummy);
1351 while ( cont )
1352 {
1353 if ( !DoExportValue(ostr, name) )
1354 return false;
1355
1356 cont = GetNextValue(name, dummy);
1357 }
1358
1359 // always terminate values by blank line, even if there were no values
1360 if ( !WriteAsciiEOL(ostr) )
1361 return false;
1362
1363 // recurse to subkeys
1364 cont = self.GetFirstKey(name, dummy);
1365 while ( cont )
1366 {
1367 wxRegKey subkey(*this, name);
1368 if ( !subkey.DoExport(ostr) )
1369 return false;
1370
1371 cont = GetNextKey(name, dummy);
1372 }
1373
1374 return true;
1375 }
1376
1377 #endif // wxUSE_STREAMS
1378
1379 // ============================================================================
1380 // implementation of global private functions
1381 // ============================================================================
1382
1383 bool KeyExists(WXHKEY hRootKey, const wxChar *szKey)
1384 {
1385 // don't close this key itself for the case of empty szKey!
1386 if ( wxIsEmpty(szKey) )
1387 return true;
1388
1389 HKEY hkeyDummy;
1390 if ( ::RegOpenKeyEx
1391 (
1392 (HKEY)hRootKey,
1393 szKey,
1394 RESERVED,
1395 KEY_READ, // we might not have enough rights for rw access
1396 &hkeyDummy
1397 ) == ERROR_SUCCESS )
1398 {
1399 ::RegCloseKey(hkeyDummy);
1400
1401 return true;
1402 }
1403
1404 return false;
1405 }
1406
1407 const wxChar *GetFullName(const wxRegKey *pKey, const wxChar *szValue)
1408 {
1409 static wxString s_str;
1410 s_str = pKey->GetName();
1411 if ( !wxIsEmpty(szValue) )
1412 s_str << wxT("\\") << szValue;
1413
1414 return s_str.c_str();
1415 }
1416
1417 inline void RemoveTrailingSeparator(wxString& str)
1418 {
1419 if ( !str.empty() && str.Last() == REG_SEPARATOR )
1420 str.Truncate(str.Len() - 1);
1421 }