[Installer] Restart explorer.exe programatically after successful update (#4215)

* Restart explorer.exe programatically after successful update

* Move RestartManager related code into common

* Add newline at the end of files

* Note that explorer.exe should not be localized string
This commit is contained in:
vldmr11080 2020-06-11 10:09:06 +02:00 committed by GitHub
parent d76234c112
commit b0a25f59d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 101 additions and 9 deletions

View File

@ -204,10 +204,6 @@
<!-- Close 'PowerToys.exe' before uninstall-->
<Property Id="MSIRESTARTMANAGERCONTROL" Value="Disable" />
<!-- Restart explorer.exe if we detect existing PowerRenameExt.dll or ImageResizerExt.dll installation -->
<util:CloseApplication Target="explorer.exe" RebootPrompt="no" TerminateProcess="0">
EXISTINGPOWERRENAMEEXTPATH OR EXISTINGIMAGERESIZERPATH
</util:CloseApplication>
<util:CloseApplication CloseMessage="yes" Target="PowerToys.exe" ElevatedCloseMessage="yes" RebootPrompt="no" TerminateProcess="0" />
</Product>

View File

@ -0,0 +1,64 @@
#include "pch.h"
#include "RestartManagement.h"
#include <RestartManager.h>
#include <Psapi.h>
std::vector<RM_UNIQUE_PROCESS> GetProcessInfoByName(const std::wstring& processName)
{
DWORD bytesReturned{};
std::vector<DWORD> processIds{};
processIds.resize(1024);
DWORD processIdSize{ (DWORD)processIds.size() * sizeof(DWORD) };
EnumProcesses(processIds.data(), processIdSize, &bytesReturned);
while (bytesReturned == processIdSize)
{
processIdSize *= 2;
processIds.resize(processIdSize / sizeof(DWORD));
EnumProcesses(processIds.data(), processIdSize, &bytesReturned);
}
std::vector<RM_UNIQUE_PROCESS> pInfos{};
for (const DWORD& processId : processIds)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
if (hProcess)
{
wchar_t name[MAX_PATH];
if (GetProcessImageFileName(hProcess, name, MAX_PATH) > 0)
{
if (processName == PathFindFileName(name))
{
FILETIME creationTime{};
FILETIME exitTime{};
FILETIME kernelTime{};
FILETIME userTime{};
if (GetProcessTimes(hProcess, &creationTime, &exitTime, &kernelTime, &userTime))
{
pInfos.push_back({ processId, creationTime });
}
}
}
CloseHandle(hProcess);
}
}
return pInfos;
}
void RestartProcess(const std::wstring& processName)
{
DWORD sessionHandle{};
WCHAR sessionKey[CCH_RM_SESSION_KEY + 1];
if (RmStartSession(&sessionHandle, 0, sessionKey) != ERROR_SUCCESS)
{
return;
}
std::vector<RM_UNIQUE_PROCESS> pInfo = GetProcessInfoByName(processName);
if (pInfo.empty() ||
RmRegisterResources(sessionHandle, 0, nullptr, sizeof(pInfo), pInfo.data(), 0, nullptr) != ERROR_SUCCESS)
{
return;
}
RmShutdown(sessionHandle, RmForceShutdown, nullptr);
RmRestart(sessionHandle, 0, nullptr);
RmEndSession(sessionHandle);
}

View File

@ -0,0 +1,5 @@
#pragma once
#include <string>
void RestartProcess(const std::wstring& processName);

View File

@ -125,6 +125,7 @@
<ClInclude Include="keyboard_layout.h" />
<ClInclude Include="keyboard_layout_impl.h" />
<ClInclude Include="notifications.h" />
<ClInclude Include="RestartManagement.h" />
<ClInclude Include="shared_constants.h" />
<ClInclude Include="timeutil.h" />
<ClInclude Include="two_way_pipe_message_ipc.h" />
@ -161,6 +162,7 @@
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="RestartManagement.cpp" />
<ClCompile Include="settings_helpers.cpp" />
<ClCompile Include="settings_objects.cpp" />
<ClCompile Include="icon_helpers.cpp" />

View File

@ -111,6 +111,9 @@
<ClInclude Include="two_way_pipe_message_ipc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RestartManagement.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="d2d_svg.cpp">
@ -180,6 +183,9 @@
<ClCompile Include="two_way_pipe_message_ipc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="RestartManagement.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@ -11,11 +11,10 @@
#include <common/common.h>
#include <common/dpi_aware.h>
#include <common/winstore.h>
#include <common/notifications.h>
#include <common/updating/updating.h>
#include <common/RestartManagement.h>
#include "update_state.h"
#include "update_utils.h"
@ -23,6 +22,9 @@
#include <winrt/Windows.System.h>
#include <Psapi.h>
#include <RestartManager.h>
#if _DEBUG && _WIN64
#include "unhandled_exception_handler.h"
#endif
@ -30,10 +32,16 @@
extern "C" IMAGE_DOS_HEADER __ImageBase;
// Window Explorer process name should not be localized.
const wchar_t EXPLORER_PROCESS_NAME[] = L"explorer.exe";
namespace localized_strings
{
const wchar_t MSI_VERSION_IS_ALREADY_RUNNING[] = L"An older version of PowerToys is already running.";
const wchar_t OLDER_MSIX_UNINSTALLED[] = L"An older MSIX version of PowerToys was uninstalled.";
const wchar_t PT_UPDATE_MESSAGE_BOX_TITLE[] = L"PowerToys";
const wchar_t PT_UPDATE_MESSAGE_BOX_TEXT[] = L"PowerToys was updated and some components require Windows Explorer to restart. Do you want to restart Windows Explorer now?";
}
namespace
@ -249,6 +257,17 @@ toast_notification_handler_result toast_notification_handler(const std::wstring_
}
}
void RequestExplorerRestart()
{
if (MessageBox(nullptr,
localized_strings::PT_UPDATE_MESSAGE_BOX_TEXT,
localized_strings::PT_UPDATE_MESSAGE_BOX_TITLE,
MB_ICONINFORMATION | MB_YESNO | MB_DEFBUTTON1) == IDYES)
{
RestartProcess(localized_strings::EXPLORER_PROCESS_NAME);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
winrt::init_apartment();
@ -273,7 +292,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
return 0;
}
case SpecialMode::ReportSuccessfulUpdate:
notifications::show_toast(GET_RESOURCE_STRING(IDS_AUTOUPDATE_SUCCESS));
RequestExplorerRestart();
break;
case SpecialMode::None:

View File

@ -69,7 +69,7 @@
<Link>
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>Msi.lib;WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Msi.lib;WindowsApp.lib;Rstrtmgr.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Manifest>
<EnableDpiAwareness>false</EnableDpiAwareness>
@ -93,7 +93,7 @@
<OptimizeReferences>true</OptimizeReferences>
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalDependencies>Msi.lib;WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Msi.lib;WindowsApp.lib;Rstrtmgr.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Manifest>
<EnableDpiAwareness>false</EnableDpiAwareness>