Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win


Performing multi-threaded listbox updates

Posted on 1998-08-20
Medium Priority
Last Modified: 2013-11-20
I have an owner-drawn listbox that displays bitmaps that are retrieved from the web after the box has been displayed.  I display a default image until the image has been downloaded, then replace the "blank" with the real image and start downloading the next image.  (This is quite similar in execution to a standard web browser.)

This function starts the retrieval thread, then is called by the thread when the thread is complete and starts a new thread to retrieve the next image:

long CMyDlg::RetrieveImage(WPARAM vResult, LPARAM l)

      pParams->vImageToRetrieve = m_ImageToRetrieveCounter;
      pParams->pImageList = &(m_pParent->m_pCurrentProc->m_OnlineImageList);
      pParams->pListBox = &m_cThumbListBox;
      pParams->hListBox = m_cThumbListBox.m_hWnd;
      pParams->pWeb = &(m_pParent->m_HospitalWeb);
      pParams->pWnd = this;

      // Are there more images to retrieve?  If not, just stop.
      if (m_ImageToRetrieveCounter >= m_TotalImages)
            return 0;

      // Activate the acquisition thread
      m_pThread = AfxBeginThread(ActivateAcquisitionThread,

      // Increment the counter for the next call

      return 1;

This next function is the thread function.  It retrieves the image and puts it into the list box.

UINT CMyDlg::ActivateAcquisitionThread(LPVOID pParam)
      CJpegDecoder vDecoder; // Will decode the retrieved jpeg
      CImageFunctions vIFunc;
      CBitmap *pBM;
      HBITMAP hThumbnail;
      CPoint vImageDim;
      BYTE *vImage;
      CThumbListBox *pListBox;
      CWnd *pWnd;

      pParams = (THREADPARAMS *)pParam;
      CStringList *pList = pParams->pImageList;

      // Retrieve the name of the image
      CString vImageName = pList->GetAt(pList->FindIndex(

      pListBox = (CThumbListBox *)CWnd::FromHandle((HWND)pParams->hListBox);

      // Retrieve the image, and get the saved file name
      vImageName = pParams->pWeb->GetImage(vImageName);
      if (vImageName == "")
            pParams->pWnd->PostMessage(UWM_THREAD_COMPLETE, -1);
            return -1;

      // Decode the image
      if ((vImage = vDecoder.Decode(vImageName, vImageDim)) == NULL)
            pWnd->PostMessage(UWM_THREAD_COMPLETE, -2);
            return -2;

        // Calls a func that assembles a BITMAP
      if (vDecoder.GetColorSpace() == JCS_GRAYSCALE)
            // Convert to RGB
            hThumbnail = vIFunc.MakeBitmap(vImage, vImageDim, 1, pParams->pWnd);
      else hThumbnail = vIFunc.MakeBitmap(vImage, vImageDim, 3, pParams->pWnd);

      // Make the bitmap and attach it
      pBM = new CBitmap();

      // Add to the list box

      // Post a "Completed" message
      pParams->pWnd->PostMessage(UWM_THREAD_COMPLETE, 1);

      return 1;

If the operations are performed in the main thread, they work fine, but I want to display the list box while the images are loading.  I keep getting errors, though.  With this code, it has trouble deleting the HWND.  The errors seem to vary somewhat, so I assume it has more to do with modifying memory elements that I shouldn't be modifying.  

Does anyone have suggestions on how I can approach this problem more safely?  If there is an alternative that is completely different from what I have shown, please share!

Thanks.  (PS if this question is harder than I think I'll up  the points.  Since every browser does this, though, it seems pretty simple.)
Question by:DenMan
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2

Accepted Solution

prasanth earned 100 total points
ID: 1321101

Couple of things:
1) Most MFC objects are confined to a single thread. You cannot pass CWnds and other such classes between threads. You can, however, pass around the underlying Windows handle, HWND in the case of CWnds. Then in the "receiving" thread use a CWnd::FromHandle(). You are doing this already with pParams->hListBox, but it looks like you are also passing pParams->pListBox which is basically useless.

2) Instead of pParams->pWnd, pass the underlying HWND as pParams->hWnd or whatever. In ActivateAcquisitionThread you have a CWnd* pWnd but it doesn't seem to have been initialized. Use

CWnd* pWnd = CWnd::FromHandle(pParams->hWnd)

instead. Also, right now

pWnd->PostMessage(UWM_THREAD_COMPLETE, -2);

should be failing because pWnd has not been initialized to anything.

3) In ActivateAcquisitionThread, you have

pParams = (THREADPARAMS *)pParam;

But all you really need is


because the structure has already been allocated; no need to allocate another one and then lose track of it. Also, be sure to free pParams before ActivateAcquisitionThread exits otherwise you'll find yourself with a memory leak.

4) You may or may not need a lock on pParams->pImageList, depending on if it can be changed while any of the ActivateAcquisitionThread threads are running. If the list is simply created once and then all the worker threads are run, you don't need to lock it.

5) I don't know what kind of an object pParams->pWeb is, but it too might need a lock if there is a possibility that is will be changed while one of the ActivateAcquisitionThreads is running.

Hope this helps...

Author Comment

ID: 1321102
Those comments were quite helpful.

pWeb is an object derived from CWnd that includes a CSocket and a variety of variables (such as site name, URL, etc) that relate to interacting with a couple web pages.  I have noticed that passing the HWND allows me to call the functions within the pWeb object, but all the variables are unassigned.  Is there any way to pass the pWeb object to the new thread yet still have access to the previously-assigned member variables?

Expert Comment

ID: 1321103
One way to do this is to put all the info (socket handles, session variables, and what-not) into a separate CWebInfo (or something) class. Then in pWeb's class definition, include a CWebInfo as a member variable: (for example)

class CHospitalWeb : public CWnd
    CWebInfo m_info;


CWebInfo really doesn't even need to be a class. It can be a simply struct:

typedef struct
   CSocket m_socket;
   CString m_username;
   CString m_password;
}  CWebInfo;

And regardless of whether it is a class or a struct, you can pass CWebInfo*'s between threads because they are not derived from CWnd. But again, you may need to put a lock on it if there is a possibility CWebInfo or any of it's member fields might be changed while another thread is reading it.

Hope this helps.

Author Comment

ID: 1321104
Hmmm...I'm still having trouble.  I can pass the CWebInfo * just fine.  It seems that I need to pass the HWND for the CHospitalWeb AND the CWebInfo *.  Then, since the m_Info within pWeb is now unassigned, I need to set those values equal to the CWebInfo *.  The problem is that if I try to set any of pWeb's variables, I get a null exception.  Will locking the CHospitalWeb solve this problem, or is there something else I'm forgetting?

Expert Comment

ID: 1321105
you need to construct a new CWebInfo before you assign it's variables...

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Here is how to use MFC's automatic Radio Button handling in your dialog boxes and forms.  Beginner programmers usually start with a OnClick handler for each radio button and that's just not the right way to go.  MFC has a very cool system for handli…
Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
In a question here at Experts Exchange (https://www.experts-exchange.com/questions/29062564/Adobe-acrobat-reader-DC.html), a member asked how to create a signature in Adobe Acrobat Reader DC (the free Reader product, not the paid, full Acrobat produ…

636 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question