urlmon.dll中有一个用于下载的API,MSDN中的定义如下:

HRESULT URLDownloadToFile(      
       LPUNKNOWN pCaller,
       LPCTSTR szURL,
      LPCTSTR szFileName,
       DWORD dwReserved,
       LPBINDSTATUSCALLBACK lpfnCB
);

Delphi的UrlMon.pas中有它的Pascal声明:

function URLDownloadToFile(      
       pCaller: IUnKnown,
      szURL: PAnsiChar,
       szFileName: PAnsiChar,
       dwReserved: DWORD,
       lpfnCB: IBindStatusCallBack;
    );HRESULT;stdcall;

szURL是要下载的文件的URL地址,szFileName是另存文件名,dwReserved是保留参数,传递0。如果不需要进度提示的话,调用这个函数很简单。比如要下载http://218.95.47.224/page/jxzy/XSZB/web/fourteens/Music/qili.mp3 这首歌,并保存为D:\ Music\七里香.mp3,就可以这样调用:

URLDownloadToFile(nil,'http://218.95.47.224/page/jxzy/XSZB/web/fourteens/Music/qili.mp3 ','D:\ Music\七里香.mp3',0,nil);

不过这样做的缺点是没有进度提示,而且会阻塞调用线程。如果要获得进度提示就要用到最后一个参数lpfnCB了,它是一个接口类型IBindStatusCallBack,定义如下:

IBindStatusCallback = interface
     ['{79eac9c1-baf9-11ce-8c82-00aa004ba90b}']
    function OnStartBinding(dwReserved: DWORD; pib: IBinding): HResult; stdcall;
    function GetPriority(out nPriority): HResult; stdcall;
    function OnLowResource(reserved: DWORD): HResult; stdcall;
    function OnProgress(ulProgress, ulProgressMax, ulStatusCode: ULONG;
       szStatusText: LPCWSTR): HResult; stdcall;
    function OnStopBinding(hresult: HResult; szError: LPCWSTR): HResult; stdcall;
    function GetBindInfo(out grfBINDF: DWORD; var bindinfo: TBindInfo): HResult; stdcall;
    function OnDataAvailable(grfBSCF: DWORD; dwSize: DWORD; formatetc: PFormatEtc;
       stgmed: PStgMedium): HResult; stdcall;
    function OnObjectAvailable(const iid: TGUID; punk: IUnknown): HResult; stdcall;
end;

进度提示就靠这个接口的OnProgress方法了。我们可以定义一个实现 IBindStatusCallback 接口的类,只处理一下OnProgress方法就可以了,其它方法咱啥都不做,就返回S_OK。下面简要说一下OnProgress:

ulProgress :当前进度值
ulProgressMax :总进度
ulStatusCode: 状态值,是tagBINDSTATUS枚举。表明正在寻找资源啊,正在连接啊这些状态。具体请查看MSDN,我们这里不需要关心它
szStatusText:状态字符串,咱也不关心它

所以我们用百分比来表示进度的话就是FloatToStr(ulProgress*100/ulProgressMax)+'/%',简单吧。如果要在下载完成前取消任务,可以在OnProgress中返回E_ABORT。
我把UrlDownloadToFile及其进度提示功能都封装进了一个线程类中,这个类的源码如下:

{ Delphi File Download Thread Class , Copyright (c) Zhou Zuoji }

unit FileDownLoadThread;

interface

uses
     Classes,
     SysUtils,
     Windows,
     ActiveX,
     UrlMon;

const
     S_ABORT = HRESULT($80004004);
    
type
     TFileDownLoadThread = class;
    
     TDownLoadProcessEvent = procedure(Sender:TFileDownLoadThread;Progress, ProgressMax:Cardinal) of object;
     TDownLoadCompleteEvent = procedure(Sender:TFileDownLoadThread) of object ;
     TDownLoadFailEvent = procedure(Sender:TFileDownLoadThread;Reason:LongInt) of object ;

TDownLoadMonitor = class( TInterfacedObject, IBindStatusCallback )
     private
         FShouldAbort: Boolean;
         FThread:TFileDownLoadThread;
     protected
        function OnStartBinding( dwReserved: DWORD; pib: IBinding ): HResult; stdcall;
        function GetPriority( out nPriority ): HResult; stdcall;
        function OnLowResource( reserved: DWORD ): HResult; stdcall;
        function OnProgress( ulProgress, ulProgressMax, ulStatusCode: ULONG;
             szStatusText: LPCWSTR): HResult; stdcall;
        function OnStopBinding( hresult: HResult; szError: LPCWSTR ): HResult; stdcall;
        function GetBindInfo( out grfBINDF: DWORD; var bindinfo: TBindInfo ): HResult; stdcall;
        function OnDataAvailable( grfBSCF: DWORD; dwSize: DWORD; formatetc: PFormatEtc;
             stgmed: PStgMedium ): HResult; stdcall;
        function OnObjectAvailable( const iid: TGUID; punk: IUnknown ): HResult; stdcall;
     public
         constructor Create(AThread:TFileDownLoadThread);
         property ShouldAbort: Boolean read FShouldAbort write FShouldAbort;
    end;

