Solved

Multithreading MFC WinInet

Posted on 1998-03-31
9
712 Views
Last Modified: 2012-06-21
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);
}
0
Comment
Question by:ossentoo
9 Comments
 
LVL 7

Expert Comment

by:galkin
ID: 1183970
Could you post a piece of code how you create worker thread and do thread sinchronization
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 1183971
  Is the thread creating any windows, like a progress control/indicator?

-=- James.
0
 

Expert Comment

by:jann
ID: 1183972
Have you try to add "BringWindowToTop" before "UpdateWindow"?
0
 

Author Comment

by:ossentoo
ID: 1183973
Edited text of question
0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 

Author Comment

by:ossentoo
ID: 1183974
Edited text of question
0
 

Author Comment

by:ossentoo
ID: 1183975
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
 
LVL 2

Expert Comment

by:lucidity
ID: 1183976
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
 

Author Comment

by:ossentoo
ID: 1183977
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
 
LVL 4

Accepted Solution

by:
jtwine100697 earned 200 total points
ID: 1183978
  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

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

760 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

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now