Introduction
The AbortSystemShutdown
function stops a system shutdown started by using the InitiateSystemShutdown
function. The InitiateSystemShutdown
function initiates a shutdown and optional restart of the specified computer (see picture below).
There is also another way how to receive this dialog (see picture below): if your computer is infected by the Blaster worm or its variants known as W32.Blaster.Worm, W32.Blaster.C.Worm, W32.Blaster.B.Worm, W32.Randex.E (Symantec), W32/Lovsan.worm (McAfee), WORM_MSBLAST.A (Trendmicro), and Win32.Posa.Worm (Computer Associates).
Code explanation
The AbortSystemShutdown
function requires version Windows NT 3.1 or later. Therefore it's useful to use Windows version requirements macros. You can find more information in this article.
#define WinVerMajor() LOBYTE(LOWORD(GetVersion()))
#define IsWinVerNTs() (GetVersion() < 0x80000000)
#define IsWinVerNT351Plus() (IsWinVerNTs() && WinVerMajor() >= 3)
To stop the local computer from shutting down, the calling process must have the SE_SHUTDOWN_NAME
privilege. That's the reason why we use the AdjustTokenPrivileges
function.
This example also illustrates load-time dynamic linking. If the DLL is not available, the application using load-time dynamic linking must simply terminate. The run-time dynamic linking example, however, can respond to the error.
The code is prepared for UNICODE. If you want to create UNICODE version, add UNICODE to the preprocessor definitions.
The FormatMessage
function can be used to obtain error message strings for the system error codes returned by GetLastError
.
#include <windows.h>
#define WinVerMajor() LOBYTE(LOWORD(GetVersion()))
#define IsWinVerNTs() (GetVersion() < 0x80000000)
#define IsWinVerNT351Plus() (IsWinVerNTs() && WinVerMajor() >= 3)
#define ERR_MSG TEXT("This program requires Windows NT version 3.1 or later!")
BOOL (__stdcall * MyAbortSystemShutdown)(LPTSTR);
BOOL fAbortSystemShutdown(LPTSTR lpMachineName);
BOOL PreventSystemShutdown(void);
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
if (IsWinVerNT351Plus())
{
PreventSystemShutdown();
}
else
{
MessageBox(NULL, ERR_MSG, TEXT("Abort System Shutdown"), MB_OK);
}
return (0);
}
BOOL fAbortSystemShutdown(LPTSTR lpMachineName)
{
HINSTANCE hinstLib;
BOOL result = FALSE;
if (IsWinVerNT351Plus())
{
hinstLib = LoadLibrary(TEXT("Advapi32.dll"));
if (hinstLib)
{
if (MyAbortSystemShutdown = (BOOL (__stdcall *)(LPTSTR))
#ifdef UNICODE
GetProcAddress(hinstLib, "AbortSystemShutdownW"))
#else
GetProcAddress(hinstLib, "AbortSystemShutdownA"))
#endif
{
result = (MyAbortSystemShutdown)(lpMachineName);
}
}
FreeLibrary(hinstLib);
}
return (result);
}
BOOL PreventSystemShutdown(void)
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
return (FALSE);
}
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES) NULL, 0);
if (GetLastError() != ERROR_SUCCESS)
{
return (FALSE);
}
if (! fAbortSystemShutdown(NULL))
{
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf, 0, NULL
);
MessageBox(NULL, (LPCTSTR) lpMsgBuf, TEXT("Error"),
MB_OK | MB_ICONINFORMATION);
LocalFree(lpMsgBuf);
return (FALSE);
}
tkp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
return (TRUE);
}
You can get the same result when executing Windows XP shutdown.exe utility with parameter -a. Also you can use shutdown -s -t 60 -c "bye-bye" command to invoke the system Shutdown dialog.