【VC编程】VC下一个通过HTTP协议下载的类(CHttpDownload)

                                       

VC下一个通过HTTP协议下载的类(CHttpDownload)

作者:dozb

这个类是基于MFC的,是对 wininet 库的封装。

下面是类头文件:

HttpDownload.h

package com.ly.util;
// HttpDownload.h: interface for the CHttpDownload class.
//
//

#if !defined(AFX_HTTPDOWNLOAD_H__E4698E96_7AD2_4DF0_AB2D_B184E46B8784__INCLUDED_)
#define AFX_HTTPDOWNLOAD_H__E4698E96_7AD2_4DF0_AB2D_B184E46B8784__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

const UINT WM_HTTPDOWNLOAD_THREAD_FINISHED = WM_APP + 81;
const UINT WM_HTTPDOWNLOAD_FILESTATUS = WM_APP + 82;
const UINT WM_HTTPDOWNLOAD_PERCENTAGE = WM_APP + 83;
const UINT WM_HTTPDOWNLOAD_TIMELEFT = WM_APP + 84;
const UINT WM_HTTPDOWNLOAD_STATUS = WM_APP + 85;
const UINT WM_HTTPDOWNLOAD_TRANSFERRATE = WM_APP + 86;

#define IDS_HTTPDOWNLOAD_FILESTATUS "%s from %s"
#define IDS_HTTPDOWNLOAD_CONNECTED "Connected to %s"
#define IDS_HTTPDOWNLOAD_RESOLVING_NAME "Resolving name: %s"
#define IDS_HTTPDOWNLOAD_RESOLVED_NAME "Resolved name to %s"
#define IDS_HTTPDOWNLOAD_CONNECTING "Connecting to %s"
#define IDS_HTTPDOWNLOAD_REDIRECTING "Redirecting to %s"
#define IDS_HTTPDOWNLOAD_GETTING_FILE_INFORMATION "Getting file information"
#define IDS_HTTPDOWNLOAD_FAIL_PARSE_ERROR "An error occurred parsing the url: %s"
#define IDS_HTTPDOWNLOAD_GENERIC_ERROR \
"An error occurred while attempting to download the file, Error:%s"
#define IDS_HTTPDOWNLOAD_FAIL_CONNECT_SERVER \
"An error occurred connecting to the server, Error:%s"


#define IDS_HTTPDOWNLOAD_BYTESPERSECOND "%s Bytes/Sec"
#define IDS_HTTPDOWNLOAD_KILOBYTESPERSECOND "%s KB/Sec"
#define IDS_HTTPDOWNLOAD_OK_TO_OVERWRITE \
"The file '%s' already exists.\nDo you want to replace it?"
#define IDS_HTTPDOWNLOAD_FAIL_FILE_OPEN \
"An error occured while opening the file to be downloaded, Error:%s"
#define IDS_HTTPDOWNLOAD_ABORTING_TRANSFER "Aborting transfer"
#define IDS_HTTPDOWNLOAD_FAIL_FILE_SEEK \
"An error occurred while seeking to the end of the file to be downloaded, Error:%s"


#define IDS_HTTPDOWNLOAD_INVALID_SERVER_RESPONSE \
"Failed to receive a valid response from the server, Error:%s"
#define IDS_HTTPDOWNLOAD_INVALID_HTTP_RESPONSE \
"Failed to receive a valid HTTP response from the server, Response Code:%s"
#define IDS_HTTPDOWNLOAD_ERROR_READFILE \
"An error occurred while downloading the file, Error:%s"
#define IDS_HTTPDOWNLOAD_PERCENTAGE "%s% of %s Completed"
#define IDS_HTTPDOWNLOAD_RETREIVEING_FILE "Retrieving the file"
#define IDS_HTTPDOWNLOAD_OF "%s of %s"
#define IDS_HTTPDOWNLOAD_SECONDS "%s sec"
#define IDS_HTTPDOWNLOAD_MINUTES "%s min"
#define IDS_HTTPDOWNLOAD_MINUTES_AND_SECONDS "%s min %s sec"
#define IDS_HTTPDOWNLOAD_BYTES "%s Bytes"
#define IDS_HTTPDOWNLOAD_KILOBYTES "%s KB"
#define IDS_HTTPDOWNLOAD_MEGABYTES "%s MB"
#define IDS_HTTPDOWNLOAD_TIMELEFT "%s (%s copied)"

