1 /** DGui project file.
2 
3 Copyright: Trogu Antonio Davide 2011-2013
4 
5 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
6 
7 Authors: Trogu Antonio Davide
8 */
9 module dguihub.registry;
10 
11 pragma(lib, "advapi32.lib");
12 
13 private import std.utf : toUTFz, toUTF8;
14 
15 private import std..string : format;
16 
17 private import std.conv;
18 import dguihub.core.winapi;
19 import dguihub.core.interfaces.idisposable;
20 import dguihub.core.exception;
21 import dguihub.core.handle;
22 
23 enum RegistryValueType : uint {
24    binary = REG_BINARY,
25    dword = REG_DWORD,
26    qword = REG_QWORD,
27    string_ = REG_SZ,
28 }
29 
30 interface IRegistryValue {
31    public void write(RegistryKey owner, string name);
32    public RegistryValueType valueType();
33 }
34 
35 abstract class RegistryValue(T) : IRegistryValue {
36    private T _value;
37 
38    public this(T val) {
39       this._value = val;
40    }
41 
42    @property public abstract RegistryValueType valueType();
43 }
44 
45 final class RegistryValueBinary : RegistryValue!(ubyte[]) {
46    public this(ubyte[] b) {
47       super(b);
48    }
49 
50    @property public override RegistryValueType valueType() {
51       return RegistryValueType.binary;
52    }
53 
54    public override string toString() {
55       string s;
56 
57       foreach (ubyte b; this._value) {
58          s ~= format("%02X", b);
59       }
60 
61       return s;
62    }
63 
64    public void write(RegistryKey owner, string name) {
65       ulong res = RegSetValueExW(owner.handle, toUTFz!(wchar*)(name), 0,
66             REG_BINARY, cast(ubyte*)this._value.ptr, this._value.length);
67 
68       if (res != ERROR_SUCCESS) {
69          throwException!(RegistryException)("RegSetValueEx failed, Key '%s'", name);
70       }
71    }
72 }
73 
74 final class RegistryValueString : RegistryValue!(string) {
75    public this(string s) {
76       super(s);
77    }
78 
79    @property public override RegistryValueType valueType() {
80       return RegistryValueType.string_;
81    }
82 
83    public override string toString() {
84       return this._value.idup;
85    }
86 
87    public void write(RegistryKey owner, string name) {
88       ulong res = RegSetValueExW(owner.handle, toUTFz!(wchar*)(name), 0,
89             REG_SZ, cast(ubyte*)this._value.ptr, this._value.length);
90 
91       if (res != ERROR_SUCCESS) {
92          throwException!(RegistryException)("RegSetValueEx failed, Key '%s'", name);
93       }
94    }
95 }
96 
97 final class RegistryValueDword : RegistryValue!(uint) {
98    public this(uint i) {
99       super(i);
100    }
101 
102    @property public override RegistryValueType valueType() {
103       return RegistryValueType.dword;
104    }
105 
106    public override string toString() {
107       return to!(string)(this._value);
108    }
109 
110    public void write(RegistryKey owner, string name) {
111       ulong res = RegSetValueExW(owner.handle, toUTFz!(wchar*)(name), 0,
112             REG_DWORD, cast(ubyte*)&this._value, uint.sizeof);
113 
114       if (res != ERROR_SUCCESS) {
115          throwException!(RegistryException)("RegSetValueEx failed, Key '%s'", name);
116       }
117    }
118 }
119 
120 final class RegistryValueQword : RegistryValue!(ulong) {
121    public this(ulong l) {
122       super(l);
123    }
124 
125    @property public override RegistryValueType valueType() {
126       return RegistryValueType.qword;
127    }
128 
129    public override string toString() {
130       return to!(string)(this._value);
131    }
132 
133    public void write(RegistryKey owner, string name) {
134       ulong res = RegSetValueExW(owner.handle, toUTFz!(wchar*)(name), 0,
135             REG_QWORD, cast(ubyte*)&this._value, ulong.sizeof);
136 
137       if (res != ERROR_SUCCESS) {
138          throwException!(RegistryException)("RegSetValueEx failed, Key '%s'", name);
139       }
140    }
141 }
142 
143 final class RegistryKey : Handle!(HKEY), IDisposable {
144    private bool _owned;
145 
146    package this(HKEY hKey, bool owned = true) {
147       this._handle = hKey;
148       this._owned = owned;
149    }
150 
151    public ~this() {
152       this.dispose();
153    }
154 
155    public void dispose() {
156       if (this._owned) {
157          RegCloseKey(this._handle);
158          this._handle = null;
159       }
160    }
161 
162    private void doDeleteSubKey(HKEY hKey, string name) {
163       const uint MAX_KEY_LENGTH = 0xFF;
164       const uint MAX_VALUE_NAME = 0x3FFF;
165 
166       HKEY hDelKey;
167       uint valuesCount, subKeysCount;
168       wchar[] keyName = new wchar[MAX_KEY_LENGTH];
169       wchar[] valName = new wchar[MAX_VALUE_NAME];
170 
171       if (RegOpenKeyExW(hKey, toUTFz!(wchar*)(name), 0, KEY_ALL_ACCESS,
172             &hDelKey) != ERROR_SUCCESS) {
173          throwException!(RegistryException)("Cannot open Key '%s'", to!(string)(name.ptr));
174       }
175 
176       if (RegQueryInfoKeyW(hDelKey, null, null, null, &subKeysCount, null,
177             null, &valuesCount, null, null, null, null) != ERROR_SUCCESS) {
178          throwException!(RegistryException)("Cannot query Key '%s'", to!(string)(name.ptr));
179       }
180 
181       for (int i = 0; i < subKeysCount; i++) {
182          uint size = MAX_KEY_LENGTH;
183 
184          RegEnumKeyExW(hDelKey, 0, keyName.ptr, &size, null, null, null, null);
185       }
186       this.doDeleteSubKey(hDelKey, toUTF8(keyName));
187 
188       for (int i = 0; i < valuesCount; i++) {
189          uint size = MAX_VALUE_NAME;
190 
191          if (RegEnumValueW(hDelKey, 0, valName.ptr, &size, null, null, null, null) != ERROR_SUCCESS) {
192             throwException!(RegistryException)("Cannot enumerate values from key '%s'", name);
193          }
194 
195          if (RegDeleteValueW(hDelKey, valName.ptr) != ERROR_SUCCESS) {
196             throwException!(RegistryException)("Cannot delete Value '%s'", toUTF8(valName));
197          }
198       }
199 
200       RegCloseKey(hDelKey);
201 
202       if (RegDeleteKeyW(hKey, toUTFz!(wchar*)(name)) != ERROR_SUCCESS) {
203          throwException!(RegistryException)("Cannot delete Key '%s'", to!(string)(name.ptr));
204       }
205    }
206 
207    public RegistryKey createSubKey(string name) {
208       HKEY hKey;
209       uint disp;
210 
211       int res = RegCreateKeyExW(this._handle, toUTFz!(wchar*)(name), 0, null,
212             0, KEY_ALL_ACCESS, null, &hKey, &disp);
213 
214       switch (res) {
215       case ERROR_SUCCESS:
216          return new RegistryKey(hKey);
217 
218       default:
219          throwException!(RegistryException)("Cannot create Key '%s'", name);
220       }
221 
222       return null;
223    }
224 
225    public void deleteSubKey(string name) {
226       this.doDeleteSubKey(this._handle, name);
227    }
228 
229    public RegistryKey getSubKey(string name) {
230       HKEY hKey;
231 
232       int res = RegOpenKeyExW(this._handle, toUTFz!(wchar*)(name), 0, KEY_ALL_ACCESS, &hKey);
233 
234       switch (res) {
235       case ERROR_SUCCESS:
236          return new RegistryKey(hKey);
237 
238       default:
239          throwException!(RegistryException)("Cannot retrieve Key '%s'", name);
240       }
241 
242       return null;
243    }
244 
245    public void setValue(string name, IRegistryValue val) {
246       val.write(this, name);
247    }
248 
249    public IRegistryValue getValue(string name) {
250       uint len;
251       uint type;
252       IRegistryValue ival = null;
253 
254       int res = RegQueryValueExW(this._handle, toUTFz!(wchar*)(name), null, &type, null, &len);
255 
256       if (res != ERROR_SUCCESS) {
257          return null;
258       }
259 
260       switch (type) {
261       case REG_BINARY:
262          ubyte[] val = new ubyte[len];
263          RegQueryValueExW(this._handle, toUTFz!(wchar*)(name), null, &type, val.ptr, &len);
264          ival = new RegistryValueBinary(val);
265          break;
266 
267       case REG_DWORD:
268          uint val;
269          RegQueryValueExW(this._handle, toUTFz!(wchar*)(name), null, &type,
270                cast(ubyte*)&val, &len);
271          ival = new RegistryValueDword(val);
272          break;
273 
274       case REG_QWORD:
275          ulong val;
276          RegQueryValueExW(this._handle, toUTFz!(wchar*)(name), null, &type,
277                cast(ubyte*)&val, &len);
278          ival = new RegistryValueQword(val);
279          break;
280 
281       case REG_SZ:
282          wchar[] val = new wchar[len];
283          RegQueryValueExW(this._handle, toUTFz!(wchar*)(name), null, &type,
284                cast(ubyte*)val.ptr, &len);
285          ival = new RegistryValueString(toUTF8(val));
286          break;
287 
288       default:
289          throwException!(RegistryException)("Unsupported Format");
290       }
291 
292       return ival;
293    }
294 }
295 
296 final class Registry {
297    private static RegistryKey _classesRoot;
298    private static RegistryKey _currentConfig;
299    private static RegistryKey _currentUser;
300    private static RegistryKey _dynData;
301    private static RegistryKey _localMachine;
302    private static RegistryKey _performanceData;
303    private static RegistryKey _users;
304 
305    private this() {
306 
307    }
308 
309    @property public static RegistryKey classesRoot() {
310       if (!_classesRoot) {
311          _classesRoot = new RegistryKey(HKEY_CLASSES_ROOT, false);
312       }
313 
314       return _classesRoot;
315    }
316 
317    @property public static RegistryKey currentConfig() {
318       if (!_currentConfig) {
319          _currentConfig = new RegistryKey(HKEY_CURRENT_CONFIG, false);
320       }
321 
322       return _currentConfig;
323    }
324 
325    @property public static RegistryKey currentUser() {
326       if (!_currentUser) {
327          _currentUser = new RegistryKey(HKEY_CURRENT_USER, false);
328       }
329 
330       return _currentUser;
331    }
332 
333    @property public static RegistryKey dynData() {
334       if (!_dynData) {
335          _dynData = new RegistryKey(HKEY_DYN_DATA, false);
336       }
337 
338       return _dynData;
339    }
340 
341    @property public static RegistryKey localMachine() {
342       if (!_localMachine) {
343          _localMachine = new RegistryKey(HKEY_LOCAL_MACHINE, false);
344       }
345 
346       return _localMachine;
347    }
348 
349    @property public static RegistryKey performanceData() {
350       if (!_performanceData) {
351          _performanceData = new RegistryKey(HKEY_PERFORMANCE_DATA, false);
352       }
353 
354       return _performanceData;
355    }
356 
357    @property public static RegistryKey users() {
358       if (!_users) {
359          _users = new RegistryKey(HKEY_USERS, false);
360       }
361 
362       return _users;
363    }
364 }