爱元元的哥哥请回答问题。 (50分)

  • 主题发起人 主题发起人 lhl20000
  • 开始时间 开始时间
L

lhl20000

Unregistered / Unconfirmed
GUEST, unregistred user!
关于:"从网络中下载一个指定文件"

to 爱元元的哥哥
能否将程序写全,并且加点注释。
写明用法。
--------------------------------------------------------------------------
// 司马华鹏

frmUpdate = class(TForm,IBindStatusCallback)
ImgTop: TImage;
LblTop: TLabel;
SpdBtnClose: TSpeedButton;
Bevel1: TBevel;
plStatus: TPanel;
plInfo: TPanel;
btnCancel: TFlatSpeedButton;
tmrUdapte: TTimer;
plProgress: TPanel;
procedure tmrUdapteTimer(Sender: TObject);
procedure btnCancelClick(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure ImgTopMouseMove(Sender: TObject; Shift: TShiftState; X,Y:
Integer);
procedure SpdBtnCloseClick(Sender: TObject);
private
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;
function GetHTMLFile(URL, FileName: string): HRESULT;
public
{ Public declarations }
end;

//------------------------------------------------------------------------
------
function TfrmUpdate.GetHTMLFile( URL , FileName : string) : HRESULT;
var
status : IBindStatusCallback ;
begin
status := IBindStatusCallback(self);
result := UrlDownLoadToFile(nil, pChar( URL ) ,pChar( FileName ),0
,Status );
end;

//------------------------------------------------------------------------
------
function TfrmUpdate.GetBindInfo(out grfBINDF: DWORD;
var bindinfo: TBindInfo): HResult;
begin
result := E_NOTIMPL;
end;

//------------------------------------------------------------------------
------
function TfrmUpdate.GetPriority(out nPriority): HResult;
begin
result := E_NOTIMPL;
end;

//------------------------------------------------------------------------
------
function TfrmUpdate.OnDataAvailable(grfBSCF, dwSize: DWORD;
formatetc: PFormatEtc; stgmed: PStgMedium): HResult;
begin
result := E_NOTIMPL;
end;

//------------------------------------------------------------------------
------
function TfrmUpdate.OnLowResource(reserved: DWORD): HResult;
begin
result := E_NOTIMPL;
end;

//------------------------------------------------------------------------
------
function TfrmUpdate.OnObjectAvailable(const iid: TGUID;
punk: IInterface): HResult;
begin
result := E_NOTIMPL;
end;

//------------------------------------------------------------------------
------
function TfrmUpdate.OnStartBinding(dwReserved: DWORD;
pib: IBinding): HResult;
begin
result := E_NOTIMPL;
end;

//------------------------------------------------------------------------
------
function TfrmUpdate.OnStopBinding(hresult: HResult;
szError: LPCWSTR): HResult;
begin
result := E_NOTIMPL;
end;

 
给点资料你,呵呵

This is a simple class based on IBindStatusCallback. It's placed
in a separate unit. For demo purposes, OnProgress handler is implemented,
so that when download is started, progress will be shown in Form1 caption.
(I assumed you have Unit1/Form1).

1. Create new unit and overwrite it with this:


unit BindStatusCallback;
// Implementation of TBindStatusCallback

interface

uses SysUtils, Windows, UrlMon, ActiveX;

type TBindStatusCallback = class(TObject, IBindStatusCallback)
protected
FRefCount: Integer;
// IUnknown
function QueryInterface(const IID: TGUID; out Obj): Integer; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
// IBindStatusCallback
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 }

uses Unit1; // where Form1 is

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
// Do something on main form- for example, show progress:
Form1.Caption:='Downloaded: '+IntToStr(ulProgress) +' bytes';
Result := S_OK;
end;


end.



-------------------------------------------------------------------------------

2. In Unit1 :


uses ...., BindStatusCallback, UrlMon;

type
TForm1 = class(TForm)

// ... blah, blah ...

end;

var
Form1: TForm1;
bsc: TBindStatusCallback; // in unit BindStatusCallback

// ... your code ...

procedure TForm1.FormCreate(Sender: TObject);
begin
bsc:=TBindStatusCallback.Create;
end;

// ... your code ...

// DEMO:
//----------
procedure TForm1.Button1Click(Sender: TObject);
begin
URLDownloadToFile(nil,
'http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_20349921.html',
'c:/ee.html', 0 , bsc);
end;
 
呵呵,在著名的IE&Delphi上有IEDownload组件,你可以看看它的代码!
 
//***********************************************************
// IEDownload ver 1.00 (Oct. 15, 2001) *
// *
// For Delphi 5 & 6 *
// Freeware Component *
// by *
// Per Linds?Larsen *
// per.lindsoe@larsen.mail.dk *
// *
// Documentation and updated versions: *
// *
// http://www.euromind.com/iedelphi *
//***********************************************************

unit IEDownload;

interface

uses
dialogs, ActiveX, Registry, Contnrs, Extctrls, wininet, Windows, UrlMon, SysUtils, Classes;


const
CP_THREAD_ACP = 3;
CP_SYMBOL = 42;

BINDINFOF_URLENCODESTGMEDDATA = $1;
BINDINFOF_URLENCODEDEXTRAINFO = $2;

HTTP_QUERY_FLAG_REQUEST_HEADERS = $80000000;
HTTP_QUERY_FLAG_SYSTEMTIME = $40000000;
HTTP_QUERY_FLAG_NUMBER = $20000000;
HTTP_QUERY_FLAG_COALESCE = $10000000;
HTTP_QUERY_MODIFIER_FLAGS_MASK = (HTTP_QUERY_FLAG_REQUEST_HEADERS
or HTTP_QUERY_FLAG_SYSTEMTIME
or HTTP_QUERY_FLAG_NUMBER
or HTTP_QUERY_FLAG_COALESCE
);