class CHttpDownload : public CObject 
{
public:
CHttpDownload();
virtual ~CHttpDownload();
public:
//Enums
enum ConnectionType
{
UsePreConfig, 
DirectToInternet,
UseProxy,
};
HWND m_hNotifyWnd;
BOOL Init( HWND hNotifyWnd,
CString sURLToDownload,
CString sFileToDownloadInto,
CString sProxyServer="",
CString sProxyUserName="",
CString sProxyPassword="",
CString sHTTPUserName="",
CString sHTTPPassword="",
CHttpDownload::ConnectionType nConnectionType = CHttpDownload::UsePreConfig,
BOOL bPromptFileOverwrite = FALSE,
BOOL PromptForProxyDetails = FALSE,
BOOL bPromptForHTTPDetails = FALSE,
double dbLimit = 0, //For BANDWIDTH Throptling, The value in Bytes / Second to limit the connection to
DWORD dwStartPos= 0 //Offset to resume the download at 
);
BOOL Start();
void Cancel();
void DisInit();


//Public Member variables
CString m_sURLToDownload;
CString m_sFileToDownloadInto;
CString m_sProxyServer;
CString m_sProxyUserName;
CString m_sProxyPassword;
CString m_sHTTPUserName;
CString m_sHTTPPassword;
CString m_sUserAgent;
ConnectionType m_ConnectionType;
BOOL m_bPromptFileOverwrite;
BOOL m_bPromptForProxyDetails;
BOOL m_bPromptForHTTPDetails;
double m_dbLimit; //For BANDWIDTH Throptling, The value in Bytes / Second to limit the connection to
DWORD m_dwStartPos; //Offset to resume the download at 
protected:
LRESULT OnThreadFinished(WPARAM wParam, LPARAM lParam);

//Methods
static void CALLBACK _OnStatusCallBack(HINTERNET hInternet, DWORD dwContext, DWORD dwInternetStatus, 
LPVOID lpvStatusInformation, DWORD dwStatusInformationLength);
static BOOL QueryStatusNumber(HINTERNET hInternet, DWORD dwFlag, DWORD& dwCode);
static BOOL QueryStatusCode(HINTERNET hInternet, DWORD& dwCode);
static BOOL QueryContentLength(HINTERNET hInternet, DWORD& dwCode);
void OnStatusCallBack(HINTERNET hInternet, DWORD dwInternetStatus, 
LPVOID lpvStatusInformation, DWORD dwStatusInformationLength);
static UINT _DownloadThread(LPVOID pParam);
virtual BOOL OnSetOptions();
virtual void HandleThreadErrorWithLastError(char* nIDError, DWORD dwLastError=0);
virtual void HandleThreadError(char* nIDError);
virtual void DownloadThread();
virtual void SetPercentage(int nPercentage);
virtual void SetTimeLeft(DWORD dwSecondsLeft, DWORD dwBytesRead, DWORD dwFileSize);
virtual void SetStatus(const CString& sCaption);
virtual void SetStatus(char * nID);
virtual void SetStatus(char* nID, const CString& lpsz1);
virtual void SetTransferRate(double KbPerSecond);
virtual void UpdateControlsDuringTransfer(DWORD dwStartTicks, DWORD& dwCurrentTicks, DWORD dwTotalBytesRead, DWORD& dwLastTotalBytes, 
DWORD& dwLastPercentage, BOOL bGotFileSize, DWORD dwFileSize);

protected:
//Member variables
CString m_sError;
CString m_sServer; 
DWORD m_dwServiceType;
CString m_sObject; 
CString m_sFilename;
INTERNET_PORT m_nPort;
HINTERNET m_hInternetSession;
HINTERNET m_hHttpConnection;
HINTERNET m_hHttpFile;
BOOL m_bAbort;
BOOL m_bSafeToClose;
CFile m_FileToWrite;
CWinThread* m_pThread;

};

#endif // !defined(AFX_HTTPDOWNLOAD_H__E4698E96_7AD2_4DF0_AB2D_B184E46B8784__INCLUDED_)


下面是类的实现文件:

HttpDownload.cpp

// HttpDownload.cpp: implementation of the CHttpDownload class.
//
//

#include "stdafx.h"
#include "HttpDownload.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//
// Construction/Destruction
//

CHttpDownload::CHttpDownload()
{

}

CHttpDownload::~CHttpDownload()
{

}

