Question

How I can abort a shutdown/reboot operation initiated by the ExitWindowsEx function?

I've read This SO question but it's unclear for me how to do it, I need a full written example to learn and understand.

I'm writting an helper Class to shutdown the system and I would like to write a method to cancel an initiated shutdown/restart or logoff.

I'm on Windows 8.1

The return information on MSDN Says:

''' <returns>
''' If the function succeeds, the return value is 'True'. 
''' The function executes asynchronously so a 'True' return value indicates that the shutdown has been initiated. 
''' It does not indicate whether the shutdown will succeed. 
''' It is possible that the system, the user, or another application will abort the shutdown.
''' If the function fails, the return value is 'False'. 
''' </returns>

I use a custom method ExitWindows to call the ExitWindowsEx function 'cause I wanted to pass more parameters.

<DllImport("user32.dll", SetLastError:=True)>
Private Function ExitWindowsEx(
        ByVal uFlags As ShutdownType,
        ByVal dwReason As ShutdownReason
) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

Public Function ExitWindows(ByVal ShutdownType As ShutdownType,
                            ByVal ForceType As ForceType,
                            ByVal ShutdownReason As ShutdownReason,
                            ByVal PlanningType As PlanningType) As Boolean

    Return ExitWindowsEx(ShutdownType Or ForceType, ShutdownReason Or PlanningType)

End Function

And this is how I'm doing a restart:

Sub Test()

    ' Reboot system. 
    ' Force applications to close if they hung.
    ' Specify 'Installation' reason.
    ' Specify that it's a planned shutdown.
    ExitWindows(ShutdownType.Reboot,
                ForceType.ForceIfHung,
                ShutdownReason.MajorOperatingSystem Or ShutdownReason.MinorInstallation,
                PlanningType.Planned)

End Sub

Then how I can abort it?

UPDATE

This is my full helper class where I need to implement an 'Abort' Method, but I don't know where to start trying it.

#Region " Imports "

Imports System.ComponentModel
Imports System.Runtime.InteropServices

#End Region

''' <summary>
''' Logs off the interactive user, shuts down the system, or restarts the system.
''' </summary>
Public Class Shutdown

#Region " P/Invoke "

