msxml3: Add IXMLDOMDocument3 stub support.
[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 #include <assert.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "ole2.h"
30 #include "msxml6.h"
31 #include "wininet.h"
32 #include "urlmon.h"
33 #include "winreg.h"
34 #include "shlwapi.h"
35
36 #include "wine/debug.h"
37
38 #include "msxml_private.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
41
42 struct bsc_t {
43     const struct IBindStatusCallbackVtbl *lpVtbl;
44
45     LONG ref;
46
47     void *obj;
48     HRESULT (*onDataAvailable)(void*,char*,DWORD);
49
50     IBinding *binding;
51     IStream *memstream;
52 };
53
54 static inline bsc_t *impl_from_IBindStatusCallback( IBindStatusCallback *iface )
55 {
56     return (bsc_t *)((char*)iface - FIELD_OFFSET(bsc_t, lpVtbl));
57 }
58
59 static HRESULT WINAPI bsc_QueryInterface(
60     IBindStatusCallback *iface,
61     REFIID riid,
62     LPVOID *ppobj )
63 {
64     if (IsEqualGUID(riid, &IID_IUnknown) ||
65         IsEqualGUID(riid, &IID_IBindStatusCallback))
66     {
67         IBindStatusCallback_AddRef( iface );
68         *ppobj = iface;
69         return S_OK;
70     }
71
72     TRACE("interface %s not implemented\n", debugstr_guid(riid));
73     return E_NOINTERFACE;
74 }
75
76 static ULONG WINAPI bsc_AddRef(
77     IBindStatusCallback *iface )
78 {
79     bsc_t *This = impl_from_IBindStatusCallback(iface);
80     LONG ref = InterlockedIncrement(&This->ref);
81
82     TRACE("(%p) ref=%d\n", This, ref);
83
84     return ref;
85 }
86
87 static ULONG WINAPI bsc_Release(
88     IBindStatusCallback *iface )
89 {
90     bsc_t *This = impl_from_IBindStatusCallback(iface);
91     LONG ref = InterlockedDecrement(&This->ref);
92
93     TRACE("(%p) ref=%d\n", This, ref);
94
95     if(!ref) {
96         if (This->binding)   IBinding_Release(This->binding);
97         if (This->memstream) IStream_Release(This->memstream);
98         heap_free(This);
99     }
100
101     return ref;
102 }
103
104 static HRESULT WINAPI bsc_OnStartBinding(
105         IBindStatusCallback* iface,
106         DWORD dwReserved,
107         IBinding* pib)
108 {
109     bsc_t *This = impl_from_IBindStatusCallback(iface);
110     HRESULT hr;
111
112     TRACE("(%p)->(%x %p)\n", This, dwReserved, pib);
113
114     This->binding = pib;
115     IBinding_AddRef(pib);
116
117     hr = CreateStreamOnHGlobal(NULL, TRUE, &This->memstream);
118     if(FAILED(hr))
119         return hr;
120
121     return S_OK;
122 }
123
124 static HRESULT WINAPI bsc_GetPriority(
125         IBindStatusCallback* iface,
126         LONG* pnPriority)
127 {
128     return S_OK;
129 }
130
131 static HRESULT WINAPI bsc_OnLowResource(
132         IBindStatusCallback* iface,
133         DWORD reserved)
134 {
135     return S_OK;
136 }
137
138 static HRESULT WINAPI bsc_OnProgress(
139         IBindStatusCallback* iface,
140         ULONG ulProgress,
141         ULONG ulProgressMax,
142         ULONG ulStatusCode,
143         LPCWSTR szStatusText)
144 {
145     return S_OK;
146 }
147
148 static HRESULT WINAPI bsc_OnStopBinding(
149         IBindStatusCallback* iface,
150         HRESULT hresult,
151         LPCWSTR szError)
152 {
153     bsc_t *This = impl_from_IBindStatusCallback(iface);
154     HRESULT hr = S_OK;
155
156     TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
157
158     if(This->binding) {
159         IBinding_Release(This->binding);
160         This->binding = NULL;
161     }
162
163     if(This->obj && SUCCEEDED(hresult)) {
164         HGLOBAL hglobal;
165         hr = GetHGlobalFromStream(This->memstream, &hglobal);
166         if(SUCCEEDED(hr))
167         {
168             DWORD len = GlobalSize(hglobal);
169             char *ptr = GlobalLock(hglobal);
170
171             hr = This->onDataAvailable(This->obj, ptr, len);
172
173             GlobalUnlock(hglobal);
174         }
175     }
176
177     return hr;
178 }
179
180 static HRESULT WINAPI bsc_GetBindInfo(
181         IBindStatusCallback* iface,
182         DWORD* grfBINDF,
183         BINDINFO* pbindinfo)
184 {
185     *grfBINDF = BINDF_GETNEWESTVERSION|BINDF_PULLDATA|BINDF_RESYNCHRONIZE|BINDF_PRAGMA_NO_CACHE;
186
187     return S_OK;
188 }
189
190 static HRESULT WINAPI bsc_OnDataAvailable(
191         IBindStatusCallback* iface,
192         DWORD grfBSCF,
193         DWORD dwSize,
194         FORMATETC* pformatetc,
195         STGMEDIUM* pstgmed)
196 {
197     bsc_t *This = impl_from_IBindStatusCallback(iface);
198     BYTE buf[4096];
199     DWORD read, written;
200     HRESULT hr;
201
202     TRACE("(%p)->(%x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
203
204     do
205     {
206         hr = IStream_Read(pstgmed->u.pstm, buf, sizeof(buf), &read);
207         if(FAILED(hr))
208             break;
209
210         hr = IStream_Write(This->memstream, buf, read, &written);
211     } while(SUCCEEDED(hr) && written != 0 && read != 0);
212
213     return S_OK;
214 }
215
216 static HRESULT WINAPI bsc_OnObjectAvailable(
217         IBindStatusCallback* iface,
218         REFIID riid,
219         IUnknown* punk)
220 {
221     return S_OK;
222 }
223
224 static const struct IBindStatusCallbackVtbl bsc_vtbl =
225 {
226     bsc_QueryInterface,
227     bsc_AddRef,
228     bsc_Release,
229     bsc_OnStartBinding,
230     bsc_GetPriority,
231     bsc_OnLowResource,
232     bsc_OnProgress,
233     bsc_OnStopBinding,
234     bsc_GetBindInfo,
235     bsc_OnDataAvailable,
236     bsc_OnObjectAvailable
237 };
238
239 HRESULT bind_url(LPCWSTR url, HRESULT (*onDataAvailable)(void*,char*,DWORD), void *obj, bsc_t **ret)
240 {
241     WCHAR fileUrl[INTERNET_MAX_URL_LENGTH];
242     bsc_t *bsc;
243     IBindCtx *pbc;
244     HRESULT hr;
245
246     TRACE("%s\n", debugstr_w(url));
247
248     if(!PathIsURLW(url))
249     {
250         WCHAR fullpath[MAX_PATH];
251         DWORD needed = sizeof(fileUrl)/sizeof(WCHAR);
252
253         if(!PathSearchAndQualifyW(url, fullpath, sizeof(fullpath)/sizeof(WCHAR)))
254         {
255             WARN("can't find path\n");
256             return E_FAIL;
257         }
258
259         if(FAILED(UrlCreateFromPathW(url, fileUrl, &needed, 0)))
260         {
261             ERR("can't create url from path\n");
262             return E_FAIL;
263         }
264         url = fileUrl;
265     }
266
267     hr = CreateBindCtx(0, &pbc);
268     if(FAILED(hr))
269         return hr;
270
271     bsc = heap_alloc(sizeof(bsc_t));
272
273     bsc->lpVtbl = &bsc_vtbl;
274     bsc->ref = 1;
275     bsc->obj = obj;
276     bsc->onDataAvailable = onDataAvailable;
277     bsc->binding = NULL;
278     bsc->memstream = NULL;
279
280     hr = RegisterBindStatusCallback(pbc, (IBindStatusCallback*)&bsc->lpVtbl, NULL, 0);
281     if(SUCCEEDED(hr))
282     {
283         IMoniker *moniker;
284
285         hr = CreateURLMoniker(NULL, url, &moniker);
286         if(SUCCEEDED(hr))
287         {
288             IStream *stream;
289             hr = IMoniker_BindToStorage(moniker, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
290             IMoniker_Release(moniker);
291             if(stream)
292                 IStream_Release(stream);
293         }
294         IBindCtx_Release(pbc);
295     }
296
297     if(FAILED(hr))
298     {
299         IBindStatusCallback_Release((IBindStatusCallback*)&bsc->lpVtbl);
300         bsc = NULL;
301     }
302
303     *ret = bsc;
304     return hr;
305 }
306
307 void detach_bsc(bsc_t *bsc)
308 {
309     if(bsc->binding)
310         IBinding_Abort(bsc->binding);
311
312     bsc->obj = NULL;
313     IBindStatusCallback_Release((IBindStatusCallback*)&bsc->lpVtbl);
314 }