user1131015
user1131015

Reputation: 67

c++ multithreaded windows GUI (accessing the forms)

I've written a simple console application using windows sockets to work as a proxy between a server and a client. I decided to make a graphical interface for watching all the in/outgoing packets real time (like a very simple wireshark).

The connection between the server and the client runs on a different thread than the message loop. When the server/client sends a packet, I would like that to be displayed (for example added to a simple text control) immediately.

But since I can not access the forms from other thread than the thread where the message loop is I dont know how to handle this.

I've found several solutions in: - Managed c++ - C++/CLI - C#, but not any without using .NET platform. (I really new to this GUI topic so I am not even sure you can use windows forms without .NET)

Maybe QT + C++ could handle this problem, but any other solution than that? If not is it possible to write a wrapper in C# / Java for the native C++ code?

There must be many applications written in C/C++ which using a GUI, what is the general way to do that?

Upvotes: 2

Views: 3386

Answers (3)

Jinhao
Jinhao

Reputation: 186

There is an alternative one, free and open-source, called Nana C++ Library (http://stdex.sourceforge.net), a pure C++ GUI library. By using Nana library, the multithreading issue can be fixed easily. There is an article on the multithreading in GUI, it would be a choice for your hobby project.

Upvotes: 2

al01
al01

Reputation: 122

A quick and dirty Win32 solution would involve a critical section, a text buffer, and a timer in the UI thread.

Define a few globals...

CRITICAL_SECTION bufferLock; // critical section (to be initialized somewhere)
char dataBuffer[65536]; // contains the data that will be sent to the form
int newdata = 0; // how much data we got (this variable must be atomic, int is ok)
char uiDataBuffer[65536]; // data available to the form
int overflow = 0; // just in case...

UI thread timer

void onTimer ()
{
     if (overflow)
     {
          // handle this
     }
     else
     if (newdata) // new data to display
     {
          // take the lock, copy the data and release the lock quickly
          EnterCriticalSection(&bufferLock);
          int dataread = newdata;
          memcpy(uiDataBuffer, dataBuffer, dataread);
          newdata = 0;
          LeaveCriticalSection(&bufferLock);

          // TODO: append the text in uiDataBuffer[] to your text control
     }
}

To be called from the worker thread:

void sendData (char* data, int size)
{
    EnterCriticalSection (&bufferLock);
    if(size+newdata > 65536)
        overflow = 1;
    else
    {
        memcpy(dataBuffer+newdata, data, size);
        newdata += size;
    }
    LeaveCriticalSection (&bufferLock);
}

Code untested. Buffer size and timer frequency are to be adjusted.

It is possible to avoid polling the buffer with the timer by using PostMessage() (with a custom message) to signal the UI that new data is available.

If performance is an issue, data exchange between a producer and a consumer thread can also be performed very efficiently with a lock-free FIFO queue.

PostMessage() alone is not a solution to exchange data between threads.

Upvotes: 0

jeffrey_t_b
jeffrey_t_b

Reputation: 1769

You are absolutely correct that you cannot access a window in a different thread. The proper way to handle this to post a message using the ::PostMessage Win32 API command (or, if you are using a wrapper library around Win32, whatever function in that wrapper that eventually calls PostMessage). Here's a useful link from Microsoft regarding message queues: http://msdn.microsoft.com/en-us/library/windows/desktop/ms644928(v=vs.85).aspx

Upvotes: 2

Related Questions