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