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.

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

mercurial