Back to index

lightning-sunbird  0.9+nobinonly
nsWindowsRegKey.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim:set ts=2 sw=2 sts=2 et cindent: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is Google Inc.
00019  * Portions created by the Initial Developer are Copyright (C) 2005
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Darin Fisher <darin@meer.net>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include <windows.h>
00040 #include <shlwapi.h>
00041 #include <stdlib.h>
00042 #include "nsWindowsRegKey.h"
00043 #include "nsNativeCharsetUtils.h"
00044 #include "nsString.h"
00045 #include "nsCOMPtr.h"
00046 
00047 // The Platform SDK included with VC6 does not define REG_QWORD.  VC 7's
00048 // WinNT.h defines REG_QWORD as follows:
00049 #ifndef REG_QWORD
00050 # define REG_QWORD 11
00051 #endif
00052 
00053 //-----------------------------------------------------------------------------
00054 
00055 // This class simplifies conversion from unicode to native charset somewhat.
00056 class PromiseNativeString : public nsCAutoString
00057 {
00058 public:
00059   PromiseNativeString(const nsAString &input)
00060   {
00061     NS_CopyUnicodeToNative(input, *this);
00062   }
00063 };
00064 
00065 //-----------------------------------------------------------------------------
00066 
00067 // According to MSDN, the following limits apply (in characters excluding room
00068 // for terminating null character):
00069 #define MAX_KEY_NAME_LEN     255
00070 #define MAX_VALUE_NAME_LEN_W 16383
00071 #define MAX_VALUE_NAME_LEN_A 255
00072 
00073 class nsWindowsRegKey : public nsIWindowsRegKey
00074 {
00075 public:
00076   NS_DECL_ISUPPORTS
00077   NS_DECL_NSIWINDOWSREGKEY
00078 
00079   nsWindowsRegKey()
00080     : mKey(NULL)
00081     , mWatchEvent(NULL)
00082     , mWatchRecursive(FALSE)
00083   {
00084     if (sUseUnicode == -1)
00085       GlobalInit();
00086   }
00087 
00088 private:
00089   ~nsWindowsRegKey()
00090   {
00091     Close();
00092   }
00093 
00094   HKEY   mKey;
00095   HANDLE mWatchEvent;
00096   BOOL   mWatchRecursive;
00097 
00098   static int sUseUnicode;
00099 
00100   static void GlobalInit();
00101 };
00102 
00103 int
00104 nsWindowsRegKey::sUseUnicode = -1;  // undetermined
00105 
00106 void
00107 nsWindowsRegKey::GlobalInit()
00108 {
00109 #ifdef DEBUG
00110   // In debug builds, allow explicit use of ANSI methods for testing purposes.
00111   if (getenv("WINREG_USE_ANSI")) {
00112     sUseUnicode = PR_FALSE;
00113     return;
00114   }
00115 #endif
00116 
00117   // Find out if we are running on a unicode enabled version of Windows
00118   OSVERSIONINFOA osvi = {0};
00119   osvi.dwOSVersionInfoSize = sizeof(osvi);
00120   if (!GetVersionExA(&osvi)) {
00121     sUseUnicode = PR_FALSE;
00122   } else {
00123     sUseUnicode = (osvi.dwPlatformId >= VER_PLATFORM_WIN32_NT);
00124   }
00125 }
00126 
00127 NS_IMPL_ISUPPORTS1(nsWindowsRegKey, nsIWindowsRegKey)
00128 
00129 NS_IMETHODIMP
00130 nsWindowsRegKey::GetKey(HKEY *key)
00131 {
00132   *key = mKey;
00133   return NS_OK;
00134 }
00135 
00136 NS_IMETHODIMP
00137 nsWindowsRegKey::SetKey(HKEY key)
00138 {
00139   // We do not close the older key!
00140   StopWatching();
00141 
00142   mKey = key;
00143   return NS_OK;
00144 }
00145 
00146 NS_IMETHODIMP
00147 nsWindowsRegKey::Close()
00148 {
00149   StopWatching();
00150 
00151   if (mKey) {
00152     RegCloseKey(mKey);
00153     mKey = NULL;
00154   }
00155   return NS_OK;
00156 }
00157 
00158 NS_IMETHODIMP
00159 nsWindowsRegKey::Open(PRUint32 rootKey, const nsAString &path, PRUint32 mode)
00160 {
00161   Close();
00162 
00163   LONG rv;
00164 
00165   if (sUseUnicode) {
00166     rv = RegOpenKeyExW((HKEY) rootKey, PromiseFlatString(path).get(), 0,
00167                        (REGSAM) mode, &mKey);
00168   } else {
00169     rv = RegOpenKeyExA((HKEY) rootKey, PromiseNativeString(path).get(), 0,
00170                        (REGSAM) mode, &mKey);
00171   }
00172 
00173   return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
00174 }
00175 
00176 NS_IMETHODIMP
00177 nsWindowsRegKey::Create(PRUint32 rootKey, const nsAString &path, PRUint32 mode)
00178 {
00179   Close();
00180 
00181   DWORD disposition;
00182   LONG rv;
00183   if (sUseUnicode) {
00184     rv = RegCreateKeyExW((HKEY) rootKey, PromiseFlatString(path).get(), 0,
00185                          NULL, REG_OPTION_NON_VOLATILE, (REGSAM) mode, NULL,
00186                          &mKey, &disposition);
00187   } else {
00188     rv = RegCreateKeyExA((HKEY) rootKey, PromiseNativeString(path).get(), 0,
00189                          NULL, REG_OPTION_NON_VOLATILE, (REGSAM) mode, NULL,
00190                          &mKey, &disposition);
00191   }
00192 
00193   return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
00194 }
00195 
00196 NS_IMETHODIMP
00197 nsWindowsRegKey::OpenChild(const nsAString &path, PRUint32 mode,
00198                            nsIWindowsRegKey **result)
00199 {
00200   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00201 
00202   nsCOMPtr<nsIWindowsRegKey> child = new nsWindowsRegKey();
00203   if (!child)
00204     return NS_ERROR_OUT_OF_MEMORY;
00205   
00206   nsresult rv = child->Open((PRUint32) mKey, path, mode);
00207   if (NS_FAILED(rv))
00208     return rv;
00209 
00210   child.swap(*result);
00211   return NS_OK;
00212 }
00213 
00214 NS_IMETHODIMP
00215 nsWindowsRegKey::CreateChild(const nsAString &path, PRUint32 mode,
00216                              nsIWindowsRegKey **result)
00217 {
00218   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00219 
00220   nsCOMPtr<nsIWindowsRegKey> child = new nsWindowsRegKey();
00221   if (!child)
00222     return NS_ERROR_OUT_OF_MEMORY;
00223   
00224   nsresult rv = child->Create((PRUint32) mKey, path, mode);
00225   if (NS_FAILED(rv))
00226     return rv;
00227 
00228   child.swap(*result);
00229   return NS_OK;
00230 }
00231 
00232 NS_IMETHODIMP
00233 nsWindowsRegKey::GetChildCount(PRUint32 *result)
00234 {
00235   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00236 
00237   // We just use the 'A' version of this function here since there are no
00238   // string parameters that we care about.
00239   
00240   DWORD numSubKeys;
00241   LONG rv = RegQueryInfoKeyA(mKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL,
00242                              NULL, NULL, NULL, NULL, NULL);
00243   NS_ENSURE_STATE(rv == ERROR_SUCCESS);
00244 
00245   *result = numSubKeys;
00246   return NS_OK;
00247 }
00248 
00249 NS_IMETHODIMP
00250 nsWindowsRegKey::GetChildName(PRUint32 index, nsAString &result)
00251 {
00252   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00253 
00254   FILETIME lastWritten;
00255   LONG rv;
00256 
00257   if (sUseUnicode) {
00258     PRUnichar nameBuf[MAX_KEY_NAME_LEN + 1];
00259     DWORD nameLen = sizeof(nameBuf) / sizeof(nameBuf[0]);
00260 
00261     rv = RegEnumKeyExW(mKey, index, nameBuf, &nameLen, NULL, NULL, NULL,
00262                        &lastWritten);
00263     if (rv != ERROR_SUCCESS)
00264       return NS_ERROR_NOT_AVAILABLE;  // XXX what's the best error code here?
00265 
00266     result.Assign(nameBuf, nameLen);
00267   } else {
00268     char nameBuf[MAX_KEY_NAME_LEN + 1];
00269     DWORD nameLen = sizeof(nameBuf) / sizeof(nameBuf[0]);
00270 
00271     rv = RegEnumKeyExA(mKey, index, nameBuf, &nameLen, NULL, NULL, NULL,
00272                        &lastWritten);
00273 
00274     if (rv != ERROR_SUCCESS)
00275       return NS_ERROR_NOT_AVAILABLE;  // XXX what's the best error code here?
00276 
00277     NS_CopyNativeToUnicode(nsDependentCString(nameBuf, nameLen), result);
00278   }
00279   return NS_OK;
00280 }
00281 
00282 NS_IMETHODIMP
00283 nsWindowsRegKey::HasChild(const nsAString &name, PRBool *result)
00284 {
00285   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00286 
00287   // Check for the existance of a child key by opening the key with minimal
00288   // rights.  Perhaps there is a more efficient way to do this?
00289 
00290   HKEY key;
00291   LONG rv;
00292 
00293   if (sUseUnicode) {
00294     rv = RegOpenKeyExW(mKey, PromiseFlatString(name).get(), 0,
00295                        STANDARD_RIGHTS_READ, &key);
00296   } else {
00297     rv = RegOpenKeyExA(mKey, PromiseNativeString(name).get(), 0,
00298                        STANDARD_RIGHTS_READ, &key);
00299   }
00300   if (*result = (rv == ERROR_SUCCESS && key))
00301     RegCloseKey(key);
00302 
00303   return NS_OK;
00304 }
00305 
00306 NS_IMETHODIMP
00307 nsWindowsRegKey::GetValueCount(PRUint32 *result)
00308 {
00309   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00310 
00311   // We just use the 'A' version of this function here since there are no
00312   // string parameters that we care about.
00313 
00314   DWORD numValues;
00315   LONG rv = RegQueryInfoKeyA(mKey, NULL, NULL, NULL, NULL, NULL, NULL,
00316                              &numValues, NULL, NULL, NULL, NULL);
00317   NS_ENSURE_STATE(rv == ERROR_SUCCESS);
00318 
00319   *result = numValues;
00320   return NS_OK;
00321 }
00322 
00323 NS_IMETHODIMP
00324 nsWindowsRegKey::GetValueName(PRUint32 index, nsAString &result)
00325 {
00326   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00327 
00328   if (sUseUnicode) {
00329     PRUnichar nameBuf[MAX_VALUE_NAME_LEN_W];
00330     DWORD nameLen = sizeof(nameBuf) / sizeof(nameBuf[0]);
00331 
00332     LONG rv = RegEnumValueW(mKey, index, nameBuf, &nameLen, NULL, NULL, NULL,
00333                             NULL);
00334     if (rv != ERROR_SUCCESS)
00335       return NS_ERROR_NOT_AVAILABLE;  // XXX what's the best error code here?
00336 
00337     result.Assign(nameBuf, nameLen);
00338   } else {
00339     char nameBuf[MAX_VALUE_NAME_LEN_A];
00340     DWORD nameLen = sizeof(nameBuf) / sizeof(nameBuf[0]);
00341 
00342     LONG rv = RegEnumValueA(mKey, index, nameBuf, &nameLen, NULL, NULL, NULL,
00343                             NULL);
00344     if (rv != ERROR_SUCCESS)
00345       return NS_ERROR_NOT_AVAILABLE;  // XXX what's the best error code here?
00346 
00347     NS_CopyNativeToUnicode(nsDependentCString(nameBuf, nameLen), result);
00348   }
00349 
00350   return NS_OK;
00351 }
00352 
00353 NS_IMETHODIMP
00354 nsWindowsRegKey::HasValue(const nsAString &name, PRBool *result)
00355 {
00356   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00357 
00358   LONG rv;
00359   if (sUseUnicode) {
00360     rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, NULL, NULL,
00361                           NULL);
00362   } else {
00363     rv = RegQueryValueExA(mKey, PromiseNativeString(name).get(), 0, NULL, NULL,
00364                           NULL);
00365   }
00366 
00367   *result = (rv == ERROR_SUCCESS);
00368   return NS_OK;
00369 }
00370 
00371 NS_IMETHODIMP
00372 nsWindowsRegKey::RemoveChild(const nsAString &name)
00373 {
00374   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00375 
00376   LONG rv;
00377   if (sUseUnicode) {
00378     rv = RegDeleteKeyW(mKey, PromiseFlatString(name).get());
00379   } else {
00380     rv = RegDeleteKeyA(mKey, PromiseNativeString(name).get());
00381   }
00382 
00383   return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
00384 }
00385 
00386 NS_IMETHODIMP
00387 nsWindowsRegKey::RemoveValue(const nsAString &name)
00388 {
00389   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00390 
00391   LONG rv;
00392   if (sUseUnicode) {
00393     rv = RegDeleteValueW(mKey, PromiseFlatString(name).get());
00394   } else {
00395     rv = RegDeleteValueA(mKey, PromiseNativeString(name).get());
00396   }
00397 
00398   return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
00399 }
00400 
00401 NS_IMETHODIMP
00402 nsWindowsRegKey::GetValueType(const nsAString &name, PRUint32 *result)
00403 {
00404   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00405 
00406   LONG rv;
00407   if (sUseUnicode) {
00408     rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0,
00409                           (LPDWORD) result, NULL, NULL);
00410   } else {
00411     rv = RegQueryValueExA(mKey, PromiseNativeString(name).get(), 0,
00412                           (LPDWORD) result, NULL, NULL);
00413   }
00414 
00415   return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
00416 }
00417 
00418 NS_IMETHODIMP
00419 nsWindowsRegKey::ReadStringValue(const nsAString &name, nsAString &result)
00420 {
00421   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00422 
00423   DWORD type, size;
00424   LONG rv;
00425   
00426   if (sUseUnicode) {
00427     const nsString &flatName = PromiseFlatString(name);
00428 
00429     rv = RegQueryValueExW(mKey, flatName.get(), 0, &type, NULL, &size);
00430     if (rv != ERROR_SUCCESS)
00431       return NS_ERROR_FAILURE;
00432 
00433     // This must be a string type in order to fetch the value as a string.
00434     // We're being a bit forgiving here by allowing types other than REG_SZ.
00435     NS_ENSURE_STATE(type == REG_SZ ||
00436                     type == REG_EXPAND_SZ ||
00437                     type == REG_MULTI_SZ);
00438 
00439     // The buffer size must be a multiple of 2.
00440     NS_ENSURE_STATE(size % 2 == 0);
00441 
00442     if (size == 0) {
00443       result.Truncate();
00444       return NS_OK;
00445     }
00446 
00447     // |size| includes room for the terminating null character
00448     DWORD resultLen = size / 2 - 1;
00449 
00450     result.SetLength(resultLen);
00451     nsAString::iterator begin;
00452     result.BeginWriting(begin);
00453     if (begin.size_forward() != resultLen)
00454       return NS_ERROR_OUT_OF_MEMORY;
00455 
00456     rv = RegQueryValueExW(mKey, flatName.get(), 0, NULL, (LPBYTE) begin.get(),
00457                           &size);
00458   } else {
00459     PromiseNativeString nativeName(name);
00460 
00461     rv = RegQueryValueExA(mKey, nativeName.get(), 0, &type, NULL, &size);
00462     if (rv != ERROR_SUCCESS)
00463       return NS_ERROR_FAILURE;
00464 
00465     // This must be a string type in order to fetch the value as a string.
00466     // We're being a bit forgiving here by allowing types other than REG_SZ.
00467     NS_ENSURE_STATE(type == REG_SZ ||
00468                     type == REG_EXPAND_SZ ||
00469                     type == REG_MULTI_SZ);
00470 
00471     if (size == 0) {
00472       result.Truncate();
00473       return NS_OK;
00474     }
00475 
00476     nsCAutoString buf;
00477     buf.SetLength(size - 1);
00478     nsACString::iterator begin;
00479     buf.BeginWriting(begin);
00480     if (begin.size_forward() != (size - 1))
00481       return NS_ERROR_OUT_OF_MEMORY;
00482 
00483     rv = RegQueryValueExA(mKey, nativeName.get(), 0, NULL,
00484                           (LPBYTE) begin.get(), &size);
00485     if (rv == ERROR_SUCCESS)
00486       NS_CopyNativeToUnicode(buf, result);
00487   }
00488 
00489   return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
00490 }
00491 
00492 NS_IMETHODIMP
00493 nsWindowsRegKey::ReadIntValue(const nsAString &name, PRUint32 *result)
00494 {
00495   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00496 
00497   DWORD size = sizeof(*result);
00498   LONG rv;
00499   
00500   if (sUseUnicode) {
00501     rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, NULL,
00502                           (LPBYTE) result, &size);
00503   } else {
00504     rv = RegQueryValueExA(mKey, PromiseNativeString(name).get(), 0, NULL,
00505                           (LPBYTE) result, &size);
00506   }
00507 
00508   return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
00509 }
00510 
00511 NS_IMETHODIMP
00512 nsWindowsRegKey::ReadInt64Value(const nsAString &name, PRUint64 *result)
00513 {
00514   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00515 
00516   DWORD size = sizeof(*result);
00517   LONG rv;
00518 
00519   if (sUseUnicode) {
00520     rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, NULL,
00521                           (LPBYTE) result, &size);
00522   } else {
00523     rv = RegQueryValueExA(mKey, PromiseNativeString(name).get(), 0, NULL,
00524                           (LPBYTE) result, &size);
00525   }
00526 
00527   return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
00528 }
00529 
00530 NS_IMETHODIMP
00531 nsWindowsRegKey::ReadBinaryValue(const nsAString &name, nsACString &result)
00532 {
00533   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00534 
00535   DWORD size;
00536   LONG rv;
00537 
00538   if (sUseUnicode) {
00539     rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0,
00540                           NULL, NULL, &size);
00541   } else {
00542     rv = RegQueryValueExA(mKey, PromiseNativeString(name).get(), 0,
00543                           NULL, NULL, &size);
00544   }
00545   if (rv != ERROR_SUCCESS)
00546     return NS_ERROR_FAILURE;
00547 
00548   result.SetLength(size);
00549   nsACString::iterator begin;
00550   result.BeginWriting(begin);
00551   if (begin.size_forward() != size)
00552     return NS_ERROR_OUT_OF_MEMORY;
00553 
00554   if (sUseUnicode) {
00555     rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, NULL,
00556                           (LPBYTE) begin.get(), &size);
00557   } else {
00558     rv = RegQueryValueExA(mKey, PromiseNativeString(name).get(), 0, NULL,
00559                           (LPBYTE) begin.get(), &size);
00560   }
00561 
00562   return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
00563 }
00564 
00565 NS_IMETHODIMP
00566 nsWindowsRegKey::WriteStringValue(const nsAString &name, const nsAString &value)
00567 {
00568   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00569 
00570   LONG rv;
00571 
00572   // Need to indicate complete size of buffer including null terminator.
00573 
00574   if (sUseUnicode) {
00575     const nsString &flatValue = PromiseFlatString(value);
00576 
00577     rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_SZ,
00578                         (const BYTE *) flatValue.get(),
00579                         (flatValue.Length() + 1) * sizeof(PRUnichar));
00580   } else {
00581     PromiseNativeString nativeValue(value);
00582 
00583     rv = RegSetValueExA(mKey, PromiseNativeString(name).get(), 0, REG_SZ,
00584                         (const BYTE *) nativeValue.get(),
00585                         (nativeValue.Length() + 1) * sizeof(char));
00586   }
00587 
00588   return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
00589 }
00590 
00591 NS_IMETHODIMP
00592 nsWindowsRegKey::WriteIntValue(const nsAString &name, PRUint32 value)
00593 {
00594   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00595 
00596   LONG rv;
00597   
00598   if (sUseUnicode) {
00599     rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_DWORD,
00600                         (const BYTE *) &value, sizeof(value));
00601   } else {
00602     rv = RegSetValueExA(mKey, PromiseNativeString(name).get(), 0, REG_DWORD,
00603                         (const BYTE *) &value, sizeof(value));
00604   }
00605 
00606   return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
00607 }
00608 
00609 NS_IMETHODIMP
00610 nsWindowsRegKey::WriteInt64Value(const nsAString &name, PRUint64 value)
00611 {
00612   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00613 
00614   LONG rv;
00615 
00616   if (sUseUnicode) {
00617     rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_QWORD,
00618                         (const BYTE *) &value, sizeof(value));
00619   } else {
00620     rv = RegSetValueExA(mKey, PromiseNativeString(name).get(), 0, REG_QWORD,
00621                         (const BYTE *) &value, sizeof(value));
00622   }
00623 
00624   return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
00625 }
00626 
00627 NS_IMETHODIMP
00628 nsWindowsRegKey::WriteBinaryValue(const nsAString &name, const nsACString &value)
00629 {
00630   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00631 
00632   const nsCString &flatValue = PromiseFlatCString(value);
00633   LONG rv;
00634 
00635   if (sUseUnicode) {
00636     rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_BINARY,
00637                         (const BYTE *) flatValue.get(), flatValue.Length());
00638   } else {
00639     rv = RegSetValueExA(mKey, PromiseNativeString(name).get(), 0, REG_BINARY,
00640                         (const BYTE *) flatValue.get(), flatValue.Length());
00641   }
00642 
00643   return (rv == ERROR_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
00644 }
00645 
00646 NS_IMETHODIMP
00647 nsWindowsRegKey::StartWatching(PRBool recurse)
00648 {
00649 #ifdef WINCE
00650   return NS_ERROR_NOT_IMPLEMENTED;
00651 #else
00652 
00653   NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED);
00654 
00655   if (mWatchEvent)
00656     return NS_OK;
00657   
00658   mWatchEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
00659   if (!mWatchEvent)
00660     return NS_ERROR_OUT_OF_MEMORY;
00661   
00662   DWORD filter = REG_NOTIFY_CHANGE_NAME |
00663                  REG_NOTIFY_CHANGE_ATTRIBUTES |
00664                  REG_NOTIFY_CHANGE_LAST_SET |
00665                  REG_NOTIFY_CHANGE_SECURITY;
00666 
00667   LONG rv = RegNotifyChangeKeyValue(mKey, recurse, filter, mWatchEvent, TRUE);
00668   if (rv != ERROR_SUCCESS) {
00669     StopWatching();
00670     // On older versions of Windows, this call is not implemented, so simply
00671     // return NS_OK in those cases and pretend that the watching is happening.
00672     return (rv == ERROR_CALL_NOT_IMPLEMENTED) ? NS_OK : NS_ERROR_FAILURE;
00673   }
00674 
00675   mWatchRecursive = recurse;
00676   return NS_OK;
00677 #endif
00678 }
00679 
00680 NS_IMETHODIMP
00681 nsWindowsRegKey::StopWatching()
00682 {
00683   if (mWatchEvent) {
00684     CloseHandle(mWatchEvent);
00685     mWatchEvent = NULL;
00686   }
00687   return NS_OK;
00688 }
00689 
00690 NS_IMETHODIMP
00691 nsWindowsRegKey::HasChanged(PRBool *result)
00692 {
00693   if (mWatchEvent && WaitForSingleObject(mWatchEvent, 0) == WAIT_OBJECT_0) {
00694     // An event only gets signaled once, then it's done, so we have to set up
00695     // another event to watch.
00696     StopWatching();
00697     StartWatching(mWatchRecursive);
00698     *result = PR_TRUE;
00699   } else {
00700     *result = PR_FALSE;
00701   }
00702   return NS_OK;
00703 }
00704 
00705 NS_IMETHODIMP
00706 nsWindowsRegKey::IsWatching(PRBool *result)
00707 {
00708   *result = (mWatchEvent != NULL);
00709   return NS_OK;
00710 }
00711 
00712 //-----------------------------------------------------------------------------
00713 
00714 nsresult
00715 NS_NewWindowsRegKey(nsIWindowsRegKey **result)
00716 {
00717   *result = new nsWindowsRegKey();
00718   if (!*result)
00719     return NS_ERROR_OUT_OF_MEMORY;
00720 
00721   NS_ADDREF(*result);
00722   return NS_OK;
00723 }
00724 
00725 //-----------------------------------------------------------------------------
00726 
00727 NS_METHOD
00728 nsWindowsRegKeyConstructor(nsISupports *delegate, const nsIID &iid,
00729                            void **result)
00730 {
00731   if (delegate)
00732     return NS_ERROR_NO_AGGREGATION;
00733 
00734   nsCOMPtr<nsIWindowsRegKey> key;
00735   nsresult rv = NS_NewWindowsRegKey(getter_AddRefs(key));
00736   if (NS_SUCCEEDED(rv))
00737     rv = key->QueryInterface(iid, result);
00738   return rv;
00739 }