URL下載的2種方法

最近,做一個類似於下載器的程序:

我用了2種方法,加上迅雷提供的插件是3種:我主要寫下微軟提供的API,通過MSDN都可以查到。

第一種:CInternetSession類

第二個:URLDownloadToFile函數

先說第一個,我使用第一個直接通過URL獲取服務器的數據(.txt文件),比如獲取網絡遊戲的最新版本號,是不需要下載的。如果遊戲需要更新需要再從服務器讀取更新列表

<版本號  下載URL>我是通過第二個方法URLDownloadToFile函數,下載到本地的,然後讀取.txt文件每行數據保存的vector中,然後刪除下載的列表文件,依據vector列表更新遊

戲數據。在下載遊戲更新包的我用的是URLDownloadToFile函數,可以實時瞭解下載文件的狀況,不支持斷點續傳;不過,要向支持可以找迅雷公開的接口API,支持斷點續傳。

CInternetSession類的應用:

         const int dwBufSize = 1024;

CInternetSession   *   Session   =   new   CInternetSession; 
CHttpFile*                 pHttpFile   =   NULL;   
CStdioFile                 pLocalFile;               
DWORD dwlen; 
try

LPBYTE   lpBuf   =   new   byte[dwBufSize];   
pLocalFile.Open(   "XXX.txt", 
CFile::modeCreate   |   
CFile::modeWrite     |   
CFile::typeBinary   ); 
pHttpFile   =(CHttpFile*)Session->OpenURL(g_NewVersionURL, 
1, 
INTERNET_FLAG_TRANSFER_BINARY   | 
INTERNET_FLAG_RELOAD   |   
INTERNET_FLAG_DONT_CACHE, 
NULL, 
0); 

//可以調用BOOL QueryInfo( DWORD dwInfoLevel, LPVOID lpvBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex = NULL ) const;

//查詢網絡狀態網址:http://baike.baidu.com/view/2911740.htm

while(dwlen   =   pHttpFile-> Read(lpBuf,   dwBufSize-1   )) 

m_lsState = LS_LOADING;
pLocalFile.Write(lpBuf,dwlen); 


pLocalFile.Close();   
pHttpFile->Close(); 

  delete pHttpFile; //一定要刪除,不然內存泄露

pHttpFile=NULL; 
delete[]   lpBuf; 

  lpBuf = NULL;

}
catch(CInternetException   eInt) 

eInt.Delete();

catch(CMemoryException   eMem)   

eMem.Delete(); 

catch(CFileException   eFile)   

eFile.Delete(); 

m_lsState = LS_FINISHED;
return 0;
}


下面說一下URLDownloadToFile函數:

我在一個網站上找的:http://www.codeproject.com/KB/IP/urldownload.aspx

===================callback.h

#pragma once


#endif // _MSC_VER > 1000


#include "URLDownloadDlg.h"
#pragma warning(disable:4100)   // disable warnings about unreferenced params


class CCallback : public IBindStatusCallback
{
public:
CCallback();
~CCallback();

// Pointer to the download progress dialog.
CURLDownloadDlg* m_pDlg;

// The time when the download should timeout.
BOOL  m_bUseTimeout;
CTime m_timeToStop;

// IBindStatusCallback methods.  Note that the only method called by IE
// is OnProgress(), so the others just return E_NOTIMPL.

STDMETHOD(OnStartBinding)(
/* [in] */ DWORD dwReserved,
/* [in] */ IBinding __RPC_FAR *pib)
        { return E_NOTIMPL; }
STDMETHOD(GetPriority)(
/* [out] */ LONG __RPC_FAR *pnPriority)
        { return E_NOTIMPL; }

STDMETHOD(OnLowResource)(
/* [in] */ DWORD reserved)
{ return E_NOTIMPL; }

STDMETHOD(OnProgress)(
/* [in] */ ULONG ulProgress,
/* [in] */ ULONG ulProgressMax,
/* [in] */ ULONG ulStatusCode,
/* [in] */ LPCWSTR wszStatusText);

STDMETHOD(OnStopBinding)(
/* [in] */ HRESULT hresult,
/* [unique][in] */ LPCWSTR szError)
{ return E_NOTIMPL; }

STDMETHOD(GetBindInfo)(
/* [out] */ DWORD __RPC_FAR *grfBINDF,
/* [unique][out][in] */ BINDINFO __RPC_FAR *pbindinfo)
{ return E_NOTIMPL; }

STDMETHOD(OnDataAvailable)(
/* [in] */ DWORD grfBSCF,
/* [in] */ DWORD dwSize,
/* [in] */ FORMATETC __RPC_FAR *pformatetc,
/* [in] */ STGMEDIUM __RPC_FAR *pstgmed)
{ return E_NOTIMPL; }

STDMETHOD(OnObjectAvailable)(
/* [in] */ REFIID riid,
/* [iid_is][in] */ IUnknown __RPC_FAR *punk)
{ return E_NOTIMPL; }

// IUnknown methods.  Note that IE never calls any of these methods, since
// the caller owns the IBindStatusCallback interface, so the methods all
// return zero/E_NOTIMPL.

STDMETHOD_(ULONG,AddRef)()
{ return 0; }

STDMETHOD_(ULONG,Release)()
{ return 0; }

STDMETHOD(QueryInterface)(
/* [in] */ REFIID riid,
/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
{ return E_NOTIMPL; }
  };


