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
13extern bool g_IsNT;
14#endif
15
16namespace NWindows {
17namespace NRegistry {
18
19#define MYASSERT(expr) // _ASSERTE(expr)
20
21LONG 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
40LONG 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
54LONG 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
67LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw()
68{
69  MYASSERT(_object != NULL);
70  return RegDeleteKey(_object, subKeyName);
71}
72
73LONG 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
98static inline UInt32 BoolToUINT32(bool value) {  return (value ? 1: 0); }
99static inline bool UINT32ToBool(UInt32 value) {  return (value != 0); }
100
101
102LONG CKey::DeleteValue(LPCTSTR name) throw()
103{
104  MYASSERT(_object != NULL);
105  return ::RegDeleteValue(_object, name);
106}
107
108#ifndef _UNICODE
109LONG 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
118LONG 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
125LONG CKey::SetValue(LPCTSTR name, bool value) throw()
126{
127  return SetValue(name, BoolToUINT32(value));
128}
129
130LONG 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/*
139LONG 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
150LONG CKey::SetValue(LPCWSTR name, LPCWSTR value)
151{
152  MYASSERT(value != NULL);
153  MYASSERT(_object != NULL);
154  if (g_IsNT)
155    return RegSetValueExW(_object, name, NULL, 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
164LONG 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
172LONG 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
182LONG 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
192LONG 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
203LONG 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
211LONG 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
220LONG 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
229LONG 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
237LONG 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
256LONG 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
264LONG 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
296LONG 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
305LONG 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
316LONG 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
337LONG 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
359LONG 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