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

📄 downdlg.cpp

📁 本程序是VC为平台开发的股票资讯系统
💻 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 + -