distas

If you have problem with StreamReader as I had, the solution will clarify the topic. I wanted to start external command line application and read standart output to my String. Everything was Ok until external application was producing output, but if not Application is still alive, but there is nothing in stream. Your StreamReader is blocked. The only solution I found was Multithreading: to run StreamReader in separate Thread. It will prevent your UserInterface thread from blocking and gives us opportunity to do something with the blocked thread.
I assume you know how to use Process class(component), if not - there are good articles about it.


.....
//in the Main thread of UserInterface

myProcess->StartInfo ->Arguments =myArguments->ToString ();

// redirect standard error stream to get output

myProcess->StartInfo ->RedirectStandardError=true;

//start our external application

myProcess->Start ();

// acquire standart outgoing stream

StreamReader* sOut=myProcess->StandardError ;

// now we Start next procedure (readStream) that will read the Stream in separate thread and pass our Stream as parameter

System::Threading::ThreadPool::QueueUserWorkItem (new System::Threading::WaitCallback(this,readStream),sOut);
// now we have a deal with StreamReader in separate stream

// wait until the process has finished
while (!myProcess->HasExited)
{
Application::DoEvents() ;
}
..........


our procedure for Stream Reading:
//we can pass only Objects
private: System::Void readStream (System::Object* processStream)
{
//derive StreamReader from object
StreamReader* errStream = (StreamReader*)processStream;

while(String* my=errStream->ReadLine () )

{
Application::DoEvents ();

// packetString is responsible for passing the read string back to our userInterface process and output it in Label for example

packetString(my);
}
}


//procedure for inter Thread communication. We pass our read string back to Form Component
private: System::Void packetString (System::Object* strData)
{
if (button1->InvokeRequired)
{

//delegate

packetStringCallback* d = new packetStringCallback(this, packetString);

// new object for Invoke method

System::Object* a __gc[] = {strData};

button1->Invoke (d, a);

}
else
{
button1->Text = (String*)strData;
}
}


// one more thing: We declare delegate for our packetString procedure. you can use any name
__delegate System::Void packetStringCallback(Object* myStr);

So, now We derived our StreamReading in seperate thread. But still have one more question: How can we stop our myProcess if it was blocked
Well in my solution I use new button on the Form with the following handler:

private: System::Void buttonStop_Click(System::Object * sender, System::EventArgs * e)
{
// just kill the process
myProcess->Kill ();
}

the myProcess should be declared as Global of cource or used as component from Toolbox->Components->Process

with hope it will help somebody,
Stas Zheltov


Re: Visual C++ General StreamReader blocked or Multithreading in VC++ (.NET 2003)

Zhi-Xin Ye - MSFT

Move from Window Forms General