diff --git a/Red_Panda_CPP.pro b/Red_Panda_CPP.pro index 148bb77d..029b91c0 100644 --- a/Red_Panda_CPP.pro +++ b/Red_Panda_CPP.pro @@ -2,5 +2,6 @@ TEMPLATE = subdirs SUBDIRS += \ # ../QScintilla/src/qscintilla.pro \ - RedPandaIDE + RedPandaIDE \ + consolepauser diff --git a/consolepauser/consolepauser.pro b/consolepauser/consolepauser.pro new file mode 100644 index 00000000..62a643d0 --- /dev/null +++ b/consolepauser/consolepauser.pro @@ -0,0 +1,26 @@ +QT -= gui + +CONFIG += c++11 console +CONFIG -= app_bundle + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +win32: { +SOURCES += \ + main.windows.cpp +} + +unix: { +SOURCES += \ + main.unix.cpp +} + +CONFIG += lrelease +CONFIG += embed_translations + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/consolepauser/main.windows.cpp b/consolepauser/main.windows.cpp new file mode 100644 index 00000000..ce4d3d81 --- /dev/null +++ b/consolepauser/main.windows.cpp @@ -0,0 +1,256 @@ +/* + * This file is part of Red Panda Dev-C++ 7 + * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/* + * This file is part of Red Panda Dev-C++ 7 + * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +using std::string; +#include +#include +#include + +#define MAX_COMMAND_LENGTH 32768 +#define MAX_ERROR_LENGTH 2048 + +enum RunProgramFlag { + RPF_PAUSE_CONSOLE = 0x0001, + RPF_REDIRECT_INPUT = 0x0002 +}; + +HANDLE hJob; + +LONGLONG GetClockTick() { + LARGE_INTEGER dummy; + QueryPerformanceCounter(&dummy); + return dummy.QuadPart; +} + +LONGLONG GetClockFrequency() { + LARGE_INTEGER dummy; + QueryPerformanceFrequency(&dummy); + return dummy.QuadPart; +} + + +string GetErrorMessage() { + string result(MAX_ERROR_LENGTH,0); + FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),&result[0],result.size(),NULL); + + // Clear newlines at end of string + for(int i = result.length()-1;i >= 0;i--) { + if(isspace(result[i])) { + result[i] = 0; + } else { + break; + } + } + return result; +} + +void PauseExit(int exitcode, bool reInp) { + HANDLE hInp=NULL; + if (reInp) { + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + HANDLE hInp = CreateFileA("CONIN$", GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_READ , &sa, OPEN_EXISTING, /*FILE_ATTRIBUTE_NORMAL*/0, NULL); + //si.hStdInput = hInp; + SetStdHandle(STD_INPUT_HANDLE,hInp); + freopen("CONIN$","r",stdin); + } + FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); + fflush(stdin); + printf("\n"); + printf("Press ANY key to exit..."); + getch(); + if (reInp) { + CloseHandle(hInp); + } + exit(exitcode); +} + +string GetCommand(int argc,char** argv,bool &reInp,bool &pauseAfterExit) { + string result; + int flags = atoi(argv[1]); + reInp = flags & RPF_REDIRECT_INPUT; + pauseAfterExit = flags & RPF_PAUSE_CONSOLE; + for(int i = 2;i < argc;i++) { + // Quote the argument in case the path name contains spaces + result += string("\"") + string(argv[i]) + string("\""); + + // Add a space except for the last argument + if(i != (argc-1)) { + result += string(" "); + } + } + + if(result.length() > MAX_COMMAND_LENGTH) { + printf("\n--------------------------------"); + printf("\nError: Length of command line string is over %d characters\n",MAX_COMMAND_LENGTH); + PauseExit(EXIT_FAILURE,reInp); + } + + return result; +} + +DWORD ExecuteCommand(string& command,bool reInp) { + STARTUPINFOA si; + PROCESS_INFORMATION pi; + + memset(&si,0,sizeof(si)); + si.cb = sizeof(si); + memset(&pi,0,sizeof(pi)); + + DWORD dwCreationFlags = CREATE_BREAKAWAY_FROM_JOB; + + + if(!CreateProcessA(NULL, (LPSTR)command.c_str(), NULL, NULL, true, dwCreationFlags, NULL, NULL, &si, &pi)) { + printf("\n--------------------------------"); + printf("\nFailed to execute \"%s\":",command.c_str()); + printf("\nError %lu: %s\n",GetLastError(),GetErrorMessage().c_str()); + PauseExit(EXIT_FAILURE,reInp); + } + WINBOOL bSuccess = AssignProcessToJobObject( hJob, pi.hProcess ); + if ( bSuccess == FALSE ) { + printf( "AssignProcessToJobObject failed: error %d\n", GetLastError() ); + return 0; + } + + WaitForSingleObject(pi.hProcess, INFINITE); // Wait for it to finish + + + DWORD result = 0; + GetExitCodeProcess(pi.hProcess, &result); + return result; +} + +int main(int argc, char** argv) { + + // First make sure we aren't going to read nonexistent arrays + if(argc < 3) { + printf("\n--------------------------------"); + printf("\nUsage: ConsolePauser.exe <0|1> \n"); + printf("\n 1 means the STDIN is redirected by Dev-CPP;0 means not\n"); + PauseExit(EXIT_SUCCESS,false); + } + + // Make us look like the paused program + SetConsoleTitleA(argv[2]); + + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = FALSE; + + hJob= CreateJobObject( &sa, NULL ); + + if ( hJob == NULL ) { + printf( "CreateJobObject failed: error %d\n", GetLastError() ); + return 0; + } + + JOBOBJECT_EXTENDED_LIMIT_INFORMATION info = { 0 }; + info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + WINBOOL bSuccess = SetInformationJobObject( hJob, JobObjectExtendedLimitInformation, &info, sizeof( info ) ); + if ( bSuccess == FALSE ) { + printf( "SetInformationJobObject failed: error %d\n", GetLastError() ); + return 0; + } + + bool reInp; + bool pauseAfterExit; + // Then build the to-run application command + string command = GetCommand(argc,argv,reInp, pauseAfterExit); + HANDLE hOutput = NULL; + if (reInp) { + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + hOutput = CreateFileA("CONOUT$", GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE , &sa, OPEN_EXISTING, /*FILE_ATTRIBUTE_NORMAL*/0, NULL); + SetStdHandle(STD_OUTPUT_HANDLE, hOutput); + SetStdHandle(STD_ERROR_HANDLE, hOutput); + freopen("CONOUT$","w+",stdout); + freopen("CONOUT$","w+",stderr); + } else { + FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); + } + + HANDLE hSharedMemory=INVALID_HANDLE_VALUE; + int BUF_SIZE=1024; + char* pBuf=nullptr; + hSharedMemory = OpenFileMappingA( + FILE_MAP_ALL_ACCESS, + FALSE, + "RED_PANDA_IDE_CONSOLE_PAUSER20211223" + ); + if (hSharedMemory != NULL) + { + pBuf = (char*) MapViewOfFile(hSharedMemory, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + BUF_SIZE); + } else { + printf("can't open shared memory!"); + } + + // Save starting timestamp + LONGLONG starttime = GetClockTick(); + + // Then execute said command + DWORD returnvalue = ExecuteCommand(command,reInp); + + // Get ending timestamp + LONGLONG endtime = GetClockTick(); + double seconds = (endtime - starttime) / (double)GetClockFrequency(); + + if (pBuf) { + strcpy(pBuf,"FINISHED"); + } + + // Done? Print return value of executed program + printf("\n--------------------------------"); + printf("\nProcess exited after %.4g seconds with return value %lu\n",seconds,returnvalue); + if (pauseAfterExit) + PauseExit(returnvalue,reInp); + return 0; +} + diff --git a/tools/ConsolePauser/.gitignore b/tools/ConsolePauser/.gitignore deleted file mode 100644 index b5be7eb0..00000000 --- a/tools/ConsolePauser/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/ConsolePauser.layout -/Makefile.win -/ConsolePauser.exe -/main.o diff --git a/tools/ConsolePauser/ConsolePauser.dev b/tools/ConsolePauser/ConsolePauser.dev deleted file mode 100644 index c182a345..00000000 --- a/tools/ConsolePauser/ConsolePauser.dev +++ /dev/null @@ -1,74 +0,0 @@ -[Project] -FileName = ConsolePauser.dev -Name = ConsolePauser -Type = 1 -Ver = 3 -ObjFiles = -Includes = -Libs = -PrivateResource = -ResourceIncludes = -MakeIncludes = -Compiler = -CppCompiler = -Linker = -IsCpp = 1 -Icon = -ExeOutput = -ObjectOutput = -LogOutput = -LogOutputEnabled = 0 -OverrideOutput = 0 -OverrideOutputName = ConsolePauser.exe -HostApplication = -Folders = -CommandLine = -UseCustomMakefile = 0 -CustomMakefile = -IncludeVersionInfo = 0 -SupportXPThemes = 0 -CompilerSet = 0 -CompilerSettings = 000000a000000000000010001 -UnitCount = 1 -UsePrecompiledHeader = 0 -PrecompiledHeader = -UseUTF8 = 0 -StaticLink = 1 -AddCharset = 1 -Encoding = AUTO -CompilerSetType = 0 - - -[VersionInfo] -Major = 1 -Minor = 0 -Release = 0 -Build = 0 -LanguageID = 1033 -CharsetID = 1252 -CompanyName = -FileVersion = 1.0.0.0 -FileDescription = Developed using the Dev-C++ IDE -InternalName = -LegalCopyright = -LegalTrademarks = -OriginalFilename = -ProductName = -ProductVersion = 1.0.0.0 -AutoIncBuildNr = 0 -SyncProduct = 1 - - -[Unit1] -FileName = main.cpp -CompileCpp = 1 -Folder = -Compile = 1 -Link = 1 -Priority = 1000 -OverrideBuildCmd = 0 -BuildCmd = -UseUTF8 = 1 -DetectEncoding = 1 -Encoding = 0 -FileEncoding = AUTO diff --git a/tools/ConsolePauser/main.cpp b/tools/ConsolePauser/main.cpp deleted file mode 100644 index 00ce5cfd..00000000 --- a/tools/ConsolePauser/main.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* - * This file is part of Red Panda Dev-C++ 7 - * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -using std::string; -#include -#include -#include - -#define MAX_COMMAND_LENGTH 32768 -#define MAX_ERROR_LENGTH 2048 - -enum RunProgramFlag { - RPF_PAUSE_CONSOLE = 0x0001, - RPF_REDIRECT_INPUT = 0x0002 -}; - -HANDLE hJob; - -LONGLONG GetClockTick() { - LARGE_INTEGER dummy; - QueryPerformanceCounter(&dummy); - return dummy.QuadPart; -} - -LONGLONG GetClockFrequency() { - LARGE_INTEGER dummy; - QueryPerformanceFrequency(&dummy); - return dummy.QuadPart; -} - - -string GetErrorMessage() { - string result(MAX_ERROR_LENGTH,0); - FormatMessage( - FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, - NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),&result[0],result.size(),NULL); - - // Clear newlines at end of string - for(int i = result.length()-1;i >= 0;i--) { - if(isspace(result[i])) { - result[i] = 0; - } else { - break; - } - } - return result; -} - -void PauseExit(int exitcode, bool reInp) { - HANDLE hInp=NULL; - if (reInp) { - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = TRUE; - - HANDLE hInp = CreateFile("CONIN$", GENERIC_WRITE | GENERIC_READ, - FILE_SHARE_READ , &sa, OPEN_EXISTING, /*FILE_ATTRIBUTE_NORMAL*/0, NULL); - //si.hStdInput = hInp; - SetStdHandle(STD_INPUT_HANDLE,hInp); - freopen("CONIN$","r",stdin); - } - FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); - fflush(stdin); - printf("\n"); - printf("Press ANY key to exit..."); - getch(); - if (reInp) { - CloseHandle(hInp); - } - exit(exitcode); -} - -string GetCommand(int argc,char** argv,bool &reInp,bool &pauseAfterExit) { - string result; - int flags = atoi(argv[1]); - reInp = flags & RPF_REDIRECT_INPUT; - pauseAfterExit = flags & RPF_PAUSE_CONSOLE; - for(int i = 2;i < argc;i++) { - // Quote the argument in case the path name contains spaces - result += string("\"") + string(argv[i]) + string("\""); - - // Add a space except for the last argument - if(i != (argc-1)) { - result += string(" "); - } - } - - if(result.length() > MAX_COMMAND_LENGTH) { - printf("\n--------------------------------"); - printf("\nError: Length of command line string is over %d characters\n",MAX_COMMAND_LENGTH); - PauseExit(EXIT_FAILURE,reInp); - } - - return result; -} - -DWORD ExecuteCommand(string& command,bool reInp) { - STARTUPINFO si; - PROCESS_INFORMATION pi; - - memset(&si,0,sizeof(si)); - si.cb = sizeof(si); - memset(&pi,0,sizeof(pi)); - - DWORD dwCreationFlags = CREATE_BREAKAWAY_FROM_JOB; - - - if(!CreateProcess(NULL, (LPSTR)command.c_str(), NULL, NULL, true, dwCreationFlags, NULL, NULL, &si, &pi)) { - printf("\n--------------------------------"); - printf("\nFailed to execute \"%s\":",command.c_str()); - printf("\nError %lu: %s\n",GetLastError(),GetErrorMessage().c_str()); - PauseExit(EXIT_FAILURE,reInp); - } - WINBOOL bSuccess = AssignProcessToJobObject( hJob, pi.hProcess ); - if ( bSuccess == FALSE ) { - printf( "AssignProcessToJobObject failed: error %d\n", GetLastError() ); - return 0; - } - - WaitForSingleObject(pi.hProcess, INFINITE); // Wait for it to finish - - - DWORD result = 0; - GetExitCodeProcess(pi.hProcess, &result); - return result; -} - -int main(int argc, char** argv) { - - // First make sure we aren't going to read nonexistent arrays - if(argc < 3) { - printf("\n--------------------------------"); - printf("\nUsage: ConsolePauser.exe <0|1> \n"); - printf("\n 1 means the STDIN is redirected by Dev-CPP;0 means not\n"); - PauseExit(EXIT_SUCCESS,false); - } - - // Make us look like the paused program - SetConsoleTitle(argv[2]); - - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = FALSE; - - hJob= CreateJobObject( &sa, NULL ); - - if ( hJob == NULL ) { - printf( "CreateJobObject failed: error %d\n", GetLastError() ); - return 0; - } - - JOBOBJECT_EXTENDED_LIMIT_INFORMATION info = { 0 }; - info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; - WINBOOL bSuccess = SetInformationJobObject( hJob, JobObjectExtendedLimitInformation, &info, sizeof( info ) ); - if ( bSuccess == FALSE ) { - printf( "SetInformationJobObject failed: error %d\n", GetLastError() ); - return 0; - } - - bool reInp; - bool pauseAfterExit; - // Then build the to-run application command - string command = GetCommand(argc,argv,reInp, pauseAfterExit); - HANDLE hOutput = NULL; - if (reInp) { - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = TRUE; - - hOutput = CreateFile("CONOUT$", GENERIC_WRITE | GENERIC_READ, - FILE_SHARE_WRITE , &sa, OPEN_EXISTING, /*FILE_ATTRIBUTE_NORMAL*/0, NULL); - SetStdHandle(STD_OUTPUT_HANDLE, hOutput); - SetStdHandle(STD_ERROR_HANDLE, hOutput); - freopen("CONOUT$","w+",stdout); - freopen("CONOUT$","w+",stderr); - } else { - FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); - } - - HANDLE hSharedMemory=INVALID_HANDLE_VALUE; - int BUF_SIZE=1024; - char* pBuf=nullptr; - hSharedMemory = OpenFileMappingA( - FILE_MAP_ALL_ACCESS, - FALSE, - "RED_PANDA_IDE_CONSOLE_PAUSER20211223" - ); - if (hSharedMemory != NULL) - { - pBuf = (char*) MapViewOfFile(hSharedMemory, // handle to map object - FILE_MAP_ALL_ACCESS, // read/write permission - 0, - 0, - BUF_SIZE); - } else { - printf("can't open shared memory!"); - } - - // Save starting timestamp - LONGLONG starttime = GetClockTick(); - - // Then execute said command - DWORD returnvalue = ExecuteCommand(command,reInp); - - // Get ending timestamp - LONGLONG endtime = GetClockTick(); - double seconds = (endtime - starttime) / (double)GetClockFrequency(); - - if (pBuf) { - strcpy(pBuf,"FINISHED"); - } - - // Done? Print return value of executed program - printf("\n--------------------------------"); - printf("\nProcess exited after %.4g seconds with return value %lu\n",seconds,returnvalue); - if (pauseAfterExit) - PauseExit(returnvalue,reInp); - return 0; -}