- enhancement: enable run/debug/compile when console program finished but pausing.

This commit is contained in:
Roy Qu 2021-12-23 17:07:27 +08:00
parent a50c6af5de
commit b956dbbcab
13 changed files with 200 additions and 41 deletions

View File

@ -1,3 +1,6 @@
Version 0.12.0 For Dev-C++ 7 Beta
- enhancement: enable run/debug/compile when console program finished but pausing.
Version 0.11.5 For Dev-C++ 7 Beta Version 0.11.5 For Dev-C++ 7 Beta
- fix: step into instruction and step over instruction not correctly disabled when cpu dialog is created - fix: step into instruction and step over instruction not correctly disabled when cpu dialog is created
- enhancement: icons in all dialogs auto change size with fonts - enhancement: icons in all dialogs auto change size with fonts

View File

@ -42,7 +42,7 @@ bool CompilerManager::backgroundSyntaxChecking()
bool CompilerManager::running() bool CompilerManager::running()
{ {
QMutexLocker locker(&mRunnerMutex); QMutexLocker locker(&mRunnerMutex);
return mRunner!=nullptr; return (mRunner!=nullptr && !mRunner->pausing());
} }
void CompilerManager::compile(const QString& filename, const QByteArray& encoding, bool rebuild, bool silent, bool onlyCheckSyntax) void CompilerManager::compile(const QString& filename, const QByteArray& encoding, bool rebuild, bool silent, bool onlyCheckSyntax)
@ -199,7 +199,7 @@ void CompilerManager::checkSyntax(const QString &filename, const QString &conten
void CompilerManager::run(const QString &filename, const QString &arguments, const QString &workDir) void CompilerManager::run(const QString &filename, const QString &arguments, const QString &workDir)
{ {
QMutexLocker locker(&mRunnerMutex); QMutexLocker locker(&mRunnerMutex);
if (mRunner!=nullptr) { if (mRunner!=nullptr && !mRunner->pausing()) {
return; return;
} }
QString redirectInputFilename; QString redirectInputFilename;
@ -234,7 +234,9 @@ void CompilerManager::run(const QString &filename, const QString &arguments, con
} }
mRunner = execRunner; mRunner = execRunner;
connect(mRunner, &Runner::finished, this ,&CompilerManager::onRunnerTerminated); connect(mRunner, &Runner::finished, this ,&CompilerManager::onRunnerTerminated);
connect(mRunner, &Runner::finished, mRunner ,&Runner::deleteLater);
connect(mRunner, &Runner::finished, pMainWindow ,&MainWindow::onRunFinished); connect(mRunner, &Runner::finished, pMainWindow ,&MainWindow::onRunFinished);
connect(mRunner, &Runner::pausingForFinish, pMainWindow ,&MainWindow::onRunPausingForFinish);
connect(mRunner, &Runner::runErrorOccurred, pMainWindow ,&MainWindow::onRunErrorOccured); connect(mRunner, &Runner::runErrorOccurred, pMainWindow ,&MainWindow::onRunErrorOccured);
mRunner->start(); mRunner->start();
} }
@ -249,6 +251,7 @@ void CompilerManager::runProblem(const QString &filename, const QString &argumen
OJProblemCasesRunner * execRunner = new OJProblemCasesRunner(filename,arguments,workDir,problemCase); OJProblemCasesRunner * execRunner = new OJProblemCasesRunner(filename,arguments,workDir,problemCase);
mRunner = execRunner; mRunner = execRunner;
connect(mRunner, &Runner::finished, this ,&CompilerManager::onRunnerTerminated); connect(mRunner, &Runner::finished, this ,&CompilerManager::onRunnerTerminated);
connect(mRunner, &Runner::finished, mRunner ,&Runner::deleteLater);
connect(mRunner, &Runner::finished, pMainWindow ,&MainWindow::onRunProblemFinished); connect(mRunner, &Runner::finished, pMainWindow ,&MainWindow::onRunProblemFinished);
connect(mRunner, &Runner::runErrorOccurred, pMainWindow ,&MainWindow::onRunErrorOccured); connect(mRunner, &Runner::runErrorOccurred, pMainWindow ,&MainWindow::onRunErrorOccured);
connect(execRunner, &OJProblemCasesRunner::caseStarted, pMainWindow, &MainWindow::onOJProblemCaseStarted); connect(execRunner, &OJProblemCasesRunner::caseStarted, pMainWindow, &MainWindow::onOJProblemCaseStarted);
@ -276,8 +279,22 @@ void CompilerManager::runProblem(const QString &filename, const QString &argumen
void CompilerManager::stopRun() void CompilerManager::stopRun()
{ {
QMutexLocker locker(&mRunnerMutex); QMutexLocker locker(&mRunnerMutex);
if (mRunner!=nullptr) if (mRunner!=nullptr) {
mRunner->stop(); mRunner->stop();
disconnect(mRunner, &Runner::finished, this ,&CompilerManager::onRunnerTerminated);
mRunner=nullptr;
}
}
void CompilerManager::stopPausing()
{
QMutexLocker locker(&mRunnerMutex);
if (mRunner!=nullptr && mRunner->pausing()) {
disconnect(mRunner, &Runner::finished, this ,&CompilerManager::onRunnerTerminated);
mRunner->stop();
disconnect(mRunner, &Runner::finished, this ,&CompilerManager::onRunnerTerminated);
mRunner=nullptr;
}
} }
void CompilerManager::stopCompile() void CompilerManager::stopCompile()
@ -309,9 +326,7 @@ void CompilerManager::onCompileFinished()
void CompilerManager::onRunnerTerminated() void CompilerManager::onRunnerTerminated()
{ {
QMutexLocker locker(&mRunnerMutex); QMutexLocker locker(&mRunnerMutex);
Runner* p=mRunner;
mRunner=nullptr; mRunner=nullptr;
p->deleteLater();
} }
void CompilerManager::onCompileIssue(PCompileIssue issue) void CompilerManager::onCompileIssue(PCompileIssue issue)

View File

@ -30,6 +30,7 @@ public:
void runProblem(const QString& filename, const QString& arguments, const QString& workDir, POJProblemCase problemCase); void runProblem(const QString& filename, const QString& arguments, const QString& workDir, POJProblemCase problemCase);
void runProblem(const QString& filename, const QString& arguments, const QString& workDir, QVector<POJProblemCase> problemCases); void runProblem(const QString& filename, const QString& arguments, const QString& workDir, QVector<POJProblemCase> problemCases);
void stopRun(); void stopRun();
void stopPausing();
void stopCompile(); void stopCompile();
void stopCheckSyntax(); void stopCheckSyntax();
bool canCompile(const QString& filename); bool canCompile(const QString& filename);

View File

@ -1,6 +1,5 @@
#include "executablerunner.h" #include "executablerunner.h"
#include <QProcess>
#include <windows.h> #include <windows.h>
#include <QDebug> #include <QDebug>
#include "compilermanager.h" #include "compilermanager.h"
@ -50,15 +49,17 @@ void ExecutableRunner::run()
{ {
emit started(); emit started();
auto action = finally([this]{ auto action = finally([this]{
mProcess.reset();
setPausing(false);
emit terminated(); emit terminated();
}); });
QProcess process;
mStop = false; mStop = false;
bool errorOccurred = false; bool errorOccurred = false;
process.setProgram(mFilename); mProcess = std::make_shared<QProcess>();
process.setArguments(QProcess::splitCommand(mArguments)); mProcess->setProgram(mFilename);
process.setWorkingDirectory(mWorkDir); mProcess->setArguments(QProcess::splitCommand(mArguments));
mProcess->setWorkingDirectory(mWorkDir);
QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString path = env.value("PATH"); QString path = env.value("PATH");
QStringList pathAdded; QStringList pathAdded;
@ -74,8 +75,8 @@ void ExecutableRunner::run()
path = pathAdded.join(PATH_SEPARATOR); path = pathAdded.join(PATH_SEPARATOR);
} }
env.insert("PATH",path); env.insert("PATH",path);
process.setProcessEnvironment(env); mProcess->setProcessEnvironment(env);
process.setCreateProcessArgumentsModifier([this](QProcess::CreateProcessArguments * args){ mProcess->setCreateProcessArgumentsModifier([this](QProcess::CreateProcessArguments * args){
if (mStartConsole) { if (mStartConsole) {
args->flags |= CREATE_NEW_CONSOLE; args->flags |= CREATE_NEW_CONSOLE;
args->flags &= ~CREATE_NO_WINDOW; args->flags &= ~CREATE_NO_WINDOW;
@ -84,56 +85,96 @@ void ExecutableRunner::run()
args->startupInfo -> dwFlags &= ~STARTF_USESTDHANDLES; args->startupInfo -> dwFlags &= ~STARTF_USESTDHANDLES;
} }
}); });
process.connect( connect(
&process, &QProcess::errorOccurred, mProcess.get(), &QProcess::errorOccurred,
[&](){ [&errorOccurred](){
errorOccurred= true; errorOccurred= true;
}); });
// if (!redirectInput()) { // if (!redirectInput()) {
// process.closeWriteChannel(); // process.closeWriteChannel();
// } // }
process.start(); mProcess->start();
process.waitForStarted(5000); mProcess->waitForStarted(5000);
if (process.state()==QProcess::Running && redirectInput()) { if (mProcess->state()==QProcess::Running && redirectInput()) {
process.write(readFileToByteArray(redirectInputFilename())); mProcess->write(readFileToByteArray(redirectInputFilename()));
process.closeWriteChannel(); mProcess->closeWriteChannel();
}
HANDLE hSharedMemory=INVALID_HANDLE_VALUE;
int BUF_SIZE=1024;
char* pBuf=nullptr;
if (mStartConsole) {
hSharedMemory = CreateFileMappingA(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
100,
"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);
if (pBuf) {
pBuf[0]=0;
}
}
} }
while (true) { while (true) {
process.waitForFinished(1000); mProcess->waitForFinished(1000);
if (process.state()!=QProcess::Running) { if (mProcess->state()!=QProcess::Running) {
break; break;
} }
if (mStop) { if (mStop) {
process.closeReadChannel(QProcess::StandardOutput); qDebug()<<"??1";
process.closeReadChannel(QProcess::StandardError); mProcess->closeReadChannel(QProcess::StandardOutput);
process.closeWriteChannel(); mProcess->closeReadChannel(QProcess::StandardError);
mProcess->closeWriteChannel();
qDebug()<<"??2";
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
if (!mStartConsole) { qDebug()<<"??3";
process.terminate(); mProcess->terminate();
if (process.waitForFinished(1000)) { qDebug()<<"??4";
if (mProcess->waitForFinished(1000)) {
break; break;
} }
}
#else #else
process.terminate(); process->terminate();
if (process.waitForFinished(1000)) { if (process->waitForFinished(1000)) {
break; break;
} }
#endif #endif
for (int i=0;i<10;i++) { for (int i=0;i<10;i++) {
process.kill(); qDebug()<<"??5";
if (process.waitForFinished(100)) { mProcess->kill();
qDebug()<<"??6";
if (mProcess->waitForFinished(500)) {
break; break;
} }
} }
break; break;
} }
if (mStartConsole && !mPausing && pBuf) {
if (strncmp(pBuf,"FINISHED",sizeof("FINISHED"))==0) {
setPausing(true);
emit pausingForFinish();
}
}
if (errorOccurred) if (errorOccurred)
break; break;
} }
if (pBuf)
UnmapViewOfFile(pBuf);
if (hSharedMemory!=INVALID_HANDLE_VALUE)
CloseHandle(hSharedMemory);
if (errorOccurred) { if (errorOccurred) {
//qDebug()<<"process error:"<<process.error(); //qDebug()<<"process error:"<<process.error();
switch (process.error()) { switch (mProcess->error()) {
case QProcess::FailedToStart: case QProcess::FailedToStart:
emit runErrorOccurred(tr("The runner process '%1' failed to start.").arg(mFilename)); emit runErrorOccurred(tr("The runner process '%1' failed to start.").arg(mFilename));
break; break;
@ -155,3 +196,38 @@ void ExecutableRunner::run()
} }
} }
} }
void ExecutableRunner::doStop()
{
std::shared_ptr<QProcess> process = mProcess;
if (process) {
// qDebug()<<"??1";
// process->closeReadChannel(QProcess::StandardOutput);
// process->closeReadChannel(QProcess::StandardError);
// process->closeWriteChannel();
// qDebug()<<"??2";
// #ifdef Q_OS_WIN
// if (!mStartConsole) {
// qDebug()<<"??3";
// process->terminate();
// qDebug()<<"??4";
// if (process->waitForFinished(1000)) {
// return;
// }
// }
// #else
// process->terminate();
// if (process->waitForFinished(1000)) {
// break;
// }
// #endif
// for (int i=0;i<10;i++) {
// qDebug()<<"??5";
// process->kill();
// qDebug()<<"??6";
// if (process->waitForFinished(100)) {
// break;
// }
// }
}
}

