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