RESUME_RESPONSE_RESUME = 0;
RESUME_RESPONSE_OVERWRITE = 1;
RESUME_RESPONSE_CANCEL = 2;


type

TInfo = record
Sender: TObject;
Url: PwideChar;
TimeOut: Integer;
FileName: string;
PostData: string;
PutFileName: string;
AdditionalHeader: TStrings;
PassWord: string;
Username: string;
CustomVerb: string;
ExtraInfo: string;
Descriptor: string;
UserAgent: string;
RangeBegin: Integer;
RangeEnd: Integer;
InheritHandle: Boolean;
BindVerbValue: Cardinal;
BindInfoValue: Cardinal;
UrlEncodeValue: Cardinal;
CodePageValue: Cardinal;
end;



{ Forward declaration }
TIEDownload = class;

TBSCB = class(TObject,
IUnknown,
IBindStatusCallback,
IHttpNegotiate,
IAuthenticate,
IHTTPSecurity)
private
{ Private declarations }
Info: TInfo;
OutputFile: TFileStream;
FBSCBTimer: TTimer;
FstartTime: TDatetime;
FTimedOut: Boolean;
FCancel: Boolean;
FBindCtx: IBindCtx;
FStream: IStream;
FMoniker: IMoniker;
FSender: TIEDownload;
FRedirect: Boolean;
FGlobalData: HGLOBAL;
FDataSize: Integer;
FTotalRead: Cardinal;
FDataAvailable: Integer;
{ Public declarations }
{IBindStatusCallBack methods}
function OnLowResource(reserved: DWORD): HResult; stdcall;
function OnProgress(ulProgress, ulProgressMax, ulStatusCode: ULONG;
szStatusText: LPCWSTR): HResult; stdcall;
function OnStartBinding(dwReserved: DWORD; pib: IBinding): HResult; stdcall;
function OnStopBinding(hresult: HResult; szError: LPCWSTR): HResult; stdcall;
function OnDataAvailable(grfBSCF: DWORD; dwSize: DWORD; formatetc: PFormatEtc;
stgmed: PStgMedium): HResult; stdcall;
function OnObjectAvailable(const iid: TGUID; punk: IUnknown): HResult; stdcall;
function GetPriority(out nPriority): HResult; stdcall;
function GetBindInfo(out grfBINDF: DWORD; var bindinfo: TBindInfo): HResult; stdcall;
{IHTTPNegotiate methods}
function OnResponse(dwResponseCode: DWORD; szResponseHeaders, szRequestHeaders: LPCWSTR;
out szAdditionalRequestHeaders: LPWSTR): HResult; stdcall;
function BeginningTransaction(szURL, szHeaders: LPCWSTR; dwReserved: DWORD;
out szAdditionalHeaders: LPWSTR): HResult; stdcall;
{IAuthenticate methods}
function Authenticate(var hwnd: HWnd; var szUserName, szPassWord: LPWSTR): HResult; stdcall;
{IWindowForbindingUI methods}
function GetWindow(const guidReason: TGUID; out hwnd): HResult; stdcall;
{IHttpSecurity methods}
function OnSecurityProblem(dwProblem: DWORD): HResult; stdcall;


constructor Create(DownloadInfo: TInfo);
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
function Download: HRESULT;
procedure ClearAll;
procedure TimerExpired(Sender: TObject);
public
Url: Pwidechar;
Stream: TStream;
Binding: IBinding;
ResponseCode: Cardinal;
function QueryInfo(dwOption: DWORD; var Info: TDateTime): Boolean; overload;
function QueryInfo(dwOption: DWORD; var Info: Cardinal): Boolean; overload;
function QueryInfo(dwOption: DWORD; var info: string): Boolean; overload;
function GetBindResult(out clsidProtocol: TCLSID; out dwResult: DWORD;
out szResult: POLEStr; dwReserved: DWORD): HResult;
destructor destroy; override;
end;


TOnProgressEvent = procedure(Sender: TBSCB; ulProgress, ulProgressMax, ulStatusCode: ULONG;
szStatusText: LPCWSTR; ElapsedTime, Speed, EstimatedTime: string) of object;
TAuthenticateEvent = function(Sender: TBSCB; var hwnd: HWnd; var szUserName, szPassWord: LPWSTR): HResult of object;
TBeginningTransactionEvent = function(Sender: TBSCB; szURL, szHeaders: LPCWSTR; dwReserved: DWORD;
out szAdditionalHeaders: LPWSTR): HResult of object;
TOnResponseEvent = function(Sender: TBSCB; dwResponseCode: DWORD; szResponseHeaders, szRequestHeaders: LPCWSTR;
out szAdditionalRequestHeaders: LPWSTR): HResult of object;
TOnDataEvent = procedure(Sender: TBSCB; var Buffer: PByte; var BufLength: Cardinal) of object;
TOnCompleteEvent = procedure(Sender: TBSCB; Stream: TStream; Result: HResult) of object;
TOnResumeEvent = procedure(Sender: TBSCB; Filename: string; var Action: DWORD) of object;
TGetWindowEvent = function(Sender: TBSCB; const guidReason: TGUID; out hwnd: LongWord): HResult of object;
TOnSecurityProblemEvent = function(Sender: TBSCB; dwProblem: DWORD): HResult of object;

TUrlEncodeOption = (PostData, ExtraInfo);
TUrlEncodeOptions = set of TUrlEncodeOption;

TBindInfoOption = (
Asynchronous, AsyncStorage, NoProgressiveRendering, OfflineOperation, GetNewestVersion,
NoWriteCache, NeedFile, PullData, IgnoreSecurityProblem, Resynchronize, Hyperlink,
No_UI, SilentOperation, Pragma_No_Cache, GetClassObject, Reserved_1, Free_Threaded,
Direct_Read, Forms_Submit, GetFromCache_If_Net_Fail, FromUrlmon, Fwd_Back, Reserved_2,
Reserved_3);

