MSIX: prompt and uninstall MSI PT version (#1248)

This commit is contained in:
Andrey Nekrasov
2020-02-18 18:11:01 +03:00
committed by GitHub
parent 733613ad28
commit 20519e3b81
19 changed files with 747 additions and 35 deletions

View File

@@ -13,6 +13,7 @@
#include <common/common.h>
#include <common/dpi_aware.h>
#include <common/msi_to_msix_upgrade_lib/msi_to_msix_upgrade.h>
#include <common/winstore.h>
#include <common/notifications.h>
@@ -22,6 +23,17 @@
extern "C" IMAGE_DOS_HEADER __ImageBase;
namespace localized_strings
{
const wchar_t MSI_VERSION_IS_ALREADY_RUNNING[] = L"An older version of PowerToys is already running.";
}
namespace
{
const wchar_t MSI_VERSION_MUTEX_NAME[] = L"Local\\PowerToyRunMutex";
const wchar_t MSIX_VERSION_MUTEX_NAME[] = L"Local\\PowerToyMSIXRunMutex";
}
void chdir_current_executable()
{
// Change current directory to the path of the executable.
@@ -34,6 +46,47 @@ void chdir_current_executable()
}
}
wil::unique_mutex_nothrow create_runner_mutex(const bool msix_version)
{
wchar_t username[UNLEN + 1];
DWORD username_length = UNLEN + 1;
GetUserNameW(username, &username_length);
wil::unique_mutex_nothrow result{ CreateMutexW(nullptr, TRUE, (std::wstring(msix_version ? MSIX_VERSION_MUTEX_NAME : MSI_VERSION_MUTEX_NAME) + username).c_str()) };
return GetLastError() == ERROR_ALREADY_EXISTS ? wil::unique_mutex_nothrow{} : std::move(result);
}
bool start_msi_uninstallation_sequence()
{
const auto package_path = get_msi_package_path();
if (package_path.empty())
{
// No MSI version detected
return true;
}
if (!offer_msi_uninstallation())
{
// User declined to uninstall or opted for "Don't show again"
return false;
}
std::wstring action_runner_path{ winrt::Windows::ApplicationModel::Package::Current().InstalledLocation().Path() };
action_runner_path += L"\\action_runner.exe";
SHELLEXECUTEINFOW sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS };
sei.lpFile = action_runner_path.c_str();
sei.nShow = SW_SHOWNORMAL;
sei.lpParameters = L"-uninstall_msi";
ShellExecuteExW(&sei);
WaitForSingleObject(sei.hProcess, INFINITE);
DWORD exit_code = 0;
GetExitCodeProcess(sei.hProcess, &exit_code);
CloseHandle(sei.hProcess);
return exit_code == 0;
}
int runner(bool isProcessElevated)
{
DPIAware::EnableDPIAwarenessForThisProcess();
@@ -44,15 +97,16 @@ int runner(bool isProcessElevated)
//init_global_error_handlers();
#endif
Trace::RegisterProvider();
winrt::init_apartment();
start_tray_icon();
if (winstore::running_as_packaged())
{
notifications::register_background_toast_handler();
}
int result;
int result = -1;
try
{
if (winstore::running_as_packaged())
{
notifications::register_background_toast_handler();
}
chdir_current_executable();
// Load Powertyos DLLS
// For now only load known DLLs
@@ -95,18 +149,43 @@ int runner(bool isProcessElevated)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WCHAR username[UNLEN + 1];
DWORD username_length = UNLEN + 1;
GetUserNameW(username, &username_length);
auto runner_mutex = CreateMutexW(nullptr, TRUE, (std::wstring(L"Local\\PowerToyRunMutex") + username).c_str());
if (runner_mutex == nullptr || GetLastError() == ERROR_ALREADY_EXISTS)
auto msix_mutex = create_runner_mutex(true);
const bool msix_mutex_failed_to_lock = !msix_mutex;
if (msix_mutex_failed_to_lock)
{
// The app is already running
return 0;
}
auto msi_mutex = create_runner_mutex(false);
const bool msi_mutex_already_taken = !msi_mutex;
if (msi_mutex_already_taken)
{
const bool declined_uninstall = !start_msi_uninstallation_sequence();
if (declined_uninstall)
{
// Warn and exit if msi version is already running
notifications::show_toast(localized_strings::MSI_VERSION_IS_ALREADY_RUNNING);
// Wait 1 second before exiting, since if we exit immediately, the toast notification becomes lost
Sleep(1000);
return 0;
}
}
int result = 0;
try
{
winrt::init_apartment();
if (winstore::running_as_packaged())
{
notifications::register_background_toast_handler();
std::thread{ [] {
start_msi_uninstallation_sequence();
} }.detach();
}
// Singletons initialization order needs to be preserved, first events and
// then modules to guarantee the reverse destruction order.
SystemMenuHelperInstace();
@@ -134,8 +213,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
MessageBoxW(nullptr, std::wstring(err_what.begin(), err_what.end()).c_str(), GET_RESOURCE_STRING(IDS_ERROR).c_str(), MB_OK | MB_ICONERROR);
result = -1;
}
ReleaseMutex(runner_mutex);
CloseHandle(runner_mutex);
if (is_restart_scheduled())
{
if (restart_if_scheduled() == false)

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.190716.2" targetFramework="native" />
</packages>

View File

@@ -23,3 +23,8 @@
#include <unordered_set>
#include <string>
#include <ProjectTelemetry.h>
#include <winrt/Windows.ApplicationModel.h>
#include <winrt/Windows.Storage.h>
#include <wil/resource.h>

View File

@@ -18,7 +18,10 @@
<ProjectName>runner</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ImportGroup Label="Shared">
<Import Project="..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.190716.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.190716.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
@@ -65,6 +68,7 @@
<Link>
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>Msi.lib;WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Manifest>
<EnableDpiAwareness>false</EnableDpiAwareness>
@@ -90,6 +94,7 @@
<OptimizeReferences>true</OptimizeReferences>
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>Msi.lib;WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Manifest>
<EnableDpiAwareness>false</EnableDpiAwareness>
@@ -223,8 +228,20 @@
<ProjectReference Include="..\common\common.vcxproj">
<Project>{74485049-c722-400f-abe5-86ac52d929b3}</Project>
</ProjectReference>
<ProjectReference Include="..\common\msi_to_msix_upgrade_lib\msi_to_msix_upgrade_lib.vcxproj">
<Project>{17da04df-e393-4397-9cf0-84dabe11032e}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.190716.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.190716.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

View File

@@ -136,4 +136,7 @@
<Filter>svgs</Filter>
</CopyFileToFolders>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>