2 This library provides Win32 Registry facilities.
4 Copyright: Copyright 2003-2004 by Matthew Wilson and Synesis Software
5 Written by Matthew Wilson
7 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
9 Author: Matthew Wilson, Kenji Hara
12 Created 15th March 2003,
13 Updated 25th April 2004,
15 Source: $(PHOBOSSRC std/windows/registry.d)
17 /* /////////////////////////////////////////////////////////////////////////////
19 * This software is provided 'as-is', without any express or implied
20 * warranty. In no event will the authors be held liable for any damages
21 * arising from the use of this software.
23 * Permission is granted to anyone to use this software for any purpose,
24 * including commercial applications, and to alter it and redistribute it
25 * freely, in both source and binary form, subject to the following
28 * - The origin of this software must not be misrepresented; you must not
29 * claim that you wrote the original software. If you use this software
30 * in a product, an acknowledgment in the product documentation would be
31 * appreciated but is not required.
32 * - Altered source versions must be plainly marked as such, and must not
33 * be misrepresented as being the original software.
34 * - This notice may not be removed or altered from any source
37 * ////////////////////////////////////////////////////////////////////////// */
38 module std
.windows
.registry
;
41 import core
.sys
.windows
.winbase
, core
.sys
.windows
.windef
, core
.sys
.windows
.winreg
;
45 import std
.internal
.cstring
;
46 import std
.internal
.windows
.advapi32
;
47 import std
.system
: Endian
, endian
;
48 import std
.windows
.syserror
;
51 debug(winreg
) import std
.stdio
;
55 import core
.sys
.windows
.winbase
: lstrlenW
;
57 void enforceSucc(LONG res
, lazy string message
, string fn
= __FILE__
, size_t ln
= __LINE__
)
59 if (res
!= ERROR_SUCCESS
)
60 throw new RegistryException(message
, res
, fn
, ln
);
64 /* ************* Exceptions *************** */
66 // Do not use. Left for compatibility.
67 class Win32Exception
: WindowsException
70 this(string message
, string fn
= __FILE__
, size_t ln
= __LINE__
, Throwable next
= null)
72 super(0, message
, fn
, ln
);
76 this(string message
, int errnum
, string fn
= __FILE__
, size_t ln
= __LINE__
, Throwable next
= null)
78 super(errnum
, message
, fn
, ln
);
81 @property int error() { return super.code
; }
84 version (StdUnittest
) import std
.string
: startsWith
, endsWith
;
88 // Test that we can throw and catch one by its own type
89 string message
= "Test W1";
91 auto e
= collectException
!Win32Exception(
92 enforce(false, new Win32Exception(message
)));
93 assert(e
.msg
.startsWith(message
));
99 string message
= "Test W2";
102 auto e
= collectException
!Win32Exception(
103 enforce(false, new Win32Exception(message
, code
)));
104 assert(e
.error
== code
);
105 assert(e
.msg
.startsWith(message
));
109 Exception class thrown by the std.windows.registry classes.
111 class RegistryException
116 Creates an instance of the exception.
119 message = The message associated with the exception.
122 this(string message
, string fn
= __FILE__
, size_t ln
= __LINE__
, Throwable next
= null)
124 super(message
, fn
, ln
, next
);
128 Creates an instance of the exception, with the given.
131 message = The message associated with the exception.
132 error = The Win32 error number associated with the exception.
135 this(string message
, int error
, string fn
= __FILE__
, size_t ln
= __LINE__
, Throwable next
= null)
137 super(message
, error
, fn
, ln
, next
);
143 // (i) Test that we can throw and catch one by its own type
144 string message
= "Test 1";
147 auto e
= collectException
!RegistryException(
148 enforce(false, new RegistryException(message
, code
)));
149 assert(e
.error
== code
);
150 assert(e
.msg
.startsWith(message
));
156 string message
= "Test 2";
158 auto e
= collectException
!RegistryException(
159 enforce(false, new RegistryException(message
)));
160 assert(e
.msg
.startsWith(message
));
163 /* ************* public enumerations *************** */
166 Enumeration of the recognised registry access modes.
170 KEY_QUERY_VALUE
= 0x0001, /// Permission to query subkey data
171 KEY_SET_VALUE
= 0x0002, /// Permission to set subkey data
172 KEY_CREATE_SUB_KEY
= 0x0004, /// Permission to create subkeys
173 KEY_ENUMERATE_SUB_KEYS
= 0x0008, /// Permission to enumerate subkeys
174 KEY_NOTIFY
= 0x0010, /// Permission for change notification
175 KEY_CREATE_LINK
= 0x0020, /// Permission to create a symbolic link
176 KEY_WOW64_32KEY
= 0x0200, /// Enables a 64- or 32-bit application to open a 32-bit key
177 KEY_WOW64_64KEY
= 0x0100, /// Enables a 64- or 32-bit application to open a 64-bit key
178 KEY_WOW64_RES
= 0x0300, ///
179 KEY_READ
= (STANDARD_RIGHTS_READ
180 | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY
)
182 /// Combines the STANDARD_RIGHTS_READ, KEY_QUERY_VALUE,
183 /// KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY access rights
184 KEY_WRITE
= (STANDARD_RIGHTS_WRITE
185 | KEY_SET_VALUE | KEY_CREATE_SUB_KEY
)
187 /// Combines the STANDARD_RIGHTS_WRITE, KEY_SET_VALUE,
188 /// and KEY_CREATE_SUB_KEY access rights
189 KEY_EXECUTE
= KEY_READ
& ~(SYNCHRONIZE
),
190 /// Permission for read access
191 KEY_ALL_ACCESS
= (STANDARD_RIGHTS_ALL
192 | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY
193 | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_CREATE_LINK
)
195 /// Combines the KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS,
196 /// KEY_NOTIFY, KEY_CREATE_SUB_KEY, KEY_CREATE_LINK, and
197 /// KEY_SET_VALUE access rights, plus all the standard
198 /// access rights except SYNCHRONIZE
202 Enumeration of the recognised registry value types.
204 enum REG_VALUE_TYPE
: DWORD
206 REG_UNKNOWN
= -1, ///
207 REG_NONE
= 0, /// The null value type. (In practise this is treated as a zero-length binary array by the Win32 registry)
208 REG_SZ
= 1, /// A zero-terminated string
209 REG_EXPAND_SZ
= 2, /// A zero-terminated string containing expandable environment variable references
210 REG_BINARY
= 3, /// A binary blob
211 REG_DWORD
= 4, /// A 32-bit unsigned integer
212 REG_DWORD_LITTLE_ENDIAN
= 4, /// A 32-bit unsigned integer, stored in little-endian byte order
213 REG_DWORD_BIG_ENDIAN
= 5, /// A 32-bit unsigned integer, stored in big-endian byte order
214 REG_LINK
= 6, /// A registry link
215 REG_MULTI_SZ
= 7, /// A set of zero-terminated strings
216 REG_RESOURCE_LIST
= 8, /// A hardware resource list
217 REG_FULL_RESOURCE_DESCRIPTOR
= 9, /// A hardware resource descriptor
218 REG_RESOURCE_REQUIREMENTS_LIST
= 10, /// A hardware resource requirements list
219 REG_QWORD
= 11, /// A 64-bit unsigned integer
220 REG_QWORD_LITTLE_ENDIAN
= 11, /// A 64-bit unsigned integer, stored in little-endian byte order
224 /* ************* private *************** */
226 import core
.sys
.windows
.winnt
:
233 STANDARD_RIGHTS_REQUIRED
,
235 STANDARD_RIGHTS_READ
,
236 STANDARD_RIGHTS_WRITE
,
237 STANDARD_RIGHTS_EXECUTE
,
239 STANDARD_RIGHTS_ALL
,
241 SPECIFIC_RIGHTS_ALL
;
243 import core
.sys
.windows
.winreg
:
244 REG_CREATED_NEW_KEY
,
245 REG_OPENED_EXISTING_KEY
;
247 // Returns samDesired but without WoW64 flags if not in WoW64 mode
248 // for compatibility with Windows 2000
249 private REGSAM
compatibleRegsam(in REGSAM samDesired
)
251 return isWow64 ? samDesired
: cast(REGSAM
)(samDesired
& ~REGSAM
.KEY_WOW64_RES
);
254 ///Returns true, if we are in WoW64 mode and have WoW64 flags
255 private bool haveWoW64Job(in REGSAM samDesired
)
257 return isWow64
&& (samDesired
& REGSAM
.KEY_WOW64_RES
);
260 private REG_VALUE_TYPE
_RVT_from_Endian(Endian endian
)
262 final switch (endian
)
264 case Endian
.bigEndian
:
265 return REG_VALUE_TYPE
.REG_DWORD_BIG_ENDIAN
;
267 case Endian
.littleEndian
:
268 return REG_VALUE_TYPE
.REG_DWORD_LITTLE_ENDIAN
;
272 private LONG
regCloseKey(in HKEY hkey
)
275 assert(hkey
!is null);
279 /* No need to attempt to close any of the standard hive keys.
280 * Although it's documented that calling RegCloseKey() on any of
281 * these hive keys is ignored, we'd rather not trust the Win32
284 if (cast(uint) hkey
& 0x80000000)
286 switch (cast(uint) hkey
)
288 case HKEY_CLASSES_ROOT
:
289 case HKEY_CURRENT_USER
:
290 case HKEY_LOCAL_MACHINE
:
292 case HKEY_PERFORMANCE_DATA
:
293 case HKEY_PERFORMANCE_TEXT
:
294 case HKEY_PERFORMANCE_NLSTEXT
:
295 case HKEY_CURRENT_CONFIG
:
297 return ERROR_SUCCESS
;
304 return RegCloseKey(hkey
);
307 private void regFlushKey(in HKEY hkey
)
310 assert(hkey
!is null);
314 immutable res
= RegFlushKey(hkey
);
315 enforceSucc(res
, "Key cannot be flushed");
318 private HKEY
regCreateKey(in HKEY hkey
, in string subKey
, in DWORD dwOptions
, in REGSAM samDesired
,
319 in LPSECURITY_ATTRIBUTES lpsa
, out DWORD disposition
)
322 assert(hkey
!is null);
323 assert(subKey
!is null);
328 enforceSucc(RegCreateKeyExW(
329 hkey
, subKey
.tempCStringW(), 0, null, dwOptions
,
330 compatibleRegsam(samDesired
), cast(LPSECURITY_ATTRIBUTES
) lpsa
,
331 &hkeyResult
, &disposition
),
332 "Failed to create requested key: \"" ~ subKey
~ "\"");
337 private void regDeleteKey(in HKEY hkey
, in string subKey
, in REGSAM samDesired
)
340 assert(hkey
!is null);
341 assert(subKey
!is null);
346 if (haveWoW64Job(samDesired
))
349 res
= pRegDeleteKeyExW(hkey
, subKey
.tempCStringW(), samDesired
, 0);
353 res
= RegDeleteKeyW(hkey
, subKey
.tempCStringW());
355 enforceSucc(res
, "Key cannot be deleted: \"" ~ subKey
~ "\"");
358 private void regDeleteValue(in HKEY hkey
, in string valueName
)
361 assert(hkey
!is null);
362 assert(valueName
!is null);
366 enforceSucc(RegDeleteValueW(hkey
, valueName
.tempCStringW()),
367 "Value cannot be deleted: \"" ~ valueName
~ "\"");
370 private HKEY
regDup(HKEY hkey
)
373 assert(hkey
!is null);
377 /* Can't duplicate standard keys, but don't need to, so can just return */
378 if (cast(uint) hkey
& 0x80000000)
380 switch (cast(uint) hkey
)
382 case HKEY_CLASSES_ROOT
:
383 case HKEY_CURRENT_USER
:
384 case HKEY_LOCAL_MACHINE
:
386 case HKEY_PERFORMANCE_DATA
:
387 case HKEY_PERFORMANCE_TEXT
:
388 case HKEY_PERFORMANCE_NLSTEXT
:
389 case HKEY_CURRENT_CONFIG
:
399 immutable res
= RegOpenKeyW(hkey
, null, &hkeyDup
);
403 if (res
!= ERROR_SUCCESS
)
405 writefln("regDup() failed: 0x%08x 0x%08x %d", hkey
, hkeyDup
, res
);
408 assert(res
== ERROR_SUCCESS
);
411 return (res
== ERROR_SUCCESS
) ? hkeyDup
: null;
414 private LONG
regEnumKeyName(in HKEY hkey
, in DWORD index
, ref wchar[] name
, out DWORD cchName
)
417 assert(hkey
!is null);
418 assert(name
!is null);
419 assert(name
.length
> 0);
423 assert(res
!= ERROR_MORE_DATA
);
427 // The Registry API lies about the lengths of a very few sub-key lengths
428 // so we have to test to see if it whinges about more data, and provide
432 cchName
= to
!DWORD(name
.length
);
433 immutable res
= RegEnumKeyExW(hkey
, index
, name
.ptr
, &cchName
, null, null, null, null);
434 if (res
!= ERROR_MORE_DATA
)
437 // Now need to increase the size of the buffer and try again
445 private LONG
regEnumValueName(in HKEY hkey
, in DWORD dwIndex
, ref wchar[] name
, out DWORD cchName
)
448 assert(hkey
!is null);
454 cchName
= to
!DWORD(name
.length
);
455 immutable res
= RegEnumValueW(hkey
, dwIndex
, name
.ptr
, &cchName
, null, null, null, null);
456 if (res
!= ERROR_MORE_DATA
)
465 private LONG
regGetNumSubKeys(in HKEY hkey
, out DWORD cSubKeys
, out DWORD cchSubKeyMaxLen
)
468 assert(hkey
!is null);
472 return RegQueryInfoKeyW(hkey
, null, null, null, &cSubKeys
,
473 &cchSubKeyMaxLen
, null, null, null, null, null, null);
476 private LONG
regGetNumValues(in HKEY hkey
, out DWORD cValues
, out DWORD cchValueMaxLen
)
479 assert(hkey
!is null);
483 return RegQueryInfoKeyW(hkey
, null, null, null, null, null, null,
484 &cValues
, &cchValueMaxLen
, null, null, null);
487 private REG_VALUE_TYPE
regGetValueType(in HKEY hkey
, in string name
)
490 assert(hkey
!is null);
495 enforceSucc(RegQueryValueExW(hkey
, name
.tempCStringW(), null, cast(LPDWORD
) &type
, null, null),
496 "Value cannot be opened: \"" ~ name
~ "\"");
501 private HKEY
regOpenKey(in HKEY hkey
, in string subKey
, in REGSAM samDesired
)
504 assert(hkey
!is null);
505 assert(subKey
!is null);
510 enforceSucc(RegOpenKeyExW(hkey
, subKey
.tempCStringW(), 0, compatibleRegsam(samDesired
), &hkeyResult
),
511 "Failed to open requested key: \"" ~ subKey
~ "\"");
516 private void regQueryValue(in HKEY hkey
, string name
, out string value
, REG_VALUE_TYPE reqType
)
519 assert(hkey
!is null);
523 import core
.bitop
: bswap;
527 // See https://issues.dlang.org/show_bug.cgi?id=961 on this
535 DWORD cbData
= u
.qw
.sizeof
;
537 auto keynameTmp
= name
.tempCStringW();
538 LONG res
= RegQueryValueExW(hkey
, keynameTmp
, null, cast(LPDWORD
) &type
, data
, &cbData
);
539 if (res
== ERROR_MORE_DATA
)
541 data
= (new ubyte[cbData
]).ptr
;
542 res
= RegQueryValueExW(hkey
, keynameTmp
, null, cast(LPDWORD
) &type
, data
, &cbData
);
546 "Cannot read the requested value");
547 enforce(type
== reqType
,
548 new RegistryException("Value type has been changed since the value was acquired"));
552 case REG_VALUE_TYPE
.REG_SZ
:
553 case REG_VALUE_TYPE
.REG_EXPAND_SZ
:
554 auto wstr
= (cast(immutable(wchar)*)data
)[0 .. cbData
/ wchar.sizeof
];
555 assert(wstr
.length
> 0 && wstr
[$-1] == '\0');
556 if (wstr
.length
&& wstr
[$-1] == '\0')
557 wstr
.length
= wstr
.length
- 1;
558 assert(wstr
.length
== 0 || wstr
[$-1] != '\0');
559 value
= wstr
.to
!string
;
562 case REG_VALUE_TYPE
.REG_DWORD_LITTLE_ENDIAN
:
563 version (LittleEndian
)
564 value
= to
!string(u
.dw);
566 value
= to
!string(bswap(u
.dw));
569 case REG_VALUE_TYPE
.REG_DWORD_BIG_ENDIAN
:
570 version (LittleEndian
)
571 value
= to
!string(bswap(u
.dw));
573 value
= to
!string(u
.dw);
576 case REG_VALUE_TYPE
.REG_QWORD_LITTLE_ENDIAN
:
577 value
= to
!string(u
.qw
);
580 case REG_VALUE_TYPE
.REG_BINARY
:
581 case REG_VALUE_TYPE
.REG_MULTI_SZ
:
583 throw new RegistryException("Cannot read the given value as a string");
587 private void regQueryValue(in HKEY hkey
, in string name
, out string
[] value
, REG_VALUE_TYPE reqType
)
590 assert(hkey
!is null);
596 auto keynameTmp
= name
.tempCStringW();
597 wchar[] data
= new wchar[256];
598 DWORD cbData
= to
!DWORD(data
.length
* wchar.sizeof
);
599 LONG res
= RegQueryValueExW(hkey
, keynameTmp
, null, cast(LPDWORD
) &type
, data
.ptr
, &cbData
);
600 if (res
== ERROR_MORE_DATA
)
602 data
.length
= cbData
/ wchar.sizeof
;
603 res
= RegQueryValueExW(hkey
, keynameTmp
, null, cast(LPDWORD
) &type
, data
.ptr
, &cbData
);
605 else if (res
== ERROR_SUCCESS
)
607 data
.length
= cbData
/ wchar.sizeof
;
609 enforceSucc(res
, "Cannot read the requested value");
610 enforce(type
== REG_VALUE_TYPE
.REG_MULTI_SZ
,
611 new RegistryException("Cannot read the given value as a string"));
612 enforce(type
== reqType
,
613 new RegistryException("Value type has been changed since the value was acquired"));
615 // Remove last two (or one) null terminator
616 assert(data
.length
> 0 && data
[$-1] == '\0');
617 data
.length
= data
.length
- 1;
618 if (data
.length
> 0 && data
[$-1] == '\0')
619 data
.length
= data
.length
- 1;
621 auto list
= std
.array
.split(data
[], "\0");
622 value
.length
= list
.length
;
623 foreach (i
, ref v
; value
)
625 v
= list
[i
].to
!string
;
629 private void regQueryValue(in HKEY hkey
, in string name
, out uint value
, REG_VALUE_TYPE reqType
)
632 assert(hkey
!is null);
636 import core
.bitop
: bswap;
640 DWORD cbData
= value
.sizeof
;
641 enforceSucc(RegQueryValueExW(hkey
, name
.tempCStringW(), null, cast(LPDWORD
) &type
, &value
, &cbData
),
642 "Cannot read the requested value");
643 enforce(type
== reqType
,
644 new RegistryException("Value type has been changed since the value was acquired"));
648 case REG_VALUE_TYPE
.REG_DWORD_LITTLE_ENDIAN
:
649 version (LittleEndian
)
650 static assert(REG_VALUE_TYPE
.REG_DWORD
== REG_VALUE_TYPE
.REG_DWORD_LITTLE_ENDIAN
);
652 value
= bswap(value
);
655 case REG_VALUE_TYPE
.REG_DWORD_BIG_ENDIAN
:
656 version (LittleEndian
)
657 value
= bswap(value
);
659 static assert(REG_VALUE_TYPE
.REG_DWORD
== REG_VALUE_TYPE
.REG_DWORD_BIG_ENDIAN
);
663 throw new RegistryException("Cannot read the given value as a 32-bit integer");
667 private void regQueryValue(in HKEY hkey
, in string name
, out ulong value
, REG_VALUE_TYPE reqType
)
670 assert(hkey
!is null);
676 DWORD cbData
= value
.sizeof
;
677 enforceSucc(RegQueryValueExW(hkey
, name
.tempCStringW(), null, cast(LPDWORD
) &type
, &value
, &cbData
),
678 "Cannot read the requested value");
679 enforce(type
== reqType
,
680 new RegistryException("Value type has been changed since the value was acquired"));
684 case REG_VALUE_TYPE
.REG_QWORD_LITTLE_ENDIAN
:
688 throw new RegistryException("Cannot read the given value as a 64-bit integer");
692 private void regQueryValue(in HKEY hkey
, in string name
, out byte[] value
, REG_VALUE_TYPE reqType
)
695 assert(hkey
!is null);
701 byte[] data
= new byte[100];
702 DWORD cbData
= to
!DWORD(data
.length
);
704 auto keynameTmp
= name
.tempCStringW();
705 res
= RegQueryValueExW(hkey
, keynameTmp
, null, cast(LPDWORD
) &type
, data
.ptr
, &cbData
);
706 if (res
== ERROR_MORE_DATA
)
708 data
.length
= cbData
;
709 res
= RegQueryValueExW(hkey
, keynameTmp
, null, cast(LPDWORD
) &type
, data
.ptr
, &cbData
);
711 enforceSucc(res
, "Cannot read the requested value");
712 enforce(type
== reqType
,
713 new RegistryException("Value type has been changed since the value was acquired"));
717 case REG_VALUE_TYPE
.REG_BINARY
:
718 data
.length
= cbData
;
723 throw new RegistryException("Cannot read the given value as a string");
727 private void regSetValue(in HKEY hkey
, in string subKey
, in REG_VALUE_TYPE type
, in LPCVOID lpData
, in DWORD cbData
)
730 assert(hkey
!is null);
734 enforceSucc(RegSetValueExW(hkey
, subKey
.tempCStringW(), 0, type
, cast(BYTE
*) lpData
, cbData
),
735 "Value cannot be set: \"" ~ subKey
~ "\"");
738 private void regProcessNthKey(Key key
, scope void delegate(scope LONG
delegate(DWORD
, out string
)) dg
)
741 DWORD cchSubKeyMaxLen
;
743 immutable res
= regGetNumSubKeys(key
.m_hkey
, cSubKeys
, cchSubKeyMaxLen
);
744 assert(res
== ERROR_SUCCESS
);
746 wchar[] sName
= new wchar[cchSubKeyMaxLen
+ 1];
748 // Capture `key` in the lambda to keep the object alive (and so its HKEY handle open).
749 dg((DWORD index
, out string name
)
752 immutable res
= regEnumKeyName(key
.m_hkey
, index
, sName
, cchName
);
753 if (res
== ERROR_SUCCESS
)
755 name
= sName
[0 .. cchName
].to
!string
;
761 private void regProcessNthValue(Key key
, scope void delegate(scope LONG
delegate(DWORD
, out string
)) dg
)
764 DWORD cchValueMaxLen
;
766 immutable res
= regGetNumValues(key
.m_hkey
, cValues
, cchValueMaxLen
);
767 assert(res
== ERROR_SUCCESS
);
769 wchar[] sName
= new wchar[cchValueMaxLen
+ 1];
771 // Capture `key` in the lambda to keep the object alive (and so its HKEY handle open).
772 dg((DWORD index
, out string name
)
775 immutable res
= regEnumValueName(key
.m_hkey
, index
, sName
, cchName
);
776 if (res
== ERROR_SUCCESS
)
778 name
= sName
[0 .. cchName
].to
!string
;
784 /* ************* public classes *************** */
787 This class represents a registry key.
794 assert(m_hkey
!is null);
799 this(HKEY hkey
, string name
, bool created
)
802 assert(hkey
!is null);
814 // Even though this is horried waste-of-cycles programming
815 // we're doing it here so that the
820 /// The name of the key
821 @property string
name() @safe pure nothrow const
827 The number of sub keys.
829 @property size_t
keyCount() const
832 uint cchSubKeyMaxLen
;
833 enforceSucc(regGetNumSubKeys(m_hkey
, cSubKeys
, cchSubKeyMaxLen
),
834 "Number of sub-keys cannot be determined");
840 An enumerable sequence of all the sub-keys of this key.
842 @property KeySequence
keys() @safe pure
844 return new KeySequence(this);
848 An enumerable sequence of the names of all the sub-keys of this key.
850 @property KeyNameSequence
keyNames() @safe pure
852 return new KeyNameSequence(this);
856 The number of values.
858 @property size_t
valueCount() const
862 enforceSucc(regGetNumValues(m_hkey
, cValues
, cchValueMaxLen
),
863 "Number of values cannot be determined");
869 An enumerable sequence of all the values of this key.
871 @property ValueSequence
values() @safe pure
873 return new ValueSequence(this);
877 An enumerable sequence of the names of all the values of this key.
879 @property ValueNameSequence
valueNames() @safe pure
881 return new ValueNameSequence(this);
885 Returns the named sub-key of this key.
888 name = The name of the subkey to create. May not be `null`.
892 `RegistryException` is thrown if the key cannot be created.
894 Key
createKey(string name
, REGSAM access
= REGSAM
.KEY_ALL_ACCESS
)
896 enforce(!name
.empty
, new RegistryException("Key name is invalid"));
899 HKEY hkey
= regCreateKey(m_hkey
, name
, 0, access
, null, disposition
);
900 assert(hkey
!is null);
902 // Potential resource leak here!!
904 // If the allocation of the memory for Key fails, the HKEY could be
905 // lost. Hence, we catch such a failure by the finally, and release
906 // the HKEY there. If the creation of
909 Key key
= new Key(hkey
, name
, disposition
== REG_CREATED_NEW_KEY
);
923 Returns the named sub-key of this key.
926 name = The name of the subkey to aquire. If name is the empty
927 string, then the called key is duplicated.
928 access = The desired access; one of the `REGSAM` enumeration.
932 This function never returns `null`. If a key corresponding to
933 the requested name is not found, `RegistryException` is thrown.
935 Key
getKey(string name
, REGSAM access
= REGSAM
.KEY_READ
)
938 return new Key(regDup(m_hkey
), m_name
, false);
940 HKEY hkey
= regOpenKey(m_hkey
, name
, access
);
941 assert(hkey
!is null);
943 // Potential resource leak here!!
945 // If the allocation of the memory for Key fails, the HKEY could be
946 // lost. Hence, we catch such a failure by the finally, and release
947 // the HKEY there. If the creation of
950 Key key
= new Key(hkey
, name
, false);
964 Deletes the named key.
967 name = The name of the key to delete. May not be `null`.
969 void deleteKey(string name
, REGSAM access
= cast(REGSAM
) 0)
971 enforce(!name
.empty
, new RegistryException("Key name is invalid"));
973 regDeleteKey(m_hkey
, name
, access
);
977 Returns the named value.
978 If `name` is the empty string, then the default value is returned.
981 This function never returns `null`. If a value corresponding
982 to the requested name is not found, `RegistryException` is thrown.
984 Value
getValue(string name
)
986 return new Value(this, name
, regGetValueType(m_hkey
, name
));
990 Sets the named value with the given 32-bit unsigned integer value.
993 name = The name of the value to set. If it is the empty string,
994 sets the default value.
995 value = The 32-bit unsigned value to set.
997 If a value corresponding to the requested name is not found,
998 `RegistryException` is thrown.
1000 void setValue(string name
, uint value
)
1002 setValue(name
, value
, endian
);
1006 Sets the named value with the given 32-bit unsigned integer value,
1007 according to the desired byte-ordering.
1010 name = The name of the value to set. If it is the empty string,
1011 sets the default value.
1012 value = The 32-bit unsigned value to set.
1013 endian = Can be `Endian.BigEndian` or `Endian.LittleEndian`.
1015 If a value corresponding to the requested name is not found,
1016 `RegistryException` is thrown.
1018 void setValue(string name
, uint value
, Endian endian
)
1020 REG_VALUE_TYPE type
= _RVT_from_Endian(endian
);
1022 assert(type
== REG_VALUE_TYPE
.REG_DWORD_BIG_ENDIAN ||
1023 type
== REG_VALUE_TYPE
.REG_DWORD_LITTLE_ENDIAN
);
1025 regSetValue(m_hkey
, name
, type
, &value
, value
.sizeof
);
1029 Sets the named value with the given 64-bit unsigned integer value.
1032 name = The name of the value to set. If it is the empty string,
1033 sets the default value.
1034 value = The 64-bit unsigned value to set.
1036 If a value corresponding to the requested name is not found,
1037 `RegistryException` is thrown.
1039 void setValue(string name
, ulong value
)
1041 regSetValue(m_hkey
, name
, REG_VALUE_TYPE
.REG_QWORD
, &value
, value
.sizeof
);
1045 Sets the named value with the given string value.
1048 name = The name of the value to set. If it is the empty string,
1049 sets the default value.
1050 value = The string value to set.
1052 If a value corresponding to the requested name is not found,
1053 `RegistryException` is thrown.
1055 void setValue(string name
, string value
)
1057 setValue(name
, value
, false);
1061 Sets the named value with the given string value.
1064 name = The name of the value to set. If it is the empty string,
1065 sets the default value.
1066 value = The string value to set.
1067 asEXPAND_SZ = If `true`, the value will be stored as an
1068 expandable environment string, otherwise as a normal string.
1070 If a value corresponding to the requested name is not found,
1071 `RegistryException` is thrown.
1073 void setValue(string name
, string value
, bool asEXPAND_SZ
)
1075 auto pszTmp
= value
.tempCStringW();
1076 const(void)* data
= pszTmp
;
1077 DWORD len
= to
!DWORD(lstrlenW(pszTmp
) * wchar.sizeof
);
1079 regSetValue(m_hkey
, name
,
1080 asEXPAND_SZ ? REG_VALUE_TYPE
.REG_EXPAND_SZ
1081 : REG_VALUE_TYPE
.REG_SZ
,
1086 Sets the named value with the given multiple-strings value.
1089 name = The name of the value to set. If it is the empty string,
1090 sets the default value.
1091 value = The multiple-strings value to set.
1093 If a value corresponding to the requested name is not found,
1094 `RegistryException` is thrown.
1096 void setValue(string name
, string
[] value
)
1098 wstring
[] data
= new wstring
[value
.length
+1];
1099 foreach (i
, ref s
; data
[0..$-1])
1101 s
= value
[i
].to
!wstring
;
1104 auto ws
= std
.array
.join(data
, "\0"w
);
1106 regSetValue(m_hkey
, name
, REG_VALUE_TYPE
.REG_MULTI_SZ
, ws
.ptr
, to
!uint(ws
.length
* wchar.sizeof
));
1110 Sets the named value with the given binary value.
1113 name = The name of the value to set. If it is the empty string,
1114 sets the default value.
1115 value = The binary value to set.
1117 If a value corresponding to the requested name is not found,
1118 `RegistryException` is thrown.
1120 void setValue(string name
, byte[] value
)
1122 regSetValue(m_hkey
, name
, REG_VALUE_TYPE
.REG_BINARY
, value
.ptr
, to
!DWORD(value
.length
));
1126 Deletes the named value.
1129 name = The name of the value to delete. May not be `null`.
1131 If a value of the requested name is not found,
1132 `RegistryException` is thrown.
1134 void deleteValue(string name
)
1136 regDeleteValue(m_hkey
, name
);
1140 Flushes any changes to the key to disk.
1144 regFlushKey(m_hkey
);
1153 This class represents a value of a registry key.
1160 assert(m_key
!is null);
1165 this(Key key
, string name
, REG_VALUE_TYPE type
)
1168 assert(null !is key
);
1179 The name of the value.
1180 If the value represents a default value of a key, which has no name,
1181 the returned string will be of zero length.
1183 @property string
name() @safe pure nothrow const
1191 @property REG_VALUE_TYPE
type() @safe pure nothrow const
1197 Obtains the current value of the value as a string.
1198 If the value's type is REG_EXPAND_SZ the returned value is <b>not</b>
1199 expanded; `value_EXPAND_SZ` should be called
1202 The contents of the value.
1204 `RegistryException` if the type of the value is not REG_SZ,
1205 REG_EXPAND_SZ, REG_DWORD, or REG_QWORD.
1207 @property string
value_SZ() const
1211 regQueryValue(m_key
.m_hkey
, m_name
, value
, m_type
);
1217 Obtains the current value as a string, within which any environment
1218 variables have undergone expansion.
1219 This function works with the same value-types as `value_SZ`.
1222 The contents of the value.
1224 @property string
value_EXPAND_SZ() const
1226 string value
= value_SZ
;
1228 // ExpandEnvironemntStrings():
1229 // http://msdn2.microsoft.com/en-us/library/ms724265.aspx
1230 const srcTmp
= value
.tempCStringW();
1231 DWORD cchRequired
= ExpandEnvironmentStringsW(srcTmp
, null, 0);
1232 wchar[] newValue
= new wchar[cchRequired
];
1234 immutable DWORD count
= enforce
!Win32Exception(
1235 ExpandEnvironmentStringsW(srcTmp
, newValue
.ptr
, to
!DWORD(newValue
.length
)),
1236 "Failed to expand environment variables");
1238 return newValue
[0 .. count
-1].to
!string
; // remove trailing 0
1242 Obtains the current value as an array of strings.
1245 The contents of the value.
1247 `RegistryException` if the type of the value is not REG_MULTI_SZ.
1249 @property string
[] value_MULTI_SZ() const
1253 regQueryValue(m_key
.m_hkey
, m_name
, value
, m_type
);
1259 Obtains the current value as a 32-bit unsigned integer, ordered
1260 correctly according to the current architecture.
1263 The contents of the value.
1265 `RegistryException` is thrown for all types other than
1266 REG_DWORD, REG_DWORD_LITTLE_ENDIAN and REG_DWORD_BIG_ENDIAN.
1268 @property uint value_DWORD() const
1272 regQueryValue(m_key
.m_hkey
, m_name
, value
, m_type
);
1278 Obtains the value as a 64-bit unsigned integer, ordered correctly
1279 according to the current architecture.
1282 The contents of the value.
1284 `RegistryException` if the type of the value is not REG_QWORD.
1286 @property ulong value_QWORD() const
1290 regQueryValue(m_key
.m_hkey
, m_name
, value
, m_type
);
1296 Obtains the value as a binary blob.
1299 The contents of the value.
1301 `RegistryException` if the type of the value is not REG_BINARY.
1303 @property byte[] value_BINARY() const
1307 regQueryValue(m_key
.m_hkey
, m_name
, value
, m_type
);
1314 REG_VALUE_TYPE m_type
;
1319 Represents the local system registry.
1321 final class Registry
1327 /// Returns the root key for the HKEY_CLASSES_ROOT hive
1328 static @property Key
classesRoot() { return new Key(HKEY_CLASSES_ROOT
, "HKEY_CLASSES_ROOT", false); }
1329 /// Returns the root key for the HKEY_CURRENT_USER hive
1330 static @property Key
currentUser() { return new Key(HKEY_CURRENT_USER
, "HKEY_CURRENT_USER", false); }
1331 /// Returns the root key for the HKEY_LOCAL_MACHINE hive
1332 static @property Key
localMachine() { return new Key(HKEY_LOCAL_MACHINE
, "HKEY_LOCAL_MACHINE", false); }
1333 /// Returns the root key for the HKEY_USERS hive
1334 static @property Key
users() { return new Key(HKEY_USERS
, "HKEY_USERS", false); }
1335 /// Returns the root key for the HKEY_PERFORMANCE_DATA hive
1336 static @property Key
performanceData() { return new Key(HKEY_PERFORMANCE_DATA
, "HKEY_PERFORMANCE_DATA", false); }
1337 /// Returns the root key for the HKEY_CURRENT_CONFIG hive
1338 static @property Key
currentConfig() { return new Key(HKEY_CURRENT_CONFIG
, "HKEY_CURRENT_CONFIG", false); }
1339 /// Returns the root key for the HKEY_DYN_DATA hive
1340 static @property Key
dynData() { return new Key(HKEY_DYN_DATA
, "HKEY_DYN_DATA", false); }
1344 An enumerable sequence representing the names of the sub-keys of a registry Key.
1349 foreach (string subkeyName; key.keyNames)
1355 class KeyNameSequence
1360 assert(m_key
!is null);
1374 @property size_t
count() const
1376 return m_key
.keyCount
;
1380 The name of the key at the given index.
1383 index = The 0-based index of the key to retrieve.
1385 The name of the key corresponding to the given index.
1387 RegistryException if no corresponding key is retrieved.
1389 string
getKeyName(size_t index
)
1392 regProcessNthKey(m_key
, (scope LONG
delegate(DWORD
, out string
) getName
)
1394 enforceSucc(getName(to
!DWORD(index
), name
), "Invalid key");
1400 The name of the key at the given index.
1403 index = The 0-based index of the key to retrieve.
1405 The name of the key corresponding to the given index.
1407 `RegistryException` if no corresponding key is retrieved.
1409 string
opIndex(size_t index
)
1411 return getKeyName(index
);
1415 int opApply(scope int delegate(ref string name
) dg
)
1418 regProcessNthKey(m_key
, (scope LONG
delegate(DWORD
, out string
) getName
)
1420 for (DWORD index
= 0; !result
; ++index
)
1423 immutable res
= getName(index
, name
);
1424 if (res
== ERROR_NO_MORE_ITEMS
) // Enumeration complete
1426 enforceSucc(res
, "Key name enumeration incomplete");
1440 An enumerable sequence representing the sub-keys of a registry Key.
1445 foreach (Key subkey; key.keys)
1456 assert(m_key
!is null);
1470 @property size_t
count() const
1472 return m_key
.keyCount
;
1476 The key at the given index.
1479 index = The 0-based index of the key to retrieve.
1481 The key corresponding to the given index.
1483 `RegistryException` if no corresponding key is retrieved.
1485 Key
getKey(size_t index
)
1488 regProcessNthKey(m_key
, (scope LONG
delegate(DWORD
, out string
) getName
)
1490 enforceSucc(getName(to
!DWORD(index
), name
), "Invalid key");
1492 return m_key
.getKey(name
);
1496 The key at the given index.
1499 index = The 0-based index of the key to retrieve.
1501 The key corresponding to the given index.
1503 `RegistryException` if no corresponding key is retrieved.
1505 Key
opIndex(size_t index
)
1507 return getKey(index
);
1511 int opApply(scope int delegate(ref Key key
) dg
)
1514 regProcessNthKey(m_key
, (scope LONG
delegate(DWORD
, out string
) getName
)
1516 for (DWORD index
= 0; !result
; ++index
)
1519 immutable res
= getName(index
, name
);
1520 if (res
== ERROR_NO_MORE_ITEMS
) // Enumeration complete
1522 enforceSucc(res
, "Key enumeration incomplete");
1526 Key key
= m_key
.getKey(name
);
1529 catch (RegistryException e
)
1531 // Skip inaccessible keys; they are
1532 // accessible via the KeyNameSequence
1533 if (e
.error
== ERROR_ACCESS_DENIED
)
1548 An enumerable sequence representing the names of the values of a registry Key.
1553 foreach (string valueName; key.valueNames)
1559 class ValueNameSequence
1564 assert(m_key
!is null);
1576 The number of values.
1578 @property size_t
count() const
1580 return m_key
.valueCount
;
1584 The name of the value at the given index.
1587 index = The 0-based index of the value to retrieve.
1589 The name of the value corresponding to the given index.
1591 `RegistryException` if no corresponding value is retrieved.
1593 string
getValueName(size_t index
)
1596 regProcessNthValue(m_key
, (scope LONG
delegate(DWORD
, out string
) getName
)
1598 enforceSucc(getName(to
!DWORD(index
), name
), "Invalid value");
1604 The name of the value at the given index.
1607 index = The 0-based index of the value to retrieve.
1609 The name of the value corresponding to the given index.
1611 `RegistryException` if no corresponding value is retrieved.
1613 string
opIndex(size_t index
)
1615 return getValueName(index
);
1619 int opApply(scope int delegate(ref string name
) dg
)
1622 regProcessNthValue(m_key
, (scope LONG
delegate(DWORD
, out string
) getName
)
1624 for (DWORD index
= 0; !result
; ++index
)
1627 immutable res
= getName(index
, name
);
1628 if (res
== ERROR_NO_MORE_ITEMS
) // Enumeration complete
1630 enforceSucc(res
, "Value name enumeration incomplete");
1643 An enumerable sequence representing the values of a registry Key.
1648 foreach (Value value; key.values)
1659 assert(m_key
!is null);
1670 /// The number of values
1671 @property size_t
count() const
1673 return m_key
.valueCount
;
1677 The value at the given `index`.
1680 index = The 0-based index of the value to retrieve
1682 The value corresponding to the given index.
1684 `RegistryException` if no corresponding value is retrieved
1686 Value
getValue(size_t index
)
1689 regProcessNthValue(m_key
, (scope LONG
delegate(DWORD
, out string
) getName
)
1691 enforceSucc(getName(to
!DWORD(index
), name
), "Invalid value");
1693 return m_key
.getValue(name
);
1697 The value at the given `index`.
1700 index = The 0-based index of the value to retrieve.
1702 The value corresponding to the given index.
1704 `RegistryException` if no corresponding value is retrieved.
1706 Value
opIndex(size_t index
)
1708 return getValue(index
);
1712 int opApply(scope int delegate(ref Value value
) dg
)
1715 regProcessNthValue(m_key
, (scope LONG
delegate(DWORD
, out string
) getName
)
1717 for (DWORD index
= 0; !result
; ++index
)
1720 immutable res
= getName(index
, name
);
1721 if (res
== ERROR_NO_MORE_ITEMS
) // Enumeration complete
1723 enforceSucc(res
, "Value enumeration incomplete");
1725 Value value
= m_key
.getValue(name
);
1739 debug(winreg
) scope(success
) writeln("unittest @", __FILE__
, ":", __LINE__
, " succeeded.");
1740 debug(winreg
) writefln("std.windows.registry.unittest read");
1743 // Mask for test speed up
1745 Key HKCR = Registry.classesRoot;
1746 Key CLSID = HKCR.getKey("CLSID");
1748 foreach (Key key; CLSID.keys)
1750 foreach (Value val; key.values)
1755 Key HKCU
= Registry
.currentUser
;
1758 // Enumerate all subkeys of key Software
1759 Key softwareKey
= HKCU
.getKey("Software");
1760 assert(softwareKey
);
1761 foreach (Key key
; softwareKey
.keys
)
1763 //writefln("Key %s", key.name);
1764 foreach (Value val
; key
.values
)
1772 debug(winreg
) scope(success
) writeln("unittest @", __FILE__
, ":", __LINE__
, " succeeded.");
1773 debug(winreg
) writefln("std.windows.registry.unittest write");
1775 // Warning: This unit test writes to the registry.
1776 // The test can fail if you don't have sufficient rights
1778 Key HKCU
= Registry
.currentUser
;
1782 string unittestKeyName
= "Temporary key for a D UnitTest which can be deleted afterwards";
1783 Key unittestKey
= HKCU
.createKey(unittestKeyName
);
1784 assert(unittestKey
);
1785 Key cityKey
= unittestKey
.createKey(
1786 "CityCollection using foreign names with umlauts and accents: "
1787 ~"\u00f6\u00e4\u00fc\u00d6\u00c4\u00dc\u00e0\u00e1\u00e2\u00df"
1789 cityKey
.setValue("K\u00f6ln", "Germany"); // Cologne
1790 cityKey
.setValue("\u041c\u0438\u043d\u0441\u043a", "Belarus"); // Minsk
1791 cityKey
.setValue("\u5317\u4eac", "China"); // Bejing
1792 bool foundCologne
, foundMinsk
, foundBeijing
;
1793 foreach (Value v
; cityKey
.values
)
1795 auto vname
= v
.name
;
1796 auto vvalue_SZ
= v
.value_SZ
;
1797 if (v
.name
== "K\u00f6ln")
1799 foundCologne
= true;
1800 assert(v
.value_SZ
== "Germany");
1802 if (v
.name
== "\u041c\u0438\u043d\u0441\u043a")
1805 assert(v
.value_SZ
== "Belarus");
1807 if (v
.name
== "\u5317\u4eac")
1809 foundBeijing
= true;
1810 assert(v
.value_SZ
== "China");
1813 assert(foundCologne
);
1815 assert(foundBeijing
);
1817 Key stateKey
= unittestKey
.createKey("StateCollection");
1818 stateKey
.setValue("Germany", ["D\u00fcsseldorf", "K\u00f6ln", "Hamburg"]);
1819 Value v
= stateKey
.getValue("Germany");
1820 string
[] actual
= v
.value_MULTI_SZ
;
1821 assert(actual
.length
== 3);
1822 assert(actual
[0] == "D\u00fcsseldorf");
1823 assert(actual
[1] == "K\u00f6ln");
1824 assert(actual
[2] == "Hamburg");
1826 Key numberKey
= unittestKey
.createKey("Number");
1827 numberKey
.setValue("One", 1);
1828 Value one
= numberKey
.getValue("One");
1829 assert(one
.value_SZ
== "1");
1830 assert(one
.value_DWORD
== 1);
1832 unittestKey
.deleteKey(numberKey
.name
);
1833 unittestKey
.deleteKey(stateKey
.name
);
1834 unittestKey
.deleteKey(cityKey
.name
);
1835 HKCU
.deleteKey(unittestKeyName
);
1837 auto e
= collectException
!RegistryException(HKCU
.getKey("cDhmxsX9K23a8Uf869uB"));
1838 assert(e
.msg
.endsWith(" (error 2)"));
1843 Key HKCU
= Registry
.currentUser
;
1846 Key key
= HKCU
.getKey("Control Panel");
1848 assert(key
.keyCount
>= 2);
1850 // Make sure `key` isn't garbage-collected while iterating over it.
1851 // Trigger a collection in the first iteration and check whether we
1852 // make it successfully to the second iteration.
1854 foreach (name
; key
.keyNames
)
1859 import core
.memory
: GC
;