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