This code is written in VC++.NET. I have a windows form that display data from a socket port using callbacks. I have main.cpp that calls Application::Run(new Form1). The socket processing code is currently in the Form's file. I want to separate the Form1 from the socket processing code. Put the socket processing code in main.cpp. But it seems that the call to Application::Run doesn't return until Form1 is closed. Is there another way of launching Form1 so timers may be set after Form1 is up? Thanks.

Dani AI

Generated

: best practice is to move socket work into a small, independent "worker" class that runs on a background thread and exposes events. The Form subscribes to those events (after its handle exists) and marshals updates onto the UI thread with Invoke/BeginInvoke. This keeps the GUI instance non-global, avoids cross-thread access errors, and makes the socket code testable and reusable. is right that you can move code between files; structure it as a clear API (Start/Stop, events) rather than global functions. correctly warned about callback context — if native code calls back, translate that into managed events or tokens so the UI never gets raw pointers.

Example skeleton (C++/CLI):

public ref class SocketWorker
{
public:
    delegate void DataHandler(System::String^ data);
    event DataHandler^ DataReceived;

    void Start()
    {
        System::Threading::Thread^ t = gcnew System::Threading::Thread(
            gcnew System::Threading::ThreadStart(this, &SocketWorker::DoNetwork));
        t->IsBackground = true;
        t->Start();
    }

private:
    void DoNetwork()
    {
        while (running) {
            System::String^ msg = ReadFromSocket();
            if (DataReceived) DataReceived(msg); // raised on worker thread
        }
    }
};

Subscription and safe UI update in the Form:

worker->DataReceived += gcnew SocketWorker::DataHandler(this, &Form1::OnDataReceived);

void Form1::OnDataReceived(System::String^ data)
{
    if (this->InvokeRequired) {
        array<Object^>^ args = gcnew array<Object^>(1) { data };
        this->BeginInvoke(gcnew SocketWorker::DataHandler(this, &Form1::OnDataReceived), args);
        return;
    }
    // safe to touch controls here
    label1->Text = data;
}

Notes and troubleshooting:

  • Subscribe in OnLoad (handle created), unsubscribe in FormClosing. Stop threads before disposing the form.
  • Use InvokeRequired/BeginInvoke for all UI updates; see Microsoft guidance for thread-safe WinForms calls: How to: Make thread-safe calls to Windows Forms controls.
  • For native callbacks, pass a small token and map it to managed objects instead of passing raw this pointers to avoid use-after-free.
  • Choose timers deliberately: Windows Forms timers run on the UI thread; use System::Threading::Timer or System::Timers::Timer for background work.

Recommended Answers

All 3 Replies

You just want to move source code from one file to another?

That's correct. If I have a global function in main that is "SendMessage" to socket, will I be able to call it from a class? My instance of the GUI class is not allowed to be global. How would I get around this? My callbacks needs to use some functions in the class.

That's correct. If I have a global function in main that is "SendMessage" to socket, will I be able to call it from a class? My instance of the GUI class is not allowed to be global. How would I get around this? My callbacks needs to use some functions in the class.

Hmm, it sounds like you are using windows async sockets by using overlapped io (anyway that is the only way I know of to do it, it might very well be there are other ways)...
When I yerked around with it some years ago I figured the easiet way to get an pointer to the calling class is to just add the overlapped struct data to the top of the class and send the object pointer as overlapped argument... Not nice, but works if you are careful not to delete memory to early when canceling results (had a bunch of those)... A better way is probably to put the pointer in the hEvent variable since it is not used when lpOverlapped is not null... Either you could put the pointer directly, or try some indirect table index / handle to avoid instances were you delete the object before the callback happens (as I said, had a bunch of those)...

*Edit, Ok I just read the original post and to me it does not seem to have anything at all to do with what I read into the second post... Well since its bad to leave an empty message I guess I'll just leave this post here anyway.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.