nsWindowsShellService.cpp
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is Shell Service.
16  *
17  * The Initial Developer of the Original Code is mozilla.org.
18  * Portions created by the Initial Developer are Copyright (C) 2004
19  * the Initial Developer. All Rights Reserved.
20  *
21  * Contributor(s):
22  * Ben Goodger <ben@mozilla.org> (Clients, Mail, New Default Browser)
23  * Joe Hewitt <hewitt@netscape.com> (Set Background)
24  * Blake Ross <blake@cs.stanford.edu> (Desktop Color, DDE support)
25  * Jungshik Shin <jshin@mailaps.org> (I18N)
26  * Robert Strong <robert.bugzilla@gmail.com>
27  * Asaf Romano <mano@mozilla.com>
28  * Ryan Jones <sciguyryan@gmail.com>
29  * Paul O'Shannessy <paul@oshannessy.com>
30  *
31  * Alternatively, the contents of this file may be used under the terms of
32  * either the GNU General Public License Version 2 or later (the "GPL"), or
33  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34  * in which case the provisions of the GPL or the LGPL are applicable instead
35  * of those above. If you wish to allow use of your version of this file only
36  * under the terms of either the GPL or the LGPL, and not to allow others to
37  * use your version of this file under the terms of the MPL, indicate your
38  * decision by deleting the provisions above and replace them with the notice
39  * and other provisions required by the GPL or the LGPL. If you do not delete
40  * the provisions above, a recipient may use your version of this file under
41  * the terms of any one of the MPL, the GPL or the LGPL.
42  *
43  * ***** END LICENSE BLOCK ***** */
44 
45 #include "imgIContainer.h"
46 #include "imgIRequest.h"
47 #include "nsIDOMDocument.h"
48 #include "nsIDOMElement.h"
49 #include "nsIDOMHTMLImageElement.h"
50 #include "nsIImageLoadingContent.h"
51 #include "nsIPrefService.h"
52 #include "nsIPrefLocalizedString.h"
53 #include "nsIServiceManager.h"
54 #include "nsIStringBundle.h"
55 #include "nsNetUtil.h"
56 #include "nsShellService.h"
57 #include "nsWindowsShellService.h"
58 #include "nsIProcess.h"
59 #include "nsICategoryManager.h"
60 #include "nsBrowserCompsCID.h"
61 #include "nsDirectoryServiceUtils.h"
62 #include "nsAppDirectoryServiceDefs.h"
63 #include "nsDirectoryServiceDefs.h"
64 #include "nsIWindowsRegKey.h"
65 #include "nsUnicharUtils.h"
66 
67 #include "windows.h"
68 #include "shellapi.h"
69 
70 #ifdef _WIN32_WINNT
71 #undef _WIN32_WINNT
72 #endif
73 #define _WIN32_WINNT 0x0600
74 #define INITGUID
75 #include <shlobj.h>
76 
77 #include <mbstring.h>
78 
79 #ifndef MAX_BUF
80 #define MAX_BUF 4096
81 #endif
82 
83 #define REG_SUCCEEDED(val) \
84  (val == ERROR_SUCCESS)
85 
86 #define REG_FAILED(val) \
87  (val != ERROR_SUCCESS)
88 
89 #ifndef WINCE
91 #else
93 #endif
94 
95 static nsresult
96 OpenKeyForReading(HKEY aKeyRoot, const nsAString& aKeyName, HKEY* aKey)
97 {
98  const nsString &flatName = PromiseFlatString(aKeyName);
99 
100  DWORD res = ::RegOpenKeyExW(aKeyRoot, flatName.get(), 0, KEY_READ, aKey);
101  switch (res) {
102  case ERROR_SUCCESS:
103  break;
104  case ERROR_ACCESS_DENIED:
105  return NS_ERROR_FILE_ACCESS_DENIED;
106  case ERROR_FILE_NOT_FOUND:
107  return NS_ERROR_NOT_AVAILABLE;
108  }
109 
110  return NS_OK;
111 }
112 
113 #ifdef WINCE
114 static nsresult
115 OpenKeyForWriting(HKEY aStartKey, const nsAString& aKeyName, HKEY* aKey)
116 {
117  const nsString &flatName = PromiseFlatString(aKeyName);
118 
119  DWORD dwDisp = 0;
120  DWORD res = ::RegCreateKeyExW(aStartKey, flatName.get(), 0, NULL,
121  0, KEY_READ | KEY_WRITE, NULL, aKey,
122  &dwDisp);
123  switch (res) {
124  case ERROR_SUCCESS:
125  break;
126  case ERROR_ACCESS_DENIED:
127  return NS_ERROR_FILE_ACCESS_DENIED;
128  case ERROR_FILE_NOT_FOUND:
129  res = ::RegCreateKeyExW(aStartKey, flatName.get(), 0, NULL,
130  0, KEY_READ | KEY_WRITE, NULL, aKey,
131  NULL);
132  if (res != ERROR_SUCCESS)
133  return NS_ERROR_FILE_ACCESS_DENIED;
134  }
135 
136  return NS_OK;
137 }
138 #endif
139 
141 // Default Browser Registry Settings
142 //
143 // The setting of these values are made by an external binary since writing
144 // these values may require elevation.
145 //
146 // - File Extension Mappings
147 // -----------------------
148 // The following file extensions:
149 // .htm .html .shtml .xht .xhtml
150 // are mapped like so:
151 //
152 // HKCU\SOFTWARE\Classes\.<ext>\ (default) REG_SZ FirefoxHTML
153 //
154 // as aliases to the class:
155 //
156 // HKCU\SOFTWARE\Classes\FirefoxHTML\
157 // DefaultIcon (default) REG_SZ <apppath>,1
158 // shell\open\command (default) REG_SZ <apppath> -requestPending -osint -url "%1"
159 // shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,,
160 // shell\open\ddeexec NoActivateHandler REG_SZ
161 // \Application (default) REG_SZ Firefox
162 // \Topic (default) REG_SZ WWW_OpenURL
163 //
164 // - Windows Vista Protocol Handler
165 //
166 // HKCU\SOFTWARE\Classes\FirefoxURL\ (default) REG_SZ <appname> URL
167 // EditFlags REG_DWORD 2
168 // FriendlyTypeName REG_SZ <appname> URL
169 // DefaultIcon (default) REG_SZ <apppath>,1
170 // shell\open\command (default) REG_SZ <apppath> -requestPending -osint -url "%1"
171 // shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,,
172 // shell\open\ddeexec NoActivateHandler REG_SZ
173 // \Application (default) REG_SZ Firefox
174 // \Topic (default) REG_SZ WWW_OpenURL
175 //
176 // - Protocol Mappings
177 // -----------------
178 // The following protocols:
179 // HTTP, HTTPS, FTP
180 // are mapped like so:
181 //
182 // HKCU\SOFTWARE\Classes<protocol>\
183 // DefaultIcon (default) REG_SZ <apppath>,1
184 // shell\open\command (default) REG_SZ <apppath> -requestPending -osint -url "%1"
185 // shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,,
186 // shell\open\ddeexec NoActivateHandler REG_SZ
187 // \Application (default) REG_SZ Firefox
188 // \Topic (default) REG_SZ WWW_OpenURL
189 //
190 // - Windows Start Menu (Win2K SP2, XP SP1, and newer)
191 // -------------------------------------------------
192 // The following keys are set to make Firefox appear in the Start Menu as the
193 // browser:
194 //
195 // HKCU\SOFTWARE\Clients\StartMenuInternet\FIREFOX.EXE\
196 // (default) REG_SZ <appname>
197 // DefaultIcon (default) REG_SZ <apppath>,0
198 // InstallInfo HideIconsCommand REG_SZ <uninstpath> /HideShortcuts
199 // InstallInfo IconsVisible REG_DWORD 1
200 // InstallInfo ReinstallCommand REG_SZ <uninstpath> /SetAsDefaultAppGlobal
201 // InstallInfo ShowIconsCommand REG_SZ <uninstpath> /ShowShortcuts
202 // shell\open\command (default) REG_SZ <apppath>
203 // shell\properties (default) REG_SZ <appname> &Options
204 // shell\properties\command (default) REG_SZ <apppath> -preferences
205 // shell\safemode (default) REG_SZ <appname> &Safe Mode
206 // shell\safemode\command (default) REG_SZ <apppath> -safe-mode
207 //
208 
209 typedef struct {
210  char* keyName;
211  char* valueName;
212  char* valueData;
213 } SETTING;
214 
215 #ifndef WINCE
216 #define APP_REG_NAME L"Firefox"
217 #define CLS_HTML "FirefoxHTML"
218 #define CLS_URL "FirefoxURL"
219 #define CPL_DESKTOP L"Control Panel\\Desktop"
220 #define VAL_OPEN "\"%APPPATH%\" -requestPending -osint -url \"%1\""
221 #define VAL_FILE_ICON "%APPPATH%,1"
222 #else
223 #define CPL_DESKTOP L"ControlPanel\\Desktop"
224 #define VAL_OPEN "\"%APPPATH%\" -osint -url \"%1\""
225 #define VAL_FILE_ICON "%APPPATH%,-2"
226 #endif
227 
228 #define DI "\\DefaultIcon"
229 #define SOP "\\shell\\open\\command"
230 
231 
232 #define MAKE_KEY_NAME1(PREFIX, MID) \
233  PREFIX MID
234 
235 // The DefaultIcon registry key value should never be used when checking if
236 // Firefox is the default browser for file handlers since other applications
237 // (e.g. MS Office) may modify the DefaultIcon registry key value to add Icon
238 // Handlers. see http://msdn2.microsoft.com/en-us/library/aa969357.aspx for
239 // more info.
240 static SETTING gSettings[] = {
241 #ifndef WINCE
242  // File Handler Class
243  { MAKE_KEY_NAME1(CLS_HTML, SOP), "", VAL_OPEN },
244 
245  // Protocol Handler Class - for Vista and above
246  { MAKE_KEY_NAME1(CLS_URL, SOP), "", VAL_OPEN },
247 #else
248  { MAKE_KEY_NAME1("FTP", DI), "", VAL_FILE_ICON },
249  { MAKE_KEY_NAME1("FTP", SOP), "", VAL_OPEN },
250 
251  // File handlers for Windows CE
252  { MAKE_KEY_NAME1("bmpfile", DI), "", VAL_FILE_ICON },
253  { MAKE_KEY_NAME1("bmpfile", SOP), "", VAL_OPEN },
254  { MAKE_KEY_NAME1("giffile", DI), "", VAL_FILE_ICON },
255  { MAKE_KEY_NAME1("giffile", SOP), "", VAL_OPEN },
256  { MAKE_KEY_NAME1("jpegfile", DI), "", VAL_FILE_ICON },
257  { MAKE_KEY_NAME1("jpegfile", SOP), "", VAL_OPEN },
258  { MAKE_KEY_NAME1("pngfile", DI), "", VAL_FILE_ICON },
259  { MAKE_KEY_NAME1("pngfile", SOP), "", VAL_OPEN },
260  { MAKE_KEY_NAME1("htmlfile", DI), "", VAL_FILE_ICON },
261  { MAKE_KEY_NAME1("htmlfile", SOP), "", VAL_OPEN },
262 #endif
263 
264  // Protocol Handlers
265  { MAKE_KEY_NAME1("HTTP", DI), "", VAL_FILE_ICON },
266  { MAKE_KEY_NAME1("HTTP", SOP), "", VAL_OPEN },
267  { MAKE_KEY_NAME1("HTTPS", DI), "", VAL_FILE_ICON },
268  { MAKE_KEY_NAME1("HTTPS", SOP), "", VAL_OPEN }
269 };
270 
271 #ifndef WINCE
272 PRBool
274 {
275 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
276  IApplicationAssociationRegistration* pAAR;
277 
278  HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
279  NULL,
280  CLSCTX_INPROC,
281  IID_IApplicationAssociationRegistration,
282  (void**)&pAAR);
283 
284  if (SUCCEEDED(hr)) {
285  hr = pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE,
286  APP_REG_NAME,
287  aIsDefaultBrowser);
288 
289  pAAR->Release();
290  return PR_TRUE;
291  }
292 #endif
293  return PR_FALSE;
294 }
295 #endif
296 
297 NS_IMETHODIMP
298 nsWindowsShellService::IsDefaultBrowser(PRBool aStartupCheck,
299  PRBool* aIsDefaultBrowser)
300 {
301  // If this is the first browser window, maintain internal state that we've
302  // checked this session (so that subsequent window opens don't show the
303  // default browser dialog).
304  if (aStartupCheck)
305  mCheckedThisSession = PR_TRUE;
306 
307  SETTING* settings;
308  SETTING* end = gSettings + sizeof(gSettings)/sizeof(SETTING);
309 
310  *aIsDefaultBrowser = PR_TRUE;
311 
312  PRUnichar exePath[MAX_BUF];
313  if (!::GetModuleFileNameW(0, exePath, MAX_BUF))
314  return NS_ERROR_FAILURE;
315 
316 #ifndef WINCE
317  // Convert the path to a long path since GetModuleFileNameW returns the path
318  // that was used to launch Firefox which is not necessarily a long path.
319  if (!::GetLongPathNameW(exePath, exePath, MAX_BUF))
320  return NS_ERROR_FAILURE;
321 #endif
322 
323  nsAutoString appLongPath(exePath);
324 
325  nsresult rv;
326  PRUnichar currValue[MAX_BUF];
327  for (settings = gSettings; settings < end; ++settings) {
328  NS_ConvertUTF8toUTF16 dataLongPath(settings->valueData);
329  NS_ConvertUTF8toUTF16 key(settings->keyName);
330  NS_ConvertUTF8toUTF16 value(settings->valueName);
331  PRInt32 offset = dataLongPath.Find("%APPPATH%");
332  dataLongPath.Replace(offset, 9, appLongPath);
333 
334  ::ZeroMemory(currValue, sizeof(currValue));
335  HKEY theKey;
336  rv = OpenKeyForReading(HKEY_CLASSES_ROOT, key, &theKey);
337  if (NS_FAILED(rv)) {
338  *aIsDefaultBrowser = PR_FALSE;
339  return NS_OK;
340  }
341 
342  DWORD len = sizeof currValue;
343  DWORD res = ::RegQueryValueExW(theKey, PromiseFlatString(value).get(),
344  NULL, NULL, (LPBYTE)currValue, &len);
345  // Close the key we opened.
346  ::RegCloseKey(theKey);
347  if (REG_FAILED(res) ||
348  !dataLongPath.Equals(currValue, CaseInsensitiveCompare)) {
349  // Key wasn't set, or was set to something other than our registry entry
350  *aIsDefaultBrowser = PR_FALSE;
351  return NS_OK;
352  }
353  }
354 
355 #ifndef WINCE
356  // Only check if Firefox is the default browser on Vista if the previous
357  // checks show that Firefox is the default browser.
358  if (*aIsDefaultBrowser)
359  IsDefaultBrowserVista(aIsDefaultBrowser);
360 #endif
361 
362  return NS_OK;
363 }
364 
365 NS_IMETHODIMP
366 nsWindowsShellService::SetDefaultBrowser(PRBool aClaimAllTypes, PRBool aForAllUsers)
367 {
368 #ifndef WINCE
369  nsresult rv;
370  nsCOMPtr<nsIProperties> directoryService =
371  do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
372  NS_ENSURE_SUCCESS(rv, rv);
373 
374  nsCOMPtr<nsILocalFile> appHelper;
375  rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(appHelper));
376  NS_ENSURE_SUCCESS(rv, rv);
377 
378  rv = appHelper->AppendNative(NS_LITERAL_CSTRING("uninstall"));
379  NS_ENSURE_SUCCESS(rv, rv);
380 
381  rv = appHelper->AppendNative(NS_LITERAL_CSTRING("helper.exe"));
382  NS_ENSURE_SUCCESS(rv, rv);
383 
384  nsAutoString appHelperPath;
385  rv = appHelper->GetPath(appHelperPath);
386  NS_ENSURE_SUCCESS(rv, rv);
387 
388  if (aForAllUsers) {
389  appHelperPath.AppendLiteral(" /SetAsDefaultAppGlobal");
390  } else {
391  appHelperPath.AppendLiteral(" /SetAsDefaultAppUser");
392  }
393 
394  STARTUPINFOW si = {sizeof(si), 0};
395  PROCESS_INFORMATION pi = {0};
396 
397  BOOL ok = CreateProcessW(NULL, (LPWSTR)appHelperPath.get(), NULL, NULL,
398  FALSE, 0, NULL, NULL, &si, &pi);
399 
400  if (!ok)
401  return NS_ERROR_FAILURE;
402 
403  CloseHandle(pi.hProcess);
404  CloseHandle(pi.hThread);
405 #else
406  SETTING* settings;
407  SETTING* end = gSettings + sizeof(gSettings)/sizeof(SETTING);
408 
409  PRUnichar exePath[MAX_BUF];
410  if (!::GetModuleFileNameW(0, exePath, MAX_BUF))
411  return NS_ERROR_FAILURE;
412 
413  nsAutoString appLongPath(exePath);
414 
415  // The .png registry key isn't present by default so also add Content Type.
416  SetRegKey(NS_LITERAL_STRING(".png"), EmptyString(),
417  NS_LITERAL_STRING("pngfile"));
418  SetRegKey(NS_LITERAL_STRING(".png"), NS_LITERAL_STRING("Content Type"),
419  NS_LITERAL_STRING("image/png"));
420 
421  // Set these keys to their default value for a clean install in case another
422  // app has changed these keys.
423  SetRegKey(NS_LITERAL_STRING(".htm"), EmptyString(),
424  NS_LITERAL_STRING("htmlfile"));
425  SetRegKey(NS_LITERAL_STRING(".html"), EmptyString(),
426  NS_LITERAL_STRING("htmlfile"));
427  SetRegKey(NS_LITERAL_STRING(".bmp"), EmptyString(),
428  NS_LITERAL_STRING("bmpfile"));
429  SetRegKey(NS_LITERAL_STRING(".gif"), EmptyString(),
430  NS_LITERAL_STRING("giffile"));
431  SetRegKey(NS_LITERAL_STRING(".jpe"), EmptyString(),
432  NS_LITERAL_STRING("jpegfile"));
433  SetRegKey(NS_LITERAL_STRING(".jpg"), EmptyString(),
434  NS_LITERAL_STRING("jpegfile"));
435  SetRegKey(NS_LITERAL_STRING(".jpeg"), EmptyString(),
436  NS_LITERAL_STRING("jpegfile"));
437 
438  for (settings = gSettings; settings < end; ++settings) {
439  NS_ConvertUTF8toUTF16 dataLongPath(settings->valueData);
440  NS_ConvertUTF8toUTF16 key(settings->keyName);
441  NS_ConvertUTF8toUTF16 value(settings->valueName);
442  PRInt32 offset = dataLongPath.Find("%APPPATH%");
443  dataLongPath.Replace(offset, 9, appLongPath);
444  SetRegKey(key, value, dataLongPath);
445  }
446  // On Windows CE RegFlushKey can negatively impact performance if there are a
447  // lot of pending writes to the HKEY_CLASSES_ROOT registry hive but it is
448  // necessary to save the values in the case where the user performs a hard
449  // power off of the device.
450  ::RegFlushKey(HKEY_CLASSES_ROOT);
451 #endif
452 
453  return NS_OK;
454 }
455 
456 #ifdef WINCE
457 void
458 nsWindowsShellService::SetRegKey(const nsString& aKeyName,
459  const nsString& aValueName,
460  const nsString& aValue)
461 {
462  PRUnichar buf[MAX_BUF];
463  DWORD len = sizeof buf;
464 
465  HKEY theKey;
466  nsresult rv = OpenKeyForWriting(HKEY_CLASSES_ROOT, aKeyName, &theKey);
467  if (NS_FAILED(rv))
468  return;
469 
470  // Get the current value.
471  DWORD res = ::RegQueryValueExW(theKey, PromiseFlatString(aValueName).get(),
472  NULL, NULL, (LPBYTE)buf, &len);
473 
474  // Set the new value if it doesn't exist or it is different than the current
475  // value.
476  nsAutoString current(buf);
477  if (REG_FAILED(res) || !current.Equals(aValue)) {
478  const nsString &flatValue = PromiseFlatString(aValue);
479 
480  ::RegSetValueExW(theKey, PromiseFlatString(aValueName).get(),
481  0, REG_SZ, (const BYTE *)flatValue.get(),
482  (flatValue.Length() + 1) * sizeof(PRUnichar));
483  }
484 
485  // Close the key we opened.
486  ::RegCloseKey(theKey);
487 }
488 #endif
489 
490 NS_IMETHODIMP
491 nsWindowsShellService::GetShouldCheckDefaultBrowser(PRBool* aResult)
492 {
493  // If we've already checked, the browser has been started and this is a
494  // new window open, and we don't want to check again.
495  if (mCheckedThisSession) {
496  *aResult = PR_FALSE;
497  return NS_OK;
498  }
499 
500  nsCOMPtr<nsIPrefBranch> prefs;
501  nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID));
502  if (pserve)
503  pserve->GetBranch("", getter_AddRefs(prefs));
504 
505  prefs->GetBoolPref(PREF_CHECKDEFAULTBROWSER, aResult);
506 
507  return NS_OK;
508 }
509 
510 NS_IMETHODIMP
511 nsWindowsShellService::SetShouldCheckDefaultBrowser(PRBool aShouldCheck)
512 {
513  nsCOMPtr<nsIPrefBranch> prefs;
514  nsCOMPtr<nsIPrefService> pserve(do_GetService(NS_PREFSERVICE_CONTRACTID));
515  if (pserve)
516  pserve->GetBranch("", getter_AddRefs(prefs));
517 
518  prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, aShouldCheck);
519 
520  return NS_OK;
521 }
522 
523 static nsresult
524 WriteBitmap(nsIFile* aFile, imgIContainer* aImage)
525 {
526  nsRefPtr<gfxImageSurface> image;
527  nsresult rv = aImage->CopyCurrentFrame(getter_AddRefs(image));
528  NS_ENSURE_SUCCESS(rv, rv);
529 
530  PRInt32 width = image->Width();
531  PRInt32 height = image->Height();
532 
533  PRUint8* bits = image->Data();
534  PRUint32 length = image->GetDataSize();
535  PRUint32 bpr = PRUint32(image->Stride());
536  PRInt32 bitCount = bpr/width;
537 
538  // initialize these bitmap structs which we will later
539  // serialize directly to the head of the bitmap file
540  BITMAPINFOHEADER bmi;
541  bmi.biSize = sizeof(BITMAPINFOHEADER);
542  bmi.biWidth = width;
543  bmi.biHeight = height;
544  bmi.biPlanes = 1;
545  bmi.biBitCount = (WORD)bitCount*8;
546  bmi.biCompression = BI_RGB;
547  bmi.biSizeImage = length;
548  bmi.biXPelsPerMeter = 0;
549  bmi.biYPelsPerMeter = 0;
550  bmi.biClrUsed = 0;
551  bmi.biClrImportant = 0;
552 
553  BITMAPFILEHEADER bf;
554  bf.bfType = 0x4D42; // 'BM'
555  bf.bfReserved1 = 0;
556  bf.bfReserved2 = 0;
557  bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
558  bf.bfSize = bf.bfOffBits + bmi.biSizeImage;
559 
560  // get a file output stream
561  nsCOMPtr<nsIOutputStream> stream;
562  rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), aFile);
563  NS_ENSURE_SUCCESS(rv, rv);
564 
565  // write the bitmap headers and rgb pixel data to the file
566  rv = NS_ERROR_FAILURE;
567  if (stream) {
568  PRUint32 written;
569  stream->Write((const char*)&bf, sizeof(BITMAPFILEHEADER), &written);
570  if (written == sizeof(BITMAPFILEHEADER)) {
571  stream->Write((const char*)&bmi, sizeof(BITMAPINFOHEADER), &written);
572  if (written == sizeof(BITMAPINFOHEADER)) {
573  // write out the image data backwards because the desktop won't
574  // show bitmaps with negative heights for top-to-bottom
575  PRUint32 i = length;
576  do {
577  i -= bpr;
578  stream->Write(((const char*)bits) + i, bpr, &written);
579  if (written == bpr) {
580  rv = NS_OK;
581  } else {
582  rv = NS_ERROR_FAILURE;
583  break;
584  }
585  } while (i != 0);
586  }
587  }
588 
589  stream->Close();
590  }
591 
592  return rv;
593 }
594 
595 NS_IMETHODIMP
596 nsWindowsShellService::SetDesktopBackground(nsIDOMElement* aElement,
597  PRInt32 aPosition)
598 {
599  nsresult rv;
600 
601  nsCOMPtr<imgIContainer> container;
602  nsCOMPtr<nsIDOMHTMLImageElement> imgElement(do_QueryInterface(aElement));
603  if (!imgElement) {
604  // XXX write background loading stuff!
605  }
606  else {
607  nsCOMPtr<nsIImageLoadingContent> imageContent =
608  do_QueryInterface(aElement, &rv);
609  if (!imageContent)
610  return rv;
611 
612  // get the image container
613  nsCOMPtr<imgIRequest> request;
614  rv = imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
615  getter_AddRefs(request));
616  if (!request)
617  return rv;
618  rv = request->GetImage(getter_AddRefs(container));
619  if (!container)
620  return NS_ERROR_FAILURE;
621  }
622 
623  // get the file name from localized strings
624  nsCOMPtr<nsIStringBundleService>
625  bundleService(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
626  NS_ENSURE_SUCCESS(rv, rv);
627 
628  nsCOMPtr<nsIStringBundle> shellBundle;
629  rv = bundleService->CreateBundle(SHELLSERVICE_PROPERTIES,
630  getter_AddRefs(shellBundle));
631  NS_ENSURE_SUCCESS(rv, rv);
632 
633  // e.g. "Desktop Background.bmp"
634  nsString fileLeafName;
635  rv = shellBundle->GetStringFromName
636  (NS_LITERAL_STRING("desktopBackgroundLeafNameWin").get(),
637  getter_Copies(fileLeafName));
638  NS_ENSURE_SUCCESS(rv, rv);
639 
640  // get the profile root directory
641  nsCOMPtr<nsIFile> file;
642  rv = NS_GetSpecialDirectory(NS_APP_APPLICATION_REGISTRY_DIR,
643  getter_AddRefs(file));
644  NS_ENSURE_SUCCESS(rv, rv);
645 
646  // eventually, the path is "%APPDATA%\Mozilla\Firefox\Desktop Background.bmp"
647  rv = file->Append(fileLeafName);
648  NS_ENSURE_SUCCESS(rv, rv);
649 
650  nsAutoString path;
651  rv = file->GetPath(path);
652  NS_ENSURE_SUCCESS(rv, rv);
653 
654  // write the bitmap to a file in the profile directory
655  rv = WriteBitmap(file, container);
656 
657  // if the file was written successfully, set it as the system wallpaper
658  if (NS_SUCCEEDED(rv)) {
659  PRBool result = PR_FALSE;
660  DWORD dwDisp = 0;
661  HKEY key;
662  // Try to create/open a subkey under HKCU.
663  DWORD res = ::RegCreateKeyExW(HKEY_CURRENT_USER, CPL_DESKTOP,
664  0, NULL, REG_OPTION_NON_VOLATILE,
665  KEY_WRITE, NULL, &key, &dwDisp);
666  if (REG_SUCCEEDED(res)) {
667 #ifndef WINCE
668  PRUnichar tile[2], style[2];
669  switch (aPosition) {
670  case BACKGROUND_TILE:
671  tile[0] = '1';
672  style[0] = '1';
673  break;
674  case BACKGROUND_CENTER:
675  tile[0] = '0';
676  style[0] = '0';
677  break;
678  case BACKGROUND_STRETCH:
679  tile[0] = '0';
680  style[0] = '2';
681  break;
682  }
683  tile[1] = '\0';
684  style[1] = '\0';
685 
686  // The size is always 3 unicode characters.
687  PRInt32 size = 3 * sizeof(PRUnichar);
688  ::RegSetValueExW(key, L"TileWallpaper",
689  0, REG_SZ, (const BYTE *)tile, size);
690  ::RegSetValueExW(key, L"WallpaperStyle",
691  0, REG_SZ, (const BYTE *)style, size);
692  ::SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, (PVOID)path.get(),
693  SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
694 #else
695  DWORD tile = (aPosition == BACKGROUND_TILE);
696  ::RegSetValueExW(key, L"Tile",
697  0, REG_DWORD, (const BYTE *)&tile, sizeof(DWORD));
698  // On WinCE SPI_SETDESKWALLPAPER isn't available, so set the registry
699  // entry ourselves and then broadcast UI change
700  PRInt32 size = (path.Length() + 1) * sizeof(PRUnichar);
701  ::RegSetValueExW(key, L"Wallpaper",
702  0, REG_SZ, (const BYTE *)path.get(), size);
703  ::SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, NULL, 0);
704 #endif
705 
706  // Close the key we opened.
707  ::RegCloseKey(key);
708 
709 #ifdef WINCE
710  // Ensure that the writes are flushed in case of hard reboot
711  ::RegFlushKey(HKEY_CURRENT_USER);
712 #endif
713  }
714  }
715  return rv;
716 }
717 
718 NS_IMETHODIMP
719 nsWindowsShellService::OpenApplication(PRInt32 aApplication)
720 {
721  nsAutoString application;
722  switch (aApplication) {
724  application.AssignLiteral("Mail");
725  break;
727  application.AssignLiteral("News");
728  break;
729  }
730 
731  // The Default Client section of the Windows Registry looks like this:
732  //
733  // Clients\aClient\
734  // e.g. aClient = "Mail"...
735  // \Mail\(default) = Client Subkey Name
736  // \Client Subkey Name
737  // \Client Subkey Name\shell\open\command\
738  // \Client Subkey Name\shell\open\command\(default) = path to exe
739  //
740 
741  // Find the default application for this class.
742  HKEY theKey;
743  nsresult rv = OpenKeyForReading(HKEY_CLASSES_ROOT, application, &theKey);
744  if (NS_FAILED(rv))
745  return rv;
746 
747  PRUnichar buf[MAX_BUF];
748  DWORD type, len = sizeof buf;
749  DWORD res = ::RegQueryValueExW(theKey, EmptyString().get(), 0,
750  &type, (LPBYTE)&buf, &len);
751 
752  if (REG_FAILED(res) || !*buf)
753  return NS_OK;
754 
755  // Close the key we opened.
756  ::RegCloseKey(theKey);
757 
758  // Find the "open" command
759  application.AppendLiteral("\\");
760  application.Append(buf);
761  application.AppendLiteral("\\shell\\open\\command");
762 
763  rv = OpenKeyForReading(HKEY_CLASSES_ROOT, application, &theKey);
764  if (NS_FAILED(rv))
765  return rv;
766 
767  ::ZeroMemory(buf, sizeof(buf));
768  len = sizeof buf;
769  res = ::RegQueryValueExW(theKey, EmptyString().get(), 0,
770  &type, (LPBYTE)&buf, &len);
771  if (REG_FAILED(res) || !*buf)
772  return NS_ERROR_FAILURE;
773 
774  // Close the key we opened.
775  ::RegCloseKey(theKey);
776 
777  // Look for any embedded environment variables and substitute their
778  // values, as |::CreateProcessW| is unable to do this.
779  nsAutoString path(buf);
780  PRInt32 end = path.Length();
781  PRInt32 cursor = 0, temp = 0;
782  ::ZeroMemory(buf, sizeof(buf));
783  do {
784  cursor = path.FindChar('%', cursor);
785  if (cursor < 0)
786  break;
787 
788  temp = path.FindChar('%', cursor + 1);
789  ++cursor;
790 
791  ::ZeroMemory(&buf, sizeof(buf));
792 
793  ::GetEnvironmentVariableW(nsAutoString(Substring(path, cursor, temp - cursor)).get(),
794  buf, sizeof(buf));
795 
796  // "+ 2" is to subtract the extra characters used to delimit the environment
797  // variable ('%').
798  path.Replace((cursor - 1), temp - cursor + 2, nsDependentString(buf));
799 
800  ++cursor;
801  }
802  while (cursor < end);
803 
804  STARTUPINFOW si;
805  PROCESS_INFORMATION pi;
806 
807  ::ZeroMemory(&si, sizeof(STARTUPINFOW));
808  ::ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
809 
810  BOOL success = ::CreateProcessW(NULL, (LPWSTR)path.get(), NULL,
811  NULL, FALSE, 0, NULL, NULL,
812  &si, &pi);
813  if (!success)
814  return NS_ERROR_FAILURE;
815 
816  return NS_OK;
817 }
818 
819 NS_IMETHODIMP
820 nsWindowsShellService::GetDesktopBackgroundColor(PRUint32* aColor)
821 {
822  PRUint32 color = ::GetSysColor(COLOR_DESKTOP);
823  *aColor = (GetRValue(color) << 16) | (GetGValue(color) << 8) | GetBValue(color);
824  return NS_OK;
825 }
826 
827 NS_IMETHODIMP
828 nsWindowsShellService::SetDesktopBackgroundColor(PRUint32 aColor)
829 {
830  int aParameters[2] = { COLOR_BACKGROUND, COLOR_DESKTOP };
831  BYTE r = (aColor >> 16);
832  BYTE g = (aColor << 16) >> 24;
833  BYTE b = (aColor << 24) >> 24;
834  COLORREF colors[2] = { RGB(r,g,b), RGB(r,g,b) };
835 
836  ::SetSysColors(sizeof(aParameters) / sizeof(int), aParameters, colors);
837 
838  // SetSysColors is persisting across sessions on Windows CE, so no need to
839  // write to registry
840 #ifndef WINCE
841  PRBool result = PR_FALSE;
842  DWORD dwDisp = 0;
843  HKEY key;
844  // Try to create/open a subkey under HKCU.
845  DWORD rv = ::RegCreateKeyExW(HKEY_CURRENT_USER,
846  L"Control Panel\\Colors", 0, NULL,
847  REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
848  &key, &dwDisp);
849 
850  if (REG_SUCCEEDED(rv)) {
851  char rgb[12];
852  sprintf((char*)rgb, "%u %u %u\0", r, g, b);
853  NS_ConvertUTF8toUTF16 backColor(rgb);
854 
855  ::RegSetValueExW(key, L"Background",
856  0, REG_SZ, (const BYTE *)backColor.get(),
857  (backColor.Length() + 1) * sizeof(PRUnichar));
858  }
859 
860  // Close the key we opened.
861  ::RegCloseKey(key);
862 #endif
863  return NS_OK;
864 }
865 
866 #ifndef WINCE
867 NS_IMETHODIMP
868 nsWindowsShellService::GetUnreadMailCount(PRUint32* aCount)
869 {
870  *aCount = 0;
871 
872  HKEY accountKey;
873  if (GetMailAccountKey(&accountKey)) {
874  DWORD type, unreadCount;
875  DWORD len = sizeof unreadCount;
876  DWORD res = ::RegQueryValueExW(accountKey, L"MessageCount", 0,
877  &type, (LPBYTE)&unreadCount, &len);
878  if (REG_SUCCEEDED(res))
879  *aCount = unreadCount;
880 
881  // Close the key we opened.
882  ::RegCloseKey(accountKey);
883  }
884 
885  return NS_OK;
886 }
887 
888 PRBool
890 {
891  NS_NAMED_LITERAL_STRING(unread,
892  "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\UnreadMail\\");
893 
894  HKEY mailKey;
895  DWORD res = ::RegOpenKeyExW(HKEY_CURRENT_USER, unread.get(), 0,
896  KEY_ENUMERATE_SUB_KEYS, &mailKey);
897 
898  PRInt32 i = 0;
899  do {
900  PRUnichar subkeyName[MAX_BUF];
901  DWORD len = sizeof subkeyName;
902  res = ::RegEnumKeyExW(mailKey, i++, subkeyName, &len, NULL, NULL,
903  NULL, NULL);
904  if (REG_SUCCEEDED(res)) {
905  HKEY accountKey;
906  res = ::RegOpenKeyExW(mailKey, PromiseFlatString(subkeyName).get(),
907  0, KEY_READ, &accountKey);
908  if (REG_SUCCEEDED(res)) {
909  *aResult = accountKey;
910 
911  // Close the key we opened.
912  ::RegCloseKey(mailKey);
913 
914  return PR_TRUE;
915  }
916  }
917  else
918  break;
919  }
920  while (1);
921 
922  // Close the key we opened.
923  ::RegCloseKey(mailKey);
924  return PR_FALSE;
925 }
926 #endif
927 
928 NS_IMETHODIMP
929 nsWindowsShellService::OpenApplicationWithURI(nsILocalFile* aApplication,
930  const nsACString& aURI)
931 {
932  nsresult rv;
933  nsCOMPtr<nsIProcess> process =
934  do_CreateInstance("@mozilla.org/process/util;1", &rv);
935  if (NS_FAILED(rv))
936  return rv;
937 
938  rv = process->Init(aApplication);
939  if (NS_FAILED(rv))
940  return rv;
941 
942  const nsCString spec(aURI);
943  const char* specStr = spec.get();
944  return process->Run(PR_FALSE, &specStr, 1);
945 }
946 
947 NS_IMETHODIMP
948 nsWindowsShellService::GetDefaultFeedReader(nsILocalFile** _retval)
949 {
950  *_retval = nsnull;
951 
952  nsresult rv;
953  nsCOMPtr<nsIWindowsRegKey> regKey =
954  do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
955  NS_ENSURE_SUCCESS(rv, rv);
956 
957  rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
958  NS_LITERAL_STRING("feed\\shell\\open\\command"),
960  NS_ENSURE_SUCCESS(rv, rv);
961 
962  nsAutoString path;
963  rv = regKey->ReadStringValue(EmptyString(), path);
964  NS_ENSURE_SUCCESS(rv, rv);
965  if (path.IsEmpty())
966  return NS_ERROR_FAILURE;
967 
968  if (path.First() == '"') {
969  // Everything inside the quotes
970  path = Substring(path, 1, path.FindChar('"', 1) - 1);
971  }
972  else {
973  // Everything up to the first space
974  path = Substring(path, 0, path.FindChar(' '));
975  }
976 
977  nsCOMPtr<nsILocalFile> defaultReader =
978  do_CreateInstance("@mozilla.org/file/local;1", &rv);
979  NS_ENSURE_SUCCESS(rv, rv);
980 
981  rv = defaultReader->InitWithPath(path);
982  NS_ENSURE_SUCCESS(rv, rv);
983 
984  PRBool exists;
985  rv = defaultReader->Exists(&exists);
986  NS_ENSURE_SUCCESS(rv, rv);
987  if (!exists)
988  return NS_ERROR_FAILURE;
989 
990  NS_ADDREF(*_retval = defaultReader);
991  return NS_OK;
992 }
static SETTING gSettings[]
PRBool IsDefaultBrowserVista(PRBool *aIsDefaultBrowser)
#define REG_FAILED(val)
return NS_OK
const long APPLICATION_NEWS
#define REG_SUCCEEDED(val)
PRBool GetMailAccountKey(HKEY *aResult)
onPageChanged aValue
Definition: FeedWriter.js:1395
const long APPLICATION_MAIL
NS_IMPL_ISUPPORTS1(sbDeviceCapabilitiesUtils, sbIDeviceCapabilitiesUtils) sbDeviceCapabilitiesUtils
#define DI
const NS_PREFSERVICE_CONTRACTID
#define SOP
#define VAL_FILE_ICON
#define CPL_DESKTOP
#define PREF_CHECKDEFAULTBROWSER
#define CLS_HTML
#define APP_REG_NAME
const long BACKGROUND_TILE
NS_IMPL_ISUPPORTS2(sbAlbumArtService, sbIAlbumArtService, nsIObserver) NS_IMETHODIMP sbAlbumArtService
function width(ele) rect(ele).width
static nsresult WriteBitmap(nsIFile *aFile, imgIContainer *aImage)
PRUint32 & offset
#define SHELLSERVICE_PROPERTIES
#define MAX_BUF
_dialogDatepicker settings
static nsresult OpenKeyForReading(HKEY aKeyRoot, const nsAString &aKeyName, HKEY *aKey)
_updateDatepicker height
Element Properties style
#define MAKE_KEY_NAME1(PREFIX, MID)
var prefs
Definition: FeedWriter.js:1169
countRef value
Definition: FeedWriter.js:1423
#define VAL_OPEN
#define CLS_URL
const long BACKGROUND_CENTER
restoreHistoryPrecursor aCount
const ACCESS_READ
Definition: pageInfo.js:194
_getSelectedPageStyle s i
var file
const long BACKGROUND_STRETCH