HKEY -> WXHKEY; wxScrolledWindow::SetScale added
[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 #include "wx/config.h" // for wxExpandEnvVars
36
37 // Windows headers
38 /*
39 #define STRICT
40 #define WIN32_LEAN_AND_MEAN
41 */
42
43 #include <windows.h>
44
45 // other std headers
46 #include <stdlib.h> // for _MAX_PATH
47
48 #ifndef _MAX_PATH
49 #define _MAX_PATH 512
50 #endif
51
52 // our header
53 #define HKEY_DEFINED // already defined in windows.h
54 #include "wx/msw/registry.h"
55
56 // some registry functions don't like signed chars
57 typedef unsigned char *RegString;
58
59 // ----------------------------------------------------------------------------
60 // constants
61 // ----------------------------------------------------------------------------
62
63 // the standard key names, short names and handles all bundled together for
64 // convenient access
65 static struct
66 {
67 HKEY hkey;
68 const char *szName;
69 const char *szShortName;
70 }
71 aStdKeys[] =
72 {
73 { HKEY_CLASSES_ROOT, "HKEY_CLASSES_ROOT", "HKCR" },
74 #ifdef __WIN32__
75 { HKEY_CURRENT_USER, "HKEY_CURRENT_USER", "HKCU" },
76 { HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE", "HKLM" },
77 { HKEY_USERS, "HKEY_USERS", "HKU" }, // short name?
78 { HKEY_PERFORMANCE_DATA, "HKEY_PERFORMANCE_DATA", "HKPD" },
79 #if WINVER >= 0x0400
80 { HKEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG", "HKCC" },
81 #ifndef __GNUWIN32__
82 { HKEY_DYN_DATA, "HKEY_DYN_DATA", "HKDD" }, // short name?
83 #endif //GNUWIN32
84 #endif //WINVER >= 4.0
85 #endif //WIN32
86 };
87
88 // the registry name separator (perhaps one day MS will change it to '/' ;-)
89 #define REG_SEPARATOR '\\'
90
91 // useful for Windows programmers: makes somewhat more clear all these zeroes
92 // being passed to Windows APIs
93 #define RESERVED (NULL)
94
95 // ----------------------------------------------------------------------------
96 // macros
97 // ----------------------------------------------------------------------------
98 // @ const_cast<> is not yet supported by all compilers
99 #define CONST_CAST ((wxRegKey *)this)->
100
101 #if !USE_MUTABLE
102 #define m_dwLastError CONST_CAST m_dwLastError
103 #endif
104
105 // ----------------------------------------------------------------------------
106 // non member functions
107 // ----------------------------------------------------------------------------
108
109 // removes the trailing backslash from the string if it has one
110 static inline void RemoveTrailingSeparator(wxString& str);
111
112 // returns TRUE if given registry key exists
113 static bool KeyExists(WXHKEY hRootKey, const char *szKey);
114
115 // combines value and key name (uses static buffer!)
116 static const char *GetFullName(const wxRegKey *pKey,
117 const char *szValue = NULL);
118
119 // ============================================================================
120 // implementation of wxRegKey class
121 // ============================================================================
122
123 // ----------------------------------------------------------------------------
124 // static functions and variables
125 // ----------------------------------------------------------------------------
126
127 const size_t wxRegKey::nStdKeys = WXSIZEOF(aStdKeys);
128
129 // @@ should take a `StdKey key', but as it's often going to be used in loops
130 // it would require casts in user code.
131 const char *wxRegKey::GetStdKeyName(size_t key)
132 {
133 // return empty string if key is invalid
134 wxCHECK_MSG( key < nStdKeys, "", "invalid key in wxRegKey::GetStdKeyName" );
135
136 return aStdKeys[key].szName;
137 }
138
139 const char *wxRegKey::GetStdKeyShortName(size_t key)
140 {
141 // return empty string if key is invalid
142 wxCHECK( key < nStdKeys, "" );
143
144 return aStdKeys[key].szShortName;
145 }
146
147 wxRegKey::StdKey wxRegKey::ExtractKeyName(wxString& strKey)
148 {
149 wxString strRoot = strKey.Left(REG_SEPARATOR);
150
151 HKEY hRootKey;
152 size_t ui;
153 for ( ui = 0; ui < nStdKeys; ui++ ) {
154 if ( strRoot.CmpNoCase(aStdKeys[ui].szName) == 0 ||
155 strRoot.CmpNoCase(aStdKeys[ui].szShortName) == 0 ) {
156 hRootKey = aStdKeys[ui].hkey;
157 break;
158 }
159 }
160
161 if ( ui == nStdKeys ) {
162 wxFAIL_MSG("invalid key prefix in wxRegKey::ExtractKeyName.");
163
164 hRootKey = HKEY_CLASSES_ROOT;
165 }
166 else {
167 strKey = strKey.After(REG_SEPARATOR);
168 if ( !strKey.IsEmpty() && strKey.Last() == REG_SEPARATOR )
169 strKey.Truncate(strKey.Len() - 1);
170 }
171
172 return (wxRegKey::StdKey)(int)hRootKey;
173 }
174
175 wxRegKey::StdKey wxRegKey::GetStdKeyFromHkey(WXHKEY hkey)
176 {
177 for ( size_t ui = 0; ui < nStdKeys; ui++ ) {
178 if ( (int) aStdKeys[ui].hkey == (int) hkey )
179 return (StdKey)ui;
180 }
181
182 wxFAIL_MSG("non root hkey passed to wxRegKey::GetStdKeyFromHkey.");
183
184 return HKCR;
185 }
186
187 // ----------------------------------------------------------------------------
188 // ctors and dtor
189 // ----------------------------------------------------------------------------
190
191 wxRegKey::wxRegKey()
192 {
193 m_hKey = 0;
194 m_hRootKey = (WXHKEY) aStdKeys[HKCR].hkey;
195 m_dwLastError = 0;
196 }
197
198 wxRegKey::wxRegKey(const wxString& strKey) : m_strKey(strKey)
199 {
200 m_hRootKey = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey;
201 m_hKey = NULL;
202 m_dwLastError = 0;
203 }
204
205 // parent is a predefined (and preopened) key
206 wxRegKey::wxRegKey(StdKey keyParent, const wxString& strKey) : m_strKey(strKey)
207 {
208 RemoveTrailingSeparator(m_strKey);
209 m_hRootKey = (WXHKEY) aStdKeys[keyParent].hkey;
210 m_hKey = NULL;
211 m_dwLastError = 0;
212 }
213
214 // parent is a normal regkey
215 wxRegKey::wxRegKey(const wxRegKey& keyParent, const wxString& strKey)
216 : m_strKey(keyParent.m_strKey)
217 {
218 // combine our name with parent's to get the full name
219 if ( !m_strKey.IsEmpty() &&
220 (strKey.IsEmpty() || strKey[0] != REG_SEPARATOR) ) {
221 m_strKey += REG_SEPARATOR;
222 }
223
224 m_strKey += strKey;
225 RemoveTrailingSeparator(m_strKey);
226
227 m_hRootKey = keyParent.m_hRootKey;
228 m_hKey = NULL;
229 m_dwLastError = 0;
230 }
231
232 // dtor closes the key releasing system resource
233 wxRegKey::~wxRegKey()
234 {
235 Close();
236 }
237
238 // ----------------------------------------------------------------------------
239 // change the key name/hkey
240 // ----------------------------------------------------------------------------
241
242 // set the full key name
243 void wxRegKey::SetName(const wxString& strKey)
244 {
245 Close();
246
247 m_strKey = strKey;
248 m_hRootKey = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey;
249 }
250
251 // the name is relative to the parent key
252 void wxRegKey::SetName(StdKey keyParent, const wxString& strKey)
253 {
254 Close();
255
256 m_strKey = strKey;
257 RemoveTrailingSeparator(m_strKey);
258 m_hRootKey = (WXHKEY) aStdKeys[keyParent].hkey;
259 }
260
261 // the name is relative to the parent key
262 void wxRegKey::SetName(const wxRegKey& keyParent, const wxString& strKey)
263 {
264 Close();
265
266 // combine our name with parent's to get the full name
267 m_strKey = keyParent.m_strKey;
268 if ( !strKey.IsEmpty() && strKey[0] != REG_SEPARATOR )
269 m_strKey += REG_SEPARATOR;
270 m_strKey += strKey;
271
272 RemoveTrailingSeparator(m_strKey);
273
274 m_hRootKey = keyParent.m_hRootKey;
275 }
276
277 // hKey should be opened and will be closed in wxRegKey dtor
278 void wxRegKey::SetHkey(WXHKEY hKey)
279 {
280 Close();
281
282 m_hKey = hKey;
283 }
284
285 // ----------------------------------------------------------------------------
286 // info about the key
287 // ----------------------------------------------------------------------------
288
289 // returns TRUE if the key exists
290 bool wxRegKey::Exists() const
291 {
292 // opened key has to exist, try to open it if not done yet
293 return IsOpened() ? TRUE : KeyExists(m_hRootKey, m_strKey);
294 }
295
296 // returns the full name of the key (prefix is abbreviated if bShortPrefix)
297 wxString wxRegKey::GetName(bool bShortPrefix) const
298 {
299 StdKey key = GetStdKeyFromHkey((StdKey) m_hRootKey);
300 wxString str = bShortPrefix ? aStdKeys[key].szShortName
301 : aStdKeys[key].szName;
302 if ( !m_strKey.IsEmpty() )
303 str << "\\" << m_strKey;
304
305 return str;
306 }
307
308 #ifdef __GNUWIN32__
309 bool wxRegKey::GetKeyInfo(size_t* pnSubKeys,
310 size_t* pnMaxKeyLen,
311 size_t* pnValues,
312 size_t* pnMaxValueLen) const
313 #else
314 bool wxRegKey::GetKeyInfo(ulong *pnSubKeys,
315 ulong *pnMaxKeyLen,
316 ulong *pnValues,
317 ulong *pnMaxValueLen) const
318 #endif
319 {
320 #ifdef __WIN32__
321 m_dwLastError = ::RegQueryInfoKey
322 (
323 (HKEY) m_hKey,
324 NULL, // class name
325 NULL, // (ptr to) size of class name buffer
326 RESERVED,
327 pnSubKeys, // [out] number of subkeys
328 pnMaxKeyLen, // [out] max length of a subkey name
329 NULL, // longest subkey class name
330 pnValues, // [out] number of values
331 pnMaxValueLen, // [out] max length of a value name
332 NULL, // longest value data
333 NULL, // security descriptor
334 NULL // time of last modification
335 );
336
337 if ( m_dwLastError != ERROR_SUCCESS ) {
338 wxLogSysError(m_dwLastError, _("can't get info about registry key '%s'"),
339 GetName().c_str());
340 return FALSE;
341 }
342 else
343 return TRUE;
344 #else // Win16
345 wxFAIL_MSG("GetKeyInfo() not implemented");
346
347 return FALSE;
348 #endif
349 }
350
351 // ----------------------------------------------------------------------------
352 // operations
353 // ----------------------------------------------------------------------------
354
355 // opens key (it's not an error to call Open() on an already opened key)
356 bool wxRegKey::Open()
357 {
358 if ( IsOpened() )
359 return TRUE;
360
361 HKEY tmpKey;
362 m_dwLastError = RegOpenKey((HKEY) m_hRootKey, m_strKey, &tmpKey);
363 if ( m_dwLastError != ERROR_SUCCESS ) {
364 wxLogSysError(m_dwLastError, _("can't open registry key '%s'"),
365 GetName().c_str());
366 return FALSE;
367 }
368 else
369 {
370 m_hKey = (WXHKEY) tmpKey;
371 return TRUE;
372 }
373 }
374
375 // creates key, failing if it exists and !bOkIfExists
376 bool wxRegKey::Create(bool bOkIfExists)
377 {
378 // check for existence only if asked (i.e. order is important!)
379 if ( !bOkIfExists && Exists() ) {
380 return FALSE;
381 }
382
383 if ( IsOpened() )
384 return TRUE;
385
386 HKEY tmpKey;
387 m_dwLastError = RegCreateKey((HKEY) m_hRootKey, m_strKey, &tmpKey);
388 if ( m_dwLastError != ERROR_SUCCESS ) {
389 wxLogSysError(m_dwLastError, _("can't create registry key '%s'"),
390 GetName().c_str());
391 return FALSE;
392 }
393 else
394 {
395 m_hKey = (WXHKEY) tmpKey;
396 return TRUE;
397 }
398 }
399
400 // close the key, it's not an error to call it when not opened
401 bool wxRegKey::Close()
402 {
403 if ( IsOpened() ) {
404 m_dwLastError = RegCloseKey((HKEY) m_hKey);
405 if ( m_dwLastError != ERROR_SUCCESS ) {
406 wxLogSysError(m_dwLastError, _("can't close registry key '%s'"),
407 GetName().c_str());
408
409 m_hKey = 0;
410 return FALSE;
411 }
412 else {
413 m_hKey = 0;
414 }
415 }
416
417 return TRUE;
418 }
419
420 // ----------------------------------------------------------------------------
421 // delete keys/values
422 // ----------------------------------------------------------------------------
423 bool wxRegKey::DeleteSelf()
424 {
425 {
426 wxLogNull nolog;
427 if ( !Open() ) {
428 // it already doesn't exist - ok!
429 return TRUE;
430 }
431 }
432
433 // we can't delete keys while enumerating because it confuses GetNextKey, so
434 // we first save the key names and then delete them all
435 wxArrayString astrSubkeys;
436
437 wxString strKey;
438 long lIndex;
439 bool bCont = GetFirstKey(strKey, lIndex);
440 while ( bCont ) {
441 astrSubkeys.Add(strKey);
442
443 bCont = GetNextKey(strKey, lIndex);
444 }
445
446 size_t nKeyCount = astrSubkeys.Count();
447 for ( size_t nKey = 0; nKey < nKeyCount; nKey++ ) {
448 wxRegKey key(*this, astrSubkeys[nKey]);
449 if ( !key.DeleteSelf() )
450 return FALSE;
451 }
452
453 // now delete this key itself
454 Close();
455
456 m_dwLastError = RegDeleteKey((HKEY) m_hRootKey, m_strKey);
457 if ( m_dwLastError != ERROR_SUCCESS ) {
458 wxLogSysError(m_dwLastError, _("can't delete key '%s'"),
459 GetName().c_str());
460 return FALSE;
461 }
462
463 return TRUE;
464 }
465
466 bool wxRegKey::DeleteKey(const char *szKey)
467 {
468 if ( !Open() )
469 return FALSE;
470
471 wxRegKey key(*this, szKey);
472 return key.DeleteSelf();
473 }
474
475 bool wxRegKey::DeleteValue(const char *szValue)
476 {
477 if ( !Open() )
478 return FALSE;
479
480 #ifdef __WIN32__
481 m_dwLastError = RegDeleteValue((HKEY) m_hKey, szValue);
482 if ( m_dwLastError != ERROR_SUCCESS ) {
483 wxLogSysError(m_dwLastError, _("can't delete value '%s' from key '%s'"),
484 szValue, GetName().c_str());
485 return FALSE;
486 }
487 #else //WIN16
488 // named registry values don't exist in Win16 world
489 wxASSERT( IsEmpty(szValue) );
490
491 // just set the (default and unique) value of the key to ""
492 m_dwLastError = RegSetValue((HKEY) m_hKey, NULL, REG_SZ, "", RESERVED);
493 if ( m_dwLastError != ERROR_SUCCESS ) {
494 wxLogSysError(m_dwLastError, _("can't delete value of key '%s'"),
495 GetName().c_str());
496 return FALSE;
497 }
498 #endif //WIN16/32
499
500 return TRUE;
501 }
502
503 // ----------------------------------------------------------------------------
504 // access to values and subkeys
505 // ----------------------------------------------------------------------------
506
507 // return TRUE if value exists
508 bool wxRegKey::HasValue(const char *szValue) const
509 {
510 // this function should be silent, so suppress possible messages from Open()
511 wxLogNull nolog;
512
513 #ifdef __WIN32__
514 if ( CONST_CAST Open() ) {
515 return RegQueryValueEx((HKEY) m_hKey, szValue, RESERVED,
516 NULL, NULL, NULL) == ERROR_SUCCESS;
517 }
518 else
519 return FALSE;
520 #else // WIN16
521 // only unnamed value exists
522 return IsEmpty(szValue);
523 #endif // WIN16/32
524 }
525
526 // returns TRUE if this key has any subkeys
527 bool wxRegKey::HasSubkeys() const
528 {
529 // just call GetFirstKey with dummy parameters
530 wxString str;
531 long l;
532 return CONST_CAST GetFirstKey(str, l);
533 }
534
535 // returns TRUE if given subkey exists
536 bool wxRegKey::HasSubKey(const char *szKey) const
537 {
538 if ( CONST_CAST Open() )
539 return KeyExists(m_hKey, szKey);
540 else
541 return FALSE;
542 }
543
544 wxRegKey::ValueType wxRegKey::GetValueType(const char *szValue)
545 {
546 #ifdef __WIN32__
547 if ( !Open() )
548 return Type_None;
549
550 DWORD dwType;
551 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, szValue, RESERVED,
552 &dwType, NULL, NULL);
553 if ( m_dwLastError != ERROR_SUCCESS ) {
554 wxLogSysError(m_dwLastError, _("can't read value of key '%s'"),
555 GetName().c_str());
556 return Type_None;
557 }
558
559 return (ValueType)dwType;
560 #else //WIN16
561 return IsEmpty(szValue) ? Type_String : Type_None;
562 #endif //WIN16/32
563 }
564
565 #ifdef __WIN32__
566 bool wxRegKey::SetValue(const char *szValue, long lValue)
567 {
568 if ( CONST_CAST Open() ) {
569 m_dwLastError = RegSetValueEx((HKEY) m_hKey, szValue, RESERVED, REG_DWORD,
570 (RegString)&lValue, sizeof(lValue));
571 if ( m_dwLastError == ERROR_SUCCESS )
572 return TRUE;
573 }
574
575 wxLogSysError(m_dwLastError, _("can't set value of '%s'"),
576 GetFullName(this, szValue));
577 return FALSE;
578 }
579
580 bool wxRegKey::QueryValue(const char *szValue, long *plValue) const
581 {
582 if ( CONST_CAST Open() ) {
583 DWORD dwType, dwSize = sizeof(DWORD);
584 RegString pBuf = (RegString)plValue;
585 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, szValue, RESERVED,
586 &dwType, pBuf, &dwSize);
587 if ( m_dwLastError != ERROR_SUCCESS ) {
588 wxLogSysError(m_dwLastError, _("can't read value of key '%s'"),
589 GetName().c_str());
590 return FALSE;
591 }
592 else {
593 // check that we read the value of right type
594 wxASSERT_MSG( dwType == REG_DWORD,
595 "Type mismatch in wxRegKey::QueryValue()." );
596
597 return TRUE;
598 }
599 }
600 else
601 return FALSE;
602 }
603
604 #endif //Win32
605
606 bool wxRegKey::QueryValue(const char *szValue, wxString& strValue) const
607 {
608 if ( CONST_CAST Open() ) {
609 #ifdef __WIN32__
610 // first get the type and size of the data
611 DWORD dwType, dwSize;
612 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, szValue, RESERVED,
613 &dwType, NULL, &dwSize);
614 if ( m_dwLastError == ERROR_SUCCESS ) {
615 RegString pBuf = (RegString)strValue.GetWriteBuf(dwSize);
616 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, szValue, RESERVED,
617 &dwType, pBuf, &dwSize);
618 strValue.UngetWriteBuf();
619 if ( m_dwLastError == ERROR_SUCCESS ) {
620 // check that it was the right type
621 wxASSERT_MSG( dwType == REG_SZ,
622 "Type mismatch in wxRegKey::QueryValue()." );
623
624 return TRUE;
625 }
626 }
627 #else //WIN16
628 // named registry values don't exist in Win16
629 wxASSERT( IsEmpty(szValue) );
630
631 m_dwLastError = RegQueryValue((HKEY) m_hKey, 0, strValue.GetWriteBuf(256), &l);
632 strValue.UngetWriteBuf();
633 if ( m_dwLastError == ERROR_SUCCESS )
634 return TRUE;
635 #endif //WIN16/32
636 }
637
638 wxLogSysError(m_dwLastError, _("can't read value of '%s'"),
639 GetFullName(this, szValue));
640 return FALSE;
641 }
642
643 bool wxRegKey::SetValue(const char *szValue, const wxString& strValue)
644 {
645 if ( CONST_CAST Open() ) {
646 #ifdef __WIN32__
647 m_dwLastError = RegSetValueEx((HKEY) m_hKey, szValue, RESERVED, REG_SZ,
648 (RegString)strValue.c_str(),
649 strValue.Len() + 1);
650 if ( m_dwLastError == ERROR_SUCCESS )
651 return TRUE;
652 #else //WIN16
653 // named registry values don't exist in Win16
654 wxASSERT( IsEmpty(szValue) );
655
656 m_dwLastError = RegSetValue((HKEY) m_hKey, NULL, REG_SZ, strValue, NULL);
657 if ( m_dwLastError == ERROR_SUCCESS )
658 return TRUE;
659 #endif //WIN16/32
660 }
661
662 wxLogSysError(m_dwLastError, _("can't set value of '%s'"),
663 GetFullName(this, szValue));
664 return FALSE;
665 }
666
667 wxRegKey::operator wxString() const
668 {
669 wxString str;
670 QueryValue(NULL, str);
671 return str;
672 }
673
674 // ----------------------------------------------------------------------------
675 // enumeration
676 // NB: all these functions require an index variable which allows to have
677 // several concurrently running indexations on the same key
678 // ----------------------------------------------------------------------------
679
680 bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex)
681 {
682 if ( !Open() )
683 return FALSE;
684
685 lIndex = 0;
686 return GetNextValue(strValueName, lIndex);
687 }
688
689 bool wxRegKey::GetNextValue(wxString& strValueName, long& lIndex) const
690 {
691 wxASSERT( IsOpened() );
692
693 // are we already at the end of enumeration?
694 if ( lIndex == -1 )
695 return FALSE;
696
697 #ifdef __WIN32__
698 char szValueName[1024]; // @@ use RegQueryInfoKey...
699 DWORD dwValueLen = WXSIZEOF(szValueName);
700
701 lIndex++;
702 m_dwLastError = RegEnumValue((HKEY) m_hKey, lIndex,
703 szValueName, &dwValueLen,
704 RESERVED,
705 NULL, // [out] type
706 NULL, // [out] buffer for value
707 NULL); // [i/o] it's length
708
709 if ( m_dwLastError != ERROR_SUCCESS ) {
710 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
711 m_dwLastError = ERROR_SUCCESS;
712 lIndex = -1;
713 }
714 else {
715 wxLogSysError(m_dwLastError, _("can't enumerate values of key '%s'"),
716 GetName().c_str());
717 }
718
719 return FALSE;
720 }
721
722 strValueName = szValueName;
723 #else //WIN16
724 // only one unnamed value
725 wxASSERT( lIndex == 0 );
726
727 lIndex = -1;
728 strValueName.Empty();
729 #endif
730
731 return TRUE;
732 }
733
734 bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex)
735 {
736 if ( !Open() )
737 return FALSE;
738
739 lIndex = 0;
740 return GetNextKey(strKeyName, lIndex);
741 }
742
743 bool wxRegKey::GetNextKey(wxString& strKeyName, long& lIndex) const
744 {
745 wxASSERT( IsOpened() );
746
747 // are we already at the end of enumeration?
748 if ( lIndex == -1 )
749 return FALSE;
750
751 char szKeyName[_MAX_PATH + 1];
752 m_dwLastError = RegEnumKey((HKEY) m_hKey, lIndex++, szKeyName, WXSIZEOF(szKeyName));
753
754 if ( m_dwLastError != ERROR_SUCCESS ) {
755 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
756 m_dwLastError = ERROR_SUCCESS;
757 lIndex = -1;
758 }
759 else {
760 wxLogSysError(m_dwLastError, _("can't enumerate subkeys of key '%s'"),
761 GetName().c_str());
762 }
763
764 return FALSE;
765 }
766
767 strKeyName = szKeyName;
768 return TRUE;
769 }
770
771 // ============================================================================
772 // implementation of global private functions
773 // ============================================================================
774 bool KeyExists(WXHKEY hRootKey, const char *szKey)
775 {
776 HKEY hkeyDummy;
777 if ( RegOpenKey( (HKEY) hRootKey, szKey, &hkeyDummy) == ERROR_SUCCESS ) {
778 RegCloseKey(hkeyDummy);
779 return TRUE;
780 }
781 else
782 return FALSE;
783 }
784
785 const char *GetFullName(const wxRegKey *pKey, const char *szValue)
786 {
787 static wxString s_str;
788 s_str = pKey->GetName();
789 if ( !IsEmpty(szValue) )
790 s_str << "\\" << szValue;
791
792 return s_str.c_str();
793 }
794
795 void RemoveTrailingSeparator(wxString& str)
796 {
797 if ( !str.IsEmpty() && str.Last() == REG_SEPARATOR )
798 str.Truncate(str.Len() - 1);
799 }
800
801 // ============================================================================
802 // global public functions
803 // ============================================================================
804
805 bool GetExtensionFromMimeType(wxString *pExt, const wxString& strMimeType)
806 {
807 // @@@ VZ: I don't know of any official documentation which mentions this
808 // location, but as a matter of fact IE uses it, so why not we?
809 static const char *szMimeDbase = "MIME\\Database\\Content Type\\";
810
811 wxString strKey = szMimeDbase;
812 strKey << strMimeType;
813
814 // suppress possible error messages
815 wxLogNull nolog;
816 wxRegKey key(wxRegKey::HKCR, strKey);
817 if ( key.Open() ) {
818 if ( key.QueryValue("Extension", *pExt) )
819 return TRUE;
820 }
821
822 // no such MIME type or no extension for it
823 return FALSE;
824 }
825
826 bool GetMimeTypeFromExtension(wxString *pMimeType, const wxString& strExt)
827 {
828 wxCHECK( !strExt.IsEmpty(), FALSE );
829
830 // add the leading point if necessary
831 wxString str;
832 if ( strExt[0] != '.' ) {
833 str = '.';
834 }
835 str << strExt;
836
837 // suppress possible error messages
838 wxLogNull nolog;
839 wxRegKey key(wxRegKey::HKCR, str);
840 if ( key.Open() ) {
841 if ( key.QueryValue("Content Type", *pMimeType) )
842 return TRUE;
843 }
844
845 // no such extension or no content-type
846 return FALSE;
847 }
848
849 bool GetFileTypeFromExtension(wxString *pFileType, const wxString& strExt)
850 {
851 wxCHECK( !strExt.IsEmpty(), FALSE );
852
853 // add the leading point if necessary
854 wxString str;
855 if ( strExt[0] != '.' ) {
856 str = '.';
857 }
858 str << strExt;
859
860 // suppress possible error messages
861 wxLogNull nolog;
862 wxRegKey key(wxRegKey::HKCR, str);
863 if ( key.Open() ) {
864 if ( key.QueryValue("", *pFileType) ) // it's the default value of the key
865 return TRUE;
866 }
867
868 // no such extension or no value
869 return FALSE;
870 }
871
872 bool GetFileTypeIcon(wxIcon *pIcon, const wxString& strFileType)
873 {
874 wxCHECK( !strFileType.IsEmpty(), FALSE );
875
876 wxString strIconKey;
877 strIconKey << strFileType << REG_SEPARATOR << "DefaultIcon";
878
879 // suppress possible error messages
880 wxLogNull nolog;
881 wxRegKey key(wxRegKey::HKCR, strIconKey);
882
883 if ( key.Open() ) {
884 wxString strIcon;
885 if ( key.QueryValue("", strIcon) ) { // it's the default value of the key
886 // the format is the following: <full path to file>, <icon index>
887 // NB: icon index may be negative as well as positive and the full path
888 // may contain the environment variables inside '%'
889 wxString strFullPath = strIcon.Before(','),
890 strIndex = strIcon.After(',');
891
892 // unless I misunderstand the format (may be index may be ommited, I
893 // don't know)
894 wxASSERT( !(strFullPath.IsEmpty() || strIndex.IsEmpty()) );
895
896 wxString strExpPath = wxExpandEnvVars(strFullPath);
897 int nIndex = atoi(strIndex);
898
899 HICON hIcon = ExtractIcon(GetModuleHandle(NULL), strExpPath, nIndex);
900 switch ( (int)hIcon ) {
901 case 0: // means no icons were found
902 case 1: // means no such file or it wasn't a DLL/EXE/OCX/ICO/...
903 wxLogDebug("incorrect registry entry '%s': no such icon.",
904 GetFullName(&key));
905 break;
906
907 default:
908 pIcon->SetHICON((WXHICON)hIcon);
909 return TRUE;
910 }
911 }
912 }
913
914 // no such file type or no value or incorrect icon entry
915 return FALSE;
916 }
917
918 bool GetFileTypeDescription(wxString *pDesc, const wxString& strFileType)
919 {
920 wxCHECK( !strFileType.IsEmpty(), FALSE );
921
922 // suppress possible error messages
923 wxLogNull nolog;
924 wxRegKey key(wxRegKey::HKCR, strFileType);
925
926 if ( key.Open() ) {
927 if ( key.QueryValue("", *pDesc) ) // it's the default value of the key
928 return TRUE;
929 }
930
931 // no such file type or no value
932 return FALSE;
933 }
934
935