xref: /reactos/dll/win32/msxml3/bsc.c (revision 1734f297)
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