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