2 * Based on ../shell32/memorystream.c
4 * Copyright 1999 Juergen Schmied
5 * Copyright 2003 Mike McCormack for CodeWeavers
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.
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.
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
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
38 #include "urlmon_main.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(urlmon
);
42 static const IStreamVtbl stvt
;
44 HRESULT
UMCreateStreamOnCacheFile(LPCWSTR pszURL
,
48 IUMCacheStream
**ppstr
)
50 IUMCacheStream
* ucstr
;
53 LPWSTR url
, c
, ext
= NULL
;
56 size
= (strlenW(pszURL
)+1)*sizeof(WCHAR
);
57 url
= heap_alloc(size
);
58 memcpy(url
, pszURL
, size
);
60 for (c
= url
; *c
&& *c
!= '#' && *c
!= '?'; ++c
)
70 if(!CreateUrlCacheEntryW(url
, dwSize
, ext
, pszFileName
, 0))
71 hr
= HRESULT_FROM_WIN32(GetLastError());
80 TRACE("Opening %s\n", debugstr_w(pszFileName
) );
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());
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.
91 *phfile
= CreateFileW( pszFileName
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
93 if (*phfile
== (HANDLE
) HFILE_ERROR
)
95 DWORD dwError
= GetLastError();
98 return HRESULT_FROM_WIN32(dwError
);
102 ucstr
= heap_alloc_zero(sizeof(IUMCacheStream
));
105 ucstr
->pszURL
= heap_alloc_zero(sizeof(WCHAR
) * (lstrlenW(pszURL
) + 1));
108 ucstr
->pszFileName
= heap_alloc_zero(sizeof(WCHAR
) * (lstrlenW(pszFileName
) + 1));
109 if (ucstr
->pszFileName
)
113 ucstr
->handle
= handle
;
115 lstrcpyW(ucstr
->pszURL
, pszURL
);
116 lstrcpyW(ucstr
->pszFileName
, pszFileName
);
122 heap_free(ucstr
->pszURL
);
128 CloseHandle(*phfile
);
129 return E_OUTOFMEMORY
;
132 void UMCloseCacheFileStream(IUMCacheStream
*This
)
138 ftZero
.dwLowDateTime
= ftZero
.dwHighDateTime
= 0;
141 CommitUrlCacheEntryW(This
->pszURL
,
153 /**************************************************************************
154 * IStream_fnQueryInterface
156 static HRESULT WINAPI
IStream_fnQueryInterface(IStream
*iface
,
160 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
162 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This
,debugstr_guid(riid
),ppvObj
);
166 if(IsEqualIID(riid
, &IID_IUnknown
) ||
167 IsEqualIID(riid
, &IID_IStream
))
174 IStream_AddRef((IStream
*)*ppvObj
);
175 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
178 TRACE("-- Interface: E_NOINTERFACE\n");
179 return E_NOINTERFACE
;
182 /**************************************************************************
185 static ULONG WINAPI
IStream_fnAddRef(IStream
*iface
)
187 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
188 ULONG refCount
= InterlockedIncrement(&This
->ref
);
190 TRACE("(%p)->(count=%u)\n", This
, refCount
- 1);
195 /**************************************************************************
198 static ULONG WINAPI
IStream_fnRelease(IStream
*iface
)
200 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
201 ULONG refCount
= InterlockedDecrement(&This
->ref
);
203 TRACE("(%p)->(count=%u)\n", This
, refCount
+ 1);
207 TRACE(" destroying UMCacheStream (%p)\n",This
);
208 UMCloseCacheFileStream(This
);
209 CloseHandle(This
->handle
);
210 heap_free(This
->pszFileName
);
211 heap_free(This
->pszURL
);
217 static HRESULT WINAPI
IStream_fnRead (IStream
* iface
,
223 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
225 TRACE("(%p)->(%p,0x%08x,%p)\n",This
, pv
, cb
, pcbRead
);
228 return STG_E_INVALIDPOINTER
;
231 pcbRead
= &dwBytesRead
;
233 if ( ! ReadFile( This
->handle
, pv
, cb
, (LPDWORD
)pcbRead
, NULL
) )
237 return This
->closed
? S_FALSE
: E_PENDING
;
241 static HRESULT WINAPI
IStream_fnWrite (IStream
* iface
,
249 static HRESULT WINAPI
IStream_fnSeek (IStream
* iface
,
250 LARGE_INTEGER dlibMove
,
252 ULARGE_INTEGER
* plibNewPosition
)
254 LARGE_INTEGER newpos
;
255 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
257 TRACE("(%p)\n",This
);
259 if (!SetFilePointerEx( This
->handle
, dlibMove
, &newpos
, dwOrigin
))
263 plibNewPosition
->QuadPart
= newpos
.QuadPart
;
268 static HRESULT WINAPI
IStream_fnSetSize (IStream
* iface
,
269 ULARGE_INTEGER libNewSize
)
271 LARGE_INTEGER newpos
;
272 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
274 TRACE("(%p)\n",This
);
276 newpos
.QuadPart
= libNewSize
.QuadPart
;
277 if( ! SetFilePointerEx( This
->handle
, newpos
, NULL
, FILE_BEGIN
) )
280 if( ! SetEndOfFile( This
->handle
) )
286 static HRESULT WINAPI
IStream_fnCopyTo (IStream
* iface
,
289 ULARGE_INTEGER
* pcbRead
,
290 ULARGE_INTEGER
* pcbWritten
)
292 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
294 TRACE("(%p)\n",This
);
299 static HRESULT WINAPI
IStream_fnCommit (IStream
* iface
,
300 DWORD grfCommitFlags
)
302 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
304 TRACE("(%p)\n",This
);
309 static HRESULT WINAPI
IStream_fnRevert (IStream
* iface
)
311 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
313 TRACE("(%p)\n",This
);
317 static HRESULT WINAPI
IStream_fnLockRegion (IStream
* iface
,
318 ULARGE_INTEGER libOffset
,
322 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
324 TRACE("(%p)\n",This
);
328 static HRESULT WINAPI
IStream_fnUnlockRegion (IStream
* iface
,
329 ULARGE_INTEGER libOffset
,
333 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
335 TRACE("(%p)\n",This
);
339 static HRESULT WINAPI
IStream_fnStat (IStream
* iface
,
343 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
345 TRACE("(%p)\n",This
);
349 static HRESULT WINAPI
IStream_fnClone (IStream
* iface
,
352 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
354 TRACE("(%p)\n",This
);
359 static const IStreamVtbl stvt
=
361 IStream_fnQueryInterface
,
371 IStream_fnLockRegion
,
372 IStream_fnUnlockRegion
,
378 typedef struct ProxyBindStatusCallback
380 const IBindStatusCallbackVtbl
*lpVtbl
;
382 IBindStatusCallback
*pBSC
;
383 } ProxyBindStatusCallback
;
385 static HRESULT WINAPI
ProxyBindStatusCallback_QueryInterface(IBindStatusCallback
*iface
, REFIID riid
, void **ppv
)
387 if (IsEqualGUID(&IID_IBindStatusCallback
, riid
) ||
388 IsEqualGUID(&IID_IUnknown
, riid
))
391 IUnknown_AddRef(iface
);
396 return E_NOINTERFACE
;
399 static ULONG WINAPI
ProxyBindStatusCallback_AddRef(IBindStatusCallback
*iface
)
404 static ULONG WINAPI
ProxyBindStatusCallback_Release(IBindStatusCallback
*iface
)
409 static HRESULT WINAPI
ProxyBindStatusCallback_OnStartBinding(IBindStatusCallback
*iface
, DWORD dwReserved
,
412 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
415 return IBindStatusCallback_OnStartBinding(This
->pBSC
, dwReserved
, pib
);
420 static HRESULT WINAPI
ProxyBindStatusCallback_GetPriority(IBindStatusCallback
*iface
, LONG
*pnPriority
)
422 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
425 return IBindStatusCallback_GetPriority(This
->pBSC
, pnPriority
);
430 static HRESULT WINAPI
ProxyBindStatusCallback_OnLowResource(IBindStatusCallback
*iface
, DWORD reserved
)
432 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
435 return IBindStatusCallback_OnLowResource(This
->pBSC
, reserved
);
440 static HRESULT WINAPI
ProxyBindStatusCallback_OnProgress(IBindStatusCallback
*iface
, ULONG ulProgress
,
441 ULONG ulProgressMax
, ULONG ulStatusCode
, LPCWSTR szStatusText
)
443 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
446 return IBindStatusCallback_OnProgress(This
->pBSC
, ulProgress
,
447 ulProgressMax
, ulStatusCode
,
453 static HRESULT WINAPI
ProxyBindStatusCallback_OnStopBinding(IBindStatusCallback
*iface
, HRESULT hresult
, LPCWSTR szError
)
455 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
458 return IBindStatusCallback_OnStopBinding(This
->pBSC
, hresult
, szError
);
463 static HRESULT WINAPI
ProxyBindStatusCallback_GetBindInfo(IBindStatusCallback
*iface
, DWORD
*grfBINDF
, BINDINFO
*pbindinfo
)
465 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
468 return IBindStatusCallback_GetBindInfo(This
->pBSC
, grfBINDF
, pbindinfo
);
473 static HRESULT WINAPI
ProxyBindStatusCallback_OnDataAvailable(IBindStatusCallback
*iface
, DWORD grfBSCF
,
474 DWORD dwSize
, FORMATETC
* pformatetc
, STGMEDIUM
* pstgmed
)
476 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
479 return IBindStatusCallback_OnDataAvailable(This
->pBSC
, grfBSCF
, dwSize
,
480 pformatetc
, pstgmed
);
485 static HRESULT WINAPI
ProxyBindStatusCallback_OnObjectAvailable(IBindStatusCallback
*iface
, REFIID riid
, IUnknown
*punk
)
487 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
490 return IBindStatusCallback_OnObjectAvailable(This
->pBSC
, riid
, punk
);
495 static HRESULT WINAPI
BlockingBindStatusCallback_OnDataAvailable(IBindStatusCallback
*iface
, DWORD grfBSCF
,
496 DWORD dwSize
, FORMATETC
* pformatetc
, STGMEDIUM
* pstgmed
)
501 static const IBindStatusCallbackVtbl BlockingBindStatusCallbackVtbl
=
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
516 static HRESULT WINAPI
AsyncBindStatusCallback_GetBindInfo(IBindStatusCallback
*iface
, DWORD
*grfBINDF
, BINDINFO
*pbindinfo
)
518 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
519 HRESULT hr
= IBindStatusCallback_GetBindInfo(This
->pBSC
, grfBINDF
, pbindinfo
);
520 *grfBINDF
|= BINDF_PULLDATA
| BINDF_ASYNCHRONOUS
| BINDF_ASYNCSTORAGE
;
524 static const IBindStatusCallbackVtbl AsyncBindStatusCallbackVtbl
=
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
539 static HRESULT
URLStartDownload(LPCWSTR szURL
, LPSTREAM
*ppStream
, IBindStatusCallback
*pBSC
)
547 hr
= CreateURLMoniker(NULL
, szURL
, &pMoniker
);
551 hr
= CreateBindCtx(0, &pbc
);
554 IMoniker_Release(pMoniker
);
558 hr
= RegisterBindStatusCallback(pbc
, pBSC
, NULL
, 0);
561 IBindCtx_Release(pbc
);
562 IMoniker_Release(pMoniker
);
566 hr
= IMoniker_BindToStorage(pMoniker
, pbc
, NULL
, &IID_IStream
, (void **)ppStream
);
568 /* BindToStorage returning E_PENDING because it's asynchronous is not an error */
569 if (hr
== E_PENDING
) hr
= S_OK
;
571 IBindCtx_Release(pbc
);
572 IMoniker_Release(pMoniker
);
577 /***********************************************************************
578 * URLOpenBlockingStreamA (URLMON.@)
580 HRESULT WINAPI
URLOpenBlockingStreamA(LPUNKNOWN pCaller
, LPCSTR szURL
,
581 LPSTREAM
*ppStream
, DWORD dwReserved
,
582 LPBINDSTATUSCALLBACK lpfnCB
)
588 TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller
, szURL
, ppStream
, dwReserved
, lpfnCB
);
590 if (!szURL
|| !ppStream
)
593 len
= MultiByteToWideChar(CP_ACP
, 0, szURL
, -1, NULL
, 0);
594 szURLW
= heap_alloc(len
* sizeof(WCHAR
));
598 return E_OUTOFMEMORY
;
600 MultiByteToWideChar(CP_ACP
, 0, szURL
, -1, szURLW
, len
);
602 hr
= URLOpenBlockingStreamW(pCaller
, szURLW
, ppStream
, dwReserved
, lpfnCB
);
609 /***********************************************************************
610 * URLOpenBlockingStreamW (URLMON.@)
612 HRESULT WINAPI
URLOpenBlockingStreamW(LPUNKNOWN pCaller
, LPCWSTR szURL
,
613 LPSTREAM
*ppStream
, DWORD dwReserved
,
614 LPBINDSTATUSCALLBACK lpfnCB
)
616 ProxyBindStatusCallback blocking_bsc
;
618 TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller
, debugstr_w(szURL
), ppStream
,
621 if (!szURL
|| !ppStream
)
624 blocking_bsc
.lpVtbl
= &BlockingBindStatusCallbackVtbl
;
625 blocking_bsc
.pBSC
= lpfnCB
;
627 return URLStartDownload(szURL
, ppStream
, (IBindStatusCallback
*)&blocking_bsc
);
630 /***********************************************************************
631 * URLOpenStreamA (URLMON.@)
633 HRESULT WINAPI
URLOpenStreamA(LPUNKNOWN pCaller
, LPCSTR szURL
, DWORD dwReserved
,
634 LPBINDSTATUSCALLBACK lpfnCB
)
640 TRACE("(%p, %s, 0x%x, %p)\n", pCaller
, szURL
, dwReserved
, lpfnCB
);
645 len
= MultiByteToWideChar(CP_ACP
, 0, szURL
, -1, NULL
, 0);
646 szURLW
= heap_alloc(len
* sizeof(WCHAR
));
648 return E_OUTOFMEMORY
;
649 MultiByteToWideChar(CP_ACP
, 0, szURL
, -1, szURLW
, len
);
651 hr
= URLOpenStreamW(pCaller
, szURLW
, dwReserved
, lpfnCB
);
658 /***********************************************************************
659 * URLOpenStreamW (URLMON.@)
661 HRESULT WINAPI
URLOpenStreamW(LPUNKNOWN pCaller
, LPCWSTR szURL
, DWORD dwReserved
,
662 LPBINDSTATUSCALLBACK lpfnCB
)
665 ProxyBindStatusCallback async_bsc
;
668 TRACE("(%p, %s, 0x%x, %p)\n", pCaller
, debugstr_w(szURL
), dwReserved
,
674 async_bsc
.lpVtbl
= &AsyncBindStatusCallbackVtbl
;
675 async_bsc
.pBSC
= lpfnCB
;
677 hr
= URLStartDownload(szURL
, &pStream
, (IBindStatusCallback
*)&async_bsc
);
678 if (SUCCEEDED(hr
) && pStream
)
679 IStream_Release(pStream
);