Sync with trunk r63174.
[reactos.git] / dll / win32 / urlmon / binding.c
1 /*
2 * Copyright 2005-2007 Jacek Caban for CodeWeavers
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 #include "urlmon_main.h"
20
21 static WCHAR cbinding_contextW[] = {'C','B','i','n','d','i','n','g',' ','C','o','n','t','e','x','t',0};
22 static WCHAR bscb_holderW[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
23
24 typedef struct {
25 IUnknown IUnknown_iface;
26
27 LONG ref;
28
29 IInternetProtocolEx *protocol;
30
31 HANDLE file;
32 HRESULT hres;
33
34 LPWSTR cache_file;
35 } stgmed_buf_t;
36
37 typedef struct _stgmed_obj_t stgmed_obj_t;
38
39 typedef struct {
40 void (*release)(stgmed_obj_t*);
41 HRESULT (*fill_stgmed)(stgmed_obj_t*,STGMEDIUM*);
42 HRESULT (*get_result)(stgmed_obj_t*,DWORD,void**);
43 } stgmed_obj_vtbl;
44
45 struct _stgmed_obj_t {
46 const stgmed_obj_vtbl *vtbl;
47 };
48
49 typedef enum {
50 BEFORE_DOWNLOAD,
51 DOWNLOADING,
52 END_DOWNLOAD
53 } download_state_t;
54
55 #define BINDING_LOCKED 0x0001
56 #define BINDING_STOPPED 0x0002
57 #define BINDING_OBJAVAIL 0x0004
58 #define BINDING_ABORTED 0x0008
59
60 typedef struct {
61 IBinding IBinding_iface;
62 IInternetProtocolSink IInternetProtocolSink_iface;
63 IInternetBindInfo IInternetBindInfo_iface;
64 IWinInetHttpInfo IWinInetHttpInfo_iface;
65 IServiceProvider IServiceProvider_iface;
66
67 LONG ref;
68
69 IBindStatusCallback *callback;
70 IServiceProvider *service_provider;
71
72 BindProtocol *protocol;
73
74 stgmed_buf_t *stgmed_buf;
75 stgmed_obj_t *stgmed_obj;
76
77 BINDINFO bindinfo;
78 DWORD bindf;
79 BOOL to_object;
80 LPWSTR mime;
81 UINT clipboard_format;
82 LPWSTR url;
83 LPWSTR redirect_url;
84 IID iid;
85 BOOL report_mime;
86 BOOL use_cache_file;
87 DWORD state;
88 HRESULT hres;
89 CLSID clsid;
90 download_state_t download_state;
91 IUnknown *obj;
92 IMoniker *mon;
93 IBindCtx *bctx;
94 HWND notif_hwnd;
95
96 CRITICAL_SECTION section;
97 } Binding;
98
99 static void read_protocol_data(stgmed_buf_t *stgmed_buf)
100 {
101 BYTE buf[8192];
102 DWORD read;
103 HRESULT hres;
104
105 do hres = IInternetProtocolEx_Read(stgmed_buf->protocol, buf, sizeof(buf), &read);
106 while(hres == S_OK);
107 }
108
109 static void dump_BINDINFO(BINDINFO *bi)
110 {
111 static const char * const BINDINFOF_str[] = {
112 "#0",
113 "BINDINFOF_URLENCODESTGMEDDATA",
114 "BINDINFOF_URLENCODEDEXTRAINFO"
115 };
116
117 static const char * const BINDVERB_str[] = {
118 "BINDVERB_GET",
119 "BINDVERB_POST",
120 "BINDVERB_PUT",
121 "BINDVERB_CUSTOM"
122 };
123
124 TRACE("\n"
125 "BINDINFO = {\n"
126 " %d, %s,\n"
127 " {%d, %p, %p},\n"
128 " %s,\n"
129 " %s,\n"
130 " %s,\n"
131 " %d, %08x, %d, %d\n"
132 " {%d %p %x},\n"
133 " %s\n"
134 " %p, %d\n"
135 "}\n",
136
137 bi->cbSize, debugstr_w(bi->szExtraInfo),
138 bi->stgmedData.tymed, bi->stgmedData.u.hGlobal, bi->stgmedData.pUnkForRelease,
139 bi->grfBindInfoF > BINDINFOF_URLENCODEDEXTRAINFO
140 ? "unknown" : BINDINFOF_str[bi->grfBindInfoF],
141 bi->dwBindVerb > BINDVERB_CUSTOM
142 ? "unknown" : BINDVERB_str[bi->dwBindVerb],
143 debugstr_w(bi->szCustomVerb),
144 bi->cbstgmedData, bi->dwOptions, bi->dwOptionsFlags, bi->dwCodePage,
145 bi->securityAttributes.nLength,
146 bi->securityAttributes.lpSecurityDescriptor,
147 bi->securityAttributes.bInheritHandle,
148 debugstr_guid(&bi->iid),
149 bi->pUnk, bi->dwReserved
150 );
151 }
152
153 static void mime_available(Binding *This, LPCWSTR mime)
154 {
155 heap_free(This->mime);
156 This->mime = heap_strdupW(mime);
157
158 if(!This->mime || !This->report_mime)
159 return;
160
161 IBindStatusCallback_OnProgress(This->callback, 0, 0, BINDSTATUS_MIMETYPEAVAILABLE, This->mime);
162
163 This->clipboard_format = RegisterClipboardFormatW(This->mime);
164 }
165
166 static void stop_binding(Binding *binding, HRESULT hres, LPCWSTR str)
167 {
168 if(binding->state & BINDING_LOCKED) {
169 IInternetProtocolEx_UnlockRequest(&binding->protocol->IInternetProtocolEx_iface);
170 binding->state &= ~BINDING_LOCKED;
171 }
172
173 if(!(binding->state & BINDING_STOPPED)) {
174 binding->state |= BINDING_STOPPED;
175
176 binding->hres = hres;
177 IBindStatusCallback_OnStopBinding(binding->callback, hres, str);
178 }
179 }
180
181 static LPWSTR get_mime_clsid(LPCWSTR mime, CLSID *clsid)
182 {
183 LPWSTR key_name, ret;
184 DWORD res, type, size;
185 HKEY hkey;
186 int len;
187 HRESULT hres;
188
189 static const WCHAR mime_keyW[] =
190 {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
191 'C','o','n','t','e','n','t',' ','T','y','p','e','\\'};
192 static const WCHAR clsidW[] = {'C','L','S','I','D',0};
193
194 len = strlenW(mime)+1;
195 key_name = heap_alloc(sizeof(mime_keyW) + len*sizeof(WCHAR));
196 memcpy(key_name, mime_keyW, sizeof(mime_keyW));
197 strcpyW(key_name + sizeof(mime_keyW)/sizeof(WCHAR), mime);
198
199 res = RegOpenKeyW(HKEY_CLASSES_ROOT, key_name, &hkey);
200 heap_free(key_name);
201 if(res != ERROR_SUCCESS) {
202 WARN("Could not open MIME key: %x\n", res);
203 return NULL;
204 }
205
206 size = 50*sizeof(WCHAR);
207 ret = heap_alloc(size);
208 res = RegQueryValueExW(hkey, clsidW, NULL, &type, (LPBYTE)ret, &size);
209 RegCloseKey(hkey);
210 if(res != ERROR_SUCCESS) {
211 WARN("Could not get CLSID: %08x\n", res);
212 heap_free(ret);
213 return NULL;
214 }
215
216 hres = CLSIDFromString(ret, clsid);
217 if(FAILED(hres)) {
218 WARN("Could not parse CLSID: %08x\n", hres);
219 heap_free(ret);
220 return NULL;
221 }
222
223 return ret;
224 }
225
226 static void load_doc_mon(Binding *binding, IPersistMoniker *persist)
227 {
228 IBindCtx *bctx;
229 HRESULT hres;
230
231 hres = CreateAsyncBindCtxEx(binding->bctx, 0, NULL, NULL, &bctx, 0);
232 if(FAILED(hres)) {
233 WARN("CreateAsyncBindCtxEx failed: %08x\n", hres);
234 return;
235 }
236
237 IBindCtx_RevokeObjectParam(bctx, bscb_holderW);
238 IBindCtx_RegisterObjectParam(bctx, cbinding_contextW, (IUnknown*)&binding->IBinding_iface);
239
240 hres = IPersistMoniker_Load(persist, binding->download_state == END_DOWNLOAD, binding->mon, bctx, 0x12);
241 IBindCtx_RevokeObjectParam(bctx, cbinding_contextW);
242 IBindCtx_Release(bctx);
243 if(FAILED(hres))
244 FIXME("Load failed: %08x\n", hres);
245 }
246
247 static HRESULT create_mime_object(Binding *binding, const CLSID *clsid, LPCWSTR clsid_str)
248 {
249 IPersistMoniker *persist;
250 HRESULT hres;
251
252 hres = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
253 &binding->iid, (void**)&binding->obj);
254 if(FAILED(hres)) {
255 WARN("CoCreateInstance failed: %08x\n", hres);
256 return INET_E_CANNOT_INSTANTIATE_OBJECT;
257 }
258
259 binding->state |= BINDING_OBJAVAIL;
260
261 hres = IUnknown_QueryInterface(binding->obj, &IID_IPersistMoniker, (void**)&persist);
262 if(SUCCEEDED(hres)) {
263 IMonikerProp *prop;
264
265 hres = IPersistMoniker_QueryInterface(persist, &IID_IMonikerProp, (void**)&prop);
266 if(SUCCEEDED(hres)) {
267 IMonikerProp_PutProperty(prop, MIMETYPEPROP, binding->mime);
268 IMonikerProp_PutProperty(prop, CLASSIDPROP, clsid_str);
269 IMonikerProp_Release(prop);
270 }
271
272 load_doc_mon(binding, persist);
273
274 IPersistMoniker_Release(persist);
275 }else {
276 FIXME("Could not get IPersistMoniker: %08x\n", hres);
277 /* FIXME: Try query IPersistFile */
278 }
279
280 IBindStatusCallback_OnObjectAvailable(binding->callback, &binding->iid, binding->obj);
281
282 return S_OK;
283 }
284
285 static void create_object(Binding *binding)
286 {
287 LPWSTR clsid_str;
288 CLSID clsid;
289 HRESULT hres;
290
291 if(!binding->mime) {
292 FIXME("MIME not available\n");
293 return;
294 }
295
296 if((clsid_str = get_mime_clsid(binding->mime, &clsid)))
297 IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_CLASSIDAVAILABLE, clsid_str);
298
299 IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_BEGINSYNCOPERATION, NULL);
300
301 if(clsid_str) {
302 hres = create_mime_object(binding, &clsid, clsid_str);
303 heap_free(clsid_str);
304 }else {
305 FIXME("Could not find object for MIME %s\n", debugstr_w(binding->mime));
306 hres = REGDB_E_CLASSNOTREG;
307 }
308
309 IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_ENDSYNCOPERATION, NULL);
310 binding->clsid = CLSID_NULL;
311
312 stop_binding(binding, hres, NULL);
313 if(FAILED(hres))
314 IInternetProtocolEx_Terminate(&binding->protocol->IInternetProtocolEx_iface, 0);
315 }
316
317 static void cache_file_available(Binding *This, const WCHAR *file_name)
318 {
319 heap_free(This->stgmed_buf->cache_file);
320 This->stgmed_buf->cache_file = heap_strdupW(file_name);
321
322 if(This->use_cache_file) {
323 This->stgmed_buf->file = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
324 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
325 if(This->stgmed_buf->file == INVALID_HANDLE_VALUE)
326 WARN("CreateFile failed: %u\n", GetLastError());
327 }
328 }
329
330 static inline stgmed_buf_t *impl_from_IUnknown(IUnknown *iface)
331 {
332 return CONTAINING_RECORD(iface, stgmed_buf_t, IUnknown_iface);
333 }
334
335 static HRESULT WINAPI StgMedUnk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
336 {
337 stgmed_buf_t *This = impl_from_IUnknown(iface);
338
339 *ppv = NULL;
340
341 if(IsEqualGUID(riid, &IID_IUnknown)) {
342 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
343
344 *ppv = &This->IUnknown_iface;
345 IUnknown_AddRef(&This->IUnknown_iface);
346 return S_OK;
347 }
348
349 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
350 return E_NOINTERFACE;
351 }
352
353 static ULONG WINAPI StgMedUnk_AddRef(IUnknown *iface)
354 {
355 stgmed_buf_t *This = impl_from_IUnknown(iface);
356 LONG ref = InterlockedIncrement(&This->ref);
357
358 TRACE("(%p) ref=%d\n", This, ref);
359
360 return ref;
361 }
362
363 static ULONG WINAPI StgMedUnk_Release(IUnknown *iface)
364 {
365 stgmed_buf_t *This = impl_from_IUnknown(iface);
366 LONG ref = InterlockedDecrement(&This->ref);
367
368 TRACE("(%p) ref=%d\n", This, ref);
369
370 if(!ref) {
371 if(This->file != INVALID_HANDLE_VALUE)
372 CloseHandle(This->file);
373 IInternetProtocolEx_Release(This->protocol);
374 heap_free(This->cache_file);
375 heap_free(This);
376
377 URLMON_UnlockModule();
378 }
379
380 return ref;
381 }
382
383 static const IUnknownVtbl StgMedUnkVtbl = {
384 StgMedUnk_QueryInterface,
385 StgMedUnk_AddRef,
386 StgMedUnk_Release
387 };
388
389 static stgmed_buf_t *create_stgmed_buf(IInternetProtocolEx *protocol)
390 {
391 stgmed_buf_t *ret = heap_alloc(sizeof(*ret));
392
393 ret->IUnknown_iface.lpVtbl = &StgMedUnkVtbl;
394 ret->ref = 1;
395 ret->file = INVALID_HANDLE_VALUE;
396 ret->hres = S_OK;
397 ret->cache_file = NULL;
398
399 IInternetProtocolEx_AddRef(protocol);
400 ret->protocol = protocol;
401
402 URLMON_LockModule();
403
404 return ret;
405 }
406
407 typedef struct {
408 stgmed_obj_t stgmed_obj;
409 IStream IStream_iface;
410
411 LONG ref;
412
413 stgmed_buf_t *buf;
414 } ProtocolStream;
415
416 static inline ProtocolStream *impl_from_IStream(IStream *iface)
417 {
418 return CONTAINING_RECORD(iface, ProtocolStream, IStream_iface);
419 }
420
421 static HRESULT WINAPI ProtocolStream_QueryInterface(IStream *iface,
422 REFIID riid, void **ppv)
423 {
424 ProtocolStream *This = impl_from_IStream(iface);
425
426 *ppv = NULL;
427
428 if(IsEqualGUID(&IID_IUnknown, riid)) {
429 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
430 *ppv = &This->IStream_iface;
431 }else if(IsEqualGUID(&IID_ISequentialStream, riid)) {
432 TRACE("(%p)->(IID_ISequentialStream %p)\n", This, ppv);
433 *ppv = &This->IStream_iface;
434 }else if(IsEqualGUID(&IID_IStream, riid)) {
435 TRACE("(%p)->(IID_IStream %p)\n", This, ppv);
436 *ppv = &This->IStream_iface;
437 }
438
439 if(*ppv) {
440 IStream_AddRef(&This->IStream_iface);
441 return S_OK;
442 }
443
444 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
445 return E_NOINTERFACE;
446 }
447
448 static ULONG WINAPI ProtocolStream_AddRef(IStream *iface)
449 {
450 ProtocolStream *This = impl_from_IStream(iface);
451 LONG ref = InterlockedIncrement(&This->ref);
452
453 TRACE("(%p) ref=%d\n", This, ref);
454
455 return ref;
456 }
457
458 static ULONG WINAPI ProtocolStream_Release(IStream *iface)
459 {
460 ProtocolStream *This = impl_from_IStream(iface);
461 LONG ref = InterlockedDecrement(&This->ref);
462
463 TRACE("(%p) ref=%d\n", This, ref);
464
465 if(!ref) {
466 IUnknown_Release(&This->buf->IUnknown_iface);
467 heap_free(This);
468
469 URLMON_UnlockModule();
470 }
471
472 return ref;
473 }
474
475 static HRESULT WINAPI ProtocolStream_Read(IStream *iface, void *pv,
476 ULONG cb, ULONG *pcbRead)
477 {
478 ProtocolStream *This = impl_from_IStream(iface);
479 DWORD read = 0;
480 HRESULT hres;
481
482 TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbRead);
483
484 if(This->buf->file == INVALID_HANDLE_VALUE) {
485 hres = This->buf->hres = IInternetProtocolEx_Read(This->buf->protocol, (PBYTE)pv, cb, &read);
486 }else {
487 hres = ReadFile(This->buf->file, pv, cb, &read, NULL) ? S_OK : INET_E_DOWNLOAD_FAILURE;
488 }
489
490 if (pcbRead)
491 *pcbRead = read;
492
493 if(hres == E_PENDING)
494 return E_PENDING;
495 else if(FAILED(hres))
496 FIXME("Read failed: %08x\n", hres);
497
498 return read ? S_OK : S_FALSE;
499 }
500
501 static HRESULT WINAPI ProtocolStream_Write(IStream *iface, const void *pv,
502 ULONG cb, ULONG *pcbWritten)
503 {
504 ProtocolStream *This = impl_from_IStream(iface);
505
506 TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbWritten);
507
508 return STG_E_ACCESSDENIED;
509 }
510
511 static HRESULT WINAPI ProtocolStream_Seek(IStream *iface, LARGE_INTEGER dlibMove,
512 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
513 {
514 ProtocolStream *This = impl_from_IStream(iface);
515 FIXME("(%p)->(%d %08x %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
516 return E_NOTIMPL;
517 }
518
519 static HRESULT WINAPI ProtocolStream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
520 {
521 ProtocolStream *This = impl_from_IStream(iface);
522 FIXME("(%p)->(%d)\n", This, libNewSize.u.LowPart);
523 return E_NOTIMPL;
524 }
525
526 static HRESULT WINAPI ProtocolStream_CopyTo(IStream *iface, IStream *pstm,
527 ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
528 {
529 ProtocolStream *This = impl_from_IStream(iface);
530 FIXME("(%p)->(%p %d %p %p)\n", This, pstm, cb.u.LowPart, pcbRead, pcbWritten);
531 return E_NOTIMPL;
532 }
533
534 static HRESULT WINAPI ProtocolStream_Commit(IStream *iface, DWORD grfCommitFlags)
535 {
536 ProtocolStream *This = impl_from_IStream(iface);
537
538 TRACE("(%p)->(%08x)\n", This, grfCommitFlags);
539
540 return E_NOTIMPL;
541 }
542
543 static HRESULT WINAPI ProtocolStream_Revert(IStream *iface)
544 {
545 ProtocolStream *This = impl_from_IStream(iface);
546
547 TRACE("(%p)\n", This);
548
549 return E_NOTIMPL;
550 }
551
552 static HRESULT WINAPI ProtocolStream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
553 ULARGE_INTEGER cb, DWORD dwLockType)
554 {
555 ProtocolStream *This = impl_from_IStream(iface);
556 FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
557 return E_NOTIMPL;
558 }
559
560 static HRESULT WINAPI ProtocolStream_UnlockRegion(IStream *iface,
561 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
562 {
563 ProtocolStream *This = impl_from_IStream(iface);
564 FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
565 return E_NOTIMPL;
566 }
567
568 static HRESULT WINAPI ProtocolStream_Stat(IStream *iface, STATSTG *pstatstg,
569 DWORD dwStatFlag)
570 {
571 ProtocolStream *This = impl_from_IStream(iface);
572 TRACE("(%p)->(%p %08x)\n", This, pstatstg, dwStatFlag);
573
574 if(!pstatstg)
575 return E_FAIL;
576
577 memset(pstatstg, 0, sizeof(STATSTG));
578
579 if(!(dwStatFlag&STATFLAG_NONAME) && This->buf->cache_file) {
580 pstatstg->pwcsName = CoTaskMemAlloc((lstrlenW(This->buf->cache_file)+1)*sizeof(WCHAR));
581 if(!pstatstg->pwcsName)
582 return STG_E_INSUFFICIENTMEMORY;
583
584 lstrcpyW(pstatstg->pwcsName, This->buf->cache_file);
585 }
586
587 pstatstg->type = STGTY_STREAM;
588 if(This->buf->file != INVALID_HANDLE_VALUE) {
589 GetFileSizeEx(This->buf->file, (PLARGE_INTEGER)&pstatstg->cbSize);
590 GetFileTime(This->buf->file, &pstatstg->ctime, &pstatstg->atime, &pstatstg->mtime);
591 if(pstatstg->cbSize.QuadPart)
592 pstatstg->grfMode = GENERIC_READ;
593 }
594
595 return S_OK;
596 }
597
598 static HRESULT WINAPI ProtocolStream_Clone(IStream *iface, IStream **ppstm)
599 {
600 ProtocolStream *This = impl_from_IStream(iface);
601 FIXME("(%p)->(%p)\n", This, ppstm);
602 return E_NOTIMPL;
603 }
604
605 static const IStreamVtbl ProtocolStreamVtbl = {
606 ProtocolStream_QueryInterface,
607 ProtocolStream_AddRef,
608 ProtocolStream_Release,
609 ProtocolStream_Read,
610 ProtocolStream_Write,
611 ProtocolStream_Seek,
612 ProtocolStream_SetSize,
613 ProtocolStream_CopyTo,
614 ProtocolStream_Commit,
615 ProtocolStream_Revert,
616 ProtocolStream_LockRegion,
617 ProtocolStream_UnlockRegion,
618 ProtocolStream_Stat,
619 ProtocolStream_Clone
620 };
621
622 static void stgmed_stream_release(stgmed_obj_t *obj)
623 {
624 ProtocolStream *stream = (ProtocolStream*)obj;
625 IStream_Release(&stream->IStream_iface);
626 }
627
628 static HRESULT stgmed_stream_fill_stgmed(stgmed_obj_t *obj, STGMEDIUM *stgmed)
629 {
630 ProtocolStream *stream = (ProtocolStream*)obj;
631
632 stgmed->tymed = TYMED_ISTREAM;
633 stgmed->u.pstm = &stream->IStream_iface;
634 stgmed->pUnkForRelease = &stream->buf->IUnknown_iface;
635
636 return S_OK;
637 }
638
639 static HRESULT stgmed_stream_get_result(stgmed_obj_t *obj, DWORD bindf, void **result)
640 {
641 ProtocolStream *stream = (ProtocolStream*)obj;
642
643 if(!(bindf & BINDF_ASYNCHRONOUS) && stream->buf->file == INVALID_HANDLE_VALUE
644 && stream->buf->hres != S_FALSE)
645 return INET_E_DATA_NOT_AVAILABLE;
646
647 IStream_AddRef(&stream->IStream_iface);
648 *result = &stream->IStream_iface;
649 return S_OK;
650 }
651
652 static const stgmed_obj_vtbl stgmed_stream_vtbl = {
653 stgmed_stream_release,
654 stgmed_stream_fill_stgmed,
655 stgmed_stream_get_result
656 };
657
658 typedef struct {
659 stgmed_obj_t stgmed_obj;
660 stgmed_buf_t *buf;
661 } stgmed_file_obj_t;
662
663 static stgmed_obj_t *create_stgmed_stream(stgmed_buf_t *buf)
664 {
665 ProtocolStream *ret = heap_alloc(sizeof(ProtocolStream));
666
667 ret->stgmed_obj.vtbl = &stgmed_stream_vtbl;
668 ret->IStream_iface.lpVtbl = &ProtocolStreamVtbl;
669 ret->ref = 1;
670
671 IUnknown_AddRef(&buf->IUnknown_iface);
672 ret->buf = buf;
673
674 URLMON_LockModule();
675
676 return &ret->stgmed_obj;
677 }
678
679 static void stgmed_file_release(stgmed_obj_t *obj)
680 {
681 stgmed_file_obj_t *file_obj = (stgmed_file_obj_t*)obj;
682
683 IUnknown_Release(&file_obj->buf->IUnknown_iface);
684 heap_free(file_obj);
685 }
686
687 static HRESULT stgmed_file_fill_stgmed(stgmed_obj_t *obj, STGMEDIUM *stgmed)
688 {
689 stgmed_file_obj_t *file_obj = (stgmed_file_obj_t*)obj;
690
691 if(!file_obj->buf->cache_file) {
692 WARN("cache_file not set\n");
693 return INET_E_DATA_NOT_AVAILABLE;
694 }
695
696 read_protocol_data(file_obj->buf);
697
698 stgmed->tymed = TYMED_FILE;
699 stgmed->u.lpszFileName = file_obj->buf->cache_file;
700 stgmed->pUnkForRelease = &file_obj->buf->IUnknown_iface;
701
702 return S_OK;
703 }
704
705 static HRESULT stgmed_file_get_result(stgmed_obj_t *obj, DWORD bindf, void **result)
706 {
707 return bindf & BINDF_ASYNCHRONOUS ? MK_S_ASYNCHRONOUS : S_OK;
708 }
709
710 static const stgmed_obj_vtbl stgmed_file_vtbl = {
711 stgmed_file_release,
712 stgmed_file_fill_stgmed,
713 stgmed_file_get_result
714 };
715
716 static stgmed_obj_t *create_stgmed_file(stgmed_buf_t *buf)
717 {
718 stgmed_file_obj_t *ret = heap_alloc(sizeof(*ret));
719
720 ret->stgmed_obj.vtbl = &stgmed_file_vtbl;
721
722 IUnknown_AddRef(&buf->IUnknown_iface);
723 ret->buf = buf;
724
725 return &ret->stgmed_obj;
726 }
727
728 static inline Binding *impl_from_IBinding(IBinding *iface)
729 {
730 return CONTAINING_RECORD(iface, Binding, IBinding_iface);
731 }
732
733 static HRESULT WINAPI Binding_QueryInterface(IBinding *iface, REFIID riid, void **ppv)
734 {
735 Binding *This = impl_from_IBinding(iface);
736
737 *ppv = NULL;
738
739 if(IsEqualGUID(&IID_IUnknown, riid)) {
740 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
741 *ppv = &This->IBinding_iface;
742 }else if(IsEqualGUID(&IID_IBinding, riid)) {
743 TRACE("(%p)->(IID_IBinding %p)\n", This, ppv);
744 *ppv = &This->IBinding_iface;
745 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
746 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
747 *ppv = &This->IInternetProtocolSink_iface;
748 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
749 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
750 *ppv = &This->IInternetBindInfo_iface;
751 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
752 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
753 *ppv = &This->IServiceProvider_iface;
754 }else if(IsEqualGUID(&IID_IWinInetInfo, riid)) {
755 TRACE("(%p)->(IID_IWinInetInfo %p)\n", This, ppv);
756
757 /* NOTE: This violidates COM rules, but tests prove that we should do it */
758 if(!This->protocol->wininet_info)
759 return E_NOINTERFACE;
760
761 *ppv = &This->IWinInetHttpInfo_iface;
762 }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) {
763 TRACE("(%p)->(IID_IWinInetHttpInfo %p)\n", This, ppv);
764
765 if(!This->protocol->wininet_http_info)
766 return E_NOINTERFACE;
767
768 *ppv = &This->IWinInetHttpInfo_iface;
769 }
770
771 if(*ppv) {
772 IBinding_AddRef(&This->IBinding_iface);
773 return S_OK;
774 }
775
776 WARN("Unsupported interface %s\n", debugstr_guid(riid));
777 return E_NOINTERFACE;
778 }
779
780 static ULONG WINAPI Binding_AddRef(IBinding *iface)
781 {
782 Binding *This = impl_from_IBinding(iface);
783 LONG ref = InterlockedIncrement(&This->ref);
784
785 TRACE("(%p) ref=%d\n", This, ref);
786
787 return ref;
788 }
789
790 static ULONG WINAPI Binding_Release(IBinding *iface)
791 {
792 Binding *This = impl_from_IBinding(iface);
793 LONG ref = InterlockedDecrement(&This->ref);
794
795 TRACE("(%p) ref=%d\n", This, ref);
796
797 if(!ref) {
798 if(This->notif_hwnd)
799 release_notif_hwnd(This->notif_hwnd);
800 if(This->mon)
801 IMoniker_Release(This->mon);
802 if(This->callback)
803 IBindStatusCallback_Release(This->callback);
804 if(This->protocol)
805 IInternetProtocolEx_Release(&This->protocol->IInternetProtocolEx_iface);
806 if(This->service_provider)
807 IServiceProvider_Release(This->service_provider);
808 if(This->stgmed_buf)
809 IUnknown_Release(&This->stgmed_buf->IUnknown_iface);
810 if(This->stgmed_obj)
811 This->stgmed_obj->vtbl->release(This->stgmed_obj);
812 if(This->obj)
813 IUnknown_Release(This->obj);
814 if(This->bctx)
815 IBindCtx_Release(This->bctx);
816
817 ReleaseBindInfo(&This->bindinfo);
818 This->section.DebugInfo->Spare[0] = 0;
819 DeleteCriticalSection(&This->section);
820 SysFreeString(This->url);
821 heap_free(This->mime);
822 heap_free(This->redirect_url);
823 heap_free(This);
824
825 URLMON_UnlockModule();
826 }
827
828 return ref;
829 }
830
831 static HRESULT WINAPI Binding_Abort(IBinding *iface)
832 {
833 Binding *This = impl_from_IBinding(iface);
834 HRESULT hres;
835
836 TRACE("(%p)\n", This);
837
838 if(This->state & BINDING_ABORTED)
839 return E_FAIL;
840
841 hres = IInternetProtocolEx_Abort(&This->protocol->IInternetProtocolEx_iface, E_ABORT,
842 ERROR_SUCCESS);
843 if(FAILED(hres))
844 return hres;
845
846 This->state |= BINDING_ABORTED;
847 return S_OK;
848 }
849
850 static HRESULT WINAPI Binding_Suspend(IBinding *iface)
851 {
852 Binding *This = impl_from_IBinding(iface);
853 FIXME("(%p)\n", This);
854 return E_NOTIMPL;
855 }
856
857 static HRESULT WINAPI Binding_Resume(IBinding *iface)
858 {
859 Binding *This = impl_from_IBinding(iface);
860 FIXME("(%p)\n", This);
861 return E_NOTIMPL;
862 }
863
864 static HRESULT WINAPI Binding_SetPriority(IBinding *iface, LONG nPriority)
865 {
866 Binding *This = impl_from_IBinding(iface);
867 FIXME("(%p)->(%d)\n", This, nPriority);
868 return E_NOTIMPL;
869 }
870
871 static HRESULT WINAPI Binding_GetPriority(IBinding *iface, LONG *pnPriority)
872 {
873 Binding *This = impl_from_IBinding(iface);
874 FIXME("(%p)->(%p)\n", This, pnPriority);
875 return E_NOTIMPL;
876 }
877
878 static HRESULT WINAPI Binding_GetBindResult(IBinding *iface, CLSID *pclsidProtocol,
879 DWORD *pdwResult, LPOLESTR *pszResult, DWORD *pdwReserved)
880 {
881 Binding *This = impl_from_IBinding(iface);
882
883 TRACE("(%p)->(%p %p %p %p)\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);
884
885 if(!pdwResult || !pszResult || pdwReserved)
886 return E_INVALIDARG;
887
888 if(!(This->state & BINDING_STOPPED)) {
889 *pclsidProtocol = CLSID_NULL;
890 *pdwResult = 0;
891 *pszResult = NULL;
892 return S_OK;
893 }
894
895 *pclsidProtocol = This->hres==S_OK ? CLSID_NULL : This->clsid;
896 *pdwResult = This->hres;
897 *pszResult = NULL;
898 return S_OK;
899 }
900
901 static const IBindingVtbl BindingVtbl = {
902 Binding_QueryInterface,
903 Binding_AddRef,
904 Binding_Release,
905 Binding_Abort,
906 Binding_Suspend,
907 Binding_Resume,
908 Binding_SetPriority,
909 Binding_GetPriority,
910 Binding_GetBindResult
911 };
912
913 static Binding *get_bctx_binding(IBindCtx *bctx)
914 {
915 IBinding *binding;
916 IUnknown *unk;
917 HRESULT hres;
918
919 hres = IBindCtx_GetObjectParam(bctx, cbinding_contextW, &unk);
920 if(FAILED(hres))
921 return NULL;
922
923 hres = IUnknown_QueryInterface(unk, &IID_IBinding, (void**)&binding);
924 IUnknown_Release(unk);
925 if(FAILED(hres))
926 return NULL;
927
928 if (binding->lpVtbl != &BindingVtbl)
929 return NULL;
930 return impl_from_IBinding(binding);
931 }
932
933 static inline Binding *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface)
934 {
935 return CONTAINING_RECORD(iface, Binding, IInternetProtocolSink_iface);
936 }
937
938 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
939 REFIID riid, void **ppv)
940 {
941 Binding *This = impl_from_IInternetProtocolSink(iface);
942 return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv);
943 }
944
945 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface)
946 {
947 Binding *This = impl_from_IInternetProtocolSink(iface);
948 return IBinding_AddRef(&This->IBinding_iface);
949 }
950
951 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface)
952 {
953 Binding *This = impl_from_IInternetProtocolSink(iface);
954 return IBinding_Release(&This->IBinding_iface);
955 }
956
957 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface,
958 PROTOCOLDATA *pProtocolData)
959 {
960 Binding *This = impl_from_IInternetProtocolSink(iface);
961
962 WARN("(%p)->(%p)\n", This, pProtocolData);
963
964 return E_FAIL;
965 }
966
967 static void on_progress(Binding *This, ULONG progress, ULONG progress_max,
968 ULONG status_code, LPCWSTR status_text)
969 {
970 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
971 status_code, status_text);
972 }
973
974 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
975 ULONG ulStatusCode, LPCWSTR szStatusText)
976 {
977 Binding *This = impl_from_IInternetProtocolSink(iface);
978
979 TRACE("(%p)->(%s %s)\n", This, debugstr_bindstatus(ulStatusCode), debugstr_w(szStatusText));
980
981 switch(ulStatusCode) {
982 case BINDSTATUS_FINDINGRESOURCE:
983 on_progress(This, 0, 0, BINDSTATUS_FINDINGRESOURCE, szStatusText);
984 break;
985 case BINDSTATUS_CONNECTING:
986 on_progress(This, 0, 0, BINDSTATUS_CONNECTING, szStatusText);
987 break;
988 case BINDSTATUS_REDIRECTING:
989 heap_free(This->redirect_url);
990 This->redirect_url = heap_strdupW(szStatusText);
991 on_progress(This, 0, 0, BINDSTATUS_REDIRECTING, szStatusText);
992 break;
993 case BINDSTATUS_BEGINDOWNLOADDATA:
994 break;
995 case BINDSTATUS_SENDINGREQUEST:
996 on_progress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, szStatusText);
997 break;
998 case BINDSTATUS_PROTOCOLCLASSID:
999 CLSIDFromString(szStatusText, &This->clsid);
1000 break;
1001 case BINDSTATUS_MIMETYPEAVAILABLE:
1002 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
1003 mime_available(This, szStatusText);
1004 break;
1005 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
1006 cache_file_available(This, szStatusText);
1007 break;
1008 case BINDSTATUS_DECODING:
1009 IBindStatusCallback_OnProgress(This->callback, 0, 0, BINDSTATUS_DECODING, szStatusText);
1010 break;
1011 case BINDSTATUS_LOADINGMIMEHANDLER:
1012 on_progress(This, 0, 0, BINDSTATUS_LOADINGMIMEHANDLER, szStatusText);
1013 break;
1014 case BINDSTATUS_DIRECTBIND: /* FIXME: Handle BINDSTATUS_DIRECTBIND in BindProtocol */
1015 This->report_mime = FALSE;
1016 break;
1017 case BINDSTATUS_ACCEPTRANGES:
1018 break;
1019 default:
1020 FIXME("Unhandled status code %d\n", ulStatusCode);
1021 return E_NOTIMPL;
1022 };
1023
1024 return S_OK;
1025 }
1026
1027 static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progress_max)
1028 {
1029 FORMATETC formatetc = {0, NULL, 1, -1, TYMED_ISTREAM};
1030 BOOL sent_begindownloaddata = FALSE;
1031
1032 TRACE("(%p)->(%d %u %u)\n", This, bscf, progress, progress_max);
1033
1034 if(This->download_state == END_DOWNLOAD || (This->state & BINDING_ABORTED)) {
1035 read_protocol_data(This->stgmed_buf);
1036 return;
1037 }
1038
1039 if(This->state & BINDING_STOPPED)
1040 return;
1041
1042 if(This->stgmed_buf->file != INVALID_HANDLE_VALUE)
1043 read_protocol_data(This->stgmed_buf);
1044
1045 if(This->download_state == BEFORE_DOWNLOAD) {
1046 This->download_state = DOWNLOADING;
1047 sent_begindownloaddata = TRUE;
1048 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
1049 BINDSTATUS_BEGINDOWNLOADDATA, This->url);
1050
1051 if(This->stgmed_buf->cache_file)
1052 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
1053 BINDSTATUS_CACHEFILENAMEAVAILABLE, This->stgmed_buf->cache_file);
1054 }
1055
1056 if(This->stgmed_buf->hres == S_FALSE || (bscf & BSCF_LASTDATANOTIFICATION)) {
1057 This->download_state = END_DOWNLOAD;
1058 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
1059 BINDSTATUS_ENDDOWNLOADDATA, This->url);
1060 }else if(!sent_begindownloaddata) {
1061 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
1062 BINDSTATUS_DOWNLOADINGDATA, This->url);
1063 }
1064
1065 if(This->state & (BINDING_STOPPED|BINDING_ABORTED))
1066 return;
1067
1068 if(This->to_object) {
1069 if(!(This->state & BINDING_OBJAVAIL)) {
1070 IBinding_AddRef(&This->IBinding_iface);
1071 create_object(This);
1072 IBinding_Release(&This->IBinding_iface);
1073 }
1074 }else {
1075 STGMEDIUM stgmed;
1076 HRESULT hres;
1077
1078 if(!(This->state & BINDING_LOCKED)) {
1079 HRESULT hres = IInternetProtocolEx_LockRequest(
1080 &This->protocol->IInternetProtocolEx_iface, 0);
1081 if(SUCCEEDED(hres))
1082 This->state |= BINDING_LOCKED;
1083 }
1084
1085 hres = This->stgmed_obj->vtbl->fill_stgmed(This->stgmed_obj, &stgmed);
1086 if(FAILED(hres)) {
1087 stop_binding(This, hres, NULL);
1088 return;
1089 }
1090
1091 formatetc.tymed = stgmed.tymed;
1092 formatetc.cfFormat = This->clipboard_format;
1093
1094 hres = IBindStatusCallback_OnDataAvailable(This->callback, bscf, progress,
1095 &formatetc, &stgmed);
1096 if(hres != S_OK) {
1097 if(This->download_state != END_DOWNLOAD) {
1098 This->download_state = END_DOWNLOAD;
1099 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
1100 BINDSTATUS_ENDDOWNLOADDATA, This->url);
1101 }
1102
1103 WARN("OnDataAvailable returned %x\n", hres);
1104 stop_binding(This, hres, NULL);
1105 return;
1106 }
1107
1108 if(This->download_state == END_DOWNLOAD)
1109 stop_binding(This, S_OK, NULL);
1110 }
1111 }
1112
1113 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1114 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1115 {
1116 Binding *This = impl_from_IInternetProtocolSink(iface);
1117
1118 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1119
1120 report_data(This, grfBSCF, ulProgress, ulProgressMax);
1121 return S_OK;
1122 }
1123
1124 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1125 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1126 {
1127 Binding *This = impl_from_IInternetProtocolSink(iface);
1128
1129 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1130
1131 stop_binding(This, hrResult, szResult);
1132
1133 IInternetProtocolEx_Terminate(&This->protocol->IInternetProtocolEx_iface, 0);
1134 return S_OK;
1135 }
1136
1137 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1138 InternetProtocolSink_QueryInterface,
1139 InternetProtocolSink_AddRef,
1140 InternetProtocolSink_Release,
1141 InternetProtocolSink_Switch,
1142 InternetProtocolSink_ReportProgress,
1143 InternetProtocolSink_ReportData,
1144 InternetProtocolSink_ReportResult
1145 };
1146
1147 static inline Binding *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
1148 {
1149 return CONTAINING_RECORD(iface, Binding, IInternetBindInfo_iface);
1150 }
1151
1152 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
1153 REFIID riid, void **ppv)
1154 {
1155 Binding *This = impl_from_IInternetBindInfo(iface);
1156 return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv);
1157 }
1158
1159 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
1160 {
1161 Binding *This = impl_from_IInternetBindInfo(iface);
1162 return IBinding_AddRef(&This->IBinding_iface);
1163 }
1164
1165 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
1166 {
1167 Binding *This = impl_from_IInternetBindInfo(iface);
1168 return IBinding_Release(&This->IBinding_iface);
1169 }
1170
1171 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
1172 DWORD *grfBINDF, BINDINFO *pbindinfo)
1173 {
1174 Binding *This = impl_from_IInternetBindInfo(iface);
1175
1176 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
1177
1178 *grfBINDF = This->bindf;
1179 return CopyBindInfo(&This->bindinfo, pbindinfo);
1180 }
1181
1182 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
1183 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
1184 {
1185 Binding *This = impl_from_IInternetBindInfo(iface);
1186
1187 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
1188
1189 switch(ulStringType) {
1190 case BINDSTRING_ACCEPT_MIMES: {
1191 static const WCHAR wszMimes[] = {'*','/','*',0};
1192
1193 if(!ppwzStr || !pcElFetched)
1194 return E_INVALIDARG;
1195
1196 ppwzStr[0] = CoTaskMemAlloc(sizeof(wszMimes));
1197 memcpy(ppwzStr[0], wszMimes, sizeof(wszMimes));
1198 *pcElFetched = 1;
1199 return S_OK;
1200 }
1201 case BINDSTRING_USER_AGENT: {
1202 IInternetBindInfo *bindinfo = NULL;
1203 HRESULT hres;
1204
1205 hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo,
1206 (void**)&bindinfo);
1207 if(FAILED(hres))
1208 return hres;
1209
1210 hres = IInternetBindInfo_GetBindString(bindinfo, ulStringType, ppwzStr,
1211 cEl, pcElFetched);
1212 IInternetBindInfo_Release(bindinfo);
1213
1214 return hres;
1215 }
1216 case BINDSTRING_URL: {
1217 DWORD size = (SysStringLen(This->url)+1) * sizeof(WCHAR);
1218
1219 if(!ppwzStr || !pcElFetched)
1220 return E_INVALIDARG;
1221
1222 *ppwzStr = CoTaskMemAlloc(size);
1223 memcpy(*ppwzStr, This->url, size);
1224 *pcElFetched = 1;
1225 return S_OK;
1226 }
1227 }
1228
1229 FIXME("not supported string type %d\n", ulStringType);
1230 return E_NOTIMPL;
1231 }
1232
1233 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
1234 InternetBindInfo_QueryInterface,
1235 InternetBindInfo_AddRef,
1236 InternetBindInfo_Release,
1237 InternetBindInfo_GetBindInfo,
1238 InternetBindInfo_GetBindString
1239 };
1240
1241 static inline Binding *impl_from_IWinInetHttpInfo(IWinInetHttpInfo *iface)
1242 {
1243 return CONTAINING_RECORD(iface, Binding, IWinInetHttpInfo_iface);
1244 }
1245
1246 static HRESULT WINAPI WinInetHttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv)
1247 {
1248 Binding *This = impl_from_IWinInetHttpInfo(iface);
1249 return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv);
1250 }
1251
1252 static ULONG WINAPI WinInetHttpInfo_AddRef(IWinInetHttpInfo *iface)
1253 {
1254 Binding *This = impl_from_IWinInetHttpInfo(iface);
1255 return IBinding_AddRef(&This->IBinding_iface);
1256 }
1257
1258 static ULONG WINAPI WinInetHttpInfo_Release(IWinInetHttpInfo *iface)
1259 {
1260 Binding *This = impl_from_IWinInetHttpInfo(iface);
1261 return IBinding_Release(&This->IBinding_iface);
1262 }
1263
1264 static HRESULT WINAPI WinInetHttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption,
1265 void *pBuffer, DWORD *pcbBuffer)
1266 {
1267 Binding *This = impl_from_IWinInetHttpInfo(iface);
1268 TRACE("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer);
1269
1270 if(!This->protocol->wininet_info)
1271 return E_FAIL;
1272
1273 return IWinInetInfo_QueryOption(This->protocol->wininet_info,
1274 dwOption, pBuffer, pcbBuffer);
1275 }
1276
1277 static HRESULT WINAPI WinInetHttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption,
1278 void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved)
1279 {
1280 Binding *This = impl_from_IWinInetHttpInfo(iface);
1281 TRACE("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
1282
1283 if(!This->protocol->wininet_http_info)
1284 return E_FAIL;
1285
1286 return IWinInetHttpInfo_QueryInfo(This->protocol->wininet_http_info,
1287 dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
1288 }
1289
1290 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
1291 WinInetHttpInfo_QueryInterface,
1292 WinInetHttpInfo_AddRef,
1293 WinInetHttpInfo_Release,
1294 WinInetHttpInfo_QueryOption,
1295 WinInetHttpInfo_QueryInfo
1296 };
1297
1298 static inline Binding *impl_from_IServiceProvider(IServiceProvider *iface)
1299 {
1300 return CONTAINING_RECORD(iface, Binding, IServiceProvider_iface);
1301 }
1302
1303 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface,
1304 REFIID riid, void **ppv)
1305 {
1306 Binding *This = impl_from_IServiceProvider(iface);
1307 return IBinding_QueryInterface(&This->IBinding_iface, riid, ppv);
1308 }
1309
1310 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
1311 {
1312 Binding *This = impl_from_IServiceProvider(iface);
1313 return IBinding_AddRef(&This->IBinding_iface);
1314 }
1315
1316 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
1317 {
1318 Binding *This = impl_from_IServiceProvider(iface);
1319 return IBinding_Release(&This->IBinding_iface);
1320 }
1321
1322 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
1323 REFGUID guidService, REFIID riid, void **ppv)
1324 {
1325 Binding *This = impl_from_IServiceProvider(iface);
1326 HRESULT hres;
1327
1328 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1329
1330 if(This->service_provider) {
1331 hres = IServiceProvider_QueryService(This->service_provider, guidService,
1332 riid, ppv);
1333 if(SUCCEEDED(hres))
1334 return hres;
1335 }
1336
1337 WARN("unknown service %s\n", debugstr_guid(guidService));
1338 return E_NOINTERFACE;
1339 }
1340
1341 static const IServiceProviderVtbl ServiceProviderVtbl = {
1342 ServiceProvider_QueryInterface,
1343 ServiceProvider_AddRef,
1344 ServiceProvider_Release,
1345 ServiceProvider_QueryService
1346 };
1347
1348 static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback)
1349 {
1350 IUnknown *unk;
1351 HRESULT hres;
1352
1353 hres = IBindCtx_GetObjectParam(pbc, bscb_holderW, &unk);
1354 if(FAILED(hres))
1355 return create_default_callback(callback);
1356
1357 hres = IUnknown_QueryInterface(unk, &IID_IBindStatusCallback, (void**)callback);
1358 IUnknown_Release(unk);
1359 return hres;
1360 }
1361
1362 static BOOL is_urlmon_protocol(IUri *uri)
1363 {
1364 DWORD scheme;
1365 HRESULT hres;
1366
1367 hres = IUri_GetScheme(uri, &scheme);
1368 if(FAILED(hres))
1369 return FALSE;
1370
1371 switch(scheme) {
1372 case URL_SCHEME_FILE:
1373 case URL_SCHEME_FTP:
1374 case URL_SCHEME_GOPHER:
1375 case URL_SCHEME_HTTP:
1376 case URL_SCHEME_HTTPS:
1377 case URL_SCHEME_MK:
1378 return TRUE;
1379 }
1380
1381 return FALSE;
1382 }
1383
1384 static HRESULT Binding_Create(IMoniker *mon, Binding *binding_ctx, IUri *uri, IBindCtx *pbc,
1385 BOOL to_obj, REFIID riid, Binding **binding)
1386 {
1387 Binding *ret;
1388 HRESULT hres;
1389
1390 URLMON_LockModule();
1391
1392 ret = heap_alloc_zero(sizeof(Binding));
1393
1394 ret->IBinding_iface.lpVtbl = &BindingVtbl;
1395 ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
1396 ret->IInternetBindInfo_iface.lpVtbl = &InternetBindInfoVtbl;
1397 ret->IWinInetHttpInfo_iface.lpVtbl = &WinInetHttpInfoVtbl;
1398 ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
1399
1400 ret->ref = 1;
1401
1402 ret->to_object = to_obj;
1403 ret->iid = *riid;
1404 ret->notif_hwnd = get_notif_hwnd();
1405 ret->report_mime = !binding_ctx;
1406 ret->download_state = BEFORE_DOWNLOAD;
1407
1408 if(to_obj) {
1409 IBindCtx_AddRef(pbc);
1410 ret->bctx = pbc;
1411 }
1412
1413 if(mon) {
1414 IMoniker_AddRef(mon);
1415 ret->mon = mon;
1416 }
1417
1418 ret->bindinfo.cbSize = sizeof(BINDINFO);
1419
1420 InitializeCriticalSection(&ret->section);
1421 ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": Binding.section");
1422
1423 hres = get_callback(pbc, &ret->callback);
1424 if(FAILED(hres)) {
1425 WARN("Could not get IBindStatusCallback\n");
1426 IBinding_Release(&ret->IBinding_iface);
1427 return hres;
1428 }
1429
1430 IBindStatusCallback_QueryInterface(ret->callback, &IID_IServiceProvider,
1431 (void**)&ret->service_provider);
1432
1433 if(binding_ctx) {
1434 ret->protocol = binding_ctx->protocol;
1435 IInternetProtocolEx_AddRef(&ret->protocol->IInternetProtocolEx_iface);
1436 }else {
1437 hres = create_binding_protocol(TRUE, &ret->protocol);
1438 if(FAILED(hres)) {
1439 WARN("Could not get protocol handler\n");
1440 IBinding_Release(&ret->IBinding_iface);
1441 return hres;
1442 }
1443 }
1444
1445 hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo);
1446 if(FAILED(hres)) {
1447 WARN("GetBindInfo failed: %08x\n", hres);
1448 IBinding_Release(&ret->IBinding_iface);
1449 return hres;
1450 }
1451
1452 TRACE("bindf %08x\n", ret->bindf);
1453 dump_BINDINFO(&ret->bindinfo);
1454
1455 ret->bindf |= BINDF_FROMURLMON;
1456 if(to_obj)
1457 ret->bindinfo.dwOptions |= 0x100000;
1458
1459 if(!(ret->bindf & BINDF_ASYNCHRONOUS) || !(ret->bindf & BINDF_PULLDATA)) {
1460 ret->bindf |= BINDF_NEEDFILE;
1461 ret->use_cache_file = TRUE;
1462 }else if(!is_urlmon_protocol(uri)) {
1463 ret->bindf |= BINDF_NEEDFILE;
1464 }
1465
1466 hres = IUri_GetDisplayUri(uri, &ret->url);
1467 if(FAILED(hres)) {
1468 IBinding_Release(&ret->IBinding_iface);
1469 return hres;
1470 }
1471
1472 if(binding_ctx) {
1473 ret->stgmed_buf = binding_ctx->stgmed_buf;
1474 IUnknown_AddRef(&ret->stgmed_buf->IUnknown_iface);
1475 ret->clipboard_format = binding_ctx->clipboard_format;
1476 }else {
1477 ret->stgmed_buf = create_stgmed_buf(&ret->protocol->IInternetProtocolEx_iface);
1478 }
1479
1480 if(to_obj) {
1481 ret->stgmed_obj = NULL;
1482 }else if(IsEqualGUID(&IID_IStream, riid)) {
1483 ret->stgmed_obj = create_stgmed_stream(ret->stgmed_buf);
1484 }else if(IsEqualGUID(&IID_IUnknown, riid)) {
1485 ret->bindf |= BINDF_NEEDFILE;
1486 ret->stgmed_obj = create_stgmed_file(ret->stgmed_buf);
1487 }else {
1488 FIXME("Unsupported riid %s\n", debugstr_guid(riid));
1489 IBinding_Release(&ret->IBinding_iface);
1490 return E_NOTIMPL;
1491 }
1492
1493 *binding = ret;
1494 return S_OK;
1495 }
1496
1497 static HRESULT start_binding(IMoniker *mon, Binding *binding_ctx, IUri *uri, IBindCtx *pbc,
1498 BOOL to_obj, REFIID riid, Binding **ret)
1499 {
1500 Binding *binding = NULL;
1501 HRESULT hres;
1502 MSG msg;
1503
1504 hres = Binding_Create(mon, binding_ctx, uri, pbc, to_obj, riid, &binding);
1505 if(FAILED(hres))
1506 return hres;
1507
1508 hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, &binding->IBinding_iface);
1509 if(FAILED(hres)) {
1510 WARN("OnStartBinding failed: %08x\n", hres);
1511 if(hres != E_ABORT && hres != E_NOTIMPL)
1512 hres = INET_E_DOWNLOAD_FAILURE;
1513
1514 stop_binding(binding, hres, NULL);
1515 IBinding_Release(&binding->IBinding_iface);
1516 return hres;
1517 }
1518
1519 if(binding_ctx) {
1520 set_binding_sink(binding->protocol, &binding->IInternetProtocolSink_iface,
1521 &binding->IInternetBindInfo_iface);
1522 if(binding_ctx->redirect_url)
1523 IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_REDIRECTING, binding_ctx->redirect_url);
1524 report_data(binding, BSCF_FIRSTDATANOTIFICATION | (binding_ctx->download_state == END_DOWNLOAD ? BSCF_LASTDATANOTIFICATION : 0),
1525 0, 0);
1526 }else {
1527 hres = IInternetProtocolEx_StartEx(&binding->protocol->IInternetProtocolEx_iface, uri,
1528 &binding->IInternetProtocolSink_iface, &binding->IInternetBindInfo_iface,
1529 PI_APARTMENTTHREADED|PI_MIMEVERIFICATION, 0);
1530
1531 TRACE("start ret %08x\n", hres);
1532
1533 if(FAILED(hres) && hres != E_PENDING) {
1534 stop_binding(binding, hres, NULL);
1535 IBinding_Release(&binding->IBinding_iface);
1536
1537 return hres;
1538 }
1539 }
1540
1541 while(!(binding->bindf & BINDF_ASYNCHRONOUS) &&
1542 !(binding->state & BINDING_STOPPED)) {
1543 MsgWaitForMultipleObjects(0, NULL, FALSE, 5000, QS_POSTMESSAGE);
1544 while (PeekMessageW(&msg, binding->notif_hwnd, WM_USER, WM_USER+117, PM_REMOVE|PM_NOYIELD)) {
1545 TranslateMessage(&msg);
1546 DispatchMessageW(&msg);
1547 }
1548 }
1549
1550 *ret = binding;
1551 return S_OK;
1552 }
1553
1554 HRESULT bind_to_storage(IUri *uri, IBindCtx *pbc, REFIID riid, void **ppv)
1555 {
1556 Binding *binding = NULL, *binding_ctx;
1557 HRESULT hres;
1558
1559 binding_ctx = get_bctx_binding(pbc);
1560
1561 hres = start_binding(NULL, binding_ctx, uri, pbc, FALSE, riid, &binding);
1562 if(binding_ctx)
1563 IBinding_Release(&binding_ctx->IBinding_iface);
1564 if(FAILED(hres))
1565 return hres;
1566
1567 if(binding->hres == S_OK && binding->download_state != BEFORE_DOWNLOAD /* FIXME */) {
1568 if((binding->state & BINDING_STOPPED) && (binding->state & BINDING_LOCKED))
1569 IInternetProtocolEx_UnlockRequest(&binding->protocol->IInternetProtocolEx_iface);
1570
1571 hres = binding->stgmed_obj->vtbl->get_result(binding->stgmed_obj, binding->bindf, ppv);
1572 }else if(binding->bindf & BINDF_ASYNCHRONOUS) {
1573 hres = MK_S_ASYNCHRONOUS;
1574 }else {
1575 hres = FAILED(binding->hres) ? binding->hres : S_OK;
1576 }
1577
1578 IBinding_Release(&binding->IBinding_iface);
1579
1580 return hres;
1581 }
1582
1583 HRESULT bind_to_object(IMoniker *mon, IUri *uri, IBindCtx *pbc, REFIID riid, void **ppv)
1584 {
1585 Binding *binding;
1586 HRESULT hres;
1587
1588 *ppv = NULL;
1589
1590 hres = start_binding(mon, NULL, uri, pbc, TRUE, riid, &binding);
1591 if(FAILED(hres))
1592 return hres;
1593
1594 if(binding->hres != S_OK) {
1595 hres = SUCCEEDED(binding->hres) ? S_OK : binding->hres;
1596 }else if(binding->bindf & BINDF_ASYNCHRONOUS) {
1597 hres = MK_S_ASYNCHRONOUS;
1598 }else {
1599 *ppv = binding->obj;
1600 IUnknown_AddRef(binding->obj);
1601 hres = S_OK;
1602 }
1603
1604 IBinding_Release(&binding->IBinding_iface);
1605
1606 return hres;
1607 }