Multithreading MFC WinInet

I have created a worker thread to download a file by passing the thread a ponter to the CInternetSession object, creating a new CFtpConnection object, going  to the current directory and downloading the file.

The problem is, when the code enters the thread, the use interface is locked until the download completes.  I thought adding a worker thread would get around this problem.  I have tried using UpdateWindow() right after creating the thread by nothing happens.  Debugging is difficult as it seems the debugger can only be at one place at a time.

Please help

Thanks

UPDATE----------------------------------------------------

#include "thDownld.h"
#include "FtpExpl.h"
#include "DownDlg.h"

UINT DownloadThread(LPVOID pParam)
{
      CString strInternetSession;
      CFtpConnection *pFtpConnection;

      CString strFileTo=_T("m:\\download\\");
      CFtpDoc* pDoc=(CFtpDoc*)pParam;
      CFtpExplApp* pApp=(CFtpExplApp*)AfxGetApp();

      strInternetSession.LoadString(IDS_APPNAME);

      try
      {
            pFtpConnection=pDoc->m_pInetSession->GetFtpConnection(
                  pDoc->m_pFtpConnection->GetServerName(), "", "", INTERNET_DEFAULT_FTP_PORT);
      }
      catch(CInternetException* pEx)
      {
            // catch errors from WinInet
            TCHAR szErr[1024];
            if (pEx->GetErrorMessage(szErr, 1024))
                  AfxMessageBox(szErr, MB_OK);
            else
                  AfxMessageBox(IDS_EXCEPTION, MB_OK);
            pEx->Delete();
            pFtpConnection = NULL;
      }
      //Set the current directory within this server.
      if(!pFtpConnection->SetCurrentDirectory(pDoc->m_pCurDir))
            return 1;
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

      //Create COPY_TO location
      strFileTo+=pApp->m_szFile;
      //Download the file
      //BOOL bDownloaded=pApp->m_pConnection->GetFile(pApp->m_lpczFileName, "readme.txt", FALSE);
      //Start this dialog and download
      CDownDlg* pDlg=new CDownDlg;
      //pDlg=(CDownDlg*)m_pDlgArr.ElementAt(m_pDlgArr.GetSize());
      pDlg->Create(IDD_DOWNLOAD);
      pDlg->ShowWindow(SW_SHOWNORMAL);

      //BOOL bDownloaded=pFtpConnection->GetFile(pApp.m_szFile, strFileTo, 1);
      Sleep(10000);
      // Get the last error
      DWORD dwError;
      dwError=GetLastError();

      //Get rid of the dialog
      pDlg->DestroyWindow();
      delete pDlg;

      //Delete the Ftp Connection Object
      pFtpConnection->Close();
      delete pFtpConnection;

      //Clear the global variable.
      return 0;    // thread completed successfully      
}
  THREAD is called from the function below:

BOOL CFtpDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
      CFtpExplApp* pApp=(CFtpExplApp*)AfxGetApp();
      //int nSize=m_pDlgArr->GetSize();
      pApp->m_szFile=lpszPathName;
      //strcpy(gbl_szFileName,lpszPathName);
      //Begin the download thread
      AfxBeginThread(DownloadThread, this,THREAD_PRIORITY_BELOW_NORMAL);
      AfxGetMainWnd()->UpdateWindow();
      return TRUE;
       //return CDocument::OnSaveDocument(lpszPathName);
}
ossentooAsked:
Who is Participating?
 
jtwine100697Connect With a Mentor Commented:
  The problem could have been answered before if you would have answered my question earlier...!

   Every Thread in Win32 has its own message queue, and you need to pump that message queue in order for the dialog (that the Thread creates) to respond to messages, and for the system to work correctly.

   Pump the message queue, with something like a PeekMessage/GetMessage/DispatchMessage loop while waiting for the download to complete.

-=- James.
0
 
galkinCommented:
Could you post a piece of code how you create worker thread and do thread sinchronization
0
 
jtwine100697Commented:
  Is the thread creating any windows, like a progress control/indicator?

-=- James.
0
Cloud Class® Course: CompTIA Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

 
jannCommented:
Have you try to add "BringWindowToTop" before "UpdateWindow"?
0
 
ossentooAuthor Commented:
Edited text of question
0
 
ossentooAuthor Commented:
Edited text of question
0
 
