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