]> git.saurik.com Git - wxWidgets.git/blame - src/msw/registry.cpp
Added missing wxBitmapComboBox::Insert() implementation
[wxWidgets.git] / src / msw / registry.cpp
CommitLineData
2bda0e17 1///////////////////////////////////////////////////////////////////////////////
df91131c 2// Name: src/msw/registry.cpp
2bda0e17
KB
3// Purpose: implementation of registry classes and functions
4// Author: Vadim Zeitlin
23f681ec 5// Modified by:
2bda0e17
KB
6// Created: 03.04.98
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
65571936 9// Licence: wxWindows licence
2bda0e17
KB
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
2bda0e17
KB
15// for compilers that support precompilation, includes "wx.h".
16#include "wx/wxprec.h"
17
18#ifdef __BORLANDC__
df91131c
WS
19 #pragma hdrstop
20#endif
21
f77c0fe3
VZ
22#if wxUSE_REGKEY
23
df91131c 24#ifndef WX_PRECOMP
57bd4c60 25 #include "wx/msw/wrapwin.h"
df91131c 26 #include "wx/string.h"
57bd4c60
WS
27 #include "wx/intl.h"
28 #include "wx/log.h"
0bf751e7 29 #include "wx/crt.h"
a5c46848 30 #include "wx/utils.h"
2bda0e17
KB
31#endif
32
a5c46848 33#include "wx/dynlib.h"
57bd4c60
WS
34#include "wx/file.h"
35#include "wx/wfstream.h"
41286812 36
2bda0e17 37// Windows headers
4676948b
JS
38#ifdef __WXWINCE__
39#include "wx/msw/private.h"
40#include <winbase.h>
41#include <winreg.h>
42#endif
43
2bda0e17
KB
44// other std headers
45#include <stdlib.h> // for _MAX_PATH
46
47#ifndef _MAX_PATH
225fe9d6 48 #define _MAX_PATH 512
2bda0e17
KB
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;
9b386eca 57typedef BYTE* RegBinary;
2bda0e17 58
0bb22291
VZ
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
21b5902b
VZ
71#ifndef KEY_WOW64_64KEY
72 #define KEY_WOW64_64KEY 0x0100
73#endif
74
2bda0e17
KB
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;
837e5743
OK
84 const wxChar *szName;
85 const wxChar *szShortName;
2bda0e17 86}
23f681ec
VZ
87aStdKeys[] =
88{
223d09f6 89 { HKEY_CLASSES_ROOT, wxT("HKEY_CLASSES_ROOT"), wxT("HKCR") },
223d09f6
KB
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") },
223d09f6 94 { HKEY_CURRENT_CONFIG, wxT("HKEY_CURRENT_CONFIG"), wxT("HKCC") },
223d09f6 95 { HKEY_DYN_DATA, wxT("HKEY_DYN_DATA"), wxT("HKDD") }, // short name?
2bda0e17
KB
96};
97
98// the registry name separator (perhaps one day MS will change it to '/' ;-)
223d09f6 99#define REG_SEPARATOR wxT('\\')
2bda0e17 100
c86f1403
VZ
101// useful for Windows programmers: makes somewhat more clear all these zeroes
102// being passed to Windows APIs
007007c5 103#define RESERVED (0)
c86f1403 104
2bda0e17
KB
105// ----------------------------------------------------------------------------
106// macros
107// ----------------------------------------------------------------------------
807a903e
VZ
108
109// const_cast<> is not yet supported by all compilers
2bda0e17
KB
110#define CONST_CAST ((wxRegKey *)this)->
111
807a903e
VZ
112// and neither is mutable which m_dwLastError should be
113#define m_dwLastError CONST_CAST m_dwLastError
2bda0e17
KB
114
115// ----------------------------------------------------------------------------
116// non member functions
117// ----------------------------------------------------------------------------
118
0b1c5a6c 119// removes the trailing backslash from the string if it has one
ca2261d3 120static inline void RemoveTrailingSeparator(wxString& str);
0b1c5a6c 121
4d08943e 122// returns true if given registry key exists
a5c46848
VZ
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);
2bda0e17 136
d38f70b2
VS
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);
2bda0e17
KB
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
23f681ec 157// it would require casts in user code.
837e5743 158const wxChar *wxRegKey::GetStdKeyName(size_t key)
2bda0e17
KB
159{
160 // return empty string if key is invalid
fda7962d 161 wxCHECK_MSG( key < nStdKeys, wxEmptyString, wxT("invalid key in wxRegKey::GetStdKeyName") );
2bda0e17
KB
162
163 return aStdKeys[key].szName;
164}
165
837e5743 166const wxChar *wxRegKey::GetStdKeyShortName(size_t key)
2bda0e17
KB
167{
168 // return empty string if key is invalid
fda7962d 169 wxCHECK( key < nStdKeys, wxEmptyString );
2bda0e17
KB
170
171 return aStdKeys[key].szShortName;
172}
173
174wxRegKey::StdKey wxRegKey::ExtractKeyName(wxString& strKey)
175{
b32719cc 176 wxString strRoot = strKey.BeforeFirst(REG_SEPARATOR);
2bda0e17 177
c86f1403 178 size_t ui;
2bda0e17 179 for ( ui = 0; ui < nStdKeys; ui++ ) {
23f681ec 180 if ( strRoot.CmpNoCase(aStdKeys[ui].szName) == 0 ||
2bda0e17 181 strRoot.CmpNoCase(aStdKeys[ui].szShortName) == 0 ) {
2bda0e17
KB
182 break;
183 }
184 }
185
186 if ( ui == nStdKeys ) {
223d09f6 187 wxFAIL_MSG(wxT("invalid key prefix in wxRegKey::ExtractKeyName."));
2bda0e17 188
aa9bfc2a 189 ui = HKCR;
2bda0e17
KB
190 }
191 else {
192 strKey = strKey.After(REG_SEPARATOR);
532d575b 193 if ( !strKey.empty() && strKey.Last() == REG_SEPARATOR )
2bda0e17
KB
194 strKey.Truncate(strKey.Len() - 1);
195 }
196
aa9bfc2a 197 return (StdKey)ui;
2bda0e17
KB
198}
199
fd6c844b 200wxRegKey::StdKey wxRegKey::GetStdKeyFromHkey(WXHKEY hkey)
2bda0e17 201{
c86f1403 202 for ( size_t ui = 0; ui < nStdKeys; ui++ ) {
aa9bfc2a 203 if ( aStdKeys[ui].hkey == (HKEY)hkey )
2bda0e17
KB
204 return (StdKey)ui;
205 }
23f681ec 206
223d09f6 207 wxFAIL_MSG(wxT("non root hkey passed to wxRegKey::GetStdKeyFromHkey."));
2bda0e17
KB
208
209 return HKCR;
210}
211
212// ----------------------------------------------------------------------------
213// ctors and dtor
214// ----------------------------------------------------------------------------
215
a5c46848 216wxRegKey::wxRegKey(WOW64ViewMode viewMode) : m_viewMode(viewMode)
2bda0e17 217{
fd6c844b 218 m_hRootKey = (WXHKEY) aStdKeys[HKCR].hkey;
807a903e
VZ
219
220 Init();
2bda0e17
KB
221}
222
a5c46848
VZ
223wxRegKey::wxRegKey(const wxString& strKey, WOW64ViewMode viewMode)
224 : m_strKey(strKey), m_viewMode(viewMode)
2bda0e17 225{
fd6c844b 226 m_hRootKey = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey;
807a903e
VZ
227
228 Init();
2bda0e17
KB
229}
230
231// parent is a predefined (and preopened) key
a5c46848
VZ
232wxRegKey::wxRegKey(StdKey keyParent,
233 const wxString& strKey,
234 WOW64ViewMode viewMode)
235 : m_strKey(strKey), m_viewMode(viewMode)
2bda0e17 236{
0b1c5a6c 237 RemoveTrailingSeparator(m_strKey);
fd6c844b 238 m_hRootKey = (WXHKEY) aStdKeys[keyParent].hkey;
807a903e
VZ
239
240 Init();
2bda0e17
KB
241}
242
243// parent is a normal regkey
244wxRegKey::wxRegKey(const wxRegKey& keyParent, const wxString& strKey)
a5c46848 245 : m_strKey(keyParent.m_strKey), m_viewMode(keyParent.GetView())
2bda0e17
KB
246{
247 // combine our name with parent's to get the full name
532d575b
WS
248 if ( !m_strKey.empty() &&
249 (strKey.empty() || strKey[0] != REG_SEPARATOR) ) {
32c66ea2
VZ
250 m_strKey += REG_SEPARATOR;
251 }
2bda0e17
KB
252
253 m_strKey += strKey;
0b1c5a6c 254 RemoveTrailingSeparator(m_strKey);
2bda0e17
KB
255
256 m_hRootKey = keyParent.m_hRootKey;
807a903e
VZ
257
258 Init();
2bda0e17
KB
259}
260
261// dtor closes the key releasing system resource
262wxRegKey::~wxRegKey()
263{
264 Close();
265}
266
0b1c5a6c
VZ
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;
fd6c844b 277 m_hRootKey = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey;
0b1c5a6c
VZ
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);
fd6c844b 287 m_hRootKey = (WXHKEY) aStdKeys[keyParent].hkey;
0b1c5a6c
VZ
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
807a903e
VZ
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;
532d575b 304 if ( !strKey.empty() && strKey[0] != REG_SEPARATOR )
0b1c5a6c 305 m_strKey += REG_SEPARATOR;
02569ba8 306 m_strKey += strKey;
0b1c5a6c
VZ
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
fd6c844b 314void wxRegKey::SetHkey(WXHKEY hKey)
0b1c5a6c
VZ
315{
316 Close();
317
318 m_hKey = hKey;
24aae88a
VZ
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;
0b1c5a6c
VZ
331}
332
2bda0e17
KB
333// ----------------------------------------------------------------------------
334// info about the key
335// ----------------------------------------------------------------------------
336
4d08943e 337// returns true if the key exists
2bda0e17
KB
338bool wxRegKey::Exists() const
339{
340 // opened key has to exist, try to open it if not done yet
a5c46848
VZ
341 return IsOpened()
342 ? true
343 : KeyExists(m_hRootKey, m_strKey, m_viewMode);
2bda0e17
KB
344}
345
346// returns the full name of the key (prefix is abbreviated if bShortPrefix)
347wxString wxRegKey::GetName(bool bShortPrefix) const
348{
333b7dac 349 StdKey key = GetStdKeyFromHkey((WXHKEY) m_hRootKey);
23f681ec 350 wxString str = bShortPrefix ? aStdKeys[key].szShortName
2bda0e17 351 : aStdKeys[key].szName;
532d575b 352 if ( !m_strKey.empty() )
9a83f860 353 str << wxT("\\") << m_strKey;
2bda0e17
KB
354
355 return str;
356}
357
23f681ec
VZ
358bool wxRegKey::GetKeyInfo(size_t *pnSubKeys,
359 size_t *pnMaxKeyLen,
360 size_t *pnValues,
361 size_t *pnMaxValueLen) const
02569ba8 362{
23f681ec 363 // old gcc headers incorrectly prototype RegQueryInfoKey()
ae090fdb 364#if defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__)
23f681ec
VZ
365 #define REG_PARAM (size_t *)
366#else
367 #define REG_PARAM (LPDWORD)
368#endif
369
6dfec4b8 370 // it might be unexpected to some that this function doesn't open the key
9a83f860 371 wxASSERT_MSG( IsOpened(), wxT("key should be opened in GetKeyInfo") );
6dfec4b8 372
02569ba8
VZ
373 m_dwLastError = ::RegQueryInfoKey
374 (
fd6c844b 375 (HKEY) m_hKey,
02569ba8
VZ
376 NULL, // class name
377 NULL, // (ptr to) size of class name buffer
378 RESERVED,
23f681ec 379 REG_PARAM
02569ba8 380 pnSubKeys, // [out] number of subkeys
23f681ec 381 REG_PARAM
02569ba8
VZ
382 pnMaxKeyLen, // [out] max length of a subkey name
383 NULL, // longest subkey class name
23f681ec 384 REG_PARAM
02569ba8 385 pnValues, // [out] number of values
23f681ec 386 REG_PARAM
02569ba8
VZ
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
23f681ec
VZ
393#undef REG_PARAM
394
02569ba8 395 if ( m_dwLastError != ERROR_SUCCESS ) {
23f681ec 396 wxLogSysError(m_dwLastError, _("Can't get info about registry key '%s'"),
02569ba8 397 GetName().c_str());
4d08943e 398 return false;
02569ba8 399 }
6dfec4b8 400
4d08943e 401 return true;
02569ba8
VZ
402}
403
2bda0e17
KB
404// ----------------------------------------------------------------------------
405// operations
406// ----------------------------------------------------------------------------
407
408// opens key (it's not an error to call Open() on an already opened key)
bee96abf 409bool wxRegKey::Open(AccessMode mode)
2bda0e17 410{
8a8c41dd 411 if ( IsOpened() )
fb5e0dcf
VZ
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 }
8a8c41dd
VZ
419
420 HKEY tmpKey;
421 m_dwLastError = ::RegOpenKeyEx
422 (
423 (HKEY) m_hRootKey,
dc874fb4 424 m_strKey.t_str(),
8a8c41dd 425 RESERVED,
a5c46848 426 GetMSWAccessFlags(mode, m_viewMode),
8a8c41dd
VZ
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());
4d08943e 434 return false;
8a8c41dd 435 }
2bda0e17 436
fd6c844b 437 m_hKey = (WXHKEY) tmpKey;
fb5e0dcf
VZ
438 m_mode = mode;
439
4d08943e 440 return true;
2bda0e17
KB
441}
442
443// creates key, failing if it exists and !bOkIfExists
444bool wxRegKey::Create(bool bOkIfExists)
445{
446 // check for existence only if asked (i.e. order is important!)
8a8c41dd 447 if ( !bOkIfExists && Exists() )
4d08943e 448 return false;
2bda0e17
KB
449
450 if ( IsOpened() )
4d08943e 451 return true;
2bda0e17 452
fd6c844b 453 HKEY tmpKey;
4676948b 454 DWORD disposition;
a5c46848
VZ
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
4676948b
JS
462 &tmpKey,
463 &disposition);
a5c46848 464
2bda0e17 465 if ( m_dwLastError != ERROR_SUCCESS ) {
23f681ec 466 wxLogSysError(m_dwLastError, _("Can't create registry key '%s'"),
2bda0e17 467 GetName().c_str());
4d08943e 468 return false;
2bda0e17
KB
469 }
470 else
fd6c844b
JS
471 {
472 m_hKey = (WXHKEY) tmpKey;
4d08943e 473 return true;
fd6c844b 474 }
2bda0e17
KB
475}
476
0b1c5a6c
VZ
477// close the key, it's not an error to call it when not opened
478bool wxRegKey::Close()
479{
480 if ( IsOpened() ) {
fd6c844b 481 m_dwLastError = RegCloseKey((HKEY) m_hKey);
807a903e
VZ
482 m_hKey = 0;
483
0b1c5a6c 484 if ( m_dwLastError != ERROR_SUCCESS ) {
23f681ec 485 wxLogSysError(m_dwLastError, _("Can't close registry key '%s'"),
0b1c5a6c
VZ
486 GetName().c_str());
487
4d08943e 488 return false;
0b1c5a6c 489 }
0b1c5a6c
VZ
490 }
491
4d08943e 492 return true;
0b1c5a6c
VZ
493}
494
d38f70b2
VS
495bool
496wxRegKey::RenameValue(const wxString& szValueOld, const wxString& szValueNew)
23f681ec 497{
4d08943e 498 bool ok = true;
23f681ec
VZ
499 if ( HasValue(szValueNew) ) {
500 wxLogError(_("Registry value '%s' already exists."), szValueNew);
501
4d08943e 502 ok = false;
23f681ec
VZ
503 }
504
225fe9d6
VZ
505 if ( !ok ||
506 !CopyValue(szValueOld, *this, szValueNew) ||
507 !DeleteValue(szValueOld) ) {
23f681ec
VZ
508 wxLogError(_("Failed to rename registry value '%s' to '%s'."),
509 szValueOld, szValueNew);
510
4d08943e 511 return false;
23f681ec
VZ
512 }
513
4d08943e 514 return true;
23f681ec
VZ
515}
516
d38f70b2 517bool wxRegKey::CopyValue(const wxString& szValue,
23f681ec 518 wxRegKey& keyDst,
d38f70b2 519 const wxString& szValueNew)
23f681ec 520{
d38f70b2
VS
521 wxString valueNew(szValueNew);
522 if ( valueNew.empty() ) {
5af3f0ef 523 // by default, use the same name
d38f70b2 524 valueNew = szValue;
5af3f0ef
VZ
525 }
526
23f681ec
VZ
527 switch ( GetValueType(szValue) ) {
528 case Type_String:
529 {
530 wxString strVal;
531 return QueryValue(szValue, strVal) &&
d38f70b2 532 keyDst.SetValue(valueNew, strVal);
23f681ec
VZ
533 }
534
535 case Type_Dword:
536 /* case Type_Dword_little_endian: == Type_Dword */
537 {
538 long dwVal;
539 return QueryValue(szValue, &dwVal) &&
d38f70b2 540 keyDst.SetValue(valueNew, dwVal);
23f681ec
VZ
541 }
542
9b386eca 543 case Type_Binary:
4d08943e
WS
544 {
545 wxMemoryBuffer buf;
546 return QueryValue(szValue,buf) &&
d38f70b2 547 keyDst.SetValue(valueNew,buf);
4d08943e 548 }
20d8c319 549
23f681ec
VZ
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)
23f681ec
VZ
554 case Type_None:
555 case Type_Expand_String:
23f681ec
VZ
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:
23f681ec
VZ
562 default:
563 wxLogError(_("Can't copy values of unsupported type %d."),
564 GetValueType(szValue));
4d08943e 565 return false;
23f681ec
VZ
566 }
567}
568
d38f70b2 569bool wxRegKey::Rename(const wxString& szNewName)
225fe9d6 570{
9a83f860 571 wxCHECK_MSG( !m_strKey.empty(), false, wxT("registry hives can't be renamed") );
225fe9d6
VZ
572
573 if ( !Exists() ) {
574 wxLogError(_("Registry key '%s' does not exist, cannot rename it."),
575 GetFullName(this));
576
4d08943e 577 return false;
225fe9d6
VZ
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);
532d575b 589 if ( !strKey.empty() ) {
225fe9d6
VZ
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
4d08943e 603 bool ok = keyDst.Create(false /* fail if alredy exists */);
225fe9d6
VZ
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
d38f70b2 624bool wxRegKey::Copy(const wxString& szNewName)
23f681ec
VZ
625{
626 // create the new key first
225fe9d6 627 wxRegKey keyDst(szNewName);
4d08943e 628 bool ok = keyDst.Create(false /* fail if alredy exists */);
23f681ec
VZ
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
641bool wxRegKey::Copy(wxRegKey& keyDst)
642{
4d08943e 643 bool ok = true;
23f681ec
VZ
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;
d38f70b2 653 ok = key.Copy(keyName);
23f681ec
VZ
654
655 if ( ok )
656 bCont = GetNextKey(strKey, lIndex);
4d08943e
WS
657 else
658 wxLogError(_("Failed to copy the registry subkey '%s' to '%s'."),
835ab90d 659 GetFullName(&key), keyName.c_str());
4d08943e 660
23f681ec
VZ
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 ) {
835ab90d
VZ
680 wxLogError(_("Failed to copy the contents of registry key '%s' to '%s'."),
681 GetFullName(this), GetFullName(&keyDst));
23f681ec
VZ
682 }
683
684 return ok;
685}
686
0b1c5a6c
VZ
687// ----------------------------------------------------------------------------
688// delete keys/values
689// ----------------------------------------------------------------------------
2bda0e17
KB
690bool wxRegKey::DeleteSelf()
691{
0b1c5a6c
VZ
692 {
693 wxLogNull nolog;
694 if ( !Open() ) {
695 // it already doesn't exist - ok!
4d08943e 696 return true;
0b1c5a6c
VZ
697 }
698 }
699
90186e52
VZ
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)
532d575b 703 if ( m_strKey.empty() ||
3cc487d1
VZ
704 ((m_hRootKey != (WXHKEY) aStdKeys[HKCR].hkey) &&
705 (m_strKey.Find(REG_SEPARATOR) == wxNOT_FOUND)) ) {
835ab90d
VZ
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));
90186e52 708
4d08943e 709 return false;
90186e52
VZ
710 }
711
0b1c5a6c
VZ
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;
2bda0e17
KB
715
716 wxString strKey;
717 long lIndex;
718 bool bCont = GetFirstKey(strKey, lIndex);
719 while ( bCont ) {
0b1c5a6c 720 astrSubkeys.Add(strKey);
2bda0e17
KB
721
722 bCont = GetNextKey(strKey, lIndex);
723 }
724
c86f1403
VZ
725 size_t nKeyCount = astrSubkeys.Count();
726 for ( size_t nKey = 0; nKey < nKeyCount; nKey++ ) {
0b1c5a6c
VZ
727 wxRegKey key(*this, astrSubkeys[nKey]);
728 if ( !key.DeleteSelf() )
4d08943e 729 return false;
0b1c5a6c
VZ
730 }
731
732 // now delete this key itself
2bda0e17
KB
733 Close();
734
86a7257f 735 // deleting a key which doesn't exist is not considered an error
a5c46848
VZ
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
86a7257f 754 if ( m_dwLastError != ERROR_SUCCESS &&
863e83fa 755 m_dwLastError != ERROR_FILE_NOT_FOUND ) {
23f681ec 756 wxLogSysError(m_dwLastError, _("Can't delete key '%s'"),
02569ba8 757 GetName().c_str());
4d08943e 758 return false;
2bda0e17
KB
759 }
760
4d08943e 761 return true;
2bda0e17
KB
762}
763
d38f70b2 764bool wxRegKey::DeleteKey(const wxString& szKey)
2bda0e17
KB
765{
766 if ( !Open() )
4d08943e 767 return false;
2bda0e17
KB
768
769 wxRegKey key(*this, szKey);
770 return key.DeleteSelf();
771}
772
d38f70b2 773bool wxRegKey::DeleteValue(const wxString& szValue)
2bda0e17 774{
92218ce6
WS
775 if ( !Open() )
776 return false;
2bda0e17 777
d38f70b2 778 m_dwLastError = RegDeleteValue((HKEY) m_hKey, RegValueStr(szValue));
886dd7d2
VZ
779
780 // deleting a value which doesn't exist is not considered an error
781 if ( (m_dwLastError != ERROR_SUCCESS) &&
92218ce6
WS
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;
2bda0e17 787 }
2bda0e17 788
92218ce6 789 return true;
2bda0e17
KB
790}
791
792// ----------------------------------------------------------------------------
793// access to values and subkeys
794// ----------------------------------------------------------------------------
795
4d08943e 796// return true if value exists
d38f70b2 797bool wxRegKey::HasValue(const wxString& szValue) const
0b1c5a6c 798{
92218ce6
WS
799 // this function should be silent, so suppress possible messages from Open()
800 wxLogNull nolog;
23f681ec 801
d305f9df 802 if ( !CONST_CAST Open(Read) )
4d08943e 803 return false;
f6bcfd97
BP
804
805 LONG dwRet = ::RegQueryValueEx((HKEY) m_hKey,
d38f70b2 806 RegValueStr(szValue),
f6bcfd97
BP
807 RESERVED,
808 NULL, NULL, NULL);
809 return dwRet == ERROR_SUCCESS;
0b1c5a6c
VZ
810}
811
4d08943e 812// returns true if this key has any values
92049cd4
VZ
813bool wxRegKey::HasValues() const
814{
815 // suppress possible messages from GetFirstValue()
816 wxLogNull nolog;
23f681ec 817
92049cd4
VZ
818 // just call GetFirstValue with dummy parameters
819 wxString str;
820 long l;
821 return CONST_CAST GetFirstValue(str, l);
822}
823
4d08943e 824// returns true if this key has any subkeys
2bda0e17
KB
825bool wxRegKey::HasSubkeys() const
826{
c19a8a9a
VZ
827 // suppress possible messages from GetFirstKey()
828 wxLogNull nolog;
23f681ec 829
2bda0e17
KB
830 // just call GetFirstKey with dummy parameters
831 wxString str;
832 long l;
833 return CONST_CAST GetFirstKey(str, l);
834}
835
4d08943e 836// returns true if given subkey exists
d38f70b2 837bool wxRegKey::HasSubKey(const wxString& szKey) const
2bda0e17 838{
c19a8a9a
VZ
839 // this function should be silent, so suppress possible messages from Open()
840 wxLogNull nolog;
23f681ec 841
d305f9df 842 if ( !CONST_CAST Open(Read) )
4d08943e 843 return false;
f6bcfd97 844
a5c46848 845 return KeyExists(m_hKey, szKey, m_viewMode);
2bda0e17
KB
846}
847
d38f70b2 848wxRegKey::ValueType wxRegKey::GetValueType(const wxString& szValue) const
2bda0e17 849{
d305f9df 850 if ( ! CONST_CAST Open(Read) )
2bda0e17
KB
851 return Type_None;
852
853 DWORD dwType;
d38f70b2 854 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, RegValueStr(szValue), RESERVED,
2bda0e17
KB
855 &dwType, NULL, NULL);
856 if ( m_dwLastError != ERROR_SUCCESS ) {
23f681ec 857 wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"),
2bda0e17
KB
858 GetName().c_str());
859 return Type_None;
860 }
861
862 return (ValueType)dwType;
2bda0e17
KB
863}
864
d38f70b2 865bool wxRegKey::SetValue(const wxString& szValue, long lValue)
2bda0e17
KB
866{
867 if ( CONST_CAST Open() ) {
d38f70b2
VS
868 m_dwLastError = RegSetValueEx((HKEY) m_hKey, RegValueStr(szValue),
869 (DWORD) RESERVED, REG_DWORD,
2bda0e17
KB
870 (RegString)&lValue, sizeof(lValue));
871 if ( m_dwLastError == ERROR_SUCCESS )
4d08943e 872 return true;
2bda0e17
KB
873 }
874
23f681ec 875 wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
2bda0e17 876 GetFullName(this, szValue));
4d08943e 877 return false;
2bda0e17
KB
878}
879
d38f70b2 880bool wxRegKey::QueryValue(const wxString& szValue, long *plValue) const
2bda0e17 881{
d305f9df 882 if ( CONST_CAST Open(Read) ) {
2bda0e17
KB
883 DWORD dwType, dwSize = sizeof(DWORD);
884 RegString pBuf = (RegString)plValue;
d38f70b2
VS
885 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, RegValueStr(szValue),
886 RESERVED,
2bda0e17
KB
887 &dwType, pBuf, &dwSize);
888 if ( m_dwLastError != ERROR_SUCCESS ) {
23f681ec 889 wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"),
2bda0e17 890 GetName().c_str());
4d08943e 891 return false;
2bda0e17
KB
892 }
893 else {
894 // check that we read the value of right type
23f681ec 895 wxASSERT_MSG( IsNumericValue(szValue),
223d09f6 896 wxT("Type mismatch in wxRegKey::QueryValue().") );
2bda0e17 897
4d08943e 898 return true;
2bda0e17
KB
899 }
900 }
901 else
4d08943e 902 return false;
2bda0e17
KB
903}
904
d38f70b2 905bool wxRegKey::SetValue(const wxString& szValue, const wxMemoryBuffer& buffer)
9b386eca
RG
906{
907#ifdef __TWIN32__
908 wxFAIL_MSG("RegSetValueEx not implemented by TWIN32");
4d08943e 909 return false;
9b386eca
RG
910#else
911 if ( CONST_CAST Open() ) {
d38f70b2
VS
912 m_dwLastError = RegSetValueEx((HKEY) m_hKey, RegValueStr(szValue),
913 (DWORD) RESERVED, REG_BINARY,
9b386eca
RG
914 (RegBinary)buffer.GetData(),buffer.GetDataLen());
915 if ( m_dwLastError == ERROR_SUCCESS )
4d08943e 916 return true;
9b386eca
RG
917 }
918
919 wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
920 GetFullName(this, szValue));
4d08943e 921 return false;
9b386eca
RG
922#endif
923}
924
d38f70b2 925bool wxRegKey::QueryValue(const wxString& szValue, wxMemoryBuffer& buffer) const
9b386eca 926{
873aefb8 927 if ( CONST_CAST Open(Read) ) {
9b386eca
RG
928 // first get the type and size of the data
929 DWORD dwType, dwSize;
d38f70b2
VS
930 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, RegValueStr(szValue),
931 RESERVED,
932 &dwType, NULL, &dwSize);
4d08943e 933
9b386eca
RG
934 if ( m_dwLastError == ERROR_SUCCESS ) {
935 if ( dwSize ) {
936 const RegBinary pBuf = (RegBinary)buffer.GetWriteBuf(dwSize);
937 m_dwLastError = RegQueryValueEx((HKEY) m_hKey,
d38f70b2 938 RegValueStr(szValue),
9b386eca
RG
939 RESERVED,
940 &dwType,
941 pBuf,
942 &dwSize);
943 buffer.UngetWriteBuf(dwSize);
4d08943e
WS
944 } else {
945 buffer.SetDataLen(0);
9b386eca
RG
946 }
947 }
948
4d08943e 949
9b386eca
RG
950 if ( m_dwLastError != ERROR_SUCCESS ) {
951 wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"),
952 GetName().c_str());
4d08943e 953 return false;
9b386eca 954 }
4d08943e 955 return true;
9b386eca 956 }
4d08943e 957 return false;
9b386eca
RG
958}
959
960
961
d38f70b2 962bool wxRegKey::QueryValue(const wxString& szValue,
6dfec4b8 963 wxString& strValue,
0c0d1521 964 bool WXUNUSED_IN_WINCE(raw)) const
2bda0e17 965{
0c0d1521
WS
966 if ( CONST_CAST Open(Read) )
967 {
6dfec4b8 968
0c0d1521 969 // first get the type and size of the data
aea25ac5 970 DWORD dwType=REG_NONE, dwSize=0;
d38f70b2
VS
971 m_dwLastError = RegQueryValueEx((HKEY) m_hKey,
972 RegValueStr(szValue),
973 RESERVED,
0c0d1521
WS
974 &dwType, NULL, &dwSize);
975 if ( m_dwLastError == ERROR_SUCCESS )
976 {
977 if ( !dwSize )
6dfec4b8 978 {
0c0d1521
WS
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,
d38f70b2 986 RegValueStr(szValue),
0c0d1521
WS
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 )
6dfec4b8 995 {
dc874fb4 996 DWORD dwExpSize = ::ExpandEnvironmentStrings(strValue.t_str(), NULL, 0);
0c0d1521
WS
997 bool ok = dwExpSize != 0;
998 if ( ok )
999 {
1000 wxString strExpValue;
dc874fb4 1001 ok = ::ExpandEnvironmentStrings(strValue.t_str(),
0c0d1521
WS
1002 wxStringBuffer(strExpValue, dwExpSize),
1003 dwExpSize
1004 ) != 0;
1005 strValue = strExpValue;
1006 }
1007
1008 if ( !ok )
1009 {
9a83f860 1010 wxLogLastError(wxT("ExpandEnvironmentStrings"));
0c0d1521 1011 }
6dfec4b8 1012 }
4676948b 1013#endif
0c0d1521
WS
1014 // __WXWINCE__
1015 }
23f681ec 1016
0c0d1521
WS
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().") );
2bda0e17 1022
0c0d1521
WS
1023 return true;
1024 }
2bda0e17 1025 }
0c0d1521 1026 }
2bda0e17 1027
0c0d1521
WS
1028 wxLogSysError(m_dwLastError, _("Can't read value of '%s'"),
1029 GetFullName(this, szValue));
1030 return false;
2bda0e17
KB
1031}
1032
d38f70b2 1033bool wxRegKey::SetValue(const wxString& szValue, const wxString& strValue)
2bda0e17
KB
1034{
1035 if ( CONST_CAST Open() ) {
d38f70b2
VS
1036 m_dwLastError = RegSetValueEx((HKEY) m_hKey,
1037 RegValueStr(szValue),
1038 (DWORD) RESERVED, REG_SZ,
a5c46848 1039 (RegString)strValue.t_str(),
f6bcfd97 1040 (strValue.Len() + 1)*sizeof(wxChar));
2bda0e17 1041 if ( m_dwLastError == ERROR_SUCCESS )
4d08943e 1042 return true;
2bda0e17
KB
1043 }
1044
23f681ec 1045 wxLogSysError(m_dwLastError, _("Can't set value of '%s'"),
2bda0e17 1046 GetFullName(this, szValue));
4d08943e 1047 return false;
2bda0e17
KB
1048}
1049
50e42404 1050wxString wxRegKey::QueryDefaultValue() const
2bda0e17
KB
1051{
1052 wxString str;
d38f70b2 1053 QueryValue(wxEmptyString, str, false);
2bda0e17
KB
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
2bda0e17
KB
1063bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex)
1064{
d305f9df 1065 if ( !Open(Read) )
4d08943e 1066 return false;
2bda0e17
KB
1067
1068 lIndex = 0;
0b1c5a6c 1069 return GetNextValue(strValueName, lIndex);
2bda0e17
KB
1070}
1071
1072bool wxRegKey::GetNextValue(wxString& strValueName, long& lIndex) const
1073{
1074 wxASSERT( IsOpened() );
2bda0e17 1075
0b1c5a6c
VZ
1076 // are we already at the end of enumeration?
1077 if ( lIndex == -1 )
4d08943e 1078 return false;
2bda0e17 1079
837e5743 1080 wxChar szValueName[1024]; // @@ use RegQueryInfoKey...
0b1c5a6c 1081 DWORD dwValueLen = WXSIZEOF(szValueName);
2bda0e17 1082
92049cd4 1083 m_dwLastError = RegEnumValue((HKEY) m_hKey, lIndex++,
0b1c5a6c 1084 szValueName, &dwValueLen,
23f681ec
VZ
1085 RESERVED,
1086 NULL, // [out] type
0b1c5a6c
VZ
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 {
23f681ec 1096 wxLogSysError(m_dwLastError, _("Can't enumerate values of key '%s'"),
0b1c5a6c
VZ
1097 GetName().c_str());
1098 }
1099
4d08943e 1100 return false;
2bda0e17
KB
1101 }
1102
0b1c5a6c 1103 strValueName = szValueName;
0b1c5a6c 1104
4d08943e 1105 return true;
2bda0e17 1106}
2bda0e17
KB
1107
1108bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex)
1109{
d305f9df 1110 if ( !Open(Read) )
4d08943e 1111 return false;
2bda0e17 1112
2bda0e17 1113 lIndex = 0;
0b1c5a6c 1114 return GetNextKey(strKeyName, lIndex);
2bda0e17
KB
1115}
1116
1117bool wxRegKey::GetNextKey(wxString& strKeyName, long& lIndex) const
1118{
1119 wxASSERT( IsOpened() );
0b1c5a6c
VZ
1120
1121 // are we already at the end of enumeration?
1122 if ( lIndex == -1 )
4d08943e 1123 return false;
2bda0e17 1124
837e5743 1125 wxChar szKeyName[_MAX_PATH + 1];
4676948b
JS
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
fd6c844b 1132 m_dwLastError = RegEnumKey((HKEY) m_hKey, lIndex++, szKeyName, WXSIZEOF(szKeyName));
4676948b 1133#endif
2bda0e17
KB
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 {
23f681ec 1141 wxLogSysError(m_dwLastError, _("Can't enumerate subkeys of key '%s'"),
2bda0e17
KB
1142 GetName().c_str());
1143 }
1144
4d08943e 1145 return false;
2bda0e17
KB
1146 }
1147
1148 strKeyName = szKeyName;
4d08943e 1149 return true;
2bda0e17
KB
1150}
1151
4d08943e 1152// returns true if the value contains a number (else it's some string)
d38f70b2 1153bool wxRegKey::IsNumericValue(const wxString& szValue) const
4d08943e
WS
1154{
1155 ValueType type = GetValueType(szValue);
1156 switch ( type ) {
03ab016d 1157 case Type_Dword:
23f681ec 1158 /* case Type_Dword_little_endian: == Type_Dword */
03ab016d 1159 case Type_Dword_big_endian:
4d08943e 1160 return true;
03ab016d
JS
1161
1162 default:
4d08943e
WS
1163 return false;
1164 }
1165}
03ab016d 1166
20d8c319
VZ
1167// ----------------------------------------------------------------------------
1168// exporting registry keys to file
1169// ----------------------------------------------------------------------------
1170
532d575b
WS
1171#if wxUSE_STREAMS
1172
20d8c319
VZ
1173// helper functions for writing ASCII strings (even in Unicode build)
1174static inline bool WriteAsciiChar(wxOutputStream& ostr, char ch)
1175{
1176 ostr.PutC(ch);
1177 return ostr.IsOk();
1178}
1179
1180static 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
1186static inline bool WriteAsciiString(wxOutputStream& ostr, const char *p)
1187{
1188 return ostr.Write(p, strlen(p)).IsOk();
1189}
1190
1191static 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
11aac4ba 1197 ostr.Write(s.mb_str(), s.length());
20d8c319
VZ
1198#endif
1199
1200 return ostr.IsOk();
1201}
1202
532d575b
WS
1203#endif // wxUSE_STREAMS
1204
20d8c319
VZ
1205bool wxRegKey::Export(const wxString& filename) const
1206{
532d575b 1207#if wxUSE_FFILE && wxUSE_STREAMS
20d8c319
VZ
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
9a83f860 1215 wxFFileOutputStream ostr(filename, wxT("w"));
20d8c319
VZ
1216
1217 return ostr.Ok() && Export(ostr);
532d575b
WS
1218#else
1219 wxUnusedVar(filename);
1220 return false;
1221#endif
20d8c319
VZ
1222}
1223
532d575b 1224#if wxUSE_STREAMS
20d8c319
VZ
1225bool 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}
532d575b 1233#endif // wxUSE_STREAMS
20d8c319
VZ
1234
1235static
1236wxString
1237FormatAsHex(const void *data,
1238 size_t size,
1239 wxRegKey::ValueType type = wxRegKey::Type_Binary)
1240{
9a83f860 1241 wxString value(wxT("hex"));
20d8c319
VZ
1242
1243 // binary values use just "hex:" prefix while the other ones must indicate
1244 // the real type
1245 if ( type != wxRegKey::Type_Binary )
9a83f860
VZ
1246 value << wxT('(') << type << wxT(')');
1247 value << wxT(':');
20d8c319
VZ
1248
1249 // write all the rest as comma-separated bytes
1250 value.reserve(3*size + 10);
5c33522f 1251 const char * const p = static_cast<const char *>(data);
20d8c319
VZ
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 )
9a83f860 1258 value << wxT(',');
20d8c319 1259
9a83f860 1260 value << wxString::Format(wxT("%02x"), (unsigned char)p[n]);
20d8c319
VZ
1261 }
1262
1263 return value;
1264}
1265
1266static inline
1267wxString FormatAsHex(const wxString& value, wxRegKey::ValueType type)
1268{
1269 return FormatAsHex(value.c_str(), value.length() + 1, type);
1270}
1271
1272wxString 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);
9a83f860 1287 rhs = wxT('"');
20d8c319
VZ
1288
1289 // there can be no NULs here
1290 bool useHex = false;
d38f70b2
VS
1291 for ( wxString::const_iterator p = value.begin();
1292 p != value.end() && !useHex; ++p )
20d8c319 1293 {
d38f70b2 1294 switch ( (*p).GetValue() )
20d8c319 1295 {
9a83f860 1296 case wxT('\n'):
20d8c319
VZ
1297 // we can only represent this string in hex
1298 useHex = true;
1299 break;
1300
9a83f860
VZ
1301 case wxT('"'):
1302 case wxT('\\'):
20d8c319 1303 // escape special symbol
9a83f860 1304 rhs += wxT('\\');
20d8c319
VZ
1305 // fall through
1306
1307 default:
1308 rhs += *p;
1309 }
1310 }
1311
1312 if ( useHex )
1313 rhs = FormatAsHex(value, Type_String);
1314 else
9a83f860 1315 rhs += wxT('"');
20d8c319
VZ
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
9a83f860 1326 rhs.Printf(wxT("dword:%08x"), (unsigned int)value);
20d8c319
VZ
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
532d575b
WS
1365#if wxUSE_STREAMS
1366
20d8c319
VZ
1367bool 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
1403bool 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;
5c33522f 1418 wxRegKey& self = const_cast<wxRegKey&>(*this);
20d8c319
VZ
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
532d575b
WS
1446#endif // wxUSE_STREAMS
1447
2bda0e17 1448// ============================================================================
1880e452 1449// implementation of global private functions
2bda0e17 1450// ============================================================================
f6bcfd97 1451
a5c46848
VZ
1452bool KeyExists(WXHKEY hRootKey,
1453 const wxString& szKey,
1454 wxRegKey::WOW64ViewMode viewMode)
2bda0e17 1455{
8a8c41dd 1456 // don't close this key itself for the case of empty szKey!
d38f70b2 1457 if ( szKey.empty() )
4d08943e 1458 return true;
8a8c41dd
VZ
1459
1460 HKEY hkeyDummy;
1461 if ( ::RegOpenKeyEx
1462 (
1463 (HKEY)hRootKey,
dc874fb4 1464 szKey.t_str(),
8a8c41dd 1465 RESERVED,
a5c46848
VZ
1466 // we might not have enough rights for rw access
1467 GetMSWAccessFlags(wxRegKey::Read, viewMode),
8a8c41dd
VZ
1468 &hkeyDummy
1469 ) == ERROR_SUCCESS )
1470 {
1471 ::RegCloseKey(hkeyDummy);
1472
4d08943e 1473 return true;
8a8c41dd 1474 }
f6bcfd97 1475
4d08943e 1476 return false;
2bda0e17
KB
1477}
1478
a5c46848
VZ
1479long 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
1512long 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
d38f70b2 1522wxString GetFullName(const wxRegKey *pKey, const wxString& szValue)
2bda0e17 1523{
d38f70b2
VS
1524 wxString str(pKey->GetName());
1525 if ( !szValue.empty() )
1526 str << wxT("\\") << szValue;
1527
1528 return str;
1529}
2bda0e17 1530
d38f70b2
VS
1531wxString GetFullName(const wxRegKey *pKey)
1532{
1533 return pKey->GetName();
0b1c5a6c
VZ
1534}
1535
ca2261d3 1536inline void RemoveTrailingSeparator(wxString& str)
0b1c5a6c 1537{
532d575b 1538 if ( !str.empty() && str.Last() == REG_SEPARATOR )
0b1c5a6c
VZ
1539 str.Truncate(str.Len() - 1);
1540}
d38f70b2
VS
1541
1542inline const wxChar *RegValueStr(const wxString& szValue)
1543{
dc874fb4 1544 return szValue.empty() ? (const wxChar*)NULL : szValue.t_str();
d38f70b2 1545}
f77c0fe3
VZ
1546
1547#endif // wxUSE_REGKEY