⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpdownloaddlg.cpp

📁 HTTP下载程序。类似IE中的下载界面
💻 CPP
📖 第 1 页 / 共 2 页
字号:
  m_sError.LoadString(nIDError);
  PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED, 1);
}

void CHttpDownloadDlg::DownloadThread()
{
  //Create the Internet session handle
  ASSERT(m_hInternetSession == NULL);
  m_hInternetSession = ::InternetOpen(AfxGetAppName(), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
  if (m_hInternetSession == NULL)
  {
    TRACE(_T("Failed in call to InternetOpen, Error:%d\n"), ::GetLastError());
    HandleThreadErrorWithLastError(IDS_HTTPDOWNLOAD_GENERIC_ERROR);
    return;
  }

  //Should we exit the thread
  if (m_bAbort)
  {
    PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED);
    return;
  }  

  //Setup the status callback function
  if (::InternetSetStatusCallback(m_hInternetSession, _OnStatusCallBack) == INTERNET_INVALID_STATUS_CALLBACK)
  {
    TRACE(_T("Failed in call to InternetSetStatusCallback, Error:%d\n"), ::GetLastError());
    HandleThreadErrorWithLastError(IDS_HTTPDOWNLOAD_GENERIC_ERROR);
    return;
  }

  //Should we exit the thread
  if (m_bAbort)
  {
    PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED);
    return;
  }  

  //Make the connection to the HTTP server          
  ASSERT(m_hHttpConnection == NULL);
  if (m_sUserName.GetLength())
    m_hHttpConnection = ::InternetConnect(m_hInternetSession, m_sServer, m_nPort, m_sUserName, 
                                          m_sPassword, m_dwServiceType, 0, (DWORD) this);
  else
    m_hHttpConnection = ::InternetConnect(m_hInternetSession, m_sServer, m_nPort, NULL, 
                                          NULL, m_dwServiceType, 0, (DWORD) this);
  if (m_hHttpConnection == NULL)
  {
    TRACE(_T("Failed in call to InternetConnect, Error:%d\n"), ::GetLastError());
    HandleThreadErrorWithLastError(IDS_HTTPDOWNLOAD_FAIL_CONNECT_SERVER);
    return;
  }

  //Should we exit the thread
  if (m_bAbort)
  {
    PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED);
    return;
  }  

  //Start the animation to signify that the download is taking place
  PlayAnimation();

  //Issue the request to read the file
  LPCTSTR ppszAcceptTypes[2];
  ppszAcceptTypes[0] = _T("*/*");  //We support accepting any mime file type since this is a simple download of a file
  ppszAcceptTypes[1] = NULL;
  ASSERT(m_hHttpFile == NULL);
  m_hHttpFile = HttpOpenRequest(m_hHttpConnection, NULL, m_sObject, NULL, NULL, ppszAcceptTypes, INTERNET_FLAG_RELOAD | 
                                INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_KEEP_CONNECTION, (DWORD) this);
  if (m_hHttpFile == NULL)
  {
    TRACE(_T("Failed in call to HttpOpenRequest, Error:%d\n"), ::GetLastError());
    HandleThreadErrorWithLastError(IDS_HTTPDOWNLOAD_FAIL_CONNECT_SERVER);
    return;
  }

  //Should we exit the thread
  if (m_bAbort)
  {
    PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED);
    return;
  }  

