xpcom/ds/nsWindowsRegKey.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include <windows.h>
michael@0 8 #include <shlwapi.h>
michael@0 9 #include <stdlib.h>
michael@0 10 #include "nsWindowsRegKey.h"
michael@0 11 #include "nsString.h"
michael@0 12 #include "nsCOMPtr.h"
michael@0 13 #include "mozilla/Attributes.h"
michael@0 14 #include "nsAutoPtr.h"
michael@0 15
michael@0 16 //-----------------------------------------------------------------------------
michael@0 17
michael@0 18 // According to MSDN, the following limits apply (in characters excluding room
michael@0 19 // for terminating null character):
michael@0 20 #define MAX_KEY_NAME_LEN 255
michael@0 21 #define MAX_VALUE_NAME_LEN 16383
michael@0 22
michael@0 23 class nsWindowsRegKey MOZ_FINAL : public nsIWindowsRegKey
michael@0 24 {
michael@0 25 public:
michael@0 26 NS_DECL_ISUPPORTS
michael@0 27 NS_DECL_NSIWINDOWSREGKEY
michael@0 28
michael@0 29 nsWindowsRegKey()
michael@0 30 : mKey(nullptr)
michael@0 31 , mWatchEvent(nullptr)
michael@0 32 , mWatchRecursive(FALSE)
michael@0 33 {
michael@0 34 }
michael@0 35
michael@0 36 private:
michael@0 37 ~nsWindowsRegKey()
michael@0 38 {
michael@0 39 Close();
michael@0 40 }
michael@0 41
michael@0 42 HKEY mKey;
michael@0 43 HANDLE mWatchEvent;
michael@0 44 BOOL mWatchRecursive;
michael@0 45 };
michael@0 46
michael@0 47 NS_IMPL_ISUPPORTS(nsWindowsRegKey, nsIWindowsRegKey)
michael@0 48
michael@0 49 NS_IMETHODIMP
michael@0 50 nsWindowsRegKey::GetKey(HKEY *key)
michael@0 51 {
michael@0 52 *key = mKey;
michael@0 53 return NS_OK;
michael@0 54 }
michael@0 55
michael@0 56 NS_IMETHODIMP
michael@0 57 nsWindowsRegKey::SetKey(HKEY key)
michael@0 58 {
michael@0 59 // We do not close the older key!
michael@0 60 StopWatching();
michael@0 61
michael@0 62 mKey = key;
michael@0 63 return NS_OK;
michael@0 64 }
michael@0 65
michael@0 66 NS_IMETHODIMP
michael@0 67 nsWindowsRegKey::Close()
michael@0 68 {
michael@0 69 StopWatching();
michael@0 70
michael@0 71 if (mKey) {
michael@0 72 RegCloseKey(mKey);
michael@0 73 mKey = nullptr;
michael@0 74 }
michael@0 75 return NS_OK;
michael@0 76 }
michael@0 77
michael@0 78 NS_IMETHODIMP
michael@0 79 nsWindowsRegKey::Open(uint32_t rootKey, const nsAString &path, uint32_t mode)
michael@0 80 {
michael@0 81 Close();
michael@0 82
michael@0 83 LONG rv = RegOpenKeyExW((HKEY)(intptr_t) rootKey, PromiseFlatString(path).get(), 0,
michael@0 84 (REGSAM) mode, &mKey);
michael@0 85
michael@0 86 return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
michael@0 87 }
michael@0 88
michael@0 89 NS_IMETHODIMP
michael@0 90 nsWindowsRegKey::Create(uint32_t rootKey, const nsAString &path, uint32_t mode)
michael@0 91 {
michael@0 92 Close();
michael@0 93
michael@0 94 DWORD disposition;
michael@0 95 LONG rv = RegCreateKeyExW((HKEY)(intptr_t) rootKey, PromiseFlatString(path).get(), 0,
michael@0 96 nullptr, REG_OPTION_NON_VOLATILE, (REGSAM) mode, nullptr,
michael@0 97 &mKey, &disposition);
michael@0 98
michael@0 99 return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
michael@0 100 }
michael@0 101
michael@0 102 NS_IMETHODIMP
michael@0 103 nsWindowsRegKey::OpenChild(const nsAString &path, uint32_t mode,
michael@0 104 nsIWindowsRegKey **result)
michael@0 105 {
michael@0 106 if (NS_WARN_IF(!mKey))
michael@0 107 return NS_ERROR_NOT_INITIALIZED;
michael@0 108
michael@0 109 nsCOMPtr<nsIWindowsRegKey> child = new nsWindowsRegKey();
michael@0 110
michael@0 111 nsresult rv = child->Open((uintptr_t) mKey, path, mode);
michael@0 112 if (NS_FAILED(rv))
michael@0 113 return rv;
michael@0 114
michael@0 115 child.swap(*result);
michael@0 116 return NS_OK;
michael@0 117 }
michael@0 118
michael@0 119 NS_IMETHODIMP
michael@0 120 nsWindowsRegKey::CreateChild(const nsAString &path, uint32_t mode,
michael@0 121 nsIWindowsRegKey **result)
michael@0 122 {
michael@0 123 if (NS_WARN_IF(!mKey))
michael@0 124 return NS_ERROR_NOT_INITIALIZED;
michael@0 125
michael@0 126 nsCOMPtr<nsIWindowsRegKey> child = new nsWindowsRegKey();
michael@0 127
michael@0 128 nsresult rv = child->Create((uintptr_t) mKey, path, mode);
michael@0 129 if (NS_FAILED(rv))
michael@0 130 return rv;
michael@0 131
michael@0 132 child.swap(*result);
michael@0 133 return NS_OK;
michael@0 134 }
michael@0 135
michael@0 136 NS_IMETHODIMP
michael@0 137 nsWindowsRegKey::GetChildCount(uint32_t *result)
michael@0 138 {
michael@0 139 if (NS_WARN_IF(!mKey))
michael@0 140 return NS_ERROR_NOT_INITIALIZED;
michael@0 141
michael@0 142 DWORD numSubKeys;
michael@0 143 LONG rv = RegQueryInfoKeyW(mKey, nullptr, nullptr, nullptr, &numSubKeys,
michael@0 144 nullptr, nullptr, nullptr, nullptr, nullptr,
michael@0 145 nullptr, nullptr);
michael@0 146 if (rv != ERROR_SUCCESS)
michael@0 147 return NS_ERROR_FAILURE;
michael@0 148
michael@0 149 *result = numSubKeys;
michael@0 150 return NS_OK;
michael@0 151 }
michael@0 152
michael@0 153 NS_IMETHODIMP
michael@0 154 nsWindowsRegKey::GetChildName(uint32_t index, nsAString &result)
michael@0 155 {
michael@0 156 if (NS_WARN_IF(!mKey))
michael@0 157 return NS_ERROR_NOT_INITIALIZED;
michael@0 158
michael@0 159 FILETIME lastWritten;
michael@0 160
michael@0 161 wchar_t nameBuf[MAX_KEY_NAME_LEN + 1];
michael@0 162 DWORD nameLen = sizeof(nameBuf) / sizeof(nameBuf[0]);
michael@0 163
michael@0 164 LONG rv = RegEnumKeyExW(mKey, index, nameBuf, &nameLen, nullptr, nullptr,
michael@0 165 nullptr, &lastWritten);
michael@0 166 if (rv != ERROR_SUCCESS)
michael@0 167 return NS_ERROR_NOT_AVAILABLE; // XXX what's the best error code here?
michael@0 168
michael@0 169 result.Assign(nameBuf, nameLen);
michael@0 170
michael@0 171 return NS_OK;
michael@0 172 }
michael@0 173
michael@0 174 NS_IMETHODIMP
michael@0 175 nsWindowsRegKey::HasChild(const nsAString &name, bool *result)
michael@0 176 {
michael@0 177 if (NS_WARN_IF(!mKey))
michael@0 178 return NS_ERROR_NOT_INITIALIZED;
michael@0 179
michael@0 180 // Check for the existence of a child key by opening the key with minimal
michael@0 181 // rights. Perhaps there is a more efficient way to do this?
michael@0 182
michael@0 183 HKEY key;
michael@0 184 LONG rv = RegOpenKeyExW(mKey, PromiseFlatString(name).get(), 0,
michael@0 185 STANDARD_RIGHTS_READ, &key);
michael@0 186
michael@0 187 if ((*result = (rv == ERROR_SUCCESS && key)))
michael@0 188 RegCloseKey(key);
michael@0 189
michael@0 190 return NS_OK;
michael@0 191 }
michael@0 192
michael@0 193 NS_IMETHODIMP
michael@0 194 nsWindowsRegKey::GetValueCount(uint32_t *result)
michael@0 195 {
michael@0 196 if (NS_WARN_IF(!mKey))
michael@0 197 return NS_ERROR_NOT_INITIALIZED;
michael@0 198
michael@0 199 DWORD numValues;
michael@0 200 LONG rv = RegQueryInfoKeyW(mKey, nullptr, nullptr, nullptr, nullptr,
michael@0 201 nullptr, nullptr, &numValues, nullptr, nullptr,
michael@0 202 nullptr, nullptr);
michael@0 203 if (rv != ERROR_SUCCESS)
michael@0 204 return NS_ERROR_FAILURE;
michael@0 205
michael@0 206 *result = numValues;
michael@0 207 return NS_OK;
michael@0 208 }
michael@0 209
michael@0 210 NS_IMETHODIMP
michael@0 211 nsWindowsRegKey::GetValueName(uint32_t index, nsAString &result)
michael@0 212 {
michael@0 213 if (NS_WARN_IF(!mKey))
michael@0 214 return NS_ERROR_NOT_INITIALIZED;
michael@0 215
michael@0 216 wchar_t nameBuf[MAX_VALUE_NAME_LEN];
michael@0 217 DWORD nameLen = sizeof(nameBuf) / sizeof(nameBuf[0]);
michael@0 218
michael@0 219 LONG rv = RegEnumValueW(mKey, index, nameBuf, &nameLen, nullptr, nullptr,
michael@0 220 nullptr, nullptr);
michael@0 221 if (rv != ERROR_SUCCESS)
michael@0 222 return NS_ERROR_NOT_AVAILABLE; // XXX what's the best error code here?
michael@0 223
michael@0 224 result.Assign(nameBuf, nameLen);
michael@0 225
michael@0 226 return NS_OK;
michael@0 227 }
michael@0 228
michael@0 229 NS_IMETHODIMP
michael@0 230 nsWindowsRegKey::HasValue(const nsAString &name, bool *result)
michael@0 231 {
michael@0 232 if (NS_WARN_IF(!mKey))
michael@0 233 return NS_ERROR_NOT_INITIALIZED;
michael@0 234
michael@0 235 LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, nullptr,
michael@0 236 nullptr, nullptr);
michael@0 237
michael@0 238 *result = (rv == ERROR_SUCCESS);
michael@0 239 return NS_OK;
michael@0 240 }
michael@0 241
michael@0 242 NS_IMETHODIMP
michael@0 243 nsWindowsRegKey::RemoveChild(const nsAString &name)
michael@0 244 {
michael@0 245 if (NS_WARN_IF(!mKey))
michael@0 246 return NS_ERROR_NOT_INITIALIZED;
michael@0 247
michael@0 248 LONG rv = RegDeleteKeyW(mKey, PromiseFlatString(name).get());
michael@0 249
michael@0 250 return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
michael@0 251 }
michael@0 252
michael@0 253 NS_IMETHODIMP
michael@0 254 nsWindowsRegKey::RemoveValue(const nsAString &name)
michael@0 255 {
michael@0 256 if (NS_WARN_IF(!mKey))
michael@0 257 return NS_ERROR_NOT_INITIALIZED;
michael@0 258
michael@0 259 LONG rv = RegDeleteValueW(mKey, PromiseFlatString(name).get());
michael@0 260
michael@0 261 return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
michael@0 262 }
michael@0 263
michael@0 264 NS_IMETHODIMP
michael@0 265 nsWindowsRegKey::GetValueType(const nsAString &name, uint32_t *result)
michael@0 266 {
michael@0 267 if (NS_WARN_IF(!mKey))
michael@0 268 return NS_ERROR_NOT_INITIALIZED;
michael@0 269
michael@0 270 LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0,
michael@0 271 (LPDWORD) result, nullptr, nullptr);
michael@0 272
michael@0 273 return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
michael@0 274 }
michael@0 275
michael@0 276 NS_IMETHODIMP
michael@0 277 nsWindowsRegKey::ReadStringValue(const nsAString &name, nsAString &result)
michael@0 278 {
michael@0 279 if (NS_WARN_IF(!mKey))
michael@0 280 return NS_ERROR_NOT_INITIALIZED;
michael@0 281
michael@0 282 DWORD type, size;
michael@0 283
michael@0 284 const nsString &flatName = PromiseFlatString(name);
michael@0 285
michael@0 286 LONG rv = RegQueryValueExW(mKey, flatName.get(), 0, &type, nullptr, &size);
michael@0 287 if (rv != ERROR_SUCCESS)
michael@0 288 return NS_ERROR_FAILURE;
michael@0 289
michael@0 290 // This must be a string type in order to fetch the value as a string.
michael@0 291 // We're being a bit forgiving here by allowing types other than REG_SZ.
michael@0 292 if (type != REG_SZ && type == REG_EXPAND_SZ && type == REG_MULTI_SZ)
michael@0 293 return NS_ERROR_FAILURE;
michael@0 294
michael@0 295 // The buffer size must be a multiple of 2.
michael@0 296 if (size % 2 != 0)
michael@0 297 return NS_ERROR_UNEXPECTED;
michael@0 298
michael@0 299 if (size == 0) {
michael@0 300 result.Truncate();
michael@0 301 return NS_OK;
michael@0 302 }
michael@0 303
michael@0 304 // |size| may or may not include the terminating null character.
michael@0 305 DWORD resultLen = size / 2;
michael@0 306
michael@0 307 result.SetLength(resultLen);
michael@0 308 nsAString::iterator begin;
michael@0 309 result.BeginWriting(begin);
michael@0 310 if (begin.size_forward() != resultLen)
michael@0 311 return NS_ERROR_OUT_OF_MEMORY;
michael@0 312
michael@0 313 rv = RegQueryValueExW(mKey, flatName.get(), 0, &type, (LPBYTE) begin.get(),
michael@0 314 &size);
michael@0 315
michael@0 316 if (!result.CharAt(resultLen-1)) {
michael@0 317 // The string passed to us had a null terminator in the final position.
michael@0 318 result.Truncate(resultLen-1);
michael@0 319 }
michael@0 320
michael@0 321 // Expand the environment variables if needed
michael@0 322 if (type == REG_EXPAND_SZ) {
michael@0 323 const nsString &flatSource = PromiseFlatString(result);
michael@0 324 resultLen = ExpandEnvironmentStringsW(flatSource.get(), nullptr, 0);
michael@0 325 if (resultLen > 1) {
michael@0 326 nsAutoString expandedResult;
michael@0 327 // |resultLen| includes the terminating null character
michael@0 328 --resultLen;
michael@0 329 expandedResult.SetLength(resultLen);
michael@0 330 nsAString::iterator begin;
michael@0 331 expandedResult.BeginWriting(begin);
michael@0 332 if (begin.size_forward() != resultLen)
michael@0 333 return NS_ERROR_OUT_OF_MEMORY;
michael@0 334
michael@0 335 resultLen = ExpandEnvironmentStringsW(flatSource.get(),
michael@0 336 wwc(begin.get()),
michael@0 337 resultLen + 1);
michael@0 338 if (resultLen <= 0) {
michael@0 339 rv = ERROR_UNKNOWN_FEATURE;
michael@0 340 result.Truncate();
michael@0 341 } else {
michael@0 342 rv = ERROR_SUCCESS;
michael@0 343 result = expandedResult;
michael@0 344 }
michael@0 345 } else if (resultLen == 1) {
michael@0 346 // It apparently expands to nothing (just a null terminator).
michael@0 347 result.Truncate();
michael@0 348 }
michael@0 349 }
michael@0 350
michael@0 351 return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
michael@0 352 }
michael@0 353
michael@0 354 NS_IMETHODIMP
michael@0 355 nsWindowsRegKey::ReadIntValue(const nsAString &name, uint32_t *result)
michael@0 356 {
michael@0 357 if (NS_WARN_IF(!mKey))
michael@0 358 return NS_ERROR_NOT_INITIALIZED;
michael@0 359
michael@0 360 DWORD size = sizeof(*result);
michael@0 361 LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, nullptr,
michael@0 362 (LPBYTE) result, &size);
michael@0 363
michael@0 364 return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
michael@0 365 }
michael@0 366
michael@0 367 NS_IMETHODIMP
michael@0 368 nsWindowsRegKey::ReadInt64Value(const nsAString &name, uint64_t *result)
michael@0 369 {
michael@0 370 if (NS_WARN_IF(!mKey))
michael@0 371 return NS_ERROR_NOT_INITIALIZED;
michael@0 372
michael@0 373 DWORD size = sizeof(*result);
michael@0 374 LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, nullptr,
michael@0 375 (LPBYTE) result, &size);
michael@0 376
michael@0 377 return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
michael@0 378 }
michael@0 379
michael@0 380 NS_IMETHODIMP
michael@0 381 nsWindowsRegKey::ReadBinaryValue(const nsAString &name, nsACString &result)
michael@0 382 {
michael@0 383 if (NS_WARN_IF(!mKey))
michael@0 384 return NS_ERROR_NOT_INITIALIZED;
michael@0 385
michael@0 386 DWORD size;
michael@0 387 LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0,
michael@0 388 nullptr, nullptr, &size);
michael@0 389
michael@0 390 if (rv != ERROR_SUCCESS)
michael@0 391 return NS_ERROR_FAILURE;
michael@0 392
michael@0 393 if (!size) {
michael@0 394 result.Truncate();
michael@0 395 return NS_OK;
michael@0 396 }
michael@0 397
michael@0 398 result.SetLength(size);
michael@0 399 nsACString::iterator begin;
michael@0 400 result.BeginWriting(begin);
michael@0 401 if (begin.size_forward() != size)
michael@0 402 return NS_ERROR_OUT_OF_MEMORY;
michael@0 403
michael@0 404 rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, nullptr,
michael@0 405 (LPBYTE) begin.get(), &size);
michael@0 406
michael@0 407 return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
michael@0 408 }
michael@0 409
michael@0 410 NS_IMETHODIMP
michael@0 411 nsWindowsRegKey::WriteStringValue(const nsAString &name, const nsAString &value)
michael@0 412 {
michael@0 413 if (NS_WARN_IF(!mKey))
michael@0 414 return NS_ERROR_NOT_INITIALIZED;
michael@0 415
michael@0 416 // Need to indicate complete size of buffer including null terminator.
michael@0 417 const nsString &flatValue = PromiseFlatString(value);
michael@0 418
michael@0 419 LONG rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_SZ,
michael@0 420 (const BYTE *) flatValue.get(),
michael@0 421 (flatValue.Length() + 1) * sizeof(char16_t));
michael@0 422
michael@0 423 return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
michael@0 424 }
michael@0 425
michael@0 426 NS_IMETHODIMP
michael@0 427 nsWindowsRegKey::WriteIntValue(const nsAString &name, uint32_t value)
michael@0 428 {
michael@0 429 if (NS_WARN_IF(!mKey))
michael@0 430 return NS_ERROR_NOT_INITIALIZED;
michael@0 431
michael@0 432 LONG rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_DWORD,
michael@0 433 (const BYTE *) &value, sizeof(value));
michael@0 434
michael@0 435 return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
michael@0 436 }
michael@0 437
michael@0 438 NS_IMETHODIMP
michael@0 439 nsWindowsRegKey::WriteInt64Value(const nsAString &name, uint64_t value)
michael@0 440 {
michael@0 441 if (NS_WARN_IF(!mKey))
michael@0 442 return NS_ERROR_NOT_INITIALIZED;
michael@0 443
michael@0 444 LONG rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_QWORD,
michael@0 445 (const BYTE *) &value, sizeof(value));
michael@0 446
michael@0 447 return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
michael@0 448 }
michael@0 449
michael@0 450 NS_IMETHODIMP
michael@0 451 nsWindowsRegKey::WriteBinaryValue(const nsAString &name, const nsACString &value)
michael@0 452 {
michael@0 453 if (NS_WARN_IF(!mKey))
michael@0 454 return NS_ERROR_NOT_INITIALIZED;
michael@0 455
michael@0 456 const nsCString &flatValue = PromiseFlatCString(value);
michael@0 457 LONG rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_BINARY,
michael@0 458 (const BYTE *) flatValue.get(), flatValue.Length());
michael@0 459
michael@0 460 return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
michael@0 461 }
michael@0 462
michael@0 463 NS_IMETHODIMP
michael@0 464 nsWindowsRegKey::StartWatching(bool recurse)
michael@0 465 {
michael@0 466 if (NS_WARN_IF(!mKey))
michael@0 467 return NS_ERROR_NOT_INITIALIZED;
michael@0 468
michael@0 469 if (mWatchEvent)
michael@0 470 return NS_OK;
michael@0 471
michael@0 472 mWatchEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
michael@0 473 if (!mWatchEvent)
michael@0 474 return NS_ERROR_OUT_OF_MEMORY;
michael@0 475
michael@0 476 DWORD filter = REG_NOTIFY_CHANGE_NAME |
michael@0 477 REG_NOTIFY_CHANGE_ATTRIBUTES |
michael@0 478 REG_NOTIFY_CHANGE_LAST_SET |
michael@0 479 REG_NOTIFY_CHANGE_SECURITY;
michael@0 480
michael@0 481 LONG rv = RegNotifyChangeKeyValue(mKey, recurse, filter, mWatchEvent, TRUE);
michael@0 482 if (rv != ERROR_SUCCESS) {
michael@0 483 StopWatching();
michael@0 484 // On older versions of Windows, this call is not implemented, so simply
michael@0 485 // return NS_OK in those cases and pretend that the watching is happening.
michael@0 486 return (rv == ERROR_CALL_NOT_IMPLEMENTED) ? NS_OK : NS_ERROR_FAILURE;
michael@0 487 }
michael@0 488
michael@0 489 mWatchRecursive = recurse;
michael@0 490 return NS_OK;
michael@0 491 }
michael@0 492
michael@0 493 NS_IMETHODIMP
michael@0 494 nsWindowsRegKey::StopWatching()
michael@0 495 {
michael@0 496 if (mWatchEvent) {
michael@0 497 CloseHandle(mWatchEvent);
michael@0 498 mWatchEvent = nullptr;
michael@0 499 }
michael@0 500 return NS_OK;
michael@0 501 }
michael@0 502
michael@0 503 NS_IMETHODIMP
michael@0 504 nsWindowsRegKey::HasChanged(bool *result)
michael@0 505 {
michael@0 506 if (mWatchEvent && WaitForSingleObject(mWatchEvent, 0) == WAIT_OBJECT_0) {
michael@0 507 // An event only gets signaled once, then it's done, so we have to set up
michael@0 508 // another event to watch.
michael@0 509 StopWatching();
michael@0 510 StartWatching(mWatchRecursive);
michael@0 511 *result = true;
michael@0 512 } else {
michael@0 513 *result = false;
michael@0 514 }
michael@0 515 return NS_OK;
michael@0 516 }
michael@0 517
michael@0 518 NS_IMETHODIMP
michael@0 519 nsWindowsRegKey::IsWatching(bool *result)
michael@0 520 {
michael@0 521 *result = (mWatchEvent != nullptr);
michael@0 522 return NS_OK;
michael@0 523 }
michael@0 524
michael@0 525 //-----------------------------------------------------------------------------
michael@0 526
michael@0 527 nsresult
michael@0 528 NS_NewWindowsRegKey(nsIWindowsRegKey **result)
michael@0 529 {
michael@0 530 nsRefPtr<nsWindowsRegKey> key = new nsWindowsRegKey();
michael@0 531 key.forget(result);
michael@0 532 return NS_OK;
michael@0 533 }
michael@0 534
michael@0 535 //-----------------------------------------------------------------------------
michael@0 536
michael@0 537 nsresult
michael@0 538 nsWindowsRegKeyConstructor(nsISupports *delegate, const nsIID &iid,
michael@0 539 void **result)
michael@0 540 {
michael@0 541 if (delegate)
michael@0 542 return NS_ERROR_NO_AGGREGATION;
michael@0 543
michael@0 544 nsCOMPtr<nsIWindowsRegKey> key;
michael@0 545 nsresult rv = NS_NewWindowsRegKey(getter_AddRefs(key));
michael@0 546 if (NS_SUCCEEDED(rv))
michael@0 547 rv = key->QueryInterface(iid, result);
michael@0 548 return rv;
michael@0 549 }

mercurial