1 /* 2 * Copyright 2008 Piotr Caban 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #define COBJMACROS 20 #define NONAMELESSUNION 21 22 #include "config.h" 23 24 #include <stdarg.h> 25 #ifdef HAVE_LIBXML2 26 # include <libxml/parser.h> 27 # include <libxml/xmlerror.h> 28 #endif 29 30 #include "windef.h" 31 #include "winbase.h" 32 #include "winuser.h" 33 #include "ole2.h" 34 #include "msxml6.h" 35 #include "wininet.h" 36 #include "urlmon.h" 37 #include "winreg.h" 38 #include "shlwapi.h" 39 40 #include "wine/debug.h" 41 42 #include "msxml_private.h" 43 44 WINE_DEFAULT_DEBUG_CHANNEL(msxml); 45 46 struct bsc_t { 47 IBindStatusCallback IBindStatusCallback_iface; 48 49 LONG ref; 50 51 void *obj; 52 HRESULT (*onDataAvailable)(void*,char*,DWORD); 53 54 IBinding *binding; 55 IStream *memstream; 56 HRESULT hres; 57 }; 58 59 static inline bsc_t *impl_from_IBindStatusCallback( IBindStatusCallback *iface ) 60 { 61 return CONTAINING_RECORD(iface, bsc_t, IBindStatusCallback_iface); 62 } 63 64 static HRESULT WINAPI bsc_QueryInterface( 65 IBindStatusCallback *iface, 66 REFIID riid, 67 LPVOID *ppobj ) 68 { 69 if (IsEqualGUID(riid, &IID_IUnknown) || 70 IsEqualGUID(riid, &IID_IBindStatusCallback)) 71 { 72 IBindStatusCallback_AddRef( iface ); 73 *ppobj = iface; 74 return S_OK; 75 } 76 77 TRACE("interface %s not implemented\n", debugstr_guid(riid)); 78 *ppobj = NULL; 79 return E_NOINTERFACE; 80 } 81 82 static ULONG WINAPI bsc_AddRef( 83 IBindStatusCallback *iface ) 84 { 85 bsc_t *This = impl_from_IBindStatusCallback(iface); 86 LONG ref = InterlockedIncrement(&This->ref); 87 88 TRACE("(%p) ref=%d\n", This, ref); 89 90 return ref; 91 } 92 93 static ULONG WINAPI bsc_Release( 94 IBindStatusCallback *iface ) 95 { 96 bsc_t *This = impl_from_IBindStatusCallback(iface); 97 LONG ref = InterlockedDecrement(&This->ref); 98 99 TRACE("(%p) ref=%d\n", This, ref); 100 101 if(!ref) { 102 if (This->binding) IBinding_Release(This->binding); 103 if (This->memstream) IStream_Release(This->memstream); 104 heap_free(This); 105 } 106 107 return ref; 108 } 109 110 static HRESULT WINAPI bsc_OnStartBinding( 111 IBindStatusCallback* iface, 112 DWORD dwReserved, 113 IBinding* pib) 114 { 115 bsc_t *This = impl_from_IBindStatusCallback(iface); 116 HRESULT hr; 117 118 TRACE("(%p)->(%x %p)\n", This, dwReserved, pib); 119 120 This->binding = pib; 121 IBinding_AddRef(pib); 122 123 hr = CreateStreamOnHGlobal(NULL, TRUE, &This->memstream); 124 if(FAILED(hr)) 125 return hr; 126 127 return S_OK; 128 } 129 130 static HRESULT WINAPI bsc_GetPriority( 131 IBindStatusCallback* iface, 132 LONG* pnPriority) 133 { 134 return S_OK; 135 } 136 137 static HRESULT WINAPI bsc_OnLowResource( 138 IBindStatusCallback* iface, 139 DWORD reserved) 140 { 141 return S_OK; 142 } 143 144 static HRESULT WINAPI bsc_OnProgress( 145 IBindStatusCallback* iface, 146 ULONG ulProgress, 147 ULONG ulProgressMax, 148 ULONG ulStatusCode, 149 LPCWSTR szStatusText) 150 { 151 return S_OK; 152 } 153 154 static HRESULT WINAPI bsc_OnStopBinding( 155 IBindStatusCallback* iface, 156 HRESULT hresult, 157 LPCWSTR szError) 158 { 159 bsc_t *This = impl_from_IBindStatusCallback(iface); 160 HRESULT hr = S_OK; 161 162 TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError)); 163 164 if(This->binding) { 165 IBinding_Release(This->binding); 166 This->binding = NULL; 167 } 168 169 if(This->obj && SUCCEEDED(hresult)) { 170 HGLOBAL hglobal; 171 hr = GetHGlobalFromStream(This->memstream, &hglobal); 172 if(SUCCEEDED(hr)) 173 { 174 DWORD len = GlobalSize(hglobal); 175 char *ptr = GlobalLock(hglobal); 176 177 This->hres = This->onDataAvailable(This->obj, ptr, len); 178 179 GlobalUnlock(hglobal); 180 } 181 } 182 183 return hr; 184 } 185 186 static HRESULT WINAPI bsc_GetBindInfo( 187 IBindStatusCallback* iface, 188 DWORD* grfBINDF, 189 BINDINFO* pbindinfo) 190 { 191 *grfBINDF = BINDF_GETNEWESTVERSION|BINDF_PULLDATA|BINDF_RESYNCHRONIZE|BINDF_PRAGMA_NO_CACHE; 192 193 return S_OK; 194 } 195 196 static HRESULT WINAPI bsc_OnDataAvailable( 197 IBindStatusCallback* iface, 198 DWORD grfBSCF, 199 DWORD dwSize, 200 FORMATETC* pformatetc, 201 STGMEDIUM* pstgmed) 202 { 203 bsc_t *This = impl_from_IBindStatusCallback(iface); 204 BYTE buf[4096]; 205 DWORD read, written; 206 HRESULT hr; 207 208 TRACE("(%p)->(%x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed); 209 210 do 211 { 212 hr = IStream_Read(pstgmed->u.pstm, buf, sizeof(buf), &read); 213 if(FAILED(hr)) 214 break; 215 216 hr = IStream_Write(This->memstream, buf, read, &written); 217 } while(SUCCEEDED(hr) && written != 0 && read != 0); 218 219 return S_OK; 220 } 221 222 static HRESULT WINAPI bsc_OnObjectAvailable( 223 IBindStatusCallback* iface, 224 REFIID riid, 225 IUnknown* punk) 226 { 227 return S_OK; 228 } 229 230 static const struct IBindStatusCallbackVtbl bsc_vtbl = 231 { 232 bsc_QueryInterface, 233 bsc_AddRef, 234 bsc_Release, 235 bsc_OnStartBinding, 236 bsc_GetPriority, 237 bsc_OnLowResource, 238 bsc_OnProgress, 239 bsc_OnStopBinding, 240 bsc_GetBindInfo, 241 bsc_OnDataAvailable, 242 bsc_OnObjectAvailable 243 }; 244 245 HRESULT create_uri(const WCHAR *url, IUri **uri) 246 { 247 WCHAR fileUrl[INTERNET_MAX_URL_LENGTH]; 248 249 TRACE("%s\n", debugstr_w(url)); 250 251 if (!PathIsURLW(url)) 252 { 253 WCHAR fullpath[MAX_PATH]; 254 DWORD needed = ARRAY_SIZE(fileUrl); 255 256 if (!PathSearchAndQualifyW(url, fullpath, ARRAY_SIZE(fullpath))) 257 { 258 WARN("can't find path\n"); 259 return E_FAIL; 260 } 261 262 if (FAILED(UrlCreateFromPathW(fullpath, fileUrl, &needed, 0))) 263 { 264 ERR("can't create url from path\n"); 265 return E_FAIL; 266 } 267 url = fileUrl; 268 } 269 270 return CreateUri(url, Uri_CREATE_ALLOW_RELATIVE | Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME, 0, uri); 271 } 272 273 HRESULT create_moniker_from_url(LPCWSTR url, IMoniker **mon) 274 { 275 HRESULT hr; 276 IUri *uri; 277 278 TRACE("%s\n", debugstr_w(url)); 279 280 if (FAILED(hr = create_uri(url, &uri))) 281 return hr; 282 283 hr = CreateURLMonikerEx2(NULL, uri, mon, 0); 284 IUri_Release(uri); 285 return hr; 286 } 287 288 HRESULT bind_url(IMoniker *mon, HRESULT (*onDataAvailable)(void*,char*,DWORD), 289 void *obj, bsc_t **ret) 290 { 291 bsc_t *bsc; 292 IBindCtx *pbc; 293 HRESULT hr; 294 295 TRACE("%p\n", mon); 296 297 hr = CreateBindCtx(0, &pbc); 298 if(FAILED(hr)) 299 return hr; 300 301 bsc = heap_alloc(sizeof(bsc_t)); 302 303 bsc->IBindStatusCallback_iface.lpVtbl = &bsc_vtbl; 304 bsc->ref = 1; 305 bsc->obj = obj; 306 bsc->onDataAvailable = onDataAvailable; 307 bsc->binding = NULL; 308 bsc->memstream = NULL; 309 bsc->hres = S_OK; 310 311 hr = RegisterBindStatusCallback(pbc, &bsc->IBindStatusCallback_iface, NULL, 0); 312 if(SUCCEEDED(hr)) 313 { 314 IStream *stream; 315 hr = IMoniker_BindToStorage(mon, pbc, NULL, &IID_IStream, (LPVOID*)&stream); 316 if(stream) 317 IStream_Release(stream); 318 IBindCtx_Release(pbc); 319 } 320 321 if(FAILED(hr)) 322 { 323 IBindStatusCallback_Release(&bsc->IBindStatusCallback_iface); 324 bsc = NULL; 325 } 326 327 *ret = bsc; 328 return hr; 329 } 330 331 HRESULT detach_bsc(bsc_t *bsc) 332 { 333 HRESULT hres; 334 335 if(bsc->binding) 336 IBinding_Abort(bsc->binding); 337 338 bsc->obj = NULL; 339 hres = bsc->hres; 340 IBindStatusCallback_Release(&bsc->IBindStatusCallback_iface); 341 342 return hres; 343 } 344