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