TBindInfoOptions = set of TBindInfoOption;

TCodePageOption = (Ansi, // default to ANSI code page
OEM, // // default to OEM code page
Mac, // default to MAC code page
ThreadsAnsi, // Current thread's ANSI code page
Symbol, // Symbol code page (42)
UTF7, // Translate using UTF-7
UTF8); // Translate using UTF-8

TSecurity = class(TPersistent)
private
FInheritHandle: Boolean;
FDescriptor: string;
published
property InheritHandle: boolean read FInheritHandle write FInheritHandle;
property Descriptor: string read FDescriptor write FDescriptor;
end;

TRange = class(TPersistent)
private
FRangeBegin: Integer;
FRangeEnd: Integer;
published
property RangeBegin: Integer read FRangeBegin write FRangeBegin;
property RangeEnd: Integer read FRangeEnd write FRangeEnd;
end;

TBindVerbOption = (Get, Post, Put, Custom);

TIEDownload = class(TComponent)
private
{ Private declarations }

FObjList: TObjectList;
FTimeOut: Integer;
FSecurity: TSecurity;
FRange: TRange;
FRefCount: Integer;
FCancel: Boolean;
FOnResume: TOnResumeEvent;
FOnData: TOnDataEvent;
FPostData: string;
FPutFileName: string;
FAdditionalHeader: Tstrings;
FPassword: string;
FUsername: string;
FExtraInfo: string;
FCustomVerb: string;
FUserAgent: string;
FBindVerbValue: Cardinal;
FBindInfoValue: Cardinal;
FCodePageValue: Cardinal;
FBindInfoOptions: TBindInfoOptions;
FBindVerbOption: TBindVerbOption;
FCodePageOption: TCodePageOption;
FUrlEncodeOptions: TUrlEncodeOptions;
FUrlEncodeValue: Cardinal;
FBeginningtransAction: TBeginningTransActionEvent;
FOnAuthenticate: TAuthenticateEvent;
FOnResponse: TOnResponseEvent;
FOnProgress: TOnProgressEvent;
FOnComplete: TOnCompleteEvent;
FGetWindow: TGetWindowEvent;
FOnSecurityProblem: TOnSecurityProblemEvent;
procedure SetAdditionalHeader(const Value: Tstrings);
protected
{Other Methods}
procedure SetBindInfoOptions(const Value: TBindInfoOptions);
procedure SetBindVerbOption(const Value: TBindVerbOption);
procedure SetCodePageOption(const Value: TCodePageOption);
procedure UpdateUrlEncodeValue;
procedure SetUrlEncodeOptions(const Value: TUrlEncodeOptions);
procedure FillInfo(var Info: TInfo);
procedure UpdateBindInfoValue;
public
{ Public declarations }
constructor create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Go(Url: string); overload;
procedure Go(Url, Fname: string); overload;
procedure Cancel(Item: TBSCB); overload;
procedure Cancel; overload;
published
property TimeOut: Integer read FTimeOut write FTimeOut;
property ExtraInfo: string read FExtraInfo write FExtraInfo;
property CustomVerb: string read FCustomVerb write FCustomVerb;
property Codepage: TCodepageOption read FCodepageOption write SetCodepageOption;
property Method: TBindVerbOption read FBindVerbOption write SetBindVerbOption;
property Options: TBindInfoOptions read FBindInfoOptions write SetBindInfoOptions;
property UrlEncode: TUrlEncodeOptions read FUrlEncodeOptions write FUrlEncodeOptions;
property Security: TSecurity read FSecurity write FSecurity;
property Range: TRange read FRange write FRange;
property Password: string read FPassword write FPassword;
property Username: string read FUsername write FUsername;
property PutFileName: string read FPutFileName write FPutFileName;
property AdditionalHeader: Tstrings read FAdditionalHeader write SetAdditionalHeader;
property PostData: string read FPostData write FPostData;
property UserAgent: string read FUserAgent write FUserAgent;

property OnProgress: TOnProgressEvent read FOnProgress write FOnProgress;
property OnResume: TOnresumeEvent read FOnResume write FOnResume;
property OnBeginningTransaction: TBeginningTransActionEvent read FBeginningTransAction write FBeginningTransAction;
property OnResponse: TOnResponseEvent read FOnResponse write FOnResponse;
property OnAuthenticate: TAuthenticateEvent read FOnAuthenticate write FOnAuthenticate;
property OnComplete: TOnCompleteEvent read FOnComplete write FOnComplete;
property OnData: TOnDataEvent read FOnData write FOnData;
property OnGetWindow: TGetWindowEvent read FGetwindow write FGetwindow;
property OnSecurityProblem: TOnSecurityProblemEvent read FOnSecurityProblem write FOnSecurityProblem;

{ Published declarations }
end;

procedure Register;
function BindStatusText(ulStatusCode: ULONG): string;
function ErrorText(errorCode: Integer): string;
function ResponseCodeText(ResponseCode: Integer): string;

implementation


function TBSCB.GetWindow(const guidReason: TGUID; out hwnd): HResult;
begin
if Assigned(FSender.FGetWindow) then Result :=
FSender.FGetWindow(self, guidReason, LongWord(hwnd)) else
Result := S_OK;
end;

function TBSCB.OnSecurityProblem(dwProblem: DWORD): HResult;
begin
if Assigned(FSender.FOnSecurityProblem) then Result :=
FSender.FOnSecurityProblem(self, dwProblem) else
Result := S_OK;
end;


