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