#Region " Methods "

    Friend Class NativeMethods

        ''' <summary>
        ''' Logs off the interactive user, shuts down the system, or shuts down and restarts the system. 
        ''' It sends the 'WM_QUERYENDSESSION' message to all applications to determine if they can be terminated.
        ''' </summary>
        ''' <param name="uFlags">
        ''' Indicates the shutdown type.
        ''' </param>
        ''' <param name="dwReason">
        ''' Indicates the reason for initiating the shutdown.
        ''' </param>
        ''' <returns>
        ''' If the function succeeds, the return value is 'True'. 
        ''' The function executes asynchronously so a 'True' return value indicates that the shutdown has been initiated. 
        ''' It does not indicate whether the shutdown will succeed. 
        ''' It is possible that the system, the user, or another application will abort the shutdown.
        ''' If the function fails, the return value is 'False'. 
        ''' </returns>
        <DllImport("user32.dll", SetLastError:=True)>
        Friend Shared Function ExitWindowsEx(
            ByVal uFlags As ShutdownType,
            ByVal dwReason As ShutdownReason
        ) As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function

    End Class

#End Region

#Region " Enumerations "

    ''' <summary>
    ''' Indicates the shutdown type.
    ''' </summary>
    <Description("Enum used in the 'uFlags' parameter of 'ExitWindowsEx' Function.")>
    <Flags()>
    Enum ShutdownType As UInteger

        ''' <summary>
        ''' Shuts down all processes running in the logon session of the process that called the 'ExitWindowsEx' function. 
        ''' Then it logs the user off.
        ''' This flag can be used only by processes running in an interactive user's logon session.
        ''' </summary>
        LogOff = &H0

        ''' <summary>
        ''' Shuts down the system to a point at which it is safe to turn off the power. 
        ''' All file buffers have been flushed to disk, and all running processes have stopped.
        ''' The calling process must have the 'SE_SHUTDOWN_NAME' privilege. 
        ''' Specifying this flag will not turn off the power even if the system supports the power-off feature, 
        ''' You must specify 'PowerOff' to do this.
        ''' </summary>
        ShutDown = &H1

        ''' <summary>
        ''' Shuts down the system and then restarts it.
        ''' The calling process must have the 'SE_SHUTDOWN_NAME' privilege. 
        ''' </summary>
        Reboot = &H2

        ''' <summary>
        ''' Shuts down the system and turns off the power. 
        ''' The system must support the power-off feature.
        ''' The calling process must have the 'SE_SHUTDOWN_NAME' privilege.
        ''' </summary>
        PowerOff = &H8

        ''' <summary>
        ''' Shuts down the system and then restarts it,
        ''' as well as any applications that have been registered for restart using the
        ''' 'RegisterApplicationRestart' function.
        ''' </summary>
        RestartApps = &H40

    End Enum

    ''' <summary>
    ''' Indicates the forcing type.
    ''' </summary>
    <Description("Enum used in combination with the 'uFlags' parameter of 'ExitWindowsEx' Function.")>
    Enum ForceType As UInteger

        ''' <summary>
        ''' Don't force the system to close the applications.
        ''' This is the default parameter.
        ''' </summary>
        Wait = &H0

        ''' <summary>
        ''' This flag has no effect if terminal services is enabled. 
        ''' Otherwise, the system does not send the 'WM_QUERYENDSESSIO'N message. 
        ''' This can cause applications to lose data. 
        ''' Therefore, you should only use this flag in an emergency.
        ''' </summary>
        Force = &H4

        ''' <summary>
        ''' Forces processes to terminate if they do not respond to the 'WM_QUERYENDSESSION',
        ''' or 'WM_ENDSESSION' message within the timeout interval.
        ''' </summary>
        ForceIfHung = &H10

    End Enum

    ''' <summary>
    ''' Indicates the shutdown reason codes. 
    ''' You can specify any minor reason in combination with any major reason, but some combinations do not make sense.
    ''' </summary>
    <Description("Enum used in the 'dwReason' parameter of 'ExitWindowsEx' Function.")>
    <Flags()>
    Enum ShutdownReason As UInteger

        ''' <summary>
        ''' Application issue.
        ''' </summary>
        MajorApplication = &H40000

        ''' <summary>
        ''' Hardware issue.
        ''' </summary>
        MajorHardware = &H10000

        ''' <summary>
        ''' The 'InitiateSystemShutdown' function was used instead of 'InitiateSystemShutdownEx'.
        ''' </summary>
        MajorLegacyApi = &H70000

        ''' <summary>
        ''' Operating system issue.
        ''' </summary>
        MajorOperatingSystem = &H20000

        ''' <summary>
        ''' Other issue.
        ''' </summary>
        MajorOther = &H0

        ''' <summary>
        ''' Power failure.
        ''' </summary>
        MajorPower = &H60000

        ''' <summary>
        ''' Software issue.
        ''' </summary>
        MajorSoftware = &H30000

        ''' <summary>
        ''' System failure..
        ''' </summary>
        MajorSystem = &H50000

        ''' <summary>
        ''' Blue screen crash event.
        ''' </summary>
        MinorBlueScreen = &HF

        ''' <summary>
        ''' Unplugged.
        ''' </summary>
        MinorCordUnplugged = &HB

        ''' <summary>
        ''' Disk.
        ''' </summary>
        MinorDisk = &H7

        ''' <summary>
        ''' Environment.
        ''' </summary>
        MinorEnvironment = &HC

        ''' <summary>
        ''' Driver.
        ''' </summary>
        MinorHardwareDriver = &HD

        ''' <summary>
        ''' Hot fix.
        ''' </summary>
        MinorHotfix = &H11

        ''' <summary>
        ''' Hot fix uninstallation.
        ''' </summary>
        MinorHotfixUninstall = &H17

        ''' <summary>
        ''' Unresponsive.
        ''' </summary>
        MinorHung = &H5

        ''' <summary>
        ''' Installation.
        ''' </summary>
        MinorInstallation = &H2

        ''' <summary>
        ''' Maintenance.
        ''' </summary>
        MinorMaintenance = &H1

        ''' <summary>
        ''' MMC issue.
        ''' </summary>
        MinorMMC = &H19

        ''' <summary>
        ''' Network connectivity.
        ''' </summary>
        MinorNetworkConnectivity = &H14

        ''' <summary>
        ''' Network card.
        ''' </summary>
        MinorNetworkCard = &H9

        ''' <summary>
        ''' Other issue.
        ''' </summary>
        MinorOther = &H0

        ''' <summary>
        ''' Other driver event.
        ''' </summary>
        MinorOtherDriver = &HE

        ''' <summary>
        ''' Power supply.
        ''' </summary>
        MinorPowerSupply = &HA

        ''' <summary>
        ''' Processor.
        ''' </summary>
        MinorProcessor = &H8

        ''' <summary>
        ''' Reconfigure.
        ''' </summary>
        MinorReconfig = &H4

        ''' <summary>
        ''' Security issue.
        ''' </summary>
        MinorSecurity = &H13

        ''' <summary>
        ''' Security patch.
        ''' </summary>
        MinorSecurityFix = &H12

        ''' <summary>
        ''' Security patch uninstallation.
        ''' </summary>
        MinorSecurityFixUninstall = &H18

        ''' <summary>
        ''' Service pack.
        ''' </summary>
        MinorServicePack = &H10

        ''' <summary>
        ''' Service pack uninstallation.
        ''' </summary>
        MinorServicePackUninstall = &H16

        ''' <summary>
        ''' Terminal Services.
        ''' </summary>
        MinorTermSrv = &H20

        ''' <summary>
        ''' Unstable.
        ''' </summary>
        MinorUnstable = &H6

        ''' <summary>
        ''' Upgrade.
        ''' </summary>
        MinorUpgrade = &H3

        ''' <summary>
        ''' WMI issue.
        ''' </summary>
        MinorWMI = &H15

    End Enum

    ''' <summary>
    ''' Indicates the planning type.
    ''' </summary>
    <Description("Enum used in combination with the 'dwReason' parameter of 'ExitWindowsEx' Function.")>
    Enum PlanningType As UInteger

        ''' <summary>
        ''' The shutdown was unplanned.
        ''' This is the default parameter.
        ''' </summary>
        Unplanned = &H0

        ''' <summary>
        ''' The reason code is defined by the user. 
        ''' For more information, see Defining a Custom Reason Code.
        ''' If this flag is not present, the reason code is defined by the system.
        ''' </summary>
        UserDefined = &H40000000

        ''' <summary>
        ''' The shutdown was planned. 
        ''' The system generates a System State Data (SSD) file. 
        ''' This file contains system state information such as the processes, threads, memory usage, and configuration.
        ''' If this flag is not present, the shutdown was unplanned.
        ''' </summary>
        Planned = &H80000000&

    End Enum

