mirror of
https://github.com/Open-Shell/Open-Shell-Menu.git
synced 2026-04-17 21:24:47 +10:00
Properly handle Windows updates during shutdown
Windows updates are applied on shutdown/reboot no matter of flags used in ExitWindowsEx (or InitiateShutdown). Windows start menu shutdown code handles updates in special way. If there are updates prepared and shutdown/reboot is selected it will use `UpdateSessionOrchestrator` object to dismiss updates and carry out the command. We will now do similar thing. Fixes #1250
This commit is contained in:
@@ -665,6 +665,159 @@ private:
|
|||||||
bool m_bArmed;
|
bool m_bArmed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Win10
|
||||||
|
MIDL_INTERFACE("833EE9A0-2999-432C-8EF2-87A8EC2D748D")
|
||||||
|
IUxUpdateManager_Win10 : public IUnknown
|
||||||
|
{
|
||||||
|
STDMETHOD(GetUxStateVariableBOOL)(enum UxUpdateStateVariable, int*, int*);
|
||||||
|
STDMETHOD(GetUxStateVariableDWORD)(UxUpdateStateVariable, DWORD*, int*);
|
||||||
|
STDMETHOD(GetUxStateVariableSYSTEMTIME)(UxUpdateStateVariable, SYSTEMTIME*, int*);
|
||||||
|
STDMETHOD(SetUxStateVariableBOOL)(UxUpdateStateVariable, int);
|
||||||
|
STDMETHOD(SetUxStateVariableDWORD)(UxUpdateStateVariable, DWORD);
|
||||||
|
STDMETHOD(SetUxStateVariableSYSTEMTIME)(UxUpdateStateVariable, SYSTEMTIME);
|
||||||
|
STDMETHOD(DeleteUxStateVariable)(UxUpdateStateVariable);
|
||||||
|
STDMETHOD(GetNextRebootTaskRunTime)(int*, SYSTEMTIME*);
|
||||||
|
STDMETHOD(CreateRebootTasks)(const wchar_t*, SYSTEMTIME);
|
||||||
|
STDMETHOD(CreateUpdateResultsTaskSchedule)(void);
|
||||||
|
STDMETHOD(CreateMigrationResultsTaskSchedule)(void);
|
||||||
|
STDMETHOD(CreateUpdateLogonNotificationTaskSchedule)(void);
|
||||||
|
STDMETHOD(CreateUpdateNotificationTaskSchedule)(SYSTEMTIME);
|
||||||
|
STDMETHOD(CreateLogonRebootTaskSchedule)(void);
|
||||||
|
STDMETHOD(DidUXRebootTaskWakeUpDevice)(int*);
|
||||||
|
STDMETHOD(RemoveUpdateResultsTaskSchedule)(void);
|
||||||
|
STDMETHOD(RemoveLogonRebootTaskSchedule)(void);
|
||||||
|
STDMETHOD(RemoveMigrationResultsTaskSchedule)(void);
|
||||||
|
STDMETHOD(EnableRebootTasks)(void);
|
||||||
|
STDMETHOD(DisableRebootTasks)(void);
|
||||||
|
STDMETHOD(ValidateAndRecoverRebootTasks)(void);
|
||||||
|
STDMETHOD(RebootToCompleteInstall)(DWORD, int, DWORD*, short, short, DWORD);
|
||||||
|
STDMETHOD(IsRestartAllowed)(DWORD, int, DWORD, int*);
|
||||||
|
STDMETHOD(GetIsWaaSOutOfDate)(DWORD, int, int, int*, DWORD*);
|
||||||
|
STDMETHOD(GetWaaSHoursOutOfDate)(int, int, DWORD*);
|
||||||
|
STDMETHOD(GetCachedPolicy)(DWORD, VARIANT*, DWORD*, DWORD*);
|
||||||
|
STDMETHOD(GetEnterpriseCachedPolicy)(DWORD, VARIANT*, DWORD*, DWORD*);
|
||||||
|
STDMETHOD(GetCachedSettingValue)(DWORD, short, VARIANT*);
|
||||||
|
STDMETHOD(GetOptInToMU)(int*);
|
||||||
|
STDMETHOD(SetOptInToMU)(int);
|
||||||
|
STDMETHOD(SetAndModifyShutdownFlags)(DWORD, DWORD*);
|
||||||
|
STDMETHOD(GetIsFlightingEnabled)(int*);
|
||||||
|
STDMETHOD(GetIsCTA)(int*);
|
||||||
|
STDMETHOD(NotifyStateVariableChange)(void);
|
||||||
|
STDMETHOD(GetAlwaysAllowMeteredNetwork)(int*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Win11
|
||||||
|
MIDL_INTERFACE("B96BA95F-9479-4656-B7A1-6F3A69091910")
|
||||||
|
IUxUpdateManager_Win11 : public IUnknown
|
||||||
|
{
|
||||||
|
STDMETHOD(GetUxStateVariableBOOL)(enum UxUpdateStateVariable, int*, int*);
|
||||||
|
STDMETHOD(GetUxStateVariableDWORD)(UxUpdateStateVariable, DWORD*, int*);
|
||||||
|
STDMETHOD(GetUxStateVariableSYSTEMTIME)(UxUpdateStateVariable, SYSTEMTIME*, int*);
|
||||||
|
STDMETHOD(SetUxStateVariableBOOL)(UxUpdateStateVariable, int);
|
||||||
|
STDMETHOD(SetUxStateVariableDWORD)(UxUpdateStateVariable, DWORD);
|
||||||
|
STDMETHOD(SetUxStateVariableSYSTEMTIME)(UxUpdateStateVariable, SYSTEMTIME);
|
||||||
|
STDMETHOD(DeleteUxStateVariable)(UxUpdateStateVariable);
|
||||||
|
STDMETHOD(GetNextScheduledRebootTaskRunTime)(SYSTEMTIME*);
|
||||||
|
STDMETHOD(GetIsRebootTaskScheduledToRun)(int*);
|
||||||
|
STDMETHOD(CreateRebootTasks)(const wchar_t*, SYSTEMTIME);
|
||||||
|
STDMETHOD(CreateUpdateResultsTaskSchedule)(void);
|
||||||
|
STDMETHOD(CreateMigrationResultsTaskSchedule)(void);
|
||||||
|
STDMETHOD(CreateUpdateLogonNotificationTaskSchedule)(void);
|
||||||
|
STDMETHOD(CreateUpdateNotificationTaskSchedule)(SYSTEMTIME);
|
||||||
|
STDMETHOD(CreateLogonRebootTaskSchedule)(void);
|
||||||
|
STDMETHOD(DidUXRebootTaskWakeUpDevice)(int*);
|
||||||
|
STDMETHOD(RemoveUpdateResultsTaskSchedule)(void);
|
||||||
|
STDMETHOD(RemoveLogonRebootTaskSchedule)(void);
|
||||||
|
STDMETHOD(RemoveMigrationResultsTaskSchedule)(void);
|
||||||
|
STDMETHOD(EnableRebootTasks)(void);
|
||||||
|
STDMETHOD(DisableRebootTasks)(void);
|
||||||
|
STDMETHOD(ValidateAndRecoverRebootTasks)(void);
|
||||||
|
STDMETHOD(RebootToCompleteInstall)(DWORD, int, DWORD*, int, int, double);
|
||||||
|
STDMETHOD(IsRestartAllowed)(DWORD, int, double, int*);
|
||||||
|
STDMETHOD(GetIsWaaSOutOfDate)(DWORD, int, int, int*, DWORD*);
|
||||||
|
STDMETHOD(GetWaaSHoursOutOfDate)(int, int, DWORD*);
|
||||||
|
STDMETHOD(GetDeviceEndOfServiceDate)(int, int*, FILETIME*);
|
||||||
|
STDMETHOD(GetCachedPolicy)(DWORD, VARIANT*, DWORD*, DWORD*);
|
||||||
|
STDMETHOD(GetEnterpriseCachedPolicy)(DWORD, VARIANT*, DWORD*, DWORD*);
|
||||||
|
STDMETHOD(GetOptInToMU)(int*);
|
||||||
|
STDMETHOD(SetOptInToMU)(int);
|
||||||
|
STDMETHOD(SetAndModifyShutdownFlags)(DWORD, DWORD*);
|
||||||
|
STDMETHOD(GetIsFlightingEnabled)(int*);
|
||||||
|
STDMETHOD(GetIsCTA)(int*);
|
||||||
|
STDMETHOD(NotifyStateVariableChange)(void);
|
||||||
|
STDMETHOD(GetAlwaysAllowMeteredNetwork)(int*);
|
||||||
|
STDMETHOD(SetInstallAtShutdown)(int);
|
||||||
|
STDMETHOD(GetUxStateVariableValueOrDefaultBOOL)(UxUpdateStateVariable, int, int*);
|
||||||
|
STDMETHOD(GetUxStateVariableValueOrDefaultDWORD)(UxUpdateStateVariable, DWORD, DWORD*);
|
||||||
|
STDMETHOD(GetUxStateVariableValueOrDefaultSYSTEMTIME)(UxUpdateStateVariable, SYSTEMTIME, SYSTEMTIME*);
|
||||||
|
STDMETHOD(GetSuggestedRebootTime)(int, SYSTEMTIME, SYSTEMTIME*, int*);
|
||||||
|
STDMETHOD(GetSuggestedActiveHours)(DWORD, DWORD*, DWORD*, int*);
|
||||||
|
STDMETHOD(GetIsIntervalAcceptableForActiveHours)(SYSTEMTIME, SYSTEMTIME, int*);
|
||||||
|
STDMETHOD(GetSmartScheduledPredictionsAccurate)(int*);
|
||||||
|
STDMETHOD(EvaluateAndStoreRebootDowntimePrediction)(void);
|
||||||
|
STDMETHOD(GetCachedRebootDowntimePrediction)(DWORD*);
|
||||||
|
STDMETHOD(GetAlwaysAllowCTADownload)(int*);
|
||||||
|
};
|
||||||
|
|
||||||
|
MIDL_INTERFACE("07F3AFAC-7C8A-4CE7-A5E0-3D24EE8A77E0")
|
||||||
|
IUpdateSessionOrchestrator : public IUnknown
|
||||||
|
{
|
||||||
|
STDMETHOD(CreateUpdateSession)(enum UpdateSessionType, const GUID&, void**);
|
||||||
|
STDMETHOD(GetCurrentActiveUpdateSessions)(class IUsoSessionCollection**);
|
||||||
|
STDMETHOD(LogTaskRunning)(const wchar_t*);
|
||||||
|
STDMETHOD(CreateUxUpdateManager)(IUnknown**);
|
||||||
|
};
|
||||||
|
|
||||||
|
DWORD WindowsUpdateAdjustShutdwonFlags(DWORD flags)
|
||||||
|
{
|
||||||
|
DWORD retval = flags;
|
||||||
|
|
||||||
|
{
|
||||||
|
// "EnhancedShutdownEnabled" value must exist if Windows updates are prepared
|
||||||
|
// otherwise there is no need to do anything
|
||||||
|
|
||||||
|
CRegKey key;
|
||||||
|
if (key.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\WindowsUpdate\\Orchestrator", KEY_READ) != ERROR_SUCCESS)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
DWORD value;
|
||||||
|
if (key.QueryDWORDValue(L"EnhancedShutdownEnabled", value) != ERROR_SUCCESS)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is what standard Windows shutdown handling does inside shutdownux!UsoCommitHelper::SetAndModifyShutdownFlags
|
||||||
|
|
||||||
|
static const GUID CLSID_UpdateSessionOrchestrator = { 0xb91d5831,0xb1bd,0x4608,{0x81,0x98,0xd7,0x2e,0x15,0x50,0x20,0xf7} };
|
||||||
|
|
||||||
|
CComPtr<IUpdateSessionOrchestrator> updateSessionOrchestrator;
|
||||||
|
if (SUCCEEDED(updateSessionOrchestrator.CoCreateInstance(CLSID_UpdateSessionOrchestrator, nullptr, CLSCTX_LOCAL_SERVER)))
|
||||||
|
{
|
||||||
|
CComPtr<IUnknown> mgr;
|
||||||
|
if (SUCCEEDED(updateSessionOrchestrator->CreateUxUpdateManager(&mgr)))
|
||||||
|
{
|
||||||
|
// call to IUxUpdateManager::SetAndModifyShutdownFlags will ensure that Windows updates will be dismissed if there is no `SHUTDOWN_INSTALL_UPDATES` flag provided
|
||||||
|
// it also provides recommended shutdown flags in some cases (so we will use them as advised)
|
||||||
|
//
|
||||||
|
// the method is implemented by `UxUpdateManager::SetAndModifyShutdownFlags` in `usosvc.dll` (Win10) / `usosvcimpl.dll` (Win11)
|
||||||
|
|
||||||
|
if (CComPtr<IUxUpdateManager_Win10> updateManager; SUCCEEDED(mgr.QueryInterface(&updateManager)))
|
||||||
|
{
|
||||||
|
DWORD newFlags;
|
||||||
|
if (SUCCEEDED(updateManager->SetAndModifyShutdownFlags(flags, &newFlags)))
|
||||||
|
retval = newFlags;
|
||||||
|
}
|
||||||
|
else if (CComPtr<IUxUpdateManager_Win11> updateManager; SUCCEEDED(mgr.QueryInterface(&updateManager)))
|
||||||
|
{
|
||||||
|
DWORD newFlags;
|
||||||
|
if (SUCCEEDED(updateManager->SetAndModifyShutdownFlags(flags, &newFlags)))
|
||||||
|
retval = newFlags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
static TOKEN_ELEVATION_TYPE GetCurrentTokenElevationType()
|
static TOKEN_ELEVATION_TYPE GetCurrentTokenElevationType()
|
||||||
{
|
{
|
||||||
TOKEN_ELEVATION_TYPE retval = TokenElevationTypeDefault;
|
TOKEN_ELEVATION_TYPE retval = TokenElevationTypeDefault;
|
||||||
@@ -740,6 +893,7 @@ static bool ExecuteShutdownCommand(TMenuID menuCommand)
|
|||||||
{
|
{
|
||||||
if (SetShutdownPrivileges())
|
if (SetShutdownPrivileges())
|
||||||
{
|
{
|
||||||
|
flags = WindowsUpdateAdjustShutdwonFlags(flags);
|
||||||
InitiateShutdown(NULL, NULL, 0, flags, SHTDN_REASON_FLAG_PLANNED);
|
InitiateShutdown(NULL, NULL, 0, flags, SHTDN_REASON_FLAG_PLANNED);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -748,6 +902,8 @@ static bool ExecuteShutdownCommand(TMenuID menuCommand)
|
|||||||
// lets try silent elevate via SystemSettingsAdminFlows (for limited admin users only)
|
// lets try silent elevate via SystemSettingsAdminFlows (for limited admin users only)
|
||||||
if (GetCurrentTokenElevationType() == TokenElevationTypeLimited)
|
if (GetCurrentTokenElevationType() == TokenElevationTypeLimited)
|
||||||
{
|
{
|
||||||
|
flags = WindowsUpdateAdjustShutdwonFlags(flags);
|
||||||
|
|
||||||
wchar_t cmdLine[32]{};
|
wchar_t cmdLine[32]{};
|
||||||
Sprintf(cmdLine, _countof(cmdLine), L"Shutdown %d %d", flags, SHTDN_REASON_FLAG_PLANNED);
|
Sprintf(cmdLine, _countof(cmdLine), L"Shutdown %d %d", flags, SHTDN_REASON_FLAG_PLANNED);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user