1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/registry.cpp
3 // Purpose: implementation of registry classes and functions
4 // Author: Vadim Zeitlin
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 ///////////////////////////////////////////////////////////////////////////////
15 // for compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
23 #include "wx/msw/wrapwin.h"
24 #include "wx/string.h"
31 #include "wx/wfstream.h"
35 #include "wx/msw/private.h"
41 #include <stdlib.h> // for _MAX_PATH
48 #define HKEY_DEFINED // already defined in windows.h
49 #include "wx/msw/registry.h"
51 // some registry functions don't like signed chars
52 typedef unsigned char *RegString
;
53 typedef BYTE
* RegBinary
;
55 #ifndef HKEY_PERFORMANCE_DATA
56 #define HKEY_PERFORMANCE_DATA ((HKEY)0x80000004)
59 #ifndef HKEY_CURRENT_CONFIG
60 #define HKEY_CURRENT_CONFIG ((HKEY)0x80000005)
64 #define HKEY_DYN_DATA ((HKEY)0x80000006)
67 // ----------------------------------------------------------------------------
69 // ----------------------------------------------------------------------------
71 // the standard key names, short names and handles all bundled together for
77 const wxChar
*szShortName
;
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?
90 // the registry name separator (perhaps one day MS will change it to '/' ;-)
91 #define REG_SEPARATOR wxT('\\')
93 // useful for Windows programmers: makes somewhat more clear all these zeroes
94 // being passed to Windows APIs
97 // ----------------------------------------------------------------------------
99 // ----------------------------------------------------------------------------
101 // const_cast<> is not yet supported by all compilers
102 #define CONST_CAST ((wxRegKey *)this)->
104 // and neither is mutable which m_dwLastError should be
105 #define m_dwLastError CONST_CAST m_dwLastError
107 // ----------------------------------------------------------------------------
108 // non member functions
109 // ----------------------------------------------------------------------------
111 // removes the trailing backslash from the string if it has one
112 static inline void RemoveTrailingSeparator(wxString
& str
);
114 // returns true if given registry key exists
115 static bool KeyExists(WXHKEY hRootKey
, const wxChar
*szKey
);
117 // combines value and key name (uses static buffer!)
118 static const wxChar
*GetFullName(const wxRegKey
*pKey
,
119 const wxChar
*szValue
= NULL
);
121 // ============================================================================
122 // implementation of wxRegKey class
123 // ============================================================================
125 // ----------------------------------------------------------------------------
126 // static functions and variables
127 // ----------------------------------------------------------------------------
129 const size_t wxRegKey::nStdKeys
= WXSIZEOF(aStdKeys
);
131 // @@ should take a `StdKey key', but as it's often going to be used in loops
132 // it would require casts in user code.
133 const wxChar
*wxRegKey::GetStdKeyName(size_t key
)
135 // return empty string if key is invalid
136 wxCHECK_MSG( key
< nStdKeys
, wxEmptyString
, wxT("invalid key in wxRegKey::GetStdKeyName") );
138 return aStdKeys
[key
].szName
;
141 const wxChar
*wxRegKey::GetStdKeyShortName(size_t key
)
143 // return empty string if key is invalid
144 wxCHECK( key
< nStdKeys
, wxEmptyString
);
146 return aStdKeys
[key
].szShortName
;
149 wxRegKey::StdKey
wxRegKey::ExtractKeyName(wxString
& strKey
)
151 wxString strRoot
= strKey
.BeforeFirst(REG_SEPARATOR
);
154 for ( ui
= 0; ui
< nStdKeys
; ui
++ ) {
155 if ( strRoot
.CmpNoCase(aStdKeys
[ui
].szName
) == 0 ||
156 strRoot
.CmpNoCase(aStdKeys
[ui
].szShortName
) == 0 ) {
161 if ( ui
== nStdKeys
) {
162 wxFAIL_MSG(wxT("invalid key prefix in wxRegKey::ExtractKeyName."));
167 strKey
= strKey
.After(REG_SEPARATOR
);
168 if ( !strKey
.empty() && strKey
.Last() == REG_SEPARATOR
)
169 strKey
.Truncate(strKey
.Len() - 1);
175 wxRegKey::StdKey
wxRegKey::GetStdKeyFromHkey(WXHKEY hkey
)
177 for ( size_t ui
= 0; ui
< nStdKeys
; ui
++ ) {
178 if ( aStdKeys
[ui
].hkey
== (HKEY
)hkey
)
182 wxFAIL_MSG(wxT("non root hkey passed to wxRegKey::GetStdKeyFromHkey."));
187 // ----------------------------------------------------------------------------
189 // ----------------------------------------------------------------------------
193 m_hRootKey
= (WXHKEY
) aStdKeys
[HKCR
].hkey
;
198 wxRegKey::wxRegKey(const wxString
& strKey
) : m_strKey(strKey
)
200 m_hRootKey
= (WXHKEY
) aStdKeys
[ExtractKeyName(m_strKey
)].hkey
;
205 // parent is a predefined (and preopened) key
206 wxRegKey::wxRegKey(StdKey keyParent
, const wxString
& strKey
) : m_strKey(strKey
)
208 RemoveTrailingSeparator(m_strKey
);
209 m_hRootKey
= (WXHKEY
) aStdKeys
[keyParent
].hkey
;
214 // parent is a normal regkey
215 wxRegKey::wxRegKey(const wxRegKey
& keyParent
, const wxString
& strKey
)
216 : m_strKey(keyParent
.m_strKey
)
218 // combine our name with parent's to get the full name
219 if ( !m_strKey
.empty() &&
220 (strKey
.empty() || strKey
[0] != REG_SEPARATOR
) ) {
221 m_strKey
+= REG_SEPARATOR
;
225 RemoveTrailingSeparator(m_strKey
);
227 m_hRootKey
= keyParent
.m_hRootKey
;
232 // dtor closes the key releasing system resource
233 wxRegKey::~wxRegKey()
238 // ----------------------------------------------------------------------------
239 // change the key name/hkey
240 // ----------------------------------------------------------------------------
242 // set the full key name
243 void wxRegKey::SetName(const wxString
& strKey
)
248 m_hRootKey
= (WXHKEY
) aStdKeys
[ExtractKeyName(m_strKey
)].hkey
;
251 // the name is relative to the parent key
252 void wxRegKey::SetName(StdKey keyParent
, const wxString
& strKey
)
257 RemoveTrailingSeparator(m_strKey
);
258 m_hRootKey
= (WXHKEY
) aStdKeys
[keyParent
].hkey
;
261 // the name is relative to the parent key
262 void wxRegKey::SetName(const wxRegKey
& keyParent
, const wxString
& strKey
)
266 // combine our name with parent's to get the full name
268 // NB: this method is called by wxRegConfig::SetPath() which is a performance
269 // critical function and so it preallocates space for our m_strKey to
270 // gain some speed - this is why we only use += here and not = which
271 // would just free the prealloc'd buffer and would have to realloc it the
274 m_strKey
+= keyParent
.m_strKey
;
275 if ( !strKey
.empty() && strKey
[0] != REG_SEPARATOR
)
276 m_strKey
+= REG_SEPARATOR
;
279 RemoveTrailingSeparator(m_strKey
);
281 m_hRootKey
= keyParent
.m_hRootKey
;
284 // hKey should be opened and will be closed in wxRegKey dtor
285 void wxRegKey::SetHkey(WXHKEY hKey
)
292 // ----------------------------------------------------------------------------
293 // info about the key
294 // ----------------------------------------------------------------------------
296 // returns true if the key exists
297 bool wxRegKey::Exists() const
299 // opened key has to exist, try to open it if not done yet
300 return IsOpened() ? true : KeyExists(m_hRootKey
, m_strKey
);
303 // returns the full name of the key (prefix is abbreviated if bShortPrefix)
304 wxString
wxRegKey::GetName(bool bShortPrefix
) const
306 StdKey key
= GetStdKeyFromHkey((WXHKEY
) m_hRootKey
);
307 wxString str
= bShortPrefix
? aStdKeys
[key
].szShortName
308 : aStdKeys
[key
].szName
;
309 if ( !m_strKey
.empty() )
310 str
<< _T("\\") << m_strKey
;
315 bool wxRegKey::GetKeyInfo(size_t *pnSubKeys
,
318 size_t *pnMaxValueLen
) const
320 // old gcc headers incorrectly prototype RegQueryInfoKey()
321 #if defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__)
322 #define REG_PARAM (size_t *)
324 #define REG_PARAM (LPDWORD)
327 // it might be unexpected to some that this function doesn't open the key
328 wxASSERT_MSG( IsOpened(), _T("key should be opened in GetKeyInfo") );
330 m_dwLastError
= ::RegQueryInfoKey
334 NULL
, // (ptr to) size of class name buffer
337 pnSubKeys
, // [out] number of subkeys
339 pnMaxKeyLen
, // [out] max length of a subkey name
340 NULL
, // longest subkey class name
342 pnValues
, // [out] number of values
344 pnMaxValueLen
, // [out] max length of a value name
345 NULL
, // longest value data
346 NULL
, // security descriptor
347 NULL
// time of last modification
352 if ( m_dwLastError
!= ERROR_SUCCESS
) {
353 wxLogSysError(m_dwLastError
, _("Can't get info about registry key '%s'"),
361 // ----------------------------------------------------------------------------
363 // ----------------------------------------------------------------------------
365 // opens key (it's not an error to call Open() on an already opened key)
366 bool wxRegKey::Open(AccessMode mode
)
370 if ( mode
<= m_mode
)
373 // we had been opened in read mode but now must be reopened in write
378 m_dwLastError
= ::RegOpenKeyEx
383 mode
== Read
? KEY_READ
: KEY_ALL_ACCESS
,
387 if ( m_dwLastError
!= ERROR_SUCCESS
)
389 wxLogSysError(m_dwLastError
, _("Can't open registry key '%s'"),
394 m_hKey
= (WXHKEY
) tmpKey
;
400 // creates key, failing if it exists and !bOkIfExists
401 bool wxRegKey::Create(bool bOkIfExists
)
403 // check for existence only if asked (i.e. order is important!)
404 if ( !bOkIfExists
&& Exists() )
413 m_dwLastError
= RegCreateKeyEx((HKEY
) m_hRootKey
, m_strKey
,
415 NULL
, // class string
422 m_dwLastError
= RegCreateKey((HKEY
) m_hRootKey
, m_strKey
, &tmpKey
);
424 if ( m_dwLastError
!= ERROR_SUCCESS
) {
425 wxLogSysError(m_dwLastError
, _("Can't create registry key '%s'"),
431 m_hKey
= (WXHKEY
) tmpKey
;
436 // close the key, it's not an error to call it when not opened
437 bool wxRegKey::Close()
440 m_dwLastError
= RegCloseKey((HKEY
) m_hKey
);
443 if ( m_dwLastError
!= ERROR_SUCCESS
) {
444 wxLogSysError(m_dwLastError
, _("Can't close registry key '%s'"),
454 bool wxRegKey::RenameValue(const wxChar
*szValueOld
, const wxChar
*szValueNew
)
457 if ( HasValue(szValueNew
) ) {
458 wxLogError(_("Registry value '%s' already exists."), szValueNew
);
464 !CopyValue(szValueOld
, *this, szValueNew
) ||
465 !DeleteValue(szValueOld
) ) {
466 wxLogError(_("Failed to rename registry value '%s' to '%s'."),
467 szValueOld
, szValueNew
);
475 bool wxRegKey::CopyValue(const wxChar
*szValue
,
477 const wxChar
*szValueNew
)
480 // by default, use the same name
481 szValueNew
= szValue
;
484 switch ( GetValueType(szValue
) ) {
488 return QueryValue(szValue
, strVal
) &&
489 keyDst
.SetValue(szValueNew
, strVal
);
493 /* case Type_Dword_little_endian: == Type_Dword */
496 return QueryValue(szValue
, &dwVal
) &&
497 keyDst
.SetValue(szValueNew
, dwVal
);
503 return QueryValue(szValue
,buf
) &&
504 keyDst
.SetValue(szValueNew
,buf
);
507 // these types are unsupported because I am not sure about how
508 // exactly they should be copied and because they shouldn't
509 // occur among the application keys (supposedly created with
512 case Type_Expand_String
:
513 case Type_Dword_big_endian
:
515 case Type_Multi_String
:
516 case Type_Resource_list
:
517 case Type_Full_resource_descriptor
:
518 case Type_Resource_requirements_list
:
520 wxLogError(_("Can't copy values of unsupported type %d."),
521 GetValueType(szValue
));
526 bool wxRegKey::Rename(const wxChar
*szNewName
)
528 wxCHECK_MSG( !m_strKey
.empty(), false, _T("registry hives can't be renamed") );
531 wxLogError(_("Registry key '%s' does not exist, cannot rename it."),
537 // do we stay in the same hive?
538 bool inSameHive
= !wxStrchr(szNewName
, REG_SEPARATOR
);
540 // construct the full new name of the key
544 // rename the key to the new name under the same parent
545 wxString strKey
= m_strKey
.BeforeLast(REG_SEPARATOR
);
546 if ( !strKey
.empty() ) {
547 // don't add '\\' in the start if strFullNewName is empty
548 strKey
+= REG_SEPARATOR
;
553 keyDst
.SetName(GetStdKeyFromHkey(m_hRootKey
), strKey
);
556 // this is the full name already
557 keyDst
.SetName(szNewName
);
560 bool ok
= keyDst
.Create(false /* fail if alredy exists */);
562 wxLogError(_("Registry key '%s' already exists."),
563 GetFullName(&keyDst
));
566 ok
= Copy(keyDst
) && DeleteSelf();
570 wxLogError(_("Failed to rename the registry key '%s' to '%s'."),
571 GetFullName(this), GetFullName(&keyDst
));
574 m_hRootKey
= keyDst
.m_hRootKey
;
575 m_strKey
= keyDst
.m_strKey
;
581 bool wxRegKey::Copy(const wxChar
*szNewName
)
583 // create the new key first
584 wxRegKey
keyDst(szNewName
);
585 bool ok
= keyDst
.Create(false /* fail if alredy exists */);
589 // we created the dest key but copying to it failed - delete it
591 (void)keyDst
.DeleteSelf();
598 bool wxRegKey::Copy(wxRegKey
& keyDst
)
602 // copy all sub keys to the new location
605 bool bCont
= GetFirstKey(strKey
, lIndex
);
606 while ( ok
&& bCont
) {
607 wxRegKey
key(*this, strKey
);
609 keyName
<< GetFullName(&keyDst
) << REG_SEPARATOR
<< strKey
;
610 ok
= key
.Copy((const wxChar
*) keyName
);
613 bCont
= GetNextKey(strKey
, lIndex
);
615 wxLogError(_("Failed to copy the registry subkey '%s' to '%s'."),
616 GetFullName(&key
), keyName
.c_str());
622 bCont
= GetFirstValue(strVal
, lIndex
);
623 while ( ok
&& bCont
) {
624 ok
= CopyValue(strVal
, keyDst
);
627 wxLogSysError(m_dwLastError
,
628 _("Failed to copy registry value '%s'"),
632 bCont
= GetNextValue(strVal
, lIndex
);
637 wxLogError(_("Failed to copy the contents of registry key '%s' to '%s'."),
638 GetFullName(this), GetFullName(&keyDst
));
644 // ----------------------------------------------------------------------------
645 // delete keys/values
646 // ----------------------------------------------------------------------------
647 bool wxRegKey::DeleteSelf()
652 // it already doesn't exist - ok!
657 // prevent a buggy program from erasing one of the root registry keys or an
658 // immediate subkey (i.e. one which doesn't have '\\' inside) of any other
659 // key except HKCR (HKCR has some "deleteable" subkeys)
660 if ( m_strKey
.empty() ||
661 ((m_hRootKey
!= (WXHKEY
) aStdKeys
[HKCR
].hkey
) &&
662 (m_strKey
.Find(REG_SEPARATOR
) == wxNOT_FOUND
)) ) {
663 wxLogError(_("Registry key '%s' is needed for normal system operation,\ndeleting it will leave your system in unusable state:\noperation aborted."),
669 // we can't delete keys while enumerating because it confuses GetNextKey, so
670 // we first save the key names and then delete them all
671 wxArrayString astrSubkeys
;
675 bool bCont
= GetFirstKey(strKey
, lIndex
);
677 astrSubkeys
.Add(strKey
);
679 bCont
= GetNextKey(strKey
, lIndex
);
682 size_t nKeyCount
= astrSubkeys
.Count();
683 for ( size_t nKey
= 0; nKey
< nKeyCount
; nKey
++ ) {
684 wxRegKey
key(*this, astrSubkeys
[nKey
]);
685 if ( !key
.DeleteSelf() )
689 // now delete this key itself
692 m_dwLastError
= RegDeleteKey((HKEY
) m_hRootKey
, m_strKey
);
693 // deleting a key which doesn't exist is not considered an error
694 if ( m_dwLastError
!= ERROR_SUCCESS
&&
695 m_dwLastError
!= ERROR_FILE_NOT_FOUND
) {
696 wxLogSysError(m_dwLastError
, _("Can't delete key '%s'"),
704 bool wxRegKey::DeleteKey(const wxChar
*szKey
)
709 wxRegKey
key(*this, szKey
);
710 return key
.DeleteSelf();
713 bool wxRegKey::DeleteValue(const wxChar
*szValue
)
718 m_dwLastError
= RegDeleteValue((HKEY
) m_hKey
, WXSTRINGCAST szValue
);
720 // deleting a value which doesn't exist is not considered an error
721 if ( (m_dwLastError
!= ERROR_SUCCESS
) &&
722 (m_dwLastError
!= ERROR_FILE_NOT_FOUND
) )
724 wxLogSysError(m_dwLastError
, _("Can't delete value '%s' from key '%s'"),
725 szValue
, GetName().c_str());
732 // ----------------------------------------------------------------------------
733 // access to values and subkeys
734 // ----------------------------------------------------------------------------
736 // return true if value exists
737 bool wxRegKey::HasValue(const wxChar
*szValue
) const
739 // this function should be silent, so suppress possible messages from Open()
742 if ( !CONST_CAST
Open(Read
) )
745 LONG dwRet
= ::RegQueryValueEx((HKEY
) m_hKey
,
746 WXSTRINGCAST szValue
,
749 return dwRet
== ERROR_SUCCESS
;
752 // returns true if this key has any values
753 bool wxRegKey::HasValues() const
755 // suppress possible messages from GetFirstValue()
758 // just call GetFirstValue with dummy parameters
761 return CONST_CAST
GetFirstValue(str
, l
);
764 // returns true if this key has any subkeys
765 bool wxRegKey::HasSubkeys() const
767 // suppress possible messages from GetFirstKey()
770 // just call GetFirstKey with dummy parameters
773 return CONST_CAST
GetFirstKey(str
, l
);
776 // returns true if given subkey exists
777 bool wxRegKey::HasSubKey(const wxChar
*szKey
) const
779 // this function should be silent, so suppress possible messages from Open()
782 if ( !CONST_CAST
Open(Read
) )
785 return KeyExists(m_hKey
, szKey
);
788 wxRegKey::ValueType
wxRegKey::GetValueType(const wxChar
*szValue
) const
790 if ( ! CONST_CAST
Open(Read
) )
794 m_dwLastError
= RegQueryValueEx((HKEY
) m_hKey
, WXSTRINGCAST szValue
, RESERVED
,
795 &dwType
, NULL
, NULL
);
796 if ( m_dwLastError
!= ERROR_SUCCESS
) {
797 wxLogSysError(m_dwLastError
, _("Can't read value of key '%s'"),
802 return (ValueType
)dwType
;
805 bool wxRegKey::SetValue(const wxChar
*szValue
, long lValue
)
807 if ( CONST_CAST
Open() ) {
808 m_dwLastError
= RegSetValueEx((HKEY
) m_hKey
, szValue
, (DWORD
) RESERVED
, REG_DWORD
,
809 (RegString
)&lValue
, sizeof(lValue
));
810 if ( m_dwLastError
== ERROR_SUCCESS
)
814 wxLogSysError(m_dwLastError
, _("Can't set value of '%s'"),
815 GetFullName(this, szValue
));
819 bool wxRegKey::QueryValue(const wxChar
*szValue
, long *plValue
) const
821 if ( CONST_CAST
Open(Read
) ) {
822 DWORD dwType
, dwSize
= sizeof(DWORD
);
823 RegString pBuf
= (RegString
)plValue
;
824 m_dwLastError
= RegQueryValueEx((HKEY
) m_hKey
, WXSTRINGCAST szValue
, RESERVED
,
825 &dwType
, pBuf
, &dwSize
);
826 if ( m_dwLastError
!= ERROR_SUCCESS
) {
827 wxLogSysError(m_dwLastError
, _("Can't read value of key '%s'"),
832 // check that we read the value of right type
833 wxASSERT_MSG( IsNumericValue(szValue
),
834 wxT("Type mismatch in wxRegKey::QueryValue().") );
843 bool wxRegKey::SetValue(const wxChar
*szValue
,const wxMemoryBuffer
& buffer
)
846 wxFAIL_MSG("RegSetValueEx not implemented by TWIN32");
849 if ( CONST_CAST
Open() ) {
850 m_dwLastError
= RegSetValueEx((HKEY
) m_hKey
, szValue
, (DWORD
) RESERVED
, REG_BINARY
,
851 (RegBinary
)buffer
.GetData(),buffer
.GetDataLen());
852 if ( m_dwLastError
== ERROR_SUCCESS
)
856 wxLogSysError(m_dwLastError
, _("Can't set value of '%s'"),
857 GetFullName(this, szValue
));
862 bool wxRegKey::QueryValue(const wxChar
*szValue
, wxMemoryBuffer
& buffer
) const
864 if ( CONST_CAST
Open(Read
) ) {
865 // first get the type and size of the data
866 DWORD dwType
, dwSize
;
867 m_dwLastError
= RegQueryValueEx((HKEY
) m_hKey
, WXSTRINGCAST szValue
, RESERVED
,
868 &dwType
, NULL
, &dwSize
);
870 if ( m_dwLastError
== ERROR_SUCCESS
) {
872 const RegBinary pBuf
= (RegBinary
)buffer
.GetWriteBuf(dwSize
);
873 m_dwLastError
= RegQueryValueEx((HKEY
) m_hKey
,
874 WXSTRINGCAST szValue
,
879 buffer
.UngetWriteBuf(dwSize
);
881 buffer
.SetDataLen(0);
886 if ( m_dwLastError
!= ERROR_SUCCESS
) {
887 wxLogSysError(m_dwLastError
, _("Can't read value of key '%s'"),
898 bool wxRegKey::QueryValue(const wxChar
*szValue
,
900 bool WXUNUSED_IN_WINCE(raw
)) const
902 if ( CONST_CAST
Open(Read
) )
905 // first get the type and size of the data
906 DWORD dwType
=REG_NONE
, dwSize
=0;
907 m_dwLastError
= RegQueryValueEx((HKEY
) m_hKey
, WXSTRINGCAST szValue
, RESERVED
,
908 &dwType
, NULL
, &dwSize
);
909 if ( m_dwLastError
== ERROR_SUCCESS
)
913 // must treat this case specially as GetWriteBuf() doesn't like
914 // being called with 0 size
919 m_dwLastError
= RegQueryValueEx((HKEY
) m_hKey
,
920 WXSTRINGCAST szValue
,
923 (RegString
)(wxChar
*)wxStringBuffer(strValue
, dwSize
),
926 // expand the var expansions in the string unless disabled
928 if ( (dwType
== REG_EXPAND_SZ
) && !raw
)
930 DWORD dwExpSize
= ::ExpandEnvironmentStrings(strValue
, NULL
, 0);
931 bool ok
= dwExpSize
!= 0;
934 wxString strExpValue
;
935 ok
= ::ExpandEnvironmentStrings(strValue
,
936 wxStringBuffer(strExpValue
, dwExpSize
),
939 strValue
= strExpValue
;
944 wxLogLastError(_T("ExpandEnvironmentStrings"));
951 if ( m_dwLastError
== ERROR_SUCCESS
)
953 // check that it was the right type
954 wxASSERT_MSG( !IsNumericValue(szValue
),
955 wxT("Type mismatch in wxRegKey::QueryValue().") );
962 wxLogSysError(m_dwLastError
, _("Can't read value of '%s'"),
963 GetFullName(this, szValue
));
967 bool wxRegKey::SetValue(const wxChar
*szValue
, const wxString
& strValue
)
969 if ( CONST_CAST
Open() ) {
970 m_dwLastError
= RegSetValueEx((HKEY
) m_hKey
, szValue
, (DWORD
) RESERVED
, REG_SZ
,
971 (RegString
)strValue
.wx_str(),
972 (strValue
.Len() + 1)*sizeof(wxChar
));
973 if ( m_dwLastError
== ERROR_SUCCESS
)
977 wxLogSysError(m_dwLastError
, _("Can't set value of '%s'"),
978 GetFullName(this, szValue
));
982 wxString
wxRegKey::QueryDefaultValue() const
985 QueryValue(NULL
, str
);
989 // ----------------------------------------------------------------------------
991 // NB: all these functions require an index variable which allows to have
992 // several concurrently running indexations on the same key
993 // ----------------------------------------------------------------------------
995 bool wxRegKey::GetFirstValue(wxString
& strValueName
, long& lIndex
)
1001 return GetNextValue(strValueName
, lIndex
);
1004 bool wxRegKey::GetNextValue(wxString
& strValueName
, long& lIndex
) const
1006 wxASSERT( IsOpened() );
1008 // are we already at the end of enumeration?
1012 wxChar szValueName
[1024]; // @@ use RegQueryInfoKey...
1013 DWORD dwValueLen
= WXSIZEOF(szValueName
);
1015 m_dwLastError
= RegEnumValue((HKEY
) m_hKey
, lIndex
++,
1016 szValueName
, &dwValueLen
,
1019 NULL
, // [out] buffer for value
1020 NULL
); // [i/o] it's length
1022 if ( m_dwLastError
!= ERROR_SUCCESS
) {
1023 if ( m_dwLastError
== ERROR_NO_MORE_ITEMS
) {
1024 m_dwLastError
= ERROR_SUCCESS
;
1028 wxLogSysError(m_dwLastError
, _("Can't enumerate values of key '%s'"),
1035 strValueName
= szValueName
;
1040 bool wxRegKey::GetFirstKey(wxString
& strKeyName
, long& lIndex
)
1046 return GetNextKey(strKeyName
, lIndex
);
1049 bool wxRegKey::GetNextKey(wxString
& strKeyName
, long& lIndex
) const
1051 wxASSERT( IsOpened() );
1053 // are we already at the end of enumeration?
1057 wxChar szKeyName
[_MAX_PATH
+ 1];
1060 DWORD sizeName
= WXSIZEOF(szKeyName
);
1061 m_dwLastError
= RegEnumKeyEx((HKEY
) m_hKey
, lIndex
++, szKeyName
, & sizeName
,
1062 0, NULL
, NULL
, NULL
);
1064 m_dwLastError
= RegEnumKey((HKEY
) m_hKey
, lIndex
++, szKeyName
, WXSIZEOF(szKeyName
));
1067 if ( m_dwLastError
!= ERROR_SUCCESS
) {
1068 if ( m_dwLastError
== ERROR_NO_MORE_ITEMS
) {
1069 m_dwLastError
= ERROR_SUCCESS
;
1073 wxLogSysError(m_dwLastError
, _("Can't enumerate subkeys of key '%s'"),
1080 strKeyName
= szKeyName
;
1084 // returns true if the value contains a number (else it's some string)
1085 bool wxRegKey::IsNumericValue(const wxChar
*szValue
) const
1087 ValueType type
= GetValueType(szValue
);
1090 /* case Type_Dword_little_endian: == Type_Dword */
1091 case Type_Dword_big_endian
:
1099 // ----------------------------------------------------------------------------
1100 // exporting registry keys to file
1101 // ----------------------------------------------------------------------------
1105 // helper functions for writing ASCII strings (even in Unicode build)
1106 static inline bool WriteAsciiChar(wxOutputStream
& ostr
, char ch
)
1112 static inline bool WriteAsciiEOL(wxOutputStream
& ostr
)
1114 // as we open the file in text mode, it is enough to write LF without CR
1115 return WriteAsciiChar(ostr
, '\n');
1118 static inline bool WriteAsciiString(wxOutputStream
& ostr
, const char *p
)
1120 return ostr
.Write(p
, strlen(p
)).IsOk();
1123 static inline bool WriteAsciiString(wxOutputStream
& ostr
, const wxString
& s
)
1126 wxCharBuffer
name(s
.mb_str());
1127 ostr
.Write(name
, strlen(name
));
1129 ostr
.Write(s
.mb_str(), s
.length());
1135 #endif // wxUSE_STREAMS
1137 bool wxRegKey::Export(const wxString
& filename
) const
1139 #if wxUSE_FFILE && wxUSE_STREAMS
1140 if ( wxFile::Exists(filename
) )
1142 wxLogError(_("Exporting registry key: file \"%s\" already exists and won't be overwritten."),
1147 wxFFileOutputStream
ostr(filename
, _T("w"));
1149 return ostr
.Ok() && Export(ostr
);
1151 wxUnusedVar(filename
);
1157 bool wxRegKey::Export(wxOutputStream
& ostr
) const
1159 // write out the header
1160 if ( !WriteAsciiString(ostr
, "REGEDIT4\n\n") )
1163 return DoExport(ostr
);
1165 #endif // wxUSE_STREAMS
1169 FormatAsHex(const void *data
,
1171 wxRegKey::ValueType type
= wxRegKey::Type_Binary
)
1173 wxString
value(_T("hex"));
1175 // binary values use just "hex:" prefix while the other ones must indicate
1177 if ( type
!= wxRegKey::Type_Binary
)
1178 value
<< _T('(') << type
<< _T(')');
1181 // write all the rest as comma-separated bytes
1182 value
.reserve(3*size
+ 10);
1183 const char * const p
= wx_static_cast(const char *, data
);
1184 for ( size_t n
= 0; n
< size
; n
++ )
1186 // TODO: line wrapping: although not required by regedit, this makes
1187 // the generated files easier to read and compare with the files
1188 // produced by regedit
1192 value
<< wxString::Format(_T("%02x"), (unsigned char)p
[n
]);
1199 wxString
FormatAsHex(const wxString
& value
, wxRegKey::ValueType type
)
1201 return FormatAsHex(value
.c_str(), value
.length() + 1, type
);
1204 wxString
wxRegKey::FormatValue(const wxString
& name
) const
1207 const ValueType type
= GetValueType(name
);
1213 if ( !QueryValue(name
, value
) )
1216 // quotes and backslashes must be quoted, linefeeds are not
1217 // allowed in string values
1218 rhs
.reserve(value
.length() + 2);
1221 // there can be no NULs here
1222 bool useHex
= false;
1223 for ( const wxChar
*p
= value
.c_str(); *p
&& !useHex
; p
++ )
1228 // we can only represent this string in hex
1234 // escape special symbol
1244 rhs
= FormatAsHex(value
, Type_String
);
1251 /* case Type_Dword_little_endian: == Type_Dword */
1254 if ( !QueryValue(name
, &value
) )
1257 rhs
.Printf(_T("dword:%08x"), (unsigned int)value
);
1261 case Type_Expand_String
:
1262 case Type_Multi_String
:
1265 if ( !QueryRawValue(name
, value
) )
1268 rhs
= FormatAsHex(value
, type
);
1275 if ( !QueryValue(name
, buf
) )
1278 rhs
= FormatAsHex(buf
.GetData(), buf
.GetDataLen());
1282 // no idea how those appear in REGEDIT4 files
1284 case Type_Dword_big_endian
:
1286 case Type_Resource_list
:
1287 case Type_Full_resource_descriptor
:
1288 case Type_Resource_requirements_list
:
1290 wxLogWarning(_("Can't export value of unsupported type %d."), type
);
1298 bool wxRegKey::DoExportValue(wxOutputStream
& ostr
, const wxString
& name
) const
1300 // first examine the value type: if it's unsupported, simply skip it
1301 // instead of aborting the entire export process because we failed to
1302 // export a single value
1303 wxString value
= FormatValue(name
);
1304 if ( value
.empty() )
1306 wxLogWarning(_("Ignoring value \"%s\" of the key \"%s\"."),
1307 name
.c_str(), GetName().c_str());
1311 // we do have the text representation of the value, now write everything
1314 // special case: unnamed/default value is represented as just "@"
1317 if ( !WriteAsciiChar(ostr
, '@') )
1320 else // normal, named, value
1322 if ( !WriteAsciiChar(ostr
, '"') ||
1323 !WriteAsciiString(ostr
, name
) ||
1324 !WriteAsciiChar(ostr
, '"') )
1328 if ( !WriteAsciiChar(ostr
, '=') )
1331 return WriteAsciiString(ostr
, value
) && WriteAsciiEOL(ostr
);
1334 bool wxRegKey::DoExport(wxOutputStream
& ostr
) const
1336 // write out this key name
1337 if ( !WriteAsciiChar(ostr
, '[') )
1340 if ( !WriteAsciiString(ostr
, GetName(false /* no short prefix */)) )
1343 if ( !WriteAsciiChar(ostr
, ']') || !WriteAsciiEOL(ostr
) )
1346 // dump all our values
1349 wxRegKey
& self
= wx_const_cast(wxRegKey
&, *this);
1350 bool cont
= self
.GetFirstValue(name
, dummy
);
1353 if ( !DoExportValue(ostr
, name
) )
1356 cont
= GetNextValue(name
, dummy
);
1359 // always terminate values by blank line, even if there were no values
1360 if ( !WriteAsciiEOL(ostr
) )
1363 // recurse to subkeys
1364 cont
= self
.GetFirstKey(name
, dummy
);
1367 wxRegKey
subkey(*this, name
);
1368 if ( !subkey
.DoExport(ostr
) )
1371 cont
= GetNextKey(name
, dummy
);
1377 #endif // wxUSE_STREAMS
1379 // ============================================================================
1380 // implementation of global private functions
1381 // ============================================================================
1383 bool KeyExists(WXHKEY hRootKey
, const wxChar
*szKey
)
1385 // don't close this key itself for the case of empty szKey!
1386 if ( wxIsEmpty(szKey
) )
1395 KEY_READ
, // we might not have enough rights for rw access
1397 ) == ERROR_SUCCESS
)
1399 ::RegCloseKey(hkeyDummy
);
1407 const wxChar
*GetFullName(const wxRegKey
*pKey
, const wxChar
*szValue
)
1409 static wxString s_str
;
1410 s_str
= pKey
->GetName();
1411 if ( !wxIsEmpty(szValue
) )
1412 s_str
<< wxT("\\") << szValue
;
1414 return s_str
.c_str();
1417 inline void RemoveTrailingSeparator(wxString
& str
)
1419 if ( !str
.empty() && str
.Last() == REG_SEPARATOR
)
1420 str
.Truncate(str
.Len() - 1);