View File

@ -2,6 +2,7 @@
#define EXECUTABLERUNNER_H #define EXECUTABLERUNNER_H
#include "runner.h" #include "runner.h"
#include <QProcess>
class ExecutableRunner : public Runner class ExecutableRunner : public Runner
{ {
@ -23,10 +24,15 @@ private:
QString mRedirectInputFilename; QString mRedirectInputFilename;
bool mRedirectInput; bool mRedirectInput;
bool mStartConsole; bool mStartConsole;
std::shared_ptr<QProcess> mProcess;
// QThread interface // QThread interface
protected: protected:
void run() override; void run() override;
// Runner interface
protected:
void doStop() override;
}; };
#endif // EXECUTABLERUNNER_H #endif // EXECUTABLERUNNER_H

View File

@ -5,6 +5,7 @@
#include "../widgets/ojproblemsetmodel.h" #include "../widgets/ojproblemsetmodel.h"
#include <QProcess> #include <QProcess>
OJProblemCasesRunner::OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir, OJProblemCasesRunner::OJProblemCasesRunner(const QString& filename, const QString& arguments, const QString& workDir,
const QVector<POJProblemCase>& problemCases, QObject *parent): const QVector<POJProblemCase>& problemCases, QObject *parent):
Runner(filename,arguments,workDir,parent) Runner(filename,arguments,workDir,parent)

