aboutsummaryrefslogtreecommitdiff
path: root/CPP/Windows/Registry.cpp
diff options
context:
space:
mode:
authorIgor Pavlov <87184205+ip7z@users.noreply.github.com>2024-11-29 00:00:00 +0000
committerIgor Pavlov <87184205+ip7z@users.noreply.github.com>2024-11-30 15:27:15 +0500
commite5431fa6f5505e385c6f9367260717e9c47dc2ee (patch)
tree4cd2c2c3b225b48c8e7053432c41d7b6b6a3d5f8 /CPP/Windows/Registry.cpp
parente008ce3976c087bfd21344af8f00a23cf69d4174 (diff)
download7zip-main.tar.gz
7zip-main.tar.bz2
7zip-main.zip
Diffstat (limited to 'CPP/Windows/Registry.cpp')
-rw-r--r--CPP/Windows/Registry.cpp295
1 files changed, 183 insertions, 112 deletions
diff --git a/CPP/Windows/Registry.cpp b/CPP/Windows/Registry.cpp
index c8b1709..a94a50f 100644
--- a/CPP/Windows/Registry.cpp
+++ b/CPP/Windows/Registry.cpp
@@ -78,7 +78,7 @@ LONG CKey::Close() throw()
78 return res; 78 return res;
79} 79}
80 80
81// win95, win98: deletes sunkey and all its subkeys 81// win95, win98: deletes subkey and all its subkeys
82// winNT to be deleted must not have subkeys 82// winNT to be deleted must not have subkeys
83LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw() 83LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw()
84{ 84{
@@ -88,22 +88,36 @@ LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw()
88 88
89LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw() 89LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw()
90{ 90{
91 CKey key;
92 LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE);
93 if (res != ERROR_SUCCESS)
94 return res;
95 FILETIME fileTime;
96 const UInt32 kBufSize = MAX_PATH + 1; // 256 in ATL
97 DWORD size = kBufSize;
98 TCHAR buffer[kBufSize];
99 while (RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime) == ERROR_SUCCESS)
100 { 91 {
101 res = key.RecurseDeleteKey(buffer); 92 CKey key;
93 LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE);
102 if (res != ERROR_SUCCESS) 94 if (res != ERROR_SUCCESS)
103 return res; 95 return res;
104 size = kBufSize; 96 FILETIME fileTime;
97 const UInt32 kBufSize = MAX_PATH + 1; // 256 in ATL
98 TCHAR buffer[kBufSize];
99 // we use loop limit here for some unexpected code failure
100 for (unsigned loop_cnt = 0; loop_cnt < (1u << 26); loop_cnt++)
101 {
102 DWORD size = kBufSize;
103 // we always request starting item (index==0) in each iteration,
104 // because we remove starting item (index==0) in each loop iteration.
105 res = RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime);
106 if (res != ERROR_SUCCESS)
107 {
108 // possible return codes:
109 // ERROR_NO_MORE_ITEMS : are no more subkeys available
110 // ERROR_MORE_DATA : name buffer is too small
111 // we can try to remove (subKeyName), even if there is non ERROR_NO_MORE_ITEMS error.
112 // if (res != ERROR_NO_MORE_ITEMS) return res;
113 break;
114 }
115 res = key.RecurseDeleteKey(buffer);
116 if (res != ERROR_SUCCESS)
117 return res;
118 }
119 // key.Close();
105 } 120 }
106 key.Close();
107 return DeleteSubKey(subKeyName); 121 return DeleteSubKey(subKeyName);
108} 122}
109 123
@@ -127,7 +141,7 @@ LONG CKey::DeleteValue(LPCWSTR name)
127 MY_ASSUME(_object != NULL); 141 MY_ASSUME(_object != NULL);
128 if (g_IsNT) 142 if (g_IsNT)
129 return ::RegDeleteValueW(_object, name); 143 return ::RegDeleteValueW(_object, name);
130 return DeleteValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name)); 144 return DeleteValue(name == NULL ? NULL : (LPCSTR)GetSystemString(name));
131} 145}
132#endif 146#endif
133 147
@@ -143,12 +157,15 @@ LONG CKey::SetValue(LPCTSTR name, bool value) throw()
143 return SetValue(name, BoolToUINT32(value)); 157 return SetValue(name, BoolToUINT32(value));
144} 158}
145 159
160
161// value must be string that is NULL terminated
146LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw() 162LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw()
147{ 163{
148 MYASSERT(value != NULL); 164 MYASSERT(value != NULL);
149 MY_ASSUME(_object != NULL); 165 MY_ASSUME(_object != NULL);
166 // note: RegSetValueEx supports (value == NULL), if (cbData == 0)
150 return RegSetValueEx(_object, name, 0, REG_SZ, 167 return RegSetValueEx(_object, name, 0, REG_SZ,
151 (const BYTE *)value, ((DWORD)lstrlen(value) + 1) * sizeof(TCHAR)); 168 (const BYTE *)value, (DWORD)(((DWORD)lstrlen(value) + 1) * sizeof(TCHAR)));
152} 169}
153 170
154/* 171/*
@@ -156,7 +173,7 @@ LONG CKey::SetValue(LPCTSTR name, const CSysString &value)
156{ 173{
157 MYASSERT(value != NULL); 174 MYASSERT(value != NULL);
158 MY_ASSUME(_object != NULL); 175 MY_ASSUME(_object != NULL);
159 return RegSetValueEx(_object, name, NULL, REG_SZ, 176 return RegSetValueEx(_object, name, 0, REG_SZ,
160 (const BYTE *)(const TCHAR *)value, (value.Len() + 1) * sizeof(TCHAR)); 177 (const BYTE *)(const TCHAR *)value, (value.Len() + 1) * sizeof(TCHAR));
161} 178}
162*/ 179*/
@@ -169,9 +186,10 @@ LONG CKey::SetValue(LPCWSTR name, LPCWSTR value)
169 MY_ASSUME(_object != NULL); 186 MY_ASSUME(_object != NULL);
170 if (g_IsNT) 187 if (g_IsNT)
171 return RegSetValueExW(_object, name, 0, REG_SZ, 188 return RegSetValueExW(_object, name, 0, REG_SZ,
172 (const BYTE * )value, (DWORD)((wcslen(value) + 1) * sizeof(wchar_t))); 189 (const BYTE *)value, (DWORD)(((DWORD)wcslen(value) + 1) * sizeof(wchar_t)));
173 return SetValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), 190 return SetValue(name == NULL ? NULL :
174 value == 0 ? 0 : (LPCSTR)GetSystemString(value)); 191 (LPCSTR)GetSystemString(name),
192 (LPCSTR)GetSystemString(value));
175} 193}
176 194
177#endif 195#endif
@@ -205,99 +223,137 @@ LONG CKey::SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw(
205 return res; 223 return res;
206} 224}
207 225
208LONG CKey::QueryValue(LPCTSTR name, UInt32 &value) throw()
209{
210 DWORD type = 0;
211 DWORD count = sizeof(DWORD);
212 LONG res = RegQueryValueEx(_object, name, NULL, &type,
213 (LPBYTE)&value, &count);
214 MYASSERT((res != ERROR_SUCCESS) || (type == REG_DWORD));
215 MYASSERT((res != ERROR_SUCCESS) || (count == sizeof(UInt32)));
216 return res;
217}
218 226
219LONG CKey::QueryValue(LPCTSTR name, bool &value) throw() 227LONG CKey::GetValue_UInt32_IfOk(LPCTSTR name, UInt32 &value) throw()
220{ 228{
221 UInt32 uintValue = BoolToUINT32(value); 229 DWORD type = 0;
222 LONG res = QueryValue(name, uintValue); 230 DWORD count = sizeof(value);
223 value = UINT32ToBool(uintValue); 231 UInt32 value2; // = value;
232 const LONG res = QueryValueEx(name, &type, (LPBYTE)&value2, &count);
233 if (res == ERROR_SUCCESS)
234 {
235 // ERROR_UNSUPPORTED_TYPE
236 if (count != sizeof(value) || type != REG_DWORD)
237 return ERROR_UNSUPPORTED_TYPE; // ERROR_INVALID_DATA;
238 value = value2;
239 }
224 return res; 240 return res;
225} 241}
226 242
227LONG CKey::GetValue_IfOk(LPCTSTR name, UInt32 &value) throw() 243LONG CKey::GetValue_UInt64_IfOk(LPCTSTR name, UInt64 &value) throw()
228{ 244{
229 UInt32 newVal; 245 DWORD type = 0;
230 LONG res = QueryValue(name, newVal); 246 DWORD count = sizeof(value);
247 UInt64 value2; // = value;
248 const LONG res = QueryValueEx(name, &type, (LPBYTE)&value2, &count);
231 if (res == ERROR_SUCCESS) 249 if (res == ERROR_SUCCESS)
232 value = newVal; 250 {
251 if (count != sizeof(value) || type != REG_QWORD)
252 return ERROR_UNSUPPORTED_TYPE;
253 value = value2;
254 }
233 return res; 255 return res;
234} 256}
235 257
236LONG CKey::GetValue_IfOk(LPCTSTR name, bool &value) throw() 258LONG CKey::GetValue_bool_IfOk(LPCTSTR name, bool &value) throw()
237{ 259{
238 bool newVal = false; 260 UInt32 uintValue;
239 LONG res = QueryValue(name, newVal); 261 const LONG res = GetValue_UInt32_IfOk(name, uintValue);
240 if (res == ERROR_SUCCESS) 262 if (res == ERROR_SUCCESS)
241 value = newVal; 263 value = UINT32ToBool(uintValue);
242 return res; 264 return res;
243} 265}
244 266
245LONG CKey::QueryValue(LPCTSTR name, LPTSTR value, UInt32 &count) throw() 267
246{
247 DWORD type = 0;
248 LONG res = RegQueryValueEx(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
249 MYASSERT((res != ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
250 return res;
251}
252 268
253LONG CKey::QueryValue(LPCTSTR name, CSysString &value) 269LONG CKey::QueryValue(LPCTSTR name, CSysString &value)
254{ 270{
255 value.Empty(); 271 value.Empty();
256 DWORD type = 0; 272 LONG res = ERROR_SUCCESS;
257 DWORD curSize = 0; 273 {
258 LONG res = RegQueryValueEx(_object, name, NULL, &type, NULL, &curSize); 274 // if we don't want multiple calls here,
259 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) 275 // we can use big value (264) here.
260 return res; 276 // 3 is default available length in new string.
261 UInt32 curSize2 = curSize; 277 DWORD size_prev = 3 * sizeof(TCHAR);
262 res = QueryValue(name, value.GetBuf(curSize), curSize2); 278 // at least 2 attempts are required. But we use more attempts for cases,
263 if (curSize > curSize2) 279 // where string can be changed by anothner process
264 curSize = curSize2; 280 for (unsigned i = 0; i < 2 + 2; i++)
265 value.ReleaseBuf_CalcLen(curSize / sizeof(TCHAR)); 281 {
282 DWORD type = 0;
283 DWORD size = size_prev;
284 {
285 LPBYTE buf = (LPBYTE)value.GetBuf(size / sizeof(TCHAR));
286 res = QueryValueEx(name, &type, size == 0 ? NULL : buf, &size);
287 // if (size_prev == 0), then (res == ERROR_SUCCESS) is expected here, because we requested only size.
288 }
289 if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
290 {
291 if (type != REG_SZ && type != REG_EXPAND_SZ)
292 {
293 res = ERROR_UNSUPPORTED_TYPE;
294 size = 0;
295 }
296 }
297 else
298 size = 0;
299 if (size > size_prev)
300 {
301 size_prev = size;
302 size = 0;
303 res = ERROR_MORE_DATA;
304 }
305 value.ReleaseBuf_CalcLen(size / sizeof(TCHAR));
306 if (res != ERROR_MORE_DATA)
307 return res;
308 }
309 }
266 return res; 310 return res;
267} 311}
268 312
269 313
270#ifndef _UNICODE 314#ifndef _UNICODE
271 315
272LONG CKey::QueryValue(LPCWSTR name, LPWSTR value, UInt32 &count)
273{
274 DWORD type = 0;
275 LONG res = RegQueryValueExW(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
276 MYASSERT((res != ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
277 return res;
278}
279
280LONG CKey::QueryValue(LPCWSTR name, UString &value) 316LONG CKey::QueryValue(LPCWSTR name, UString &value)
281{ 317{
282 value.Empty(); 318 value.Empty();
283 DWORD type = 0; 319 LONG res = ERROR_SUCCESS;
284 DWORD curSize = 0;
285 LONG res;
286 if (g_IsNT) 320 if (g_IsNT)
287 { 321 {
288 res = RegQueryValueExW(_object, name, NULL, &type, NULL, &curSize); 322 DWORD size_prev = 3 * sizeof(wchar_t);
289 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) 323 for (unsigned i = 0; i < 2 + 2; i++)
290 return res; 324 {
291 UInt32 curSize2 = curSize; 325 DWORD type = 0;
292 res = QueryValue(name, value.GetBuf(curSize), curSize2); 326 DWORD size = size_prev;
293 if (curSize > curSize2) 327 {
294 curSize = curSize2; 328 LPBYTE buf = (LPBYTE)value.GetBuf(size / sizeof(wchar_t));
295 value.ReleaseBuf_CalcLen(curSize / sizeof(wchar_t)); 329 res = RegQueryValueExW(_object, name, NULL, &type,
330 size == 0 ? NULL : buf, &size);
331 }
332 if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
333 {
334 if (type != REG_SZ && type != REG_EXPAND_SZ)
335 {
336 res = ERROR_UNSUPPORTED_TYPE;
337 size = 0;
338 }
339 }
340 else
341 size = 0;
342 if (size > size_prev)
343 {
344 size_prev = size;
345 size = 0;
346 res = ERROR_MORE_DATA;
347 }
348 value.ReleaseBuf_CalcLen(size / sizeof(wchar_t));
349 if (res != ERROR_MORE_DATA)
350 return res;
351 }
296 } 352 }
297 else 353 else
298 { 354 {
299 AString vTemp; 355 AString vTemp;
300 res = QueryValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), vTemp); 356 res = QueryValue(name == NULL ? NULL : (LPCSTR)GetSystemString(name), vTemp);
301 value = GetUnicodeString(vTemp); 357 value = GetUnicodeString(vTemp);
302 } 358 }
303 return res; 359 return res;
@@ -306,26 +362,43 @@ LONG CKey::QueryValue(LPCWSTR name, UString &value)
306#endif 362#endif
307 363
308 364
309LONG CKey::QueryValue(LPCTSTR name, void *value, UInt32 &count) throw() 365LONG CKey::QueryValue_Binary(LPCTSTR name, CByteBuffer &value)
310{ 366{
311 DWORD type = 0; 367 // value.Free();
312 LONG res = RegQueryValueEx(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count); 368 DWORD size_prev = 0;
313 MYASSERT((res != ERROR_SUCCESS) || (type == REG_BINARY)); 369 LONG res = ERROR_SUCCESS;
370 for (unsigned i = 0; i < 2 + 2; i++)
371 {
372 DWORD type = 0;
373 DWORD size = size_prev;
374 value.Alloc(size_prev);
375 res = QueryValueEx(name, &type, value.NonConstData(), &size);
376 // if (size_prev == 0), then (res == ERROR_SUCCESS) is expected here, because we requested only size.
377 if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
378 {
379 if (type != REG_BINARY)
380 {
381 res = ERROR_UNSUPPORTED_TYPE;
382 size = 0;
383 }
384 }
385 else
386 size = 0;
387 if (size > size_prev)
388 {
389 size_prev = size;
390 size = 0;
391 res = ERROR_MORE_DATA;
392 }
393 if (size < value.Size())
394 value.ChangeSize_KeepData(size, size);
395 if (res != ERROR_MORE_DATA)
396 return res;
397 }
314 return res; 398 return res;
315} 399}
316 400
317 401
318LONG CKey::QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize)
319{
320 DWORD type = 0;
321 dataSize = 0;
322 LONG res = RegQueryValueEx(_object, name, NULL, &type, NULL, (DWORD *)&dataSize);
323 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
324 return res;
325 value.Alloc(dataSize);
326 return QueryValue(name, (BYTE *)value, dataSize);
327}
328
329LONG CKey::EnumKeys(CSysStringVector &keyNames) 402LONG CKey::EnumKeys(CSysStringVector &keyNames)
330{ 403{
331 keyNames.Clear(); 404 keyNames.Clear();
@@ -334,23 +407,23 @@ LONG CKey::EnumKeys(CSysStringVector &keyNames)
334 { 407 {
335 const unsigned kBufSize = MAX_PATH + 1; // 256 in ATL 408 const unsigned kBufSize = MAX_PATH + 1; // 256 in ATL
336 FILETIME lastWriteTime; 409 FILETIME lastWriteTime;
337 UInt32 nameSize = kBufSize; 410 DWORD nameSize = kBufSize;
338 LONG result = ::RegEnumKeyEx(_object, index, keyName.GetBuf(kBufSize), 411 const LONG res = ::RegEnumKeyEx(_object, index,
339 (DWORD *)&nameSize, NULL, NULL, NULL, &lastWriteTime); 412 keyName.GetBuf(kBufSize), &nameSize,
413 NULL, NULL, NULL, &lastWriteTime);
340 keyName.ReleaseBuf_CalcLen(kBufSize); 414 keyName.ReleaseBuf_CalcLen(kBufSize);
341 if (result == ERROR_NO_MORE_ITEMS) 415 if (res == ERROR_NO_MORE_ITEMS)
342 break; 416 return ERROR_SUCCESS;
343 if (result != ERROR_SUCCESS) 417 if (res != ERROR_SUCCESS)
344 return result; 418 return res;
345 keyNames.Add(keyName); 419 keyNames.Add(keyName);
346 } 420 }
347 return ERROR_SUCCESS;
348} 421}
349 422
423
350LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings) 424LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings)
351{ 425{
352 size_t numChars = 0; 426 size_t numChars = 0;
353
354 unsigned i; 427 unsigned i;
355 428
356 for (i = 0; i < strings.Size(); i++) 429 for (i = 0; i < strings.Size(); i++)
@@ -362,10 +435,11 @@ LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings)
362 for (i = 0; i < strings.Size(); i++) 435 for (i = 0; i < strings.Size(); i++)
363 { 436 {
364 const UString &s = strings[i]; 437 const UString &s = strings[i];
365 size_t size = s.Len() + 1; 438 const size_t size = s.Len() + 1;
366 wmemcpy(buffer + pos, s, size); 439 wmemcpy(buffer + pos, s, size);
367 pos += size; 440 pos += size;
368 } 441 }
442 // if (pos != numChars) return E_FAIL;
369 return SetValue(valueName, buffer, (UInt32)numChars * sizeof(wchar_t)); 443 return SetValue(valueName, buffer, (UInt32)numChars * sizeof(wchar_t));
370} 444}
371 445
@@ -373,20 +447,18 @@ LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings)
373{ 447{
374 strings.Clear(); 448 strings.Clear();
375 CByteBuffer buffer; 449 CByteBuffer buffer;
376 UInt32 dataSize = 0; 450 const LONG res = QueryValue_Binary(valueName, buffer);
377 const LONG res = QueryValue(valueName, buffer, dataSize);
378 if (res != ERROR_SUCCESS) 451 if (res != ERROR_SUCCESS)
379 return res; 452 return res;
380 if (dataSize > buffer.Size()) 453 const size_t dataSize = buffer.Size();
381 return E_FAIL; 454 if (dataSize % sizeof(wchar_t))
382 if (dataSize % sizeof(wchar_t) != 0) 455 return ERROR_INVALID_DATA;
383 return E_FAIL;
384
385 const wchar_t *data = (const wchar_t *)(const void *)(const Byte *)buffer; 456 const wchar_t *data = (const wchar_t *)(const void *)(const Byte *)buffer;
386 const size_t numChars = dataSize / sizeof(wchar_t); 457 const size_t numChars = dataSize / sizeof(wchar_t);
458 // we can check that all names are finished
459 // if (numChars != 0 && data[numChars - 1] != 0) return ERROR_INVALID_DATA;
387 size_t prev = 0; 460 size_t prev = 0;
388 UString s; 461 UString s;
389
390 for (size_t i = 0; i < numChars; i++) 462 for (size_t i = 0; i < numChars; i++)
391 { 463 {
392 if (data[i] == 0) 464 if (data[i] == 0)
@@ -396,7 +468,6 @@ LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings)
396 prev = i + 1; 468 prev = i + 1;
397 } 469 }
398 } 470 }
399
400 return res; 471 return res;
401} 472}
402 473