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