summaryrefslogtreecommitdiffstats
path: root/browser/components/shell/nsWindowsShellService.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/shell/nsWindowsShellService.cpp')
-rw-r--r--browser/components/shell/nsWindowsShellService.cpp1277
1 files changed, 0 insertions, 1277 deletions
diff --git a/browser/components/shell/nsWindowsShellService.cpp b/browser/components/shell/nsWindowsShellService.cpp
deleted file mode 100644
index 879b0c7f0..000000000
--- a/browser/components/shell/nsWindowsShellService.cpp
+++ /dev/null
@@ -1,1277 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsWindowsShellService.h"
-
-#include "imgIContainer.h"
-#include "imgIRequest.h"
-#include "mozilla/gfx/2D.h"
-#include "mozilla/RefPtr.h"
-#include "nsIDOMElement.h"
-#include "nsIDOMHTMLImageElement.h"
-#include "nsIImageLoadingContent.h"
-#include "nsIPrefService.h"
-#include "nsIPrefLocalizedString.h"
-#include "nsIServiceManager.h"
-#include "nsIStringBundle.h"
-#include "nsNetUtil.h"
-#include "nsServiceManagerUtils.h"
-#include "nsShellService.h"
-#include "nsIProcess.h"
-#include "nsICategoryManager.h"
-#include "nsBrowserCompsCID.h"
-#include "nsDirectoryServiceUtils.h"
-#include "nsAppDirectoryServiceDefs.h"
-#include "nsDirectoryServiceDefs.h"
-#include "nsIWindowsRegKey.h"
-#include "nsUnicharUtils.h"
-#include "nsIWinTaskbar.h"
-#include "nsISupportsPrimitives.h"
-#include "nsIURLFormatter.h"
-#include "nsThreadUtils.h"
-#include "nsXULAppAPI.h"
-#include "mozilla/WindowsVersion.h"
-
-#include "windows.h"
-#include "shellapi.h"
-
-#ifdef _WIN32_WINNT
-#undef _WIN32_WINNT
-#endif
-#define _WIN32_WINNT 0x0600
-#define INITGUID
-#undef NTDDI_VERSION
-#define NTDDI_VERSION NTDDI_WIN8
-// Needed for access to IApplicationActivationManager
-#include <shlobj.h>
-
-#include <mbstring.h>
-#include <shlwapi.h>
-
-#include <lm.h>
-#undef ACCESS_READ
-
-#ifndef MAX_BUF
-#define MAX_BUF 4096
-#endif
-
-#define REG_SUCCEEDED(val) \
- (val == ERROR_SUCCESS)
-
-#define REG_FAILED(val) \
- (val != ERROR_SUCCESS)
-
-#define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
-
-using mozilla::IsWin8OrLater;
-using namespace mozilla;
-using namespace mozilla::gfx;
-
-NS_IMPL_ISUPPORTS(nsWindowsShellService, nsIWindowsShellService, nsIShellService)
-
-static nsresult
-OpenKeyForReading(HKEY aKeyRoot, const nsAString& aKeyName, HKEY* aKey)
-{
- const nsString &flatName = PromiseFlatString(aKeyName);
-
- DWORD res = ::RegOpenKeyExW(aKeyRoot, flatName.get(), 0, KEY_READ, aKey);
- switch (res) {
- case ERROR_SUCCESS:
- break;
- case ERROR_ACCESS_DENIED:
- return NS_ERROR_FILE_ACCESS_DENIED;
- case ERROR_FILE_NOT_FOUND:
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- return NS_OK;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Default Browser Registry Settings
-//
-// The setting of these values are made by an external binary since writing
-// these values may require elevation.
-//
-// - File Extension Mappings
-// -----------------------
-// The following file extensions:
-// .htm .html .shtml .xht .xhtml
-// are mapped like so:
-//
-// HKCU\SOFTWARE\Classes\.<ext>\ (default) REG_SZ BasiliskHTML
-//
-// as aliases to the class:
-//
-// HKCU\SOFTWARE\Classes\BasiliskHTML\
-// DefaultIcon (default) REG_SZ <apppath>,1
-// shell\open\command (default) REG_SZ <apppath> -osint -url "%1"
-// shell\open\ddeexec (default) REG_SZ <empty string>
-//
-// - Windows Vista and above Protocol Handler
-//
-// HKCU\SOFTWARE\Classes\BasiliskURL\ (default) REG_SZ <appname> URL
-// EditFlags REG_DWORD 2
-// FriendlyTypeName REG_SZ <appname> URL
-// DefaultIcon (default) REG_SZ <apppath>,1
-// shell\open\command (default) REG_SZ <apppath> -osint -url "%1"
-// shell\open\ddeexec (default) REG_SZ <empty string>
-//
-// - Protocol Mappings
-// -----------------
-// The following protocols:
-// HTTP, HTTPS, FTP
-// are mapped like so:
-//
-// HKCU\SOFTWARE\Classes\<protocol>\
-// DefaultIcon (default) REG_SZ <apppath>,1
-// shell\open\command (default) REG_SZ <apppath> -osint -url "%1"
-// shell\open\ddeexec (default) REG_SZ <empty string>
-//
-// - Windows Start Menu (XP SP1 and newer)
-// -------------------------------------------------
-// The following keys are set to make Basilisk appear in the Start Menu as the
-// browser:
-//
-// HKCU\SOFTWARE\Clients\StartMenuInternet\BASILISK.EXE\
-// (default) REG_SZ <appname>
-// DefaultIcon (default) REG_SZ <apppath>,0
-// InstallInfo HideIconsCommand REG_SZ <uninstpath> /HideShortcuts
-// InstallInfo IconsVisible REG_DWORD 1
-// InstallInfo ReinstallCommand REG_SZ <uninstpath> /SetAsDefaultAppGlobal
-// InstallInfo ShowIconsCommand REG_SZ <uninstpath> /ShowShortcuts
-// shell\open\command (default) REG_SZ <apppath>
-// shell\properties (default) REG_SZ <appname> &Options
-// shell\properties\command (default) REG_SZ <apppath> -preferences
-// shell\safemode (default) REG_SZ <appname> &Safe Mode
-// shell\safemode\command (default) REG_SZ <apppath> -safe-mode
-//
-
-// The values checked are all default values so the value name is not needed.
-typedef struct {
- const char* keyName;
- const char* valueData;
- const char* oldValueData;
-} SETTING;
-
-#define APP_REG_NAME L"Basilisk"
-#define VAL_FILE_ICON "%APPPATH%,1"
-#define VAL_OPEN "\"%APPPATH%\" -osint -url \"%1\""
-#define OLD_VAL_OPEN "\"%APPPATH%\" -requestPending -osint -url \"%1\""
-#define DI "\\DefaultIcon"
-#define SOC "\\shell\\open\\command"
-#define SOD "\\shell\\open\\ddeexec"
-// Used for updating the FTP protocol handler's shell open command under HKCU.
-#define FTP_SOC L"Software\\Classes\\ftp\\shell\\open\\command"
-
-#define MAKE_KEY_NAME1(PREFIX, MID) \
- PREFIX MID
-
-// The DefaultIcon registry key value should never be used when checking if
-// Basilisk is the default browser for file handlers since other applications
-// (e.g. MS Office) may modify the DefaultIcon registry key value to add Icon
-// Handlers. see http://msdn2.microsoft.com/en-us/library/aa969357.aspx for
-// more info. The FTP protocol is not checked so advanced users can set the FTP
-// handler to another application and still have Basilisk check if it is the
-// default HTTP and HTTPS handler.
-// *** Do not add additional checks here unless you skip them when aForAllTypes
-// is false below***.
-static SETTING gSettings[] = {
- // File Handler Class
- // ***keep this as the first entry because when aForAllTypes is not set below
- // it will skip over this check.***
- { MAKE_KEY_NAME1("BasiliskHTML", SOC), VAL_OPEN, OLD_VAL_OPEN },
-
- // Protocol Handler Class - for Vista and above
- { MAKE_KEY_NAME1("BasiliskURL", SOC), VAL_OPEN, OLD_VAL_OPEN },
-
- // Protocol Handlers
- { MAKE_KEY_NAME1("HTTP", DI), VAL_FILE_ICON },
- { MAKE_KEY_NAME1("HTTP", SOC), VAL_OPEN, OLD_VAL_OPEN },
- { MAKE_KEY_NAME1("HTTPS", DI), VAL_FILE_ICON },
- { MAKE_KEY_NAME1("HTTPS", SOC), VAL_OPEN, OLD_VAL_OPEN }
-};
-
-// The settings to disable DDE are separate from the default browser settings
-// since they are only checked when Basilisk is the default browser and if they
-// are incorrect they are fixed without notifying the user.
-static SETTING gDDESettings[] = {
- // File Handler Class
- { MAKE_KEY_NAME1("Software\\Classes\\BasiliskHTML", SOD) },
-
- // Protocol Handler Class - for Vista and above
- { MAKE_KEY_NAME1("Software\\Classes\\BasiliskURL", SOD) },
-
- // Protocol Handlers
- { MAKE_KEY_NAME1("Software\\Classes\\FTP", SOD) },
- { MAKE_KEY_NAME1("Software\\Classes\\HTTP", SOD) },
- { MAKE_KEY_NAME1("Software\\Classes\\HTTPS", SOD) }
-};
-
-nsresult
-GetHelperPath(nsAutoString& aPath)
-{
- nsresult rv;
- nsCOMPtr<nsIProperties> directoryService =
- do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
- nsCOMPtr<nsIFile> appHelper;
- rv = directoryService->Get(XRE_EXECUTABLE_FILE,
- NS_GET_IID(nsIFile),
- getter_AddRefs(appHelper));
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = appHelper->SetNativeLeafName(NS_LITERAL_CSTRING("uninstall"));
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = appHelper->AppendNative(NS_LITERAL_CSTRING("helper.exe"));
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = appHelper->GetPath(aPath);
-
- aPath.Insert(L'"', 0);
- aPath.Append(L'"');
- return rv;
-}
-
-nsresult
-LaunchHelper(nsAutoString& aPath)
-{
- STARTUPINFOW si = {sizeof(si), 0};
- PROCESS_INFORMATION pi = {0};
-
- if (!CreateProcessW(nullptr, (LPWSTR)aPath.get(), nullptr, nullptr, FALSE,
- 0, nullptr, nullptr, &si, &pi)) {
- return NS_ERROR_FAILURE;
- }
-
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
- return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWindowsShellService::ShortcutMaintenance()
-{
- nsresult rv;
-
- // XXX App ids were updated to a constant install path hash,
- // XXX this code can be removed after a few upgrade cycles.
-
- // Launch helper.exe so it can update the application user model ids on
- // shortcuts in the user's taskbar and start menu. This keeps older pinned
- // shortcuts grouped correctly after major updates. Note, we also do this
- // through the upgrade installer script, however, this is the only place we
- // have a chance to trap links created by users who do control the install/
- // update process of the browser.
-
- nsCOMPtr<nsIWinTaskbar> taskbarInfo =
- do_GetService(NS_TASKBAR_CONTRACTID);
- if (!taskbarInfo) // If we haven't built with win7 sdk features, this fails.
- return NS_OK;
-
- // Avoid if this isn't Win7+
- bool isSupported = false;
- taskbarInfo->GetAvailable(&isSupported);
- if (!isSupported)
- return NS_OK;
-
- nsAutoString appId;
- if (NS_FAILED(taskbarInfo->GetDefaultGroupId(appId)))
- return NS_ERROR_UNEXPECTED;
-
- NS_NAMED_LITERAL_CSTRING(prefName, "browser.taskbar.lastgroupid");
- nsCOMPtr<nsIPrefBranch> prefs =
- do_GetService(NS_PREFSERVICE_CONTRACTID);
- if (!prefs)
- return NS_ERROR_UNEXPECTED;
-
- nsCOMPtr<nsISupportsString> prefString;
- rv = prefs->GetComplexValue(prefName.get(),
- NS_GET_IID(nsISupportsString),
- getter_AddRefs(prefString));
- if (NS_SUCCEEDED(rv)) {
- nsAutoString version;
- prefString->GetData(version);
- if (!version.IsEmpty() && version.Equals(appId)) {
- // We're all good, get out of here.
- return NS_OK;
- }
- }
- // Update the version in prefs
- prefString =
- do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
- if (NS_FAILED(rv))
- return rv;
-
- prefString->SetData(appId);
- rv = prefs->SetComplexValue(prefName.get(),
- NS_GET_IID(nsISupportsString),
- prefString);
- if (NS_FAILED(rv)) {
- NS_WARNING("Couldn't set last user model id!");
- return NS_ERROR_UNEXPECTED;
- }
-
- nsAutoString appHelperPath;
- if (NS_FAILED(GetHelperPath(appHelperPath)))
- return NS_ERROR_UNEXPECTED;
-
- appHelperPath.AppendLiteral(" /UpdateShortcutAppUserModelIds");
-
- return LaunchHelper(appHelperPath);
-}
-
-static bool
-IsAARDefault(const RefPtr<IApplicationAssociationRegistration>& pAAR,
- LPCWSTR aClassName)
-{
- // Make sure the Prog ID matches what we have
- LPWSTR registeredApp;
- bool isProtocol = *aClassName != L'.';
- ASSOCIATIONTYPE queryType = isProtocol ? AT_URLPROTOCOL : AT_FILEEXTENSION;
- HRESULT hr = pAAR->QueryCurrentDefault(aClassName, queryType, AL_EFFECTIVE,
- &registeredApp);
- if (FAILED(hr)) {
- return false;
- }
-
- LPCWSTR progID = isProtocol ? L"BasiliskURL" : L"BasiliskHTML";
- bool isDefault = !wcsicmp(registeredApp, progID);
- CoTaskMemFree(registeredApp);
-
- return isDefault;
-}
-
-static void
-IsDefaultBrowserWin8(bool aCheckAllTypes, bool* aIsDefaultBrowser)
-{
- RefPtr<IApplicationAssociationRegistration> pAAR;
- HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
- nullptr,
- CLSCTX_INPROC,
- IID_IApplicationAssociationRegistration,
- getter_AddRefs(pAAR));
- if (FAILED(hr)) {
- return;
- }
-
- bool res = IsAARDefault(pAAR, L"http");
- if (*aIsDefaultBrowser) {
- *aIsDefaultBrowser = res;
- }
- res = IsAARDefault(pAAR, L".html");
- if (*aIsDefaultBrowser && aCheckAllTypes) {
- *aIsDefaultBrowser = res;
- }
-}
-
-/*
- * Query's the AAR for the default status.
- * This only checks for BasiliskURL and if aCheckAllTypes is set, then
- * it also checks for BasiliskHTML. Note that those ProgIDs are shared
- * by all Basilisk browsers.
-*/
-bool
-nsWindowsShellService::IsDefaultBrowserVista(bool aCheckAllTypes,
- bool* aIsDefaultBrowser)
-{
- RefPtr<IApplicationAssociationRegistration> pAAR;
- HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
- nullptr,
- CLSCTX_INPROC,
- IID_IApplicationAssociationRegistration,
- getter_AddRefs(pAAR));
- if (FAILED(hr)) {
- return false;
- }
-
- if (aCheckAllTypes) {
- BOOL res;
- hr = pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE,
- APP_REG_NAME,
- &res);
- *aIsDefaultBrowser = res;
- } else if (!IsWin8OrLater()) {
- *aIsDefaultBrowser = IsAARDefault(pAAR, L"http");
- }
-
- return true;
-}
-
-NS_IMETHODIMP
-nsWindowsShellService::IsDefaultBrowser(bool aStartupCheck,
- bool aForAllTypes,
- bool* aIsDefaultBrowser)
-{
- // Assume we're the default unless one of the several checks below tell us
- // otherwise.
- *aIsDefaultBrowser = true;
-
- wchar_t exePath[MAX_BUF];
- if (!::GetModuleFileNameW(0, exePath, MAX_BUF))
- return NS_ERROR_FAILURE;
-
- // Convert the path to a long path since GetModuleFileNameW returns the path
- // that was used to launch Basilisk which is not necessarily a long path.
- if (!::GetLongPathNameW(exePath, exePath, MAX_BUF))
- return NS_ERROR_FAILURE;
-
- nsAutoString appLongPath(exePath);
-
- HKEY theKey;
- DWORD res;
- nsresult rv;
- wchar_t currValue[MAX_BUF];
-
- SETTING* settings = gSettings;
- if (!aForAllTypes && IsWin8OrLater()) {
- // Skip over the file handler check
- settings++;
- }
-
- SETTING* end = gSettings + sizeof(gSettings) / sizeof(SETTING);
-
- for (; settings < end; ++settings) {
- NS_ConvertUTF8toUTF16 keyName(settings->keyName);
- NS_ConvertUTF8toUTF16 valueData(settings->valueData);
- int32_t offset = valueData.Find("%APPPATH%");
- valueData.Replace(offset, 9, appLongPath);
-
- rv = OpenKeyForReading(HKEY_CLASSES_ROOT, keyName, &theKey);
- if (NS_FAILED(rv)) {
- *aIsDefaultBrowser = false;
- return NS_OK;
- }
-
- ::ZeroMemory(currValue, sizeof(currValue));
- DWORD len = sizeof currValue;
- res = ::RegQueryValueExW(theKey, L"", nullptr, nullptr,
- (LPBYTE)currValue, &len);
- // Close the key that was opened.
- ::RegCloseKey(theKey);
- if (REG_FAILED(res) ||
- _wcsicmp(valueData.get(), currValue)) {
- // Key wasn't set or was set to something other than our registry entry.
- NS_ConvertUTF8toUTF16 oldValueData(settings->oldValueData);
- offset = oldValueData.Find("%APPPATH%");
- oldValueData.Replace(offset, 9, appLongPath);
- // The current registry value doesn't match the current or the old format.
- if (_wcsicmp(oldValueData.get(), currValue)) {
- *aIsDefaultBrowser = false;
- return NS_OK;
- }
-
- res = ::RegOpenKeyExW(HKEY_CLASSES_ROOT, PromiseFlatString(keyName).get(),
- 0, KEY_SET_VALUE, &theKey);
- if (REG_FAILED(res)) {
- // If updating the open command fails try to update it using the helper
- // application when setting Basilisk as the default browser.
- *aIsDefaultBrowser = false;
- return NS_OK;
- }
-
- const nsString &flatValue = PromiseFlatString(valueData);
- res = ::RegSetValueExW(theKey, L"", 0, REG_SZ,
- (const BYTE *) flatValue.get(),
- (flatValue.Length() + 1) * sizeof(char16_t));
- // Close the key that was created.
- ::RegCloseKey(theKey);
- if (REG_FAILED(res)) {
- // If updating the open command fails try to update it using the helper
- // application when setting Basilisk as the default browser.
- *aIsDefaultBrowser = false;
- return NS_OK;
- }
- }
- }
-
- // Only check if Basilisk is the default browser on Vista and above if the
- // previous checks show that Basilisk is the default browser.
- if (*aIsDefaultBrowser) {
- IsDefaultBrowserVista(aForAllTypes, aIsDefaultBrowser);
- if (IsWin8OrLater()) {
- IsDefaultBrowserWin8(aForAllTypes, aIsDefaultBrowser);
- }
- }
-
- // To handle the case where DDE isn't disabled due for a user because there
- // account didn't perform a Basilisk update this will check if Basilisk is the
- // default browser and if dde is disabled for each handler
- // and if it isn't disable it. When Basilisk is not the default browser the
- // helper application will disable dde for each handler.
- if (*aIsDefaultBrowser && aForAllTypes) {
- // Check ftp settings
-
- end = gDDESettings + sizeof(gDDESettings) / sizeof(SETTING);
-
- for (settings = gDDESettings; settings < end; ++settings) {
- NS_ConvertUTF8toUTF16 keyName(settings->keyName);
-
- rv = OpenKeyForReading(HKEY_CURRENT_USER, keyName, &theKey);
- if (NS_FAILED(rv)) {
- ::RegCloseKey(theKey);
- // If disabling DDE fails try to disable it using the helper
- // application when setting Basilisk as the default browser.
- *aIsDefaultBrowser = false;
- return NS_OK;
- }
-
- ::ZeroMemory(currValue, sizeof(currValue));
- DWORD len = sizeof currValue;
- res = ::RegQueryValueExW(theKey, L"", nullptr, nullptr,
- (LPBYTE)currValue, &len);
- // Close the key that was opened.
- ::RegCloseKey(theKey);
- if (REG_FAILED(res) || char16_t('\0') != *currValue) {
- // Key wasn't set or was set to something other than our registry entry.
- // Delete the key along with all of its childrean and then recreate it.
- const nsString &flatName = PromiseFlatString(keyName);
- ::SHDeleteKeyW(HKEY_CURRENT_USER, flatName.get());
- res = ::RegCreateKeyExW(HKEY_CURRENT_USER, flatName.get(), 0, nullptr,
- REG_OPTION_NON_VOLATILE, KEY_SET_VALUE,
- nullptr, &theKey, nullptr);
- if (REG_FAILED(res)) {
- // If disabling DDE fails try to disable it using the helper
- // application when setting Basilisk as the default browser.
- *aIsDefaultBrowser = false;
- return NS_OK;
- }
-
- res = ::RegSetValueExW(theKey, L"", 0, REG_SZ, (const BYTE *) L"",
- sizeof(char16_t));
- // Close the key that was created.
- ::RegCloseKey(theKey);
- if (REG_FAILED(res)) {
- // If disabling DDE fails try to disable it using the helper
- // application when setting Basilisk as the default browser.
- *aIsDefaultBrowser = false;
- return NS_OK;
- }
- }
- }
-
- // Update the FTP protocol handler's shell open command if it is the old
- // format.
- res = ::RegOpenKeyExW(HKEY_CURRENT_USER, FTP_SOC, 0, KEY_ALL_ACCESS,
- &theKey);
- // Don't update the FTP protocol handler's shell open command when opening
- // its registry key fails under HKCU since it most likely doesn't exist.
- if (NS_FAILED(rv)) {
- return NS_OK;
- }
-
- NS_ConvertUTF8toUTF16 oldValueOpen(OLD_VAL_OPEN);
- int32_t offset = oldValueOpen.Find("%APPPATH%");
- oldValueOpen.Replace(offset, 9, appLongPath);
-
- ::ZeroMemory(currValue, sizeof(currValue));
- DWORD len = sizeof currValue;
- res = ::RegQueryValueExW(theKey, L"", nullptr, nullptr, (LPBYTE)currValue,
- &len);
-
- // Don't update the FTP protocol handler's shell open command when the
- // current registry value doesn't exist or matches the old format.
- if (REG_FAILED(res) ||
- _wcsicmp(oldValueOpen.get(), currValue)) {
- ::RegCloseKey(theKey);
- return NS_OK;
- }
-
- NS_ConvertUTF8toUTF16 valueData(VAL_OPEN);
- valueData.Replace(offset, 9, appLongPath);
- const nsString &flatValue = PromiseFlatString(valueData);
- res = ::RegSetValueExW(theKey, L"", 0, REG_SZ,
- (const BYTE *) flatValue.get(),
- (flatValue.Length() + 1) * sizeof(char16_t));
- // Close the key that was created.
- ::RegCloseKey(theKey);
- // If updating the FTP protocol handlers shell open command fails try to
- // update it using the helper application when setting Basilisk as the
- // default browser.
- if (REG_FAILED(res)) {
- *aIsDefaultBrowser = false;
- }
- }
-
- return NS_OK;
-}
-
-static nsresult
-DynSHOpenWithDialog(HWND hwndParent, const OPENASINFO *poainfo)
-{
- // shell32.dll is in the knownDLLs list so will always be loaded from the
- // system32 directory.
- static const wchar_t kSehllLibraryName[] = L"shell32.dll";
- HMODULE shellDLL = ::LoadLibraryW(kSehllLibraryName);
- if (!shellDLL) {
- return NS_ERROR_FAILURE;
- }
-
- decltype(SHOpenWithDialog)* SHOpenWithDialogFn =
- (decltype(SHOpenWithDialog)*) GetProcAddress(shellDLL, "SHOpenWithDialog");
-
- if (!SHOpenWithDialogFn) {
- return NS_ERROR_FAILURE;
- }
-
- nsresult rv;
- HRESULT hr = SHOpenWithDialogFn(hwndParent, poainfo);
- if (SUCCEEDED(hr) || (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED))) {
- rv = NS_OK;
- } else {
- rv = NS_ERROR_FAILURE;
- }
- FreeLibrary(shellDLL);
- return rv;
-}
-
-nsresult
-nsWindowsShellService::LaunchControlPanelDefaultsSelectionUI()
-{
- IApplicationAssociationRegistrationUI* pAARUI;
- HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistrationUI,
- NULL,
- CLSCTX_INPROC,
- IID_IApplicationAssociationRegistrationUI,
- (void**)&pAARUI);
- if (SUCCEEDED(hr)) {
- hr = pAARUI->LaunchAdvancedAssociationUI(APP_REG_NAME);
- pAARUI->Release();
- }
- return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
-}
-
-nsresult
-nsWindowsShellService::LaunchControlPanelDefaultPrograms()
-{
- // Build the path control.exe path safely
- WCHAR controlEXEPath[MAX_PATH + 1] = { '\0' };
- if (!GetSystemDirectoryW(controlEXEPath, MAX_PATH)) {
- return NS_ERROR_FAILURE;
- }
- LPCWSTR controlEXE = L"control.exe";
- if (wcslen(controlEXEPath) + wcslen(controlEXE) >= MAX_PATH) {
- return NS_ERROR_FAILURE;
- }
- if (!PathAppendW(controlEXEPath, controlEXE)) {
- return NS_ERROR_FAILURE;
- }
-
- WCHAR params[] = L"control.exe /name Microsoft.DefaultPrograms /page "
- "pageDefaultProgram\\pageAdvancedSettings?pszAppName=" APP_REG_NAME;
- STARTUPINFOW si = {sizeof(si), 0};
- si.dwFlags = STARTF_USESHOWWINDOW;
- si.wShowWindow = SW_SHOWDEFAULT;
- PROCESS_INFORMATION pi = {0};
- if (!CreateProcessW(controlEXEPath, params, nullptr, nullptr, FALSE,
- 0, nullptr, nullptr, &si, &pi)) {
- return NS_ERROR_FAILURE;
- }
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
-
- return NS_OK;
-}
-
-static bool
-IsWindowsLogonConnected()
-{
- WCHAR userName[UNLEN + 1];
- DWORD size = ArrayLength(userName);
- if (!GetUserNameW(userName, &size)) {
- return false;
- }
-
- LPUSER_INFO_24 info;
- if (NetUserGetInfo(nullptr, userName, 24, (LPBYTE *)&info)
- != NERR_Success) {
- return false;
- }
- bool connected = info->usri24_internet_identity;
- NetApiBufferFree(info);
-
- return connected;
-}
-
-static bool
-SettingsAppBelievesConnected()
-{
- nsresult rv;
- nsCOMPtr<nsIWindowsRegKey> regKey =
- do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
- if (NS_FAILED(rv)) {
- return false;
- }
-
- rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
- NS_LITERAL_STRING("SOFTWARE\\Microsoft\\Windows\\Shell\\Associations"),
- nsIWindowsRegKey::ACCESS_READ);
- if (NS_FAILED(rv)) {
- return false;
- }
-
- uint32_t value;
- rv = regKey->ReadIntValue(NS_LITERAL_STRING("IsConnectedAtLogon"), &value);
- if (NS_FAILED(rv)) {
- return false;
- }
-
- return !!value;
-}
-
-nsresult
-nsWindowsShellService::LaunchModernSettingsDialogDefaultApps()
-{
- if (!IsWindowsBuildOrLater(14965) &&
- !IsWindowsLogonConnected() && SettingsAppBelievesConnected()) {
- // Use the classic Control Panel to work around a bug of older
- // builds of Windows 10.
- return LaunchControlPanelDefaultPrograms();
- }
-
- IApplicationActivationManager* pActivator;
- HRESULT hr = CoCreateInstance(CLSID_ApplicationActivationManager,
- nullptr,
- CLSCTX_INPROC,
- IID_IApplicationActivationManager,
- (void**)&pActivator);
-
- if (SUCCEEDED(hr)) {
- DWORD pid;
- hr = pActivator->ActivateApplication(
- L"windows.immersivecontrolpanel_cw5n1h2txyewy"
- L"!microsoft.windows.immersivecontrolpanel",
- L"page=SettingsPageAppsDefaults", AO_NONE, &pid);
- if (SUCCEEDED(hr)) {
- // Do not check error because we could at least open
- // the "Default apps" setting.
- pActivator->ActivateApplication(
- L"windows.immersivecontrolpanel_cw5n1h2txyewy"
- L"!microsoft.windows.immersivecontrolpanel",
- L"page=SettingsPageAppsDefaults"
- L"&target=SystemSettings_DefaultApps_Browser", AO_NONE, &pid);
- }
- pActivator->Release();
- return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
- }
- return NS_OK;
-}
-
-nsresult
-nsWindowsShellService::InvokeHTTPOpenAsVerb()
-{
- nsCOMPtr<nsIURLFormatter> formatter(
- do_GetService("@mozilla.org/toolkit/URLFormatterService;1"));
- if (!formatter) {
- return NS_ERROR_UNEXPECTED;
- }
-
- nsString urlStr;
- nsresult rv = formatter->FormatURLPref(
- NS_LITERAL_STRING("app.support.baseURL"), urlStr);
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (!StringBeginsWith(urlStr, NS_LITERAL_STRING("https://"))) {
- return NS_ERROR_FAILURE;
- }
- urlStr.AppendLiteral("win10-default-browser");
-
- SHELLEXECUTEINFOW seinfo = { sizeof(SHELLEXECUTEINFOW) };
- seinfo.lpVerb = L"openas";
- seinfo.lpFile = urlStr.get();
- seinfo.nShow = SW_SHOWNORMAL;
- if (!ShellExecuteExW(&seinfo)) {
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
-}
-
-nsresult
-nsWindowsShellService::LaunchHTTPHandlerPane()
-{
- OPENASINFO info;
- info.pcszFile = L"http";
- info.pcszClass = nullptr;
- info.oaifInFlags = OAIF_FORCE_REGISTRATION |
- OAIF_URL_PROTOCOL |
- OAIF_REGISTER_EXT;
- return DynSHOpenWithDialog(nullptr, &info);
-}
-
-NS_IMETHODIMP
-nsWindowsShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
-{
- nsAutoString appHelperPath;
- if (NS_FAILED(GetHelperPath(appHelperPath)))
- return NS_ERROR_FAILURE;
-
- if (aForAllUsers) {
- appHelperPath.AppendLiteral(" /SetAsDefaultAppGlobal");
- } else {
- appHelperPath.AppendLiteral(" /SetAsDefaultAppUser");
- }
-
- nsresult rv = LaunchHelper(appHelperPath);
- if (NS_SUCCEEDED(rv) && IsWin8OrLater()) {
- if (aClaimAllTypes) {
- if (IsWin10OrLater()) {
- rv = LaunchModernSettingsDialogDefaultApps();
- } else {
- rv = LaunchControlPanelDefaultsSelectionUI();
- }
- // The above call should never really fail, but just in case
- // fall back to showing the HTTP association screen only.
- if (NS_FAILED(rv)) {
- if (IsWin10OrLater()) {
- rv = InvokeHTTPOpenAsVerb();
- } else {
- rv = LaunchHTTPHandlerPane();
- }
- }
- } else {
- // Windows 10 blocks attempts to load the
- // HTTP Handler association dialog.
- if (IsWin10OrLater()) {
- rv = LaunchModernSettingsDialogDefaultApps();
- } else {
- rv = LaunchHTTPHandlerPane();
- }
-
- // The above call should never really fail, but just in case
- // fall back to showing control panel for all defaults
- if (NS_FAILED(rv)) {
- rv = LaunchControlPanelDefaultsSelectionUI();
- }
- }
- }
-
- nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
- if (prefs) {
- (void) prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true);
- // Reset the number of times the dialog should be shown
- // before it is silenced.
- (void) prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT, 0);
- }
-
- return rv;
-}
-
-static nsresult
-WriteBitmap(nsIFile* aFile, imgIContainer* aImage)
-{
- nsresult rv;
-
- RefPtr<SourceSurface> surface =
- aImage->GetFrame(imgIContainer::FRAME_FIRST,
- imgIContainer::FLAG_SYNC_DECODE);
- NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
-
- // For either of the following formats we want to set the biBitCount member
- // of the BITMAPINFOHEADER struct to 32, below. For that value the bitmap
- // format defines that the A8/X8 WORDs in the bitmap byte stream be ignored
- // for the BI_RGB value we use for the biCompression member.
- MOZ_ASSERT(surface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
- surface->GetFormat() == SurfaceFormat::B8G8R8X8);
-
- RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
- NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
-
- int32_t width = dataSurface->GetSize().width;
- int32_t height = dataSurface->GetSize().height;
- int32_t bytesPerPixel = 4 * sizeof(uint8_t);
- uint32_t bytesPerRow = bytesPerPixel * width;
-
- // initialize these bitmap structs which we will later
- // serialize directly to the head of the bitmap file
- BITMAPINFOHEADER bmi;
- bmi.biSize = sizeof(BITMAPINFOHEADER);
- bmi.biWidth = width;
- bmi.biHeight = height;
- bmi.biPlanes = 1;
- bmi.biBitCount = (WORD)bytesPerPixel*8;
- bmi.biCompression = BI_RGB;
- bmi.biSizeImage = bytesPerRow * height;
- bmi.biXPelsPerMeter = 0;
- bmi.biYPelsPerMeter = 0;
- bmi.biClrUsed = 0;
- bmi.biClrImportant = 0;
-
- BITMAPFILEHEADER bf;
- bf.bfType = 0x4D42; // 'BM'
- bf.bfReserved1 = 0;
- bf.bfReserved2 = 0;
- bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
- bf.bfSize = bf.bfOffBits + bmi.biSizeImage;
-
- // get a file output stream
- nsCOMPtr<nsIOutputStream> stream;
- rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), aFile);
- NS_ENSURE_SUCCESS(rv, rv);
-
- DataSourceSurface::MappedSurface map;
- if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
- return NS_ERROR_FAILURE;
- }
-
- // write the bitmap headers and rgb pixel data to the file
- rv = NS_ERROR_FAILURE;
- if (stream) {
- uint32_t written;
- stream->Write((const char*)&bf, sizeof(BITMAPFILEHEADER), &written);
- if (written == sizeof(BITMAPFILEHEADER)) {
- stream->Write((const char*)&bmi, sizeof(BITMAPINFOHEADER), &written);
- if (written == sizeof(BITMAPINFOHEADER)) {
- // write out the image data backwards because the desktop won't
- // show bitmaps with negative heights for top-to-bottom
- uint32_t i = map.mStride * height;
- do {
- i -= map.mStride;
- stream->Write(((const char*)map.mData) + i, bytesPerRow, &written);
- if (written == bytesPerRow) {
- rv = NS_OK;
- } else {
- rv = NS_ERROR_FAILURE;
- break;
- }
- } while (i != 0);
- }
- }
-
- stream->Close();
- }
-
- dataSurface->Unmap();
-
- return rv;
-}
-
-NS_IMETHODIMP
-nsWindowsShellService::SetDesktopBackground(nsIDOMElement* aElement,
- int32_t aPosition)
-{
- nsresult rv;
-
- nsCOMPtr<imgIContainer> container;
- nsCOMPtr<nsIDOMHTMLImageElement> imgElement(do_QueryInterface(aElement));
- if (!imgElement) {
- // XXX write background loading stuff!
- return NS_ERROR_NOT_AVAILABLE;
- }
- else {
- nsCOMPtr<nsIImageLoadingContent> imageContent =
- do_QueryInterface(aElement, &rv);
- if (!imageContent)
- return rv;
-
- // get the image container
- nsCOMPtr<imgIRequest> request;
- rv = imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
- getter_AddRefs(request));
- if (!request)
- return rv;
- rv = request->GetImage(getter_AddRefs(container));
- if (!container)
- return NS_ERROR_FAILURE;
- }
-
- // get the file name from localized strings
- nsCOMPtr<nsIStringBundleService>
- bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
- NS_ENSURE_SUCCESS(rv, rv);
-
- nsCOMPtr<nsIStringBundle> shellBundle;
- rv = bundleService->CreateBundle(SHELLSERVICE_PROPERTIES,
- getter_AddRefs(shellBundle));
- NS_ENSURE_SUCCESS(rv, rv);
-
- // e.g. "Desktop Background.bmp"
- nsString fileLeafName;
- rv = shellBundle->GetStringFromName
- (u"desktopBackgroundLeafNameWin",
- getter_Copies(fileLeafName));
- NS_ENSURE_SUCCESS(rv, rv);
-
- // get the profile root directory
- nsCOMPtr<nsIFile> file;
- rv = NS_GetSpecialDirectory(NS_APP_APPLICATION_REGISTRY_DIR,
- getter_AddRefs(file));
- NS_ENSURE_SUCCESS(rv, rv);
-
- // eventually, the path is "%APPDATA%\Mozilla\Basilisk\Desktop Background.bmp"
- rv = file->Append(fileLeafName);
- NS_ENSURE_SUCCESS(rv, rv);
-
- nsAutoString path;
- rv = file->GetPath(path);
- NS_ENSURE_SUCCESS(rv, rv);
-
- // write the bitmap to a file in the profile directory
- rv = WriteBitmap(file, container);
-
- // if the file was written successfully, set it as the system wallpaper
- if (NS_SUCCEEDED(rv)) {
- nsCOMPtr<nsIWindowsRegKey> regKey =
- do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
- NS_LITERAL_STRING("Control Panel\\Desktop"),
- nsIWindowsRegKey::ACCESS_SET_VALUE);
- NS_ENSURE_SUCCESS(rv, rv);
-
- nsAutoString tile;
- nsAutoString style;
- switch (aPosition) {
- case BACKGROUND_TILE:
- style.Assign('0');
- tile.Assign('1');
- break;
- case BACKGROUND_CENTER:
- style.Assign('0');
- tile.Assign('0');
- break;
- case BACKGROUND_STRETCH:
- style.Assign('2');
- tile.Assign('0');
- break;
- case BACKGROUND_FILL:
- style.AssignLiteral("10");
- tile.Assign('0');
- break;
- case BACKGROUND_FIT:
- style.Assign('6');
- tile.Assign('0');
- break;
- }
-
- rv = regKey->WriteStringValue(NS_LITERAL_STRING("TileWallpaper"), tile);
- NS_ENSURE_SUCCESS(rv, rv);
- rv = regKey->WriteStringValue(NS_LITERAL_STRING("WallpaperStyle"), style);
- NS_ENSURE_SUCCESS(rv, rv);
- rv = regKey->Close();
- NS_ENSURE_SUCCESS(rv, rv);
-
- ::SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, (PVOID)path.get(),
- SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
- }
- return rv;
-}
-
-NS_IMETHODIMP
-nsWindowsShellService::OpenApplication(int32_t aApplication)
-{
- nsAutoString application;
- switch (aApplication) {
- case nsIShellService::APPLICATION_MAIL:
- application.AssignLiteral("Mail");
- break;
- case nsIShellService::APPLICATION_NEWS:
- application.AssignLiteral("News");
- break;
- }
-
- // The Default Client section of the Windows Registry looks like this:
- //
- // Clients\aClient\
- // e.g. aClient = "Mail"...
- // \Mail\(default) = Client Subkey Name
- // \Client Subkey Name
- // \Client Subkey Name\shell\open\command\
- // \Client Subkey Name\shell\open\command\(default) = path to exe
- //
-
- // Find the default application for this class.
- HKEY theKey;
- nsresult rv = OpenKeyForReading(HKEY_CLASSES_ROOT, application, &theKey);
- if (NS_FAILED(rv))
- return rv;
-
- wchar_t buf[MAX_BUF];
- DWORD type, len = sizeof buf;
- DWORD res = ::RegQueryValueExW(theKey, EmptyString().get(), 0,
- &type, (LPBYTE)&buf, &len);
-
- if (REG_FAILED(res) || !*buf)
- return NS_OK;
-
- // Close the key we opened.
- ::RegCloseKey(theKey);
-
- // Find the "open" command
- application.Append('\\');
- application.Append(buf);
- application.AppendLiteral("\\shell\\open\\command");
-
- rv = OpenKeyForReading(HKEY_CLASSES_ROOT, application, &theKey);
- if (NS_FAILED(rv))
- return rv;
-
- ::ZeroMemory(buf, sizeof(buf));
- len = sizeof buf;
- res = ::RegQueryValueExW(theKey, EmptyString().get(), 0,
- &type, (LPBYTE)&buf, &len);
- if (REG_FAILED(res) || !*buf)
- return NS_ERROR_FAILURE;
-
- // Close the key we opened.
- ::RegCloseKey(theKey);
-
- // Look for any embedded environment variables and substitute their
- // values, as |::CreateProcessW| is unable to do this.
- nsAutoString path(buf);
- int32_t end = path.Length();
- int32_t cursor = 0, temp = 0;
- ::ZeroMemory(buf, sizeof(buf));
- do {
- cursor = path.FindChar('%', cursor);
- if (cursor < 0)
- break;
-
- temp = path.FindChar('%', cursor + 1);
- ++cursor;
-
- ::ZeroMemory(&buf, sizeof(buf));
-
- ::GetEnvironmentVariableW(nsAutoString(Substring(path, cursor, temp - cursor)).get(),
- buf, sizeof(buf));
-
- // "+ 2" is to subtract the extra characters used to delimit the environment
- // variable ('%').
- path.Replace((cursor - 1), temp - cursor + 2, nsDependentString(buf));
-
- ++cursor;
- }
- while (cursor < end);
-
- STARTUPINFOW si;
- PROCESS_INFORMATION pi;
-
- ::ZeroMemory(&si, sizeof(STARTUPINFOW));
- ::ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
-
- BOOL success = ::CreateProcessW(nullptr, (LPWSTR)path.get(), nullptr,
- nullptr, FALSE, 0, nullptr, nullptr,
- &si, &pi);
- if (!success)
- return NS_ERROR_FAILURE;
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWindowsShellService::GetDesktopBackgroundColor(uint32_t* aColor)
-{
- uint32_t color = ::GetSysColor(COLOR_DESKTOP);
- *aColor = (GetRValue(color) << 16) | (GetGValue(color) << 8) | GetBValue(color);
- return NS_OK;
-}
-
-NS_IMETHODIMP
-nsWindowsShellService::SetDesktopBackgroundColor(uint32_t aColor)
-{
- int aParameters[2] = { COLOR_BACKGROUND, COLOR_DESKTOP };
- BYTE r = (aColor >> 16);
- BYTE g = (aColor << 16) >> 24;
- BYTE b = (aColor << 24) >> 24;
- COLORREF colors[2] = { RGB(r,g,b), RGB(r,g,b) };
-
- ::SetSysColors(sizeof(aParameters) / sizeof(int), aParameters, colors);
-
- nsresult rv;
- nsCOMPtr<nsIWindowsRegKey> regKey =
- do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
- NS_LITERAL_STRING("Control Panel\\Colors"),
- nsIWindowsRegKey::ACCESS_SET_VALUE);
- NS_ENSURE_SUCCESS(rv, rv);
-
- wchar_t rgb[12];
- _snwprintf(rgb, 12, L"%u %u %u", r, g, b);
-
- rv = regKey->WriteStringValue(NS_LITERAL_STRING("Background"),
- nsDependentString(rgb));
- NS_ENSURE_SUCCESS(rv, rv);
-
- return regKey->Close();
-}
-
-nsWindowsShellService::nsWindowsShellService()
-{
-}
-
-nsWindowsShellService::~nsWindowsShellService()
-{
-}
-
-NS_IMETHODIMP
-nsWindowsShellService::OpenApplicationWithURI(nsIFile* aApplication,
- const nsACString& aURI)
-{
- nsresult rv;
- nsCOMPtr<nsIProcess> process =
- do_CreateInstance("@mozilla.org/process/util;1", &rv);
- if (NS_FAILED(rv))
- return rv;
-
- rv = process->Init(aApplication);
- if (NS_FAILED(rv))
- return rv;
-
- const nsCString spec(aURI);
- const char* specStr = spec.get();
- return process->Run(false, &specStr, 1);
-}
-
-NS_IMETHODIMP
-nsWindowsShellService::GetDefaultFeedReader(nsIFile** _retval)
-{
- *_retval = nullptr;
-
- nsresult rv;
- nsCOMPtr<nsIWindowsRegKey> regKey =
- do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
- NS_LITERAL_STRING("feed\\shell\\open\\command"),
- nsIWindowsRegKey::ACCESS_READ);
- NS_ENSURE_SUCCESS(rv, rv);
-
- nsAutoString path;
- rv = regKey->ReadStringValue(EmptyString(), path);
- NS_ENSURE_SUCCESS(rv, rv);
- if (path.IsEmpty())
- return NS_ERROR_FAILURE;
-
- if (path.First() == '"') {
- // Everything inside the quotes
- path = Substring(path, 1, path.FindChar('"', 1) - 1);
- }
- else {
- // Everything up to the first space
- path = Substring(path, 0, path.FindChar(' '));
- }
-
- nsCOMPtr<nsIFile> defaultReader =
- do_CreateInstance("@mozilla.org/file/local;1", &rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
- rv = defaultReader->InitWithPath(path);
- NS_ENSURE_SUCCESS(rv, rv);
-
- bool exists;
- rv = defaultReader->Exists(&exists);
- NS_ENSURE_SUCCESS(rv, rv);
- if (!exists)
- return NS_ERROR_FAILURE;
-
- NS_ADDREF(*_retval = defaultReader);
- return NS_OK;
-}