]> git.saurik.com Git - wxWidgets.git/blame - src/msw/registry.cpp
Shared libs now get installed correctly on Linux.
[wxWidgets.git] / src / msw / registry.cpp
CommitLineData
2bda0e17
KB
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
41286812
VZ
35#include "wx/config.h" // for wxExpandEnvVars
36
2bda0e17 37// Windows headers
57a7b7c1 38/*
2bda0e17
KB
39#define STRICT
40#define WIN32_LEAN_AND_MEAN
57a7b7c1
JS
41*/
42
2bda0e17
KB
43#include <windows.h>
44
45// other std headers
46#include <stdlib.h> // for _MAX_PATH
47
48#ifndef _MAX_PATH
0b1c5a6c 49 #define _MAX_PATH 512
2bda0e17
KB
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
57typedef 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
65static struct
66{
67 HKEY hkey;
68 const char *szName;
69 const char *szShortName;
70}
71aStdKeys[] =
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?
0b1c5a6c 83#endif //GNUWIN32
2bda0e17
KB
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
c86f1403
VZ
91// useful for Windows programmers: makes somewhat more clear all these zeroes
92// being passed to Windows APIs
93#define RESERVED (NULL)
94
2bda0e17
KB
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
0b1c5a6c
VZ
109// removes the trailing backslash from the string if it has one
110static inline void RemoveTrailingSeparator(wxString& str);
111
cf447356 112// returns TRUE if given registry key exists
fd6c844b 113static bool KeyExists(WXHKEY hRootKey, const char *szKey);
2bda0e17
KB
114
115// combines value and key name (uses static buffer!)
116static 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
127const 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.
c86f1403 131const char *wxRegKey::GetStdKeyName(size_t key)
2bda0e17
KB
132{
133 // return empty string if key is invalid
1311c7a9 134 wxCHECK_MSG( key < nStdKeys, "", "invalid key in wxRegKey::GetStdKeyName" );
2bda0e17
KB
135
136 return aStdKeys[key].szName;
137}
138
c86f1403 139const char *wxRegKey::GetStdKeyShortName(size_t key)
2bda0e17
KB
140{
141 // return empty string if key is invalid
1311c7a9 142 wxCHECK( key < nStdKeys, "" );
2bda0e17
KB
143
144 return aStdKeys[key].szShortName;
145}
146
147wxRegKey::StdKey wxRegKey::ExtractKeyName(wxString& strKey)
148{
149 wxString strRoot = strKey.Left(REG_SEPARATOR);
150
151 HKEY hRootKey;
c86f1403 152 size_t ui;
2bda0e17
KB
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
fd6c844b 175wxRegKey::StdKey wxRegKey::GetStdKeyFromHkey(WXHKEY hkey)
2bda0e17 176{
c86f1403 177 for ( size_t ui = 0; ui < nStdKeys; ui++ ) {
fd6c844b 178 if ( (int) aStdKeys[ui].hkey == (int) hkey )
2bda0e17
KB
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
191wxRegKey::wxRegKey()
192{
193 m_hKey = 0;
fd6c844b 194 m_hRootKey = (WXHKEY) aStdKeys[HKCR].hkey;
2bda0e17
KB
195 m_dwLastError = 0;
196}
197
198wxRegKey::wxRegKey(const wxString& strKey) : m_strKey(strKey)
199{
fd6c844b 200 m_hRootKey = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey;
2bda0e17
KB
201 m_hKey = NULL;
202 m_dwLastError = 0;
203}
204
205// parent is a predefined (and preopened) key
206wxRegKey::wxRegKey(StdKey keyParent, const wxString& strKey) : m_strKey(strKey)
207{
0b1c5a6c 208 RemoveTrailingSeparator(m_strKey);
fd6c844b 209 m_hRootKey = (WXHKEY) aStdKeys[keyParent].hkey;
2bda0e17
KB
210 m_hKey = NULL;
211 m_dwLastError = 0;
212}
213
214// parent is a normal regkey
215wxRegKey::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
32c66ea2
VZ
219 if ( !m_strKey.IsEmpty() &&
220 (strKey.IsEmpty() || strKey[0] != REG_SEPARATOR) ) {
221 m_strKey += REG_SEPARATOR;
222 }
2bda0e17
KB
223
224 m_strKey += strKey;
0b1c5a6c 225 RemoveTrailingSeparator(m_strKey);
2bda0e17
KB
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
233wxRegKey::~wxRegKey()
234{
235 Close();
236}
237
0b1c5a6c
VZ
238// ----------------------------------------------------------------------------
239// change the key name/hkey
240// ----------------------------------------------------------------------------
241
242// set the full key name
243void wxRegKey::SetName(const wxString& strKey)
244{
245 Close();
246
247 m_strKey = strKey;
fd6c844b 248 m_hRootKey = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey;
0b1c5a6c
VZ
249}
250
251// the name is relative to the parent key
252void wxRegKey::SetName(StdKey keyParent, const wxString& strKey)
253{
254 Close();
255
256 m_strKey = strKey;
257 RemoveTrailingSeparator(m_strKey);
fd6c844b 258 m_hRootKey = (WXHKEY) aStdKeys[keyParent].hkey;
0b1c5a6c
VZ
259}
260
261// the name is relative to the parent key
262void wxRegKey::SetName(const wxRegKey& keyParent, const wxString& strKey)
263{
264 Close();
265
266 // combine our name with parent's to get the full name
02569ba8 267 m_strKey = keyParent.m_strKey;
0b1c5a6c
VZ
268 if ( !strKey.IsEmpty() && strKey[0] != REG_SEPARATOR )
269 m_strKey += REG_SEPARATOR;
02569ba8 270 m_strKey += strKey;
0b1c5a6c
VZ
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
fd6c844b 278void wxRegKey::SetHkey(WXHKEY hKey)
0b1c5a6c
VZ
279{
280 Close();
281
282 m_hKey = hKey;
283}
284
2bda0e17
KB
285// ----------------------------------------------------------------------------
286// info about the key
287// ----------------------------------------------------------------------------
288
cf447356 289// returns TRUE if the key exists
2bda0e17
KB
290bool wxRegKey::Exists() const
291{
292 // opened key has to exist, try to open it if not done yet
cf447356 293 return IsOpened() ? TRUE : KeyExists(m_hRootKey, m_strKey);
2bda0e17
KB
294}
295
296// returns the full name of the key (prefix is abbreviated if bShortPrefix)
297wxString wxRegKey::GetName(bool bShortPrefix) const
298{
fd6c844b 299 StdKey key = GetStdKeyFromHkey((StdKey) m_hRootKey);
2bda0e17
KB
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
088a95f5 308#ifdef __GNUWIN32__
c86f1403
VZ
309bool wxRegKey::GetKeyInfo(size_t* pnSubKeys,
310 size_t* pnMaxKeyLen,
311 size_t* pnValues,
312 size_t* pnMaxValueLen) const
088a95f5 313#else
02569ba8
VZ
314bool wxRegKey::GetKeyInfo(ulong *pnSubKeys,
315 ulong *pnMaxKeyLen,
316 ulong *pnValues,
317 ulong *pnMaxValueLen) const
088a95f5 318#endif
02569ba8
VZ
319{
320#ifdef __WIN32__
321 m_dwLastError = ::RegQueryInfoKey
322 (
fd6c844b 323 (HKEY) m_hKey,
02569ba8
VZ
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
2bda0e17
KB
351// ----------------------------------------------------------------------------
352// operations
353// ----------------------------------------------------------------------------
354
355// opens key (it's not an error to call Open() on an already opened key)
356bool wxRegKey::Open()
357{
358 if ( IsOpened() )
cf447356 359 return TRUE;
2bda0e17 360
fd6c844b
JS
361 HKEY tmpKey;
362 m_dwLastError = RegOpenKey((HKEY) m_hRootKey, m_strKey, &tmpKey);
2bda0e17 363 if ( m_dwLastError != ERROR_SUCCESS ) {
02569ba8 364 wxLogSysError(m_dwLastError, _("can't open registry key '%s'"),
2bda0e17 365 GetName().c_str());
cf447356 366 return FALSE;
2bda0e17
KB
367 }
368 else
fd6c844b
JS
369 {
370 m_hKey = (WXHKEY) tmpKey;
cf447356 371 return TRUE;
fd6c844b 372 }
2bda0e17
KB
373}
374
375// creates key, failing if it exists and !bOkIfExists
376bool wxRegKey::Create(bool bOkIfExists)
377{
378 // check for existence only if asked (i.e. order is important!)
379 if ( !bOkIfExists && Exists() ) {
cf447356 380 return FALSE;
2bda0e17
KB
381 }
382
383 if ( IsOpened() )
cf447356 384 return TRUE;
2bda0e17 385
fd6c844b
JS
386 HKEY tmpKey;
387 m_dwLastError = RegCreateKey((HKEY) m_hRootKey, m_strKey, &tmpKey);
2bda0e17 388 if ( m_dwLastError != ERROR_SUCCESS ) {
02569ba8 389 wxLogSysError(m_dwLastError, _("can't create registry key '%s'"),
2bda0e17 390 GetName().c_str());
cf447356 391 return FALSE;
2bda0e17
KB
392 }
393 else
fd6c844b
JS
394 {
395 m_hKey = (WXHKEY) tmpKey;
cf447356 396 return TRUE;
fd6c844b 397 }
2bda0e17
KB
398}
399
0b1c5a6c
VZ
400// close the key, it's not an error to call it when not opened
401bool wxRegKey::Close()
402{
403 if ( IsOpened() ) {
fd6c844b 404 m_dwLastError = RegCloseKey((HKEY) m_hKey);
0b1c5a6c 405 if ( m_dwLastError != ERROR_SUCCESS ) {
02569ba8 406 wxLogSysError(m_dwLastError, _("can't close registry key '%s'"),
0b1c5a6c
VZ
407 GetName().c_str());
408
409 m_hKey = 0;
cf447356 410 return FALSE;
0b1c5a6c
VZ
411 }
412 else {
413 m_hKey = 0;
414 }
415 }
416
cf447356 417 return TRUE;
0b1c5a6c
VZ
418}
419
420// ----------------------------------------------------------------------------
421// delete keys/values
422// ----------------------------------------------------------------------------
2bda0e17
KB
423bool wxRegKey::DeleteSelf()
424{
0b1c5a6c
VZ
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;
2bda0e17
KB
436
437 wxString strKey;
438 long lIndex;
439 bool bCont = GetFirstKey(strKey, lIndex);
440 while ( bCont ) {
0b1c5a6c 441 astrSubkeys.Add(strKey);
2bda0e17
KB
442
443 bCont = GetNextKey(strKey, lIndex);
444 }
445
c86f1403
VZ
446 size_t nKeyCount = astrSubkeys.Count();
447 for ( size_t nKey = 0; nKey < nKeyCount; nKey++ ) {
0b1c5a6c
VZ
448 wxRegKey key(*this, astrSubkeys[nKey]);
449 if ( !key.DeleteSelf() )
450 return FALSE;
451 }
452
453 // now delete this key itself
2bda0e17
KB
454 Close();
455
fd6c844b 456 m_dwLastError = RegDeleteKey((HKEY) m_hRootKey, m_strKey);
2bda0e17 457 if ( m_dwLastError != ERROR_SUCCESS ) {
02569ba8
VZ
458 wxLogSysError(m_dwLastError, _("can't delete key '%s'"),
459 GetName().c_str());
2bda0e17
KB
460 return FALSE;
461 }
462
463 return TRUE;
464}
465
466bool wxRegKey::DeleteKey(const char *szKey)
467{
468 if ( !Open() )
cf447356 469 return FALSE;
2bda0e17
KB
470
471 wxRegKey key(*this, szKey);
472 return key.DeleteSelf();
473}
474
475bool wxRegKey::DeleteValue(const char *szValue)
476{
477 if ( !Open() )
cf447356 478 return FALSE;
2bda0e17
KB
479
480 #ifdef __WIN32__
fd6c844b 481 m_dwLastError = RegDeleteValue((HKEY) m_hKey, szValue);
2bda0e17 482 if ( m_dwLastError != ERROR_SUCCESS ) {
02569ba8 483 wxLogSysError(m_dwLastError, _("can't delete value '%s' from key '%s'"),
2bda0e17 484 szValue, GetName().c_str());
cf447356 485 return FALSE;
2bda0e17
KB
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 ""
fd6c844b 492 m_dwLastError = RegSetValue((HKEY) m_hKey, NULL, REG_SZ, "", RESERVED);
2bda0e17 493 if ( m_dwLastError != ERROR_SUCCESS ) {
02569ba8 494 wxLogSysError(m_dwLastError, _("can't delete value of key '%s'"),
2bda0e17 495 GetName().c_str());
cf447356 496 return FALSE;
2bda0e17
KB
497 }
498 #endif //WIN16/32
499
cf447356 500 return TRUE;
2bda0e17
KB
501}
502
503// ----------------------------------------------------------------------------
504// access to values and subkeys
505// ----------------------------------------------------------------------------
506
cf447356 507// return TRUE if value exists
0b1c5a6c
VZ
508bool wxRegKey::HasValue(const char *szValue) const
509{
32c66ea2
VZ
510 // this function should be silent, so suppress possible messages from Open()
511 wxLogNull nolog;
512
0b1c5a6c
VZ
513 #ifdef __WIN32__
514 if ( CONST_CAST Open() ) {
fd6c844b 515 return RegQueryValueEx((HKEY) m_hKey, szValue, RESERVED,
0b1c5a6c
VZ
516 NULL, NULL, NULL) == ERROR_SUCCESS;
517 }
518 else
cf447356 519 return FALSE;
0b1c5a6c
VZ
520 #else // WIN16
521 // only unnamed value exists
522 return IsEmpty(szValue);
523 #endif // WIN16/32
524}
525
cf447356 526// returns TRUE if this key has any subkeys
2bda0e17
KB
527bool 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
cf447356 535// returns TRUE if given subkey exists
2bda0e17
KB
536bool wxRegKey::HasSubKey(const char *szKey) const
537{
538 if ( CONST_CAST Open() )
539 return KeyExists(m_hKey, szKey);
540 else
cf447356 541 return FALSE;
2bda0e17
KB
542}
543
544wxRegKey::ValueType wxRegKey::GetValueType(const char *szValue)
545{
546 #ifdef __WIN32__
547 if ( !Open() )
548 return Type_None;
549
550 DWORD dwType;
fd6c844b 551 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, szValue, RESERVED,
2bda0e17
KB
552 &dwType, NULL, NULL);
553 if ( m_dwLastError != ERROR_SUCCESS ) {
02569ba8 554 wxLogSysError(m_dwLastError, _("can't read value of key '%s'"),
2bda0e17
KB
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__
566bool wxRegKey::SetValue(const char *szValue, long lValue)
567{
568 if ( CONST_CAST Open() ) {
fd6c844b 569 m_dwLastError = RegSetValueEx((HKEY) m_hKey, szValue, RESERVED, REG_DWORD,
2bda0e17
KB
570 (RegString)&lValue, sizeof(lValue));
571 if ( m_dwLastError == ERROR_SUCCESS )
cf447356 572 return TRUE;
2bda0e17
KB
573 }
574
02569ba8 575 wxLogSysError(m_dwLastError, _("can't set value of '%s'"),
2bda0e17 576 GetFullName(this, szValue));
cf447356 577 return FALSE;
2bda0e17
KB
578}
579
580bool 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;
fd6c844b 585 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, szValue, RESERVED,
2bda0e17
KB
586 &dwType, pBuf, &dwSize);
587 if ( m_dwLastError != ERROR_SUCCESS ) {
02569ba8 588 wxLogSysError(m_dwLastError, _("can't read value of key '%s'"),
2bda0e17 589 GetName().c_str());
cf447356 590 return FALSE;
2bda0e17
KB
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
cf447356 597 return TRUE;
2bda0e17
KB
598 }
599 }
600 else
cf447356 601 return FALSE;
2bda0e17
KB
602}
603
604#endif //Win32
605
606bool 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;
fd6c844b 612 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, szValue, RESERVED,
2bda0e17
KB
613 &dwType, NULL, &dwSize);
614 if ( m_dwLastError == ERROR_SUCCESS ) {
615 RegString pBuf = (RegString)strValue.GetWriteBuf(dwSize);
fd6c844b 616 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, szValue, RESERVED,
2bda0e17 617 &dwType, pBuf, &dwSize);
44a6c8e6 618 strValue.UngetWriteBuf();
2bda0e17
KB
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
cf447356 624 return TRUE;
2bda0e17
KB
625 }
626 }
627 #else //WIN16
628 // named registry values don't exist in Win16
629 wxASSERT( IsEmpty(szValue) );
630
fd6c844b 631 m_dwLastError = RegQueryValue((HKEY) m_hKey, 0, strValue.GetWriteBuf(256), &l);
44a6c8e6 632 strValue.UngetWriteBuf();
2bda0e17 633 if ( m_dwLastError == ERROR_SUCCESS )
cf447356 634 return TRUE;
2bda0e17
KB
635 #endif //WIN16/32
636 }
637
02569ba8 638 wxLogSysError(m_dwLastError, _("can't read value of '%s'"),
2bda0e17 639 GetFullName(this, szValue));
cf447356 640 return FALSE;
2bda0e17
KB
641}
642
643bool wxRegKey::SetValue(const char *szValue, const wxString& strValue)
644{
645 if ( CONST_CAST Open() ) {
646 #ifdef __WIN32__
fd6c844b 647 m_dwLastError = RegSetValueEx((HKEY) m_hKey, szValue, RESERVED, REG_SZ,
2bda0e17
KB
648 (RegString)strValue.c_str(),
649 strValue.Len() + 1);
650 if ( m_dwLastError == ERROR_SUCCESS )
cf447356 651 return TRUE;
2bda0e17
KB
652 #else //WIN16
653 // named registry values don't exist in Win16
654 wxASSERT( IsEmpty(szValue) );
655
fd6c844b 656 m_dwLastError = RegSetValue((HKEY) m_hKey, NULL, REG_SZ, strValue, NULL);
2bda0e17 657 if ( m_dwLastError == ERROR_SUCCESS )
cf447356 658 return TRUE;
2bda0e17
KB
659 #endif //WIN16/32
660 }
661
02569ba8 662 wxLogSysError(m_dwLastError, _("can't set value of '%s'"),
2bda0e17 663 GetFullName(this, szValue));
cf447356 664 return FALSE;
2bda0e17
KB
665}
666
667wxRegKey::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
2bda0e17
KB
680bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex)
681{
682 if ( !Open() )
cf447356 683 return FALSE;
2bda0e17
KB
684
685 lIndex = 0;
0b1c5a6c 686 return GetNextValue(strValueName, lIndex);
2bda0e17
KB
687}
688
689bool wxRegKey::GetNextValue(wxString& strValueName, long& lIndex) const
690{
691 wxASSERT( IsOpened() );
2bda0e17 692
0b1c5a6c
VZ
693 // are we already at the end of enumeration?
694 if ( lIndex == -1 )
cf447356 695 return FALSE;
2bda0e17 696
0b1c5a6c
VZ
697 #ifdef __WIN32__
698 char szValueName[1024]; // @@ use RegQueryInfoKey...
699 DWORD dwValueLen = WXSIZEOF(szValueName);
2bda0e17 700
0b1c5a6c 701 lIndex++;
fd6c844b 702 m_dwLastError = RegEnumValue((HKEY) m_hKey, lIndex,
0b1c5a6c
VZ
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 {
02569ba8 715 wxLogSysError(m_dwLastError, _("can't enumerate values of key '%s'"),
0b1c5a6c
VZ
716 GetName().c_str());
717 }
718
cf447356 719 return FALSE;
2bda0e17
KB
720 }
721
0b1c5a6c
VZ
722 strValueName = szValueName;
723 #else //WIN16
724 // only one unnamed value
725 wxASSERT( lIndex == 0 );
2bda0e17 726
0b1c5a6c
VZ
727 lIndex = -1;
728 strValueName.Empty();
729 #endif
730
cf447356 731 return TRUE;
2bda0e17 732}
2bda0e17
KB
733
734bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex)
735{
736 if ( !Open() )
cf447356 737 return FALSE;
2bda0e17 738
2bda0e17 739 lIndex = 0;
0b1c5a6c 740 return GetNextKey(strKeyName, lIndex);
2bda0e17
KB
741}
742
743bool wxRegKey::GetNextKey(wxString& strKeyName, long& lIndex) const
744{
745 wxASSERT( IsOpened() );
0b1c5a6c
VZ
746
747 // are we already at the end of enumeration?
748 if ( lIndex == -1 )
cf447356 749 return FALSE;
2bda0e17
KB
750
751 char szKeyName[_MAX_PATH + 1];
fd6c844b 752 m_dwLastError = RegEnumKey((HKEY) m_hKey, lIndex++, szKeyName, WXSIZEOF(szKeyName));
2bda0e17
KB
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 {
02569ba8 760 wxLogSysError(m_dwLastError, _("can't enumerate subkeys of key '%s'"),
2bda0e17
KB
761 GetName().c_str());
762 }
763
cf447356 764 return FALSE;
2bda0e17
KB
765 }
766
767 strKeyName = szKeyName;
cf447356 768 return TRUE;
2bda0e17
KB
769}
770
771// ============================================================================
1880e452 772// implementation of global private functions
2bda0e17 773// ============================================================================
fd6c844b 774bool KeyExists(WXHKEY hRootKey, const char *szKey)
2bda0e17
KB
775{
776 HKEY hkeyDummy;
fd6c844b 777 if ( RegOpenKey( (HKEY) hRootKey, szKey, &hkeyDummy) == ERROR_SUCCESS ) {
2bda0e17 778 RegCloseKey(hkeyDummy);
cf447356 779 return TRUE;
2bda0e17
KB
780 }
781 else
cf447356 782 return FALSE;
2bda0e17
KB
783}
784
785const 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();
0b1c5a6c
VZ
793}
794
795void RemoveTrailingSeparator(wxString& str)
796{
797 if ( !str.IsEmpty() && str.Last() == REG_SEPARATOR )
798 str.Truncate(str.Len() - 1);
799}
1880e452
VZ
800
801// ============================================================================
802// global public functions
803// ============================================================================
804
805bool 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);
41286812 817 if ( key.Open() ) {
1880e452
VZ
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
826bool 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);
41286812 840 if ( key.Open() ) {
1880e452
VZ
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
849bool 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);
41286812 863 if ( key.Open() ) {
1880e452
VZ
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;
41286812
VZ
870}
871
872bool 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
918bool 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}
fd6c844b
JS
934
935