+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS shutdown/logoff utility
+ * FILE: base/applications/shutdown/misc.c
+ * PURPOSE: Misc. functions used for the shutdown utility
+ * PROGRAMMERS: Lee Schroeder
+ */
+
#include "precomp.h"
-static INT
-LengthOfStrResource(IN HINSTANCE hInst,
- IN UINT uID)
+const DWORD defaultReason = SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER;
+
+REASON shutdownReason[] =
{
- HRSRC hrSrc;
- HGLOBAL hRes;
- LPWSTR lpName, lpStr;
+ {L"U" , 0, 0, SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER}, /* Other (Unplanned) */
+ {L"E" , 0, 0, SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER}, /* Other (Unplanned) */
+ {L"EP", 0, 0, SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED}, /* Other (Planned) */
+ {L"U" , 0, 5, SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_HUNG}, /* Other Failure: System Unresponsive */
+ {L"E" , 1, 1, SHTDN_REASON_MAJOR_HARDWARE | SHTDN_REASON_MINOR_MAINTENANCE}, /* Hardware: Maintenance (Unplanned) */
+ {L"EP", 1, 1, SHTDN_REASON_MAJOR_HARDWARE | SHTDN_REASON_MINOR_MAINTENANCE | SHTDN_REASON_FLAG_PLANNED}, /* Hardware: Maintenance (Planned) */
+ {L"E" , 1, 2, SHTDN_REASON_MAJOR_HARDWARE | SHTDN_REASON_MINOR_INSTALLATION}, /* Hardware: Installation (Unplanned) */
+ {L"EP", 1, 2, SHTDN_REASON_MAJOR_HARDWARE | SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED}, /* Hardware: Installation (Planned) */
+ {L"P" , 2, 3, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_UPGRADE | SHTDN_REASON_FLAG_PLANNED}, /* Operating System: Upgrade (Planned) */
+ {L"E" , 2, 4, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_RECONFIG}, /* Operating System: Reconfiguration (Unplanned) */
+ {L"EP", 2, 4, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_RECONFIG | SHTDN_REASON_FLAG_PLANNED}, /* Operating System: Reconfiguration (Planned) */
+ {L"P" , 2, 16, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_RECONFIG | SHTDN_REASON_FLAG_PLANNED}, /* Operating System: Service pack (Planned) */
+ {L"U" , 2, 17, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_HOTFIX}, /* Operating System: Hotfix (Unplanned) */
+ {L"P" , 2, 17, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_HOTFIX | SHTDN_REASON_FLAG_PLANNED}, /* Operating System: Hotfix (Planned) */
+ {L"U" , 2, 18, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_SECURITYFIX}, /* Operating System: Security fix (Unplanned) */
+ {L"P" , 2, 18, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_SECURITYFIX | SHTDN_REASON_FLAG_PLANNED}, /* Operating System: Security fix (Planned) */
+ {L"E" , 4, 1, SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_MAINTENANCE}, /* Application: Maintenance (Unplanned) */
+ {L"EP", 4, 1, SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_MAINTENANCE | SHTDN_REASON_FLAG_PLANNED}, /* Application: Maintenance (Planned) */
+ {L"EP", 4, 2, SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED}, /* Application: Installation (Planned) */
+ {L"E" , 4, 5, SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_HUNG}, /* Application: Unresponsive */
+ {L"E" , 4, 6, SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_UNSTABLE}, /* Application: Unstable */
+ {L"U" , 5, 15, SHTDN_REASON_MAJOR_SYSTEM | SHTDN_REASON_MINOR_BLUESCREEN}, /* System Failure: Stop Error */
+ {L"E" , 5, 19, SHTDN_REASON_MAJOR_SYSTEM | SHTDN_REASON_MINOR_SECURITY}, /* Security Issue */
+ {L"U" , 5, 19, SHTDN_REASON_MAJOR_SYSTEM | SHTDN_REASON_MINOR_SECURITY}, /* Security Issue */
+ {L"EP", 5, 19, SHTDN_REASON_MAJOR_SYSTEM | SHTDN_REASON_MINOR_SECURITY | SHTDN_REASON_FLAG_PLANNED}, /* Security Issue (Planned) */
+ {L"E" , 5, 20, SHTDN_REASON_MAJOR_SYSTEM | SHTDN_REASON_MINOR_NETWORK_CONNECTIVITY}, /* Loss of Network Connectivity (Unplanned) */
+ {L"U" , 6, 11, SHTDN_REASON_MAJOR_POWER | SHTDN_REASON_MINOR_CORDUNPLUGGED}, /* Power Failure: Cord Unplugged */
+ {L"U" , 6, 12, SHTDN_REASON_MAJOR_POWER | SHTDN_REASON_MINOR_ENVIRONMENT}, /* Power Failure: Environment */
+ {L"P" , 7, 0, SHTDN_REASON_MAJOR_POWER | SHTDN_REASON_MINOR_ENVIRONMENT} /* Legacy API shutdown (Planned) */
+};
- if (hInst == NULL)
- {
- return -1;
- }
+/*
+ * This command helps to work around the fact that the shutdown utility has
+ * different upper limits for the comment flag since each version of Windows
+ * seems to have different upper limits.
+ */
+BOOL CheckCommentLength(LPCWSTR comment)
+{
+ DWORD finalLength = 0;
+ size_t strLength = 0;
+ DWORD osVersion = 0;
+ DWORD osMajorVersion = 0;
+ DWORD osMinorVersion = 0;
- /* There are always blocks of 16 strings */
- lpName = (LPWSTR)MAKEINTRESOURCE((uID >> 4) + 1);
+ /* An empty string is always valid. */
+ if (!comment || *comment == 0)
+ return TRUE;
- /* Find the string table block */
- if ((hrSrc = FindResourceW(hInst, lpName, (LPWSTR)RT_STRING)) &&
- (hRes = LoadResource(hInst, hrSrc)) &&
- (lpStr = (WCHAR*) LockResource(hRes)))
- {
- UINT x;
+ /* Grab the version of the current Operating System. */
+ osVersion = GetVersion();
+
+ osMajorVersion = (DWORD)(LOBYTE(LOWORD(osVersion)));
+ osMinorVersion = (DWORD)(HIBYTE(LOWORD(osVersion)));
- /* Find the string we're looking for */
- uID &= 0xF; /* position in the block, same as % 16 */
- for (x = 0; x < uID; x++)
+ /*
+ * Check to make sure that the proper length is being used
+ * based upon the version of Windows currently being used.
+ */
+ if (osMajorVersion == 5) /* Windows XP/2003 */
+ {
+ if ((osMinorVersion == 1) || (osMinorVersion == 2))
{
- lpStr += (*lpStr) + 1;
+ finalLength = 127;
}
-
- /* Found the string */
- return (int)(*lpStr);
}
- return -1;
+ else if (osMajorVersion == 6) /* Windows Vista/7/2008 */
+ {
+ if ((osMinorVersion == 0) || (osMinorVersion == 1))
+ {
+ finalLength = 512;
+ }
+ }
+
+ /* Grab the length of the comment string. */
+ strLength = wcslen(comment);
+
+ /*
+ * Compare the size of the string to make sure
+ * it fits with the current version of Windows,
+ * and return TRUE or FALSE accordingly.
+ */
+ return (strLength <= finalLength);
}
-INT
-AllocAndLoadString(OUT LPTSTR *lpTarget,
- IN HINSTANCE hInst,
- IN UINT uID)
+/*
+ * This function parses the reason code to a usable format that will specify
+ * why the user wants to shut the computer down. Although this is used for
+ * both client and server environments, use of a reason code is more important
+ * in a server environment since servers are supposed to be on all the time
+ * for easier access.
+ */
+DWORD ParseReasonCode(LPCWSTR code)
{
- INT ln;
+ PREASON reasonptr;
+ int majorCode = 0;
+ int minorCode = 0;
+ LPWSTR tmpPrefix = NULL;
+ size_t codeSize;
- ln = LengthOfStrResource(hInst,
- uID);
- if (ln++ > 0)
+ /* If no reason code is specified, use "Other (Unplanned)" as the default option */
+ if(code == NULL)
{
- (*lpTarget) = (LPTSTR)LocalAlloc(LMEM_FIXED,
- ln * sizeof(TCHAR));
- if ((*lpTarget) != NULL)
+ return defaultReason;
+ }
+ else
+ {
+ /* Store the size of the code so we can use it later */
+ codeSize = (size_t)wcslen(code);
+
+ /* A colon cannot be the first or last character in the reason code */
+ if ((code[0] == L':') || (code[codeSize] == L':'))
{
- INT Ret;
- if (!(Ret = LoadString(hInst, uID, *lpTarget, ln)))
+ return defaultReason;
+ }
+
+ /* The minimum length that a reason code can be is 5-7 characters in length */
+ if ((codeSize < 5) || (codeSize > 7))
+ {
+ return defaultReason;
+ }
+
+ /* TODO: Add code for reason parsing here. */
+
+ /* Make sure that the major and minor codes are within size limits */
+ if ((majorCode > 7 ) || (majorCode < 0) ||
+ (minorCode > 20) || (minorCode < 0))
+ {
+ return defaultReason;
+ }
+
+ /* Figure out what flags to return */
+ for (reasonptr = shutdownReason ; reasonptr->prefix ; reasonptr++)
+ {
+ if ((majorCode == reasonptr->major) &&
+ (minorCode == reasonptr->minor) &&
+ (_wcsicmp(tmpPrefix, reasonptr->prefix) != 0))
{
- LocalFree((HLOCAL)(*lpTarget));
+ return reasonptr->flag;
}
- return Ret;
}
}
- return 0;
+
+ return defaultReason;
}
+
+/* Writes the last error as both text and error code to the console */
+VOID DisplayError(DWORD dwError)
+{
+ LPWSTR lpMsgBuf = NULL;
+ DWORD errLength; /* Error message length */
+ LPSTR resMsg; /* For error message in OEM symbols */
+
+ /* Grabs the length of the error message */
+ errLength = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ dwError,
+ LANG_USER_DEFAULT,
+ (LPWSTR)&lpMsgBuf,
+ 0,
+ NULL) + 1;
+
+ /* Gets the error message ready for output */
+ resMsg = (LPSTR)LocalAlloc(LPTR, errLength * sizeof(WCHAR));
+ CharToOemBuffW(lpMsgBuf, resMsg, errLength);
+
+ /* Prints out the error message to the user */
+ fprintf(stderr, resMsg);
+ fwprintf(stderr, L"Error code: %d\n", dwError);
+
+ LocalFree(lpMsgBuf);
+ LocalFree(resMsg);
+}
+
+/* EOF */