]>
Commit | Line | Data |
---|---|---|
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 | |
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? | |
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 |
110 | static inline void RemoveTrailingSeparator(wxString& str); | |
111 | ||
cf447356 | 112 | // returns TRUE if given registry key exists |
fd6c844b | 113 | static bool KeyExists(WXHKEY hRootKey, const char *szKey); |
2bda0e17 KB |
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. | |
c86f1403 | 131 | const 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 | 139 | const 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 | ||
147 | wxRegKey::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 | 175 | wxRegKey::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 | ||
191 | wxRegKey::wxRegKey() | |
192 | { | |
193 | m_hKey = 0; | |
fd6c844b | 194 | m_hRootKey = (WXHKEY) aStdKeys[HKCR].hkey; |
2bda0e17 KB |
195 | m_dwLastError = 0; |
196 | } | |
197 | ||
198 | wxRegKey::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 | |
206 | wxRegKey::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 | |
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 | |
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 | |
233 | wxRegKey::~wxRegKey() | |
234 | { | |
235 | Close(); | |
236 | } | |
237 | ||
0b1c5a6c VZ |
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; | |
fd6c844b | 248 | m_hRootKey = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey; |
0b1c5a6c VZ |
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); | |
fd6c844b | 258 | m_hRootKey = (WXHKEY) aStdKeys[keyParent].hkey; |
0b1c5a6c VZ |
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 | |
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 | 278 | void 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 |
290 | bool 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) | |
297 | wxString 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 |
309 | bool wxRegKey::GetKeyInfo(size_t* pnSubKeys, |
310 | size_t* pnMaxKeyLen, | |
311 | size_t* pnValues, | |
312 | size_t* pnMaxValueLen) const | |
088a95f5 | 313 | #else |
02569ba8 VZ |
314 | bool 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) | |
356 | bool 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 | |
376 | bool 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 |
401 | bool 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 |
423 | bool 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 | ||
466 | bool 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 | ||
475 | bool 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 |
508 | bool 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 |
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 | ||
cf447356 | 535 | // returns TRUE if given subkey exists |
2bda0e17 KB |
536 | bool 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 | ||
544 | wxRegKey::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__ | |
566 | bool 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 | ||
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; | |
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 | ||
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; | |
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 | ||
643 | bool 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 | ||
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 | ||
2bda0e17 KB |
680 | bool 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 | ||
689 | bool 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 | |
734 | bool 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 | ||
743 | bool 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 | 774 | bool 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 | ||
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(); | |
0b1c5a6c VZ |
793 | } |
794 | ||
795 | void 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 | ||
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); | |
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 | ||
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); | |
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 | ||
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); | |
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 | ||
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 | } | |
fd6c844b JS |
934 | |
935 |