Amit
Amit

Reputation: 703

Working with WINAPI with couple of threads

I've been working on WinAPI for a while, and I noticed that whenever I try to use WINAPI functions (such as create buttons/windows / update listview and such) inside a thread which isn't the main thread, it just wont show up.

So for example, if I want to add items to a ListView, and I call a function that takes a string and adds it to the listview, if I call the function from the main thread, it'll work great, but if I call it from a different thread, it won't work at all.

What can I do?

Upvotes: 0

Views: 230

Answers (2)

jlahd
jlahd

Reputation: 6303

You should either use PostMessage:

static LVITEM lvi = { ... };
PostMessage( myListView, LVM_INSERTITEM, 0, (LPARAM)&lvi );

or, if you need the return value, create a message pump for your thread first:

MSG msg;
PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE );
static LVITEM lvi = { ... };
ListView_InsertItem( myListView, &lvi );

If you use PostMessage, be sure to keep the memory alive also after PostMessage returns, as the message is processed asynchronously by your main thread.

Upvotes: 0

noelicus
noelicus

Reputation: 15055

As with most (all?) GUI systems you need to update the GUI from the thread that owns the window (usually the main thread). You need to find a way to communicate between the two threads. In Win32 my preferred way is to send a user message to the GUI thread (via PostMessage) and update accordingly. You will need to ensure there's no concurrent access to data you send between them, for example protect global data with a Critical Section or something.

A simple example, semi pseudo code:

#define WM_MY_MESSAGE WM_USER+1

thread
{
    do some number crunching...
    // inform user
    EnterCriticalSection(&MessageCrit);
    strncpy(StatusMessageText, "Crunching away...", ARRAYSIZE(StatusMessageText));
    LeaveCriticalSection(&MessageCrit);
    PostMessage(hwndMain, WM_MY_MESSAGE, 0, 0); // You can utilize the params to your hearts content: structures, enums, etc...
}

guithread
{
switch (message)
{
case WM_INITDIALOG: // etc - whatever is in your normal message handler
    break;
case WM_MY_MESSAGE:
    ListView_InsertItem(...); // etc
    EnterCriticalSection(&MessageCrit); // Protect the global data
    ListView_SetItemText(item, StatusMessageText);
    LeaveCriticalSection(&MessageCrit);    
    break;
}
}

Upvotes: 4

Related Questions