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