오늘은 C++에서 많이 사용하는 기능 중 웹서버에 있는 이미지나 파일을 다운로드 받아야 하는데.. 이 부분을 클래스로 만들어 사용하면 편할 것 같애 소개합니다.
제가 현재 사용하고 있는 클래스인데 이 클래스를 등록해 놓고 사용하시면 편리합니다.
6.0 기준입니다.
* 소스코드 (header)
#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:%1"
#define IDS_HTTPDOWNLOAD_FAIL_CONNECT_SERVER "An error occurred connecting to the server, Error:%1"
#define IDS_HTTPDOWNLOAD_INVALID_SERVER_RESPONSE "Failed to receive a valid response from the server"
#define IDS_HTTPDOWNLOAD_INVALID_HTTP_RESPONSE "Failed to receive a valid HTTP response from the server"
#define IDS_HTTPDOWNLOAD_ERROR_READFILE "An error occurred while downloading the file, Error:%1"
#define IDS_HTTPDOWNLOAD_GETTING_FILE_INFORMATION "Getting file information"
#define IDS_HTTPDOWNLOAD_RETREIVEING_FILE "Retrieving the file"
#define IDS_HTTPDOWNLOAD_RESOLVING_NAME "Resolving name: %1"
#define IDS_HTTPDOWNLOAD_RESOLVED_NAME "Resolved name to %1"
#define IDS_HTTPDOWNLOAD_CONNECTING "Connecting to %1"
#define IDS_HTTPDOWNLOAD_REDIRECTING "Redirecting to %1"
#define IDS_HTTPDOWNLOAD_ABORTING_TRANSFER "Aborting transfer"
class HttpDownloadWnd : public CWnd
{
DECLARE_DYNAMIC(HttpDownloadWnd);
private:
CString m_filename;
CString m_fileurl;
CString m_localpath;
CString m_logname;
CString m_logpass;
CString m_save_path;
CString m_ctrlFileStatus;
int m_percent;
int m_length, m_current_len;
CWnd *mp_parent_wnd;
public:
HttpDownloadWnd();
int m_completed_flag;
CString GetCompletedFilePath();
void SetConfiguration(CWnd *parm_wnd, CString parm_path, CString parm_save_path);
int StartHttpDownload();
void SetFinalize();
static void CALLBACK _OnStatusCallBack(HINTERNET hInternet, DWORD dwContext, DWORD dwInternetStatus,
LPVOID lpvStatusInformation, DWORD dwStatusInformationLength);
void OnStatusCallBack(HINTERNET hInternet, DWORD dwInternetStatus,
LPVOID lpvStatusInformation, DWORD dwStatusInformationLength);
static UINT _DownloadThread(LPVOID pParam);
void HandleThreadErrorWithLastError(char *pError, DWORD dwLastError=0);
void HandleThreadError(char *pError);
void DownloadThread();
void SetPercentage(int nPercentage);
int GetPercentage();
void SetTimeLeft(DWORD dwSecondsLeft, DWORD dwBytesRead, DWORD dwFileSize);
void SetProgressRange(DWORD dwFileSize);
void SetStatus(CString sCaption, CString sCaption2="");
void SetStatus(UINT nID);
void SetStatus(UINT nID, const CString& lpsz1);
void SetTransferRate(double KbPerSecond);
void PlayAnimation();
void SetProgress(DWORD dwBytesRead);
void UpdateControlsDuringTransfer(DWORD dwStartTicks, DWORD& dwCurrentTicks, DWORD dwTotalBytesRead, DWORD& dwLastTotalBytes,
DWORD& dwLastPercentage, BOOL bGotFileSize, DWORD dwFileSize);
void OnCancel();
CString m_sError;
CString m_sServer;
CString m_sObject;
CString m_sFilename;
INTERNET_PORT m_nPort;
DWORD m_dwServiceType;
HINTERNET m_hInternetSession;
HINTERNET m_hHttpConnection;
HINTERNET m_hHttpFile;
BOOL m_bAbort;
BOOL m_bSafeToClose;
CFile m_FileToWrite;
CWinThread* m_pThread;
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(HttpDownloadWnd)
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~HttpDownloadWnd();
// Generated message map functions
protected:
//{{AFX_MSG(HttpDownloadWnd)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
//}}AFX_MSG
afx_msg LRESULT OnThreadFinished(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
* 소스코드 (cpp)
#include "stdafx.h"
#include "HttpDownloadWnd.h"
#include <direct.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// HttpDownloadWnd
const UINT WM_HTTPDOWNLOAD_THREAD_FINISHED = WM_APP + 1;
IMPLEMENT_DYNAMIC(HttpDownloadWnd, CWnd);
HttpDownloadWnd::HttpDownloadWnd()
{
m_hInternetSession = NULL;
m_hHttpConnection = NULL;
m_hHttpFile = NULL;
m_bAbort = FALSE;
m_bSafeToClose = FALSE;
m_pThread = NULL;
m_completed_flag = 0;
m_percent = 0;
mp_parent_wnd = NULL;
}
HttpDownloadWnd::~HttpDownloadWnd()
{
}
BEGIN_MESSAGE_MAP(HttpDownloadWnd, CWnd)
//{{AFX_MSG_MAP(HttpDownloadWnd)
ON_WM_CREATE()
ON_WM_DESTROY()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_HTTPDOWNLOAD_THREAD_FINISHED, OnThreadFinished)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// HttpDownloadWnd message handlers
LRESULT HttpDownloadWnd::OnThreadFinished(WPARAM wParam, LPARAM /*lParam*/)
{
m_bSafeToClose = TRUE;
if(wParam){ // error
m_completed_flag = 1;
mp_parent_wnd->SendMessage(WM_FILEFINISH, wParam, 0);
}else{
m_completed_flag = 1;
mp_parent_wnd->SendMessage(WM_FILEFINISH, wParam, 1);
}
SetFinalize();
return 0L;
}
CString HttpDownloadWnd::GetCompletedFilePath()
{
return m_localpath;
}
int HttpDownloadWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1) return -1;
return 0;
}
int HttpDownloadWnd::StartHttpDownload()
{
if (!AfxParseURL(m_fileurl, m_dwServiceType, m_sServer, m_sObject, m_nPort)){
//Try sticking "http://" before it
//m_fileurl = _T("http://") + m_fileurl;
if (!AfxParseURL(m_fileurl, m_dwServiceType, m_sServer, m_sObject, m_nPort)){
TRACE(_T("Failed to parse the URL: %s\n"), m_fileurl);
return -1;
}
}
//char windows_dir[256]={0,};
//::GetWindowsDirectory(windows_dir, 256);
// MAKE FOLDER...
//m_localpath.Format("%s\\temp", windows_dir);
//_mkdir((const char *)m_localpath);
//m_localpath += ("\\"+m_filename);
CFileStatus fs;
ASSERT(m_localpath.GetLength());
//if (CFile::GetStatus(m_localpath, fs)){
// CString sMsg;
// //AfxFormatString1(sMsg, IDS_HTTPDOWNLOAD_OK_TO_OVERWRITE, m_localpath);
// if (AfxMessageBox(sMsg, MB_YESNO) != IDYES){
// TRACE(_T("Failed to confirm file overwrite, download aborted\n"));
// return -1;
// }
//}
//Try and open the file we will download into
if (!m_FileToWrite.Open(m_localpath, 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());
//AfxMessageBox("File Write Error "+sError);
return -1;
}
//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());
//AfxFormatString2(sFileStatus, IDS_HTTPDOWNLOAD_FILESTATUS, m_sFilename, m_sServer);
m_ctrlFileStatus = sFileStatus;
//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"));
return -1;
}
m_pThread->m_bAutoDelete = FALSE;
m_pThread->ResumeThread();
return 0;
}
void HttpDownloadWnd::OnDestroy()
{
CWnd::OnDestroy();
SetFinalize();
}
void HttpDownloadWnd::SetFinalize()
{
//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;
}
}
UINT HttpDownloadWnd::_DownloadThread(LPVOID pParam)
{
//Convert from the SDK world to the C++ world
HttpDownloadWnd* pDlg = (HttpDownloadWnd*) pParam;
ASSERT(pDlg);
ASSERT(pDlg->IsKindOf(RUNTIME_CLASS(HttpDownloadWnd)));
pDlg->DownloadThread();
return 0;
}
void HttpDownloadWnd::SetPercentage(int nPercentage)
{
m_percent = nPercentage;
//CString test_str;
//test_str.Format("%d ", m_percent);
mp_parent_wnd->SendMessage(WM_FILETRANSFER, m_percent, 0);
//((CEnUpdateDlg *)mp_parent_wnd)->ShowTransfer(m_percent);
//CString per_str;
//per_str.Format("Downlod %d%%", m_percent);
//mp_parent_wnd->SetWindowTextExt(per_str);
//Change the progress control
//m_ctrlProgress.SetPos(nPercentage);
//Change the caption text
//CString sPercentage;
//sPercentage.Format(_T("%d"), nPercentage);
//CString sCaption;
//AfxFormatString2(sCaption, IDS_HTTPDOWNLOAD_PERCENTAGE, sPercentage, m_sFilename);
//m_percent = sCaption;
// SendMessage...
}
int HttpDownloadWnd::GetPercentage()
{
return m_percent;
}
void HttpDownloadWnd::SetProgressRange(DWORD dwFileSize)
{
m_length = (dwFileSize+512)/1024;
}
void HttpDownloadWnd::SetProgress(DWORD dwBytesRead)
{
m_current_len = dwBytesRead/1024;
}
void HttpDownloadWnd::SetTimeLeft(DWORD dwSecondsLeft, DWORD dwBytesRead, DWORD dwFileSize)
{
/* CString sCopied;
if (dwBytesRead < 1024)
{
CString sBytes;
sBytes.Format(_T("%d"), dwBytesRead);
//AfxFormatString1(sCopied, IDS_HTTPDOWNLOAD_BYTES, sBytes);
}
else if (dwBytesRead < 1048576)
{
CString sKiloBytes;
sKiloBytes.Format(_T("%0.1f"), dwBytesRead/1024.0);
//AfxFormatString1(sCopied, IDS_HTTPDOWNLOAD_KILOBYTES, sKiloBytes);
}
else
{
CString sMegaBytes;
sMegaBytes.Format(_T("%0.2f"), dwBytesRead/1048576.0);
//AfxFormatString1(sCopied, IDS_HTTPDOWNLOAD_MEGABYTES, sMegaBytes);
}
CString sTotal;
if (dwFileSize < 1024)
{
CString sBytes;
sBytes.Format(_T("%d"), dwFileSize);
//AfxFormatString1(sTotal, IDS_HTTPDOWNLOAD_BYTES, sBytes);
}
else if (dwFileSize < 1048576)
{
CString sKiloBytes;
sKiloBytes.Format(_T("%0.1f"), dwFileSize/1024.0);
//AfxFormatString1(sTotal, IDS_HTTPDOWNLOAD_KILOBYTES, sKiloBytes);
}
else
{
CString sMegaBytes;
sMegaBytes.Format(_T("%0.2f"), dwFileSize/1048576.0);
//AfxFormatString1(sTotal, IDS_HTTPDOWNLOAD_MEGABYTES, sMegaBytes);
}
CString sOf;
//AfxFormatString2(sOf, IDS_HTTPDOWNLOAD_OF, sCopied, sTotal);
CString sTime;
if (dwSecondsLeft < 60)
{
CString sSeconds;
sSeconds.Format(_T("%d"), dwSecondsLeft);
//AfxFormatString1(sTime, 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)
//AfxFormatString1(sTime, IDS_HTTPDOWNLOAD_MINUTES, sMinutes);
else
//AfxFormatString2(sTime, IDS_HTTPDOWNLOAD_MINUTES_AND_SECONDS, sMinutes, sSeconds);
}
CString sTimeLeft;
//AfxFormatString2(sTimeLeft, IDS_HTTPDOWNLOAD_TIMELEFT, sTime, sOf);
m_ctrlTimeLeft.SetWindowText(sTimeLeft);
*/
}
void HttpDownloadWnd::SetStatus(CString sCaption, CString sCaption2)
{
//m_ctrlStatus.SetWindowText(sCaption);
TRACE("%s\n", sCaption);
}
void HttpDownloadWnd::SetStatus(UINT nID)
{
CString sCaption;
sCaption.LoadString(nID);
SetStatus(sCaption, "");
}
void HttpDownloadWnd::SetTransferRate(double KbPerSecond)
{
/* CString sRate;
if (KbPerSecond < 1)
{
CString sBytesPerSecond;
sBytesPerSecond.Format(_T("%0.0f"), KbPerSecond*1024);
//AfxFormatString1(sRate, IDS_HTTPDOWNLOAD_BYTESPERSECOND, sBytesPerSecond);
}
else if (KbPerSecond < 10)
{
CString sKiloBytesPerSecond;
sKiloBytesPerSecond.Format(_T("%0.2f"), KbPerSecond);
//AfxFormatString1(sRate, IDS_HTTPDOWNLOAD_KILOBYTESPERSECOND, sKiloBytesPerSecond);
}
else
{
CString sKiloBytesPerSecond;
sKiloBytesPerSecond.Format(_T("%0.0f"), KbPerSecond);
//AfxFormatString1(sRate, IDS_HTTPDOWNLOAD_KILOBYTESPERSECOND, sKiloBytesPerSecond);
}
m_ctrlTransferRate.SetWindowText(sRate);
*/
}
void HttpDownloadWnd::HandleThreadErrorWithLastError(char *pError, 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);
//AfxMessageBox(pError);
//Delete the file being downloaded to if it is present
m_FileToWrite.Close();
::DeleteFile(m_localpath);
PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED, 1);
}
void HttpDownloadWnd::HandleThreadError(char *pError)
{
// m_sError.LoadString(nIDError);
//AfxMessageBox(pError);
PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED, 1);
}
void HttpDownloadWnd::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_logname.GetLength()) m_hHttpConnection = ::InternetConnect(m_hInternetSession, m_sServer, m_nPort, m_logname,
m_logpass, 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_localpath);
//We're finished
PostMessage(WM_HTTPDOWNLOAD_THREAD_FINISHED);
}
void HttpDownloadWnd::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 HttpDownloadWnd::_OnStatusCallBack(HINTERNET hInternet, DWORD dwContext, DWORD dwInternetStatus,
LPVOID lpvStatusInformation, DWORD dwStatusInformationLength)
{
//Convert from the SDK C world to the C++ world
HttpDownloadWnd* pDlg = (HttpDownloadWnd*) dwContext;
ASSERT(pDlg);
ASSERT(pDlg->IsKindOf(RUNTIME_CLASS(HttpDownloadWnd)));
pDlg->OnStatusCallBack(hInternet, dwInternetStatus, lpvStatusInformation, dwStatusInformationLength);
}
void HttpDownloadWnd::OnStatusCallBack(HINTERNET /*hInternet*/, DWORD dwInternetStatus,
LPVOID lpvStatusInformation, DWORD /*dwStatusInformationLength*/)
{
switch(dwInternetStatus){
case INTERNET_STATUS_RESOLVING_NAME:
{
SetStatus(IDS_HTTPDOWNLOAD_RESOLVING_NAME, (LPCSTR) lpvStatusInformation);
break;
}
case INTERNET_STATUS_NAME_RESOLVED:
{
SetStatus(IDS_HTTPDOWNLOAD_RESOLVED_NAME, (LPCSTR) lpvStatusInformation);
break;
}
case INTERNET_STATUS_CONNECTING_TO_SERVER:
{
SetStatus(IDS_HTTPDOWNLOAD_CONNECTING, (LPCSTR) lpvStatusInformation);
break;
}
case INTERNET_STATUS_CONNECTED_TO_SERVER:
{
//SetStatus(IDS_HTTPDOWNLOAD_CONNECTED, (LPCSTR) lpvStatusInformation);
break;
}
case INTERNET_STATUS_REDIRECT:
{
SetStatus(IDS_HTTPDOWNLOAD_REDIRECTING, (LPCSTR) lpvStatusInformation);
break;
}
default:
{
break;
}
}
}
void HttpDownloadWnd::OnCancel()
{
m_bAbort = TRUE;
SetStatus(IDS_HTTPDOWNLOAD_ABORTING_TRANSFER);
}
void HttpDownloadWnd::SetConfiguration(CWnd *parm_wnd, CString parm_path, CString parm_save_path)
{
mp_parent_wnd = parm_wnd;
m_fileurl = parm_path;
m_localpath = parm_save_path;
}
* 사용법 (header)
// 해더 쪽에 선언 및 변수선언
#include "HttpDownloadWnd.h"
HttpDownloadWnd *mp_download_wnd;
* 사용법 (cpp)
// 생성
mp_download_wnd = NULL;
mp_download_wnd = new HttpDownloadWnd();
mp_download_wnd->Create(NULL,NULL,WS_CHILD | WS_VISIBLE,CRect(0,0,0,0),this, 100001);
// 다운로드
if(mp_download_wnd && ::IsWindow(mp_download_wnd->m_hWnd)){
mp_download_wnd->SetConfiguration(this, "http://url.com/uplod/text.jpg", "c:\download\text.jpg");
if(mp_download_wnd->StartHttpDownload() < 0){
// err
}
}
// 생성해제
if(mp_download_wnd && ::IsWindow(mp_download_wnd->m_hWnd)){
mp_download_wnd->DestroyWindow();
delete mp_download_wnd; mp_download_wnd = NULL;
}
좀 너무 간략히 설명드렸지만, 클래스에 적힌 설명과 밑에 사용만 보시면 쉽게 이해가 가실 거고, 클래스만 선언해서 사용하시면 편리합니다.
그리고, 위 방식은 통상 프로세스바 나 프로그래스가 없이 사용할 때 사용하시면 되며. 그런 형태를 사용하시려면 이벤트 등록해서 사용하시면 됩니다.
이벤트는 WM_FILETRANSFER, WM_FILEFINISH 두가지 메세지를 메인클래스에서 받을 수 있습니다.
* header
afx_msg LRESULT OnMsg_FileTransfer(WPARAM wp, LPARAM lp);
afx_msg LRESULT OnMsg_FileFinish(WPARAM wp, LPARAM lp);
* cpp
ON_MESSAGE(WM_FILETRANSFER, OnMsg_FileTransfer)
ON_MESSAGE(WM_FILEFINISH, OnMsg_FileFinish)
LRESULT CWiseUpdateDlg::OnMsg_FileTransfer(WPARAM wp, LPARAM lp)
{
//ShowTransfer((int)wp);
return 1;
}
LRESULT CWiseUpdateDlg::OnMsg_FileFinish(WPARAM wp, LPARAM lp)
{
if(int(lp)==0){
m_str.Format("[WiseUpdate] %s", "다운로드 실패" );
AfxMessageBox(m_str);
}
return 1;
}
위 부분을 넣게 되면 이벤트를 받을 수 있습니다.
많이많이 사용해 주세요~
#http#request#다운로드#파일
'프로그램 > C++' 카테고리의 다른 글
작업관리자에서 해당 프로세스가 실행중인지.. (0) | 2021.01.15 |
---|---|
강제로 프로세스 종료하기 (0) | 2021.01.15 |
현재 실행중인 폴더 위치 (0) | 2021.01.13 |
Dialog 모달리스 사용하기 (0) | 2021.01.13 |
클래스기반의 쓰레드 사용하기 (0) | 2021.01.13 |