📄 downdlg.cpp
字号:
// DownDlg.cpp : implementation file
//
#include "stdafx.h"
#include "Resource.h"
#include "DownDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
const UINT WM_HTTPDOWNLOAD_THREAD_FINISHED = WM_APP + 10;
/////////////////////////////////////////////////////////////////////////////
// CDownDlg dialog
IMPLEMENT_DYNAMIC(CDownDlg, CDialog);
CDownDlg::CDownDlg(CWnd* pParent /*=NULL*/)
: CDialog(CDownDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CDownDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_hInternetSession = NULL;
m_hHttpConnection = NULL;
m_hHttpFile = NULL;
m_bAbort = FALSE;
m_bSafeToClose = FALSE;
m_pThread = NULL;
m_bOverwrite = FALSE;
}
void CDownDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDownDlg)
DDX_Control(pDX, IDC_ANIMATE1, m_ctrlAnimate);
DDX_Control(pDX, IDC_PROGRESS1, m_ctrlProgress);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CDownDlg, CDialog)
//{{AFX_MSG_MAP(CDownDlg)
ON_WM_DESTROY()
ON_WM_CLOSE()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_HTTPDOWNLOAD_THREAD_FINISHED, OnThreadFinished)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDownDlg message handlers
LRESULT CDownDlg::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);
return 0L;
}
BOOL CDownDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
// Setup the animation control
m_ctrlAnimate.Open(IDR_AVI_UPDATE);
//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))
{
TRACE(_T("Failed to parse the URL: %s\n"), m_sURLToDownload);
EndDialog(IDCANCEL);
return TRUE;
}
}
//Check to see if the file we are downloading to exists and if
//it does, then ask the user if they were it overwritten
if(!m_sFileToDownloadInto.IsEmpty())
{
CFileStatus fs;
ASSERT(m_sFileToDownloadInto.GetLength());
if (!m_bOverwrite && CFile::GetStatus(m_sFileToDownloadInto, fs))
{
CString sMsg;
AfxFormatString1(sMsg, IDS_OK_TO_OVERWRITE, m_sFileToDownloadInto);
if (AfxMessageBox(sMsg, MB_YESNO) != IDYES)
{
TRACE(_T("Failed to confirm file overwrite, download aborted\n"));
EndDialog(IDCANCEL);
return TRUE;
}
}
//Try and open the file we will download into
if (!m_FileToWrite.Open(m_sFileToDownloadInto, CFile::modeCreate | CFile::modeWrite | CFile::shareDenyWrite))
{
TRACE(_T("Failed to open the file to download into, Error:%d\n"), GetLastError());
CString sError;
sError.Format(_T("%d"), ::GetLastError());
CString sMsg;
AfxFormatString1(sMsg, IDS_FAIL_FILE_OPEN, sError);
AfxMessageBox(sMsg);
EndDialog(IDCANCEL);
return TRUE;
}
}
//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;
//Spin off the background thread which will do the actual downloading
m_pThread = AfxBeginThread(_DownloadThread, this, THREAD_PRIORITY_NORMAL, CREATE_SUSPENDED);
if (m_pThread == NULL)
{
TRACE(_T("Failed to create download thread, dialog is aborting\n"));
EndDialog(IDCANCEL);
return TRUE;
}
m_pThread->m_bAutoDelete = FALSE;
m_pThread->ResumeThread();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
UINT CDownDlg::_DownloadThread(LPVOID pParam)
{
//Convert from the SDK world to the C++ world
CDownDlg* pDlg = (CDownDlg*) pParam;
ASSERT(pDlg);
ASSERT(pDlg->IsKindOf(RUNTIME_CLASS(CDownDlg)));
pDlg->DownloadThread();
return 0;
}
void CDownDlg::SetProgressRange(DWORD dwFileSize)
{
m_ctrlProgress.SetRange(0, (short)((dwFileSize+512)/1024));
}
void CDownDlg::SetProgress(DWORD dwBytesRead)
{
m_ctrlProgress.SetPos(dwBytesRead/1024);
}
void CDownDlg::PlayAnimation()
{
m_ctrlAnimate.Play(0, (UINT)-1, (UINT)-1);
}
void CDownDlg::HandleThreadErrorWithLastError(UINT nIDError, DWORD dwLastError)
{
//Form the error string to report
CString sError;
if (dwLastError)
sError.Format(_T("%d"), dwLastError);
else
sError.Format(_T("%d"), ::GetLastError());
AfxFormatString1(m_sError, nIDError, sError);
//Delete the file being downloaded to if it is present
if(!m_sFileToDownloadInto.IsEmpty())
m_FileToWrite.Close();
::DeleteFile(m_sFileToDownloadInto);
PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED, 1);
}
void CDownDlg::HandleThreadError(UINT nIDError)
{
m_sError.LoadString(nIDError);
PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED, 1);
}
void CDownDlg::DownloadThread()
{
//Create the Internet session handle
ASSERT(m_hInternetSession == NULL);
m_hInternetSession = ::InternetOpen(NULL, 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;
}
//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_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], lpszVerb;
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);
if(m_sFormData.IsEmpty())
lpszVerb = NULL;
else
lpszVerb = _T("POST");
m_hHttpFile = HttpOpenRequest(m_hHttpConnection, lpszVerb, 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_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
LPCTSTR lpszHeaders = NULL;
LPCTSTR lpszFormData = NULL;
DWORD dwHeadersLength = 0;
DWORD dwFormDataLength = 0;
if(!m_sFormData.IsEmpty())
{
lpszHeaders = _T("Content-Type: application/x-www-form-urlencoded");
dwHeadersLength = strlen(lpszHeaders);
lpszFormData = m_sFormData;
dwFormDataLength = m_sFormData.GetLength();
}
BOOL bSend = ::HttpSendRequest(m_hHttpFile, lpszHeaders, dwHeadersLength, (LPVOID)lpszFormData, dwFormDataLength);
if (!bSend)
{
TRACE(_T("Failed in call to HttpSendRequest, Error:%d\n"), ::GetLastError());
HandleThreadErrorWithLastError(IDS_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;
}
}
// 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);
}
//Now do the actual read of the file
DWORD dwBytesRead = 0;
char szReadBuf[1024];
DWORD dwBytesToRead = 1024;
DWORD dwTotalBytesRead = 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_ERROR_READFILE);
return;
}
else if (dwBytesRead && !m_bAbort)
{
//Write the data to file
TRY
{
if(!m_sFileToDownloadInto.IsEmpty())
m_FileToWrite.Write(szReadBuf, dwBytesRead);
else
m_sBuffer += szReadBuf;
}
CATCH(CFileException, e);
{
TRACE(_T("An exception occured while writing to the download file\n"));
HandleThreadErrorWithLastError(IDS_ERROR_READFILE, e->m_lOsError);
e->Delete();
return;
}
END_CATCH
//Increment the total number of bytes read
dwTotalBytesRead += dwBytesRead;
UpdateControlsDuringTransfer(dwTotalBytesRead, dwLastPercentage, bGotFileSize, dwFileSize);
}
}
while (dwBytesRead && !m_bAbort);
//Delete the file being downloaded to if it is present and the download was aborted
if(!m_sFileToDownloadInto.IsEmpty())
m_FileToWrite.Close();
if (m_bAbort)
::DeleteFile(m_sFileToDownloadInto);
//We're finished
PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED);
}
void CDownDlg::UpdateControlsDuringTransfer(DWORD dwTotalBytesRead, 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)
{
//Update the progress control bar
SetProgress(dwTotalBytesRead);
}
}
}
void CDownDlg::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 CDownDlg::OnClose()
{
// TODO: Add your message handler code here and/or call default
if (m_bSafeToClose)
CDialog::OnClose();
else
{
//Just set the abort flag to TRUE and
//disable the cancel button
m_bAbort = TRUE;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -