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