프로그램/C++

Http Request 로 파일 다운로드 하기

네오류이 2021. 1. 14. 09:21
728x90
반응형

오늘은 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#다운로드#파일

728x90
반응형