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