function TBSCB.Authenticate(var hwnd: HWnd; var szUserName,
szPassWord: LPWSTR): HResult;
var
Len: Integer;
begin
Result := S_OK;
if Assigned(FSender.FOnAuthenticate) then Result :=
FSender.FOnAuthentiCate(self, hwnd, szUsername, szPassword) else
begin
if Info.Username <> '' then
begin
Len := Length(Info.Username);
szUsername := CoTaskMemAlloc(Len * 2);
MultiByteToWideChar(0, 0, Pointer(Info.Username), Len, szUsername, Len);
end else szUsername := nil;
if Info.Password <> '' then
begin
Len := Length(Info.Password);
szPassword := CoTaskMemAlloc(Len * 2);
MultiByteToWideChar(0, 0, Pointer(Info.Password), Len, szPassword, Len);
end else szPassword := nil;
end;
end;

function TBSCB.BeginningTransaction(szURL, szHeaders: LPCWSTR;
dwReserved: DWORD; out szAdditionalHeaders: LPWSTR): HResult;
var
sr: TSearchRec;
Action: Cardinal;
s: string;
Size: Longint;
ResumeSupported: Boolean;
x, Len: Integer;
begin
if FCancel or FSender.FCancel then
begin
Result := E_ABORT;
if Assigned(FSender.FOnComplete) then FSender.FOnComplete(Self, nil, Result);
exit;
end;
if Info.Useragent <> '' then S := 'User-agent: ' + Info.UserAgent + #13#10;
if (Info.FileName <> '') then begin

if FindFirst(Info.FileName, faAnyFile, sr) = 0 then
begin
Size := sr.Size;
FindClose(sr);
Info.RangeEnd := 0;
Action := 0;
if Assigned(FSender.OnResume) then
FSender.OnResume(Self, Info.Filename, Action);
case Action of
RESUME_RESPONSE_CANCEL:
begin
Result := E_ABORT;
exit;
end;
RESUME_RESPONSE_OVERWRITE: Info.RangeBegin := 0;
else
Info.RangeBegin := Size;
end;

end else
begin
Info.RangeBegin := 0;
Info.RangeEnd := 0;
end;
end;

if ((Info.RangeBegin <> 0) or (Info.RangeEnd <> 0)) then
begin

S := S + 'Range: bytes=' + IntToStr(Info.RangeBegin) + '-';
if Info.RangeEnd <> 0 then
S := S + InttoStr(Info.RangeEnd) + #13#10
else s := S + #13#10;

end;
if (Info.AdditionalHeader[0] <> '') then for x := 0 to Info.AdditionalHeader.Count - 1 do
S := S + info.additionalheader[x];
Len := Length(S);
szAdditionalheaders := CoTaskMemAlloc(Len * 2);
MultiByteToWideChar(0, 0, Pointer(S), Len,
szAdditionalheaders, Len);
if Assigned(FSender.FBeginningTransaction) then
Result := FSender.FBeginningTransaction(self, szUrl, szHeaders, dwReserved, szAdditionalHeaders) else
Result := S_OK;
FBSCBTimer := TTimer.Create(nil);
FBSCBTimer.OnTimer := TimerExpired;
FBSCBTimer.Interval := Info.TimeOut;
FBSCBTimer.Enabled := True;
FTimedOut := False;
end;


function TBSCB.OnResponse(dwResponseCode: DWORD; szResponseHeaders,
szRequestHeaders: LPCWSTR;
out szAdditionalRequestHeaders: LPWSTR): HResult;
var
Res: HResult;
len: Cardinal;
s: string;
begin
ResponseCode := dwResponseCode;
if QueryInfo(HTTP_QUERY_CONTENT_LENGTH, Len) and (Len = 0) then
begin
Res := S_OK;
if Assigned(FSender.FOnComplete) then FSender.FOnComplete(Self, nil, Res);
Result := E_ABORT;
end else
if (ResponseCode >= 400) and (ResponseCode < 500) or FCancel or FSender.FCancel then
begin
Result := E_ABORT;
if Assigned(FSender.FOnComplete) then FSender.FOnComplete(Self, nil, Result);
end
else
begin
if Assigned(FSender.FOnresponse) then Result :=
FSender.FOnResponse(self, dwResponseCode, szresponseHeaders, szRequestHeaders, szAdditionalRequestHeaders)
else
Result := S_OK;
if (Info.RangeBegin <> 0) and (Info.FileName <> '') then
begin
QueryInfo(HTTP_QUERY_ACCEPT_RANGES, S);
if (S = 'bytes') or (dwResponseCode = 206) then
begin
Outputfile := TFileStream.Create(Info.FileName, fmOpenReadWrite);
Outputfile.Seek(0, soFromEnd);
end else
begin
Outputfile := TFileStream.Create(Info.FileName, fmCreate);
Info.RangeBegin := 0;
end;
end else if Info.FileName <> '' then Outputfile := TFileStream.Create(Info.FileName, fmCreate);
end;
end;


