winex11: Add support for retrieving multi-rate animated cursor data.
[wine.git] / dlls / urlmon / download.c
blob9759e71d18ee4590eda433f3870c50825a96a270
1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "urlmon_main.h"
20 #include "wine/debug.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
24 typedef struct {
25 IBindStatusCallback IBindStatusCallback_iface;
26 IServiceProvider IServiceProvider_iface;
28 LONG ref;
30 IBindStatusCallback *callback;
31 LPWSTR file_name;
32 LPWSTR cache_file;
33 } DownloadBSC;
35 static inline DownloadBSC *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
37 return CONTAINING_RECORD(iface, DownloadBSC, IBindStatusCallback_iface);
40 static inline DownloadBSC *impl_from_IServiceProvider(IServiceProvider *iface)
42 return CONTAINING_RECORD(iface, DownloadBSC, IServiceProvider_iface);
45 static HRESULT WINAPI DownloadBSC_QueryInterface(IBindStatusCallback *iface,
46 REFIID riid, void **ppv)
48 DownloadBSC *This = impl_from_IBindStatusCallback(iface);
50 *ppv = NULL;
52 if(IsEqualGUID(&IID_IUnknown, riid)) {
53 TRACE("(%p)->(IID_IUnknown, %p)\n", This, ppv);
54 *ppv = &This->IBindStatusCallback_iface;
55 }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) {
56 TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This, ppv);
57 *ppv = &This->IBindStatusCallback_iface;
58 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
59 TRACE("(%p)->(IID_IServiceProvider, %p)\n", This, ppv);
60 *ppv = &This->IServiceProvider_iface;
63 if(*ppv) {
64 IBindStatusCallback_AddRef((IUnknown*)*ppv);
65 return S_OK;
68 TRACE("Unsupported riid = %s\n", debugstr_guid(riid));
69 return E_NOINTERFACE;
72 static ULONG WINAPI DownloadBSC_AddRef(IBindStatusCallback *iface)
74 DownloadBSC *This = impl_from_IBindStatusCallback(iface);
75 LONG ref = InterlockedIncrement(&This->ref);
77 TRACE("(%p) ref = %d\n", This, ref);
79 return ref;
82 static ULONG WINAPI DownloadBSC_Release(IBindStatusCallback *iface)
84 DownloadBSC *This = impl_from_IBindStatusCallback(iface);
85 LONG ref = InterlockedDecrement(&This->ref);
87 TRACE("(%p) ref = %d\n", This, ref);
89 if(!ref) {
90 if(This->callback)
91 IBindStatusCallback_Release(This->callback);
92 heap_free(This->file_name);
93 heap_free(This->cache_file);
94 heap_free(This);
97 return ref;
100 static HRESULT WINAPI DownloadBSC_OnStartBinding(IBindStatusCallback *iface,
101 DWORD dwReserved, IBinding *pbind)
103 DownloadBSC *This = impl_from_IBindStatusCallback(iface);
105 TRACE("(%p)->(%d %p)\n", This, dwReserved, pbind);
107 if(This->callback)
108 IBindStatusCallback_OnStartBinding(This->callback, dwReserved, pbind);
110 return S_OK;
113 static HRESULT WINAPI DownloadBSC_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
115 DownloadBSC *This = impl_from_IBindStatusCallback(iface);
116 FIXME("(%p)->(%p)\n", This, pnPriority);
117 return E_NOTIMPL;
120 static HRESULT WINAPI DownloadBSC_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
122 DownloadBSC *This = impl_from_IBindStatusCallback(iface);
123 FIXME("(%p)->(%d)\n", This, reserved);
124 return E_NOTIMPL;
127 static HRESULT on_progress(DownloadBSC *This, ULONG progress, ULONG progress_max, ULONG status_code, LPCWSTR status_text)
129 HRESULT hres;
131 if(!This->callback)
132 return S_OK;
134 hres = IBindStatusCallback_OnProgress(This->callback, progress, progress_max, status_code, status_text);
135 return hres;
138 static HRESULT WINAPI DownloadBSC_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
139 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
141 DownloadBSC *This = impl_from_IBindStatusCallback(iface);
142 HRESULT hres = S_OK;
144 TRACE("%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
145 debugstr_w(szStatusText));
147 switch(ulStatusCode) {
148 case BINDSTATUS_CONNECTING:
149 case BINDSTATUS_BEGINDOWNLOADDATA:
150 case BINDSTATUS_DOWNLOADINGDATA:
151 case BINDSTATUS_ENDDOWNLOADDATA:
152 case BINDSTATUS_SENDINGREQUEST:
153 case BINDSTATUS_MIMETYPEAVAILABLE:
154 hres = on_progress(This, ulProgress, ulProgressMax, ulStatusCode, szStatusText);
155 break;
157 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
158 hres = on_progress(This, ulProgress, ulProgressMax, ulStatusCode, szStatusText);
159 This->cache_file = heap_strdupW(szStatusText);
160 break;
162 case BINDSTATUS_FINDINGRESOURCE: /* FIXME */
163 break;
165 default:
166 FIXME("Unsupported status %u\n", ulStatusCode);
169 return hres;
172 static HRESULT WINAPI DownloadBSC_OnStopBinding(IBindStatusCallback *iface,
173 HRESULT hresult, LPCWSTR szError)
175 DownloadBSC *This = impl_from_IBindStatusCallback(iface);
177 TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
179 if(This->file_name) {
180 if(This->cache_file) {
181 BOOL b;
183 b = CopyFileW(This->cache_file, This->file_name, FALSE);
184 if(!b)
185 FIXME("CopyFile failed: %u\n", GetLastError());
186 }else {
187 FIXME("No cache file\n");
191 if(This->callback)
192 IBindStatusCallback_OnStopBinding(This->callback, hresult, szError);
194 return S_OK;
197 static HRESULT WINAPI DownloadBSC_GetBindInfo(IBindStatusCallback *iface,
198 DWORD *grfBINDF, BINDINFO *pbindinfo)
200 DownloadBSC *This = impl_from_IBindStatusCallback(iface);
201 DWORD bindf = 0;
203 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
205 if(This->callback) {
206 BINDINFO bindinfo;
207 HRESULT hres;
209 memset(&bindinfo, 0, sizeof(bindinfo));
210 bindinfo.cbSize = sizeof(bindinfo);
212 hres = IBindStatusCallback_GetBindInfo(This->callback, &bindf, &bindinfo);
213 if(SUCCEEDED(hres))
214 ReleaseBindInfo(&bindinfo);
217 *grfBINDF = BINDF_PULLDATA | BINDF_NEEDFILE | (bindf & BINDF_ENFORCERESTRICTED);
218 return S_OK;
221 static HRESULT WINAPI DownloadBSC_OnDataAvailable(IBindStatusCallback *iface,
222 DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
224 DownloadBSC *This = impl_from_IBindStatusCallback(iface);
226 TRACE("(%p)->(%08x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
228 return S_OK;
231 static HRESULT WINAPI DownloadBSC_OnObjectAvailable(IBindStatusCallback *iface,
232 REFIID riid, IUnknown *punk)
234 DownloadBSC *This = impl_from_IBindStatusCallback(iface);
235 FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), punk);
236 return E_NOTIMPL;
239 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
240 DownloadBSC_QueryInterface,
241 DownloadBSC_AddRef,
242 DownloadBSC_Release,
243 DownloadBSC_OnStartBinding,
244 DownloadBSC_GetPriority,
245 DownloadBSC_OnLowResource,
246 DownloadBSC_OnProgress,
247 DownloadBSC_OnStopBinding,
248 DownloadBSC_GetBindInfo,
249 DownloadBSC_OnDataAvailable,
250 DownloadBSC_OnObjectAvailable
253 static HRESULT WINAPI DwlServiceProvider_QueryInterface(IServiceProvider *iface,
254 REFIID riid, void **ppv)
256 DownloadBSC *This = impl_from_IServiceProvider(iface);
257 return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
260 static ULONG WINAPI DwlServiceProvider_AddRef(IServiceProvider *iface)
262 DownloadBSC *This = impl_from_IServiceProvider(iface);
263 return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
266 static ULONG WINAPI DwlServiceProvider_Release(IServiceProvider *iface)
268 DownloadBSC *This = impl_from_IServiceProvider(iface);
269 return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
272 static HRESULT WINAPI DwlServiceProvider_QueryService(IServiceProvider *iface,
273 REFGUID guidService, REFIID riid, void **ppv)
275 DownloadBSC *This = impl_from_IServiceProvider(iface);
276 IServiceProvider *serv_prov;
277 HRESULT hres;
279 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
281 if(!This->callback)
282 return E_NOINTERFACE;
284 hres = IBindStatusCallback_QueryInterface(This->callback, riid, ppv);
285 if(SUCCEEDED(hres))
286 return S_OK;
288 hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IServiceProvider, (void**)&serv_prov);
289 if(SUCCEEDED(hres)) {
290 hres = IServiceProvider_QueryService(serv_prov, guidService, riid, ppv);
291 IServiceProvider_Release(serv_prov);
292 return hres;
295 return E_NOINTERFACE;
298 static const IServiceProviderVtbl ServiceProviderVtbl = {
299 DwlServiceProvider_QueryInterface,
300 DwlServiceProvider_AddRef,
301 DwlServiceProvider_Release,
302 DwlServiceProvider_QueryService
305 static HRESULT DownloadBSC_Create(IBindStatusCallback *callback, LPCWSTR file_name, IBindStatusCallback **ret_callback)
307 DownloadBSC *ret = heap_alloc(sizeof(*ret));
309 ret->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl;
310 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
311 ret->ref = 1;
312 ret->file_name = heap_strdupW(file_name);
313 ret->cache_file = NULL;
315 if(callback)
316 IBindStatusCallback_AddRef(callback);
317 ret->callback = callback;
319 *ret_callback = &ret->IBindStatusCallback_iface;
320 return S_OK;
323 HRESULT create_default_callback(IBindStatusCallback **ret)
325 IBindStatusCallback *callback;
326 HRESULT hres;
328 hres = DownloadBSC_Create(NULL, NULL, &callback);
329 if(FAILED(hres))
330 return hres;
332 hres = wrap_callback(callback, ret);
333 IBindStatusCallback_Release(callback);
334 return hres;
337 /***********************************************************************
338 * URLDownloadToFileW (URLMON.@)
340 * Downloads URL szURL to file szFileName and call lpfnCB callback to
341 * report progress.
343 * PARAMS
344 * pCaller [I] controlling IUnknown interface.
345 * szURL [I] URL of the file to download
346 * szFileName [I] file name to store the content of the URL
347 * dwReserved [I] reserved - set to 0
348 * lpfnCB [I] callback for progress report
350 * RETURNS
351 * S_OK on success
353 HRESULT WINAPI URLDownloadToFileW(LPUNKNOWN pCaller, LPCWSTR szURL, LPCWSTR szFileName,
354 DWORD dwReserved, LPBINDSTATUSCALLBACK lpfnCB)
356 IBindStatusCallback *callback;
357 IUnknown *unk;
358 IMoniker *mon;
359 IBindCtx *bindctx;
360 HRESULT hres;
362 TRACE("(%p %s %s %d %p)\n", pCaller, debugstr_w(szURL), debugstr_w(szFileName), dwReserved, lpfnCB);
364 if(pCaller)
365 FIXME("pCaller not supported\n");
367 hres = DownloadBSC_Create(lpfnCB, szFileName, &callback);
368 if(FAILED(hres))
369 return hres;
371 hres = CreateAsyncBindCtx(0, callback, NULL, &bindctx);
372 IBindStatusCallback_Release(callback);
373 if(FAILED(hres))
374 return hres;
376 hres = CreateURLMoniker(NULL, szURL, &mon);
377 if(FAILED(hres)) {
378 IBindCtx_Release(bindctx);
379 return hres;
382 hres = IMoniker_BindToStorage(mon, bindctx, NULL, &IID_IUnknown, (void**)&unk);
383 IMoniker_Release(mon);
384 IBindCtx_Release(bindctx);
386 if(unk)
387 IUnknown_Release(unk);
389 return hres == MK_S_ASYNCHRONOUS ? S_OK : hres;
392 /***********************************************************************
393 * URLDownloadToFileA (URLMON.@)
395 * Downloads URL szURL to rile szFileName and call lpfnCB callback to
396 * report progress.
398 * PARAMS
399 * pCaller [I] controlling IUnknown interface.
400 * szURL [I] URL of the file to download
401 * szFileName [I] file name to store the content of the URL
402 * dwReserved [I] reserved - set to 0
403 * lpfnCB [I] callback for progress report
405 * RETURNS
406 * S_OK on success
408 HRESULT WINAPI URLDownloadToFileA(LPUNKNOWN pCaller, LPCSTR szURL, LPCSTR szFileName, DWORD dwReserved,
409 LPBINDSTATUSCALLBACK lpfnCB)
411 LPWSTR urlW, file_nameW;
412 HRESULT hres;
414 TRACE("(%p %s %s %d %p)\n", pCaller, debugstr_a(szURL), debugstr_a(szFileName), dwReserved, lpfnCB);
416 urlW = heap_strdupAtoW(szURL);
417 file_nameW = heap_strdupAtoW(szFileName);
419 hres = URLDownloadToFileW(pCaller, urlW, file_nameW, dwReserved, lpfnCB);
421 heap_free(urlW);
422 heap_free(file_nameW);
424 return hres;