我想制作从互联网上下载页面的程序并对其进行一些解析.第二部分很容易,问题是第一部分.
我想使用URLDownloadToFile()函数.但默认情况下,它不会等待完成下载.MSDN说最后一个参数是一种回调函数,但是我找不到任何关于如何使用它的信息(当它被调用时它必须做什么,甚至它是什么类型的函数).有人可以解释我最后一个参数是什么以及如何使用它(在C++中)让我的应用程序等待?
由于错误,可能会立即返回函数.
如果将LPBINDSTATUSCALLBACK lpfnCB设置为NULL,则URLDownloadToFile()绝对是同步函数.
它是如此"同步",即使网络连接失败并且会阻塞你的线程,它在下载完成之前永远不会结束.使用TerminateThread()函数正在进行的URLDownloadToFile()杀死线程将导致资源泄漏,并且系统dll的子调用未完成,并且在几次URLDownloadToFile()将拒绝在当前进程的上下文中工作.
在没有回调函数的情况下可靠地使用URLDownloadToFile()的唯一方法是将单独的进程分支到它并且如果下载资源消耗停顿则终止该进程.
URLDownloadToFile()下载行为与IE完全相同,用户配置文件中的所有IE代理和网络设置在此功能运行的上下文中也适用于此功能.
即使使用回调函数,URLDownloadToFile()也不会立即返回.我考虑在单独的线程中启动URLDownloadToFile()以安全地控制和中止网络下载.
回调函数的简单示例在https://github.com/choptastic/OldCode-Public/blob/master/URLDownloadToFile/URLDownloadToFile.cpp
为了安全下载,您应该至少使用以下内容升级代码:
private:
int progress, filesize;
int AbortDownload;
public:
STDMETHOD(OnStartBinding)(
{
AbortDownload=0;
progress=0;
filesize=0;
return E_NOTIMPL; }
STDMETHOD(GetProgress)()
{ return progress; }
STDMETHOD(GetFileSize)()
{ return filesize; }
STDMETHOD(AbortDownl)()
{
AbortDownload=1;
return E_NOTIMPL; }
HRESULT DownloadStatus::OnProgress ( ULONG ulProgress, ULONG ulProgressMax,ULONG ulStatusCode, LPCWSTR wszStatusText )
{
progress=ulProgress;
filesize=ulProgressMax;
if (AbortDownload) return E_ABORT;
return S_OK;
}
Run Code Online (Sandbox Code Playgroud)
所以你总是可以中止下载并检查下载进度.
即使已经通过URLDownloadToFile()函数返回的S_OK指示下载已完成,您也必须比较progress == filesize值,因为URLDownloadToFile()可能会错误地下载S_OK,例如,如果通过本地网络的网桥进行连接接口和桥接器由于某种原因而下降.
此外,您必须注意与URLDownloadToFile()配对的DeleteUrlCacheEntry()函数以在下载后释放磁盘空间,因为默认情况下根据IE缓存策略将所有已加载的内容缓存在磁盘上.
您必须创建一个实现IBindStatusCallback接口的类.您可以为大多数方法返回E_NOTIMPL.使用OnProgress()显示进度.这是一个完成此操作的示例程序:
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#pragma comment(lib, "urlmon.lib")
using namespace std;
class DownloadProgress : public IBindStatusCallback {
public:
HRESULT __stdcall QueryInterface(const IID &,void **) {
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef(void) {
return 1;
}
ULONG STDMETHODCALLTYPE Release(void) {
return 1;
}
HRESULT STDMETHODCALLTYPE OnStartBinding(DWORD dwReserved, IBinding *pib) {
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE GetPriority(LONG *pnPriority) {
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE OnLowResource(DWORD reserved) {
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE OnStopBinding(HRESULT hresult, LPCWSTR szError) {
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE GetBindInfo(DWORD *grfBINDF, BINDINFO *pbindinfo) {
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed) {
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE OnObjectAvailable(REFIID riid, IUnknown *punk) {
return E_NOTIMPL;
}
virtual HRESULT __stdcall OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
{
wcout << ulProgress << L" of " << ulProgressMax;
if (szStatusText) wcout << " " << szStatusText;
wcout << endl;
return S_OK;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
DownloadProgress progress;
HRESULT hr = URLDownloadToFile(0,
L"http://sstatic.net/stackoverflow/img/sprites.png?v=3",
L"c:/temp/test.png", 0,
static_cast<IBindStatusCallback*>(&progress));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
0 of 0 sstatic.net
0 of 0 64.34.119.12
0 of 0
0 of 0 image/x-png
3550 of 16542 http://sstatic.net/stackoverflow/img/sprites.png?v=3
3550 of 16542 C:\Users\hpassant\AppData\Local\Microsoft\Windows\Temporary Inter
et Files\Content.IE5\NRPH4KHK\sprites[1].png
7330 of 16542 http://sstatic.net/stackoverflow/img/sprites.png?v=3
8590 of 16542 http://sstatic.net/stackoverflow/img/sprites.png?v=3
12370 of 16542 http://sstatic.net/stackoverflow/img/sprites.png?v=3
13630 of 16542 http://sstatic.net/stackoverflow/img/sprites.png?v=3
16542 of 16542 http://sstatic.net/stackoverflow/img/sprites.png?v=3
Run Code Online (Sandbox Code Playgroud)