mshtml: Added IHTMLStyleSheet::get_rules implementation.
[wine] / dlls / urlmon / umstream.c
1 /*
2  * Based on ../shell32/memorystream.c
3  *
4  * Copyright 1999 Juergen Schmied
5  * Copyright 2003 Mike McCormack for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winternl.h"
30 #include "winuser.h"
31 #include "objbase.h"
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
34 #include "ole2.h"
35 #include "urlmon.h"
36 #include "wininet.h"
37 #include "shlwapi.h"
38 #include "urlmon_main.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
41
42 static const IStreamVtbl stvt;
43
44 HRESULT UMCreateStreamOnCacheFile(LPCWSTR pszURL,
45                                   DWORD dwSize,
46                                   LPWSTR pszFileName,
47                                   HANDLE *phfile,
48                                   IUMCacheStream **ppstr)
49 {
50     IUMCacheStream* ucstr;
51     HANDLE handle;
52     DWORD size;
53     LPWSTR url, c, ext = NULL;
54     HRESULT hr;
55
56     size = (strlenW(pszURL)+1)*sizeof(WCHAR);
57     url = heap_alloc(size);
58     memcpy(url, pszURL, size);
59
60     for (c = url; *c && *c != '#' && *c != '?'; ++c)
61     {
62         if (*c == '.')
63             ext = c+1;
64         else if(*c == '/')
65             ext = NULL;
66     }
67
68     *c = 0;
69
70     if(!CreateUrlCacheEntryW(url, dwSize, ext, pszFileName, 0))
71        hr = HRESULT_FROM_WIN32(GetLastError());
72     else
73        hr = 0;
74
75     heap_free(url);
76
77     if (hr)
78        return hr;
79
80     TRACE("Opening %s\n", debugstr_w(pszFileName) );
81
82     handle = CreateFileW( pszFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL );
83     if( handle == INVALID_HANDLE_VALUE )
84        return HRESULT_FROM_WIN32(GetLastError());
85
86     if (phfile)
87     {
88        /* Call CreateFileW again because we need a handle with its own file pointer, and DuplicateHandle will return
89         * a handle that shares its file pointer with the original.
90         */
91            *phfile = CreateFileW( pszFileName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
92
93        if (*phfile == (HANDLE) HFILE_ERROR)
94        {
95            DWORD dwError = GetLastError();
96
97            CloseHandle(handle);
98            return HRESULT_FROM_WIN32(dwError);
99        }
100     }
101
102     ucstr = heap_alloc_zero(sizeof(IUMCacheStream));
103     if(ucstr)
104     {
105        ucstr->pszURL = heap_alloc_zero(sizeof(WCHAR) * (lstrlenW(pszURL) + 1));
106        if (ucstr->pszURL)
107        {
108             ucstr->pszFileName = heap_alloc_zero(sizeof(WCHAR) * (lstrlenW(pszFileName) + 1));
109            if (ucstr->pszFileName)
110            {
111               ucstr->lpVtbl=&stvt;
112               ucstr->ref = 1;
113               ucstr->handle = handle;
114               ucstr->closed = 0;
115               lstrcpyW(ucstr->pszURL, pszURL);
116               lstrcpyW(ucstr->pszFileName, pszFileName);
117
118               *ppstr = ucstr;
119
120               return S_OK;
121            }
122            heap_free(ucstr->pszURL);
123        }
124        heap_free(ucstr);
125     }
126     CloseHandle(handle);
127     if (phfile)
128        CloseHandle(*phfile);
129     return E_OUTOFMEMORY;
130 }
131
132 void UMCloseCacheFileStream(IUMCacheStream *This)
133 {
134     if (!This->closed)
135     {
136        FILETIME ftZero;
137
138        ftZero.dwLowDateTime = ftZero.dwHighDateTime = 0;
139
140        This->closed = 1;
141        CommitUrlCacheEntryW(This->pszURL,
142                             This->pszFileName,
143                             ftZero,
144                             ftZero,
145                             NORMAL_CACHE_ENTRY,
146                             0,
147                             0,
148                             0,
149                             0);
150     }
151 }
152
153 /**************************************************************************
154 *  IStream_fnQueryInterface
155 */
156 static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface,
157                                                REFIID riid,
158                                                LPVOID *ppvObj)
159 {
160     IUMCacheStream *This = (IUMCacheStream *)iface;
161
162     TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
163
164     *ppvObj = NULL;
165
166     if(IsEqualIID(riid, &IID_IUnknown) ||
167        IsEqualIID(riid, &IID_IStream))
168     {
169       *ppvObj = This;
170     }
171
172     if(*ppvObj)
173     {
174       IStream_AddRef((IStream*)*ppvObj);
175       TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
176       return S_OK;
177     }
178     TRACE("-- Interface: E_NOINTERFACE\n");
179     return E_NOINTERFACE;
180 }
181
182 /**************************************************************************
183 *  IStream_fnAddRef
184 */
185 static ULONG WINAPI IStream_fnAddRef(IStream *iface)
186 {
187     IUMCacheStream *This = (IUMCacheStream *)iface;
188     ULONG refCount = InterlockedIncrement(&This->ref);
189
190     TRACE("(%p)->(count=%u)\n", This, refCount - 1);
191
192     return refCount;
193 }
194
195 /**************************************************************************
196 *  IStream_fnRelease
197 */
198 static ULONG WINAPI IStream_fnRelease(IStream *iface)
199 {
200     IUMCacheStream *This = (IUMCacheStream *)iface;
201     ULONG refCount = InterlockedDecrement(&This->ref);
202
203     TRACE("(%p)->(count=%u)\n", This, refCount + 1);
204
205     if (!refCount)
206     {
207        TRACE(" destroying UMCacheStream (%p)\n",This);
208        UMCloseCacheFileStream(This);
209        CloseHandle(This->handle);
210        heap_free(This->pszFileName);
211        heap_free(This->pszURL);
212        heap_free(This);
213     }
214     return refCount;
215 }
216
217 static HRESULT WINAPI IStream_fnRead (IStream * iface, 
218                                       void* pv,
219                                       ULONG cb,
220                                       ULONG* pcbRead)
221 {
222     ULONG dwBytesRead;
223     IUMCacheStream *This = (IUMCacheStream *)iface;
224
225     TRACE("(%p)->(%p,0x%08x,%p)\n",This, pv, cb, pcbRead);
226
227     if ( !pv )
228        return STG_E_INVALIDPOINTER;
229
230     if ( !pcbRead)
231         pcbRead = &dwBytesRead;
232
233     if ( ! ReadFile( This->handle, pv, cb, (LPDWORD)pcbRead, NULL ) )
234        return S_FALSE;
235
236     if (!*pcbRead)
237         return This->closed ? S_FALSE : E_PENDING;
238     return S_OK;
239 }
240
241 static HRESULT WINAPI IStream_fnWrite (IStream * iface,
242                                        const void* pv,
243                                        ULONG cb,
244                                        ULONG* pcbWritten)
245 {
246     return E_NOTIMPL;
247 }
248
249 static HRESULT WINAPI IStream_fnSeek (IStream * iface,
250                                    LARGE_INTEGER dlibMove,
251                                    DWORD dwOrigin,
252                                    ULARGE_INTEGER* plibNewPosition)
253 {
254     LARGE_INTEGER newpos;
255     IUMCacheStream *This = (IUMCacheStream *)iface;
256
257     TRACE("(%p)\n",This);
258
259     if (!SetFilePointerEx( This->handle, dlibMove, &newpos, dwOrigin ))
260        return E_FAIL;
261
262     if (plibNewPosition)
263         plibNewPosition->QuadPart = newpos.QuadPart;
264
265     return S_OK;
266 }
267
268 static HRESULT WINAPI IStream_fnSetSize (IStream * iface,
269                                          ULARGE_INTEGER libNewSize)
270 {
271     LARGE_INTEGER newpos;
272     IUMCacheStream *This = (IUMCacheStream *)iface;
273
274     TRACE("(%p)\n",This);
275
276     newpos.QuadPart = libNewSize.QuadPart;
277     if( ! SetFilePointerEx( This->handle, newpos, NULL, FILE_BEGIN ) )
278        return E_FAIL;
279
280     if( ! SetEndOfFile( This->handle ) )
281        return E_FAIL;
282
283     return S_OK;
284 }
285
286 static HRESULT WINAPI IStream_fnCopyTo (IStream * iface,
287                                    IStream* pstm,
288                                    ULARGE_INTEGER cb,
289                                    ULARGE_INTEGER* pcbRead,
290                                    ULARGE_INTEGER* pcbWritten)
291 {
292     IUMCacheStream *This = (IUMCacheStream *)iface;
293
294     TRACE("(%p)\n",This);
295
296     return E_NOTIMPL;
297 }
298
299 static HRESULT WINAPI IStream_fnCommit (IStream * iface,
300                                    DWORD grfCommitFlags)
301 {
302     IUMCacheStream *This = (IUMCacheStream *)iface;
303
304     TRACE("(%p)\n",This);
305
306     return E_NOTIMPL;
307 }
308
309 static HRESULT WINAPI IStream_fnRevert (IStream * iface)
310 {
311     IUMCacheStream *This = (IUMCacheStream *)iface;
312
313     TRACE("(%p)\n",This);
314
315     return E_NOTIMPL;
316 }
317 static HRESULT WINAPI IStream_fnLockRegion (IStream * iface,
318                                             ULARGE_INTEGER libOffset,
319                                             ULARGE_INTEGER cb,
320                                             DWORD dwLockType)
321 {
322     IUMCacheStream *This = (IUMCacheStream *)iface;
323
324     TRACE("(%p)\n",This);
325
326     return E_NOTIMPL;
327 }
328 static HRESULT WINAPI IStream_fnUnlockRegion (IStream * iface,
329                                               ULARGE_INTEGER libOffset,
330                                               ULARGE_INTEGER cb,
331                                               DWORD dwLockType)
332 {
333     IUMCacheStream *This = (IUMCacheStream *)iface;
334
335     TRACE("(%p)\n",This);
336
337     return E_NOTIMPL;
338 }
339 static HRESULT WINAPI IStream_fnStat (IStream * iface,
340                                       STATSTG*   pstatstg,
341                                       DWORD grfStatFlag)
342 {
343     IUMCacheStream *This = (IUMCacheStream *)iface;
344
345     TRACE("(%p)\n",This);
346
347     return E_NOTIMPL;
348 }
349 static HRESULT WINAPI IStream_fnClone (IStream * iface,
350                                        IStream** ppstm)
351 {
352     IUMCacheStream *This = (IUMCacheStream *)iface;
353
354     TRACE("(%p)\n",This);
355
356     return E_NOTIMPL;
357 }
358
359 static const IStreamVtbl stvt =
360 {
361     IStream_fnQueryInterface,
362     IStream_fnAddRef,
363     IStream_fnRelease,
364     IStream_fnRead,
365     IStream_fnWrite,
366     IStream_fnSeek,
367     IStream_fnSetSize,
368     IStream_fnCopyTo,
369     IStream_fnCommit,
370     IStream_fnRevert,
371     IStream_fnLockRegion,
372     IStream_fnUnlockRegion,
373     IStream_fnStat,
374     IStream_fnClone
375
376 };
377
378 typedef struct ProxyBindStatusCallback
379 {
380     const IBindStatusCallbackVtbl *lpVtbl;
381
382     IBindStatusCallback *pBSC;
383 } ProxyBindStatusCallback;
384
385 static HRESULT WINAPI ProxyBindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
386 {
387     if (IsEqualGUID(&IID_IBindStatusCallback, riid) ||
388         IsEqualGUID(&IID_IUnknown, riid))
389     {
390         *ppv = iface;
391         IUnknown_AddRef(iface);
392         return S_OK;
393     }
394
395     *ppv = NULL;
396     return E_NOINTERFACE;
397 }
398
399 static ULONG WINAPI ProxyBindStatusCallback_AddRef(IBindStatusCallback *iface)
400 {
401     return 2;
402 }
403
404 static ULONG WINAPI ProxyBindStatusCallback_Release(IBindStatusCallback *iface)
405 {
406     return 1;
407 }
408
409 static HRESULT WINAPI ProxyBindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
410                                                IBinding *pib)
411 {
412     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
413
414     if(This->pBSC)
415         return IBindStatusCallback_OnStartBinding(This->pBSC, dwReserved, pib);
416
417     return S_OK;
418 }
419
420 static HRESULT WINAPI ProxyBindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
421 {
422     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
423
424     if(This->pBSC)
425         return IBindStatusCallback_GetPriority(This->pBSC, pnPriority);
426
427     return S_OK;
428 }
429
430 static HRESULT WINAPI ProxyBindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
431 {
432     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
433
434     if(This->pBSC)
435         return IBindStatusCallback_OnLowResource(This->pBSC, reserved);
436
437     return S_OK;
438 }
439
440 static HRESULT WINAPI ProxyBindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
441                                            ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
442 {
443     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
444
445     if(This->pBSC)
446         return IBindStatusCallback_OnProgress(This->pBSC, ulProgress,
447                                           ulProgressMax, ulStatusCode,
448                                           szStatusText);
449
450     return S_OK;
451 }
452
453 static HRESULT WINAPI ProxyBindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
454 {
455     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
456
457     if(This->pBSC)
458         return IBindStatusCallback_OnStopBinding(This->pBSC, hresult, szError);
459
460     return S_OK;
461 }
462
463 static HRESULT WINAPI ProxyBindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
464 {
465     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
466
467     if(This->pBSC)
468         return IBindStatusCallback_GetBindInfo(This->pBSC, grfBINDF, pbindinfo);
469
470     return E_INVALIDARG;
471 }
472
473 static HRESULT WINAPI ProxyBindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
474                                                               DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
475 {
476     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
477
478     if(This->pBSC)
479         return IBindStatusCallback_OnDataAvailable(This->pBSC, grfBSCF, dwSize,
480                                                pformatetc, pstgmed);
481
482     return S_OK;
483 }
484
485 static HRESULT WINAPI ProxyBindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
486 {
487     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
488
489     if(This->pBSC)
490         return IBindStatusCallback_OnObjectAvailable(This->pBSC, riid, punk);
491
492     return S_OK;
493 }
494
495 static HRESULT WINAPI BlockingBindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
496                                                                  DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
497 {
498     return S_OK;
499 }
500
501 static const IBindStatusCallbackVtbl BlockingBindStatusCallbackVtbl =
502 {
503     ProxyBindStatusCallback_QueryInterface,
504     ProxyBindStatusCallback_AddRef,
505     ProxyBindStatusCallback_Release,
506     ProxyBindStatusCallback_OnStartBinding,
507     ProxyBindStatusCallback_GetPriority,
508     ProxyBindStatusCallback_OnLowResource,
509     ProxyBindStatusCallback_OnProgress,
510     ProxyBindStatusCallback_OnStopBinding,
511     ProxyBindStatusCallback_GetBindInfo,
512     BlockingBindStatusCallback_OnDataAvailable,
513     ProxyBindStatusCallback_OnObjectAvailable
514 };
515
516 static HRESULT WINAPI AsyncBindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
517 {
518     ProxyBindStatusCallback *This = (ProxyBindStatusCallback *)iface;
519     HRESULT hr = IBindStatusCallback_GetBindInfo(This->pBSC, grfBINDF, pbindinfo);
520     *grfBINDF |= BINDF_PULLDATA | BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE;
521     return hr;
522 }
523
524 static const IBindStatusCallbackVtbl AsyncBindStatusCallbackVtbl =
525 {
526     ProxyBindStatusCallback_QueryInterface,
527     ProxyBindStatusCallback_AddRef,
528     ProxyBindStatusCallback_Release,
529     ProxyBindStatusCallback_OnStartBinding,
530     ProxyBindStatusCallback_GetPriority,
531     ProxyBindStatusCallback_OnLowResource,
532     ProxyBindStatusCallback_OnProgress,
533     ProxyBindStatusCallback_OnStopBinding,
534     AsyncBindStatusCallback_GetBindInfo,
535     ProxyBindStatusCallback_OnDataAvailable,
536     ProxyBindStatusCallback_OnObjectAvailable
537 };
538
539 static HRESULT URLStartDownload(LPCWSTR szURL, LPSTREAM *ppStream, IBindStatusCallback *pBSC)
540 {
541     HRESULT hr;
542     IMoniker *pMoniker;
543     IBindCtx *pbc;
544
545     *ppStream = NULL;
546
547     hr = CreateURLMoniker(NULL, szURL, &pMoniker);
548     if (FAILED(hr))
549         return hr;
550
551     hr = CreateBindCtx(0, &pbc);
552     if (FAILED(hr))
553     {
554         IMoniker_Release(pMoniker);
555         return hr;
556     }
557
558     hr = RegisterBindStatusCallback(pbc, pBSC, NULL, 0);
559     if (FAILED(hr))
560     {
561         IBindCtx_Release(pbc);
562         IMoniker_Release(pMoniker);
563         return hr;
564     }
565
566     hr = IMoniker_BindToStorage(pMoniker, pbc, NULL, &IID_IStream, (void **)ppStream);
567
568     /* BindToStorage returning E_PENDING because it's asynchronous is not an error */
569     if (hr == E_PENDING) hr = S_OK;
570
571     IBindCtx_Release(pbc);
572     IMoniker_Release(pMoniker);
573
574     return hr;
575 }
576
577 /***********************************************************************
578  *              URLOpenBlockingStreamA (URLMON.@)
579  */
580 HRESULT WINAPI URLOpenBlockingStreamA(LPUNKNOWN pCaller, LPCSTR szURL,
581                                       LPSTREAM *ppStream, DWORD dwReserved,
582                                       LPBINDSTATUSCALLBACK lpfnCB)
583 {
584     LPWSTR szURLW;
585     int len;
586     HRESULT hr;
587
588     TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller, szURL, ppStream, dwReserved, lpfnCB);
589
590     if (!szURL || !ppStream)
591         return E_INVALIDARG;
592
593     len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
594     szURLW = heap_alloc(len * sizeof(WCHAR));
595     if (!szURLW)
596     {
597         *ppStream = NULL;
598         return E_OUTOFMEMORY;
599     }
600     MultiByteToWideChar(CP_ACP, 0, szURL, -1, szURLW, len);
601
602     hr = URLOpenBlockingStreamW(pCaller, szURLW, ppStream, dwReserved, lpfnCB);
603
604     heap_free(szURLW);
605
606     return hr;
607 }
608
609 /***********************************************************************
610  *              URLOpenBlockingStreamW (URLMON.@)
611  */
612 HRESULT WINAPI URLOpenBlockingStreamW(LPUNKNOWN pCaller, LPCWSTR szURL,
613                                       LPSTREAM *ppStream, DWORD dwReserved,
614                                       LPBINDSTATUSCALLBACK lpfnCB)
615 {
616     ProxyBindStatusCallback blocking_bsc;
617
618     TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller, debugstr_w(szURL), ppStream,
619           dwReserved, lpfnCB);
620
621     if (!szURL || !ppStream)
622         return E_INVALIDARG;
623
624     blocking_bsc.lpVtbl = &BlockingBindStatusCallbackVtbl;
625     blocking_bsc.pBSC = lpfnCB;
626
627     return URLStartDownload(szURL, ppStream, (IBindStatusCallback *)&blocking_bsc);
628 }
629
630 /***********************************************************************
631  *              URLOpenStreamA (URLMON.@)
632  */
633 HRESULT WINAPI URLOpenStreamA(LPUNKNOWN pCaller, LPCSTR szURL, DWORD dwReserved,
634                               LPBINDSTATUSCALLBACK lpfnCB)
635 {
636     LPWSTR szURLW;
637     int len;
638     HRESULT hr;
639
640     TRACE("(%p, %s, 0x%x, %p)\n", pCaller, szURL, dwReserved, lpfnCB);
641
642     if (!szURL)
643         return E_INVALIDARG;
644
645     len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
646     szURLW = heap_alloc(len * sizeof(WCHAR));
647     if (!szURLW)
648         return E_OUTOFMEMORY;
649     MultiByteToWideChar(CP_ACP, 0, szURL, -1, szURLW, len);
650
651     hr = URLOpenStreamW(pCaller, szURLW, dwReserved, lpfnCB);
652
653     heap_free(szURLW);
654
655     return hr;
656 }
657
658 /***********************************************************************
659  *              URLOpenStreamW (URLMON.@)
660  */
661 HRESULT WINAPI URLOpenStreamW(LPUNKNOWN pCaller, LPCWSTR szURL, DWORD dwReserved,
662                               LPBINDSTATUSCALLBACK lpfnCB)
663 {
664     HRESULT hr;
665     ProxyBindStatusCallback async_bsc;
666     IStream *pStream;
667
668     TRACE("(%p, %s, 0x%x, %p)\n", pCaller, debugstr_w(szURL), dwReserved,
669           lpfnCB);
670
671     if (!szURL)
672         return E_INVALIDARG;
673
674     async_bsc.lpVtbl = &AsyncBindStatusCallbackVtbl;
675     async_bsc.pBSC = lpfnCB;
676
677     hr = URLStartDownload(szURL, &pStream, (IBindStatusCallback *)&async_bsc);
678     if (SUCCEEDED(hr) && pStream)
679         IStream_Release(pStream);
680
681     return hr;
682 }