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