BOOL CHttpDownload::Init(
HWND hNotifyWnd,
CString sURLToDownload,
CString sFileToDownloadInto,
CString sProxyServer,
CString sProxyUserName,
CString sProxyPassword,
CString sHTTPUserName,
CString sHTTPPassword,
CHttpDownload::ConnectionType nConnectionType,
BOOL bPromptFileOverwrite,
BOOL bPromptForProxyDetails,
BOOL bPromptForHTTPDetails,
double dbLimit, //For BANDWIDTH Throptling, The value in Bytes / Second to limit the connection to
DWORD dwStartPos //Offset to resume the download at 
)
{
m_hNotifyWnd = hNotifyWnd;
m_sURLToDownload = sURLToDownload;
m_sFileToDownloadInto = sFileToDownloadInto;
m_sProxyServer = sProxyServer;
m_sProxyUserName = sProxyUserName;
m_sProxyPassword = sProxyPassword;
m_sHTTPUserName = sHTTPUserName;
m_sHTTPPassword = sHTTPPassword;
m_ConnectionType = nConnectionType;
m_bPromptFileOverwrite = bPromptFileOverwrite;
m_bPromptForProxyDetails = bPromptForProxyDetails;
m_bPromptForHTTPDetails = bPromptForHTTPDetails;
m_dbLimit = dbLimit;
m_dwStartPos = dwStartPos;

m_hInternetSession = NULL;
m_hHttpConnection = NULL;
m_hHttpFile = NULL;
m_bAbort = FALSE;
m_bSafeToClose = FALSE;
m_pThread = NULL;

m_dwServiceType = 0;
return TRUE;
}
LRESULT CHttpDownload::OnThreadFinished(WPARAM wParam, LPARAM lParam)
{
//It's now safe to close since the thread has signaled us
m_bSafeToClose = TRUE;

//Stop the animation
// m_ctrlAnimate.Stop();

//If an error occured display the message box
if (m_bAbort)
{
// EndDialog(IDCANCEL);
}
else if (wParam)
{
AfxMessageBox(m_sError);
// EndDialog(IDCANCEL);
}
else
{
// EndDialog(IDOK);
}

PostMessage(m_hNotifyWnd,WM_HTTPDOWNLOAD_THREAD_FINISHED, wParam,lParam);
return 0L;
}
BOOL CHttpDownload::Start()
{
//Validate the URL
ASSERT(m_sURLToDownload.GetLength()); //Did you forget to specify the file to download
if (!AfxParseURL(m_sURLToDownload, m_dwServiceType, m_sServer, m_sObject, m_nPort))
{
//Try sticking "http://" before it
m_sURLToDownload = _T("http://") + m_sURLToDownload;
if (!AfxParseURL(m_sURLToDownload, m_dwServiceType, m_sServer, m_sObject, m_nPort))
{
CString sMsg;
sMsg.Format(_T("Failed to parse the URL: %s\n"), m_sURLToDownload);
AfxMessageBox(sMsg);
return FALSE;
}
}

//Check to see if the file we are downloading to exists and if
//it does, then ask the user if they were it overwritten
CFileStatus fs;
ASSERT(m_sFileToDownloadInto.GetLength());
BOOL bDownloadFileExists = CFile::GetStatus(m_sFileToDownloadInto, fs);
if (bDownloadFileExists && m_dwStartPos == 0 && m_bPromptFileOverwrite)
{
CString sMsg;
sMsg.Format(IDS_HTTPDOWNLOAD_OK_TO_OVERWRITE, m_sFileToDownloadInto);
if (AfxMessageBox(sMsg, MB_YESNO) != IDYES)
{
TRACE(_T("Failed to confirm file overwrite, download aborted\n"));
// EndDialog(IDCANCEL);
return FALSE;
}
}

//Try and open the file we will download into
DWORD dwFileFlags = 0;
if (bDownloadFileExists && (m_dwStartPos > 0))
dwFileFlags = CFile::modeCreate | CFile::modeNoTruncate | CFile::modeWrite | CFile::shareDenyWrite;
else
dwFileFlags = CFile::modeCreate | CFile::modeWrite | CFile::shareDenyWrite;
if (!m_FileToWrite.Open(m_sFileToDownloadInto, dwFileFlags))
{
CString sError;
sError.Format(_T("%d"), ::GetLastError());
CString sMsg;
sMsg.Format(IDS_HTTPDOWNLOAD_FAIL_FILE_OPEN, GetLastError());
AfxMessageBox(sMsg);
//EndDialog(IDCANCEL);
return FALSE;
}
else
{
//Seek to the end of the file
try
{
m_FileToWrite.Seek(m_dwStartPos, CFile::begin); 
m_FileToWrite.SetLength(m_dwStartPos);
}
catch(CFileException* pEx) 
{
CString sError;
sError.Format(_T("%d"), pEx->m_lOsError);
CString sMsg;
sMsg.Format(IDS_HTTPDOWNLOAD_FAIL_FILE_SEEK, pEx->m_lOsError);
AfxMessageBox(sMsg);
// EndDialog(IDCANCEL);
return FALSE;
} 
}

//Pull out just the filename component
int nSlash = m_sObject.ReverseFind(_T('/'));
if (nSlash == -1)
nSlash = m_sObject.ReverseFind(_T('\\'));
if (nSlash != -1 && m_sObject.GetLength() > 1)
m_sFilename = m_sObject.Right(m_sObject.GetLength() - nSlash - 1);
else
m_sFilename = m_sObject;

//Set the file status text
CString sFileStatus;
ASSERT(m_sObject.GetLength());
ASSERT(m_sServer.GetLength());
sFileStatus.Format(IDS_HTTPDOWNLOAD_FILESTATUS, m_sFilename, m_sServer);
// m_ctrlFileStatus.SetWindowText(sFileStatus);
SendMessage(m_hNotifyWnd,WM_HTTPDOWNLOAD_FILESTATUS,(WPARAM)&sFileStatus,0); 
//Spin off the background thread which will do the actual downloading
m_pThread = AfxBeginThread(_DownloadThread, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
if (m_pThread == NULL)
{
CString sMsg;
sMsg.Format(_T("Failed to create download thread, dialog is aborting\n"));
AfxMessageBox(sMsg);
// EndDialog(IDCANCEL);
return FALSE;
}
m_pThread->m_bAutoDelete = FALSE;
m_pThread->ResumeThread();

return TRUE;

}

UINT CHttpDownload::_DownloadThread(LPVOID pParam)
{
//Convert from the SDK world to the C++ world
CHttpDownload* pHttpDownload = (CHttpDownload*) pParam;
ASSERT(pHttpDownload);
pHttpDownload->DownloadThread();
return 0;
}

void CHttpDownload::SetPercentage(int nPercentage)
{
//Change the progress control
// m_ctrlProgress.SetPos(nPercentage);

//Change the caption text
CString sPercentage;
sPercentage.Format(_T("%d"), nPercentage);
CString sCaption;
sCaption.Format(IDS_HTTPDOWNLOAD_PERCENTAGE, sPercentage, m_sFilename);
// SetWindowText(sCaption);
SendMessage(m_hNotifyWnd,WM_HTTPDOWNLOAD_PERCENTAGE,(WPARAM)&sCaption,nPercentage); 

}

void CHttpDownload::SetTimeLeft(DWORD dwSecondsLeft, DWORD dwBytesRead, DWORD dwFileSize)
{
CString sCopied;
if (dwBytesRead < 1024)
{
CString sBytes;
sBytes.Format(_T("%d"), dwBytesRead);
sCopied.Format(IDS_HTTPDOWNLOAD_BYTES, sBytes);
}
else if (dwBytesRead < 1048576)
{
CString sKiloBytes;
sKiloBytes.Format(_T("%0.1f"), dwBytesRead/1024.0);
sCopied.Format(IDS_HTTPDOWNLOAD_KILOBYTES, sKiloBytes);
}
else
{
CString sMegaBytes;
sMegaBytes.Format(_T("%0.2f"), dwBytesRead/1048576.0);
sCopied.Format(IDS_HTTPDOWNLOAD_MEGABYTES, sMegaBytes);
}

CString sTotal;
if (dwFileSize < 1024)
{
CString sBytes;
sBytes.Format(_T("%d"), dwFileSize);
sTotal.Format(IDS_HTTPDOWNLOAD_BYTES, sBytes);
}
else if (dwFileSize < 1048576)
{
CString sKiloBytes;
sKiloBytes.Format(_T("%0.1f"), dwFileSize/1024.0);
sTotal.Format(IDS_HTTPDOWNLOAD_KILOBYTES, sKiloBytes);
}
else
{
CString sMegaBytes;
sMegaBytes.Format(_T("%0.2f"), dwFileSize/1048576.0);
sTotal.Format(IDS_HTTPDOWNLOAD_MEGABYTES, sMegaBytes);
}

CString sOf;
sOf.Format(IDS_HTTPDOWNLOAD_OF, sCopied, sTotal);

CString sTime;
if (dwSecondsLeft < 60)
{
CString sSeconds;
sSeconds.Format(_T("%d"), dwSecondsLeft);
sTime.Format(IDS_HTTPDOWNLOAD_SECONDS, sSeconds);
}
else
{
DWORD dwMinutes = dwSecondsLeft / 60;
DWORD dwSeconds = dwSecondsLeft % 60;
CString sSeconds;
sSeconds.Format(_T("%d"), dwSeconds);
CString sMinutes;
sMinutes.Format(_T("%d"), dwMinutes);
if (dwSeconds == 0)
sTime.Format(IDS_HTTPDOWNLOAD_MINUTES, sMinutes);
else
sTime.Format(IDS_HTTPDOWNLOAD_MINUTES_AND_SECONDS, sMinutes, sSeconds);
}

CString sTimeLeft;
sTimeLeft.Format(IDS_HTTPDOWNLOAD_TIMELEFT, sTime, sOf);
// m_ctrlTimeLeft.SetWindowText(sTimeLeft);
SendMessage(m_hNotifyWnd,WM_HTTPDOWNLOAD_TIMELEFT,(WPARAM)&sTimeLeft,0); 

}

void CHttpDownload::SetStatus(const CString& sCaption)
{
// m_ctrlStatus.SetWindowText(sCaption);
SendMessage(m_hNotifyWnd,WM_HTTPDOWNLOAD_STATUS,(WPARAM)&sCaption,0); 
}

void CHttpDownload::SetStatus(char* nID)
{
CString sCaption;
sCaption = nID;
SetStatus(sCaption);
}

void CHttpDownload::SetStatus(char* nID, const CString& lpsz1)
{
CString sStatus;
sStatus.Format(nID, lpsz1);
SetStatus(sStatus);
}

void CHttpDownload::SetTransferRate(double KbPerSecond)
{
CString sRate;
if (KbPerSecond < 1)
{
CString sBytesPerSecond;
sBytesPerSecond.Format(_T("%0.0f"), KbPerSecond*1024);
sRate.Format(IDS_HTTPDOWNLOAD_BYTESPERSECOND, sBytesPerSecond);
}
else if (KbPerSecond < 10)
{
CString sKiloBytesPerSecond;
sKiloBytesPerSecond.Format(_T("%0.2f"), KbPerSecond);
sRate.Format(IDS_HTTPDOWNLOAD_KILOBYTESPERSECOND, sKiloBytesPerSecond);
}
else
{
CString sKiloBytesPerSecond;
sKiloBytesPerSecond.Format(_T("%0.0f"), KbPerSecond);
sRate.Format(IDS_HTTPDOWNLOAD_KILOBYTESPERSECOND, sKiloBytesPerSecond);
}
// m_ctrlTransferRate.SetWindowText(sRate);
SendMessage(m_hNotifyWnd,WM_HTTPDOWNLOAD_TRANSFERRATE,(WPARAM)&sRate,0); 

}

void CHttpDownload::HandleThreadErrorWithLastError(char* nIDError, DWORD dwLastError)
{
//Form the error string to report
CString sError;
if (dwLastError)
sError.Format(_T("%d"), dwLastError);
else
sError.Format(_T("%d"), ::GetLastError());
m_sError.Format(nIDError, sError);

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

OnThreadFinished( 1,0);
}

void CHttpDownload::HandleThreadError(char* nIDError)
{
m_sError = nIDError;
OnThreadFinished( 1,0);
}

BOOL CHttpDownload::OnSetOptions()
{
//Do nothing but your derviced class could override this function and
//do things ssuch as InternetSetOptions(m_hInternetSession, INTERNET_OPTION_CONNECT_RETRIES, ..) etc.

return TRUE; //To continue processing
}

BOOL CHttpDownload::QueryStatusNumber(HINTERNET hInternet, DWORD dwFlag, DWORD& dwCode)
{
dwCode = 0;
DWORD dwSize = sizeof(DWORD);
return HttpQueryInfo(hInternet, dwFlag | HTTP_QUERY_FLAG_NUMBER, &dwCode, &dwSize, NULL);
}

BOOL CHttpDownload::QueryStatusCode(HINTERNET hInternet, DWORD& dwCode) 
{
return QueryStatusNumber(hInternet, HTTP_QUERY_STATUS_CODE, dwCode);
}

BOOL CHttpDownload::QueryContentLength(HINTERNET hInternet, DWORD& dwCode) 
{
return QueryStatusNumber(hInternet, HTTP_QUERY_CONTENT_LENGTH, dwCode);
}

void CHttpDownload::DownloadThread()
{
//Create the Internet session handle
ASSERT(m_hInternetSession == NULL);

switch (m_ConnectionType)
{
case UsePreConfig:
{
m_hInternetSession = ::InternetOpen(m_sUserAgent.GetLength() ? m_sUserAgent : AfxGetAppName(), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); 
break;
}
case DirectToInternet:
{
m_hInternetSession = ::InternetOpen(m_sUserAgent.GetLength() ? m_sUserAgent : AfxGetAppName(), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); 
break;
}
case UseProxy:
{
ASSERT(m_sProxyServer.GetLength()); //You need to give me a proxy Server
m_hInternetSession = ::InternetOpen(m_sUserAgent.GetLength() ? m_sUserAgent : AfxGetAppName(), INTERNET_OPEN_TYPE_PROXY, m_sProxyServer, NULL, 0); 
break;
}
default: 
{
ASSERT(FALSE);
break;
}
}

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)
{
OnThreadFinished(0,0);
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)
{
OnThreadFinished(0,0);
return;
} 

//Make the connection to the HTTP server 
ASSERT(m_hHttpConnection == NULL);
if (m_sHTTPUserName.GetLength())
m_hHttpConnection = ::InternetConnect(m_hInternetSession, m_sServer, m_nPort, m_sHTTPUserName, 
m_sHTTPPassword, INTERNET_SERVICE_HTTP, 0, (DWORD) this);
else
m_hHttpConnection = ::InternetConnect(m_hInternetSession, m_sServer, m_nPort, NULL, 
NULL, INTERNET_SERVICE_HTTP, 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)
{
OnThreadFinished(0,0);
return;
} 

//Call the virtual function to allow session customisation
if (!OnSetOptions())
{
TRACE(_T("Failed in call to OnSetOptions\n"));
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);
DWORD dwFlags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_KEEP_CONNECTION;
if (m_dwServiceType == AFX_INET_SERVICE_HTTPS) 
dwFlags |= (INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID);
m_hHttpFile = HttpOpenRequest(m_hHttpConnection, NULL, m_sObject, _T("HTTP/1.1"), NULL, ppszAcceptTypes, dwFlags, (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.
//The purpose is to check if user has pressed the cancel button
if (m_bAbort)
{
OnThreadFinished(0,0);
return;
} 

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

//Issue the request
CString sRange;
if (m_dwStartPos != 0) //we will build the range request.
sRange.Format(_T("Range: bytes=%d-\r\n"), m_dwStartPos);
BOOL bSend = FALSE;
if (sRange.IsEmpty())
bSend = ::HttpSendRequest(m_hHttpFile, NULL, 0, NULL, 0);
else
bSend = ::HttpSendRequest(m_hHttpFile, sRange, sRange.GetLength(), 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
DWORD dwStatusCode = 0;
if (!QueryStatusCode(m_hHttpFile, dwStatusCode))
{
TRACE(_T("Failed in call to HttpQueryInfo for HTTP query status code, Error:%d\n"), ::GetLastError());
HandleThreadError(IDS_HTTPDOWNLOAD_INVALID_SERVER_RESPONSE);
return;
}
else
{
//Handle any authentication errors
if ((dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ) || (dwStatusCode == 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 = 0;
do
{
::InternetReadFile(m_hHttpFile, (LPVOID)szData, 50, &dwSize);
}
while (dwSize != 0);

BOOL bPrompt = FALSE;
if (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ)
{
//Set the proxy details if we have them
int nProxyUserLength = m_sProxyUserName.GetLength();
if (nProxyUserLength)
{
if (!InternetSetOption(m_hHttpFile, INTERNET_OPTION_PROXY_USERNAME, (LPVOID) m_sProxyUserName.operator LPCTSTR(), (nProxyUserLength+1) * sizeof(TCHAR)))
TRACE(_T("Failed in call to InternetSetOption for Proxy Username, Error:%d\n"), ::GetLastError());
if (!InternetSetOption(m_hHttpFile, INTERNET_OPTION_PROXY_PASSWORD, (LPVOID) m_sProxyPassword.operator LPCTSTR(), (m_sProxyPassword.GetLength()+1) * sizeof(TCHAR)))
TRACE(_T("Failed in call to InternetSetOption for Proxy Password, Error:%d\n"), ::GetLastError());
}
else if (m_bPromptForProxyDetails)
bPrompt = TRUE;
}
else if (dwStatusCode == HTTP_STATUS_DENIED)
{
//Set the proxy details if we have them
int nHTTPUserLength = m_sHTTPUserName.GetLength();
if (nHTTPUserLength)
{
if (!InternetSetOption(m_hHttpFile, INTERNET_OPTION_USERNAME, (LPVOID) m_sHTTPUserName.operator LPCTSTR(), (nHTTPUserLength+1) * sizeof(TCHAR)))
TRACE(_T("Failed in call to InternetSetOption for HTTP Username, Error:%d\n"), ::GetLastError());
if (!InternetSetOption(m_hHttpFile, INTERNET_OPTION_PASSWORD, (LPVOID) m_sHTTPPassword.operator LPCTSTR(), (m_sHTTPPassword.GetLength()+1) * sizeof(TCHAR)))
TRACE(_T("Failed in call to InternetSetOption for HTTP Password, Error:%d\n"), ::GetLastError());
}
else if (m_bPromptForHTTPDetails)
bPrompt = TRUE;
}

//Bring up the standard authentication dialog if required
if (bPrompt && ::InternetErrorDlg(m_hNotifyWnd, 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 (dwStatusCode != HTTP_STATUS_OK && dwStatusCode != HTTP_STATUS_PARTIAL_CONTENT)
{
TRACE(_T("Failed to retrieve a HTTP OK or partial content status, Status Code:%d\n"), dwStatusCode);
HandleThreadErrorWithLastError(IDS_HTTPDOWNLOAD_INVALID_HTTP_RESPONSE, dwStatusCode);
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. 
DWORD dwFileSize = 0;
BOOL bGotFileSize = FALSE;
if (QueryContentLength(m_hHttpFile, dwFileSize))
{
//Set the progress control range
bGotFileSize = TRUE;
//m_ctrlProgress.SetRange(0, 100);
}

//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, 1024, &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* pEx)
{
TRACE(_T("An exception occured while writing to the download file\n"));
HandleThreadErrorWithLastError(IDS_HTTPDOWNLOAD_ERROR_READFILE, pEx->m_lOsError);
pEx->Delete();
return;
}

// For bandwidth throttling
if (m_dbLimit > 0.0f) 
{
double t = (double)(GetTickCount() - dwStartTicks);
double q = (double)((double)dwTotalBytesRead / t);

if (q > m_dbLimit) 
Sleep((DWORD)((((q*t)/m_dbLimit)-t)));
}
}

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

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

//Just close the file before we return
m_FileToWrite.Close();

//We're finished
OnThreadFinished(0,0);
}

void CHttpDownload::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 + m_dwStartPos) * 100.0 / (dwFileSize + m_dwStartPos));
if (dwPercentage != dwLastPercentage)
{
//Update the progress control bar
SetPercentage(dwPercentage);
dwLastPercentage = dwPercentage;
}
}

//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 + m_dwStartPos, dwFileSize + m_dwStartPos);
}
}
}
}

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

void CHttpDownload::OnStatusCallBack(HINTERNET /*hInternet*/, DWORD dwInternetStatus, 
LPVOID lpvStatusInformation, DWORD /*dwStatusInformationLength*/)
{
USES_CONVERSION;

switch (dwInternetStatus)
{
case INTERNET_STATUS_RESOLVING_NAME:
{
SetStatus(IDS_HTTPDOWNLOAD_RESOLVING_NAME, A2T((LPSTR) lpvStatusInformation));
break;
}
case INTERNET_STATUS_NAME_RESOLVED:
{
SetStatus(IDS_HTTPDOWNLOAD_RESOLVED_NAME, A2T((LPSTR) lpvStatusInformation));
break;
}
case INTERNET_STATUS_CONNECTING_TO_SERVER:
{
SetStatus(IDS_HTTPDOWNLOAD_CONNECTING, A2T((LPSTR) lpvStatusInformation));
break;
}
case INTERNET_STATUS_CONNECTED_TO_SERVER:
{
SetStatus(IDS_HTTPDOWNLOAD_CONNECTED, A2T((LPSTR) lpvStatusInformation));
break;
}
case INTERNET_STATUS_REDIRECT:
{
SetStatus(IDS_HTTPDOWNLOAD_REDIRECTING, A2T((LPSTR) lpvStatusInformation));
break;
}
default:
{
break;
}
}
}

void CHttpDownload::DisInit() 
{
Cancel();
//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;
}

}

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

}



 

