📄 httpdownloaddlg.cpp
字号:
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 + -