mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-06-12 04:33:10 +08:00
wix: install dotnet 3 after installation if needed (#2775)
This commit is contained in:
parent
9f724221fa
commit
73c6cbb562
@ -47,8 +47,8 @@
|
|||||||
<UIRef Id="WixUI_PTInstallDir"/>
|
<UIRef Id="WixUI_PTInstallDir"/>
|
||||||
<Publish Dialog="ExitDialog"
|
<Publish Dialog="ExitDialog"
|
||||||
Control="Finish"
|
Control="Finish"
|
||||||
Event="DoAction"
|
Event="EndDialog"
|
||||||
Value="LaunchApplication">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish>
|
Value="Return">NOT Installed</Publish>
|
||||||
<Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Property="_REMOVE_ALL" Value="Yes">1</Publish>
|
<Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Property="_REMOVE_ALL" Value="Yes">1</Publish>
|
||||||
<Publish Dialog="UserExit" Control="Finish" Event="DoAction" Value="TelemetryLogInstallCancel">NOT Installed</Publish>
|
<Publish Dialog="UserExit" Control="Finish" Event="DoAction" Value="TelemetryLogInstallCancel">NOT Installed</Publish>
|
||||||
<Publish Dialog="FatalError" Control="Finish" Event="DoAction" Value="TelemetryLogInstallFail">NOT Installed</Publish>
|
<Publish Dialog="FatalError" Control="Finish" Event="DoAction" Value="TelemetryLogInstallFail">NOT Installed</Publish>
|
||||||
@ -62,11 +62,8 @@
|
|||||||
<WixVariable Id="WixUILicenseRtf" Value="$(var.RepoDir)\installer\License.rtf" />
|
<WixVariable Id="WixUILicenseRtf" Value="$(var.RepoDir)\installer\License.rtf" />
|
||||||
<Property Id="INSTALLSTARTMENUSHORTCUT" Value="1"/>
|
<Property Id="INSTALLSTARTMENUSHORTCUT" Value="1"/>
|
||||||
<Property Id="CREATESCHEDULEDTASK" Value="1"/>
|
<Property Id="CREATESCHEDULEDTASK" Value="1"/>
|
||||||
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOX" Value="1"/>
|
<Property Id="WixShellExecTarget" Value="[#action_runner.exe]" />
|
||||||
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch PowerToys" />
|
|
||||||
<Property Id="WixShellExecTarget" Value="[#PowerToys.exe]" />
|
|
||||||
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
|
|
||||||
|
|
||||||
<Property Id ="EXISTINGPOWERRENAMEEXTPATH">
|
<Property Id ="EXISTINGPOWERRENAMEEXTPATH">
|
||||||
<RegistrySearch Id="ExistingExtPath" Root="HKCR" Key="CLSID\{0440049F-D1DC-4E46-B27B-98393D79486B}\InprocServer32" Type="raw"/>
|
<RegistrySearch Id="ExistingExtPath" Root="HKCR" Key="CLSID\{0440049F-D1DC-4E46-B27B-98393D79486B}\InprocServer32" Type="raw"/>
|
||||||
</Property>
|
</Property>
|
||||||
@ -90,8 +87,21 @@
|
|||||||
<Custom Action="TelemetryLogUninstallSuccess" After="InstallFinalize">
|
<Custom Action="TelemetryLogUninstallSuccess" After="InstallFinalize">
|
||||||
Installed and (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
|
Installed and (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
|
||||||
</Custom>
|
</Custom>
|
||||||
|
|
||||||
|
<Custom Action="InstallDotNet" After="InstallFinalize">
|
||||||
|
NOT Installed
|
||||||
|
</Custom>
|
||||||
|
|
||||||
</InstallExecuteSequence>
|
</InstallExecuteSequence>
|
||||||
|
|
||||||
|
<CustomAction
|
||||||
|
Id="InstallDotNet"
|
||||||
|
FileKey="action_runner.exe"
|
||||||
|
ExeCommand="-install_dotnet"
|
||||||
|
Return="asyncNoWait"
|
||||||
|
Execute="immediate"
|
||||||
|
Impersonate="no" />
|
||||||
|
|
||||||
<CustomAction Id="SetRegisterPowerToysSchTaskParam"
|
<CustomAction Id="SetRegisterPowerToysSchTaskParam"
|
||||||
Property="RegisterPowerToysSchTask"
|
Property="RegisterPowerToysSchTask"
|
||||||
Value="[#PowerToys.exe]" />
|
Value="[#PowerToys.exe]" />
|
||||||
|
@ -14,6 +14,10 @@
|
|||||||
#include "../runner/tray_icon.h"
|
#include "../runner/tray_icon.h"
|
||||||
#include "../runner/action_runner_utils.h"
|
#include "../runner/action_runner_utils.h"
|
||||||
|
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||||
|
|
||||||
int uninstall_msi_action()
|
int uninstall_msi_action()
|
||||||
{
|
{
|
||||||
const auto package_path = updating::get_msi_package_path();
|
const auto package_path = updating::get_msi_package_path();
|
||||||
@ -122,6 +126,56 @@ bool install_new_version_stage_2(std::wstring_view installer_path, std::wstring_
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool dotnet_is_installed()
|
||||||
|
{
|
||||||
|
auto runtimes = exec_and_read_output(LR"(dotnet --list-runtimes)");
|
||||||
|
if (!runtimes)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const char DESKTOP_DOTNET_RUNTIME_STRING[] = "Microsoft.WindowsDesktop.App 3.1.";
|
||||||
|
return runtimes->find(DESKTOP_DOTNET_RUNTIME_STRING) != std::string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool install_dotnet()
|
||||||
|
{
|
||||||
|
const wchar_t DOTNET_DESKTOP_DOWNLOAD_LINK[] = L"https://download.visualstudio.microsoft.com/download/pr/a1510e74-b31a-4434-b8a0-8074ff31fb3f/b7de8ecba4a14d8312551cfdc745dea1/windowsdesktop-runtime-3.1.0-win-x64.exe";
|
||||||
|
const wchar_t DOTNET_DESKTOP_FILENAME[] = L"windowsdesktop-runtime-3.1.0-win-x64.exe";
|
||||||
|
|
||||||
|
auto dotnet_download_path = fs::temp_directory_path() / DOTNET_DESKTOP_FILENAME;
|
||||||
|
winrt::Windows::Foundation::Uri download_link{ DOTNET_DESKTOP_DOWNLOAD_LINK };
|
||||||
|
|
||||||
|
const size_t max_attempts = 3;
|
||||||
|
bool download_success = false;
|
||||||
|
for (size_t i = 0; i < max_attempts; ++i)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
updating::try_download_file(dotnet_download_path, download_link).wait();
|
||||||
|
download_success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
// couldn't download
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!download_success)
|
||||||
|
{
|
||||||
|
MessageBoxW(nullptr,
|
||||||
|
GET_RESOURCE_STRING(IDS_DOTNET_CORE_DOWNLOAD_FAILURE).c_str(),
|
||||||
|
GET_RESOURCE_STRING(IDS_DOTNET_CORE_DOWNLOAD_FAILURE_TITLE).c_str(),
|
||||||
|
MB_OK | MB_ICONERROR);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||||
|
sei.fMask = { SEE_MASK_NOASYNC };
|
||||||
|
sei.lpFile = dotnet_download_path.c_str();
|
||||||
|
sei.nShow = SW_SHOWNORMAL;
|
||||||
|
sei.lpParameters = L"/install /passive";
|
||||||
|
return ShellExecuteExW(&sei) == TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
||||||
{
|
{
|
||||||
int nArgs = 0;
|
int nArgs = 0;
|
||||||
@ -132,7 +186,15 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
|||||||
}
|
}
|
||||||
std::wstring_view action{ args[1] };
|
std::wstring_view action{ args[1] };
|
||||||
|
|
||||||
if (action == L"-uninstall_msi")
|
if (action == L"-install_dotnet")
|
||||||
|
{
|
||||||
|
if (dotnet_is_installed())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return !install_dotnet();
|
||||||
|
}
|
||||||
|
else if (action == L"-uninstall_msi")
|
||||||
{
|
{
|
||||||
return uninstall_msi_action();
|
return uninstall_msi_action();
|
||||||
}
|
}
|
||||||
|
43
src/action_runner/action_runner.rc
Normal file
43
src/action_runner/action_runner.rc
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// Microsoft Visual C++ generated resource script.
|
||||||
|
//
|
||||||
|
#include "resource.h"
|
||||||
|
#include "../common/version.h"
|
||||||
|
|
||||||
|
STRINGTABLE
|
||||||
|
BEGIN
|
||||||
|
IDS_DOTNET_CORE_DOWNLOAD_FAILURE "Couldn't download .NET Core Desktop Runtime 3.1.3, please install it manually."
|
||||||
|
IDS_DOTNET_CORE_DOWNLOAD_FAILURE_TITLE "PowerToys installation error"
|
||||||
|
END
|
||||||
|
|
||||||
|
1 VERSIONINFO
|
||||||
|
FILEVERSION FILE_VERSION
|
||||||
|
PRODUCTVERSION PRODUCT_VERSION
|
||||||
|
FILEFLAGSMASK 0x3fL
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS 0x1L
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
#endif
|
||||||
|
FILEOS 0x40004L
|
||||||
|
FILETYPE 0x1L
|
||||||
|
FILESUBTYPE 0x0L
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "CompanyName", COMPANY_NAME
|
||||||
|
VALUE "FileDescription", "PowerToys Action Runner"
|
||||||
|
VALUE "FileVersion", FILE_VERSION_STRING
|
||||||
|
VALUE "InternalName", "PowerToys Action Runner"
|
||||||
|
VALUE "LegalCopyright", COPYRIGHT_NOTE
|
||||||
|
VALUE "OriginalFilename", "action_runner.exe"
|
||||||
|
VALUE "ProductName", "PowerToys"
|
||||||
|
VALUE "ProductVersion", PRODUCT_VERSION_STRING
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1200
|
||||||
|
END
|
||||||
|
END
|
@ -160,10 +160,14 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\runner\updating.h" />
|
<ClInclude Include="..\runner\updating.h" />
|
||||||
|
<ClInclude Include="resource.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ResourceCompile Include="action_runner.rc" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
<Import Project="..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
<Import Project="..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.200316.3\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||||
|
3
src/action_runner/resource.h
Normal file
3
src/action_runner/resource.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#define IDS_DOTNET_CORE_DOWNLOAD_FAILURE 101
|
||||||
|
#define IDS_DOTNET_CORE_DOWNLOAD_FAILURE_TITLE 102
|
||||||
|
|
@ -6,6 +6,8 @@
|
|||||||
#include <sddl.h>
|
#include <sddl.h>
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
|
#include <wil/resource.h>
|
||||||
|
|
||||||
#pragma comment(lib, "advapi32.lib")
|
#pragma comment(lib, "advapi32.lib")
|
||||||
#pragma comment(lib, "shlwapi.lib")
|
#pragma comment(lib, "shlwapi.lib")
|
||||||
|
|
||||||
@ -735,3 +737,64 @@ bool find_app_name_in_path(const std::wstring& where, const std::vector<std::wst
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> exec_and_read_output(const std::wstring_view command, const DWORD timeout)
|
||||||
|
{
|
||||||
|
SECURITY_ATTRIBUTES saAttr{ sizeof(saAttr) };
|
||||||
|
saAttr.bInheritHandle = true;
|
||||||
|
|
||||||
|
wil::unique_handle childStdoutRead;
|
||||||
|
wil::unique_handle childStdoutWrite;
|
||||||
|
if (!CreatePipe(&childStdoutRead, &childStdoutWrite, &saAttr, 0))
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetHandleInformation(childStdoutRead.get(), HANDLE_FLAG_INHERIT, 0))
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
PROCESS_INFORMATION piProcInfo{};
|
||||||
|
STARTUPINFOW siStartInfo{ sizeof(siStartInfo) };
|
||||||
|
|
||||||
|
siStartInfo.hStdError = childStdoutWrite.get();
|
||||||
|
siStartInfo.hStdOutput = childStdoutWrite.get();
|
||||||
|
siStartInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
|
||||||
|
siStartInfo.wShowWindow = SW_HIDE;
|
||||||
|
|
||||||
|
std::wstring cmdLine{ command };
|
||||||
|
if (!CreateProcessW(nullptr,
|
||||||
|
cmdLine.data(),
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
true,
|
||||||
|
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
&siStartInfo,
|
||||||
|
&piProcInfo))
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitForSingleObject(piProcInfo.hProcess, timeout);
|
||||||
|
|
||||||
|
childStdoutWrite.reset();
|
||||||
|
CloseHandle(piProcInfo.hThread);
|
||||||
|
|
||||||
|
std::string childOutput;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
char buffer[4096];
|
||||||
|
DWORD gotBytes = 0;
|
||||||
|
if (!ReadFile(childStdoutRead.get(), buffer, sizeof(buffer), &gotBytes, nullptr) || !gotBytes)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
childOutput += std::string_view{ buffer, gotBytes };
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(piProcInfo.hProcess);
|
||||||
|
return childOutput;
|
||||||
|
}
|
@ -99,6 +99,8 @@ std::wstring get_resource_string(UINT resource_id, HINSTANCE instance, const wch
|
|||||||
// is added to the .cpp file.
|
// is added to the .cpp file.
|
||||||
#define GET_RESOURCE_STRING(resource_id) get_resource_string(resource_id, reinterpret_cast<HINSTANCE>(&__ImageBase), L#resource_id)
|
#define GET_RESOURCE_STRING(resource_id) get_resource_string(resource_id, reinterpret_cast<HINSTANCE>(&__ImageBase), L#resource_id)
|
||||||
|
|
||||||
|
std::optional<std::string> exec_and_read_output(const std::wstring_view command, const DWORD timeout = INFINITE);
|
||||||
|
|
||||||
// Helper class for various COM-related APIs, e.g working with security descriptors
|
// Helper class for various COM-related APIs, e.g working with security descriptors
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct typed_storage
|
struct typed_storage
|
||||||
|
@ -209,7 +209,7 @@ namespace updating
|
|||||||
return { std::move(path_str) };
|
return { std::move(path_str) };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future<void> attempt_to_download_installer(const std::filesystem::path& destination, const winrt::Windows::Foundation::Uri& url)
|
std::future<void> try_download_file(const std::filesystem::path& destination, const winrt::Windows::Foundation::Uri& url)
|
||||||
{
|
{
|
||||||
namespace storage = winrt::Windows::Storage;
|
namespace storage = winrt::Windows::Storage;
|
||||||
|
|
||||||
@ -218,6 +218,7 @@ namespace updating
|
|||||||
(void)response.EnsureSuccessStatusCode();
|
(void)response.EnsureSuccessStatusCode();
|
||||||
auto msi_installer_file_stream = co_await storage::Streams::FileRandomAccessStream::OpenAsync(destination.c_str(), storage::FileAccessMode::ReadWrite, storage::StorageOpenOptions::AllowReadersAndWriters, storage::Streams::FileOpenDisposition::CreateAlways);
|
auto msi_installer_file_stream = co_await storage::Streams::FileRandomAccessStream::OpenAsync(destination.c_str(), storage::FileAccessMode::ReadWrite, storage::StorageOpenOptions::AllowReadersAndWriters, storage::Streams::FileOpenDisposition::CreateAlways);
|
||||||
co_await response.Content().WriteToStreamAsync(msi_installer_file_stream);
|
co_await response.Content().WriteToStreamAsync(msi_installer_file_stream);
|
||||||
|
msi_installer_file_stream.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::future<void> try_autoupdate(const bool download_updates_automatically)
|
std::future<void> try_autoupdate(const bool download_updates_automatically)
|
||||||
@ -244,7 +245,7 @@ namespace updating
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
co_await attempt_to_download_installer(installer_download_dst, new_version->msi_download_url);
|
co_await try_download_file(installer_download_dst, new_version->msi_download_url);
|
||||||
download_success = true;
|
download_success = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
namespace updating
|
namespace updating
|
||||||
{
|
{
|
||||||
|
std::future<void> try_download_file(const std::filesystem::path& destination, const winrt::Windows::Foundation::Uri& url);
|
||||||
|
|
||||||
std::wstring get_msi_package_path();
|
std::wstring get_msi_package_path();
|
||||||
bool uninstall_msi_version(const std::wstring& package_path);
|
bool uninstall_msi_version(const std::wstring& package_path);
|
||||||
bool offer_msi_uninstallation();
|
bool offer_msi_uninstallation();
|
||||||
|
Loading…
Reference in New Issue
Block a user