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