/[pcsx2_0.9.7]/branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/msw/registry.cpp
ViewVC logotype

Contents of /branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/msw/registry.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.22