diff --git a/ShutdownWithUpdates/INFO.txt b/ShutdownWithUpdates/INFO.txt
new file mode 100644
index 0000000..c10bfff
--- /dev/null
+++ b/ShutdownWithUpdates/INFO.txt
@@ -0,0 +1,116 @@
+Utility To Install Pre-Downloaded Windows Updates & Shutdown/Reboot
+v.1.2.1.0
+Copyright (c) 2016-2018 by www.dennisbabkin.com. All rights reserved.
+(Windows Vista/7/8/8.1/10)
+
+LAST MODIFIED: April 8, 2019
+
+
+DESCRIPTION:
+================
+Utility that initiates installation of pre-downloaded updates on the Windows system & reboots,
+or shuts it down. Note that if Windows updates were not downloaded prior to calling this utility,
+the OS will simply perform the power operation.
+
+Windows 10: Updates will be installed during a reboot regardless of the options described below.
+ Some major updates may require user interaction to proceed.
+
+Additional: Major updates, such as Windows Feature Updates, may require user interaction in despite
+ of the options specified by this tool. Such requirement is stipulated by Microsoft and
+ cannot be overridden by this tool.
+
+
+Usage: ShutdownWithUpdates [/s | /r | /hs | /g | /a | /?] [/f] [/v] [/nu]
+ [/m \\computer] [/t x] [/c "msg"] [/d [p|u:]xx:yy]
+
+ /s Install updates & shut down computer.
+ (Updates must be already downloaded on computer being shut down.)
+ /r Install updates & reboot computer.
+ (Updates must be already downloaded on computer being rebooted.)
+ /hs Install updates & initiate hybrid shut-down of computer. (Windows 8,10)
+ (Updates must be already downloaded on computer being shut down.)
+ /g Install updates & reboot computer & restart registered applications.
+ (Updates must be already downloaded on computer being rebooted.)
+ /abo Go to advanced boot options menu. (Windows 8,10)
+ (Pre-Windows 10: Updates will not be installed.)
+ /a Abort previous shut-down/rebooting.
+ (Can be used only during previous time-out period.)
+ /? Show command line help.
+ /f Use forced action.
+ WARNING: May result in the loss of unsaved data on target computer!
+ /v Show user confirmation before proceeding.
+ (Local computer only. It is shown before time-out is initiated.)
+ /nu Not to install updates.
+ (Windows 10: This option is not supported.)
+ /m \\computer Specify target/remote computer.
+ /t x Set time-out before performing action to x seconds.
+ (Valid range is 0-315360000, or 10 yrs, with a default of 0.)
+ /c "msg" Message to be displayed in the interactive shutdown dialog box.
+ (Maximum of 512 characters is allowed.)
+ /d [p|u:]xx:yy Reason for shut-down or rebooting (used for logging):
+ p if action was planned.
+ u if action was user-defined.
+ (If neither p or u is used, assumes unplanned.)
+ xx = major reason number (less than 65536.)
+ yy = minor reason number (greater than 65536.)
+ (Reason numbers can be decimal or hex if begin with 0x)
+ For major and minor reason values check "System Shutdown Reason Codes":
+ msdn.microsoft.com/en-us/library/windows/desktop/aa376885(v=vs.85).aspx
+
+
+Exit Codes:
+ 0 if success.
+ -1 if general failure in the module.
+ Other if error, will contain "System Error Code". For details check:
+ msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
+
+
+Examples:
+(1) Install updates and reboot local computer without a delay:
+ (Fail if unsaved user data on computer.)
+
+ ShutdownWithUpdates /r
+
+(2) Install updates and shut down local computer after 30 sec delay:
+ (Force applications with unsaved data to close & lose data! Show message.)
+
+ ShutdownWithUpdates /s /f /t 30 /c "Forced shut-down in 30 sec!"
+
+(3) Do not install updates and reboot remote computer after a 20 sec delay:
+ (Not supported under Windows 10.)
+ (Fail if unsaved user data on remote computer.)
+ (Specify reason as planned, application issue, installation.)
+
+ ShutdownWithUpdates /r /nu /m \\MYSERVER /t 20 /d p:0x00040000:0x00000002
+
+
+
+** This is an Open Source project. **
+ You can download its source code at:
+ https://github.com/dennisbabkin/ShutdownWithUpdates
+
+
+For feedback & bug reports go to:
+https://www.dennisbabkin.com/sfb/?what=info&name=ShutdownWithUpdates
+
+
+Thank you!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ShutdownWithUpdates/ShutdownWithUpdates.sln b/ShutdownWithUpdates/ShutdownWithUpdates.sln
new file mode 100644
index 0000000..1aab7e4
--- /dev/null
+++ b/ShutdownWithUpdates/ShutdownWithUpdates.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShutdownWithUpdates", "ShutdownWithUpdates\ShutdownWithUpdates.vcproj", "{73AFA8D4-A44E-41E9-925C-9BCEA5F6404A}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {73AFA8D4-A44E-41E9-925C-9BCEA5F6404A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {73AFA8D4-A44E-41E9-925C-9BCEA5F6404A}.Debug|Win32.Build.0 = Debug|Win32
+ {73AFA8D4-A44E-41E9-925C-9BCEA5F6404A}.Release|Win32.ActiveCfg = Release|Win32
+ {73AFA8D4-A44E-41E9-925C-9BCEA5F6404A}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/ShutdownWithUpdates/ShutdownWithUpdates/Main.cpp b/ShutdownWithUpdates/ShutdownWithUpdates/Main.cpp
new file mode 100644
index 0000000..d590e43
--- /dev/null
+++ b/ShutdownWithUpdates/ShutdownWithUpdates/Main.cpp
@@ -0,0 +1,1936 @@
+/*
+ * ShutdownWithUpdates
+ * "Utility To Install Pre-Downloaded Windows Updates & Shutdown/Reboot"
+ * Copyright (c) 2016-2019 www.dennisbabkin.com
+ *
+ * https://dennisbabkin.com/utilities/#ShutdownWithUpdates
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+#include "StdAfx.h"
+#include "Main.h"
+
+
+int CMain::doWork(int argc, _TCHAR* argv[])
+{
+ //RETURN:
+ // = See _tmain()
+ int nRes = ERROR_GEN_FAILURE;
+
+ __try
+ {
+ nRes = doWork_RAW(argc, argv);
+ }
+ __except(1)
+ {
+ //Exception
+ nRes = -1;
+
+ _tprintf(L"FATAL ERROR: Contact developers: support@dennisbabkin.com\n");
+ }
+
+ return nRes;
+}
+
+int CMain::doWork_RAW(int argc, _TCHAR* argv[])
+{
+ //DO NOT CALL directly
+ //RETURN: = See doWork()
+ int nResOSErrCode = ERROR_GEN_FAILURE;
+
+ //Check if this file has a "mark of the web" stream attached to it & remove it
+ CheckForXP_SP2_FileBlockAndRemoveIt();
+
+
+
+ if(argc > 1)
+ {
+ //Check for arguments provided
+
+ BOOL bDoActions = FALSE; //TRUE to do power op actions
+
+ ACTIONS_INFO ai;
+
+ //See what version of Windows we're running on
+ OSVERSIONINFO osi;
+ osi.dwOSVersionInfoSize = sizeof(osi);
+ BOOL bGV = RTL_OS_VERSION::GetVersionEx2(&osi);
+
+ //Is it Windows 8 or later?
+ BOOL bWin8 = bGV && ((osi.dwMajorVersion == 6 && osi.dwMinorVersion >= 2) || osi.dwMajorVersion > 6);
+
+
+ //Go through command line arguments
+ for(int c = 1; c < argc; c++)
+ {
+ //Identify a command
+ LPCTSTR pStrCmd = argv[c];
+ CMD_TYPE cmdType = getCommandType(pStrCmd);
+
+ if(cmdType == CTP_SHOW_HELP)
+ {
+ //Show help -- and don't do anything else
+ bDoActions = FALSE;
+ nResOSErrCode = NO_ERROR;
+
+ outputMainLogo();
+ ShowHelpInfo();
+
+ break;
+ }
+ else if(cmdType == CTP_SHUT_DOWN)
+ {
+ //Shut-down
+ if(ai.pwrAction == PWR_OP_NONE)
+ {
+ bDoActions = TRUE;
+ ai.pwrAction = PWR_OP_SHUT_DOWN;
+ }
+ else
+ {
+ //Error
+ _tprintf(L"ERROR: Power action is already defined before parameter: %s\n", pStrCmd);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_DATATYPE_MISMATCH;
+ break;
+ }
+ }
+ else if(cmdType == CTP_REBOOT)
+ {
+ //Reboot
+ if(ai.pwrAction == PWR_OP_NONE)
+ {
+ bDoActions = TRUE;
+ ai.pwrAction = PWR_OP_REBOOT;
+ }
+ else
+ {
+ //Error
+ _tprintf(L"ERROR: Power action is already defined before parameter: %s\n", pStrCmd);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_DATATYPE_MISMATCH;
+ break;
+ }
+ }
+ else if(cmdType == CTP_HYBRID_SHUT_DOWN)
+ {
+ //Hybrid shut-down
+
+ //Parameter only supported on Windows 8 and later OS
+ if(bWin8)
+ {
+ if(ai.pwrAction == PWR_OP_NONE)
+ {
+ bDoActions = TRUE;
+ ai.pwrAction = PWR_OP_HYBRID_SHUT_DOWN;
+ }
+ else
+ {
+ //Error
+ _tprintf(L"ERROR: Power action is already defined before parameter: %s\n", pStrCmd);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_DATATYPE_MISMATCH;
+ break;
+ }
+ }
+ else
+ {
+ //Error
+ _tprintf(L"ERROR: Parameter not supported on this OS: %s\n", pStrCmd);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_NOT_SUPPORTED;
+ break;
+ }
+ }
+ else if(cmdType == CTP_REBOOT_WITH_APP_RESTART)
+ {
+ //Reboot & restart apps
+ if(ai.pwrAction == PWR_OP_NONE)
+ {
+ bDoActions = TRUE;
+ ai.pwrAction = PWR_OP_REBOOT_WITH_APP_RESTART;
+ }
+ else
+ {
+ //Error
+ _tprintf(L"ERROR: Power action is already defined before parameter: %s\n", pStrCmd);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_DATATYPE_MISMATCH;
+ break;
+ }
+ }
+ else if(cmdType == CTP_ADVANCED_BOOT_MENU)
+ {
+ //Advanced boot options menu
+
+ //Parameter only supported on Windows 8 and later OS
+ if(bWin8)
+ {
+ if(ai.pwrAction == PWR_OP_NONE)
+ {
+ bDoActions = TRUE;
+ ai.pwrAction = PWR_OP_ADVANCED_BOOT_OPTIONS_MENU;
+ }
+ else
+ {
+ //Error
+ _tprintf(L"ERROR: Power action is already defined before parameter: %s\n", pStrCmd);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_DATATYPE_MISMATCH;
+ break;
+ }
+ }
+ else
+ {
+ //Error
+ _tprintf(L"ERROR: Parameter not supported on this OS: %s\n", pStrCmd);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_NOT_SUPPORTED;
+ break;
+ }
+ }
+ else if(cmdType == CTP_ABORT_SHUT_DOWN)
+ {
+ //Abort previous power action
+ if(ai.pwrAction == PWR_OP_NONE)
+ {
+ bDoActions = TRUE;
+ ai.pwrAction = PWR_OP_ABORT_SHUT_DOWN;
+ }
+ else
+ {
+ //Error
+ _tprintf(L"ERROR: Power action is already defined before parameter: %s\n", pStrCmd);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_DATATYPE_MISMATCH;
+ break;
+ }
+ }
+ else if(cmdType == CTP_FORCED)
+ {
+ //Forced
+ ai.bForced = TRUE;
+ }
+ else if(cmdType == CTP_VERBOSE)
+ {
+ //Verbose
+ ai.bVerbose = TRUE;
+ }
+ else if(cmdType == CTP_NO_UPDATES)
+ {
+ //No updates
+ ai.bNoUpdates = TRUE;
+ }
+ else if(cmdType == CTP_REMOTE_COMPUTER)
+ {
+ //Remove computer
+ if(c + 1 < argc)
+ {
+ //Get next param
+ ai.pStrRemoteCompName = argv[++c];
+ }
+ else
+ {
+ //Error
+ _tprintf(L"ERROR: Remote computer name is required for parameter: %s\n", pStrCmd);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_DATATYPE_MISMATCH;
+ break;
+ }
+ }
+ else if(cmdType == CTP_TIMEOUT)
+ {
+ //Timeout
+ if(c + 1 < argc)
+ {
+ //Get next param as timeout value
+ int nValTO = 0;
+ LPCTSTR pStrParam = argv[++c];
+ if(CMain::parseDecimalInt32(pStrParam, &nValTO))
+ {
+ if(nValTO >= 0)
+ {
+ //Use it
+ ai.nTimeoutSec = nValTO;
+ }
+ else
+ {
+ //Error
+ _tprintf(L"ERROR: Invalid time-out value (%s) for parameter: %s\n", pStrParam, pStrCmd);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_DATATYPE_MISMATCH;
+ break;
+ }
+ }
+ else
+ {
+ //Error
+ _tprintf(L"ERROR: Failed to parse time-out value for parameter: %s\n", pStrCmd);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_DATATYPE_MISMATCH;
+ break;
+ }
+ }
+ else
+ {
+ //Error
+ _tprintf(L"ERROR: Time-out value in seconds is required for parameter: %s\n", pStrCmd);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_DATATYPE_MISMATCH;
+ break;
+ }
+ }
+ else if(cmdType == CTP_SHOW_MESSAGE)
+ {
+ //Message
+ if(c + 1 < argc)
+ {
+ //Get next param
+ ai.pStrMessage = argv[++c];
+ }
+ else
+ {
+ //Error
+ _tprintf(L"ERROR: Message text is required for parameter: %s\n", pStrCmd);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_DATATYPE_MISMATCH;
+ break;
+ }
+ }
+ else if(cmdType == CTP_REASON)
+ {
+ //Get reason that follows
+ if(c + 1 < argc)
+ {
+ //Get next param
+ LPCTSTR pStrParam = argv[++c];
+
+ if(!CMain::parseReasonParam(pStrParam, &ai.dwReason))
+ {
+ //Failed to parse
+ _tprintf(L"ERROR: Failed to parse shut-down/rebooting reason parameter: %s\n", pStrParam);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_DATATYPE_MISMATCH;
+ break;
+ }
+ }
+ else
+ {
+ //Error
+ _tprintf(L"ERROR: Shut-down/rebooting reason value is required for parameter: %s\n", pStrCmd);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_DATATYPE_MISMATCH;
+ break;
+ }
+ }
+ else if(cmdType == CTP_NONE)
+ {
+ //Not a command
+ if(pStrCmd[0])
+ {
+ //Show warning
+ _tprintf(L"WARNING: Unexpected argument: %s\n", pStrCmd);
+ }
+ else
+ ASSERT(NULL);
+ }
+ else if(cmdType == CTP_UNKNOWN)
+ {
+ //Unknown command
+ if(pStrCmd[0])
+ {
+ //Show warning
+ _tprintf(L"WARNING: Unknown command: %s\n", pStrCmd);
+ }
+ else
+ ASSERT(NULL);
+ }
+ else
+ {
+ //Error
+ ASSERT(NULL);
+
+ _tprintf(L"ERROR: Bad command: %s\n", pStrCmd);
+
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_UNSUPPORTED_TYPE;
+ break;
+ }
+ }
+
+
+ //Are we doing the power op
+ if(bDoActions)
+ {
+ //Do we need to ask user?
+ if(ai.bVerbose)
+ {
+ //Need to ask by showing UI
+ // = 1 if we're allowed to continue
+ // = 0 if user canceled (and we're not allowed to continue)
+ // = -1 if error (check GetLastError() for info) -- we're not allowed to continue
+ int nResUI = ShowUserConfirmation(&ai);
+ if(nResUI == 0)
+ {
+ //User canceled
+ bDoActions = FALSE;
+ nResOSErrCode = ERROR_CANCELLED;
+ }
+ else if(nResUI != 1)
+ {
+ //Error
+ bDoActions = FALSE;
+ nResOSErrCode = ::GetLastError();
+ }
+ }
+
+ //Still allowed
+ if(bDoActions)
+ {
+ //Perform actions
+ nResOSErrCode = doActions(&ai);
+
+ }
+ }
+ else
+ {
+ //Did we get an error?
+ if(nResOSErrCode == ERROR_GEN_FAILURE)
+ {
+ //Not enough parameters
+#ifndef ERROR_INVALID_FIELD_IN_PARAMETER_LIST
+#define ERROR_INVALID_FIELD_IN_PARAMETER_LIST 328
+#endif
+ nResOSErrCode = ERROR_INVALID_FIELD_IN_PARAMETER_LIST;
+ _tprintf(L"ERROR: Not enough parameters\n");
+ }
+ }
+ }
+ else
+ {
+ //No arguments
+ outputMainLogo();
+
+ //Show how to get to help
+ _tprintf(L"Use -? to see command line options.\n");
+
+ nResOSErrCode = ERROR_EMPTY;
+ }
+
+ return nResOSErrCode;
+}
+
+
+CMD_TYPE CMain::getCommandType(LPCTSTR pStrCmd)
+{
+ //Determine type of command in 'pStrCmd'
+ //RETURN:
+ // = Command type
+ CMD_TYPE res = CTP_NONE;
+
+ if(pStrCmd &&
+ pStrCmd[0])
+ {
+ TCHAR z = pStrCmd[0];
+ if(z == '/' ||
+ z == '\\' ||
+ z == '-')
+ {
+ pStrCmd++;
+
+ //Assume Unidentified
+ res = CTP_UNKNOWN;
+
+ static CMD_STR cmds[] = {
+ {CTP_SHOW_HELP, L"?"},
+ {CTP_SHOW_HELP, L"help"},
+ {CTP_SHUT_DOWN, L"s"},
+ {CTP_REBOOT, L"r"},
+ {CTP_HYBRID_SHUT_DOWN, L"hs"},
+ {CTP_REBOOT_WITH_APP_RESTART, L"g"},
+ {CTP_ABORT_SHUT_DOWN, L"a"},
+ {CTP_FORCED, L"f"},
+ {CTP_VERBOSE, L"v"},
+ {CTP_NO_UPDATES, L"nu"},
+ {CTP_REMOTE_COMPUTER, L"m"},
+ {CTP_TIMEOUT, L"t"},
+ {CTP_SHOW_MESSAGE, L"c"},
+ {CTP_REASON, L"d"},
+ {CTP_ADVANCED_BOOT_MENU, L"abo"},
+ };
+
+ for(int c = 0; c < SIZEOF(cmds); c++)
+ {
+ if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, pStrCmd, -1, cmds[c].pStrCmd, -1) == CSTR_EQUAL)
+ {
+ //Got a match
+ res = cmds[c].cmdID;
+ break;
+ }
+ }
+
+ }
+ }
+
+ return res;
+}
+
+int CMain::CheckForXP_SP2_FileBlockAndRemoveIt()
+{
+ //Checks if the "mark of the web" stream is on the 'this' file & removes it if so
+ //(It will be there if file was downloaded from the Internet, or from another computer)
+ //RETURN:
+ // = 0 if not such block was found
+ // = 1 if block was found (and removed if 'bRemoveIt' == TRUE)
+ // = 2 if block was found, but COULD NOT remove it (if 'bRemoveIt' == TRUE)
+ // = -1 if error
+ // = -2 if not supported
+
+ BOOL bRemoveIt = TRUE;
+
+ //No, get current file
+ TCHAR strFilePath[MAX_PATH * 4];
+ strFilePath[0] = 0;
+ if(!::GetModuleFileName(NULL, strFilePath, SIZEOF(strFilePath)))
+ return -1;
+
+ strFilePath[SIZEOF(strFilePath) - 1] = 0;
+
+
+ //Load API needed for the process
+ NTQUERYINFORMATIONFILE pfnNtQueryInformationFile;
+ (FARPROC&)pfnNtQueryInformationFile = ::GetProcAddress(::GetModuleHandle(_T("ntdll.dll")), "NtQueryInformationFile");
+ if(!pfnNtQueryInformationFile)
+ return -2;
+
+ //Obtain SE_BACKUP_NAME privilege (required for opening a directory)
+ HANDLE hToken = NULL;
+ TOKEN_PRIVILEGES tp;
+ if(OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
+ {
+ if(LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &tp.Privileges[0].Luid))
+ {
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ if(AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
+ {
+ //All done
+ }
+ }
+ }
+ if(hToken)
+ ::CloseHandle(hToken);
+
+ //Now open the file
+ HANDLE hFile = ::CreateFile(strFilePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if(hFile == INVALID_HANDLE_VALUE)
+ return -1;
+
+ //Get stream information block (assume memory size in the beginning)
+ LPBYTE pInfoBlock = NULL;
+ ULONG uInfoBlockSize = 0;
+ IO_STATUS_BLOCK ioStatus;
+ NTSTATUS status;
+ do
+ {
+ uInfoBlockSize += 16 * 1024;
+ if(pInfoBlock)
+ delete [] pInfoBlock;
+
+ pInfoBlock = new BYTE [uInfoBlockSize];
+ ((PFILE_STREAM_INFORMATION)pInfoBlock)->StreamNameLength = 0;
+ status = pfnNtQueryInformationFile(hFile, &ioStatus, (LPVOID)pInfoBlock, uInfoBlockSize, FileStreamInformation);
+ }
+ while(status == STATUS_BUFFER_OVERFLOW);
+
+ //Close file handle
+ ::CloseHandle(hFile);
+
+ //Go through stream info and look for our stream
+ int nRet = 0;
+ WCHAR wszStreamName[MAX_PATH];
+ TCHAR szStreamName[MAX_PATH];
+ PFILE_STREAM_INFORMATION pStreamInfo = (PFILE_STREAM_INFORMATION)(LPVOID)pInfoBlock;
+ for(;;)
+ {
+ // Check if stream info block is empty (directory may have no stream)
+ if(pStreamInfo->StreamNameLength == 0)
+ break;
+
+ // Get stream name
+ memcpy(wszStreamName, pStreamInfo->StreamName, pStreamInfo->StreamNameLength);
+ wszStreamName[pStreamInfo->StreamNameLength / sizeof(WCHAR)] = L'\0';
+
+ // Remove attribute tag and convert to char
+ LPWSTR pTag = wcsstr(wszStreamName, L":$DATA");
+ if (pTag)
+ *pTag = L'\0';
+ ::StringCchCopy(szStreamName, SIZEOF(szStreamName), (const TCHAR*)wszStreamName);
+
+ //Is it the name we're looking for?
+ if (lstrcmpi(szStreamName, _T(":Zone.Identifier")) == 0)
+ {
+ //Our Named stream?
+ nRet = 1;
+
+ //Do we need to remove it?
+ if(!bRemoveIt)
+ break;
+
+ //Make file name for the stream
+ TCHAR strStreamFileName[MAX_PATH * 4];
+ strStreamFileName[0] = 0;
+ ::StringCchCopy(strStreamFileName, SIZEOF(strStreamFileName), strFilePath);
+ ::StringCchCat(strStreamFileName, SIZEOF(strStreamFileName), szStreamName);
+ strStreamFileName[SIZEOF(strStreamFileName) - 1] = 0;
+
+ //Delete this stream
+ hFile = ::CreateFile(strStreamFileName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+ OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ //Erased it
+ if(!::CloseHandle(hFile))
+ {
+ //Error removing
+ nRet = 2;
+ }
+ }
+ else
+ {
+ //Error removing
+ nRet = 2;
+ }
+ }
+
+ //Do we have more stream records?
+ if(pStreamInfo->NextEntryOffset == 0)
+ break;
+
+ //Go to the next one
+ pStreamInfo = (PFILE_STREAM_INFORMATION)((LPBYTE)pStreamInfo + pStreamInfo->NextEntryOffset);
+ }
+
+ //Free memory
+ if(pInfoBlock)
+ delete [] pInfoBlock;
+
+ return nRet;
+}
+
+
+
+void CMain::ShowHelpInfo()
+{
+ //Show help information
+
+ _tprintf(
+ L"Usage: ShutdownWithUpdates [/s | /r | /hs | /g | /a | /?] [/f] [/v] [/nu]\n"
+ L" [/m \\\\computer] [/t x] [/c \"msg\"] [/d [p|u:]xx:yy]\n"
+ L"\n"
+ L" /s Install updates & shut down computer.\n"
+ L" (Updates must be already downloaded on computer being shut down.)\n"
+ L" /r Install updates & reboot computer.\n"
+ L" (Updates must be already downloaded on computer being rebooted.)\n"
+ L" /hs Install updates & initiate hybrid shut-down of computer. (Windows 8,10)\n"
+ L" (Updates must be already downloaded on computer being shut down.)\n"
+ L" /g Install updates & reboot computer & restart registered applications.\n"
+ L" (Updates must be already downloaded on computer being rebooted.)\n"
+ L" /abo Go to advanced boot options menu. (Windows 8,10)\n"
+ L" (Pre-Windows 10: Updates will not be installed.)\n"
+ L" /a Abort previous shut-down/rebooting.\n"
+ L" (Can be used only during previous time-out period.)\n"
+ L" /? Show command line help.\n"
+ L" /f Use forced action.\n"
+ L" WARNING: May result in the loss of unsaved data on target computer!\n"
+ L" /v Show user confirmation before proceeding.\n"
+ L" (Local computer only. It is shown before time-out is initiated.)\n"
+ L" /nu Not to install updates.\n"
+ L" (Windows 10: This option is not supported.)\n"
+ L" /m \\\\computer Specify target/remote computer.\n"
+ L" /t x Set time-out before performing action to x seconds.\n"
+ L" (Valid range is 0-%d, or 10 yrs, with a default of 0.)\n"
+ L" /c \"msg\" Message to be displayed in the interactive shutdown dialog box.\n"
+ L" (Maximum of 512 characters is allowed.)\n"
+ L" /d [p|u:]xx:yy Reason for shut-down or rebooting (used for logging):\n"
+ L" p if action was planned.\n"
+ L" u if action was user-defined.\n"
+ L" (If neither p or u is used, assumes unplanned.)\n"
+ L" xx = major reason number (less than %d.)\n"
+ L" yy = minor reason number (greater than %d.)\n"
+ L" (Reason numbers can be decimal or hex if begin with 0x)\n"
+ L" For major and minor reason values check \"System Shutdown Reason Codes\":\n"
+ L" msdn.microsoft.com/en-us/library/windows/desktop/aa376885(v=vs.85).aspx\n"
+ L"\n"
+ L"Exit Codes:\n"
+ L" 0 if success.\n"
+ L" -1 if general failure in the module.\n"
+ L" Other if error, will contain \"System Error Code\". For details check:\n"
+ L" msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx\n"
+ L"\n"
+ L"Examples:\n"
+ L"(1) Install updates and reboot local computer without a delay:\n"
+ L" (Fail if unsaved user data on computer.)\n"
+ L"\n"
+ L" ShutdownWithUpdates /r\n"
+ L"\n"
+ L"(2) Install updates and shut down local computer after 30 sec delay:\n"
+ L" (Force applications with unsaved data to close & lose data! Show message.)\n"
+ L"\n"
+ L" ShutdownWithUpdates /s /f /t 30 /c \"Forced shut-down in 30 sec!\"\n"
+ L"\n"
+ L"(3) Do not install updates and reboot remote computer after a 20 sec delay:\n"
+ L" (Not supported under Windows 10.)\n"
+ L" (Fail if unsaved user data on remote computer.)\n"
+ L" (Specify reason as planned, application issue, installation.)\n"
+ L"\n"
+ L" ShutdownWithUpdates /r /nu /m \\\\MYSERVER /t 20 /d p:0x00040000:0x00000002\n"
+ L"\n"
+ L"\n"
+ L"** This is an Open Source project. **\n"
+ L" You can download its source code at:\n"
+ L" https://github.com/dennisbabkin/ShutdownWithUpdates\n"
+ L"\n"
+ ,
+
+ MAX_SHUTDOWN_TIMEOUT,
+ 0x10000,
+ 0x10000
+ );
+
+}
+
+
+int CMain::findCharInStrCaseSensitive(LPCTSTR pStr, TCHAR chSearch, int nIndBegin)
+{
+ //'nIndBegin' = 0-based index in 'pStr' to begin search from
+ //RETURN:
+ // = Index of 'chSearch' in 'pStr'
+ // = -1 if none
+ int nInd = -1;
+
+ if(pStr)
+ {
+ for(int i = nIndBegin;; i++)
+ {
+ TCHAR z = pStr[i];
+ if(z == 0)
+ {
+ //End of string
+ break;
+ }
+ else if(z == chSearch)
+ {
+ //Got it
+ nInd = i;
+ break;
+ }
+ }
+ }
+
+ return nInd;
+}
+
+
+BOOL CMain::parseReasonInt32(LPCTSTR pStr, int* pnOutVal)
+{
+ //'pStr' = can be signed 32-bit integer, as decimal or hex
+ //'pnOutVal' = if not NULL, Value read
+ //RETURN:
+ // = TRUE if read OK
+ BOOL bRes = FALSE;
+
+ int nV = 0;
+
+ //First assume hex
+ UINT nValHex = 0;
+ if(parseHexUInt32(pStr, &nValHex))
+ {
+ //Got it
+ nV = nValHex;
+ bRes = TRUE;
+ }
+ else
+ {
+ //Parse it as decimal
+ int nValDecimal = 0;
+ if(parseDecimalInt32(pStr, &nValDecimal))
+ {
+ //Got it
+ nV = nValDecimal;
+ bRes = TRUE;
+ }
+ }
+
+ if(pnOutVal)
+ *pnOutVal = nV;
+
+ return bRes;
+}
+
+BOOL CMain::parseDecimalInt32(LPCTSTR pStr, int* pnOutVal)
+{
+ //'pStr' = can be signed 32-bit integer
+ //'pnOutVal' = if not NULL, Value read
+ //RETURN:
+ // = TRUE if read OK
+ BOOL bRes = FALSE;
+
+ int nV = 0;
+
+ if(pStr &&
+ pStr[0])
+ {
+ int i = 0;
+
+ //Check for sign first
+ TCHAR chSign = pStr[0];
+ if(chSign == '+' ||
+ chSign == '-')
+ {
+ i++;
+ }
+
+ //Flag if we found at least one digit
+ BOOL bDigitFound = FALSE;
+
+ //See if it's valid
+ for(;; i++)
+ {
+ TCHAR z = pStr[i];
+ if(z == 0)
+ {
+ //End of line
+ if(bDigitFound)
+ {
+ //Scan it
+ int val = 0;
+ if(_stscanf_s(pStr, L"%d", &val) == 1)
+ {
+ //Done
+ nV = val;
+
+ bRes = TRUE;
+ }
+ }
+
+ break;
+ }
+ else if(z >= '0' && z <= '9')
+ {
+ //Found a digit
+ bDigitFound = TRUE;
+ }
+ else
+ {
+ //Something else -- wrong char
+ break;
+ }
+ }
+ }
+
+ if(pnOutVal)
+ *pnOutVal = nV;
+
+ return bRes;
+}
+
+
+BOOL CMain::parseHexUInt32(LPCTSTR pStr, UINT* pnOutVal)
+{
+ //'pStr' = can be unsigned 32-bit hex integer
+ //'pnOutVal' = if not NULL, Value read
+ //RETURN:
+ // = TRUE if read OK
+ BOOL bRes = FALSE;
+
+ UINT nV = 0;
+
+ if(pStr &&
+ pStr[0])
+ {
+ //Must begin with 0x
+ if(pStr[0] == '0')
+ {
+ if(pStr[1] == 'x')
+ {
+ //Flag if we found at least one digit
+ BOOL bDigitFound = FALSE;
+
+ //See if it's valid
+ for(int i = 2;; i++)
+ {
+ TCHAR z = pStr[i];
+ if(z == 0)
+ {
+ //End of line
+ if(bDigitFound)
+ {
+ //Scan it
+ int val = 0;
+ if(_stscanf_s(pStr, L"%x", &val) == 1)
+ {
+ //Done
+ nV = val;
+
+ bRes = TRUE;
+ }
+ }
+
+ break;
+ }
+ else if((z >= '0' && z <= '9') ||
+ (z >= 'a' && z <= 'f') ||
+ (z >= 'A' && z <= 'F'))
+ {
+ //Found a digit
+ bDigitFound = TRUE;
+ }
+ else
+ {
+ //Something else -- wrong char
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if(pnOutVal)
+ *pnOutVal = nV;
+
+ return bRes;
+}
+
+BOOL CMain::parseReasonParam(LPCTSTR pStrParam, DWORD* pnOutReason)
+{
+ //Parse reason parameter from 'pStrParam'
+ //'pnOutReason' = if not NULL, receives the reason if success
+ //RETURN:
+ // = TRUE if success
+ // = FALSE if failed to parse
+ BOOL bRes = FALSE;
+
+ DWORD dwReason = 0;
+
+ //[p|u:]xx:yy
+ if(pStrParam &&
+ pStrParam[0])
+ {
+ //Split into segments by :
+ int nFnd0 = findCharInStrCaseSensitive(pStrParam, L':', 0);
+ if(nFnd0 >= 0)
+ {
+ TCHAR* pBuff0 = NULL;
+ TCHAR* pBuff1 = NULL;
+
+ int nFnd1 = findCharInStrCaseSensitive(pStrParam, L':', nFnd0 + 1);
+ if(nFnd1 >= 0)
+ {
+ int nFnd2 = findCharInStrCaseSensitive(pStrParam, L':', nFnd1 + 1);
+ if(nFnd2 < 0)
+ {
+ //[p|u:]xx:yy
+ if(nFnd0 == 1)
+ {
+ TCHAR chPU = pStrParam[0];
+
+ int nchLn0 = nFnd1 - nFnd0;
+ pBuff0 = new (std::nothrow) TCHAR[nchLn0];
+ if(pBuff0)
+ {
+ memcpy(pBuff0, pStrParam + nFnd0 + 1, (nchLn0 - 1) * sizeof(TCHAR));
+ pBuff0[nchLn0 - 1] = 0;
+
+ int nchLn1 = lstrlen(pStrParam) - nFnd1;
+ pBuff1 = new (std::nothrow) TCHAR[nchLn1];
+ if(pBuff1)
+ {
+ memcpy(pBuff1, pStrParam + nFnd1 + 1, (nchLn1 - 1) * sizeof(TCHAR));
+ pBuff1[nchLn1 - 1] = 0;
+
+ //Parse values
+ UINT uiMajor = 0;
+ if(parseReasonInt32(pBuff0, (int*)&uiMajor))
+ {
+ UINT uiMinor = 0;
+ if(parseReasonInt32(pBuff1, (int*)&uiMinor))
+ {
+ //Check reason itself
+ if(chPU == 'p' ||
+ chPU == 'P')
+ {
+ //Planned
+ dwReason = SHTDN_REASON_FLAG_PLANNED;
+
+ goto lbl_use_rsn;
+ }
+ else if(chPU == 'u' ||
+ chPU == 'U')
+ {
+ //User-defined
+ dwReason = SHTDN_REASON_FLAG_USER_DEFINED;
+lbl_use_rsn:
+ //Use it
+ dwReason |= (uiMajor & 0xFFFF0000) | (uiMinor & 0xFFFF);
+
+ bRes = TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ //xx:yy
+ pBuff0 = new (std::nothrow) TCHAR[nFnd0 + 1];
+ if(pBuff0)
+ {
+ memcpy(pBuff0, pStrParam, nFnd0 * sizeof(TCHAR));
+ pBuff0[nFnd0] = 0;
+
+ int nchLn1 = lstrlen(pStrParam) - nFnd0;
+ pBuff1 = new (std::nothrow) TCHAR[nchLn1];
+ if(pBuff1)
+ {
+ memcpy(pBuff1, pStrParam + nFnd0 + 1, (nchLn1 - 1) * sizeof(TCHAR));
+ pBuff1[nchLn1 - 1] = 0;
+
+ //Parse two digits
+ UINT uiMajor = 0;
+ if(parseReasonInt32(pBuff0, (int*)&uiMajor))
+ {
+ UINT uiMinor = 0;
+ if(parseReasonInt32(pBuff1, (int*)&uiMinor))
+ {
+ //Got both
+ dwReason = (uiMajor & 0xFFFF0000) | (uiMinor & 0xFFFF);
+
+ bRes = TRUE;
+ }
+ }
+ }
+
+ }
+ }
+
+
+ //Free mem
+ if(pBuff0)
+ {
+ delete[] pBuff0;
+ pBuff0 = NULL;
+ }
+
+ if(pBuff1)
+ {
+ delete[] pBuff1;
+ pBuff1 = NULL;
+ }
+
+
+ }
+ }
+
+ if(pnOutReason)
+ *pnOutReason = dwReason;
+
+ return bRes;
+}
+
+
+TCHAR* CMain::CapitalizeFirstLetter(TCHAR* pBuff)
+{
+ //Capitalize first letter in 'pBuff'
+ //RETURN:
+ // = Pointer to the buffer in 'pBuff'
+
+ if(pBuff &&
+ pBuff[0])
+ {
+ TCHAR buff[2] = {pBuff[0], 0};
+ ::CharUpper(buff);
+
+ pBuff[0] = buff[0];
+ }
+
+ return pBuff;
+}
+
+
+BOOL CMain::FormatSecSmart(TCHAR* pBuff, int nchBuffSz, int nSeconds)
+{
+ //Format 'nSeconds' into days:hours:minutes:seconds
+ //'pBuff' = receives formatted string
+ //'nchBuffSz' = size of 'pBuff' in TCHARs
+ //'nSeconds' = number of seconds, can be negative
+ //RETURN:
+ // = TRUE if success
+ BOOL bRes = FALSE;
+
+ if(pBuff &&
+ nchBuffSz > 0)
+ {
+ BOOL bNegative = FALSE;
+ pBuff[0] = 0;
+
+ //Is it negative?
+ if(nSeconds < 0)
+ {
+ nSeconds = -nSeconds;
+ bNegative = TRUE;
+
+ if(FAILED(::StringCchCat(pBuff, nchBuffSz, L"-")))
+ return FALSE;
+ }
+
+ int n_Secs = nSeconds % 60;
+
+ nSeconds /= 60;
+ int n_Mins = nSeconds % 60;
+
+ nSeconds /= 60;
+ int n_Hrs = nSeconds % 24;
+
+ nSeconds /= 24;
+ int ii_Days = nSeconds;
+
+ //Format it
+ if(ii_Days != 0)
+ {
+ int nLn = lstrlen(pBuff);
+ if(FAILED(::StringCchPrintf(pBuff + nLn, nchBuffSz - nLn, L"%d%s", ii_Days, LOC_STRING(IDS_STRING118))))
+ return FALSE;
+ }
+
+ if(n_Hrs != 0 || pBuff[0])
+ {
+ int nLn = lstrlen(pBuff);
+ if(FAILED(::StringCchPrintf(pBuff + nLn, nchBuffSz - nLn, L"%s%d%s", !pBuff[0] ? L"" : L":", n_Hrs, LOC_STRING(IDS_STRING117))))
+ return FALSE;
+ }
+
+ if(n_Mins != 0 || pBuff[0])
+ {
+ int nLn = lstrlen(pBuff);
+ if(FAILED(::StringCchPrintf(pBuff + nLn, nchBuffSz - nLn, L"%s%d%s", !pBuff[0] ? L"" : L":", n_Mins, LOC_STRING(IDS_STRING116))))
+ return FALSE;
+ }
+
+ if(n_Secs != 0 || pBuff[0])
+ {
+ int nLn = lstrlen(pBuff);
+ if(FAILED(::StringCchPrintf(pBuff + nLn, nchBuffSz - nLn, L"%s%d%s", !pBuff[0] ? L"" : L":", n_Secs, LOC_STRING(IDS_STRING110))))
+ return FALSE;
+ }
+
+ if(!pBuff[0])
+ {
+ //If nothing there
+ if(FAILED(::StringCchPrintf(pBuff, nchBuffSz, L"0%s", LOC_STRING(IDS_STRING110))))
+ return FALSE;
+ }
+
+ //Done
+ bRes = TRUE;
+ }
+
+ return bRes;
+}
+
+
+int CMain::ShowUserConfirmation(ACTIONS_INFO* pAI)
+{
+ //Request user confirmation for action in 'pAI'
+ //RETURN:
+ // = 1 if we're allowed to continue
+ // = 0 if user canceled (and we're not allowed to continue)
+ // = -1 if error (check GetLastError() for info) -- we're not allowed to continue
+ int nRes = -1;
+ int nOSError = NO_ERROR;
+
+ if(pAI)
+ {
+ //Compose message
+ TCHAR buffMsg[1024 * 2 + 512] = {0};
+
+ //Power op
+ TCHAR buffPowerOp[1024] = {0};
+
+ //Are we aborting?
+ BOOL bAborting = pAI->pwrAction == PWR_OP_ABORT_SHUT_DOWN;
+ BOOL bAdvBootMenu = pAI->pwrAction == PWR_OP_ADVANCED_BOOT_OPTIONS_MENU;
+
+ //Are we installing updates?
+ if(!pAI->bNoUpdates &&
+ !bAborting &&
+ !bAdvBootMenu)
+ {
+ ::StringCchPrintf(buffPowerOp, SIZEOF(buffPowerOp), L"%s, ", LOC_STRING(IDS_STRING101)); //L"install downloaded updates"
+ }
+
+
+ switch(pAI->pwrAction)
+ {
+ case PWR_OP_SHUT_DOWN:
+ ::StringCchCat(buffPowerOp, SIZEOF(buffPowerOp), LOC_STRING(IDS_STRING102)); //L"shut down computer"
+ break;
+ case PWR_OP_REBOOT:
+ ::StringCchCat(buffPowerOp, SIZEOF(buffPowerOp), LOC_STRING(IDS_STRING103)); //L"reboot computer"
+ break;
+ case PWR_OP_HYBRID_SHUT_DOWN:
+ ::StringCchCat(buffPowerOp, SIZEOF(buffPowerOp), LOC_STRING(IDS_STRING104)); //L"hybrid shut-down of computer"
+ break;
+ case PWR_OP_REBOOT_WITH_APP_RESTART:
+ ::StringCchCat(buffPowerOp, SIZEOF(buffPowerOp), LOC_STRING(IDS_STRING105)); //L"reboot & restart registered apps"
+ break;
+
+ case PWR_OP_ADVANCED_BOOT_OPTIONS_MENU:
+ ::StringCchCopy(buffPowerOp, SIZEOF(buffPowerOp), LOC_STRING(IDS_STRING119)); //L"go to advanced boot options menu"
+ break;
+
+ case PWR_OP_ABORT_SHUT_DOWN:
+ ::StringCchCopy(buffPowerOp, SIZEOF(buffPowerOp), LOC_STRING(IDS_STRING106)); //L"abort pending shut-down or rebooting"
+ break;
+
+ default:
+ ASSERT(NULL);
+ buffPowerOp[0] = 0;
+ break;
+ }
+
+ if(buffPowerOp[0])
+ {
+ //Is it forced
+ TCHAR buffForced[256] = {0};
+ if(!bAborting)
+ {
+ if(pAI->bForced)
+ {
+ ::StringCchPrintf(buffForced, SIZEOF(buffForced), L" (%s)", LOC_STRING(IDS_STRING107)); //L"forced"
+ }
+ }
+
+ //Computer
+ TCHAR buffComp[256] = {0};
+ if(pAI->pStrRemoteCompName &&
+ pAI->pStrRemoteCompName[0])
+ {
+ //Use name
+ ::StringCchCopy(buffComp, SIZEOF(buffComp), pAI->pStrRemoteCompName);
+ }
+ else
+ {
+ //Local
+ ::StringCchCopy(buffComp, SIZEOF(buffComp), CapitalizeFirstLetter(LOC_STRING(IDS_STRING108))); //L"local"
+ }
+
+ //Time-out
+ TCHAR buffTimeout[256] = {0};
+ if(!bAborting)
+ {
+ if(pAI->nTimeoutSec > 0)
+ {
+ //Set timeout
+ TCHAR buffTO_val[256];
+ if(FormatSecSmart(buffTO_val, SIZEOF(buffTO_val), pAI->nTimeoutSec))
+ {
+ ::StringCchPrintf(buffTimeout, SIZEOF(buffTimeout), L"\n%s: %s",
+ CapitalizeFirstLetter(LOC_STRING(IDS_STRING109)), //L"timeout"
+ buffTO_val
+ );
+ }
+ else
+ {
+ //Failed -- use just seconds
+ ASSERT(NULL);
+ ::StringCchPrintf(buffTimeout, SIZEOF(buffTimeout), L"\n%s: %d %s",
+ CapitalizeFirstLetter(LOC_STRING(IDS_STRING109)), //L"timeout"
+ pAI->nTimeoutSec,
+ LOC_STRING(IDS_STRING110) //L"sec"
+ );
+ }
+ }
+ else
+ {
+ //No timeout
+ ::StringCchPrintf(buffTimeout, SIZEOF(buffTimeout), L"\n%s: %s",
+ CapitalizeFirstLetter(LOC_STRING(IDS_STRING109)), //L"timeout"
+ CapitalizeFirstLetter(LOC_STRING(IDS_STRING111)) //L"none"
+ );
+ }
+ }
+
+ //Message to display
+ TCHAR buffUserMsg[512] = {0};
+ if(!bAborting)
+ {
+ if(pAI->pStrMessage &&
+ pAI->pStrMessage[0])
+ {
+ ::StringCchPrintf(buffUserMsg, SIZEOF(buffUserMsg), L"\n%s: %s"
+ ,
+ CapitalizeFirstLetter(LOC_STRING(IDS_STRING112)), //L"User Message"
+ pAI->pStrMessage);
+ }
+ }
+
+
+ //Make main message
+ ::StringCchPrintf(buffMsg, SIZEOF(buffMsg),
+ L"%s\n\n"
+ L"\"%s%s\"\n\n"
+ L"%s: %s"
+ L"%s"
+ L"%s"
+ ,
+ LOC_STRING(IDS_STRING113), //Do you want to perform the following operation?
+ CapitalizeFirstLetter(buffPowerOp), buffForced,
+ CapitalizeFirstLetter(LOC_STRING(IDS_STRING114)), //Computer
+ buffComp,
+ buffTimeout,
+ buffUserMsg
+ );
+
+ //Show UI
+ ::SetLastError(NO_ERROR);
+ int nResMB = ::MessageBox(NULL, buffMsg,
+ LOC_STRING(IDS_STRING115),
+ MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONQUESTION | MB_SYSTEMMODAL | MB_SETFOREGROUND);
+
+ if(nResMB == IDYES)
+ {
+ //User chose to continue
+ nRes = 1;
+ }
+ else if(nResMB == IDNO ||
+ nResMB == IDCANCEL)
+ {
+ //User chose not to continue
+ nRes = 0;
+ }
+ else
+ {
+ //Error
+ nOSError = ::GetLastError();
+ if(nOSError == NO_ERROR)
+ nOSError = ERROR_INVALID_LEVEL;
+ }
+ }
+ else
+ {
+ //Error
+ nOSError = ERROR_INVALID_PARAMETER;
+ }
+ }
+ else
+ nOSError = ERROR_INVALID_PARAMETER;
+
+ ::SetLastError(nOSError);
+ return nRes;
+}
+
+
+BOOL CMain::AdjustPrivilege(LPCTSTR pStrMachine, LPCTSTR pPrivilegeName, BOOL bEnable, HANDLE hProcess)
+{
+ //Tries to adjust the 'pPrivilegeName' privilege for the process
+ //'pStrMachine' = computer name, or NULL for local computer
+ //'bEnable' = TRUE to enable, FALSE to disable a privilege
+ //'hProcess' = Process to adjust privilege for, or NULL for current process
+ //RETURN: - TRUE if done;
+ // - FALSE if privileges were not adjusted (check GetLastError() for info)
+ BOOL bRes = FALSE;
+ int nOSError = NO_ERROR;
+
+ HANDLE hToken;
+ TOKEN_PRIVILEGES tkp;
+
+ //Get a token for this process.
+ if(!OpenProcessToken(hProcess ? hProcess : GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
+ return FALSE;
+
+ //Get the LUID for the shutdown privilege.
+ if(LookupPrivilegeValue(pStrMachine, pPrivilegeName, &tkp.Privileges[0].Luid))
+ {
+ //One privilege to set
+ tkp.PrivilegeCount = 1;
+ tkp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : SE_PRIVILEGE_REMOVED;
+
+ //Adjust it now
+ bRes = AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
+ nOSError = GetLastError();
+ if(bRes)
+ {
+ //See if no error
+ if(nOSError != ERROR_SUCCESS)
+ bRes = FALSE;
+ }
+ }
+ else
+ {
+ //Failed
+ nOSError = ::GetLastError();
+ }
+
+ //Close handle
+ CloseHandle(hToken);
+
+ ::SetLastError(nOSError);
+ return bRes;
+}
+
+
+TCHAR* CMain::trimBuffer(TCHAR* pBuff)
+{
+ //Remove spaces from left and right side of 'pBuff'
+ //RETURN:
+ // = Pointer to the buffer from 'pBuff'
+
+ //Do left & then right
+ return trimBufferRight(trimBufferLeft(pBuff));
+}
+
+TCHAR* CMain::trimBufferLeft(TCHAR* pBuff)
+{
+ //Remove spaces from left side of 'pBuff'
+ //RETURN:
+ // = Pointer to the buffer from 'pBuff'
+ if(pBuff)
+ {
+ for(int i = 0;; i++)
+ {
+ TCHAR z = pBuff[i];
+ if(z == ' ' ||
+ z == '\t' ||
+ z == '\n' ||
+ z == '\r')
+ {
+ }
+ else
+ {
+ //See if we need to remove it
+ if(i > 0)
+ {
+ //Find the end of string
+ int nEndInd = i;
+ for(;; nEndInd++)
+ {
+ if(pBuff[nEndInd] == 0)
+ break;
+ }
+
+ memcpy(pBuff, pBuff + i, (nEndInd - i + 1) * sizeof(TCHAR));
+ }
+
+ break;
+ }
+ }
+ }
+
+ return pBuff;
+}
+
+TCHAR* CMain::trimBufferRight(TCHAR* pBuff)
+{
+ //Remove spaces from right side of 'pBuff'
+ //RETURN:
+ // = Pointer to the buffer from 'pBuff'
+ if(pBuff)
+ {
+ //Find the end of string
+ int nLn = 0;
+ while(pBuff[nLn])
+ {
+ nLn++;
+ }
+
+ for(int i = nLn - 1; i >= 0; i--)
+ {
+ TCHAR z = pBuff[i];
+ if(z == ' ' ||
+ z == '\t' ||
+ z == '\n' ||
+ z == '\r')
+ {
+ }
+ else
+ {
+ //See if we need to remove it
+ if(i < nLn - 1)
+ {
+ pBuff[i + 1] = 0;
+ }
+
+ break;
+ }
+ }
+ }
+
+ return pBuff;
+}
+
+
+TCHAR* CMain::FormatErrorMessage(int nOSError, TCHAR* pBuff, int nchLnBuff, BOOL bUseDescriptionForNoError)
+{
+ //Convert OS error code to string
+ //'nOSError' = OS error code to format
+ //'pBuff' = text buffer to use for formatting
+ //'nchLnBuff' = length of 'pBuff' in TCHARs
+ //'bUseDescriptionForNoError' = TRUE to use system provided description for NO_ERROR (that is "Operation completed successfully")
+ // = FALSE to use empty string for NO_ERROR
+ //RETURN: = Error description buffer in 'pBuff'
+ int nPrev_OSError = ::GetLastError();
+ LPVOID lpMsgBuf = NULL;
+ DWORD dwRes;
+
+ if(pBuff &&
+ nchLnBuff > 0)
+ {
+ //Reset buffer
+ pBuff[0] = 0;
+
+ if(nOSError != NO_ERROR ||
+ bUseDescriptionForNoError)
+ {
+ //Convert error code
+ if(nOSError >= INTERNET_ERROR_BASE && nOSError <= INTERNET_ERROR_LAST)
+ {
+ //Get system folder
+ TCHAR buffSysFolder[MAX_PATH * 2];
+ buffSysFolder[0] = 0;
+ if(int nLn = ::GetSystemDirectory(buffSysFolder, SIZEOF(buffSysFolder)))
+ {
+ //Make sure folder ends with slash
+ if(buffSysFolder[nLn - 1] != '/' &&
+ buffSysFolder[nLn - 1] != '\\')
+ {
+ ::StringCchCat(buffSysFolder, SIZEOF(buffSysFolder), L"\\");
+ }
+
+ ::StringCchCat(buffSysFolder, SIZEOF(buffSysFolder), L"wininet.dll");
+ }
+
+ if(buffSysFolder[0])
+ {
+ //Spec code
+ HMODULE hMod = LoadLibrary(buffSysFolder);
+ dwRes = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS,
+ hMod, nOSError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
+ FreeLibrary(hMod);
+ }
+ }
+ else
+ {
+ //Regular
+ dwRes = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ nOSError,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf, 0, NULL);
+ }
+
+ if(lpMsgBuf)
+ {
+ //Copy data to our buffer
+ ::StringCchCopy(pBuff, nchLnBuff, (LPCTSTR)lpMsgBuf);
+
+ //Free mem
+ LocalFree(lpMsgBuf);
+ }
+
+ //Did we get something?
+ trimBuffer(pBuff);
+ if(!pBuff[0])
+ {
+ //If we get nothing, then use just the code
+ ::StringCchPrintf(pBuff, nchLnBuff, L"Error %d", nOSError);
+ }
+ }
+ }
+
+ ::SetLastError(nPrev_OSError);
+ return pBuff;
+}
+
+
+
+
+BOOL CMain::SetNeededShutdownPrivileges(LPCTSTR pStrRemoteCompName)
+{
+ //Set privileges needed for a shut-down
+ //RETURN:
+ // = TRUE if success
+ BOOL bRes = TRUE;
+
+ //Set SE_DEBUG_NAME privilege
+ if(!AdjustPrivilege(NULL, L"SeShutdownPrivilege", TRUE))
+ {
+ //Error
+ //int nErr = ::GetLastError();
+ //TCHAR buffErr[1024];
+
+ //_tprintf(L"WARNING: Failed to set shut-down privilege: (%d) %s\n"
+ // ,
+ // nErr,
+ // FormatErrorMessage(nErr, buffErr, SIZEOF(buffErr))
+ // );
+
+ bRes = FALSE;
+ }
+
+ //Is it a remove computer?
+ if(pStrRemoteCompName &&
+ pStrRemoteCompName[0])
+ {
+ //Set privilege
+ //INFO: You can grant SeRemoteShutdownPrivilege through secpol.msc > Local Policies > User Rights Assignment,
+ // by editing the "Force shutdown from remote system" entry.
+ //
+ if(!AdjustPrivilege(NULL /*pStrRemoteCompName*/, L"SeRemoteShutdownPrivilege", TRUE))
+ {
+ //Error
+ //int nErr = ::GetLastError();
+ //TCHAR buffErr[1024];
+
+ //_tprintf(L"WARNING: Failed to set shut-down privilege for computer: \"%s\", (%d) %s\n"
+ // ,
+ // pStrRemoteCompName,
+ // nErr,
+ // FormatErrorMessage(nErr, buffErr, SIZEOF(buffErr))
+ // );
+
+ bRes = FALSE;
+ }
+
+ }
+
+ return bRes;
+}
+
+
+
+
+int CMain::doActions(ACTIONS_INFO* pAI)
+{
+ //Perform power actions in 'pAI'
+ //RETURN:
+ // = Value to return _tmain()
+ int nResOSErrCode = ERROR_INTERNAL_ERROR;
+
+
+ //Make shut-down flags
+ DWORD dwShutDownFlags = 0;
+
+ BOOL bSetShutdownPriv = FALSE;
+
+ //Is it a remote computer
+ BOOL bRemoteComp = pAI->pStrRemoteCompName && pAI->pStrRemoteCompName[0];
+
+
+ //For some reason the API needs non-constant strings
+ TCHAR* pStrMessage = NULL;
+ int nLnRemoteCompName = pAI->pStrRemoteCompName && pAI->pStrRemoteCompName[0] ? lstrlen(pAI->pStrRemoteCompName) : 0;
+ TCHAR* pStrRemoteCompName = new (std::nothrow) TCHAR[nLnRemoteCompName + 1];
+ if(pStrRemoteCompName)
+ {
+ //Copy it
+ if(nLnRemoteCompName > 0)
+ memcpy(pStrRemoteCompName, pAI->pStrRemoteCompName, nLnRemoteCompName * sizeof(TCHAR));
+
+ pStrRemoteCompName[nLnRemoteCompName] = 0;
+
+ //Now the message to the user
+ int nLnMessage = pAI->pStrMessage && pAI->pStrMessage[0] ? lstrlen(pAI->pStrMessage) : 0;
+ pStrMessage = new (std::nothrow) TCHAR[nLnMessage + 1];
+ if(pStrMessage)
+ {
+ //Copy it
+ if(nLnMessage > 0)
+ memcpy(pStrMessage, pAI->pStrMessage, nLnMessage * sizeof(TCHAR));
+
+ pStrMessage[nLnMessage] = 0;
+
+
+ //Error message buffer
+ TCHAR buffErrMsg[1024];
+ buffErrMsg[0] = 0;
+
+ LPCTSTR pStrPwrOpName = L">";
+
+
+ //Go by power op type
+ switch(pAI->pwrAction)
+ {
+ case PWR_OP_SHUT_DOWN:
+ {
+ pStrPwrOpName = L"shut-down";
+ dwShutDownFlags = SHUTDOWN_POWEROFF;
+ bSetShutdownPriv = TRUE;
+ }
+ break;
+
+ case PWR_OP_REBOOT:
+ {
+ pStrPwrOpName = L"rebooting";
+ dwShutDownFlags = SHUTDOWN_RESTART;
+ }
+ break;
+
+ case PWR_OP_HYBRID_SHUT_DOWN:
+ {
+ pStrPwrOpName = L"hybrid shut-down";
+ dwShutDownFlags = SHUTDOWN_POWEROFF | SHUTDOWN_HYBRID;
+ bSetShutdownPriv = TRUE;
+ }
+ break;
+
+ case PWR_OP_REBOOT_WITH_APP_RESTART:
+ {
+ pStrPwrOpName = L"rebooting & restart of registered apps";
+ dwShutDownFlags = SHUTDOWN_RESTART | SHUTDOWN_RESTARTAPPS;
+ }
+ break;
+
+ case PWR_OP_ADVANCED_BOOT_OPTIONS_MENU:
+ {
+ pStrPwrOpName = L"going to advanced boot options menu";
+ dwShutDownFlags = SHUTDOWN_RESTART;
+ dwShutDownFlags |= 0x400; //Special flag for Windows 10
+
+ //Cannot install updates, but it can be forced
+ pAI->bNoUpdates = TRUE;
+ }
+ break;
+
+ case PWR_OP_ABORT_SHUT_DOWN:
+ {
+ //Abort previous
+
+ //Don't run main action
+ dwShutDownFlags = 0;
+
+ //Set needed privelge (it will post warnings internally)
+ SetNeededShutdownPrivileges(pAI->pStrRemoteCompName);
+
+ //Abort
+ if(::AbortSystemShutdown(nLnRemoteCompName > 0 ? pStrRemoteCompName : NULL))
+ {
+ //Success
+ nResOSErrCode = NO_ERROR;
+ _tprintf(L"Success aborting power operation...\n");
+ }
+ else
+ {
+ //Failed
+ nResOSErrCode = ::GetLastError();
+ _tprintf(L"ERROR: Failed to abort power operation: (%d) %s\n",
+ nResOSErrCode,
+ CMain::FormatErrorMessage(nResOSErrCode, buffErrMsg, SIZEOF(buffErrMsg))
+ );
+ }
+ }
+ break;
+
+ default:
+ {
+ //Wrong flag
+ ASSERT(NULL);
+ nResOSErrCode = ERROR_INVALID_USER_BUFFER;
+ _tprintf(L"INTERNAL ERROR: Wrong action type=%d\n", pAI->pwrAction);
+ }
+ break;
+ }
+
+
+ if(dwShutDownFlags != 0)
+ {
+ //Adjust computer name
+ LPTSTR pStrCompNm = nLnRemoteCompName > 0 ? pStrRemoteCompName : NULL;
+
+ //See if we have first two leading slashes
+ if(nLnRemoteCompName > 2)
+ {
+ if(pStrCompNm[0] == '\\' ||
+ pStrCompNm[1] == '\\')
+ {
+ //Skip slashes
+ pStrCompNm = pStrCompNm + 2;
+ }
+ }
+
+ //Set needed privelge (it will post warnings internally)
+ SetNeededShutdownPrivileges(pStrCompNm);
+
+
+ //See what API do we need to use?
+ if(!pAI->bNoUpdates ||
+ (pAI->pwrAction != PWR_OP_SHUT_DOWN &&
+ pAI->pwrAction != PWR_OP_REBOOT)
+ )
+ {
+ //Installing updates?
+ if(!pAI->bNoUpdates)
+ {
+ dwShutDownFlags |= SHUTDOWN_INSTALL_UPDATES;
+ }
+
+ //Forced?
+ if(pAI->bForced)
+ {
+ dwShutDownFlags |= SHUTDOWN_FORCE_SELF | SHUTDOWN_FORCE_OTHERS;
+ }
+
+
+ //Now execute power op
+ ::SetLastError(NO_ERROR);
+ nResOSErrCode = ::InitiateShutdown(
+ pStrCompNm,
+ nLnMessage > 0 ? pStrMessage : NULL,
+ pAI->nTimeoutSec,
+ dwShutDownFlags,
+ pAI->dwReason);
+ }
+ else
+ {
+ //Use different API
+ //INFO: We need to do this because InitiateShutdown() does not work on remote computers!
+
+ //Pick operation
+ BOOL bRebootAfter = -1;
+ if(pAI->pwrAction == PWR_OP_SHUT_DOWN)
+ {
+ bRebootAfter = FALSE;
+ }
+ else if(pAI->pwrAction == PWR_OP_REBOOT)
+ {
+ bRebootAfter = TRUE;
+ }
+
+ if(bRebootAfter == TRUE ||
+ bRebootAfter == FALSE)
+ {
+ //Initiate now
+ ::SetLastError(NO_ERROR);
+ if(::InitiateSystemShutdownEx(
+ pStrCompNm,
+ nLnMessage > 0 ? pStrMessage : NULL,
+ pAI->nTimeoutSec,
+ pAI->bForced,
+ bRebootAfter,
+ pAI->dwReason))
+ {
+ //Success
+ nResOSErrCode = NO_ERROR;
+ }
+ else
+ {
+ //Failed
+ nResOSErrCode = ::GetLastError();
+ }
+ }
+ else
+ {
+ //Bad power op
+ nResOSErrCode = ERROR_INVALID_FUNCTION;
+ }
+ }
+
+ //Check result
+ if(nResOSErrCode == NO_ERROR)
+ {
+ //Success
+ _tprintf(L"Success initiating %s...\n", pStrPwrOpName);
+ }
+ else
+ {
+ //Failed
+ _tprintf(L"ERROR: Failed to initiate %s: (%d) %s\n",
+ pStrPwrOpName,
+ nResOSErrCode,
+ CMain::FormatErrorMessage(nResOSErrCode, buffErrMsg, SIZEOF(buffErrMsg))
+ );
+ }
+ }
+
+ }
+ else
+ nResOSErrCode = ERROR_OUTOFMEMORY;
+ }
+ else
+ nResOSErrCode = ERROR_OUTOFMEMORY;
+
+
+
+ //Free mem
+ if(pStrRemoteCompName)
+ {
+ delete[] pStrRemoteCompName;
+ pStrRemoteCompName = NULL;
+ }
+
+ if(pStrMessage)
+ {
+ delete[] pStrMessage;
+ pStrMessage = NULL;
+ }
+
+ return nResOSErrCode;
+}
+
+
+
+void CMain::outputMainLogo()
+{
+ SYSTEMTIME st;
+ ::GetSystemTime(&st);
+
+ _tprintf(
+ L"Utility To Install Pre-Downloaded Windows Updates & Shutdown/Reboot\n"
+ L"v.%s\n"
+ L"Copyright (c) %s%d by www.dennisbabkin.com. All rights reserved.\n"
+ L"\n"
+ ,
+ PROG_VER,
+ st.wYear > 2016 ? L"2016-" : L"",
+ st.wYear
+ );
+
+}
+
+
+
+
+
diff --git a/ShutdownWithUpdates/ShutdownWithUpdates/Main.h b/ShutdownWithUpdates/ShutdownWithUpdates/Main.h
new file mode 100644
index 0000000..967dfe0
--- /dev/null
+++ b/ShutdownWithUpdates/ShutdownWithUpdates/Main.h
@@ -0,0 +1,62 @@
+/*
+ * ShutdownWithUpdates
+ * "Utility To Install Pre-Downloaded Windows Updates & Shutdown/Reboot"
+ * Copyright (c) 2016-2019 www.dennisbabkin.com
+ *
+ * https://dennisbabkin.com/utilities/#ShutdownWithUpdates
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+#pragma once
+
+
+#include "types.h"
+#include "resource.h"
+
+
+
+class CMain
+{
+private:
+ CMain(void);
+ ~CMain(void);
+public:
+ static int doWork(int argc, _TCHAR* argv[]);
+private:
+ static int doWork_RAW(int argc, _TCHAR* argv[]);
+protected:
+ static int CheckForXP_SP2_FileBlockAndRemoveIt();
+ static CMD_TYPE getCommandType(LPCTSTR pStrCmd);
+ static void ShowHelpInfo();
+ static int findCharInStrCaseSensitive(LPCTSTR pStr, TCHAR chSearch, int nIndBegin = 0);
+ static BOOL parseReasonInt32(LPCTSTR pStr, int* pnOutVal = NULL);
+ static BOOL parseDecimalInt32(LPCTSTR pStr, int* pnOutVal = NULL);
+ static BOOL parseHexUInt32(LPCTSTR pStr, UINT* pnOutVal = NULL);
+ static BOOL parseReasonParam(LPCTSTR pStrParam, DWORD* pnOutReason = NULL);
+ static TCHAR* CapitalizeFirstLetter(TCHAR* pBuff);
+ static BOOL FormatSecSmart(TCHAR* pBuff, int nchBuffSz, int nSeconds);
+ static int ShowUserConfirmation(ACTIONS_INFO* pAI);
+ static BOOL AdjustPrivilege(LPCTSTR pStrMachine, LPCTSTR pPrivilegeName, BOOL bEnable, HANDLE hProcess = NULL);
+ static TCHAR* trimBuffer(TCHAR* pBuff);
+ static TCHAR* trimBufferLeft(TCHAR* pBuff);
+ static TCHAR* trimBufferRight(TCHAR* pBuff);
+ static TCHAR* FormatErrorMessage(int nOSError, TCHAR* pBuff, int nchLnBuff, BOOL bUseDescriptionForNoError = FALSE);
+ static BOOL SetNeededShutdownPrivileges(LPCTSTR pStrRemoteCompName);
+ static int doActions(ACTIONS_INFO* pAI);
+ static void outputMainLogo();
+
+};
diff --git a/ShutdownWithUpdates/ShutdownWithUpdates/ShutdownWithUpdates.cpp b/ShutdownWithUpdates/ShutdownWithUpdates/ShutdownWithUpdates.cpp
new file mode 100644
index 0000000..d6d81ed
--- /dev/null
+++ b/ShutdownWithUpdates/ShutdownWithUpdates/ShutdownWithUpdates.cpp
@@ -0,0 +1,37 @@
+/*
+ * ShutdownWithUpdates
+ * "Utility To Install Pre-Downloaded Windows Updates & Shutdown/Reboot"
+ * Copyright (c) 2016-2019 www.dennisbabkin.com
+ *
+ * https://dennisbabkin.com/utilities/#ShutdownWithUpdates
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+#include "stdafx.h"
+#include "Main.h"
+
+
+int _tmain(int argc, _TCHAR* argv[])
+{
+ //RETURN:
+ // = Exit code from the main process:
+ // = 0 if success
+ // = -1 if general exception in the process
+ // = Other - OS Error code
+ return CMain::doWork(argc, argv);
+}
+
diff --git a/ShutdownWithUpdates/ShutdownWithUpdates/ShutdownWithUpdates.rc b/ShutdownWithUpdates/ShutdownWithUpdates/ShutdownWithUpdates.rc
new file mode 100644
index 0000000..f6e1a4f
--- /dev/null
+++ b/ShutdownWithUpdates/ShutdownWithUpdates/ShutdownWithUpdates.rc
@@ -0,0 +1,135 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,2,1,0
+ PRODUCTVERSION 1,2,1,0
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x0L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "www.dennisbabkin.com"
+ VALUE "FileDescription", "Utility To Install Pre-Downloaded Windows Updates & Shutdown/Reboot"
+ VALUE "FileVersion", "1.2.1.0"
+ VALUE "InternalName", "ShutdownWithUpdates.exe"
+ VALUE "LegalCopyright", "Copyright (c) 2016-2019 by dennisbabkin.com. All rights reserved."
+ VALUE "OriginalFilename", "ShutdownWithUpdates.exe"
+ VALUE "ProductName", "Utility To Install Pre-Downloaded Windows Updates & Shutdown/Reboot"
+ VALUE "ProductVersion", "1.2.1.0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_STRING101 "install downloaded updates"
+ IDS_STRING102 "shut down computer"
+ IDS_STRING103 "reboot computer"
+ IDS_STRING104 "hybrid shut-down of computer"
+ IDS_STRING105 "reboot & restart registered apps"
+ IDS_STRING106 "abort pending shut-down or rebooting"
+ IDS_STRING107 "forced"
+ IDS_STRING108 "local"
+ IDS_STRING109 "timeout"
+ IDS_STRING110 "s"
+ IDS_STRING111 "none"
+END
+
+STRINGTABLE
+BEGIN
+ IDS_STRING112 "User Message"
+ IDS_STRING113 "Do you want to perform the following operation?"
+ IDS_STRING114 "computer"
+ IDS_STRING115 "ShutdownWithUpdates Tool"
+ IDS_STRING116 "m"
+ IDS_STRING117 "h"
+ IDS_STRING118 "d"
+ IDS_STRING119 "go to advanced boot options menu"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/ShutdownWithUpdates/ShutdownWithUpdates/ShutdownWithUpdates.vcproj b/ShutdownWithUpdates/ShutdownWithUpdates/ShutdownWithUpdates.vcproj
new file mode 100644
index 0000000..0be2bf8
--- /dev/null
+++ b/ShutdownWithUpdates/ShutdownWithUpdates/ShutdownWithUpdates.vcproj
@@ -0,0 +1,249 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ShutdownWithUpdates/ShutdownWithUpdates/Types.h b/ShutdownWithUpdates/ShutdownWithUpdates/Types.h
new file mode 100644
index 0000000..87876ae
--- /dev/null
+++ b/ShutdownWithUpdates/ShutdownWithUpdates/Types.h
@@ -0,0 +1,214 @@
+//Custom types
+
+/*
+ * ShutdownWithUpdates
+ * "Utility To Install Pre-Downloaded Windows Updates & Shutdown/Reboot"
+ * Copyright (c) 2016-2019 www.dennisbabkin.com
+ *
+ * https://dennisbabkin.com/utilities/#ShutdownWithUpdates
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+#pragma once
+
+
+
+
+
+enum CMD_TYPE{
+ CTP_NONE,
+ CTP_UNKNOWN, //Unknown command
+ CTP_SHOW_HELP, //-?
+ CTP_SHUT_DOWN, //-s
+ CTP_REBOOT, //-r
+ CTP_HYBRID_SHUT_DOWN, //-hs
+ CTP_REBOOT_WITH_APP_RESTART, //-g
+ CTP_ADVANCED_BOOT_MENU, //-abo
+ CTP_ABORT_SHUT_DOWN, //-a
+ CTP_FORCED, //-f
+ CTP_VERBOSE, //-v
+ CTP_NO_UPDATES, //-nu
+ CTP_REMOTE_COMPUTER, //-m
+ CTP_TIMEOUT, //-t
+ CTP_SHOW_MESSAGE, //-c
+ CTP_REASON, //-d
+};
+
+
+
+struct CMD_STR{
+ CMD_TYPE cmdID;
+ LPCTSTR pStrCmd;
+};
+
+
+
+enum POWER_OP{
+ PWR_OP_NONE,
+ PWR_OP_SHUT_DOWN,
+ PWR_OP_REBOOT,
+ PWR_OP_HYBRID_SHUT_DOWN,
+ PWR_OP_REBOOT_WITH_APP_RESTART,
+ PWR_OP_ABORT_SHUT_DOWN,
+ PWR_OP_ADVANCED_BOOT_OPTIONS_MENU,
+};
+
+
+#ifndef SHUTDOWN_HYBRID
+#define SHUTDOWN_HYBRID 0x00000200
+#endif
+
+
+
+
+struct ACTIONS_INFO{
+ POWER_OP pwrAction;
+ DWORD dwReason;
+ BOOL bForced;
+ BOOL bVerbose;
+ BOOL bNoUpdates;
+
+ LPCTSTR pStrRemoteCompName;
+ int nTimeoutSec;
+
+ LPCTSTR pStrMessage;
+
+ ACTIONS_INFO()
+ {
+ pwrAction = PWR_OP_NONE;
+ dwReason = SHTDN_REASON_FLAG_PLANNED | 0xFF;
+ bForced = FALSE;
+ bVerbose = FALSE;
+ bNoUpdates = FALSE;
+
+ pStrRemoteCompName = NULL;
+ nTimeoutSec = 0;
+
+ pStrMessage = NULL;
+ }
+};
+
+
+#pragma warning(push)
+#pragma warning(disable: 4200)
+struct MY_STRINGRESOURCEIMAGE
+{
+ WORD nLength;
+ WCHAR achString[];
+};
+#pragma warning(pop) // C4200
+
+
+
+struct LOC_STRING{
+ LOC_STRING(UINT nID)
+ {
+ //'nID' = string ID from resources
+ pString = NULL;
+ loadStringFromRsrc(nID);
+ }
+
+ ~LOC_STRING()
+ {
+ //Free mem
+ freeString();
+ }
+
+ operator const TCHAR*()
+ {
+ return pString ? pString : L"";
+ }
+ operator TCHAR*()
+ {
+ return pString ? pString : L"";
+ }
+
+private:
+ TCHAR* pString; //Loaded string, or NULL if error
+
+private:
+ void freeString()
+ {
+ if(pString)
+ {
+ delete[] pString;
+ pString = NULL;
+ }
+ }
+
+ BOOL loadStringFromRsrc(UINT nID)
+ {
+ //RETURN:
+ // = TRUE if success
+ BOOL bRes = FALSE;
+
+ HMODULE hInstance = ::GetModuleHandle(NULL);
+ if(hInstance)
+ {
+ HRSRC hResource = ::FindResource(hInstance, MAKEINTRESOURCE( ((nID>>4)+1) ), RT_STRING);
+ if(hResource)
+ {
+ HGLOBAL hGlobal = ::LoadResource(hInstance, hResource);
+ if(hGlobal)
+ {
+ const MY_STRINGRESOURCEIMAGE* pImage = (const MY_STRINGRESOURCEIMAGE*)::LockResource(hGlobal);
+ if(pImage)
+ {
+ ULONG nResourceSize = ::SizeofResource(hInstance, hResource);
+
+ const MY_STRINGRESOURCEIMAGE* pImageEnd = (const MY_STRINGRESOURCEIMAGE*)(LPBYTE( pImage )+nResourceSize);
+ UINT iIndex = nID & 0x000f;
+
+ while( (iIndex > 0) && (pImage < pImageEnd) )
+ {
+ pImage = (const MY_STRINGRESOURCEIMAGE*)(LPBYTE( pImage )+(sizeof( MY_STRINGRESOURCEIMAGE )+(pImage->nLength * sizeof( WCHAR ))));
+ iIndex--;
+ }
+
+ if(pImage < pImageEnd)
+ {
+ if(pImage->nLength != 0)
+ {
+ //Free old string
+ freeString();
+
+ //Reserve mem
+ pString = new (std::nothrow) TCHAR[pImage->nLength + 1];
+ if(pString)
+ {
+ //Copy string
+ memcpy(pString, pImage->achString, pImage->nLength * sizeof(TCHAR));
+ pString[pImage->nLength] = 0;
+
+ bRes = TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return bRes;
+ }
+};
+
+
+
+
+
+
diff --git a/ShutdownWithUpdates/ShutdownWithUpdates/altstreams.h b/ShutdownWithUpdates/ShutdownWithUpdates/altstreams.h
new file mode 100644
index 0000000..9541799
--- /dev/null
+++ b/ShutdownWithUpdates/ShutdownWithUpdates/altstreams.h
@@ -0,0 +1,81 @@
+//
+// This header contains definitions from DDK
+//
+// ADS-related definitions
+//
+#include
+
+
+//#ifndef NTSTATUS
+//typedef INT NTSTATUS;
+//#endif
+
+// The only return code we check for
+#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L)
+
+
+typedef struct _IO_STATUS_BLOCK {
+ NTSTATUS Status;
+ ULONG Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+
+typedef enum _FILE_INFORMATION_CLASS {
+ FileDirectoryInformation = 1, // 1
+ FileFullDirectoryInformation, // 2
+ FileBothDirectoryInformation, // 3
+ FileBasicInformation, // 4
+ FileStandardInformation, // 5
+ FileInternalInformation, // 6
+ FileEaInformation, // 7
+ FileAccessInformation, // 8
+ FileNameInformation, // 9
+ FileRenameInformation, // 10
+ FileLinkInformation, // 11
+ FileNamesInformation, // 12
+ FileDispositionInformation, // 13
+ FilePositionInformation, // 14
+ FileModeInformation = 16, // 16
+ FileAlignmentInformation, // 17
+ FileAllInformation, // 18
+ FileAllocationInformation, // 19
+ FileEndOfFileInformation, // 20
+ FileAlternateNameInformation, // 21
+ FileStreamInformation, // 22
+ FilePipeInformation, // 23
+ FilePipeLocalInformation, // 24
+ FilePipeRemoteInformation, // 25
+ FileMailslotQueryInformation, // 26
+ FileMailslotSetInformation, // 27
+ FileCompressionInformation, // 28
+ FileObjectIdInformation, // 29
+ FileCompletionInformation, // 30
+ FileMoveClusterInformation, // 31
+ FileQuotaInformation, // 32
+ FileReparsePointInformation, // 33
+ FileNetworkOpenInformation, // 34
+ FileAttributeTagInformation, // 35
+ FileTrackingInformation // 36
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+
+#pragma pack(push, 4)
+
+typedef struct _FILE_STREAM_INFORMATION { // Information Class 22
+ ULONG NextEntryOffset;
+ ULONG StreamNameLength;
+ LARGE_INTEGER EndOfStream;
+ LARGE_INTEGER AllocationSize;
+ WCHAR StreamName[1];
+} FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION;
+
+#pragma pack(pop)
+
+
+// Define pointer to function type for dynamic loading
+typedef NTSTATUS (NTAPI *NTQUERYINFORMATIONFILE)(
+ IN HANDLE FileHandle,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ OUT PVOID FileInformation,
+ IN ULONG Length,
+ IN FILE_INFORMATION_CLASS FileInformationClass);
diff --git a/ShutdownWithUpdates/ShutdownWithUpdates/ntddstor.h b/ShutdownWithUpdates/ShutdownWithUpdates/ntddstor.h
new file mode 100644
index 0000000..b5e34b6
--- /dev/null
+++ b/ShutdownWithUpdates/ShutdownWithUpdates/ntddstor.h
@@ -0,0 +1,750 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ ntddstor.h
+
+Abstract:
+
+ This is the include file that defines all common constants and types
+ accessing the storage class drivers
+
+Author:
+
+ Peter Wieland 19-Jun-1996
+
+Revision History:
+
+--*/
+
+#pragma once
+
+//#include
+
+//
+// Interface GUIDs
+//
+// need these GUIDs outside conditional includes so that user can
+// #include in precompiled header
+// #include in a single source file
+// #include in that source file a second time to instantiate the GUIDs
+//
+#ifdef DEFINE_GUID
+//
+// Make sure FAR is defined...
+//
+#ifndef FAR
+#ifdef _WIN32
+#define FAR
+#else
+#define FAR _far
+#endif
+#endif
+
+/*
+// begin_wioctlguids
+DEFINE_GUID(GUID_DEVINTERFACE_DISK, 0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
+DEFINE_GUID(GUID_DEVINTERFACE_CDROM, 0x53f56308L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
+DEFINE_GUID(GUID_DEVINTERFACE_PARTITION, 0x53f5630aL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
+DEFINE_GUID(GUID_DEVINTERFACE_TAPE, 0x53f5630bL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
+DEFINE_GUID(GUID_DEVINTERFACE_WRITEONCEDISK, 0x53f5630cL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
+DEFINE_GUID(GUID_DEVINTERFACE_VOLUME, 0x53f5630dL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
+DEFINE_GUID(GUID_DEVINTERFACE_MEDIUMCHANGER, 0x53f56310L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
+DEFINE_GUID(GUID_DEVINTERFACE_FLOPPY, 0x53f56311L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
+DEFINE_GUID(GUID_DEVINTERFACE_CDCHANGER, 0x53f56312L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
+DEFINE_GUID(GUID_DEVINTERFACE_STORAGEPORT, 0x2accfe60L, 0xc130, 0x11d2, 0xb0, 0x82, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
+// end_wioctlguids
+*/
+// begin_wioctlobsoleteguids
+#define DiskClassGuid GUID_DEVINTERFACE_DISK
+#define CdRomClassGuid GUID_DEVINTERFACE_CDROM
+#define PartitionClassGuid GUID_DEVINTERFACE_PARTITION
+#define TapeClassGuid GUID_DEVINTERFACE_TAPE
+#define WriteOnceDiskClassGuid GUID_DEVINTERFACE_WRITEONCEDISK
+#define VolumeClassGuid GUID_DEVINTERFACE_VOLUME
+#define MediumChangerClassGuid GUID_DEVINTERFACE_MEDIUMCHANGER
+#define FloppyClassGuid GUID_DEVINTERFACE_FLOPPY
+#define CdChangerClassGuid GUID_DEVINTERFACE_CDCHANGER
+#define StoragePortClassGuid GUID_DEVINTERFACE_STORAGEPORT
+// end_wioctlobsoleteguids
+#endif
+
+// begin_winioctl
+
+#ifndef _NTDDSTOR_H_
+#define _NTDDSTOR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//
+// IoControlCode values for storage devices
+//
+
+#define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE
+
+//
+// The following device control codes are common for all class drivers. They
+// should be used in place of the older IOCTL_DISK, IOCTL_CDROM and IOCTL_TAPE
+// common codes
+//
+
+#define IOCTL_STORAGE_CHECK_VERIFY CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_CHECK_VERIFY2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_MEDIA_REMOVAL CTL_CODE(IOCTL_STORAGE_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_EJECT_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0202, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_LOAD_MEDIA CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_LOAD_MEDIA2 CTL_CODE(IOCTL_STORAGE_BASE, 0x0203, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_RESERVE CTL_CODE(IOCTL_STORAGE_BASE, 0x0204, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_RELEASE CTL_CODE(IOCTL_STORAGE_BASE, 0x0205, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_FIND_NEW_DEVICES CTL_CODE(IOCTL_STORAGE_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_STORAGE_EJECTION_CONTROL CTL_CODE(IOCTL_STORAGE_BASE, 0x0250, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_MCN_CONTROL CTL_CODE(IOCTL_STORAGE_BASE, 0x0251, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define IOCTL_STORAGE_GET_MEDIA_TYPES CTL_CODE(IOCTL_STORAGE_BASE, 0x0300, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_GET_MEDIA_TYPES_EX CTL_CODE(IOCTL_STORAGE_BASE, 0x0301, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0304, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_GET_HOTPLUG_INFO CTL_CODE(IOCTL_STORAGE_BASE, 0x0305, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_SET_HOTPLUG_INFO CTL_CODE(IOCTL_STORAGE_BASE, 0x0306, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_STORAGE_RESET_BUS CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_RESET_DEVICE CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_STORAGE_BREAK_RESERVATION CTL_CODE(IOCTL_STORAGE_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+#define IOCTL_STORAGE_GET_DEVICE_NUMBER CTL_CODE(IOCTL_STORAGE_BASE, 0x0420, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_STORAGE_PREDICT_FAILURE CTL_CODE(IOCTL_STORAGE_BASE, 0x0440, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+// end_winioctl
+
+
+#define IOCTL_STORAGE_QUERY_PROPERTY CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+// begin_winioctl
+
+//
+// These ioctl codes are obsolete. They are defined here to avoid resuing them
+// and to allow class drivers to respond to them more easily.
+//
+
+#define OBSOLETE_IOCTL_STORAGE_RESET_BUS CTL_CODE(IOCTL_STORAGE_BASE, 0x0400, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define OBSOLETE_IOCTL_STORAGE_RESET_DEVICE CTL_CODE(IOCTL_STORAGE_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+
+//
+// IOCTL_STORAGE_GET_HOTPLUG_INFO
+//
+
+typedef struct _STORAGE_HOTPLUG_INFO {
+ ULONG Size; // version
+ BOOLEAN MediaRemovable; // ie. zip, jaz, cdrom, mo, etc. vs hdd
+ BOOLEAN MediaHotplug; // ie. does the device succeed a lock even though its not lockable media?
+ BOOLEAN DeviceHotplug; // ie. 1394, USB, etc.
+ BOOLEAN WriteCacheEnableOverride; // This field should not be relied upon because it is no longer used
+} STORAGE_HOTPLUG_INFO, *PSTORAGE_HOTPLUG_INFO;
+
+//
+// IOCTL_STORAGE_GET_DEVICE_NUMBER
+//
+// input - none
+//
+// output - STORAGE_DEVICE_NUMBER structure
+// The values in the STORAGE_DEVICE_NUMBER structure are guaranteed
+// to remain unchanged until the system is rebooted. They are not
+// guaranteed to be persistant across boots.
+//
+
+/*
+typedef struct _STORAGE_DEVICE_NUMBER {
+
+ //
+ // The FILE_DEVICE_XXX type for this device.
+ //
+
+ DEVICE_TYPE DeviceType;
+
+ //
+ // The number of this device
+ //
+
+ ULONG DeviceNumber;
+
+ //
+ // If the device is partitionable, the partition number of the device.
+ // Otherwise -1
+ //
+
+ ULONG PartitionNumber;
+} STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER;
+*/
+
+//
+// Define the structures for scsi resets
+//
+
+typedef struct _STORAGE_BUS_RESET_REQUEST {
+ UCHAR PathId;
+} STORAGE_BUS_RESET_REQUEST, *PSTORAGE_BUS_RESET_REQUEST;
+
+//
+// IOCTL_STORAGE_MEDIA_REMOVAL disables the mechanism
+// on a storage device that ejects media. This function
+// may or may not be supported on storage devices that
+// support removable media.
+//
+// TRUE means prevent media from being removed.
+// FALSE means allow media removal.
+//
+
+typedef struct _PREVENT_MEDIA_REMOVAL {
+ BOOLEAN PreventMediaRemoval;
+} PREVENT_MEDIA_REMOVAL, *PPREVENT_MEDIA_REMOVAL;
+
+// begin_ntminitape
+
+
+typedef struct _TAPE_STATISTICS {
+ ULONG Version;
+ ULONG Flags;
+ LARGE_INTEGER RecoveredWrites;
+ LARGE_INTEGER UnrecoveredWrites;
+ LARGE_INTEGER RecoveredReads;
+ LARGE_INTEGER UnrecoveredReads;
+ UCHAR CompressionRatioReads;
+ UCHAR CompressionRatioWrites;
+} TAPE_STATISTICS, *PTAPE_STATISTICS;
+
+#define RECOVERED_WRITES_VALID 0x00000001
+#define UNRECOVERED_WRITES_VALID 0x00000002
+#define RECOVERED_READS_VALID 0x00000004
+#define UNRECOVERED_READS_VALID 0x00000008
+#define WRITE_COMPRESSION_INFO_VALID 0x00000010
+#define READ_COMPRESSION_INFO_VALID 0x00000020
+
+typedef struct _TAPE_GET_STATISTICS {
+ ULONG Operation;
+} TAPE_GET_STATISTICS, *PTAPE_GET_STATISTICS;
+
+#define TAPE_RETURN_STATISTICS 0L
+#define TAPE_RETURN_ENV_INFO 1L
+#define TAPE_RESET_STATISTICS 2L
+
+//
+// IOCTL_STORAGE_GET_MEDIA_TYPES_EX will return an array of DEVICE_MEDIA_INFO
+// structures, one per supported type, embedded in the GET_MEDIA_TYPES struct.
+//
+
+typedef enum _STORAGE_MEDIA_TYPE {
+ //
+ // Following are defined in ntdddisk.h in the MEDIA_TYPE enum
+ //
+ // Unknown, // Format is unknown
+ // F5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector
+ // F3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector
+ // F3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector
+ // F3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector
+ // F3_720_512, // 3.5", 720KB, 512 bytes/sector
+ // F5_360_512, // 5.25", 360KB, 512 bytes/sector
+ // F5_320_512, // 5.25", 320KB, 512 bytes/sector
+ // F5_320_1024, // 5.25", 320KB, 1024 bytes/sector
+ // F5_180_512, // 5.25", 180KB, 512 bytes/sector
+ // F5_160_512, // 5.25", 160KB, 512 bytes/sector
+ // RemovableMedia, // Removable media other than floppy
+ // FixedMedia, // Fixed hard disk media
+ // F3_120M_512, // 3.5", 120M Floppy
+ // F3_640_512, // 3.5" , 640KB, 512 bytes/sector
+ // F5_640_512, // 5.25", 640KB, 512 bytes/sector
+ // F5_720_512, // 5.25", 720KB, 512 bytes/sector
+ // F3_1Pt2_512, // 3.5" , 1.2Mb, 512 bytes/sector
+ // F3_1Pt23_1024, // 3.5" , 1.23Mb, 1024 bytes/sector
+ // F5_1Pt23_1024, // 5.25", 1.23MB, 1024 bytes/sector
+ // F3_128Mb_512, // 3.5" MO 128Mb 512 bytes/sector
+ // F3_230Mb_512, // 3.5" MO 230Mb 512 bytes/sector
+ // F8_256_128, // 8", 256KB, 128 bytes/sector
+ // F3_200Mb_512, // 3.5", 200M Floppy (HiFD)
+ //
+
+ DDS_4mm = 0x20, // Tape - DAT DDS1,2,... (all vendors)
+ MiniQic, // Tape - miniQIC Tape
+ Travan, // Tape - Travan TR-1,2,3,...
+ QIC, // Tape - QIC
+ MP_8mm, // Tape - 8mm Exabyte Metal Particle
+ AME_8mm, // Tape - 8mm Exabyte Advanced Metal Evap
+ AIT1_8mm, // Tape - 8mm Sony AIT
+ DLT, // Tape - DLT Compact IIIxt, IV
+ NCTP, // Tape - Philips NCTP
+ IBM_3480, // Tape - IBM 3480
+ IBM_3490E, // Tape - IBM 3490E
+ IBM_Magstar_3590, // Tape - IBM Magstar 3590
+ IBM_Magstar_MP, // Tape - IBM Magstar MP
+ STK_DATA_D3, // Tape - STK Data D3
+ SONY_DTF, // Tape - Sony DTF
+ DV_6mm, // Tape - 6mm Digital Video
+ DMI, // Tape - Exabyte DMI and compatibles
+ SONY_D2, // Tape - Sony D2S and D2L
+ CLEANER_CARTRIDGE, // Cleaner - All Drive types that support Drive Cleaners
+ CD_ROM, // Opt_Disk - CD
+ CD_R, // Opt_Disk - CD-Recordable (Write Once)
+ CD_RW, // Opt_Disk - CD-Rewriteable
+ DVD_ROM, // Opt_Disk - DVD-ROM
+ DVD_R, // Opt_Disk - DVD-Recordable (Write Once)
+ DVD_RW, // Opt_Disk - DVD-Rewriteable
+ MO_3_RW, // Opt_Disk - 3.5" Rewriteable MO Disk
+ MO_5_WO, // Opt_Disk - MO 5.25" Write Once
+ MO_5_RW, // Opt_Disk - MO 5.25" Rewriteable (not LIMDOW)
+ MO_5_LIMDOW, // Opt_Disk - MO 5.25" Rewriteable (LIMDOW)
+ PC_5_WO, // Opt_Disk - Phase Change 5.25" Write Once Optical
+ PC_5_RW, // Opt_Disk - Phase Change 5.25" Rewriteable
+ PD_5_RW, // Opt_Disk - PhaseChange Dual Rewriteable
+ ABL_5_WO, // Opt_Disk - Ablative 5.25" Write Once Optical
+ PINNACLE_APEX_5_RW, // Opt_Disk - Pinnacle Apex 4.6GB Rewriteable Optical
+ SONY_12_WO, // Opt_Disk - Sony 12" Write Once
+ PHILIPS_12_WO, // Opt_Disk - Philips/LMS 12" Write Once
+ HITACHI_12_WO, // Opt_Disk - Hitachi 12" Write Once
+ CYGNET_12_WO, // Opt_Disk - Cygnet/ATG 12" Write Once
+ KODAK_14_WO, // Opt_Disk - Kodak 14" Write Once
+ MO_NFR_525, // Opt_Disk - Near Field Recording (Terastor)
+ NIKON_12_RW, // Opt_Disk - Nikon 12" Rewriteable
+ IOMEGA_ZIP, // Mag_Disk - Iomega Zip
+ IOMEGA_JAZ, // Mag_Disk - Iomega Jaz
+ SYQUEST_EZ135, // Mag_Disk - Syquest EZ135
+ SYQUEST_EZFLYER, // Mag_Disk - Syquest EzFlyer
+ SYQUEST_SYJET, // Mag_Disk - Syquest SyJet
+ AVATAR_F2, // Mag_Disk - 2.5" Floppy
+ MP2_8mm, // Tape - 8mm Hitachi
+ DST_S, // Ampex DST Small Tapes
+ DST_M, // Ampex DST Medium Tapes
+ DST_L, // Ampex DST Large Tapes
+ VXATape_1, // Ecrix 8mm Tape
+ VXATape_2, // Ecrix 8mm Tape
+ STK_9840, // STK 9840
+ LTO_Ultrium, // IBM, HP, Seagate LTO Ultrium
+ LTO_Accelis, // IBM, HP, Seagate LTO Accelis
+ DVD_RAM, // Opt_Disk - DVD-RAM
+ AIT_8mm, // AIT2 or higher
+ ADR_1, // OnStream ADR Mediatypes
+ ADR_2
+} STORAGE_MEDIA_TYPE, *PSTORAGE_MEDIA_TYPE;
+
+#define MEDIA_ERASEABLE 0x00000001
+#define MEDIA_WRITE_ONCE 0x00000002
+#define MEDIA_READ_ONLY 0x00000004
+#define MEDIA_READ_WRITE 0x00000008
+
+#define MEDIA_WRITE_PROTECTED 0x00000100
+#define MEDIA_CURRENTLY_MOUNTED 0x80000000
+
+//
+// Define the different storage bus types
+// Bus types below 128 (0x80) are reserved for Microsoft use
+//
+
+typedef enum _STORAGE_BUS_TYPE {
+ BusTypeUnknown = 0x00,
+ BusTypeScsi,
+ BusTypeAtapi,
+ BusTypeAta,
+ BusType1394,
+ BusTypeSsa,
+ BusTypeFibre,
+ BusTypeUsb,
+ BusTypeRAID,
+ BusTypeMaxReserved = 0x7F
+} STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE;
+
+typedef struct _DEVICE_MEDIA_INFO {
+ union {
+ struct {
+ LARGE_INTEGER Cylinders;
+ STORAGE_MEDIA_TYPE MediaType;
+ ULONG TracksPerCylinder;
+ ULONG SectorsPerTrack;
+ ULONG BytesPerSector;
+ ULONG NumberMediaSides;
+ ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values.
+ } DiskInfo;
+
+ struct {
+ LARGE_INTEGER Cylinders;
+ STORAGE_MEDIA_TYPE MediaType;
+ ULONG TracksPerCylinder;
+ ULONG SectorsPerTrack;
+ ULONG BytesPerSector;
+ ULONG NumberMediaSides;
+ ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values.
+ } RemovableDiskInfo;
+
+ struct {
+ STORAGE_MEDIA_TYPE MediaType;
+ ULONG MediaCharacteristics; // Bitmask of MEDIA_XXX values.
+ ULONG CurrentBlockSize;
+ STORAGE_BUS_TYPE BusType;
+
+ //
+ // Bus specific information describing the medium supported.
+ //
+
+ union {
+ struct {
+ UCHAR MediumType;
+ UCHAR DensityCode;
+ } ScsiInformation;
+ } BusSpecificData;
+
+ } TapeInfo;
+ } DeviceSpecific;
+} DEVICE_MEDIA_INFO, *PDEVICE_MEDIA_INFO;
+
+typedef struct _GET_MEDIA_TYPES {
+ ULONG DeviceType; // FILE_DEVICE_XXX values
+ ULONG MediaInfoCount;
+ DEVICE_MEDIA_INFO MediaInfo[1];
+} GET_MEDIA_TYPES, *PGET_MEDIA_TYPES;
+
+
+//
+// IOCTL_STORAGE_PREDICT_FAILURE
+//
+// input - none
+//
+// output - STORAGE_PREDICT_FAILURE structure
+// PredictFailure returns zero if no failure predicted and non zero
+// if a failure is predicted.
+//
+// VendorSpecific returns 512 bytes of vendor specific information
+// if a failure is predicted
+//
+typedef struct _STORAGE_PREDICT_FAILURE
+{
+ ULONG PredictFailure;
+ UCHAR VendorSpecific[512];
+} STORAGE_PREDICT_FAILURE, *PSTORAGE_PREDICT_FAILURE;
+
+// end_ntminitape
+// end_winioctl
+
+//
+// Property Query Structures
+//
+
+//
+// IOCTL_STORAGE_QUERY_PROPERTY
+//
+// Input Buffer:
+// a STORAGE_PROPERTY_QUERY structure which describes what type of query
+// is being done, what property is being queried for, and any additional
+// parameters which a particular property query requires.
+//
+// Output Buffer:
+// Contains a buffer to place the results of the query into. Since all
+// property descriptors can be cast into a STORAGE_DESCRIPTOR_HEADER,
+// the IOCTL can be called once with a small buffer then again using
+// a buffer as large as the header reports is necessary.
+//
+
+
+//
+// Types of queries
+//
+
+typedef enum _STORAGE_QUERY_TYPE {
+ PropertyStandardQuery = 0, // Retrieves the descriptor
+ PropertyExistsQuery, // Used to test whether the descriptor is supported
+ PropertyMaskQuery, // Used to retrieve a mask of writeable fields in the descriptor
+ PropertyQueryMaxDefined // use to validate the value
+} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;
+
+//
+// define some initial property id's
+//
+
+typedef enum _STORAGE_PROPERTY_ID {
+ StorageDeviceProperty = 0,
+ StorageAdapterProperty,
+ StorageDeviceIdProperty
+} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
+
+//
+// Query structure - additional parameters for specific queries can follow
+// the header
+//
+
+typedef struct _STORAGE_PROPERTY_QUERY {
+
+ //
+ // ID of the property being retrieved
+ //
+
+ STORAGE_PROPERTY_ID PropertyId;
+
+ //
+ // Flags indicating the type of query being performed
+ //
+
+ STORAGE_QUERY_TYPE QueryType;
+
+ //
+ // Space for additional parameters if necessary
+ //
+
+ UCHAR AdditionalParameters[1];
+
+} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;
+
+//
+// Standard property descriptor header. All property pages should use this
+// as their first element or should contain these two elements
+//
+
+typedef struct _STORAGE_DESCRIPTOR_HEADER {
+
+ ULONG Version;
+
+ ULONG Size;
+
+} STORAGE_DESCRIPTOR_HEADER, *PSTORAGE_DESCRIPTOR_HEADER;
+
+//
+// Device property descriptor - this is really just a rehash of the inquiry
+// data retrieved from a scsi device
+//
+// This may only be retrieved from a target device. Sending this to the bus
+// will result in an error
+//
+
+typedef struct _STORAGE_DEVICE_DESCRIPTOR {
+
+ //
+ // Sizeof(STORAGE_DEVICE_DESCRIPTOR)
+ //
+
+ ULONG Version;
+
+ //
+ // Total size of the descriptor, including the space for additional
+ // data and id strings
+ //
+
+ ULONG Size;
+
+ //
+ // The SCSI-2 device type
+ //
+
+ UCHAR DeviceType;
+
+ //
+ // The SCSI-2 device type modifier (if any) - this may be zero
+ //
+
+ UCHAR DeviceTypeModifier;
+
+ //
+ // Flag indicating whether the device's media (if any) is removable. This
+ // field should be ignored for media-less devices
+ //
+
+ BOOLEAN RemovableMedia;
+
+ //
+ // Flag indicating whether the device can support mulitple outstanding
+ // commands. The actual synchronization in this case is the responsibility
+ // of the port driver.
+ //
+
+ BOOLEAN CommandQueueing;
+
+ //
+ // Byte offset to the zero-terminated ascii string containing the device's
+ // vendor id string. For devices with no such ID this will be zero
+ //
+
+ ULONG VendorIdOffset;
+
+ //
+ // Byte offset to the zero-terminated ascii string containing the device's
+ // product id string. For devices with no such ID this will be zero
+ //
+
+ ULONG ProductIdOffset;
+
+ //
+ // Byte offset to the zero-terminated ascii string containing the device's
+ // product revision string. For devices with no such string this will be
+ // zero
+ //
+
+ ULONG ProductRevisionOffset;
+
+ //
+ // Byte offset to the zero-terminated ascii string containing the device's
+ // serial number. For devices with no serial number this will be zero
+ //
+
+ ULONG SerialNumberOffset;
+
+ //
+ // Contains the bus type (as defined above) of the device. It should be
+ // used to interpret the raw device properties at the end of this structure
+ // (if any)
+ //
+
+ STORAGE_BUS_TYPE BusType;
+
+ //
+ // The number of bytes of bus-specific data which have been appended to
+ // this descriptor
+ //
+
+ ULONG RawPropertiesLength;
+
+ //
+ // Place holder for the first byte of the bus specific property data
+ //
+
+ UCHAR RawDeviceProperties[1];
+
+} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;
+
+
+//
+// Adapter properties
+//
+// This descriptor can be retrieved from a target device object of from the
+// device object for the bus. Retrieving from the target device object will
+// forward the request to the underlying bus
+//
+
+typedef struct _STORAGE_ADAPTER_DESCRIPTOR {
+
+ ULONG Version;
+
+ ULONG Size;
+
+ ULONG MaximumTransferLength;
+
+ ULONG MaximumPhysicalPages;
+
+ ULONG AlignmentMask;
+
+ BOOLEAN AdapterUsesPio;
+
+ BOOLEAN AdapterScansDown;
+
+ BOOLEAN CommandQueueing;
+
+ BOOLEAN AcceleratedTransfer;
+
+ UCHAR BusType;
+
+ USHORT BusMajorVersion;
+
+ USHORT BusMinorVersion;
+
+} STORAGE_ADAPTER_DESCRIPTOR, *PSTORAGE_ADAPTER_DESCRIPTOR;
+
+//
+// Storage identification descriptor.
+// The definitions here are based on the SCSI/SBP vital product data
+// device identifier page.
+//
+
+typedef enum _STORAGE_IDENTIFIER_CODE_SET {
+ StorageIdCodeSetReserved = 0,
+ StorageIdCodeSetBinary = 1,
+ StorageIdCodeSetAscii = 2
+} STORAGE_IDENTIFIER_CODE_SET, *PSTORAGE_IDENTIFIER_CODE_SET;
+
+typedef enum _STORAGE_IDENTIFIER_TYPE {
+ StorageIdTypeVendorSpecific = 0,
+ StorageIdTypeVendorId = 1,
+ StorageIdTypeEUI64 = 2,
+ StorageIdTypeFCPHName = 3,
+ StorageIdTypePortRelative = 4
+} STORAGE_IDENTIFIER_TYPE, *PSTORAGE_IDENTIFIER_TYPE;
+
+typedef enum _STORAGE_ASSOCIATION_TYPE {
+ StorageIdAssocDevice = 0,
+ StorageIdAssocPort = 1
+} STORAGE_ASSOCIATION_TYPE, *PSTORAGE_ASSOCIATION_TYPE;
+
+typedef struct _STORAGE_IDENTIFIER {
+ STORAGE_IDENTIFIER_CODE_SET CodeSet;
+ STORAGE_IDENTIFIER_TYPE Type;
+ USHORT IdentifierSize;
+ USHORT NextOffset;
+
+ //
+ // Add new fields here since existing code depends on
+ // the above layout not changing.
+ //
+
+ STORAGE_ASSOCIATION_TYPE Association;
+
+ //
+ // The identifier is a variable length array of bytes.
+ //
+
+ UCHAR Identifier[1];
+} STORAGE_IDENTIFIER, *PSTORAGE_IDENTIFIER;
+
+typedef struct _STORAGE_DEVICE_ID_DESCRIPTOR {
+
+ ULONG Version;
+
+ ULONG Size;
+
+ //
+ // The number of identifiers reported by the device.
+ //
+
+ ULONG NumberOfIdentifiers;
+
+ //
+ // The following field is actually a variable length array of identification
+ // descriptors. Unfortunately there's no C notation for an array of
+ // variable length structures so we're forced to just pretend.
+ //
+
+ UCHAR Identifiers[1];
+} STORAGE_DEVICE_ID_DESCRIPTOR, *PSTORAGE_DEVICE_ID_DESCRIPTOR;
+
+
+#pragma warning(push)
+#pragma warning(disable:4200)
+typedef struct _STORAGE_MEDIA_SERIAL_NUMBER_DATA {
+
+ USHORT Reserved;
+
+ //
+ // the SerialNumberLength will be set to zero
+ // if the command is supported and the media
+ // does not have a valid serial number.
+ //
+
+ USHORT SerialNumberLength;
+
+ //
+ // the following data is binary, and is not guaranteed
+ // to be NULL terminated. this is an excercise for the
+ // caller.
+ //
+
+ UCHAR SerialNumber[0];
+
+} STORAGE_MEDIA_SERIAL_NUMBER_DATA, *PSTORAGE_MEDIA_SERIAL_NUMBER_DATA;
+#pragma warning(push)
+
+
+// begin_winioctl
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _NTDDSTOR_H_
+// end_winioctl
diff --git a/ShutdownWithUpdates/ShutdownWithUpdates/resource.h b/ShutdownWithUpdates/ShutdownWithUpdates/resource.h
new file mode 100644
index 0000000..3135896
--- /dev/null
+++ b/ShutdownWithUpdates/ShutdownWithUpdates/resource.h
@@ -0,0 +1,34 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by ShutdownWithUpdates.rc
+//
+#define IDS_STRING101 101
+#define IDS_STRING102 102
+#define IDS_STRING103 103
+#define IDS_STRING104 104
+#define IDS_STRING105 105
+#define IDS_STRING106 106
+#define IDS_STRING107 107
+#define IDS_STRING108 108
+#define IDS_STRING109 109
+#define IDS_STRING110 110
+#define IDS_STRING111 111
+#define IDS_STRING112 112
+#define IDS_STRING113 113
+#define IDS_STRING114 114
+#define IDS_STRING115 115
+#define IDS_STRING116 116
+#define IDS_STRING117 117
+#define IDS_STRING118 118
+#define IDS_STRING119 119
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 102
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/ShutdownWithUpdates/ShutdownWithUpdates/rtlVersion.h b/ShutdownWithUpdates/ShutdownWithUpdates/rtlVersion.h
new file mode 100644
index 0000000..3e947df
--- /dev/null
+++ b/ShutdownWithUpdates/ShutdownWithUpdates/rtlVersion.h
@@ -0,0 +1,224 @@
+//Determines "true" version of the OS
+
+/*
+ * ShutdownWithUpdates
+ * "Utility To Install Pre-Downloaded Windows Updates & Shutdown/Reboot"
+ * Copyright (c) 2016-2019 www.dennisbabkin.com
+ *
+ * https://dennisbabkin.com/utilities/#ShutdownWithUpdates
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+#pragma once
+
+
+
+#define TXT_SIZEOF(f) ((sizeof(f) / sizeof(f[0])) - 1)
+
+
+struct RTL_OS_VERSION{
+ static BOOL GetVersionEx2(OSVERSIONINFO* pOutVersionInfo, BOOL bAllowOriginalAPIAsFallback = TRUE)
+ {
+ //Retrieve "real" OS version
+ //INFO: It uses kernel-mode API that does not depend on the manifest included in the executable!
+ //'pOutVersionInfo' = struct to fill in, may point to OSVERSIONINFO or OSVERSIONINFOEX structs
+ // INFO: Make sure to fill in its 'dwOSVersionInfoSize' to the struct size!
+ //'bAllowOriginalAPIAsFallback' = TRUE to use original "deprecated" API if this kernel-mode fails, FALSE - not to
+ //RETURN:
+ // = TRUE if success
+ // = FALSE if error (check GetLastError() for info)
+ BOOL bRes = FALSE;
+ int nOSError = NO_ERROR;
+
+ if(pOutVersionInfo)
+ {
+ //Get info
+ RTL_OSVERSIONINFOEXW ver = {0};
+ if(__rtl_get_version(ver))
+ {
+ //Check struct size
+ if(pOutVersionInfo->dwOSVersionInfoSize == sizeof(OSVERSIONINFO))
+ {
+ //Smaller struct
+ pOutVersionInfo->dwMajorVersion = ver.dwMajorVersion;
+ pOutVersionInfo->dwMinorVersion = ver.dwMinorVersion;
+ pOutVersionInfo->dwBuildNumber = ver.dwBuildNumber;
+ pOutVersionInfo->dwPlatformId = ver.dwPlatformId;
+
+ if(TXT_SIZEOF(pOutVersionInfo->szCSDVersion) == TXT_SIZEOF(ver.szCSDVersion))
+ {
+#ifdef UNICODE
+ //Unicode version
+ memcpy(pOutVersionInfo->szCSDVersion, ver.szCSDVersion, sizeof(ver.szCSDVersion));
+#else
+ //ANSI version
+ ver.szCSDVersion[(sizeof(ver.szCSDVersion) / sizeof(ver.szCSDVersion[0])) - 1] = 0;
+
+ int nLn = lstrlenW(ver.szCSDVersion);
+ if(nLn > TXT_SIZEOF(pOutVersionInfo->szCSDVersion))
+ nLn = TXT_SIZEOF(pOutVersionInfo->szCSDVersion);
+
+ nLn++;
+
+ CHAR* pTgt = pOutVersionInfo->szCSDVersion;
+ pTgt[0] = 0;
+ ::WideCharToMultiByte(CP_ACP, 0, ver.szCSDVersion, nLn, pTgt, nLn, NULL, NULL);
+ pTgt[(sizeof(pOutVersionInfo->szCSDVersion) / sizeof(pOutVersionInfo->szCSDVersion[0])) - 1] = 0;
+#endif
+
+ //Done
+ bRes = TRUE;
+ }
+ else
+ nOSError = ERROR_INVALID_BLOCK_LENGTH;
+ }
+ else if(pOutVersionInfo->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEX))
+ {
+ //Larger struct
+ ((OSVERSIONINFOEX*)pOutVersionInfo)->dwMajorVersion = ver.dwMajorVersion;
+ ((OSVERSIONINFOEX*)pOutVersionInfo)->dwMinorVersion = ver.dwMinorVersion;
+ ((OSVERSIONINFOEX*)pOutVersionInfo)->dwBuildNumber = ver.dwBuildNumber;
+ ((OSVERSIONINFOEX*)pOutVersionInfo)->dwPlatformId = ver.dwPlatformId;
+ ((OSVERSIONINFOEX*)pOutVersionInfo)->wServicePackMajor = ver.wServicePackMajor;
+ ((OSVERSIONINFOEX*)pOutVersionInfo)->wServicePackMinor = ver.wServicePackMinor;
+ ((OSVERSIONINFOEX*)pOutVersionInfo)->wSuiteMask = ver.wSuiteMask;
+ ((OSVERSIONINFOEX*)pOutVersionInfo)->wProductType = ver.wProductType;
+ ((OSVERSIONINFOEX*)pOutVersionInfo)->wReserved = ver.wReserved;
+
+ if(TXT_SIZEOF(((OSVERSIONINFOEX*)pOutVersionInfo)->szCSDVersion) == TXT_SIZEOF(ver.szCSDVersion))
+ {
+#ifdef UNICODE
+ //Unicode version
+ memcpy(((OSVERSIONINFOEX*)pOutVersionInfo)->szCSDVersion, ver.szCSDVersion, sizeof(ver.szCSDVersion));
+#else
+ //ANSI version
+ ver.szCSDVersion[(sizeof(ver.szCSDVersion) / sizeof(ver.szCSDVersion[0])) - 1] = 0;
+
+ int nLn = lstrlenW(ver.szCSDVersion);
+ if(nLn > TXT_SIZEOF(((OSVERSIONINFOEX*)pOutVersionInfo)->szCSDVersion))
+ nLn = TXT_SIZEOF(((OSVERSIONINFOEX*)pOutVersionInfo)->szCSDVersion);
+
+ nLn++;
+
+ CHAR* pTgt = ((OSVERSIONINFOEX*)pOutVersionInfo)->szCSDVersion;
+ pTgt[0] = 0;
+ ::WideCharToMultiByte(CP_ACP, 0, ver.szCSDVersion, nLn, pTgt, nLn, NULL, NULL);
+ pTgt[(sizeof(((OSVERSIONINFOEX*)pOutVersionInfo)->szCSDVersion) / sizeof(((OSVERSIONINFOEX*)pOutVersionInfo)->szCSDVersion[0])) - 1] = 0;
+#endif
+
+ //Done
+ bRes = TRUE;
+ }
+ else
+ nOSError = ERROR_INVALID_BLOCK_LENGTH;
+ }
+ else
+ nOSError = ERROR_INSUFFICIENT_BUFFER;
+ }
+ else
+ nOSError = ::GetLastError();
+
+ //Did we fail?
+ if(!bRes &&
+ bAllowOriginalAPIAsFallback)
+ {
+ //Use original API as a fall-back
+ bRes = ::GetVersionEx(pOutVersionInfo);
+ nOSError = ::GetLastError();
+ }
+ }
+ else
+ nOSError = ERROR_INVALID_PARAMETER;
+
+ ::SetLastError(nOSError);
+ return bRes;
+ }
+
+ static DWORD ConvertNtStatusToWin32Error(LONG ntstatus)
+ {
+ //For more info on error codes check:
+ // http://msdn.microsoft.com/en-us/library/cc704588.aspx
+ // http://support.microsoft.com/kb/113996
+ // and
+ // http://www.cprogramming.com/snippets/source-code/convert-ntstatus-win32-error
+ //RETURN:
+ // = GetLastError() type error for 'ntstatus', or
+ // = unaltered 'ntstatus' as the last resort
+ DWORD result;
+ DWORD br = 0;
+ OVERLAPPED o = {0};
+
+ o.Internal = ntstatus;
+
+ ::GetOverlappedResult(NULL, &o, &br, FALSE);
+ result = GetLastError();
+
+ if(result == NO_ERROR)
+ {
+ //Failed
+ result = ntstatus;
+ }
+
+ ::SetLastError(result);
+ return result;
+ }
+
+
+private:
+ static BOOL __rtl_get_version(RTL_OSVERSIONINFOEXW& verOut)
+ {
+ //Try to use kernel-mode API that doesn't "lie" about the results
+ BOOL bRes = FALSE;
+ int nOSError = NO_ERROR;
+
+ __try
+ {
+ LONG (WINAPI *pfnRtlGetVersion)(RTL_OSVERSIONINFOEXW*);
+ (FARPROC&)pfnRtlGetVersion = GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "RtlGetVersion");
+ if(pfnRtlGetVersion)
+ {
+ verOut.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
+
+ LONG status = pfnRtlGetVersion(&verOut);
+ if(status == 0) //STATUS_SUCCESS
+ {
+ bRes = TRUE;
+ }
+ else
+ {
+ //Convert to Win32 error code
+ nOSError = ConvertNtStatusToWin32Error(status);
+ }
+ }
+ else
+ nOSError = ERROR_NOT_SUPPORTED;
+ }
+ __except(1)
+ {
+ //Failed
+ bRes = FALSE;
+ nOSError = ERROR_ARENA_TRASHED;
+ }
+
+ ::SetLastError(nOSError);
+ return bRes;
+ }
+};
+
+
+
+
diff --git a/ShutdownWithUpdates/ShutdownWithUpdates/stdafx.cpp b/ShutdownWithUpdates/ShutdownWithUpdates/stdafx.cpp
new file mode 100644
index 0000000..a62437a
--- /dev/null
+++ b/ShutdownWithUpdates/ShutdownWithUpdates/stdafx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// ShutdownWithUpdates.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/ShutdownWithUpdates/ShutdownWithUpdates/stdafx.h b/ShutdownWithUpdates/ShutdownWithUpdates/stdafx.h
new file mode 100644
index 0000000..73be216
--- /dev/null
+++ b/ShutdownWithUpdates/ShutdownWithUpdates/stdafx.h
@@ -0,0 +1,46 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#include "targetver.h"
+
+#include
+#include
+
+
+
+// TODO: reference additional headers your program requires here
+
+#include
+#include
+
+#include
+
+#include
+
+
+#include "AltStreams.h" //Needed for CheckForXP_SP2_FileBlockAndRemoveIt()
+#include "ntddstor.h" //Needed for CheckForXP_SP2_FileBlockAndRemoveIt()
+
+#include "rtlVersion.h"
+
+
+#define PROG_VER L"1.2.1.0" //Program version
+
+
+
+#define SIZEOF(f) (sizeof(f)/sizeof(f[0]))
+
+#ifndef ASSERT
+#ifdef _DEBUG
+#define ASSERT(f) if(!(f)){char ___bf029[1024]; ::StringCchPrintfA(___bf029, 1024, "Assertion Failed:\n\nFile: %s\nLine: %d", __FILE__, __LINE__); ::MessageBoxA(NULL, ___bf029, "** ASSERTION **", MB_ICONERROR | MB_OK);}
+#else
+#define ASSERT(f)
+#endif
+#endif
+
+
+
diff --git a/ShutdownWithUpdates/ShutdownWithUpdates/targetver.h b/ShutdownWithUpdates/ShutdownWithUpdates/targetver.h
new file mode 100644
index 0000000..a38195a
--- /dev/null
+++ b/ShutdownWithUpdates/ShutdownWithUpdates/targetver.h
@@ -0,0 +1,13 @@
+#pragma once
+
+// The following macros define the minimum required platform. The minimum required platform
+// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
+// your application. The macros work by enabling all features available on platform versions up to and
+// including the version specified.
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
+#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
+#endif
+