OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2003 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 // Registry configuration wrapers class implementation | |
12 // | |
13 // Change made by S. Ganesh - ganesh@google.com: | |
14 // Use SHQueryValueEx instead of RegQueryValueEx throughout. | |
15 // A call to the SHLWAPI function is essentially a call to the standard | |
16 // function but with post-processing: | |
17 // * to fix REG_SZ or REG_EXPAND_SZ data that is not properly null-terminated; | |
18 // * to expand REG_EXPAND_SZ data. | |
19 | |
20 #include "webrtc/base/win32regkey.h" | |
21 | |
22 #include <shlwapi.h> | |
23 | |
24 #include <memory> | |
25 | |
26 #include "webrtc/base/common.h" | |
27 #include "webrtc/base/logging.h" | |
28 | |
29 namespace rtc { | |
30 | |
31 RegKey::RegKey() { | |
32 h_key_ = NULL; | |
33 } | |
34 | |
35 RegKey::~RegKey() { | |
36 Close(); | |
37 } | |
38 | |
39 HRESULT RegKey::Create(HKEY parent_key, const wchar_t* key_name) { | |
40 return Create(parent_key, | |
41 key_name, | |
42 REG_NONE, | |
43 REG_OPTION_NON_VOLATILE, | |
44 KEY_ALL_ACCESS, | |
45 NULL, | |
46 NULL); | |
47 } | |
48 | |
49 HRESULT RegKey::Open(HKEY parent_key, const wchar_t* key_name) { | |
50 return Open(parent_key, key_name, KEY_ALL_ACCESS); | |
51 } | |
52 | |
53 bool RegKey::HasValue(const TCHAR* value_name) const { | |
54 return (ERROR_SUCCESS == ::RegQueryValueEx(h_key_, value_name, NULL, | |
55 NULL, NULL, NULL)); | |
56 } | |
57 | |
58 HRESULT RegKey::SetValue(const wchar_t* full_key_name, | |
59 const wchar_t* value_name, | |
60 DWORD value) { | |
61 ASSERT(full_key_name != NULL); | |
62 | |
63 return SetValueStaticHelper(full_key_name, value_name, REG_DWORD, &value); | |
64 } | |
65 | |
66 HRESULT RegKey::SetValue(const wchar_t* full_key_name, | |
67 const wchar_t* value_name, | |
68 DWORD64 value) { | |
69 ASSERT(full_key_name != NULL); | |
70 | |
71 return SetValueStaticHelper(full_key_name, value_name, REG_QWORD, &value); | |
72 } | |
73 | |
74 HRESULT RegKey::SetValue(const wchar_t* full_key_name, | |
75 const wchar_t* value_name, | |
76 float value) { | |
77 ASSERT(full_key_name != NULL); | |
78 | |
79 return SetValueStaticHelper(full_key_name, value_name, | |
80 REG_BINARY, &value, sizeof(value)); | |
81 } | |
82 | |
83 HRESULT RegKey::SetValue(const wchar_t* full_key_name, | |
84 const wchar_t* value_name, | |
85 double value) { | |
86 ASSERT(full_key_name != NULL); | |
87 | |
88 return SetValueStaticHelper(full_key_name, value_name, | |
89 REG_BINARY, &value, sizeof(value)); | |
90 } | |
91 | |
92 HRESULT RegKey::SetValue(const wchar_t* full_key_name, | |
93 const wchar_t* value_name, | |
94 const TCHAR* value) { | |
95 ASSERT(full_key_name != NULL); | |
96 ASSERT(value != NULL); | |
97 | |
98 return SetValueStaticHelper(full_key_name, value_name, | |
99 REG_SZ, const_cast<wchar_t*>(value)); | |
100 } | |
101 | |
102 HRESULT RegKey::SetValue(const wchar_t* full_key_name, | |
103 const wchar_t* value_name, | |
104 const uint8_t* value, | |
105 DWORD byte_count) { | |
106 ASSERT(full_key_name != NULL); | |
107 | |
108 return SetValueStaticHelper(full_key_name, value_name, REG_BINARY, | |
109 const_cast<uint8_t*>(value), byte_count); | |
110 } | |
111 | |
112 HRESULT RegKey::SetValueMultiSZ(const wchar_t* full_key_name, | |
113 const wchar_t* value_name, | |
114 const uint8_t* value, | |
115 DWORD byte_count) { | |
116 ASSERT(full_key_name != NULL); | |
117 | |
118 return SetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ, | |
119 const_cast<uint8_t*>(value), byte_count); | |
120 } | |
121 | |
122 HRESULT RegKey::GetValue(const wchar_t* full_key_name, | |
123 const wchar_t* value_name, | |
124 DWORD* value) { | |
125 ASSERT(full_key_name != NULL); | |
126 ASSERT(value != NULL); | |
127 | |
128 return GetValueStaticHelper(full_key_name, value_name, REG_DWORD, value); | |
129 } | |
130 | |
131 HRESULT RegKey::GetValue(const wchar_t* full_key_name, | |
132 const wchar_t* value_name, | |
133 DWORD64* value) { | |
134 ASSERT(full_key_name != NULL); | |
135 ASSERT(value != NULL); | |
136 | |
137 return GetValueStaticHelper(full_key_name, value_name, REG_QWORD, value); | |
138 } | |
139 | |
140 HRESULT RegKey::GetValue(const wchar_t* full_key_name, | |
141 const wchar_t* value_name, | |
142 float* value) { | |
143 ASSERT(value != NULL); | |
144 ASSERT(full_key_name != NULL); | |
145 | |
146 DWORD byte_count = 0; | |
147 byte* buffer_raw = nullptr; | |
148 HRESULT hr = GetValueStaticHelper(full_key_name, value_name, | |
149 REG_BINARY, &buffer_raw, &byte_count); | |
150 std::unique_ptr<byte[]> buffer(buffer_raw); | |
151 if (SUCCEEDED(hr)) { | |
152 ASSERT(byte_count == sizeof(*value)); | |
153 if (byte_count == sizeof(*value)) { | |
154 *value = *reinterpret_cast<float*>(buffer.get()); | |
155 } | |
156 } | |
157 return hr; | |
158 } | |
159 | |
160 HRESULT RegKey::GetValue(const wchar_t* full_key_name, | |
161 const wchar_t* value_name, | |
162 double* value) { | |
163 ASSERT(value != NULL); | |
164 ASSERT(full_key_name != NULL); | |
165 | |
166 DWORD byte_count = 0; | |
167 byte* buffer_raw = nullptr; | |
168 HRESULT hr = GetValueStaticHelper(full_key_name, value_name, | |
169 REG_BINARY, &buffer_raw, &byte_count); | |
170 std::unique_ptr<byte[]> buffer(buffer_raw); | |
171 if (SUCCEEDED(hr)) { | |
172 ASSERT(byte_count == sizeof(*value)); | |
173 if (byte_count == sizeof(*value)) { | |
174 *value = *reinterpret_cast<double*>(buffer.get()); | |
175 } | |
176 } | |
177 return hr; | |
178 } | |
179 | |
180 HRESULT RegKey::GetValue(const wchar_t* full_key_name, | |
181 const wchar_t* value_name, | |
182 wchar_t** value) { | |
183 ASSERT(full_key_name != NULL); | |
184 ASSERT(value != NULL); | |
185 | |
186 return GetValueStaticHelper(full_key_name, value_name, REG_SZ, value); | |
187 } | |
188 | |
189 HRESULT RegKey::GetValue(const wchar_t* full_key_name, | |
190 const wchar_t* value_name, | |
191 std::wstring* value) { | |
192 ASSERT(full_key_name != NULL); | |
193 ASSERT(value != NULL); | |
194 | |
195 wchar_t* buffer_raw = nullptr; | |
196 HRESULT hr = RegKey::GetValue(full_key_name, value_name, &buffer_raw); | |
197 std::unique_ptr<wchar_t[]> buffer(buffer_raw); | |
198 if (SUCCEEDED(hr)) { | |
199 value->assign(buffer.get()); | |
200 } | |
201 return hr; | |
202 } | |
203 | |
204 HRESULT RegKey::GetValue(const wchar_t* full_key_name, | |
205 const wchar_t* value_name, | |
206 std::vector<std::wstring>* value) { | |
207 ASSERT(full_key_name != NULL); | |
208 ASSERT(value != NULL); | |
209 | |
210 return GetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ, value); | |
211 } | |
212 | |
213 HRESULT RegKey::GetValue(const wchar_t* full_key_name, | |
214 const wchar_t* value_name, | |
215 uint8_t** value, | |
216 DWORD* byte_count) { | |
217 ASSERT(full_key_name != NULL); | |
218 ASSERT(value != NULL); | |
219 ASSERT(byte_count != NULL); | |
220 | |
221 return GetValueStaticHelper(full_key_name, value_name, | |
222 REG_BINARY, value, byte_count); | |
223 } | |
224 | |
225 HRESULT RegKey::DeleteSubKey(const wchar_t* key_name) { | |
226 ASSERT(key_name != NULL); | |
227 ASSERT(h_key_ != NULL); | |
228 | |
229 LONG res = ::RegDeleteKey(h_key_, key_name); | |
230 HRESULT hr = HRESULT_FROM_WIN32(res); | |
231 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || | |
232 hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) { | |
233 hr = S_FALSE; | |
234 } | |
235 return hr; | |
236 } | |
237 | |
238 HRESULT RegKey::DeleteValue(const wchar_t* value_name) { | |
239 ASSERT(h_key_ != NULL); | |
240 | |
241 LONG res = ::RegDeleteValue(h_key_, value_name); | |
242 HRESULT hr = HRESULT_FROM_WIN32(res); | |
243 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || | |
244 hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) { | |
245 hr = S_FALSE; | |
246 } | |
247 return hr; | |
248 } | |
249 | |
250 HRESULT RegKey::Close() { | |
251 HRESULT hr = S_OK; | |
252 if (h_key_ != NULL) { | |
253 LONG res = ::RegCloseKey(h_key_); | |
254 hr = HRESULT_FROM_WIN32(res); | |
255 h_key_ = NULL; | |
256 } | |
257 return hr; | |
258 } | |
259 | |
260 HRESULT RegKey::Create(HKEY parent_key, | |
261 const wchar_t* key_name, | |
262 wchar_t* lpszClass, | |
263 DWORD options, | |
264 REGSAM sam_desired, | |
265 LPSECURITY_ATTRIBUTES lpSecAttr, | |
266 LPDWORD lpdwDisposition) { | |
267 ASSERT(key_name != NULL); | |
268 ASSERT(parent_key != NULL); | |
269 | |
270 DWORD dw = 0; | |
271 HKEY h_key = NULL; | |
272 LONG res = ::RegCreateKeyEx(parent_key, key_name, 0, lpszClass, options, | |
273 sam_desired, lpSecAttr, &h_key, &dw); | |
274 HRESULT hr = HRESULT_FROM_WIN32(res); | |
275 | |
276 if (lpdwDisposition) { | |
277 *lpdwDisposition = dw; | |
278 } | |
279 | |
280 // we have to close the currently opened key | |
281 // before replacing it with the new one | |
282 if (hr == S_OK) { | |
283 hr = Close(); | |
284 ASSERT(hr == S_OK); | |
285 h_key_ = h_key; | |
286 } | |
287 return hr; | |
288 } | |
289 | |
290 HRESULT RegKey::Open(HKEY parent_key, | |
291 const wchar_t* key_name, | |
292 REGSAM sam_desired) { | |
293 ASSERT(key_name != NULL); | |
294 ASSERT(parent_key != NULL); | |
295 | |
296 HKEY h_key = NULL; | |
297 LONG res = ::RegOpenKeyEx(parent_key, key_name, 0, sam_desired, &h_key); | |
298 HRESULT hr = HRESULT_FROM_WIN32(res); | |
299 | |
300 // we have to close the currently opened key | |
301 // before replacing it with the new one | |
302 if (hr == S_OK) { | |
303 // close the currently opened key if any | |
304 hr = Close(); | |
305 ASSERT(hr == S_OK); | |
306 h_key_ = h_key; | |
307 } | |
308 return hr; | |
309 } | |
310 | |
311 // save the key and all of its subkeys and values to a file | |
312 HRESULT RegKey::Save(const wchar_t* full_key_name, const wchar_t* file_name) { | |
313 ASSERT(full_key_name != NULL); | |
314 ASSERT(file_name != NULL); | |
315 | |
316 std::wstring key_name(full_key_name); | |
317 HKEY h_key = GetRootKeyInfo(&key_name); | |
318 if (!h_key) { | |
319 return E_FAIL; | |
320 } | |
321 | |
322 RegKey key; | |
323 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ); | |
324 if (FAILED(hr)) { | |
325 return hr; | |
326 } | |
327 | |
328 AdjustCurrentProcessPrivilege(SE_BACKUP_NAME, true); | |
329 LONG res = ::RegSaveKey(key.h_key_, file_name, NULL); | |
330 AdjustCurrentProcessPrivilege(SE_BACKUP_NAME, false); | |
331 | |
332 return HRESULT_FROM_WIN32(res); | |
333 } | |
334 | |
335 // restore the key and all of its subkeys and values which are saved into a file | |
336 HRESULT RegKey::Restore(const wchar_t* full_key_name, | |
337 const wchar_t* file_name) { | |
338 ASSERT(full_key_name != NULL); | |
339 ASSERT(file_name != NULL); | |
340 | |
341 std::wstring key_name(full_key_name); | |
342 HKEY h_key = GetRootKeyInfo(&key_name); | |
343 if (!h_key) { | |
344 return E_FAIL; | |
345 } | |
346 | |
347 RegKey key; | |
348 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_WRITE); | |
349 if (FAILED(hr)) { | |
350 return hr; | |
351 } | |
352 | |
353 AdjustCurrentProcessPrivilege(SE_RESTORE_NAME, true); | |
354 LONG res = ::RegRestoreKey(key.h_key_, file_name, REG_FORCE_RESTORE); | |
355 AdjustCurrentProcessPrivilege(SE_RESTORE_NAME, false); | |
356 | |
357 return HRESULT_FROM_WIN32(res); | |
358 } | |
359 | |
360 // check if the current key has the specified subkey | |
361 bool RegKey::HasSubkey(const wchar_t* key_name) const { | |
362 ASSERT(key_name != NULL); | |
363 | |
364 RegKey key; | |
365 HRESULT hr = key.Open(h_key_, key_name, KEY_READ); | |
366 key.Close(); | |
367 return hr == S_OK; | |
368 } | |
369 | |
370 // static flush key | |
371 HRESULT RegKey::FlushKey(const wchar_t* full_key_name) { | |
372 ASSERT(full_key_name != NULL); | |
373 | |
374 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); | |
375 // get the root HKEY | |
376 std::wstring key_name(full_key_name); | |
377 HKEY h_key = GetRootKeyInfo(&key_name); | |
378 | |
379 if (h_key != NULL) { | |
380 LONG res = ::RegFlushKey(h_key); | |
381 hr = HRESULT_FROM_WIN32(res); | |
382 } | |
383 return hr; | |
384 } | |
385 | |
386 // static SET helper | |
387 HRESULT RegKey::SetValueStaticHelper(const wchar_t* full_key_name, | |
388 const wchar_t* value_name, | |
389 DWORD type, | |
390 LPVOID value, | |
391 DWORD byte_count) { | |
392 ASSERT(full_key_name != NULL); | |
393 | |
394 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); | |
395 // get the root HKEY | |
396 std::wstring key_name(full_key_name); | |
397 HKEY h_key = GetRootKeyInfo(&key_name); | |
398 | |
399 if (h_key != NULL) { | |
400 RegKey key; | |
401 hr = key.Create(h_key, key_name.c_str()); | |
402 if (hr == S_OK) { | |
403 switch (type) { | |
404 case REG_DWORD: | |
405 hr = key.SetValue(value_name, *(static_cast<DWORD*>(value))); | |
406 break; | |
407 case REG_QWORD: | |
408 hr = key.SetValue(value_name, *(static_cast<DWORD64*>(value))); | |
409 break; | |
410 case REG_SZ: | |
411 hr = key.SetValue(value_name, static_cast<const wchar_t*>(value)); | |
412 break; | |
413 case REG_BINARY: | |
414 hr = key.SetValue(value_name, static_cast<const uint8_t*>(value), | |
415 byte_count); | |
416 break; | |
417 case REG_MULTI_SZ: | |
418 hr = key.SetValue(value_name, static_cast<const uint8_t*>(value), | |
419 byte_count, type); | |
420 break; | |
421 default: | |
422 ASSERT(false); | |
423 hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH); | |
424 break; | |
425 } | |
426 // close the key after writing | |
427 HRESULT temp_hr = key.Close(); | |
428 if (hr == S_OK) { | |
429 hr = temp_hr; | |
430 } | |
431 } | |
432 } | |
433 return hr; | |
434 } | |
435 | |
436 // static GET helper | |
437 HRESULT RegKey::GetValueStaticHelper(const wchar_t* full_key_name, | |
438 const wchar_t* value_name, | |
439 DWORD type, | |
440 LPVOID value, | |
441 DWORD* byte_count) { | |
442 ASSERT(full_key_name != NULL); | |
443 | |
444 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); | |
445 // get the root HKEY | |
446 std::wstring key_name(full_key_name); | |
447 HKEY h_key = GetRootKeyInfo(&key_name); | |
448 | |
449 if (h_key != NULL) { | |
450 RegKey key; | |
451 hr = key.Open(h_key, key_name.c_str(), KEY_READ); | |
452 if (hr == S_OK) { | |
453 switch (type) { | |
454 case REG_DWORD: | |
455 hr = key.GetValue(value_name, reinterpret_cast<DWORD*>(value)); | |
456 break; | |
457 case REG_QWORD: | |
458 hr = key.GetValue(value_name, reinterpret_cast<DWORD64*>(value)); | |
459 break; | |
460 case REG_SZ: | |
461 hr = key.GetValue(value_name, reinterpret_cast<wchar_t**>(value)); | |
462 break; | |
463 case REG_MULTI_SZ: | |
464 hr = key.GetValue(value_name, reinterpret_cast< | |
465 std::vector<std::wstring>*>(value)); | |
466 break; | |
467 case REG_BINARY: | |
468 hr = key.GetValue(value_name, reinterpret_cast<uint8_t**>(value), | |
469 byte_count); | |
470 break; | |
471 default: | |
472 ASSERT(false); | |
473 hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH); | |
474 break; | |
475 } | |
476 // close the key after writing | |
477 HRESULT temp_hr = key.Close(); | |
478 if (hr == S_OK) { | |
479 hr = temp_hr; | |
480 } | |
481 } | |
482 } | |
483 return hr; | |
484 } | |
485 | |
486 // GET helper | |
487 HRESULT RegKey::GetValueHelper(const wchar_t* value_name, | |
488 DWORD* type, | |
489 uint8_t** value, | |
490 DWORD* byte_count) const { | |
491 ASSERT(byte_count != NULL); | |
492 ASSERT(value != NULL); | |
493 ASSERT(type != NULL); | |
494 | |
495 // init return buffer | |
496 *value = NULL; | |
497 | |
498 // get the size of the return data buffer | |
499 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, type, NULL, byte_count); | |
500 HRESULT hr = HRESULT_FROM_WIN32(res); | |
501 | |
502 if (hr == S_OK) { | |
503 // if the value length is 0, nothing to do | |
504 if (*byte_count != 0) { | |
505 // allocate the buffer | |
506 *value = new byte[*byte_count]; | |
507 ASSERT(*value != NULL); | |
508 | |
509 // make the call again to get the data | |
510 res = ::SHQueryValueEx(h_key_, value_name, NULL, | |
511 type, *value, byte_count); | |
512 hr = HRESULT_FROM_WIN32(res); | |
513 ASSERT(hr == S_OK); | |
514 } | |
515 } | |
516 return hr; | |
517 } | |
518 | |
519 // Int32 Get | |
520 HRESULT RegKey::GetValue(const wchar_t* value_name, DWORD* value) const { | |
521 ASSERT(value != NULL); | |
522 | |
523 DWORD type = 0; | |
524 DWORD byte_count = sizeof(DWORD); | |
525 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, &type, | |
526 value, &byte_count); | |
527 HRESULT hr = HRESULT_FROM_WIN32(res); | |
528 ASSERT((hr != S_OK) || (type == REG_DWORD)); | |
529 ASSERT((hr != S_OK) || (byte_count == sizeof(DWORD))); | |
530 return hr; | |
531 } | |
532 | |
533 // Int64 Get | |
534 HRESULT RegKey::GetValue(const wchar_t* value_name, DWORD64* value) const { | |
535 ASSERT(value != NULL); | |
536 | |
537 DWORD type = 0; | |
538 DWORD byte_count = sizeof(DWORD64); | |
539 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, &type, | |
540 value, &byte_count); | |
541 HRESULT hr = HRESULT_FROM_WIN32(res); | |
542 ASSERT((hr != S_OK) || (type == REG_QWORD)); | |
543 ASSERT((hr != S_OK) || (byte_count == sizeof(DWORD64))); | |
544 return hr; | |
545 } | |
546 | |
547 // String Get | |
548 HRESULT RegKey::GetValue(const wchar_t* value_name, wchar_t** value) const { | |
549 ASSERT(value != NULL); | |
550 | |
551 DWORD byte_count = 0; | |
552 DWORD type = 0; | |
553 | |
554 // first get the size of the string buffer | |
555 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, | |
556 &type, NULL, &byte_count); | |
557 HRESULT hr = HRESULT_FROM_WIN32(res); | |
558 | |
559 if (hr == S_OK) { | |
560 // allocate room for the string and a terminating \0 | |
561 *value = new wchar_t[(byte_count / sizeof(wchar_t)) + 1]; | |
562 | |
563 if ((*value) != NULL) { | |
564 if (byte_count != 0) { | |
565 // make the call again | |
566 res = ::SHQueryValueEx(h_key_, value_name, NULL, &type, | |
567 *value, &byte_count); | |
568 hr = HRESULT_FROM_WIN32(res); | |
569 } else { | |
570 (*value)[0] = L'\0'; | |
571 } | |
572 | |
573 ASSERT((hr != S_OK) || (type == REG_SZ) || | |
574 (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ)); | |
575 } else { | |
576 hr = E_OUTOFMEMORY; | |
577 } | |
578 } | |
579 | |
580 return hr; | |
581 } | |
582 | |
583 // get a string value | |
584 HRESULT RegKey::GetValue(const wchar_t* value_name, std::wstring* value) const { | |
585 ASSERT(value != NULL); | |
586 | |
587 DWORD byte_count = 0; | |
588 DWORD type = 0; | |
589 | |
590 // first get the size of the string buffer | |
591 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, | |
592 &type, NULL, &byte_count); | |
593 HRESULT hr = HRESULT_FROM_WIN32(res); | |
594 | |
595 if (hr == S_OK) { | |
596 if (byte_count != 0) { | |
597 // Allocate some memory and make the call again | |
598 value->resize(byte_count / sizeof(wchar_t) + 1); | |
599 res = ::SHQueryValueEx(h_key_, value_name, NULL, &type, | |
600 &value->at(0), &byte_count); | |
601 hr = HRESULT_FROM_WIN32(res); | |
602 value->resize(wcslen(value->data())); | |
603 } else { | |
604 value->clear(); | |
605 } | |
606 | |
607 ASSERT((hr != S_OK) || (type == REG_SZ) || | |
608 (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ)); | |
609 } | |
610 | |
611 return hr; | |
612 } | |
613 | |
614 // convert REG_MULTI_SZ bytes to string array | |
615 HRESULT RegKey::MultiSZBytesToStringArray(const uint8_t* buffer, | |
616 DWORD byte_count, | |
617 std::vector<std::wstring>* value) { | |
618 ASSERT(buffer != NULL); | |
619 ASSERT(value != NULL); | |
620 | |
621 const wchar_t* data = reinterpret_cast<const wchar_t*>(buffer); | |
622 DWORD data_len = byte_count / sizeof(wchar_t); | |
623 value->clear(); | |
624 if (data_len > 1) { | |
625 // must be terminated by two null characters | |
626 if (data[data_len - 1] != 0 || data[data_len - 2] != 0) { | |
627 return E_INVALIDARG; | |
628 } | |
629 | |
630 // put null-terminated strings into arrays | |
631 while (*data) { | |
632 std::wstring str(data); | |
633 value->push_back(str); | |
634 data += str.length() + 1; | |
635 } | |
636 } | |
637 return S_OK; | |
638 } | |
639 | |
640 // get a std::vector<std::wstring> value from REG_MULTI_SZ type | |
641 HRESULT RegKey::GetValue(const wchar_t* value_name, | |
642 std::vector<std::wstring>* value) const { | |
643 ASSERT(value != NULL); | |
644 | |
645 DWORD byte_count = 0; | |
646 DWORD type = 0; | |
647 uint8_t* buffer = 0; | |
648 | |
649 // first get the size of the buffer | |
650 HRESULT hr = GetValueHelper(value_name, &type, &buffer, &byte_count); | |
651 ASSERT((hr != S_OK) || (type == REG_MULTI_SZ)); | |
652 | |
653 if (SUCCEEDED(hr)) { | |
654 hr = MultiSZBytesToStringArray(buffer, byte_count, value); | |
655 } | |
656 | |
657 return hr; | |
658 } | |
659 | |
660 // Binary data Get | |
661 HRESULT RegKey::GetValue(const wchar_t* value_name, | |
662 uint8_t** value, | |
663 DWORD* byte_count) const { | |
664 ASSERT(byte_count != NULL); | |
665 ASSERT(value != NULL); | |
666 | |
667 DWORD type = 0; | |
668 HRESULT hr = GetValueHelper(value_name, &type, value, byte_count); | |
669 ASSERT((hr != S_OK) || (type == REG_MULTI_SZ) || (type == REG_BINARY)); | |
670 return hr; | |
671 } | |
672 | |
673 // Raw data get | |
674 HRESULT RegKey::GetValue(const wchar_t* value_name, | |
675 uint8_t** value, | |
676 DWORD* byte_count, | |
677 DWORD* type) const { | |
678 ASSERT(type != NULL); | |
679 ASSERT(byte_count != NULL); | |
680 ASSERT(value != NULL); | |
681 | |
682 return GetValueHelper(value_name, type, value, byte_count); | |
683 } | |
684 | |
685 // Int32 set | |
686 HRESULT RegKey::SetValue(const wchar_t* value_name, DWORD value) const { | |
687 ASSERT(h_key_ != NULL); | |
688 | |
689 LONG res = | |
690 ::RegSetValueEx(h_key_, value_name, NULL, REG_DWORD, | |
691 reinterpret_cast<const uint8_t*>(&value), sizeof(DWORD)); | |
692 return HRESULT_FROM_WIN32(res); | |
693 } | |
694 | |
695 // Int64 set | |
696 HRESULT RegKey::SetValue(const wchar_t* value_name, DWORD64 value) const { | |
697 ASSERT(h_key_ != NULL); | |
698 | |
699 LONG res = ::RegSetValueEx(h_key_, value_name, NULL, REG_QWORD, | |
700 reinterpret_cast<const uint8_t*>(&value), | |
701 sizeof(DWORD64)); | |
702 return HRESULT_FROM_WIN32(res); | |
703 } | |
704 | |
705 // String set | |
706 HRESULT RegKey::SetValue(const wchar_t* value_name, | |
707 const wchar_t* value) const { | |
708 ASSERT(value != NULL); | |
709 ASSERT(h_key_ != NULL); | |
710 | |
711 LONG res = ::RegSetValueEx(h_key_, value_name, NULL, REG_SZ, | |
712 reinterpret_cast<const uint8_t*>(value), | |
713 (lstrlen(value) + 1) * sizeof(wchar_t)); | |
714 return HRESULT_FROM_WIN32(res); | |
715 } | |
716 | |
717 // Binary data set | |
718 HRESULT RegKey::SetValue(const wchar_t* value_name, | |
719 const uint8_t* value, | |
720 DWORD byte_count) const { | |
721 ASSERT(h_key_ != NULL); | |
722 | |
723 // special case - if 'value' is NULL make sure byte_count is zero | |
724 if (value == NULL) { | |
725 byte_count = 0; | |
726 } | |
727 | |
728 LONG res = ::RegSetValueEx(h_key_, value_name, NULL, | |
729 REG_BINARY, value, byte_count); | |
730 return HRESULT_FROM_WIN32(res); | |
731 } | |
732 | |
733 // Raw data set | |
734 HRESULT RegKey::SetValue(const wchar_t* value_name, | |
735 const uint8_t* value, | |
736 DWORD byte_count, | |
737 DWORD type) const { | |
738 ASSERT(value != NULL); | |
739 ASSERT(h_key_ != NULL); | |
740 | |
741 LONG res = ::RegSetValueEx(h_key_, value_name, NULL, type, value, byte_count); | |
742 return HRESULT_FROM_WIN32(res); | |
743 } | |
744 | |
745 bool RegKey::HasKey(const wchar_t* full_key_name) { | |
746 ASSERT(full_key_name != NULL); | |
747 | |
748 // get the root HKEY | |
749 std::wstring key_name(full_key_name); | |
750 HKEY h_key = GetRootKeyInfo(&key_name); | |
751 | |
752 if (h_key != NULL) { | |
753 RegKey key; | |
754 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ); | |
755 key.Close(); | |
756 return S_OK == hr; | |
757 } | |
758 return false; | |
759 } | |
760 | |
761 // static version of HasValue | |
762 bool RegKey::HasValue(const wchar_t* full_key_name, const wchar_t* value_name) { | |
763 ASSERT(full_key_name != NULL); | |
764 | |
765 bool has_value = false; | |
766 // get the root HKEY | |
767 std::wstring key_name(full_key_name); | |
768 HKEY h_key = GetRootKeyInfo(&key_name); | |
769 | |
770 if (h_key != NULL) { | |
771 RegKey key; | |
772 if (key.Open(h_key, key_name.c_str(), KEY_READ) == S_OK) { | |
773 has_value = key.HasValue(value_name); | |
774 key.Close(); | |
775 } | |
776 } | |
777 return has_value; | |
778 } | |
779 | |
780 HRESULT RegKey::GetValueType(const wchar_t* full_key_name, | |
781 const wchar_t* value_name, | |
782 DWORD* value_type) { | |
783 ASSERT(full_key_name != NULL); | |
784 ASSERT(value_type != NULL); | |
785 | |
786 *value_type = REG_NONE; | |
787 | |
788 std::wstring key_name(full_key_name); | |
789 HKEY h_key = GetRootKeyInfo(&key_name); | |
790 | |
791 RegKey key; | |
792 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ); | |
793 if (SUCCEEDED(hr)) { | |
794 LONG res = ::SHQueryValueEx(key.h_key_, value_name, NULL, value_type, | |
795 NULL, NULL); | |
796 if (res != ERROR_SUCCESS) { | |
797 hr = HRESULT_FROM_WIN32(res); | |
798 } | |
799 } | |
800 | |
801 return hr; | |
802 } | |
803 | |
804 HRESULT RegKey::DeleteKey(const wchar_t* full_key_name) { | |
805 ASSERT(full_key_name != NULL); | |
806 | |
807 return DeleteKey(full_key_name, true); | |
808 } | |
809 | |
810 HRESULT RegKey::DeleteKey(const wchar_t* full_key_name, bool recursively) { | |
811 ASSERT(full_key_name != NULL); | |
812 | |
813 // need to open the parent key first | |
814 // get the root HKEY | |
815 std::wstring key_name(full_key_name); | |
816 HKEY h_key = GetRootKeyInfo(&key_name); | |
817 | |
818 // get the parent key | |
819 std::wstring parent_key(GetParentKeyInfo(&key_name)); | |
820 | |
821 RegKey key; | |
822 HRESULT hr = key.Open(h_key, parent_key.c_str()); | |
823 | |
824 if (hr == S_OK) { | |
825 hr = recursively ? key.RecurseDeleteSubKey(key_name.c_str()) | |
826 : key.DeleteSubKey(key_name.c_str()); | |
827 } else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || | |
828 hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) { | |
829 hr = S_FALSE; | |
830 } | |
831 | |
832 key.Close(); | |
833 return hr; | |
834 } | |
835 | |
836 HRESULT RegKey::DeleteValue(const wchar_t* full_key_name, | |
837 const wchar_t* value_name) { | |
838 ASSERT(full_key_name != NULL); | |
839 | |
840 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); | |
841 // get the root HKEY | |
842 std::wstring key_name(full_key_name); | |
843 HKEY h_key = GetRootKeyInfo(&key_name); | |
844 | |
845 if (h_key != NULL) { | |
846 RegKey key; | |
847 hr = key.Open(h_key, key_name.c_str()); | |
848 if (hr == S_OK) { | |
849 hr = key.DeleteValue(value_name); | |
850 key.Close(); | |
851 } | |
852 } | |
853 return hr; | |
854 } | |
855 | |
856 HRESULT RegKey::RecurseDeleteSubKey(const wchar_t* key_name) { | |
857 ASSERT(key_name != NULL); | |
858 | |
859 RegKey key; | |
860 HRESULT hr = key.Open(h_key_, key_name); | |
861 | |
862 if (hr == S_OK) { | |
863 // enumerate all subkeys of this key and recursivelly delete them | |
864 FILETIME time = {0}; | |
865 wchar_t key_name_buf[kMaxKeyNameChars] = {0}; | |
866 DWORD key_name_buf_size = kMaxKeyNameChars; | |
867 while (hr == S_OK && | |
868 ::RegEnumKeyEx(key.h_key_, 0, key_name_buf, &key_name_buf_size, | |
869 NULL, NULL, NULL, &time) == ERROR_SUCCESS) { | |
870 hr = key.RecurseDeleteSubKey(key_name_buf); | |
871 | |
872 // restore the buffer size | |
873 key_name_buf_size = kMaxKeyNameChars; | |
874 } | |
875 // close the top key | |
876 key.Close(); | |
877 } | |
878 | |
879 if (hr == S_OK) { | |
880 // the key has no more children keys | |
881 // delete the key and all of its values | |
882 hr = DeleteSubKey(key_name); | |
883 } | |
884 | |
885 return hr; | |
886 } | |
887 | |
888 HKEY RegKey::GetRootKeyInfo(std::wstring* full_key_name) { | |
889 ASSERT(full_key_name != NULL); | |
890 | |
891 HKEY h_key = NULL; | |
892 // get the root HKEY | |
893 size_t index = full_key_name->find(L'\\'); | |
894 std::wstring root_key; | |
895 | |
896 if (index == -1) { | |
897 root_key = *full_key_name; | |
898 *full_key_name = L""; | |
899 } else { | |
900 root_key = full_key_name->substr(0, index); | |
901 *full_key_name = full_key_name->substr(index + 1, | |
902 full_key_name->length() - index - 1); | |
903 } | |
904 | |
905 for (std::wstring::iterator iter = root_key.begin(); | |
906 iter != root_key.end(); ++iter) { | |
907 *iter = toupper(*iter); | |
908 } | |
909 | |
910 if (!root_key.compare(L"HKLM") || | |
911 !root_key.compare(L"HKEY_LOCAL_MACHINE")) { | |
912 h_key = HKEY_LOCAL_MACHINE; | |
913 } else if (!root_key.compare(L"HKCU") || | |
914 !root_key.compare(L"HKEY_CURRENT_USER")) { | |
915 h_key = HKEY_CURRENT_USER; | |
916 } else if (!root_key.compare(L"HKU") || | |
917 !root_key.compare(L"HKEY_USERS")) { | |
918 h_key = HKEY_USERS; | |
919 } else if (!root_key.compare(L"HKCR") || | |
920 !root_key.compare(L"HKEY_CLASSES_ROOT")) { | |
921 h_key = HKEY_CLASSES_ROOT; | |
922 } | |
923 | |
924 return h_key; | |
925 } | |
926 | |
927 | |
928 // Returns true if this key name is 'safe' for deletion | |
929 // (doesn't specify a key root) | |
930 bool RegKey::SafeKeyNameForDeletion(const wchar_t* key_name) { | |
931 ASSERT(key_name != NULL); | |
932 std::wstring key(key_name); | |
933 | |
934 HKEY root_key = GetRootKeyInfo(&key); | |
935 | |
936 if (!root_key) { | |
937 key = key_name; | |
938 } | |
939 if (key.empty()) { | |
940 return false; | |
941 } | |
942 bool found_subkey = false, backslash_found = false; | |
943 for (size_t i = 0 ; i < key.length() ; ++i) { | |
944 if (key[i] == L'\\') { | |
945 backslash_found = true; | |
946 } else if (backslash_found) { | |
947 found_subkey = true; | |
948 break; | |
949 } | |
950 } | |
951 return (root_key == HKEY_USERS) ? found_subkey : true; | |
952 } | |
953 | |
954 std::wstring RegKey::GetParentKeyInfo(std::wstring* key_name) { | |
955 ASSERT(key_name != NULL); | |
956 | |
957 // get the parent key | |
958 size_t index = key_name->rfind(L'\\'); | |
959 std::wstring parent_key; | |
960 if (index == -1) { | |
961 parent_key = L""; | |
962 } else { | |
963 parent_key = key_name->substr(0, index); | |
964 *key_name = key_name->substr(index + 1, key_name->length() - index - 1); | |
965 } | |
966 | |
967 return parent_key; | |
968 } | |
969 | |
970 // get the number of values for this key | |
971 uint32_t RegKey::GetValueCount() { | |
972 DWORD num_values = 0; | |
973 | |
974 if (ERROR_SUCCESS != ::RegQueryInfoKey( | |
975 h_key_, // key handle | |
976 NULL, // buffer for class name | |
977 NULL, // size of class string | |
978 NULL, // reserved | |
979 NULL, // number of subkeys | |
980 NULL, // longest subkey size | |
981 NULL, // longest class string | |
982 &num_values, // number of values for this key | |
983 NULL, // longest value name | |
984 NULL, // longest value data | |
985 NULL, // security descriptor | |
986 NULL)) { // last write time | |
987 ASSERT(false); | |
988 } | |
989 return num_values; | |
990 } | |
991 | |
992 // Enumerators for the value_names for this key | |
993 | |
994 // Called to get the value name for the given value name index | |
995 // Use GetValueCount() to get the total value_name count for this key | |
996 // Returns failure if no key at the specified index | |
997 HRESULT RegKey::GetValueNameAt(int index, std::wstring* value_name, | |
998 DWORD* type) { | |
999 ASSERT(value_name != NULL); | |
1000 | |
1001 LONG res = ERROR_SUCCESS; | |
1002 wchar_t value_name_buf[kMaxValueNameChars] = {0}; | |
1003 DWORD value_name_buf_size = kMaxValueNameChars; | |
1004 res = ::RegEnumValue(h_key_, index, value_name_buf, &value_name_buf_size, | |
1005 NULL, type, NULL, NULL); | |
1006 | |
1007 if (res == ERROR_SUCCESS) { | |
1008 value_name->assign(value_name_buf); | |
1009 } | |
1010 | |
1011 return HRESULT_FROM_WIN32(res); | |
1012 } | |
1013 | |
1014 uint32_t RegKey::GetSubkeyCount() { | |
1015 // number of values for key | |
1016 DWORD num_subkeys = 0; | |
1017 | |
1018 if (ERROR_SUCCESS != ::RegQueryInfoKey( | |
1019 h_key_, // key handle | |
1020 NULL, // buffer for class name | |
1021 NULL, // size of class string | |
1022 NULL, // reserved | |
1023 &num_subkeys, // number of subkeys | |
1024 NULL, // longest subkey size | |
1025 NULL, // longest class string | |
1026 NULL, // number of values for this key | |
1027 NULL, // longest value name | |
1028 NULL, // longest value data | |
1029 NULL, // security descriptor | |
1030 NULL)) { // last write time | |
1031 ASSERT(false); | |
1032 } | |
1033 return num_subkeys; | |
1034 } | |
1035 | |
1036 HRESULT RegKey::GetSubkeyNameAt(int index, std::wstring* key_name) { | |
1037 ASSERT(key_name != NULL); | |
1038 | |
1039 LONG res = ERROR_SUCCESS; | |
1040 wchar_t key_name_buf[kMaxKeyNameChars] = {0}; | |
1041 DWORD key_name_buf_size = kMaxKeyNameChars; | |
1042 | |
1043 res = ::RegEnumKeyEx(h_key_, index, key_name_buf, &key_name_buf_size, | |
1044 NULL, NULL, NULL, NULL); | |
1045 | |
1046 if (res == ERROR_SUCCESS) { | |
1047 key_name->assign(key_name_buf); | |
1048 } | |
1049 | |
1050 return HRESULT_FROM_WIN32(res); | |
1051 } | |
1052 | |
1053 // Is the key empty: having no sub-keys and values | |
1054 bool RegKey::IsKeyEmpty(const wchar_t* full_key_name) { | |
1055 ASSERT(full_key_name != NULL); | |
1056 | |
1057 bool is_empty = true; | |
1058 | |
1059 // Get the root HKEY | |
1060 std::wstring key_name(full_key_name); | |
1061 HKEY h_key = GetRootKeyInfo(&key_name); | |
1062 | |
1063 // Open the key to check | |
1064 if (h_key != NULL) { | |
1065 RegKey key; | |
1066 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ); | |
1067 if (SUCCEEDED(hr)) { | |
1068 is_empty = key.GetSubkeyCount() == 0 && key.GetValueCount() == 0; | |
1069 key.Close(); | |
1070 } | |
1071 } | |
1072 | |
1073 return is_empty; | |
1074 } | |
1075 | |
1076 bool AdjustCurrentProcessPrivilege(const TCHAR* privilege, bool to_enable) { | |
1077 ASSERT(privilege != NULL); | |
1078 | |
1079 bool ret = false; | |
1080 HANDLE token; | |
1081 if (::OpenProcessToken(::GetCurrentProcess(), | |
1082 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) { | |
1083 LUID luid; | |
1084 memset(&luid, 0, sizeof(luid)); | |
1085 if (::LookupPrivilegeValue(NULL, privilege, &luid)) { | |
1086 TOKEN_PRIVILEGES privs; | |
1087 privs.PrivilegeCount = 1; | |
1088 privs.Privileges[0].Luid = luid; | |
1089 privs.Privileges[0].Attributes = to_enable ? SE_PRIVILEGE_ENABLED : 0; | |
1090 if (::AdjustTokenPrivileges(token, FALSE, &privs, 0, NULL, 0)) { | |
1091 ret = true; | |
1092 } else { | |
1093 LOG_GLE(LS_ERROR) << "AdjustTokenPrivileges failed"; | |
1094 } | |
1095 } else { | |
1096 LOG_GLE(LS_ERROR) << "LookupPrivilegeValue failed"; | |
1097 } | |
1098 CloseHandle(token); | |
1099 } else { | |
1100 LOG_GLE(LS_ERROR) << "OpenProcessToken(GetCurrentProcess) failed"; | |
1101 } | |
1102 | |
1103 return ret; | |
1104 } | |
1105 | |
1106 } // namespace rtc | |
OLD | NEW |