TFileDownLoadThread = class( TThread )
     private
         FSourceURL: string;
         FSaveFileName: string;
         FProgress,FProgressMax:Cardinal;
         FOnProcess: TDownLoadProcessEvent;
         FOnComplete: TDownLoadCompleteEvent;
         FOnFail: TDownLoadFailEvent;
         FMonitor: TDownLoadMonitor;
     protected
        procedure Execute; override;
        procedure UpdateProgress(Progress, ProgressMax, StatusCode: Cardinal; StatusText:string);
        procedure DoUpdateUI;
     public
         constructor Create( ASrcURL, ASaveFileName: string; AProgressEvent:TDownLoadProcessEvent = nil;
           ACompleteEvent:TDownLoadCompleteEvent = nil;AFailEvent:TDownLoadFailEvent=nil;CreateSuspended: Boolean=False );
         property SourceURL: string read FSourceURL;
         property SaveFileName: string read FSaveFileName;
         property OnProcess: TDownLoadProcessEvent read FOnProcess write FOnProcess;
         property OnComplete: TDownLoadCompleteEvent read FOnComplete write FOnComplete;
         property OnFail: TDownLoadFailEvent read FOnFail write FOnFail;
    end;

implementation

constructor TDownLoadMonitor.Create(AThread: TFileDownLoadThread);
begin
     inherited Create;
     FThread:=AThread;
     FShouldAbort:=False;
end;

function TDownLoadMonitor.GetBindInfo( out grfBINDF: DWORD; var bindinfo: TBindInfo ): HResult;
begin
     result := S_OK;
end;

function TDownLoadMonitor.GetPriority( out nPriority ): HResult;
begin
     Result := S_OK;
end;

function TDownLoadMonitor.OnDataAvailable( grfBSCF, dwSize: DWORD; formatetc: PFormatEtc; stgmed: PStgMedium ): HResult;
begin
     Result := S_OK;
end;

function TDownLoadMonitor.OnLowResource( reserved: DWORD ): HResult;
begin
     Result := S_OK;
end;

function TDownLoadMonitor.OnObjectAvailable( const iid: TGUID; punk: IInterface ): HResult;
begin
     Result := S_OK;
end;

function TDownLoadMonitor.OnProgress( ulProgress, ulProgressMax, ulStatusCode: ULONG; szStatusText: LPCWSTR ): HResult;
begin
    if FThread<>nil then
         FThread.UpdateProgress(ulProgress,ulProgressMax,ulStatusCode,'');
    if FShouldAbort then
         Result := E_ABORT
    else
         Result := S_OK;
end;

function TDownLoadMonitor.OnStartBinding( dwReserved: DWORD; pib: IBinding ): HResult;
begin
     Result := S_OK;
end;

function TDownLoadMonitor.OnStopBinding( hresult: HResult; szError: LPCWSTR ): HResult;
begin
     Result := S_OK;
end;
{ TFileDownLoadThread }

constructor TFileDownLoadThread.Create( ASrcURL, ASaveFileName: string;AProgressEvent:TDownLoadProcessEvent ;
           ACompleteEvent:TDownLoadCompleteEvent;AFailEvent:TDownLoadFailEvent; CreateSuspended: Boolean );
begin
    if (@AProgressEvent=nil) or (@ACompleteEvent=nil) or (@AFailEvent=nil) then
         CreateSuspended:=True;
     inherited Create( CreateSuspended );
     FSourceURL:=ASrcURL;
     FSaveFileName:=ASaveFileName;
     FOnProcess:=AProgressEvent;
     FOnComplete:=ACompleteEvent;
     FOnFail:=AFailEvent;
end;

procedure TFileDownLoadThread.DoUpdateUI;
begin
     if Assigned(FOnProcess) then
         FOnProcess(Self,FProgress,FProgressMax);
end;

procedure TFileDownLoadThread.Execute;
var
     DownRet:HRESULT;
begin
     inherited;
     FMonitor:=TDownLoadMonitor.Create(Self);
     DownRet:= URLDownloadToFile( nil, PAnsiChar( FSourceURL ), PAnsiChar( FSaveFileName ), 0,FMonitor as IBindStatusCallback);
    if DownRet=S_OK then
    begin
        if Assigned(FOnComplete) then
             FOnComplete(Self);
    end
    else
    begin
        if Assigned(FOnFail) then
             FOnFail(Self,DownRet);
    end;
     FMonitor:=nil;
end;

procedure TFileDownLoadThread.UpdateProgress(Progress, ProgressMax, StatusCode: Cardinal; StatusText: string);
begin
     FProgress:=Progress;
     FProgressMax:=ProgressMax;
     Synchronize(DoUpdateUI);
    if Terminated then
         FMonitor.ShouldAbort:=True;
end;

end.

