minor fixes
[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(HKEY 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(HKEY hkey)
176 {
177 for ( size_t ui = 0; ui < nStdKeys; ui++ ) {
178 if ( aStdKeys[ui].hkey == 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 = aStdKeys[HKCR].hkey;
195 m_dwLastError = 0;
196 }
197
198 wxRegKey::wxRegKey(const wxString& strKey) : m_strKey(strKey)
199 {
200 m_hRootKey = 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 = 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 = 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 = 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(HKEY 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(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 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 m_dwLastError = RegOpenKey(m_hRootKey, m_strKey, &m_hKey);
362 if ( m_dwLastError != ERROR_SUCCESS ) {
363 wxLogSysError(m_dwLastError, _("can't open registry key '%s'"),
364 GetName().c_str());
365 return FALSE;
366 }
367 else
368 return TRUE;
369 }
370
371 // creates key, failing if it exists and !bOkIfExists
372 bool wxRegKey::Create(bool bOkIfExists)
373 {
374 // check for existence only if asked (i.e. order is important!)
375 if ( !bOkIfExists && Exists() ) {
376 return FALSE;
377 }
378
379 if ( IsOpened() )
380 return TRUE;
381
382 m_dwLastError = RegCreateKey(m_hRootKey, m_strKey, &m_hKey);
383 if ( m_dwLastError != ERROR_SUCCESS ) {
384 wxLogSysError(m_dwLastError, _("can't create registry key '%s'"),
385 GetName().c_str());
386 return FALSE;
387 }
388 else
389 return TRUE;
390 }
391
392 // close the key, it's not an error to call it when not opened
393 bool wxRegKey::Close()
394 {
395 if ( IsOpened() ) {
396 m_dwLastError = RegCloseKey(m_hKey);
397 if ( m_dwLastError != ERROR_SUCCESS ) {
398 wxLogSysError(m_dwLastError, _("can't close registry key '%s'"),
399 GetName().c_str());
400
401 m_hKey = 0;
402 return FALSE;
403 }
404 else {
405 m_hKey = 0;
406 }
407 }
408
409 return TRUE;
410 }
411
412 // ----------------------------------------------------------------------------
413 // delete keys/values
414 // ----------------------------------------------------------------------------
415 bool wxRegKey::DeleteSelf()
416 {
417 {
418 wxLogNull nolog;
419 if ( !Open() ) {
420 // it already doesn't exist - ok!
421 return TRUE;
422 }
423 }
424
425 // we can't delete keys while enumerating because it confuses GetNextKey, so
426 // we first save the key names and then delete them all
427 wxArrayString astrSubkeys;
428
429 wxString strKey;
430 long lIndex;
431 bool bCont = GetFirstKey(strKey, lIndex);
432 while ( bCont ) {
433 astrSubkeys.Add(strKey);
434
435 bCont = GetNextKey(strKey, lIndex);
436 }
437
438 size_t nKeyCount = astrSubkeys.Count();
439 for ( size_t nKey = 0; nKey < nKeyCount; nKey++ ) {
440 wxRegKey key(*this, astrSubkeys[nKey]);
441 if ( !key.DeleteSelf() )
442 return FALSE;
443 }
444
445 // now delete this key itself
446 Close();
447
448 m_dwLastError = RegDeleteKey(m_hRootKey, m_strKey);
449 if ( m_dwLastError != ERROR_SUCCESS ) {
450 wxLogSysError(m_dwLastError, _("can't delete key '%s'"),
451 GetName().c_str());
452 return FALSE;
453 }
454
455 return TRUE;
456 }
457
458 bool wxRegKey::DeleteKey(const char *szKey)
459 {
460 if ( !Open() )
461 return FALSE;
462
463 wxRegKey key(*this, szKey);
464 return key.DeleteSelf();
465 }
466
467 bool wxRegKey::DeleteValue(const char *szValue)
468 {
469 if ( !Open() )
470 return FALSE;
471
472 #ifdef __WIN32__
473 m_dwLastError = RegDeleteValue(m_hKey, szValue);
474 if ( m_dwLastError != ERROR_SUCCESS ) {
475 wxLogSysError(m_dwLastError, _("can't delete value '%s' from key '%s'"),
476 szValue, GetName().c_str());
477 return FALSE;
478 }
479 #else //WIN16
480 // named registry values don't exist in Win16 world
481 wxASSERT( IsEmpty(szValue) );
482
483 // just set the (default and unique) value of the key to ""
484 m_dwLastError = RegSetValue(m_hKey, NULL, REG_SZ, "", RESERVED);
485 if ( m_dwLastError != ERROR_SUCCESS ) {
486 wxLogSysError(m_dwLastError, _("can't delete value of key '%s'"),
487 GetName().c_str());
488 return FALSE;
489 }
490 #endif //WIN16/32
491
492 return TRUE;
493 }
494
495 // ----------------------------------------------------------------------------
496 // access to values and subkeys
497 // ----------------------------------------------------------------------------
498
499 // return TRUE if value exists
500 bool wxRegKey::HasValue(const char *szValue) const
501 {
502 // this function should be silent, so suppress possible messages from Open()
503 wxLogNull nolog;
504
505 #ifdef __WIN32__
506 if ( CONST_CAST Open() ) {
507 return RegQueryValueEx(m_hKey, szValue, RESERVED,
508 NULL, NULL, NULL) == ERROR_SUCCESS;
509 }
510 else
511 return FALSE;
512 #else // WIN16
513 // only unnamed value exists
514 return IsEmpty(szValue);
515 #endif // WIN16/32
516 }
517
518 // returns TRUE if this key has any subkeys
519 bool wxRegKey::HasSubkeys() const
520 {
521 // just call GetFirstKey with dummy parameters
522 wxString str;
523 long l;
524 return CONST_CAST GetFirstKey(str, l);
525 }
526
527 // returns TRUE if given subkey exists
528 bool wxRegKey::HasSubKey(const char *szKey) const
529 {
530 if ( CONST_CAST Open() )
531 return KeyExists(m_hKey, szKey);
532 else
533 return FALSE;
534 }
535
536 wxRegKey::ValueType wxRegKey::GetValueType(const char *szValue)
537 {
538 #ifdef __WIN32__
539 if ( !Open() )
540 return Type_None;
541
542 DWORD dwType;
543 m_dwLastError = RegQueryValueEx(m_hKey, szValue, RESERVED,
544 &dwType, NULL, NULL);
545 if ( m_dwLastError != ERROR_SUCCESS ) {
546 wxLogSysError(m_dwLastError, _("can't read value of key '%s'"),
547 GetName().c_str());
548 return Type_None;
549 }
550
551 return (ValueType)dwType;
552 #else //WIN16
553 return IsEmpty(szValue) ? Type_String : Type_None;
554 #endif //WIN16/32
555 }
556
557 #ifdef __WIN32__
558 bool wxRegKey::SetValue(const char *szValue, long lValue)
559 {
560 if ( CONST_CAST Open() ) {
561 m_dwLastError = RegSetValueEx(m_hKey, szValue, RESERVED, REG_DWORD,
562 (RegString)&lValue, sizeof(lValue));
563 if ( m_dwLastError == ERROR_SUCCESS )
564 return TRUE;
565 }
566
567 wxLogSysError(m_dwLastError, _("can't set value of '%s'"),
568 GetFullName(this, szValue));
569 return FALSE;
570 }
571
572 bool wxRegKey::QueryValue(const char *szValue, long *plValue) const
573 {
574 if ( CONST_CAST Open() ) {
575 DWORD dwType, dwSize = sizeof(DWORD);
576 RegString pBuf = (RegString)plValue;
577 m_dwLastError = RegQueryValueEx(m_hKey, szValue, RESERVED,
578 &dwType, pBuf, &dwSize);
579 if ( m_dwLastError != ERROR_SUCCESS ) {
580 wxLogSysError(m_dwLastError, _("can't read value of key '%s'"),
581 GetName().c_str());
582 return FALSE;
583 }
584 else {
585 // check that we read the value of right type
586 wxASSERT_MSG( dwType == REG_DWORD,
587 "Type mismatch in wxRegKey::QueryValue()." );
588
589 return TRUE;
590 }
591 }
592 else
593 return FALSE;
594 }
595
596 #endif //Win32
597
598 bool wxRegKey::QueryValue(const char *szValue, wxString& strValue) const
599 {
600 if ( CONST_CAST Open() ) {
601 #ifdef __WIN32__
602 // first get the type and size of the data
603 DWORD dwType, dwSize;
604 m_dwLastError = RegQueryValueEx(m_hKey, szValue, RESERVED,
605 &dwType, NULL, &dwSize);
606 if ( m_dwLastError == ERROR_SUCCESS ) {
607 RegString pBuf = (RegString)strValue.GetWriteBuf(dwSize);
608 m_dwLastError = RegQueryValueEx(m_hKey, szValue, RESERVED,
609 &dwType, pBuf, &dwSize);
610 strValue.UngetWriteBuf();
611 if ( m_dwLastError == ERROR_SUCCESS ) {
612 // check that it was the right type
613 wxASSERT_MSG( dwType == REG_SZ,
614 "Type mismatch in wxRegKey::QueryValue()." );
615
616 return TRUE;
617 }
618 }
619 #else //WIN16
620 // named registry values don't exist in Win16
621 wxASSERT( IsEmpty(szValue) );
622
623 m_dwLastError = RegQueryValue(m_hKey, 0, strValue.GetWriteBuf(256), &l);
624 strValue.UngetWriteBuf();
625 if ( m_dwLastError == ERROR_SUCCESS )
626 return TRUE;
627 #endif //WIN16/32
628 }
629
630 wxLogSysError(m_dwLastError, _("can't read value of '%s'"),
631 GetFullName(this, szValue));
632 return FALSE;
633 }
634
635 bool wxRegKey::SetValue(const char *szValue, const wxString& strValue)
636 {
637 if ( CONST_CAST Open() ) {
638 #ifdef __WIN32__
639 m_dwLastError = RegSetValueEx(m_hKey, szValue, RESERVED, REG_SZ,
640 (RegString)strValue.c_str(),
641 strValue.Len() + 1);
642 if ( m_dwLastError == ERROR_SUCCESS )
643 return TRUE;
644 #else //WIN16
645 // named registry values don't exist in Win16
646 wxASSERT( IsEmpty(szValue) );
647
648 m_dwLastError = RegSetValue(m_hKey, NULL, REG_SZ, strValue, NULL);
649 if ( m_dwLastError == ERROR_SUCCESS )
650 return TRUE;
651 #endif //WIN16/32
652 }
653
654 wxLogSysError(m_dwLastError, _("can't set value of '%s'"),
655 GetFullName(this, szValue));
656 return FALSE;
657 }
658
659 wxRegKey::operator wxString() const
660 {
661 wxString str;
662 QueryValue(NULL, str);
663 return str;
664 }
665
666 // ----------------------------------------------------------------------------
667 // enumeration
668 // NB: all these functions require an index variable which allows to have
669 // several concurrently running indexations on the same key
670 // ----------------------------------------------------------------------------
671
672 bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex)
673 {
674 if ( !Open() )
675 return FALSE;
676
677 lIndex = 0;
678 return GetNextValue(strValueName, lIndex);
679 }
680
681 bool wxRegKey::GetNextValue(wxString& strValueName, long& lIndex) const
682 {
683 wxASSERT( IsOpened() );
684
685 // are we already at the end of enumeration?
686 if ( lIndex == -1 )
687 return FALSE;
688
689 #ifdef __WIN32__
690 char szValueName[1024]; // @@ use RegQueryInfoKey...
691 DWORD dwValueLen = WXSIZEOF(szValueName);
692
693 lIndex++;
694 m_dwLastError = RegEnumValue(m_hKey, lIndex,
695 szValueName, &dwValueLen,
696 RESERVED,
697 NULL, // [out] type
698 NULL, // [out] buffer for value
699 NULL); // [i/o] it's length
700
701 if ( m_dwLastError != ERROR_SUCCESS ) {
702 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
703 m_dwLastError = ERROR_SUCCESS;
704 lIndex = -1;
705 }
706 else {
707 wxLogSysError(m_dwLastError, _("can't enumerate values of key '%s'"),
708 GetName().c_str());
709 }
710
711 return FALSE;
712 }
713
714 strValueName = szValueName;
715 #else //WIN16
716 // only one unnamed value
717 wxASSERT( lIndex == 0 );
718
719 lIndex = -1;
720 strValueName.Empty();
721 #endif
722
723 return TRUE;
724 }
725
726 bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex)
727 {
728 if ( !Open() )
729 return FALSE;
730
731 lIndex = 0;
732 return GetNextKey(strKeyName, lIndex);
733 }
734
735 bool wxRegKey::GetNextKey(wxString& strKeyName, long& lIndex) const
736 {
737 wxASSERT( IsOpened() );
738
739 // are we already at the end of enumeration?
740 if ( lIndex == -1 )
741 return FALSE;
742
743 char szKeyName[_MAX_PATH + 1];
744 m_dwLastError = RegEnumKey(m_hKey, lIndex++, szKeyName, WXSIZEOF(szKeyName));
745
746 if ( m_dwLastError != ERROR_SUCCESS ) {
747 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) {
748 m_dwLastError = ERROR_SUCCESS;
749 lIndex = -1;
750 }
751 else {
752 wxLogSysError(m_dwLastError, _("can't enumerate subkeys of key '%s'"),
753 GetName().c_str());
754 }
755
756 return FALSE;
757 }
758
759 strKeyName = szKeyName;
760 return TRUE;
761 }
762
763 // ============================================================================
764 // implementation of global private functions
765 // ============================================================================
766 bool KeyExists(HKEY hRootKey, const char *szKey)
767 {
768 HKEY hkeyDummy;
769 if ( RegOpenKey(hRootKey, szKey, &hkeyDummy) == ERROR_SUCCESS ) {
770 RegCloseKey(hkeyDummy);
771 return TRUE;
772 }
773 else
774 return FALSE;
775 }
776
777 const char *GetFullName(const wxRegKey *pKey, const char *szValue)
778 {
779 static wxString s_str;
780 s_str = pKey->GetName();
781 if ( !IsEmpty(szValue) )
782 s_str << "\\" << szValue;
783
784 return s_str.c_str();
785 }
786
787 void RemoveTrailingSeparator(wxString& str)
788 {
789 if ( !str.IsEmpty() && str.Last() == REG_SEPARATOR )
790 str.Truncate(str.Len() - 1);
791 }
792
793 // ============================================================================
794 // global public functions
795 // ============================================================================
796
797 bool GetExtensionFromMimeType(wxString *pExt, const wxString& strMimeType)
798 {
799 // @@@ VZ: I don't know of any official documentation which mentions this
800 // location, but as a matter of fact IE uses it, so why not we?
801 static const char *szMimeDbase = "MIME\\Database\\Content Type\\";
802
803 wxString strKey = szMimeDbase;
804 strKey << strMimeType;
805
806 // suppress possible error messages
807 wxLogNull nolog;
808 wxRegKey key(wxRegKey::HKCR, strKey);
809 if ( key.Open() ) {
810 if ( key.QueryValue("Extension", *pExt) )
811 return TRUE;
812 }
813
814 // no such MIME type or no extension for it
815 return FALSE;
816 }
817
818 bool GetMimeTypeFromExtension(wxString *pMimeType, const wxString& strExt)
819 {
820 wxCHECK( !strExt.IsEmpty(), FALSE );
821
822 // add the leading point if necessary
823 wxString str;
824 if ( strExt[0] != '.' ) {
825 str = '.';
826 }
827 str << strExt;
828
829 // suppress possible error messages
830 wxLogNull nolog;
831 wxRegKey key(wxRegKey::HKCR, str);
832 if ( key.Open() ) {
833 if ( key.QueryValue("Content Type", *pMimeType) )
834 return TRUE;
835 }
836
837 // no such extension or no content-type
838 return FALSE;
839 }
840
841 bool GetFileTypeFromExtension(wxString *pFileType, const wxString& strExt)
842 {
843 wxCHECK( !strExt.IsEmpty(), FALSE );
844
845 // add the leading point if necessary
846 wxString str;
847 if ( strExt[0] != '.' ) {
848 str = '.';
849 }
850 str << strExt;
851
852 // suppress possible error messages
853 wxLogNull nolog;
854 wxRegKey key(wxRegKey::HKCR, str);
855 if ( key.Open() ) {
856 if ( key.QueryValue("", *pFileType) ) // it's the default value of the key
857 return TRUE;
858 }
859
860 // no such extension or no value
861 return FALSE;
862 }
863
864 bool GetFileTypeIcon(wxIcon *pIcon, const wxString& strFileType)
865 {
866 wxCHECK( !strFileType.IsEmpty(), FALSE );
867
868 wxString strIconKey;
869 strIconKey << strFileType << REG_SEPARATOR << "DefaultIcon";
870
871 // suppress possible error messages
872 wxLogNull nolog;
873 wxRegKey key(wxRegKey::HKCR, strIconKey);
874
875 if ( key.Open() ) {
876 wxString strIcon;
877 if ( key.QueryValue("", strIcon) ) { // it's the default value of the key
878 // the format is the following: <full path to file>, <icon index>
879 // NB: icon index may be negative as well as positive and the full path
880 // may contain the environment variables inside '%'
881 wxString strFullPath = strIcon.Before(','),
882 strIndex = strIcon.After(',');
883
884 // unless I misunderstand the format (may be index may be ommited, I
885 // don't know)
886 wxASSERT( !(strFullPath.IsEmpty() || strIndex.IsEmpty()) );
887
888 wxString strExpPath = wxExpandEnvVars(strFullPath);
889 int nIndex = atoi(strIndex);
890
891 HICON hIcon = ExtractIcon(GetModuleHandle(NULL), strExpPath, nIndex);
892 switch ( (int)hIcon ) {
893 case 0: // means no icons were found
894 case 1: // means no such file or it wasn't a DLL/EXE/OCX/ICO/...
895 wxLogDebug("incorrect registry entry '%s': no such icon.",
896 GetFullName(&key));
897 break;
898
899 default:
900 pIcon->SetHICON((WXHICON)hIcon);
901 return TRUE;
902 }
903 }
904 }
905
906 // no such file type or no value or incorrect icon entry
907 return FALSE;
908 }
909
910 bool GetFileTypeDescription(wxString *pDesc, const wxString& strFileType)
911 {
912 wxCHECK( !strFileType.IsEmpty(), FALSE );
913
914 // suppress possible error messages
915 wxLogNull nolog;
916 wxRegKey key(wxRegKey::HKCR, strFileType);
917
918 if ( key.Open() ) {
919 if ( key.QueryValue("", *pDesc) ) // it's the default value of the key
920 return TRUE;
921 }
922
923 // no such file type or no value
924 return FALSE;
925 }