msxml3: Use right COM invocation macro.
[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 "msxml2.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     FIXME("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)
97             IBinding_Release(This->binding);
98         if(This->memstream)
99             IStream_Release(This->memstream);
100         HeapFree(GetProcessHeap(), 0, This);
101     }
102
103     return ref;
104 }
105
106 static HRESULT WINAPI bsc_OnStartBinding(
107         IBindStatusCallback* iface,
108         DWORD dwReserved,
109         IBinding* pib)
110 {
111     bsc_t *This = impl_from_IBindStatusCallback(iface);
112     HRESULT hr;
113
114     TRACE("(%p)->(%x %p)\n", This, dwReserved, pib);
115
116     This->binding = pib;
117     IBinding_AddRef(pib);
118
119     hr = CreateStreamOnHGlobal(NULL, TRUE, &This->memstream);
120     if(FAILED(hr))
121         return hr;
122
123     return S_OK;
124 }
125
126 static HRESULT WINAPI bsc_GetPriority(
127         IBindStatusCallback* iface,
128         LONG* pnPriority)
129 {
130     return S_OK;
131 }
132
133 static HRESULT WINAPI bsc_OnLowResource(
134         IBindStatusCallback* iface,
135         DWORD reserved)
136 {
137     return S_OK;
138 }
139
140 static HRESULT WINAPI bsc_OnProgress(
141         IBindStatusCallback* iface,
142         ULONG ulProgress,
143         ULONG ulProgressMax,
144         ULONG ulStatusCode,
145         LPCWSTR szStatusText)
146 {
147     return S_OK;
148 }
149
150 static HRESULT WINAPI bsc_OnStopBinding(
151         IBindStatusCallback* iface,
152         HRESULT hresult,
153         LPCWSTR szError)
154 {
155     bsc_t *This = impl_from_IBindStatusCallback(iface);
156     HRESULT hr = S_OK;
157
158     TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
159
160     if(This->binding) {
161         IBinding_Release(This->binding);
162         This->binding = NULL;
163     }
164
165     if(This->obj && SUCCEEDED(hresult)) {
166         HGLOBAL hglobal;
167         hr = GetHGlobalFromStream(This->memstream, &hglobal);
168         if(SUCCEEDED(hr))
169         {
170             DWORD len = GlobalSize(hglobal);
171             char *ptr = GlobalLock(hglobal);
172
173             hr = This->onDataAvailable(This->obj, ptr, len);
174
175             GlobalUnlock(hglobal);
176         }
177     }
178
179     return hr;
180 }
181
182 static HRESULT WINAPI bsc_GetBindInfo(
183         IBindStatusCallback* iface,
184         DWORD* grfBINDF,
185         BINDINFO* pbindinfo)
186 {
187     *grfBINDF = BINDF_GETNEWESTVERSION|BINDF_PULLDATA|BINDF_RESYNCHRONIZE|BINDF_PRAGMA_NO_CACHE;
188
189     return S_OK;
190 }
191
192 static HRESULT WINAPI bsc_OnDataAvailable(
193         IBindStatusCallback* iface,
194         DWORD grfBSCF,
195         DWORD dwSize,
196         FORMATETC* pformatetc,
197         STGMEDIUM* pstgmed)
198 {
199     bsc_t *This = impl_from_IBindStatusCallback(iface);
200     BYTE buf[4096];
201     DWORD read, written;
202     HRESULT hr;
203
204     TRACE("(%p)->(%x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
205
206     do
207     {
208         hr = IStream_Read(pstgmed->u.pstm, buf, sizeof(buf), &read);
209         if(FAILED(hr))
210             break;
211
212         hr = IStream_Write(This->memstream, buf, read, &written);
213     } while(SUCCEEDED(hr) && written != 0 && read != 0);
214
215     return S_OK;
216 }
217
218 static HRESULT WINAPI bsc_OnObjectAvailable(
219         IBindStatusCallback* iface,
220         REFIID riid,
221         IUnknown* punk)
222 {
223     return S_OK;
224 }
225
226 static const struct IBindStatusCallbackVtbl bsc_vtbl =
227 {
228     bsc_QueryInterface,
229     bsc_AddRef,
230     bsc_Release,
231     bsc_OnStartBinding,
232     bsc_GetPriority,
233     bsc_OnLowResource,
234     bsc_OnProgress,
235     bsc_OnStopBinding,
236     bsc_GetBindInfo,
237     bsc_OnDataAvailable,
238     bsc_OnObjectAvailable
239 };
240
241 HRESULT bind_url(LPCWSTR url, HRESULT (*onDataAvailable)(void*,char*,DWORD), void *obj, bsc_t **ret)
242 {
243     WCHAR fileUrl[INTERNET_MAX_URL_LENGTH];
244     bsc_t *bsc;
245     IBindCtx *pbc;
246     HRESULT hr;
247
248     TRACE("%s\n", debugstr_w(url));
249
250     if(!PathIsURLW(url))
251     {
252         WCHAR fullpath[MAX_PATH];
253         DWORD needed = sizeof(fileUrl)/sizeof(WCHAR);
254
255         if(!PathSearchAndQualifyW(url, fullpath, sizeof(fullpath)/sizeof(WCHAR)))
256         {
257             WARN("can't find path\n");
258             return E_FAIL;
259         }
260
261         if(FAILED(UrlCreateFromPathW(url, fileUrl, &needed, 0)))
262         {
263             ERR("can't create url from path\n");
264             return E_FAIL;
265         }
266         url = fileUrl;
267     }
268
269     hr = CreateBindCtx(0, &pbc);
270     if(FAILED(hr))
271         return hr;
272
273     bsc = HeapAlloc(GetProcessHeap(), 0, sizeof(bsc_t));
274
275     bsc->lpVtbl = &bsc_vtbl;
276     bsc->ref = 1;
277     bsc->obj = obj;
278     bsc->onDataAvailable = onDataAvailable;
279     bsc->binding = NULL;
280     bsc->memstream = NULL;
281
282     hr = RegisterBindStatusCallback(pbc, (IBindStatusCallback*)&bsc->lpVtbl, NULL, 0);
283     if(SUCCEEDED(hr))
284     {
285         IMoniker *moniker;
286
287         hr = CreateURLMoniker(NULL, url, &moniker);
288         if(SUCCEEDED(hr))
289         {
290             IStream *stream;
291             hr = IMoniker_BindToStorage(moniker, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
292             IMoniker_Release(moniker);
293             if(stream)
294                 IStream_Release(stream);
295         }
296         IBindCtx_Release(pbc);
297     }
298
299     *ret = bsc;
300     return hr;
301 }
302
303 void detach_bsc(bsc_t *bsc)
304 {
305     if(bsc->binding)
306         IBinding_Abort(bsc->binding);
307
308     bsc->obj = NULL;
309     IBindStatusCallback_Release((IBindStatusCallback*)&bsc->lpVtbl);
310 }