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

来源:互联网 发布:阿里云虚拟主机 ssh 编辑:程序博客网 时间:2024/05/06 09:55
                                       

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 > 1000const 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://Enumsenum 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 toDWORD dwStartPos= 0 //Offset to resume the download at );BOOL Start();void Cancel();void DisInit();//Public Member variablesCString 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 toDWORD m_dwStartPos; //Offset to resume the download at protected:LRESULT OnThreadFinished(WPARAM wParam, LPARAM lParam);//Methodsstatic 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 variablesCString 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_FILEstatic 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 toDWORD 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 usm_bSafeToClose = TRUE;//Stop the animation// m_ctrlAnimate.Stop();//If an error occured display the message boxif (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 URLASSERT(m_sURLToDownload.GetLength()); //Did you forget to specify the file to downloadif (!AfxParseURL(m_sURLToDownload, m_dwServiceType, m_sServer, m_sObject, m_nPort)){//Try sticking "http://" before itm_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 overwrittenCFileStatus 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 intoDWORD dwFileFlags = 0;if (bDownloadFileExists && (m_dwStartPos > 0))dwFileFlags = CFile::modeCreate | CFile::modeNoTruncate | CFile::modeWrite | CFile::shareDenyWrite;elsedwFileFlags = 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 filetry{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 componentint 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);elsem_sFilename = m_sObject;//Set the file status textCString 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 downloadingm_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++ worldCHttpDownload* 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 textCString 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);elsesTime.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 reportCString sError;if (dwLastError)sError.Format(_T("%d"), dwLastError);elsesError.Format(_T("%d"), ::GetLastError());m_sError.Format(nIDError, sError);//Delete the file being downloaded to if it is presentm_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 handleASSERT(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 Serverm_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 threadif (m_bAbort){OnThreadFinished(0,0);return;} //Setup the status callback functionif (::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 threadif (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);elsem_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 threadif (m_bAbort){OnThreadFinished(0,0);return;} //Call the virtual function to allow session customisationif (!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 fileLPCTSTR ppszAcceptTypes[2];ppszAcceptTypes[0] = _T("*/*"); //We support accepting any mime file type since this is a simple download of a fileppszAcceptTypes[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 buttonif (m_bAbort){OnThreadFinished(0,0);return;} //label used to jump to if we need to resend the requestresend://Issue the requestCString 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);elsebSend = ::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 codeDWORD 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 errorsif ((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 themint 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 themint 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 requiredif (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 informationSetStatus(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 rangebGotFileSize = TRUE;//m_ctrlProgress.SetRange(0, 100);}//Update the status to say that we are now downloading the fileSetStatus(IDS_HTTPDOWNLOAD_RETREIVEING_FILE);//Now do the actual read of the fileDWORD 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 filetry{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 throttlingif (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 readdwTotalBytesRead += dwBytesRead; //Update the UIUpdateControlsDuringTransfer(dwStartTicks, dwCurrentTicks, dwTotalBytesRead, dwLastTotalBytes, dwLastPercentage, bGotFileSize, dwFileSize);}} while (dwBytesRead && !m_bAbort);//Just close the file before we returnm_FileToWrite.Close();//We're finishedOnThreadFinished(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 captionDWORD dwPercentage = (DWORD) ((dwTotalBytesRead + m_dwStartPos) * 100.0 / (dwFileSize + m_dwStartPos));if (dwPercentage != dwLastPercentage){//Update the progress control barSetPercentage(dwPercentage);dwLastPercentage = dwPercentage;}}//Update the transfer rate amd estimated time left every secondDWORD 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 loopdwCurrentTicks = dwNowTicks;dwLastTotalBytes = dwTotalBytesRead;if (bGotFileSize){//Update the estimated time leftif (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++ worldCHttpDownload* 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 exitif (m_pThread){WaitForSingleObject(m_pThread->m_hThread, INFINITE);delete m_pThread;m_pThread = NULL;}//Free up the internet handles we may be usingif (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 buttonm_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)// Constructionpublic: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// Implementationprotected:// Generated message map functions//{{AFX_MSG(CBrowsePage)virtual BOOL OnInitDialog();//}}AFX_MSGafx_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_MAPON_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;}

有问题给我留言。:)

原创粉丝点击