Updating a form from a serialport component.

Having been a Borland C++ chappie over the years, I've basically created my own RS232 object and dumped it in a seperate Thread, which then directly calls a static function in the forms thread, which then updates the the main forms bit & bobs.

Problems occured when the RS232 object starts pummeling data into the function before it is cleared etc, and then all goes bonkers!

I obviously had broken the cardinal rule "Thou shalt not interact with a control's properties from a thread other than the one that created the control."

In comes VC++ Express and a serialPort object, written by someone who knows what they are doing...

To cut to the chase:

I need to pass the recieved buffer of the serialPort object back to the form on which it was created, when I try the following:

private: System::Void serialPort1_DataReceived(System::Object^ sender, System::IO::Ports::SerialDataReceivedEventArgs^ e) {

String^ myString;

myString = serialPort1->ReadExisting() ;

RichTextBox1->AppendText(myString);

}

I just get the message

"An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll

Additional information: Cross-thread operation not valid: Control 'richTextBox1' accessed from a thread other than the thread it was created on."

I've looked at the BackgroundWorker component, but from the examples, (which all seem to be in VB) find it really difficult to translate over to C++. Also using express from BCB4 feels like I'm learning it all again from scratch.

Any help would be great, Thanks in advance.

David




Answer this question

Updating a form from a serialport component.

  • NemanjaTheLost

    Hello Juha.

    Do you know how to create event handlers for events raised by a Windows Form or component

    Eg. do you know how to set a Label's Text when the user clicks a button



  • moobah

    Thank you Ayman,

    Paying attention to the case got it complied and run. However, I got a lot of words "data". Ok, my problems are most likely my background, unfamiliarity of the system and the framework and my unability to find or understand the help. For the uninitiated, a line of code about event handler does not help much without the big picture and a (even a skeleton of) working application... But I really find this more difficult in my 25 years of programming to get a "serial device hello world" program to run than about any other system.

    This is what the application should be doing. Sounds simple enough an a conference table:

    when a character arrives, examine it and the buffer content;
    if not enough data yet
    store the character in buffer
    else
    figure out the device status from the buffer content and update the status form;

    On the form, click some buttons, control data gets sent.


    Can you please show (or point me to a document showing) how to receive a character and pass it to a thread that has access to the main form (writing wou be nice, too...)

    (I understand Im asking basic things, but perhaps you can get an insight to a veteran programmers mind here. In my other thread, I ask about the buffer. In old days (and embedded world today) I would write something like static char buffer[xx] to get a storage space for the buffer. Now I am in a stange object orineted NET framework, and I don't even know these fundamental issues, like where global buffers are placed. Somehow, I have a feeling that there should be none...)

    Thank you for your insight!

    Juha

  • ndhuy

    JuKu wrote:
    I just can't figure out how to raise an event in one thread and pass data to it from another thread, nor have I found an beginner's explanation.

    Are you having trouble declaring the delegate or using it
    Have you used the qsort/bsearch function before



  • cyn_atl

    I have spent way too many hours on this also, and i am about to give up on VC++.

    This does not work. The line
    R
    ichTextBox1->AppendText(myString);
    does not compile (undeclared identifier), even thoug there is earlier VC++ generated line
    private: System::Windows::Forms::RichTextBox^ richTextBox1;

    There is discussion about the issue at
    http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=22421&SiteID=1
    where Anthny Wong shows how to do this in C#, but this .NET newbie can't translate the solution to C++.

    I am really frustrated, please help! Visual programming is advertised to be easy. If that is true, my serial hello world would be here after two days or so!





  • Zappos

    Are you using a beta of Visual C++ Somebody mentioned that the beta docs didn't have a C++ code example for BackgroundWorker (this has since changed for the final release, http://msdn2.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx has an example in VB/C#/C++).

    In the meantime, richTextBox has an Invoke method which you can use to make cross thread calls to a delegate of your choice. This requires you to know how to create and use delegates.

  • jdegaetani

    Hi OShah,

    Yes, that is the delightful part in visual programming:

    private: System::Void button1_Click_1(System::Object^ sender, System::EventArgs^ e) {
    if (label1->Text == "B")
    label1->Text = "A";
    else
    label1->Text = "B";
    }


    Building user interfaces just can't become easier than this! The problem with serial ports is that the event handlers run in a different thread. At a serial port event, the labels and other controls of the GUI are not accessible. I just can't figure out how to raise an event in one thread and pass data to it from another thread, nor have I found an beginner's explanation. I understand the idea of what is going on, but can't handle the issue myself, at least not in my first real life VC++ program. :-(

    In http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=22421&SiteID=1 Anthony shows hw to handle the issue in C#, but I just can't translate the solution to C++, can't find a good enough explanation of the concept and correct syntax, and my two books and two days of reading helps and searching the net hasn't got me any closer to solution.

    Frustrated,

    Juha

  • scottportraits

    Please note that C++ is case sensitive. That is the declaration is richTextBox1 but you are trying to use RichTextBox1. The "R" should be in small case.

    Hope this is what is causing the error!

    Thanks,
    Ayman Shoukry
    VC++ Team


  • ROBSR

    I've updated this thread because it seems I've solved the problem! :)

    My solution was to replace this line:

    pDelegate->Invoke("Invoked");

    with these three lines:

    System::IAsyncResult^ invokeResult;

    invokeResult = GlobalObjects::myForm->textBox1->BeginInvoke(pDelegate, "Invoke");

    GlobalObjects::myForm->textBox1->EndInvoke(invokeResult);

    /Johannes


  • MyNameisMud

    I've also a problems with threads. I've a callback function locked to the midiInOpen function.

    In that function I want to set a TextBox in my Form1. This is a simplified example:

    [code]

     

    delegate void MyDelegate(String^ _str);

     

    void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)

    {

    if(GlobalObjects::myForm->textBox1->InvokeRequired)

    {

    MyDelegate^ pDelegate = gcnew MyDelegate(GlobalObjects::myForm->textBox1, &TextBox::Text::set);

    pDelegate->Invoke("Invoked");

    }//if

    else

    {

    myForm->textBox1->Text = "Not invoked!";

    }//else

    }//callback function

    [/code]

     

    Maybe you say this code will work but still I got this error-message:

    An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll

    Additional information: Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.

     

    HELP!


  • Updating a form from a serialport component.