 #pragma warning(default:4100)
 #endif 

===================callback.cpp
#include "stdafx.h"
#include "URLDownload.h"
#include <shlwapi.h>                    // for StrFormatByteSize()
 
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
 
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
 
CCallback::CCallback() : m_bUseTimeout(FALSE), m_pDlg(NULL)
{
}
 
CCallback::~CCallback()
{
}
 
HRESULT CCallback::OnProgress ( ULONG ulProgress,   ULONG ulProgressMax,
ULONG ulStatusCode, LPCWSTR wszStatusText )
{
// Local variables are declared static so they don't have to be reallocated on
// the stack every time.  This is safe in this app since I know I'll only have
// one thread downloading.
static CString sIEStatusMsg;
static TCHAR   szCustomStatusMsg [256];
static TCHAR   szAmtDownloaded [256], szTotalSize [256];


UNREFERENCED_PARAMETER(ulStatusCode);
 
// Did the user hit the Stop button?
if ( 0 != g_fAbortDownload )
return E_ABORT;
 
// Has the timeout period elapsed?
if ( m_bUseTimeout  &&  CTime::GetCurrentTime() > m_timeToStop )
return E_ABORT;
 
// Use CString to convert IE's status message to a TCHAR string.
     if ( NULL != wszStatusText )
{
sIEStatusMsg = wszStatusText;
}
else
{
sIEStatusMsg.Empty();
}
 
// Make our own progress message - we'll show the amount downloaded and
// the total file size (if known).
StrFormatByteSize ( ulProgress, szAmtDownloaded, 256 );
StrFormatByteSize ( ulProgressMax, szTotalSize, 256 );
 
if ( 0 != ulProgressMax )
{
wsprintf ( szCustomStatusMsg, _T("Downloaded %s of %s"), szAmtDownloaded, szTotalSize );
}
else
{
wsprintf ( szCustomStatusMsg, _T("Downloaded %s (total size unknown)"), szAmtDownloaded );
}
     
// Report the progress back to the main window.
if ( 0 != ulProgressMax )
{
m_pDlg->ProgressUpdate ( sIEStatusMsg, szCustomStatusMsg, int( 100.0 * ulProgress / ulProgressMax) );
}
else
{
m_pDlg->ProgressUpdate ( sIEStatusMsg, szCustomStatusMsg, 0 );
}
return S_OK;
 
}

======================函數的使用

 
#include "stdafx.h"
#include "URLDownload.h"
#include "URLDownloadDlg.h"
#include "BindStatusCallback.h"
 
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
 
static UINT gThreadProc ( void* pv );
  
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
 
class CAboutDlg : public CDialog
{


public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
     protected:
virtual void DoDataExchange(CDataExchange* pDX);  
// DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
  };


CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}


void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
    //}}AFX_DATA_MAP
}
 
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
     //{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
 
// CURLDownloadDlg dialog


CURLDownloadDlg::CURLDownloadDlg(CWnd* pParent /*=NULL*/)
      : CDialog(CURLDownloadDlg::IDD, pParent)
 {
//{{AFX_DATA_INIT(CURLDownloadDlg)
m_uTimeout = 0;
    //}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}


void CURLDownloadDlg::DoDataExchange(CDataExchange* pDX)
 {
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CURLDownloadDlg)
DDX_Control(pDX, IDC_TIMEOUT_SECS, m_editTimeout);
DDX_Control(pDX, IDC_TIMEOUT, m_btnTimeout);
DDX_Control(pDX, IDC_SPIN, m_spinner);
    DDX_Control(pDX, IDC_FILE, m_editFile);
DDX_Control(pDX, IDC_ABOUT, m_btnAbout);
DDX_Control(pDX, IDC_URL, m_editURL);
DDX_Control(pDX, IDCANCEL, m_btnExit);
DDX_Control(pDX, IDC_STOP, m_btnStop);
DDX_Control(pDX, IDC_START, m_btnStart);
DDX_Control(pDX, IDC_PROGRESS, m_progress);
DDX_Control(pDX, IDC_IE_STATUS, m_stIEMsg);
DDX_Control(pDX, IDC_CUSTOM_STATUS, m_stCustomMsg);
DDX_Text(pDX, IDC_TIMEOUT_SECS, m_uTimeout);
//}}AFX_DATA_MAP
 }


