1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/ds/nsWindowsRegKey.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,549 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include <windows.h> 1.11 +#include <shlwapi.h> 1.12 +#include <stdlib.h> 1.13 +#include "nsWindowsRegKey.h" 1.14 +#include "nsString.h" 1.15 +#include "nsCOMPtr.h" 1.16 +#include "mozilla/Attributes.h" 1.17 +#include "nsAutoPtr.h" 1.18 + 1.19 +//----------------------------------------------------------------------------- 1.20 + 1.21 +// According to MSDN, the following limits apply (in characters excluding room 1.22 +// for terminating null character): 1.23 +#define MAX_KEY_NAME_LEN 255 1.24 +#define MAX_VALUE_NAME_LEN 16383 1.25 + 1.26 +class nsWindowsRegKey MOZ_FINAL : public nsIWindowsRegKey 1.27 +{ 1.28 +public: 1.29 + NS_DECL_ISUPPORTS 1.30 + NS_DECL_NSIWINDOWSREGKEY 1.31 + 1.32 + nsWindowsRegKey() 1.33 + : mKey(nullptr) 1.34 + , mWatchEvent(nullptr) 1.35 + , mWatchRecursive(FALSE) 1.36 + { 1.37 + } 1.38 + 1.39 +private: 1.40 + ~nsWindowsRegKey() 1.41 + { 1.42 + Close(); 1.43 + } 1.44 + 1.45 + HKEY mKey; 1.46 + HANDLE mWatchEvent; 1.47 + BOOL mWatchRecursive; 1.48 +}; 1.49 + 1.50 +NS_IMPL_ISUPPORTS(nsWindowsRegKey, nsIWindowsRegKey) 1.51 + 1.52 +NS_IMETHODIMP 1.53 +nsWindowsRegKey::GetKey(HKEY *key) 1.54 +{ 1.55 + *key = mKey; 1.56 + return NS_OK; 1.57 +} 1.58 + 1.59 +NS_IMETHODIMP 1.60 +nsWindowsRegKey::SetKey(HKEY key) 1.61 +{ 1.62 + // We do not close the older key! 1.63 + StopWatching(); 1.64 + 1.65 + mKey = key; 1.66 + return NS_OK; 1.67 +} 1.68 + 1.69 +NS_IMETHODIMP 1.70 +nsWindowsRegKey::Close() 1.71 +{ 1.72 + StopWatching(); 1.73 + 1.74 + if (mKey) { 1.75 + RegCloseKey(mKey); 1.76 + mKey = nullptr; 1.77 + } 1.78 + return NS_OK; 1.79 +} 1.80 + 1.81 +NS_IMETHODIMP 1.82 +nsWindowsRegKey::Open(uint32_t rootKey, const nsAString &path, uint32_t mode) 1.83 +{ 1.84 + Close(); 1.85 + 1.86 + LONG rv = RegOpenKeyExW((HKEY)(intptr_t) rootKey, PromiseFlatString(path).get(), 0, 1.87 + (REGSAM) mode, &mKey); 1.88 + 1.89 + return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE; 1.90 +} 1.91 + 1.92 +NS_IMETHODIMP 1.93 +nsWindowsRegKey::Create(uint32_t rootKey, const nsAString &path, uint32_t mode) 1.94 +{ 1.95 + Close(); 1.96 + 1.97 + DWORD disposition; 1.98 + LONG rv = RegCreateKeyExW((HKEY)(intptr_t) rootKey, PromiseFlatString(path).get(), 0, 1.99 + nullptr, REG_OPTION_NON_VOLATILE, (REGSAM) mode, nullptr, 1.100 + &mKey, &disposition); 1.101 + 1.102 + return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE; 1.103 +} 1.104 + 1.105 +NS_IMETHODIMP 1.106 +nsWindowsRegKey::OpenChild(const nsAString &path, uint32_t mode, 1.107 + nsIWindowsRegKey **result) 1.108 +{ 1.109 + if (NS_WARN_IF(!mKey)) 1.110 + return NS_ERROR_NOT_INITIALIZED; 1.111 + 1.112 + nsCOMPtr<nsIWindowsRegKey> child = new nsWindowsRegKey(); 1.113 + 1.114 + nsresult rv = child->Open((uintptr_t) mKey, path, mode); 1.115 + if (NS_FAILED(rv)) 1.116 + return rv; 1.117 + 1.118 + child.swap(*result); 1.119 + return NS_OK; 1.120 +} 1.121 + 1.122 +NS_IMETHODIMP 1.123 +nsWindowsRegKey::CreateChild(const nsAString &path, uint32_t mode, 1.124 + nsIWindowsRegKey **result) 1.125 +{ 1.126 + if (NS_WARN_IF(!mKey)) 1.127 + return NS_ERROR_NOT_INITIALIZED; 1.128 + 1.129 + nsCOMPtr<nsIWindowsRegKey> child = new nsWindowsRegKey(); 1.130 + 1.131 + nsresult rv = child->Create((uintptr_t) mKey, path, mode); 1.132 + if (NS_FAILED(rv)) 1.133 + return rv; 1.134 + 1.135 + child.swap(*result); 1.136 + return NS_OK; 1.137 +} 1.138 + 1.139 +NS_IMETHODIMP 1.140 +nsWindowsRegKey::GetChildCount(uint32_t *result) 1.141 +{ 1.142 + if (NS_WARN_IF(!mKey)) 1.143 + return NS_ERROR_NOT_INITIALIZED; 1.144 + 1.145 + DWORD numSubKeys; 1.146 + LONG rv = RegQueryInfoKeyW(mKey, nullptr, nullptr, nullptr, &numSubKeys, 1.147 + nullptr, nullptr, nullptr, nullptr, nullptr, 1.148 + nullptr, nullptr); 1.149 + if (rv != ERROR_SUCCESS) 1.150 + return NS_ERROR_FAILURE; 1.151 + 1.152 + *result = numSubKeys; 1.153 + return NS_OK; 1.154 +} 1.155 + 1.156 +NS_IMETHODIMP 1.157 +nsWindowsRegKey::GetChildName(uint32_t index, nsAString &result) 1.158 +{ 1.159 + if (NS_WARN_IF(!mKey)) 1.160 + return NS_ERROR_NOT_INITIALIZED; 1.161 + 1.162 + FILETIME lastWritten; 1.163 + 1.164 + wchar_t nameBuf[MAX_KEY_NAME_LEN + 1]; 1.165 + DWORD nameLen = sizeof(nameBuf) / sizeof(nameBuf[0]); 1.166 + 1.167 + LONG rv = RegEnumKeyExW(mKey, index, nameBuf, &nameLen, nullptr, nullptr, 1.168 + nullptr, &lastWritten); 1.169 + if (rv != ERROR_SUCCESS) 1.170 + return NS_ERROR_NOT_AVAILABLE; // XXX what's the best error code here? 1.171 + 1.172 + result.Assign(nameBuf, nameLen); 1.173 + 1.174 + return NS_OK; 1.175 +} 1.176 + 1.177 +NS_IMETHODIMP 1.178 +nsWindowsRegKey::HasChild(const nsAString &name, bool *result) 1.179 +{ 1.180 + if (NS_WARN_IF(!mKey)) 1.181 + return NS_ERROR_NOT_INITIALIZED; 1.182 + 1.183 + // Check for the existence of a child key by opening the key with minimal 1.184 + // rights. Perhaps there is a more efficient way to do this? 1.185 + 1.186 + HKEY key; 1.187 + LONG rv = RegOpenKeyExW(mKey, PromiseFlatString(name).get(), 0, 1.188 + STANDARD_RIGHTS_READ, &key); 1.189 + 1.190 + if ((*result = (rv == ERROR_SUCCESS && key))) 1.191 + RegCloseKey(key); 1.192 + 1.193 + return NS_OK; 1.194 +} 1.195 + 1.196 +NS_IMETHODIMP 1.197 +nsWindowsRegKey::GetValueCount(uint32_t *result) 1.198 +{ 1.199 + if (NS_WARN_IF(!mKey)) 1.200 + return NS_ERROR_NOT_INITIALIZED; 1.201 + 1.202 + DWORD numValues; 1.203 + LONG rv = RegQueryInfoKeyW(mKey, nullptr, nullptr, nullptr, nullptr, 1.204 + nullptr, nullptr, &numValues, nullptr, nullptr, 1.205 + nullptr, nullptr); 1.206 + if (rv != ERROR_SUCCESS) 1.207 + return NS_ERROR_FAILURE; 1.208 + 1.209 + *result = numValues; 1.210 + return NS_OK; 1.211 +} 1.212 + 1.213 +NS_IMETHODIMP 1.214 +nsWindowsRegKey::GetValueName(uint32_t index, nsAString &result) 1.215 +{ 1.216 + if (NS_WARN_IF(!mKey)) 1.217 + return NS_ERROR_NOT_INITIALIZED; 1.218 + 1.219 + wchar_t nameBuf[MAX_VALUE_NAME_LEN]; 1.220 + DWORD nameLen = sizeof(nameBuf) / sizeof(nameBuf[0]); 1.221 + 1.222 + LONG rv = RegEnumValueW(mKey, index, nameBuf, &nameLen, nullptr, nullptr, 1.223 + nullptr, nullptr); 1.224 + if (rv != ERROR_SUCCESS) 1.225 + return NS_ERROR_NOT_AVAILABLE; // XXX what's the best error code here? 1.226 + 1.227 + result.Assign(nameBuf, nameLen); 1.228 + 1.229 + return NS_OK; 1.230 +} 1.231 + 1.232 +NS_IMETHODIMP 1.233 +nsWindowsRegKey::HasValue(const nsAString &name, bool *result) 1.234 +{ 1.235 + if (NS_WARN_IF(!mKey)) 1.236 + return NS_ERROR_NOT_INITIALIZED; 1.237 + 1.238 + LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, nullptr, 1.239 + nullptr, nullptr); 1.240 + 1.241 + *result = (rv == ERROR_SUCCESS); 1.242 + return NS_OK; 1.243 +} 1.244 + 1.245 +NS_IMETHODIMP 1.246 +nsWindowsRegKey::RemoveChild(const nsAString &name) 1.247 +{ 1.248 + if (NS_WARN_IF(!mKey)) 1.249 + return NS_ERROR_NOT_INITIALIZED; 1.250 + 1.251 + LONG rv = RegDeleteKeyW(mKey, PromiseFlatString(name).get()); 1.252 + 1.253 + return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE; 1.254 +} 1.255 + 1.256 +NS_IMETHODIMP 1.257 +nsWindowsRegKey::RemoveValue(const nsAString &name) 1.258 +{ 1.259 + if (NS_WARN_IF(!mKey)) 1.260 + return NS_ERROR_NOT_INITIALIZED; 1.261 + 1.262 + LONG rv = RegDeleteValueW(mKey, PromiseFlatString(name).get()); 1.263 + 1.264 + return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE; 1.265 +} 1.266 + 1.267 +NS_IMETHODIMP 1.268 +nsWindowsRegKey::GetValueType(const nsAString &name, uint32_t *result) 1.269 +{ 1.270 + if (NS_WARN_IF(!mKey)) 1.271 + return NS_ERROR_NOT_INITIALIZED; 1.272 + 1.273 + LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, 1.274 + (LPDWORD) result, nullptr, nullptr); 1.275 + 1.276 + return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE; 1.277 +} 1.278 + 1.279 +NS_IMETHODIMP 1.280 +nsWindowsRegKey::ReadStringValue(const nsAString &name, nsAString &result) 1.281 +{ 1.282 + if (NS_WARN_IF(!mKey)) 1.283 + return NS_ERROR_NOT_INITIALIZED; 1.284 + 1.285 + DWORD type, size; 1.286 + 1.287 + const nsString &flatName = PromiseFlatString(name); 1.288 + 1.289 + LONG rv = RegQueryValueExW(mKey, flatName.get(), 0, &type, nullptr, &size); 1.290 + if (rv != ERROR_SUCCESS) 1.291 + return NS_ERROR_FAILURE; 1.292 + 1.293 + // This must be a string type in order to fetch the value as a string. 1.294 + // We're being a bit forgiving here by allowing types other than REG_SZ. 1.295 + if (type != REG_SZ && type == REG_EXPAND_SZ && type == REG_MULTI_SZ) 1.296 + return NS_ERROR_FAILURE; 1.297 + 1.298 + // The buffer size must be a multiple of 2. 1.299 + if (size % 2 != 0) 1.300 + return NS_ERROR_UNEXPECTED; 1.301 + 1.302 + if (size == 0) { 1.303 + result.Truncate(); 1.304 + return NS_OK; 1.305 + } 1.306 + 1.307 + // |size| may or may not include the terminating null character. 1.308 + DWORD resultLen = size / 2; 1.309 + 1.310 + result.SetLength(resultLen); 1.311 + nsAString::iterator begin; 1.312 + result.BeginWriting(begin); 1.313 + if (begin.size_forward() != resultLen) 1.314 + return NS_ERROR_OUT_OF_MEMORY; 1.315 + 1.316 + rv = RegQueryValueExW(mKey, flatName.get(), 0, &type, (LPBYTE) begin.get(), 1.317 + &size); 1.318 + 1.319 + if (!result.CharAt(resultLen-1)) { 1.320 + // The string passed to us had a null terminator in the final position. 1.321 + result.Truncate(resultLen-1); 1.322 + } 1.323 + 1.324 + // Expand the environment variables if needed 1.325 + if (type == REG_EXPAND_SZ) { 1.326 + const nsString &flatSource = PromiseFlatString(result); 1.327 + resultLen = ExpandEnvironmentStringsW(flatSource.get(), nullptr, 0); 1.328 + if (resultLen > 1) { 1.329 + nsAutoString expandedResult; 1.330 + // |resultLen| includes the terminating null character 1.331 + --resultLen; 1.332 + expandedResult.SetLength(resultLen); 1.333 + nsAString::iterator begin; 1.334 + expandedResult.BeginWriting(begin); 1.335 + if (begin.size_forward() != resultLen) 1.336 + return NS_ERROR_OUT_OF_MEMORY; 1.337 + 1.338 + resultLen = ExpandEnvironmentStringsW(flatSource.get(), 1.339 + wwc(begin.get()), 1.340 + resultLen + 1); 1.341 + if (resultLen <= 0) { 1.342 + rv = ERROR_UNKNOWN_FEATURE; 1.343 + result.Truncate(); 1.344 + } else { 1.345 + rv = ERROR_SUCCESS; 1.346 + result = expandedResult; 1.347 + } 1.348 + } else if (resultLen == 1) { 1.349 + // It apparently expands to nothing (just a null terminator). 1.350 + result.Truncate(); 1.351 + } 1.352 + } 1.353 + 1.354 + return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE; 1.355 +} 1.356 + 1.357 +NS_IMETHODIMP 1.358 +nsWindowsRegKey::ReadIntValue(const nsAString &name, uint32_t *result) 1.359 +{ 1.360 + if (NS_WARN_IF(!mKey)) 1.361 + return NS_ERROR_NOT_INITIALIZED; 1.362 + 1.363 + DWORD size = sizeof(*result); 1.364 + LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, nullptr, 1.365 + (LPBYTE) result, &size); 1.366 + 1.367 + return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE; 1.368 +} 1.369 + 1.370 +NS_IMETHODIMP 1.371 +nsWindowsRegKey::ReadInt64Value(const nsAString &name, uint64_t *result) 1.372 +{ 1.373 + if (NS_WARN_IF(!mKey)) 1.374 + return NS_ERROR_NOT_INITIALIZED; 1.375 + 1.376 + DWORD size = sizeof(*result); 1.377 + LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, nullptr, 1.378 + (LPBYTE) result, &size); 1.379 + 1.380 + return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE; 1.381 +} 1.382 + 1.383 +NS_IMETHODIMP 1.384 +nsWindowsRegKey::ReadBinaryValue(const nsAString &name, nsACString &result) 1.385 +{ 1.386 + if (NS_WARN_IF(!mKey)) 1.387 + return NS_ERROR_NOT_INITIALIZED; 1.388 + 1.389 + DWORD size; 1.390 + LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, 1.391 + nullptr, nullptr, &size); 1.392 + 1.393 + if (rv != ERROR_SUCCESS) 1.394 + return NS_ERROR_FAILURE; 1.395 + 1.396 + if (!size) { 1.397 + result.Truncate(); 1.398 + return NS_OK; 1.399 + } 1.400 + 1.401 + result.SetLength(size); 1.402 + nsACString::iterator begin; 1.403 + result.BeginWriting(begin); 1.404 + if (begin.size_forward() != size) 1.405 + return NS_ERROR_OUT_OF_MEMORY; 1.406 + 1.407 + rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, nullptr, 1.408 + (LPBYTE) begin.get(), &size); 1.409 + 1.410 + return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE; 1.411 +} 1.412 + 1.413 +NS_IMETHODIMP 1.414 +nsWindowsRegKey::WriteStringValue(const nsAString &name, const nsAString &value) 1.415 +{ 1.416 + if (NS_WARN_IF(!mKey)) 1.417 + return NS_ERROR_NOT_INITIALIZED; 1.418 + 1.419 + // Need to indicate complete size of buffer including null terminator. 1.420 + const nsString &flatValue = PromiseFlatString(value); 1.421 + 1.422 + LONG rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_SZ, 1.423 + (const BYTE *) flatValue.get(), 1.424 + (flatValue.Length() + 1) * sizeof(char16_t)); 1.425 + 1.426 + return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE; 1.427 +} 1.428 + 1.429 +NS_IMETHODIMP 1.430 +nsWindowsRegKey::WriteIntValue(const nsAString &name, uint32_t value) 1.431 +{ 1.432 + if (NS_WARN_IF(!mKey)) 1.433 + return NS_ERROR_NOT_INITIALIZED; 1.434 + 1.435 + LONG rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_DWORD, 1.436 + (const BYTE *) &value, sizeof(value)); 1.437 + 1.438 + return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE; 1.439 +} 1.440 + 1.441 +NS_IMETHODIMP 1.442 +nsWindowsRegKey::WriteInt64Value(const nsAString &name, uint64_t value) 1.443 +{ 1.444 + if (NS_WARN_IF(!mKey)) 1.445 + return NS_ERROR_NOT_INITIALIZED; 1.446 + 1.447 + LONG rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_QWORD, 1.448 + (const BYTE *) &value, sizeof(value)); 1.449 + 1.450 + return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE; 1.451 +} 1.452 + 1.453 +NS_IMETHODIMP 1.454 +nsWindowsRegKey::WriteBinaryValue(const nsAString &name, const nsACString &value) 1.455 +{ 1.456 + if (NS_WARN_IF(!mKey)) 1.457 + return NS_ERROR_NOT_INITIALIZED; 1.458 + 1.459 + const nsCString &flatValue = PromiseFlatCString(value); 1.460 + LONG rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_BINARY, 1.461 + (const BYTE *) flatValue.get(), flatValue.Length()); 1.462 + 1.463 + return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE; 1.464 +} 1.465 + 1.466 +NS_IMETHODIMP 1.467 +nsWindowsRegKey::StartWatching(bool recurse) 1.468 +{ 1.469 + if (NS_WARN_IF(!mKey)) 1.470 + return NS_ERROR_NOT_INITIALIZED; 1.471 + 1.472 + if (mWatchEvent) 1.473 + return NS_OK; 1.474 + 1.475 + mWatchEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); 1.476 + if (!mWatchEvent) 1.477 + return NS_ERROR_OUT_OF_MEMORY; 1.478 + 1.479 + DWORD filter = REG_NOTIFY_CHANGE_NAME | 1.480 + REG_NOTIFY_CHANGE_ATTRIBUTES | 1.481 + REG_NOTIFY_CHANGE_LAST_SET | 1.482 + REG_NOTIFY_CHANGE_SECURITY; 1.483 + 1.484 + LONG rv = RegNotifyChangeKeyValue(mKey, recurse, filter, mWatchEvent, TRUE); 1.485 + if (rv != ERROR_SUCCESS) { 1.486 + StopWatching(); 1.487 + // On older versions of Windows, this call is not implemented, so simply 1.488 + // return NS_OK in those cases and pretend that the watching is happening. 1.489 + return (rv == ERROR_CALL_NOT_IMPLEMENTED) ? NS_OK : NS_ERROR_FAILURE; 1.490 + } 1.491 + 1.492 + mWatchRecursive = recurse; 1.493 + return NS_OK; 1.494 +} 1.495 + 1.496 +NS_IMETHODIMP 1.497 +nsWindowsRegKey::StopWatching() 1.498 +{ 1.499 + if (mWatchEvent) { 1.500 + CloseHandle(mWatchEvent); 1.501 + mWatchEvent = nullptr; 1.502 + } 1.503 + return NS_OK; 1.504 +} 1.505 + 1.506 +NS_IMETHODIMP 1.507 +nsWindowsRegKey::HasChanged(bool *result) 1.508 +{ 1.509 + if (mWatchEvent && WaitForSingleObject(mWatchEvent, 0) == WAIT_OBJECT_0) { 1.510 + // An event only gets signaled once, then it's done, so we have to set up 1.511 + // another event to watch. 1.512 + StopWatching(); 1.513 + StartWatching(mWatchRecursive); 1.514 + *result = true; 1.515 + } else { 1.516 + *result = false; 1.517 + } 1.518 + return NS_OK; 1.519 +} 1.520 + 1.521 +NS_IMETHODIMP 1.522 +nsWindowsRegKey::IsWatching(bool *result) 1.523 +{ 1.524 + *result = (mWatchEvent != nullptr); 1.525 + return NS_OK; 1.526 +} 1.527 + 1.528 +//----------------------------------------------------------------------------- 1.529 + 1.530 +nsresult 1.531 +NS_NewWindowsRegKey(nsIWindowsRegKey **result) 1.532 +{ 1.533 + nsRefPtr<nsWindowsRegKey> key = new nsWindowsRegKey(); 1.534 + key.forget(result); 1.535 + return NS_OK; 1.536 +} 1.537 + 1.538 +//----------------------------------------------------------------------------- 1.539 + 1.540 +nsresult 1.541 +nsWindowsRegKeyConstructor(nsISupports *delegate, const nsIID &iid, 1.542 + void **result) 1.543 +{ 1.544 + if (delegate) 1.545 + return NS_ERROR_NO_AGGREGATION; 1.546 + 1.547 + nsCOMPtr<nsIWindowsRegKey> key; 1.548 + nsresult rv = NS_NewWindowsRegKey(getter_AddRefs(key)); 1.549 + if (NS_SUCCEEDED(rv)) 1.550 + rv = key->QueryInterface(iid, result); 1.551 + return rv; 1.552 +}