2018-04-01 22:38:18 +00:00
|
|
|
/*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS Winlogon
|
|
|
|
* FILE: base/system/winlogon/shutdown.c
|
|
|
|
* PURPOSE: System shutdown dialog
|
2020-10-03 23:01:46 +00:00
|
|
|
* PROGRAMMERS: Edward Bronsten <tanki.alpha5056@gmail.com>
|
|
|
|
* Eric Kohl
|
2020-10-03 23:31:31 +00:00
|
|
|
* Hermes Belusca-Maito
|
2018-04-01 22:38:18 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
|
|
|
|
#include "winlogon.h"
|
|
|
|
|
|
|
|
#include <rpc.h>
|
|
|
|
#include <winreg_s.h>
|
|
|
|
|
|
|
|
/* DEFINES *******************************************************************/
|
|
|
|
|
2018-04-02 10:47:15 +00:00
|
|
|
#define SHUTDOWN_TIMER_ID 2000
|
2018-04-02 16:52:47 +00:00
|
|
|
#define SECONDS_PER_DAY 86400
|
|
|
|
#define SECONDS_PER_DECADE 315360000
|
2018-04-02 10:47:15 +00:00
|
|
|
|
2018-04-01 22:38:18 +00:00
|
|
|
/* STRUCTS *******************************************************************/
|
|
|
|
|
|
|
|
typedef struct _SYS_SHUTDOWN_PARAMS
|
|
|
|
{
|
2018-04-02 10:47:15 +00:00
|
|
|
PWSTR pszMessage;
|
2018-04-01 22:38:18 +00:00
|
|
|
ULONG dwTimeout;
|
2020-10-03 23:31:31 +00:00
|
|
|
|
|
|
|
HDESK hShutdownDesk;
|
|
|
|
WCHAR DesktopName[512];
|
|
|
|
WINDOWPLACEMENT wpPos;
|
|
|
|
|
|
|
|
BOOLEAN bShuttingDown;
|
2018-04-01 22:38:18 +00:00
|
|
|
BOOLEAN bRebootAfterShutdown;
|
|
|
|
BOOLEAN bForceAppsClosed;
|
|
|
|
DWORD dwReason;
|
|
|
|
} SYS_SHUTDOWN_PARAMS, *PSYS_SHUTDOWN_PARAMS;
|
|
|
|
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
|
|
|
|
SYS_SHUTDOWN_PARAMS g_ShutdownParams;
|
|
|
|
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
2018-04-28 16:14:53 +00:00
|
|
|
static
|
|
|
|
BOOL
|
|
|
|
DoSystemShutdown(
|
|
|
|
IN PSYS_SHUTDOWN_PARAMS pShutdownParams)
|
|
|
|
{
|
|
|
|
BOOL Success;
|
|
|
|
|
|
|
|
/* If shutdown has been cancelled, bail out now */
|
|
|
|
if (!pShutdownParams->bShuttingDown)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
Success = ExitWindowsEx((pShutdownParams->bRebootAfterShutdown ? EWX_REBOOT : EWX_SHUTDOWN) |
|
|
|
|
(pShutdownParams->bForceAppsClosed ? EWX_FORCE : 0),
|
|
|
|
pShutdownParams->dwReason);
|
|
|
|
if (!Success)
|
|
|
|
{
|
|
|
|
/* Something went wrong, cancel shutdown */
|
|
|
|
pShutdownParams->bShuttingDown = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Success;
|
|
|
|
}
|
|
|
|
|
2018-04-01 23:37:50 +00:00
|
|
|
static
|
|
|
|
VOID
|
|
|
|
OnTimer(
|
2020-10-03 23:01:46 +00:00
|
|
|
IN HWND hwndDlg,
|
|
|
|
IN PSYS_SHUTDOWN_PARAMS pShutdownParams)
|
2018-04-01 23:37:50 +00:00
|
|
|
{
|
2020-10-03 23:31:31 +00:00
|
|
|
HDESK hInputDesktop;
|
|
|
|
BOOL bSuccess;
|
|
|
|
DWORD dwSize;
|
|
|
|
INT iSeconds, iMinutes, iHours, iDays;
|
2018-04-29 15:09:37 +00:00
|
|
|
WCHAR szFormatBuffer[32];
|
|
|
|
WCHAR szBuffer[32];
|
2020-10-03 23:31:31 +00:00
|
|
|
WCHAR DesktopName[512];
|
2018-04-01 23:37:50 +00:00
|
|
|
|
2018-04-28 16:14:53 +00:00
|
|
|
if (!pShutdownParams->bShuttingDown)
|
|
|
|
{
|
|
|
|
/* Shutdown has been cancelled, close the dialog and bail out */
|
2020-10-03 23:31:31 +00:00
|
|
|
EndDialog(hwndDlg, IDABORT);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check whether the input desktop has changed. If so, close the dialog,
|
|
|
|
* and let the shutdown thread recreate it on the new desktop.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// TODO: Investigate: It would be great if we could also compare with
|
|
|
|
// our internally maintained desktop handles, before calling that heavy
|
|
|
|
// comparison.
|
|
|
|
// (Note that we cannot compare handles with arbitrary input desktop,
|
|
|
|
// since OpenInputDesktop() creates new handle instances everytime.)
|
|
|
|
|
|
|
|
hInputDesktop = OpenInputDesktop(0, FALSE, GENERIC_ALL);
|
|
|
|
if (!hInputDesktop)
|
|
|
|
{
|
|
|
|
/* No input desktop but we have a dialog: kill it */
|
|
|
|
ERR("OpenInputDesktop() failed, error 0x%lx\n", GetLastError());
|
2018-04-28 16:14:53 +00:00
|
|
|
EndDialog(hwndDlg, 0);
|
|
|
|
return;
|
|
|
|
}
|
2020-10-03 23:31:31 +00:00
|
|
|
bSuccess = GetUserObjectInformationW(hInputDesktop,
|
|
|
|
UOI_NAME,
|
|
|
|
DesktopName,
|
|
|
|
sizeof(DesktopName),
|
|
|
|
&dwSize);
|
|
|
|
if (!bSuccess)
|
|
|
|
{
|
|
|
|
ERR("GetUserObjectInformationW(0x%p) failed, error 0x%lx\n",
|
|
|
|
hInputDesktop, GetLastError());
|
|
|
|
}
|
|
|
|
CloseDesktop(hInputDesktop);
|
|
|
|
|
|
|
|
if (bSuccess && (wcscmp(DesktopName, pShutdownParams->DesktopName) != 0))
|
|
|
|
{
|
|
|
|
TRACE("Input desktop has changed: '%S' --> '%S'\n",
|
|
|
|
pShutdownParams->DesktopName, DesktopName);
|
|
|
|
|
|
|
|
/* Save the original dialog position to be restored later */
|
|
|
|
pShutdownParams->wpPos.length = sizeof(pShutdownParams->wpPos);
|
|
|
|
GetWindowPlacement(hwndDlg, &pShutdownParams->wpPos);
|
2018-04-28 16:14:53 +00:00
|
|
|
|
2020-10-03 23:31:31 +00:00
|
|
|
/* Close the dialog */
|
|
|
|
EndDialog(hwndDlg, IDCANCEL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the shutdown timeout */
|
2018-04-02 16:52:47 +00:00
|
|
|
if (pShutdownParams->dwTimeout < SECONDS_PER_DAY)
|
|
|
|
{
|
|
|
|
iSeconds = (INT)pShutdownParams->dwTimeout;
|
|
|
|
iHours = iSeconds / 3600;
|
|
|
|
iSeconds -= iHours * 3600;
|
|
|
|
iMinutes = iSeconds / 60;
|
|
|
|
iSeconds -= iMinutes * 60;
|
|
|
|
|
2018-04-29 15:09:37 +00:00
|
|
|
LoadStringW(hAppInstance, IDS_TIMEOUTSHORTFORMAT, szFormatBuffer, ARRAYSIZE(szFormatBuffer));
|
|
|
|
swprintf(szBuffer, szFormatBuffer, iHours, iMinutes, iSeconds);
|
2018-04-02 16:52:47 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
iDays = (INT)(pShutdownParams->dwTimeout / SECONDS_PER_DAY);
|
2018-04-29 15:09:37 +00:00
|
|
|
|
|
|
|
LoadStringW(hAppInstance, IDS_TIMEOUTLONGFORMAT, szFormatBuffer, ARRAYSIZE(szFormatBuffer));
|
|
|
|
swprintf(szBuffer, szFormatBuffer, iDays);
|
2018-04-02 16:52:47 +00:00
|
|
|
}
|
2018-04-01 23:37:50 +00:00
|
|
|
|
2018-04-02 11:33:41 +00:00
|
|
|
SetDlgItemTextW(hwndDlg, IDC_SYSSHUTDOWNTIMELEFT, szBuffer);
|
2018-04-01 23:37:50 +00:00
|
|
|
|
|
|
|
if (pShutdownParams->dwTimeout == 0)
|
|
|
|
{
|
2020-10-03 23:31:31 +00:00
|
|
|
/* Close the dialog and let the shutdown thread perform the system shutdown */
|
2018-04-28 16:14:53 +00:00
|
|
|
EndDialog(hwndDlg, 0);
|
|
|
|
return;
|
2018-04-01 23:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pShutdownParams->dwTimeout--;
|
|
|
|
}
|
|
|
|
|
2018-04-01 22:38:18 +00:00
|
|
|
static
|
|
|
|
INT_PTR
|
|
|
|
CALLBACK
|
2018-04-01 23:37:50 +00:00
|
|
|
ShutdownDialogProc(
|
2020-10-03 23:01:46 +00:00
|
|
|
IN HWND hwndDlg,
|
|
|
|
IN UINT uMsg,
|
|
|
|
IN WPARAM wParam,
|
|
|
|
IN LPARAM lParam)
|
2018-04-01 22:38:18 +00:00
|
|
|
{
|
2018-04-01 23:37:50 +00:00
|
|
|
PSYS_SHUTDOWN_PARAMS pShutdownParams;
|
|
|
|
|
2020-10-03 23:31:31 +00:00
|
|
|
pShutdownParams = (PSYS_SHUTDOWN_PARAMS)GetWindowLongPtrW(hwndDlg, DWLP_USER);
|
2018-04-01 23:37:50 +00:00
|
|
|
|
2018-04-01 22:38:18 +00:00
|
|
|
switch (uMsg)
|
|
|
|
{
|
|
|
|
case WM_INITDIALOG:
|
2018-04-28 16:14:53 +00:00
|
|
|
{
|
2018-04-01 23:37:50 +00:00
|
|
|
pShutdownParams = (PSYS_SHUTDOWN_PARAMS)lParam;
|
2020-10-03 23:31:31 +00:00
|
|
|
SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)pShutdownParams);
|
2018-04-01 23:37:50 +00:00
|
|
|
|
2020-10-03 23:31:31 +00:00
|
|
|
/* Display the shutdown message */
|
2018-04-02 10:47:15 +00:00
|
|
|
if (pShutdownParams->pszMessage)
|
2018-04-01 22:38:18 +00:00
|
|
|
{
|
|
|
|
SetDlgItemTextW(hwndDlg,
|
2018-04-02 11:33:41 +00:00
|
|
|
IDC_SYSSHUTDOWNMESSAGE,
|
2018-04-02 10:47:15 +00:00
|
|
|
pShutdownParams->pszMessage);
|
2018-04-01 22:38:18 +00:00
|
|
|
}
|
2018-04-02 10:47:15 +00:00
|
|
|
|
2020-10-03 23:31:31 +00:00
|
|
|
/* Remove the Close menu item */
|
2018-04-28 16:14:53 +00:00
|
|
|
DeleteMenu(GetSystemMenu(hwndDlg, FALSE), SC_CLOSE, MF_BYCOMMAND);
|
2018-04-02 10:47:15 +00:00
|
|
|
|
2020-10-03 23:31:31 +00:00
|
|
|
/* Position the window (initial position, or restore from old) */
|
|
|
|
if (pShutdownParams->wpPos.length == sizeof(pShutdownParams->wpPos))
|
|
|
|
SetWindowPlacement(hwndDlg, &pShutdownParams->wpPos);
|
|
|
|
|
|
|
|
SetWindowPos(hwndDlg, HWND_TOPMOST, 0, 0, 0, 0,
|
|
|
|
SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
|
|
|
|
|
|
|
|
/* Initialize the timer */
|
|
|
|
PostMessageW(hwndDlg, WM_TIMER, 0, 0);
|
2018-04-02 10:47:15 +00:00
|
|
|
SetTimer(hwndDlg, SHUTDOWN_TIMER_ID, 1000, NULL);
|
2018-04-01 23:37:50 +00:00
|
|
|
break;
|
2018-04-28 16:14:53 +00:00
|
|
|
}
|
2018-04-01 23:37:50 +00:00
|
|
|
|
2018-04-28 16:14:53 +00:00
|
|
|
/* NOTE: Do not handle WM_CLOSE */
|
|
|
|
case WM_DESTROY:
|
2018-04-02 10:47:15 +00:00
|
|
|
KillTimer(hwndDlg, SHUTDOWN_TIMER_ID);
|
2018-04-01 23:37:50 +00:00
|
|
|
break;
|
|
|
|
|
2018-04-01 22:38:18 +00:00
|
|
|
case WM_TIMER:
|
2018-04-01 23:37:50 +00:00
|
|
|
OnTimer(hwndDlg, pShutdownParams);
|
|
|
|
break;
|
|
|
|
|
2018-04-01 22:38:18 +00:00
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
2018-04-01 23:37:50 +00:00
|
|
|
|
2018-04-01 22:38:18 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
DWORD
|
|
|
|
WINAPI
|
2018-04-01 23:37:50 +00:00
|
|
|
InitiateSystemShutdownThread(
|
2020-10-03 23:01:46 +00:00
|
|
|
IN LPVOID lpParameter)
|
2018-04-01 22:38:18 +00:00
|
|
|
{
|
2018-04-01 23:37:50 +00:00
|
|
|
PSYS_SHUTDOWN_PARAMS pShutdownParams;
|
2020-10-03 23:31:31 +00:00
|
|
|
HDESK hInputDesktop;
|
|
|
|
DWORD dwSize;
|
|
|
|
INT_PTR res;
|
2018-04-01 23:37:50 +00:00
|
|
|
|
|
|
|
pShutdownParams = (PSYS_SHUTDOWN_PARAMS)lpParameter;
|
|
|
|
|
2020-10-03 23:31:31 +00:00
|
|
|
/* Default to initial dialog position */
|
|
|
|
pShutdownParams->wpPos.length = 0;
|
|
|
|
|
|
|
|
/* Continuously display the shutdown dialog on the current input desktop */
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
/* Retrieve the current input desktop */
|
|
|
|
hInputDesktop = OpenInputDesktop(0, FALSE, GENERIC_ALL);
|
|
|
|
if (!hInputDesktop)
|
|
|
|
{
|
|
|
|
/* No input desktop on the current WinSta0, just shut down */
|
|
|
|
ERR("OpenInputDesktop() failed, error 0x%lx\n", GetLastError());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remember it for checking desktop changes later */
|
|
|
|
pShutdownParams->hShutdownDesk = hInputDesktop;
|
|
|
|
if (!GetUserObjectInformationW(pShutdownParams->hShutdownDesk,
|
|
|
|
UOI_NAME,
|
|
|
|
pShutdownParams->DesktopName,
|
|
|
|
sizeof(pShutdownParams->DesktopName),
|
|
|
|
&dwSize))
|
|
|
|
{
|
|
|
|
ERR("GetUserObjectInformationW(0x%p) failed, error 0x%lx\n",
|
|
|
|
pShutdownParams->hShutdownDesk, GetLastError());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Assign the desktop to the current thread */
|
|
|
|
SetThreadDesktop(hInputDesktop);
|
|
|
|
|
|
|
|
/* Display the shutdown dialog on the current input desktop */
|
|
|
|
res = DialogBoxParamW(hAppInstance,
|
|
|
|
MAKEINTRESOURCEW(IDD_SYSSHUTDOWN),
|
|
|
|
NULL,
|
|
|
|
ShutdownDialogProc,
|
|
|
|
(LPARAM)pShutdownParams);
|
|
|
|
|
|
|
|
/* Close the desktop */
|
|
|
|
CloseDesktop(hInputDesktop);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check why the dialog has been closed.
|
|
|
|
*
|
|
|
|
* - If it failed to be created (returned -1), don't care about
|
|
|
|
* re-creating it, and proceed directly to shutdown.
|
|
|
|
*
|
|
|
|
* - If it closed unexpectedly (returned != 1), check whether a
|
|
|
|
* shutdown is in progress. If the shutdown has been cancelled,
|
|
|
|
* just bail out; if a shutdown is in progress and the timeout
|
|
|
|
* is 0, bail out and proceed to shutdown.
|
|
|
|
*
|
|
|
|
* - If the dialog has closed because the input desktop changed,
|
|
|
|
* loop again and recreate it on the new desktop.
|
|
|
|
*/
|
|
|
|
if ((res == -1) || (res != IDCANCEL) ||
|
|
|
|
!(pShutdownParams->bShuttingDown && (pShutdownParams->dwTimeout > 0)))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reset dialog information */
|
|
|
|
pShutdownParams->hShutdownDesk = NULL;
|
|
|
|
ZeroMemory(&pShutdownParams->DesktopName, sizeof(pShutdownParams->DesktopName));
|
|
|
|
ZeroMemory(&pShutdownParams->wpPos, sizeof(pShutdownParams->wpPos));
|
2018-04-01 23:37:50 +00:00
|
|
|
|
2018-04-02 10:47:15 +00:00
|
|
|
if (pShutdownParams->pszMessage)
|
2018-04-01 22:38:18 +00:00
|
|
|
{
|
2018-04-02 10:47:15 +00:00
|
|
|
HeapFree(GetProcessHeap(), 0, pShutdownParams->pszMessage);
|
|
|
|
pShutdownParams->pszMessage = NULL;
|
2018-04-01 22:38:18 +00:00
|
|
|
}
|
2018-04-02 10:47:15 +00:00
|
|
|
|
2020-10-03 23:31:31 +00:00
|
|
|
if (pShutdownParams->bShuttingDown)
|
|
|
|
{
|
|
|
|
/* Perform the system shutdown */
|
|
|
|
if (DoSystemShutdown(pShutdownParams))
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
else
|
|
|
|
return GetLastError();
|
|
|
|
}
|
2018-04-01 23:37:50 +00:00
|
|
|
|
2018-04-28 16:14:53 +00:00
|
|
|
pShutdownParams->bShuttingDown = FALSE;
|
2020-10-03 23:31:31 +00:00
|
|
|
return ERROR_SUCCESS;
|
2018-04-01 22:38:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
|
|
TerminateSystemShutdown(VOID)
|
|
|
|
{
|
2018-04-28 16:14:53 +00:00
|
|
|
if (_InterlockedCompareExchange8((volatile char*)&g_ShutdownParams.bShuttingDown, FALSE, TRUE) == FALSE)
|
2018-04-01 22:38:18 +00:00
|
|
|
return ERROR_NO_SHUTDOWN_IN_PROGRESS;
|
2018-04-01 23:37:50 +00:00
|
|
|
|
2018-04-28 16:14:53 +00:00
|
|
|
return ERROR_SUCCESS;
|
2018-04-01 22:38:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
|
|
StartSystemShutdown(
|
2020-10-03 23:01:46 +00:00
|
|
|
IN PUNICODE_STRING pMessage,
|
|
|
|
IN ULONG dwTimeout,
|
|
|
|
IN BOOLEAN bForceAppsClosed,
|
|
|
|
IN BOOLEAN bRebootAfterShutdown,
|
|
|
|
IN ULONG dwReason)
|
2018-04-01 22:38:18 +00:00
|
|
|
{
|
|
|
|
HANDLE hThread;
|
|
|
|
|
2018-04-02 16:52:47 +00:00
|
|
|
/* Fail if the timeout is 10 years or more */
|
|
|
|
if (dwTimeout >= SECONDS_PER_DECADE)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
2018-04-01 23:37:50 +00:00
|
|
|
if (_InterlockedCompareExchange8((volatile char*)&g_ShutdownParams.bShuttingDown, TRUE, FALSE) == TRUE)
|
2018-04-01 22:38:18 +00:00
|
|
|
return ERROR_SHUTDOWN_IN_PROGRESS;
|
2018-04-01 23:37:50 +00:00
|
|
|
|
2020-10-03 23:31:31 +00:00
|
|
|
if ((dwTimeout != 0) && pMessage && pMessage->Length && pMessage->Buffer)
|
2018-04-01 22:38:18 +00:00
|
|
|
{
|
2018-04-02 10:47:15 +00:00
|
|
|
g_ShutdownParams.pszMessage = HeapAlloc(GetProcessHeap(),
|
|
|
|
HEAP_ZERO_MEMORY,
|
2020-10-03 23:01:46 +00:00
|
|
|
pMessage->Length + sizeof(UNICODE_NULL));
|
2018-04-02 10:47:15 +00:00
|
|
|
if (g_ShutdownParams.pszMessage == NULL)
|
2018-04-01 22:38:18 +00:00
|
|
|
{
|
2018-04-01 23:37:50 +00:00
|
|
|
g_ShutdownParams.bShuttingDown = FALSE;
|
2018-04-01 22:38:18 +00:00
|
|
|
return GetLastError();
|
|
|
|
}
|
2018-04-01 23:37:50 +00:00
|
|
|
|
2018-04-02 10:47:15 +00:00
|
|
|
wcsncpy(g_ShutdownParams.pszMessage,
|
2020-10-03 23:01:46 +00:00
|
|
|
pMessage->Buffer,
|
|
|
|
pMessage->Length / sizeof(WCHAR));
|
2018-04-01 22:38:18 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-04-02 10:47:15 +00:00
|
|
|
g_ShutdownParams.pszMessage = NULL;
|
2018-04-01 22:38:18 +00:00
|
|
|
}
|
2018-04-01 23:37:50 +00:00
|
|
|
|
2018-04-01 22:38:18 +00:00
|
|
|
g_ShutdownParams.dwTimeout = dwTimeout;
|
|
|
|
g_ShutdownParams.bForceAppsClosed = bForceAppsClosed;
|
|
|
|
g_ShutdownParams.bRebootAfterShutdown = bRebootAfterShutdown;
|
|
|
|
g_ShutdownParams.dwReason = dwReason;
|
2018-04-01 23:37:50 +00:00
|
|
|
|
2020-10-03 23:01:46 +00:00
|
|
|
/* If dwTimeout is zero perform an immediate system shutdown,
|
|
|
|
* otherwise display the countdown shutdown dialog. */
|
2018-04-28 16:14:53 +00:00
|
|
|
if (g_ShutdownParams.dwTimeout == 0)
|
2018-04-01 22:38:18 +00:00
|
|
|
{
|
2018-04-28 16:14:53 +00:00
|
|
|
if (DoSystemShutdown(&g_ShutdownParams))
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-10-03 23:01:46 +00:00
|
|
|
hThread = CreateThread(NULL, 0, InitiateSystemShutdownThread,
|
|
|
|
&g_ShutdownParams, 0, NULL);
|
2018-04-28 16:14:53 +00:00
|
|
|
if (hThread)
|
|
|
|
{
|
|
|
|
CloseHandle(hThread);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2018-04-01 22:38:18 +00:00
|
|
|
}
|
2018-04-01 23:37:50 +00:00
|
|
|
|
2018-04-02 10:47:15 +00:00
|
|
|
if (g_ShutdownParams.pszMessage)
|
2018-04-01 22:38:18 +00:00
|
|
|
{
|
2018-04-02 10:47:15 +00:00
|
|
|
HeapFree(GetProcessHeap(), 0, g_ShutdownParams.pszMessage);
|
|
|
|
g_ShutdownParams.pszMessage = NULL;
|
2018-04-01 22:38:18 +00:00
|
|
|
}
|
2018-04-01 23:37:50 +00:00
|
|
|
|
|
|
|
g_ShutdownParams.bShuttingDown = FALSE;
|
|
|
|
return GetLastError();
|
2018-04-01 22:38:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|