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