urlmon: Added Uri IMarshal implementation.
[wine] / dlls / msxml3 / bsc.c
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 = hr = 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 bind_url(LPCWSTR url, HRESULT (*onDataAvailable)(void*,char*,DWORD), void *obj, bsc_t **ret)
246 {
247     WCHAR fileUrl[INTERNET_MAX_URL_LENGTH];
248     bsc_t *bsc;
249     IBindCtx *pbc;
250     HRESULT hr;
251
252     TRACE("%s\n", debugstr_w(url));
253
254     if(!PathIsURLW(url))
255     {
256         WCHAR fullpath[MAX_PATH];
257         DWORD needed = sizeof(fileUrl)/sizeof(WCHAR);
258
259         if(!PathSearchAndQualifyW(url, fullpath, sizeof(fullpath)/sizeof(WCHAR)))
260         {
261             WARN("can't find path\n");
262             return E_FAIL;
263         }
264
265         if(FAILED(UrlCreateFromPathW(url, fileUrl, &needed, 0)))
266         {
267             ERR("can't create url from path\n");
268             return E_FAIL;
269         }
270         url = fileUrl;
271     }
272
273     hr = CreateBindCtx(0, &pbc);
274     if(FAILED(hr))
275         return hr;
276
277     bsc = heap_alloc(sizeof(bsc_t));
278
279     bsc->IBindStatusCallback_iface.lpVtbl = &bsc_vtbl;
280     bsc->ref = 1;
281     bsc->obj = obj;
282     bsc->onDataAvailable = onDataAvailable;
283     bsc->binding = NULL;
284     bsc->memstream = NULL;
285     bsc->hres = S_OK;
286
287     hr = RegisterBindStatusCallback(pbc, &bsc->IBindStatusCallback_iface, NULL, 0);
288     if(SUCCEEDED(hr))
289     {
290         IMoniker *moniker;
291
292         hr = CreateURLMoniker(NULL, url, &moniker);
293         if(SUCCEEDED(hr))
294         {
295             IStream *stream;
296             hr = IMoniker_BindToStorage(moniker, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
297             IMoniker_Release(moniker);
298             if(stream)
299                 IStream_Release(stream);
300         }
301         IBindCtx_Release(pbc);
302     }
303
304     if(FAILED(hr))
305     {
306         IBindStatusCallback_Release(&bsc->IBindStatusCallback_iface);
307         bsc = NULL;
308     }
309
310     *ret = bsc;
311     return hr;
312 }
313
314 HRESULT detach_bsc(bsc_t *bsc)
315 {
316     HRESULT hres;
317
318     if(bsc->binding)
319         IBinding_Abort(bsc->binding);
320
321     bsc->obj = NULL;
322     hres = bsc->hres;
323     IBindStatusCallback_Release(&bsc->IBindStatusCallback_iface);
324
325     return hres;
326 }