From 5ca20089c4a5acd192175cb7d5819ea2b1a996aa Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Mon, 18 Feb 2008 01:03:24 +0100 Subject: [PATCH] urlmon: Reimplement URLDownloadToFileW on top of URL moniker. --- dlls/urlmon/Makefile.in | 1 + dlls/urlmon/download.c | 370 ++++++++++++++++++++++++++++++++++++++++++++++++ dlls/urlmon/umon.c | 167 ---------------------- 3 files changed, 371 insertions(+), 167 deletions(-) create mode 100644 dlls/urlmon/download.c diff --git a/dlls/urlmon/Makefile.in b/dlls/urlmon/Makefile.in index e1b95ef6412..bab6d03f706 100644 --- a/dlls/urlmon/Makefile.in +++ b/dlls/urlmon/Makefile.in @@ -11,6 +11,7 @@ C_SRCS = \ bindctx.c \ binding.c \ bindprot.c \ + download.c \ file.c \ format.c \ ftp.c \ diff --git a/dlls/urlmon/download.c b/dlls/urlmon/download.c new file mode 100644 index 00000000000..a3ac35cd2ff --- /dev/null +++ b/dlls/urlmon/download.c @@ -0,0 +1,370 @@ +/* + * 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 void on_progress(DownloadBSC *This, ULONG progress, ULONG progress_max, ULONG status_code, LPCWSTR status_text) +{ + HRESULT hres; + + if(!This->callback) + return; + + hres = IBindStatusCallback_OnProgress(This->callback, progress, progress_max, status_code, status_text); + if(FAILED(hres)) + FIXME("OnProgress failed: %08x\n", hres); +} + +static HRESULT WINAPI DownloadBSC_OnProgress(IBindStatusCallback *iface, ULONG ulProgress, + ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText) +{ + DownloadBSC *This = STATUSCLB_THIS(iface); + + TRACE("%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode, + debugstr_w(szStatusText)); + + switch(ulStatusCode) { + case BINDSTATUS_BEGINDOWNLOADDATA: + case BINDSTATUS_DOWNLOADINGDATA: + case BINDSTATUS_ENDDOWNLOADDATA: + case BINDSTATUS_SENDINGREQUEST: + case BINDSTATUS_MIMETYPEAVAILABLE: + on_progress(This, ulProgress, ulProgressMax, ulStatusCode, szStatusText); + break; + + case BINDSTATUS_CACHEFILENAMEAVAILABLE: + on_progress(This, ulProgress, ulProgressMax, ulStatusCode, szStatusText); + This->cache_file = heap_strdupW(szStatusText); + break; + + case BINDSTATUS_FINDINGRESOURCE: + case BINDSTATUS_CONNECTING: + break; + + default: + FIXME("Unsupported status %u\n", ulStatusCode); + } + + return S_OK; +} + +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->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 IBindStatusCallback *DownloadBSC_Create(IBindStatusCallback *callback, LPCWSTR file_name) +{ + DownloadBSC *ret = heap_alloc(sizeof(*ret)); + + ret->lpBindStatusCallbackVtbl = &BindStatusCallbackVtbl; + ret->lpServiceProviderVtbl = &ServiceProviderVtbl; + ret->ref = 1; + ret->file_name = heap_strdupW(file_name); + + if(callback) + IBindStatusCallback_AddRef(callback); + ret->callback = callback; + + return STATUSCLB(ret); +} + +/*********************************************************************** + * 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"); + + callback = DownloadBSC_Create(lpfnCB, szFileName); + 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; +} diff --git a/dlls/urlmon/umon.c b/dlls/urlmon/umon.c index 640f3821be0..abfce91f923 100644 --- a/dlls/urlmon/umon.c +++ b/dlls/urlmon/umon.c @@ -1254,173 +1254,6 @@ HRESULT WINAPI URLDownloadToFileA(LPUNKNOWN pCaller, } /*********************************************************************** - * URLDownloadToFileW (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 - * E_OUTOFMEMORY when going out of memory - */ -HRESULT WINAPI URLDownloadToFileW(LPUNKNOWN pCaller, - LPCWSTR szURL, - LPCWSTR szFileName, - DWORD dwReserved, - LPBINDSTATUSCALLBACK lpfnCB) -{ - HINTERNET hinternet, hcon, hreq; - BOOL r; - CHAR buffer[0x1000]; - DWORD sz, total, written; - DWORD total_size = 0xFFFFFFFF, arg_size = sizeof(total_size); - URL_COMPONENTSW url; - WCHAR host[0x80], path[0x100]; - HANDLE hfile; - static const WCHAR wszAppName[]={'u','r','l','m','o','n','.','d','l','l',0}; - - /* Note: all error codes would need to be checked agains real Windows behaviour... */ - TRACE("(%p,%s,%s,%08x,%p) stub!\n", pCaller, debugstr_w(szURL), debugstr_w(szFileName), dwReserved, lpfnCB); - - if ((szURL == NULL) || (szFileName == NULL)) { - FIXME(" cannot accept NULL strings !\n"); - return E_INVALIDARG; - } - - /* Would be better to use the application name here rather than 'urlmon' :-/ */ - hinternet = InternetOpenW(wszAppName, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); - if (hinternet == NULL) { - return E_OUTOFMEMORY; - } - - memset(&url, 0, sizeof(url)); - url.dwStructSize = sizeof(url); - url.lpszHostName = host; - url.dwHostNameLength = sizeof(host); - url.lpszUrlPath = path; - url.dwUrlPathLength = sizeof(path); - - if (!InternetCrackUrlW(szURL, 0, 0, &url)) { - InternetCloseHandle(hinternet); - return E_OUTOFMEMORY; - } - - if (lpfnCB) { - if (IBindStatusCallback_OnProgress(lpfnCB, 0, 0, BINDSTATUS_CONNECTING, url.lpszHostName) == E_ABORT) { - InternetCloseHandle(hinternet); - return S_OK; - } - } - - hcon = InternetConnectW(hinternet, url.lpszHostName, url.nPort, - url.lpszUserName, url.lpszPassword, - INTERNET_SERVICE_HTTP, 0, 0); - if (!hcon) { - InternetCloseHandle(hinternet); - return E_OUTOFMEMORY; - } - - hreq = HttpOpenRequestW(hcon, NULL, url.lpszUrlPath, NULL, NULL, NULL, 0, 0); - if (!hreq) { - InternetCloseHandle(hinternet); - InternetCloseHandle(hcon); - return E_OUTOFMEMORY; - } - - if (!HttpSendRequestW(hreq, NULL, 0, NULL, 0)) { - InternetCloseHandle(hinternet); - InternetCloseHandle(hcon); - InternetCloseHandle(hreq); - return E_OUTOFMEMORY; - } - - if (HttpQueryInfoW(hreq, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, - &total_size, &arg_size, NULL)) { - TRACE(" total size : %d\n", total_size); - } - - hfile = CreateFileW(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL ); - if (hfile == INVALID_HANDLE_VALUE) { - return E_ACCESSDENIED; - } - - if (lpfnCB) { - if (IBindStatusCallback_OnProgress(lpfnCB, 0, total_size != 0xFFFFFFFF ? total_size : 0, - BINDSTATUS_BEGINDOWNLOADDATA, szURL) == E_ABORT) { - InternetCloseHandle(hreq); - InternetCloseHandle(hcon); - InternetCloseHandle(hinternet); - CloseHandle(hfile); - return S_OK; - } - } - - total = 0; - while (1) { - r = InternetReadFile(hreq, buffer, sizeof(buffer), &sz); - if (!r) { - InternetCloseHandle(hreq); - InternetCloseHandle(hcon); - InternetCloseHandle(hinternet); - - CloseHandle(hfile); - return E_OUTOFMEMORY; - } - if (!sz) - break; - - total += sz; - - if (lpfnCB) { - if (IBindStatusCallback_OnProgress(lpfnCB, total, total_size != 0xFFFFFFFF ? total_size : 0, - BINDSTATUS_DOWNLOADINGDATA, szURL) == E_ABORT) { - InternetCloseHandle(hreq); - InternetCloseHandle(hcon); - InternetCloseHandle(hinternet); - CloseHandle(hfile); - return S_OK; - } - } - - if (!WriteFile(hfile, buffer, sz, &written, NULL)) { - InternetCloseHandle(hreq); - InternetCloseHandle(hcon); - InternetCloseHandle(hinternet); - - CloseHandle(hfile); - return E_OUTOFMEMORY; - } - } - - if (lpfnCB) { - if (IBindStatusCallback_OnProgress(lpfnCB, total, total_size != 0xFFFFFFFF ? total_size : 0, - BINDSTATUS_ENDDOWNLOADDATA, szURL) == E_ABORT) { - InternetCloseHandle(hreq); - InternetCloseHandle(hcon); - InternetCloseHandle(hinternet); - CloseHandle(hfile); - return S_OK; - } - } - - InternetCloseHandle(hreq); - InternetCloseHandle(hcon); - InternetCloseHandle(hinternet); - - CloseHandle(hfile); - - return S_OK; -} - -/*********************************************************************** * URLDownloadToCacheFileA (URLMON.@) */ HRESULT WINAPI URLDownloadToCacheFileA(LPUNKNOWN lpUnkCaller, LPCSTR szURL, LPSTR szFileName, -- 2.11.4.GIT