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
22 #include "urlmon_main.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(urlmon
);
33 static const IStreamVtbl stvt
;
35 HRESULT
UMCreateStreamOnCacheFile(LPCWSTR pszURL
,
39 IUMCacheStream
**ppstr
)
41 IUMCacheStream
* ucstr
;
44 LPWSTR url
, c
, ext
= NULL
;
47 size
= (strlenW(pszURL
)+1)*sizeof(WCHAR
);
48 url
= heap_alloc(size
);
49 memcpy(url
, pszURL
, size
);
51 for (c
= url
; *c
&& *c
!= '#' && *c
!= '?'; ++c
)
61 if(!CreateUrlCacheEntryW(url
, dwSize
, ext
, pszFileName
, 0))
62 hr
= HRESULT_FROM_WIN32(GetLastError());
71 TRACE("Opening %s\n", debugstr_w(pszFileName
) );
73 handle
= CreateFileW( pszFileName
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
, 0, NULL
);
74 if( handle
== INVALID_HANDLE_VALUE
)
75 return HRESULT_FROM_WIN32(GetLastError());
79 /* Call CreateFileW again because we need a handle with its own file pointer, and DuplicateHandle will return
80 * a handle that shares its file pointer with the original.
82 *phfile
= CreateFileW( pszFileName
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, OPEN_EXISTING
, 0, NULL
);
84 if (*phfile
== (HANDLE
) HFILE_ERROR
)
86 DWORD dwError
= GetLastError();
89 return HRESULT_FROM_WIN32(dwError
);
93 ucstr
= heap_alloc_zero(sizeof(IUMCacheStream
));
96 ucstr
->pszURL
= heap_alloc_zero(sizeof(WCHAR
) * (lstrlenW(pszURL
) + 1));
99 ucstr
->pszFileName
= heap_alloc_zero(sizeof(WCHAR
) * (lstrlenW(pszFileName
) + 1));
100 if (ucstr
->pszFileName
)
104 ucstr
->handle
= handle
;
106 lstrcpyW(ucstr
->pszURL
, pszURL
);
107 lstrcpyW(ucstr
->pszFileName
, pszFileName
);
113 heap_free(ucstr
->pszURL
);
119 CloseHandle(*phfile
);
120 return E_OUTOFMEMORY
;
123 void UMCloseCacheFileStream(IUMCacheStream
*This
)
129 ftZero
.dwLowDateTime
= ftZero
.dwHighDateTime
= 0;
132 CommitUrlCacheEntryW(This
->pszURL
,
144 /**************************************************************************
145 * IStream_fnQueryInterface
147 static HRESULT WINAPI
IStream_fnQueryInterface(IStream
*iface
,
151 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
153 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This
,debugstr_guid(riid
),ppvObj
);
157 if(IsEqualIID(riid
, &IID_IUnknown
) ||
158 IsEqualIID(riid
, &IID_IStream
))
165 IStream_AddRef((IStream
*)*ppvObj
);
166 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
169 TRACE("-- Interface: E_NOINTERFACE\n");
170 return E_NOINTERFACE
;
173 /**************************************************************************
176 static ULONG WINAPI
IStream_fnAddRef(IStream
*iface
)
178 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
179 ULONG refCount
= InterlockedIncrement(&This
->ref
);
181 TRACE("(%p)->(count=%u)\n", This
, refCount
- 1);
186 /**************************************************************************
189 static ULONG WINAPI
IStream_fnRelease(IStream
*iface
)
191 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
192 ULONG refCount
= InterlockedDecrement(&This
->ref
);
194 TRACE("(%p)->(count=%u)\n", This
, refCount
+ 1);
198 TRACE(" destroying UMCacheStream (%p)\n",This
);
199 UMCloseCacheFileStream(This
);
200 CloseHandle(This
->handle
);
201 heap_free(This
->pszFileName
);
202 heap_free(This
->pszURL
);
208 static HRESULT WINAPI
IStream_fnRead (IStream
* iface
,
214 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
216 TRACE("(%p)->(%p,0x%08x,%p)\n",This
, pv
, cb
, pcbRead
);
219 return STG_E_INVALIDPOINTER
;
222 pcbRead
= &dwBytesRead
;
224 if ( ! ReadFile( This
->handle
, pv
, cb
, pcbRead
, NULL
) )
228 return This
->closed
? S_FALSE
: E_PENDING
;
232 static HRESULT WINAPI
IStream_fnWrite (IStream
* iface
,
240 static HRESULT WINAPI
IStream_fnSeek (IStream
* iface
,
241 LARGE_INTEGER dlibMove
,
243 ULARGE_INTEGER
* plibNewPosition
)
245 LARGE_INTEGER newpos
;
246 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
248 TRACE("(%p)\n",This
);
250 if (!SetFilePointerEx( This
->handle
, dlibMove
, &newpos
, dwOrigin
))
254 plibNewPosition
->QuadPart
= newpos
.QuadPart
;
259 static HRESULT WINAPI
IStream_fnSetSize (IStream
* iface
,
260 ULARGE_INTEGER libNewSize
)
262 LARGE_INTEGER newpos
;
263 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
265 TRACE("(%p)\n",This
);
267 newpos
.QuadPart
= libNewSize
.QuadPart
;
268 if( ! SetFilePointerEx( This
->handle
, newpos
, NULL
, FILE_BEGIN
) )
271 if( ! SetEndOfFile( This
->handle
) )
277 static HRESULT WINAPI
IStream_fnCopyTo (IStream
* iface
,
280 ULARGE_INTEGER
* pcbRead
,
281 ULARGE_INTEGER
* pcbWritten
)
283 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
285 TRACE("(%p)\n",This
);
290 static HRESULT WINAPI
IStream_fnCommit (IStream
* iface
,
291 DWORD grfCommitFlags
)
293 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
295 TRACE("(%p)\n",This
);
300 static HRESULT WINAPI
IStream_fnRevert (IStream
* iface
)
302 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
304 TRACE("(%p)\n",This
);
308 static HRESULT WINAPI
IStream_fnLockRegion (IStream
* iface
,
309 ULARGE_INTEGER libOffset
,
313 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
315 TRACE("(%p)\n",This
);
319 static HRESULT WINAPI
IStream_fnUnlockRegion (IStream
* iface
,
320 ULARGE_INTEGER libOffset
,
324 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
326 TRACE("(%p)\n",This
);
330 static HRESULT WINAPI
IStream_fnStat (IStream
* iface
,
334 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
336 TRACE("(%p)\n",This
);
340 static HRESULT WINAPI
IStream_fnClone (IStream
* iface
,
343 IUMCacheStream
*This
= (IUMCacheStream
*)iface
;
345 TRACE("(%p)\n",This
);
350 static const IStreamVtbl stvt
=
352 IStream_fnQueryInterface
,
362 IStream_fnLockRegion
,
363 IStream_fnUnlockRegion
,
369 typedef struct ProxyBindStatusCallback
371 const IBindStatusCallbackVtbl
*lpVtbl
;
373 IBindStatusCallback
*pBSC
;
374 } ProxyBindStatusCallback
;
376 static HRESULT WINAPI
ProxyBindStatusCallback_QueryInterface(IBindStatusCallback
*iface
, REFIID riid
, void **ppv
)
378 if (IsEqualGUID(&IID_IBindStatusCallback
, riid
) ||
379 IsEqualGUID(&IID_IUnknown
, riid
))
382 IUnknown_AddRef(iface
);
387 return E_NOINTERFACE
;
390 static ULONG WINAPI
ProxyBindStatusCallback_AddRef(IBindStatusCallback
*iface
)
395 static ULONG WINAPI
ProxyBindStatusCallback_Release(IBindStatusCallback
*iface
)
400 static HRESULT WINAPI
ProxyBindStatusCallback_OnStartBinding(IBindStatusCallback
*iface
, DWORD dwReserved
,
403 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
406 return IBindStatusCallback_OnStartBinding(This
->pBSC
, dwReserved
, pib
);
411 static HRESULT WINAPI
ProxyBindStatusCallback_GetPriority(IBindStatusCallback
*iface
, LONG
*pnPriority
)
413 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
416 return IBindStatusCallback_GetPriority(This
->pBSC
, pnPriority
);
421 static HRESULT WINAPI
ProxyBindStatusCallback_OnLowResource(IBindStatusCallback
*iface
, DWORD reserved
)
423 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
426 return IBindStatusCallback_OnLowResource(This
->pBSC
, reserved
);
431 static HRESULT WINAPI
ProxyBindStatusCallback_OnProgress(IBindStatusCallback
*iface
, ULONG ulProgress
,
432 ULONG ulProgressMax
, ULONG ulStatusCode
, LPCWSTR szStatusText
)
434 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
437 return IBindStatusCallback_OnProgress(This
->pBSC
, ulProgress
,
438 ulProgressMax
, ulStatusCode
,
444 static HRESULT WINAPI
ProxyBindStatusCallback_OnStopBinding(IBindStatusCallback
*iface
, HRESULT hresult
, LPCWSTR szError
)
446 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
449 return IBindStatusCallback_OnStopBinding(This
->pBSC
, hresult
, szError
);
454 static HRESULT WINAPI
ProxyBindStatusCallback_GetBindInfo(IBindStatusCallback
*iface
, DWORD
*grfBINDF
, BINDINFO
*pbindinfo
)
456 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
459 return IBindStatusCallback_GetBindInfo(This
->pBSC
, grfBINDF
, pbindinfo
);
464 static HRESULT WINAPI
ProxyBindStatusCallback_OnDataAvailable(IBindStatusCallback
*iface
, DWORD grfBSCF
,
465 DWORD dwSize
, FORMATETC
* pformatetc
, STGMEDIUM
* pstgmed
)
467 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
470 return IBindStatusCallback_OnDataAvailable(This
->pBSC
, grfBSCF
, dwSize
,
471 pformatetc
, pstgmed
);
476 static HRESULT WINAPI
ProxyBindStatusCallback_OnObjectAvailable(IBindStatusCallback
*iface
, REFIID riid
, IUnknown
*punk
)
478 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
481 return IBindStatusCallback_OnObjectAvailable(This
->pBSC
, riid
, punk
);
486 static HRESULT WINAPI
BlockingBindStatusCallback_OnDataAvailable(IBindStatusCallback
*iface
, DWORD grfBSCF
,
487 DWORD dwSize
, FORMATETC
* pformatetc
, STGMEDIUM
* pstgmed
)
492 static const IBindStatusCallbackVtbl BlockingBindStatusCallbackVtbl
=
494 ProxyBindStatusCallback_QueryInterface
,
495 ProxyBindStatusCallback_AddRef
,
496 ProxyBindStatusCallback_Release
,
497 ProxyBindStatusCallback_OnStartBinding
,
498 ProxyBindStatusCallback_GetPriority
,
499 ProxyBindStatusCallback_OnLowResource
,
500 ProxyBindStatusCallback_OnProgress
,
501 ProxyBindStatusCallback_OnStopBinding
,
502 ProxyBindStatusCallback_GetBindInfo
,
503 BlockingBindStatusCallback_OnDataAvailable
,
504 ProxyBindStatusCallback_OnObjectAvailable
507 static HRESULT WINAPI
AsyncBindStatusCallback_GetBindInfo(IBindStatusCallback
*iface
, DWORD
*grfBINDF
, BINDINFO
*pbindinfo
)
509 ProxyBindStatusCallback
*This
= (ProxyBindStatusCallback
*)iface
;
510 HRESULT hr
= IBindStatusCallback_GetBindInfo(This
->pBSC
, grfBINDF
, pbindinfo
);
511 *grfBINDF
|= BINDF_PULLDATA
| BINDF_ASYNCHRONOUS
| BINDF_ASYNCSTORAGE
;
515 static const IBindStatusCallbackVtbl AsyncBindStatusCallbackVtbl
=
517 ProxyBindStatusCallback_QueryInterface
,
518 ProxyBindStatusCallback_AddRef
,
519 ProxyBindStatusCallback_Release
,
520 ProxyBindStatusCallback_OnStartBinding
,
521 ProxyBindStatusCallback_GetPriority
,
522 ProxyBindStatusCallback_OnLowResource
,
523 ProxyBindStatusCallback_OnProgress
,
524 ProxyBindStatusCallback_OnStopBinding
,
525 AsyncBindStatusCallback_GetBindInfo
,
526 ProxyBindStatusCallback_OnDataAvailable
,
527 ProxyBindStatusCallback_OnObjectAvailable
530 static HRESULT
URLStartDownload(LPCWSTR szURL
, LPSTREAM
*ppStream
, IBindStatusCallback
*pBSC
)
538 hr
= CreateURLMoniker(NULL
, szURL
, &pMoniker
);
542 hr
= CreateBindCtx(0, &pbc
);
545 IMoniker_Release(pMoniker
);
549 hr
= RegisterBindStatusCallback(pbc
, pBSC
, NULL
, 0);
552 IBindCtx_Release(pbc
);
553 IMoniker_Release(pMoniker
);
557 hr
= IMoniker_BindToStorage(pMoniker
, pbc
, NULL
, &IID_IStream
, (void **)ppStream
);
559 /* BindToStorage returning E_PENDING because it's asynchronous is not an error */
560 if (hr
== E_PENDING
) hr
= S_OK
;
562 IBindCtx_Release(pbc
);
563 IMoniker_Release(pMoniker
);
568 /***********************************************************************
569 * URLOpenBlockingStreamA (URLMON.@)
571 HRESULT WINAPI
URLOpenBlockingStreamA(LPUNKNOWN pCaller
, LPCSTR szURL
,
572 LPSTREAM
*ppStream
, DWORD dwReserved
,
573 LPBINDSTATUSCALLBACK lpfnCB
)
579 TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller
, szURL
, ppStream
, dwReserved
, lpfnCB
);
581 if (!szURL
|| !ppStream
)
584 len
= MultiByteToWideChar(CP_ACP
, 0, szURL
, -1, NULL
, 0);
585 szURLW
= heap_alloc(len
* sizeof(WCHAR
));
589 return E_OUTOFMEMORY
;
591 MultiByteToWideChar(CP_ACP
, 0, szURL
, -1, szURLW
, len
);
593 hr
= URLOpenBlockingStreamW(pCaller
, szURLW
, ppStream
, dwReserved
, lpfnCB
);
600 /***********************************************************************
601 * URLOpenBlockingStreamW (URLMON.@)
603 HRESULT WINAPI
URLOpenBlockingStreamW(LPUNKNOWN pCaller
, LPCWSTR szURL
,
604 LPSTREAM
*ppStream
, DWORD dwReserved
,
605 LPBINDSTATUSCALLBACK lpfnCB
)
607 ProxyBindStatusCallback blocking_bsc
;
609 TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller
, debugstr_w(szURL
), ppStream
,
612 if (!szURL
|| !ppStream
)
615 blocking_bsc
.lpVtbl
= &BlockingBindStatusCallbackVtbl
;
616 blocking_bsc
.pBSC
= lpfnCB
;
618 return URLStartDownload(szURL
, ppStream
, (IBindStatusCallback
*)&blocking_bsc
);
621 /***********************************************************************
622 * URLOpenStreamA (URLMON.@)
624 HRESULT WINAPI
URLOpenStreamA(LPUNKNOWN pCaller
, LPCSTR szURL
, DWORD dwReserved
,
625 LPBINDSTATUSCALLBACK lpfnCB
)
631 TRACE("(%p, %s, 0x%x, %p)\n", pCaller
, szURL
, dwReserved
, lpfnCB
);
636 len
= MultiByteToWideChar(CP_ACP
, 0, szURL
, -1, NULL
, 0);
637 szURLW
= heap_alloc(len
* sizeof(WCHAR
));
639 return E_OUTOFMEMORY
;
640 MultiByteToWideChar(CP_ACP
, 0, szURL
, -1, szURLW
, len
);
642 hr
= URLOpenStreamW(pCaller
, szURLW
, dwReserved
, lpfnCB
);
649 /***********************************************************************
650 * URLOpenStreamW (URLMON.@)
652 HRESULT WINAPI
URLOpenStreamW(LPUNKNOWN pCaller
, LPCWSTR szURL
, DWORD dwReserved
,
653 LPBINDSTATUSCALLBACK lpfnCB
)
656 ProxyBindStatusCallback async_bsc
;
659 TRACE("(%p, %s, 0x%x, %p)\n", pCaller
, debugstr_w(szURL
), dwReserved
,
665 async_bsc
.lpVtbl
= &AsyncBindStatusCallbackVtbl
;
666 async_bsc
.pBSC
= lpfnCB
;
668 hr
= URLStartDownload(szURL
, &pStream
, (IBindStatusCallback
*)&async_bsc
);
669 if (SUCCEEDED(hr
) && pStream
)
670 IStream_Release(pStream
);