1 // Written by Christopher E. Miller 2 // See the included license.txt for copyright and license details. 3 4 5 // Not actually part of forms, but is handy. 6 7 /// 8 module dfl.registry; 9 10 private import dfl.internal.dlib; 11 12 private import dfl.internal.winapi, dfl.base, dfl.internal.utf; 13 14 15 class DflRegistryException: DflException // package 16 { 17 this(Dstring msg, int errorCode = 0) 18 { 19 this.errorCode = errorCode; 20 debug 21 { 22 if(errorCode) 23 msg = msg ~ " (error " ~ intToString(errorCode) ~ ")"; // Dup. 24 } 25 super(msg); 26 } 27 28 29 int errorCode; 30 } 31 32 33 /// 34 class Registry // docmain 35 { 36 private this() {} 37 38 39 static: 40 41 /// 42 @property RegistryKey classesRoot() // getter 43 { 44 if(!_classesRoot) 45 _classesRoot = new RegistryKey(HKEY_CLASSES_ROOT, false); 46 return _classesRoot; 47 } 48 49 /// ditto 50 @property RegistryKey currentConfig() // getter 51 { 52 if(!_currentConfig) 53 _currentConfig = new RegistryKey(HKEY_CURRENT_CONFIG, false); 54 return _currentConfig; 55 } 56 57 /// ditto 58 @property RegistryKey currentUser() // getter 59 { 60 if(!_currentUser) 61 _currentUser = new RegistryKey(HKEY_CURRENT_USER, false); 62 return _currentUser; 63 } 64 65 /// ditto 66 @property RegistryKey dynData() // getter 67 { 68 if(!_dynData) 69 _dynData = new RegistryKey(HKEY_DYN_DATA, false); 70 return _dynData; 71 } 72 73 /// ditto 74 @property RegistryKey localMachine() // getter 75 { 76 if(!_localMachine) 77 _localMachine = new RegistryKey(HKEY_LOCAL_MACHINE, false); 78 return _localMachine; 79 } 80 81 /// ditto 82 @property RegistryKey performanceData() // getter 83 { 84 if(!_performanceData) 85 _performanceData = new RegistryKey(HKEY_PERFORMANCE_DATA, false); 86 return _performanceData; 87 } 88 89 /// ditto 90 @property RegistryKey users() // getter 91 { 92 if(!_users) 93 _users = new RegistryKey(HKEY_USERS, false); 94 return _users; 95 } 96 97 98 private: 99 RegistryKey _classesRoot; 100 RegistryKey _currentConfig; 101 RegistryKey _currentUser; 102 RegistryKey _dynData; 103 RegistryKey _localMachine; 104 RegistryKey _performanceData; 105 RegistryKey _users; 106 107 108 /+ 109 static this() 110 { 111 _classesRoot = new RegistryKey(HKEY_CLASSES_ROOT, false); 112 _currentConfig = new RegistryKey(HKEY_CURRENT_CONFIG, false); 113 _currentUser = new RegistryKey(HKEY_CURRENT_USER, false); 114 _dynData = new RegistryKey(HKEY_DYN_DATA, false); 115 _localMachine = new RegistryKey(HKEY_LOCAL_MACHINE, false); 116 _performanceData = new RegistryKey(HKEY_PERFORMANCE_DATA, false); 117 _users = new RegistryKey(HKEY_USERS, false); 118 } 119 +/ 120 } 121 122 123 private enum uint MAX_REG_BUFFER = 256; 124 125 126 /// 127 abstract class RegistryValue 128 { 129 @property DWORD valueType(); // getter 130 override Dstring toString(); 131 /+ package +/ protected LONG save(HKEY hkey, Dstring name); // package 132 package final @property RegistryValue _reg() { return this; } 133 } 134 135 136 /// 137 class RegistryValueSz: RegistryValue 138 { 139 /// 140 Dstring value; 141 142 143 /// 144 this(Dstring str) 145 { 146 this.value = str; 147 } 148 149 /// ditto 150 this() 151 { 152 } 153 154 155 override @property DWORD valueType() // getter 156 { 157 return REG_SZ; 158 } 159 160 161 override Dstring toString() 162 { 163 return value; 164 } 165 166 167 /+ package +/ protected override LONG save(HKEY hkey, Dstring name) // package 168 { 169 auto valuez = unsafeStringz(value); 170 return RegSetValueExA(hkey, unsafeStringz(name), 0, REG_SZ, cast(BYTE*)valuez, value.length + 1); 171 } 172 } 173 174 175 /+ 176 // Extra. 177 /// 178 class RegistryValueSzW: RegistryValue 179 { 180 /// 181 wDstring value; 182 183 184 /// 185 this(wDstring str) 186 { 187 this.value = str; 188 } 189 190 /// ditto 191 this() 192 { 193 } 194 195 196 override @property DWORD valueType() // getter 197 { 198 return REG_SZ; 199 } 200 201 202 override Dstring toString() 203 { 204 return utf16stringtoUtf8string(value); 205 } 206 207 208 /+ package +/ protected override LONG save(HKEY hkey, Dstring name) // package 209 { 210 if(dfl.internal.utf.useUnicode) 211 { 212 213 } 214 else 215 { 216 217 } 218 } 219 } 220 +/ 221 222 223 /// 224 class RegistryValueMultiSz: RegistryValue 225 { 226 /// 227 Dstring[] value; 228 229 230 /// 231 this(Dstring[] strs) 232 { 233 this.value = strs; 234 } 235 236 /// ditto 237 this() 238 { 239 } 240 241 242 override @property DWORD valueType() // getter 243 { 244 return REG_MULTI_SZ; 245 } 246 247 248 override Dstring toString() 249 { 250 Dstring result; 251 foreach(Dstring str; value) 252 { 253 result ~= str ~ "\r\n"; 254 } 255 if(result.length) 256 result = result[0 .. result.length - 2]; // Exclude last \r\n. 257 return result; 258 } 259 260 261 /+ package +/ protected override LONG save(HKEY hkey, Dstring name) // package 262 { 263 char[] multi; 264 uint i; 265 266 i = value.length + 1; // Each NUL and the extra terminating NUL. 267 foreach(Dstring s; value) 268 { 269 i += s.length; 270 } 271 272 multi = new char[i]; 273 foreach(Dstring s; value) 274 { 275 if(!s.length) 276 throw new DflRegistryException("Empty strings are not allowed in multi_sz registry values"); 277 278 multi[i .. i + s.length] = s[]; 279 i += s.length; 280 multi[i++] = 0; 281 } 282 multi[i++] = 0; 283 assert(i == multi.length); 284 285 return RegSetValueExA(hkey, unsafeStringz(name), 0, REG_MULTI_SZ, cast(BYTE*)multi, multi.length); 286 } 287 } 288 289 290 /// 291 class RegistryValueExpandSz: RegistryValue 292 { 293 /// 294 Dstring value; 295 296 297 /// 298 this(Dstring str) 299 { 300 this.value = str; 301 } 302 303 /// ditto 304 this() 305 { 306 } 307 308 309 override @property DWORD valueType() // getter 310 { 311 return REG_EXPAND_SZ; 312 } 313 314 315 override Dstring toString() 316 { 317 return value; 318 } 319 320 321 /+ package +/ protected override LONG save(HKEY hkey, Dstring name) // package 322 { 323 auto valuez = unsafeStringz(value); 324 return RegSetValueExA(hkey, unsafeStringz(name), 0, REG_EXPAND_SZ, cast(BYTE*)valuez, value.length + 1); 325 } 326 } 327 328 329 private Dstring dwordToString(DWORD dw) 330 out(result) 331 { 332 assert(result.length == 10); 333 assert(result[0 .. 2] == "0x"); 334 foreach(char ch; result[2 .. result.length]) 335 { 336 assert(charIsHexDigit(ch)); 337 } 338 } 339 body 340 { 341 char[] result; 342 Dstring stmp; 343 uint ntmp; 344 345 stmp = uintToHexString(dw); 346 assert(stmp.length <= 8); 347 ntmp = 8 - stmp.length + 2; // Plus 0x. 348 result = new char[ntmp + stmp.length]; 349 result[0 .. 2] = "0x"; 350 result[2 .. ntmp] = '0'; 351 result[ntmp .. result.length] = stmp[]; 352 353 //return result; 354 return cast(Dstring)result; // Needed in D2. 355 } 356 357 358 unittest 359 { 360 assert(dwordToString(0x8934) == "0x00008934"); 361 assert(dwordToString(0xF00BA2) == "0x00F00BA2"); 362 assert(dwordToString(0xBADBEEF0) == "0xBADBEEF0"); 363 assert(dwordToString(0xCAFEBEEF) == "0xCAFEBEEF"); 364 assert(dwordToString(0x09090BB) == "0x009090BB"); 365 assert(dwordToString(0) == "0x00000000"); 366 } 367 368 369 /// 370 class RegistryValueDword: RegistryValue 371 { 372 /// 373 DWORD value; 374 375 376 /// 377 this(DWORD dw) 378 { 379 this.value = dw; 380 } 381 382 /// ditto 383 this() 384 { 385 } 386 387 388 override @property DWORD valueType() // getter 389 { 390 return REG_DWORD; 391 } 392 393 394 override Dstring toString() 395 { 396 return dwordToString(value); 397 } 398 399 400 /+ package +/ protected override LONG save(HKEY hkey, Dstring name) // package 401 { 402 return RegSetValueExA(hkey, unsafeStringz(name), 0, REG_DWORD, cast(BYTE*)&value, DWORD.sizeof); 403 } 404 } 405 406 /// ditto 407 alias RegistryValueDword RegistryValueDwordLittleEndian; 408 409 /// ditto 410 class RegistryValueDwordBigEndian: RegistryValue 411 { 412 /// 413 DWORD value; 414 415 416 /// 417 this(DWORD dw) 418 { 419 this.value = dw; 420 } 421 422 /// ditto 423 this() 424 { 425 } 426 427 428 override @property DWORD valueType() // getter 429 { 430 return REG_DWORD_BIG_ENDIAN; 431 } 432 433 434 override Dstring toString() 435 { 436 return dwordToString(value); 437 } 438 439 440 /+ package +/ protected override LONG save(HKEY hkey, Dstring name) // package 441 { 442 return RegSetValueExA(hkey, unsafeStringz(name), 0, REG_DWORD_BIG_ENDIAN, cast(BYTE*)&value, DWORD.sizeof); 443 } 444 } 445 446 447 /// 448 class RegistryValueBinary: RegistryValue 449 { 450 /// 451 void[] value; 452 453 454 /// 455 this(void[] val) 456 { 457 this.value = val; 458 } 459 460 /// ditto 461 this() 462 { 463 } 464 465 466 override @property DWORD valueType() // getter 467 { 468 return REG_BINARY; 469 } 470 471 472 override Dstring toString() 473 { 474 return "Binary"; 475 } 476 477 478 /+ package +/ protected override LONG save(HKEY hkey, Dstring name) // package 479 { 480 return RegSetValueExA(hkey, unsafeStringz(name), 0, REG_BINARY, cast(BYTE*)value, value.length); 481 } 482 } 483 484 485 /// 486 class RegistryValueLink: RegistryValue 487 { 488 /// 489 void[] value; 490 491 492 /// 493 this(void[] val) 494 { 495 this.value = val; 496 } 497 498 /// ditto 499 this() 500 { 501 } 502 503 504 override @property DWORD valueType() // getter 505 { 506 return REG_LINK; 507 } 508 509 510 override Dstring toString() 511 { 512 return "Symbolic Link"; 513 } 514 515 516 /+ package +/ protected override LONG save(HKEY hkey, Dstring name) // package 517 { 518 return RegSetValueExA(hkey, unsafeStringz(name), 0, REG_LINK, cast(BYTE*)value, value.length); 519 } 520 } 521 522 523 /// 524 class RegistryValueResourceList: RegistryValue 525 { 526 /// 527 void[] value; 528 529 530 /// 531 this(void[] val) 532 { 533 this.value = val; 534 } 535 536 /// ditto 537 this() 538 { 539 } 540 541 542 override @property DWORD valueType() // getter 543 { 544 return REG_RESOURCE_LIST; 545 } 546 547 548 override Dstring toString() 549 { 550 return "Resource List"; 551 } 552 553 554 /+ package +/ protected override LONG save(HKEY hkey, Dstring name) // package 555 { 556 return RegSetValueExA(hkey, unsafeStringz(name), 0, REG_RESOURCE_LIST, cast(BYTE*)value, value.length); 557 } 558 } 559 560 561 /// 562 class RegistryValueNone: RegistryValue 563 { 564 /// 565 void[] value; 566 567 568 /// 569 this(void[] val) 570 { 571 this.value = val; 572 } 573 574 /// ditto 575 this() 576 { 577 } 578 579 580 override @property DWORD valueType() // getter 581 { 582 return REG_NONE; 583 } 584 585 586 override Dstring toString() 587 { 588 return "None"; 589 } 590 591 592 /+ package +/ protected override LONG save(HKEY hkey, Dstring name) // package 593 { 594 return RegSetValueExA(hkey, unsafeStringz(name), 0, REG_NONE, cast(BYTE*)value, value.length); 595 } 596 } 597 598 599 /// 600 enum RegistryHive: size_t 601 { 602 /+ 603 // DMD 0.98: 604 // C:\dmd\bin\..\src\phobos\std\c\windows\windows.d(493): cast(HKEY)(2147483648) is not an expression 605 // ... 606 CLASSES_ROOT = cast(size_t)HKEY_CLASSES_ROOT, 607 CURRENT_CONFIG = cast(size_t)HKEY_CURRENT_CONFIG, 608 CURRENT_USER = cast(size_t)HKEY_CURRENT_USER, 609 DYN_DATA = cast(size_t)HKEY_DYN_DATA, 610 LOCAL_MACHINE = cast(size_t)HKEY_LOCAL_MACHINE, 611 PERFORMANCE_DATA = cast(size_t)HKEY_PERFORMANCE_DATA, 612 USERS = cast(size_t)HKEY_USERS, 613 +/ 614 615 CLASSES_ROOT = 0x80000000, /// 616 CURRENT_CONFIG = 0x80000005, /// ditto 617 CURRENT_USER = 0x80000001, /// ditto 618 DYN_DATA = 0x80000006, /// ditto 619 LOCAL_MACHINE = 0x80000002, /// ditto 620 PERFORMANCE_DATA = 0x80000004, /// ditto 621 USERS = 0x80000003, /// ditto 622 } 623 624 625 /// 626 class RegistryKey // docmain 627 { 628 private: 629 HKEY hkey; 630 bool owned = true; 631 632 633 public: 634 final: 635 /+ 636 // An absolute key path. 637 // This doesn't work. 638 final @property Dstring name() // getter 639 { 640 Dstring buf; 641 DWORD buflen; 642 643 buf = new char[MAX_REG_BUFFER]; 644 buflen = buf.length; 645 if(ERROR_SUCCESS != RegQueryInfoKeyA(hkey, buf, &buflen, null, null, 646 null, null, null, null, null, null, null)) 647 infoErr(); 648 649 return buf[0 .. buflen]; 650 } 651 +/ 652 653 654 /// 655 final @property int subKeyCount() // getter 656 { 657 DWORD count; 658 659 LONG rr = RegQueryInfoKeyA(hkey, null, null, null, &count, 660 null, null, null, null, null, null, null); 661 if(ERROR_SUCCESS != rr) 662 infoErr(rr); 663 664 return count; 665 } 666 667 668 /// 669 final @property int valueCount() // getter 670 { 671 DWORD count; 672 673 LONG rr = RegQueryInfoKeyA(hkey, null, null, null, null, 674 null, null, &count, null, null, null, null); 675 if(ERROR_SUCCESS != rr) 676 infoErr(rr); 677 678 return count; 679 } 680 681 682 /// 683 final void close() 684 { 685 //if(!owned) 686 RegCloseKey(hkey); 687 } 688 689 690 /// 691 final RegistryKey createSubKey(Dstring name) 692 { 693 HKEY newHkey; 694 DWORD cdisp; 695 696 LONG rr = RegCreateKeyExA(hkey, unsafeStringz(name), 0, null, 0, KEY_ALL_ACCESS, null, &newHkey, &cdisp); 697 if(ERROR_SUCCESS != rr) 698 throw new DflRegistryException("Unable to create registry key", rr); 699 700 return new RegistryKey(newHkey); 701 } 702 703 704 /// 705 final void deleteSubKey(Dstring name, bool throwIfMissing) 706 { 707 HKEY openHkey; 708 709 if(!name.length || !name[0]) 710 throw new DflRegistryException("Unable to delete subkey"); 711 712 auto namez = unsafeStringz(name); 713 714 LONG opencode = RegOpenKeyExA(hkey, namez, 0, KEY_ALL_ACCESS, &openHkey); 715 if(ERROR_SUCCESS == opencode) 716 { 717 DWORD count; 718 719 LONG querycode = RegQueryInfoKeyA(openHkey, null, null, null, &count, 720 null, null, null, null, null, null, null); 721 if(ERROR_SUCCESS == querycode) 722 { 723 RegCloseKey(openHkey); 724 725 LONG delcode; 726 if(!count) 727 { 728 delcode = RegDeleteKeyA(hkey, namez); 729 if(ERROR_SUCCESS == delcode) 730 return; // OK. 731 732 throw new DflRegistryException("Unable to delete subkey", delcode); 733 } 734 735 throw new DflRegistryException("Cannot delete registry key with subkeys"); 736 } 737 738 RegCloseKey(openHkey); 739 740 throw new DflRegistryException("Unable to delete registry key", querycode); 741 } 742 else 743 { 744 if(!throwIfMissing) 745 { 746 switch(opencode) 747 { 748 case ERROR_FILE_NOT_FOUND: 749 return; 750 751 default: 752 } 753 } 754 755 throw new DflRegistryException("Unable to delete registry key", opencode); 756 } 757 } 758 759 /// ditto 760 final void deleteSubKey(Dstring name) 761 { 762 deleteSubKey(name, true); 763 } 764 765 766 /// 767 final void deleteSubKeyTree(Dstring name) 768 { 769 _deleteSubKeyTree(hkey, name); 770 } 771 772 773 // Note: name is not written to! it's just not "invariant". 774 private static void _deleteSubKeyTree(HKEY shkey, Dstring name) 775 { 776 HKEY openHkey; 777 778 auto namez = unsafeStringz(name); 779 780 if(ERROR_SUCCESS == RegOpenKeyExA(shkey, namez, 0, KEY_ALL_ACCESS, &openHkey)) 781 { 782 void ouch(LONG why = 0) 783 { 784 throw new DflRegistryException("Unable to delete entire subkey tree", why); 785 } 786 787 788 DWORD count; 789 790 LONG querycode = RegQueryInfoKeyA(openHkey, null, null, null, &count, 791 null, null, null, null, null, null, null); 792 if(ERROR_SUCCESS == querycode) 793 { 794 if(!count) 795 { 796 del_me: 797 RegCloseKey(openHkey); 798 LONG delcode = RegDeleteKeyA(shkey, namez); 799 if(ERROR_SUCCESS == delcode) 800 return; // OK. 801 802 ouch(delcode); 803 } 804 else 805 { 806 try 807 { 808 // deleteSubKeyTree on all subkeys. 809 810 char[MAX_REG_BUFFER] skn; 811 DWORD len; 812 813 next_subkey: 814 len = skn.length; 815 LONG enumcode = RegEnumKeyExA(openHkey, 0, skn.ptr, &len, null, null, null, null); 816 switch(enumcode) 817 { 818 case ERROR_SUCCESS: 819 //_deleteSubKeyTree(openHkey, skn[0 .. len]); 820 _deleteSubKeyTree(openHkey, cast(Dstring)skn[0 .. len]); // Needed in D2. WARNING: NOT REALLY INVARIANT. 821 goto next_subkey; 822 823 case ERROR_NO_MORE_ITEMS: 824 // Done! 825 break; 826 827 default: 828 ouch(enumcode); 829 } 830 831 // Now go back to delete the origional key. 832 goto del_me; 833 } 834 finally 835 { 836 RegCloseKey(openHkey); 837 } 838 } 839 } 840 else 841 { 842 ouch(querycode); 843 } 844 } 845 } 846 847 848 /// 849 final void deleteValue(Dstring name, bool throwIfMissing) 850 { 851 LONG rr = RegDeleteValueA(hkey, unsafeStringz(name)); 852 switch(rr) 853 { 854 case ERROR_SUCCESS: 855 break; 856 857 case ERROR_FILE_NOT_FOUND: 858 if(!throwIfMissing) 859 break; 860 goto default; 861 default: 862 throw new DflRegistryException("Unable to delete registry value", rr); 863 } 864 } 865 866 /// ditto 867 final void deleteValue(Dstring name) 868 { 869 deleteValue(name, true); 870 } 871 872 873 override Dequ opEquals(Object o) 874 { 875 RegistryKey rk; 876 877 rk = cast(RegistryKey)o; 878 if(!rk) 879 return false; 880 return opEquals(rk); 881 } 882 883 884 Dequ opEquals(RegistryKey rk) 885 { 886 return hkey == rk.hkey; 887 } 888 889 890 /// 891 final void flush() 892 { 893 RegFlushKey(hkey); 894 } 895 896 897 /// 898 final Dstring[] getSubKeyNames() 899 { 900 char[MAX_REG_BUFFER] buf; 901 DWORD len; 902 DWORD idx; 903 Dstring[] result; 904 905 key_names: 906 for(idx = 0;; idx++) 907 { 908 len = buf.length; 909 LONG rr = RegEnumKeyExA(hkey, idx, buf.ptr, &len, null, null, null, null); 910 switch(rr) 911 { 912 case ERROR_SUCCESS: 913 //result ~= buf[0 .. len].dup; 914 //result ~= buf[0 .. len].idup; // Needed in D2. Doesn't work in D1. 915 result ~= cast(Dstring)buf[0 .. len].dup; // Needed in D2. 916 break; 917 918 case ERROR_NO_MORE_ITEMS: 919 // Done! 920 break key_names; 921 922 default: 923 throw new DflRegistryException("Unable to obtain subkey names", rr); 924 } 925 } 926 927 return result; 928 } 929 930 931 /// 932 final RegistryValue getValue(Dstring name, RegistryValue defaultValue) 933 { 934 DWORD type; 935 DWORD len; 936 ubyte[] data; 937 938 len = 0; 939 LONG querycode = RegQueryValueExA(hkey, unsafeStringz(name), null, &type, null, &len); 940 switch(querycode) 941 { 942 case ERROR_SUCCESS: 943 // Good. 944 break; 945 946 case ERROR_FILE_NOT_FOUND: 947 // Value doesn't exist. 948 return defaultValue; 949 950 default: errquerycode: 951 throw new DflRegistryException("Unable to get registry value", querycode); 952 } 953 954 data = new ubyte[len]; 955 // Note: reusing querycode here and above. 956 querycode = RegQueryValueExA(hkey, unsafeStringz(name), null, &type, data.ptr, &len); 957 if(ERROR_SUCCESS != querycode) 958 goto errquerycode; 959 960 switch(type) 961 { 962 case REG_SZ: 963 with(new RegistryValueSz) 964 { 965 assert(!data[data.length - 1]); 966 value = cast(Dstring)data[0 .. data.length - 1]; 967 defaultValue = _reg; 968 } 969 break; 970 971 case REG_DWORD: // REG_DWORD_LITTLE_ENDIAN 972 with(new RegistryValueDword) 973 { 974 assert(data.length == DWORD.sizeof); 975 value = *(cast(DWORD*)cast(void*)data); 976 defaultValue = _reg; 977 } 978 break; 979 980 case REG_EXPAND_SZ: 981 with(new RegistryValueExpandSz) 982 { 983 assert(!data[data.length - 1]); 984 value = cast(Dstring)data[0 .. data.length - 1]; 985 defaultValue = _reg; 986 } 987 break; 988 989 case REG_MULTI_SZ: 990 with(new RegistryValueMultiSz) 991 { 992 Dstring s; 993 994 next_sz: 995 s = stringFromStringz(cast(char*)data); 996 if(s.length) 997 { 998 value ~= s; 999 data = data[s.length + 1 .. data.length]; 1000 goto next_sz; 1001 } 1002 1003 defaultValue = _reg; 1004 } 1005 break; 1006 1007 case REG_BINARY: 1008 with(new RegistryValueBinary) 1009 { 1010 value = data; 1011 defaultValue = _reg; 1012 } 1013 break; 1014 1015 case REG_DWORD_BIG_ENDIAN: 1016 with(new RegistryValueDwordBigEndian) 1017 { 1018 assert(data.length == DWORD.sizeof); 1019 value = *(cast(DWORD*)cast(void*)data); 1020 defaultValue = _reg; 1021 } 1022 break; 1023 1024 case REG_LINK: 1025 with(new RegistryValueLink) 1026 { 1027 value = data; 1028 defaultValue = _reg; 1029 } 1030 break; 1031 1032 case REG_RESOURCE_LIST: 1033 with(new RegistryValueResourceList) 1034 { 1035 value = data; 1036 defaultValue = _reg; 1037 } 1038 break; 1039 1040 case REG_NONE: 1041 with(new RegistryValueNone) 1042 { 1043 value = data; 1044 defaultValue = _reg; 1045 } 1046 break; 1047 1048 default: 1049 throw new DflRegistryException("Unknown type for registry value"); 1050 } 1051 1052 return defaultValue; 1053 } 1054 1055 /// ditto 1056 final RegistryValue getValue(Dstring name) 1057 { 1058 return getValue(name, null); 1059 } 1060 1061 1062 /// 1063 final Dstring[] getValueNames() 1064 { 1065 char[MAX_REG_BUFFER] buf; 1066 DWORD len; 1067 DWORD idx; 1068 Dstring[] result; 1069 1070 value_names: 1071 for(idx = 0;; idx++) 1072 { 1073 len = buf.length; 1074 LONG rr = RegEnumValueA(hkey, idx, buf.ptr, &len, null, null, null, null); 1075 switch(rr) 1076 { 1077 case ERROR_SUCCESS: 1078 //result ~= buf[0 .. len].dup; 1079 //result ~= buf[0 .. len].idup; // Needed in D2. Doesn't work in D1. 1080 result ~= cast(Dstring)buf[0 .. len].dup; // Needed in D2. 1081 break; 1082 1083 case ERROR_NO_MORE_ITEMS: 1084 // Done! 1085 break value_names; 1086 1087 default: 1088 throw new DflRegistryException("Unable to obtain value names", rr); 1089 } 1090 } 1091 1092 return result; 1093 } 1094 1095 1096 /// 1097 static RegistryKey openRemoteBaseKey(RegistryHive hhive, Dstring machineName) 1098 { 1099 HKEY openHkey; 1100 1101 LONG rr = RegConnectRegistryA(unsafeStringz(machineName), cast(HKEY)hhive, &openHkey); 1102 if(ERROR_SUCCESS != rr) 1103 throw new DflRegistryException("Unable to open remote base key", rr); 1104 1105 return new RegistryKey(openHkey); 1106 } 1107 1108 1109 /// 1110 // Returns null on error. 1111 final RegistryKey openSubKey(Dstring name, bool writeAccess) 1112 { 1113 HKEY openHkey; 1114 1115 if(ERROR_SUCCESS != RegOpenKeyExA(hkey, unsafeStringz(name), 0, 1116 writeAccess ? KEY_READ | KEY_WRITE : KEY_READ, &openHkey)) 1117 return null; 1118 1119 return new RegistryKey(openHkey); 1120 } 1121 1122 /// ditto 1123 final RegistryKey openSubKey(Dstring name) 1124 { 1125 return openSubKey(name, false); 1126 } 1127 1128 1129 /// 1130 final void setValue(Dstring name, RegistryValue value) 1131 { 1132 LONG rr = value.save(hkey, name); 1133 if(ERROR_SUCCESS != rr) 1134 throw new DflRegistryException("Unable to set registry value", rr); 1135 } 1136 1137 /// ditto 1138 // Shortcut. 1139 final void setValue(Dstring name, Dstring value) 1140 { 1141 scope rv = new RegistryValueSz(value); 1142 setValue(name, rv); 1143 } 1144 1145 /// ditto 1146 // Shortcut. 1147 final void setValue(Dstring name, Dstring[] value) 1148 { 1149 scope rv = new RegistryValueMultiSz(value); 1150 setValue(name, rv); 1151 } 1152 1153 /// ditto 1154 // Shortcut. 1155 final void setValue(Dstring name, DWORD value) 1156 { 1157 scope rv = new RegistryValueDword(value); 1158 setValue(name, rv); 1159 } 1160 1161 1162 /// 1163 // Used internally. 1164 final @property HKEY handle() // getter 1165 { 1166 return hkey; 1167 } 1168 1169 1170 // Used internally. 1171 this(HKEY hkey, bool owned = true) 1172 { 1173 this.hkey = hkey; 1174 this.owned = owned; 1175 } 1176 1177 1178 ~this() 1179 { 1180 if(owned) 1181 RegCloseKey(hkey); 1182 } 1183 1184 1185 private void infoErr(LONG why) 1186 { 1187 throw new DflRegistryException("Unable to obtain registry information", why); 1188 } 1189 } 1190