@@ -665,6 +665,159 @@ class ExitGuard
665
665
bool m_bArmed;
666
666
};
667
667
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
+
668
821
static TOKEN_ELEVATION_TYPE GetCurrentTokenElevationType ()
669
822
{
670
823
TOKEN_ELEVATION_TYPE retval = TokenElevationTypeDefault;
@@ -740,6 +893,7 @@ static bool ExecuteShutdownCommand(TMenuID menuCommand)
740
893
{
741
894
if (SetShutdownPrivileges ())
742
895
{
896
+ flags = WindowsUpdateAdjustShutdwonFlags (flags);
743
897
InitiateShutdown (NULL , NULL , 0 , flags, SHTDN_REASON_FLAG_PLANNED);
744
898
}
745
899
else
@@ -748,6 +902,8 @@ static bool ExecuteShutdownCommand(TMenuID menuCommand)
748
902
// lets try silent elevate via SystemSettingsAdminFlows (for limited admin users only)
749
903
if (GetCurrentTokenElevationType () == TokenElevationTypeLimited)
750
904
{
905
+ flags = WindowsUpdateAdjustShutdwonFlags (flags);
906
+
751
907
wchar_t cmdLine[32 ]{};
752
908
Sprintf (cmdLine, _countof (cmdLine), L" Shutdown %d %d" , flags, SHTDN_REASON_FLAG_PLANNED);
753
909
0 commit comments