線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:2979
推到 Plurk!
推到 Facebook!

請問使用URLdownloadtofile如何知道所要下載的檔案大小以及是否下載完成?

 
qubeley2004
一般會員


發表:52
回覆:71
積分:24
註冊:2004-07-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2006-07-28 16:09:54 IP:61.229.xxx.xxx 未訂閱
請問使用URLdownloadtofile如何知道所要下載的檔案大小以及是否下載完成?
謝謝~
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#2 引用回覆 回覆 發表時間:2006-07-31 15:15:06 IP:61.219.xxx.xxx 未訂閱

#include

HRESULT URLDownloadToFile(
    LPUNKNOWN pCaller,
    LPCSTR szURL,
    LPCSTR szFileName,
    DWORD dwReserved,
    LPBINDSTATUSCALLBACK lpfnCB);
pCaller
is used only if the caller is an ActiveX object. If the calling app is not an ActiveX object, this parameter can be NULL.
szURL
is the absolute URL of the file to download.
szFileName
contains the fully-qualified name of the file to be created.
dwReserved
must be zero.
lpfnCB
is a pointer to an IBindStatusCallback interface, which IE uses to inform you of the download progress.

The steps involved in using URLDownloadToFile() are:

  • Obtain the URL for the file you want to download.
  • Construct the fully-qualified path for the file to be created.
  • Create an IBindStatusCallback-derived class and write an OnProgress() function for it.
  • Instantiate an object of that class.
  • Call URLDownloadToFile(). The call is synchronous, so you will probably want to call the function from a worker thread.
  • In your OnProgress() function, provide any progress indicators or other UI that you want. The return from OnProgress() tells IE whether to continue the download, or abort it.

Using IBindStatusCallback

IBindStatusCallback has eight methods, but for the purposes of downloading, the only function you need to be concerned with is OnProgress(). The others can just return E_NOTIMPL. The prototype for OnProgress() is:

HRESULT OnProgress(
                   ULONG  ulProgress,
                   ULONG  ulProgressMax,
                   ULONG  ulStatusCode,
                 LPCWSTR  szStatusText );
ulProgress
is the number of bytes downloaded so far.
ulProgressMax
is the size of the file, or zero if the size is not known. Note that technically, this value may change between calls to OnProgress(), so you should not store the value in a static variable; you should check the value every time the function is called.
ulStatusCode
is a number indicating whether the download is in progress. The value can be BINDSTATUS_BEGINDOWNLOADCOMPONENTS, BINDSTATUS_INSTALLINGCOMPONENTS, or BINDSTATUS_ENDDOWNLOADCOMPONENTS.
szStatusText
is a string suitable for using in UI, if you want to take what IE gives you. This text is pretty bare-bones, and you'll probably want to use something more substantial for your progress UI. Note that technically, this parameter may be NULL, so be sure to check the value before using it.

OnProgress() returns S_OK to tell IE to keep downloading, or E_ABORT to abort the download.

qubeley2004
一般會員


發表:52
回覆:71
積分:24
註冊:2004-07-13

發送簡訊給我
#3 引用回覆 回覆 發表時間:2006-08-03 00:45:24 IP:220.139.xxx.xxx 未訂閱
抱歉..我還是看不懂要怎樣去使用OnProgress
程式碼只有這樣,煩在請教是要在哪邊加上語法呢??
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#4 引用回覆 回覆 發表時間:2006-08-11 08:44:26 IP:61.219.xxx.xxx 未訂閱
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#5 引用回覆 回覆 發表時間:2006-08-11 08:45:51 IP:61.219.xxx.xxx 未訂閱
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#6 引用回覆 回覆 發表時間:2006-08-11 14:47:59 IP:61.229.xxx.xxx 未訂閱

給你一個我的實作吧,這樣比較容易懂。因為要傳入的是一個物件的指標,而此物件要繼承interface,也就是把此抽象化的類別實作出來,在實作每個虛member function的過程中,我們只要把精力放在onProgress上,因為URLDownloadToFile的最後參數雖指向整個object,但它主要是call這個method。

我把需作實這個interface的class寫成一個unit,請加入你的project中,然後在URLDownloadToFile前面個的create 這個object,然後把指標指給它最後一個參教。
至於 onProgress裡的實作,請自行加入自己的需求,比如說取出ulProgressMax這個值得到檔案長度,但有時候這個值會等於0,那就是指未知大小…

// header 的部份,onProgress外的method都以inline的形式完成實作了,僅留onProgress這個在cpp檔
//供你自己去修改自己的需求

//---------------------------------------------------------------------------

#ifndef Unit2H
#define Unit2H
//---------------------------------------------------------------------------
#include


