MFC文件下载
来源:互联网 发布:java将字符转换成数字 编辑:程序博客网 时间:2024/05/23 19:03
我们知道,windows有关网络连接的API在wininet.h里,而在MFC里,这些API被封装成了类。
CInternetSession类:直接继承自CObject类,该类用来建立与某个Internet服务器的会话
CInternetConnection类:帮助用户管理与Internet服务器的连接,同时还提供一些函数完成和响应服务器的通信
CInternetConnection类又派生出三个类:
CHttpConnection类:管理与HTTP服务器的连接
CFtpConnection类:用于管理与FTP服务器的连接
CGopherConnection类:管理与Gopher服务器的连接
我们要实现根据URL下载并保存文件,就需要CInternetSession、CHttpConnection、CHttpFile。
CHttpFile用来做什么呢?它可以关联起URL指向的一个WEB对象,由于CHttpFile继承与CFile,我们可以像读取一个CFile文件一样,把它从HTTP服务器上下载下来。
MFC就是通过对CHttpFile对象的读写来完成与HTTP服务器的对话的,包括GET/POST提交数据,接收数据。
1.CInternetSession
使用类CInternetSession 创建并初始化一个或多个同时的Internet会话。如果需要,还可描述与代理服务器的连接。如果Internet 连接必须在应用过程中保持着,可创建一个类CWinApp的CInternetSession成员。一旦已建起Internet 会话,就可调用OpenURL。CInternetSession会通过调用全局函数AfxParseURL来为分析映射URL。无论协议类型如何,CInternetSession 解释URL并管理它。它可处理由URL资源“file://”标志的本地文件的请求。如果传给它的名字是本地文件,OpenURL将返回一个指向CStdioFile对象的指针。
如果使用OpenURL在Internet服务器上打开一个URL,你可从此处读取信息。如果要执行定位在服务器上的指定的服务(例如,HTTP,FTP或Gopher)行为,必须与此服务器建立适当的连接。直接打开与指定的服务器的指定的类型的连接,请使用下列成员函数:
·GetGopherConnection
打开与Gopher服务的连接。
·GetHttpConnection
打开与HTTP服务的连接。
·GetFtpConnection
打开与FTP服务的连接。
可使用以下代码连接到代理服务器:
INTERNET_PROXY_INFO proxyinfo;
proxyinfo.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
proxyinfo.lpszProxy ="192.168.69.160:808";
proxyinfo.lpszProxyBypass = NULL;
session.SetOption(INTERNET_OPTION_PROXY,(LPVOID)&proxyinfo,
sizeof(INTERNET_PROXY_INFO));
QueryOption和SetOption允许设置会话的查询选项,如超时值、再试次数等等。Internet会话过程中,象查找或数据下载这样的事务处理会占用一定的时间。使用者可能想继续工作,或获得事务处理进程的状态信息。为解决这个问题,CInternetSession可以让查找和数据传输异步发生,允许使用者在传输结束时进行其它任务。如果要为使用者提供状态信息,或异步处理任意操作,必须设置三个条件:
1
在构造函数中,dwFlags必须包括INTERNET_FLAG_ASYNC。
2
在构造函数中,dwContext必须设置为1。
3
必须通过调用EnableStatusCallback来建立回调函数。
使用覆盖成员函数OnStatusCallback来获得异步获取的状态信息。使用此覆盖成员函数,必须从CInternetSession派生你自己的类。设置会话的查询选项可使用如下代码:
CInternetSessionsession;
session.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, 15000); // 15秒的连接超时
session.SetOption(INTERNET_OPTION_SEND_TIMEOUT, 1000); // 1秒的发送超时
session.SetOption(INTERNET_OPTION_RECEIVE_TIMEOUT, 37000); // 37秒的接收超时
session.SetOption(INTERNET_OPTION_DATA_SEND_TIMEOUT, 1000); // 1秒的发送超时
session.SetOption(INTERNET_OPTION_DATA_RECEIVE_TIMEOUT, 37000); // 37秒的接收超时
session.SetOption(INTERNET_OPTION_CONNECT_RETRIES, 10); // 10次重试
2.CHttpConnection
MFC类CHttpConnection管理与HTTP服务器的连接。HTTP是用MFCWinInet类实现的三个Internet服务器协议之中的一个。类CHttpConnection包含一个构造函数和一个成员函数OpenRequest,使用HTTP协议来管理与服务器的连接。要与一个HTTP服务器通讯,必须先构造一个CInternetSession的实例,然后构造一个CHttpConnection对象。不能直接构造一个CHttpConnection对象,而是调用CInternetSession::GetHttpConnection,创建CHttpConnection对象并返回其指针。
3.CHttpFile
CHttpFile提供向HTTP服务器中请求和读取的功能。如果Internet会话要从一个HTTP服务器中读取数据,则必须构造一个CHttpFile实例。
可用如下代码建立与互联网上文件的连接,实现文件下载的前提,这也是文件下载的核心代码了。
CInternetSession session;
CHttpConnection* pHttpConnection = NULL;
CHttpFile* pHttpFile = NULL;
pHttpConnection = session.GetHttpConnection(strServer, wPort);
CString strServer, strObject;
INTERNET_PORT wPort;
DWORD dwType;
AfxParseURL(“待下载文件的URL”, dwType, strServer, strObject, wPort);
pHttpConnection = session.GetHttpConnection(strServer, wPort);
pHttpFile = pHttpConnection->OpenRequest(CHttpConnection::HTTP_VERB_GET, strObject);
附(文件下载函数)
bool XXX::Download(const CString& strFileURLInServer, //待下载文件的URLconst CString & strFileLocalFullPath)//存放到本地的路径
{
ASSERT(strFileURLInServer != "");
ASSERT(strFileLocalFullPath != "");
CInternetSession session;
CHttpConnection* pHttpConnection = NULL;
CHttpFile* pHttpFile = NULL;
proxyinfo.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
proxyinfo.lpszProxy ="192.168.69.160:808";
proxyinfo.lpszProxyBypass = NULL;
session.SetOption(INTERNET_OPTION_PROXY,(LPVOID)&proxyinfo,
sizeof(INTERNET_PROXY_INFO));
session.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, 15000); // 15秒的连接超时
session.SetOption(INTERNET_OPTION_SEND_TIMEOUT, 1000); // 1秒的发送超时
session.SetOption(INTERNET_OPTION_RECEIVE_TIMEOUT, 37000); // 37秒的接收超时
session.SetOption(INTERNET_OPTION_DATA_SEND_TIMEOUT, 1000); // 1秒的发送超时
session.SetOption(INTERNET_OPTION_DATA_RECEIVE_TIMEOUT, 37000); // 37秒的接收超时
session.SetOption(INTERNET_OPTION_CONNECT_RETRIES, 10); // 10次重试
CString strServer, strObject;
INTERNET_PORT wPort;
DWORD dwType;
char* pszBuffer = NULL;
try
{
AfxParseURL(strFileURLInServer, dwType, strServer, strObject, wPort);
pHttpConnection = session.GetHttpConnection(strServer, wPort);
pHttpFile = pHttpConnection->OpenRequest(CHttpConnection::HTTP_VERB_GET, strObject);
if (pHttpFile->SendRequest() == FALSE)
return false;
DWORD dwStateCode;
pHttpFile->QueryInfoStatusCode(dwStateCode);
if (dwStateCode == HTTP_STATUS_OK)
{
HANDLE hFile = CreateFile(strFileLocalFullPath, GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
NULL); //创建本地文件
if (hFile == INVALID_HANDLE_VALUE)
{
pHttpFile->Close();
pHttpConnection->Close();
session.Close();
return false;
}
char szInfoBuffer[1000]; //返回消息
DWORD dwFileSize = 0; //文件长度
DWORD dwInfoBufferSize = sizeof(szInfoBuffer);
BOOL bResult = FALSE;
bResult = pHttpFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH,
(void*)szInfoBuffer, &dwInfoBufferSize, NULL);
dwFileSize = atoi(szInfoBuffer);
const int BUFFER_LENGTH = 1024 * 10;
pszBuffer = new char[BUFFER_LENGTH]; //读取文件的缓冲
DWORD dwWrite, dwTotalWrite;
dwWrite = dwTotalWrite = 0;
UINT nRead = pHttpFile->Read(pszBuffer, BUFFER_LENGTH); //读取服务器上数据
while (nRead > 0)
{
WriteFile(hFile, pszBuffer, nRead, &dwWrite, NULL); //写到本地文件
dwTotalWrite += dwWrite;
nRead = pHttpFile->Read(pszBuffer, BUFFER_LENGTH);
}
delete[]pszBuffer;
pszBuffer = NULL;
CloseHandle(hFile);
}
else
{
delete[]pszBuffer;
pszBuffer = NULL;
if (pHttpFile != NULL)
{
pHttpFile->Close();
delete pHttpFile;
pHttpFile = NULL;
}
if (pHttpConnection != NULL)
{
pHttpConnection->Close();
delete pHttpConnection;
pHttpConnection = NULL;
}
session.Close();
return false;
}
}
catch (...)
{
delete[]pszBuffer;
pszBuffer = NULL;
if (pHttpFile != NULL)
{
pHttpFile->Close();
delete pHttpFile;
pHttpFile = NULL;
}
if (pHttpConnection != NULL)
{
pHttpConnection->Close();
delete pHttpConnection;
pHttpConnection = NULL;
}
session.Close();
return false;
}
if (pHttpFile != NULL)
pHttpFile->Close();
if (pHttpConnection != NULL)
pHttpConnection->Close();
session.Close();
return true;
}
利用以上的下载函数,是可以实现下载功能的,需要说明一下的是,要测试下载功能需要有一个下载的连接地址URL,也许你还不清除这个要怎么弄来,这里也说明下:URL不是云盘上的目录地址,而是下载链接,打开下载管理器,右键即可复制了
我们来做个简单的下载工具,模拟这个Sogou的下载管理器。
有了下载函数,主要还要做以下功能:
1、进度条
2、图片按钮
3、开启定时器来显示下载进度
4、控件背景
5、下载类型的文件图标
下面就来解决这些问题:
1、进度条
文件下载是比较耗能的工作,因此是不适合在下载函数里显示进度条进度的,事实上,进度条显示的,都是时间比较长的工作,不然干嘛需要用进度条来显示进度从而告诉我们程序没卡死呢,因此,进度条的显示都是开线程或者用线程回调来做的。
获得进度条id
先定义 CProgressCtrl m_ctrProgress; //进度条控制函数
再在下面的地方添加:
void CdowmloadDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_PROGRESS1, m_ctrProgress);
}
在头文件添加声明
DWORD _stdcall ShowThread(LPVOIDlpParam);
在cpp文件写下面的线程处理函数
DWORD _stdcall ShowThread(LPVOIDlpParam)
{
m_ctrProgress.SetRange32(0,filesize);//设置进度条的上下界
m_ctrProgress.SetPos(dwTotalWrite);//当前进度
return 0;
}
在文件下载的函数循环里创建线程
CreateThread(NULL,0,ShowThread,NULL,0,NULL);
2、图片按钮
图片按钮的方法有几种的:
1、按钮贴图,然后再改变按钮样式来实现
按钮属性里的Bitmap要选为TRUE‘
(1)首先建立位图句柄,
- // 方法一:加载非资源图片
- HBITMAP hBitmap;
- hBitmap = (HBITMAP)::LoadImage(
- NULL,
- "E://a.bmp", // 图片全路径
- IMAGE_BITMAP, // 图片格式
- 0,0,
- LR_LOADFROMFILE|LR_CREATEDIBSECTION); // 注意LR_LOADFROMFILE
- // 方法二:加载资源图片
- HBITMAP hBitmap;
- hBitmap = LoadBitmap(AfxGetInstanceHandle(),
- MAKEINTRESOURCE(IDB_BITMAP_TEST)); // IDB_BITMAP_TEST为资源图片ID
- ((CButton *)GetDlgItem(IDC_BUTTON_TEST))->SetBitmap(hBitmap);
2、自己绘制
按钮属性里的Owner Draw要选为TRUE,按钮自定义绘图,需要用户在OndrawItem消息处理函数中绘制按钮的外观。代码大概用下面的
CRect rect;
Btn_start->GetWindowRect(rect);
ScreenToClient(rect);//
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP1);//其中IDB_BITMAP是位图名称
CBrush brush(&bitmap);
CClientDC dc(this);
dc.FillRect(rect,&brush);
3、用MFC现成的类CBitmapButton,我就是用这个来实现的,方便点,就是有点局限
(1)在头文件中声明
CBitmapButtonbmpBtnStart,bmpBtnStop,bmpBtnCancle;
(2)在cpp文件中的BOOL CxxxDlg::OnInitDialog()中
bmpBtnStart.LoadBitmaps(IDB_start,IDB_startOn); //绑定图片,IDB_BTN_LOGIN为图片资源名,资源需要事先导入
bmpBtnStart.SubclassDlgItem(IDC_BTN_START,this); //绑定控件ID
bmpBtnStart.SizeToContent(); //设置控件大小与图片相同
bmpBtnStop.LoadBitmaps(IDB_stop,IDB_stopOn);
bmpBtnStop.SubclassDlgItem(IDC_BTN_STOP,this);
bmpBtnStop.SizeToContent();
bmpBtnCancle.LoadBitmaps(IDB_close,IDB_closeOn);
bmpBtnCancle.SubclassDlgItem(IDC_BTN_cancel,this);
bmpBtnCancle.SizeToContent();
当然需要先在资源文件里加载图片资源。
3、开启定时器来显示下载进度
(1)头文件中什么消息响应函数void OnTimer(UINT_PTR nIDEvent);
(2)cpp中首先要添加消息 ON_WM_TIMER()
(3)cpp中定时器响应函数
void CxxxDlg::OnTimer(UINT_PTR nIDEvent)
{
switch (nIDEvent)
{
case 1: // 计时器1
.... // 处理的代码
KillTimer(1); // 删除此计时器,否则计时器中断完后会自动重新开始计时,到下一次中断时还会发生新的中断
break;
case 2: // 计时器2
.... // 处理的代码
break;
default:
MessageBox("default: KillTimer");
KillTimer(nIDEvent);
break;
}
}
(4)启动一个1秒钟的定时器SetTimer(1,1000, NULL);
关闭该定时器 KillTimer(1);
4、控件背景
(1)头文件里声明 HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
(2)cpp里添加重载消息 ON_WM_CTLCOLOR()
(3)重载函数
HBRUSH CdowmloadDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
switch(nCtlColor)
{
case CTLCOLOR_STATIC: //静态文本控件
{
// pDC->SetBkMode(TRANSPARENT);
// //pDC->SetTextColor(RGB(255,255,0)); //设置字体颜色
// //pWnd->SetFont(cfont); //设置字体
// HBRUSH B = CreateSolidBrush(RGB(125,125,255)); //创建画刷
//pDC->SetTextColor(RGB(250,250,250));
pDC->SetBkColor(RGB(250,250,250));
return (HBRUSH)staticBrush;
}
// case CTLCOLOR_BTN: //按钮控件
// {
// pDC->SetBkMode(TRANSPARENT);
// /* pDC->SetTextColor(RGB(255,255,0));
// pWnd->SetFont(cfont); */
// HBRUSH B = CreateSolidBrush(RGB(125,125,255));
// return (HBRUSH) B;
// }
}
return hbr;
}
5、下载类型的文件图标
(1)添加一个picture control的控件,其实它用起来和static控件差不多
(2)判断待下载的图片类型,然后用对应的图标显示就可以了。下面为加载图片代码
CStatic *pStatic = (CStatic *)GetDlgItem(IDC_picture);
//加载资源图片
HBITMAP hBitmap;
hBitmap = LoadBitmap(AfxGetInstanceHandle(),
MAKEINTRESOURCE(IDB_zip)); // IDB_BITMAP_TEST为资源图片ID
程序效果图:
文件下载的源代码http://download.csdn.net/detail/sns1991sns/9150529
- MFC 下载文件
- mfc ftp文件下载
- MFC文件下载
- MFC用http类下载文件
- MFC CInternetSession OpenUrl 下载文件 防止异常
- MFC实现文件下载和上传
- 用MFC 网络接口下载/上传文件
- 使用MFC提供的Http类下载和上传文件
- MFC通过URL下载并保存文件代码
- 使用MFC提供的Http类下载和上传文件
- MFC通过URL下载并保存文件代码
- MFC通过URL下载并保存文件代码
- mfc文件
- MFC:文件
- VC++/MFC 源码下载
- 在MFC下实现POST网页表单,下载服务器文件或取得网页源代码
- VC++/MFC怎么实现局域网里下载FTP服务器上的文件?
- 使用MFC对FTP文件或者文件夹进行下载、断点续传等功能的个人理解
- C++数组名的思考
- LeetCode 274/275 H-Index Java
- idea创建maven项目
- javascript正则表达式
- 用命令形式从Windows系统拷贝文件到Linux
- MFC文件下载
- Android中This、super、getApplicationContext()、getApplication()之间的区别
- 对java中json格式变量数据的一些理解
- POJ 1125 Stockbroker Grapevine (floyd_DP)
- 动态库和Linux调试技术
- log4j配置文件位置详解
- Cocos如何绑定lua自定义类
- 【Bug】Android SDK content loader 0%
- Java集合简介