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

Side by Side Diff: chrome_elf/nt_registry/nt_registry.cc

Issue 1841573002: [Chrome ELF] New NT registry API. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: PRESUBMIT to allow chrome_elf directory files to use wstring. Created 4 years, 5 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 | « chrome_elf/nt_registry/nt_registry.h ('k') | chrome_elf/nt_registry/nt_registry.gyp » ('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 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome_elf/nt_registry/nt_registry.h"
6
7 namespace {
8
9 // Function pointers used for registry access.
10 RtlInitUnicodeStringFunction g_rtl_init_unicode_string = nullptr;
11 NtCreateKeyFunction g_nt_create_key = nullptr;
12 NtDeleteKeyFunction g_nt_delete_key = nullptr;
13 NtOpenKeyExFunction g_nt_open_key_ex = nullptr;
14 NtCloseFunction g_nt_close = nullptr;
15 NtQueryValueKeyFunction g_nt_query_value_key = nullptr;
16 NtSetValueKeyFunction g_nt_set_value_key = nullptr;
17
18 // Lazy init. No concern about concurrency in chrome_elf.
19 bool g_initialized = false;
20 bool g_system_install = false;
21 bool g_reg_redirection = false;
22 const size_t g_kMaxPathLen = 255;
23 wchar_t g_kRegPathHKLM[] = L"\\Registry\\Machine\\";
24 wchar_t g_kRegPathHKCU[g_kMaxPathLen] = L"";
25 wchar_t g_current_user_sid_string[g_kMaxPathLen] = L"";
26 wchar_t g_override_path[g_kMaxPathLen] = L"";
27
28 // Not using install_util, to prevent circular dependency.
29 bool IsThisProcSystem() {
30 wchar_t program_dir[MAX_PATH] = {};
31 wchar_t* cmd_line = GetCommandLineW();
32 // If our command line starts with the "Program Files" or
33 // "Program Files (x86)" path, we're system.
34 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, MAX_PATH);
35 if (ret && ret < MAX_PATH && !::wcsncmp(cmd_line, program_dir, ret))
36 return true;
37
38 ret = ::GetEnvironmentVariable(L"PROGRAMFILES(X86)", program_dir, MAX_PATH);
39 if (ret && ret < MAX_PATH && !::wcsncmp(cmd_line, program_dir, ret))
40 return true;
41
42 return false;
43 }
44
45 bool InitNativeRegApi() {
46 HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");
47
48 // Setup the global function pointers for registry access.
49 g_rtl_init_unicode_string = reinterpret_cast<RtlInitUnicodeStringFunction>(
50 ::GetProcAddress(ntdll, "RtlInitUnicodeString"));
51
52 g_nt_create_key = reinterpret_cast<NtCreateKeyFunction>(
53 ::GetProcAddress(ntdll, "NtCreateKey"));
54
55 g_nt_delete_key = reinterpret_cast<NtDeleteKeyFunction>(
56 ::GetProcAddress(ntdll, "NtDeleteKey"));
57
58 g_nt_open_key_ex = reinterpret_cast<NtOpenKeyExFunction>(
59 ::GetProcAddress(ntdll, "NtOpenKeyEx"));
60
61 g_nt_close =
62 reinterpret_cast<NtCloseFunction>(::GetProcAddress(ntdll, "NtClose"));
63
64 g_nt_query_value_key = reinterpret_cast<NtQueryValueKeyFunction>(
65 ::GetProcAddress(ntdll, "NtQueryValueKey"));
66
67 g_nt_set_value_key = reinterpret_cast<NtSetValueKeyFunction>(
68 ::GetProcAddress(ntdll, "NtSetValueKey"));
69
70 if (!g_rtl_init_unicode_string || !g_nt_create_key || !g_nt_open_key_ex ||
71 !g_nt_delete_key || !g_nt_close || !g_nt_query_value_key ||
72 !g_nt_set_value_key)
73 return false;
74
75 // We need to set HKCU based on the sid of the current user account.
76 RtlFormatCurrentUserKeyPathFunction rtl_current_user_string =
77 reinterpret_cast<RtlFormatCurrentUserKeyPathFunction>(
78 ::GetProcAddress(ntdll, "RtlFormatCurrentUserKeyPath"));
79
80 RtlFreeUnicodeStringFunction rtl_free_unicode_str =
81 reinterpret_cast<RtlFreeUnicodeStringFunction>(
82 ::GetProcAddress(ntdll, "RtlFreeUnicodeString"));
83
84 if (!rtl_current_user_string || !rtl_free_unicode_str)
85 return false;
86
87 UNICODE_STRING current_user_reg_path;
88 if (!NT_SUCCESS(rtl_current_user_string(&current_user_reg_path)))
89 return false;
90
91 // Finish setting up global HKCU path.
92 ::wcsncat(g_kRegPathHKCU, current_user_reg_path.Buffer, (g_kMaxPathLen - 1));
93 ::wcsncat(g_kRegPathHKCU, L"\\",
94 (g_kMaxPathLen - ::wcslen(g_kRegPathHKCU) - 1));
95 // Keep the sid string as well.
96 wchar_t* ptr = ::wcsrchr(current_user_reg_path.Buffer, L'\\');
97 ptr++;
98 ::wcsncpy(g_current_user_sid_string, ptr, (g_kMaxPathLen - 1));
99 rtl_free_unicode_str(&current_user_reg_path);
100
101 // Figure out if we're a system or user install.
102 g_system_install = IsThisProcSystem();
103
104 g_initialized = true;
105 return true;
106 }
107
108 const wchar_t* ConvertRootKey(nt::ROOT_KEY root) {
109 nt::ROOT_KEY key = root;
110
111 if (!root) {
112 // AUTO
113 key = g_system_install ? nt::HKLM : nt::HKCU;
114 }
115
116 if ((key == nt::HKCU) && (::wcslen(nt::HKCU_override) != 0)) {
117 std::wstring temp(g_kRegPathHKCU);
118 temp.append(nt::HKCU_override);
119 temp.append(L"\\");
120 ::wcsncpy(g_override_path, temp.c_str(), g_kMaxPathLen - 1);
121 g_reg_redirection = true;
122 return g_override_path;
123 } else if ((key == nt::HKLM) && (::wcslen(nt::HKLM_override) != 0)) {
124 std::wstring temp(g_kRegPathHKCU);
125 temp.append(nt::HKLM_override);
126 temp.append(L"\\");
127 ::wcsncpy(g_override_path, temp.c_str(), g_kMaxPathLen - 1);
128 g_reg_redirection = true;
129 return g_override_path;
130 }
131
132 g_reg_redirection = false;
133 if (key == nt::HKCU)
134 return g_kRegPathHKCU;
135 else
136 return g_kRegPathHKLM;
137 }
138
139 // Turns a root and subkey path into the registry base hive and the rest of the
140 // subkey tokens.
141 // - |converted_root| should come directly out of ConvertRootKey function.
142 // - E.g. base hive: "\Registry\Machine\", "\Registry\User\<SID>\".
143 bool ParseFullRegPath(const wchar_t* converted_root,
144 const wchar_t* subkey_path,
145 std::wstring* out_base,
146 std::vector<std::wstring>* subkeys) {
147 out_base->clear();
148 subkeys->clear();
149 std::wstring temp = L"";
150
151 if (g_reg_redirection) {
152 // Why process |converted_root|? To handle reg redirection used by tests.
153 // E.g.:
154 // |converted_root| = "\REGISTRY\USER\S-1-5-21-39260824-743453154-142223018-
155 // 716772\Software\Chromium\TempTestKeys\13110669370890870$94c6ed9d-bc34-
156 // 44f3-a0b3-9eee2d3f2f82\".
157 // |subkey_path| = "SOFTWARE\Google\Chrome\BrowserSec".
158 temp.append(converted_root);
159 }
160 if (subkey_path != nullptr)
161 temp.append(subkey_path);
162
163 // Tokenize the full path.
164 size_t find_start = 0;
165 size_t delimiter = temp.find_first_of(L'\\');
166 while (delimiter != std::wstring::npos) {
167 std::wstring token = temp.substr(find_start, delimiter - find_start);
168 if (!token.empty())
169 subkeys->push_back(token);
170 find_start = delimiter + 1;
171 delimiter = temp.find_first_of(L'\\', find_start);
172 }
173 if (!temp.empty() && find_start < temp.length())
174 // Get the last token.
175 subkeys->push_back(temp.substr(find_start));
176
177 if (g_reg_redirection) {
178 // The base hive for HKCU needs to include the user SID.
179 uint32_t num_base_tokens = 2;
180 const wchar_t* hkcu = L"\\REGISTRY\\USER\\";
181 if (0 == ::wcsnicmp(converted_root, hkcu, ::wcslen(hkcu)))
182 num_base_tokens = 3;
183
184 if (subkeys->size() < num_base_tokens)
185 return false;
186
187 // Pull out the base hive tokens.
188 out_base->push_back(L'\\');
189 for (size_t i = 0; i < num_base_tokens; i++) {
190 out_base->append((*subkeys)[i].c_str());
191 out_base->push_back(L'\\');
192 }
193 subkeys->erase(subkeys->begin(), subkeys->begin() + num_base_tokens);
194 } else {
195 out_base->assign(converted_root);
196 }
197
198 return true;
199 }
200
201 NTSTATUS CreateKeyWrapper(const std::wstring& key_path,
202 ACCESS_MASK access,
203 HANDLE* out_handle,
204 ULONG* create_or_open OPTIONAL) {
205 UNICODE_STRING key_path_uni = {};
206 g_rtl_init_unicode_string(&key_path_uni, key_path.c_str());
207
208 OBJECT_ATTRIBUTES obj = {};
209 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL,
210 nullptr);
211
212 return g_nt_create_key(out_handle, access, &obj, 0, nullptr,
213 REG_OPTION_NON_VOLATILE, create_or_open);
214 }
215
216 } // namespace
217
218 namespace nt {
219
220 const size_t g_kRegMaxPathLen = 255;
221 wchar_t HKLM_override[g_kRegMaxPathLen] = L"";
222 wchar_t HKCU_override[g_kRegMaxPathLen] = L"";
223
224 //------------------------------------------------------------------------------
225 // Create, open, delete, close functions
226 //------------------------------------------------------------------------------
227
228 bool CreateRegKey(ROOT_KEY root,
229 const wchar_t* key_path,
230 ACCESS_MASK access,
231 HANDLE* out_handle OPTIONAL) {
232 if (!g_initialized)
233 InitNativeRegApi();
234
235 std::wstring current_path;
236 std::vector<std::wstring> subkeys;
237 if (!ParseFullRegPath(ConvertRootKey(root), key_path, &current_path,
238 &subkeys))
239 return false;
240
241 // Open the base hive first. It should always exist already.
242 HANDLE last_handle = INVALID_HANDLE_VALUE;
243 NTSTATUS status =
244 CreateKeyWrapper(current_path, access, &last_handle, nullptr);
245 if (!NT_SUCCESS(status))
246 return false;
247
248 size_t subkeys_size = subkeys.size();
249 if (subkeys_size != 0)
250 g_nt_close(last_handle);
251
252 // Recursively open/create each subkey.
253 std::vector<HANDLE> rollback;
254 bool success = true;
255 for (size_t i = 0; i < subkeys_size; i++) {
256 current_path.append(subkeys[i]);
257 current_path.push_back(L'\\');
258
259 // Process the latest subkey.
260 ULONG created = 0;
261 HANDLE key_handle = INVALID_HANDLE_VALUE;
262 status =
263 CreateKeyWrapper(current_path.c_str(), access, &key_handle, &created);
264 if (!NT_SUCCESS(status)) {
265 success = false;
266 break;
267 }
268
269 if (i == subkeys_size - 1) {
270 last_handle = key_handle;
271 } else {
272 // Save any subkey handle created, in case of rollback.
273 if (created == REG_CREATED_NEW_KEY)
274 rollback.push_back(key_handle);
275 else
276 g_nt_close(key_handle);
277 }
278 }
279
280 if (!success) {
281 // Delete any subkeys created.
282 for (HANDLE handle : rollback) {
283 g_nt_delete_key(handle);
284 }
285 }
286 for (HANDLE handle : rollback) {
287 // Close the rollback handles, on success or failure.
288 g_nt_close(handle);
289 }
290 if (!success)
291 return false;
292
293 // See if caller wants the handle left open.
294 if (out_handle)
295 *out_handle = last_handle;
296 else
297 g_nt_close(last_handle);
298
299 return true;
300 }
301
302 bool OpenRegKey(ROOT_KEY root,
303 const wchar_t* key_path,
304 ACCESS_MASK access,
305 HANDLE* out_handle,
306 NTSTATUS* error_code OPTIONAL) {
307 if (!g_initialized)
308 InitNativeRegApi();
309
310 NTSTATUS status = STATUS_UNSUCCESSFUL;
311 UNICODE_STRING key_path_uni = {};
312 OBJECT_ATTRIBUTES obj = {};
313 *out_handle = INVALID_HANDLE_VALUE;
314
315 std::wstring full_path(ConvertRootKey(root));
316 full_path.append(key_path);
317
318 g_rtl_init_unicode_string(&key_path_uni, full_path.c_str());
319 InitializeObjectAttributes(&obj, &key_path_uni, OBJ_CASE_INSENSITIVE, NULL,
320 NULL);
321
322 status = g_nt_open_key_ex(out_handle, access, &obj, 0);
323 // See if caller wants the NTSTATUS.
324 if (error_code)
325 *error_code = status;
326
327 if (NT_SUCCESS(status))
328 return true;
329
330 return false;
331 }
332
333 bool DeleteRegKey(HANDLE key) {
334 if (!g_initialized)
335 InitNativeRegApi();
336
337 NTSTATUS status = STATUS_UNSUCCESSFUL;
338
339 status = g_nt_delete_key(key);
340
341 if (NT_SUCCESS(status))
342 return true;
343
344 return false;
345 }
346
347 // wrapper function
348 bool DeleteRegKey(ROOT_KEY root, const wchar_t* key_path) {
349 HANDLE key = INVALID_HANDLE_VALUE;
350
351 if (!OpenRegKey(root, key_path, DELETE, &key, nullptr))
352 return false;
353
354 if (!DeleteRegKey(key)) {
355 CloseRegKey(key);
356 return false;
357 }
358
359 CloseRegKey(key);
360 return true;
361 }
362
363 void CloseRegKey(HANDLE key) {
364 if (!g_initialized)
365 InitNativeRegApi();
366 g_nt_close(key);
367 }
368
369 //------------------------------------------------------------------------------
370 // Getter functions
371 //------------------------------------------------------------------------------
372
373 bool QueryRegKeyValue(HANDLE key,
374 const wchar_t* value_name,
375 ULONG* out_type,
376 BYTE** out_buffer,
377 DWORD* out_size) {
378 if (!g_initialized)
379 InitNativeRegApi();
380
381 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL;
382 UNICODE_STRING value_uni = {};
383 g_rtl_init_unicode_string(&value_uni, value_name);
384 DWORD size_needed = 0;
385 bool success = false;
386
387 // First call to find out how much room we need for the value!
388 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation,
389 nullptr, 0, &size_needed);
390 if (ntstatus != STATUS_BUFFER_TOO_SMALL)
391 return false;
392
393 KEY_VALUE_FULL_INFORMATION* value_info =
394 reinterpret_cast<KEY_VALUE_FULL_INFORMATION*>(new BYTE[size_needed]);
395
396 // Second call to get the value.
397 ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation,
398 value_info, size_needed, &size_needed);
399 if (NT_SUCCESS(ntstatus)) {
400 *out_type = value_info->Type;
401 *out_size = value_info->DataLength;
402 *out_buffer = new BYTE[*out_size];
403 ::memcpy(*out_buffer,
404 (reinterpret_cast<BYTE*>(value_info) + value_info->DataOffset),
405 *out_size);
406 success = true;
407 }
408
409 delete[] value_info;
410 return success;
411 }
412
413 // wrapper function
414 bool QueryRegValueDWORD(HANDLE key,
415 const wchar_t* value_name,
416 DWORD* out_dword) {
417 ULONG type = REG_NONE;
418 BYTE* value_bytes = nullptr;
419 DWORD ret_size = 0;
420
421 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) ||
422 type != REG_DWORD)
423 return false;
424
425 *out_dword = *(reinterpret_cast<DWORD*>(value_bytes));
426
427 delete[] value_bytes;
428 return true;
429 }
430
431 // wrapper function
432 bool QueryRegValueDWORD(ROOT_KEY root,
433 const wchar_t* key_path,
434 const wchar_t* value_name,
435 DWORD* out_dword) {
436 HANDLE key = INVALID_HANDLE_VALUE;
437
438 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key,
439 NULL))
440 return false;
441
442 if (!QueryRegValueDWORD(key, value_name, out_dword)) {
443 CloseRegKey(key);
444 return false;
445 }
446
447 CloseRegKey(key);
448 return true;
449 }
450
451 // wrapper function
452 bool QueryRegValueSZ(HANDLE key,
453 const wchar_t* value_name,
454 std::wstring* out_sz) {
455 BYTE* value_bytes = nullptr;
456 DWORD ret_size = 0;
457 ULONG type = REG_NONE;
458
459 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) ||
460 type != REG_SZ)
461 return false;
462
463 *out_sz = reinterpret_cast<wchar_t*>(value_bytes);
464
465 delete[] value_bytes;
466 return true;
467 }
468
469 // wrapper function
470 bool QueryRegValueSZ(ROOT_KEY root,
471 const wchar_t* key_path,
472 const wchar_t* value_name,
473 std::wstring* out_sz) {
474 HANDLE key = INVALID_HANDLE_VALUE;
475
476 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key,
477 NULL))
478 return false;
479
480 if (!QueryRegValueSZ(key, value_name, out_sz)) {
481 CloseRegKey(key);
482 return false;
483 }
484
485 CloseRegKey(key);
486 return true;
487 }
488
489 // wrapper function
490 bool QueryRegValueMULTISZ(HANDLE key,
491 const wchar_t* value_name,
492 std::vector<std::wstring>* out_multi_sz) {
493 BYTE* value_bytes = nullptr;
494 DWORD ret_size = 0;
495 ULONG type = REG_NONE;
496
497 if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) ||
498 type != REG_MULTI_SZ)
499 return false;
500
501 // Make sure the vector is empty to start.
502 (*out_multi_sz).resize(0);
503
504 wchar_t* pointer = reinterpret_cast<wchar_t*>(value_bytes);
505 std::wstring temp = pointer;
506 // Loop. Each string is separated by '\0'. Another '\0' at very end (so 2 in
507 // a row).
508 while (temp.length() != 0) {
509 (*out_multi_sz).push_back(temp);
510
511 pointer += temp.length() + 1;
512 temp = pointer;
513 }
514
515 // Handle the case of "empty multi_sz".
516 if (out_multi_sz->size() == 0)
517 out_multi_sz->push_back(L"");
518
519 delete[] value_bytes;
520 return true;
521 }
522
523 // wrapper function
524 bool QueryRegValueMULTISZ(ROOT_KEY root,
525 const wchar_t* key_path,
526 const wchar_t* value_name,
527 std::vector<std::wstring>* out_multi_sz) {
528 HANDLE key = INVALID_HANDLE_VALUE;
529
530 if (!OpenRegKey(root, key_path, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key,
531 NULL))
532 return false;
533
534 if (!QueryRegValueMULTISZ(key, value_name, out_multi_sz)) {
535 CloseRegKey(key);
536 return false;
537 }
538
539 CloseRegKey(key);
540 return true;
541 }
542
543 //------------------------------------------------------------------------------
544 // Setter functions
545 //------------------------------------------------------------------------------
546
547 bool SetRegKeyValue(HANDLE key,
548 const wchar_t* value_name,
549 ULONG type,
550 const BYTE* data,
551 DWORD data_size) {
552 if (!g_initialized)
553 InitNativeRegApi();
554
555 NTSTATUS ntstatus = STATUS_UNSUCCESSFUL;
556 UNICODE_STRING value_uni = {};
557 g_rtl_init_unicode_string(&value_uni, value_name);
558
559 BYTE* non_const_data = const_cast<BYTE*>(data);
560 ntstatus =
561 g_nt_set_value_key(key, &value_uni, 0, type, non_const_data, data_size);
562
563 if (NT_SUCCESS(ntstatus))
564 return true;
565
566 return false;
567 }
568
569 // wrapper function
570 bool SetRegValueDWORD(HANDLE key, const wchar_t* value_name, DWORD value) {
571 return SetRegKeyValue(key, value_name, REG_DWORD,
572 reinterpret_cast<BYTE*>(&value), sizeof(value));
573 }
574
575 // wrapper function
576 bool SetRegValueDWORD(ROOT_KEY root,
577 const wchar_t* key_path,
578 const wchar_t* value_name,
579 DWORD value) {
580 HANDLE key = INVALID_HANDLE_VALUE;
581
582 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL))
583 return false;
584
585 if (!SetRegValueDWORD(key, value_name, value)) {
586 CloseRegKey(key);
587 return false;
588 }
589
590 return true;
591 }
592
593 // wrapper function
594 bool SetRegValueSZ(HANDLE key,
595 const wchar_t* value_name,
596 const std::wstring& value) {
597 // Make sure the number of bytes in |value|, including EoS, fits in a DWORD.
598 if (std::numeric_limits<DWORD>::max() <
599 ((value.length() + 1) * sizeof(wchar_t)))
600 return false;
601
602 DWORD size = (static_cast<DWORD>((value.length() + 1) * sizeof(wchar_t)));
603 return SetRegKeyValue(key, value_name, REG_SZ,
604 reinterpret_cast<const BYTE*>(value.c_str()), size);
605 }
606
607 // wrapper function
608 bool SetRegValueSZ(ROOT_KEY root,
609 const wchar_t* key_path,
610 const wchar_t* value_name,
611 const std::wstring& value) {
612 HANDLE key = INVALID_HANDLE_VALUE;
613
614 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL))
615 return false;
616
617 if (!SetRegValueSZ(key, value_name, value)) {
618 CloseRegKey(key);
619 return false;
620 }
621
622 return true;
623 }
624
625 // wrapper function
626 bool SetRegValueMULTISZ(HANDLE key,
627 const wchar_t* value_name,
628 const std::vector<std::wstring>& values) {
629 std::vector<wchar_t> builder;
630
631 for (auto& string : values) {
632 // Just in case someone is passing in an illegal empty string
633 // (not allowed in REG_MULTI_SZ), ignore it.
634 if (!string.empty()) {
635 for (const wchar_t& w : string) {
636 builder.push_back(w);
637 }
638 builder.push_back(L'\0');
639 }
640 }
641 // Add second null terminator to end REG_MULTI_SZ.
642 builder.push_back(L'\0');
643 // Handle rare case where the vector passed in was empty,
644 // or only had an empty string.
645 if (builder.size() == 1)
646 builder.push_back(L'\0');
647
648 if (std::numeric_limits<DWORD>::max() < builder.size())
649 return false;
650
651 return SetRegKeyValue(
652 key, value_name, REG_MULTI_SZ, reinterpret_cast<BYTE*>(builder.data()),
653 (static_cast<DWORD>(builder.size()) + 1) * sizeof(wchar_t));
654 }
655
656 // wrapper function
657 bool SetRegValueMULTISZ(ROOT_KEY root,
658 const wchar_t* key_path,
659 const wchar_t* value_name,
660 const std::vector<std::wstring>& values) {
661 HANDLE key = INVALID_HANDLE_VALUE;
662
663 if (!OpenRegKey(root, key_path, KEY_SET_VALUE | KEY_WOW64_32KEY, &key, NULL))
664 return false;
665
666 if (!SetRegValueMULTISZ(key, value_name, values)) {
667 CloseRegKey(key);
668 return false;
669 }
670
671 return true;
672 }
673
674 //------------------------------------------------------------------------------
675 // Utils
676 //------------------------------------------------------------------------------
677
678 const wchar_t* GetCurrentUserSidString() {
679 if (!g_initialized)
680 InitNativeRegApi();
681
682 return g_current_user_sid_string;
683 }
684
685 }; // namespace nt
OLDNEW
« no previous file with comments | « chrome_elf/nt_registry/nt_registry.h ('k') | chrome_elf/nt_registry/nt_registry.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698