6 五月, 2007

VC: UrlDownloadToFile中的IBindStatusCallback和Custom HTTP headers

UrlDownloadToFile和UrlDownloadToCacheFile是URL Monikers Functions中的简单易用的2个函数。这两个函数在发送下载文件的请求的时候,会自动根据cache control来判别是否需要重新下载,如果需要,则会在HTTP头中自动添加If-Modified-Since和If-None-Match信息,以及对应于该Url的合法的cookie信息。

使用这两个函数下载文件,但是需要添加某项头信息,譬如Referer,或者修改某项头信息,譬如User-Agent,该如何实现呢?这就需要用到这两个函数的最后一个参数“LPBINDSTATUSCALLBACK lpfnCB”。以UrlDownloadToFile为例,它在Binding lpfnCB指向的回调接口的时候,会尝试QueryInterface(IID_IHttpNegotiate),如果这个接口存在,它会调用IHttpNegotiate::BeginningTransaction方法以获取additional Request Headers。所以你可以在IHttpNegotiate::BeginningTransaction方法内实现Custom headers的目的。

具体步骤:

参考:SAMPLE: PostMon.exe Demonstrates How to Use URL Moniker to POST Data

例程(Custom request header as "User-Agent: CB/1.0;Referer: http://www.utblog.com"):


//声明CBindCBHttpNego类
class CBindCBHttpNego : public IBindStatusCallback, public IHttpNegotiate
{
public:
DWORD m_cRef;

CBindCBHttpNego() : m_cRef(1) {}
virtual ~CBindCBHttpNego() {}

// IBindStatusCallback methods.
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)
{ return E_NOTIMPL; }

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; }

// IHttpNegotiate methods
STDMETHODIMP BeginningTransaction(/* [in] */ LPCWSTR szURL,
/* [unique][in] */ LPCWSTR szHeaders,
/* [in] */ DWORD dwReserved,
/* [out] */ LPWSTR __RPC_FAR *pszAdditionalHeaders);

STDMETHODIMP OnResponse(/* [in] */ DWORD dwResponseCode,
/* [unique][in] */ LPCWSTR szResponseHeaders,
/* [unique][in] */ LPCWSTR szRequestHeaders,
/* [out] */ LPWSTR __RPC_FAR *pszAdditionalRequestHeaders)
{ return E_NOTIMPL; }

// IUnknown methods.
// @Note that IE never calls any of these methods, since the caller owns the IBindStatusCallback interface
STDMETHOD_(ULONG,AddRef)() { return m_cRef++; }
STDMETHOD_(ULONG,Release)() { if (--m_cRef == 0) { delete this; return 0; } return m_cRef; }
STDMETHOD(QueryInterface)(
/* [in] */ REFIID riid,
/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
{
*ppvObject = NULL;
if (riid==IID_IUnknown || riid==IID_IBindStatusCallback)
{
*ppvObject = (IBindStatusCallback*)this;
AddRef();
return S_OK;
}
else if (riid==IID_IHttpNegotiate)
{
*ppvObject = (IHttpNegotiate*)this;
AddRef();
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
};
//实现IHttpNegotiate::BeginningTransaction方法,定制"User-Agent: CB/1.0rnReferer: http://www.utblog.comrn"
STDMETHODIMP CBindCBHttpNego::BeginningTransaction(LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR __RPC_FAR *pszAdditionalHeaders)
{
// Here's opportunity to custom headers
if (!pszAdditionalHeaders)
{
return E_POINTER;
}
*pszAdditionalHeaders = NULL;
const WCHAR c_wszHeaders[] = L"User-Agent: CB/1.0rnReferer: http://www.utblog.comrn";
LPWSTR wszAdditionalHeaders = (LPWSTR)CoTaskMemAlloc((wcslen(c_wszHeaders)+1) *sizeof(WCHAR));
if (!wszAdditionalHeaders)
{
return E_OUTOFMEMORY;
}
wcscpy(wszAdditionalHeaders, c_wszHeaders);
return NOERROR;
}

//调用

CBindCBHttpNego customHeaders;

UrlDownloadToFile(pCaller, szUrl, szFilename, 0, &customHeaders);

最新回复
发表评论


















Bold Italic Link