1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
|
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tchar.h>
#include <iostream> // must be included before hack.h as SAL annotations
#include <iomanip> // collide with GCC's standard library implmentation
#include "hack.h" // contains #defines of SAL annotations (to nothing)
// plus
#include "urlmon.h" // copied into project folder (from Windows SDK)
// along with an empty "msxml.h" file
#include <wininet.h> // MinGW does provide this (needed for DeleteUrlCacheEntry)
using namespace std;
#ifdef _UNICODE
#define tcout wcout
#else
#define tcout cout
#endif
// Adapted from:
// Creating a progress bar in C/C++ (or any other console app.)
// http://www.rosshemsley.co.uk/2011/02/creating-a-progress-bar-in-c-or-any-other-console-app/
void LoadBar(unsigned curr_val, unsigned max_val, unsigned bar_width = 20)
{
if((curr_val != max_val) && (curr_val % (max_val / 100) != 0))
return;
double ratio = curr_val / (double)max_val;
unsigned bar_now = (unsigned)(ratio * bar_width);
tcout << _T("\r") << setw(3) << (unsigned)(ratio * 100.0) << _T("% [");
for(unsigned curr_val = 0; curr_val < bar_now; ++curr_val)
tcout << _T("=");
for(unsigned curr_val = bar_now; curr_val < bar_width; ++curr_val)
tcout << _T(" ");
tcout << _T("]") << flush;
}
class CallbackHandler : public IBindStatusCallback
{
private:
int m_percentLast;
public:
CallbackHandler() : m_percentLast(0)
{
}
// IUnknown
HRESULT STDMETHODCALLTYPE
QueryInterface(REFIID riid, void** ppvObject)
{
if( IsEqualIID(IID_IBindStatusCallback, riid)
|| IsEqualIID(IID_IUnknown, riid) )
{
*ppvObject = reinterpret_cast<void*>(this);
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE
AddRef()
{
return 2UL;
}
ULONG STDMETHODCALLTYPE
Release()
{
return 1UL;
}
// IBindStatusCallback
HRESULT STDMETHODCALLTYPE
OnStartBinding(DWORD /*dwReserved*/,
IBinding* /*pib*/)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE
GetPriority(LONG* /*pnPriority*/)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE
OnLowResource(DWORD /*reserved*/)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE
OnProgress(ULONG ulProgress,
ULONG ulProgressMax,
ULONG ulStatusCode,
LPCWSTR /*szStatusText*/)
{
switch(ulStatusCode)
{
case BINDSTATUS_FINDINGRESOURCE:
tcout << _T("Finding resource...") << endl;
break;
case BINDSTATUS_CONNECTING:
tcout << _T("Connecting...") << endl;
break;
case BINDSTATUS_SENDINGREQUEST:
tcout << _T("Sending request...") << endl;
break;
case BINDSTATUS_MIMETYPEAVAILABLE:
tcout << _T("Mime type available") << endl;
break;
case BINDSTATUS_CACHEFILENAMEAVAILABLE:
tcout << _T("Cache filename available") << endl;
break;
case BINDSTATUS_BEGINDOWNLOADDATA:
tcout << _T("Begin download") << endl;
break;
case BINDSTATUS_DOWNLOADINGDATA:
case BINDSTATUS_ENDDOWNLOADDATA:
{
int percent = (int)(100.0 * static_cast<double>(ulProgress)
/ static_cast<double>(ulProgressMax));
if(m_percentLast < percent)
{
LoadBar(percent, 100);
m_percentLast = percent;
}
if(ulStatusCode == BINDSTATUS_ENDDOWNLOADDATA)
{
tcout << endl << _T("End download") << endl;
}
}
break;
default:
{
tcout << _T("Status code : ") << ulStatusCode << endl;
}
}
// The download can be cancelled by returning E_ABORT here
// of from any other of the methods.
return S_OK;
}
HRESULT STDMETHODCALLTYPE
OnStopBinding(HRESULT /*hresult*/,
LPCWSTR /*szError*/)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE
GetBindInfo(DWORD* /*grfBINDF*/,
BINDINFO* /*pbindinfo*/)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE
OnDataAvailable(DWORD /*grfBSCF*/,
DWORD /*dwSize*/,
FORMATETC* /*pformatetc*/,
STGMEDIUM* /*pstgmed*/)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE
OnObjectAvailable(REFIID /*riid*/,
IUnknown* /*punk*/)
{
return E_NOTIMPL;
}
};
int main()
{
const TCHAR url[] = _T("http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf");
const TCHAR filePath[] = _T("C:\\Test\\n3337.pdf");
tcout << _T("Downloading : ") << url << endl;
tcout << _T("To local file : ") << filePath << endl;
// invalidate cache, so file is always downloaded from web site
// (if not called, the file will be retieved from the cache if
// it's already been downloaded.)
DeleteUrlCacheEntry(url);
CallbackHandler callbackHandler;
IBindStatusCallback* pBindStatusCallback = NULL;
callbackHandler.QueryInterface(IID_IBindStatusCallback,
reinterpret_cast<void**>(&pBindStatusCallback));
HRESULT hr = URLDownloadToFile(
NULL, // A pointer to the controlling IUnknown interface
url,
filePath,
0, // Reserved. Must be set to 0.
pBindStatusCallback );
if(SUCCEEDED(hr))
{
tcout << _T("Downloaded OK") << endl;
}
else
{
tcout << _T("An error occured : error code = 0x") << hex << hr << endl;
}
// should usually call Release on a COM object, but this one (callbackHandler)
// was created on the stack so is going out of scope now and will die anyway.
return 0;
}
| |