mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 08:25:03 +00:00
[TIMEOUT]: Implement the TIMEOUT utility (found on Win2k3 and upwards). This is an improved "pause" command, with elapsed time count display.
Based from a patch by Lee Schröder, with modifications by myself. CORE-10044 #resolve svn path=/trunk/; revision=75968
This commit is contained in:
parent
d2669dc03b
commit
6b45a088f3
7 changed files with 441 additions and 0 deletions
|
@ -18,6 +18,7 @@ add_subdirectory(reg)
|
|||
add_subdirectory(schtasks)
|
||||
add_subdirectory(sort)
|
||||
add_subdirectory(taskkill)
|
||||
add_subdirectory(timeout)
|
||||
add_subdirectory(tree)
|
||||
add_subdirectory(whoami)
|
||||
add_subdirectory(wmic)
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
||||
|
||||
add_executable(timeout timeout.c timeout.rc)
|
||||
set_module_type(timeout win32cui UNICODE)
|
||||
target_link_libraries(timeout conutils ${PSEH_LIB})
|
||||
add_importlibs(timeout msvcrt kernel32)
|
||||
add_cd_file(TARGET timeout DESTINATION reactos/system32 FOR all)
|
33
reactos/base/applications/cmdutils/timeout/lang/en-US.rc
Normal file
33
reactos/base/applications/cmdutils/timeout/lang/en-US.rc
Normal file
|
@ -0,0 +1,33 @@
|
|||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_USAGE "ReactOS Timeout Utility\n\
|
||||
\n\
|
||||
TIMEOUT [/?] [/T] delay [/NOBREAK]\n\
|
||||
\n\
|
||||
Description:\n\
|
||||
This tool waits until a specified time period (in seconds) has elapsed,\n\
|
||||
or until any key is pressed. A parameter to ignore the key press is also\n\
|
||||
accepted.\n\
|
||||
\n\
|
||||
Parameters:\n\
|
||||
/? Display this help screen.\n\
|
||||
\n\
|
||||
/T delay Specify the number of seconds to wait (-1 to 99999).\n\
|
||||
A value of -1 means the program will wait until a key is pressed.\n\
|
||||
Note that the ""/T"" specification is optional, you can just\n\
|
||||
specify the delay value without it.\n\
|
||||
\n\
|
||||
/NOBREAK Ignore all keyboard input except for Ctrl+C.\n\
|
||||
"
|
||||
IDS_ERROR_OUT_OF_RANGE "ERROR: The timer value must be within range (-1 to 99999).\n"
|
||||
IDS_ERROR_INVALID_HANDLE_VALUE "ERROR: Unable to get the standard handle for the console (error %lu).\n"
|
||||
IDS_ERROR_READ_INPUT "ERROR: Unable to read the console input (error %lu).\n"
|
||||
IDS_ERROR_NO_TIMER_VALUE "ERROR: The timer value must be specified (-1 to 99999).\n"
|
||||
IDS_ERROR_ONE_TIME "ERROR: Only one timer value is needed.\n"
|
||||
IDS_NOBREAK_INPUT "Press Ctrl+C to quit..."
|
||||
IDS_USER_INPUT "Press any key to continue..."
|
||||
IDS_NOBREAK_INPUT_COUNT "Waiting for %d second(s), press Ctrl+C to quit..."
|
||||
IDS_USER_INPUT_COUNT "Waiting for %d second(s), press any key to continue..."
|
||||
END
|
34
reactos/base/applications/cmdutils/timeout/lang/fr-FR.rc
Normal file
34
reactos/base/applications/cmdutils/timeout/lang/fr-FR.rc
Normal file
|
@ -0,0 +1,34 @@
|
|||
LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_USAGE "ReactOS Timeout Utility\n\
|
||||
\n\
|
||||
TIMEOUT [/?] [/T] délai [/NOBREAK]\n\
|
||||
\n\
|
||||
Description :\n\
|
||||
Cet outil permet d'attendre jusqu'à ce qu'un délai (en secondes) s'écoule,\n\
|
||||
ou bien jusqu'à ce qu'une touche de clavier soit pressée. Un paramètre\n\
|
||||
permettant d'ignorer l'appui de touche de clavier est accepté.\n\
|
||||
\n\
|
||||
Liste de paramètres :\n\
|
||||
/? Affiche cet écran d'aide.\n\
|
||||
\n\
|
||||
/T délai Spécifie le délai d'attente en secondes (entre -1 et 99999).\n\
|
||||
La valeur -1 signifie que le programme attend jusqu'à ce qu'une\n\
|
||||
touche soit pressée.\n\
|
||||
Veuillez noter que la spécification ""/T"" est optionnelle, vous\n\
|
||||
pouvez spécifier la valeur de délai sans celle-ci.\n\
|
||||
\n\
|
||||
/NOBREAK Ignore toute frappe de clavier, sauf pour Ctrl+C.\n\
|
||||
"
|
||||
IDS_ERROR_OUT_OF_RANGE "ERREUR: Le délai d'attente doit être compris dans la plage (entre -1 et 99999).\n"
|
||||
IDS_ERROR_INVALID_HANDLE_VALUE "ERREUR: Impossible d'obtenir le handle standard pour la console (erreur %lu).\n"
|
||||
IDS_ERROR_READ_INPUT "ERREUR: Impossible de lire l'entrée de console (erreur %lu).\n"
|
||||
IDS_ERROR_NO_TIMER_VALUE "ERREUR: Le délai d'attente doit être spécifié (entre -1 et 99999).\n"
|
||||
IDS_ERROR_ONE_TIME "ERREUR: Une seule valeur de délai est nécessaire.\n"
|
||||
IDS_NOBREAK_INPUT "Appuyez sur Ctrl+C pour quitter..."
|
||||
IDS_USER_INPUT "Appuyez sur une touche pour continuer..."
|
||||
IDS_NOBREAK_INPUT_COUNT "Attendre %d seconde(s), appuyez sur Ctrl+C pour quitter..."
|
||||
IDS_USER_INPUT_COUNT "Attendre %d seconde(s), appuyez sur une touche pour continuer..."
|
||||
END
|
12
reactos/base/applications/cmdutils/timeout/resource.h
Normal file
12
reactos/base/applications/cmdutils/timeout/resource.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#define IDS_USAGE 0
|
||||
#define IDS_ERROR_OUT_OF_RANGE 1
|
||||
#define IDS_ERROR_INVALID_HANDLE_VALUE 2
|
||||
#define IDS_ERROR_READ_INPUT 3
|
||||
#define IDS_ERROR_NO_TIMER_VALUE 4
|
||||
#define IDS_ERROR_ONE_TIME 5
|
||||
#define IDS_NOBREAK_INPUT 6
|
||||
#define IDS_USER_INPUT 7
|
||||
#define IDS_NOBREAK_INPUT_COUNT 8
|
||||
#define IDS_USER_INPUT_COUNT 9
|
332
reactos/base/applications/cmdutils/timeout/timeout.c
Normal file
332
reactos/base/applications/cmdutils/timeout/timeout.c
Normal file
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Timeout utility
|
||||
* FILE: base/applications/cmdutils/timeout/timeout.c
|
||||
* PURPOSE: An enhanced alternative to the Pause command.
|
||||
* PROGRAMMERS: Lee Schroeder (spaceseel at gmail dot com)
|
||||
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <wincon.h>
|
||||
#include <winuser.h>
|
||||
|
||||
#include <conutils.h>
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
VOID PrintError(DWORD dwError)
|
||||
{
|
||||
if (dwError == ERROR_SUCCESS)
|
||||
return;
|
||||
|
||||
ConMsgPuts(StdErr, FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL, dwError, LANG_USER_DEFAULT);
|
||||
ConPuts(StdErr, L"\n");
|
||||
}
|
||||
|
||||
BOOL
|
||||
WINAPI
|
||||
CtrlCIntercept(DWORD dwCtrlType)
|
||||
{
|
||||
switch (dwCtrlType)
|
||||
{
|
||||
case CTRL_C_EVENT:
|
||||
ConPuts(StdOut, L"\n");
|
||||
SetConsoleCtrlHandler(NULL, FALSE);
|
||||
ExitProcess(EXIT_FAILURE);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
INT InputWait(BOOL bNoBreak, INT timerValue)
|
||||
{
|
||||
INT Status = EXIT_SUCCESS;
|
||||
HANDLE hInput;
|
||||
BOOL bUseTimer = (timerValue != -1);
|
||||
DWORD dwStartTime;
|
||||
LONG timeElapsed;
|
||||
DWORD dwWaitState;
|
||||
INPUT_RECORD InputRecords[5];
|
||||
ULONG NumRecords, i;
|
||||
BOOL DisplayMsg = TRUE;
|
||||
UINT WaitMsgId = (bNoBreak ? IDS_NOBREAK_INPUT : IDS_USER_INPUT);
|
||||
UINT WaitCountMsgId = (bNoBreak ? IDS_NOBREAK_INPUT_COUNT : IDS_USER_INPUT_COUNT);
|
||||
|
||||
/* Retrieve the current input handle */
|
||||
hInput = ConStreamGetOSHandle(StdIn);
|
||||
if (hInput == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ConResPrintf(StdErr, IDS_ERROR_INVALID_HANDLE_VALUE, GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Start a new wait if we use the timer */
|
||||
if (bUseTimer)
|
||||
dwStartTime = GetTickCount();
|
||||
|
||||
/* If /NOBREAK is used, monitor for Ctrl-C input */
|
||||
if (bNoBreak)
|
||||
SetConsoleCtrlHandler(CtrlCIntercept, TRUE);
|
||||
|
||||
/* Initially flush the console input queue to remove any pending events */
|
||||
if (!GetNumberOfConsoleInputEvents(hInput, &NumRecords) ||
|
||||
!FlushConsoleInputBuffer(hInput))
|
||||
{
|
||||
/* A problem happened, bail out */
|
||||
PrintError(GetLastError());
|
||||
Status = EXIT_FAILURE;
|
||||
goto Quit;
|
||||
}
|
||||
|
||||
ConPuts(StdOut, L"\n");
|
||||
|
||||
/* If the timer is not used, just show the message */
|
||||
if (!bUseTimer)
|
||||
{
|
||||
ConPuts(StdOut, L"\r");
|
||||
ConResPuts(StdOut, WaitMsgId);
|
||||
}
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
/* Decrease the timer if we use it */
|
||||
if (bUseTimer)
|
||||
{
|
||||
/*
|
||||
* Compute how much time the previous operations took.
|
||||
* This allows us in particular to take account for any time
|
||||
* elapsed if something slowed down, or if the console has been
|
||||
* paused in the meantime.
|
||||
*/
|
||||
timeElapsed = GetTickCount() - dwStartTime;
|
||||
if (timeElapsed >= 1000)
|
||||
{
|
||||
/* Increase dwStartTime by steps of 1 second */
|
||||
timeElapsed /= 1000;
|
||||
dwStartTime += (1000 * timeElapsed);
|
||||
|
||||
if (timeElapsed <= timerValue)
|
||||
timerValue -= timeElapsed;
|
||||
else
|
||||
timerValue = 0;
|
||||
|
||||
DisplayMsg = TRUE;
|
||||
}
|
||||
|
||||
if (DisplayMsg)
|
||||
{
|
||||
ConPuts(StdOut, L"\r");
|
||||
ConResPrintf(StdOut, WaitCountMsgId, timerValue);
|
||||
ConPuts(StdOut, L" \b");
|
||||
|
||||
DisplayMsg = FALSE;
|
||||
}
|
||||
|
||||
/* Stop when the timer reaches zero */
|
||||
if (timerValue <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If /NOBREAK is used, only allow Ctrl-C input which is handled by the console handler */
|
||||
if (bNoBreak)
|
||||
{
|
||||
if (bUseTimer)
|
||||
{
|
||||
/* We use the timer: wait a little bit before updating it */
|
||||
Sleep(100);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No timer is used: wait indefinitely */
|
||||
Sleep(INFINITE);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* /NOBREAK is not used, check for user key presses */
|
||||
|
||||
/*
|
||||
* If the timer is used, use a passive wait of maximum 1 second
|
||||
* while monitoring for incoming console input events, so that
|
||||
* we are still able to display the timing count.
|
||||
* Indeed, ReadConsoleInputW() indefinitely waits until an input
|
||||
* event appears. ReadConsoleInputW() is however used to retrieve
|
||||
* the input events where there are some, as well as for waiting
|
||||
* indefinitely in case we do not use the timer.
|
||||
*/
|
||||
if (bUseTimer)
|
||||
{
|
||||
/* Wait a maximum of 1 second for input events */
|
||||
timeElapsed = GetTickCount() - dwStartTime;
|
||||
if (timeElapsed < 1000)
|
||||
dwWaitState = WaitForSingleObject(hInput, 1000 - timeElapsed);
|
||||
else
|
||||
dwWaitState = WAIT_TIMEOUT;
|
||||
|
||||
/* Check whether the input handle has been signaled, or a timeout happened */
|
||||
if (dwWaitState == WAIT_TIMEOUT)
|
||||
continue;
|
||||
if (dwWaitState != WAIT_OBJECT_0)
|
||||
{
|
||||
/* An error happened, bail out */
|
||||
PrintError(GetLastError());
|
||||
Status = EXIT_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Be sure there is someting in the console input queue */
|
||||
if (!PeekConsoleInputW(hInput, InputRecords, ARRAYSIZE(InputRecords), &NumRecords))
|
||||
{
|
||||
/* An error happened, bail out */
|
||||
ConResPrintf(StdErr, IDS_ERROR_READ_INPUT, GetLastError());
|
||||
Status = EXIT_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (NumRecords == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some events have been detected, pop them out from the input queue.
|
||||
* In case we do not use the timer, wait indefinitely until an input
|
||||
* event appears.
|
||||
*/
|
||||
if (!ReadConsoleInputW(hInput, InputRecords, ARRAYSIZE(InputRecords), &NumRecords))
|
||||
{
|
||||
/* An error happened, bail out */
|
||||
ConResPrintf(StdErr, IDS_ERROR_READ_INPUT, GetLastError());
|
||||
Status = EXIT_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check the input events for a key press */
|
||||
for (i = 0; i < NumRecords; ++i)
|
||||
{
|
||||
/* Ignore any non-key event */
|
||||
if (InputRecords[i].EventType != KEY_EVENT)
|
||||
continue;
|
||||
|
||||
/* Ignore any system key event */
|
||||
if ((InputRecords[i].Event.KeyEvent.wVirtualKeyCode == VK_CONTROL) ||
|
||||
// (InputRecords[i].Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED )) ||
|
||||
// (InputRecords[i].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) ||
|
||||
(InputRecords[i].Event.KeyEvent.wVirtualKeyCode == VK_MENU))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This is a non-system key event, stop waiting */
|
||||
goto Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Stop:
|
||||
ConPuts(StdOut, L"\n");
|
||||
|
||||
Quit:
|
||||
if (bNoBreak)
|
||||
SetConsoleCtrlHandler(NULL, FALSE);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
int wmain(int argc, WCHAR* argv[])
|
||||
{
|
||||
INT timerValue = -1;
|
||||
PWCHAR pszNext;
|
||||
BOOL bDisableInput = FALSE, fTimerFlags = 0;
|
||||
int index = 0;
|
||||
|
||||
/* Initialize the Console Standard Streams */
|
||||
ConInitStdStreams();
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
ConResPrintf(StdOut, IDS_USAGE);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Parse the command line for options */
|
||||
for (index = 1; index < argc; index++)
|
||||
{
|
||||
if (argv[index][0] == L'-' || argv[index][0] == L'/')
|
||||
{
|
||||
switch (towupper(argv[index][1]))
|
||||
{
|
||||
case L'?': /* Help */
|
||||
{
|
||||
ConResPrintf(StdOut, IDS_USAGE);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
case L'T': /* Timer */
|
||||
{
|
||||
/* Consecutive /T switches are invalid */
|
||||
if (fTimerFlags & 2)
|
||||
{
|
||||
ConResPrintf(StdErr, IDS_ERROR_ONE_TIME);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Remember that a /T switch has been encountered */
|
||||
fTimerFlags |= 2;
|
||||
|
||||
/* Go to the next (timer) value */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* This flag is used to ignore any keyboard keys but Ctrl-C */
|
||||
if (_wcsicmp(&argv[index][1], L"NOBREAK") == 0)
|
||||
{
|
||||
bDisableInput = TRUE;
|
||||
|
||||
/* Go to next value */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* The timer value can also be specified without the /T switch */
|
||||
|
||||
/* Only one timer value is supported */
|
||||
if (fTimerFlags & 1)
|
||||
{
|
||||
ConResPrintf(StdErr, IDS_ERROR_ONE_TIME);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
timerValue = wcstol(argv[index], &pszNext, 10);
|
||||
if (*pszNext)
|
||||
{
|
||||
ConResPrintf(StdErr, IDS_ERROR_OUT_OF_RANGE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Remember that the timer value has been set */
|
||||
fTimerFlags |= 1;
|
||||
}
|
||||
|
||||
/* A timer value is mandatory in order to continue */
|
||||
if (!(fTimerFlags & 1))
|
||||
{
|
||||
ConResPrintf(StdErr, IDS_ERROR_NO_TIMER_VALUE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Make sure the timer value is within range */
|
||||
if ((timerValue < -1) || (timerValue > 99999))
|
||||
{
|
||||
ConResPrintf(StdErr, IDS_ERROR_OUT_OF_RANGE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return InputWait(bDisableInput, timerValue);
|
||||
}
|
21
reactos/base/applications/cmdutils/timeout/timeout.rc
Normal file
21
reactos/base/applications/cmdutils/timeout/timeout.rc
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include <windef.h>
|
||||
// #include <winuser.h>
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Timeout Utility"
|
||||
#define REACTOS_STR_INTERNAL_NAME "timeout"
|
||||
#define REACTOS_STR_ORIGINAL_FILENAME "timeout.exe"
|
||||
#include <reactos/version.rc>
|
||||
|
||||
/* UTF-8 */
|
||||
#pragma code_page(65001)
|
||||
|
||||
#ifdef LANGUAGE_EN_US
|
||||
#include "lang/en-US.rc"
|
||||
#endif
|
||||
#ifdef LANGUAGE_FR_FR
|
||||
#include "lang/fr-FR.rc"
|
||||
#endif
|
Loading…
Reference in a new issue