]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/registry.cpp
removed broken and global GetLine() function from wx/protocol/protocol.h; there's...
[wxWidgets.git] / src / msw / registry.cpp
... / ...
CommitLineData
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
52typedef unsigned char *RegString;
53typedef 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
73static struct
74{
75 HKEY hkey;
76 const wxChar *szName;
77 const wxChar *szShortName;
78}
79aStdKeys[] =
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
112static inline void RemoveTrailingSeparator(wxString& str);
113
114// returns true if given registry key exists
115static bool KeyExists(WXHKEY hRootKey, const wxString& szKey);
116
117// combines value and key name
118static wxString GetFullName(const wxRegKey *pKey);
119static 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
124static inline const wxChar *RegValueStr(const wxString& szValue);
125
126// ============================================================================
127// implementation of wxRegKey class
128// ============================================================================
129
130// ----------------------------------------------------------------------------
131// static functions and variables
132// ----------------------------------------------------------------------------
133
134const 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.
138const 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
146const 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
154wxRegKey::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
180wxRegKey::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
196wxRegKey::wxRegKey()
197{
198 m_hRootKey = (WXHKEY) aStdKeys[HKCR].hkey;
199
200 Init();
201}
202
203wxRegKey::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
211wxRegKey::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
220wxRegKey::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
238wxRegKey::~wxRegKey()
239{
240 Close();
241}
242
243// ----------------------------------------------------------------------------
244// change the key name/hkey
245// ----------------------------------------------------------------------------
246
247// set the full key name
248void 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
257void 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
267void 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
290void 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
302bool 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)
309wxString 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
320bool 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)
371bool 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
406bool 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
442bool 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
459bool
460wxRegKey::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
481bool 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
533bool 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
588bool 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
605bool 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// ----------------------------------------------------------------------------
654bool 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
711bool wxRegKey::DeleteKey(const wxString& szKey)
712{
713 if ( !Open() )
714 return false;
715
716 wxRegKey key(*this, szKey);
717 return key.DeleteSelf();
718}
719
720bool 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
744bool 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
760bool 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
772bool 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
784bool 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
795wxRegKey::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
812bool 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
827bool 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
852bool 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
872bool 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
909bool 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
980bool 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
997wxString 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
1010bool 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
1019bool 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
1055bool 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
1064bool 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)
1100bool 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)
1121static inline bool WriteAsciiChar(wxOutputStream& ostr, char ch)
1122{
1123 ostr.PutC(ch);
1124 return ostr.IsOk();
1125}
1126
1127static 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
1133static inline bool WriteAsciiString(wxOutputStream& ostr, const char *p)
1134{
1135 return ostr.Write(p, strlen(p)).IsOk();
1136}
1137
1138static 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
1152bool 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
1172bool 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
1182static
1183wxString
1184FormatAsHex(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
1213static inline
1214wxString FormatAsHex(const wxString& value, wxRegKey::ValueType type)
1215{
1216 return FormatAsHex(value.c_str(), value.length() + 1, type);
1217}
1218
1219wxString 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
1314bool 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
1350bool 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
1399bool 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
1423wxString 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
1432wxString GetFullName(const wxRegKey *pKey)
1433{
1434 return pKey->GetName();
1435}
1436
1437inline void RemoveTrailingSeparator(wxString& str)
1438{
1439 if ( !str.empty() && str.Last() == REG_SEPARATOR )
1440 str.Truncate(str.Len() - 1);
1441}
1442
1443inline const wxChar *RegValueStr(const wxString& szValue)
1444{
1445 return szValue.empty() ? (const wxChar*)NULL : szValue.wx_str();
1446}