function TBSCB.GetBindInfo(out grfBINDF: DWORD;
var bindinfo: TBindInfo): HResult;
var
PutFile: TFileStream;
Len: Integer;
begin
grfBINDF := Info.BindInfoValue;
with BindInfo do begin
cbSize := sizeof(TBINDINFO);
if FReDirect then
dwBindVerb := BINDVERB_GET else
dwBindVerb := Info.BindVerbValue;
grfBindInfoF := Info.UrlEncodeValue; //I don't think it is supported by Urlmon.dll yet
dwCodePage := Info.CodepageValue;
with SecurityAttributes do
begin
nLength := SizeOf(TSecurityAttributes);
bInheritHandle := Info.InheritHandle;
if Info.Descriptor <> '' then
lpSecurityDescriptor := Pchar(Info.Descriptor) else
lpSecurityDescriptor := nil;
end;
if Info.ExtraInfo <> '' then
begin
Len := Length(Info.ExtraInfo);
szExtraInfo := CoTaskMemAlloc(Len * 2);
MultiByteToWideChar(0, 0, Pointer(Info.ExtraInfo), Len, szExtraInfo, Len);
end else szExtraInfo := nil;
if (Info.BindVerbValue = BINDVERB_PUT) then
begin
PutFile := TFileStream.Create(Info.PutFileName, fmOpenRead);
putfile.Seek(0, 0);
FglobalData := GlobalAlloc(GPTR, PutFile.Size);
FDataSize := PutFile.Size;
putfile.ReadBuffer(Pointer(FGlobalData)^, Putfile.Size);
putfile.Free;
end;
if (Info.BindVerbValue = BINDVERB_POST) then
begin
FglobalData := GlobalAlloc(GPTR, Length(Info.Postdata) + 1);
FDataSize := Length(Info.PostData) + 1;
move(Info.Postdata[1], Pointer(FGlobalData)^, Length(Info.Postdata));
end;
if (Info.CustomVerb <> '') and (dwBindVerb = BINDVERB_CUSTOM) then
begin
Len := Length(Info.CustomVerb);
szCustomVerb := CoTaskMemAlloc(Len * 2);
MultiByteToWideChar(0, 0, Pointer(Info.CustomVerb), Len, szCustomVerb, Len);
end else szCustomVerb := nil;
Fillchar(stgmedData, 0, sizeof(STGMEDIUM));
cbStgmedData := FDataSize;
with StgmedData do
begin
if dwBindVerb = BINDVERB_GET
then Tymed := TYMED_NULL else
Tymed := TYMED_HGLOBAL; // this is the only medium urlmon supports right now
hGlobal := FGlobalData;
IUnknown(unkForRelease) := self;
end;
end;
Result := S_OK;
end;

function TBSCB.GetPriority(out nPriority): HResult;
begin
if FCancel or FSender.FCancel then binding.Abort;
Result := S_OK;
end;

function TBSCB.OnDataAvailable(grfBSCF, dwSize: DWORD;
formatetc: PFormatEtc; stgmed: PStgMedium): HResult;
var
Data: PByte;
BufL, dwRead, dwActuallyRead: Cardinal;
begin
If FStarttime=0 then FStarttime:=Now;
if FCancel or FSender.FCancel then binding.Abort else
begin
FBSCBTimer.enabled := False;
FBSCBTimer.enabled := true;
if (grfBSCF = grfBSCF or BSCF_FIRSTDATANOTIFICATION)
then
if (FStream = nil) and (stgmed.tymed = TYMED_ISTREAM)
then FStream := IStream(stgmed.stm);
dwRead := dwSize - FTotalRead;
dwActuallyRead := 0;
if (dwRead > 0) then
repeat
Data := AllocMem(dwRead + 1);
FStream.Read(Data, dwRead, @dwActuallyRead);
bufl := dwActuallyRead;
if Assigned(FSender.FOnData) then
begin
FSender.FOnData(self, Data, bufl);
end;
if info.filename <> '' then
Outputfile.WriteBuffer(Data^, bufl) else
Stream.WriteBuffer(Data^, bufl);
Inc(FTotalRead, dwActuallyRead);
FreeMem(data);
until dwActuallyRead = 0;
end;
Result := S_OK;
end;

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

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

function TBSCB.OnProgress(ulProgress, ulProgressMax, ulStatusCode: ULONG;
szStatusText: LPCWSTR): HResult;
var
Elapsed: string;
temp, _Speed: double;
Speed: string;
Remaining: string;
begin
if FCancel or FSender.FCancel then binding.Abort else
begin
if (ulStatusCode = BINDSTATUS_DOWNLOADINGDATA) and Assigned(FSender.FOnProgress) then
begin
if FStarttime <> 0 then Elapsed := TimeToStr(FStartTime - Now) else
Elapsed := '';
_Speed := ulProgress / (Now - FStarttime) * SecsPerDay * 1000;
Speed := FloatToStr(_Speed);
Speed := Copy(Speed, 1, Pos(Decimalseparator, Speed) + 2) + ' kb/sec';
if ulProgressMax <> 0 then
remaining := TimeToStr((ulProgressMax - ulProgress) / _speed * 1000 * SecsPerDay)
else
Remaining := '';
end;
FRedirect := (ulStatusCode = BINDSTATUS_REDIRECTING);
if Assigned(FSender.FOnProgress) then
FSender.FOnProgress(self, ulProgress + Info.RangeBegin, ulProgressMax + Info.RangeBegin, ulStatusCode, szStatusText,
Elapsed, Speed, Remaining);
end;
Result := S_OK;
end;

procedure TBSCB.TimerExpired(Sender: TObject);
begin
FTimedOut := TRUE;
Binding.Abort;
end;

function TBSCB.OnStartBinding(dwReserved: DWORD; pib: IBinding): HResult;
begin
if FCancel or FSender.FCancel then
begin
Result := E_FAIL;
if Assigned(FSender.FOnComplete) then FSender.FOnComplete(Self, nil, E_ABORT);
end else
begin
Binding := pib;
Result := S_OK;
end;
end;

function TBSCB.OnStopBinding(hresult: HResult; szError: LPCWSTR): HResult;
begin
Result := S_OK;
if FTimedOut then hResult := INET_E_CONNECTION_TIMEOUT;
if info.filename <> '' then
begin
Outputfile.Seek(0, 0);
if Assigned(FSender.FOnComplete) then FSender.FOnComplete(Self, Outputfile, hResult);
end
else
if Assigned(FSender.FOnComplete) then FSender.FOnComplete(Self, stream, hResult);
if (Info.Filename <> '') then
begin
Outputfile.Free;
Outputfile := nil;
end;
if Info.BindInfoValue = Info.BindInfoValue or BINDF_ASYNCHRONOUS then
FSender.FObjList.Remove(Self);
end;



constructor TBSCB.Create(DownloadInfo: TInfo);
begin
inherited Create;
FStarttime:=0;
if (Info.FileName = '') then Stream := TMemoryStream.Create;
info := DownloadInfo;
FSender := TIEDownload(Info.Sender);
Url := Info.Url;
binding := nil;
if not Succeeded(download) then free;
end;

