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