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