function TBSCB.Download: HRESULT;
var
hr: HRESULT;
begin
FCancel := False;
Result := S_FALSE;
ClearAll;
hr := CreateURLMoniker(nil, URL, FMoniker);
if (hr <> S_OK) then
begin
if Assigned(FSender.FOnComplete) then FSender.FOnComplete(self, nil, hr);
exit;
end;
hr := CreateAsyncBindCtx(0, SELF, nil, FBindCtx);
if (hr <> S_OK) then
begin
if Assigned(FSender.FOnComplete) then FSender.FOnComplete(self, nil, hr);
exit;
end;
hr := IsValidUrl(FBindCtx, URL, 0);
if hr <> S_OK then
begin
if Assigned(FSender.FOnComplete) then FSender.FOnComplete(self, nil, MK_E_SYNTAX);
exit;
end;
hr := FMoniker.BindToStorage(FbindCtx, nil, IStream, fstream);
if (hr <> S_OK) and (hr <> MK_S_ASYNCHRONOUS) then
begin
if Assigned(FSender.FOnComplete) then FSender.FOnComplete(self, nil, hr);
exit;
end else
begin
Result := S_OK;
end;
end;

procedure TBSCB.ClearAll;
begin
binding := nil;
fmoniker := nil;
fbindctx := nil;
FGlobalData := 0;
FTotalRead := 0;
FDataAvailable := 0;
end;

destructor TBSCB.destroy;
begin
if FBSCBTimer <> nil then FBSCBTimer.Free;
if Outputfile <> nil then outputfile.Free;
info.AdditionalHeader.Free;
Stream.Free;
clearall;
inherited;
end;

function TBSCB._AddRef: Integer;
begin
Result := InterlockedIncrement(FSender.FRefCount);
end;

function TBSCB._Release: Integer;
begin
Result := InterlockedDecrement(Fsender.FRefCount);
if Result = 0 then Destroy;
end;

function TBSCB.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE;
end;



function TBSCB.QueryInfo(dwOption: DWORD; var Info: Cardinal): Boolean;
var
HttpInfo: IWinInetHttpInfo;
C: Cardinal;
BufferLength: Cardinal;
Reserved, dwFlags: Cardinal;
begin
Info := 0;
Httpinfo := Binding as IWinInetHttpInfo;
if Httpinfo <> nil then
begin
Reserved := 0;
dwFlags := 0;
BufferLength := SizeOf(Cardinal);
Result := not Boolean(httpInfo.QueryInfo(dwOption or HTTP_QUERY_FLAG_NUMBER,
@C, BufferLength, dwflags, reserved));
if Result then Info := C;
end else Result := FALSE;
httpinfo := nil;
end;

function TBSCB.QueryInfo(dwOption: DWORD; var info: string): Boolean;
var

buf: array[0..INTERNET_MAX_PATH_LENGTH] of char;
HttpInfo: IWinInetHttpInfo;
buflength, dwReserved, dwFlags: Cardinal;
begin
Info := '';
dwReserved := 0;
dwFlags := 0;
Httpinfo := Binding as IWinInetHttpInfo;
if Httpinfo <> nil then
begin
buflength := INTERNET_MAX_PATH_LENGTH + 1;
Result := not Boolean(Httpinfo.QueryInfo(dwOption, @buf, bufLength, dwFlags, dwReserved));
if Result then Info := Buf;
end else
Result := FALSE;
httpinfo := nil;
end;

function TBSCB.QueryInfo(dwOption: DWORD; var Info: TDateTime): Boolean;
var
HttpInfo: IWinInetHttpInfo;
SysTime: TSystemtime;
BufferLength: Cardinal;
Reserved, dwFlags: Cardinal;
begin
Info := 0;
Httpinfo := Binding as IWinInetHttpInfo;
if Httpinfo <> nil then
begin
Reserved := 0;
dwFlags := 0;
BufferLength := SizeOf(TSystemtime);
Result := not Boolean(httpInfo.QueryInfo(dwOption or HTTP_QUERY_FLAG_SYSTEMTIME,
@SysTime, BufferLength, dwflags, reserved));
if Result then Info := SystemtimetoDatetime(SysTime);
end else Result := FALSE;
httpinfo := nil;
end;



function TBSCB.GetBindResult(out clsidProtocol: TCLSID;
out dwResult: DWORD; out szResult: POLEStr; dwReserved: DWORD): HResult;
begin
Result := Binding.GetBindResult(clsidProtocol, dwResult, szResult, 0);
end;

{ TDownloader }

function GetDefaultUserAgent: string;
var
reg: TRegistry;
begin
Reg := TRegistry.Create;
try
Reg.RootKey := HKEY_CURRENT_USER;
if Reg.OpenKey('/Software/Microsoft/Windows/CurrentVersion/Internet Settings/', FALSE)
then Result := Reg.ReadString('User Agent');
finally
Reg.CloseKey;
Reg.Free;
end;
end;

constructor TIEDownload.create(AOwner: TComponent);
begin
inherited;
FObjList := TObjectList.Create;
FAdditionalHeader := TStringlist.Create;
Frange := TRange.Create;
FSecurity := TSecurity.Create;
FRefcount := 1;
FBindInfoOptions := [Asynchronous, AsyncStorage, PullData, NoWriteCache, GetNewestVersion]; //Options;
FBindVerbOption := Get; //Method;
FCodePageOption := Ansi; //Ansi Code page;
FUserAgent := GetDefaultUserAgent;
FAdditionalHeader.Add('Content-Type: application/x-www-form-urlencoded');
end;

