@@ -665,6 +665,159 @@ class ExitGuard
665665 bool m_bArmed;
666666};
667667
668+ // Win10
669+ MIDL_INTERFACE (" 833EE9A0-2999-432C-8EF2-87A8EC2D748D" )
670+ IUxUpdateManager_Win10 : public IUnknown
671+ {
672+ STDMETHOD (GetUxStateVariableBOOL)(enum UxUpdateStateVariable, int *, int *);
673+ STDMETHOD (GetUxStateVariableDWORD)(UxUpdateStateVariable, DWORD*, int *);
674+ STDMETHOD (GetUxStateVariableSYSTEMTIME)(UxUpdateStateVariable, SYSTEMTIME*, int *);
675+ STDMETHOD (SetUxStateVariableBOOL)(UxUpdateStateVariable, int );
676+ STDMETHOD (SetUxStateVariableDWORD)(UxUpdateStateVariable, DWORD);
677+ STDMETHOD (SetUxStateVariableSYSTEMTIME)(UxUpdateStateVariable, SYSTEMTIME);
678+ STDMETHOD (DeleteUxStateVariable)(UxUpdateStateVariable);
679+ STDMETHOD (GetNextRebootTaskRunTime)(int *, SYSTEMTIME*);
680+ STDMETHOD (CreateRebootTasks)(const wchar_t *, SYSTEMTIME);
681+ STDMETHOD (CreateUpdateResultsTaskSchedule)(void );
682+ STDMETHOD (CreateMigrationResultsTaskSchedule)(void );
683+ STDMETHOD (CreateUpdateLogonNotificationTaskSchedule)(void );
684+ STDMETHOD (CreateUpdateNotificationTaskSchedule)(SYSTEMTIME);
685+ STDMETHOD (CreateLogonRebootTaskSchedule)(void );
686+ STDMETHOD (DidUXRebootTaskWakeUpDevice)(int *);
687+ STDMETHOD (RemoveUpdateResultsTaskSchedule)(void );
688+ STDMETHOD (RemoveLogonRebootTaskSchedule)(void );
689+ STDMETHOD (RemoveMigrationResultsTaskSchedule)(void );
690+ STDMETHOD (EnableRebootTasks)(void );
691+ STDMETHOD (DisableRebootTasks)(void );
692+ STDMETHOD (ValidateAndRecoverRebootTasks)(void );
693+ STDMETHOD (RebootToCompleteInstall)(DWORD, int , DWORD*, short , short , DWORD);
694+ STDMETHOD (IsRestartAllowed)(DWORD, int , DWORD, int *);
695+ STDMETHOD (GetIsWaaSOutOfDate)(DWORD, int , int , int *, DWORD*);
696+ STDMETHOD (GetWaaSHoursOutOfDate)(int , int , DWORD*);
697+ STDMETHOD (GetCachedPolicy)(DWORD, VARIANT*, DWORD*, DWORD*);
698+ STDMETHOD (GetEnterpriseCachedPolicy)(DWORD, VARIANT*, DWORD*, DWORD*);
699+ STDMETHOD (GetCachedSettingValue)(DWORD, short , VARIANT*);
700+ STDMETHOD (GetOptInToMU)(int *);
701+ STDMETHOD (SetOptInToMU)(int );
702+ STDMETHOD (SetAndModifyShutdownFlags)(DWORD, DWORD*);
703+ STDMETHOD (GetIsFlightingEnabled)(int *);
704+ STDMETHOD (GetIsCTA)(int *);
705+ STDMETHOD (NotifyStateVariableChange)(void );
706+ STDMETHOD (GetAlwaysAllowMeteredNetwork)(int *);
707+ };
708+
709+ // Win11
710+ MIDL_INTERFACE (" B96BA95F-9479-4656-B7A1-6F3A69091910" )
711+ IUxUpdateManager_Win11 : public IUnknown
712+ {
713+ STDMETHOD (GetUxStateVariableBOOL)(enum UxUpdateStateVariable, int *, int *);
714+ STDMETHOD (GetUxStateVariableDWORD)(UxUpdateStateVariable, DWORD*, int *);
715+ STDMETHOD (GetUxStateVariableSYSTEMTIME)(UxUpdateStateVariable, SYSTEMTIME*, int *);
716+ STDMETHOD (SetUxStateVariableBOOL)(UxUpdateStateVariable, int );
717+ STDMETHOD (SetUxStateVariableDWORD)(UxUpdateStateVariable, DWORD);
718+ STDMETHOD (SetUxStateVariableSYSTEMTIME)(UxUpdateStateVariable, SYSTEMTIME);
719+ STDMETHOD (DeleteUxStateVariable)(UxUpdateStateVariable);
720+ STDMETHOD (GetNextScheduledRebootTaskRunTime)(SYSTEMTIME*);
721+ STDMETHOD (GetIsRebootTaskScheduledToRun)(int *);
722+ STDMETHOD (CreateRebootTasks)(const wchar_t *, SYSTEMTIME);
723+ STDMETHOD (CreateUpdateResultsTaskSchedule)(void );
724+ STDMETHOD (CreateMigrationResultsTaskSchedule)(void );
725+ STDMETHOD (CreateUpdateLogonNotificationTaskSchedule)(void );
726+ STDMETHOD (CreateUpdateNotificationTaskSchedule)(SYSTEMTIME);
727+ STDMETHOD (CreateLogonRebootTaskSchedule)(void );
728+ STDMETHOD (DidUXRebootTaskWakeUpDevice)(int *);
729+ STDMETHOD (RemoveUpdateResultsTaskSchedule)(void );
730+ STDMETHOD (RemoveLogonRebootTaskSchedule)(void );
731+ STDMETHOD (RemoveMigrationResultsTaskSchedule)(void );
732+ STDMETHOD (EnableRebootTasks)(void );
733+ STDMETHOD (DisableRebootTasks)(void );
734+ STDMETHOD (ValidateAndRecoverRebootTasks)(void );
735+ STDMETHOD (RebootToCompleteInstall)(DWORD, int , DWORD*, int , int , double );
736+ STDMETHOD (IsRestartAllowed)(DWORD, int , double , int *);
737+ STDMETHOD (GetIsWaaSOutOfDate)(DWORD, int , int , int *, DWORD*);
738+ STDMETHOD (GetWaaSHoursOutOfDate)(int , int , DWORD*);
739+ STDMETHOD (GetDeviceEndOfServiceDate)(int , int *, FILETIME*);
740+ STDMETHOD (GetCachedPolicy)(DWORD, VARIANT*, DWORD*, DWORD*);
741+ STDMETHOD (GetEnterpriseCachedPolicy)(DWORD, VARIANT*, DWORD*, DWORD*);
742+ STDMETHOD (GetOptInToMU)(int *);
743+ STDMETHOD (SetOptInToMU)(int );
744+ STDMETHOD (SetAndModifyShutdownFlags)(DWORD, DWORD*);
745+ STDMETHOD (GetIsFlightingEnabled)(int *);
746+ STDMETHOD (GetIsCTA)(int *);
747+ STDMETHOD (NotifyStateVariableChange)(void );
748+ STDMETHOD (GetAlwaysAllowMeteredNetwork)(int *);
749+ STDMETHOD (SetInstallAtShutdown)(int );
750+ STDMETHOD (GetUxStateVariableValueOrDefaultBOOL)(UxUpdateStateVariable, int , int *);
751+ STDMETHOD (GetUxStateVariableValueOrDefaultDWORD)(UxUpdateStateVariable, DWORD, DWORD*);
752+ STDMETHOD (GetUxStateVariableValueOrDefaultSYSTEMTIME)(UxUpdateStateVariable, SYSTEMTIME, SYSTEMTIME*);
753+ STDMETHOD (GetSuggestedRebootTime)(int , SYSTEMTIME, SYSTEMTIME*, int *);
754+ STDMETHOD (GetSuggestedActiveHours)(DWORD, DWORD*, DWORD*, int *);
755+ STDMETHOD (GetIsIntervalAcceptableForActiveHours)(SYSTEMTIME, SYSTEMTIME, int *);
756+ STDMETHOD (GetSmartScheduledPredictionsAccurate)(int *);
757+ STDMETHOD (EvaluateAndStoreRebootDowntimePrediction)(void );
758+ STDMETHOD (GetCachedRebootDowntimePrediction)(DWORD*);
759+ STDMETHOD (GetAlwaysAllowCTADownload)(int *);
760+ };
761+
762+ MIDL_INTERFACE (" 07F3AFAC-7C8A-4CE7-A5E0-3D24EE8A77E0" )
763+ IUpdateSessionOrchestrator : public IUnknown
764+ {
765+ STDMETHOD (CreateUpdateSession)(enum UpdateSessionType, const GUID&, void **);
766+ STDMETHOD (GetCurrentActiveUpdateSessions)(class IUsoSessionCollection **);
767+ STDMETHOD (LogTaskRunning)(const wchar_t *);
768+ STDMETHOD (CreateUxUpdateManager)(IUnknown**);
769+ };
770+
771+ DWORD WindowsUpdateAdjustShutdwonFlags (DWORD flags)
772+ {
773+ DWORD retval = flags;
774+
775+ {
776+ // "EnhancedShutdownEnabled" value must exist if Windows updates are prepared
777+ // otherwise there is no need to do anything
778+
779+ CRegKey key;
780+ if (key.Open (HKEY_LOCAL_MACHINE, L" SOFTWARE\\ Microsoft\\ WindowsUpdate\\ Orchestrator" , KEY_READ) != ERROR_SUCCESS)
781+ return retval;
782+
783+ DWORD value;
784+ if (key.QueryDWORDValue (L" EnhancedShutdownEnabled" , value) != ERROR_SUCCESS)
785+ return retval;
786+ }
787+
788+ // this is what standard Windows shutdown handling does inside shutdownux!UsoCommitHelper::SetAndModifyShutdownFlags
789+
790+ static const GUID CLSID_UpdateSessionOrchestrator = { 0xb91d5831 ,0xb1bd ,0x4608 ,{0x81 ,0x98 ,0xd7 ,0x2e ,0x15 ,0x50 ,0x20 ,0xf7 } };
791+
792+ CComPtr<IUpdateSessionOrchestrator> updateSessionOrchestrator;
793+ if (SUCCEEDED (updateSessionOrchestrator.CoCreateInstance (CLSID_UpdateSessionOrchestrator, nullptr , CLSCTX_LOCAL_SERVER)))
794+ {
795+ CComPtr<IUnknown> mgr;
796+ if (SUCCEEDED (updateSessionOrchestrator->CreateUxUpdateManager (&mgr)))
797+ {
798+ // call to IUxUpdateManager::SetAndModifyShutdownFlags will ensure that Windows updates will be dismissed if there is no `SHUTDOWN_INSTALL_UPDATES` flag provided
799+ // it also provides recommended shutdown flags in some cases (so we will use them as advised)
800+ //
801+ // the method is implemented by `UxUpdateManager::SetAndModifyShutdownFlags` in `usosvc.dll` (Win10) / `usosvcimpl.dll` (Win11)
802+
803+ if (CComPtr<IUxUpdateManager_Win10> updateManager; SUCCEEDED (mgr.QueryInterface (&updateManager)))
804+ {
805+ DWORD newFlags;
806+ if (SUCCEEDED (updateManager->SetAndModifyShutdownFlags (flags, &newFlags)))
807+ retval = newFlags;
808+ }
809+ else if (CComPtr<IUxUpdateManager_Win11> updateManager; SUCCEEDED (mgr.QueryInterface (&updateManager)))
810+ {
811+ DWORD newFlags;
812+ if (SUCCEEDED (updateManager->SetAndModifyShutdownFlags (flags, &newFlags)))
813+ retval = newFlags;
814+ }
815+ }
816+ }
817+
818+ return retval;
819+ }
820+
668821static TOKEN_ELEVATION_TYPE GetCurrentTokenElevationType ()
669822{
670823 TOKEN_ELEVATION_TYPE retval = TokenElevationTypeDefault;
@@ -740,6 +893,7 @@ static bool ExecuteShutdownCommand(TMenuID menuCommand)
740893 {
741894 if (SetShutdownPrivileges ())
742895 {
896+ flags = WindowsUpdateAdjustShutdwonFlags (flags);
743897 InitiateShutdown (NULL , NULL , 0 , flags, SHTDN_REASON_FLAG_PLANNED);
744898 }
745899 else
@@ -748,6 +902,8 @@ static bool ExecuteShutdownCommand(TMenuID menuCommand)
748902 // lets try silent elevate via SystemSettingsAdminFlows (for limited admin users only)
749903 if (GetCurrentTokenElevationType () == TokenElevationTypeLimited)
750904 {
905+ flags = WindowsUpdateAdjustShutdwonFlags (flags);
906+
751907 wchar_t cmdLine[32 ]{};
752908 Sprintf (cmdLine, _countof (cmdLine), L" Shutdown %d %d" , flags, SHTDN_REASON_FLAG_PLANNED);
753909
0 commit comments