1 // Windows/Registry.cpp
2 
3 #include "StdAfx.h"
4 
5 #ifndef _UNICODE
6 #include "Common/StringConvert.h"
7 #endif
8 #include "Windows/Registry.h"
9 
10 #ifndef _UNICODE
11 extern bool g_IsNT;
12 #endif
13 
14 namespace NWindows {
15 namespace NRegistry {
16 
17 #define MYASSERT(expr) // _ASSERTE(expr)
18 
Create(HKEY parentKey,LPCTSTR keyName,LPTSTR keyClass,DWORD options,REGSAM accessMask,LPSECURITY_ATTRIBUTES securityAttributes,LPDWORD disposition)19 LONG CKey::Create(HKEY parentKey, LPCTSTR keyName,
20     LPTSTR keyClass, DWORD options, REGSAM accessMask,
21     LPSECURITY_ATTRIBUTES securityAttributes, LPDWORD disposition)
22 {
23   MYASSERT(parentKey != NULL);
24   DWORD dispositionReal;
25   HKEY key = NULL;
26   LONG res = RegCreateKeyEx(parentKey, keyName, 0, keyClass,
27       options, accessMask, securityAttributes, &key, &dispositionReal);
28   if (disposition != NULL)
29     *disposition = dispositionReal;
30   if (res == ERROR_SUCCESS)
31   {
32     res = Close();
33     _object = key;
34   }
35   return res;
36 }
37 
Open(HKEY parentKey,LPCTSTR keyName,REGSAM accessMask)38 LONG CKey::Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask)
39 {
40   MYASSERT(parentKey != NULL);
41   HKEY key = NULL;
42   LONG res = RegOpenKeyEx(parentKey, keyName, 0, accessMask, &key);
43   if (res == ERROR_SUCCESS)
44   {
45     res = Close();
46     MYASSERT(res == ERROR_SUCCESS);
47     _object = key;
48   }
49   return res;
50 }
51 
Close()52 LONG CKey::Close()
53 {
54   LONG res = ERROR_SUCCESS;
55   if (_object != NULL)
56   {
57     res = RegCloseKey(_object);
58     _object = NULL;
59   }
60   return res;
61 }
62 
63 // win95, win98: deletes sunkey and all its subkeys
64 // winNT to be deleted must not have subkeys
DeleteSubKey(LPCTSTR subKeyName)65 LONG CKey::DeleteSubKey(LPCTSTR subKeyName)
66 {
67   MYASSERT(_object != NULL);
68   return RegDeleteKey(_object, subKeyName);
69 }
70 
RecurseDeleteKey(LPCTSTR subKeyName)71 LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName)
72 {
73   CKey key;
74   LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE);
75   if (res != ERROR_SUCCESS)
76     return res;
77   FILETIME fileTime;
78   const UInt32 kBufferSize = MAX_PATH + 1; // 256 in ATL
79   DWORD size = kBufferSize;
80   TCHAR buffer[kBufferSize];
81   while (RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime) == ERROR_SUCCESS)
82   {
83     res = key.RecurseDeleteKey(buffer);
84     if (res != ERROR_SUCCESS)
85       return res;
86     size = kBufferSize;
87   }
88   key.Close();
89   return DeleteSubKey(subKeyName);
90 }
91 
92 
93 /////////////////////////
94 // Value Functions
95 
BoolToUINT32(bool value)96 static inline UInt32 BoolToUINT32(bool value) {  return (value ? 1: 0); }
UINT32ToBool(UInt32 value)97 static inline bool UINT32ToBool(UInt32 value) {  return (value != 0); }
98 
99 
DeleteValue(LPCTSTR name)100 LONG CKey::DeleteValue(LPCTSTR name)
101 {
102   MYASSERT(_object != NULL);
103   return ::RegDeleteValue(_object, name);
104 }
105 
106 #ifndef _UNICODE
DeleteValue(LPCWSTR name)107 LONG CKey::DeleteValue(LPCWSTR name)
108 {
109   MYASSERT(_object != NULL);
110   if (g_IsNT)
111     return ::RegDeleteValueW(_object, name);
112   return DeleteValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name));
113 }
114 #endif
115 
SetValue(LPCTSTR name,UInt32 value)116 LONG CKey::SetValue(LPCTSTR name, UInt32 value)
117 {
118   MYASSERT(_object != NULL);
119   return RegSetValueEx(_object, name, NULL, REG_DWORD,
120       (BYTE * const)&value, sizeof(UInt32));
121 }
122 
SetValue(LPCTSTR name,bool value)123 LONG CKey::SetValue(LPCTSTR name, bool value)
124 {
125   return SetValue(name, BoolToUINT32(value));
126 }
127 
SetValue(LPCTSTR name,LPCTSTR value)128 LONG CKey::SetValue(LPCTSTR name, LPCTSTR value)
129 {
130   MYASSERT(value != NULL);
131   MYASSERT(_object != NULL);
132   return RegSetValueEx(_object, name, NULL, REG_SZ,
133       (const BYTE * )value, (lstrlen(value) + 1) * sizeof(TCHAR));
134 }
135 
136 /*
137 LONG CKey::SetValue(LPCTSTR name, const CSysString &value)
138 {
139   MYASSERT(value != NULL);
140   MYASSERT(_object != NULL);
141   return RegSetValueEx(_object, name, NULL, REG_SZ,
142       (const BYTE *)(const TCHAR *)value, (value.Length() + 1) * sizeof(TCHAR));
143 }
144 */
145 
146 #ifndef _UNICODE
147 
SetValue(LPCWSTR name,LPCWSTR value)148 LONG CKey::SetValue(LPCWSTR name, LPCWSTR value)
149 {
150   MYASSERT(value != NULL);
151   MYASSERT(_object != NULL);
152   if (g_IsNT)
153     return RegSetValueExW(_object, name, NULL, REG_SZ,
154       (const BYTE * )value, (DWORD)((wcslen(value) + 1) * sizeof(wchar_t)));
155   return SetValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name),
156     value == 0 ? 0 : (LPCSTR)GetSystemString(value));
157 }
158 
159 #endif
160 
161 
SetValue(LPCTSTR name,const void * value,UInt32 size)162 LONG CKey::SetValue(LPCTSTR name, const void *value, UInt32 size)
163 {
164   MYASSERT(value != NULL);
165   MYASSERT(_object != NULL);
166   return RegSetValueEx(_object, name, NULL, REG_BINARY,
167       (const BYTE *)value, size);
168 }
169 
SetValue(HKEY parentKey,LPCTSTR keyName,LPCTSTR valueName,LPCTSTR value)170 LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value)
171 {
172   MYASSERT(value != NULL);
173   CKey key;
174   LONG res = key.Create(parentKey, keyName);
175   if (res == ERROR_SUCCESS)
176     res = key.SetValue(valueName, value);
177   return res;
178 }
179 
SetKeyValue(LPCTSTR keyName,LPCTSTR valueName,LPCTSTR value)180 LONG CKey::SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value)
181 {
182   MYASSERT(value != NULL);
183   CKey key;
184   LONG res = key.Create(_object, keyName);
185   if (res == ERROR_SUCCESS)
186     res = key.SetValue(valueName, value);
187   return res;
188 }
189 
QueryValue(LPCTSTR name,UInt32 & value)190 LONG CKey::QueryValue(LPCTSTR name, UInt32 &value)
191 {
192   DWORD type = NULL;
193   DWORD count = sizeof(DWORD);
194   LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type,
195     (LPBYTE)&value, &count);
196   MYASSERT((res!=ERROR_SUCCESS) || (type == REG_DWORD));
197   MYASSERT((res!=ERROR_SUCCESS) || (count == sizeof(UInt32)));
198   return res;
199 }
200 
QueryValue(LPCTSTR name,bool & value)201 LONG CKey::QueryValue(LPCTSTR name, bool &value)
202 {
203   UInt32 uintValue = BoolToUINT32(value);
204   LONG res = QueryValue(name, uintValue);
205   value = UINT32ToBool(uintValue);
206   return res;
207 }
208 
GetValue_IfOk(LPCTSTR name,UInt32 & value)209 LONG CKey::GetValue_IfOk(LPCTSTR name, UInt32 &value)
210 {
211   UInt32 newVal;
212   LONG res = QueryValue(name, newVal);
213   if (res == ERROR_SUCCESS)
214     value = newVal;
215   return res;
216 }
217 
GetValue_IfOk(LPCTSTR name,bool & value)218 LONG CKey::GetValue_IfOk(LPCTSTR name, bool &value)
219 {
220   bool newVal;
221   LONG res = QueryValue(name, newVal);
222   if (res == ERROR_SUCCESS)
223     value = newVal;
224   return res;
225 }
226 
QueryValue(LPCTSTR name,LPTSTR value,UInt32 & count)227 LONG CKey::QueryValue(LPCTSTR name, LPTSTR value, UInt32 &count)
228 {
229   MYASSERT(count != NULL);
230   DWORD type = NULL;
231   LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
232   MYASSERT((res!=ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
233   return res;
234 }
235 
QueryValue(LPCTSTR name,CSysString & value)236 LONG CKey::QueryValue(LPCTSTR name, CSysString &value)
237 {
238   value.Empty();
239   DWORD type = NULL;
240   UInt32 currentSize = 0;
241   LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, NULL, (DWORD *)&currentSize);
242   if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
243     return res;
244   res = QueryValue(name, value.GetBuffer(currentSize), currentSize);
245   value.ReleaseBuffer();
246   return res;
247 }
248 
249 #ifndef _UNICODE
QueryValue(LPCWSTR name,LPWSTR value,UInt32 & count)250 LONG CKey::QueryValue(LPCWSTR name, LPWSTR value, UInt32 &count)
251 {
252   MYASSERT(count != NULL);
253   DWORD type = NULL;
254   LONG res = RegQueryValueExW(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
255   MYASSERT((res!=ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
256   return res;
257 }
QueryValue(LPCWSTR name,UString & value)258 LONG CKey::QueryValue(LPCWSTR name, UString &value)
259 {
260   value.Empty();
261   DWORD type = NULL;
262   UInt32 currentSize = 0;
263 
264   LONG res;
265   if (g_IsNT)
266   {
267     res = RegQueryValueExW(_object, name, NULL, &type, NULL, (DWORD *)&currentSize);
268     if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
269       return res;
270     res = QueryValue(name, value.GetBuffer(currentSize), currentSize);
271     value.ReleaseBuffer();
272   }
273   else
274   {
275     AString vTemp;
276     res = QueryValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), vTemp);
277     value = GetUnicodeString(vTemp);
278   }
279   return res;
280 }
281 #endif
282 
QueryValue(LPCTSTR name,void * value,UInt32 & count)283 LONG CKey::QueryValue(LPCTSTR name, void *value, UInt32 &count)
284 {
285   DWORD type = NULL;
286   LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
287   MYASSERT((res!=ERROR_SUCCESS) || (type == REG_BINARY));
288   return res;
289 }
290 
291 
QueryValue(LPCTSTR name,CByteBuffer & value,UInt32 & dataSize)292 LONG CKey::QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize)
293 {
294   DWORD type = NULL;
295   dataSize = 0;
296   LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, NULL, (DWORD *)&dataSize);
297   if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
298     return res;
299   value.SetCapacity(dataSize);
300   return QueryValue(name, (BYTE *)value, dataSize);
301 }
302 
EnumKeys(CSysStringVector & keyNames)303 LONG CKey::EnumKeys(CSysStringVector &keyNames)
304 {
305   keyNames.Clear();
306   CSysString keyName;
307   for (UInt32 index = 0; ; index++)
308   {
309     const UInt32 kBufferSize = MAX_PATH + 1; // 256 in ATL
310     FILETIME lastWriteTime;
311     UInt32 nameSize = kBufferSize;
312     LONG result = ::RegEnumKeyEx(_object, index, keyName.GetBuffer(kBufferSize),
313         (DWORD *)&nameSize, NULL, NULL, NULL, &lastWriteTime);
314     keyName.ReleaseBuffer();
315     if (result == ERROR_NO_MORE_ITEMS)
316       break;
317     if (result != ERROR_SUCCESS)
318       return result;
319     keyNames.Add(keyName);
320   }
321   return ERROR_SUCCESS;
322 }
323 
SetValue_Strings(LPCTSTR valueName,const UStringVector & strings)324 LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings)
325 {
326   UInt32 numChars = 0;
327   int i;
328   for (i = 0; i < strings.Size(); i++)
329     numChars += strings[i].Length() + 1;
330   CBuffer<wchar_t> buffer;
331   buffer.SetCapacity(numChars);
332   int pos = 0;
333   for (i = 0; i < strings.Size(); i++)
334   {
335     const UString &s = strings[i];
336     MyStringCopy((wchar_t *)buffer + pos, (const wchar_t *)s);
337     pos += s.Length() + 1;
338   }
339   return SetValue(valueName, buffer, numChars * sizeof(wchar_t));
340 }
341 
GetValue_Strings(LPCTSTR valueName,UStringVector & strings)342 LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings)
343 {
344   strings.Clear();
345   CByteBuffer buffer;
346   UInt32 dataSize;
347   LONG res = QueryValue(valueName, buffer, dataSize);
348   if (res != ERROR_SUCCESS)
349     return res;
350   if (dataSize % sizeof(wchar_t) != 0)
351     return E_FAIL;
352   const wchar_t *data = (const wchar_t *)(const Byte  *)buffer;
353   int numChars = dataSize / sizeof(wchar_t);
354   UString s;
355   for (int i = 0; i < numChars; i++)
356   {
357     wchar_t c = data[i];
358     if (c == 0)
359     {
360       strings.Add(s);
361       s.Empty();
362     }
363     else
364       s += c;
365   }
366   return res;
367 }
368 
369 }}
370