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
);
25 IBindStatusCallback IBindStatusCallback_iface
;
26 IServiceProvider IServiceProvider_iface
;
30 IBindStatusCallback
*callback
;
36 stop_cache_binding_proc_t onstop_proc
;
40 static inline DownloadBSC
*impl_from_IBindStatusCallback(IBindStatusCallback
*iface
)
42 return CONTAINING_RECORD(iface
, DownloadBSC
, IBindStatusCallback_iface
);
45 static inline DownloadBSC
*impl_from_IServiceProvider(IServiceProvider
*iface
)
47 return CONTAINING_RECORD(iface
, DownloadBSC
, IServiceProvider_iface
);
50 static HRESULT WINAPI
DownloadBSC_QueryInterface(IBindStatusCallback
*iface
,
51 REFIID riid
, void **ppv
)
53 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
57 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
58 TRACE("(%p)->(IID_IUnknown, %p)\n", This
, ppv
);
59 *ppv
= &This
->IBindStatusCallback_iface
;
60 }else if(IsEqualGUID(&IID_IBindStatusCallback
, riid
)) {
61 TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This
, ppv
);
62 *ppv
= &This
->IBindStatusCallback_iface
;
63 }else if(IsEqualGUID(&IID_IServiceProvider
, riid
)) {
64 TRACE("(%p)->(IID_IServiceProvider, %p)\n", This
, ppv
);
65 *ppv
= &This
->IServiceProvider_iface
;
69 IUnknown_AddRef((IUnknown
*)*ppv
);
73 TRACE("Unsupported riid = %s\n", debugstr_guid(riid
));
77 static ULONG WINAPI
DownloadBSC_AddRef(IBindStatusCallback
*iface
)
79 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
80 LONG ref
= InterlockedIncrement(&This
->ref
);
82 TRACE("(%p) ref = %ld\n", This
, ref
);
87 static ULONG WINAPI
DownloadBSC_Release(IBindStatusCallback
*iface
)
89 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
90 LONG ref
= InterlockedDecrement(&This
->ref
);
92 TRACE("(%p) ref = %ld\n", This
, ref
);
96 IBindStatusCallback_Release(This
->callback
);
98 IBinding_Release(This
->binding
);
99 free(This
->file_name
);
100 free(This
->cache_file
);
107 static HRESULT WINAPI
DownloadBSC_OnStartBinding(IBindStatusCallback
*iface
,
108 DWORD dwReserved
, IBinding
*pbind
)
110 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
113 TRACE("(%p)->(%ld %p)\n", This
, dwReserved
, pbind
);
116 hres
= IBindStatusCallback_OnStartBinding(This
->callback
, dwReserved
, pbind
);
118 IBinding_AddRef(pbind
);
119 This
->binding
= pbind
;
122 /* Windows seems to ignore E_NOTIMPL if it's returned from the client. */
123 return hres
== E_NOTIMPL
? S_OK
: hres
;
126 static HRESULT WINAPI
DownloadBSC_GetPriority(IBindStatusCallback
*iface
, LONG
*pnPriority
)
128 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
129 FIXME("(%p)->(%p)\n", This
, pnPriority
);
133 static HRESULT WINAPI
DownloadBSC_OnLowResource(IBindStatusCallback
*iface
, DWORD reserved
)
135 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
136 FIXME("(%p)->(%ld)\n", This
, reserved
);
140 static HRESULT
on_progress(DownloadBSC
*This
, ULONG progress
, ULONG progress_max
, ULONG status_code
, LPCWSTR status_text
)
147 hres
= IBindStatusCallback_OnProgress(This
->callback
, progress
, progress_max
, status_code
, status_text
);
148 if(hres
== E_ABORT
) {
150 IBinding_Abort(This
->binding
);
152 FIXME("No binding, not sure what to do!\n");
158 static HRESULT WINAPI
DownloadBSC_OnProgress(IBindStatusCallback
*iface
, ULONG ulProgress
,
159 ULONG ulProgressMax
, ULONG ulStatusCode
, LPCWSTR szStatusText
)
161 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
164 TRACE("%p)->(%lu %lu %lu %s)\n", This
, ulProgress
, ulProgressMax
, ulStatusCode
,
165 debugstr_w(szStatusText
));
167 switch(ulStatusCode
) {
168 case BINDSTATUS_CONNECTING
:
169 case BINDSTATUS_BEGINDOWNLOADDATA
:
170 case BINDSTATUS_DOWNLOADINGDATA
:
171 case BINDSTATUS_ENDDOWNLOADDATA
:
172 case BINDSTATUS_SENDINGREQUEST
:
173 case BINDSTATUS_MIMETYPEAVAILABLE
:
174 hres
= on_progress(This
, ulProgress
, ulProgressMax
, ulStatusCode
, szStatusText
);
177 case BINDSTATUS_CACHEFILENAMEAVAILABLE
:
178 hres
= on_progress(This
, ulProgress
, ulProgressMax
, ulStatusCode
, szStatusText
);
179 This
->cache_file
= wcsdup(szStatusText
);
182 case BINDSTATUS_FINDINGRESOURCE
: /* FIXME */
186 FIXME("Unsupported status %lu\n", ulStatusCode
);
192 static HRESULT WINAPI
DownloadBSC_OnStopBinding(IBindStatusCallback
*iface
,
193 HRESULT hresult
, LPCWSTR szError
)
195 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
198 TRACE("(%p)->(%08lx %s)\n", This
, hresult
, debugstr_w(szError
));
200 if(This
->file_name
) {
201 if(This
->cache_file
) {
204 b
= CopyFileW(This
->cache_file
, This
->file_name
, FALSE
);
206 FIXME("CopyFile failed: %lu\n", GetLastError());
208 FIXME("No cache file\n");
212 if(This
->onstop_proc
)
213 hres
= This
->onstop_proc(This
->ctx
, This
->cache_file
, hresult
, szError
);
214 else if(This
->callback
)
215 IBindStatusCallback_OnStopBinding(This
->callback
, hresult
, szError
);
218 IBinding_Release(This
->binding
);
219 This
->binding
= NULL
;
225 static HRESULT WINAPI
DownloadBSC_GetBindInfo(IBindStatusCallback
*iface
,
226 DWORD
*grfBINDF
, BINDINFO
*pbindinfo
)
228 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
231 TRACE("(%p)->(%p %p)\n", This
, grfBINDF
, pbindinfo
);
237 memset(&bindinfo
, 0, sizeof(bindinfo
));
238 bindinfo
.cbSize
= sizeof(bindinfo
);
240 hres
= IBindStatusCallback_GetBindInfo(This
->callback
, &bindf
, &bindinfo
);
242 ReleaseBindInfo(&bindinfo
);
245 *grfBINDF
= BINDF_PULLDATA
| BINDF_NEEDFILE
| (bindf
& BINDF_ENFORCERESTRICTED
) | This
->bindf
;
249 static HRESULT WINAPI
DownloadBSC_OnDataAvailable(IBindStatusCallback
*iface
,
250 DWORD grfBSCF
, DWORD dwSize
, FORMATETC
*pformatetc
, STGMEDIUM
*pstgmed
)
252 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
254 TRACE("(%p)->(%08lx %ld %p %p)\n", This
, grfBSCF
, dwSize
, pformatetc
, pstgmed
);
259 static HRESULT WINAPI
DownloadBSC_OnObjectAvailable(IBindStatusCallback
*iface
,
260 REFIID riid
, IUnknown
*punk
)
262 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
263 FIXME("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), punk
);
267 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl
= {
268 DownloadBSC_QueryInterface
,
271 DownloadBSC_OnStartBinding
,
272 DownloadBSC_GetPriority
,
273 DownloadBSC_OnLowResource
,
274 DownloadBSC_OnProgress
,
275 DownloadBSC_OnStopBinding
,
276 DownloadBSC_GetBindInfo
,
277 DownloadBSC_OnDataAvailable
,
278 DownloadBSC_OnObjectAvailable
281 static HRESULT WINAPI
DwlServiceProvider_QueryInterface(IServiceProvider
*iface
,
282 REFIID riid
, void **ppv
)
284 DownloadBSC
*This
= impl_from_IServiceProvider(iface
);
285 return IBindStatusCallback_QueryInterface(&This
->IBindStatusCallback_iface
, riid
, ppv
);
288 static ULONG WINAPI
DwlServiceProvider_AddRef(IServiceProvider
*iface
)
290 DownloadBSC
*This
= impl_from_IServiceProvider(iface
);
291 return IBindStatusCallback_AddRef(&This
->IBindStatusCallback_iface
);
294 static ULONG WINAPI
DwlServiceProvider_Release(IServiceProvider
*iface
)
296 DownloadBSC
*This
= impl_from_IServiceProvider(iface
);
297 return IBindStatusCallback_Release(&This
->IBindStatusCallback_iface
);
300 static HRESULT WINAPI
DwlServiceProvider_QueryService(IServiceProvider
*iface
,
301 REFGUID guidService
, REFIID riid
, void **ppv
)
303 DownloadBSC
*This
= impl_from_IServiceProvider(iface
);
304 IServiceProvider
*serv_prov
;
307 TRACE("(%p)->(%s %s %p)\n", This
, debugstr_guid(guidService
), debugstr_guid(riid
), ppv
);
310 return E_NOINTERFACE
;
312 hres
= IBindStatusCallback_QueryInterface(This
->callback
, riid
, ppv
);
316 hres
= IBindStatusCallback_QueryInterface(This
->callback
, &IID_IServiceProvider
, (void**)&serv_prov
);
317 if(SUCCEEDED(hres
)) {
318 hres
= IServiceProvider_QueryService(serv_prov
, guidService
, riid
, ppv
);
319 IServiceProvider_Release(serv_prov
);
323 return E_NOINTERFACE
;
326 static const IServiceProviderVtbl ServiceProviderVtbl
= {
327 DwlServiceProvider_QueryInterface
,
328 DwlServiceProvider_AddRef
,
329 DwlServiceProvider_Release
,
330 DwlServiceProvider_QueryService
333 static HRESULT
DownloadBSC_Create(IBindStatusCallback
*callback
, LPCWSTR file_name
, DownloadBSC
**ret_callback
)
337 ret
= calloc(1, sizeof(*ret
));
339 return E_OUTOFMEMORY
;
341 ret
->IBindStatusCallback_iface
.lpVtbl
= &BindStatusCallbackVtbl
;
342 ret
->IServiceProvider_iface
.lpVtbl
= &ServiceProviderVtbl
;
346 ret
->file_name
= wcsdup(file_name
);
347 if(!ret
->file_name
) {
349 return E_OUTOFMEMORY
;
354 IBindStatusCallback_AddRef(callback
);
355 ret
->callback
= callback
;
361 HRESULT
create_default_callback(IBindStatusCallback
**ret
)
363 DownloadBSC
*callback
;
366 hres
= DownloadBSC_Create(NULL
, NULL
, &callback
);
370 hres
= wrap_callback(&callback
->IBindStatusCallback_iface
, ret
);
371 IBindStatusCallback_Release(&callback
->IBindStatusCallback_iface
);
375 HRESULT
download_to_cache(IUri
*uri
, stop_cache_binding_proc_t proc
, void *ctx
, IBindStatusCallback
*callback
)
377 DownloadBSC
*dwl_bsc
;
383 hres
= DownloadBSC_Create(callback
, NULL
, &dwl_bsc
);
387 dwl_bsc
->onstop_proc
= proc
;
389 dwl_bsc
->bindf
= BINDF_ASYNCHRONOUS
;
391 hres
= CreateAsyncBindCtx(0, &dwl_bsc
->IBindStatusCallback_iface
, NULL
, &bindctx
);
392 IBindStatusCallback_Release(&dwl_bsc
->IBindStatusCallback_iface
);
396 hres
= CreateURLMonikerEx2(NULL
, uri
, &mon
, 0);
398 IBindCtx_Release(bindctx
);
402 hres
= IMoniker_BindToStorage(mon
, bindctx
, NULL
, &IID_IUnknown
, (void**)&unk
);
403 IMoniker_Release(mon
);
404 IBindCtx_Release(bindctx
);
405 if(SUCCEEDED(hres
) && unk
)
406 IUnknown_Release(unk
);
411 /***********************************************************************
412 * URLDownloadToFileW (URLMON.@)
414 * Downloads URL szURL to file szFileName and call lpfnCB callback to
418 * pCaller [I] controlling IUnknown interface.
419 * szURL [I] URL of the file to download
420 * szFileName [I] file name to store the content of the URL
421 * dwReserved [I] reserved - set to 0
422 * lpfnCB [I] callback for progress report
427 HRESULT WINAPI
URLDownloadToFileW(LPUNKNOWN pCaller
, LPCWSTR szURL
, LPCWSTR szFileName
,
428 DWORD dwReserved
, LPBINDSTATUSCALLBACK lpfnCB
)
430 DownloadBSC
*callback
;
436 TRACE("(%p %s %s %ld %p)\n", pCaller
, debugstr_w(szURL
), debugstr_w(szFileName
), dwReserved
, lpfnCB
);
439 FIXME("pCaller not supported\n");
441 hres
= DownloadBSC_Create(lpfnCB
, szFileName
, &callback
);
445 hres
= CreateAsyncBindCtx(0, &callback
->IBindStatusCallback_iface
, NULL
, &bindctx
);
446 IBindStatusCallback_Release(&callback
->IBindStatusCallback_iface
);
450 hres
= CreateURLMoniker(NULL
, szURL
, &mon
);
452 IBindCtx_Release(bindctx
);
456 hres
= IMoniker_BindToStorage(mon
, bindctx
, NULL
, &IID_IUnknown
, (void**)&unk
);
457 IMoniker_Release(mon
);
458 IBindCtx_Release(bindctx
);
461 IUnknown_Release(unk
);
463 return hres
== MK_S_ASYNCHRONOUS
? S_OK
: hres
;
466 /***********************************************************************
467 * URLDownloadToFileA (URLMON.@)
469 * Downloads URL szURL to rile szFileName and call lpfnCB callback to
473 * pCaller [I] controlling IUnknown interface.
474 * szURL [I] URL of the file to download
475 * szFileName [I] file name to store the content of the URL
476 * dwReserved [I] reserved - set to 0
477 * lpfnCB [I] callback for progress report
482 HRESULT WINAPI
URLDownloadToFileA(LPUNKNOWN pCaller
, LPCSTR szURL
, LPCSTR szFileName
, DWORD dwReserved
,
483 LPBINDSTATUSCALLBACK lpfnCB
)
485 LPWSTR urlW
, file_nameW
;
488 TRACE("(%p %s %s %ld %p)\n", pCaller
, debugstr_a(szURL
), debugstr_a(szFileName
), dwReserved
, lpfnCB
);
490 urlW
= strdupAtoW(szURL
);
491 file_nameW
= strdupAtoW(szFileName
);
493 hres
= URLDownloadToFileW(pCaller
, urlW
, file_nameW
, dwReserved
, lpfnCB
);