URLDownloadToFile

来源:互联网 发布:矿用防爆网络交换机 编辑:程序博客网 时间:2024/06/03 18:20
closed account (3hMz8vqX)
Hi All,

I am a beginner in WINAPI C++ and I like to download files from the internet using 
the URLDownloadToFile() function 

I did all the syntax and stuff correctly . . . 
I use Orwell Dev-C++ TDM GCC
Im using Windows 7 Ultimate 32 bit . . . 

But I get the following error when I compile my project
C:\Users\user\Documents\CC++\main.o main.cpp:(.text+0x3e): undefined reference to `URLDownloadToFileA@20'

And I cannot find liburlmon.a ???

Please Please help me . . . 
Thankyou everyone in advance!!!


 Aug 3, 2013 at 12:06am
closed account (Dy7SLyTq)
are you linking right?
 Aug 3, 2013 at 3:05am
andywestken (4007)
Out of interest, is the header urlmon.h provided with your GCC? Or have you obtained it from elsewhere?

I have GCC 4.7.2 from the main MinGW release (http://sourceforge.net/projects/mingw/ ) and it has neither the urlmon.h header nor the import library.

If you can't find a suitable import library, you could dynamically link instead. You only need the single function for the basic use of the URLDownloadToFile function.

Andy

PS If you want to receive progress messages while downloading a file with URLDownloadToFile, it's rather more compicated!
Last edited on Aug 3, 2013 at 5:07am
 Aug 3, 2013 at 4:09am
andywestken (4007)
I have got a small program to link by using the libmon header and import lib from the Windows SDK (version 7.0).

But it did involve a bit of hacking, mostly to #define away all the SAL annotations littering urlmon.h. I also had to provide an empty msxml.h file and #define a few pretend types to make the compiler happy (types I would not be using, so any old definition was ok).

After that, I think dynamic linking would be both easier and rather tidier!

Andy

SAL Annotations
http://msdn.microsoft.com/en-us/library/ms235402%28v=vs.100%29.aspx

I copied urlmon.h and urlmon.lib from the Windows SDK into a directory along with:
a. main.cpp (see below)
b. an empty file named msxml.h
c. hack.h (see below)

And then built main.cpp using g++ and a regular Windows command prompt, with the MinGW tools on the path, using:

g++ -ggdb -O2 -fomit-frame-pointer -std=c++11 -Wall -pedantic -U __STRICT_ANSI__-DNDEBUG -o url_test.exe main.cpp -lwininet -luuid urlmon.lib

(but without wrapping; that was done to make it display a bit better here.)

There were a couple of warnings about unknown #pragma's, but other than that it built ok, to url_test.exe. And ran! (It downloads a copy of the working draft of the C++ standard to the folder C:\Test, which is assumed to exist.)

Where main.cpp is:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
#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 a few pretend types#include "urlmon.h" // copied into project folder (from Windows SDK)                    // along with the import library and 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#endifint main(){    const TCHAR url[] = _T("<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf" "="" style="text-decoration: none; color: rgb(0, 0, 112);">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);    HRESULT hr = URLDownloadToFile(        NULL,   // A pointer to the controlling IUnknown interface (not needed here)        url,        filePath,        0,      // Reserved. Must be set to 0.        NULL ); // status callback interface (not needed for basic use)    if(SUCCEEDED(hr))    {        tcout << _T("Downloaded OK") << endl;    }    else    {        tcout << _T("An error occured : error code = 0x") << hex << hr << endl;    }    return 0;}
Edit & Run


and hack.h is:

123456789101112131415161718192021222324252627282930313233343536373839404142
// some of these are defined in MinGw's specstrings.h, but not all...#define uCLSSPEC     void*#define QUERYCONTEXT void*struct IXMLElement{    void* unused;};#define __in#define __in_opt#define __out#define __out_opt#define __inout_opt#define __inout#define __deref_inout#define __out_ecount_part(c, p)#define __in_bcount_opt(c)#define __out_bcount_part(c, p)#define __reserved#define __deref_out#define __deref_out_opt#define __out_ecount(c)#define __out_bcount_part_opt(c, p)#define __in_range(a, b)#define __RPC__in#define __RPC__in_opt#define __RPC__out#define __RPC__out_opt#define __RPC__inout#define __RPC__inout_opt#define __RPC_unique_pointer#define __RPC__deref_out_opt#define __RPC__deref_out_ecount_full_opt(c)#define __RPC__in_ecount_full(c)#define __RPC__out_ecount_full(c)#define __RPC__in_xcount(c)#define __RPC__inout_xcount(c)#define __RPC__inout_ecount_full(c)#define __RPC__out_ecount(c) 
 

Last edited on Aug 3, 2013 at 5:05am
 Aug 3, 2013 at 4:56am
andywestken (4007)
And this version of main.cpp show what you need to do to receive status feedback (as it's a console app, I use the status info to update an ASCII progress bar...)

The URLDownloadToFile function appears to have been designed to work with ActiveX controls (i.e. COM objects), so that's the way the callback mechanism works. Might not be so easy to understand if you don't already know COM.

Component Object Model
http://en.wikipedia.org/wiki/Component_Object_Model

Andy

C:\cplusplus\url_tool>url_test.exeDownloading   : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdfTo local file : C:\Test\n3337.pdfFinding resource...Connecting...Sending request...Mime type availableBegin downloadCache filename available100% [====================]End downloadDownloaded OK


123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
#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("<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf" "="" style="text-decoration: none; color: rgb(0, 0, 112);">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;}
Edit & Run
Last edited on Aug 3, 2013 at 5:05am
Topic archived. No new replies allowed.
0 0
原创粉丝点击