wine/dlls/urlmon/umstream.c
2012-07-27 17:05:26 +02:00

343 lines
10 KiB
C

/*
* Based on ../shell32/memorystream.c
*
* Copyright 1999 Juergen Schmied
* Copyright 2003 Mike McCormack for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "urlmon_main.h"
#include "winreg.h"
#include "winternl.h"
#include "wininet.h"
#include "shlwapi.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
typedef struct ProxyBindStatusCallback
{
IBindStatusCallback IBindStatusCallback_iface;
IBindStatusCallback *pBSC;
} ProxyBindStatusCallback;
static inline ProxyBindStatusCallback *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
{
return CONTAINING_RECORD(iface, ProxyBindStatusCallback, IBindStatusCallback_iface);
}
static HRESULT WINAPI ProxyBindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
{
if (IsEqualGUID(&IID_IBindStatusCallback, riid) ||
IsEqualGUID(&IID_IUnknown, riid))
{
*ppv = iface;
IBindStatusCallback_AddRef(iface);
return S_OK;
}
*ppv = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI ProxyBindStatusCallback_AddRef(IBindStatusCallback *iface)
{
return 2;
}
static ULONG WINAPI ProxyBindStatusCallback_Release(IBindStatusCallback *iface)
{
return 1;
}
static HRESULT WINAPI ProxyBindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
IBinding *pib)
{
ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
if(This->pBSC)
return IBindStatusCallback_OnStartBinding(This->pBSC, dwReserved, pib);
return S_OK;
}
static HRESULT WINAPI ProxyBindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
{
ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
if(This->pBSC)
return IBindStatusCallback_GetPriority(This->pBSC, pnPriority);
return S_OK;
}
static HRESULT WINAPI ProxyBindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
{
ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
if(This->pBSC)
return IBindStatusCallback_OnLowResource(This->pBSC, reserved);
return S_OK;
}
static HRESULT WINAPI ProxyBindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
{
ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
if(This->pBSC)
return IBindStatusCallback_OnProgress(This->pBSC, ulProgress,
ulProgressMax, ulStatusCode,
szStatusText);
return S_OK;
}
static HRESULT WINAPI ProxyBindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
{
ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
if(This->pBSC)
return IBindStatusCallback_OnStopBinding(This->pBSC, hresult, szError);
return S_OK;
}
static HRESULT WINAPI ProxyBindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
{
ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
if(This->pBSC)
return IBindStatusCallback_GetBindInfo(This->pBSC, grfBINDF, pbindinfo);
return E_INVALIDARG;
}
static HRESULT WINAPI ProxyBindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
{
ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
if(This->pBSC)
return IBindStatusCallback_OnDataAvailable(This->pBSC, grfBSCF, dwSize,
pformatetc, pstgmed);
return S_OK;
}
static HRESULT WINAPI ProxyBindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
{
ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
if(This->pBSC)
return IBindStatusCallback_OnObjectAvailable(This->pBSC, riid, punk);
return S_OK;
}
static HRESULT WINAPI BlockingBindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
{
return S_OK;
}
static const IBindStatusCallbackVtbl BlockingBindStatusCallbackVtbl =
{
ProxyBindStatusCallback_QueryInterface,
ProxyBindStatusCallback_AddRef,
ProxyBindStatusCallback_Release,
ProxyBindStatusCallback_OnStartBinding,
ProxyBindStatusCallback_GetPriority,
ProxyBindStatusCallback_OnLowResource,
ProxyBindStatusCallback_OnProgress,
ProxyBindStatusCallback_OnStopBinding,
ProxyBindStatusCallback_GetBindInfo,
BlockingBindStatusCallback_OnDataAvailable,
ProxyBindStatusCallback_OnObjectAvailable
};
static HRESULT WINAPI AsyncBindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
{
ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
HRESULT hr = IBindStatusCallback_GetBindInfo(This->pBSC, grfBINDF, pbindinfo);
*grfBINDF |= BINDF_PULLDATA | BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE;
return hr;
}
static const IBindStatusCallbackVtbl AsyncBindStatusCallbackVtbl =
{
ProxyBindStatusCallback_QueryInterface,
ProxyBindStatusCallback_AddRef,
ProxyBindStatusCallback_Release,
ProxyBindStatusCallback_OnStartBinding,
ProxyBindStatusCallback_GetPriority,
ProxyBindStatusCallback_OnLowResource,
ProxyBindStatusCallback_OnProgress,
ProxyBindStatusCallback_OnStopBinding,
AsyncBindStatusCallback_GetBindInfo,
ProxyBindStatusCallback_OnDataAvailable,
ProxyBindStatusCallback_OnObjectAvailable
};
static HRESULT URLStartDownload(LPCWSTR szURL, LPSTREAM *ppStream, IBindStatusCallback *pBSC)
{
HRESULT hr;
IMoniker *pMoniker;
IBindCtx *pbc;
*ppStream = NULL;
hr = CreateURLMoniker(NULL, szURL, &pMoniker);
if (FAILED(hr))
return hr;
hr = CreateBindCtx(0, &pbc);
if (FAILED(hr))
{
IMoniker_Release(pMoniker);
return hr;
}
hr = RegisterBindStatusCallback(pbc, pBSC, NULL, 0);
if (FAILED(hr))
{
IBindCtx_Release(pbc);
IMoniker_Release(pMoniker);
return hr;
}
hr = IMoniker_BindToStorage(pMoniker, pbc, NULL, &IID_IStream, (void **)ppStream);
/* BindToStorage returning E_PENDING because it's asynchronous is not an error */
if (hr == E_PENDING) hr = S_OK;
IBindCtx_Release(pbc);
IMoniker_Release(pMoniker);
return hr;
}
/***********************************************************************
* URLOpenBlockingStreamA (URLMON.@)
*/
HRESULT WINAPI URLOpenBlockingStreamA(LPUNKNOWN pCaller, LPCSTR szURL,
LPSTREAM *ppStream, DWORD dwReserved,
LPBINDSTATUSCALLBACK lpfnCB)
{
LPWSTR szURLW;
int len;
HRESULT hr;
TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller, szURL, ppStream, dwReserved, lpfnCB);
if (!szURL || !ppStream)
return E_INVALIDARG;
len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
szURLW = heap_alloc(len * sizeof(WCHAR));
if (!szURLW)
{
*ppStream = NULL;
return E_OUTOFMEMORY;
}
MultiByteToWideChar(CP_ACP, 0, szURL, -1, szURLW, len);
hr = URLOpenBlockingStreamW(pCaller, szURLW, ppStream, dwReserved, lpfnCB);
heap_free(szURLW);
return hr;
}
/***********************************************************************
* URLOpenBlockingStreamW (URLMON.@)
*/
HRESULT WINAPI URLOpenBlockingStreamW(LPUNKNOWN pCaller, LPCWSTR szURL,
LPSTREAM *ppStream, DWORD dwReserved,
LPBINDSTATUSCALLBACK lpfnCB)
{
ProxyBindStatusCallback blocking_bsc;
TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller, debugstr_w(szURL), ppStream,
dwReserved, lpfnCB);
if (!szURL || !ppStream)
return E_INVALIDARG;
blocking_bsc.IBindStatusCallback_iface.lpVtbl = &BlockingBindStatusCallbackVtbl;
blocking_bsc.pBSC = lpfnCB;
return URLStartDownload(szURL, ppStream, &blocking_bsc.IBindStatusCallback_iface);
}
/***********************************************************************
* URLOpenStreamA (URLMON.@)
*/
HRESULT WINAPI URLOpenStreamA(LPUNKNOWN pCaller, LPCSTR szURL, DWORD dwReserved,
LPBINDSTATUSCALLBACK lpfnCB)
{
LPWSTR szURLW;
int len;
HRESULT hr;
TRACE("(%p, %s, 0x%x, %p)\n", pCaller, szURL, dwReserved, lpfnCB);
if (!szURL)
return E_INVALIDARG;
len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
szURLW = heap_alloc(len * sizeof(WCHAR));
if (!szURLW)
return E_OUTOFMEMORY;
MultiByteToWideChar(CP_ACP, 0, szURL, -1, szURLW, len);
hr = URLOpenStreamW(pCaller, szURLW, dwReserved, lpfnCB);
heap_free(szURLW);
return hr;
}
/***********************************************************************
* URLOpenStreamW (URLMON.@)
*/
HRESULT WINAPI URLOpenStreamW(LPUNKNOWN pCaller, LPCWSTR szURL, DWORD dwReserved,
LPBINDSTATUSCALLBACK lpfnCB)
{
HRESULT hr;
ProxyBindStatusCallback async_bsc;
IStream *pStream;
TRACE("(%p, %s, 0x%x, %p)\n", pCaller, debugstr_w(szURL), dwReserved,
lpfnCB);
if (!szURL)
return E_INVALIDARG;
async_bsc.IBindStatusCallback_iface.lpVtbl = &AsyncBindStatusCallbackVtbl;
async_bsc.pBSC = lpfnCB;
hr = URLStartDownload(szURL, &pStream, &async_bsc.IBindStatusCallback_iface);
if (SUCCEEDED(hr) && pStream)
IStream_Release(pStream);
return hr;
}