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