#End Region

#End Region

#Region " Public Methods "

    ''' <summary>
    ''' Shuts down all processes running in the logon session and then logs off the interactive user. 
    ''' </summary>
    ''' <param name="Force">
    ''' Indicates whether it's a forced shutdown.
    ''' </param>
    ''' <param name="Reason">
    ''' Indicates the reason for initiating the shutdown.
    ''' </param>
    ''' <param name="Planning">
    ''' Indicates the shutdown planning.
    ''' </param>
    ''' <returns>
    ''' If the function succeeds, the return value is 'True'. 
    ''' The function executes asynchronously so a 'True' return value indicates that the shutdown has been initiated. 
    ''' It does not indicate whether the shutdown will succeed. 
    ''' It is possible that the system, the user, or another application will abort the shutdown.
    ''' If the function fails, the return value is 'False'. 
    ''' </returns>
    Public Shared Function LogOff(ByVal Force As ForceType,
                                  ByVal Reason As ShutdownReason,
                                  ByVal Planning As PlanningType) As Boolean

        Return NativeMethods.ExitWindowsEx(ShutdownType.LogOff Or Force, Reason Or Planning)

    End Function

    ''' <summary>
    ''' Shuts down the system and turns off the power. 
    ''' </summary>
    ''' <param name="Force">
    ''' Indicates whether it's a forced shutdown.
    ''' </param>
    ''' <param name="Reason">
    ''' Indicates the reason for initiating the shutdown.
    ''' </param>
    ''' <param name="Planning">
    ''' Indicates the shutdown planning.
    ''' </param>
    ''' <returns>
    ''' If the function succeeds, the return value is 'True'. 
    ''' The function executes asynchronously so a 'True' return value indicates that the shutdown has been initiated. 
    ''' It does not indicate whether the shutdown will succeed. 
    ''' It is possible that the system, the user, or another application will abort the shutdown.
    ''' If the function fails, the return value is 'False'. 
    ''' </returns>
    Public Shared Function PowerOff(ByVal Force As ForceType,
                                    ByVal Reason As ShutdownReason,
                                    ByVal Planning As PlanningType) As Boolean

        Return NativeMethods.ExitWindowsEx(ShutdownType.PowerOff Or Force, Reason Or Planning)

    End Function

    ''' <summary>
    ''' Shuts down the system and then restarts it. 
    ''' </summary>
    ''' <param name="Force">
    ''' Indicates whether it's a forced shutdown.
    ''' </param>
    ''' <param name="Reason">
    ''' Indicates the reason for initiating the shutdown.
    ''' </param>
    ''' <param name="Planning">
    ''' Indicates the shutdown planning.
    ''' </param>
    ''' <returns>
    ''' If the function succeeds, the return value is 'True'. 
    ''' The function executes asynchronously so a 'True' return value indicates that the shutdown has been initiated. 
    ''' It does not indicate whether the shutdown will succeed. 
    ''' It is possible that the system, the user, or another application will abort the shutdown.
    ''' If the function fails, the return value is 'False'. 
    ''' </returns>
    Public Shared Function Reboot(ByVal Force As ForceType,
                                  ByVal Reason As ShutdownReason,
                                  ByVal Planning As PlanningType) As Boolean

        Return NativeMethods.ExitWindowsEx(ShutdownType.Reboot Or Force, Reason Or Planning)

    End Function

    ''' <summary>
    ''' Shuts down the system and then restarts it,
    ''' as well as any applications that have been registered for restart. 
    ''' </summary>
    ''' <param name="Force">
    ''' Indicates whether it's a forced shutdown.
    ''' </param>
    ''' <param name="Reason">
    ''' Indicates the reason for initiating the shutdown.
    ''' </param>
    ''' <param name="Planning">
    ''' Indicates the shutdown planning.
    ''' </param>
    ''' <returns>
    ''' If the function succeeds, the return value is 'True'. 
    ''' The function executes asynchronously so a 'True' return value indicates that the shutdown has been initiated. 
    ''' It does not indicate whether the shutdown will succeed. 
    ''' It is possible that the system, the user, or another application will abort the shutdown.
    ''' If the function fails, the return value is 'False'. 
    ''' </returns>
    Public Shared Function RestartApps(ByVal Force As ForceType,
                                      ByVal Reason As ShutdownReason,
                                      ByVal Planning As PlanningType) As Boolean

        Return NativeMethods.ExitWindowsEx(ShutdownType.RestartApps Or Force, Reason Or Planning)

    End Function

    ''' <summary>
    ''' Shuts down the system to a point at which it is safe to turn off the power. 
    ''' </summary>
    ''' <param name="Force">
    ''' Indicates whether it's a forced shutdown.
    ''' </param>
    ''' <param name="Reason">
    ''' Indicates the reason for initiating the shutdown.
    ''' </param>
    ''' <param name="Planning">
    ''' Indicates the shutdown planning.
    ''' </param>
    ''' <returns>
    ''' If the function succeeds, the return value is 'True'. 
    ''' The function executes asynchronously so a 'True' return value indicates that the shutdown has been initiated. 
    ''' It does not indicate whether the shutdown will succeed. 
    ''' It is possible that the system, the user, or another application will abort the shutdown.
    ''' If the function fails, the return value is 'False'. 
    ''' </returns>
    Public Shared Function ShutDown(ByVal Force As ForceType,
                                    ByVal Reason As ShutdownReason,
                                    ByVal Planning As PlanningType) As Boolean

        Return NativeMethods.ExitWindowsEx(ShutdownType.ShutDown Or Force, Reason Or Planning)

    End Function

