main.cpp (3376B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 #include <iostream> 5 #include <optional> 6 #include <rpc.h> 7 #include <shellapi.h> 8 #include <string> 9 #include <windows.h> 10 #include "download_firefox.h" 11 #include "file_sink.h" 12 #include "find_firefox.h" 13 #include "tempfile_name.h" 14 15 #define DOWNLOAD_PAGE L"https://www.mozilla.org/firefox/new/" 16 #define STUB_INSTALLER_ARGS L"/Prompt /LaunchedBy:desktoplauncher" 17 18 /** 19 * Runs the provided path using the shell using the provided command-line 20 * parameters. 21 * 22 * Blocks until the application starts accepting input, or until a 23 * Windows-internal timeout is reached. Refer to SEE_MASK_WAITFORINPUTIDLE's 24 * documentation. 25 * 26 * @param path The path to the file or URL to run. 27 * @param params Command-line arguments to pass. May be null. 28 * @returns Truthy if the launch succeeded, false otherwise. 29 */ 30 static bool ExecuteAndWaitForIdle(const std::wstring& path, 31 const wchar_t* params) { 32 SHELLEXECUTEINFOW sei = {0}; 33 sei.cbSize = sizeof(sei); 34 sei.fMask = SEE_MASK_WAITFORINPUTIDLE | SEE_MASK_NOASYNC; 35 sei.lpFile = path.c_str(); 36 sei.lpParameters = params; 37 sei.nShow = SW_SHOWNORMAL; 38 ShellExecuteExW(&sei); 39 return (uintptr_t)sei.hInstApp > 32; 40 } 41 42 int wmain() { 43 // For telemetry purposes, let's set the env variable to indicate that 44 // we used the launcher to start Firefox 45 if (!SetEnvironmentVariableW(L"FIREFOX_LAUNCHED_BY_DESKTOP_LAUNCHER", 46 L"TRUE")) { 47 std::wcout 48 << L"Could not set env variable FIREFOX_LAUNCHED_BY_DESKTOP_LAUNCHER" 49 << std::endl; 50 } 51 52 // First, we try to launch Firefox if it is installed 53 std::optional<std::wstring> firefox_path = lookupFirefoxPath(); 54 if (firefox_path.has_value()) { 55 std::wcout << L"Found Firefox at path " << firefox_path.value() 56 << std::endl; 57 if (ExecuteAndWaitForIdle(firefox_path.value(), nullptr)) { 58 std::wcout << L"Firefox launched" << std::endl; 59 return 0; 60 } 61 } 62 bool download_completed = false; 63 // If that doesn't work, we try to download the installer. 64 std::optional<std::wstring> tempfileName = get_tempfile_name(); 65 // If we do create a fileSink, it needs to live until the 66 // ExecuteAndWaitForIdle calls return to ensure that other processes cannot 67 // delete or rename it. 68 std::unique_ptr<FileSink> fileSink; 69 if (tempfileName.has_value()) { 70 fileSink = std::make_unique<FileSink>(); 71 if (fileSink->open(tempfileName.value())) { 72 ErrCode rc = download_firefox(fileSink.get()); 73 if (rc == ErrCode::OK) { 74 std::wcout << L"Firefox installer successfully downloaded" << std::endl; 75 download_completed = true; 76 } 77 } 78 } 79 // If the installer successfully downloaded, try to launch it 80 if (download_completed) { 81 if (fileSink->freeze() && 82 ExecuteAndWaitForIdle(tempfileName.value(), STUB_INSTALLER_ARGS)) { 83 std::wcout << L"Firefox installer launched" << std::endl; 84 return 0; 85 } 86 } 87 88 // If that doesn't work, open the download page in the default browser 89 if (ExecuteAndWaitForIdle(DOWNLOAD_PAGE, nullptr)) { 90 std::wcout << L"Opened default browser to the download page" << std::endl; 91 } 92 return 0; 93 }