初始化时需要传递一个窗口句柄,用来通知下载状态等各种消息。需要实现的消息如下,已经在HttpDownload.h类中定义了。

const UINT WM_HTTPDOWNLOAD_THREAD_FINISHED = WM_APP + 81;
const UINT WM_HTTPDOWNLOAD_FILESTATUS = WM_APP + 82;
const UINT WM_HTTPDOWNLOAD_PERCENTAGE = WM_APP + 83;
const UINT WM_HTTPDOWNLOAD_TIMELEFT = WM_APP + 84;
const UINT WM_HTTPDOWNLOAD_STATUS = WM_APP + 85;
const UINT WM_HTTPDOWNLOAD_TRANSFERRATE = WM_APP + 86;

下面是其他应用中使用的例子代码,可以参考 :)

类头文件

class CBrowsePage : public CPropertyPage
{
DECLARE_DYNCREATE(CBrowsePage)

// Construction
public:
CBrowsePage();
~CBrowsePage();

// Dialog Data
//{{AFX_DATA(CBrowsePage)
enum { IDD = IDD_BROWSEPAGE };
CProgressCtrl m_ctrlProgress;
CString m_sStatus;
CString m_sUpdateInfo;
//}}AFX_DATA


// Overrides
// ClassWizard generate virtual function overrides
//{{AFX_VIRTUAL(CBrowsePage)
public:
virtual BOOL OnSetActive();
virtual void OnCancel();
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL

// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CBrowsePage)
virtual BOOL OnInitDialog();
//}}AFX_MSG
afx_msg LRESULT OnHttpDownloadFinished(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnHttpDownloadPercentage(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnHttpDownloadTimeLeft(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnHttpDownloadFileStatus(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnDownloadFinished(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
private:
CHttpDownload m_HttpDownload;

};


类的实现文件

CBrowsePage::CBrowsePage() : CPropertyPage(CBrowsePage::IDD)
{
//{{AFX_DATA_INIT(CBrowsePage)
m_sStatus = _T("");
m_sUpdateInfo = _T("");
//}}AFX_DATA_INIT
}

CBrowsePage::~CBrowsePage()
{
}

void CBrowsePage::DoDataExchange(CDataExchange* pDX)
{
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CBrowsePage)
DDX_Control(pDX, IDC_PROGRESS1, m_ctrlProgress);
DDX_Text(pDX, IDC_STATUS, m_sStatus);
DDX_Text(pDX, IDC_EDITUPDATEINFO, m_sUpdateInfo);
//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CBrowsePage, CPropertyPage)
//{{AFX_MSG_MAP(CBrowsePage)
//}}AFX_MSG_MAP
ON_MESSAGE(WM_HTTPDOWNLOAD_FILESTATUS, OnHttpDownloadFileStatus)
ON_MESSAGE(WM_HTTPDOWNLOAD_TIMELEFT, OnHttpDownloadTimeLeft)
ON_MESSAGE(WM_HTTPDOWNLOAD_PERCENTAGE, OnHttpDownloadPercentage)
ON_MESSAGE(WM_HTTPDOWNLOAD_THREAD_FINISHED, OnHttpDownloadFinished)
ON_MESSAGE(WM_BROWSEPAGE_DOWNLOADFINISHED, OnDownloadFinished)

END_MESSAGE_MAP()
BOOL CBrowsePage::OnSetActive() 
{
_UpdatePackageList.RemoveAll();
CPropertySheet* pParent = (CPropertySheet*)GetParent();
ASSERT_KINDOF(CPropertySheet, pParent);
_WriteLog("开始从[%s]获取[%s]...",_sURL,_sUpdateListFile);
if(_bIsFromLocalFile)
{
PostMessage(WM_BROWSEPAGE_DOWNLOADFINISHED,!_IsFile(_sUpdateListFile),0);
}
else
{
CString sLiveUpdateUrl = _sURL + _UPDATELISTFILENAME;
m_HttpDownload.Init(
m_hWnd,
sLiveUpdateUrl,
_sUpdateListFile,
_sProxyServer,
_sProxyUserName,
_sProxyPassword,
_sHTTPUserName,
_sHTTPPassword,
(CHttpDownload::ConnectionType)_nConnection);
if(m_HttpDownload.Start())
{
pParent->SetWizardButtons(0);
}else
{
pParent->SetWizardButtons(0);
}
} 
return CPropertyPage::OnSetActive();
}
BOOL CBrowsePage::OnInitDialog() 
{
CPropertyPage::OnInitDialog();
m_ctrlProgress.SetRange(0, 100);


return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}

LRESULT CBrowsePage::OnHttpDownloadFileStatus(WPARAM wParam, LPARAM lParam)
{
CString sMsg(*(CString*)wParam);
m_sStatus = sMsg;
_WriteLog("%s",m_sStatus);
UpdateData(FALSE);
return 0;
}

LRESULT CBrowsePage::OnHttpDownloadTimeLeft(WPARAM wParam, LPARAM lParam)
{
CString sMsg(*(CString*)wParam);
m_sStatus = sMsg;
UpdateData(FALSE);
return 0;
}

LRESULT CBrowsePage::OnHttpDownloadPercentage(WPARAM wParam, LPARAM lParam)
{
CString sMsg(*(CString*)wParam);
m_ctrlProgress.SetPos(lParam);
return 0;
}

LRESULT CBrowsePage::OnHttpDownloadFinished(WPARAM wParam, LPARAM lParam)
{
m_HttpDownload.DisInit();
OnDownloadFinished(wParam,lParam);
return 0;
}

void CBrowsePage::OnCancel() 
{
m_HttpDownload.Cancel(); 
CPropertyPage::OnCancel();
}
LRESULT CBrowsePage::OnDownloadFinished(WPARAM wParam, LPARAM lParam)
{
CPropertySheet* pParent = (CPropertySheet*)GetParent();
ASSERT_KINDOF(CPropertySheet, pParent);
CString sServerLastupdateTime;
if(wParam == 0)
{
_WriteLog("获取[%s]成功。",_sUpdateListFile);
pParent->SetWizardButtons(PSWIZB_NEXT);
char szTemp[1001];
ini_GetPrivateProfileString("update","lastupdatetime","0",szTemp,500,_sUpdateListFile);
sServerLastupdateTime = szTemp;
_WriteLog("更新服务器%s:[%s]","lastupdatetime",sServerLastupdateTime);
int nPackageCount = ini_GetPrivateProfileInt("update","packagecount",0,_sUpdateListFile);
_WriteLog("更新服务器%s:[%s]","packagecount",nPackageCount);
for(int i=0;i<nPackageCount;i++)
{
CString sPackId;
sPackId.Format("updatepackage%d",i+1);
ini_GetPrivateProfileString(sPackId,"filename","",szTemp,500,_sUpdateListFile);
if(strlen(szTemp)<=0) continue;
CString sFileName = szTemp;
ini_GetPrivateProfileString(sPackId,"description","",szTemp,500,_sUpdateListFile);
CString sDescription = szTemp;
int nSize = ini_GetPrivateProfileInt(sPackId,"size",0,_sUpdateListFile);

_UpdatePackageList.Add(_UpdatePackageStruct(sFileName,nSize,sDescription));
}
nPackageCount = _UpdatePackageList.GetSize();

if(sServerLastupdateTime > _sLastUpdateTime && nPackageCount>0)
{
_sLastUpdateTime = sServerLastupdateTime;
//pParent->SetActivePage(2);
m_sStatus.Format("获取更新列表成功,单击“下一步”获取最新软件!");
m_sUpdateInfo = "当前安装路径信息:\r\n";
if(_sCallCenterPath !="")
m_sUpdateInfo += "Isc 核心软件安装在 "+_sCallCenterPath+"\r\n";
if(_sIscConfigPath !="")
m_sUpdateInfo += "IscWeb配置工具安装在 "+_sIscConfigPath+"\r\n";

m_sUpdateInfo += "---------------------------------------------------\r\n";
m_sUpdateInfo += "本次Isc软件更新包包括:\r\n";
for(int i=0;i<nPackageCount;i++)
{
CString sTmp;
sTmp.Format("%s (file:%s size:%d)\r\n",
_UpdatePackageList[i].sDescription ,
_UpdatePackageList[i].sFileName,
_UpdatePackageList[i].nSize);
m_sUpdateInfo +=sTmp;
}
m_sUpdateInfo += "---------------------------------------------------\r\n";
ini_GetPrivateProfileString("update","description","",szTemp,1000,_sUpdateListFile);
m_sUpdateInfo += szTemp;
_WriteLog("%s",m_sUpdateInfo);
}else
{
_WriteLog("所有软件都是最新版本,不需要更新!");
pParent->SetActivePage(4);
}

}else
{
pParent->SetWizardButtons(0);
m_sStatus.Format("获取更新列表失败,请检查后重试!");
_WriteLog("%s",m_sStatus);
}
UpdateData(FALSE);
return TRUE;
}



有问题给我留言。:)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值