External process stops everything else
-
I have a windows Forms application that calls a mathematical calculations .exe
superMinerProcess->Start(); superMinerProcess->BeginOutputReadLine(); //Start reading the output while (!superMinerProcess->HasExited) { //... }
If I set a breakpoint after the
Start();
the program only reaches it after the process has finished. I don't understand... Any idea? -
I have a windows Forms application that calls a mathematical calculations .exe
superMinerProcess->Start(); superMinerProcess->BeginOutputReadLine(); //Start reading the output while (!superMinerProcess->HasExited) { //... }
If I set a breakpoint after the
Start();
the program only reaches it after the process has finished. I don't understand... Any idea?That is inconclusive. Where is this code located? what is in the
while
loop? what is it you are trying to achieve? :)Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
-
That is inconclusive. Where is this code located? what is in the
while
loop? what is it you are trying to achieve? :)Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
The application is a dialog that runs a long mathematical calculation (the external process, an independent executable) when pressing a Run button. Hence, this code is located within the
buttonRun_Click
function.while (!superMinerProcess->HasExited)
{
if (processCancelled)
{
processCancelled = false;
break;
}
}processCancelled
is set to true inbuttonCancel_Click
. What I´m trying is to be able to kill the process when the user clicks on the Cancel button. I´ve tried writingsuperMinerProcess->Kill()
inbuttonCancel_Click
but it won´t work because the Cancel button is just not clickable while the process is running. Here´s the rest of relevant code of the processsuperMinerProcess = gcnew System::Diagnostics::Process;
superMinerProcess->StartInfo = gcnew System::Diagnostics::ProcessStartInfo;
superMinerProcess->StartInfo->RedirectStandardOutput = true;
superMinerProcess->StartInfo->UseShellExecute = false; //Necessary to redirect
superMinerProcess->StartInfo->FileName = SUPERMINER_EXE;
superMinerProcess->StartInfo->CreateNoWindow = true; //Don't open a new window for Process
//Arguments
superMinerProcess->StartInfo->Arguments = getArguments();
superMinerProcess->OutputDataReceived += gcnew System::Diagnostics::DataReceivedEventHandler (&Form1::StdoutHandler); -
The application is a dialog that runs a long mathematical calculation (the external process, an independent executable) when pressing a Run button. Hence, this code is located within the
buttonRun_Click
function.while (!superMinerProcess->HasExited)
{
if (processCancelled)
{
processCancelled = false;
break;
}
}processCancelled
is set to true inbuttonCancel_Click
. What I´m trying is to be able to kill the process when the user clicks on the Cancel button. I´ve tried writingsuperMinerProcess->Kill()
inbuttonCancel_Click
but it won´t work because the Cancel button is just not clickable while the process is running. Here´s the rest of relevant code of the processsuperMinerProcess = gcnew System::Diagnostics::Process;
superMinerProcess->StartInfo = gcnew System::Diagnostics::ProcessStartInfo;
superMinerProcess->StartInfo->RedirectStandardOutput = true;
superMinerProcess->StartInfo->UseShellExecute = false; //Necessary to redirect
superMinerProcess->StartInfo->FileName = SUPERMINER_EXE;
superMinerProcess->StartInfo->CreateNoWindow = true; //Don't open a new window for Process
//Arguments
superMinerProcess->StartInfo->Arguments = getArguments();
superMinerProcess->OutputDataReceived += gcnew System::Diagnostics::DataReceivedEventHandler (&Form1::StdoutHandler);OK, that is quite wrong for several reasons: 1. the while loop has no blocking calls, so it will spin at full speed, consuming all cycles of one (perhaps the only) core. If you must have a polling loop like that, at least slow it down by inserting say
Thread.Sleep(100);
However it is in general better to avoid a polling loop. 2. It is not OK to halt the main thread like that, as the whole GUI will freeze. If e.g. another window pops up on top of your app, and then goes away again, your app won't repaint itself. The correct approach would be: - to have a separate thread (I suggest a BackgroundWorker) which launches the process, captures its output, and waits for its termination; - to launch this thread from your button click handler (possibly also disabling said button, turning the cursor into a wait cursor, etc); - to have a delegate dealing with intermediate results (maybe showing them in a ListBox); - to have another delegate dealing with the termination of the process (restoring the GUI back to normal). BTW: said thread would not need a polling loop onsuperMinerProcess->HasExited
, as it could usesuperMinerProcess->WaitForExit()
:)Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
-
OK, that is quite wrong for several reasons: 1. the while loop has no blocking calls, so it will spin at full speed, consuming all cycles of one (perhaps the only) core. If you must have a polling loop like that, at least slow it down by inserting say
Thread.Sleep(100);
However it is in general better to avoid a polling loop. 2. It is not OK to halt the main thread like that, as the whole GUI will freeze. If e.g. another window pops up on top of your app, and then goes away again, your app won't repaint itself. The correct approach would be: - to have a separate thread (I suggest a BackgroundWorker) which launches the process, captures its output, and waits for its termination; - to launch this thread from your button click handler (possibly also disabling said button, turning the cursor into a wait cursor, etc); - to have a delegate dealing with intermediate results (maybe showing them in a ListBox); - to have another delegate dealing with the termination of the process (restoring the GUI back to normal). BTW: said thread would not need a polling loop onsuperMinerProcess->HasExited
, as it could usesuperMinerProcess->WaitForExit()
:)Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
I like the idea of having the process in a different thread. It does work much better. However I have a problem when it comes to display in my form the text captured from the process. I have a delegate
superMinerThreadWorkCompleted
in charge of displaying the results.void superMinerThreadWorkCompleted (System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e)
{
textBox = "Process text";
}But I get the error
C3352: superMinerThreadWorkCompleted(System::Object ^,System::ComponentModel::DoWorkEventArgs ^)' : the specified function does not match the delegate type 'void (System::Object ^,System::ComponentModel::RunWorkerCompletedEventArgs ^)' 1>Form1.cpp
in the linesuperMinerThread->RunWorkerCompleted += gcnew System::ComponentModel::RunWorkerCompletedEventHandler (&Form1::superMinerThreadWorkCompleted);
I can fix this by making the delegate
static
but then I cannot modify member classtextBox
. What could be the way around this? -
I like the idea of having the process in a different thread. It does work much better. However I have a problem when it comes to display in my form the text captured from the process. I have a delegate
superMinerThreadWorkCompleted
in charge of displaying the results.void superMinerThreadWorkCompleted (System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e)
{
textBox = "Process text";
}But I get the error
C3352: superMinerThreadWorkCompleted(System::Object ^,System::ComponentModel::DoWorkEventArgs ^)' : the specified function does not match the delegate type 'void (System::Object ^,System::ComponentModel::RunWorkerCompletedEventArgs ^)' 1>Form1.cpp
in the linesuperMinerThread->RunWorkerCompleted += gcnew System::ComponentModel::RunWorkerCompletedEventHandler (&Form1::superMinerThreadWorkCompleted);
I can fix this by making the delegate
static
but then I cannot modify member classtextBox
. What could be the way around this?piul wrote:
DoWorkEventArgs
piul wrote:
RunWorkerCompletedEventArgs
these are different! the former is just wrong. :)
Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
-
piul wrote:
DoWorkEventArgs
piul wrote:
RunWorkerCompletedEventArgs
these are different! the former is just wrong. :)
Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
Changed the delegate to
void superMinerThreadWorkCompleted (System::Object^ sender,
System::ComponentModel::RunWorkerCompletedEventArgs^ e)
{}and still got the same error
'void SuperMinerGUI::Form1::superMinerThreadWorkCompleted(System::Object ^,System::ComponentModel::RunWorkerCompletedEventArgs ^)' : the specified function does not match the delegate type 'void (System::Object ^,System::ComponentModel::RunWorkerCompletedEventArgs ^)' 1>Form1.cpp
-
Changed the delegate to
void superMinerThreadWorkCompleted (System::Object^ sender,
System::ComponentModel::RunWorkerCompletedEventArgs^ e)
{}and still got the same error
'void SuperMinerGUI::Form1::superMinerThreadWorkCompleted(System::Object ^,System::ComponentModel::RunWorkerCompletedEventArgs ^)' : the specified function does not match the delegate type 'void (System::Object ^,System::ComponentModel::RunWorkerCompletedEventArgs ^)' 1>Form1.cpp
for non-static (instance) delegates, you need a constructor that takes two arguments, the first being
this
.superMinerThread->RunWorkerCompleted += gcnew System::ComponentModel::RunWorkerCompletedEventHandler
(this, &Form1::superMinerThreadWorkCompleted);:)
Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
-
for non-static (instance) delegates, you need a constructor that takes two arguments, the first being
this
.superMinerThread->RunWorkerCompleted += gcnew System::ComponentModel::RunWorkerCompletedEventHandler
(this, &Form1::superMinerThreadWorkCompleted);:)
Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.