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