procedure TIEDownload.FillInfo(var Info: TInfo);
begin
with info do begin
Sender := Self;
AdditionalHeader.AddStrings(FAdditionalHeader);
BindVerbValue := FBindVerbValue;
BindInfoValue := FBindInfoValue;
PassWord := FPassWord;
Username := FUsername;
CustomVerb := FCustomVerb;
ExtraInfo := FExtraInfo;
PostData := FPostData;
PutFileName := FPutFileName;
Descriptor := Security.Descriptor;
InheritHandle := Security.InheritHandle;
RangeBegin := Range.RangeBegin;
RangeEnd := Range.RangeEnd;
UrlEncodeValue := FUrlEncodeValue;
CodePageValue := FCodepageValue;
TimeOut := FtimeOut;
end;
end;

procedure TIEDownload.Go(Url, Fname: string);
var
Info: TInfo;
bs: TBscb;
begin
FCancel := False;
Info.Url := StringToOleStr(Url);
Info.FileName := FName;
Info.AdditionalHeader := TStringlist.Create;
FillInfo(Info);
bs := TBSCB.Create(Info);
if FBindInfoValue <> FBindInfoValue or BINDF_ASYNCHRONOUS then
BS.Free else FObjList.add(bs);
end;


procedure TIEDownload.Go(Url: string);
var
Info: TInfo;
bs: TBscb;
begin
FCancel := False;
Info.Url := StringToOleStr(Url);
Info.FileName := '';
Info.AdditionalHeader := TStringlist.Create;
FillInfo(Info);
bs := TBSCB.Create(Info);
if FBindInfoValue <> FBindInfoValue or BINDF_ASYNCHRONOUS then
BS.Free else FObjList.add(bs);
end;

destructor TIEDownload.Destroy;
begin
FObjlist.Free;
FRange.Free;
FSecurity.Free;
FAdditionalHeader.Free;
inherited;
end;

procedure TIEdownload.UpdateUrlEncodeValue;
const
acardUrlEncodeValues: array[TUrlEncodeOption] of Cardinal = (
$00000001, $00000002);
var
i: TUrlEncodeOption;
begin
FUrlEncodeValue := 0;
if (FUrlEncodeOptions <> []) then
for i := Low(TUrlEncodeOption) to High(TUrlEncodeOption) do
if (i in FUrlEncodeOptions) then
Inc(FUrlencodeValue, acardUrlEncodeValues);
end;

procedure TIEDownload.SetUrlEncodeOptions(const Value:
TUrlEncodeOptions);
begin
FUrlEncodeOptions := Value;
UpdateUrlEncodeValue;
end;

procedure TIEDownload.UpdateBindInfoValue;
const
acardBindInfoValues: array[TBindInfoOption] of Cardinal = (
$00000001, $00000002, $00000004, $00000008, $00000010, $00000020, $00000040, $00000080,
$00000100, $00000200, $00000400, $00000800, $00001000, $00002000, $00004000, $00008000,
$00010000, $00020000, $00040000, $00080000, $00100000, $00200000, $00400000, $00800000);
var
i: TBindInfoOption;
begin
FBindInfoValue := 0;
if (FBindInfoOptions <> []) then
for i := Low(TBindInfoOption) to High(TBIndInfoOption) do
if (i in FBindInfoOptions) then
Inc(FBindInfoValue, acardBindInfoValues);
end;

procedure TIEDownload.SetBindInfoOptions(const Value:
TBindInfoOptions);
begin
FBindInfoOptions := Value;
UpdateBindInfoValue;
end;

procedure TIEDownload.SetCodePageOption(const Value: TCodepageOption);
begin
FCodepageOption := Value;
case FCodepageOption of
Ansi: FCodepageValue := CP_ACP;
Mac: FCodepageValue := CP_MACCP;
OEM: FCodepageValue := CP_OEMCP;
Symbol: FCodepageValue := CP_SYMBOL;
ThreadsAnsi: FCodepageValue := CP_THREAD_ACP;
UTF7: FCodepageValue := CP_UTF7;
UTF8: FCodepageValue := CP_UTF8;
end;
end;

procedure TIEDownload.SetBindVerbOption(const Value:
TBindVerbOption);
begin
FBindVerbOption := Value;
case FBindVerbOption of
Get: FBindVerbValue := BINDVERB_GET;
Put: FBindVerbValue := BINDVERB_PUT;
Post: FBindVerbValue := BINDVERB_POST;
Custom: FBindVerbValue := BINDVERB_CUSTOM;
end;
end;

procedure TIEDownload.Cancel;
begin
FCancel := True;
end;

procedure TIEDownload.Cancel(Item: TBSCB);
begin
Item.FCancel := True;
end;




procedure Register;
begin
RegisterComponents('Samples', [TIEDownload]);
end;


function ResponseCodeText(ResponseCode: Integer): string;
begin
case ResponseCode of
100: Result := 'Continue';
101: Result := 'Switching Protocols';
200: Result := 'OK';
201: Result := 'Created';
202: Result := 'Accepted';
203: Result := 'Non-Authoritative Information';
204: Result := 'No Content';
205: Result := 'Reset Content';
206: Result := 'Partial Content';
300: Result := 'Multiple Choices';
301: Result := 'Moved Permanently';
302: Result := 'Moved Temporarily';
303: Result := 'See Other';
304: Result := 'Not Modified';
305: Result := 'Use Proxy';
400: Result := 'Bad Request';
401: Result := 'Unauthorized';
402: Result := 'Payment Required';
403: Result := 'Forbidden';
404: Result := 'Not Found';
405: Result := 'Method Not Allowed';
406: Result := 'None Acceptable';
407: Result := 'Proxy Authentication Required';
408: Result := 'Request Timeout';
409: Result := 'Conflict';
410: Result := 'Gone';
411: Result := 'Length Required';
412: Result := 'Precondition Failed';
413: Result := 'Request Entity Too Large';
414: Result := 'Request-URI Too Long';
415: Result := 'Unsupported Media Type';
416: Result := 'Requested Range Not Satisfiable';
417: Result := 'Expectation Failed';
500: Result := 'Internal Server Error';
501: Result := 'Not Implemented';
502: Result := 'Bad Gateway';
503: Result := 'Service Unavailable';
504: Result := 'Gateway Timeout';
505: Result := 'HTTP Version Not Supported';


