]> git.saurik.com Git - wxWidgets.git/blob - src/msw/registry.cpp
c6d0142dc1fb940c9637b4a19935fcc8a4e3c3ad
[wxWidgets.git] / src / msw / registry.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: msw/registry.cpp
3 // Purpose: implementation of registry classes and functions
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 03.04.98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows license
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
15 // ============================================================================
16 // declarations
17 // ============================================================================
18
19 // ----------------------------------------------------------------------------
20 // headers
21 // ----------------------------------------------------------------------------
22
23 // for compilers that support precompilation, includes "wx.h".
24 #include "wx/wxprec.h"
25
26 #ifdef __BORLANDC__
27 #pragma hdrstop
28 #endif
29
30 // other wxWindows headers
31 #include "wx/string.h"
32 #include "wx/intl.h"
33 #include "wx/log.h"
34
35 // Windows headers
36 /*
37 #define STRICT
38 #define WIN32_LEAN_AND_MEAN
39 */
40
41 #include <windows.h>
42
43 // other std headers
44 #include <stdlib.h> // for _MAX_PATH
45
46 #ifndef _MAX_PATH
47 #define _MAX_PATH 512
48 #endif
49
50 // our header
51 #define HKEY_DEFINED // already defined in windows.h
52 #include "wx/msw/registry.h"
53
54 // some registry functions don't like signed chars
55 typedef unsigned char *RegString;
56
57 // ----------------------------------------------------------------------------
58 // constants
59 // ----------------------------------------------------------------------------
60
61 // the standard key names, short names and handles all bundled together for
62 // convenient access
63 static struct
64 {
65 HKEY hkey;
66 const char *szName;
67 const char *szShortName;
68 }
69 aStdKeys[] =
70 {
71 { HKEY_CLASSES_ROOT, "HKEY_CLASSES_ROOT", "HKCR" },
72 #ifdef __WIN32__
73 { HKEY_CURRENT_USER, "HKEY_CURRENT_USER", "HKCU" },
74 { HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE", "HKLM" },
75 { HKEY_USERS, "HKEY_USERS", "HKU" }, // short name?
76 { HKEY_PERFORMANCE_DATA, "HKEY_PERFORMANCE_DATA", "HKPD" },
77 #if WINVER >= 0x0400
78 { HKEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG", "HKCC" },
79 #ifndef __GNUWIN32__
80 { HKEY_DYN_DATA, "HKEY_DYN_DATA", "HKDD" }, // short name?
81 #endif //GNUWIN32
82 #endif //WINVER >= 4.0
83 #endif //WIN32
84 };
85
86 // the registry name separator (perhaps one day MS will change it to '/' ;-)
87 #define REG_SEPARATOR '\\'
88
89 // ----------------------------------------------------------------------------
90 // macros
91 // ----------------------------------------------------------------------------
92 // @ const_cast<> is not yet supported by all compilers
93 #define CONST_CAST ((wxRegKey *)this)->
94
95 #if !USE_MUTABLE
96 #define m_dwLastError CONST_CAST m_dwLastError
97 #endif
98
99 // ----------------------------------------------------------------------------
100 // non member functions
101 // ----------------------------------------------------------------------------
102
103 // removes the trailing backslash from the string if it has one
104 static inline void RemoveTrailingSeparator(wxString& str);
105
106 // returns TRUE if given registry key exists
107 static bool KeyExists(HKEY hRootKey, const char *szKey);
108
109 // combines value and key name (uses static buffer!)
110 static const char *GetFullName(const wxRegKey *pKey,
111 const char *szValue = NULL);
112
113 // ============================================================================
114 // implementation of wxRegKey class
115 // ============================================================================
116
117 // ----------------------------------------------------------------------------
118 // static functions and variables
119 // ----------------------------------------------------------------------------
120
121 const size_t wxRegKey::nStdKeys = WXSIZEOF(aStdKeys);
122
123 // @@ should take a `StdKey key', but as it's often going to be used in loops
124 // it would require casts in user code.
125 const char *wxRegKey::GetStdKeyName(uint key)
126 {
127 // return empty string if key is invalid
128 wxCHECK_MSG( key < nStdKeys, "", "invalid key in wxRegKey::GetStdKeyName" );
129
130 return aStdKeys[key].szName;
131 }
132
133 const char *wxRegKey::GetStdKeyShortName(uint key)
134 {
135 // return empty string if key is invalid
136 wxCHECK( key < nStdKeys, "" );
137
138 return aStdKeys[key].szShortName;
139 }
140
141 wxRegKey::StdKey wxRegKey::ExtractKeyName(wxString& strKey)
142 {
143 wxString strRoot = strKey.Left(REG_SEPARATOR);
144
145 HKEY hRootKey;
146 uint ui;
147 for ( ui = 0; ui < nStdKeys; ui++ ) {
148 if ( strRoot.CmpNoCase(aStdKeys[ui].szName) == 0 ||
149 strRoot.CmpNoCase(aStdKeys[ui].szShortName) == 0 ) {
150 hRootKey = aStdKeys[ui].hkey;
151 break;
152 }
153 }
154
155 if ( ui == nStdKeys ) {
156 wxFAIL_MSG("invalid key prefix in wxRegKey::ExtractKeyName.");
157
158 hRootKey = HKEY_CLASSES_ROOT;
159 }
160 else {
161 strKey = strKey.After(REG_SEPARATOR);
162 if ( !strKey.IsEmpty() && strKey.Last() == REG_SEPARATOR )
163 strKey.Truncate(strKey.Len() - 1);
164 }
165
166 return (wxRegKey::StdKey)(int)hRootKey;
167 }
168
169 wxRegKey::StdKey wxRegKey::GetStdKeyFromHkey(HKEY hkey)
170 {
171 for ( uint ui = 0; ui < nStdKeys; ui++ ) {
172 if ( aStdKeys[ui].hkey == hkey )
173 return (StdKey)ui;
174 }
175
176 wxFAIL_MSG("non root hkey passed to wxRegKey::GetStdKeyFromHkey.");
177
178 return HKCR;
179 }
180
181 // ----------------------------------------------------------------------------
182 // ctors and dtor
183 // ----------------------------------------------------------------------------
184
185 wxRegKey::wxRegKey()
186 {
187 m_hKey = 0;
188 m_hRootKey = aStdKeys[HKCR].hkey;
189 m_dwLastError = 0;
190 }
191
192 wxRegKey::wxRegKey(const wxString& strKey) : m_strKey(strKey)
193 {
194 m_hRootKey = aStdKeys[ExtractKeyName(m_strKey)].hkey;
195 m_hKey = NULL;
196 m_dwLastError = 0;
197 }
198
199 // parent is a predefined (and preopened) key
200 wxRegKey::wxRegKey(StdKey keyParent, const wxString& strKey) : m_strKey(strKey)
201 {
202 RemoveTrailingSeparator(m_strKey);
203 m_hRootKey = aStdKeys[keyParent].hkey;
204 m_hKey = NULL;
205 m_dwLastError = 0;
206 }
207
208 // parent is a normal regkey
209 wxRegKey::wxRegKey(const wxRegKey& keyParent, const wxString& strKey)
210 : m_strKey(keyParent.m_strKey)
211 {
212 // combine our name with parent's to get the full name
213 if ( !strKey.IsEmpty() && strKey[0] != REG_SEPARATOR )
214 m_strKey += REG_SEPARATOR;
215
216 m_strKey += strKey;
217 RemoveTrailingSeparator(m_strKey);
218
219 m_hRootKey = keyParent.m_hRootKey;
220 m_hKey = NULL;
221 m_dwLastError = 0;
222 }
223
224 // dtor closes the key releasing system resource
225 wxRegKey::~wxRegKey()
226 {
227 Close();
228 }
229
230 // ----------------------------------------------------------------------------
231 // change the key name/hkey
232 // ----------------------------------------------------------------------------
233
234 // set the full key name
235 void wxRegKey::SetName(const wxString& strKey)
236 {
237 Close();
238
239 m_strKey = strKey;
240 m_hRootKey = aStdKeys[ExtractKeyName(m_strKey)].hkey;
241 }
242
243 // the name is relative to the parent key
244 void wxRegKey::SetName(StdKey keyParent, const wxString& strKey)
245 {
246 Close();
247
248 m_strKey = strKey;
249 RemoveTrailingSeparator(m_strKey);
250 m_hRootKey = aStdKeys[keyParent].hkey;
251 }
252
253 // the name is relative to the parent key
254 void wxRegKey::SetName(const wxRegKey& keyParent, const wxString& strKey)
255 {
256 Close();
257
258 // combine our name with parent's to get the full name
259 m_strKey = strKey;
260 if ( !strKey.IsEmpty() && strKey[0] != REG_SEPARATOR )
261 m_strKey += REG_SEPARATOR;
262
263 RemoveTrailingSeparator(m_strKey);
264
265 m_hRootKey = keyParent.m_hRootKey;
266 }
267
268 // hKey should be opened and will be closed in wxRegKey dtor
269 void wxRegKey::SetHkey(HKEY hKey)
270 {
271 Close();
272
273 m_hKey = hKey;
274 }
275
276 // ----------------------------------------------------------------------------
277 // info about the key
278 // ----------------------------------------------------------------------------
279
280 // returns TRUE if the key exists
281 bool wxRegKey::Exists() const
282 {
283 // opened key has to exist, try to open it if not done yet
284 return IsOpened() ? TRUE : KeyExists(m_hRootKey, m_strKey);
285 }
286
287 // returns the full name of the key (prefix is abbreviated if bShortPrefix)
288 wxString wxRegKey::GetName(bool bShortPrefix) const
289 {
290 StdKey key = GetStdKeyFromHkey(m_hRootKey);
291 wxString str = bShortPrefix ? aStdKeys[key].szShortName
292 : aStdKeys[key].szName;
293 if ( !m_strKey.IsEmpty() )
294 str << "\\" << m_strKey;
295
296 return str;
297 }
298
299 // ----------------------------------------------------------------------------
300 // operations
301 // ----------------------------------------------------------------------------
302
303 // opens key (it's not an error to call Open() on an already opened key)
304 bool wxRegKey::Open()
305 {
306 if ( IsOpened() )
307 return TRUE;
308
309 m_dwLastError = RegOpenKey(m_hRootKey, m_strKey, &m_hKey);
310 if ( m_dwLastError != ERROR_SUCCESS ) {
311 wxLogSysError(m_dwLastError, "can't open registry key '%s'",
312 GetName().c_str());
313 return FALSE;
314 }
315 else
316 return TRUE;
317 }
318
319 // creates key, failing if it exists and !bOkIfExists
320 bool wxRegKey::Create(bool bOkIfExists)
321 {
322 // check for existence only if asked (i.e. order is important!)
323 if ( !bOkIfExists && Exists() ) {
324 return FALSE;
325 }
326
327 if ( IsOpened() )
328 return TRUE;
329
330 m_dwLastError = RegCreateKey(m_hRootKey, m_strKey, &m_hKey);
331 if ( m_dwLastError != ERROR_SUCCESS ) {
332 wxLogSysError(m_dwLastError, "can't create registry key '%s'",
333 GetName().c_str());
334 return FALSE;
335 }
336 else
337 return TRUE;
338 }
339
340 // close the key, it's not an error to call it when not opened
341 bool wxRegKey::Close()
342 {
343 if ( IsOpened() ) {
344 m_dwLastError = RegCloseKey(m_hKey);
345 if ( m_dwLastError != ERROR_SUCCESS ) {
346 wxLogSysError(m_dwLastError, "can't close registry key '%s'",
347 GetName().c_str());
348
349 m_hKey = 0;
350 return FALSE;
351 }
352 else {
353 m_hKey = 0;
354 }
355 }
356
357 return TRUE;
358 }
359
360 // ----------------------------------------------------------------------------
361 // delete keys/values
362 // ----------------------------------------------------------------------------
363 bool wxRegKey::DeleteSelf()
364 {
365 {
366 wxLogNull nolog;
367 if ( !Open() ) {
368 // it already doesn't exist - ok!
369 return TRUE;
370 }
371 }
372
373 // we can't delete keys while enumerating because it confuses GetNextKey, so
374 // we first save the key names and then delete them all
375 wxArrayString astrSubkeys;
376
377 wxString strKey;
378 long lIndex;
379 bool bCont = GetFirstKey(strKey, lIndex);
380 while ( bCont ) {
381 astrSubkeys.Add(strKey);
382
383 bCont = GetNextKey(strKey, lIndex);
384 }
385
386 uint nKeyCount = astrSubkeys.Count();
387 for ( uint nKey = 0; nKey < nKeyCount; nKey++ ) {
388 wxRegKey key(*this, astrSubkeys[nKey]);
389 if ( !key.DeleteSelf() )
390 return FALSE;
391 }
392
393 // now delete this key itself
394 Close();
395
396 m_dwLastError = RegDeleteKey(m_hRootKey, m_strKey);
397 if ( m_dwLastError != ERROR_SUCCESS ) {
398 wxLogSysError(m_dwLastError, "can't delete key '%s'", GetName().c_str());
399 return FALSE;
400 }
401
402 return TRUE;
403 }
404
405 bool wxRegKey::DeleteKey(const char *szKey)
406 {
407 if ( !Open() )
408 return FALSE;
409
410 wxRegKey key(*this, szKey);
411 return key.DeleteSelf();
412 }
413
414 bool wxRegKey::DeleteValue(const char *szValue)
415 {
416 if ( !Open() )
417 return FALSE;
418
419 #ifdef __WIN32__
420 m_dwLastError = RegDeleteValue(m_hKey, szValue);
421 if ( m_dwLastError != ERROR_SUCCESS ) {
422 wxLogSysError(m_dwLastError, "can't delete value '%s' from key '%s'",
423 szValue, GetName().c_str());
424 return FALSE;
425 }
426 #else //WIN16
427 // named registry values don't exist in Win16 world
428 wxASSERT( IsEmpty(szValue) );
429
430 // just set the (default and unique) value of the key to ""
431 m_dwLastError = RegSetValue(m_hKey, NULL, REG_SZ, "", RESERVED);
432 if ( m_dwLastError != ERROR_SUCCESS ) {
433 wxLogSysError(m_dwLastError, "can't delete value of key '%s'",
434 GetName().c_str());
435 return FALSE;
436 }
437 #endif //WIN16/32
438
439 return TRUE;
440 }
441
442 // ----------------------------------------------------------------------------
443 // access to values and subkeys
444 // ----------------------------------------------------------------------------
445
446 // return TRUE if value exists
447 bool wxRegKey::HasValue(const char *szValue) const
448 {
449 #ifdef __WIN32__
450 if ( CONST_CAST Open() ) {
451 return RegQueryValueEx(m_hKey, szValue, RESERVED,
452 NULL, NULL, NULL) == ERROR_SUCCESS;
453 }
454 else
455 return FALSE;
456 #else // WIN16
457 // only unnamed value exists
458 return IsEmpty(szValue);
459 #endif // WIN16/32
460 }
461
462 // returns TRUE if this key has any subkeys
463 bool wxRegKey::HasSubkeys() const
464 {
465 // just call GetFirstKey with dummy parameters
466 wxString str;
467 long l;
468 return CONST_CAST GetFirstKey(str, l);
469 }
470
471 // returns TRUE if given subkey exists
472 bool wxRegKey::HasSubKey(const char *szKey) const
473 {
474 if ( CONST_CAST Open() )
475 return KeyExists(m_hKey, szKey);
476 else
477 return FALSE;
478 }
479
480 wxRegKey::ValueType wxRegKey::GetValueType(const char *szValue)
481 {
482 #ifdef __WIN32__
483 if ( !Open() )
484 return Type_None;
485
486 DWORD dwType;
487 m_dwLastError = RegQueryValueEx(m_hKey, szValue, RESERVED,
488 &dwType, NULL, NULL);
489 if ( m_dwLastError != ERROR_SUCCESS ) {
490 wxLogSysError(m_dwLastError, "can't read value of key '%s'",
491 GetName().c_str());
492 return Type_None;
493 }
494
495 return (ValueType)dwType;
496 #else //WIN16
497 return IsEmpty(szValue) ? Type_String : Type_None;
498 #endif //WIN16/32
499 }
500
501 #ifdef __WIN32__
502 bool wxRegKey::SetValue(const char *szValue, long lValue)
503 {
504 if ( CONST_CAST Open() ) {
505 m_dwLastError = RegSetValueEx(m_hKey, szValue, RESERVED, REG_DWORD,
506 (RegString)&lValue, sizeof(lValue));
507 if ( m_dwLastError == ERROR_SUCCESS )
508 return TRUE;
509 }
510
511 wxLogSysError(m_dwLastError, "can't set value of '%s'",
512 GetFullName(this, szValue));
513 return FALSE;
514 }
515
516 bool wxRegKey::QueryValue(const char *szValue, long *plValue) const
517 {
518 if ( CONST_CAST Open() ) {
519 DWORD dwType, dwSize = sizeof(DWORD);
520 RegString pBuf = (RegString)plValue;
521 m_dwLastError = RegQueryValueEx(m_hKey, szValue, RESERVED,
522 &dwType, pBuf, &dwSize);
523 if ( m_dwLastError != ERROR_SUCCESS ) {
524 wxLogSysError(m_dwLastError, "can't read value of key '%s'",
525 GetName().c_str());
526 return FALSE;
527 }
528 else {
529 // check that we read the value of right type
530 wxASSERT_MSG( dwType == REG_DWORD,
531 "Type mismatch in wxRegKey::QueryValue()." );
532
533 return TRUE;
534 }
535 }
536 else
537 return FALSE;
538 }
539
540 #endif //Win32
541
542 bool wxRegKey::QueryValue(const char *szValue, wxString& strValue) const
543 {
544 if ( CONST_CAST Open() ) {
545 #ifdef __WIN32__
546 // first get the type and size of the data
547 DWORD dwType, dwSize;
548 m_dwLastError = RegQueryValueEx(m_hKey, szValue, RESERVED,
549 &dwType, NULL, &dwSize);
550 if ( m_dwLastError == ERROR_SUCCESS ) {
551 RegString pBuf = (RegString)strValue.GetWriteBuf(dwSize);
552 m_dwLastError = RegQueryValueEx(m_hKey, szValue, RESERVED,
553 &dwType, pBuf, &dwSize);
554 if ( m_dwLastError == ERROR_SUCCESS ) {
555 // check that it was the right type
556 wxASSERT_MSG( dwType == REG_SZ,
557 "Type mismatch in wxRegKey::QueryValue()." );
558
559 return TRUE;
560 }
561 }
562 #else //WIN16
563 // named registry values don't exist in Win16
564 wxASSERT( IsEmpty(szValue) );
565
566 m_dwLastError = RegQueryValue(m_hKey, 0, strValue.GetWriteBuf(256), &l);
567 if ( m_dwLastError == ERROR_SUCCESS )
568 return TRUE;
569 #endif //WIN16/32
570 }
571
572 wxLogSysError(m_dwLastError, "can't read value of '%s'",
573 GetFullName(this, szValue));
574 return FALSE;
575 }
576
577 bool wxRegKey::SetValue(const char *szValue, const wxString& strValue)
578 {
579 if ( CONST_CAST Open() ) {
580 #ifdef __WIN32__
581 m_dwLastError = RegSetValueEx(m_hKey, szValue, RESERVED, REG_SZ,
582 (RegString)strValue.c_str(),
583 strValue.Len() + 1);
584 if ( m_dwLastError == ERROR_SUCCESS )
585 return TRUE;
586 #else //WIN16
587 // named registry values don't exist in Win16
588 wxASSERT( IsEmpty(szValue) );
589
590 m_dwLastError = RegSetValue(m_hKey, NULL, REG_SZ, strValue, NULL);
591 if ( m_dwLastError == ERROR_SUCCESS )
592 return TRUE;
593 #endif //WIN16/32
594 }
595
596 wxLogSysError(m_dwLastError, "can't set value of '%s'",
597 GetFullName(this, szValue));
598 return FALSE;
599 }
600
601 wxRegKey::operator wxString() const
602 {
603 wxString str;
604 QueryValue(NULL, str);
605 return str;
606 }
607
608 // ----------------------------------------------------------------------------
609 // enumeration
610 // NB: all these functions require an index variable which allows to have
611 // several concurrently running indexations on the same key
612 // ----------------------------------------------------------------------------
613
614 bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex)
615 {
616 if ( !Open() )
617 return FALSE;
618
619 lIndex = 0;
620 return GetNextValue(strValueName, lIndex);
621 }
622
623 bool wxRegKey::GetNextValue(wxString& strValueName, long& lIndex) const
624 {
625 wxASSERT( IsOpened() );
626
627 // are we already at the end of enumeration?
628 if ( lIndex == -1 )
629 return FALSE;
630
631 #ifdef __WIN32__
632 char szValueName[1024]; // @@ use RegQueryInfoKey...
633 DWORD dwValueLen = WXSIZEOF(szValueName);
634
635 lIndex++;
636 m_dwLastError = RegEnumValue(m_hKey, lIndex,
637 szValueName, &dwValueLen,
638 RESERVED,
639 NULL, // [out] type
640 NULL, // [out] buffer for value
641 NULL); // [i/o] it's length
642
643 if ( m_dwLastError != ERROR_SUCCESS ) {
644 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
645 m_dwLastError = ERROR_SUCCESS;
646 lIndex = -1;
647 }
648 else {
649 wxLogSysError(m_dwLastError, "can't enumerate values of key '%s'",
650 GetName().c_str());
651 }
652
653 return FALSE;
654 }
655
656 strValueName = szValueName;
657 #else //WIN16
658 // only one unnamed value
659 wxASSERT( lIndex == 0 );
660
661 lIndex = -1;
662 strValueName.Empty();
663 #endif
664
665 return TRUE;
666 }
667
668 bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex)
669 {
670 if ( !Open() )
671 return FALSE;
672
673 lIndex = 0;
674 return GetNextKey(strKeyName, lIndex);
675 }
676
677 bool wxRegKey::GetNextKey(wxString& strKeyName, long& lIndex) const
678 {
679 wxASSERT( IsOpened() );
680
681 // are we already at the end of enumeration?
682 if ( lIndex == -1 )
683 return FALSE;
684
685 char szKeyName[_MAX_PATH + 1];
686 m_dwLastError = RegEnumKey(m_hKey, lIndex++, szKeyName, WXSIZEOF(szKeyName));
687
688 if ( m_dwLastError != ERROR_SUCCESS ) {
689 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
690 m_dwLastError = ERROR_SUCCESS;
691 lIndex = -1;
692 }
693 else {
694 wxLogSysError(m_dwLastError, "can't enumerate subkeys of key '%s'",
695 GetName().c_str());
696 }
697
698 return FALSE;
699 }
700
701 strKeyName = szKeyName;
702 return TRUE;
703 }
704
705 // ============================================================================
706 // implementation of global functions
707 // ============================================================================
708 bool KeyExists(HKEY hRootKey, const char *szKey)
709 {
710 HKEY hkeyDummy;
711 if ( RegOpenKey(hRootKey, szKey, &hkeyDummy) == ERROR_SUCCESS ) {
712 RegCloseKey(hkeyDummy);
713 return TRUE;
714 }
715 else
716 return FALSE;
717 }
718
719 const char *GetFullName(const wxRegKey *pKey, const char *szValue)
720 {
721 static wxString s_str;
722 s_str = pKey->GetName();
723 if ( !IsEmpty(szValue) )
724 s_str << "\\" << szValue;
725
726 return s_str.c_str();
727 }
728
729 void RemoveTrailingSeparator(wxString& str)
730 {
731 if ( !str.IsEmpty() && str.Last() == REG_SEPARATOR )
732 str.Truncate(str.Len() - 1);
733 }