利用WinInet和多线程实现实时显示的下载进度条
来源:互联网 发布:java换ip刷页面访问量 编辑:程序博客网 时间:2024/06/11 23:08
利用WinInet和多线程实现下载进度实时显示
作者:阿珊境界
源代码下载
大家对Internet文件下载一定不陌生,如果不讲究下载细节,一个API函数URLDownloadToFile就能搞定。但如果你要下载的数据量较大,或你的软件需要在线升级,那么,还是给个进度条让用户看看,免得让人以为你的软件已经挂掉。要实现这些,首先用到的就是多线程技术,把下载线程和界面线程分开;其次,要把下载进度及时反馈给界面进度条,还要用到WinInet提供的接口。程序界面如图1。
图1
本例程用到4个WinInet接口函数,分别是InternetGetConnectdState、InternetOpen、InternetOpenUrl和HttpQueryInfo,分别用以获取当前网络连接信息、打开网络连接、打开具体URL和查看连接信息。在工程中,我们写一个函数InternetGetFile对下载细节进行封装,代码如下:
int CDownloadProgressDlg::InternetGetFile (HWND hWnd,CString szUrl,CString szFileName)
{
DWORD dwFlags;
InternetGetConnectedState(&dwFlags, 0); //获取当前网络连接信息
CHAR strAgent[64];
sprintf(strAgent, "Agent%ld", timeGetTime()); //timeGetTime用以获取系统启动后的时间
HINTERNET hOpen;
if(!(dwFlags & INTERNET_CONNECTION_PROXY))
hOpen = InternetOpenA(strAgent, INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY, NULL, NULL, 0);
else
hOpen = InternetOpenA(strAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if(!hOpen)
{
AfxMessageBox("Internet连接错误!");
return -1;
}
DWORD dwSize;
//CHAR szHead[] = "Accept: */*/r/n/r/n";
CHAR szHead[] =
_T("Accept: */*/r/nAccept-Language: zh-cn/r/nAccept-Encoding: gzip, deflate/r/nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; MyIE2; .NET CLR 1.1.4322)");
VOID* szTemp[16384];
HINTERNET hConnect;
CFile file;
if ( !(hConnect = InternetOpenUrlA ( hOpen, szUrl, szHead,
lstrlenA (szHead), INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD, 0)))
{
AfxMessageBox("不能打开该URL!");
return -1;
}
if (file.Open(szFileName,CFile::modeWrite|CFile::modeCreate)==FALSE )
{
AfxMessageBox("不能打开本地的文件!");
return -1;
}
DWORD dwByteToRead = 0;
DWORD dwSizeOfRq = 4;
DWORD dwBytes = 0;
if (!HttpQueryInfo(hConnect, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
(LPVOID)&dwByteToRead, &dwSizeOfRq, NULL))
{
dwByteToRead = 0;
}
DWORD start; //记录时间
DWORD end;
DWORD time;
int nPos;
CString tempstring;
time = 10;
start = timeGetTime();
do
{
if (!InternetReadFile (hConnect, szTemp, 16384, &dwSize))
{
AfxMessageBox("读文件出错!");
file.Close();
return -1;
}
if (dwSize==0)
break;
else
file.Write(szTemp,dwSize);
dwBytes+=dwSize;
if(dwByteToRead)
{
tempstring.Format("%d%%",(dwBytes*100)/dwByteToRead);
nPos=(dwBytes*100)/dwByteToRead;
// SetDlgItemText(IDC_PERCENT_TEXT,tempstring);
}
float fSpeed = 0; //计算速度
fSpeed = (float)dwBytes;
fSpeed /= (float)((float)time/(float)1000);
fSpeed /= (float)1024;
//tempstring.Format("%4.2fKB/S",fSpeed);
TRACE(tempstring);
//下面的代码我将作出解释,请看下文
SHOWINFO* pShowInfo=new SHOWINFO;
pShowInfo->strSpeed.Format("%4.1f KB/秒",fSpeed);
pShowInfo->nPos=nPos;
::PostMessage(hWnd,MSG_PROGRESS,0,(LPARAM)pShowInfo);
end = timeGetTime();
time = end - start;
if(time == 0)
time = 10;
}while (TRUE);
file.Close();
InternetCloseHandle(hOpen); //关闭句柄
return 0;
}
这个函数的后半段代码我解释一下。SHOWINFO是一个自定义的结构体,用其把当前速度和进度传递给界面进度条。定义如下:
struct SHOWINFO
{
CString strSpeed;
int nPos;
};
传递信息给界面的方式是用PostMessage,这里,它的第二个参数就用SHOWINFO的对象了。注意使用时强制转化为LPARAM。MSG_PROGRESS是个自定义消息,它的响应函数为OnStep,在其中处理进度条的显示。代码如下:
LRESULT CDownloadProgressDlg::OnStep(WPARAM wParam, LPARAM lParam)
{
CString strSpeed=((SHOWINFO*)lParam)->strSpeed;
int nPos=((SHOWINFO*)lParam)->nPos;
delete (SHOWINFO*)lParam;
CString strPercent;
strPercent.Format("%d%%",nPos);
SetDlgItemText(IDC_SPEED_TEXT,strSpeed);
SetDlgItemText(IDC_PERCENT_TEXT,strPercent);
m_progress.SetPos(nPos);
if(nPos==100)
{
GetDlgItem(IDC_DOWNLOAD)->EnableWindow(TRUE);
GetDlgItem(IDOK)->EnableWindow(TRUE);
MessageBox("文件下载完成!","OK",MB_ICONINFORMATION);
}
return TRUE;
}
函数InternetGetFile在单独的线程中调用,起新线程的动作在“下载”按钮点击事件中进行,代码如下:
void CDownloadProgressDlg::OnDownload()
{
// TODO: Add your control notification handler code here
CString url,filename;
GetDlgItemText(IDC_FILE_URL,url);
GetDlgItemText(IDC_LOCAL_DIRECTORY,filename);
if(url.IsEmpty())
{
AfxMessageBox("请输入Internet文件的URL!");
return;
}
if(filename.IsEmpty())
{
AfxMessageBox("请输入需要保存的文件路径!");
return;
}
//下面代码我要解释一下,见下文
DOWNINFO* pDownInfo=new DOWNINFO;
pDownInfo->hWnd=m_hWnd;
pDownInfo->url=url;
pDownInfo->filename=filename;
//GetDlgItem(IDC_DOWNLOAD)->EnableWindow(FALSE);
//GetDlgItem(IDOK)->EnableWindow(FALSE);
AfxBeginThread(DownProc,(LPVOID)pDownInfo);
}
上面函数中的DOWNINFO也是一个自定义结构体,用以向新线程传递句柄、URL和文件名。定义如下:
struct DOWNINFO
{
HWND hWnd;
CString url;
CString filename;
};
DownProc是个回调函数,它的函数结构和参数表系统已经为我们定义好。函数内容如下:
UINT CDownloadProgressDlg::DownProc(LPVOID pDownInfo)
{
HWND hWnd=((DOWNINFO*)pDownInfo)->hWnd;
CString url,filename;
url=((DOWNINFO*)pDownInfo)->url;
filename=((DOWNINFO*)pDownInfo)->filename;
if(InternetGetFile(hWnd,url,filename)==0)
{
//AfxMessageBox("下载成功!");
//g_nAbort=TRUE;
return 1;
}
else
{
AfxMessageBox("下载失败!");
return 0;
}
}
回顾本例程,我们的代码并没有用到计时器去显示进度,而是每下载一定字节数就向窗口发送自定义消息来让进度条显示进度,所以做了实时性和准确性。文中代码在VC6.0 + Win XP中调试通过,如有不妥之处,欢迎批评指正。
- 利用WinInet和多线程实现实时显示的下载进度条
- [转]关于VC下多线程和进度条实时显示
- 利用WinInet下载文件
- 利用多线程让没有窗口的程序显示进度条
- 使用wininet实现网络资源的下载
- 多线程下载更新包并显示进度条
- 利用AsyncHttpClient实现图片的上传与下载+进度条
- MFC 用进度条在状态栏显示某个按钮响应函数的过程,并用多线程实时更新
- 利用WinInet下载指定URL
- 利用WinInet下载指定URL
- asihttprequest下载例子,集进度条和字节数显示,多线程异步下载,断点续传,解压缩
- VC中进度条实时显示的解决方法
- 多线程下载和断点续传和进度条
- VC进度条实时显示
- VC进度条实时显示
- 安卓实训第七天---多线程下载实现(进度条)
- 利用Ajax生成ProgressBar:实现同类大批量数据批量生成Html,并实时显示进度条,可查看处理日志
- 使用WinINet实现HTTP下载
- YouMonitor.Us功能FAQ
- ASP.NET的环境安装
- Linux操作系统Vmstat命令列出的属性详解
- ASP.NET的环境安装
- ALTER TABLE语法--mysql
- 利用WinInet和多线程实现实时显示的下载进度条
- 在Linux中增加swap空间
- 于细微处见品质-YouMonitor.Us报表
- Linux性能分析工具(vmstat,iostat,sar)
- asp.net 页面事件:顺序与回传
- 如何得到 .NET Framework 安装的文件夹?
- .NET中的强名称机制
- 35岁成功人的12条黄金法则
- 有人机交互能力的排列组合算法(C++版)