else
Result := 'Unknown Response';
end
end;



function BindStatusText(ulStatusCode: ULONG): string;
begin
case ulStatusCode of
BINDSTATUS_REDIRECTING: Result := 'Server redirecting client...';
BINDSTATUS_FINDINGRESOURCE: Result := 'Finding resource...';
BINDSTATUS_CONNECTING: Result := 'Connecting...';
BINDSTATUS_BEGINDOWNLOADDATA: Result := 'Beginning to download data...';
BINDSTATUS_DOWNLOADINGDATA: Result := 'Downloading data...';
BINDSTATUS_ENDDOWNLOADDATA: Result := 'Ending data download...';
BINDSTATUS_BEGINDOWNLOADCOMPONENTS: Result := 'Beginning to download components...';
BINDSTATUS_INSTALLINGCOMPONENTS: Result := 'Installing components...';
BINDSTATUS_ENDDOWNLOADCOMPONENTS: Result := 'Ending component download...';
BINDSTATUS_USINGCACHEDCOPY: Result := 'Using cached copy...';
BINDSTATUS_SENDINGREQUEST: Result := 'Sending request...';
BINDSTATUS_CLASSIDAVAILABLE: Result := 'CLSID available...';
BINDSTATUS_MIMETYPEAVAILABLE: Result := 'MIME type available...';
BINDSTATUS_CACHEFILENAMEAVAILABLE: Result := 'Cache file name available...';
else Result := 'Bindstatus Unknown';
end;
end;


function ErrorText(errorCode: Integer): string;
begin
case errorCode of
S_OK: Result := 'Download complete...';
E_INVALIDARG: result := 'One or more parameters are invalid.';
E_OUTOFMEMORY: Result := 'There was insufficient memory ...';
E_ABORT: Result := 'Cancelled ...';
STG_E_ACCESSDENIED: Result := 'Unable to access the storage object.';
MK_E_NOSTORAGE: Result := 'The object identified by the moniker does not have its own storage.';
MK_E_EXCEEDEDDEADLINE: Result := 'The operation could not be completed within the time limit specified by the bind context''s BIND_OPTS structure.';
MK_E_CONNECTMANUALLY: Result := 'The operation was unable to connect to the storage, possibly because a network device could not be connected to. For more information, see IMoniker::BindToObject.';
MK_E_INTERMEDIATEINTERFACENOTSUPPORTED: Result := 'An intermediate object was found but it did not support an interface required for an operation. For example, an item moniker returns this value if its container does not support the IOleItemContainer interface.';
MK_E_SYNTAX: Result := 'A moniker could not be created because of invalid URL syntax.';
INET_E_AUTHENTICATION_REQUIRED: Result := 'Authentication is needed to access the object.';
INET_E_CANNOT_CONNECT: Result := 'The attempt to connect to the Internet has failed.';
INET_E_CANNOT_INSTANTIATE_OBJECT: Result := 'CoCreateInstance failed.';
INET_E_CANNOT_LOAD_DATA: Result := 'The object could not be loaded.';
INET_E_CANNOT_LOCK_REQUEST: Result := 'The requested resource could not be locked.';
INET_E_CONNECTION_TIMEOUT: Result := 'The Internet connection has timed out.';
INET_E_DATA_NOT_AVAILABLE: Result := 'An Internet connection was established, but the data cannot be retrieved.';
INET_E_DEFAULT_ACTION: Result := 'Use the default action.';
INET_E_DOWNLOAD_FAILURE: Result := 'The download has failed (the connection was interrupted).';
INET_E_INVALID_REQUEST: Result := 'The request was invalid.';
INET_E_INVALID_URL: Result := 'The URL could not be parsed.';
INET_E_NO_SESSION: Result := 'No Internet session was established.';
INET_E_NO_VALID_MEDIA: Result := 'The object is not in one of the acceptable MIME types.';
INET_E_OBJECT_NOT_FOUND: Result := 'The object was not found.';
INET_E_QUERYOPTION_UNKNOWN: Result := 'The requested option is unknown.';
INET_E_REDIRECT_TO_DIR: Result := 'The request is being redirected to a directory.';
INET_E_REDIRECTING: Result := 'The request is being redirected.';
INET_E_RESOURCE_NOT_FOUND: Result := 'The server or proxy was not found.';
INET_E_SECURITY_PROBLEM: Result := 'A security problem was encountered.';
INET_E_UNKNOWN_PROTOCOL: Result := 'The protocol is not known and no pluggable protocols have been entered that match.';
else
if errorCode <> 0 then Result := 'Error: ' + InttoStr(ErrorCode);
end;
end;

procedure TIEDownload.SetAdditionalHeader(const Value: Tstrings);
begin
FAdditionalHeader.Assign(Value);
end;


initialization
coInitialize(nil);
finalization
coUninitialize;

end.
 
好象只有开始值:0
和下载完之后的值:MAX
中间的值是不是没取到,还是只能得到两个值。
 
呵呵,下午要赶项目,我没有时间喽,我的QQ:25950596,有空我会给你详细解释的。
 
to :爱元元的哥哥
问题解决了。

开始我上的是宽带,下载文件大小为2.34MB,因为速度快,所以只显示0和MAX值;
后来我换用猫上网后,文件的中间值显示了。
看来状态是每隔一定时间判断的。时间间隔我不太会设置,或者时间间隔是固定的吧。
你的IEDownload控件我不太会用,以后有时间做个例子给我,多谢了。

我的EMAIL:
LHL19770714@yahoo.com.cn

接分50。

 
后退
顶部