?
Solved

Multithreading MFC WinInet

Posted on 1998-03-31
9
Medium Priority
?
780 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
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!

 

Author Comment

by:ossentoo
ID: 1183973
Edited text of question
0
 

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 400 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

Industry Leaders: 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

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.
Suggested Courses

864 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