ossentooAuthor Commented:
Here is the function code:
(Will try bring window to top)
BOOL CFtpDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
      CFtpExplApp* pApp=(CFtpExplApp*)AfxGetApp();
      //int nSize=m_pDlgArr->GetSize();
      pApp->m_szFile=lpszPathName;
      //strcpy(gbl_szFileName,lpszPathName);
      //Begin the download thread
      AfxBeginThread(DownloadThread, this,THREAD_PRIORITY_BELOW_NORMAL);
      AfxGetMainWnd()->UpdateWindow();
      return TRUE;
       //return CDocument::OnSaveDocument(lpszPathName);
}

0
 
lucidityCommented:
GetFile is a high-level routine that handles all of the overhead associated with reading a file from an FTP server and storing it locally. Applications that only retrieve file data, or that require close control over the file transfer, should use OpenFile and CInternetFile::Read instead.
0
 
ossentooAuthor Commented:
Have now created a new User Interface Class:

#include "stdafx.h"
#include "FtpExpl.h"
#include "uiDownld.h"
#include "DownDlg.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

// A single global event handle is used to synchronize the termination
// of the application and the termination of bounce threads.  This
// synchronization avoids false memory leak detection of CDownThread
// objects that did not have time to be auto-destroyed before the
// application terminates.
//
// The reason that m_hEventDownloadThreadKilled cannot be a per-object member
// variable of the CDownThread object is because the event handle must
// be referred to by the delete operator.   By the time the delete operator
// is called, the member variable no longer can be referenced.  The reason
// that it is permissable to use a global event, instead of per thread events,
// is that each CDownWnd window is destroyed in sequence, one after another.
// Therefore, each CDownThread is destroyed in sequence, one after another.

HANDLE CDownThread::m_hEventDownloadThreadKilled;

/////////////////////////////////////////////////////////////////////////////
// CDownThread

IMPLEMENT_DYNCREATE(CDownThread, CWinThread)

CDownThread::CDownThread()
{
}

CDownThread::~CDownThread()
{
}

void CDownThread::operator delete(void* p)
{
      // The exiting main application thread waits for this event before completely
      // terminating in order to avoid a false memory leak detection.  See also
      // CDownWnd::OnNcDestroy in bounce.cpp.
      SetEvent(m_hEventDownloadThreadKilled);

      CWinThread::operator delete(p);
}

int CDownThread::InitInstance()
{
      m_pDlg=new CDownDlg;
      //pDlg=(CDownDlg*)m_pDlgArr.ElementAt(m_pDlgArr.GetSize());
      BOOL bReturn=m_pDlg->Create(IDD_DOWNLOAD);
      m_pDlg->ShowWindow(SW_SHOWNORMAL);

      ASSERT(m_pDlg);

      // It is important to set CWinThread::m_pMainWnd to the user interface
      // window.  This is required so that when the m_pMainWnd is destroyed,
      // the CWinThread is also automatically destroyed.  For insight into
      // how the CWinThread is automatically destroyed when the m_pMainWnd
      // window is destroyed, see the implementation of CWnd::OnNcDestroy
      // in wincore.cpp of the MFC sources.
      if (bReturn)
            m_pMainWnd = m_pDlg;
      
      m_pDlg->DownloadFile();
      return bReturn;
}

int CDownThread::ExitInstance()
{
      //Make sure we have de-referenced the dialog box memory
      delete m_pDlg;

      return CWinThread::ExitInstance();
}

BEGIN_MESSAGE_MAP(CDownThread, CWinThread)
      //{{AFX_MSG_MAP(CDownThread)
            // NOTE - the ClassWizard will add and remove mapping macros here.
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDownThread message handlers




This is called from:

BOOL CFtpDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
      CFtpExplApp* pApp=(CFtpExplApp*)AfxGetApp();
      //int nSize=m_pDlgArr->GetSize();
      pApp->m_szFile=lpszPathName;
      //strcpy(gbl_szFileName,lpszPathName);
      CDownThread* pDownThread = new CDownThread();
      pDownThread->CreateThread();
      //Begin the download thread
      //AfxBeginThread(DownloadThread, this,THREAD_PRIORITY_BELOW_NORMAL);
      //AfxGetMainWnd()->BringWindowToTop();
      return TRUE;
       //return CDocument::OnSaveDocument(lpszPathName);
}


I still get locking.  I should be able to move the dialog or the main frame with the mouse even though downloading is taking place.  BUT I CAN'T

Anybody know why (I have tried to implement the suggestions above, but to no avail!!)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.