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