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