Pause the console pauser before exiting, when there's some wrong in program execution.

This commit is contained in:
Roy Qu 2024-05-09 21:31:22 +08:00
parent 1a59e3190b
commit 891d29f011
1 changed files with 46 additions and 34 deletions

View File

@ -23,6 +23,7 @@ using std::string;
#include <psapi.h> #include <psapi.h>
#include <processthreadsapi.h> #include <processthreadsapi.h>
#include <conio.h> #include <conio.h>
#include <stdbool.h>
#ifndef WINBOOL #ifndef WINBOOL
#define WINBOOL BOOL #define WINBOOL BOOL
@ -36,6 +37,14 @@ using std::string;
#define MAX_COMMAND_LENGTH 32768 #define MAX_COMMAND_LENGTH 32768
#define MAX_ERROR_LENGTH 2048 #define MAX_ERROR_LENGTH 2048
#define EXIT_WRONG_ARGUMENTS -1
#define EXIT_COMMAND_TOO_LONG -2
#define EXIT_CREATE_JOB_OBJ_FAILED -3
#define EXIT_SET_JOB_OBJ_INFO_FAILED -4
#define EXIT_CREATE_PROCESS_FAILED -5
#define EXIT_ASSGIN_PROCESS_JOB_FAILED -6
enum RunProgramFlag { enum RunProgramFlag {
RPF_PAUSE_CONSOLE = 0x0001, RPF_PAUSE_CONSOLE = 0x0001,
RPF_REDIRECT_INPUT = 0x0002, RPF_REDIRECT_INPUT = 0x0002,
@ -44,6 +53,8 @@ enum RunProgramFlag {
HANDLE hJob; HANDLE hJob;
bool pauseBeforeExit = false;
LONGLONG GetClockTick() { LONGLONG GetClockTick() {
LARGE_INTEGER dummy; LARGE_INTEGER dummy;
QueryPerformanceCounter(&dummy); QueryPerformanceCounter(&dummy);
@ -75,35 +86,37 @@ string GetErrorMessage() {
} }
void PauseExit(int exitcode, bool reInp) { void PauseExit(int exitcode, bool reInp) {
HANDLE hInp=NULL; if (pauseBeforeExit) {
if (reInp) { HANDLE hInp=NULL;
SECURITY_ATTRIBUTES sa; if (reInp) {
sa.nLength = sizeof(sa); SECURITY_ATTRIBUTES sa;
sa.lpSecurityDescriptor = NULL; sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
HANDLE hInp = CreateFileA("CONIN$", GENERIC_WRITE | GENERIC_READ, HANDLE hInp = CreateFileA("CONIN$", GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ , &sa, OPEN_EXISTING, /*FILE_ATTRIBUTE_NORMAL*/0, NULL); FILE_SHARE_READ , &sa, OPEN_EXISTING, /*FILE_ATTRIBUTE_NORMAL*/0, NULL);
//si.hStdInput = hInp; //si.hStdInput = hInp;
SetStdHandle(STD_INPUT_HANDLE,hInp); SetStdHandle(STD_INPUT_HANDLE,hInp);
freopen("CONIN$","r",stdin); freopen("CONIN$","r",stdin);
} }
FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
fflush(stdin); fflush(stdin);
printf("\n"); printf("\n");
printf("Press ANY key to exit..."); printf("Press ANY key to exit...");
getch(); getch();
if (reInp) { if (reInp) {
CloseHandle(hInp); CloseHandle(hInp);
}
} }
exit(exitcode); exit(exitcode);
} }
string GetCommand(int argc,char** argv,bool &reInp,bool &pauseAfterExit, bool &enableVisualTerminalSeq) { string GetCommand(int argc,char** argv,bool &reInp, bool &enableVisualTerminalSeq) {
string result; string result;
int flags = atoi(argv[1]); int flags = atoi(argv[1]);
reInp = flags & RPF_REDIRECT_INPUT; reInp = flags & RPF_REDIRECT_INPUT;
pauseAfterExit = flags & RPF_PAUSE_CONSOLE; pauseBeforeExit = flags & RPF_PAUSE_CONSOLE;
enableVisualTerminalSeq = flags & RPF_ENABLE_VIRTUAL_TERMINAL_PROCESSING; enableVisualTerminalSeq = flags & RPF_ENABLE_VIRTUAL_TERMINAL_PROCESSING;
for(int i = 3;i < argc;i++) { for(int i = 3;i < argc;i++) {
// Quote the argument in case the path name contains spaces // Quote the argument in case the path name contains spaces
@ -118,7 +131,7 @@ string GetCommand(int argc,char** argv,bool &reInp,bool &pauseAfterExit, bool &e
if(result.length() > MAX_COMMAND_LENGTH) { if(result.length() > MAX_COMMAND_LENGTH) {
printf("\n--------------------------------"); printf("\n--------------------------------");
printf("\nError: Length of command line string is over %d characters\n",MAX_COMMAND_LENGTH); printf("\nError: Length of command line string is over %d characters\n",MAX_COMMAND_LENGTH);
PauseExit(EXIT_FAILURE,reInp); PauseExit(EXIT_COMMAND_TOO_LONG,reInp);
} }
return result; return result;
@ -139,12 +152,12 @@ DWORD ExecuteCommand(string& command,bool reInp, LONGLONG &peakMemory, LONGLONG
printf("\n--------------------------------"); printf("\n--------------------------------");
printf("\nFailed to execute \"%s\":",command.c_str()); printf("\nFailed to execute \"%s\":",command.c_str());
printf("\nError %lu: %s\n",GetLastError(),GetErrorMessage().c_str()); printf("\nError %lu: %s\n",GetLastError(),GetErrorMessage().c_str());
PauseExit(EXIT_FAILURE,reInp); PauseExit(EXIT_CREATE_PROCESS_FAILED,reInp);
} }
WINBOOL bSuccess = AssignProcessToJobObject( hJob, pi.hProcess ); WINBOOL bSuccess = AssignProcessToJobObject( hJob, pi.hProcess );
if ( bSuccess == FALSE ) { if ( bSuccess == FALSE ) {
printf( "AssignProcessToJobObject failed: error %lu\n", GetLastError() ); printf( "AssignProcessToJobObject failed: error %lu\n", GetLastError() );
return 0; PauseExit(EXIT_ASSGIN_PROCESS_JOB_FAILED);
} }
WaitForSingleObject(pi.hProcess, INFINITE); // Wait for it to finish WaitForSingleObject(pi.hProcess, INFINITE); // Wait for it to finish
@ -190,7 +203,7 @@ int main(int argc, char** argv) {
printf("\n--------------------------------"); printf("\n--------------------------------");
printf("\nUsage: consolepauser.exe <0|1> <shared_memory_id> <filename> <parameters>\n"); printf("\nUsage: consolepauser.exe <0|1> <shared_memory_id> <filename> <parameters>\n");
printf("\n 1 means the STDIN is redirected by Red Panda C++; 0 means not\n"); printf("\n 1 means the STDIN is redirected by Red Panda C++; 0 means not\n");
PauseExit(EXIT_SUCCESS,false); PauseExit(EXIT_WRONG_ARGUMENTS,false);
} }
// Make us look like the paused program // Make us look like the paused program
@ -203,11 +216,16 @@ int main(int argc, char** argv) {
sa.lpSecurityDescriptor = NULL; sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = FALSE; sa.bInheritHandle = FALSE;
bool reInp;
bool enableVisualTerminalSeq;
// Then build the to-run application command
string command = GetCommand(argc, argv, reInp, enableVisualTerminalSeq);
hJob= CreateJobObject( &sa, NULL ); hJob= CreateJobObject( &sa, NULL );
if ( hJob == NULL ) { if ( hJob == NULL ) {
printf( "CreateJobObject failed: error %lu\n", GetLastError() ); printf( "CreateJobObject failed: error %lu\n", GetLastError() );
return 0; PauseExit(EXIT_CREATE_JOB_OBJ_FAILED,reInp);
} }
JOBOBJECT_EXTENDED_LIMIT_INFORMATION info; JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
@ -216,14 +234,9 @@ int main(int argc, char** argv) {
WINBOOL bSuccess = SetInformationJobObject( hJob, JobObjectExtendedLimitInformation, &info, sizeof( info ) ); WINBOOL bSuccess = SetInformationJobObject( hJob, JobObjectExtendedLimitInformation, &info, sizeof( info ) );
if ( bSuccess == FALSE ) { if ( bSuccess == FALSE ) {
printf( "SetInformationJobObject failed: error %lu\n", GetLastError() ); printf( "SetInformationJobObject failed: error %lu\n", GetLastError() );
return 0; PauseExit(EXIT_SET_JOB_OBJ_INFO_FAILED,reInp);
} }
bool reInp;
bool pauseAfterExit;
bool enableVisualTerminalSeq;
// Then build the to-run application command
string command = GetCommand(argc,argv,reInp, pauseAfterExit, enableVisualTerminalSeq);
HANDLE hOutput = NULL; HANDLE hOutput = NULL;
if (reInp) { if (reInp) {
SECURITY_ATTRIBUTES sa; SECURITY_ATTRIBUTES sa;
@ -287,8 +300,7 @@ int main(int argc, char** argv) {
// Done? Print return value of executed program // Done? Print return value of executed program
printf("\n--------------------------------"); printf("\n--------------------------------");
printf("\nProcess exited after %.4g seconds with return value %lu (%.4g ms cpu time, %lld KB mem used).\n",seconds,returnvalue, execSeconds, peakMemory); printf("\nProcess exited after %.4g seconds with return value %lu (%.4g ms cpu time, %lld KB mem used).\n",seconds,returnvalue, execSeconds, peakMemory);
if (pauseAfterExit) PauseExit(returnvalue,reInp);
PauseExit(returnvalue,reInp);
return 0; return 0;
} }