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 static inline DownloadBSC
*impl_from_IBindStatusCallback(IBindStatusCallback
*iface
)
38 return CONTAINING_RECORD(iface
, DownloadBSC
, IBindStatusCallback_iface
);
41 static inline DownloadBSC
*impl_from_IServiceProvider(IServiceProvider
*iface
)
43 return CONTAINING_RECORD(iface
, DownloadBSC
, IServiceProvider_iface
);
46 static HRESULT WINAPI
DownloadBSC_QueryInterface(IBindStatusCallback
*iface
,
47 REFIID riid
, void **ppv
)
49 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
53 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
54 TRACE("(%p)->(IID_IUnknown, %p)\n", This
, ppv
);
55 *ppv
= &This
->IBindStatusCallback_iface
;
56 }else if(IsEqualGUID(&IID_IBindStatusCallback
, riid
)) {
57 TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This
, ppv
);
58 *ppv
= &This
->IBindStatusCallback_iface
;
59 }else if(IsEqualGUID(&IID_IServiceProvider
, riid
)) {
60 TRACE("(%p)->(IID_IServiceProvider, %p)\n", This
, ppv
);
61 *ppv
= &This
->IServiceProvider_iface
;
65 IBindStatusCallback_AddRef((IUnknown
*)*ppv
);
69 TRACE("Unsupported riid = %s\n", debugstr_guid(riid
));
73 static ULONG WINAPI
DownloadBSC_AddRef(IBindStatusCallback
*iface
)
75 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
76 LONG ref
= InterlockedIncrement(&This
->ref
);
78 TRACE("(%p) ref = %d\n", This
, ref
);
83 static ULONG WINAPI
DownloadBSC_Release(IBindStatusCallback
*iface
)
85 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
86 LONG ref
= InterlockedDecrement(&This
->ref
);
88 TRACE("(%p) ref = %d\n", This
, ref
);
92 IBindStatusCallback_Release(This
->callback
);
94 IBinding_Release(This
->binding
);
95 heap_free(This
->file_name
);
96 heap_free(This
->cache_file
);
103 static HRESULT WINAPI
DownloadBSC_OnStartBinding(IBindStatusCallback
*iface
,
104 DWORD dwReserved
, IBinding
*pbind
)
106 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
109 TRACE("(%p)->(%d %p)\n", This
, dwReserved
, pbind
);
112 hres
= IBindStatusCallback_OnStartBinding(This
->callback
, dwReserved
, pbind
);
114 IBinding_AddRef(pbind
);
115 This
->binding
= pbind
;
118 /* Windows seems to ignore E_NOTIMPL if it's returned from the client. */
119 return hres
== E_NOTIMPL
? S_OK
: hres
;
122 static HRESULT WINAPI
DownloadBSC_GetPriority(IBindStatusCallback
*iface
, LONG
*pnPriority
)
124 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
125 FIXME("(%p)->(%p)\n", This
, pnPriority
);
129 static HRESULT WINAPI
DownloadBSC_OnLowResource(IBindStatusCallback
*iface
, DWORD reserved
)
131 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
132 FIXME("(%p)->(%d)\n", This
, reserved
);
136 static HRESULT
on_progress(DownloadBSC
*This
, ULONG progress
, ULONG progress_max
, ULONG status_code
, LPCWSTR status_text
)
143 hres
= IBindStatusCallback_OnProgress(This
->callback
, progress
, progress_max
, status_code
, status_text
);
144 if(hres
== E_ABORT
) {
146 IBinding_Abort(This
->binding
);
148 FIXME("No binding, not sure what to do!\n");
154 static HRESULT WINAPI
DownloadBSC_OnProgress(IBindStatusCallback
*iface
, ULONG ulProgress
,
155 ULONG ulProgressMax
, ULONG ulStatusCode
, LPCWSTR szStatusText
)
157 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
160 TRACE("%p)->(%u %u %u %s)\n", This
, ulProgress
, ulProgressMax
, ulStatusCode
,
161 debugstr_w(szStatusText
));
163 switch(ulStatusCode
) {
164 case BINDSTATUS_CONNECTING
:
165 case BINDSTATUS_BEGINDOWNLOADDATA
:
166 case BINDSTATUS_DOWNLOADINGDATA
:
167 case BINDSTATUS_ENDDOWNLOADDATA
:
168 case BINDSTATUS_SENDINGREQUEST
:
169 case BINDSTATUS_MIMETYPEAVAILABLE
:
170 hres
= on_progress(This
, ulProgress
, ulProgressMax
, ulStatusCode
, szStatusText
);
173 case BINDSTATUS_CACHEFILENAMEAVAILABLE
:
174 hres
= on_progress(This
, ulProgress
, ulProgressMax
, ulStatusCode
, szStatusText
);
175 This
->cache_file
= heap_strdupW(szStatusText
);
178 case BINDSTATUS_FINDINGRESOURCE
: /* FIXME */
182 FIXME("Unsupported status %u\n", ulStatusCode
);
188 static HRESULT WINAPI
DownloadBSC_OnStopBinding(IBindStatusCallback
*iface
,
189 HRESULT hresult
, LPCWSTR szError
)
191 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
193 TRACE("(%p)->(%08x %s)\n", This
, hresult
, debugstr_w(szError
));
195 if(This
->file_name
) {
196 if(This
->cache_file
) {
199 b
= CopyFileW(This
->cache_file
, This
->file_name
, FALSE
);
201 FIXME("CopyFile failed: %u\n", GetLastError());
203 FIXME("No cache file\n");
208 IBindStatusCallback_OnStopBinding(This
->callback
, hresult
, szError
);
211 IBinding_Release(This
->binding
);
212 This
->binding
= NULL
;
218 static HRESULT WINAPI
DownloadBSC_GetBindInfo(IBindStatusCallback
*iface
,
219 DWORD
*grfBINDF
, BINDINFO
*pbindinfo
)
221 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
224 TRACE("(%p)->(%p %p)\n", This
, grfBINDF
, pbindinfo
);
230 memset(&bindinfo
, 0, sizeof(bindinfo
));
231 bindinfo
.cbSize
= sizeof(bindinfo
);
233 hres
= IBindStatusCallback_GetBindInfo(This
->callback
, &bindf
, &bindinfo
);
235 ReleaseBindInfo(&bindinfo
);
238 *grfBINDF
= BINDF_PULLDATA
| BINDF_NEEDFILE
| (bindf
& BINDF_ENFORCERESTRICTED
);
242 static HRESULT WINAPI
DownloadBSC_OnDataAvailable(IBindStatusCallback
*iface
,
243 DWORD grfBSCF
, DWORD dwSize
, FORMATETC
*pformatetc
, STGMEDIUM
*pstgmed
)
245 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
247 TRACE("(%p)->(%08x %d %p %p)\n", This
, grfBSCF
, dwSize
, pformatetc
, pstgmed
);
252 static HRESULT WINAPI
DownloadBSC_OnObjectAvailable(IBindStatusCallback
*iface
,
253 REFIID riid
, IUnknown
*punk
)
255 DownloadBSC
*This
= impl_from_IBindStatusCallback(iface
);
256 FIXME("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), punk
);
260 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl
= {
261 DownloadBSC_QueryInterface
,
264 DownloadBSC_OnStartBinding
,
265 DownloadBSC_GetPriority
,
266 DownloadBSC_OnLowResource
,
267 DownloadBSC_OnProgress
,
268 DownloadBSC_OnStopBinding
,
269 DownloadBSC_GetBindInfo
,
270 DownloadBSC_OnDataAvailable
,
271 DownloadBSC_OnObjectAvailable
274 static HRESULT WINAPI
DwlServiceProvider_QueryInterface(IServiceProvider
*iface
,
275 REFIID riid
, void **ppv
)
277 DownloadBSC
*This
= impl_from_IServiceProvider(iface
);
278 return IBindStatusCallback_QueryInterface(&This
->IBindStatusCallback_iface
, riid
, ppv
);
281 static ULONG WINAPI
DwlServiceProvider_AddRef(IServiceProvider
*iface
)
283 DownloadBSC
*This
= impl_from_IServiceProvider(iface
);
284 return IBindStatusCallback_AddRef(&This
->IBindStatusCallback_iface
);
287 static ULONG WINAPI
DwlServiceProvider_Release(IServiceProvider
*iface
)
289 DownloadBSC
*This
= impl_from_IServiceProvider(iface
);
290 return IBindStatusCallback_Release(&This
->IBindStatusCallback_iface
);
293 static HRESULT WINAPI
DwlServiceProvider_QueryService(IServiceProvider
*iface
,
294 REFGUID guidService
, REFIID riid
, void **ppv
)
296 DownloadBSC
*This
= impl_from_IServiceProvider(iface
);
297 IServiceProvider
*serv_prov
;
300 TRACE("(%p)->(%s %s %p)\n", This
, debugstr_guid(guidService
), debugstr_guid(riid
), ppv
);
303 return E_NOINTERFACE
;
305 hres
= IBindStatusCallback_QueryInterface(This
->callback
, riid
, ppv
);
309 hres
= IBindStatusCallback_QueryInterface(This
->callback
, &IID_IServiceProvider
, (void**)&serv_prov
);
310 if(SUCCEEDED(hres
)) {
311 hres
= IServiceProvider_QueryService(serv_prov
, guidService
, riid
, ppv
);
312 IServiceProvider_Release(serv_prov
);
316 return E_NOINTERFACE
;
319 static const IServiceProviderVtbl ServiceProviderVtbl
= {
320 DwlServiceProvider_QueryInterface
,
321 DwlServiceProvider_AddRef
,
322 DwlServiceProvider_Release
,
323 DwlServiceProvider_QueryService
326 static HRESULT
DownloadBSC_Create(IBindStatusCallback
*callback
, LPCWSTR file_name
, IBindStatusCallback
**ret_callback
)
328 DownloadBSC
*ret
= heap_alloc(sizeof(*ret
));
330 ret
->IBindStatusCallback_iface
.lpVtbl
= &BindStatusCallbackVtbl
;
331 ret
->IServiceProvider_iface
.lpVtbl
= &ServiceProviderVtbl
;
333 ret
->file_name
= heap_strdupW(file_name
);
334 ret
->cache_file
= NULL
;
338 IBindStatusCallback_AddRef(callback
);
339 ret
->callback
= callback
;
341 *ret_callback
= &ret
->IBindStatusCallback_iface
;
345 HRESULT
create_default_callback(IBindStatusCallback
**ret
)
347 IBindStatusCallback
*callback
;
350 hres
= DownloadBSC_Create(NULL
, NULL
, &callback
);
354 hres
= wrap_callback(callback
, ret
);
355 IBindStatusCallback_Release(callback
);
359 /***********************************************************************
360 * URLDownloadToFileW (URLMON.@)
362 * Downloads URL szURL to file szFileName and call lpfnCB callback to
366 * pCaller [I] controlling IUnknown interface.
367 * szURL [I] URL of the file to download
368 * szFileName [I] file name to store the content of the URL
369 * dwReserved [I] reserved - set to 0
370 * lpfnCB [I] callback for progress report
375 HRESULT WINAPI
URLDownloadToFileW(LPUNKNOWN pCaller
, LPCWSTR szURL
, LPCWSTR szFileName
,
376 DWORD dwReserved
, LPBINDSTATUSCALLBACK lpfnCB
)
378 IBindStatusCallback
*callback
;
384 TRACE("(%p %s %s %d %p)\n", pCaller
, debugstr_w(szURL
), debugstr_w(szFileName
), dwReserved
, lpfnCB
);
387 FIXME("pCaller not supported\n");
389 hres
= DownloadBSC_Create(lpfnCB
, szFileName
, &callback
);
393 hres
= CreateAsyncBindCtx(0, callback
, NULL
, &bindctx
);
394 IBindStatusCallback_Release(callback
);
398 hres
= CreateURLMoniker(NULL
, szURL
, &mon
);
400 IBindCtx_Release(bindctx
);
404 hres
= IMoniker_BindToStorage(mon
, bindctx
, NULL
, &IID_IUnknown
, (void**)&unk
);
405 IMoniker_Release(mon
);
406 IBindCtx_Release(bindctx
);
409 IUnknown_Release(unk
);
411 return hres
== MK_S_ASYNCHRONOUS
? S_OK
: hres
;
414 /***********************************************************************
415 * URLDownloadToFileA (URLMON.@)
417 * Downloads URL szURL to rile szFileName and call lpfnCB callback to
421 * pCaller [I] controlling IUnknown interface.
422 * szURL [I] URL of the file to download
423 * szFileName [I] file name to store the content of the URL
424 * dwReserved [I] reserved - set to 0
425 * lpfnCB [I] callback for progress report
430 HRESULT WINAPI
URLDownloadToFileA(LPUNKNOWN pCaller
, LPCSTR szURL
, LPCSTR szFileName
, DWORD dwReserved
,
431 LPBINDSTATUSCALLBACK lpfnCB
)
433 LPWSTR urlW
, file_nameW
;
436 TRACE("(%p %s %s %d %p)\n", pCaller
, debugstr_a(szURL
), debugstr_a(szFileName
), dwReserved
, lpfnCB
);
438 urlW
= heap_strdupAtoW(szURL
);
439 file_nameW
= heap_strdupAtoW(szFileName
);
441 hres
= URLDownloadToFileW(pCaller
, urlW
, file_nameW
, dwReserved
, lpfnCB
);
444 heap_free(file_nameW
);