#End Region

End Class
Was it helpful?

Solution

So this is my understanding of how Windows NT handles it's Shutdown procedures:

This will initiate a shutdown procedure that will send WM_QUERYENDSESSION to each running Application. It will return a nonzero value if the initialization of the async shutdown procedure succeeds.

Applications that would lose data on unattended termination may block/veto the shutdown and appear on a list on the user interface.

The system will prompt the user to decide whether to go ahead with the shutdown, handle applications that require the attention of the user or to abort the shutdown entirely. (since Vista)

Note that ExitWindowsEx is only meant to be aborted by an interactive user

The MSDN article of this function actually suggests, that a non interactive user should call a different function instead:

This requires the calling thread to have the SE_SHUTDOWN_NAME or SE_REMOTE_SHUTDOWN_NAME privileges to initiate the shutdown of the local or a remote machine respectivly.

It will also return a nonzero value on successfull initiation of the shutdown procedure.

This type of shutdown can be aborted via AbortSystemShutdown

Trivia: The executable shutdown.exe actually uses this type of shutdown procedure (in fact calling said Winuser functions)

OTHER TIPS

Finally here is my approach that I want to share, was very hard the investigation and all those XML documentation writting.

This helper class can logoff, restart, shutdown/poweroff and abort an operation, all using WinAPI. Enjoy it!

