1 // Windows/Registry.cpp
2
3 #include "StdAfx.h"
4
5 #include <wchar.h>
6 // #include <stdio.h>
7
8 #ifndef _UNICODE
9 #include "../Common/StringConvert.h"
10 #endif
11 #include "Registry.h"
12
13 #ifndef _UNICODE
14 extern bool g_IsNT;
15 #endif
16
17 namespace NWindows {
18 namespace NRegistry {
19
20 #define MYASSERT(expr) // _ASSERTE(expr)
21 #define MY_ASSUME(expr)
22
23 /*
24 static void Error()
25 {
26 #ifdef _CONSOLE
27 printf("\nregistry error\n");
28 #else
29 MessageBoxW(0, L"registry error", L"", 0);
30 // exit(1);
31 #endif
32 }
33
34 #define MY_ASSUME(expr) { if (!(expr)) Error(); }
35 */
36
Create(HKEY parentKey,LPCTSTR keyName,LPTSTR keyClass,DWORD options,REGSAM accessMask,LPSECURITY_ATTRIBUTES securityAttributes,LPDWORD disposition)37 LONG CKey::Create(HKEY parentKey, LPCTSTR keyName,
38 LPTSTR keyClass, DWORD options, REGSAM accessMask,
39 LPSECURITY_ATTRIBUTES securityAttributes, LPDWORD disposition) throw()
40 {
41 MY_ASSUME(parentKey != NULL);
42 DWORD dispositionReal;
43 HKEY key = NULL;
44 LONG res = RegCreateKeyEx(parentKey, keyName, 0, keyClass,
45 options, accessMask, securityAttributes, &key, &dispositionReal);
46 if (disposition != NULL)
47 *disposition = dispositionReal;
48 if (res == ERROR_SUCCESS)
49 {
50 res = Close();
51 _object = key;
52 }
53 return res;
54 }
55
Open(HKEY parentKey,LPCTSTR keyName,REGSAM accessMask)56 LONG CKey::Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask) throw()
57 {
58 MY_ASSUME(parentKey != NULL);
59 HKEY key = NULL;
60 LONG res = RegOpenKeyEx(parentKey, keyName, 0, accessMask, &key);
61 if (res == ERROR_SUCCESS)
62 {
63 res = Close();
64 MYASSERT(res == ERROR_SUCCESS);
65 _object = key;
66 }
67 return res;
68 }
69
Close()70 LONG CKey::Close() throw()
71 {
72 LONG res = ERROR_SUCCESS;
73 if (_object != NULL)
74 {
75 res = RegCloseKey(_object);
76 _object = NULL;
77 }
78 return res;
79 }
80
81 // win95, win98: deletes subkey and all its subkeys
82 // winNT to be deleted must not have subkeys
DeleteSubKey(LPCTSTR subKeyName)83 LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw()
84 {
85 MY_ASSUME(_object != NULL);
86 return RegDeleteKey(_object, subKeyName);
87 }
88
RecurseDeleteKey(LPCTSTR subKeyName)89 LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw()
90 {
91 {
92 CKey key;
93 LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE);
94 if (res != ERROR_SUCCESS)
95 return res;
96 FILETIME fileTime;
97 const UInt32 kBufSize = MAX_PATH + 1; // 256 in ATL
98 TCHAR buffer[kBufSize];
99 // we use loop limit here for some unexpected code failure
100 for (unsigned loop_cnt = 0; loop_cnt < (1u << 26); loop_cnt++)
101 {
102 DWORD size = kBufSize;
103 // we always request starting item (index==0) in each iteration,
104 // because we remove starting item (index==0) in each loop iteration.
105 res = RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime);
106 if (res != ERROR_SUCCESS)
107 {
108 // possible return codes:
109 // ERROR_NO_MORE_ITEMS : are no more subkeys available
110 // ERROR_MORE_DATA : name buffer is too small
111 // we can try to remove (subKeyName), even if there is non ERROR_NO_MORE_ITEMS error.
112 // if (res != ERROR_NO_MORE_ITEMS) return res;
113 break;
114 }
115 res = key.RecurseDeleteKey(buffer);
116 if (res != ERROR_SUCCESS)
117 return res;
118 }
119 // key.Close();
120 }
121 return DeleteSubKey(subKeyName);
122 }
123
124
125 /////////////////////////
126 // Value Functions
127
BoolToUINT32(bool value)128 static inline UInt32 BoolToUINT32(bool value) { return (value ? 1: 0); }
UINT32ToBool(UInt32 value)129 static inline bool UINT32ToBool(UInt32 value) { return (value != 0); }
130
131
DeleteValue(LPCTSTR name)132 LONG CKey::DeleteValue(LPCTSTR name) throw()
133 {
134 MY_ASSUME(_object != NULL);
135 return ::RegDeleteValue(_object, name);
136 }
137
138 #ifndef _UNICODE
DeleteValue(LPCWSTR name)139 LONG CKey::DeleteValue(LPCWSTR name)
140 {
141 MY_ASSUME(_object != NULL);
142 if (g_IsNT)
143 return ::RegDeleteValueW(_object, name);
144 return DeleteValue(name == NULL ? NULL : (LPCSTR)GetSystemString(name));
145 }
146 #endif
147
SetValue(LPCTSTR name,UInt32 value)148 LONG CKey::SetValue(LPCTSTR name, UInt32 value) throw()
149 {
150 MY_ASSUME(_object != NULL);
151 return RegSetValueEx(_object, name, 0, REG_DWORD,
152 (const BYTE *)&value, sizeof(UInt32));
153 }
154
SetValue(LPCTSTR name,bool value)155 LONG CKey::SetValue(LPCTSTR name, bool value) throw()
156 {
157 return SetValue(name, BoolToUINT32(value));
158 }
159
160
161 // value must be string that is NULL terminated
SetValue(LPCTSTR name,LPCTSTR value)162 LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw()
163 {
164 MYASSERT(value != NULL);
165 MY_ASSUME(_object != NULL);
166 // note: RegSetValueEx supports (value == NULL), if (cbData == 0)
167 return RegSetValueEx(_object, name, 0, REG_SZ,
168 (const BYTE *)value, (DWORD)(((DWORD)lstrlen(value) + 1) * sizeof(TCHAR)));
169 }
170
171 /*
172 LONG CKey::SetValue(LPCTSTR name, const CSysString &value)
173 {
174 MYASSERT(value != NULL);
175 MY_ASSUME(_object != NULL);
176 return RegSetValueEx(_object, name, 0, REG_SZ,
177 (const BYTE *)(const TCHAR *)value, (value.Len() + 1) * sizeof(TCHAR));
178 }
179 */
180
181 #ifndef _UNICODE
182
SetValue(LPCWSTR name,LPCWSTR value)183 LONG CKey::SetValue(LPCWSTR name, LPCWSTR value)
184 {
185 MYASSERT(value != NULL);
186 MY_ASSUME(_object != NULL);
187 if (g_IsNT)
188 return RegSetValueExW(_object, name, 0, REG_SZ,
189 (const BYTE *)value, (DWORD)(((DWORD)wcslen(value) + 1) * sizeof(wchar_t)));
190 return SetValue(name == NULL ? NULL :
191 (LPCSTR)GetSystemString(name),
192 (LPCSTR)GetSystemString(value));
193 }
194
195 #endif
196
197
SetValue(LPCTSTR name,const void * value,UInt32 size)198 LONG CKey::SetValue(LPCTSTR name, const void *value, UInt32 size) throw()
199 {
200 MYASSERT(value != NULL);
201 MY_ASSUME(_object != NULL);
202 return RegSetValueEx(_object, name, 0, REG_BINARY,
203 (const BYTE *)value, size);
204 }
205
SetValue(HKEY parentKey,LPCTSTR keyName,LPCTSTR valueName,LPCTSTR value)206 LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value)
207 {
208 MYASSERT(value != NULL);
209 CKey key;
210 LONG res = key.Create(parentKey, keyName);
211 if (res == ERROR_SUCCESS)
212 res = key.SetValue(valueName, value);
213 return res;
214 }
215
SetKeyValue(LPCTSTR keyName,LPCTSTR valueName,LPCTSTR value)216 LONG CKey::SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw()
217 {
218 MYASSERT(value != NULL);
219 CKey key;
220 LONG res = key.Create(_object, keyName);
221 if (res == ERROR_SUCCESS)
222 res = key.SetValue(valueName, value);
223 return res;
224 }
225
226
GetValue_UInt32_IfOk(LPCTSTR name,UInt32 & value)227 LONG CKey::GetValue_UInt32_IfOk(LPCTSTR name, UInt32 &value) throw()
228 {
229 DWORD type = 0;
230 DWORD count = sizeof(value);
231 UInt32 value2; // = value;
232 const LONG res = QueryValueEx(name, &type, (LPBYTE)&value2, &count);
233 if (res == ERROR_SUCCESS)
234 {
235 // ERROR_UNSUPPORTED_TYPE
236 if (count != sizeof(value) || type != REG_DWORD)
237 return ERROR_UNSUPPORTED_TYPE; // ERROR_INVALID_DATA;
238 value = value2;
239 }
240 return res;
241 }
242
GetValue_UInt64_IfOk(LPCTSTR name,UInt64 & value)243 LONG CKey::GetValue_UInt64_IfOk(LPCTSTR name, UInt64 &value) throw()
244 {
245 DWORD type = 0;
246 DWORD count = sizeof(value);
247 UInt64 value2; // = value;
248 const LONG res = QueryValueEx(name, &type, (LPBYTE)&value2, &count);
249 if (res == ERROR_SUCCESS)
250 {
251 if (count != sizeof(value) || type != REG_QWORD)
252 return ERROR_UNSUPPORTED_TYPE;
253 value = value2;
254 }
255 return res;
256 }
257
GetValue_bool_IfOk(LPCTSTR name,bool & value)258 LONG CKey::GetValue_bool_IfOk(LPCTSTR name, bool &value) throw()
259 {
260 UInt32 uintValue;
261 const LONG res = GetValue_UInt32_IfOk(name, uintValue);
262 if (res == ERROR_SUCCESS)
263 value = UINT32ToBool(uintValue);
264 return res;
265 }
266
267
268
QueryValue(LPCTSTR name,CSysString & value)269 LONG CKey::QueryValue(LPCTSTR name, CSysString &value)
270 {
271 value.Empty();
272 LONG res = ERROR_SUCCESS;
273 {
274 // if we don't want multiple calls here,
275 // we can use big value (264) here.
276 // 3 is default available length in new string.
277 DWORD size_prev = 3 * sizeof(TCHAR);
278 // at least 2 attempts are required. But we use more attempts for cases,
279 // where string can be changed by anothner process
280 for (unsigned i = 0; i < 2 + 2; i++)
281 {
282 DWORD type = 0;
283 DWORD size = size_prev;
284 {
285 LPBYTE buf = (LPBYTE)value.GetBuf(size / sizeof(TCHAR));
286 res = QueryValueEx(name, &type, size == 0 ? NULL : buf, &size);
287 // if (size_prev == 0), then (res == ERROR_SUCCESS) is expected here, because we requested only size.
288 }
289 if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
290 {
291 if (type != REG_SZ && type != REG_EXPAND_SZ)
292 {
293 res = ERROR_UNSUPPORTED_TYPE;
294 size = 0;
295 }
296 }
297 else
298 size = 0;
299 if (size > size_prev)
300 {
301 size_prev = size;
302 size = 0;
303 res = ERROR_MORE_DATA;
304 }
305 value.ReleaseBuf_CalcLen(size / sizeof(TCHAR));
306 if (res != ERROR_MORE_DATA)
307 return res;
308 }
309 }
310 return res;
311 }
312
313
314 #ifndef _UNICODE
315
QueryValue(LPCWSTR name,UString & value)316 LONG CKey::QueryValue(LPCWSTR name, UString &value)
317 {
318 value.Empty();
319 LONG res = ERROR_SUCCESS;
320 if (g_IsNT)
321 {
322 DWORD size_prev = 3 * sizeof(wchar_t);
323 for (unsigned i = 0; i < 2 + 2; i++)
324 {
325 DWORD type = 0;
326 DWORD size = size_prev;
327 {
328 LPBYTE buf = (LPBYTE)value.GetBuf(size / sizeof(wchar_t));
329 res = RegQueryValueExW(_object, name, NULL, &type,
330 size == 0 ? NULL : buf, &size);
331 }
332 if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
333 {
334 if (type != REG_SZ && type != REG_EXPAND_SZ)
335 {
336 res = ERROR_UNSUPPORTED_TYPE;
337 size = 0;
338 }
339 }
340 else
341 size = 0;
342 if (size > size_prev)
343 {
344 size_prev = size;
345 size = 0;
346 res = ERROR_MORE_DATA;
347 }
348 value.ReleaseBuf_CalcLen(size / sizeof(wchar_t));
349 if (res != ERROR_MORE_DATA)
350 return res;
351 }
352 }
353 else
354 {
355 AString vTemp;
356 res = QueryValue(name == NULL ? NULL : (LPCSTR)GetSystemString(name), vTemp);
357 value = GetUnicodeString(vTemp);
358 }
359 return res;
360 }
361
362 #endif
363
364
QueryValue_Binary(LPCTSTR name,CByteBuffer & value)365 LONG CKey::QueryValue_Binary(LPCTSTR name, CByteBuffer &value)
366 {
367 // value.Free();
368 DWORD size_prev = 0;
369 LONG res = ERROR_SUCCESS;
370 for (unsigned i = 0; i < 2 + 2; i++)
371 {
372 DWORD type = 0;
373 DWORD size = size_prev;
374 value.Alloc(size_prev);
375 res = QueryValueEx(name, &type, value.NonConstData(), &size);
376 // if (size_prev == 0), then (res == ERROR_SUCCESS) is expected here, because we requested only size.
377 if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
378 {
379 if (type != REG_BINARY)
380 {
381 res = ERROR_UNSUPPORTED_TYPE;
382 size = 0;
383 }
384 }
385 else
386 size = 0;
387 if (size > size_prev)
388 {
389 size_prev = size;
390 size = 0;
391 res = ERROR_MORE_DATA;
392 }
393 if (size < value.Size())
394 value.ChangeSize_KeepData(size, size);
395 if (res != ERROR_MORE_DATA)
396 return res;
397 }
398 return res;
399 }
400
401
EnumKeys(CSysStringVector & keyNames)402 LONG CKey::EnumKeys(CSysStringVector &keyNames)
403 {
404 keyNames.Clear();
405 CSysString keyName;
406 for (DWORD index = 0; ; index++)
407 {
408 const unsigned kBufSize = MAX_PATH + 1; // 256 in ATL
409 FILETIME lastWriteTime;
410 DWORD nameSize = kBufSize;
411 const LONG res = ::RegEnumKeyEx(_object, index,
412 keyName.GetBuf(kBufSize), &nameSize,
413 NULL, NULL, NULL, &lastWriteTime);
414 keyName.ReleaseBuf_CalcLen(kBufSize);
415 if (res == ERROR_NO_MORE_ITEMS)
416 return ERROR_SUCCESS;
417 if (res != ERROR_SUCCESS)
418 return res;
419 keyNames.Add(keyName);
420 }
421 }
422
423
SetValue_Strings(LPCTSTR valueName,const UStringVector & strings)424 LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings)
425 {
426 size_t numChars = 0;
427 unsigned i;
428
429 for (i = 0; i < strings.Size(); i++)
430 numChars += strings[i].Len() + 1;
431
432 CObjArray<wchar_t> buffer(numChars);
433 size_t pos = 0;
434
435 for (i = 0; i < strings.Size(); i++)
436 {
437 const UString &s = strings[i];
438 const size_t size = s.Len() + 1;
439 wmemcpy(buffer + pos, s, size);
440 pos += size;
441 }
442 // if (pos != numChars) return E_FAIL;
443 return SetValue(valueName, buffer, (UInt32)numChars * sizeof(wchar_t));
444 }
445
GetValue_Strings(LPCTSTR valueName,UStringVector & strings)446 LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings)
447 {
448 strings.Clear();
449 CByteBuffer buffer;
450 const LONG res = QueryValue_Binary(valueName, buffer);
451 if (res != ERROR_SUCCESS)
452 return res;
453 const size_t dataSize = buffer.Size();
454 if (dataSize % sizeof(wchar_t))
455 return ERROR_INVALID_DATA;
456 const wchar_t *data = (const wchar_t *)(const void *)(const Byte *)buffer;
457 const size_t numChars = dataSize / sizeof(wchar_t);
458 // we can check that all names are finished
459 // if (numChars != 0 && data[numChars - 1] != 0) return ERROR_INVALID_DATA;
460 size_t prev = 0;
461 UString s;
462 for (size_t i = 0; i < numChars; i++)
463 {
464 if (data[i] == 0)
465 {
466 s = data + prev;
467 strings.Add(s);
468 prev = i + 1;
469 }
470 }
471 return res;
472 }
473
474 }}
475