Transfer MFC data to the main stream through PostMessage

I have a C ++ / MFC application that is required for restructuring. The application used to process most of the data in the main stream therefore blocks the input, and now I want to change it so that all GUI updates are done through PostMessage.

Unfortunately, I cannot find a good source of how to achieve this goal.

Now I'm going to create a priority queue protected by a critical section, a worker thread (while (true)) that processes this queue, and a PostMessage mechanism that sends pointers to data in the main thread.

What scares me of this approach is that PostMessage does not guarantee that it will reach the main thread at all, so if I understand correctly, there is a chance of a memory leak.

The second problem is that another application may send a custom message to my application, and my application may try to dereference WPARAM or LPARAM as a pointer, thereby causing AV.

Does anyone know what are the best practices for such tasks?

The data may be HTML content for web management or other content for lists, drop-down lists, etc.

+4
source share
3 answers

Your messages will get there. I'm not sure why you think PostMessage does not guarantee work - it is. (EDIT: Assuming PostMessage () returns TRUE! Check return codes!)

You want to avoid using a queue to transfer data between threads. Any queue that both threads access must be secured. Adding hard locks on both sides will serialize your application.

Instead, create a data structure on the heap using new , which contains your data, and then tell another thread: "I have data for you, and here it is." The receiving stream then takes responsibility for this data pointer and is responsible for delete for its use. So there are no hard locks.

Now the only trick is to figure out the “tell a different topic” part, but it's easy too.

If you are sending data from a workflow to the main thread, just use PostMessage() :

 worker_thread_proc() { // .. // Create the data object you're going to pass to the MT MyData* data = new MyData; data->some_value_ = "foo"; // Pass it: PostMessage(main_wnd, WM_YOU_HAVE_DATA, reinterpret_cast<WPARAM>(data), 0); } 

... the main thread processes this and then deletes the data:

 MainWnd::OnYouHaveData(WPARAM wp, LPARAM) { std::auto_ptr<MyData> data(reinterpret_cast<MyData*>(wp)); my_widget->set_text(data->some_value_); // you get the idea } 

If you are worried that custom messages from external applications are bumping into you, you can force Windows to give you a unique message identifier using RegisterWindowsMessage () - your only problem here is to choose the right name for your message.

If you send data from the main thread to the workflow, you can do the same as above, except using PostMessage() to send data on the wall, you can use either QueueUserAPC () (make sure your work thead is in standby - read comments in related docs) or PostThreadMessage () .

EDIT:

In your comments on the OP, I now understand why you are worried that PostMessage () is not working.

Yes, there is a hard limit on the size of the Windows message queue. By default, only 4,000 messages can be queued. (registry settings can configure this up to 10,000).

If the queue is full, any call to PostMessage() will end with an error code. When you check GetLastError () (I don’t remember which error code it is returning right now), it will be clear that the message queue is full.

Doesn't sound like a mother chicken, but you really need to check your return values ​​from API calls. But besides this, if you are working in a thread of a message queue, I would say that your application will break anyway. When the queue is full, your application will not be able to breathe. The screen will not draw, any processing that you do will be out of date, and all kinds of bad things happen. If this is the situation you are in, you may need to see why.

+9
source

Use two queues, one for work requests going to the workflow and one for results returning to the main thread. You can use PostMessage to wake up the main thread and tell it to check the queue, but you don't need any parameters in the message.

+2
source

I solved a similar problem a while ago. I made a single queue to store data (or actions) that should flow from background threads to a user interface (main) thread. The queue is protected by a critical section. The background thread queues its data and sends a message. The message does not contain any data, it acts as a simple wake-up call "hey, main thread, look at the queue, there is work for you."

Thus, you do not risk leaking any memory or other resources; A queue can be safely destroyed by all the data it contains.

+1
source

All Articles