| 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]; |
|---|
| 5 |
|---|