root/trunk/tango/scrapple/sys/win32/Registry.d

Revision 39, 26.2 kB (checked in by flithm, 4 years ago)

Fixes for Tango 0.99.4

Line 
1 /*
2  * Copyright (c) 2007 John Chapman
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use,
8  * copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following
11  * conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23  * OTHER DEALINGS IN THE SOFTWARE.
24  */
25
26 /**
27  * Provides classes for working with the Windows _registry.
28  * modified by yidabu, 20070922
29    under DMD 1.021, tango 0.99.1 RC4, WindosXP SP2
30    example:
31   
32     import tango.io.Stdout;
33     import Registry;
34
35     void main()
36     {
37         char[] result;
38         scope httpkey = RegistryKey.classesRoot.openSubKey(r"HTTP\shell\open\command");
39         if(httpkey !is null)
40         {
41             result = httpkey.getValue!(string)(null);
42             Stdout(result).newline;
43             //"C:\Program Files\Internet Explorer\iexplore.exe" -nohome
44         }
45         else
46             Stdout("failed").newline;
47         
48     }   
49  
50  
51  */
52 //module juno.utils.registry;
53 module Registry;
54
55 /*
56 private import juno.base.core,
57   juno.base.string,
58   juno.base.environment,
59   juno.base.numeric,
60   juno.base.native,
61   juno.io.core;
62 */
63 private import tango.core.Exception;
64 private import tango.stdc.string : wcslen;
65 private import tango.text.convert.Utf : toString16, toUTF8 = toString;
66
67 // Grabbed from juno.base.native, use tango.sys.win32.UserGdi have some problem here
68 typedef void* Handle = null;
69 extern(Windows)
70 {
71     extern final Handle INVALID_HANDLE_VALUE; // Already defined by Phobos
72     struct OVERLAPPED {
73       uint Internal;
74       uint InternalHigh;
75       union {
76         struct {
77           uint Offset;
78           uint OffsetHigh;
79         }
80         void* Pointer;
81       }
82       Handle hEvent;
83     }
84     struct FILETIME {
85       uint dwLowDateTime;
86       uint dwHighDateTime;
87     }
88     struct SECURITY_ATTRIBUTES {
89       uint nLength;
90       void* lpSecurityDescriptor;
91       int bInheritHandle;
92     }
93     enum : uint {
94       REG_NONE                        = 0,
95       REG_SZ                          = 1,
96       REG_EXPAND_SZ                   = 2,
97       REG_BINARY                      = 3,
98       REG_DWORD                       = 4,
99       REG_DWORD_LITTLE_ENDIAN         = 4,
100       REG_DWORD_BIG_ENDIAN            = 5,
101       REG_LINK                        = 6,
102       REG_MULTI_SZ                    = 7,
103       REG_RESOURCE_LIST               = 8,
104       REG_FULL_RESOURCE_DESCRIPTOR    = 9,
105       REG_RESOURCE_REQUIREMENTS_LIST  = 10,
106       REG_QWORD                       = 11,
107       REG_QWORD_LITTLE_ENDIAN         = 11
108     }
109     enum : uint {
110       DELETE                          = 0x00010000,
111       READ_CONTROL                    = 0x00020000,
112       WRITE_DAC                       = 0x00040000,
113       WRITE_OWNER                     = 0x00080000,
114       SYNCHRONIZE                     = 0x00100000,
115       STANDARD_RIGHTS_REQUIRED        = 0x000F0000,
116       STANDARD_RIGHTS_READ            = READ_CONTROL,
117       STANDARD_RIGHTS_WRITE           = READ_CONTROL,
118       STANDARD_RIGHTS_EXECUTE         = READ_CONTROL,
119       STANDARD_RIGHTS_ALL             = 0x001F0000,
120       SPECIFIC_RIGHTS_ALL             = 0x0000FFFF
121     }
122     enum {
123       ERROR_SUCCESS = 0,
124       ERROR_INVALID_FUNCTION = 1,
125       ERROR_FILE_NOT_FOUND = 2,
126       ERROR_PATH_NOT_FOUND = 3,
127       ERROR_TOO_MANY_OPEN_FILES = 4,
128       ERROR_ACCESS_DENIED = 5,
129       ERROR_INVALID_HANDLE = 6,
130       ERROR_CLASS_ALREADY_EXISTS = 1410
131     }
132
133     enum : uint {
134       KEY_QUERY_VALUE        = 0x0001,
135       KEY_SET_VALUE          = 0x0002,
136       KEY_CREATE_SUB_KEY     = 0x0004,
137       KEY_ENUMERATE_SUB_KEYS = 0x0008,
138       KEY_NOTIFY             = 0x0010,
139       KEY_CREATE_LINK        = 0x0020,
140
141       KEY_READ               = (STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & ~SYNCHRONIZE,
142       KEY_WRITE              = (STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) & ~SYNCHRONIZE,
143       KEY_EXECUTE            = KEY_READ & ~SYNCHRONIZE,
144       KEY_ALL_ACCESS         = (STANDARD_RIGHTS_ALL | KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_CREATE_LINK) & ~SYNCHRONIZE,
145     }
146     alias void function(uint dwErrorCode, uint dwNumberOfBytesTransferred, OVERLAPPED* lpOverlapped) OVERLAPPED_COMPLETION_ROUTINE;
147     uint ExpandEnvironmentStringsW(wchar* lpSrc, wchar* lpDst, uint nSize);
148     alias ExpandEnvironmentStringsW ExpandEnvironmentStrings;
149     extern final Handle HKEY_CLASSES_ROOT;
150     extern final Handle HKEY_CURRENT_USER;
151     extern final Handle HKEY_LOCAL_MACHINE;
152     extern final Handle HKEY_USERS;
153     extern final Handle HKEY_PERFORMANCE_DATA;
154     extern final Handle HKEY_CURRENT_CONFIG;
155     extern final Handle HKEY_DYN_DATA;
156     int ReadDirectoryChangesW(Handle hDirectory, void* lpBuffer, uint nBufferLength, int bWatchSubtree, uint dwNotifyFilter, ref uint lpBytesReturned, OVERLAPPED* lpOverlapped, OVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
157     alias ReadDirectoryChangesW ReadDirectoryChanges;
158
159     int RegOpenKeyExW(Handle hKey, wchar* lpSubKey, uint ulOptions, uint samDesired, out Handle phkResult);
160     alias RegOpenKeyExW RegOpenKeyEx;
161
162     int RegQueryValueExW(Handle hKey, wchar* lpValueName, uint* lpReserved, uint* lpType, ubyte* lpData, uint* lpcbData);
163     alias RegQueryValueExW RegQueryValueEx;
164
165     int RegQueryInfoKeyW(Handle hKey, wchar* lpClass, uint* lpcchClass, uint* lpReserved, uint* lpcSubKeys, uint* lpcbMaxSubKeyLen, uint* lpcbMaxClassLen, uint* lpcValues, uint* lpcbMaxValueNameLen, uint* lpcMaxValueLen, uint* lpcbSecurityDescriptor, FILETIME* lpftLastWriteTime);
166     alias RegQueryInfoKeyW RegQueryInfoKey;
167
168     int RegEnumKeyExW(Handle hKey, uint dwIndex, wchar* lpName, uint* lpcchName, uint* lpReserved, wchar* lpClass, uint* lpcchClass, FILETIME* lpftLastWriteTime);
169     alias RegEnumKeyExW RegEnumKeyEx;
170
171     int RegEnumValueW(Handle hKey, uint dwIndex, wchar* lpValueName, uint* lpcchValueName, uint* lpReserved, uint* lpType, ubyte* lpData, uint* lpcbData);
172     alias RegEnumValueW RegEnumValue;
173
174     int RegCreateKeyExW(Handle hKey, wchar* lpSubKey, uint Reserved, wchar* lpClass, uint dwOptions, int samDesired, SECURITY_ATTRIBUTES* lpSecurityAttriubtes, out Handle phkResult, out uint lpsdwDisposition);
175     alias RegCreateKeyExW RegCreateKeyEx;
176
177     int RegCloseKey(Handle hKey);
178
179     int RegFlushKey(Handle hKey);
180
181     int RegDeleteKeyW(Handle hKey, wchar* lpName);
182     alias RegDeleteKeyW RegDeleteKey;
183
184     int RegDeleteValueW(Handle hKey, wchar* lpValueName);
185     alias RegDeleteValueW RegDeleteValue;
186
187     int RegSetValueExW(Handle hKey, wchar* lpValueName, uint Reserved, uint dwType, ubyte* lpData, uint cbData);
188     alias RegSetValueExW RegSetValueEx;
189 }//extern
190
191
192 /*
193 //for tango.sys.win32.UserGdi
194 alias RegQueryInfoKeyW RegQueryInfoKey;
195 alias RegSetValueExW RegSetValueEx;
196 alias RegUnLoadKeyW RegUnLoadKey;
197 alias RegRestoreKeyW RegRestoreKey;
198 alias RegSaveKeyW RegSaveKey;
199 alias RegSetValueW RegSetValue;
200 alias RegQueryValueW RegQueryValue;
201 alias RegQueryMultipleValuesW RegQueryMultipleValues;
202 alias RegQueryValueExW RegQueryValueEx;
203 alias RegReplaceKeyW RegReplaceKey;
204 alias RegConnectRegistryW RegConnectRegistry;
205 alias RegCreateKeyW RegCreateKey;
206 alias RegCreateKeyExW RegCreateKeyEx;
207 alias RegDeleteKeyW RegDeleteKey;
208 alias RegDeleteValueW RegDeleteValue;
209 alias RegEnumKeyW RegEnumKey;
210 alias RegEnumKeyExW RegEnumKeyEx;
211 alias RegEnumValueW RegEnumValue;
212 alias RegLoadKeyW RegLoadKey;
213 alias RegOpenKeyW RegOpenKey;
214 alias RegOpenKeyExW RegOpenKeyEx;
215 alias RegQueryInfoKeyW RegQueryInfoKey;
216 alias HANDLE Handle;
217 */
218
219 alias char[] string;
220
221 // Grabbed from juno.base.string since Tango's stdc.stringz, text.convert.Utf lacks these:
222 public wchar* toString16z(string s, int start = 0, int count = -1) {
223   if (s is null)
224     return null;
225   if (s.length == 0 || count == 0)
226     return "";
227   if (count == -1)
228     count = s.length;
229   return s[start .. count].toUTF16z();
230 }
231 public string toString(wchar* s, int start = 0, int count = -1) {
232   if (s == null)
233     return null;
234   if (count == -1)
235     count = wcslen(cast(dchar*)s);
236   return s[start .. count].toUTF8();
237 }
238 /**
239  * Returns a string array containing the substrings in s that are delimited by elements of the specified char array.
240  * Params:
241  *   s = The string to _split.
242  *   separator = An array of characters that delimit the substrings in s.
243  *   count = The maximum number of substrings to return.
244  *   removeEmptyEntries = true to omit empty array elements from the array returned, or false to include empty array elements in the array returned.
245  * Returns: An array whose elements contain the substrings in s that are delimited by one or more characters in separator.
246  */
247 public string[] split(string s, char[] separator, int count = int.max, bool removeEmptyEntries = false) {
248
249   int createSeparatorList(ref int[] sepList) {
250     int foundCount;
251     if (separator.length == 0) {
252       for (int i = 0; i < s.length && foundCount < sepList.length; i++) {
253         if (isWhiteSpace(s[i]))
254           sepList[foundCount++] = i;
255       }
256     }
257     else {
258       for (int i = 0; i < s.length && foundCount < sepList.length; i++) {
259         for (int j = 0; j < separator.length; j++) {
260           if (s[i] == separator[j]) {
261             sepList[foundCount++] = i;
262             break;
263           }
264         }
265       }
266     }
267     return foundCount;
268   }
269
270   if (count == 0 || (removeEmptyEntries && s.length == 0))
271     return new string[0];
272
273   int[] sepList = new int[s.length];
274   int replaceCount = createSeparatorList(sepList);
275
276   if (replaceCount == 0 || count == 1)
277     return [ s ];
278
279   string[] splitStrings;
280   int arrayIndex, currentIndex;
281
282   if (removeEmptyEntries) {
283     int max = (replaceCount < count) ? replaceCount + 1 : count;
284     splitStrings.length = max;
285     for (int i = 0; i < replaceCount && currentIndex < s.length; i++) {
286       if (sepList[i] - currentIndex > 0)
287         splitStrings[arrayIndex++] = s[currentIndex .. sepList[i]];
288       currentIndex = sepList[i] + 1;
289       if (arrayIndex == count - 1) {
290         while (i < replaceCount - 1 && currentIndex == sepList[++i]) {
291           currentIndex += 1;
292         }
293         break;
294       }
295     }
296
297     if (currentIndex < s.length)
298       splitStrings[arrayIndex++] = s[currentIndex .. $];
299
300     string[] strings = splitStrings;
301     if (arrayIndex != max) {
302       strings.length = arrayIndex;
303       for (int j = 0; j < arrayIndex; j++)
304         strings[j] = splitStrings[j];
305     }
306     splitStrings = strings;
307   }
308   else {
309     count--;
310     int max = (replaceCount < count) ? replaceCount : count;
311     splitStrings.length = max + 1;
312     for (int i = 0; i < max && currentIndex < s.length; i++) {
313       splitStrings[arrayIndex++] = s[currentIndex .. sepList[i]];
314       currentIndex = sepList[i] + 1;
315     }
316
317     if (currentIndex < s.length && max >= 0)
318       splitStrings[arrayIndex] = s[currentIndex .. $];
319     else if (arrayIndex == max)
320       splitStrings[arrayIndex] = null;
321   }
322
323   return splitStrings;
324 }
325 private final char[] WhiteSpaceChars = [ '\t', '\n', '\v', '\f', '\r', ' ' ];
326
327 /**
328  * Indicates whether the specified character is white space.
329  * Params: c = A character.
330  * Returns: true if c is white space; otherwise, false.
331  */
332 public bool isWhiteSpace(char c) {
333   foreach (ch; WhiteSpaceChars) {
334     if (ch == c)
335       return true;
336   }
337   return false;
338 }
339
340
341     wchar* toUTF16z(char[] s)
342     {
343         wchar[] ws;
344         ws = toString16(s);
345         ws ~= '\0';
346         return ws.ptr;
347     }
348    
349
350 public string expandEnvironmentVariables(string name) {
351   string[] parts = name.split(['%']);
352
353   int c = 100;
354   wchar[] buffer = new wchar[c];
355   for (int i = 1; i < parts.length - 1; i++) {
356     if (parts[i].length > 0) {
357       string temp = "%" ~ parts[i] ~ "%";
358       uint n = ExpandEnvironmentStrings(temp.toString16z(), buffer.ptr, c);
359       while (n > c) {
360         c = n;
361         buffer.length = c;
362         n = ExpandEnvironmentStrings(temp.toString16z(), buffer.ptr, c);
363       }
364     }
365   }
366   int n = ExpandEnvironmentStrings(name.toString16z(), buffer.ptr, c);
367   while (n > c) {
368     c = n;
369     buffer.length = c;
370     n = ExpandEnvironmentStrings(name.toString16z(), buffer.ptr, c);
371   }
372
373   return .toString(buffer.ptr);
374 }
375
376
377 /**
378  * Identifies the data type of a value in the registry.
379  */
380 public enum RegistryValueKind {
381   Unknown = 0,        /// Indicates an unsupported registry data type.
382   String = 1,         /// Specifies a string. Equivalent to REG_SZ.
383   ExpandString = 2,   /// Specifies a string containing references to environment variables. Equivalent to REG_EXPAND_SZ.
384   Binary = 3,         /// Specifies binary data in any form. Equivalent to REG_BINARY.
385   DWord = 4,          /// Specifies a 32-bit binary number. Equivalent to REG_DWORD.
386   MultiString = 7,    /// Specifies an array of strings. Equivalent to REG_MULTI_SZ.
387   QWord = 11          /// Specifies a 64-bit binary number. Equivalent to REG_QWORD.
388 }
389
390 /**
391  * Represents a node in the Windows registry.
392  */
393 public final class RegistryKey {
394
395   private const string[] HKEY_NAMES = [
396     "HKEY_CLASSES_ROOT", "HKEY_CURRENT_USER", "HKEY_LOCAL_MACHINE", "HKEY_USERS", "HKEY_PERFORMANCE_DATA", "HKEY_CURRENT_CONFIG", "HKEY_DYN_DATA"
397   ];
398
399   public static const RegistryKey classesRoot;      /// Defines the types of documents and properties associated with those types. Reads HKEY_CLASSES_ROOT.
400   public static const RegistryKey currentUser;      /// Contains information about the current user preferences. Reads HKEY_CURRENT_USER.
401   public static const RegistryKey localMachine;     /// Contains configuration data for the local machine. Reads HKEY_LOCAL_MACHINE.
402   public static const RegistryKey users;            /// Contains information about the default user configuration. Reads HKEY_USERS.
403   public static const RegistryKey performanceData;  /// Contains performance information for software components. Reads HKEY_PERFORMANCE_DATA.
404   public static const RegistryKey currentConfig;    /// Contains configuration information about hardware that is not specifiec to the user. Reads HKEY_CURRENT_CONFIG.
405   public static const RegistryKey dynData;          /// Contains dynamic registry data. Reads HKEY_DYN_DATA.
406
407   private Handle hKey_;
408   private string name_;
409   private bool systemKey_;
410   private bool perfDataKey_;
411   private bool writable_;
412   private bool remoteKey_;
413   private bool dirty_;
414
415   static this() {
416     classesRoot = get(cast(Handle)HKEY_CLASSES_ROOT);
417     currentUser = get(cast(Handle)HKEY_CURRENT_USER);
418     localMachine = get(cast(Handle)HKEY_LOCAL_MACHINE);
419     users = get(cast(Handle)HKEY_USERS);
420     performanceData = get(cast(Handle)HKEY_PERFORMANCE_DATA);
421     currentConfig = get(cast(Handle)HKEY_CURRENT_CONFIG);
422     dynData = get(cast(Handle)HKEY_DYN_DATA);
423   }
424
425   ~this() {
426     close();
427   }
428
429   /**
430    * Retrieves a string representation of this key.
431    * Returns: A string representing the key.
432    */
433   //public override string toString() {
434   public string toString() {
435     return name_;
436   }
437
438   /**
439    * Closes the key.
440    */
441   public void close() {
442     if (hKey_ != Handle.init) {
443       if (!systemKey_) {
444         RegCloseKey(hKey_);
445         hKey_ = Handle.init;
446       }
447     }
448   }
449
450   /**
451    * Writes all the attributes of this key to the registry.
452    */
453   public void flush() {
454     if (hKey_ != Handle.init && dirty_)
455       RegFlushKey(hKey_);
456   }
457
458   /**
459    * Retrieves a subkey.
460    * Params:
461    *   name = Name or path of the subkey to open.
462    *   writable = true if you need write access to the key.
463    * Returns: The subkey requested, or null if the operation failed.
464    */
465   public RegistryKey openSubKey(string name, bool writable = false) {
466     Handle hkey;
467     int r = RegOpenKeyEx(hKey_, name.toString16z(), 0, (writable ? (KEY_READ | KEY_WRITE) : KEY_READ), hkey);
468     if (r == ERROR_SUCCESS && hkey != Handle.init && hkey != INVALID_HANDLE_VALUE) {
469       auto key = new RegistryKey(hkey, writable, false, false, false);
470       key.name_ = this.name_ ~ '\\' ~ name;
471       return key;
472     }
473     //if (r == ERROR_ACCESS_DENIED)
474       //issueError(r, name_ ~ '\\' ~ name);
475     return null;
476   }
477
478   public RegistryKey createSubKey(string name) {
479     Handle hkey;
480     uint disposition;
481     int r = RegCreateKeyEx(hKey_, name.toString16z(), 0, null, 0, KEY_READ | KEY_WRITE, null, hkey, disposition);
482     if (r == ERROR_SUCCESS && hkey != Handle.init && hkey != INVALID_HANDLE_VALUE) {
483       auto key = new RegistryKey(hkey, true, false, false, false);
484       if (name.length == 0)
485         key.name_ = name_;
486       else
487         key.name_ = name_ ~ '\\' ~ name;
488       return key;
489     }
490     //if (r != ERROR_SUCCESS)
491       //issueError(r, name_ ~ '\\' ~ name);
492     return null;
493   }
494
495   /**
496    * Deletes the specified subkey.
497    * Params: name = The _name of the subkey to delete.
498    */
499   public void deleteSubKey(string name) {
500     RegDeleteKey(hKey_, name.toString16z());
501   }
502
503   public void deleteSubKeyTree(string name) {
504     scope key = openSubKey(name, true);
505     if (key !is null) {
506       if (key.subKeyCount > 0) {
507         foreach (subkey; key.subKeyNames)
508           key.deleteSubKeyTree(subkey);
509       }
510
511       key.close();
512
513       int r = RegDeleteKey(hKey_, name.toString16z());
514       //if (r != ERROR_SUCCESS)
515         //issueError(r, null);
516     }
517     else
518       throw new RegistryException("Cannot delete a subkey tree because the subkey does not exist.");
519   }
520
521   /**
522    * Deletes the specified value from the registry.
523    * Params: name = The _name of the value to delete.
524    */
525   public void deleteValue(string name) {
526     RegDeleteValue(hKey_, name.toString16z());
527   }
528
529   /**
530    * Retrieves the registry data type of the value associated with the specified _name.
531    * Params: name = The _name of the value whose registry data type is to be retrieved.
532    * Returns: A value representing the registry data type of the value associated with name.
533    */
534   public RegistryValueKind getValueKind(string name) {
535     uint cb, type;
536     RegQueryValueEx(hKey_, name.toString16z(), null, &type, null, &cb);
537     return cast(RegistryValueKind)type;
538   }
539
540   /**
541    * Retrieves the value associated with the specified _name.
542    * Params:
543    *   name = The _name of the value to retrieve.
544    *   defaultValue = The value to return if name does not exist.
545    *   doNotExpand = Specify false to expand environment values.
546    * Returns: The value associated with name, or defaultValue if name is not found.
547    */
548   public T getValue(T)(string name, T defaultValue = T.init, bool doNotExpand = false) {
549     uint cb, type;
550     if (RegQueryValueEx(hKey_, name.toString16z(), null, &type, null, &cb) == 0) {
551       static if (is(T == int)) {
552         if (type == REG_DWORD) {
553           int b;
554           RegQueryValueEx(hKey_, name.toString16z(), null, &type, cast(ubyte*)&b, &cb);
555           return b;
556         }
557       }
558       else static if (is(T == long)) {
559         if (type == REG_QWORD) {
560           long b;
561           RegQueryValueEx(hKey_, name.toString16z(), null, &type, cast(ubyte*)&b, &cb);
562           return b;
563         }
564       }
565       else static if (is(T : string)) {
566         if (type == REG_SZ || type == REG_EXPAND_SZ) {
567           wchar[] b = new wchar[cb / 2];
568           RegQueryValueEx(hKey_, name.toString16z(), null, &type, cast(ubyte*)b.ptr, &cb);
569           string result = .toString(b.ptr);
570
571           if (!doNotExpand && type == REG_EXPAND_SZ)
572             return expandEnvironmentVariables(result);
573
574           return result;
575         }
576       }
577       else static if (is(T : string[])) {
578         if (type == REG_MULTI_SZ) {
579           string[] result;
580
581           wchar[] b = new wchar[cb / 2];
582           RegQueryValueEx(hKey_, name.toString16z(), null, &type, cast(ubyte*)b.ptr, &cb);
583
584           uint index = 0;
585           int end = b.length;
586           while (index < end) {
587             uint pos = index;
588             while (pos < end && b[pos] != '\0') pos++;
589
590             if (pos < end) {
591               if (pos - index > 0) result ~= .toString(b.ptr, index, pos);
592               else if (pos != end - 1) result ~= "";
593             }
594             else result ~= .toString(b.ptr, index, end);
595
596             index = pos + 1;
597           }
598
599           return result;
600         }
601       }
602       else static if (is(T == ubyte[])) {
603         if (type == REG_BINARY || type == REG_DWORD_BIG_ENDIAN) {
604           ubyte[] b = new ubyte[cb];
605           RegQueryValueEx(hKey_, name.toString16z(), null, &type, b.ptr, &cb);
606           return b;
607         }
608       }
609     }
610     return defaultValue;
611   }
612
613   /**
614    * Sets the _value of a name/value pair in the registry key using the specified registry data type.
615    * Params:
616    *   name = The _name of the _value to be stored.
617    *   value = The data to be stored.
618    *   valueKind = The registry data type to use when storing the data.
619    */
620   public void setValue(T)(string name, T value, RegistryValueKind valueKind = RegistryValueKind.Unknown) {
621     if (valueKind == RegistryValueKind.Unknown) {
622       static if (is(T : string))
623         valueKind = RegistryValueKind.String;
624       else static if (is(T : string[]))
625         valueKind = RegistryValueKind.MultiString;
626       else static if (is(T == ubyte[]))
627         valueKind = RegistryValueKind.Binary;
628       else static if (is(T == int))
629         valueKind = RegistryValueKind.DWord;
630       else static if (is(T == long))
631         valueKind = RegistryValueKind.QWord;
632       else
633         valueKind = RegistryValueKind.String;
634     }
635
636     int r = ERROR_SUCCESS;
637
638     switch (valueKind) {
639       case RegistryValueKind.String, RegistryValueKind.ExpandString:
640         string s;
641         static if (!is(T : string))
642           s = .toString(value);
643         else
644           s = value;
645         r = RegSetValueEx(hKey_, name.toString16z(), 0, REG_SZ, cast(ubyte*)s.toString16z(), (s.length * 2) + 2);
646         break;
647       case RegistryValueKind.MultiString:
648         break;
649       case RegistryValueKind.Binary:
650         r = RegSetValueEx(hKey_, name.toString16z(), 0, REG_BINARY, cast(ubyte*)value.ptr, value.length);
651         break;
652       case RegistryValueKind.DWord:
653         r = RegSetValueEx(hKey_, name.toString16z(), 0, REG_DWORD, cast(ubyte*)&value, int.sizeof);
654         break;
655       case RegistryValueKind.QWord:
656         r = RegSetValueEx(hKey_, name.toString16z(), 0, REG_QWORD, cast(ubyte*)&value, long.sizeof);
657         break;
658       default:
659     }
660
661     if (r == ERROR_SUCCESS)
662       dirty_ = true;
663   }
664
665   /**
666    * Returns: The _name of the key.
667    */
668   public string name() {
669     return name_;
670   }
671
672   /**
673    * Retrieves the count of subkeys of this key.
674    * Returns: The number of subkeys.
675    */
676   public int subKeyCount() {
677     uint result;
678     RegQueryInfoKey(hKey_, null, null, null, &result, null, null, null, null, null, null, null);
679     return result;
680   }
681
682   /**
683    * Returns: An array of strings containing the subkey names.
684    */
685   public string[] subKeyNames() {
686     int count = subKeyCount;
687     string[] result = new string[count];
688
689     if (count > 0) {
690       wchar[256] buffer;
691       for (int index = 0; index < count; index++) {
692         uint cch = buffer.length;
693         RegEnumKeyEx(hKey_, index, buffer.ptr, &cch, null, null, null, null);
694         result[index] = .toString(buffer.ptr);
695       }
696     }
697
698     return result;
699   }
700
701   /**
702    * Retrieves the count of values in the key.
703    * Returns: The number of values.
704    */
705   public int valueCount() {
706     uint result;
707     RegQueryInfoKey(hKey_, null, null, null, null, null, null, &result, null, null, null, null);
708     return result;
709   }
710
711   /**
712    * Retrieves an array of strings containing the value names associated with this key.
713    * Returns: An array of strings containing the value names.
714    */
715   public string[] valueNames() {
716     int count = valueCount;
717     string[] result = new string[count];
718
719     if (count > 0) {
720       wchar[256] buffer;
721       for (int index = 0; index < count; index++) {
722         uint cch = buffer.length;
723         RegEnumValue(hKey_, index, buffer.ptr, &cch, null, null, null, null);
724         result[index] = .toString(buffer.ptr);
725       }
726     }
727
728     return result;
729   }
730
731   private this(Handle hKey, bool writable, bool systemKey = false, bool remoteKey = false, bool perfDataKey = false) {
732     hKey_ = hKey;
733     writable_ = writable;
734     systemKey_ = systemKey;
735     perfDataKey_ = perfDataKey;
736   }
737
738   private static RegistryKey get(Handle hKey) {
739     auto key = new RegistryKey(hKey, true, true, false, hKey == HKEY_PERFORMANCE_DATA);
740     key.name_ = HKEY_NAMES[cast(int)hKey & 0x0FFFFFFF];
741     return key;
742   }
743
744   /*
745   private void issueError(int errorCode, string s) {
746
747     string getErrorMessage(uint error) {
748       wchar[256] buffer;
749       uint r = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_IGNORE_INSERTS, null, error, LOCALE_USER_DEFAULT, buffer.ptr, buffer.length + 1, null);
750       if (r != 0) {
751         return toString(buffer.ptr, 0, r);
752       }
753       return format("Unspecified error (0x{0:X8})", error);
754     }
755
756     switch (errorCode) {
757       case ERROR_FILE_NOT_FOUND:
758         throw new IOException("The specified registry key does not exist.");
759       case ERROR_ACCESS_DENIED:
760         throw new UnauthorizedAccessException("Access to the registry key '" ~ s ~ "' is denied.");
761       default:
762         throw new IOException(getErrorMessage(errorCode));
763     }
764     
765   }
766   */
767
768 }
Note: See TracBrowser for help on using the browser.