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"
22 IBindStatusCallback IBindStatusCallback_iface
;
23 IServiceProvider IServiceProvider_iface
;
27 IBindStatusCallback
*callback
;
33 stop_cache_binding_proc_t onstop_proc
;
37 static inline DownloadBSC
*impl_from_IBindStatusCallback(IBindStatusCallback
*iface
)
39 return CONTAINING_RECORD(iface
, DownloadBSC
, IBindStatusCallback_iface
);
42 static inline DownloadBSC
*impl_from_IServiceProvider(IServiceProvider
*iface
)
44 return CONTAINING_RECORD(iface
, DownloadBSC
, IServiceProvider_iface
);
47 static HRESULT WINAPI
DownloadBSC_QueryInterface(IBindStatusCallback
*iface
,
48 REFIID riid
, void **ppv
)
50 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
54 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
55 TRACE("(%p)->(IID_IUnknown, %p)\n", This
, ppv
);
56 *ppv
= &This
->IBindStatusCallback_iface
;
57 }else if(IsEqualGUID(&IID_IBindStatusCallback
, riid
)) {
58 TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This
, ppv
);
59 *ppv
= &This
->IBindStatusCallback_iface
;
60 }else if(IsEqualGUID(&IID_IServiceProvider
, riid
)) {
61 TRACE("(%p)->(IID_IServiceProvider, %p)\n", This
, ppv
);
62 *ppv
= &This
->IServiceProvider_iface
;
66 IUnknown_AddRef((IUnknown
*)*ppv
);
70 TRACE("Unsupported riid = %s\n", debugstr_guid(riid
));
74 static ULONG WINAPI
DownloadBSC_AddRef(IBindStatusCallback
*iface
)
76 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
77 LONG ref
= InterlockedIncrement(&This
->ref
);
79 TRACE("(%p) ref = %d\n", This
, ref
);
84 static ULONG WINAPI
DownloadBSC_Release(IBindStatusCallback
*iface
)
86 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
87 LONG ref
= InterlockedDecrement(&This
->ref
);
89 TRACE("(%p) ref = %d\n", This
, ref
);
93 IBindStatusCallback_Release(This
->callback
);
95 IBinding_Release(This
->binding
);
96 heap_free(This
->file_name
);
97 heap_free(This
->cache_file
);
104 static HRESULT WINAPI
DownloadBSC_OnStartBinding(IBindStatusCallback
*iface
,
105 DWORD dwReserved
, IBinding
*pbind
)
107 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
110 TRACE("(%p)->(%d %p)\n", This
, dwReserved
, pbind
);
113 hres
= IBindStatusCallback_OnStartBinding(This
->callback
, dwReserved
, pbind
);
115 IBinding_AddRef(pbind
);
116 This
->binding
= pbind
;
119 /* Windows seems to ignore E_NOTIMPL if it's returned from the client. */
120 return hres
== E_NOTIMPL
? S_OK
: hres
;
123 static HRESULT WINAPI
DownloadBSC_GetPriority(IBindStatusCallback
*iface
, LONG
*pnPriority
)
125 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
126 FIXME("(%p)->(%p)\n", This
, pnPriority
);
130 static HRESULT WINAPI
DownloadBSC_OnLowResource(IBindStatusCallback
*iface
, DWORD reserved
)
132 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
133 FIXME("(%p)->(%d)\n", This
, reserved
);
137 static HRESULT
on_progress(DownloadBSC
*This
, ULONG progress
, ULONG progress_max
, ULONG status_code
, LPCWSTR status_text
)
144 hres
= IBindStatusCallback_OnProgress(This
->callback
, progress
, progress_max
, status_code
, status_text
);
145 if(hres
== E_ABORT
) {
147 IBinding_Abort(This
->binding
);
149 FIXME("No binding, not sure what to do!\n");
155 static HRESULT WINAPI
DownloadBSC_OnProgress(IBindStatusCallback
*iface
, ULONG ulProgress
,
156 ULONG ulProgressMax
, ULONG ulStatusCode
, LPCWSTR szStatusText
)
158 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
161 TRACE("%p)->(%u %u %u %s)\n", This
, ulProgress
, ulProgressMax
, ulStatusCode
,
162 debugstr_w(szStatusText
));
164 switch(ulStatusCode
) {
165 case BINDSTATUS_CONNECTING
:
166 case BINDSTATUS_BEGINDOWNLOADDATA
:
167 case BINDSTATUS_DOWNLOADINGDATA
:
168 case BINDSTATUS_ENDDOWNLOADDATA
:
169 case BINDSTATUS_SENDINGREQUEST
:
170 case BINDSTATUS_MIMETYPEAVAILABLE
:
171 hres
= on_progress(This
, ulProgress
, ulProgressMax
, ulStatusCode
, szStatusText
);
174 case BINDSTATUS_CACHEFILENAMEAVAILABLE
:
175 hres
= on_progress(This
, ulProgress
, ulProgressMax
, ulStatusCode
, szStatusText
);
176 This
->cache_file
= heap_strdupW(szStatusText
);
179 case BINDSTATUS_FINDINGRESOURCE
: /* FIXME */
183 FIXME("Unsupported status %u\n", ulStatusCode
);
189 static HRESULT WINAPI
DownloadBSC_OnStopBinding(IBindStatusCallback
*iface
,
190 HRESULT hresult
, LPCWSTR szError
)
192 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
195 TRACE("(%p)->(%08x %s)\n", This
, hresult
, debugstr_w(szError
));
197 if(This
->file_name
) {
198 if(This
->cache_file
) {
201 b
= CopyFileW(This
->cache_file
, This
->file_name
, FALSE
);
203 FIXME("CopyFile failed: %u\n", GetLastError());
205 FIXME("No cache file\n");
209 if(This
->onstop_proc
)
210 hres
= This
->onstop_proc(This
->ctx
, This
->cache_file
, hresult
, szError
);
211 else if(This
->callback
)
212 IBindStatusCallback_OnStopBinding(This
->callback
, hresult
, szError
);
215 IBinding_Release(This
->binding
);
216 This
->binding
= NULL
;
222 static HRESULT WINAPI
DownloadBSC_GetBindInfo(IBindStatusCallback
*iface
,
223 DWORD
*grfBINDF
, BINDINFO
*pbindinfo
)
225 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
228 TRACE("(%p)->(%p %p)\n", This
, grfBINDF
, pbindinfo
);
234 memset(&bindinfo
, 0, sizeof(bindinfo
));
235 bindinfo
.cbSize
= sizeof(bindinfo
);
237 hres
= IBindStatusCallback_GetBindInfo(This
->callback
, &bindf
, &bindinfo
);
239 ReleaseBindInfo(&bindinfo
);
242 *grfBINDF
= BINDF_PULLDATA
| BINDF_NEEDFILE
| (bindf
& BINDF_ENFORCERESTRICTED
) | This
->bindf
;
246 static HRESULT WINAPI
DownloadBSC_OnDataAvailable(IBindStatusCallback
*iface
,
247 DWORD grfBSCF
, DWORD dwSize
, FORMATETC
*pformatetc
, STGMEDIUM
*pstgmed
)
249 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
251 TRACE("(%p)->(%08x %d %p %p)\n", This
, grfBSCF
, dwSize
, pformatetc
, pstgmed
);
256 static HRESULT WINAPI
DownloadBSC_OnObjectAvailable(IBindStatusCallback
*iface
,
257 REFIID riid
, IUnknown
*punk
)
259 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
260 FIXME("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), punk
);
264 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl
= {
265 DownloadBSC_QueryInterface
,
268 DownloadBSC_OnStartBinding
,
269 DownloadBSC_GetPriority
,
270 DownloadBSC_OnLowResource
,
271 DownloadBSC_OnProgress
,
272 DownloadBSC_OnStopBinding
,
273 DownloadBSC_GetBindInfo
,
274 DownloadBSC_OnDataAvailable
,
275 DownloadBSC_OnObjectAvailable
278 static HRESULT WINAPI
DwlServiceProvider_QueryInterface(IServiceProvider
*iface
,
279 REFIID riid
, void **ppv
)
281 DownloadBSC
*This
= impl_from_IServiceProvider(iface
);
282 return IBindStatusCallback_QueryInterface(&This
->IBindStatusCallback_iface
, riid
, ppv
);
285 static ULONG WINAPI
DwlServiceProvider_AddRef(IServiceProvider
*iface
)
287 DownloadBSC
*This
= impl_from_IServiceProvider(iface
);
288 return IBindStatusCallback_AddRef(&This
->IBindStatusCallback_iface
);
291 static ULONG WINAPI
DwlServiceProvider_Release(IServiceProvider
*iface
)
293 DownloadBSC
*This
= impl_from_IServiceProvider(iface
);
294 return IBindStatusCallback_Release(&This
->IBindStatusCallback_iface
);
297 static HRESULT WINAPI
DwlServiceProvider_QueryService(IServiceProvider
*iface
,
298 REFGUID guidService
, REFIID riid
, void **ppv
)
300 DownloadBSC
*This
= impl_from_IServiceProvider(iface
);
301 IServiceProvider
*serv_prov
;
304 TRACE("(%p)->(%s %s %p)\n", This
, debugstr_guid(guidService
), debugstr_guid(riid
), ppv
);
307 return E_NOINTERFACE
;
309 hres
= IBindStatusCallback_QueryInterface(This
->callback
, riid
, ppv
);
313 hres
= IBindStatusCallback_QueryInterface(This
->callback
, &IID_IServiceProvider
, (void**)&serv_prov
);
314 if(SUCCEEDED(hres
)) {
315 hres
= IServiceProvider_QueryService(serv_prov
, guidService
, riid
, ppv
);
316 IServiceProvider_Release(serv_prov
);
320 return E_NOINTERFACE
;
323 static const IServiceProviderVtbl ServiceProviderVtbl
= {
324 DwlServiceProvider_QueryInterface
,
325 DwlServiceProvider_AddRef
,
326 DwlServiceProvider_Release
,
327 DwlServiceProvider_QueryService
330 static HRESULT
DownloadBSC_Create(IBindStatusCallback
*callback
, LPCWSTR file_name
, DownloadBSC
**ret_callback
)
334 ret
= heap_alloc_zero(sizeof(*ret
));
336 return E_OUTOFMEMORY
;
338 ret
->IBindStatusCallback_iface
.lpVtbl
= &BindStatusCallbackVtbl
;
339 ret
->IServiceProvider_iface
.lpVtbl
= &ServiceProviderVtbl
;
343 ret
->file_name
= heap_strdupW(file_name
);
344 if(!ret
->file_name
) {
346 return E_OUTOFMEMORY
;
351 IBindStatusCallback_AddRef(callback
);
352 ret
->callback
= callback
;
358 HRESULT
create_default_callback(IBindStatusCallback
**ret
)
360 DownloadBSC
*callback
;
363 hres
= DownloadBSC_Create(NULL
, NULL
, &callback
);
367 hres
= wrap_callback(&callback
->IBindStatusCallback_iface
, ret
);
368 IBindStatusCallback_Release(&callback
->IBindStatusCallback_iface
);
372 HRESULT
download_to_cache(IUri
*uri
, stop_cache_binding_proc_t proc
, void *ctx
, IBindStatusCallback
*callback
)
374 DownloadBSC
*dwl_bsc
;
380 hres
= DownloadBSC_Create(callback
, NULL
, &dwl_bsc
);
384 dwl_bsc
->onstop_proc
= proc
;
386 dwl_bsc
->bindf
= BINDF_ASYNCHRONOUS
;
388 hres
= CreateAsyncBindCtx(0, &dwl_bsc
->IBindStatusCallback_iface
, NULL
, &bindctx
);
389 IBindStatusCallback_Release(&dwl_bsc
->IBindStatusCallback_iface
);
393 hres
= CreateURLMonikerEx2(NULL
, uri
, &mon
, 0);
395 IBindCtx_Release(bindctx
);
399 hres
= IMoniker_BindToStorage(mon
, bindctx
, NULL
, &IID_IUnknown
, (void**)&unk
);
400 IMoniker_Release(mon
);
401 IBindCtx_Release(bindctx
);
402 if(SUCCEEDED(hres
) && unk
)
403 IUnknown_Release(unk
);
408 /***********************************************************************
409 * URLDownloadToFileW (URLMON.@)
411 * Downloads URL szURL to file szFileName and call lpfnCB callback to
415 * pCaller [I] controlling IUnknown interface.
416 * szURL [I] URL of the file to download
417 * szFileName [I] file name to store the content of the URL
418 * dwReserved [I] reserved - set to 0
419 * lpfnCB [I] callback for progress report
424 HRESULT WINAPI
URLDownloadToFileW(LPUNKNOWN pCaller
, LPCWSTR szURL
, LPCWSTR szFileName
,
425 DWORD dwReserved
, LPBINDSTATUSCALLBACK lpfnCB
)
427 DownloadBSC
*callback
;
433 TRACE("(%p %s %s %d %p)\n", pCaller
, debugstr_w(szURL
), debugstr_w(szFileName
), dwReserved
, lpfnCB
);
436 FIXME("pCaller not supported\n");
438 hres
= DownloadBSC_Create(lpfnCB
, szFileName
, &callback
);
442 hres
= CreateAsyncBindCtx(0, &callback
->IBindStatusCallback_iface
, NULL
, &bindctx
);
443 IBindStatusCallback_Release(&callback
->IBindStatusCallback_iface
);
447 hres
= CreateURLMoniker(NULL
, szURL
, &mon
);
449 IBindCtx_Release(bindctx
);
453 hres
= IMoniker_BindToStorage(mon
, bindctx
, NULL
, &IID_IUnknown
, (void**)&unk
);
454 IMoniker_Release(mon
);
455 IBindCtx_Release(bindctx
);
458 IUnknown_Release(unk
);
460 return hres
== MK_S_ASYNCHRONOUS
? S_OK
: hres
;
463 /***********************************************************************
464 * URLDownloadToFileA (URLMON.@)
466 * Downloads URL szURL to rile szFileName and call lpfnCB callback to
470 * pCaller [I] controlling IUnknown interface.
471 * szURL [I] URL of the file to download
472 * szFileName [I] file name to store the content of the URL
473 * dwReserved [I] reserved - set to 0
474 * lpfnCB [I] callback for progress report
479 HRESULT WINAPI
URLDownloadToFileA(LPUNKNOWN pCaller
, LPCSTR szURL
, LPCSTR szFileName
, DWORD dwReserved
,
480 LPBINDSTATUSCALLBACK lpfnCB
)
482 LPWSTR urlW
, file_nameW
;
485 TRACE("(%p %s %s %d %p)\n", pCaller
, debugstr_a(szURL
), debugstr_a(szFileName
), dwReserved
, lpfnCB
);
487 urlW
= heap_strdupAtoW(szURL
);
488 file_nameW
= heap_strdupAtoW(szFileName
);
490 hres
= URLDownloadToFileW(pCaller
, urlW
, file_nameW
, dwReserved
, lpfnCB
);
493 heap_free(file_nameW
);