1/////////////////////////////////////////////////////////////////////////////// 2// Name: src/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: registry.cpp 47482 2007-07-15 14:12:08Z VS $ 8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 9// Licence: wxWindows licence 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// for compilers that support precompilation, includes "wx.h". 16#include "wx/wxprec.h" 17 18#ifdef __BORLANDC__ 19 #pragma hdrstop 20#endif 21 22#ifndef WX_PRECOMP 23 #include "wx/msw/wrapwin.h" 24 #include "wx/string.h" 25 #include "wx/intl.h" 26 #include "wx/log.h" 27#endif 28 29#include "wx/file.h" 30#include "wx/wfstream.h" 31 32// Windows headers 33#ifdef __WXWINCE__ 34#include "wx/msw/private.h" 35#include <winbase.h> 36#include <winreg.h> 37#endif 38 39// other std headers 40#include <stdlib.h> // for _MAX_PATH 41 42#ifndef _MAX_PATH 43 #define _MAX_PATH 512 44#endif 45 46// our header 47#define HKEY_DEFINED // already defined in windows.h 48#include "wx/msw/registry.h" 49 50// some registry functions don't like signed chars 51typedef unsigned char *RegString; 52typedef BYTE* RegBinary; 53 54#ifndef HKEY_PERFORMANCE_DATA 55 #define HKEY_PERFORMANCE_DATA ((HKEY)0x80000004) 56#endif 57 58#ifndef HKEY_CURRENT_CONFIG 59 #define HKEY_CURRENT_CONFIG ((HKEY)0x80000005) 60#endif 61 62#ifndef HKEY_DYN_DATA 63 #define HKEY_DYN_DATA ((HKEY)0x80000006) 64#endif 65 66// ---------------------------------------------------------------------------- 67// constants 68// ---------------------------------------------------------------------------- 69 70// the standard key names, short names and handles all bundled together for 71// convenient access 72static struct 73{ 74 HKEY hkey; 75 const wxChar *szName; 76 const wxChar *szShortName; 77} 78aStdKeys[] = 79{ 80 { HKEY_CLASSES_ROOT, wxT("HKEY_CLASSES_ROOT"), wxT("HKCR") }, 81 { HKEY_CURRENT_USER, wxT("HKEY_CURRENT_USER"), wxT("HKCU") }, 82 { HKEY_LOCAL_MACHINE, wxT("HKEY_LOCAL_MACHINE"), wxT("HKLM") }, 83 { HKEY_USERS, wxT("HKEY_USERS"), wxT("HKU") }, // short name? 84 { HKEY_PERFORMANCE_DATA, wxT("HKEY_PERFORMANCE_DATA"), wxT("HKPD") }, 85 { HKEY_CURRENT_CONFIG, wxT("HKEY_CURRENT_CONFIG"), wxT("HKCC") }, 86 { HKEY_DYN_DATA, wxT("HKEY_DYN_DATA"), wxT("HKDD") }, // short name? 87}; 88 89// the registry name separator (perhaps one day MS will change it to '/' ;-) 90#define REG_SEPARATOR wxT('\\') 91 92// useful for Windows programmers: makes somewhat more clear all these zeroes 93// being passed to Windows APIs 94#define RESERVED (0) 95 96// ---------------------------------------------------------------------------- 97// macros 98// ---------------------------------------------------------------------------- 99 100// const_cast<> is not yet supported by all compilers 101#define CONST_CAST ((wxRegKey *)this)-> 102 103// and neither is mutable which m_dwLastError should be 104#define m_dwLastError CONST_CAST m_dwLastError 105 106// ---------------------------------------------------------------------------- 107// non member functions 108// ---------------------------------------------------------------------------- 109 110// removes the trailing backslash from the string if it has one 111static inline void RemoveTrailingSeparator(wxString& str); 112 113// returns true if given registry key exists 114static bool KeyExists(WXHKEY hRootKey, const wxChar *szKey); 115 116// combines value and key name (uses static buffer!) 117static const wxChar *GetFullName(const wxRegKey *pKey, 118 const wxChar *szValue = NULL); 119 120static inline const wxChar *RegValueStr(const wxChar *szValue) 121{ 122 return wxIsEmpty(szValue) ? NULL : szValue; 123} 124 125// ============================================================================ 126// implementation of wxRegKey class 127// ============================================================================ 128 129// ---------------------------------------------------------------------------- 130// static functions and variables 131// ---------------------------------------------------------------------------- 132 133const size_t wxRegKey::nStdKeys = WXSIZEOF(aStdKeys); 134 135// @@ should take a `StdKey key', but as it's often going to be used in loops 136// it would require casts in user code. 137const wxChar *wxRegKey::GetStdKeyName(size_t key) 138{ 139 // return empty string if key is invalid 140 wxCHECK_MSG( key < nStdKeys, wxEmptyString, wxT("invalid key in wxRegKey::GetStdKeyName") ); 141 142 return aStdKeys[key].szName; 143} 144 145const wxChar *wxRegKey::GetStdKeyShortName(size_t key) 146{ 147 // return empty string if key is invalid 148 wxCHECK( key < nStdKeys, wxEmptyString ); 149 150 return aStdKeys[key].szShortName; 151} 152 153wxRegKey::StdKey wxRegKey::ExtractKeyName(wxString& strKey) 154{ 155 wxString strRoot = strKey.BeforeFirst(REG_SEPARATOR); 156 157 size_t ui; 158 for ( ui = 0; ui < nStdKeys; ui++ ) { 159 if ( strRoot.CmpNoCase(aStdKeys[ui].szName) == 0 || 160 strRoot.CmpNoCase(aStdKeys[ui].szShortName) == 0 ) { 161 break; 162 } 163 } 164 165 if ( ui == nStdKeys ) { 166 wxFAIL_MSG(wxT("invalid key prefix in wxRegKey::ExtractKeyName.")); 167 168 ui = HKCR; 169 } 170 else { 171 strKey = strKey.After(REG_SEPARATOR); 172 if ( !strKey.empty() && strKey.Last() == REG_SEPARATOR ) 173 strKey.Truncate(strKey.Len() - 1); 174 } 175 176 return (StdKey)ui; 177} 178 179wxRegKey::StdKey wxRegKey::GetStdKeyFromHkey(WXHKEY hkey) 180{ 181 for ( size_t ui = 0; ui < nStdKeys; ui++ ) { 182 if ( aStdKeys[ui].hkey == (HKEY)hkey ) 183 return (StdKey)ui; 184 } 185 186 wxFAIL_MSG(wxT("non root hkey passed to wxRegKey::GetStdKeyFromHkey.")); 187 188 return HKCR; 189} 190 191// ---------------------------------------------------------------------------- 192// ctors and dtor 193// ---------------------------------------------------------------------------- 194 195wxRegKey::wxRegKey() 196{ 197 m_hRootKey = (WXHKEY) aStdKeys[HKCR].hkey; 198 199 Init(); 200} 201 202wxRegKey::wxRegKey(const wxString& strKey) : m_strKey(strKey) 203{ 204 m_hRootKey = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey; 205 206 Init(); 207} 208 209// parent is a predefined (and preopened) key 210wxRegKey::wxRegKey(StdKey keyParent, const wxString& strKey) : m_strKey(strKey) 211{ 212 RemoveTrailingSeparator(m_strKey); 213 m_hRootKey = (WXHKEY) aStdKeys[keyParent].hkey; 214 215 Init(); 216} 217 218// parent is a normal regkey 219wxRegKey::wxRegKey(const wxRegKey& keyParent, const wxString& strKey) 220 : m_strKey(keyParent.m_strKey) 221{ 222 // combine our name with parent's to get the full name 223 if ( !m_strKey.empty() && 224 (strKey.empty() || strKey[0] != REG_SEPARATOR) ) { 225 m_strKey += REG_SEPARATOR; 226 } 227 228 m_strKey += strKey; 229 RemoveTrailingSeparator(m_strKey); 230 231 m_hRootKey = keyParent.m_hRootKey; 232 233 Init(); 234} 235 236// dtor closes the key releasing system resource 237wxRegKey::~wxRegKey() 238{ 239 Close(); 240} 241 242// ---------------------------------------------------------------------------- 243// change the key name/hkey 244// ---------------------------------------------------------------------------- 245 246// set the full key name 247void wxRegKey::SetName(const wxString& strKey) 248{ 249 Close(); 250 251 m_strKey = strKey; 252 m_hRootKey = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey; 253} 254 255// the name is relative to the parent key 256void wxRegKey::SetName(StdKey keyParent, const wxString& strKey) 257{ 258 Close(); 259 260 m_strKey = strKey; 261 RemoveTrailingSeparator(m_strKey); 262 m_hRootKey = (WXHKEY) aStdKeys[keyParent].hkey; 263} 264 265// the name is relative to the parent key 266void wxRegKey::SetName(const wxRegKey& keyParent, const wxString& strKey) 267{ 268 Close(); 269 270 // combine our name with parent's to get the full name 271 272 // NB: this method is called by wxRegConfig::SetPath() which is a performance 273 // critical function and so it preallocates space for our m_strKey to 274 // gain some speed - this is why we only use += here and not = which 275 // would just free the prealloc'd buffer and would have to realloc it the 276 // next line! 277 m_strKey.clear(); 278 m_strKey += keyParent.m_strKey; 279 if ( !strKey.empty() && strKey[0] != REG_SEPARATOR ) 280 m_strKey += REG_SEPARATOR; 281 m_strKey += strKey; 282 283 RemoveTrailingSeparator(m_strKey); 284 285 m_hRootKey = keyParent.m_hRootKey; 286} 287 288// hKey should be opened and will be closed in wxRegKey dtor 289void wxRegKey::SetHkey(WXHKEY hKey) 290{ 291 Close(); 292 293 m_hKey = hKey; 294} 295 296// ---------------------------------------------------------------------------- 297// info about the key 298// ---------------------------------------------------------------------------- 299 300// returns true if the key exists 301bool wxRegKey::Exists() const 302{ 303 // opened key has to exist, try to open it if not done yet 304 return IsOpened() ? true : KeyExists(m_hRootKey, m_strKey); 305} 306 307// returns the full name of the key (prefix is abbreviated if bShortPrefix) 308wxString wxRegKey::GetName(bool bShortPrefix) const 309{ 310 StdKey key = GetStdKeyFromHkey((WXHKEY) m_hRootKey); 311 wxString str = bShortPrefix ? aStdKeys[key].szShortName 312 : aStdKeys[key].szName; 313 if ( !m_strKey.empty() ) 314 str << _T("\\") << m_strKey; 315 316 return str; 317} 318 319bool wxRegKey::GetKeyInfo(size_t *pnSubKeys, 320 size_t *pnMaxKeyLen, 321 size_t *pnValues, 322 size_t *pnMaxValueLen) const 323{ 324 // old gcc headers incorrectly prototype RegQueryInfoKey() 325#if defined(__GNUWIN32_OLD__) && !defined(__CYGWIN10__) 326 #define REG_PARAM (size_t *) 327#else 328 #define REG_PARAM (LPDWORD) 329#endif 330 331 // it might be unexpected to some that this function doesn't open the key 332 wxASSERT_MSG( IsOpened(), _T("key should be opened in GetKeyInfo") ); 333 334 m_dwLastError = ::RegQueryInfoKey 335 ( 336 (HKEY) m_hKey, 337 NULL, // class name 338 NULL, // (ptr to) size of class name buffer 339 RESERVED, 340 REG_PARAM 341 pnSubKeys, // [out] number of subkeys 342 REG_PARAM 343 pnMaxKeyLen, // [out] max length of a subkey name 344 NULL, // longest subkey class name 345 REG_PARAM 346 pnValues, // [out] number of values 347 REG_PARAM 348 pnMaxValueLen, // [out] max length of a value name 349 NULL, // longest value data 350 NULL, // security descriptor 351 NULL // time of last modification 352 ); 353 354#undef REG_PARAM 355 356 if ( m_dwLastError != ERROR_SUCCESS ) { 357 wxLogSysError(m_dwLastError, _("Can't get info about registry key '%s'"), 358 GetName().c_str()); 359 return false; 360 } 361 362 return true; 363} 364 365// ---------------------------------------------------------------------------- 366// operations 367// ---------------------------------------------------------------------------- 368 369// opens key (it's not an error to call Open() on an already opened key) 370bool wxRegKey::Open(AccessMode mode) 371{ 372 if ( IsOpened() ) 373 { 374 if ( mode <= m_mode ) 375 return true; 376 377 // we had been opened in read mode but now must be reopened in write 378 Close(); 379 } 380 381 HKEY tmpKey; 382 m_dwLastError = ::RegOpenKeyEx 383 ( 384 (HKEY) m_hRootKey, 385 m_strKey, 386 RESERVED, 387 mode == Read ? KEY_READ : KEY_ALL_ACCESS, 388 &tmpKey 389 ); 390 391 if ( m_dwLastError != ERROR_SUCCESS ) 392 { 393 wxLogSysError(m_dwLastError, _("Can't open registry key '%s'"), 394 GetName().c_str()); 395 return false; 396 } 397 398 m_hKey = (WXHKEY) tmpKey; 399 m_mode = mode; 400 401 return true; 402} 403 404// creates key, failing if it exists and !bOkIfExists 405bool wxRegKey::Create(bool bOkIfExists) 406{ 407 // check for existence only if asked (i.e. order is important!) 408 if ( !bOkIfExists && Exists() ) 409 return false; 410 411 if ( IsOpened() ) 412 return true; 413 414 HKEY tmpKey; 415#ifdef __WXWINCE__ 416 DWORD disposition; 417 m_dwLastError = RegCreateKeyEx((HKEY) m_hRootKey, m_strKey, 418 NULL, // reserved 419 NULL, // class string 420 0, 421 0, 422 NULL, 423 &tmpKey, 424 &disposition); 425#else 426 m_dwLastError = RegCreateKey((HKEY) m_hRootKey, m_strKey, &tmpKey); 427#endif 428 if ( m_dwLastError != ERROR_SUCCESS ) { 429 wxLogSysError(m_dwLastError, _("Can't create registry key '%s'"), 430 GetName().c_str()); 431 return false; 432 } 433 else 434 { 435 m_hKey = (WXHKEY) tmpKey; 436 return true; 437 } 438} 439 440// close the key, it's not an error to call it when not opened 441bool wxRegKey::Close() 442{ 443 if ( IsOpened() ) { 444 m_dwLastError = RegCloseKey((HKEY) m_hKey); 445 m_hKey = 0; 446 447 if ( m_dwLastError != ERROR_SUCCESS ) { 448 wxLogSysError(m_dwLastError, _("Can't close registry key '%s'"), 449 GetName().c_str()); 450 451 return false; 452 } 453 } 454 455 return true; 456} 457 458bool wxRegKey::RenameValue(const wxChar *szValueOld, const wxChar *szValueNew) 459{ 460 bool ok = true; 461 if ( HasValue(szValueNew) ) { 462 wxLogError(_("Registry value '%s' already exists."), szValueNew); 463 464 ok = false; 465 } 466 467 if ( !ok || 468 !CopyValue(szValueOld, *this, szValueNew) || 469 !DeleteValue(szValueOld) ) { 470 wxLogError(_("Failed to rename registry value '%s' to '%s'."), 471 szValueOld, szValueNew); 472 473 return false; 474 } 475 476 return true; 477} 478 479bool wxRegKey::CopyValue(const wxChar *szValue, 480 wxRegKey& keyDst, 481 const wxChar *szValueNew) 482{ 483 if ( wxIsEmpty(szValueNew) ) { 484 // by default, use the same name 485 szValueNew = szValue; 486 } 487 488 switch ( GetValueType(szValue) ) { 489 case Type_String: 490 { 491 wxString strVal; 492 return QueryValue(szValue, strVal) && 493 keyDst.SetValue(szValueNew, strVal); 494 } 495 496 case Type_Dword: 497 /* case Type_Dword_little_endian: == Type_Dword */ 498 { 499 long dwVal; 500 return QueryValue(szValue, &dwVal) && 501 keyDst.SetValue(szValueNew, dwVal); 502 } 503 504 case Type_Binary: 505 { 506 wxMemoryBuffer buf; 507 return QueryValue(szValue,buf) && 508 keyDst.SetValue(szValueNew,buf); 509 } 510 511 // these types are unsupported because I am not sure about how 512 // exactly they should be copied and because they shouldn't 513 // occur among the application keys (supposedly created with 514 // this class) 515 case Type_None: 516 case Type_Expand_String: 517 case Type_Dword_big_endian: 518 case Type_Link: 519 case Type_Multi_String: 520 case Type_Resource_list: 521 case Type_Full_resource_descriptor: 522 case Type_Resource_requirements_list: 523 default: 524 wxLogError(_("Can't copy values of unsupported type %d."), 525 GetValueType(szValue)); 526 return false; 527 } 528} 529 530bool wxRegKey::Rename(const wxChar *szNewName) 531{ 532 wxCHECK_MSG( !m_strKey.empty(), false, _T("registry hives can't be renamed") ); 533 534 if ( !Exists() ) { 535 wxLogError(_("Registry key '%s' does not exist, cannot rename it."), 536 GetFullName(this)); 537 538 return false; 539 } 540 541 // do we stay in the same hive? 542 bool inSameHive = !wxStrchr(szNewName, REG_SEPARATOR); 543 544 // construct the full new name of the key 545 wxRegKey keyDst; 546 547 if ( inSameHive ) { 548 // rename the key to the new name under the same parent 549 wxString strKey = m_strKey.BeforeLast(REG_SEPARATOR); 550 if ( !strKey.empty() ) { 551 // don't add '\\' in the start if strFullNewName is empty 552 strKey += REG_SEPARATOR; 553 } 554 555 strKey += szNewName; 556 557 keyDst.SetName(GetStdKeyFromHkey(m_hRootKey), strKey); 558 } 559 else { 560 // this is the full name already 561 keyDst.SetName(szNewName); 562 } 563 564 bool ok = keyDst.Create(false /* fail if alredy exists */); 565 if ( !ok ) { 566 wxLogError(_("Registry key '%s' already exists."), 567 GetFullName(&keyDst)); 568 } 569 else { 570 ok = Copy(keyDst) && DeleteSelf(); 571 } 572 573 if ( !ok ) { 574 wxLogError(_("Failed to rename the registry key '%s' to '%s'."), 575 GetFullName(this), GetFullName(&keyDst)); 576 } 577 else { 578 m_hRootKey = keyDst.m_hRootKey; 579 m_strKey = keyDst.m_strKey; 580 } 581 582 return ok; 583} 584 585bool wxRegKey::Copy(const wxChar *szNewName) 586{ 587 // create the new key first 588 wxRegKey keyDst(szNewName); 589 bool ok = keyDst.Create(false /* fail if alredy exists */); 590 if ( ok ) { 591 ok = Copy(keyDst); 592 593 // we created the dest key but copying to it failed - delete it 594 if ( !ok ) { 595 (void)keyDst.DeleteSelf(); 596 } 597 } 598 599 return ok; 600} 601 602bool wxRegKey::Copy(wxRegKey& keyDst) 603{ 604 bool ok = true; 605 606 // copy all sub keys to the new location 607 wxString strKey; 608 long lIndex; 609 bool bCont = GetFirstKey(strKey, lIndex); 610 while ( ok && bCont ) { 611 wxRegKey key(*this, strKey); 612 wxString keyName; 613 keyName << GetFullName(&keyDst) << REG_SEPARATOR << strKey; 614 ok = key.Copy((const wxChar*) keyName); 615 616 if ( ok ) 617 bCont = GetNextKey(strKey, lIndex); 618 else 619 wxLogError(_("Failed to copy the registry subkey '%s' to '%s'."), 620 GetFullName(&key), keyName.c_str()); 621 622 } 623 624 // copy all values 625 wxString strVal; 626 bCont = GetFirstValue(strVal, lIndex); 627 while ( ok && bCont ) { 628 ok = CopyValue(strVal, keyDst); 629 630 if ( !ok ) { 631 wxLogSysError(m_dwLastError, 632 _("Failed to copy registry value '%s'"), 633 strVal.c_str()); 634 } 635 else { 636 bCont = GetNextValue(strVal, lIndex); 637 } 638 } 639 640 if ( !ok ) { 641 wxLogError(_("Failed to copy the contents of registry key '%s' to '%s'."), 642 GetFullName(this), GetFullName(&keyDst)); 643 } 644 645 return ok; 646} 647 648// ---------------------------------------------------------------------------- 649// delete keys/values 650// ---------------------------------------------------------------------------- 651bool wxRegKey::DeleteSelf() 652{ 653 { 654 wxLogNull nolog; 655 if ( !Open() ) { 656 // it already doesn't exist - ok! 657 return true; 658 } 659 } 660 661 // prevent a buggy program from erasing one of the root registry keys or an 662 // immediate subkey (i.e. one which doesn't have '\\' inside) of any other 663 // key except HKCR (HKCR has some "deleteable" subkeys) 664 if ( m_strKey.empty() || 665 ((m_hRootKey != (WXHKEY) aStdKeys[HKCR].hkey) && 666 (m_strKey.Find(REG_SEPARATOR) == wxNOT_FOUND)) ) { 667 wxLogError(_("Registry key '%s' is needed for normal system operation,\ndeleting it will leave your system in unusable state:\noperation aborted."), 668 GetFullName(this)); 669 670 return false; 671 } 672 673 // we can't delete keys while enumerating because it confuses GetNextKey, so 674 // we first save the key names and then delete them all 675 wxArrayString astrSubkeys; 676 677 wxString strKey; 678 long lIndex; 679 bool bCont = GetFirstKey(strKey, lIndex); 680 while ( bCont ) { 681 astrSubkeys.Add(strKey); 682 683 bCont = GetNextKey(strKey, lIndex); 684 } 685 686 size_t nKeyCount = astrSubkeys.Count(); 687 for ( size_t nKey = 0; nKey < nKeyCount; nKey++ ) { 688 wxRegKey key(*this, astrSubkeys[nKey]); 689 if ( !key.DeleteSelf() ) 690 return false; 691 } 692 693 // now delete this key itself 694 Close(); 695 696 m_dwLastError = RegDeleteKey((HKEY) m_hRootKey, m_strKey); 697 // deleting a key which doesn't exist is not considered an error 698 if ( m_dwLastError != ERROR_SUCCESS && 699 m_dwLastError != ERROR_FILE_NOT_FOUND ) { 700 wxLogSysError(m_dwLastError, _("Can't delete key '%s'"), 701 GetName().c_str()); 702 return false; 703 } 704 705 return true; 706} 707 708bool wxRegKey::DeleteKey(const wxChar *szKey) 709{ 710 if ( !Open() ) 711 return false; 712 713 wxRegKey key(*this, szKey); 714 return key.DeleteSelf(); 715} 716 717bool wxRegKey::DeleteValue(const wxChar *szValue) 718{ 719 if ( !Open() ) 720 return false; 721 722 m_dwLastError = RegDeleteValue((HKEY) m_hKey, RegValueStr(szValue)); 723 724 // deleting a value which doesn't exist is not considered an error 725 if ( (m_dwLastError != ERROR_SUCCESS) && 726 (m_dwLastError != ERROR_FILE_NOT_FOUND) ) 727 { 728 wxLogSysError(m_dwLastError, _("Can't delete value '%s' from key '%s'"), 729 szValue, GetName().c_str()); 730 return false; 731 } 732 733 return true; 734} 735 736// ---------------------------------------------------------------------------- 737// access to values and subkeys 738// ---------------------------------------------------------------------------- 739 740// return true if value exists 741bool wxRegKey::HasValue(const wxChar *szValue) const 742{ 743 // this function should be silent, so suppress possible messages from Open() 744 wxLogNull nolog; 745 746 if ( !CONST_CAST Open(Read) ) 747 return false; 748 749 LONG dwRet = ::RegQueryValueEx((HKEY) m_hKey, 750 RegValueStr(szValue), 751 RESERVED, 752 NULL, NULL, NULL); 753 return dwRet == ERROR_SUCCESS; 754} 755 756// returns true if this key has any values 757bool wxRegKey::HasValues() const 758{ 759 // suppress possible messages from GetFirstValue() 760 wxLogNull nolog; 761 762 // just call GetFirstValue with dummy parameters 763 wxString str; 764 long l; 765 return CONST_CAST GetFirstValue(str, l); 766} 767 768// returns true if this key has any subkeys 769bool wxRegKey::HasSubkeys() const 770{ 771 // suppress possible messages from GetFirstKey() 772 wxLogNull nolog; 773 774 // just call GetFirstKey with dummy parameters 775 wxString str; 776 long l; 777 return CONST_CAST GetFirstKey(str, l); 778} 779 780// returns true if given subkey exists 781bool wxRegKey::HasSubKey(const wxChar *szKey) const 782{ 783 // this function should be silent, so suppress possible messages from Open() 784 wxLogNull nolog; 785 786 if ( !CONST_CAST Open(Read) ) 787 return false; 788 789 return KeyExists(m_hKey, szKey); 790} 791 792wxRegKey::ValueType wxRegKey::GetValueType(const wxChar *szValue) const 793{ 794 if ( ! CONST_CAST Open(Read) ) 795 return Type_None; 796 797 DWORD dwType; 798 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, RegValueStr(szValue), RESERVED, 799 &dwType, NULL, NULL); 800 if ( m_dwLastError != ERROR_SUCCESS ) { 801 wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"), 802 GetName().c_str()); 803 return Type_None; 804 } 805 806 return (ValueType)dwType; 807} 808 809bool wxRegKey::SetValue(const wxChar *szValue, long lValue) 810{ 811 if ( CONST_CAST Open() ) { 812 m_dwLastError = RegSetValueEx((HKEY) m_hKey, RegValueStr(szValue), (DWORD) RESERVED, REG_DWORD, 813 (RegString)&lValue, sizeof(lValue)); 814 if ( m_dwLastError == ERROR_SUCCESS ) 815 return true; 816 } 817 818 wxLogSysError(m_dwLastError, _("Can't set value of '%s'"), 819 GetFullName(this, szValue)); 820 return false; 821} 822 823bool wxRegKey::QueryValue(const wxChar *szValue, long *plValue) const 824{ 825 if ( CONST_CAST Open(Read) ) { 826 DWORD dwType, dwSize = sizeof(DWORD); 827 RegString pBuf = (RegString)plValue; 828 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, RegValueStr(szValue), RESERVED, 829 &dwType, pBuf, &dwSize); 830 if ( m_dwLastError != ERROR_SUCCESS ) { 831 wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"), 832 GetName().c_str()); 833 return false; 834 } 835 else { 836 // check that we read the value of right type 837 wxASSERT_MSG( IsNumericValue(szValue), 838 wxT("Type mismatch in wxRegKey::QueryValue().") ); 839 840 return true; 841 } 842 } 843 else 844 return false; 845} 846 847bool wxRegKey::SetValue(const wxChar *szValue,const wxMemoryBuffer& buffer) 848{ 849#ifdef __TWIN32__ 850 wxFAIL_MSG("RegSetValueEx not implemented by TWIN32"); 851 return false; 852#else 853 if ( CONST_CAST Open() ) { 854 m_dwLastError = RegSetValueEx((HKEY) m_hKey, RegValueStr(szValue), (DWORD) RESERVED, REG_BINARY, 855 (RegBinary)buffer.GetData(),buffer.GetDataLen()); 856 if ( m_dwLastError == ERROR_SUCCESS ) 857 return true; 858 } 859 860 wxLogSysError(m_dwLastError, _("Can't set value of '%s'"), 861 GetFullName(this, szValue)); 862 return false; 863#endif 864} 865 866bool wxRegKey::QueryValue(const wxChar *szValue, wxMemoryBuffer& buffer) const 867{ 868 if ( CONST_CAST Open(Read) ) { 869 // first get the type and size of the data 870 DWORD dwType, dwSize; 871 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, RegValueStr(szValue), RESERVED, 872 &dwType, NULL, &dwSize); 873 874 if ( m_dwLastError == ERROR_SUCCESS ) { 875 if ( dwSize ) { 876 const RegBinary pBuf = (RegBinary)buffer.GetWriteBuf(dwSize); 877 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, 878 RegValueStr(szValue), 879 RESERVED, 880 &dwType, 881 pBuf, 882 &dwSize); 883 buffer.UngetWriteBuf(dwSize); 884 } else { 885 buffer.SetDataLen(0); 886 } 887 } 888 889 890 if ( m_dwLastError != ERROR_SUCCESS ) { 891 wxLogSysError(m_dwLastError, _("Can't read value of key '%s'"), 892 GetName().c_str()); 893 return false; 894 } 895 return true; 896 } 897 return false; 898} 899 900 901 902bool wxRegKey::QueryValue(const wxChar *szValue, 903 wxString& strValue, 904 bool WXUNUSED_IN_WINCE(raw)) const 905{ 906 if ( CONST_CAST Open(Read) ) 907 { 908 909 // first get the type and size of the data 910 DWORD dwType=REG_NONE, dwSize=0; 911 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, 912 RegValueStr(szValue), 913 RESERVED, 914 &dwType, NULL, &dwSize); 915 if ( m_dwLastError == ERROR_SUCCESS ) 916 { 917 if ( !dwSize ) 918 { 919 // must treat this case specially as GetWriteBuf() doesn't like 920 // being called with 0 size 921 strValue.Empty(); 922 } 923 else 924 { 925 m_dwLastError = RegQueryValueEx((HKEY) m_hKey, 926 RegValueStr(szValue), 927 RESERVED, 928 &dwType, 929 (RegString)(wxChar*)wxStringBuffer(strValue, dwSize), 930 &dwSize); 931 932 // expand the var expansions in the string unless disabled 933#ifndef __WXWINCE__ 934 if ( (dwType == REG_EXPAND_SZ) && !raw ) 935 { 936 DWORD dwExpSize = ::ExpandEnvironmentStrings(strValue, NULL, 0); 937 bool ok = dwExpSize != 0; 938 if ( ok ) 939 { 940 wxString strExpValue; 941 ok = ::ExpandEnvironmentStrings(strValue, 942 wxStringBuffer(strExpValue, dwExpSize), 943 dwExpSize 944 ) != 0; 945 strValue = strExpValue; 946 } 947 948 if ( !ok ) 949 { 950 wxLogLastError(_T("ExpandEnvironmentStrings")); 951 } 952 } 953#endif 954 // __WXWINCE__ 955 } 956 957 if ( m_dwLastError == ERROR_SUCCESS ) 958 { 959 // check that it was the right type 960 wxASSERT_MSG( !IsNumericValue(szValue), 961 wxT("Type mismatch in wxRegKey::QueryValue().") ); 962 963 return true; 964 } 965 } 966 } 967 968 wxLogSysError(m_dwLastError, _("Can't read value of '%s'"), 969 GetFullName(this, szValue)); 970 return false; 971} 972 973bool wxRegKey::SetValue(const wxChar *szValue, const wxString& strValue) 974{ 975 if ( CONST_CAST Open() ) { 976 m_dwLastError = RegSetValueEx((HKEY) m_hKey, RegValueStr(szValue), 977 (DWORD) RESERVED, REG_SZ, 978 (RegString)strValue.c_str(), 979 (strValue.Len() + 1)*sizeof(wxChar)); 980 if ( m_dwLastError == ERROR_SUCCESS ) 981 return true; 982 } 983 984 wxLogSysError(m_dwLastError, _("Can't set value of '%s'"), 985 GetFullName(this, szValue)); 986 return false; 987} 988 989wxString wxRegKey::QueryDefaultValue() const 990{ 991 wxString str; 992 QueryValue(NULL, str); 993 return str; 994} 995 996// ---------------------------------------------------------------------------- 997// enumeration 998// NB: all these functions require an index variable which allows to have 999// several concurrently running indexations on the same key 1000// ---------------------------------------------------------------------------- 1001 1002bool wxRegKey::GetFirstValue(wxString& strValueName, long& lIndex) 1003{ 1004 if ( !Open(Read) ) 1005 return false; 1006 1007 lIndex = 0; 1008 return GetNextValue(strValueName, lIndex); 1009} 1010 1011bool wxRegKey::GetNextValue(wxString& strValueName, long& lIndex) const 1012{ 1013 wxASSERT( IsOpened() ); 1014 1015 // are we already at the end of enumeration? 1016 if ( lIndex == -1 ) 1017 return false; 1018 1019 wxChar szValueName[1024]; // @@ use RegQueryInfoKey... 1020 DWORD dwValueLen = WXSIZEOF(szValueName); 1021 1022 m_dwLastError = RegEnumValue((HKEY) m_hKey, lIndex++, 1023 szValueName, &dwValueLen, 1024 RESERVED, 1025 NULL, // [out] type 1026 NULL, // [out] buffer for value 1027 NULL); // [i/o] it's length 1028 1029 if ( m_dwLastError != ERROR_SUCCESS ) { 1030 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) { 1031 m_dwLastError = ERROR_SUCCESS; 1032 lIndex = -1; 1033 } 1034 else { 1035 wxLogSysError(m_dwLastError, _("Can't enumerate values of key '%s'"), 1036 GetName().c_str()); 1037 } 1038 1039 return false; 1040 } 1041 1042 strValueName = szValueName; 1043 1044 return true; 1045} 1046 1047bool wxRegKey::GetFirstKey(wxString& strKeyName, long& lIndex) 1048{ 1049 if ( !Open(Read) ) 1050 return false; 1051 1052 lIndex = 0; 1053 return GetNextKey(strKeyName, lIndex); 1054} 1055 1056bool wxRegKey::GetNextKey(wxString& strKeyName, long& lIndex) const 1057{ 1058 wxASSERT( IsOpened() ); 1059 1060 // are we already at the end of enumeration? 1061 if ( lIndex == -1 ) 1062 return false; 1063 1064 wxChar szKeyName[_MAX_PATH + 1]; 1065 1066#ifdef __WXWINCE__ 1067 DWORD sizeName = WXSIZEOF(szKeyName); 1068 m_dwLastError = RegEnumKeyEx((HKEY) m_hKey, lIndex++, szKeyName, & sizeName, 1069 0, NULL, NULL, NULL); 1070#else 1071 m_dwLastError = RegEnumKey((HKEY) m_hKey, lIndex++, szKeyName, WXSIZEOF(szKeyName)); 1072#endif 1073 1074 if ( m_dwLastError != ERROR_SUCCESS ) { 1075 if ( m_dwLastError == ERROR_NO_MORE_ITEMS ) { 1076 m_dwLastError = ERROR_SUCCESS; 1077 lIndex = -1; 1078 } 1079 else { 1080 wxLogSysError(m_dwLastError, _("Can't enumerate subkeys of key '%s'"), 1081 GetName().c_str()); 1082 } 1083 1084 return false; 1085 } 1086 1087 strKeyName = szKeyName; 1088 return true; 1089} 1090 1091// returns true if the value contains a number (else it's some string) 1092bool wxRegKey::IsNumericValue(const wxChar *szValue) const 1093{ 1094 ValueType type = GetValueType(szValue); 1095 switch ( type ) { 1096 case Type_Dword: 1097 /* case Type_Dword_little_endian: == Type_Dword */ 1098 case Type_Dword_big_endian: 1099 return true; 1100 1101 default: 1102 return false; 1103 } 1104} 1105 1106// ---------------------------------------------------------------------------- 1107// exporting registry keys to file 1108// ---------------------------------------------------------------------------- 1109 1110#if wxUSE_STREAMS 1111 1112// helper functions for writing ASCII strings (even in Unicode build) 1113static inline bool WriteAsciiChar(wxOutputStream& ostr, char ch) 1114{ 1115 ostr.PutC(ch); 1116 return ostr.IsOk(); 1117} 1118 1119static inline bool WriteAsciiEOL(wxOutputStream& ostr) 1120{ 1121 // as we open the file in text mode, it is enough to write LF without CR 1122 return WriteAsciiChar(ostr, '\n'); 1123} 1124 1125static inline bool WriteAsciiString(wxOutputStream& ostr, const char *p) 1126{ 1127 return ostr.Write(p, strlen(p)).IsOk(); 1128} 1129 1130static inline bool WriteAsciiString(wxOutputStream& ostr, const wxString& s) 1131{ 1132#if wxUSE_UNICODE 1133 wxCharBuffer name(s.mb_str()); 1134 ostr.Write(name, strlen(name)); 1135#else 1136 ostr.Write(s, s.length()); 1137#endif 1138 1139 return ostr.IsOk(); 1140} 1141 1142#endif // wxUSE_STREAMS 1143 1144bool wxRegKey::Export(const wxString& filename) const 1145{ 1146#if wxUSE_FFILE && wxUSE_STREAMS 1147 if ( wxFile::Exists(filename) ) 1148 { 1149 wxLogError(_("Exporting registry key: file \"%s\" already exists and won't be overwritten."), 1150 filename.c_str()); 1151 return false; 1152 } 1153 1154 wxFFileOutputStream ostr(filename, _T("w")); 1155 1156 return ostr.Ok() && Export(ostr); 1157#else 1158 wxUnusedVar(filename); 1159 return false; 1160#endif 1161} 1162 1163#if wxUSE_STREAMS 1164bool wxRegKey::Export(wxOutputStream& ostr) const 1165{ 1166 // write out the header 1167 if ( !WriteAsciiString(ostr, "REGEDIT4\n\n") ) 1168 return false; 1169 1170 return DoExport(ostr); 1171} 1172#endif // wxUSE_STREAMS 1173 1174static 1175wxString 1176FormatAsHex(const void *data, 1177 size_t size, 1178 wxRegKey::ValueType type = wxRegKey::Type_Binary) 1179{ 1180 wxString value(_T("hex")); 1181 1182 // binary values use just "hex:" prefix while the other ones must indicate 1183 // the real type 1184 if ( type != wxRegKey::Type_Binary ) 1185 value << _T('(') << type << _T(')'); 1186 value << _T(':'); 1187 1188 // write all the rest as comma-separated bytes 1189 value.reserve(3*size + 10); 1190 const char * const p = wx_static_cast(const char *, data); 1191 for ( size_t n = 0; n < size; n++ ) 1192 { 1193 // TODO: line wrapping: although not required by regedit, this makes 1194 // the generated files easier to read and compare with the files 1195 // produced by regedit 1196 if ( n ) 1197 value << _T(','); 1198 1199 value << wxString::Format(_T("%02x"), (unsigned char)p[n]); 1200 } 1201 1202 return value; 1203} 1204 1205static inline 1206wxString FormatAsHex(const wxString& value, wxRegKey::ValueType type) 1207{ 1208 return FormatAsHex(value.c_str(), value.length() + 1, type); 1209} 1210 1211wxString wxRegKey::FormatValue(const wxString& name) const 1212{ 1213 wxString rhs; 1214 const ValueType type = GetValueType(name); 1215 switch ( type ) 1216 { 1217 case Type_String: 1218 { 1219 wxString value; 1220 if ( !QueryValue(name, value) ) 1221 break; 1222 1223 // quotes and backslashes must be quoted, linefeeds are not 1224 // allowed in string values 1225 rhs.reserve(value.length() + 2); 1226 rhs = _T('"'); 1227 1228 // there can be no NULs here 1229 bool useHex = false; 1230 for ( const wxChar *p = value.c_str(); *p && !useHex; p++ ) 1231 { 1232 switch ( *p ) 1233 { 1234 case _T('\n'): 1235 // we can only represent this string in hex 1236 useHex = true; 1237 break; 1238 1239 case _T('"'): 1240 case _T('\\'): 1241 // escape special symbol 1242 rhs += _T('\\'); 1243 // fall through 1244 1245 default: 1246 rhs += *p; 1247 } 1248 } 1249 1250 if ( useHex ) 1251 rhs = FormatAsHex(value, Type_String); 1252 else 1253 rhs += _T('"'); 1254 } 1255 break; 1256 1257 case Type_Dword: 1258 /* case Type_Dword_little_endian: == Type_Dword */ 1259 { 1260 long value; 1261 if ( !QueryValue(name, &value) ) 1262 break; 1263 1264 rhs.Printf(_T("dword:%08x"), (unsigned int)value); 1265 } 1266 break; 1267 1268 case Type_Expand_String: 1269 case Type_Multi_String: 1270 { 1271 wxString value; 1272 if ( !QueryRawValue(name, value) ) 1273 break; 1274 1275 rhs = FormatAsHex(value, type); 1276 } 1277 break; 1278 1279 case Type_Binary: 1280 { 1281 wxMemoryBuffer buf; 1282 if ( !QueryValue(name, buf) ) 1283 break; 1284 1285 rhs = FormatAsHex(buf.GetData(), buf.GetDataLen()); 1286 } 1287 break; 1288 1289 // no idea how those appear in REGEDIT4 files 1290 case Type_None: 1291 case Type_Dword_big_endian: 1292 case Type_Link: 1293 case Type_Resource_list: 1294 case Type_Full_resource_descriptor: 1295 case Type_Resource_requirements_list: 1296 default: 1297 wxLogWarning(_("Can't export value of unsupported type %d."), type); 1298 } 1299 1300 return rhs; 1301} 1302 1303#if wxUSE_STREAMS 1304 1305bool wxRegKey::DoExportValue(wxOutputStream& ostr, const wxString& name) const 1306{ 1307 // first examine the value type: if it's unsupported, simply skip it 1308 // instead of aborting the entire export process because we failed to 1309 // export a single value 1310 wxString value = FormatValue(name); 1311 if ( value.empty() ) 1312 { 1313 wxLogWarning(_("Ignoring value \"%s\" of the key \"%s\"."), 1314 name.c_str(), GetName().c_str()); 1315 return true; 1316 } 1317 1318 // we do have the text representation of the value, now write everything 1319 // out 1320 1321 // special case: unnamed/default value is represented as just "@" 1322 if ( name.empty() ) 1323 { 1324 if ( !WriteAsciiChar(ostr, '@') ) 1325 return false; 1326 } 1327 else // normal, named, value 1328 { 1329 if ( !WriteAsciiChar(ostr, '"') || 1330 !WriteAsciiString(ostr, name) || 1331 !WriteAsciiChar(ostr, '"') ) 1332 return false; 1333 } 1334 1335 if ( !WriteAsciiChar(ostr, '=') ) 1336 return false; 1337 1338 return WriteAsciiString(ostr, value) && WriteAsciiEOL(ostr); 1339} 1340 1341bool wxRegKey::DoExport(wxOutputStream& ostr) const 1342{ 1343 // write out this key name 1344 if ( !WriteAsciiChar(ostr, '[') ) 1345 return false; 1346 1347 if ( !WriteAsciiString(ostr, GetName(false /* no short prefix */)) ) 1348 return false; 1349 1350 if ( !WriteAsciiChar(ostr, ']') || !WriteAsciiEOL(ostr) ) 1351 return false; 1352 1353 // dump all our values 1354 long dummy; 1355 wxString name; 1356 wxRegKey& self = wx_const_cast(wxRegKey&, *this); 1357 bool cont = self.GetFirstValue(name, dummy); 1358 while ( cont ) 1359 { 1360 if ( !DoExportValue(ostr, name) ) 1361 return false; 1362 1363 cont = GetNextValue(name, dummy); 1364 } 1365 1366 // always terminate values by blank line, even if there were no values 1367 if ( !WriteAsciiEOL(ostr) ) 1368 return false; 1369 1370 // recurse to subkeys 1371 cont = self.GetFirstKey(name, dummy); 1372 while ( cont ) 1373 { 1374 wxRegKey subkey(*this, name); 1375 if ( !subkey.DoExport(ostr) ) 1376 return false; 1377 1378 cont = GetNextKey(name, dummy); 1379 } 1380 1381 return true; 1382} 1383 1384#endif // wxUSE_STREAMS 1385 1386// ============================================================================ 1387// implementation of global private functions 1388// ============================================================================ 1389 1390bool KeyExists(WXHKEY hRootKey, const wxChar *szKey) 1391{ 1392 // don't close this key itself for the case of empty szKey! 1393 if ( wxIsEmpty(szKey) ) 1394 return true; 1395 1396 HKEY hkeyDummy; 1397 if ( ::RegOpenKeyEx 1398 ( 1399 (HKEY)hRootKey, 1400 szKey, 1401 RESERVED, 1402 KEY_READ, // we might not have enough rights for rw access 1403 &hkeyDummy 1404 ) == ERROR_SUCCESS ) 1405 { 1406 ::RegCloseKey(hkeyDummy); 1407 1408 return true; 1409 } 1410 1411 return false; 1412} 1413 1414const wxChar *GetFullName(const wxRegKey *pKey, const wxChar *szValue) 1415{ 1416 static wxString s_str; 1417 s_str = pKey->GetName(); 1418 if ( !wxIsEmpty(szValue) ) 1419 s_str << wxT("\\") << szValue; 1420 1421 return s_str.c_str(); 1422} 1423 1424inline void RemoveTrailingSeparator(wxString& str) 1425{ 1426 if ( !str.empty() && str.Last() == REG_SEPARATOR ) 1427 str.Truncate(str.Len() - 1); 1428} 1429