Delphi编写下载程序:UrlDownloadToFile的进度提示的更多相关文章

  1. 转 : 用Delphi编写安装程序

    http://www.okbase.net/doc/details/931  还没有亲自验证过,仅收藏 当你完成一个应用软件的开发后,那么你还需要为该软件做一个规范化的安装程序,这是程序设计的最后一步 ...

  2. 分享一次C#调用Delphi编写Dll程序

    1.前言: 最近接手了一个项目需要和Delphi语言编写的一个系统进行一些接口的对接,数据在传输过程中采用Des加密方式,因为Delphi 平台的加密方式和C#平台的加密方式不互通,所以采用的方式是C ...

  3. python中如何使用requests模块下载文件并获取进度提示?

    Reference: https://www.zhihu.com/question/41132103 #!/usr/bin/env python3 import requests from conte ...

  4. python使用requests模块下载文件并获取进度提示

    一.概述 使用python3写了一个获取某网站文件的小脚本,使用了requests模块的get方法得到内容,然后通过文件读写的方式保存到硬盘同时需要实现下载进度的显示 二.代码实现 安装模块 pip3 ...

  5. DELPHI编写服务程序总结(在系统服务和桌面程序之间共享内存,在服务中使用COM组件)

    DELPHI编写服务程序总结 一.服务程序和桌面程序的区别 Windows 2000/XP/2003等支持一种叫做“系统服务程序”的进程,系统服务和桌面程序的区别是:系统服务不用登陆系统即可运行:系统 ...

  6. 利用Delphi编写Socket通信程序

    一.Delphi与Socket 计算机网络是由一系列网络通信协议组成的,其中的核心协议是传输层的TCP/IP和UDP协议.TCP是面向连接的,通信双方保持一条通路,好比目前的电话线,使用telnet登 ...

  7. 用Eclipse编写Android程序的代码提示功能

    用Eclipse编写Android程序的代码提示功能主要是在java和xml文件中,有时候会失效,默认的提示功能有限. 1)java文件自动提示     Window->Preferences- ...

  8. DELPHI编写服务程序总结

    DELPHI编写服务程序总结 一.服务程序和桌面程序的区别 Windows 2000/XP/2003等支持一种叫做“系统服务程序”的进程,系统服务和桌面程序的区别是:系统服务不用登陆系统即可运行:系统 ...

  9. Microsemi Libero使用技巧——使用命令行模式下载程序

    前言 在工程代码编译完成之后,如果需要给某个芯片下载程序时,或者是工厂量产烧录程序时,我们不需要把整个工程文件给别人,而只需要把生成的下载文件给别人,然后使用FlashPro就可以单独下载程序文件了. ...

随机推荐

  1. iOS之美: UIView 与 UIWindow之间的关系

    转自:http://leopard168.blog.163.com/blog/static/168471844201381584533466/ 面对iOS初学者,总会被问到一些不常被关注的问题,比如: ...

  2. Java类的实例化的初始化过程

    A a = new A(); new 创建对象过程: 1.类加载     代码验证 2.给对象在内存(堆)中分配空间(给属性赋值): 3.属性赋默认值: byte,short.int,long -&g ...

  3. 使用nio实现web服务器

    package com.nio; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocket ...

  4. python操作excel之 模块 xlrd (详解)

    二.使用介绍 1.导入模块 import xlrd 2.打开Excel文件读取数据 data = xlrd.open_workbook('excelFile.xls') 3.使用技巧 获取一个工作表 ...

  5. Makefile 11——支持头文件目录指定

    现在,是时候在对应目录放入对应文件了: /× foo.h */ #ifndef __FOO_H #define __FOO_H void foo(void) #endif/*__FOO_H*/ /* ...

  6. 单调栈poj2796

    题意:给你一段区间,需要你求出(在这段区间之类的最小值*这段区间所有元素之和)的最大值...... 例如: 6 3 1 6 4 5 2 以4为最小值,向左右延伸,6 4 5  值为60....... ...

  7. 一款基于jQuery的带文字标题上下切换焦点图

    今天给大家分享一款很实用的jQuery焦点图插件,它的最大特点就是使用非常方便,而且实现相对比较简单.焦点图的图片下方悬浮文字链接,鼠标滑过文字时即可切换至相应的图片,在图片切换的过程中出现淡入淡出的 ...

  8. 脚本中出现“+ $'\r' : command not found

    脚本中的部分应该是从doc直接拷过来的,造成回车符“\r”出现问题 通过将脚本内容在linux下拷贝一次,就解决了这个问题!

  9. 关于Linux网卡调优之:RPS (Receive Packet Steering)

    昨天在查LVS调度均衡性问题时,最终确定是 persistence_timeout 参数会使用IP哈希.目的是为了保证长连接,即一定时间内访问到的是同一台机器.而我们内部系统,由于出口IP相对单一,所 ...

  10. 详解 Go 语言中的 time.Duration 类型

    swardsman详解 Go 语言中的 time.Duration 类型swardsman · 2018-03-17 23:10:54 · 5448 次点击 · 预计阅读时间 5 分钟 · 31分钟之 ...