nsWindowsShellService.cpp 40 KB

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