Files
sousa-gecko/browser/app/desktop-launcher/main.cpp
T
Duncan McIntosh d88792ab9d Bug 2000411 - Use GetTempPathW instead of GetTempPath2W. r=cdupuis!
We want to avoid GetTempPath2W since it is only available on Windows 11
and some of the latest versions of Windows 10.

The only case that they're different is when running as SYSTEM. Most
users won't run the desktop launcher as SYSTEM; for those who do (please
don't), we now hold a handle to the file during the execution to prevent
renaming or symbolic link issues. This should prevent any theoretical
issues that could have happened with GetTempPath2W.

Differential Revision: https://phabricator.services.mozilla.com/D272905
2025-11-17 21:55:00 +00:00

94 lines
3.3 KiB
C++

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <iostream>
#include <optional>
#include <rpc.h>
#include <shellapi.h>
#include <string>
#include <windows.h>
#include "download_firefox.h"
#include "file_sink.h"
#include "find_firefox.h"
#include "tempfile_name.h"
#define DOWNLOAD_PAGE L"https://www.mozilla.org/firefox/new/"
#define STUB_INSTALLER_ARGS L"/Prompt /LaunchedBy:desktoplauncher"
/**
* Runs the provided path using the shell using the provided command-line
* parameters.
*
* Blocks until the application starts accepting input, or until a
* Windows-internal timeout is reached. Refer to SEE_MASK_WAITFORINPUTIDLE's
* documentation.
*
* @param path The path to the file or URL to run.
* @param params Command-line arguments to pass. May be null.
* @returns Truthy if the launch succeeded, false otherwise.
*/
static bool ExecuteAndWaitForIdle(const std::wstring& path,
const wchar_t* params) {
SHELLEXECUTEINFOW sei = {0};
sei.cbSize = sizeof(sei);
sei.fMask = SEE_MASK_WAITFORINPUTIDLE | SEE_MASK_NOASYNC;
sei.lpFile = path.c_str();
sei.lpParameters = params;
sei.nShow = SW_SHOWNORMAL;
ShellExecuteExW(&sei);
return (uintptr_t)sei.hInstApp > 32;
}
int wmain() {
// For telemetry purposes, let's set the env variable to indicate that
// we used the launcher to start Firefox
if (!SetEnvironmentVariableW(L"FIREFOX_LAUNCHED_BY_DESKTOP_LAUNCHER",
L"TRUE")) {
std::wcout
<< L"Could not set env variable FIREFOX_LAUNCHED_BY_DESKTOP_LAUNCHER"
<< std::endl;
}
// First, we try to launch Firefox if it is installed
std::optional<std::wstring> firefox_path = lookupFirefoxPath();
if (firefox_path.has_value()) {
std::wcout << L"Found Firefox at path " << firefox_path.value()
<< std::endl;
if (ExecuteAndWaitForIdle(firefox_path.value(), nullptr)) {
std::wcout << L"Firefox launched" << std::endl;
return 0;
}
}
bool download_completed = false;
// If that doesn't work, we try to download the installer.
std::optional<std::wstring> tempfileName = get_tempfile_name();
// If we do create a fileSink, it needs to live until the
// ExecuteAndWaitForIdle calls return to ensure that other processes cannot
// delete or rename it.
std::unique_ptr<FileSink> fileSink;
if (tempfileName.has_value()) {
fileSink = std::make_unique<FileSink>();
if (fileSink->open(tempfileName.value())) {
ErrCode rc = download_firefox(fileSink.get());
if (rc == ErrCode::OK) {
std::wcout << L"Firefox installer successfully downloaded" << std::endl;
download_completed = true;
}
}
}
// If the installer successfully downloaded, try to launch it
if (download_completed) {
if (fileSink->freeze() &&
ExecuteAndWaitForIdle(tempfileName.value(), STUB_INSTALLER_ARGS)) {
std::wcout << L"Firefox installer launched" << std::endl;
return 0;
}
}
// If that doesn't work, open the download page in the default browser
if (ExecuteAndWaitForIdle(DOWNLOAD_PAGE, nullptr)) {
std::wcout << L"Opened default browser to the download page" << std::endl;
}
return 0;
}