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
11extern bool g_IsNT;
12#endif
13
14namespace NWindows {
15namespace NRegistry {
16
17#define MYASSERT(expr) // _ASSERTE(expr)
18
19LONG 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
38LONG 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
52LONG 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
65LONG CKey::DeleteSubKey(LPCTSTR subKeyName)
66{
67  MYASSERT(_object != NULL);
68  return RegDeleteKey(_object, subKeyName);
69}
70
71LONG 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
96static inline UInt32 BoolToUINT32(bool value) {  return (value ? 1: 0); }
97static inline bool UINT32ToBool(UInt32 value) {  return (value != 0); }
98
99
100LONG CKey::DeleteValue(LPCTSTR name)
101{
102  MYASSERT(_object != NULL);
103  return ::RegDeleteValue(_object, name);
104}
105
106#ifndef _UNICODE
107LONG 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
116LONG 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
123LONG CKey::SetValue(LPCTSTR name, bool value)
124{
125  return SetValue(name, BoolToUINT32(value));
126}
127
128LONG 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/*
137LONG 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
148LONG 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
162LONG 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
170LONG 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
180LONG 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
190LONG 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
201LONG 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
209LONG 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
218LONG 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
227LONG 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
236LONG 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
250LONG 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}
258LONG 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
283LONG 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
292LONG 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
303LONG 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
324LONG 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
342LONG 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