Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(929)

Side by Side Diff: base/reg_key.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/reg_key.h ('k') | base/reg_key_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2003-2009 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15 //
16 // Registry configuration wrapers class implementation
17
18 #include <raserror.h>
19 #include "omaha/base/reg_key.h"
20 #include "omaha/base/logging.h"
21 #include "omaha/base/scoped_any.h"
22 #include "omaha/base/scoped_ptr_address.h"
23 #include "omaha/base/static_assert.h"
24 #include "omaha/base/string.h"
25 #include "omaha/base/synchronized.h"
26 #include "omaha/base/system.h"
27 #include "omaha/base/utils.h"
28
29 namespace omaha {
30
31 HRESULT RegKey::Close() {
32 HRESULT hr = S_OK;
33 if (h_key_ != NULL) {
34 LONG res = RegCloseKey(h_key_);
35 hr = HRESULT_FROM_WIN32(res);
36 h_key_ = NULL;
37 }
38 return hr;
39 }
40
41 HRESULT RegKey::Create(HKEY hKeyParent,
42 const TCHAR * key_name,
43 TCHAR * lpszClass,
44 DWORD options,
45 REGSAM sam_desired,
46 LPSECURITY_ATTRIBUTES lpSecAttr,
47 LPDWORD lpdwDisposition) {
48 // lpszClass may be NULL
49 ASSERT1(key_name);
50 ASSERT1(hKeyParent != NULL);
51 DWORD dw;
52 HKEY hKey = NULL;
53 LONG res = ::RegCreateKeyEx(hKeyParent,
54 key_name,
55 0,
56 lpszClass,
57 options,
58 sam_desired,
59 lpSecAttr,
60 &hKey,
61 &dw);
62 HRESULT hr = HRESULT_FROM_WIN32(res);
63
64 if (lpdwDisposition != NULL)
65 *lpdwDisposition = dw;
66 // we have to close the currently opened key
67 // before replacing it with the new one
68 if (hr == S_OK) {
69 hr = Close();
70 ASSERT1(hr == S_OK);
71 h_key_ = hKey;
72 }
73 return hr;
74 }
75
76 HRESULT RegKey::Create(const TCHAR * full_key_name,
77 TCHAR * lpszClass, DWORD options,
78 REGSAM sam_desired,
79 LPSECURITY_ATTRIBUTES lpSecAttr,
80 LPDWORD lpdwDisposition) {
81 // lpszClass may be NULL
82 ASSERT1(full_key_name);
83 CString key_name(full_key_name);
84
85 HKEY parent_key = RegKey::GetRootKeyInfo(&key_name);
86 if (!parent_key) {
87 ASSERT(false, (_T("unable to get root key location %s"), full_key_name));
88 return HRESULT_FROM_WIN32(ERROR_KEY_NOT_FOUND);
89 }
90
91 return Create(parent_key, key_name, lpszClass,
92 options, sam_desired, lpSecAttr, lpdwDisposition);
93 }
94
95 HRESULT RegKey::CreateKeys(const TCHAR* keys_to_create[],
96 DWORD number_of_keys,
97 TCHAR* lpszClass,
98 DWORD options,
99 LPSECURITY_ATTRIBUTES lpSecAttr) {
100 ASSERT1(keys_to_create);
101 ASSERT1(number_of_keys);
102
103 for (DWORD i = 0; i < number_of_keys; i++) {
104 HRESULT hr = CreateKey(keys_to_create[i], lpszClass, options, lpSecAttr);
105 if (FAILED(hr)) {
106 return hr;
107 }
108 }
109
110 return S_OK;
111 }
112
113 HRESULT RegKey::CreateKey(const TCHAR* full_key_name,
114 TCHAR* lpszClass,
115 DWORD options,
116 LPSECURITY_ATTRIBUTES lpSecAttr) {
117 ASSERT1(full_key_name);
118
119 RegKey key;
120 HRESULT hr = key.Create(full_key_name,
121 lpszClass,
122 options,
123 KEY_ALL_ACCESS,
124 lpSecAttr,
125 NULL);
126 if (FAILED(hr)) {
127 UTIL_LOG(L3, (_T("[couldn't create %s reg key]"), full_key_name));
128 return hr;
129 }
130
131 return S_OK;
132 }
133
134 HRESULT RegKey::Open(HKEY hKeyParent,
135 const TCHAR * key_name,
136 REGSAM sam_desired) {
137 ASSERT1(key_name);
138 ASSERT1(hKeyParent != NULL);
139 HKEY hKey = NULL;
140 LONG res = ::RegOpenKeyEx(hKeyParent, key_name, 0, sam_desired, &hKey);
141 HRESULT hr = HRESULT_FROM_WIN32(res);
142
143 // we have to close the currently opened key
144 // before replacing it with the new one
145 if (hr == S_OK) {
146 // close the currently opened key if any
147 hr = Close();
148 ASSERT1(hr == S_OK);
149 h_key_ = hKey;
150 }
151 return hr;
152 }
153
154 HRESULT RegKey::Open(const TCHAR * full_key_name, REGSAM sam_desired) {
155 ASSERT1(full_key_name);
156 CString key_name(full_key_name);
157
158 HKEY parent_key = RegKey::GetRootKeyInfo(&key_name);
159 if (!parent_key) {
160 ASSERT(false, (_T("unable to get root key for %s"), full_key_name));
161 return HRESULT_FROM_WIN32(ERROR_KEY_NOT_FOUND);
162 }
163
164 return Open(parent_key, key_name, sam_desired);
165 }
166
167 // save the key and all of its subkeys and values to a file
168 HRESULT RegKey::Save(const TCHAR* full_key_name, const TCHAR* file_name) {
169 ASSERT1(full_key_name);
170 ASSERT1(file_name);
171
172 CString key_name(full_key_name);
173 HKEY h_key = GetRootKeyInfo(&key_name);
174 if (!h_key) {
175 return E_FAIL;
176 }
177
178 RegKey key;
179 HRESULT hr = key.Open(h_key, key_name, KEY_READ);
180 if (FAILED(hr)) {
181 return hr;
182 }
183
184 System::AdjustPrivilege(SE_BACKUP_NAME, true);
185 LONG res = ::RegSaveKey(key.h_key_, file_name, NULL);
186 System::AdjustPrivilege(SE_BACKUP_NAME, false);
187
188 return HRESULT_FROM_WIN32(res);
189 }
190
191 // restore the key and all of its subkeys and values which are saved into a file
192 HRESULT RegKey::Restore(const TCHAR* full_key_name, const TCHAR* file_name) {
193 ASSERT1(full_key_name);
194 ASSERT1(file_name);
195
196 CString key_name(full_key_name);
197 HKEY h_key = GetRootKeyInfo(&key_name);
198 if (!h_key) {
199 return E_FAIL;
200 }
201
202 RegKey key;
203 HRESULT hr = key.Open(h_key, key_name, KEY_WRITE);
204 if (FAILED(hr)) {
205 return hr;
206 }
207
208 System::AdjustPrivilege(SE_RESTORE_NAME, true);
209 LONG res = ::RegRestoreKey(key.h_key_, file_name, REG_FORCE_RESTORE);
210 System::AdjustPrivilege(SE_RESTORE_NAME, false);
211
212 return HRESULT_FROM_WIN32(res);
213 }
214
215 // check if the current key has the specified subkey
216 bool RegKey::HasSubkey(const TCHAR * key_name) const {
217 ASSERT1(key_name);
218 ASSERT1(h_key_);
219
220 RegKey key;
221 HRESULT hr = key.Open(h_key_, key_name, KEY_READ);
222 key.Close();
223 return S_OK == hr;
224 }
225
226 // static flush key
227 HRESULT RegKey::FlushKey(const TCHAR * full_key_name) {
228 ASSERT1(full_key_name);
229
230 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
231 // get the root HKEY
232 CString key_name(full_key_name);
233 HKEY h_key = GetRootKeyInfo(&key_name);
234
235 if (h_key != NULL) {
236 LONG res = RegFlushKey(h_key);
237 hr = HRESULT_FROM_WIN32(res);
238 }
239 return hr;
240 }
241
242 // static SET helper
243 HRESULT RegKey::SetValueStaticHelper(const TCHAR * full_key_name,
244 const TCHAR * value_name,
245 DWORD type,
246 LPVOID value,
247 DWORD byte_count) {
248 // value_name may be NULL
249 ASSERT1(full_key_name);
250
251 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
252 // get the root HKEY
253 CString key_name(full_key_name);
254 HKEY h_key = GetRootKeyInfo(&key_name);
255
256 if (h_key != NULL) {
257 RegKey key;
258 hr = key.Create(h_key, key_name.GetString());
259 if (hr == S_OK) {
260 switch (type) {
261 case REG_DWORD:
262 hr = key.SetValue(value_name, *reinterpret_cast<DWORD *>(value));
263 if (SUCCEEDED(hr)) {
264 UTIL_LOG(L6, (_T("[Wrote int32 value: %s:%s = %d]"),
265 full_key_name,
266 value_name,
267 *reinterpret_cast<DWORD*>(value)));
268 }
269 break;
270 case REG_QWORD:
271 hr = key.SetValue(value_name, *reinterpret_cast<DWORD64 *>(value));
272 if (SUCCEEDED(hr)) {
273 UTIL_LOG(L6, (_T("[Wrote int64 value: %s:%s = %s]"),
274 full_key_name,
275 value_name,
276 String_Int64ToString(
277 *reinterpret_cast<DWORD64*>(value), 10)));
278 }
279 break;
280 case REG_SZ:
281 hr = key.SetValue(value_name, reinterpret_cast<const TCHAR *>(value));
282 if (SUCCEEDED(hr)) {
283 UTIL_LOG(L6, (_T("[Wrote string value: %s:%s = %s]"),
284 full_key_name,
285 value_name,
286 reinterpret_cast<const TCHAR *>(value)));
287 }
288 break;
289 case REG_BINARY:
290 hr = key.SetValue(value_name,
291 reinterpret_cast<const byte *>(value),
292 byte_count);
293 if (SUCCEEDED(hr)) {
294 UTIL_LOG(L6, (_T("[Wrote binary value: %s:%s, len = %d]"),
295 full_key_name, value_name, byte_count));
296 }
297 break;
298 case REG_MULTI_SZ:
299 hr = key.SetValue(value_name,
300 reinterpret_cast<const byte *>(value),
301 byte_count,
302 type);
303 if (SUCCEEDED(hr)) {
304 UTIL_LOG(L6, (_T("[Wrote multi-sz value: %s:%s, len = %d]"),
305 full_key_name, value_name, byte_count));
306 }
307 break;
308 case REG_EXPAND_SZ:
309 hr = key.SetStringValue(value_name,
310 reinterpret_cast<const TCHAR *>(value),
311 type);
312 if (SUCCEEDED(hr)) {
313 UTIL_LOG(L6, (_T("[Wrote expandable string value: %s:%s = %s]"),
314 full_key_name, value_name, (const TCHAR *)value));
315 }
316 break;
317 default:
318 ASSERT(false, (_T("Unsupported Registry Type")));
319 hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
320 break;
321 }
322 // close the key after writing
323 HRESULT temp_res = key.Close();
324 if (hr == S_OK) {
325 hr = temp_res;
326 } else {
327 ASSERT(false, (_T("Failed to write reg value: %s:%s (hr=0x%x)"),
328 full_key_name, value_name, hr));
329 }
330 } else {
331 UTIL_LOG(L3, (_T("[Failed to create reg key: %s]"), full_key_name));
332 }
333 }
334 return hr;
335 }
336
337 // static GET helper
338 // byte_count may be NULL.
339 // value_name may be NULL.
340 HRESULT RegKey::GetValueStaticHelper(const TCHAR * full_key_name,
341 const TCHAR * value_name,
342 DWORD type,
343 LPVOID value,
344 DWORD * byte_count) {
345 ASSERT1(full_key_name);
346
347 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
348 // get the root HKEY
349 CString key_name(full_key_name);
350 HKEY h_key = GetRootKeyInfo(&key_name);
351
352 if (h_key != NULL) {
353 RegKey key;
354 hr = key.Open(h_key, key_name.GetString(), KEY_READ);
355 if (hr == S_OK) {
356 switch (type) {
357 case REG_DWORD:
358 hr = key.GetValue(value_name, reinterpret_cast<DWORD *>(value));
359 if (SUCCEEDED(hr)) {
360 UTIL_LOG(L6, (_T("[Read int32 value: %s:%s = %d]"),
361 full_key_name,
362 value_name,
363 *reinterpret_cast<DWORD*>(value)));
364 }
365 break;
366 case REG_QWORD:
367 hr = key.GetValue(value_name, reinterpret_cast<DWORD64 *>(value));
368 if (SUCCEEDED(hr)) {
369 UTIL_LOG(L6, (_T("[Read int64 value: %s:%s = %s]"),
370 full_key_name,
371 value_name,
372 String_Int64ToString(
373 *(reinterpret_cast<DWORD64*>(value)), 10)));
374 }
375 break;
376 case REG_SZ:
377 hr = key.GetValue(value_name, reinterpret_cast<TCHAR * *>(value));
378 if (SUCCEEDED(hr)) {
379 UTIL_LOG(L6, (_T("[Read string value: %s:%s = %s]"),
380 full_key_name,
381 value_name,
382 *reinterpret_cast<TCHAR * *>(value)));
383 }
384 break;
385 case REG_MULTI_SZ:
386 hr = key.GetValue(value_name,
387 reinterpret_cast<std::vector<CString> *>(value));
388 if (SUCCEEDED(hr)) {
389 UTIL_LOG(L6, (_T("[Read multi string value: %s:%s = %d]"),
390 full_key_name,
391 value_name,
392 reinterpret_cast<std::vector<CString>*>(value)->size()));
393 }
394 break;
395 case REG_BINARY:
396 hr = key.GetValue(value_name,
397 reinterpret_cast<byte * *>(value),
398 byte_count);
399 if (SUCCEEDED(hr)) {
400 UTIL_LOG(L6, (_T("[Read binary value: %s:%s, len = %d]"),
401 full_key_name, value_name, byte_count));
402 }
403 break;
404 default:
405 ASSERT(false, (_T("Unsupported Registry Type")));
406 hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
407 break;
408 }
409 // close the key after writing
410 HRESULT temp_res = key.Close();
411 if (hr == S_OK) {
412 hr = temp_res;
413 } else {
414 UTIL_LOG(L5, (_T("[Failed to read reg value: %s:%s]"),
415 full_key_name, value_name));
416 }
417 } else {
418 UTIL_LOG(L5, (_T("[reg value does not exist: %s]"), key_name));
419 }
420 }
421 return hr;
422 }
423
424 // GET helper
425 // value_name may be NULL.
426 HRESULT RegKey::GetValueHelper(const TCHAR * value_name,
427 DWORD * type,
428 byte * * value,
429 DWORD * byte_count) const {
430 ASSERT1(byte_count);
431 ASSERT1(value);
432 ASSERT1(type);
433 ASSERT1(h_key_);
434
435 // init return buffer
436 *value = NULL;
437
438 // get the size of the return data buffer
439 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, type, NULL, byte_count);
440 HRESULT hr = HRESULT_FROM_WIN32(res);
441
442 if (hr == S_OK) {
443 // if the value length is 0, nothing to do
444 if (*byte_count != 0) {
445 // allocate the buffer
446 *value = new byte[*byte_count];
447 ASSERT1(*value);
448
449 // make the call again to get the data
450 res = ::SHQueryValueEx(h_key_,
451 value_name,
452 NULL,
453 type,
454 *value,
455 byte_count);
456 hr = HRESULT_FROM_WIN32(res);
457 ASSERT1(S_OK == hr);
458 }
459 }
460 return hr;
461 }
462
463 // value_name may be NULL
464 HRESULT RegKey::GetValueType(const TCHAR* value_name,
465 DWORD* value_type) const {
466 ASSERT1(value_type);
467
468 *value_type = REG_NONE;
469
470 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, value_type, NULL, NULL);
471 if (res != ERROR_SUCCESS) {
472 return HRESULT_FROM_WIN32(res);
473 }
474
475 return S_OK;
476 }
477
478 // Int32 Get
479 // value_name may be NULL.
480 HRESULT RegKey::GetValue(const TCHAR * value_name, DWORD * value) const {
481 ASSERT1(value);
482 ASSERT1(h_key_);
483
484 DWORD type = 0;
485 DWORD byte_count = sizeof(DWORD);
486 LONG res = ::SHQueryValueEx(h_key_,
487 value_name,
488 NULL,
489 &type,
490 reinterpret_cast<byte*>(value),
491 &byte_count);
492 HRESULT hr = HRESULT_FROM_WIN32(res);
493 ASSERT1((hr != S_OK) || (type == REG_DWORD));
494 ASSERT1((hr != S_OK) || (byte_count == sizeof(DWORD)));
495 return hr;
496 }
497
498 // Int64 Get
499 // value_name may be NULL.
500 HRESULT RegKey::GetValue(const TCHAR * value_name, DWORD64 * value) const {
501 ASSERT1(value);
502 ASSERT1(h_key_);
503
504 DWORD type = 0;
505 DWORD byte_count = sizeof(DWORD64);
506 LONG res = ::SHQueryValueEx(h_key_,
507 value_name,
508 NULL,
509 &type,
510 reinterpret_cast<byte *>(value),
511 &byte_count);
512 HRESULT hr = HRESULT_FROM_WIN32(res);
513 ASSERT1((hr != S_OK) || (type == REG_QWORD));
514 ASSERT1((hr != S_OK) || (byte_count == sizeof(DWORD64)));
515 return hr;
516 }
517
518 // String Get
519 // value_name may be NULL.
520 HRESULT RegKey::GetValue(const TCHAR * value_name, TCHAR * * value) const {
521 ASSERT1(value);
522 ASSERT1(h_key_);
523
524 DWORD byte_count = 0;
525 DWORD type = 0;
526
527 // first get the size of the string buffer
528 LONG res = ::SHQueryValueEx(h_key_,
529 value_name,
530 NULL,
531 &type,
532 NULL,
533 &byte_count);
534 HRESULT hr = HRESULT_FROM_WIN32(res);
535
536 if (hr == S_OK) {
537 // allocate room for the string and a terminating \0
538 *value = new TCHAR[(byte_count / sizeof(TCHAR)) + 1];
539
540 if ((*value) != NULL) {
541 if (byte_count != 0) {
542 // make the call again
543 res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
544 reinterpret_cast<byte*>(*value), &byte_count);
545 hr = HRESULT_FROM_WIN32(res);
546 } else {
547 (*value)[0] = _T('\0');
548 }
549
550 ASSERT1((hr != S_OK) || (type == REG_SZ) ||
551 (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
552 } else {
553 hr = E_OUTOFMEMORY;
554 }
555 }
556
557 return hr;
558 }
559
560 // CString Get
561 // value_name may be NULL.
562 HRESULT RegKey::GetValue(const TCHAR* value_name, OUT CString* value) const {
563 ASSERT1(value);
564 ASSERT1(h_key_);
565
566 DWORD byte_count = 0;
567 DWORD type = 0;
568
569 // first get the size of the string buffer
570 LONG res = ::SHQueryValueEx(h_key_,
571 value_name,
572 NULL,
573 &type,
574 NULL,
575 &byte_count);
576 HRESULT hr = HRESULT_FROM_WIN32(res);
577
578 if (hr == S_OK) {
579 if (byte_count != 0) {
580 // Allocate some memory and make the call again
581 TCHAR* buffer = value->GetBuffer(byte_count / sizeof(TCHAR) + 1);
582 if (buffer == NULL) {
583 hr = E_OUTOFMEMORY;
584 } else {
585 res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
586 reinterpret_cast<byte*>(buffer), &byte_count);
587 hr = HRESULT_FROM_WIN32(res);
588 }
589 value->ReleaseBuffer();
590 } else {
591 value->Empty();
592 }
593
594 ASSERT1((hr != S_OK) || (type == REG_SZ) ||
595 (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
596 }
597
598 return hr;
599 }
600
601 // convert REG_MULTI_SZ bytes to string array
602 HRESULT RegKey::MultiSZBytesToStringArray(const byte * buffer,
603 DWORD byte_count,
604 std::vector<CString> * value) {
605 ASSERT1(buffer);
606 ASSERT1(value);
607
608 const TCHAR* data = reinterpret_cast<const TCHAR*>(buffer);
609 DWORD data_len = byte_count / sizeof(TCHAR);
610 value->clear();
611 if (data_len > 1) {
612 // must be terminated by two null characters
613 if (data[data_len - 1] != 0 || data[data_len - 2] != 0) {
614 return E_INVALIDARG;
615 }
616
617 // put null-terminated strings into arrays
618 while (*data) {
619 CString str(data);
620 value->push_back(str);
621 data += str.GetLength() + 1;
622 }
623 }
624 return S_OK;
625 }
626
627 // get a vector<CString> value from REG_MULTI_SZ type
628 HRESULT RegKey::GetValue(const TCHAR * value_name,
629 std::vector<CString> * value) const {
630 ASSERT1(value);
631 // value_name may be NULL
632
633 DWORD byte_count = 0;
634 DWORD type = 0;
635 byte* buffer = 0;
636
637 // first get the size of the buffer
638 HRESULT hr = GetValueHelper(value_name, &type, &buffer, &byte_count);
639 ASSERT1((hr != S_OK) || (type == REG_MULTI_SZ));
640
641 if (SUCCEEDED(hr)) {
642 hr = MultiSZBytesToStringArray(buffer, byte_count, value);
643 }
644
645 return hr;
646 }
647
648 // Binary data Get
649 HRESULT RegKey::GetValue(const TCHAR * value_name,
650 byte * * value,
651 DWORD * byte_count) const {
652 ASSERT1(byte_count);
653 ASSERT1(value);
654 // value_name may be NULL
655
656 DWORD type = 0;
657 HRESULT hr = GetValueHelper(value_name, &type, value, byte_count);
658 ASSERT1((hr != S_OK) || (type == REG_MULTI_SZ) || (type == REG_BINARY));
659 return hr;
660 }
661
662 // Raw data get
663 HRESULT RegKey::GetValue(const TCHAR * value_name,
664 byte * * value,
665 DWORD * byte_count,
666 DWORD *type) const {
667 ASSERT1(type);
668 ASSERT1(byte_count);
669 ASSERT1(value);
670
671 return GetValueHelper(value_name, type, value, byte_count);
672 }
673
674 // Int32 set
675 // value_name may be NULL
676 HRESULT RegKey::SetValue(const TCHAR * value_name, DWORD value) const {
677 ASSERT1(h_key_);
678 LONG res = RegSetValueEx(h_key_,
679 value_name,
680 NULL,
681 REG_DWORD,
682 reinterpret_cast<byte *>(&value),
683 sizeof(DWORD));
684 return HRESULT_FROM_WIN32(res);
685 }
686
687 // Int64 set
688 // value_name may be NULL
689 HRESULT RegKey::SetValue(const TCHAR * value_name, DWORD64 value) const {
690 ASSERT1(h_key_);
691 LONG res = RegSetValueEx(h_key_,
692 value_name,
693 NULL,
694 REG_QWORD,
695 reinterpret_cast<byte *>(&value),
696 sizeof(DWORD64));
697 return HRESULT_FROM_WIN32(res);
698 }
699
700 // String set
701 HRESULT RegKey::SetValue(const TCHAR * value_name, const TCHAR * value) const {
702 return SetStringValue(value_name, value, REG_SZ);
703 }
704
705 // String set helper
706 // value_name may be NULL.
707 HRESULT RegKey::SetStringValue(const TCHAR * value_name,
708 const TCHAR * value,
709 DWORD type) const {
710 ASSERT1(value);
711 ASSERT1(h_key_);
712 ASSERT1(type == REG_SZ || type == REG_EXPAND_SZ);
713 LONG res = RegSetValueEx(h_key_,
714 value_name,
715 NULL,
716 type,
717 reinterpret_cast<const byte *>(value),
718 (lstrlen(value) + 1) * sizeof(TCHAR));
719 return HRESULT_FROM_WIN32(res);
720 }
721
722 // Binary data set
723 // value may be NULL.
724 // value_name may be NULL.
725 HRESULT RegKey::SetValue(const TCHAR * value_name,
726 const byte * value,
727 DWORD byte_count) const {
728 ASSERT1(h_key_);
729
730 // special case - if 'value' is NULL make sure byte_count is zero
731 if (value == NULL) {
732 byte_count = 0;
733 }
734
735 LONG res = RegSetValueEx(h_key_,
736 value_name,
737 NULL,
738 REG_BINARY,
739 value,
740 byte_count);
741 return HRESULT_FROM_WIN32(res);
742 }
743
744 // Raw data set
745 // value_name may be NULL.
746 HRESULT RegKey::SetValue(const TCHAR * value_name,
747 const byte * value,
748 DWORD byte_count,
749 DWORD type) const {
750 ASSERT1(value);
751 ASSERT1(h_key_);
752 LONG res = RegSetValueEx(h_key_, value_name, NULL, type, value, byte_count);
753 return HRESULT_FROM_WIN32(res);
754 }
755
756 HRESULT RegKey::RenameValue(const TCHAR* old_value_name,
757 const TCHAR* new_value_name) const {
758 ASSERT1(h_key_);
759 ASSERT1(new_value_name);
760 ASSERT1(old_value_name);
761
762 scoped_ptr<byte> value;
763 DWORD byte_count = 0;
764 DWORD type = 0;
765
766 HRESULT hr = GetValue(old_value_name, address(value), &byte_count, &type);
767 if (FAILED(hr)) {
768 return hr;
769 }
770
771 hr = SetValue(new_value_name, value.get(), byte_count, type);
772 if (FAILED(hr)) {
773 return hr;
774 }
775
776 VERIFY1(SUCCEEDED(DeleteValue(old_value_name)));
777 return S_OK;
778 }
779
780 bool RegKey::HasKey(const TCHAR * full_key_name) {
781 return HasKeyHelper(full_key_name, KEY_READ);
782 }
783
784 bool RegKey::HasNativeKey(const TCHAR * full_key_name) {
785 return HasKeyHelper(full_key_name, KEY_READ | KEY_WOW64_64KEY);
786 }
787
788 bool RegKey::HasKeyHelper(const TCHAR * full_key_name, DWORD sam_flags) {
789 ASSERT1(full_key_name);
790 ASSERT1(sam_flags & KEY_READ);
791
792 // get the root HKEY
793 CString key_name(full_key_name);
794 HKEY h_key = GetRootKeyInfo(&key_name);
795
796 if (h_key != NULL) {
797 RegKey key;
798 HRESULT hr = key.Open(h_key, key_name.GetString(), sam_flags);
799 key.Close();
800 return S_OK == hr;
801 }
802 return false;
803 }
804
805 HRESULT RegKey::CopyValue(const TCHAR * full_from_key_name,
806 const TCHAR * from_value_name,
807 const TCHAR * full_to_key_name,
808 const TCHAR * to_value_name) {
809 ASSERT1(full_from_key_name);
810 ASSERT1(full_to_key_name);
811
812 RegKey from_reg_key;
813 HRESULT hr = from_reg_key.Open(full_from_key_name, KEY_READ);
814 if (FAILED(hr)) {
815 return hr;
816 }
817
818 scoped_ptr<byte> val;
819 DWORD byte_count = 0;
820 DWORD type = 0;
821 hr = from_reg_key.GetValue(from_value_name, address(val), &byte_count, &type);
822 if (FAILED(hr)) {
823 return hr;
824 }
825
826 RegKey to_reg_key;
827 hr = to_reg_key.Open(full_to_key_name, KEY_WRITE);
828 if (FAILED(hr)) {
829 return hr;
830 }
831
832 return to_reg_key.SetValue(to_value_name, val.get(), byte_count, type);
833 }
834
835 // static version of HasValue
836 bool RegKey::HasValue(const TCHAR * full_key_name, const TCHAR * value_name) {
837 ASSERT1(full_key_name);
838
839 bool has_value = false;
840 // get the root HKEY
841 CString key_name(full_key_name);
842 HKEY h_key = GetRootKeyInfo(&key_name);
843
844 if (h_key != NULL) {
845 RegKey key;
846 if (key.Open(h_key, key_name.GetString(), KEY_READ) == S_OK) {
847 has_value = key.HasValue(value_name);
848 key.Close();
849 }
850 }
851 return has_value;
852 }
853
854 HRESULT RegKey::GetValueType(const TCHAR* full_key_name,
855 const TCHAR* value_name,
856 DWORD* value_type) {
857 ASSERT1(full_key_name);
858 // value_name may be NULL
859 ASSERT1(value_type);
860
861 *value_type = REG_NONE;
862
863 CString key_name(full_key_name);
864 HKEY root_key = GetRootKeyInfo(&key_name);
865
866 RegKey key;
867 HRESULT hr = key.Open(root_key, key_name, KEY_READ);
868 if (FAILED(hr)) {
869 return hr;
870 }
871 return key.GetValueType(value_name, value_type);
872 }
873
874 HRESULT RegKey::DeleteKey(const TCHAR* full_key_name) {
875 ASSERT1(full_key_name);
876
877 return DeleteKey(full_key_name, true);
878 }
879
880 HRESULT RegKey::DeleteKey(const TCHAR* full_key_name, bool recursively) {
881 ASSERT1(full_key_name);
882
883 // need to open the parent key first
884 // get the root HKEY
885 CString key_name(full_key_name);
886 HKEY h_key = GetRootKeyInfo(&key_name);
887
888 // get the parent key
889 CString parent_key(GetParentKeyInfo(&key_name));
890
891 RegKey key;
892 HRESULT hr = key.Open(h_key, parent_key);
893
894 if (hr == S_OK) {
895 hr = recursively ? key.RecurseDeleteSubKey(key_name) :
896 key.DeleteSubKey(key_name);
897 } else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
898 hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
899 hr = S_FALSE;
900 }
901
902 key.Close();
903 return hr;
904 }
905
906 HRESULT RegKey::DeleteValue(const TCHAR * full_key_name,
907 const TCHAR * value_name) {
908 ASSERT1(value_name);
909 ASSERT1(full_key_name);
910
911 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
912 // get the root HKEY
913 CString key_name(full_key_name);
914 HKEY h_key = GetRootKeyInfo(&key_name);
915
916 if (h_key != NULL) {
917 RegKey key;
918 hr = key.Open(h_key, key_name.GetString());
919 if (hr == S_OK) {
920 hr = key.DeleteValue(value_name);
921 key.Close();
922 }
923 }
924 return hr;
925 }
926
927 HRESULT RegKey::RecurseDeleteSubKey(const TCHAR * key_name) {
928 ASSERT1(key_name);
929 ASSERT1(h_key_);
930
931 RegKey key;
932 HRESULT hr = key.Open(h_key_, key_name);
933 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
934 hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
935 hr = S_FALSE;
936 }
937 if (hr != S_OK) {
938 return hr;
939 }
940
941 // enumerate all subkeys of this key
942 // and recursivelly delete them
943 FILETIME time;
944 TCHAR key_name_buf[kMaxKeyNameChars];
945 DWORD key_name_buf_size = kMaxKeyNameChars;
946 while (RegEnumKeyEx(key.h_key_,
947 0,
948 key_name_buf,
949 &key_name_buf_size,
950 NULL,
951 NULL,
952 NULL,
953 &time) == ERROR_SUCCESS) {
954 hr = key.RecurseDeleteSubKey(key_name_buf);
955 // return if error deleting key
956 if (hr != S_OK)
957 return hr;
958 // restore the buffer size
959 key_name_buf_size = kMaxKeyNameChars;
960 }
961 // close the top key
962 key.Close();
963
964 // the key has no more children keys
965 // delete the key and all of its values
966 return DeleteSubKey(key_name);
967 }
968
969 HKEY RegKey::GetRootKeyInfo(CString * full_key_name) {
970 ASSERT1(full_key_name);
971
972 HKEY h_key = NULL;
973 // get the root HKEY
974 int index = String_FindChar(*(full_key_name), '\\');
975 CString root_key;
976
977 if (index == -1) {
978 root_key = *full_key_name;
979 *full_key_name = _T("");
980 } else {
981 root_key= full_key_name->Left(index);
982 *full_key_name =
983 full_key_name->Right(full_key_name->GetLength() - index - 1);
984 }
985
986 if (!root_key.CompareNoCase(_T("HKLM")) ||
987 !root_key.CompareNoCase(_T("HKEY_LOCAL_MACHINE")))
988 h_key = HKEY_LOCAL_MACHINE;
989 else if (!root_key.CompareNoCase(_T("HKCU")) ||
990 !root_key.CompareNoCase(_T("HKEY_CURRENT_USER")))
991 h_key = HKEY_CURRENT_USER;
992 else if (!root_key.CompareNoCase(_T("HKU")) ||
993 !root_key.CompareNoCase(_T("HKEY_USERS")))
994 h_key = HKEY_USERS;
995 else if (!root_key.CompareNoCase(_T("HKCR")) ||
996 !root_key.CompareNoCase(_T("HKEY_CLASSES_ROOT")))
997 h_key = HKEY_CLASSES_ROOT;
998
999 return h_key;
1000 }
1001
1002
1003 // Returns true if this key name is 'safe' for deletion (doesn't specify a
1004 // key root)
1005 bool RegKey::SafeKeyNameForDeletion(const wchar_t *key_name) {
1006 ASSERT1(key_name);
1007 CString key(key_name);
1008
1009 HKEY root_key = GetRootKeyInfo(&key);
1010
1011 if ( !root_key ) {
1012 key = key_name;
1013 }
1014 if ( key.IsEmpty() ) {
1015 return false;
1016 }
1017 bool found_subkey = false, backslash_found = false;
1018 for (int i = 0 ; i < key.GetLength() ; ++i) {
1019 if ( key[i] == L'\\' ) {
1020 backslash_found = true;
1021 } else if ( backslash_found ) {
1022 found_subkey = true;
1023 break;
1024 }
1025 }
1026 return ( root_key == HKEY_USERS ) ? found_subkey : true;
1027 }
1028
1029 CString RegKey::GetParentKeyInfo(CString * key_name) {
1030 ASSERT1(key_name);
1031
1032 // get the parent key
1033 int index = key_name->ReverseFind('\\');
1034 CString parent_key;
1035 if (index == -1) {
1036 parent_key = _T("");
1037 } else {
1038 parent_key = key_name->Left(index);
1039 *key_name = key_name->Right(key_name->GetLength() - index - 1);
1040 }
1041
1042 return parent_key;
1043 }
1044
1045 // get the number of values for this key
1046 uint32 RegKey::GetValueCount() {
1047 ASSERT1(h_key_);
1048 // number of values for key
1049 DWORD num_values = 0;
1050
1051 LONG res = ::RegQueryInfoKey(h_key_, // key handle
1052 NULL, // buffer for class name
1053 NULL, // size of class string
1054 NULL, // reserved
1055 NULL, // number of subkeys
1056 NULL, // longest subkey size
1057 NULL, // longest class string
1058 &num_values, // number of values for this key
1059 NULL, // longest value name
1060 NULL, // longest value data
1061 NULL, // security descriptor
1062 NULL); // last write time
1063
1064 ASSERT1(res == ERROR_SUCCESS);
1065 return num_values;
1066 }
1067
1068 // Enumerators for the value_names for this key
1069
1070 // Called to get the value name for the given value name index
1071 // Use GetValueCount() to get the total value_name count for this key
1072 // Returns failure if no key at the specified index
1073 // type may be NULL.
1074 HRESULT RegKey::GetValueNameAt(int index, CString *value_name, DWORD *type) {
1075 ASSERT1(value_name);
1076 ASSERT1(h_key_);
1077
1078 LONG res = ERROR_SUCCESS;
1079 TCHAR value_name_buf[kMaxValueNameChars];
1080 DWORD value_name_buf_size = kMaxValueNameChars;
1081 res = ::RegEnumValue(h_key_,
1082 index,
1083 value_name_buf,
1084 &value_name_buf_size,
1085 NULL,
1086 type,
1087 NULL,
1088 NULL);
1089
1090 if (res == ERROR_SUCCESS) {
1091 value_name->SetString(value_name_buf);
1092 }
1093
1094 return HRESULT_FROM_WIN32(res);
1095 }
1096
1097 uint32 RegKey::GetSubkeyCount() {
1098 ASSERT1(h_key_);
1099
1100 DWORD num_subkeys = 0; // number of values for key
1101
1102 LONG res = ::RegQueryInfoKey(h_key_, // key handle
1103 NULL, // buffer for class name
1104 NULL, // size of class string
1105 NULL, // reserved
1106 &num_subkeys, // number of subkeys
1107 NULL, // longest subkey size
1108 NULL, // longest class string
1109 NULL, // number of values for this key
1110 NULL, // longest value name
1111 NULL, // longest value data
1112 NULL, // security descriptor
1113 NULL); // last write time
1114
1115 ASSERT1(res == ERROR_SUCCESS);
1116 return num_subkeys;
1117 }
1118
1119 HRESULT RegKey::GetSubkeyNameAt(int index, CString * key_name) {
1120 ASSERT1(key_name);
1121 ASSERT1(h_key_);
1122
1123 LONG res = ERROR_SUCCESS;
1124 TCHAR key_name_buf[kMaxKeyNameChars];
1125 DWORD key_name_buf_size = kMaxKeyNameChars;
1126
1127 res = ::RegEnumKeyEx(h_key_,
1128 index,
1129 key_name_buf,
1130 &key_name_buf_size,
1131 NULL,
1132 NULL,
1133 NULL,
1134 NULL);
1135
1136 if (res == ERROR_SUCCESS) {
1137 key_name->SetString(key_name_buf);
1138 }
1139
1140 return HRESULT_FROM_WIN32(res);
1141 }
1142
1143 // Is the key empty: having no sub-keys and values
1144 bool RegKey::IsKeyEmpty(const TCHAR* full_key_name) {
1145 ASSERT1(full_key_name);
1146
1147 bool is_empty = true;
1148
1149 // Get the root HKEY
1150 CString key_name(full_key_name);
1151 HKEY h_key = GetRootKeyInfo(&key_name);
1152
1153 // Open the key to check
1154 if (h_key != NULL) {
1155 RegKey key;
1156 HRESULT hr = key.Open(h_key, key_name.GetString(), KEY_READ);
1157 if (SUCCEEDED(hr)) {
1158 is_empty = key.GetSubkeyCount() == 0 && key.GetValueCount() == 0;
1159 key.Close();
1160 }
1161 }
1162
1163 return is_empty;
1164 }
1165
1166 // close this reg key and the event
1167 HRESULT RegKeyWithChangeEvent::Close() {
1168 reset(change_event_);
1169 return RegKey::Close();
1170 }
1171
1172 // Called to create/reset the event that gets signaled
1173 // any time the registry key changes
1174 // Note:
1175 // * reg key should have been opened using KEY_NOTIFY for the sam_desired
1176 //
1177 // See the documentation for RegNotifyChangeKeyValue
1178 // for values for notify_filter.
1179 HRESULT RegKeyWithChangeEvent::SetupEvent(bool watch_subtree,
1180 DWORD notify_filter) {
1181 // If the event exists, then it should be in the signaled state
1182 // indicating a registry change took place. If not, then
1183 // the caller is setting up the event a second time and this
1184 // will create a memory leak.
1185 ASSERT(!valid(change_event_) || HasChangeOccurred(),
1186 (_T("Event is getting set-up for a second ")
1187 _T("time without being signaled.")));
1188
1189 if (!valid(change_event_)) {
1190 reset(change_event_, ::CreateEvent(NULL, TRUE, FALSE, NULL));
1191 if (!valid(change_event_)) {
1192 ASSERT(false, (_T("create event failed")));
1193 return HRESULT_FROM_WIN32(::GetLastError());
1194 }
1195 } else {
1196 if (!::ResetEvent(get(change_event_))) {
1197 ASSERT(false, (_T("reset event failed")));
1198 return HRESULT_FROM_WIN32(::GetLastError());
1199 }
1200 }
1201
1202 LONG res = ::RegNotifyChangeKeyValue(Key(), watch_subtree, notify_filter,
1203 get(change_event_), TRUE);
1204
1205 if (res != ERROR_SUCCESS) {
1206 // You may get this failure if you didn't pass in KEY_NOTIFY
1207 // as part of the sam_desired flags during Open or Create
1208 ASSERT(false, (_T("setting up change notification for a reg key failed")));
1209
1210 // Leave the event around so that it never changes once it has been set-up
1211 // but in this case it will not get signaled again.
1212 }
1213
1214 return HRESULT_FROM_WIN32(res);
1215 }
1216
1217 // Indicates if any changes (that are being monitored have occured)
1218 bool RegKeyWithChangeEvent::HasChangeOccurred() const {
1219 return IsHandleSignaled(get(change_event_));
1220 }
1221
1222
1223 RegKeyWatcher::RegKeyWatcher(const TCHAR* reg_key, bool watch_subtree,
1224 DWORD notify_filter, bool allow_creation)
1225 : reg_key_string_(reg_key),
1226 watch_subtree_(watch_subtree),
1227 notify_filter_(notify_filter),
1228 allow_creation_(allow_creation) {
1229 UTIL_LOG(L3, (_T("[RegKeyWatcher::RegKeyWatcher][%s]"), reg_key));
1230 }
1231
1232 HRESULT RegKeyWatcher::EnsureEventSetup() {
1233 UTIL_LOG(L3, (_T("[RegKeyWatcher::EnsureEventSetup]")));
1234 if (!reg_key_with_change_event_.get()) {
1235 scoped_ptr<RegKeyWithChangeEvent> local_reg_key(new RegKeyWithChangeEvent);
1236 if (!local_reg_key.get()) {
1237 ASSERT(false, (_T("unable to allocate local_reg_key")));
1238 return E_FAIL;
1239 }
1240
1241 if (allow_creation_ && !RegKey::HasKey(reg_key_string_)) {
1242 RegKey key;
1243 VERIFY1(SUCCEEDED(key.Create(reg_key_string_)));
1244 }
1245
1246 HRESULT hr = local_reg_key->Open(reg_key_string_, KEY_NOTIFY);
1247 if (FAILED(hr)) {
1248 ASSERT(false, (_T("couldn't open %s reg key for notifications. ")
1249 _T("Make sure you have pre-created the key!"),
1250 reg_key_string_));
1251 return hr;
1252 }
1253 reg_key_with_change_event_.reset(local_reg_key.release());
1254 reg_key_string_.Empty();
1255 }
1256
1257 // if the event is set-up and no changes have occurred,
1258 // then there is no need to re-setup the event.
1259 if (reg_key_with_change_event_->change_event() && !HasChangeOccurred()) {
1260 return S_OK;
1261 }
1262
1263 return reg_key_with_change_event_->SetupEvent(watch_subtree_,
1264 notify_filter_);
1265 }
1266
1267 // Get the event that is signaled on registry changes.
1268 HANDLE RegKeyWatcher::change_event() const {
1269 if (!reg_key_with_change_event_.get()) {
1270 ASSERT(false, (_T("call RegKeyWatcher::EnsureEventSetup first")));
1271 return NULL;
1272 }
1273 return reg_key_with_change_event_->change_event();
1274 }
1275
1276 } // namespace omaha
1277
OLDNEW
« no previous file with comments | « base/reg_key.h ('k') | base/reg_key_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698