BEGIN_MESSAGE_MAP(CURLDownloadDlg, CDialog)
 //{{AFX_MSG_MAP(CURLDownloadDlg
 ON_WM_SYSCOMMAND()
 ON_BN_CLICKED(IDC_START, OnStart)
 ON_BN_CLICKED(IDC_STOP, OnStop)
 ON_BN_CLICKED(IDC_ABOUT, OnAbout)
 ON_BN_CLICKED(IDC_TIMEOUT, OnClickedTimeout)
 //}}AFX_MSG_MAP
 
 END_MESSAGE_MAP()
  
 /////////////////////////////////////////////////////////////////////////////
 // CURLDownloadDlg message handlers
 
 BOOL CURLDownloadDlg::OnInitDialog()
 {
CDialog::OnInitDialog();

// Add "About..." menu item to system menu.

// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);

CMenu* pSysMenu = GetSystemMenu(FALSE);


if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);


if (!strAboutMenu.IsEmpty())
{


pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}

SetIcon(m_hIcon, TRUE);         // Set big icon
SetIcon(m_hIcon, FALSE);        // Set small icon

// Init & pre-fill some of the dlg controls.
m_spinner.SetRange ( 1, 120 );
    m_progress.SetRange ( 0, 100 );
    
// Fill the URL editbox with "http://"

m_editURL.SetWindowText ( _T("http://") );


// Fill the file editbox with the user's MyDocs directory.
LPITEMIDLIST pidl;
LPMALLOC     pMalloc;
TCHAR        szDocsDir [MAX_PATH];

if ( SUCCEEDED( SHGetSpecialFolderLocation ( NULL, CSIDL_PERSONAL,  &pidl )))
{
if ( SHGetPathFromIDList ( pidl, szDocsDir ))
{
lstrcat ( szDocsDir, _T("\\") );
m_editFile.SetWindowText ( szDocsDir );
}

if ( SUCCEEDED( SHGetMalloc ( &pMalloc )))
{
pMalloc->Free ( pidl );
pMalloc->Release();
}
}

GotoDlgCtrl ( &m_editURL );
m_editURL.SetSel ( -1, -1 );

    return FALSE;  // return TRUE  unless you set the focus to a control
  }




void CURLDownloadDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
 }


void CURLDownloadDlg::OnOK() 
{





void CURLDownloadDlg::OnStart()
{

CWinThread* pWorkerThread;
UpdateData();


if ( m_editURL.GetWindowTextLength() == 0 )
{
AfxMessageBox ( _T("Please enter a URL.") );
return;
}

if ( m_editURL.GetWindowTextLength() == 0 )
{


AfxMessageBox ( _T("Please enter a filename.") );
return;
}


pWorkerThread = AfxBeginThread ( gThreadProc, this,
                                    THREAD_PRIORITY_NORMAL, 0, 
                                    CREATE_SUSPENDED );
 
    // Note: Yeah I know that it's BAD to pass a CWnd object between threads.
    // I forgot about that rule when I wrote the above call, and it turns out
    // that I got lucky and it works.  All the stuff the worker thread does
    // involves just sending messages to window handles.  Since accessing the
    // data member CWnd::m_hWnd is safe to do across threads, nothing ever
    // asserted to alert me of this mistake.
    // Since I have finished this sample app and just now noticed this mistake,
    // I;m gonna be lazy and not fix it. :D


if ( NULL != pWorkerThread )
{
g_fAbortDownload = 0;

m_editURL.    EnableWindow ( FALSE );
m_editFile.   EnableWindow ( FALSE );
m_editTimeout.EnableWindow ( FALSE );
m_btnStart.   EnableWindow ( FALSE );
m_btnStop.    EnableWindow ();
m_btnExit.    EnableWindow ( FALSE );
m_btnAbout.   EnableWindow ( FALSE );
m_btnTimeout. EnableWindow ( FALSE );
m_spinner.    EnableWindow ( FALSE );

GotoDlgCtrl ( &m_btnStop );

// Kick off the download!
pWorkerThread->ResumeThread();
}

else
{
        AfxMessageBox ( _T("Couldn't create worker thread!"), MB_ICONERROR );
}
 }


void CURLDownloadDlg::OnStop() 
 {
InterlockedExchange ( &g_fAbortDownload, 1 );
 }


void CURLDownloadDlg::OnAbout() 
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}


void CURLDownloadDlg::OnClickedTimeout() 
 {
    UpdateTimeoutCtrls();
 }


void CURLDownloadDlg::UpdateTimeoutCtrls()
{
BOOL bEnable = m_btnTimeout.GetCheck();

m_editTimeout.EnableWindow ( bEnable );
m_spinner.EnableWindow ( bEnable );
}

