| /* |
| * Copyright 2008 Jacek Caban for CodeWeavers |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "urlmon_main.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(urlmon); |
| |
| typedef struct { |
| const IBindStatusCallbackVtbl *lpBindStatusCallbackVtbl; |
| const IServiceProviderVtbl *lpServiceProviderVtbl; |
| |
| LONG ref; |
| |
| IBindStatusCallback *callback; |
| LPWSTR file_name; |
| LPWSTR cache_file; |
| } DownloadBSC; |
| |
| #define STATUSCLB(x) ((IBindStatusCallback*) &(x)->lpBindStatusCallbackVtbl) |
| #define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl) |
| |
| #define STATUSCLB_THIS(iface) DEFINE_THIS(DownloadBSC, BindStatusCallback, iface) |
| |
| static HRESULT WINAPI DownloadBSC_QueryInterface(IBindStatusCallback *iface, |
| REFIID riid, void **ppv) |
| { |
| DownloadBSC *This = STATUSCLB_THIS(iface); |
| |
| *ppv = NULL; |
| |
| if(IsEqualGUID(&IID_IUnknown, riid)) { |
| TRACE("(%p)->(IID_IUnknown, %p)\n", This, ppv); |
| *ppv = STATUSCLB(This); |
| }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) { |
| TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This, ppv); |
| *ppv = STATUSCLB(This); |
| }else if(IsEqualGUID(&IID_IServiceProvider, riid)) { |
| TRACE("(%p)->(IID_IServiceProvider, %p)\n", This, ppv); |
| *ppv = SERVPROV(This); |
| } |
| |
| if(*ppv) { |
| IBindStatusCallback_AddRef((IUnknown*)*ppv); |
| return S_OK; |
| } |
| |
| TRACE("Unsupported riid = %s\n", debugstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI DownloadBSC_AddRef(IBindStatusCallback *iface) |
| { |
| DownloadBSC *This = STATUSCLB_THIS(iface); |
| LONG ref = InterlockedIncrement(&This->ref); |
| |
| TRACE("(%p) ref = %d\n", This, ref); |
| |
| return ref; |
| } |
| |
| static ULONG WINAPI DownloadBSC_Release(IBindStatusCallback *iface) |
| { |
| DownloadBSC *This = STATUSCLB_THIS(iface); |
| LONG ref = InterlockedDecrement(&This->ref); |
| |
| TRACE("(%p) ref = %d\n", This, ref); |
| |
| if(!ref) { |
| if(This->callback) |
| IBindStatusCallback_Release(This->callback); |
| heap_free(This->file_name); |
| heap_free(This->cache_file); |
| heap_free(This); |
| } |
| |
| return ref; |
| } |
| |
| static HRESULT WINAPI DownloadBSC_OnStartBinding(IBindStatusCallback *iface, |
| DWORD dwReserved, IBinding *pbind) |
| { |
| DownloadBSC *This = STATUSCLB_THIS(iface); |
| |
| TRACE("(%p)->(%d %p)\n", This, dwReserved, pbind); |
| |
| if(This->callback) |
| IBindStatusCallback_OnStartBinding(This->callback, dwReserved, pbind); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI DownloadBSC_GetPriority(IBindStatusCallback *iface, LONG *pnPriority) |
| { |
| DownloadBSC *This = STATUSCLB_THIS(iface); |
| FIXME("(%p)->(%p)\n", This, pnPriority); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI DownloadBSC_OnLowResource(IBindStatusCallback *iface, DWORD reserved) |
| { |
| DownloadBSC *This = STATUSCLB_THIS(iface); |
| FIXME("(%p)->(%d)\n", This, reserved); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT on_progress(DownloadBSC *This, ULONG progress, ULONG progress_max, ULONG status_code, LPCWSTR status_text) |
| { |
| HRESULT hres; |
| |
| if(!This->callback) |
| return S_OK; |
| |
| hres = IBindStatusCallback_OnProgress(This->callback, progress, progress_max, status_code, status_text); |
| return hres; |
| } |
| |
| static HRESULT WINAPI DownloadBSC_OnProgress(IBindStatusCallback *iface, ULONG ulProgress, |
| ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText) |
| { |
| DownloadBSC *This = STATUSCLB_THIS(iface); |
| HRESULT hres = S_OK; |
| |
| TRACE("%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode, |
| debugstr_w(szStatusText)); |
| |
| switch(ulStatusCode) { |
| case BINDSTATUS_CONNECTING: |
| case BINDSTATUS_BEGINDOWNLOADDATA: |
| case BINDSTATUS_DOWNLOADINGDATA: |
| case BINDSTATUS_ENDDOWNLOADDATA: |
| case BINDSTATUS_SENDINGREQUEST: |
| case BINDSTATUS_MIMETYPEAVAILABLE: |
| hres = on_progress(This, ulProgress, ulProgressMax, ulStatusCode, szStatusText); |
| break; |
| |
| case BINDSTATUS_CACHEFILENAMEAVAILABLE: |
| hres = on_progress(This, ulProgress, ulProgressMax, ulStatusCode, szStatusText); |
| This->cache_file = heap_strdupW(szStatusText); |
| break; |
| |
| case BINDSTATUS_FINDINGRESOURCE: /* FIXME */ |
| break; |
| |
| default: |
| FIXME("Unsupported status %u\n", ulStatusCode); |
| } |
| |
| return hres; |
| } |
| |
| static HRESULT WINAPI DownloadBSC_OnStopBinding(IBindStatusCallback *iface, |
| HRESULT hresult, LPCWSTR szError) |
| { |
| DownloadBSC *This = STATUSCLB_THIS(iface); |
| |
| TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError)); |
| |
| if(This->file_name) { |
| if(This->cache_file) { |
| BOOL b; |
| |
| b = CopyFileW(This->cache_file, This->file_name, FALSE); |
| if(!b) |
| FIXME("CopyFile failed: %u\n", GetLastError()); |
| }else { |
| FIXME("No cache file\n"); |
| } |
| } |
| |
| if(This->callback) |
| IBindStatusCallback_OnStopBinding(This->callback, hresult, szError); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI DownloadBSC_GetBindInfo(IBindStatusCallback *iface, |
| DWORD *grfBINDF, BINDINFO *pbindinfo) |
| { |
| DownloadBSC *This = STATUSCLB_THIS(iface); |
| DWORD bindf = 0; |
| |
| TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo); |
| |
| if(This->callback) { |
| BINDINFO bindinfo; |
| HRESULT hres; |
| |
| memset(&bindinfo, 0, sizeof(bindinfo)); |
| bindinfo.cbSize = sizeof(bindinfo); |
| |
| hres = IBindStatusCallback_GetBindInfo(This->callback, &bindf, &bindinfo); |
| if(SUCCEEDED(hres)) |
| ReleaseBindInfo(&bindinfo); |
| } |
| |
| *grfBINDF = BINDF_PULLDATA | BINDF_NEEDFILE | (bindf & BINDF_ENFORCERESTRICTED); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI DownloadBSC_OnDataAvailable(IBindStatusCallback *iface, |
| DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed) |
| { |
| DownloadBSC *This = STATUSCLB_THIS(iface); |
| |
| TRACE("(%p)->(%08x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI DownloadBSC_OnObjectAvailable(IBindStatusCallback *iface, |
| REFIID riid, IUnknown *punk) |
| { |
| DownloadBSC *This = STATUSCLB_THIS(iface); |
| FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), punk); |
| return E_NOTIMPL; |
| } |
| |
| #undef STATUSCLB_THIS |
| |
| static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = { |
| DownloadBSC_QueryInterface, |
| DownloadBSC_AddRef, |
| DownloadBSC_Release, |
| DownloadBSC_OnStartBinding, |
| DownloadBSC_GetPriority, |
| DownloadBSC_OnLowResource, |
| DownloadBSC_OnProgress, |
| DownloadBSC_OnStopBinding, |
| DownloadBSC_GetBindInfo, |
| DownloadBSC_OnDataAvailable, |
| DownloadBSC_OnObjectAvailable |
| }; |
| |
| #define SERVPROV_THIS(iface) DEFINE_THIS(DownloadBSC, ServiceProvider, iface) |
| |
| static HRESULT WINAPI DwlServiceProvider_QueryInterface(IServiceProvider *iface, |
| REFIID riid, void **ppv) |
| { |
| DownloadBSC *This = SERVPROV_THIS(iface); |
| return IBindStatusCallback_QueryInterface(STATUSCLB(This), riid, ppv); |
| } |
| |
| static ULONG WINAPI DwlServiceProvider_AddRef(IServiceProvider *iface) |
| { |
| DownloadBSC *This = SERVPROV_THIS(iface); |
| return IBindStatusCallback_AddRef(STATUSCLB(This)); |
| } |
| |
| static ULONG WINAPI DwlServiceProvider_Release(IServiceProvider *iface) |
| { |
| DownloadBSC *This = SERVPROV_THIS(iface); |
| return IBindStatusCallback_Release(STATUSCLB(This)); |
| } |
| |
| static HRESULT WINAPI DwlServiceProvider_QueryService(IServiceProvider *iface, |
| REFGUID guidService, REFIID riid, void **ppv) |
| { |
| DownloadBSC *This = SERVPROV_THIS(iface); |
| IServiceProvider *serv_prov; |
| HRESULT hres; |
| |
| TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv); |
| |
| if(!This->callback) |
| return E_NOINTERFACE; |
| |
| hres = IBindStatusCallback_QueryInterface(This->callback, riid, ppv); |
| if(SUCCEEDED(hres)) |
| return S_OK; |
| |
| hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IServiceProvider, (void**)&serv_prov); |
| if(SUCCEEDED(hres)) { |
| hres = IServiceProvider_QueryService(serv_prov, guidService, riid, ppv); |
| IServiceProvider_Release(serv_prov); |
| return hres; |
| } |
| |
| return E_NOINTERFACE; |
| } |
| |
| #undef SERVPROV_THIS |
| |
| static const IServiceProviderVtbl ServiceProviderVtbl = { |
| DwlServiceProvider_QueryInterface, |
| DwlServiceProvider_AddRef, |
| DwlServiceProvider_Release, |
| DwlServiceProvider_QueryService |
| }; |
| |
| static HRESULT DownloadBSC_Create(IBindStatusCallback *callback, LPCWSTR file_name, IBindStatusCallback **ret_callback) |
| { |
| DownloadBSC *ret = heap_alloc(sizeof(*ret)); |
| |
| ret->lpBindStatusCallbackVtbl = &BindStatusCallbackVtbl; |
| ret->lpServiceProviderVtbl = &ServiceProviderVtbl; |
| ret->ref = 1; |
| ret->file_name = heap_strdupW(file_name); |
| ret->cache_file = NULL; |
| |
| if(callback) |
| IBindStatusCallback_AddRef(callback); |
| ret->callback = callback; |
| |
| *ret_callback = STATUSCLB(ret); |
| return S_OK; |
| } |
| |
| HRESULT create_default_callback(IBindStatusCallback **ret) |
| { |
| IBindStatusCallback *callback; |
| HRESULT hres; |
| |
| hres = DownloadBSC_Create(NULL, NULL, &callback); |
| if(FAILED(hres)) |
| return hres; |
| |
| hres = wrap_callback(callback, ret); |
| IBindStatusCallback_Release(callback); |
| return hres; |
| } |
| |
| /*********************************************************************** |
| * URLDownloadToFileW (URLMON.@) |
| * |
| * Downloads URL szURL to file szFileName and call lpfnCB callback to |
| * report progress. |
| * |
| * PARAMS |
| * pCaller [I] controlling IUnknown interface. |
| * szURL [I] URL of the file to download |
| * szFileName [I] file name to store the content of the URL |
| * dwReserved [I] reserved - set to 0 |
| * lpfnCB [I] callback for progress report |
| * |
| * RETURNS |
| * S_OK on success |
| */ |
| HRESULT WINAPI URLDownloadToFileW(LPUNKNOWN pCaller, LPCWSTR szURL, LPCWSTR szFileName, |
| DWORD dwReserved, LPBINDSTATUSCALLBACK lpfnCB) |
| { |
| IBindStatusCallback *callback; |
| IUnknown *unk; |
| IMoniker *mon; |
| IBindCtx *bindctx; |
| HRESULT hres; |
| |
| TRACE("(%p %s %s %d %p)\n", pCaller, debugstr_w(szURL), debugstr_w(szFileName), dwReserved, lpfnCB); |
| |
| if(pCaller) |
| FIXME("pCaller not supported\n"); |
| |
| hres = DownloadBSC_Create(lpfnCB, szFileName, &callback); |
| if(FAILED(hres)) |
| return hres; |
| |
| hres = CreateAsyncBindCtx(0, callback, NULL, &bindctx); |
| IBindStatusCallback_Release(callback); |
| if(FAILED(hres)) |
| return hres; |
| |
| hres = CreateURLMoniker(NULL, szURL, &mon); |
| if(FAILED(hres)) { |
| IBindCtx_Release(bindctx); |
| return hres; |
| } |
| |
| hres = IMoniker_BindToStorage(mon, bindctx, NULL, &IID_IUnknown, (void**)&unk); |
| IMoniker_Release(mon); |
| IBindCtx_Release(bindctx); |
| |
| if(unk) |
| IUnknown_Release(unk); |
| |
| return hres == MK_S_ASYNCHRONOUS ? S_OK : hres; |
| } |
| |
| /*********************************************************************** |
| * URLDownloadToFileA (URLMON.@) |
| * |
| * Downloads URL szURL to rile szFileName and call lpfnCB callback to |
| * report progress. |
| * |
| * PARAMS |
| * pCaller [I] controlling IUnknown interface. |
| * szURL [I] URL of the file to download |
| * szFileName [I] file name to store the content of the URL |
| * dwReserved [I] reserved - set to 0 |
| * lpfnCB [I] callback for progress report |
| * |
| * RETURNS |
| * S_OK on success |
| */ |
| HRESULT WINAPI URLDownloadToFileA(LPUNKNOWN pCaller, LPCSTR szURL, LPCSTR szFileName, DWORD dwReserved, |
| LPBINDSTATUSCALLBACK lpfnCB) |
| { |
| LPWSTR urlW, file_nameW; |
| HRESULT hres; |
| |
| TRACE("(%p %s %s %d %p)\n", pCaller, debugstr_a(szURL), debugstr_a(szFileName), dwReserved, lpfnCB); |
| |
| urlW = heap_strdupAtoW(szURL); |
| file_nameW = heap_strdupAtoW(szFileName); |
| |
| hres = URLDownloadToFileW(pCaller, urlW, file_nameW, dwReserved, lpfnCB); |
| |
| heap_free(urlW); |
| heap_free(file_nameW); |
| |
| return hres; |
| } |