需要用到的API函数名字为 URLDownloadToFile 此函数在UrlMon单元中的声明如下:
const
UrlMonLib = 'URLMON.DLL';
function URLDownloadToFile; external UrlMonLib name 'URLDownloadToFileA';
function URLDownloadToFile(Caller: IUnknown; URL: PChar; FileName: PChar; Reserved: DWORD; StatusCB: IBindStatusCallback): HResult; stdcall;
关于其中的参数用意大家可以直接访问 http://msdn.microsoft.com/library/default.asp?url=/workshop/networking/moniker/reference/functions/urldownloadtofile.asp 来得到解释.
下面我们将获取该函数的下载进度
实现 IBindStatusCallback 接口即可, 该接口在 UrlMon单元中的具体声明:
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;
接下来我们所要完成的任务就是写一个类来实现 IBindStatusCallback 接口,请看下面
unit BindStatusCallback;
interface
uses SysUtils, Windows, UrlMon, ActiveX;
type
TNotifyDownloading = procedure (FileName: PChar; ulProgress, ulProgressMax,
ulStatusCode: ULONG; szStatusText: LPCWSTR) of object;
TBindStatusCallback = class(TObject, IBindStatusCallback)
protected
FRefCount: Integer;
FNotifyDownloading: TNotifyDownloading;
function QueryInterface(const IID: TGUID; out Obj): Integer; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
FileName: string;
property OnDownloading: TNotifyDownloading read FNotifyDownloading write FNotifyDownloading;
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;
implementation
{ TBindStatusCallback }
function TBindStatusCallback.QueryInterface(const IID: TGUID;
out Obj): Integer;
begin
if GetInterface(IID, Obj) then Result := S_OK
else Result := E_NOINTERFACE;
end;
function TBindStatusCallback._AddRef: Integer;
begin
Inc(FRefCount);
Result := FRefCount;
end;
function TBindStatusCallback._Release: Integer;
begin
Dec(FRefCount);
Result := FRefCount;
end;
function TBindStatusCallback.GetBindInfo(out grfBINDF: DWORD;
var bindinfo: TBindInfo): HResult;
begin
Result := E_NOTIMPL;
end;
function TBindStatusCallback.GetPriority(out nPriority): HResult;
begin
Result := E_NOTIMPL;
end;
function TBindStatusCallback.OnDataAvailable(grfBSCF, dwSize: DWORD;
formatetc: PFormatEtc; stgmed: PStgMedium): HResult;
begin
Result := E_NOTIMPL;
end;
function TBindStatusCallback.OnLowResource(reserved: DWORD): HResult;
begin
Result := E_NOTIMPL;
end;
function TBindStatusCallback.OnObjectAvailable(const iid: TGUID;
punk: IUnknown): HResult;
begin
Result := E_NOTIMPL;
end;
function TBindStatusCallback.OnStartBinding(dwReserved: DWORD;
pib: IBinding): HResult;
begin
Result := E_NOTIMPL;
end;
function TBindStatusCallback.OnStopBinding(hresult: HResult;
szError: LPCWSTR): HResult;
begin
Result := E_NOTIMPL;
end;
function TBindStatusCallback.OnProgress(ulProgress, ulProgressMax,
ulStatusCode: ULONG; szStatusText: LPCWSTR): HResult;
begin
if (Assigned(FNotifyDownloading)) then
FNotifyDownloading(Pchar(FileName), ulProgress, ulProgressMax,
ulStatusCode, szStatusText);
Result := S_OK;
end;
end.
大家可能注意到了怎么多了个 FNotifyDownloading 事件, 没错, 这个事实是用来实现进度回调的.只需要您的事件类型声明为
TNotifyDownloading = procedure (FileName: PChar; ulProgress, ulProgressMax,
ulStatusCode: ULONG; szStatusText: LPCWSTR) of object;
就可以实现进度回调.
下面就进入正式应用了
首先声明一个TBindStatusCallback类型的变量(这里设定为 BSC)然后创建它.
function Download(Url: Pchar; FileName: Pchar; BSC: TBindStatusCallback): Boolean;
begin
result := (UrlDownloadToFile(nil, Url, FileName, 0, BSC) = S_OK);
end;
......
var BSC: TBindStatusCallback;
begin
BSC:=TBindStatusCallback.Create;
BSC.OnDownloading := Self.OnDownloading;
if (Download('http://www.jxmarket.com/building.exe', 'c:\building.exe', BSC)) then
...下载成功
else
...下载失败
end;
procedure OnDownloading(FileName: PChar; ulProgress, ulProgressMax,
ulStatusCode: ULONG; szStatusText: LPCWSTR);
begin
进度在此显示....
end;
const
UrlMonLib = 'URLMON.DLL';
function URLDownloadToFile; external UrlMonLib name 'URLDownloadToFileA';
function URLDownloadToFile(Caller: IUnknown; URL: PChar; FileName: PChar; Reserved: DWORD; StatusCB: IBindStatusCallback): HResult; stdcall;
关于其中的参数用意大家可以直接访问 http://msdn.microsoft.com/library/default.asp?url=/workshop/networking/moniker/reference/functions/urldownloadtofile.asp 来得到解释.
下面我们将获取该函数的下载进度
实现 IBindStatusCallback 接口即可, 该接口在 UrlMon单元中的具体声明:
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;
接下来我们所要完成的任务就是写一个类来实现 IBindStatusCallback 接口,请看下面
unit BindStatusCallback;
interface
uses SysUtils, Windows, UrlMon, ActiveX;
type
TNotifyDownloading = procedure (FileName: PChar; ulProgress, ulProgressMax,
ulStatusCode: ULONG; szStatusText: LPCWSTR) of object;
TBindStatusCallback = class(TObject, IBindStatusCallback)
protected
FRefCount: Integer;
FNotifyDownloading: TNotifyDownloading;
function QueryInterface(const IID: TGUID; out Obj): Integer; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
FileName: string;
property OnDownloading: TNotifyDownloading read FNotifyDownloading write FNotifyDownloading;
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;
implementation
{ TBindStatusCallback }
function TBindStatusCallback.QueryInterface(const IID: TGUID;
out Obj): Integer;
begin
if GetInterface(IID, Obj) then Result := S_OK
else Result := E_NOINTERFACE;
end;
function TBindStatusCallback._AddRef: Integer;
begin
Inc(FRefCount);
Result := FRefCount;
end;
function TBindStatusCallback._Release: Integer;
begin
Dec(FRefCount);
Result := FRefCount;
end;
function TBindStatusCallback.GetBindInfo(out grfBINDF: DWORD;
var bindinfo: TBindInfo): HResult;
begin
Result := E_NOTIMPL;
end;
function TBindStatusCallback.GetPriority(out nPriority): HResult;
begin
Result := E_NOTIMPL;
end;
function TBindStatusCallback.OnDataAvailable(grfBSCF, dwSize: DWORD;
formatetc: PFormatEtc; stgmed: PStgMedium): HResult;
begin
Result := E_NOTIMPL;
end;
function TBindStatusCallback.OnLowResource(reserved: DWORD): HResult;
begin
Result := E_NOTIMPL;
end;
function TBindStatusCallback.OnObjectAvailable(const iid: TGUID;
punk: IUnknown): HResult;
begin
Result := E_NOTIMPL;
end;
function TBindStatusCallback.OnStartBinding(dwReserved: DWORD;
pib: IBinding): HResult;
begin
Result := E_NOTIMPL;
end;
function TBindStatusCallback.OnStopBinding(hresult: HResult;
szError: LPCWSTR): HResult;
begin
Result := E_NOTIMPL;
end;
function TBindStatusCallback.OnProgress(ulProgress, ulProgressMax,
ulStatusCode: ULONG; szStatusText: LPCWSTR): HResult;
begin
if (Assigned(FNotifyDownloading)) then
FNotifyDownloading(Pchar(FileName), ulProgress, ulProgressMax,
ulStatusCode, szStatusText);
Result := S_OK;
end;
end.
大家可能注意到了怎么多了个 FNotifyDownloading 事件, 没错, 这个事实是用来实现进度回调的.只需要您的事件类型声明为
TNotifyDownloading = procedure (FileName: PChar; ulProgress, ulProgressMax,
ulStatusCode: ULONG; szStatusText: LPCWSTR) of object;
就可以实现进度回调.
下面就进入正式应用了
首先声明一个TBindStatusCallback类型的变量(这里设定为 BSC)然后创建它.
function Download(Url: Pchar; FileName: Pchar; BSC: TBindStatusCallback): Boolean;
begin
result := (UrlDownloadToFile(nil, Url, FileName, 0, BSC) = S_OK);
end;
......
var BSC: TBindStatusCallback;
begin
BSC:=TBindStatusCallback.Create;
BSC.OnDownloading := Self.OnDownloading;
if (Download('http://www.jxmarket.com/building.exe', 'c:\building.exe', BSC)) then
...下载成功
else
...下载失败
end;
procedure OnDownloading(FileName: PChar; ulProgress, ulProgressMax,
ulStatusCode: ULONG; szStatusText: LPCWSTR);
begin
进度在此显示....
end;