class DlCallback : public IBindStatusCallback
{
public:

STDMETHOD(OnStartBinding)(
/* [in] */ DWORD dwReserved,
/* [in] */ IBinding __RPC_FAR *pib)
{ return E_NOTIMPL; }

STDMETHOD(GetPriority)(
/* [out] */ LONG __RPC_FAR *pnPriority)
{ return E_NOTIMPL; }

STDMETHOD(OnLowResource)(
/* [in] */ DWORD reserved)
{ return E_NOTIMPL; }

STDMETHOD(OnProgress)(
/* [in] */ ULONG ulProgress,
/* [in] */ ULONG ulProgressMax,
/* [in] */ ULONG ulStatusCode,
/* [in] */ LPCWSTR wszStatusText);

STDMETHOD(OnStopBinding)(
/* [in] */ HRESULT hresult,
/* [unique][in] */ LPCWSTR szError)
{ return E_NOTIMPL; }

STDMETHOD(GetBindInfo)(
/* [out] */ DWORD __RPC_FAR *grfBINDF,
/* [unique][out][in] */ BINDINFO __RPC_FAR *pbindinfo)
{ return E_NOTIMPL; }

STDMETHOD(OnDataAvailable)(
/* [in] */ DWORD grfBSCF,
/* [in] */ DWORD dwSize,
/* [in] */ FORMATETC __RPC_FAR *pformatetc,
/* [in] */ STGMEDIUM __RPC_FAR *pstgmed)
{ return E_NOTIMPL; }

STDMETHOD(OnObjectAvailable)(
/* [in] */ REFIID riid,
/* [iid_is][in] */ IUnknown __RPC_FAR *punk)
{ return E_NOTIMPL; }

STDMETHOD_(ULONG,AddRef)()
{ return 0; }

STDMETHOD_(ULONG,Release)()
{ return 0; }

STDMETHOD(QueryInterface)(
/* [in] */ REFIID riid,
/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
{ return E_NOTIMPL; }
};

#endif

//以下是檔身cpp的部份

//---------------------------------------------------------------------------
#include
#pragma hdrstop
#include "Unit2.h"
#include "Unit1.h"
#include

//---------------------------------------------------------------------------

STDMETHODIMP DlCallback::OnProgress ( ULONG ulProgress, ULONG ulProgressMax,
ULONG ulStatusCode, LPCWSTR wszStatusText )
{

/*
static char szTotalBytes[256];
static char szDlBytes[256];
String asDlMsg;

if(ulProgressMax > 0)
{
Form1->ProgressBar1->Position = int(ulProgress/double(ulProgressMax)*100);
StrFormatByteSize(ulProgress,szDlBytes,255);
StrFormatByteSize(ulProgressMax,szTotalBytes,255);
Form1->Label2->Caption = asDlMsg.sprintf("Downloaded %s of %s",
szDlBytes,szTotalBytes);
Form1->Label6->Caption = String(wszStatusText);


}
else
{
Form1->Label2->Caption = "Known size";
}

if(Form1->Abort)
return E_ABORT;

*/

return S_OK;
}

//上面的method裡有放著我的實作,我已經mark起來,但你應該可以猜出我在做什麼!
// unit1是我的form,而我還有用個unit3做一個thread,讓URLDownloadToFile在thread中跑,這樣才可以顯示出一些
//即時的狀態,若你只想要單一使用progress bar那就不用thread,直接在button click上加入類似下面的code:

String url = Form1->Edit1->Text;
String dest = Form1->Edit2->Text;
DlCallback *dlbk = new DlCallback();
try
{
// URLDownloadToFile(NULL,"http://tw.yimg.com/i/tw/hp/spirit/yahoo_logo.gif","C:\\1.jpg",0,dlbk);
if(S_OK == URLDownloadToFile(NULL, url.c_str(),dest.c_str(),0,dlbk))
MessageBox(0,"Download Completed!","Download Info",MB_OK);
//ShowMessage isn't work here cause "canvas does not allow drawing"
// lock problem? myabe....
else
if (Form1->Abort)
MessageBox(0,"Download Canceled!","Download Info",MB_OK);
else
MessageBox(0,"Download Failed!","Download Info",MB_OK);
}
__finally
{
delete dlbk;
}

應該夠清楚了吧?! 希望能有幫助!,如果想要完整的demo,我是寫好了…你可以email給我,我寄給你!

蕭沖 qs.xiao@gmail.com

------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#7 引用回覆 回覆 發表時間:2006-08-11 14:52:48 IP:61.229.xxx.xxx 未訂閱

忘了重要的一件事,在你的form的unit中要加入

#pragma comment(lib,"C:\Program Files\Borland\CBuilder6\Lib\Psdk\urlmon.lib")

//下面這行你不一定需要,只要在用到shlwapi中的StrFormatByteSize function時才要加
#pragma comment(lib,"C:\Program Files\Borland\CBuilder6\Lib\Psdk\shlwapi.lib")

------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
qubeley2004
一般會員


發表:52
回覆:71
積分:24
註冊:2004-07-13

發送簡訊給我
#8 引用回覆 回覆 發表時間:2006-08-12 21:49:30 IP:61.229.xxx.xxx 未訂閱
蕭兄~
非常感謝您的回答,寫的非常詳細,讓我獲益良多
不過小弟有個問題就是
Form1->Abort
上面那個Abort這個是什麼阿??有的話我就complier不能過了
aftcast
站務副站長


發表:81
回覆:1485
積分:1763
註冊:2002-11-21

發送簡訊給我
#9 引用回覆 回覆 發表時間:2006-08-13 08:14:25 IP:61.229.xxx.xxx 未訂閱

===================引 用 文 章===================
蕭兄~
非常感謝您的回答,寫的非常詳細,讓我獲益良多
不過小弟有個問題就是
Form1->Abort
上面那個Abort這個是什麼阿??有的話我就complier不能過了
你好,關於Form1->Abort 這個property是我自己加在Form1裡的。並非原來TForm裡的屬性。

private:
bool FAbort; // 自己加的
public: // User declarations
__fastcall TForm1(TComponent* Owner);
__property bool Abort = { read=FAbort, write=FAbort }; // 自己加的
是為了記載使用者是否有按下cancel button,若有則記為true。如此callback function就會知道該結束下載…
對了,順便一提,這個URLDownloadToFile是可以續傳的,如果ie的temporary internet file 沒有被清空的話。
結論: 你若沒有要讓使用者自行cancel download,你可以不用實作這部份,就不用管這個Abort的地方了!
------


蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
qubeley2004
一般會員


發表:52
回覆:71
積分:24
註冊:2004-07-13

發送簡訊給我
#10 引用回覆 回覆 發表時間:2006-08-13 14:56:04 IP:61.229.xxx.xxx 未訂閱
暸解了~謝謝~
系統時間:2024-11-23 13:20:06
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!