#pragma once class CDownloadDlg; class CInternetDownload { public: typedef struct { DWORD nStart;//文件片段的起始位置 DWORD nEnd;//文件片段的长度 size_t nIndex;//当前线程的编号 size_t nTotal; CInternetDownload* pThis; } ThreadParam; CInternetDownload(CDownloadDlg* pDlg); virtual ~CInternetDownload(void); virtual int Download(const CString& strUrl, size_t nThreads); protected: static CString s_strUrl; static CDownloadDlg* s_pDlg; virtual DWORD GetFileLength(const CString& strUrl) = 0; virtual CFile* GetInternetFile(LPVOID) = 0; static UINT ServerWorkerThread(LPVOID lpParam); CInternetSession internetSession; private: CFile* m_internetFile; }; InternetDownload.cpp #include "StdAfx.h" #include "./internetdownload.h" #include "DownloadDlg.h" CDownloadDlg* CInternetDownload::s_pDlg = NULL; CString CInternetDownload::s_strUrl; CInternetDownload::CInternetDownload(CDownloadDlg* pDlg) : m_internetFile(NULL) { s_pDlg = pDlg; } CInternetDownload::~CInternetDownload(void) { } UINT CInternetDownload::ServerWorkerThread(LPVOID lpParam) { ThreadParam *pParam = static_cast<ThreadParam *>(lpParam); CFile *pFile = pParam->pThis->GetInternetFile(lpParam); if (!pFile) return -1; CFile localFile; CString strFileName; strFileName.Format("c://temp.part%d", pParam->nIndex); if (!localFile.Open(strFileName, CFile::modeCreate | CFile::modeWrite)) return -1; char * const pBuffer = new char[1024]; DWORD nLeft = pParam->nEnd - pParam->nStart + 1; while (TRUE) { int nRead = pFile->Read(pBuffer, nLeft > 1024 ? 1024 : nLeft); localFile.Write(pBuffer, nRead); if (nRead < 1024) break; nLeft -= nRead; } localFile.Close(); delete []pBuffer; pFile->Close(); delete pFile; s_pDlg->PostMessage(WM_DOWNLOADED_MESSAGE, pParam->nTotal, pParam->nIndex); delete pParam; pParam = NULL; return 0; } int CInternetDownload::Download(const CString& strUrl, size_t nThreads) { s_strUrl = strUrl; DWORD nFileSize = GetFileLength(strUrl); UINT nSegmentLength = (nFileSize + nThreads - 1) / nThreads; for (size_t i = 0; i < nThreads; i++) { ThreadParam *lpParam = new ThreadParam; //memset(lpParam, '/0', sizeof(ThreadParam)); lpParam->nTotal = nThreads; lpParam->nIndex = i; lpParam->nStart = nSegmentLength * i; lpParam->nEnd = lpParam->nStart + nSegmentLength - 1; lpParam->pThis = this; if (lpParam->nEnd >= nFileSize) lpParam->nEnd = nFileSize - 1; AfxBeginThread(ServerWorkerThread, static_cast<LPVOID>(lpParam), THREAD_PRIORITY_NORMAL, 0, 0, NULL); //CreateThread(NULL, 0, ServerWorkerThread, (LPVOID)i, 0, 0); } return 0; } #pragma once #include "InternetDownload.h" class CFtpDownload : public CInternetDownload { public: CFtpDownload(CDownloadDlg* pDlg); virtual ~CFtpDownload(void); // int Download(const CString& strUrl, size_t nThreads); private: DWORD GetFileLength(const CString& strUrl); CFile* GetInternetFile(LPVOID lpParam); }; #include "StdAfx.h" #include "./ftpdownload.h" #include "DownloadDlg.h" #include <winsock2.h> #include "shlwapi.h" #pragma comment(lib, "Wininet.lib") #pragma comment(lib, "shlwapi.lib") CFtpDownload::CFtpDownload(CDownloadDlg* pDlg) : CInternetDownload(pDlg) { // s_pDlg = pDlg; } CFtpDownload::~CFtpDownload(void) { } CFile* CFtpDownload::GetInternetFile(LPVOID lpParam) { ThreadParam *pParam = static_cast<ThreadParam *>(lpParam); CFtpConnection *pFtpConn = NULL; CString strServerName, strObject, strUserName, strPassword; DWORD dwServiceType; INTERNET_PORT nPort; if (!AfxParseURLEx(s_strUrl, dwServiceType, strServerName, strObject, nPort, strUserName, strPassword) || dwServiceType != INTERNET_SERVICE_FTP) { TRACE(_T("Not a ftp Quest! /n")); } pFtpConn = internetSession.GetFtpConnection(strServerName, strUserName, strPassword); CString strFtpCommand; strFtpCommand.Format("REST %d", pParam->nStart); if (!FtpCommand(*pFtpConn, FALSE, FTP_TRANSFER_TYPE_ASCII, strFtpCommand, 0, 0)) { int i = WSAGetLastError(); return NULL; } CFile *pFile = pFtpConn->OpenFile(strObject); return pFile; } /* int CFtpDownload::Download(const CString& strUrl, size_t nThreads) { DWORD nFileSize = GetFileLength(strUrl); s_strUrl = strUrl; UINT nSegmentLength = (nFileSize + nThreads - 1) / nThreads; for (size_t i = 0; i < nThreads; i++) { ThreadParam *lpParam = new ThreadParam; //memset(lpParam, '/0', sizeof(ThreadParam)); lpParam->nTotal = nThreads; lpParam->nIndex = i; lpParam->nStart = nSegmentLength * i; lpParam->nEnd = lpParam->nStart + nSegmentLength - 1; lpParam->pThis = this; if (lpParam->nEnd >= nFileSize) lpParam->nEnd = nFileSize - 1; AfxBeginThread(ServerWorkerThread, static_cast<LPVOID>(lpParam), THREAD_PRIORITY_NORMAL, 0, 0, NULL); //CreateThread(NULL, 0, ServerWorkerThread, (LPVOID)i, 0, 0); } return 0; } */ DWORD CFtpDownload::GetFileLength(const CString& strUrl) { CInternetSession internetSession; CFtpConnection *pFtpConn = NULL; CString strServerName, strObject, strUserName, strPassword; DWORD dwServiceType; INTERNET_PORT nPort; if (!AfxParseURLEx(strUrl, dwServiceType, strServerName, strObject, nPort, strUserName, strPassword) || dwServiceType != INTERNET_SERVICE_FTP) { TRACE(_T("Not a ftp Quest! /n")); return -1; } pFtpConn = internetSession.GetFtpConnection(strServerName, strUserName, strPassword); //FtpCommand("REST 1024"); /* if (!FtpCommand(*pFtpConn, FALSE, FTP_TRANSFER_TYPE_ASCII, "REST 1024", 0, 0)) return -1;*/ CInternetFile *pFile = pFtpConn->OpenFile(strObject); DWORD nFileSize = FtpGetFileSize(*pFile, 0); pFile->Close(); delete pFile; return nFileSize; } #pragma once #include "InternetDownload.h" class CHttpDownload : public CInternetDownload { public: CHttpDownload(CDownloadDlg* pDlg); virtual ~CHttpDownload(void); private: // static UINT ServerWorkerThread(LPVOID lpParam); DWORD GetFileLength(const CString& strUrl); CFile* GetInternetFile(LPVOID lpParam); public: // int Download(const CString& strUrl, int nThreads); int FormatRequestHeader(void); }; #include "StdAfx.h" #include "./httpdownload.h" #include "DownloadDlg.h" static const char szHeaders[] = "Accept: */*/r/nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)/r/n"; CFile* CHttpDownload::GetInternetFile(LPVOID lpParam) { ThreadParam *pParam = static_cast<ThreadParam *>(lpParam); DWORD dwFlag = INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD; CString strHeader;//请求头 strHeader.Format("%sRange: bytes=%d-%d/r/n", szHeaders, pParam->nStart, pParam->nEnd);//pParam->nIndex * 8192);//, 1024 * 1024); return internetSession.OpenURL(s_strUrl, 1, dwFlag, strHeader, -1); } /* UINT CHttpDownload::ServerWorkerThread(LPVOID lpParam) { //size_t nIndex = reinterpret_cast<size_t>(lpParam);//第几个文件片段 ThreadParam *pParam = static_cast<ThreadParam *>(lpParam); char * const pBuffer = new char[1024]; //for (int i = 0; ; i++) while (TRUE) { int nRead = pHttpFile->Read(pBuffer, 1024); localFile.Write(pBuffer, nRead); if (nRead < 1024) break; } localFile.Close(); delete []pBuffer; pHttpFile->Close(); delete pHttpFile; s_pDlg->PostMessage(WM_DOWNLOADED_MESSAGE, pParam->nTotal, pParam->nIndex); delete pParam; return 0; } */ CHttpDownload::CHttpDownload(CDownloadDlg* pDlg) : CInternetDownload(pDlg) //: m_strHeader("Accept: */*/r/nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.00; Windows XP)/r/n") { } CHttpDownload::~CHttpDownload(void) { } /* int CHttpDownload::Download(const CString& strUrl, int nThreads) { s_strUrl = strUrl; DWORD nFileSize = GetFileLength(strUrl); UINT nSegmentLength = (nFileSize + nThreads - 1) / nThreads; for (size_t i = 0; i < nThreads; i++) { ThreadParam *lpParam = new ThreadParam; //memset(lpParam, '/0', sizeof(ThreadParam)); lpParam->nTotal = nThreads; lpParam->nIndex = i; lpParam->nStart = nSegmentLength * i; lpParam->nEnd = lpParam->nStart + nSegmentLength - 1; if (lpParam->nEnd >= nFileSize) lpParam->nEnd = nFileSize - 1; AfxBeginThread(ServerWorkerThread, static_cast<LPVOID>(lpParam), THREAD_PRIORITY_NORMAL, 0, 0, NULL); //CreateThread(NULL, 0, ServerWorkerThread, (LPVOID)i, 0, 0); } return 0; } */ int CHttpDownload::FormatRequestHeader(void) { // char szHeader[1024]; return 0; } DWORD CHttpDownload::GetFileLength(const CString& strUrl) { CInternetSession sess; DWORD dwFlag = INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD; s_strUrl = strUrl; CHttpFile* pHttpFile = (CHttpFile* )sess.OpenURL(s_strUrl, 1, dwFlag); if (!pHttpFile) return -1; CString strLength; pHttpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH, strLength); pHttpFile->Close(); delete pHttpFile; return _ttoi(strLength); } // DownloadDlg.cpp : 实现文件 // #include "stdafx.h" #include "Download.h" #include "DownloadDlg.h" #include "./downloaddlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialog { public: CAboutDlg(); // 对话框数据 enum { IDD = IDD_ABOUTBOX }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) END_MESSAGE_MAP() // CDownloadDlg 对话框 CDownloadDlg::CDownloadDlg(CWnd* pParent /*=NULL*/) : CDialog(CDownloadDlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_pDownloader = NULL; } void CDownloadDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } //#define WM_XXXX 10O //const static int WM_DOWNLOADED_MESSAGE = WM_USER+100; BEGIN_MESSAGE_MAP(CDownloadDlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_MESSAGE(WM_DOWNLOADED_MESSAGE, OnDownloadMessage) ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedButton1) ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedButton2) END_MESSAGE_MAP() // CDownloadDlg 消息处理程序 BOOL CDownloadDlg::OnInitDialog() { CDialog::OnInitDialog(); // 将/“关于.../”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 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); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 // GetDlgItem(IDC_EDIT1)->SetWindowText("http://codeproject.com/");//http://192.168.8.246:8080/sogou_wubi_15b.exe GetDlgItem(IDC_EDIT1)->SetWindowText("ftp://me:me@192.168.69.86/inet.h");//ftp://192.168.14.130/InstallPack/5.9.5.x/5.9.5.976/5.9.5.976.txt"); GetDlgItem(IDC_EDIT2)->SetWindowText("4"); return TRUE; // 除非设置了控件的焦点,否则返回 TRUE } void CDownloadDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CDownloadDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标显示。 HCURSOR CDownloadDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } #include "InternetDownload.h" #include "FtpDownload.h" #include "HttpDownload.h" void CDownloadDlg::OnBnClickedButton1() { CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST1); for (int i = pListBox->GetCount() - 1; i >= 0; i--) { pListBox->DeleteString( i ); } //downloader.Download("http://192.168.8.246:8080/sogou_wubi_15b.exe"); CString strUrl; GetDlgItem(IDC_EDIT1)->GetWindowText(strUrl); CString strThreads; CWnd* pEditCtrl = GetDlgItem(IDC_EDIT2); pEditCtrl->GetWindowText(strThreads); if (!strUrl.IsEmpty() && !strThreads.IsEmpty()) { GetDlgItem(IDC_EDIT1)->EnableWindow(FALSE); GetDlgItem(IDC_EDIT2)->EnableWindow(FALSE); CString strServerName, strObject, strUserName, strPassword; DWORD dwServiceType; INTERNET_PORT nPort; if (!AfxParseURLEx(strUrl, dwServiceType, strServerName, strObject, nPort, strUserName, strPassword)) { TRACE(_T("Not a valid Quest! /n")); GetDlgItem(IDC_EDIT2)->EnableWindow(); GetDlgItem(IDC_EDIT2)->EnableWindow(); } if (dwServiceType == INTERNET_SERVICE_HTTP) { m_pDownloader = new CHttpDownload(this); m_pDownloader->Download(strUrl, _ttoi(strThreads)); } else if (dwServiceType = INTERNET_SERVICE_FTP) { m_pDownloader = new CFtpDownload(this); m_pDownloader->Download(strUrl, _ttoi(strThreads)); } else { TRACE(_T("Not a valid Quest! /n")); GetDlgItem(IDC_EDIT2)->EnableWindow(); GetDlgItem(IDC_EDIT2)->EnableWindow(); } //delete pDownloader; } else { AfxMessageBox("please input url & thread number"); return; } } LRESULT CDownloadDlg::OnDownloadMessage(WPARAM wParam, LPARAM lParam) { CString strInfo; strInfo.Format("part %d complete.", lParam); CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST1); pListBox->InsertString(pListBox->GetCount(), strInfo); CString strThreads; CWnd* pEditCtrl = GetDlgItem(IDC_EDIT2); pEditCtrl->GetWindowText(strThreads); if (pListBox->GetCount() == wParam) { //MergeFile(); CFile resultFile("c://temp.exe", CFile::modeCreate | CFile::modeWrite); if (!resultFile) return -1; char buffer[1024]; for (size_t i = 0; i < wParam; i++) { int nLength; CString strFileName; strFileName.Format("c:/temp.part%d", i); CFile tempFile(strFileName, CFile::modeRead); //nLength = file2.GetLength(); if (!tempFile) { AfxMessageBox("error: cannot find.."); return -1; } while ( (nLength = tempFile.Read(buffer, 1024)) > 0) { resultFile.Write(buffer, nLength); if (nLength < 1024) break; } tempFile.Close(); } resultFile.Close(); pListBox->InsertString(wParam, "Merge Ok!"); GetDlgItem(IDC_EDIT1)->EnableWindow(); GetDlgItem(IDC_EDIT2)->EnableWindow(); delete m_pDownloader; m_pDownloader = NULL; } return 0; } void CDownloadDlg::OnBnClickedButton2() { CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST1); for (int i = pListBox->GetCount() - 1; i >= 0; i--) { pListBox->DeleteString( i ); } }