~> SystemRestarter for VB.NET - by Elektro

PS: Maybe it could not work as expected restarting/aborting remote machines, I can't test it in that way.

Usage example:

Sub Test()

   ' Restart the current computer in 30 seconds and wait for applications to close.
   ' Specify that the restart operation is planned because a consecuence of an installation.
   Dim Success =
   SystemRestarter.Restart(Nothing, 30, "System is gonna be restarted quickly, save all your data...!",
                           SystemRestarter.Enums.InitiateShutdown_Force.Wait,
                           SystemRestarter.Enums.ShutdownReason.MajorOperatingSystem Or
                           SystemRestarter.Enums.ShutdownReason.MinorInstallation,
                           SystemRestarter.Enums.ShutdownPlanning.Planned)

   Console.WriteLine(String.Format("Restart operation initiated successfully?: {0}", CStr(Success)))

   ' Abort the current operation.
   If Success Then
       Dim IsAborted = SystemRestarter.Abort()
       Console.WriteLine(String.Format("Restart operation aborted   successfully?: {0}", CStr(IsAborted)))
   Else
       Console.WriteLine("There is any restart operation to abort.")
   End If
   Console.ReadKey()

   ' Shutdown the current computer instantlly and force applications to close.
   ' ( When timeout is '0' the operation can't be aborted )
   SystemRestarter.Shutdown(Nothing, 0, Nothing, SystemRestarter.Enums.InitiateShutdown_Force.ForceSelf)

   ' LogOffs the current user.
   SystemRestarter.LogOff(SystemRestarter.Enums.ExitwindowsEx_Force.Wait)

End Sub
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top