//label used to jump to if we need to resend the request
resend:

  //Issue the request
  BOOL bSend = ::HttpSendRequest(m_hHttpFile, NULL, 0, NULL, 0);
  if (!bSend)
  {
    TRACE(_T("Failed in call to HttpSendRequest, Error:%d\n"), ::GetLastError());
    HandleThreadErrorWithLastError(IDS_HTTPDOWNLOAD_FAIL_CONNECT_SERVER);
    return;
  }

  //Check the HTTP status code
	TCHAR szStatusCode[32];
	DWORD dwInfoSize = 32;
	if (!HttpQueryInfo(m_hHttpFile, HTTP_QUERY_STATUS_CODE, szStatusCode, &dwInfoSize, NULL))
  {
    TRACE(_T("Failed in call to HttpQueryInfo for HTTP query status code, Error:%d\n"), ::GetLastError());
    HandleThreadError(IDS_HTTPDOWNLOAD_INVALID_SERVER_RESPONSE);
    return;
  }
  else
  {
    long nStatusCode = _ttol(szStatusCode);

    //Handle any authentication errors
    if (nStatusCode == HTTP_STATUS_PROXY_AUTH_REQ || nStatusCode == HTTP_STATUS_DENIED)
    {
      // We have to read all outstanding data on the Internet handle
      // before we can resubmit request. Just discard the data.
      char szData[51];
      DWORD dwSize;
      do
	    {
		    ::InternetReadFile(m_hHttpFile, (LPVOID)szData, 50, &dwSize);
	    }
	    while (dwSize != 0);

      //Bring up the standard authentication dialog
      if (::InternetErrorDlg(GetSafeHwnd(), m_hHttpFile, ERROR_INTERNET_INCORRECT_PASSWORD, FLAGS_ERROR_UI_FILTER_FOR_ERRORS |
                             FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, NULL) == ERROR_INTERNET_FORCE_RETRY)
        goto resend;
    }
  	else if (nStatusCode != HTTP_STATUS_OK)
    {
      TRACE(_T("Failed to retrieve a HTTP 200 status, Status Code:%d\n"), nStatusCode);
      HandleThreadErrorWithLastError(IDS_HTTPDOWNLOAD_INVALID_HTTP_RESPONSE, nStatusCode);
      return;
    }
  }

  //Update the status control to reflect that we are getting the file information
  SetStatus(IDS_HTTPDOWNLOAD_GETTING_FILE_INFORMATION);

  // Get the length of the file.            
  TCHAR szContentLength[32];
  dwInfoSize = 32;
  DWORD dwFileSize = 0;
  BOOL bGotFileSize = FALSE;
  if (::HttpQueryInfo(m_hHttpFile, HTTP_QUERY_CONTENT_LENGTH, szContentLength, &dwInfoSize, NULL))
  {
    //Set the progress control range
    bGotFileSize = TRUE;
    dwFileSize = (DWORD) _ttol(szContentLength);
    SetProgressRange(dwFileSize);
  }

  //Update the status to say that we are now downloading the file
  SetStatus(IDS_HTTPDOWNLOAD_RETREIVEING_FILE);

  //Now do the actual read of the file
  DWORD dwStartTicks = ::GetTickCount();
  DWORD dwCurrentTicks = dwStartTicks;
  DWORD dwBytesRead = 0;
  char szReadBuf[1024];
  DWORD dwBytesToRead = 1024;
  DWORD dwTotalBytesRead = 0;
  DWORD dwLastTotalBytes = 0;
  DWORD dwLastPercentage = 0;
  do
  {
    if (!::InternetReadFile(m_hHttpFile, szReadBuf, dwBytesToRead, &dwBytesRead))
    {
      TRACE(_T("Failed in call to InternetReadFile, Error:%d\n"), ::GetLastError());
      HandleThreadErrorWithLastError(IDS_HTTPDOWNLOAD_ERROR_READFILE);
      return;
    }
    else if (dwBytesRead && !m_bAbort)
    {
      //Write the data to file
      TRY
      {
        m_FileToWrite.Write(szReadBuf, dwBytesRead);
      }
      CATCH(CFileException, e);                                          
      {
        TRACE(_T("An exception occured while writing to the download file\n"));
        HandleThreadErrorWithLastError(IDS_HTTPDOWNLOAD_ERROR_READFILE, e->m_lOsError);
        e->Delete();
        return;
      }
      END_CATCH

      //Increment the total number of bytes read
      dwTotalBytesRead += dwBytesRead;  

      UpdateControlsDuringTransfer(dwStartTicks, dwCurrentTicks, dwTotalBytesRead, dwLastTotalBytes, 
                                     dwLastPercentage, bGotFileSize, dwFileSize);
    }
  } 
  while (dwBytesRead && !m_bAbort);

  //Delete the file being downloaded to if it is present and the download was aborted
  m_FileToWrite.Close();
  if (m_bAbort)
    ::DeleteFile(m_sFileToDownloadInto);

  //We're finished
  PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED);
}