View File

@ -25,6 +25,7 @@ private:
// QThread interface // QThread interface
protected: protected:
void run() override; void run() override;
}; };
#endif // OJPROBLEMCASESRUNNER_H #endif // OJPROBLEMCASESRUNNER_H

View File

@ -2,6 +2,7 @@
Runner::Runner(const QString &filename, const QString &arguments, const QString &workDir Runner::Runner(const QString &filename, const QString &arguments, const QString &workDir
,QObject *parent) : QThread(parent), ,QObject *parent) : QThread(parent),
mPausing(false),
mStop(false), mStop(false),
mFilename(filename), mFilename(filename),
mArguments(arguments), mArguments(arguments),
@ -13,5 +14,21 @@ Runner::Runner(const QString &filename, const QString &arguments, const QString
void Runner::stop() void Runner::stop()
{ {
mStop = true; mStop = true;
doStop();
}
void Runner::doStop()
{
}
bool Runner::pausing() const
{
return mPausing;
}
void Runner::setPausing(bool newCanFinish)
{
mPausing = newCanFinish;
} }

View File

@ -9,15 +9,22 @@ class Runner : public QThread
public: public:
explicit Runner(const QString& filename, const QString& arguments, const QString& workDir, QObject *parent = nullptr); explicit Runner(const QString& filename, const QString& arguments, const QString& workDir, QObject *parent = nullptr);
bool pausing() const;
signals: signals:
void started(); void started();
void terminated(); void terminated();
void runErrorOccurred(const QString& reason); void runErrorOccurred(const QString& reason);
void pausingForFinish(); // finish but pausing
public slots: public slots:
void stop(); void stop();
protected: protected:
virtual void doStop();
void setPausing(bool newCanFinish);
protected:
bool mPausing;
bool mStop; bool mStop;
QString mFilename; QString mFilename;
QString mArguments; QString mArguments;

View File

@ -1312,6 +1312,7 @@ void MainWindow::checkSyntaxInBack(Editor *e)
bool MainWindow::compile(bool rebuild) bool MainWindow::compile(bool rebuild)
{ {
mCompilerManager->stopPausing();
CompileTarget target =getCompileTarget(); CompileTarget target =getCompileTarget();
if (target == CompileTarget::Project) { if (target == CompileTarget::Project) {
if (mProject->modified()) if (mProject->modified())
@ -1355,6 +1356,7 @@ bool MainWindow::compile(bool rebuild)
void MainWindow::runExecutable(const QString &exeName,const QString &filename,RunType runType) void MainWindow::runExecutable(const QString &exeName,const QString &filename,RunType runType)
{ {
mCompilerManager->stopPausing();
// Check if it exists // Check if it exists
if (!fileExists(exeName)) { if (!fileExists(exeName)) {
if (ui->actionCompile_Run->isEnabled()) { if (ui->actionCompile_Run->isEnabled()) {
@ -1452,6 +1454,7 @@ void MainWindow::debug()
{ {
if (mCompilerManager->compiling()) if (mCompilerManager->compiling())
return; return;
mCompilerManager->stopPausing();
Settings::PCompilerSet compilerSet = pSettings->compilerSets().defaultSet(); Settings::PCompilerSet compilerSet = pSettings->compilerSets().defaultSet();
if (!compilerSet) { if (!compilerSet) {
QMessageBox::critical(pMainWindow, QMessageBox::critical(pMainWindow,
@ -3910,6 +3913,11 @@ void MainWindow::onRunFinished()
updateAppTitle(); updateAppTitle();
} }
void MainWindow::onRunPausingForFinish()
{
updateCompileActions();
}
void MainWindow::onRunProblemFinished() void MainWindow::onRunProblemFinished()
{ {
ui->pbProblemCases->setVisible(false); ui->pbProblemCases->setVisible(false);

View File

@ -172,6 +172,7 @@ public slots:
void onCompileErrorOccured(const QString& reason); void onCompileErrorOccured(const QString& reason);
void onRunErrorOccured(const QString& reason); void onRunErrorOccured(const QString& reason);
void onRunFinished(); void onRunFinished();
void onRunPausingForFinish();
void onRunProblemFinished(); void onRunProblemFinished();
void onOJProblemCaseStarted(const QString& id, int current, int total); void onOJProblemCaseStarted(const QString& id, int current, int total);
void onOJProblemCaseFinished(const QString& id, int current, int total); void onOJProblemCaseFinished(const QString& id, int current, int total);

View File

@ -28,7 +28,7 @@ CustomMakefile =
IncludeVersionInfo = 0 IncludeVersionInfo = 0
SupportXPThemes = 0 SupportXPThemes = 0
CompilerSet = 0 CompilerSet = 0
CompilerSettings = 000000a000110000000001000 CompilerSettings = 000000a000000000000010001
UnitCount = 1 UnitCount = 1
UsePrecompiledHeader = 0 UsePrecompiledHeader = 0
PrecompiledHeader = PrecompiledHeader =

View File

@ -181,6 +181,25 @@ int main(int argc, char** argv) {
FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); 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 // Save starting timestamp
LONGLONG starttime = GetClockTick(); LONGLONG starttime = GetClockTick();
@ -191,6 +210,10 @@ int main(int argc, char** argv) {
LONGLONG endtime = GetClockTick(); LONGLONG endtime = GetClockTick();
double seconds = (endtime - starttime) / (double)GetClockFrequency(); double seconds = (endtime - starttime) / (double)GetClockFrequency();
if (pBuf) {
strcpy(pBuf,"FINISHED");
}
// 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\n",seconds,returnvalue); printf("\nProcess exited after %.4g seconds with return value %lu\n",seconds,returnvalue);