browser/components/shell/src/nsWindowsShellService.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "imgIContainer.h"
     7 #include "imgIRequest.h"
     8 #include "mozilla/gfx/2D.h"
     9 #include "mozilla/RefPtr.h"
    10 #include "nsIDOMElement.h"
    11 #include "nsIDOMHTMLImageElement.h"
    12 #include "nsIImageLoadingContent.h"
    13 #include "nsIPrefService.h"
    14 #include "nsIPrefLocalizedString.h"
    15 #include "nsIServiceManager.h"
    16 #include "nsIStringBundle.h"
    17 #include "nsNetUtil.h"
    18 #include "nsShellService.h"
    19 #include "nsWindowsShellService.h"
    20 #include "nsIProcess.h"
    21 #include "nsICategoryManager.h"
    22 #include "nsBrowserCompsCID.h"
    23 #include "nsDirectoryServiceUtils.h"
    24 #include "nsAppDirectoryServiceDefs.h"
    25 #include "nsDirectoryServiceDefs.h"
    26 #include "nsIWindowsRegKey.h"
    27 #include "nsUnicharUtils.h"
    28 #include "nsIWinTaskbar.h"
    29 #include "nsISupportsPrimitives.h"
    30 #include "nsThreadUtils.h"
    31 #include "nsXULAppAPI.h"
    32 #include "mozilla/WindowsVersion.h"
    34 #include "windows.h"
    35 #include "shellapi.h"
    37 #ifdef _WIN32_WINNT
    38 #undef _WIN32_WINNT
    39 #endif
    40 #define _WIN32_WINNT 0x0600
    41 #define INITGUID
    42 #include <shlobj.h>
    44 #include <mbstring.h>
    45 #include <shlwapi.h>
    47 #ifndef MAX_BUF
    48 #define MAX_BUF 4096
    49 #endif
    51 #define REG_SUCCEEDED(val) \
    52   (val == ERROR_SUCCESS)
    54 #define REG_FAILED(val) \
    55   (val != ERROR_SUCCESS)
    57 #define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
    59 using mozilla::IsWin8OrLater;
    60 using namespace mozilla;
    61 using namespace mozilla::gfx;
    63 NS_IMPL_ISUPPORTS(nsWindowsShellService, nsIWindowsShellService, nsIShellService)
    65 static nsresult
    66 OpenKeyForReading(HKEY aKeyRoot, const nsAString& aKeyName, HKEY* aKey)
    67 {
    68   const nsString &flatName = PromiseFlatString(aKeyName);
    70   DWORD res = ::RegOpenKeyExW(aKeyRoot, flatName.get(), 0, KEY_READ, aKey);
    71   switch (res) {
    72   case ERROR_SUCCESS:
    73     break;
    74   case ERROR_ACCESS_DENIED:
    75     return NS_ERROR_FILE_ACCESS_DENIED;
    76   case ERROR_FILE_NOT_FOUND:
    77     return NS_ERROR_NOT_AVAILABLE;
    78   }
    80   return NS_OK;
    81 }
    83 ///////////////////////////////////////////////////////////////////////////////
    84 // Default Browser Registry Settings
    85 //
    86 // The setting of these values are made by an external binary since writing
    87 // these values may require elevation.
    88 //
    89 // - File Extension Mappings
    90 //   -----------------------
    91 //   The following file extensions:
    92 //    .htm .html .shtml .xht .xhtml 
    93 //   are mapped like so:
    94 //
    95 //   HKCU\SOFTWARE\Classes\.<ext>\      (default)         REG_SZ     FirefoxHTML
    96 //
    97 //   as aliases to the class:
    98 //
    99 //   HKCU\SOFTWARE\Classes\FirefoxHTML\
   100 //     DefaultIcon                      (default)         REG_SZ     <apppath>,1
   101 //     shell\open\command               (default)         REG_SZ     <apppath> -osint -url "%1"
   102 //     shell\open\ddeexec               (default)         REG_SZ     <empty string>
   103 //
   104 // - Windows Vista and above Protocol Handler
   105 //
   106 //   HKCU\SOFTWARE\Classes\FirefoxURL\  (default)         REG_SZ     <appname> URL
   107 //                                      EditFlags         REG_DWORD  2
   108 //                                      FriendlyTypeName  REG_SZ     <appname> URL
   109 //     DefaultIcon                      (default)         REG_SZ     <apppath>,1
   110 //     shell\open\command               (default)         REG_SZ     <apppath> -osint -url "%1"
   111 //     shell\open\ddeexec               (default)         REG_SZ     <empty string>
   112 //
   113 // - Protocol Mappings
   114 //   -----------------
   115 //   The following protocols:
   116 //    HTTP, HTTPS, FTP
   117 //   are mapped like so:
   118 //
   119 //   HKCU\SOFTWARE\Classes\<protocol>\
   120 //     DefaultIcon                      (default)         REG_SZ     <apppath>,1
   121 //     shell\open\command               (default)         REG_SZ     <apppath> -osint -url "%1"
   122 //     shell\open\ddeexec               (default)         REG_SZ     <empty string>
   123 //
   124 // - Windows Start Menu (XP SP1 and newer)
   125 //   -------------------------------------------------
   126 //   The following keys are set to make Firefox appear in the Start Menu as the
   127 //   browser:
   128 //   
   129 //   HKCU\SOFTWARE\Clients\StartMenuInternet\FIREFOX.EXE\
   130 //                                      (default)         REG_SZ     <appname>
   131 //     DefaultIcon                      (default)         REG_SZ     <apppath>,0
   132 //     InstallInfo                      HideIconsCommand  REG_SZ     <uninstpath> /HideShortcuts
   133 //     InstallInfo                      IconsVisible      REG_DWORD  1
   134 //     InstallInfo                      ReinstallCommand  REG_SZ     <uninstpath> /SetAsDefaultAppGlobal
   135 //     InstallInfo                      ShowIconsCommand  REG_SZ     <uninstpath> /ShowShortcuts
   136 //     shell\open\command               (default)         REG_SZ     <apppath>
   137 //     shell\properties                 (default)         REG_SZ     <appname> &Options
   138 //     shell\properties\command         (default)         REG_SZ     <apppath> -preferences
   139 //     shell\safemode                   (default)         REG_SZ     <appname> &Safe Mode
   140 //     shell\safemode\command           (default)         REG_SZ     <apppath> -safe-mode
   141 //
   143 // The values checked are all default values so the value name is not needed.
   144 typedef struct {
   145   const char* keyName;
   146   const char* valueData;
   147   const char* oldValueData;
   148 } SETTING;
   150 #define APP_REG_NAME L"Firefox"
   151 #define VAL_FILE_ICON "%APPPATH%,1"
   152 #define VAL_OPEN "\"%APPPATH%\" -osint -url \"%1\""
   153 #define OLD_VAL_OPEN "\"%APPPATH%\" -requestPending -osint -url \"%1\""
   154 #define DI "\\DefaultIcon"
   155 #define SOC "\\shell\\open\\command"
   156 #define SOD "\\shell\\open\\ddeexec"
   157 // Used for updating the FTP protocol handler's shell open command under HKCU.
   158 #define FTP_SOC L"Software\\Classes\\ftp\\shell\\open\\command"
   160 #define MAKE_KEY_NAME1(PREFIX, MID) \
   161   PREFIX MID
   163 // The DefaultIcon registry key value should never be used when checking if
   164 // Firefox is the default browser for file handlers since other applications
   165 // (e.g. MS Office) may modify the DefaultIcon registry key value to add Icon
   166 // Handlers. see http://msdn2.microsoft.com/en-us/library/aa969357.aspx for
   167 // more info. The FTP protocol is not checked so advanced users can set the FTP
   168 // handler to another application and still have Firefox check if it is the
   169 // default HTTP and HTTPS handler.
   170 // *** Do not add additional checks here unless you skip them when aForAllTypes
   171 // is false below***.
   172 static SETTING gSettings[] = {
   173   // File Handler Class
   174   // ***keep this as the first entry because when aForAllTypes is not set below
   175   // it will skip over this check.***
   176   { MAKE_KEY_NAME1("FirefoxHTML", SOC), VAL_OPEN, OLD_VAL_OPEN },
   178   // Protocol Handler Class - for Vista and above
   179   { MAKE_KEY_NAME1("FirefoxURL", SOC), VAL_OPEN, OLD_VAL_OPEN },
   181   // Protocol Handlers
   182   { MAKE_KEY_NAME1("HTTP", DI), VAL_FILE_ICON },
   183   { MAKE_KEY_NAME1("HTTP", SOC), VAL_OPEN, OLD_VAL_OPEN },
   184   { MAKE_KEY_NAME1("HTTPS", DI), VAL_FILE_ICON },
   185   { MAKE_KEY_NAME1("HTTPS", SOC), VAL_OPEN, OLD_VAL_OPEN }
   186 };
   188 // The settings to disable DDE are separate from the default browser settings
   189 // since they are only checked when Firefox is the default browser and if they
   190 // are incorrect they are fixed without notifying the user.
   191 static SETTING gDDESettings[] = {
   192   // File Handler Class
   193   { MAKE_KEY_NAME1("Software\\Classes\\FirefoxHTML", SOD) },
   195   // Protocol Handler Class - for Vista and above
   196   { MAKE_KEY_NAME1("Software\\Classes\\FirefoxURL", SOD) },
   198   // Protocol Handlers
   199   { MAKE_KEY_NAME1("Software\\Classes\\FTP", SOD) },
   200   { MAKE_KEY_NAME1("Software\\Classes\\HTTP", SOD) },
   201   { MAKE_KEY_NAME1("Software\\Classes\\HTTPS", SOD) }
   202 };
   204 nsresult
   205 GetHelperPath(nsAutoString& aPath)
   206 {
   207   nsresult rv;
   208   nsCOMPtr<nsIProperties> directoryService = 
   209     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
   210   NS_ENSURE_SUCCESS(rv, rv);
   212   nsCOMPtr<nsIFile> appHelper;
   213   rv = directoryService->Get(XRE_EXECUTABLE_FILE,
   214                              NS_GET_IID(nsIFile),
   215                              getter_AddRefs(appHelper));
   216   NS_ENSURE_SUCCESS(rv, rv);
   218   rv = appHelper->SetNativeLeafName(NS_LITERAL_CSTRING("uninstall"));
   219   NS_ENSURE_SUCCESS(rv, rv);
   221   rv = appHelper->AppendNative(NS_LITERAL_CSTRING("helper.exe"));
   222   NS_ENSURE_SUCCESS(rv, rv);
   224   rv = appHelper->GetPath(aPath);
   226   aPath.Insert(L'"', 0);
   227   aPath.Append(L'"');
   228   return rv;
   229 }
   231 nsresult
   232 LaunchHelper(nsAutoString& aPath)
   233 {
   234   STARTUPINFOW si = {sizeof(si), 0};
   235   PROCESS_INFORMATION pi = {0};
   237   if (!CreateProcessW(nullptr, (LPWSTR)aPath.get(), nullptr, nullptr, FALSE,
   238                       0, nullptr, nullptr, &si, &pi)) {
   239     return NS_ERROR_FAILURE;
   240   }
   242   CloseHandle(pi.hProcess);
   243   CloseHandle(pi.hThread);
   244   return NS_OK;
   245 }
   247 NS_IMETHODIMP
   248 nsWindowsShellService::ShortcutMaintenance()
   249 {
   250   nsresult rv;
   252   // XXX App ids were updated to a constant install path hash,
   253   // XXX this code can be removed after a few upgrade cycles.
   255   // Launch helper.exe so it can update the application user model ids on
   256   // shortcuts in the user's taskbar and start menu. This keeps older pinned
   257   // shortcuts grouped correctly after major updates. Note, we also do this
   258   // through the upgrade installer script, however, this is the only place we
   259   // have a chance to trap links created by users who do control the install/
   260   // update process of the browser.
   262   nsCOMPtr<nsIWinTaskbar> taskbarInfo =
   263     do_GetService(NS_TASKBAR_CONTRACTID);
   264   if (!taskbarInfo) // If we haven't built with win7 sdk features, this fails.
   265     return NS_OK;
   267   // Avoid if this isn't Win7+
   268   bool isSupported = false;
   269   taskbarInfo->GetAvailable(&isSupported);
   270   if (!isSupported)
   271     return NS_OK;
   273   nsAutoString appId;
   274   if (NS_FAILED(taskbarInfo->GetDefaultGroupId(appId)))
   275     return NS_ERROR_UNEXPECTED;
   277   NS_NAMED_LITERAL_CSTRING(prefName, "browser.taskbar.lastgroupid");
   278   nsCOMPtr<nsIPrefService> prefs =
   279     do_GetService(NS_PREFSERVICE_CONTRACTID);
   280   if (!prefs)
   281     return NS_ERROR_UNEXPECTED;
   283   nsCOMPtr<nsIPrefBranch> prefBranch;
   284   prefs->GetBranch(nullptr, getter_AddRefs(prefBranch));
   285   if (!prefBranch)
   286     return NS_ERROR_UNEXPECTED;
   288   nsCOMPtr<nsISupportsString> prefString;
   289   rv = prefBranch->GetComplexValue(prefName.get(),
   290                                    NS_GET_IID(nsISupportsString),
   291                                    getter_AddRefs(prefString));
   292   if (NS_SUCCEEDED(rv)) {
   293     nsAutoString version;
   294     prefString->GetData(version);
   295     if (!version.IsEmpty() && version.Equals(appId)) {
   296       // We're all good, get out of here.
   297       return NS_OK;
   298     }
   299   }
   300   // Update the version in prefs
   301   prefString =
   302     do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
   303   if (NS_FAILED(rv))
   304     return rv;
   306   prefString->SetData(appId);
   307   rv = prefBranch->SetComplexValue(prefName.get(),
   308                                    NS_GET_IID(nsISupportsString),
   309                                    prefString);
   310   if (NS_FAILED(rv)) {
   311     NS_WARNING("Couldn't set last user model id!");
   312     return NS_ERROR_UNEXPECTED;
   313   }
   315   nsAutoString appHelperPath;
   316   if (NS_FAILED(GetHelperPath(appHelperPath)))
   317     return NS_ERROR_UNEXPECTED;
   319   appHelperPath.AppendLiteral(" /UpdateShortcutAppUserModelIds");
   321   return LaunchHelper(appHelperPath);
   322 }
   324 static bool
   325 IsAARDefaultHTTP(IApplicationAssociationRegistration* pAAR,
   326                  bool* aIsDefaultBrowser)
   327 {
   328   // Make sure the Prog ID matches what we have
   329   LPWSTR registeredApp;
   330   HRESULT hr = pAAR->QueryCurrentDefault(L"http", AT_URLPROTOCOL, AL_EFFECTIVE,
   331                                          &registeredApp);
   332   if (SUCCEEDED(hr)) {
   333     LPCWSTR firefoxHTTPProgID = L"FirefoxURL";
   334     *aIsDefaultBrowser = !wcsicmp(registeredApp, firefoxHTTPProgID);
   335     CoTaskMemFree(registeredApp);
   336   } else {
   337     *aIsDefaultBrowser = false;
   338   }
   339   return SUCCEEDED(hr);
   340 }
   342 static bool
   343 IsAARDefaultHTML(IApplicationAssociationRegistration* pAAR,
   344                  bool* aIsDefaultBrowser)
   345 {
   346   LPWSTR registeredApp;
   347   HRESULT hr = pAAR->QueryCurrentDefault(L".html", AT_FILEEXTENSION, AL_EFFECTIVE,
   348                                          &registeredApp);
   349   if (SUCCEEDED(hr)) {
   350     LPCWSTR firefoxHTMLProgID = L"FirefoxHTML";
   351     *aIsDefaultBrowser = !wcsicmp(registeredApp, firefoxHTMLProgID);
   352     CoTaskMemFree(registeredApp);
   353   } else {
   354     *aIsDefaultBrowser = false;
   355   }
   356   return SUCCEEDED(hr);
   357 }
   359 /*
   360  * Query's the AAR for the default status.
   361  * This only checks for FirefoxURL and if aCheckAllTypes is set, then
   362  * it also checks for FirefoxHTML.  Note that those ProgIDs are shared
   363  * by all Firefox browsers.
   364 */
   365 bool
   366 nsWindowsShellService::IsDefaultBrowserVista(bool aCheckAllTypes,
   367                                              bool* aIsDefaultBrowser)
   368 {
   369   IApplicationAssociationRegistration* pAAR;
   370   HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
   371                                 nullptr,
   372                                 CLSCTX_INPROC,
   373                                 IID_IApplicationAssociationRegistration,
   374                                 (void**)&pAAR);
   376   if (SUCCEEDED(hr)) {
   377     if (aCheckAllTypes) {
   378       BOOL res;
   379       hr = pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE,
   380                                       APP_REG_NAME,
   381                                       &res);
   382       *aIsDefaultBrowser = res;
   384       // If we have all defaults, let's make sure that our ProgID
   385       // is explicitly returned as well. Needed only for Windows 8.
   386       if (*aIsDefaultBrowser && IsWin8OrLater()) {
   387         IsAARDefaultHTTP(pAAR, aIsDefaultBrowser);
   388         if (*aIsDefaultBrowser) {
   389           IsAARDefaultHTML(pAAR, aIsDefaultBrowser);
   390         }
   391       }
   392     } else {
   393       IsAARDefaultHTTP(pAAR, aIsDefaultBrowser);
   394     }
   396     pAAR->Release();
   397     return true;
   398   }
   399   return false;
   400 }
   402 NS_IMETHODIMP
   403 nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck,
   404                                         bool aForAllTypes,
   405                                         bool* aIsDefaultBrowser)
   406 {
   407   // If this is the first browser window, maintain internal state that we've
   408   // checked this session (so that subsequent window opens don't show the
   409   // default browser dialog).
   410   if (aStartupCheck)
   411     mCheckedThisSession = true;
   413   // Assume we're the default unless one of the several checks below tell us
   414   // otherwise.
   415   *aIsDefaultBrowser = true;
   417   wchar_t exePath[MAX_BUF];
   418   if (!::GetModuleFileNameW(0, exePath, MAX_BUF))
   419     return NS_ERROR_FAILURE;
   421   // Convert the path to a long path since GetModuleFileNameW returns the path
   422   // that was used to launch Firefox which is not necessarily a long path.
   423   if (!::GetLongPathNameW(exePath, exePath, MAX_BUF))
   424     return NS_ERROR_FAILURE;
   426   nsAutoString appLongPath(exePath);
   428   HKEY theKey;
   429   DWORD res;
   430   nsresult rv;
   431   wchar_t currValue[MAX_BUF];
   433   SETTING* settings = gSettings;
   434   if (!aForAllTypes && IsWin8OrLater()) {
   435     // Skip over the file handler check
   436     settings++;
   437   }
   439   SETTING* end = gSettings + sizeof(gSettings) / sizeof(SETTING);
   441   for (; settings < end; ++settings) {
   442     NS_ConvertUTF8toUTF16 keyName(settings->keyName);
   443     NS_ConvertUTF8toUTF16 valueData(settings->valueData);
   444     int32_t offset = valueData.Find("%APPPATH%");
   445     valueData.Replace(offset, 9, appLongPath);
   447     rv = OpenKeyForReading(HKEY_CLASSES_ROOT, keyName, &theKey);
   448     if (NS_FAILED(rv)) {
   449       *aIsDefaultBrowser = false;
   450       return NS_OK;
   451     }
   453     ::ZeroMemory(currValue, sizeof(currValue));
   454     DWORD len = sizeof currValue;
   455     res = ::RegQueryValueExW(theKey, L"", nullptr, nullptr,
   456                              (LPBYTE)currValue, &len);
   457     // Close the key that was opened.
   458     ::RegCloseKey(theKey);
   459     if (REG_FAILED(res) ||
   460         _wcsicmp(valueData.get(), currValue)) {
   461       // Key wasn't set or was set to something other than our registry entry.
   462       NS_ConvertUTF8toUTF16 oldValueData(settings->oldValueData);
   463       offset = oldValueData.Find("%APPPATH%");
   464       oldValueData.Replace(offset, 9, appLongPath);
   465       // The current registry value doesn't match the current or the old format.
   466       if (_wcsicmp(oldValueData.get(), currValue)) {
   467         *aIsDefaultBrowser = false;
   468         return NS_OK;
   469       }
   471       res = ::RegOpenKeyExW(HKEY_CLASSES_ROOT, PromiseFlatString(keyName).get(),
   472                             0, KEY_SET_VALUE, &theKey);
   473       if (REG_FAILED(res)) {
   474         // If updating the open command fails try to update it using the helper
   475         // application when setting Firefox as the default browser.
   476         *aIsDefaultBrowser = false;
   477         return NS_OK;
   478       }
   480       const nsString &flatValue = PromiseFlatString(valueData);
   481       res = ::RegSetValueExW(theKey, L"", 0, REG_SZ,
   482                              (const BYTE *) flatValue.get(),
   483                              (flatValue.Length() + 1) * sizeof(char16_t));
   484       // Close the key that was created.
   485       ::RegCloseKey(theKey);
   486       if (REG_FAILED(res)) {
   487         // If updating the open command fails try to update it using the helper
   488         // application when setting Firefox as the default browser.
   489         *aIsDefaultBrowser = false;
   490         return NS_OK;
   491       }
   492     }
   493   }
   495   // Only check if Firefox is the default browser on Vista and above if the
   496   // previous checks show that Firefox is the default browser.
   497   if (*aIsDefaultBrowser) {
   498     IsDefaultBrowserVista(aForAllTypes, aIsDefaultBrowser);
   499   }
   501   // To handle the case where DDE isn't disabled due for a user because there
   502   // account didn't perform a Firefox update this will check if Firefox is the
   503   // default browser and if dde is disabled for each handler
   504   // and if it isn't disable it. When Firefox is not the default browser the
   505   // helper application will disable dde for each handler.
   506   if (*aIsDefaultBrowser && aForAllTypes) {
   507     // Check ftp settings
   509     end = gDDESettings + sizeof(gDDESettings) / sizeof(SETTING);
   511     for (settings = gDDESettings; settings < end; ++settings) {
   512       NS_ConvertUTF8toUTF16 keyName(settings->keyName);
   514       rv = OpenKeyForReading(HKEY_CURRENT_USER, keyName, &theKey);
   515       if (NS_FAILED(rv)) {
   516         ::RegCloseKey(theKey);
   517         // If disabling DDE fails try to disable it using the helper
   518         // application when setting Firefox as the default browser.
   519         *aIsDefaultBrowser = false;
   520         return NS_OK;
   521       }
   523       ::ZeroMemory(currValue, sizeof(currValue));
   524       DWORD len = sizeof currValue;
   525       res = ::RegQueryValueExW(theKey, L"", nullptr, nullptr,
   526                                (LPBYTE)currValue, &len);
   527       // Close the key that was opened.
   528       ::RegCloseKey(theKey);
   529       if (REG_FAILED(res) || char16_t('\0') != *currValue) {
   530         // Key wasn't set or was set to something other than our registry entry.
   531         // Delete the key along with all of its childrean and then recreate it.
   532         const nsString &flatName = PromiseFlatString(keyName);
   533         ::SHDeleteKeyW(HKEY_CURRENT_USER, flatName.get());
   534         res = ::RegCreateKeyExW(HKEY_CURRENT_USER, flatName.get(), 0, nullptr,
   535                                 REG_OPTION_NON_VOLATILE, KEY_SET_VALUE,
   536                                 nullptr, &theKey, nullptr);
   537         if (REG_FAILED(res)) {
   538           // If disabling DDE fails try to disable it using the helper
   539           // application when setting Firefox as the default browser.
   540           *aIsDefaultBrowser = false;
   541           return NS_OK;
   542         }
   544         res = ::RegSetValueExW(theKey, L"", 0, REG_SZ, (const BYTE *) L"",
   545                                sizeof(char16_t));
   546         // Close the key that was created.
   547         ::RegCloseKey(theKey);
   548         if (REG_FAILED(res)) {
   549           // If disabling DDE fails try to disable it using the helper
   550           // application when setting Firefox as the default browser.
   551           *aIsDefaultBrowser = false;
   552           return NS_OK;
   553         }
   554       }
   555     }
   557     // Update the FTP protocol handler's shell open command if it is the old
   558     // format.
   559     res = ::RegOpenKeyExW(HKEY_CURRENT_USER, FTP_SOC, 0, KEY_ALL_ACCESS,
   560                           &theKey);
   561     // Don't update the FTP protocol handler's shell open command when opening
   562     // its registry key fails under HKCU since it most likely doesn't exist.
   563     if (NS_FAILED(rv)) {
   564       return NS_OK;
   565     }
   567     NS_ConvertUTF8toUTF16 oldValueOpen(OLD_VAL_OPEN);
   568     int32_t offset = oldValueOpen.Find("%APPPATH%");
   569     oldValueOpen.Replace(offset, 9, appLongPath);
   571     ::ZeroMemory(currValue, sizeof(currValue));
   572     DWORD len = sizeof currValue;
   573     res = ::RegQueryValueExW(theKey, L"", nullptr, nullptr, (LPBYTE)currValue,
   574                              &len);
   576     // Don't update the FTP protocol handler's shell open command when the
   577     // current registry value doesn't exist or matches the old format.
   578     if (REG_FAILED(res) ||
   579         _wcsicmp(oldValueOpen.get(), currValue)) {
   580       ::RegCloseKey(theKey);
   581       return NS_OK;
   582     }
   584     NS_ConvertUTF8toUTF16 valueData(VAL_OPEN);
   585     valueData.Replace(offset, 9, appLongPath);
   586     const nsString &flatValue = PromiseFlatString(valueData);
   587     res = ::RegSetValueExW(theKey, L"", 0, REG_SZ,
   588                            (const BYTE *) flatValue.get(),
   589                            (flatValue.Length() + 1) * sizeof(char16_t));
   590     // Close the key that was created.
   591     ::RegCloseKey(theKey);
   592     // If updating the FTP protocol handlers shell open command fails try to
   593     // update it using the helper application when setting Firefox as the
   594     // default browser.
   595     if (REG_FAILED(res)) {
   596       *aIsDefaultBrowser = false;
   597     }
   598   }
   600   return NS_OK;
   601 }
   603 NS_IMETHODIMP
   604 nsWindowsShellService::GetCanSetDesktopBackground(bool* aResult)
   605 {
   606   *aResult = true;
   607   return NS_OK;
   608 }
   610 static nsresult
   611 DynSHOpenWithDialog(HWND hwndParent, const OPENASINFO *poainfo)
   612 {
   613   // shell32.dll is in the knownDLLs list so will always be loaded from the
   614   // system32 directory.
   615   static const wchar_t kSehllLibraryName[] =  L"shell32.dll";
   616   HMODULE shellDLL = ::LoadLibraryW(kSehllLibraryName);
   617   if (!shellDLL) {
   618     return NS_ERROR_FAILURE;
   619   }
   621   decltype(SHOpenWithDialog)* SHOpenWithDialogFn =
   622     (decltype(SHOpenWithDialog)*) GetProcAddress(shellDLL, "SHOpenWithDialog");
   624   if (!SHOpenWithDialogFn) {
   625     return NS_ERROR_FAILURE;
   626   }
   628   nsresult rv = 
   629     SUCCEEDED(SHOpenWithDialogFn(hwndParent, poainfo)) ? NS_OK :
   630                                                          NS_ERROR_FAILURE;
   631   FreeLibrary(shellDLL);
   632   return rv;
   633 }
   635 nsresult
   636 nsWindowsShellService::LaunchControlPanelDefaultPrograms()
   637 {
   638   // Build the path control.exe path safely
   639   WCHAR controlEXEPath[MAX_PATH + 1] = { '\0' };
   640   if (!GetSystemDirectoryW(controlEXEPath, MAX_PATH)) {
   641     return NS_ERROR_FAILURE;
   642   }
   643   LPCWSTR controlEXE = L"control.exe";
   644   if (wcslen(controlEXEPath) + wcslen(controlEXE) >= MAX_PATH) {
   645     return NS_ERROR_FAILURE;
   646   }
   647   if (!PathAppendW(controlEXEPath, controlEXE)) {
   648     return NS_ERROR_FAILURE;
   649   }
   651   WCHAR params[] = L"control.exe /name Microsoft.DefaultPrograms /page pageDefaultProgram";
   652   STARTUPINFOW si = {sizeof(si), 0};
   653   si.dwFlags = STARTF_USESHOWWINDOW;
   654   si.wShowWindow = SW_SHOWDEFAULT;
   655   PROCESS_INFORMATION pi = {0};
   656   if (!CreateProcessW(controlEXEPath, params, nullptr, nullptr, FALSE,
   657                       0, nullptr, nullptr, &si, &pi)) {
   658     return NS_ERROR_FAILURE;
   659   }
   660   CloseHandle(pi.hProcess);
   661   CloseHandle(pi.hThread);
   663   return NS_OK;
   664 }
   666 nsresult
   667 nsWindowsShellService::LaunchHTTPHandlerPane()
   668 {
   669   OPENASINFO info;
   670   info.pcszFile = L"http";
   671   info.pcszClass = nullptr;
   672   info.oaifInFlags = OAIF_FORCE_REGISTRATION | 
   673                      OAIF_URL_PROTOCOL |
   674                      OAIF_REGISTER_EXT;
   675   return DynSHOpenWithDialog(nullptr, &info);
   676 }
   678 NS_IMETHODIMP
   679 nsWindowsShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
   680 {
   681   nsAutoString appHelperPath;
   682   if (NS_FAILED(GetHelperPath(appHelperPath)))
   683     return NS_ERROR_FAILURE;
   685   if (aForAllUsers) {
   686     appHelperPath.AppendLiteral(" /SetAsDefaultAppGlobal");
   687   } else {
   688     appHelperPath.AppendLiteral(" /SetAsDefaultAppUser");
   689   }
   691   nsresult rv = LaunchHelper(appHelperPath);
   692   if (NS_SUCCEEDED(rv) && IsWin8OrLater()) {
   693     if (aClaimAllTypes) {
   694       rv = LaunchControlPanelDefaultPrograms();
   695       // The above call should never really fail, but just in case
   696       // fall back to showing the HTTP association screen only.
   697       if (NS_FAILED(rv)) {
   698         rv = LaunchHTTPHandlerPane();
   699       }
   700     } else {
   701       rv = LaunchHTTPHandlerPane();
   702       // The above calls hould never really fail, but just in case
   703       // fallb ack to showing control panel for all defaults
   704       if (NS_FAILED(rv)) {
   705         rv = LaunchControlPanelDefaultPrograms();
   706       }
   707     }
   708   }
   710   return rv;
   711 }
   713 NS_IMETHODIMP
   714 nsWindowsShellService::GetShouldCheckDefaultBrowser(bool* aResult)
   715 {
   716   NS_ENSURE_ARG_POINTER(aResult);
   718   // If we've already checked, the browser has been started and this is a 
   719   // new window open, and we don't want to check again.
   720   if (mCheckedThisSession) {
   721     *aResult = false;
   722     return NS_OK;
   723   }
   725   nsCOMPtr<nsIPrefBranch> prefs;
   726   nsresult rv;
   727   nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
   728   NS_ENSURE_SUCCESS(rv, rv);
   730   rv = pserve->GetBranch("", getter_AddRefs(prefs));
   731   NS_ENSURE_SUCCESS(rv, rv);
   733   return prefs->GetBoolPref(PREF_CHECKDEFAULTBROWSER, aResult);
   734 }
   736 NS_IMETHODIMP
   737 nsWindowsShellService::SetShouldCheckDefaultBrowser(bool aShouldCheck)
   738 {
   739   nsCOMPtr<nsIPrefBranch> prefs;
   740   nsresult rv;
   742   nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
   743   NS_ENSURE_SUCCESS(rv, rv);
   745   rv = pserve->GetBranch("", getter_AddRefs(prefs));
   746   NS_ENSURE_SUCCESS(rv, rv);
   748   return prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, aShouldCheck);
   749 }
   751 static nsresult
   752 WriteBitmap(nsIFile* aFile, imgIContainer* aImage)
   753 {
   754   nsresult rv;
   756   RefPtr<SourceSurface> surface =
   757     aImage->GetFrame(imgIContainer::FRAME_FIRST,
   758                      imgIContainer::FLAG_SYNC_DECODE);
   759   NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
   761   // For either of the following formats we want to set the biBitCount member
   762   // of the BITMAPINFOHEADER struct to 32, below. For that value the bitmap
   763   // format defines that the A8/X8 WORDs in the bitmap byte stream be ignored
   764   // for the BI_RGB value we use for the biCompression member.
   765   MOZ_ASSERT(surface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
   766              surface->GetFormat() == SurfaceFormat::B8G8R8X8);
   768   RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
   769   NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
   771   int32_t width = dataSurface->GetSize().width;
   772   int32_t height = dataSurface->GetSize().height;
   773   int32_t bytesPerPixel = 4 * sizeof(uint8_t);
   774   uint32_t bytesPerRow = bytesPerPixel * width;
   776   // initialize these bitmap structs which we will later
   777   // serialize directly to the head of the bitmap file
   778   BITMAPINFOHEADER bmi;
   779   bmi.biSize = sizeof(BITMAPINFOHEADER);
   780   bmi.biWidth = width;
   781   bmi.biHeight = height;
   782   bmi.biPlanes = 1;
   783   bmi.biBitCount = (WORD)bytesPerPixel*8;
   784   bmi.biCompression = BI_RGB;
   785   bmi.biSizeImage = bytesPerRow * height;
   786   bmi.biXPelsPerMeter = 0;
   787   bmi.biYPelsPerMeter = 0;
   788   bmi.biClrUsed = 0;
   789   bmi.biClrImportant = 0;
   791   BITMAPFILEHEADER bf;
   792   bf.bfType = 0x4D42; // 'BM'
   793   bf.bfReserved1 = 0;
   794   bf.bfReserved2 = 0;
   795   bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
   796   bf.bfSize = bf.bfOffBits + bmi.biSizeImage;
   798   // get a file output stream
   799   nsCOMPtr<nsIOutputStream> stream;
   800   rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), aFile);
   801   NS_ENSURE_SUCCESS(rv, rv);
   803   DataSourceSurface::MappedSurface map;
   804   if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
   805     return NS_ERROR_FAILURE;
   806   }
   808   // write the bitmap headers and rgb pixel data to the file
   809   rv = NS_ERROR_FAILURE;
   810   if (stream) {
   811     uint32_t written;
   812     stream->Write((const char*)&bf, sizeof(BITMAPFILEHEADER), &written);
   813     if (written == sizeof(BITMAPFILEHEADER)) {
   814       stream->Write((const char*)&bmi, sizeof(BITMAPINFOHEADER), &written);
   815       if (written == sizeof(BITMAPINFOHEADER)) {
   816         // write out the image data backwards because the desktop won't
   817         // show bitmaps with negative heights for top-to-bottom
   818         uint32_t i = map.mStride * height;
   819         do {
   820           i -= map.mStride;
   821           stream->Write(((const char*)map.mData) + i, bytesPerRow, &written);
   822           if (written == bytesPerRow) {
   823             rv = NS_OK;
   824           } else {
   825             rv = NS_ERROR_FAILURE;
   826             break;
   827           }
   828         } while (i != 0);
   829       }
   830     }
   832     stream->Close();
   833   }
   835   dataSurface->Unmap();
   837   return rv;
   838 }
   840 NS_IMETHODIMP
   841 nsWindowsShellService::SetDesktopBackground(nsIDOMElement* aElement, 
   842                                             int32_t aPosition)
   843 {
   844   nsresult rv;
   846   nsCOMPtr<imgIContainer> container;
   847   nsCOMPtr<nsIDOMHTMLImageElement> imgElement(do_QueryInterface(aElement));
   848   if (!imgElement) {
   849     // XXX write background loading stuff!
   850     return NS_ERROR_NOT_AVAILABLE;
   851   } 
   852   else {
   853     nsCOMPtr<nsIImageLoadingContent> imageContent =
   854       do_QueryInterface(aElement, &rv);
   855     if (!imageContent)
   856       return rv;
   858     // get the image container
   859     nsCOMPtr<imgIRequest> request;
   860     rv = imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
   861                                   getter_AddRefs(request));
   862     if (!request)
   863       return rv;
   864     rv = request->GetImage(getter_AddRefs(container));
   865     if (!container)
   866       return NS_ERROR_FAILURE;
   867   }
   869   // get the file name from localized strings
   870   nsCOMPtr<nsIStringBundleService>
   871     bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
   872   NS_ENSURE_SUCCESS(rv, rv);
   874   nsCOMPtr<nsIStringBundle> shellBundle;
   875   rv = bundleService->CreateBundle(SHELLSERVICE_PROPERTIES,
   876                                    getter_AddRefs(shellBundle));
   877   NS_ENSURE_SUCCESS(rv, rv);
   879   // e.g. "Desktop Background.bmp"
   880   nsString fileLeafName;
   881   rv = shellBundle->GetStringFromName
   882                       (MOZ_UTF16("desktopBackgroundLeafNameWin"),
   883                        getter_Copies(fileLeafName));
   884   NS_ENSURE_SUCCESS(rv, rv);
   886   // get the profile root directory
   887   nsCOMPtr<nsIFile> file;
   888   rv = NS_GetSpecialDirectory(NS_APP_APPLICATION_REGISTRY_DIR,
   889                               getter_AddRefs(file));
   890   NS_ENSURE_SUCCESS(rv, rv);
   892   // eventually, the path is "%APPDATA%\Mozilla\Firefox\Desktop Background.bmp"
   893   rv = file->Append(fileLeafName);
   894   NS_ENSURE_SUCCESS(rv, rv);
   896   nsAutoString path;
   897   rv = file->GetPath(path);
   898   NS_ENSURE_SUCCESS(rv, rv);
   900   // write the bitmap to a file in the profile directory
   901   rv = WriteBitmap(file, container);
   903   // if the file was written successfully, set it as the system wallpaper
   904   if (NS_SUCCEEDED(rv)) {
   905     nsCOMPtr<nsIWindowsRegKey> regKey =
   906       do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
   907     NS_ENSURE_SUCCESS(rv, rv);
   909     rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
   910                         NS_LITERAL_STRING("Control Panel\\Desktop"),
   911                         nsIWindowsRegKey::ACCESS_SET_VALUE);
   912     NS_ENSURE_SUCCESS(rv, rv);
   914     nsAutoString tile;
   915     nsAutoString style;
   916     switch (aPosition) {
   917       case BACKGROUND_TILE:
   918         style.AssignLiteral("0");
   919         tile.AssignLiteral("1");
   920         break;
   921       case BACKGROUND_CENTER:
   922         style.AssignLiteral("0");
   923         tile.AssignLiteral("0");
   924         break;
   925       case BACKGROUND_STRETCH:
   926         style.AssignLiteral("2");
   927         tile.AssignLiteral("0");
   928         break;
   929       case BACKGROUND_FILL:
   930         style.AssignLiteral("10");
   931         tile.AssignLiteral("0");
   932         break;
   933       case BACKGROUND_FIT:
   934         style.AssignLiteral("6");
   935         tile.AssignLiteral("0");
   936         break;
   937     }
   939     rv = regKey->WriteStringValue(NS_LITERAL_STRING("TileWallpaper"), tile);
   940     NS_ENSURE_SUCCESS(rv, rv);
   941     rv = regKey->WriteStringValue(NS_LITERAL_STRING("WallpaperStyle"), style);
   942     NS_ENSURE_SUCCESS(rv, rv);
   943     rv = regKey->Close();
   944     NS_ENSURE_SUCCESS(rv, rv);
   946     ::SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, (PVOID)path.get(),
   947                             SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
   948   }
   949   return rv;
   950 }
   952 NS_IMETHODIMP
   953 nsWindowsShellService::OpenApplication(int32_t aApplication)
   954 {
   955   nsAutoString application;
   956   switch (aApplication) {
   957   case nsIShellService::APPLICATION_MAIL:
   958     application.AssignLiteral("Mail");
   959     break;
   960   case nsIShellService::APPLICATION_NEWS:
   961     application.AssignLiteral("News");
   962     break;
   963   }
   965   // The Default Client section of the Windows Registry looks like this:
   966   // 
   967   // Clients\aClient\
   968   //  e.g. aClient = "Mail"...
   969   //        \Mail\(default) = Client Subkey Name
   970   //             \Client Subkey Name
   971   //             \Client Subkey Name\shell\open\command\ 
   972   //             \Client Subkey Name\shell\open\command\(default) = path to exe
   973   //
   975   // Find the default application for this class.
   976   HKEY theKey;
   977   nsresult rv = OpenKeyForReading(HKEY_CLASSES_ROOT, application, &theKey);
   978   if (NS_FAILED(rv))
   979     return rv;
   981   wchar_t buf[MAX_BUF];
   982   DWORD type, len = sizeof buf;
   983   DWORD res = ::RegQueryValueExW(theKey, EmptyString().get(), 0,
   984                                  &type, (LPBYTE)&buf, &len);
   986   if (REG_FAILED(res) || !*buf)
   987     return NS_OK;
   989   // Close the key we opened.
   990   ::RegCloseKey(theKey);
   992   // Find the "open" command
   993   application.AppendLiteral("\\");
   994   application.Append(buf);
   995   application.AppendLiteral("\\shell\\open\\command");
   997   rv = OpenKeyForReading(HKEY_CLASSES_ROOT, application, &theKey);
   998   if (NS_FAILED(rv))
   999     return rv;
  1001   ::ZeroMemory(buf, sizeof(buf));
  1002   len = sizeof buf;
  1003   res = ::RegQueryValueExW(theKey, EmptyString().get(), 0,
  1004                            &type, (LPBYTE)&buf, &len);
  1005   if (REG_FAILED(res) || !*buf)
  1006     return NS_ERROR_FAILURE;
  1008   // Close the key we opened.
  1009   ::RegCloseKey(theKey);
  1011   // Look for any embedded environment variables and substitute their 
  1012   // values, as |::CreateProcessW| is unable to do this.
  1013   nsAutoString path(buf);
  1014   int32_t end = path.Length();
  1015   int32_t cursor = 0, temp = 0;
  1016   ::ZeroMemory(buf, sizeof(buf));
  1017   do {
  1018     cursor = path.FindChar('%', cursor);
  1019     if (cursor < 0) 
  1020       break;
  1022     temp = path.FindChar('%', cursor + 1);
  1023     ++cursor;
  1025     ::ZeroMemory(&buf, sizeof(buf));
  1027     ::GetEnvironmentVariableW(nsAutoString(Substring(path, cursor, temp - cursor)).get(),
  1028                               buf, sizeof(buf));
  1030     // "+ 2" is to subtract the extra characters used to delimit the environment
  1031     // variable ('%').
  1032     path.Replace((cursor - 1), temp - cursor + 2, nsDependentString(buf));
  1034     ++cursor;
  1036   while (cursor < end);
  1038   STARTUPINFOW si;
  1039   PROCESS_INFORMATION pi;
  1041   ::ZeroMemory(&si, sizeof(STARTUPINFOW));
  1042   ::ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
  1044   BOOL success = ::CreateProcessW(nullptr, (LPWSTR)path.get(), nullptr,
  1045                                   nullptr, FALSE, 0, nullptr,  nullptr,
  1046                                   &si, &pi);
  1047   if (!success)
  1048     return NS_ERROR_FAILURE;
  1050   return NS_OK;
  1053 NS_IMETHODIMP
  1054 nsWindowsShellService::GetDesktopBackgroundColor(uint32_t* aColor)
  1056   uint32_t color = ::GetSysColor(COLOR_DESKTOP);
  1057   *aColor = (GetRValue(color) << 16) | (GetGValue(color) << 8) | GetBValue(color);
  1058   return NS_OK;
  1061 NS_IMETHODIMP
  1062 nsWindowsShellService::SetDesktopBackgroundColor(uint32_t aColor)
  1064   int aParameters[2] = { COLOR_BACKGROUND, COLOR_DESKTOP };
  1065   BYTE r = (aColor >> 16);
  1066   BYTE g = (aColor << 16) >> 24;
  1067   BYTE b = (aColor << 24) >> 24;
  1068   COLORREF colors[2] = { RGB(r,g,b), RGB(r,g,b) };
  1070   ::SetSysColors(sizeof(aParameters) / sizeof(int), aParameters, colors);
  1072   nsresult rv;
  1073   nsCOMPtr<nsIWindowsRegKey> regKey =
  1074     do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
  1075   NS_ENSURE_SUCCESS(rv, rv);
  1077   rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
  1078                       NS_LITERAL_STRING("Control Panel\\Colors"),
  1079                       nsIWindowsRegKey::ACCESS_SET_VALUE);
  1080   NS_ENSURE_SUCCESS(rv, rv);
  1082   wchar_t rgb[12];
  1083   _snwprintf(rgb, 12, L"%u %u %u", r, g, b);
  1085   rv = regKey->WriteStringValue(NS_LITERAL_STRING("Background"),
  1086                                 nsDependentString(rgb));
  1087   NS_ENSURE_SUCCESS(rv, rv);
  1089   return regKey->Close();
  1092 nsWindowsShellService::nsWindowsShellService() : 
  1093   mCheckedThisSession(false) 
  1097 nsWindowsShellService::~nsWindowsShellService()
  1101 NS_IMETHODIMP
  1102 nsWindowsShellService::OpenApplicationWithURI(nsIFile* aApplication,
  1103                                               const nsACString& aURI)
  1105   nsresult rv;
  1106   nsCOMPtr<nsIProcess> process = 
  1107     do_CreateInstance("@mozilla.org/process/util;1", &rv);
  1108   if (NS_FAILED(rv))
  1109     return rv;
  1111   rv = process->Init(aApplication);
  1112   if (NS_FAILED(rv))
  1113     return rv;
  1115   const nsCString spec(aURI);
  1116   const char* specStr = spec.get();
  1117   return process->Run(false, &specStr, 1);
  1120 NS_IMETHODIMP
  1121 nsWindowsShellService::GetDefaultFeedReader(nsIFile** _retval)
  1123   *_retval = nullptr;
  1125   nsresult rv;
  1126   nsCOMPtr<nsIWindowsRegKey> regKey =
  1127     do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
  1128   NS_ENSURE_SUCCESS(rv, rv);
  1130   rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
  1131                     NS_LITERAL_STRING("feed\\shell\\open\\command"),
  1132                     nsIWindowsRegKey::ACCESS_READ);
  1133   NS_ENSURE_SUCCESS(rv, rv);
  1135   nsAutoString path;
  1136   rv = regKey->ReadStringValue(EmptyString(), path);
  1137   NS_ENSURE_SUCCESS(rv, rv);
  1138   if (path.IsEmpty())
  1139     return NS_ERROR_FAILURE;
  1141   if (path.First() == '"') {
  1142     // Everything inside the quotes
  1143     path = Substring(path, 1, path.FindChar('"', 1) - 1);
  1145   else {
  1146     // Everything up to the first space
  1147     path = Substring(path, 0, path.FindChar(' '));
  1150   nsCOMPtr<nsIFile> defaultReader =
  1151     do_CreateInstance("@mozilla.org/file/local;1", &rv);
  1152   NS_ENSURE_SUCCESS(rv, rv);
  1154   rv = defaultReader->InitWithPath(path);
  1155   NS_ENSURE_SUCCESS(rv, rv);
  1157   bool exists;
  1158   rv = defaultReader->Exists(&exists);
  1159   NS_ENSURE_SUCCESS(rv, rv);
  1160   if (!exists)
  1161     return NS_ERROR_FAILURE;
  1163   NS_ADDREF(*_retval = defaultReader);
  1164   return NS_OK;

mercurial