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