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