Added CSIDL_MYVIDEO|MYPICTURES|MYMUSIC to _SHRegisterUserShellFolders.
[wine] / dlls / urlmon / binding.c
1 /*
2  * Copyright 2005 Jacek 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #include <stdarg.h>
20
21 #define COBJMACROS
22 #define NONAMELESSUNION
23 #define NONAMELESSSTRUCT
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "ole2.h"
29 #include "urlmon.h"
30 #include "urlmon_main.h"
31
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
36
37 typedef struct {
38     const IBindingVtbl               *lpBindingVtbl;
39     const IInternetProtocolSinkVtbl  *lpInternetProtocolSinkVtbl;
40     const IInternetBindInfoVtbl      *lpInternetBindInfoVtbl;
41     const IServiceProviderVtbl       *lpServiceProviderVtbl;
42
43     LONG ref;
44
45     IBindStatusCallback *callback;
46     IInternetProtocol *protocol;
47     IStream *stream;
48
49     BINDINFO bindinfo;
50     DWORD bindf;
51     LPWSTR mime;
52     LPWSTR url;
53 } Binding;
54
55 #define BINDING(x)   ((IBinding*)               &(x)->lpBindingVtbl)
56 #define PROTSINK(x)  ((IInternetProtocolSink*)  &(x)->lpInternetProtocolSinkVtbl)
57 #define BINDINF(x)   ((IInternetBindInfo*)      &(x)->lpInternetBindInfoVtbl)
58 #define SERVPROV(x)  ((IServiceProvider*)       &(x)->lpServiceProviderVtbl)
59
60
61 #define BINDING_THIS(iface) DEFINE_THIS(Binding, Binding, iface)
62
63 static HRESULT WINAPI Binding_QueryInterface(IBinding *iface, REFIID riid, void **ppv)
64 {
65     Binding *This = BINDING_THIS(iface);
66
67     *ppv = NULL;
68
69     if(IsEqualGUID(&IID_IUnknown, riid)) {
70         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
71         *ppv = BINDING(This);
72     }else if(IsEqualGUID(&IID_IBinding, riid)) {
73         TRACE("(%p)->(IID_IBinding %p)\n", This, ppv);
74         *ppv = BINDING(This);
75     }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
76         TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
77         *ppv = PROTSINK(This);
78     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
79         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
80         *ppv = BINDINF(This);
81     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
82         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
83         *ppv = SERVPROV(This);
84     }
85
86     if(*ppv)
87         return S_OK;
88
89     WARN("Unsupported interface %s\n", debugstr_guid(riid));
90     return E_NOINTERFACE;
91 }
92
93 static ULONG WINAPI Binding_AddRef(IBinding *iface)
94 {
95     Binding *This = BINDING_THIS(iface);
96     LONG ref = InterlockedIncrement(&This->ref);
97
98     TRACE("(%p) ref=%ld\n", This, ref);
99
100     return ref;
101 }
102
103 static ULONG WINAPI Binding_Release(IBinding *iface)
104 {
105     Binding *This = BINDING_THIS(iface);
106     LONG ref = InterlockedDecrement(&This->ref);
107
108     TRACE("(%p) ref=%ld\n", This, ref);
109
110     if(!ref) {
111         if(This->callback)
112             IBindStatusCallback_Release(This->callback);
113         if(This->protocol)
114             IInternetProtocol_Release(This->protocol);
115         if(This->stream)
116             IStream_Release(This->stream);
117
118         ReleaseBindInfo(&This->bindinfo);
119         HeapFree(GetProcessHeap(), 0, This->mime);
120         HeapFree(GetProcessHeap(), 0, This->url);
121
122         HeapFree(GetProcessHeap(), 0, This);
123     }
124
125     return ref;
126 }
127
128 static HRESULT WINAPI Binding_Abort(IBinding *iface)
129 {
130     Binding *This = BINDING_THIS(iface);
131     FIXME("(%p)\n", This);
132     return E_NOTIMPL;
133 }
134
135 static HRESULT WINAPI Binding_Suspend(IBinding *iface)
136 {
137     Binding *This = BINDING_THIS(iface);
138     FIXME("(%p)\n", This);
139     return E_NOTIMPL;
140 }
141
142 static HRESULT WINAPI Binding_Resume(IBinding *iface)
143 {
144     Binding *This = BINDING_THIS(iface);
145     FIXME("(%p)\n", This);
146     return E_NOTIMPL;
147 }
148
149 static HRESULT WINAPI Binding_SetPriority(IBinding *iface, LONG nPriority)
150 {
151     Binding *This = BINDING_THIS(iface);
152     FIXME("(%p)->(%ld)\n", This, nPriority);
153     return E_NOTIMPL;
154 }
155
156 static HRESULT WINAPI Binding_GetPriority(IBinding *iface, LONG *pnPriority)
157 {
158     Binding *This = BINDING_THIS(iface);
159     FIXME("(%p)->(%p)\n", This, pnPriority);
160     return E_NOTIMPL;
161 }
162
163 static HRESULT WINAPI Binding_GetBindResult(IBinding *iface, CLSID *pclsidProtocol,
164         DWORD *pdwResult, LPOLESTR *pszResult, DWORD *pdwReserved)
165 {
166     Binding *This = BINDING_THIS(iface);
167     FIXME("(%p)->(%p %p %p %p)\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);
168     return E_NOTIMPL;
169 }
170
171 #undef BINDING_THIS
172
173 static const IBindingVtbl BindingVtbl = {
174     Binding_QueryInterface,
175     Binding_AddRef,
176     Binding_Release,
177     Binding_Abort,
178     Binding_Suspend,
179     Binding_Resume,
180     Binding_SetPriority,
181     Binding_GetPriority,
182     Binding_GetBindResult
183 };
184
185 #define PROTSINK_THIS(iface) DEFINE_THIS(Binding, InternetProtocolSink, iface)
186
187 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
188         REFIID riid, void **ppv)
189 {
190     Binding *This = PROTSINK_THIS(iface);
191     return IBinding_QueryInterface(BINDING(This), riid, ppv);
192 }
193
194 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface)
195 {
196     Binding *This = PROTSINK_THIS(iface);
197     return IBinding_AddRef(BINDING(This));
198 }
199
200 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface)
201 {
202     Binding *This = PROTSINK_THIS(iface);
203     return IBinding_Release(BINDING(This));
204 }
205
206 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface,
207         PROTOCOLDATA *pProtocolData)
208 {
209     Binding *This = PROTSINK_THIS(iface);
210     FIXME("(%p)->(%p)\n", This, pProtocolData);
211     return E_NOTIMPL;
212 }
213
214 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
215         ULONG ulStatusCode, LPCWSTR szStatusText)
216 {
217     Binding *This = PROTSINK_THIS(iface);
218
219     TRACE("(%p)->(%lu %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
220
221     switch(ulStatusCode) {
222     case BINDSTATUS_MIMETYPEAVAILABLE: {
223         int len = strlenW(szStatusText)+1;
224         This->mime = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
225         memcpy(This->mime, szStatusText, len*sizeof(WCHAR));
226         break;
227     }
228     default:
229         FIXME("Unhandled status code %ld\n", ulStatusCode);
230         return E_NOTIMPL;
231     };
232
233     return S_OK;
234 }
235
236 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
237         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
238 {
239     Binding *This = PROTSINK_THIS(iface);
240     DWORD read = 0, cread;
241     STGMEDIUM stgmed;
242     BYTE buf[1024];
243
244     TRACE("(%p)->(%ld %lu %lu)\n", This, grfBSCF, ulProgress, ulProgressMax);
245
246     if(grfBSCF & BSCF_FIRSTDATANOTIFICATION) {
247         if(This->mime)
248             IBindStatusCallback_OnProgress(This->callback, ulProgress, ulProgressMax,
249                                            BINDSTATUS_MIMETYPEAVAILABLE, This->mime);
250         IBindStatusCallback_OnProgress(This->callback, ulProgress, ulProgressMax,
251                                        BINDSTATUS_BEGINDOWNLOADDATA, This->url);
252     }
253
254     if(grfBSCF & BSCF_LASTDATANOTIFICATION)
255         IBindStatusCallback_OnProgress(This->callback, ulProgress, ulProgressMax,
256                                        BINDSTATUS_ENDDOWNLOADDATA, This->url);
257
258     if(grfBSCF & BSCF_FIRSTDATANOTIFICATION)
259         IInternetProtocol_LockRequest(This->protocol, 0);
260     do {
261         cread = 0;
262         IInternetProtocol_Read(This->protocol, buf, sizeof(buf), &cread);
263         IStream_Write(This->stream, buf, read, NULL);
264         read += cread;
265     }while(cread);
266
267     stgmed.tymed = TYMED_ISTREAM;
268     stgmed.u.pstm = This->stream;
269
270     IBindStatusCallback_OnDataAvailable(This->callback, grfBSCF, read,
271             NULL /* FIXME */, &stgmed);
272
273     if(grfBSCF & BSCF_LASTDATANOTIFICATION)
274         IBindStatusCallback_OnStopBinding(This->callback, S_OK, NULL);
275
276     return S_OK;
277 }
278
279 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
280         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
281 {
282     Binding *This = PROTSINK_THIS(iface);
283     FIXME("(%p)->(%08lx %ld %s)\n", This, hrResult, dwError, debugstr_w(szResult));
284     return E_NOTIMPL;
285 }
286
287 #undef PROTSINK_THIS
288
289 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
290     InternetProtocolSink_QueryInterface,
291     InternetProtocolSink_AddRef,
292     InternetProtocolSink_Release,
293     InternetProtocolSink_Switch,
294     InternetProtocolSink_ReportProgress,
295     InternetProtocolSink_ReportData,
296     InternetProtocolSink_ReportResult
297 };
298
299 #define BINDINF_THIS(iface) DEFINE_THIS(Binding, InternetBindInfo, iface)
300
301 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
302         REFIID riid, void **ppv)
303 {
304     Binding *This = BINDINF_THIS(iface);
305     return IBinding_QueryInterface(BINDING(This), riid, ppv);
306 }
307
308 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
309 {
310     Binding *This = BINDINF_THIS(iface);
311     return IBinding_AddRef(BINDING(This));
312 }
313
314 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
315 {
316     Binding *This = BINDINF_THIS(iface);
317     return IBinding_Release(BINDING(This));
318 }
319
320 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
321         DWORD *grfBINDF, BINDINFO *pbindinfo)
322 {
323     Binding *This = BINDINF_THIS(iface);
324
325     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
326
327     *grfBINDF = This->bindf;
328
329     memcpy(pbindinfo, &This->bindinfo, sizeof(BINDINFO));
330
331     if(pbindinfo->szExtraInfo || pbindinfo->szCustomVerb)
332         FIXME("copy strings\n");
333
334     if(pbindinfo->pUnk)
335         IUnknown_AddRef(pbindinfo->pUnk);
336
337     return S_OK;
338 }
339
340 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
341         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
342 {
343     Binding *This = BINDINF_THIS(iface);
344     FIXME("(%p)->(%ld %p %ld %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
345     return E_NOTIMPL;
346 }
347
348 #undef BINDF_THIS
349
350 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
351     InternetBindInfo_QueryInterface,
352     InternetBindInfo_AddRef,
353     InternetBindInfo_Release,
354     InternetBindInfo_GetBindInfo,
355     InternetBindInfo_GetBindString
356 };
357
358 #define SERVPROV_THIS(iface) DEFINE_THIS(Binding, ServiceProvider, iface)
359
360 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface,
361         REFIID riid, void **ppv)
362 {
363     Binding *This = SERVPROV_THIS(iface);
364     return IBinding_QueryInterface(BINDING(This), riid, ppv);
365 }
366
367 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
368 {
369     Binding *This = SERVPROV_THIS(iface);
370     return IBinding_AddRef(BINDING(This));
371 }
372
373 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
374 {
375     Binding *This = SERVPROV_THIS(iface);
376     return IBinding_Release(BINDING(This));
377 }
378
379 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
380         REFGUID guidService, REFIID riid, void **ppv)
381 {
382     Binding *This = SERVPROV_THIS(iface);
383     FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
384     return E_NOTIMPL;
385 }
386
387 #undef SERVPROV_THIS
388
389 static const IServiceProviderVtbl ServiceProviderVtbl = {
390     ServiceProvider_QueryInterface,
391     ServiceProvider_AddRef,
392     ServiceProvider_Release,
393     ServiceProvider_QueryService
394 };
395
396 static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback)
397 {
398     HRESULT hres;
399
400     static WCHAR wszBSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
401
402     hres = IBindCtx_GetObjectParam(pbc, wszBSCBHolder, (IUnknown**)callback);
403     if(FAILED(hres))
404         return INET_E_DATA_NOT_AVAILABLE;
405
406     return S_OK;
407 }
408
409 static HRESULT get_protocol(Binding *This, LPCWSTR url)
410 {
411     IUnknown *unk = NULL;
412     IClassFactory *cf = NULL;
413     HRESULT hres;
414
415     hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetProtocol,
416             (void**)&This->protocol);
417     if(SUCCEEDED(hres))
418         return S_OK;
419
420     hres = get_protocol_iface(url, &unk);
421     if(FAILED(hres))
422         return hres;
423
424     hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&cf);
425     IUnknown_Release(unk);
426     if(FAILED(hres))
427         return hres;
428
429     hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&This->protocol);
430     IClassFactory_Release(cf);
431
432     return hres;
433 }
434
435 static HRESULT Binding_Create(LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding **binding)
436 {
437     Binding *ret;
438     int len;
439     HRESULT hres;
440
441     if(!IsEqualGUID(&IID_IStream, riid)) {
442         FIXME("Unsupported riid %s\n", debugstr_guid(riid));
443         return E_NOTIMPL;
444     }
445
446     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(Binding));
447
448     ret->lpBindingVtbl              = &BindingVtbl;
449     ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
450     ret->lpInternetBindInfoVtbl     = &InternetBindInfoVtbl;
451     ret->lpServiceProviderVtbl      = &ServiceProviderVtbl;
452
453     ret->ref = 1;
454
455     ret->callback = NULL;
456     ret->protocol = NULL;
457     ret->stream = NULL;
458     ret->mime = NULL;
459     ret->url = NULL;
460
461     memset(&ret->bindinfo, 0, sizeof(BINDINFO));
462     ret->bindinfo.cbSize = sizeof(BINDINFO);
463     ret->bindf = 0;
464
465     hres = get_callback(pbc, &ret->callback);
466     if(FAILED(hres)) {
467         WARN("Could not get IBindStatusCallback\n");
468         IBinding_Release(BINDING(ret));
469         return hres;
470     }
471
472     hres = get_protocol(ret, url);
473     if(FAILED(hres)) {
474         WARN("Could not get protocol handler\n");
475         IBinding_Release(BINDING(ret));
476         return hres;
477     }
478
479     hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo);
480     if(FAILED(hres)) {
481         WARN("GetBindInfo failed: %08lx\n", hres);
482         IBinding_Release(BINDING(ret));
483         return hres;
484     }
485
486     ret->bindf |= (BINDF_FROMURLMON|BINDF_NEEDFILE);
487
488     len = strlenW(url)+1;
489     ret->url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
490     memcpy(ret->url, url, len*sizeof(WCHAR));
491
492     CreateStreamOnHGlobal(NULL, TRUE, &ret->stream);
493
494     *binding = ret;
495     return S_OK;
496 }
497
498 HRESULT start_binding(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
499 {
500     Binding *binding = NULL;
501     HRESULT hres;
502
503     *ppv = NULL;
504
505     hres = Binding_Create(url, pbc, riid, &binding);
506     if(FAILED(hres))
507         return hres;
508
509     hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, BINDING(binding));
510     if(FAILED(hres)) {
511         WARN("OnStartBinding failed: %08lx\n", hres);
512         IBindStatusCallback_OnStopBinding(binding->callback, 0x800c0008, NULL);
513         IBinding_Release(BINDING(binding));
514         return hres;
515     }
516
517     hres = IInternetProtocol_Start(binding->protocol, url, PROTSINK(binding),
518              BINDINF(binding), 0, 0);
519     IInternetProtocol_Terminate(binding->protocol, 0);
520
521     if(SUCCEEDED(hres)) {
522         IInternetProtocol_UnlockRequest(binding->protocol);
523     }else {
524         WARN("Start failed: %08lx\n", hres);
525         IBindStatusCallback_OnStopBinding(binding->callback, S_OK, NULL);
526     }
527
528     IStream_AddRef(binding->stream);
529     *ppv = binding->stream;
530
531     IBinding_Release(BINDING(binding));
532
533     return hres;
534 }