]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/registry.cpp
Enable variadic macros for VC9 and later.
[wxWidgets.git] / src / msw / registry.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/msw/registry.cpp
3// Purpose: implementation of registry classes and functions
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 03.04.98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// Licence: wxWindows licence
10// TODO: - parsing of registry key names
11// - support of other (than REG_SZ/REG_DWORD) registry types
12// - add high level functions (RegisterOleServer, ...)
13///////////////////////////////////////////////////////////////////////////////
14
15// for compilers that support precompilation, includes "wx.h".
16#include "wx/wxprec.h"
17
18#ifdef __BORLANDC__
19 #pragma hdrstop
20#endif
21
22#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
56typedef unsigned char *RegString;
57typedef 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
81static struct
82{
83 HKEY hkey;
84 const wxChar *szName;
85 const wxChar *szShortName;
86}
87aStdKeys[] =
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
120static inline void RemoveTrailingSeparator(wxString& str);
121
122// returns true if given registry key exists
123static 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
130static 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
134static long
135GetMSWAccessFlags(wxRegKey::AccessMode mode, wxRegKey::WOW64ViewMode viewMode);
136
137// combines value and key name
138static wxString GetFullName(const wxRegKey *pKey);
139static 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
144static inline const wxChar *RegValueStr(const wxString& szValue);
145
146// ============================================================================
147// implementation of wxRegKey class
148// ============================================================================
149
150// ----------------------------------------------------------------------------
151// static functions and variables
152// ----------------------------------------------------------------------------
153
154const 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.
158const 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
166const 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
174wxRegKey::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
200wxRegKey::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
216wxRegKey::wxRegKey(WOW64ViewMode viewMode) : m_viewMode(viewMode)
217{
218 m_hRootKey = (WXHKEY) aStdKeys[HKCR].hkey;
219
220 Init();
221}
222
223wxRegKey::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
232wxRegKey::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
244wxRegKey::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
262wxRegKey::~wxRegKey()
263{
264 Close();
265}
266
267// ----------------------------------------------------------------------------
268// change the key name/hkey
269// ----------------------------------------------------------------------------
270
271// set the full key name
272void 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
281void 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
291void 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
314void 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.clear();
330 m_dwLastError = 0;
331}
332
333// ----------------------------------------------------------------------------
334// info about the key
335// ----------------------------------------------------------------------------
336
337// returns true if the key exists
338bool 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)
347wxString 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
358bool wxRegKey::GetKeyInfo(size_t *pnSubKeys,
359 size_t *pnMaxKeyLen,
360 size_t *pnValues,
361 size_t *pnMaxValueLen) const
362{
363 // it might be unexpected to some that this function doesn't open the key
364 wxASSERT_MSG( IsOpened(), wxT("key should be opened in GetKeyInfo") );
365
366 // We need to use intermediate variables in 64 bit build as the function
367 // parameters must be 32 bit DWORDs and not 64 bit size_t values.
368#ifdef __WIN64__
369 DWORD dwSubKeys = 0,
370 dwMaxKeyLen = 0,
371 dwValues = 0,
372 dwMaxValueLen = 0;
373
374 #define REG_PARAM(name) &dw##name
375#else // Win32
376 // Old gcc headers incorrectly prototype RegQueryInfoKey() as taking
377 // size_t but normally we need a cast, even when sizeof(size_t) is the same
378 // as sizeof(DWORD).
379 #if defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__)
380 #define REG_PARAM(name) pn##name
381 #else
382 #define REG_PARAM(name) (LPDWORD)(pn##name)
383 #endif
384#endif
385
386
387 m_dwLastError = ::RegQueryInfoKey
388 (
389 (HKEY) m_hKey,
390 NULL, // class name
391 NULL, // (ptr to) size of class name buffer
392 RESERVED,
393 REG_PARAM(SubKeys), // [out] number of subkeys
394 REG_PARAM(MaxKeyLen), // [out] max length of a subkey name
395 NULL, // longest subkey class name
396 REG_PARAM(Values), // [out] number of values
397 REG_PARAM(MaxValueLen), // [out] max length of a value name
398 NULL, // longest value data
399 NULL, // security descriptor
400 NULL // time of last modification
401 );
402
403#ifdef __WIN64__
404 if ( pnSubKeys )
405 *pnSubKeys = dwSubKeys;
406 if ( pnMaxKeyLen )
407 *pnMaxKeyLen = dwMaxKeyLen;
408 if ( pnValues )
409 *pnValues = dwValues;
410 if ( pnMaxValueLen )
411 *pnMaxValueLen = dwMaxValueLen;
412#endif // __WIN64__
413
414#undef REG_PARAM
415
416 if ( m_dwLastError != ERROR_SUCCESS ) {
417 wxLogSysError(m_dwLastError, _("Can't get info about registry key '%s'"),
418 GetName().c_str());
419 return false;
420 }
421
422 return true;
423}
424
425// ----------------------------------------------------------------------------
426// operations
427// ----------------------------------------------------------------------------
428
429// opens key (it's not an error to call Open() on an already opened key)
430bool wxRegKey::Open(AccessMode mode)
431{
432 if ( IsOpened() )
433 {
434 if ( mode <= m_mode )
435 return true;
436
437 // we had been opened in read mode but now must be reopened in write
438 Close();
439 }
440
441 HKEY tmpKey;
442 m_dwLastError = ::RegOpenKeyEx
443 (
444 (HKEY) m_hRootKey,
445 m_strKey.t_str(),
446 RESERVED,
447 GetMSWAccessFlags(mode, m_viewMode),
448 &tmpKey
449 );
450
451 if ( m_dwLastError != ERROR_SUCCESS )
452 {
453 wxLogSysError(m_dwLastError, _("Can't open registry key '%s'"),
454 GetName().c_str());
455 return false;
456 }
457
458 m_hKey = (WXHKEY) tmpKey;
459 m_mode = mode;
460
461 return true;
462}
463
464// creates key, failing if it exists and !bOkIfExists
465bool wxRegKey::Create(bool bOkIfExists)
466{
467 // check for existence only if asked (i.e. order is important!)
468 if ( !bOkIfExists && Exists() )
469 return false;
470
471 if ( IsOpened() )
472 return true;
473
474 HKEY tmpKey;
475 DWORD disposition;
476 // Minimum supported OS for RegCreateKeyEx: Win 95, Win NT 3.1, Win CE 1.0
477 m_dwLastError = RegCreateKeyEx((HKEY) m_hRootKey, m_strKey.t_str(),
478 0, // reserved and must be 0
479 NULL, // The user-defined class type of this key.
480 REG_OPTION_NON_VOLATILE, // supports other values as well; see MS docs
481 GetMSWAccessFlags(wxRegKey::Write, m_viewMode),
482 NULL, // pointer to a SECURITY_ATTRIBUTES structure
483 &tmpKey,
484 &disposition);
485
486 if ( m_dwLastError != ERROR_SUCCESS ) {
487 wxLogSysError(m_dwLastError, _("Can't create registry key '%s'"),
488 GetName().c_str());
489 return false;
490 }
491 else
492 {
493 m_hKey = (WXHKEY) tmpKey;
494 return true;
495 }
496}
497
498// close the key, it's not an error to call it when not opened
499bool wxRegKey::Close()
500{
501 if ( IsOpened() ) {
502 m_dwLastError = RegCloseKey((HKEY) m_hKey);
503 m_hKey = 0;
504
505 if ( m_dwLastError != ERROR_SUCCESS ) {
506 wxLogSysError(m_dwLastError, _("Can't close registry key '%s'"),
507 GetName().c_str());
508
509 return false;
510 }
511 }
512
513 return true;
514}
515
516bool
517wxRegKey::RenameValue(const wxString& szValueOld, const wxString& szValueNew)
518{
519 bool ok = true;
520 if ( HasValue(szValueNew) ) {
521 wxLogError(_("Registry value '%s' already exists."), szValueNew);
522
523 ok = false;
524 }
525
526 if ( !ok ||
527 !CopyValue(szValueOld, *this, szValueNew) ||
528 !DeleteValue(szValueOld) ) {
529 wxLogError(_("Failed to rename registry value '%s' to '%s'."),
530 szValueOld, szValueNew);
531
532 return false;
533 }
534
535 return true;
536}
537
538bool wxRegKey::CopyValue(const wxString& szValue,
539 wxRegKey& keyDst,
540 const wxString& szValueNew)
541{
542 wxString valueNew(szValueNew);
543 if ( valueNew.empty() ) {
544 // by default, use the same name
545 valueNew = szValue;
546 }
547
548 switch ( GetValueType(szValue) ) {
549 case Type_String:
550 {
551 wxString strVal;
552 return QueryValue(szValue, strVal) &&
553 keyDst.SetValue(valueNew, strVal);
554 }
555
556 case Type_Dword:
557 /* case Type_Dword_little_endian: == Type_Dword */
558 {
559 long dwVal;
560 return QueryValue(szValue, &dwVal) &&
561 keyDst.SetValue(valueNew, dwVal);
562 }
563
564 case Type_Binary:
565 {
566 wxMemoryBuffer buf;
567 return QueryValue(szValue,buf) &&
568 keyDst.SetValue(valueNew,buf);
569 }
570
571 // these types are unsupported because I am not sure about how
572 // exactly they should be copied and because they shouldn't
573 // occur among the application keys (supposedly created with
574 // this class)
575 case Type_None:
576 case Type_Expand_String:
577 case Type_Dword_big_endian:
578 case Type_Link:
579 case Type_Multi_String:
580 case Type_Resource_list:
581 case Type_Full_resource_descriptor:
582 case Type_Resource_requirements_list:
583 default:
584 wxLogError(_("Can't copy values of unsupported type %d."),
585 GetValueType(szValue));
586 return false;
587 }
588}
589
590bool wxRegKey::Rename(const wxString& szNewName)
591{
592 wxCHECK_MSG( !m_strKey.empty(), false, wxT("registry hives can't be renamed") );
593
594 if ( !Exists() ) {
595 wxLogError(_("Registry key '%s' does not exist, cannot rename it."),
596 GetFullName(this));
597
598 return false;
599 }
600
601 // do we stay in the same hive?
602 bool inSameHive = !wxStrchr(szNewName, REG_SEPARATOR);
603
604 // construct the full new name of the key
605 wxRegKey keyDst;
606
607 if ( inSameHive ) {
608 // rename the key to the new name under the same parent
609 wxString strKey = m_strKey.BeforeLast(REG_SEPARATOR);
610 if ( !strKey.empty() ) {
611 // don't add '\\' in the start if strFullNewName is empty
612 strKey += REG_SEPARATOR;
613 }
614
615 strKey += szNewName;
616
617 keyDst.SetName(GetStdKeyFromHkey(m_hRootKey), strKey);
618 }
619 else {
620 // this is the full name already
621 keyDst.SetName(szNewName);
622 }
623
624 bool ok = keyDst.Create(false /* fail if alredy exists */);
625 if ( !ok ) {
626 wxLogError(_("Registry key '%s' already exists."),
627 GetFullName(&keyDst));
628 }
629 else {
630 ok = Copy(keyDst) && DeleteSelf();
631 }
632
633 if ( !ok ) {
634 wxLogError(_("Failed to rename the registry key '%s' to '%s'."),
635 GetFullName(this), GetFullName(&keyDst));
636 }
637 else {
638 m_hRootKey = keyDst.m_hRootKey;
639 m_strKey = keyDst.m_strKey;
640 }
641
642 return ok;
643}
644
645bool wxRegKey::Copy(const wxString& szNewName)
646{
647 // create the new key first
648 wxRegKey keyDst(szNewName);
649 bool ok = keyDst.Create(false /* fail if alredy exists */);
650 if ( ok ) {
651 ok = Copy(keyDst);
652
653 // we created the dest key but copying to it failed - delete it
654 if ( !ok ) {
655 (void)keyDst.DeleteSelf();
656 }
657 }
658
659 return ok;
660}
661
662bool wxRegKey::Copy(wxRegKey& keyDst)
663{
664 bool ok = true;
665
666 // copy all sub keys to the new location
667 wxString strKey;
668 long lIndex;
669 bool bCont = GetFirstKey(strKey, lIndex);
670 while ( ok && bCont ) {
671 wxRegKey key(*this, strKey);
672 wxString keyName;
673 keyName << GetFullName(&keyDst) << REG_SEPARATOR << strKey;
674 ok = key.Copy(keyName);
675
676 if ( ok )
677 bCont = GetNextKey(strKey, lIndex);
678 else
679 wxLogError(_("Failed to copy the registry subkey '%s' to '%s'."),
680 GetFullName(&key), keyName.c_str());
681
682 }
683
684 // copy all values
685 wxString strVal;
686 bCont = GetFirstValue(strVal, lIndex);
687 while ( ok && bCont ) {
688 ok = CopyValue(strVal, keyDst);
689
690 if ( !ok ) {
691 wxLogSysError(m_dwLastError,
692 _("Failed to copy registry value '%s'"),
693 strVal.c_str());
694 }
695 else {
696 bCont = GetNextValue(strVal, lIndex);
697 }
698 }
699
700 if ( !ok ) {
701 wxLogError(_("Failed to copy the contents of registry key '%s' to '%s'."),
702 GetFullName(this), GetFullName(&keyDst));
703 }
704
705 return ok;
706}
707
708// ----------------------------------------------------------------------------
709// delete keys/values
710// ----------------------------------------------------------------------------
711bool wxRegKey::DeleteSelf()
712{
713 {
714 wxLogNull nolog;
715 if ( !Open() ) {
716 // it already doesn't exist - ok!
717 return true;
718 }
719 }
720
721 // prevent a buggy program from erasing one of the root registry keys or an
722 // immediate subkey (i.e. one which doesn't have '\\' inside) of any other
723 // key except HKCR (HKCR has some "deleteable" subkeys)
724 if ( m_strKey.empty() ||
725 ((m_hRootKey != (WXHKEY) aStdKeys[HKCR].hkey) &&
726 (m_strKey.Find(REG_SEPARATOR) == wxNOT_FOUND)) ) {
727 wxLogError(_("Registry key '%s' is needed for normal system operation,\ndeleting it will leave your system in unusable state:\noperation aborted."),
728 GetFullName(this));
729
730 return false;
731 }
732
733 // we can't delete keys while enumerating because it confuses GetNextKey, so
734 // we first save the key names and then delete them all
735 wxArrayString astrSubkeys;
736
737 wxString strKey;
738 long lIndex;
739 bool bCont = GetFirstKey(strKey, lIndex);
740 while ( bCont ) {
741 astrSubkeys.Add(strKey);
742
743 bCont = GetNextKey(strKey, lIndex);
744 }
745
746 size_t nKeyCount = astrSubkeys.Count();
747 for ( size_t nKey = 0; nKey < nKeyCount; nKey++ ) {
748 wxRegKey key(*this, astrSubkeys[nKey]);
749 if ( !key.DeleteSelf() )
750 return false;
751 }
752
753 // now delete this key itself
754 Close();
755
756 // deleting a key which doesn't exist is not considered an error
757#if wxUSE_DYNLIB_CLASS
758 wxDynamicLibrary dllAdvapi32(wxT("advapi32"));
759 // Minimum supported OS for RegDeleteKeyEx: Vista, XP Pro x64, Win Server 2008, Win Server 2003 SP1
760 if(dllAdvapi32.HasSymbol(wxT("RegDeleteKeyEx")))
761 {
762 typedef LONG (WINAPI *RegDeleteKeyEx_t)(HKEY, LPCTSTR, REGSAM, DWORD);
763 wxDYNLIB_FUNCTION(RegDeleteKeyEx_t, RegDeleteKeyEx, dllAdvapi32);
764
765 m_dwLastError = (*pfnRegDeleteKeyEx)((HKEY) m_hRootKey, m_strKey.t_str(),
766 GetMSWViewFlags(m_viewMode),
767 0); // This parameter is reserved and must be zero.
768 }
769 else
770#endif // wxUSE_DYNLIB_CLASS
771 {
772 m_dwLastError = RegDeleteKey((HKEY) m_hRootKey, m_strKey.t_str());
773 }
774
775 if ( m_dwLastError != ERROR_SUCCESS &&
776 m_dwLastError != ERROR_FILE_NOT_FOUND ) {
777 wxLogSysError(m_dwLastError, _("Can't delete key '%s'"),
778 GetName().c_str());
779 return false;
780 }
781
782 return true;
783}
784
785bool wxRegKey::DeleteKey(const wxString& szKey)
786{
787 if ( !Open() )
788 return false;
789
790 wxRegKey key(*this, szKey);
791 return key.DeleteSelf();
792}
793
794bool wxRegKey::DeleteValue(const wxString& szValue)
795{
796 if ( !Open() )
797 return false;
798
799 m_dwLastError = RegDeleteValue((HKEY) m_hKey, RegValueStr(szValue));
800
801 // deleting a value which doesn't exist is not considered an error
802 if ( (m_dwLastError != ERROR_SUCCESS) &&
803 (m_dwLastError != ERROR_FILE_NOT_FOUND) )
804 {
805 wxLogSysError(m_dwLastError, _("Can't delete value '%s' from key '%s'"),
806 szValue, GetName().c_str());
807 return false;
808 }
809
810 return true;
811}
812
813// ----------------------------------------------------------------------------
814// access to values and subkeys
815// ----------------------------------------------------------------------------
816
817// return true if value exists
818bool wxRegKey::HasValue(const wxString& szValue) const
819{
820 // this function should be silent, so suppress possible messages from Open()
821 wxLogNull nolog;
822
823 if ( !CONST_CAST Open(Read) )
824 return false;
825
826 LONG dwRet = ::RegQueryValueEx((HKEY) m_hKey,
827 RegValueStr(szValue),
828 RESERVED,
829 NULL, NULL, NULL);
830 return dwRet == ERROR_SUCCESS;
831}
832
833// returns true if this key has any values
834bool wxRegKey::HasValues() const
835{
836 // suppress possible messages from GetFirstValue()
837 wxLogNull nolog;
838
839 // just call GetFirstValue with dummy parameters
840 wxString str;
841 long l;
842 return CONST_CAST GetFirstValue(str, l);
843}
844
845// returns true if this key has any subkeys
846bool wxRegKey::HasSubkeys() const
847{
848 // suppress possible messages from GetFirstKey()
849 wxLogNull nolog;
850
851 // just call GetFirstKey with dummy parameters
852 wxString str;
853 long l;
854 return CONST_CAST GetFirstKey(str, l);
855}
856
857// returns true if given subkey exists
858bool wxRegKey::HasSubKey(const wxString& szKey) const
859{
860 // this function should be silent, so suppress possible messages from Open()
861 wxLogNull nolog;
862
863 if ( !CONST_CAST Open(Read) )
864 return false;
865
866 return KeyExists(m_hKey, szKey, m_viewMode);
867}
868
869wxRegKey::ValueType wxRegKey::GetValueType(const wxString& szValue) const
870{
871 if ( ! CONST_CAST Open(Read) )
872 return Type_None;
873
874 DWORD dwType;
875 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, RegValueStr(szValue), RESERVED,
876 &dwType, NULL, NULL);
877 if ( m_dwLastError != ERROR_SUCCESS ) {
878 wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"),
879 GetName().c_str());
880 return Type_None;
881 }
882
883 return (ValueType)dwType;
884}
885
886bool wxRegKey::SetValue(const wxString& szValue, long lValue)
887{
888 if ( CONST_CAST Open() ) {
889 m_dwLastError = RegSetValueEx((HKEY) m_hKey, RegValueStr(szValue),
890 (DWORD) RESERVED, REG_DWORD,
891 (RegString)&lValue, sizeof(lValue));
892 if ( m_dwLastError == ERROR_SUCCESS )
893 return true;
894 }
895
896 wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
897 GetFullName(this, szValue));
898 return false;
899}
900
901bool wxRegKey::QueryValue(const wxString& szValue, long *plValue) const
902{
903 if ( CONST_CAST Open(Read) ) {
904 DWORD dwType, dwSize = sizeof(DWORD);
905 RegString pBuf = (RegString)plValue;
906 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, RegValueStr(szValue),
907 RESERVED,
908 &dwType, pBuf, &dwSize);
909 if ( m_dwLastError != ERROR_SUCCESS ) {
910 wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"),
911 GetName().c_str());
912 return false;
913 }
914 else {
915 // check that we read the value of right type
916 wxASSERT_MSG( IsNumericValue(szValue),
917 wxT("Type mismatch in wxRegKey::QueryValue().") );
918
919 return true;
920 }
921 }
922 else
923 return false;
924}
925
926bool wxRegKey::SetValue(const wxString& szValue, const wxMemoryBuffer& buffer)
927{
928#ifdef __TWIN32__
929 wxFAIL_MSG("RegSetValueEx not implemented by TWIN32");
930 return false;
931#else
932 if ( CONST_CAST Open() ) {
933 m_dwLastError = RegSetValueEx((HKEY) m_hKey, RegValueStr(szValue),
934 (DWORD) RESERVED, REG_BINARY,
935 (RegBinary)buffer.GetData(),buffer.GetDataLen());
936 if ( m_dwLastError == ERROR_SUCCESS )
937 return true;
938 }
939
940 wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
941 GetFullName(this, szValue));
942 return false;
943#endif
944}
945
946bool wxRegKey::QueryValue(const wxString& szValue, wxMemoryBuffer& buffer) const
947{
948 if ( CONST_CAST Open(Read) ) {
949 // first get the type and size of the data
950 DWORD dwType, dwSize;
951 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, RegValueStr(szValue),
952 RESERVED,
953 &dwType, NULL, &dwSize);
954
955 if ( m_dwLastError == ERROR_SUCCESS ) {
956 if ( dwSize ) {
957 const RegBinary pBuf = (RegBinary)buffer.GetWriteBuf(dwSize);
958 m_dwLastError = RegQueryValueEx((HKEY) m_hKey,
959 RegValueStr(szValue),
960 RESERVED,
961 &dwType,
962 pBuf,
963 &dwSize);
964 buffer.UngetWriteBuf(dwSize);
965 } else {
966 buffer.SetDataLen(0);
967 }
968 }
969
970
971 if ( m_dwLastError != ERROR_SUCCESS ) {
972 wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"),
973 GetName().c_str());
974 return false;
975 }
976 return true;
977 }
978 return false;
979}
980
981
982
983bool wxRegKey::QueryValue(const wxString& szValue,
984 wxString& strValue,
985 bool WXUNUSED_IN_WINCE(raw)) const
986{
987 if ( CONST_CAST Open(Read) )
988 {
989
990 // first get the type and size of the data
991 DWORD dwType=REG_NONE, dwSize=0;
992 m_dwLastError = RegQueryValueEx((HKEY) m_hKey,
993 RegValueStr(szValue),
994 RESERVED,
995 &dwType, NULL, &dwSize);
996 if ( m_dwLastError == ERROR_SUCCESS )
997 {
998 if ( !dwSize )
999 {
1000 // must treat this case specially as GetWriteBuf() doesn't like
1001 // being called with 0 size
1002 strValue.Empty();
1003 }
1004 else
1005 {
1006 m_dwLastError = RegQueryValueEx((HKEY) m_hKey,
1007 RegValueStr(szValue),
1008 RESERVED,
1009 &dwType,
1010 (RegString)(wxChar*)wxStringBuffer(strValue, dwSize),
1011 &dwSize);
1012
1013 // expand the var expansions in the string unless disabled
1014#ifndef __WXWINCE__
1015 if ( (dwType == REG_EXPAND_SZ) && !raw )
1016 {
1017 DWORD dwExpSize = ::ExpandEnvironmentStrings(strValue.t_str(), NULL, 0);
1018 bool ok = dwExpSize != 0;
1019 if ( ok )
1020 {
1021 wxString strExpValue;
1022 ok = ::ExpandEnvironmentStrings(strValue.t_str(),
1023 wxStringBuffer(strExpValue, dwExpSize),
1024 dwExpSize
1025 ) != 0;
1026 strValue = strExpValue;
1027 }
1028
1029 if ( !ok )
1030 {
1031 wxLogLastError(wxT("ExpandEnvironmentStrings"));
1032 }
1033 }
1034#endif
1035 // __WXWINCE__
1036 }
1037
1038 if ( m_dwLastError == ERROR_SUCCESS )
1039 {
1040 // check that it was the right type
1041 wxASSERT_MSG( !IsNumericValue(szValue),
1042 wxT("Type mismatch in wxRegKey::QueryValue().") );
1043
1044 return true;
1045 }
1046 }
1047 }
1048
1049 wxLogSysError(m_dwLastError, _("Can't read value of '%s'"),
1050 GetFullName(this, szValue));
1051 return false;
1052}
1053
1054bool wxRegKey::SetValue(const wxString& szValue, const wxString& strValue)
1055{
1056 if ( CONST_CAST Open() ) {
1057 m_dwLastError = RegSetValueEx((HKEY) m_hKey,
1058 RegValueStr(szValue),
1059 (DWORD) RESERVED, REG_SZ,
1060 (RegString)strValue.t_str(),
1061 (strValue.Len() + 1)*sizeof(wxChar));
1062 if ( m_dwLastError == ERROR_SUCCESS )
1063 return true;
1064 }
1065
1066 wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
1067 GetFullName(this, szValue));
1068 return false;
1069}
1070
1071wxString wxRegKey::QueryDefaultValue() const
1072{
1073 wxString str;
1074 QueryValue(wxEmptyString, str, false);
1075 return str;
1076}
1077
1078// ----------------------------------------------------------------------------
1079// enumeration
1080// NB: all these functions require an index variable which allows to have
1081// several concurrently running indexations on the same key
1082// ----------------------------------------------------------------------------
1083
1084bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex)
1085{
1086 if ( !Open(Read) )
1087 return false;
1088
1089 lIndex = 0;
1090 return GetNextValue(strValueName, lIndex);
1091}
1092
1093bool wxRegKey::GetNextValue(wxString& strValueName, long& lIndex) const
1094{
1095 wxASSERT( IsOpened() );
1096
1097 // are we already at the end of enumeration?
1098 if ( lIndex == -1 )
1099 return false;
1100
1101 wxChar szValueName[1024]; // @@ use RegQueryInfoKey...
1102 DWORD dwValueLen = WXSIZEOF(szValueName);
1103
1104 m_dwLastError = RegEnumValue((HKEY) m_hKey, lIndex++,
1105 szValueName, &dwValueLen,
1106 RESERVED,
1107 NULL, // [out] type
1108 NULL, // [out] buffer for value
1109 NULL); // [i/o] it's length
1110
1111 if ( m_dwLastError != ERROR_SUCCESS ) {
1112 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
1113 m_dwLastError = ERROR_SUCCESS;
1114 lIndex = -1;
1115 }
1116 else {
1117 wxLogSysError(m_dwLastError, _("Can't enumerate values of key '%s'"),
1118 GetName().c_str());
1119 }
1120
1121 return false;
1122 }
1123
1124 strValueName = szValueName;
1125
1126 return true;
1127}
1128
1129bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex)
1130{
1131 if ( !Open(Read) )
1132 return false;
1133
1134 lIndex = 0;
1135 return GetNextKey(strKeyName, lIndex);
1136}
1137
1138bool wxRegKey::GetNextKey(wxString& strKeyName, long& lIndex) const
1139{
1140 wxASSERT( IsOpened() );
1141
1142 // are we already at the end of enumeration?
1143 if ( lIndex == -1 )
1144 return false;
1145
1146 wxChar szKeyName[_MAX_PATH + 1];
1147
1148#ifdef __WXWINCE__
1149 DWORD sizeName = WXSIZEOF(szKeyName);
1150 m_dwLastError = RegEnumKeyEx((HKEY) m_hKey, lIndex++, szKeyName, & sizeName,
1151 0, NULL, NULL, NULL);
1152#else
1153 m_dwLastError = RegEnumKey((HKEY) m_hKey, lIndex++, szKeyName, WXSIZEOF(szKeyName));
1154#endif
1155
1156 if ( m_dwLastError != ERROR_SUCCESS ) {
1157 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
1158 m_dwLastError = ERROR_SUCCESS;
1159 lIndex = -1;
1160 }
1161 else {
1162 wxLogSysError(m_dwLastError, _("Can't enumerate subkeys of key '%s'"),
1163 GetName().c_str());
1164 }
1165
1166 return false;
1167 }
1168
1169 strKeyName = szKeyName;
1170 return true;
1171}
1172
1173// returns true if the value contains a number (else it's some string)
1174bool wxRegKey::IsNumericValue(const wxString& szValue) const
1175{
1176 ValueType type = GetValueType(szValue);
1177 switch ( type ) {
1178 case Type_Dword:
1179 /* case Type_Dword_little_endian: == Type_Dword */
1180 case Type_Dword_big_endian:
1181 return true;
1182
1183 default:
1184 return false;
1185 }
1186}
1187
1188// ----------------------------------------------------------------------------
1189// exporting registry keys to file
1190// ----------------------------------------------------------------------------
1191
1192#if wxUSE_STREAMS
1193
1194// helper functions for writing ASCII strings (even in Unicode build)
1195static inline bool WriteAsciiChar(wxOutputStream& ostr, char ch)
1196{
1197 ostr.PutC(ch);
1198 return ostr.IsOk();
1199}
1200
1201static inline bool WriteAsciiEOL(wxOutputStream& ostr)
1202{
1203 // as we open the file in text mode, it is enough to write LF without CR
1204 return WriteAsciiChar(ostr, '\n');
1205}
1206
1207static inline bool WriteAsciiString(wxOutputStream& ostr, const char *p)
1208{
1209 return ostr.Write(p, strlen(p)).IsOk();
1210}
1211
1212static inline bool WriteAsciiString(wxOutputStream& ostr, const wxString& s)
1213{
1214#if wxUSE_UNICODE
1215 wxCharBuffer name(s.mb_str());
1216 ostr.Write(name, strlen(name));
1217#else
1218 ostr.Write(s.mb_str(), s.length());
1219#endif
1220
1221 return ostr.IsOk();
1222}
1223
1224#endif // wxUSE_STREAMS
1225
1226bool wxRegKey::Export(const wxString& filename) const
1227{
1228#if wxUSE_FFILE && wxUSE_STREAMS
1229 if ( wxFile::Exists(filename) )
1230 {
1231 wxLogError(_("Exporting registry key: file \"%s\" already exists and won't be overwritten."),
1232 filename.c_str());
1233 return false;
1234 }
1235
1236 wxFFileOutputStream ostr(filename, wxT("w"));
1237
1238 return ostr.IsOk() && Export(ostr);
1239#else
1240 wxUnusedVar(filename);
1241 return false;
1242#endif
1243}
1244
1245#if wxUSE_STREAMS
1246bool wxRegKey::Export(wxOutputStream& ostr) const
1247{
1248 // write out the header
1249 if ( !WriteAsciiString(ostr, "REGEDIT4\n\n") )
1250 return false;
1251
1252 return DoExport(ostr);
1253}
1254#endif // wxUSE_STREAMS
1255
1256static
1257wxString
1258FormatAsHex(const void *data,
1259 size_t size,
1260 wxRegKey::ValueType type = wxRegKey::Type_Binary)
1261{
1262 wxString value(wxT("hex"));
1263
1264 // binary values use just "hex:" prefix while the other ones must indicate
1265 // the real type
1266 if ( type != wxRegKey::Type_Binary )
1267 value << wxT('(') << type << wxT(')');
1268 value << wxT(':');
1269
1270 // write all the rest as comma-separated bytes
1271 value.reserve(3*size + 10);
1272 const char * const p = static_cast<const char *>(data);
1273 for ( size_t n = 0; n < size; n++ )
1274 {
1275 // TODO: line wrapping: although not required by regedit, this makes
1276 // the generated files easier to read and compare with the files
1277 // produced by regedit
1278 if ( n )
1279 value << wxT(',');
1280
1281 value << wxString::Format(wxT("%02x"), (unsigned char)p[n]);
1282 }
1283
1284 return value;
1285}
1286
1287static inline
1288wxString FormatAsHex(const wxString& value, wxRegKey::ValueType type)
1289{
1290 return FormatAsHex(value.c_str(), value.length() + 1, type);
1291}
1292
1293wxString wxRegKey::FormatValue(const wxString& name) const
1294{
1295 wxString rhs;
1296 const ValueType type = GetValueType(name);
1297 switch ( type )
1298 {
1299 case Type_String:
1300 {
1301 wxString value;
1302 if ( !QueryValue(name, value) )
1303 break;
1304
1305 // quotes and backslashes must be quoted, linefeeds are not
1306 // allowed in string values
1307 rhs.reserve(value.length() + 2);
1308 rhs = wxT('"');
1309
1310 // there can be no NULs here
1311 bool useHex = false;
1312 for ( wxString::const_iterator p = value.begin();
1313 p != value.end() && !useHex; ++p )
1314 {
1315 switch ( (*p).GetValue() )
1316 {
1317 case wxT('\n'):
1318 // we can only represent this string in hex
1319 useHex = true;
1320 break;
1321
1322 case wxT('"'):
1323 case wxT('\\'):
1324 // escape special symbol
1325 rhs += wxT('\\');
1326 // fall through
1327
1328 default:
1329 rhs += *p;
1330 }
1331 }
1332
1333 if ( useHex )
1334 rhs = FormatAsHex(value, Type_String);
1335 else
1336 rhs += wxT('"');
1337 }
1338 break;
1339
1340 case Type_Dword:
1341 /* case Type_Dword_little_endian: == Type_Dword */
1342 {
1343 long value;
1344 if ( !QueryValue(name, &value) )
1345 break;
1346
1347 rhs.Printf(wxT("dword:%08x"), (unsigned int)value);
1348 }
1349 break;
1350
1351 case Type_Expand_String:
1352 case Type_Multi_String:
1353 {
1354 wxString value;
1355 if ( !QueryRawValue(name, value) )
1356 break;
1357
1358 rhs = FormatAsHex(value, type);
1359 }
1360 break;
1361
1362 case Type_Binary:
1363 {
1364 wxMemoryBuffer buf;
1365 if ( !QueryValue(name, buf) )
1366 break;
1367
1368 rhs = FormatAsHex(buf.GetData(), buf.GetDataLen());
1369 }
1370 break;
1371
1372 // no idea how those appear in REGEDIT4 files
1373 case Type_None:
1374 case Type_Dword_big_endian:
1375 case Type_Link:
1376 case Type_Resource_list:
1377 case Type_Full_resource_descriptor:
1378 case Type_Resource_requirements_list:
1379 default:
1380 wxLogWarning(_("Can't export value of unsupported type %d."), type);
1381 }
1382
1383 return rhs;
1384}
1385
1386#if wxUSE_STREAMS
1387
1388bool wxRegKey::DoExportValue(wxOutputStream& ostr, const wxString& name) const
1389{
1390 // first examine the value type: if it's unsupported, simply skip it
1391 // instead of aborting the entire export process because we failed to
1392 // export a single value
1393 wxString value = FormatValue(name);
1394 if ( value.empty() )
1395 {
1396 wxLogWarning(_("Ignoring value \"%s\" of the key \"%s\"."),
1397 name.c_str(), GetName().c_str());
1398 return true;
1399 }
1400
1401 // we do have the text representation of the value, now write everything
1402 // out
1403
1404 // special case: unnamed/default value is represented as just "@"
1405 if ( name.empty() )
1406 {
1407 if ( !WriteAsciiChar(ostr, '@') )
1408 return false;
1409 }
1410 else // normal, named, value
1411 {
1412 if ( !WriteAsciiChar(ostr, '"') ||
1413 !WriteAsciiString(ostr, name) ||
1414 !WriteAsciiChar(ostr, '"') )
1415 return false;
1416 }
1417
1418 if ( !WriteAsciiChar(ostr, '=') )
1419 return false;
1420
1421 return WriteAsciiString(ostr, value) && WriteAsciiEOL(ostr);
1422}
1423
1424bool wxRegKey::DoExport(wxOutputStream& ostr) const
1425{
1426 // write out this key name
1427 if ( !WriteAsciiChar(ostr, '[') )
1428 return false;
1429
1430 if ( !WriteAsciiString(ostr, GetName(false /* no short prefix */)) )
1431 return false;
1432
1433 if ( !WriteAsciiChar(ostr, ']') || !WriteAsciiEOL(ostr) )
1434 return false;
1435
1436 // dump all our values
1437 long dummy;
1438 wxString name;
1439 wxRegKey& self = const_cast<wxRegKey&>(*this);
1440 bool cont = self.GetFirstValue(name, dummy);
1441 while ( cont )
1442 {
1443 if ( !DoExportValue(ostr, name) )
1444 return false;
1445
1446 cont = GetNextValue(name, dummy);
1447 }
1448
1449 // always terminate values by blank line, even if there were no values
1450 if ( !WriteAsciiEOL(ostr) )
1451 return false;
1452
1453 // recurse to subkeys
1454 cont = self.GetFirstKey(name, dummy);
1455 while ( cont )
1456 {
1457 wxRegKey subkey(*this, name);
1458 if ( !subkey.DoExport(ostr) )
1459 return false;
1460
1461 cont = GetNextKey(name, dummy);
1462 }
1463
1464 return true;
1465}
1466
1467#endif // wxUSE_STREAMS
1468
1469// ============================================================================
1470// implementation of global private functions
1471// ============================================================================
1472
1473bool KeyExists(WXHKEY hRootKey,
1474 const wxString& szKey,
1475 wxRegKey::WOW64ViewMode viewMode)
1476{
1477 // don't close this key itself for the case of empty szKey!
1478 if ( szKey.empty() )
1479 return true;
1480
1481 HKEY hkeyDummy;
1482 if ( ::RegOpenKeyEx
1483 (
1484 (HKEY)hRootKey,
1485 szKey.t_str(),
1486 RESERVED,
1487 // we might not have enough rights for rw access
1488 GetMSWAccessFlags(wxRegKey::Read, viewMode),
1489 &hkeyDummy
1490 ) == ERROR_SUCCESS )
1491 {
1492 ::RegCloseKey(hkeyDummy);
1493
1494 return true;
1495 }
1496
1497 return false;
1498}
1499
1500long GetMSWViewFlags(wxRegKey::WOW64ViewMode viewMode)
1501{
1502 long samWOW64ViewMode = 0;
1503
1504 switch ( viewMode )
1505 {
1506 case wxRegKey::WOW64ViewMode_32:
1507#ifdef __WIN64__ // the flag is only needed by 64 bit apps
1508 samWOW64ViewMode = KEY_WOW64_32KEY;
1509#endif // Win64
1510 break;
1511
1512 case wxRegKey::WOW64ViewMode_64:
1513#ifndef __WIN64__ // the flag is only needed by 32 bit apps
1514 // 64 bit registry can only be accessed under 64 bit platforms
1515 if ( wxIsPlatform64Bit() )
1516 samWOW64ViewMode = KEY_WOW64_64KEY;
1517#endif // Win32
1518 break;
1519
1520 default:
1521 wxFAIL_MSG("Unknown registry view.");
1522 // fall through
1523
1524 case wxRegKey::WOW64ViewMode_Default:
1525 // Use default registry view for the current application,
1526 // i.e. 32 bits for 32 bit ones and 64 bits for 64 bit apps
1527 ;
1528 }
1529
1530 return samWOW64ViewMode;
1531}
1532
1533long GetMSWAccessFlags(wxRegKey::AccessMode mode,
1534 wxRegKey::WOW64ViewMode viewMode)
1535{
1536 long sam = mode == wxRegKey::Read ? KEY_READ : KEY_ALL_ACCESS;
1537
1538 sam |= GetMSWViewFlags(viewMode);
1539
1540 return sam;
1541}
1542
1543wxString GetFullName(const wxRegKey *pKey, const wxString& szValue)
1544{
1545 wxString str(pKey->GetName());
1546 if ( !szValue.empty() )
1547 str << wxT("\\") << szValue;
1548
1549 return str;
1550}
1551
1552wxString GetFullName(const wxRegKey *pKey)
1553{
1554 return pKey->GetName();
1555}
1556
1557inline void RemoveTrailingSeparator(wxString& str)
1558{
1559 if ( !str.empty() && str.Last() == REG_SEPARATOR )
1560 str.Truncate(str.Len() - 1);
1561}
1562
1563inline const wxChar *RegValueStr(const wxString& szValue)
1564{
1565 return szValue.empty() ? (const wxChar*)NULL : szValue.t_str();
1566}
1567
1568#endif // wxUSE_REGKEY