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