Sorted

I am using VC++ Beta 2, with Windows Forms. I want to run a process in the background, leaving the UI responsive, and also to update a text box on the UI with interim progress data from my process. I have found a way to initiate a worker thread on the NET - as below.

using namespace System;

using namespace System::Threading;

public ref class ThreadExample

{

public:

static void ThreadProc()

{

//Do stuff}

};

void RunProcess()

{

Thread^ oThread = gcnew Thread( gcnew ThreadStart( &ThreadExample::ThreadProc ) );

oThread->Start();

}

RunProcess starts the thread fine, but I can't do anything with the process (get data from it to the UI, or cancel it) once it's started. I read that Windows Forms provides a class to sort this stuff out - the backgroundWorker component, but all of the examples I've seen of its use are in C# or VB. I'm not at all familiar with these languages, so my attempts to "convert" them have not gone well. What I really need is a walk-through, or a little example in the correct syntax, to get me going - can anyone direct me to one

Thanks.

Tom



Answer this question

Sorted

  • Lila44602

    Disclaimer A: I'm not using beta 2 of VS (I'm on the final release). Disclaimer B: If it ain't broke, don't fix it.

    It is true you can use BackgroundWorker to report progress/status and optionally cancel a worker thread cleanly (at the end of one iteration, you need to call ReportProgress() and check if CancellationPending==true).

    I can't remember if the beta 2 help included a C++ code example for the BackgroundWorker, but I definitely know that the current help does have one. Check it out at: http://msdn2.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx.



  • benlung

    Take a look at the second overload of ReportProgress(Int32, Object ^).  The second parameter of this overload, an Object ^, allows you to pass your array to the callback (without the need of a global). Although the docs recommend you pass your this pointer as the second parameter, you can actually pass in anything as the second parameter.

    In your case, you'd want that be the array, or some struct which contains your values (and any information which could be useful).

     



  • Satish Chandran

    Yes, I'd just come to that conclusion myself. All this pre-defined stuff is a great help, once you understand what it all means! Thanks for your help.
  • Magnus Hedin

    Right - that's a great start. Thanks for your help!
  • Robert-IS

    No worries, I have sort this problem out. Thanks for the initial answer!
  • Leif Lundgren

    I've also discovered that in some circumstances, when I run the programme with no breakpoints, it throws up an error - here's the error:

    ///////////////////////////

    An unhandled exception of type 'System.IndexOutOfRangeException' occurred in System.Drawing.dll

    Additional information: Index was outside the bounds of the array.

    /////////////////////////////

    I'm obviously doing something wrong here... Can anyone point me toward an answer

    Tom


  • Comrad78

    Okay... So I've got the thing working, but still run into some problems. I'm trying to send back data (formatted text) from the worker thread to update a text box. I assumed I can do this with the OnProgressChanged event, called using worker->reportprogress(). But I couldn't work out how to get textual, user defined information through to the event. So I added a global array, which I update directly, and which the OnProgressChanged event then reads before updating the text box... I worry that I may be breaking some rule here.

    This is the code:

    private: System::Void backgroundWorker1_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {

    // Get the BackgroundWorker that raised this event.

    BackgroundWorker^ worker = dynamic_cast<BackgroundWorker^>(sender);

    Body(worker, e ); //The shell for my main computation

    }

    private: System::Void backgroundWorker1_ProgressChanged(System::Object^ sender, System::ComponentModel::ProgressChangedEventArgs^ e) {

    System::String^ NewString;

    for(int s=0;s<3;s++)

    {

    NewString += System::Convert::ToString(ProgressValsSleep);

    NewString += "\t";

    }

    NewString += "\r\n";

    this->TextBox_Output->Text += NewString;

    }

    //Called from somewhere in my code, I've passed the "worker" variable through all the way from the initial DoWorkEvent.

    void PrintProgress(int Batches, double ErrorRate, double MaxDelta, BackgroundWorker^ worker)

    {

    ProgressVals[0] = Batches;

    ProgressVals[1] = ErrorRate;

    ProgressVals[2] = MaxDelta;

    worker->ReportProgress(0);

    }

    I get some very strange stuff happening here, which makes me thing the method is fundamentally wrong. If I set a break point at the call to "Body()", then follow the execution into that function by pressing "f11", the thing seems to work fine. But if I do not set that break point, the whole application freezes and I have to force it off. I can't see why these two situations should produce such different results - any ideas

    Any help on this would be much appreciated.

    Tom


  • Sorted