void CHttpDownloadDlg::UpdateControlsDuringTransfer(DWORD dwStartTicks, DWORD& dwCurrentTicks, DWORD dwTotalBytesRead, DWORD& dwLastTotalBytes, 
                                                    DWORD& dwLastPercentage, BOOL bGotFileSize, DWORD dwFileSize)
{
  if (bGotFileSize)
  {
    //Update the percentage downloaded in the caption
    DWORD dwPercentage = (DWORD) (dwTotalBytesRead * 100.0 / dwFileSize);
    if (dwPercentage != dwLastPercentage)
    {
      SetPercentage(dwPercentage);
      dwLastPercentage = dwPercentage;

      //Update the progress control bar
      SetProgress(dwTotalBytesRead);
    }
  }

  //Update the transfer rate amd estimated time left every second
  DWORD dwNowTicks = GetTickCount();
  DWORD dwTimeTaken = dwNowTicks - dwCurrentTicks;
  if (dwTimeTaken > 1000)
  {
    double KbPerSecond = ((double)(dwTotalBytesRead) - (double)(dwLastTotalBytes)) / ((double)(dwTimeTaken));
    SetTransferRate(KbPerSecond);

    //Setup for the next time around the loop
    dwCurrentTicks = dwNowTicks;
    dwLastTotalBytes = dwTotalBytesRead;

    if (bGotFileSize)
    {
      //Update the estimated time left
      if (dwTotalBytesRead)
      {
        DWORD dwSecondsLeft = (DWORD) (((double)dwNowTicks - dwStartTicks) / dwTotalBytesRead * 
                                       (dwFileSize - dwTotalBytesRead) / 1000);
        SetTimeLeft(dwSecondsLeft, dwTotalBytesRead, dwFileSize);
      }
    }
  }
}

void CALLBACK CHttpDownloadDlg::_OnStatusCallBack(HINTERNET hInternet, DWORD dwContext, DWORD dwInternetStatus, 
                                                  LPVOID lpvStatusInformation, DWORD dwStatusInformationLength)
{
  //Convert from the SDK C world to the C++ world
  CHttpDownloadDlg* pDlg = (CHttpDownloadDlg*) dwContext;
  ASSERT(pDlg);
  ASSERT(pDlg->IsKindOf(RUNTIME_CLASS(CHttpDownloadDlg)));
  pDlg->OnStatusCallBack(hInternet, dwInternetStatus, lpvStatusInformation, dwStatusInformationLength);
}

void CHttpDownloadDlg::OnStatusCallBack(HINTERNET /*hInternet*/, DWORD dwInternetStatus, 
                                         LPVOID lpvStatusInformation, DWORD /*dwStatusInformationLength*/)
{
  switch (dwInternetStatus)
  {
    case INTERNET_STATUS_RESOLVING_NAME:
    {
      SetStatus(IDS_HTTPDOWNLOAD_RESOLVING_NAME, (LPCTSTR) lpvStatusInformation);
      break;
    }
    case INTERNET_STATUS_NAME_RESOLVED:
    {
      SetStatus(IDS_HTTPDOWNLOAD_RESOLVED_NAME, (LPCTSTR) lpvStatusInformation);
      break;
    }
    case INTERNET_STATUS_CONNECTING_TO_SERVER:
    {
      SetStatus(IDS_HTTPDOWNLOAD_CONNECTING, (LPCTSTR) lpvStatusInformation);
      break;
    }
    case INTERNET_STATUS_CONNECTED_TO_SERVER:
    {
      SetStatus(IDS_HTTPDOWNLOAD_CONNECTED, (LPCTSTR) lpvStatusInformation);
      break;
    }
    case INTERNET_STATUS_REDIRECT:
    {
      SetStatus(IDS_HTTPDOWNLOAD_REDIRECTING, (LPCTSTR) lpvStatusInformation);
      break;
    }
    default:
    {
      break;
    }
  }
}

void CHttpDownloadDlg::OnDestroy() 
{
  //Wait for the worker thread to exit
  if (m_pThread)
  {
    WaitForSingleObject(m_pThread->m_hThread, INFINITE);
    delete m_pThread;
    m_pThread = NULL;
  }

  //Free up the internet handles we may be using
  if (m_hHttpFile)
  {
    ::InternetCloseHandle(m_hHttpFile);
    m_hHttpFile = NULL;
  }
  if (m_hHttpConnection)
  {
    ::InternetCloseHandle(m_hHttpConnection);
    m_hHttpConnection = NULL;
  }
  if (m_hInternetSession)
  {
    ::InternetCloseHandle(m_hInternetSession);
    m_hInternetSession = NULL;
  }

  //Let the parent class do its thing
	CDialog::OnDestroy();
}

void CHttpDownloadDlg::OnCancel() 
{
  //Just set the abort flag to TRUE and
  //disable the cancel button
  m_bAbort = TRUE;	
  GetDlgItem(IDCANCEL)->EnableWindow(FALSE);
  SetStatus(IDS_HTTPDOWNLOAD_ABORTING_TRANSFER);
}

void CHttpDownloadDlg::OnClose() 
{
  if (m_bSafeToClose)	
	  CDialog::OnClose();
  else
  {
    //Just set the abort flag to TRUE and
    //disable the cancel button
    m_bAbort = TRUE;	
    GetDlgItem(IDCANCEL)->EnableWindow(FALSE);
    SetStatus(IDS_HTTPDOWNLOAD_ABORTING_TRANSFER);
  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -