Sync with trunk r63174.
[reactos.git] / dll / win32 / 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 "urlmon_main.h"
23
24 typedef struct ProxyBindStatusCallback
25 {
26 IBindStatusCallback IBindStatusCallback_iface;
27
28 IBindStatusCallback *pBSC;
29 } ProxyBindStatusCallback;
30
31 static inline ProxyBindStatusCallback *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
32 {
33 return CONTAINING_RECORD(iface, ProxyBindStatusCallback, IBindStatusCallback_iface);
34 }
35
36 static HRESULT WINAPI ProxyBindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
37 {
38 if (IsEqualGUID(&IID_IBindStatusCallback, riid) ||
39 IsEqualGUID(&IID_IUnknown, riid))
40 {
41 *ppv = iface;
42 IBindStatusCallback_AddRef(iface);
43 return S_OK;
44 }
45
46 *ppv = NULL;
47 return E_NOINTERFACE;
48 }
49
50 static ULONG WINAPI ProxyBindStatusCallback_AddRef(IBindStatusCallback *iface)
51 {
52 return 2;
53 }
54
55 static ULONG WINAPI ProxyBindStatusCallback_Release(IBindStatusCallback *iface)
56 {
57 return 1;
58 }
59
60 static HRESULT WINAPI ProxyBindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
61 IBinding *pib)
62 {
63 ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
64
65 if(This->pBSC)
66 return IBindStatusCallback_OnStartBinding(This->pBSC, dwReserved, pib);
67
68 return S_OK;
69 }
70
71 static HRESULT WINAPI ProxyBindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
72 {
73 ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
74
75 if(This->pBSC)
76 return IBindStatusCallback_GetPriority(This->pBSC, pnPriority);
77
78 return S_OK;
79 }
80
81 static HRESULT WINAPI ProxyBindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
82 {
83 ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
84
85 if(This->pBSC)
86 return IBindStatusCallback_OnLowResource(This->pBSC, reserved);
87
88 return S_OK;
89 }
90
91 static HRESULT WINAPI ProxyBindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
92 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
93 {
94 ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
95
96 if(This->pBSC)
97 return IBindStatusCallback_OnProgress(This->pBSC, ulProgress,
98 ulProgressMax, ulStatusCode,
99 szStatusText);
100
101 return S_OK;
102 }
103
104 static HRESULT WINAPI ProxyBindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
105 {
106 ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
107
108 if(This->pBSC)
109 return IBindStatusCallback_OnStopBinding(This->pBSC, hresult, szError);
110
111 return S_OK;
112 }
113
114 static HRESULT WINAPI ProxyBindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
115 {
116 ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
117
118 if(This->pBSC)
119 return IBindStatusCallback_GetBindInfo(This->pBSC, grfBINDF, pbindinfo);
120
121 return E_INVALIDARG;
122 }
123
124 static HRESULT WINAPI ProxyBindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
125 DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
126 {
127 ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
128
129 if(This->pBSC)
130 return IBindStatusCallback_OnDataAvailable(This->pBSC, grfBSCF, dwSize,
131 pformatetc, pstgmed);
132
133 return S_OK;
134 }
135
136 static HRESULT WINAPI ProxyBindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
137 {
138 ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
139
140 if(This->pBSC)
141 return IBindStatusCallback_OnObjectAvailable(This->pBSC, riid, punk);
142
143 return S_OK;
144 }
145
146 static HRESULT WINAPI BlockingBindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
147 DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
148 {
149 return S_OK;
150 }
151
152 static const IBindStatusCallbackVtbl BlockingBindStatusCallbackVtbl =
153 {
154 ProxyBindStatusCallback_QueryInterface,
155 ProxyBindStatusCallback_AddRef,
156 ProxyBindStatusCallback_Release,
157 ProxyBindStatusCallback_OnStartBinding,
158 ProxyBindStatusCallback_GetPriority,
159 ProxyBindStatusCallback_OnLowResource,
160 ProxyBindStatusCallback_OnProgress,
161 ProxyBindStatusCallback_OnStopBinding,
162 ProxyBindStatusCallback_GetBindInfo,
163 BlockingBindStatusCallback_OnDataAvailable,
164 ProxyBindStatusCallback_OnObjectAvailable
165 };
166
167 static HRESULT WINAPI AsyncBindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
168 {
169 ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
170 HRESULT hr = IBindStatusCallback_GetBindInfo(This->pBSC, grfBINDF, pbindinfo);
171 *grfBINDF |= BINDF_PULLDATA | BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE;
172 return hr;
173 }
174
175 static const IBindStatusCallbackVtbl AsyncBindStatusCallbackVtbl =
176 {
177 ProxyBindStatusCallback_QueryInterface,
178 ProxyBindStatusCallback_AddRef,
179 ProxyBindStatusCallback_Release,
180 ProxyBindStatusCallback_OnStartBinding,
181 ProxyBindStatusCallback_GetPriority,
182 ProxyBindStatusCallback_OnLowResource,
183 ProxyBindStatusCallback_OnProgress,
184 ProxyBindStatusCallback_OnStopBinding,
185 AsyncBindStatusCallback_GetBindInfo,
186 ProxyBindStatusCallback_OnDataAvailable,
187 ProxyBindStatusCallback_OnObjectAvailable
188 };
189
190 static HRESULT URLStartDownload(LPCWSTR szURL, LPSTREAM *ppStream, IBindStatusCallback *pBSC)
191 {
192 HRESULT hr;
193 IMoniker *pMoniker;
194 IBindCtx *pbc;
195
196 *ppStream = NULL;
197
198 hr = CreateURLMoniker(NULL, szURL, &pMoniker);
199 if (FAILED(hr))
200 return hr;
201
202 hr = CreateBindCtx(0, &pbc);
203 if (FAILED(hr))
204 {
205 IMoniker_Release(pMoniker);
206 return hr;
207 }
208
209 hr = RegisterBindStatusCallback(pbc, pBSC, NULL, 0);
210 if (FAILED(hr))
211 {
212 IBindCtx_Release(pbc);
213 IMoniker_Release(pMoniker);
214 return hr;
215 }
216
217 hr = IMoniker_BindToStorage(pMoniker, pbc, NULL, &IID_IStream, (void **)ppStream);
218
219 /* BindToStorage returning E_PENDING because it's asynchronous is not an error */
220 if (hr == E_PENDING) hr = S_OK;
221
222 IBindCtx_Release(pbc);
223 IMoniker_Release(pMoniker);
224
225 return hr;
226 }
227
228 /***********************************************************************
229 * URLOpenBlockingStreamA (URLMON.@)
230 */
231 HRESULT WINAPI URLOpenBlockingStreamA(LPUNKNOWN pCaller, LPCSTR szURL,
232 LPSTREAM *ppStream, DWORD dwReserved,
233 LPBINDSTATUSCALLBACK lpfnCB)
234 {
235 LPWSTR szURLW;
236 int len;
237 HRESULT hr;
238
239 TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller, szURL, ppStream, dwReserved, lpfnCB);
240
241 if (!szURL || !ppStream)
242 return E_INVALIDARG;
243
244 len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
245 szURLW = heap_alloc(len * sizeof(WCHAR));
246 if (!szURLW)
247 {
248 *ppStream = NULL;
249 return E_OUTOFMEMORY;
250 }
251 MultiByteToWideChar(CP_ACP, 0, szURL, -1, szURLW, len);
252
253 hr = URLOpenBlockingStreamW(pCaller, szURLW, ppStream, dwReserved, lpfnCB);
254
255 heap_free(szURLW);
256
257 return hr;
258 }
259
260 /***********************************************************************
261 * URLOpenBlockingStreamW (URLMON.@)
262 */
263 HRESULT WINAPI URLOpenBlockingStreamW(LPUNKNOWN pCaller, LPCWSTR szURL,
264 LPSTREAM *ppStream, DWORD dwReserved,
265 LPBINDSTATUSCALLBACK lpfnCB)
266 {
267 ProxyBindStatusCallback blocking_bsc;
268
269 TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller, debugstr_w(szURL), ppStream,
270 dwReserved, lpfnCB);
271
272 if (!szURL || !ppStream)
273 return E_INVALIDARG;
274
275 blocking_bsc.IBindStatusCallback_iface.lpVtbl = &BlockingBindStatusCallbackVtbl;
276 blocking_bsc.pBSC = lpfnCB;
277
278 return URLStartDownload(szURL, ppStream, &blocking_bsc.IBindStatusCallback_iface);
279 }
280
281 /***********************************************************************
282 * URLOpenStreamA (URLMON.@)
283 */
284 HRESULT WINAPI URLOpenStreamA(LPUNKNOWN pCaller, LPCSTR szURL, DWORD dwReserved,
285 LPBINDSTATUSCALLBACK lpfnCB)
286 {
287 LPWSTR szURLW;
288 int len;
289 HRESULT hr;
290
291 TRACE("(%p, %s, 0x%x, %p)\n", pCaller, szURL, dwReserved, lpfnCB);
292
293 if (!szURL)
294 return E_INVALIDARG;
295
296 len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
297 szURLW = heap_alloc(len * sizeof(WCHAR));
298 if (!szURLW)
299 return E_OUTOFMEMORY;
300 MultiByteToWideChar(CP_ACP, 0, szURL, -1, szURLW, len);
301
302 hr = URLOpenStreamW(pCaller, szURLW, dwReserved, lpfnCB);
303
304 heap_free(szURLW);
305
306 return hr;
307 }
308
309 /***********************************************************************
310 * URLOpenStreamW (URLMON.@)
311 */
312 HRESULT WINAPI URLOpenStreamW(LPUNKNOWN pCaller, LPCWSTR szURL, DWORD dwReserved,
313 LPBINDSTATUSCALLBACK lpfnCB)
314 {
315 HRESULT hr;
316 ProxyBindStatusCallback async_bsc;
317 IStream *pStream;
318
319 TRACE("(%p, %s, 0x%x, %p)\n", pCaller, debugstr_w(szURL), dwReserved,
320 lpfnCB);
321
322 if (!szURL)
323 return E_INVALIDARG;
324
325 async_bsc.IBindStatusCallback_iface.lpVtbl = &AsyncBindStatusCallbackVtbl;
326 async_bsc.pBSC = lpfnCB;
327
328 hr = URLStartDownload(szURL, &pStream, &async_bsc.IBindStatusCallback_iface);
329 if (SUCCEEDED(hr) && pStream)
330 IStream_Release(pStream);
331
332 return hr;
333 }