duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

win32_main.cpp (3527B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #include "updater.h"
      5 #include "win32_progress_callback.h"
      6 
      7 #include "common/file_system.h"
      8 #include "common/log.h"
      9 #include "common/path.h"
     10 #include "common/scoped_guard.h"
     11 #include "common/string_util.h"
     12 #include "common/windows_headers.h"
     13 
     14 #include <combaseapi.h>
     15 #include <shellapi.h>
     16 
     17 static void WaitForProcessToExit(int process_id)
     18 {
     19   HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, process_id);
     20   if (!hProcess)
     21     return;
     22 
     23   WaitForSingleObject(hProcess, INFINITE);
     24   CloseHandle(hProcess);
     25 }
     26 
     27 int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
     28 {
     29   Win32ProgressCallback progress;
     30 
     31   const bool com_initialized = SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED));
     32   const ScopedGuard com_guard = [com_initialized]() {
     33     if (com_initialized)
     34       CoUninitialize();
     35   };
     36 
     37   int argc = 0;
     38   LPWSTR* argv = CommandLineToArgvW(lpCmdLine, &argc);
     39   if (!argv || argc <= 0)
     40   {
     41     progress.ModalError("Failed to parse command line.");
     42     return 1;
     43   }
     44   if (argc != 4)
     45   {
     46     progress.ModalError("Expected 4 arguments: parent process id, output directory, update zip, program to "
     47                         "launch.\n\nThis program is not intended to be run manually, please use the Qt frontend and "
     48                         "click Help->Check for Updates.");
     49     LocalFree(argv);
     50     return 1;
     51   }
     52 
     53   const int parent_process_id = StringUtil::FromChars<int>(StringUtil::WideStringToUTF8String(argv[0])).value_or(0);
     54   std::string destination_directory = Path::ToNativePath(StringUtil::WideStringToUTF8String(argv[1]));
     55   std::string staging_directory = Path::Combine(destination_directory, "UPDATE_STAGING");
     56   std::string zip_path = Path::ToNativePath(StringUtil::WideStringToUTF8String(argv[2]));
     57   std::wstring program_to_launch(argv[3]);
     58   LocalFree(argv);
     59 
     60   if (parent_process_id <= 0 || destination_directory.empty() || zip_path.empty() || program_to_launch.empty())
     61   {
     62     progress.ModalError("One or more parameters is empty.");
     63     return 1;
     64   }
     65 
     66   Log::SetFileOutputParams(true, Path::Combine(destination_directory, "updater.log").c_str());
     67 
     68   progress.FormatStatusText("Waiting for parent process {} to exit...", parent_process_id);
     69   WaitForProcessToExit(parent_process_id);
     70 
     71   Updater updater(&progress);
     72   if (!updater.Initialize(std::move(staging_directory), std::move(destination_directory)))
     73   {
     74     progress.ModalError("Failed to initialize updater.");
     75     return 1;
     76   }
     77 
     78   if (!updater.OpenUpdateZip(zip_path.c_str()))
     79   {
     80     progress.FormatModalError("Could not open update zip '{}'. Update not installed.", zip_path);
     81     return 1;
     82   }
     83 
     84   if (!updater.PrepareStagingDirectory())
     85   {
     86     progress.ModalError("Failed to prepare staging directory. Update not installed.");
     87     return 1;
     88   }
     89 
     90   if (!updater.StageUpdate())
     91   {
     92     progress.ModalError("Failed to stage update. Update not installed.");
     93     return 1;
     94   }
     95 
     96   if (!updater.CommitUpdate())
     97   {
     98     progress.ModalError(
     99       "Failed to commit update. Your installation may be corrupted, please re-download a fresh version from GitHub.");
    100     return 1;
    101   }
    102 
    103   updater.CleanupStagingDirectory();
    104   updater.RemoveUpdateZip();
    105 
    106   progress.FormatInformation("Launching '{}'...", StringUtil::WideStringToUTF8String(program_to_launch));
    107   ShellExecuteW(nullptr, L"open", program_to_launch.c_str(), L"-updatecleanup", nullptr, SW_SHOWNORMAL);
    108   return 0;
    109 }