UINT gThreadProc ( void* pv )
{
CURLDownloadDlg* pDlg = (CURLDownloadDlg*) pv;

pDlg->WorkerThreadProc();

return 0;
}


void CURLDownloadDlg::WorkerThreadProc()
{
CCallback callback;
HRESULT   hr;
CString   sURL, sFile;
callback.m_pDlg = this;

m_editURL.GetWindowText ( sURL );
m_editFile.GetWindowText ( sFile );

if ( m_btnTimeout.GetCheck() )
{
callback.m_bUseTimeout = TRUE;
        
callback.m_timeToStop = CTime::GetCurrentTime() + CTimeSpan( 0, 0, 0, m_uTimeout );
}

hr = URLDownloadToFile ( NULL,      // ptr to ActiveX container
                            sURL,      // URL to get
                            sFile,     // file to store data in
                            0,         // reserved
                            &callback  // ptr to IBindStatusCallback
                            );

if ( SUCCEEDED(hr) )
{
AfxMessageBox ( _T("Download completed successfully!"), 
MB_ICONINFORMATION );
}
else
{
LPTSTR lpszErrorMessage;
CString sMsg;

if ( FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER | 
                             FORMAT_MESSAGE_FROM_SYSTEM | 
                             FORMAT_MESSAGE_IGNORE_INSERTS,
                             NULL, hr, 
                             MAKELANGID ( LANG_NEUTRAL, SUBLANG_DEFAULT ),
                            (LPTSTR) &lpszErrorMessage, 0, NULL ))
{
sMsg.Format ( _T("Download failed.  Error = 0x%08lX\n\n%s"),
(DWORD) hr, lpszErrorMessage );

LocalFree ( lpszErrorMessage );
}
else
{
sMsg.Format ( _T("Download failed.  Error = 0x%08lX\n\nNo message available."), (DWORD) hr );
}

AfxMessageBox ( sMsg );
}
    
m_editURL.   EnableWindow();
m_editFile.  EnableWindow();
m_btnStart.  EnableWindow();
m_btnStop.   EnableWindow ( FALSE );
m_btnExit.   EnableWindow();
m_btnAbout.  EnableWindow();
        m_btnTimeout.EnableWindow();
UpdateTimeoutCtrls();
GotoDlgCtrl ( &m_editURL );
 }


void CURLDownloadDlg::ProgressUpdate ( LPCTSTR szIEMsg,
                                        LPCTSTR szCustomMsg,
                                        const int nPercentDone )


{
ASSERT ( AfxIsValidString ( szIEMsg ));
ASSERT ( AfxIsValidString ( szCustomMsg ));
ASSERT ( nPercentDone >= 0  &&  nPercentDone <= 100 );
       m_stIEMsg.SetWindowText ( szIEMsg );
m_stCustomMsg.SetWindowText ( szCustomMsg );
m_progress.SetPos ( nPercentDone );
 }

///////////////////////////////////////////////////////////////////////////////////////////

#pragma once


#endif // _MSC_VER > 1000
/////////////////////////////////////////////////////////////////////////////
// CURLDownloadDlg dialog
 
class CURLDownloadDlg : public CDialog
{
// Construction
  public:
      CURLDownloadDlg(CWnd* pParent = NULL);  
 
 // standard constructor
 // Dialog Data
 //{{AFX_DATA(CURLDownloadDlg)
 enum { IDD = IDD_URLDOWNLOAD_DIALOG };
 CEdit   m_editTimeout;
 CButton m_btnTimeout;
 CSpinButtonCtrl m_spinner;
      CEdit   m_editFile;
 CButton m_btnAbout;
 CEdit   m_editURL;
 CButton m_btnExit;
 CButton m_btnStop;
 CButton m_btnStart;
 CProgressCtrl   m_progress;
 CStatic m_stIEMsg;
 CStatic m_stCustomMsg;
 UINT    m_uTimeout;
 //}}AFX_DATA
      
 // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CURLDownloadDlg)
  protected:
 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 //}}AFX_VIRTUAL
 // Implementation
  protected:
 HICON m_hIcon;
 void UpdateTimeoutCtrls();


  public:
 void WorkerThreadProc();
      void ProgressUpdate ( LPCTSTR szIEMsg, LPCTSTR szCustomMsg, const int nPercentDone );
      // Generated message map functions
      //{{AFX_MSG(CURLDownloadDlg)
      
 virtual BOOL OnInitDialog();
 afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
      virtual void OnOK();
 afx_msg void OnStart();
 afx_msg void OnStop();
 afx_msg void OnAbout();
 afx_msg void OnClickedTimeout();
      //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
  };
 //{{AFX_INSERT_LOCATION}}
 // Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章