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