user32: Fix a spelling typo.
[wine.git] / dlls / urlmon / binding.c
blob66b5bdfd66bbc82f0ec150661d3b4a31207455e6
1 /*
2 * Copyright 2005-2007 Jacek Caban for CodeWeavers
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.
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.
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
19 #include "urlmon_main.h"
20 #include "winreg.h"
22 #include "wine/debug.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
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 };
29 typedef struct Binding Binding;
31 struct _task_header_t;
33 typedef void (*task_proc_t)(Binding*, struct _task_header_t*);
35 typedef struct _task_header_t {
36 task_proc_t proc;
37 struct _task_header_t *next;
38 } task_header_t;
40 typedef struct {
41 const IStreamVtbl *lpStreamVtbl;
43 LONG ref;
45 IInternetProtocol *protocol;
47 BYTE buf[1024*8];
48 DWORD buf_size;
49 BOOL init_buf;
50 HRESULT hres;
51 } ProtocolStream;
53 typedef enum {
54 BEFORE_DOWNLOAD,
55 DOWNLOADING,
56 END_DOWNLOAD
57 } download_state_t;
59 #define BINDING_LOCKED 0x0001
60 #define BINDING_STOPPED 0x0002
61 #define BINDING_OBJAVAIL 0x0004
63 struct Binding {
64 const IBindingVtbl *lpBindingVtbl;
65 const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl;
66 const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
67 const IServiceProviderVtbl *lpServiceProviderVtbl;
69 LONG ref;
71 IBindStatusCallback *callback;
72 IInternetProtocol *protocol;
73 IServiceProvider *service_provider;
74 ProtocolStream *stream;
76 BINDINFO bindinfo;
77 DWORD bindf;
78 BOOL to_object;
79 LPWSTR mime;
80 UINT clipboard_format;
81 LPWSTR url;
82 IID iid;
83 BOOL report_mime;
84 DWORD continue_call;
85 DWORD state;
86 HRESULT hres;
87 download_state_t download_state;
88 IUnknown *obj;
89 IMoniker *mon;
90 IBindCtx *bctx;
92 DWORD apartment_thread;
93 HWND notif_hwnd;
95 STGMEDIUM stgmed;
97 task_header_t *task_queue_head, *task_queue_tail;
98 CRITICAL_SECTION section;
101 #define BINDING(x) ((IBinding*) &(x)->lpBindingVtbl)
102 #define PROTSINK(x) ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl)
103 #define BINDINF(x) ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
104 #define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl)
106 #define STREAM(x) ((IStream*) &(x)->lpStreamVtbl)
107 #define HTTPNEG2(x) ((IHttpNegotiate2*) &(x)->lpHttpNegotiate2Vtbl)
109 #define WM_MK_CONTINUE (WM_USER+101)
111 static void push_task(Binding *binding, task_header_t *task, task_proc_t proc)
113 task->proc = proc;
114 task->next = NULL;
116 EnterCriticalSection(&binding->section);
118 if(binding->task_queue_tail) {
119 binding->task_queue_tail->next = task;
120 binding->task_queue_tail = task;
121 }else {
122 binding->task_queue_tail = binding->task_queue_head = task;
125 LeaveCriticalSection(&binding->section);
128 static task_header_t *pop_task(Binding *binding)
130 task_header_t *ret;
132 EnterCriticalSection(&binding->section);
134 ret = binding->task_queue_head;
135 if(ret) {
136 binding->task_queue_head = ret->next;
137 if(!binding->task_queue_head)
138 binding->task_queue_tail = NULL;
141 LeaveCriticalSection(&binding->section);
143 return ret;
146 static void fill_stream_buffer(ProtocolStream *This)
148 DWORD read = 0;
150 if(sizeof(This->buf) == This->buf_size)
151 return;
153 This->hres = IInternetProtocol_Read(This->protocol, This->buf+This->buf_size,
154 sizeof(This->buf)-This->buf_size, &read);
155 This->buf_size += read;
156 if(read > 0)
157 This->init_buf = TRUE;
160 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
162 if(msg == WM_MK_CONTINUE) {
163 Binding *binding = (Binding*)lParam;
164 task_header_t *task;
166 while((task = pop_task(binding))) {
167 binding->continue_call++;
168 task->proc(binding, task);
169 binding->continue_call--;
172 IBinding_Release(BINDING(binding));
173 return 0;
176 return DefWindowProcW(hwnd, msg, wParam, lParam);
179 static HWND get_notif_hwnd(void)
181 static ATOM wnd_class = 0;
182 HWND hwnd;
184 static const WCHAR wszURLMonikerNotificationWindow[] =
185 {'U','R','L',' ','M','o','n','i','k','e','r',' ',
186 'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
188 if(!wnd_class) {
189 static WNDCLASSEXW wndclass = {
190 sizeof(wndclass), 0,
191 notif_wnd_proc, 0, 0,
192 NULL, NULL, NULL, NULL, NULL,
193 wszURLMonikerNotificationWindow,
194 NULL
197 wndclass.hInstance = URLMON_hInstance;
199 wnd_class = RegisterClassExW(&wndclass);
200 if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
201 wnd_class = 1;
204 hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
205 wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
206 NULL, URLMON_hInstance, NULL);
208 TRACE("hwnd = %p\n", hwnd);
210 return hwnd;
213 static void dump_BINDINFO(BINDINFO *bi)
215 static const char * const BINDINFOF_str[] = {
216 "#0",
217 "BINDINFOF_URLENCODESTGMEDDATA",
218 "BINDINFOF_URLENCODEDEXTRAINFO"
221 static const char * const BINDVERB_str[] = {
222 "BINDVERB_GET",
223 "BINDVERB_POST",
224 "BINDVERB_PUT",
225 "BINDVERB_CUSTOM"
228 TRACE("\n"
229 "BINDINFO = {\n"
230 " %d, %s,\n"
231 " {%d, %p, %p},\n"
232 " %s,\n"
233 " %s,\n"
234 " %s,\n"
235 " %d, %08x, %d, %d\n"
236 " {%d %p %x},\n"
237 " %s\n"
238 " %p, %d\n"
239 "}\n",
241 bi->cbSize, debugstr_w(bi->szExtraInfo),
242 bi->stgmedData.tymed, bi->stgmedData.u.hGlobal, bi->stgmedData.pUnkForRelease,
243 bi->grfBindInfoF > BINDINFOF_URLENCODEDEXTRAINFO
244 ? "unknown" : BINDINFOF_str[bi->grfBindInfoF],
245 bi->dwBindVerb > BINDVERB_CUSTOM
246 ? "unknown" : BINDVERB_str[bi->dwBindVerb],
247 debugstr_w(bi->szCustomVerb),
248 bi->cbstgmedData, bi->dwOptions, bi->dwOptionsFlags, bi->dwCodePage,
249 bi->securityAttributes.nLength,
250 bi->securityAttributes.lpSecurityDescriptor,
251 bi->securityAttributes.bInheritHandle,
252 debugstr_guid(&bi->iid),
253 bi->pUnk, bi->dwReserved
257 static void set_binding_mime(Binding *binding, LPCWSTR mime)
259 EnterCriticalSection(&binding->section);
261 if(binding->report_mime) {
262 heap_free(binding->mime);
263 binding->mime = heap_strdupW(mime);
266 LeaveCriticalSection(&binding->section);
269 static void handle_mime_available(Binding *binding, BOOL verify)
271 BOOL report_mime;
273 EnterCriticalSection(&binding->section);
274 report_mime = binding->report_mime;
275 binding->report_mime = FALSE;
276 LeaveCriticalSection(&binding->section);
278 if(!report_mime)
279 return;
281 if(verify) {
282 LPWSTR mime = NULL;
284 fill_stream_buffer(binding->stream);
285 FindMimeFromData(NULL, binding->url, binding->stream->buf,
286 min(binding->stream->buf_size, 255), binding->mime, 0, &mime, 0);
288 heap_free(binding->mime);
289 binding->mime = heap_strdupW(mime);
290 CoTaskMemFree(mime);
293 IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_MIMETYPEAVAILABLE, binding->mime);
295 binding->clipboard_format = RegisterClipboardFormatW(binding->mime);
298 typedef struct {
299 task_header_t header;
300 BOOL verify;
301 } mime_available_task_t;
303 static void mime_available_proc(Binding *binding, task_header_t *t)
305 mime_available_task_t *task = (mime_available_task_t*)t;
307 handle_mime_available(binding, task->verify);
309 heap_free(task);
312 static void mime_available(Binding *This, LPCWSTR mime, BOOL verify)
314 if(mime)
315 set_binding_mime(This, mime);
317 if(GetCurrentThreadId() == This->apartment_thread) {
318 handle_mime_available(This, verify);
319 }else {
320 mime_available_task_t *task = heap_alloc(sizeof(task_header_t));
321 task->verify = verify;
322 push_task(This, &task->header, mime_available_proc);
326 static void stop_binding(Binding *binding, HRESULT hres, LPCWSTR str)
328 if(binding->state & BINDING_LOCKED) {
329 IInternetProtocol_UnlockRequest(binding->protocol);
330 binding->state &= ~BINDING_LOCKED;
333 if(!(binding->state & BINDING_STOPPED)) {
334 binding->state |= BINDING_STOPPED;
336 IBindStatusCallback_OnStopBinding(binding->callback, hres, str);
337 binding->hres = hres;
341 static LPWSTR get_mime_clsid(LPCWSTR mime, CLSID *clsid)
343 LPWSTR key_name, ret;
344 DWORD res, type, size;
345 HKEY hkey;
346 int len;
347 HRESULT hres;
349 static const WCHAR mime_keyW[] =
350 {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
351 'C','o','n','t','e','n','t',' ','T','y','p','e','\\'};
352 static const WCHAR clsidW[] = {'C','L','S','I','D',0};
354 len = strlenW(mime)+1;
355 key_name = heap_alloc(sizeof(mime_keyW) + len*sizeof(WCHAR));
356 memcpy(key_name, mime_keyW, sizeof(mime_keyW));
357 strcpyW(key_name + sizeof(mime_keyW)/sizeof(WCHAR), mime);
359 res = RegOpenKeyW(HKEY_CLASSES_ROOT, key_name, &hkey);
360 heap_free(key_name);
361 if(res != ERROR_SUCCESS) {
362 WARN("Could not open MIME key: %x\n", res);
363 return NULL;
366 size = 50*sizeof(WCHAR);
367 ret = heap_alloc(size);
368 res = RegQueryValueExW(hkey, clsidW, NULL, &type, (LPBYTE)ret, &size);
369 RegCloseKey(hkey);
370 if(res != ERROR_SUCCESS) {
371 WARN("Could not get CLSID: %08x\n", res);
372 heap_free(ret);
373 return NULL;
376 hres = CLSIDFromString(ret, clsid);
377 if(FAILED(hres)) {
378 WARN("Could not parse CLSID: %08x\n", hres);
379 heap_free(ret);
380 return NULL;
383 return ret;
386 static void load_doc_mon(Binding *binding, IPersistMoniker *persist)
388 IBindCtx *bctx;
389 HRESULT hres;
391 hres = CreateAsyncBindCtxEx(binding->bctx, 0, NULL, NULL, &bctx, 0);
392 if(FAILED(hres)) {
393 WARN("CreateAsyncBindCtxEx failed: %08x\n", hres);
394 return;
397 IBindCtx_RevokeObjectParam(bctx, bscb_holderW);
398 IBindCtx_RegisterObjectParam(bctx, cbinding_contextW, (IUnknown*)BINDING(binding));
400 hres = IPersistMoniker_Load(persist, binding->download_state == END_DOWNLOAD, binding->mon, bctx, 0x12);
401 IBindCtx_RevokeObjectParam(bctx, cbinding_contextW);
402 IBindCtx_Release(bctx);
403 if(FAILED(hres))
404 FIXME("Load failed: %08x\n", hres);
407 static void create_object(Binding *binding)
409 IPersistMoniker *persist;
410 LPWSTR clsid_str;
411 CLSID clsid;
412 HRESULT hres;
414 if(!binding->mime) {
415 FIXME("MIME unavailable\n");
416 return;
419 if(!(clsid_str = get_mime_clsid(binding->mime, &clsid))) {
420 FIXME("Could not find object for MIME %s\n", debugstr_w(binding->mime));
421 return;
424 IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_CLASSIDAVAILABLE, clsid_str);
426 IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_BEGINSYNCOPERATION, NULL);
428 hres = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
429 &binding->iid, (void**)&binding->obj);
430 if(FAILED(hres))
431 FIXME("CoCreateInstance failed: %08x\n", hres);
433 binding->state |= BINDING_OBJAVAIL;
435 hres = IUnknown_QueryInterface(binding->obj, &IID_IPersistMoniker, (void**)&persist);
436 if(SUCCEEDED(hres)) {
437 IMonikerProp *prop;
439 hres = IPersistMoniker_QueryInterface(persist, &IID_IMonikerProp, (void**)&prop);
440 if(SUCCEEDED(hres)) {
441 IMonikerProp_PutProperty(prop, MIMETYPEPROP, binding->mime);
442 IMonikerProp_PutProperty(prop, CLASSIDPROP, clsid_str);
443 IMonikerProp_Release(prop);
446 load_doc_mon(binding, persist);
448 IPersistMoniker_Release(persist);
449 }else {
450 FIXME("Could not get IPersistMoniker: %08x\n", hres);
451 /* FIXME: Try query IPersistFile */
454 heap_free(clsid_str);
456 IBindStatusCallback_OnObjectAvailable(binding->callback, &binding->iid, binding->obj);
458 IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_ENDSYNCOPERATION, NULL);
460 stop_binding(binding, S_OK, NULL);
463 #define STREAM_THIS(iface) DEFINE_THIS(ProtocolStream, Stream, iface)
465 static HRESULT WINAPI ProtocolStream_QueryInterface(IStream *iface,
466 REFIID riid, void **ppv)
468 ProtocolStream *This = STREAM_THIS(iface);
470 *ppv = NULL;
472 if(IsEqualGUID(&IID_IUnknown, riid)) {
473 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
474 *ppv = STREAM(This);
475 }else if(IsEqualGUID(&IID_ISequentialStream, riid)) {
476 TRACE("(%p)->(IID_ISequentialStream %p)\n", This, ppv);
477 *ppv = STREAM(This);
478 }else if(IsEqualGUID(&IID_IStream, riid)) {
479 TRACE("(%p)->(IID_IStream %p)\n", This, ppv);
480 *ppv = STREAM(This);
483 if(*ppv) {
484 IStream_AddRef(STREAM(This));
485 return S_OK;
488 WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
489 return E_NOINTERFACE;
492 static ULONG WINAPI ProtocolStream_AddRef(IStream *iface)
494 ProtocolStream *This = STREAM_THIS(iface);
495 LONG ref = InterlockedIncrement(&This->ref);
497 TRACE("(%p) ref=%d\n", This, ref);
499 return ref;
502 static ULONG WINAPI ProtocolStream_Release(IStream *iface)
504 ProtocolStream *This = STREAM_THIS(iface);
505 LONG ref = InterlockedDecrement(&This->ref);
507 TRACE("(%p) ref=%d\n", This, ref);
509 if(!ref) {
510 IInternetProtocol_Release(This->protocol);
511 heap_free(This);
513 URLMON_UnlockModule();
516 return ref;
519 static HRESULT WINAPI ProtocolStream_Read(IStream *iface, void *pv,
520 ULONG cb, ULONG *pcbRead)
522 ProtocolStream *This = STREAM_THIS(iface);
523 DWORD read = 0, pread = 0;
525 TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbRead);
527 if(This->buf_size) {
528 read = cb;
530 if(read > This->buf_size)
531 read = This->buf_size;
533 memcpy(pv, This->buf, read);
535 if(read < This->buf_size)
536 memmove(This->buf, This->buf+read, This->buf_size-read);
537 This->buf_size -= read;
540 if(read == cb) {
541 if (pcbRead)
542 *pcbRead = read;
543 return S_OK;
546 This->hres = IInternetProtocol_Read(This->protocol, (PBYTE)pv+read, cb-read, &pread);
547 if (pcbRead)
548 *pcbRead = read + pread;
550 if(This->hres == E_PENDING)
551 return E_PENDING;
552 else if(FAILED(This->hres))
553 FIXME("Read failed: %08x\n", This->hres);
555 return read || pread ? S_OK : S_FALSE;
558 static HRESULT WINAPI ProtocolStream_Write(IStream *iface, const void *pv,
559 ULONG cb, ULONG *pcbWritten)
561 ProtocolStream *This = STREAM_THIS(iface);
563 TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbWritten);
565 return STG_E_ACCESSDENIED;
568 static HRESULT WINAPI ProtocolStream_Seek(IStream *iface, LARGE_INTEGER dlibMove,
569 DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
571 ProtocolStream *This = STREAM_THIS(iface);
572 FIXME("(%p)->(%d %08x %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
573 return E_NOTIMPL;
576 static HRESULT WINAPI ProtocolStream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
578 ProtocolStream *This = STREAM_THIS(iface);
579 FIXME("(%p)->(%d)\n", This, libNewSize.u.LowPart);
580 return E_NOTIMPL;
583 static HRESULT WINAPI ProtocolStream_CopyTo(IStream *iface, IStream *pstm,
584 ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
586 ProtocolStream *This = STREAM_THIS(iface);
587 FIXME("(%p)->(%p %d %p %p)\n", This, pstm, cb.u.LowPart, pcbRead, pcbWritten);
588 return E_NOTIMPL;
591 static HRESULT WINAPI ProtocolStream_Commit(IStream *iface, DWORD grfCommitFlags)
593 ProtocolStream *This = STREAM_THIS(iface);
595 TRACE("(%p)->(%08x)\n", This, grfCommitFlags);
597 return E_NOTIMPL;
600 static HRESULT WINAPI ProtocolStream_Revert(IStream *iface)
602 ProtocolStream *This = STREAM_THIS(iface);
604 TRACE("(%p)\n", This);
606 return E_NOTIMPL;
609 static HRESULT WINAPI ProtocolStream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
610 ULARGE_INTEGER cb, DWORD dwLockType)
612 ProtocolStream *This = STREAM_THIS(iface);
613 FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
614 return E_NOTIMPL;
617 static HRESULT WINAPI ProtocolStream_UnlockRegion(IStream *iface,
618 ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
620 ProtocolStream *This = STREAM_THIS(iface);
621 FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType);
622 return E_NOTIMPL;
625 static HRESULT WINAPI ProtocolStream_Stat(IStream *iface, STATSTG *pstatstg,
626 DWORD dwStatFlag)
628 ProtocolStream *This = STREAM_THIS(iface);
629 FIXME("(%p)->(%p %08x)\n", This, pstatstg, dwStatFlag);
630 return E_NOTIMPL;
633 static HRESULT WINAPI ProtocolStream_Clone(IStream *iface, IStream **ppstm)
635 ProtocolStream *This = STREAM_THIS(iface);
636 FIXME("(%p)->(%p)\n", This, ppstm);
637 return E_NOTIMPL;
640 #undef STREAM_THIS
642 static const IStreamVtbl ProtocolStreamVtbl = {
643 ProtocolStream_QueryInterface,
644 ProtocolStream_AddRef,
645 ProtocolStream_Release,
646 ProtocolStream_Read,
647 ProtocolStream_Write,
648 ProtocolStream_Seek,
649 ProtocolStream_SetSize,
650 ProtocolStream_CopyTo,
651 ProtocolStream_Commit,
652 ProtocolStream_Revert,
653 ProtocolStream_LockRegion,
654 ProtocolStream_UnlockRegion,
655 ProtocolStream_Stat,
656 ProtocolStream_Clone
659 #define BINDING_THIS(iface) DEFINE_THIS(Binding, Binding, iface)
661 static ProtocolStream *create_stream(IInternetProtocol *protocol)
663 ProtocolStream *ret = heap_alloc(sizeof(ProtocolStream));
665 ret->lpStreamVtbl = &ProtocolStreamVtbl;
666 ret->ref = 1;
667 ret->buf_size = 0;
668 ret->init_buf = FALSE;
669 ret->hres = S_OK;
671 IInternetProtocol_AddRef(protocol);
672 ret->protocol = protocol;
674 URLMON_LockModule();
676 return ret;
679 static HRESULT WINAPI Binding_QueryInterface(IBinding *iface, REFIID riid, void **ppv)
681 Binding *This = BINDING_THIS(iface);
683 *ppv = NULL;
685 if(IsEqualGUID(&IID_IUnknown, riid)) {
686 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
687 *ppv = BINDING(This);
688 }else if(IsEqualGUID(&IID_IBinding, riid)) {
689 TRACE("(%p)->(IID_IBinding %p)\n", This, ppv);
690 *ppv = BINDING(This);
691 }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
692 TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
693 *ppv = PROTSINK(This);
694 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
695 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
696 *ppv = BINDINF(This);
697 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
698 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
699 *ppv = SERVPROV(This);
702 if(*ppv) {
703 IBinding_AddRef(BINDING(This));
704 return S_OK;
707 WARN("Unsupported interface %s\n", debugstr_guid(riid));
708 return E_NOINTERFACE;
711 static ULONG WINAPI Binding_AddRef(IBinding *iface)
713 Binding *This = BINDING_THIS(iface);
714 LONG ref = InterlockedIncrement(&This->ref);
716 TRACE("(%p) ref=%d\n", This, ref);
718 return ref;
721 static ULONG WINAPI Binding_Release(IBinding *iface)
723 Binding *This = BINDING_THIS(iface);
724 LONG ref = InterlockedDecrement(&This->ref);
726 TRACE("(%p) ref=%d\n", This, ref);
728 if(!ref) {
729 if (This->notif_hwnd)
730 DestroyWindow( This->notif_hwnd );
731 if(This->mon)
732 IMoniker_Release(This->mon);
733 if(This->callback)
734 IBindStatusCallback_Release(This->callback);
735 if(This->protocol)
736 IInternetProtocol_Release(This->protocol);
737 if(This->service_provider)
738 IServiceProvider_Release(This->service_provider);
739 if(This->stream)
740 IStream_Release(STREAM(This->stream));
741 if(This->obj)
742 IUnknown_Release(This->obj);
743 if(This->bctx)
744 IBindCtx_Release(This->bctx);
746 ReleaseBindInfo(&This->bindinfo);
747 This->section.DebugInfo->Spare[0] = 0;
748 DeleteCriticalSection(&This->section);
749 heap_free(This->mime);
750 heap_free(This->url);
752 heap_free(This);
754 URLMON_UnlockModule();
757 return ref;
760 static HRESULT WINAPI Binding_Abort(IBinding *iface)
762 Binding *This = BINDING_THIS(iface);
763 FIXME("(%p)\n", This);
764 return E_NOTIMPL;
767 static HRESULT WINAPI Binding_Suspend(IBinding *iface)
769 Binding *This = BINDING_THIS(iface);
770 FIXME("(%p)\n", This);
771 return E_NOTIMPL;
774 static HRESULT WINAPI Binding_Resume(IBinding *iface)
776 Binding *This = BINDING_THIS(iface);
777 FIXME("(%p)\n", This);
778 return E_NOTIMPL;
781 static HRESULT WINAPI Binding_SetPriority(IBinding *iface, LONG nPriority)
783 Binding *This = BINDING_THIS(iface);
784 FIXME("(%p)->(%d)\n", This, nPriority);
785 return E_NOTIMPL;
788 static HRESULT WINAPI Binding_GetPriority(IBinding *iface, LONG *pnPriority)
790 Binding *This = BINDING_THIS(iface);
791 FIXME("(%p)->(%p)\n", This, pnPriority);
792 return E_NOTIMPL;
795 static HRESULT WINAPI Binding_GetBindResult(IBinding *iface, CLSID *pclsidProtocol,
796 DWORD *pdwResult, LPOLESTR *pszResult, DWORD *pdwReserved)
798 Binding *This = BINDING_THIS(iface);
799 FIXME("(%p)->(%p %p %p %p)\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);
800 return E_NOTIMPL;
803 static Binding *get_bctx_binding(IBindCtx *bctx)
805 IBinding *binding;
806 IUnknown *unk;
807 HRESULT hres;
809 hres = IBindCtx_GetObjectParam(bctx, cbinding_contextW, &unk);
810 if(FAILED(hres))
811 return NULL;
813 hres = IUnknown_QueryInterface(unk, &IID_IBinding, (void*)&binding);
814 IUnknown_Release(unk);
815 if(FAILED(hres))
816 return NULL;
818 /* FIXME!!! */
819 return BINDING_THIS(binding);
822 #undef BINDING_THIS
824 static const IBindingVtbl BindingVtbl = {
825 Binding_QueryInterface,
826 Binding_AddRef,
827 Binding_Release,
828 Binding_Abort,
829 Binding_Suspend,
830 Binding_Resume,
831 Binding_SetPriority,
832 Binding_GetPriority,
833 Binding_GetBindResult
836 #define PROTSINK_THIS(iface) DEFINE_THIS(Binding, InternetProtocolSink, iface)
838 static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
839 REFIID riid, void **ppv)
841 Binding *This = PROTSINK_THIS(iface);
842 return IBinding_QueryInterface(BINDING(This), riid, ppv);
845 static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface)
847 Binding *This = PROTSINK_THIS(iface);
848 return IBinding_AddRef(BINDING(This));
851 static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface)
853 Binding *This = PROTSINK_THIS(iface);
854 return IBinding_Release(BINDING(This));
857 typedef struct {
858 task_header_t header;
859 PROTOCOLDATA data;
860 } switch_task_t;
862 static void switch_proc(Binding *binding, task_header_t *t)
864 switch_task_t *task = (switch_task_t*)t;
866 IInternetProtocol_Continue(binding->protocol, &task->data);
868 heap_free(task);
871 static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface,
872 PROTOCOLDATA *pProtocolData)
874 Binding *This = PROTSINK_THIS(iface);
875 switch_task_t *task;
877 TRACE("(%p)->(%p)\n", This, pProtocolData);
879 task = heap_alloc(sizeof(switch_task_t));
880 memcpy(&task->data, pProtocolData, sizeof(PROTOCOLDATA));
882 push_task(This, &task->header, switch_proc);
884 IBinding_AddRef(BINDING(This));
885 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
887 return S_OK;
890 typedef struct {
891 task_header_t header;
893 Binding *binding;
894 ULONG progress;
895 ULONG progress_max;
896 ULONG status_code;
897 LPWSTR status_text;
898 } on_progress_task_t;
900 static void on_progress_proc(Binding *binding, task_header_t *t)
902 on_progress_task_t *task = (on_progress_task_t*)t;
904 IBindStatusCallback_OnProgress(binding->callback, task->progress,
905 task->progress_max, task->status_code, task->status_text);
907 heap_free(task->status_text);
908 heap_free(task);
911 static void on_progress(Binding *This, ULONG progress, ULONG progress_max,
912 ULONG status_code, LPCWSTR status_text)
914 on_progress_task_t *task;
916 if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) {
917 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
918 status_code, status_text);
919 return;
922 task = heap_alloc(sizeof(on_progress_task_t));
924 task->progress = progress;
925 task->progress_max = progress_max;
926 task->status_code = status_code;
928 if(status_text) {
929 DWORD size = (strlenW(status_text)+1)*sizeof(WCHAR);
931 task->status_text = heap_alloc(size);
932 memcpy(task->status_text, status_text, size);
933 }else {
934 task->status_text = NULL;
937 push_task(This, &task->header, on_progress_proc);
939 if(GetCurrentThreadId() != This->apartment_thread) {
940 IBinding_AddRef(BINDING(This));
941 PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
945 static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
946 ULONG ulStatusCode, LPCWSTR szStatusText)
948 Binding *This = PROTSINK_THIS(iface);
950 TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
952 switch(ulStatusCode) {
953 case BINDSTATUS_FINDINGRESOURCE:
954 on_progress(This, 0, 0, BINDSTATUS_FINDINGRESOURCE, szStatusText);
955 break;
956 case BINDSTATUS_CONNECTING:
957 on_progress(This, 0, 0, BINDSTATUS_CONNECTING, szStatusText);
958 break;
959 case BINDSTATUS_BEGINDOWNLOADDATA:
960 fill_stream_buffer(This->stream);
961 break;
962 case BINDSTATUS_MIMETYPEAVAILABLE:
963 set_binding_mime(This, szStatusText);
964 break;
965 case BINDSTATUS_SENDINGREQUEST:
966 on_progress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, szStatusText);
967 break;
968 case BINDSTATUS_PROTOCOLCLASSID:
969 break;
970 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
971 mime_available(This, szStatusText, FALSE);
972 break;
973 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
974 break;
975 case BINDSTATUS_DIRECTBIND:
976 This->report_mime = FALSE;
977 break;
978 default:
979 FIXME("Unhandled status code %d\n", ulStatusCode);
980 return E_NOTIMPL;
983 return S_OK;
986 static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progress_max)
988 FORMATETC formatetc = {0, NULL, 1, -1, TYMED_ISTREAM};
989 BOOL sent_begindownloaddata = FALSE;
991 TRACE("(%p)->(%d %u %u)\n", This, bscf, progress, progress_max);
993 if(This->download_state == END_DOWNLOAD)
994 return;
996 if(GetCurrentThreadId() != This->apartment_thread)
997 FIXME("called from worker thread\n");
999 if(This->report_mime)
1000 mime_available(This, NULL, TRUE);
1002 if(This->download_state == BEFORE_DOWNLOAD) {
1003 fill_stream_buffer(This->stream);
1005 This->download_state = DOWNLOADING;
1006 sent_begindownloaddata = TRUE;
1007 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
1008 BINDSTATUS_BEGINDOWNLOADDATA, This->url);
1011 if(This->stream->hres == S_FALSE || (bscf & BSCF_LASTDATANOTIFICATION)) {
1012 This->download_state = END_DOWNLOAD;
1013 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
1014 BINDSTATUS_ENDDOWNLOADDATA, This->url);
1015 }else if(!sent_begindownloaddata) {
1016 IBindStatusCallback_OnProgress(This->callback, progress, progress_max,
1017 BINDSTATUS_DOWNLOADINGDATA, This->url);
1020 if(This->to_object) {
1021 if(!(This->state & BINDING_OBJAVAIL))
1022 create_object(This);
1023 }else {
1024 if(!(This->state & BINDING_LOCKED)) {
1025 HRESULT hres = IInternetProtocol_LockRequest(This->protocol, 0);
1026 if(SUCCEEDED(hres))
1027 This->state |= BINDING_LOCKED;
1030 formatetc.cfFormat = This->clipboard_format;
1031 IBindStatusCallback_OnDataAvailable(This->callback, bscf, progress,
1032 &formatetc, &This->stgmed);
1034 if(This->download_state == END_DOWNLOAD)
1035 stop_binding(This, S_OK, NULL);
1039 typedef struct {
1040 task_header_t header;
1041 DWORD bscf;
1042 ULONG progress;
1043 ULONG progress_max;
1044 } report_data_task_t;
1046 static void report_data_proc(Binding *binding, task_header_t *t)
1048 report_data_task_t *task = (report_data_task_t*)t;
1050 report_data(binding, task->bscf, task->progress, task->progress_max);
1052 heap_free(task);
1055 static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1056 DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1058 Binding *This = PROTSINK_THIS(iface);
1060 TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1062 if(GetCurrentThreadId() != This->apartment_thread)
1063 FIXME("called from worked hread\n");
1065 if(This->continue_call) {
1066 report_data_task_t *task = heap_alloc(sizeof(report_data_task_t));
1067 task->bscf = grfBSCF;
1068 task->progress = ulProgress;
1069 task->progress_max = ulProgressMax;
1071 push_task(This, &task->header, report_data_proc);
1072 }else {
1073 report_data(This, grfBSCF, ulProgress, ulProgressMax);
1076 return S_OK;
1079 typedef struct {
1080 task_header_t header;
1082 HRESULT hres;
1083 LPWSTR str;
1084 } report_result_task_t;
1086 static void report_result_proc(Binding *binding, task_header_t *t)
1088 report_result_task_t *task = (report_result_task_t*)t;
1090 IInternetProtocol_Terminate(binding->protocol, 0);
1092 stop_binding(binding, task->hres, task->str);
1094 heap_free(task->str);
1095 heap_free(task);
1098 static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1099 HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1101 Binding *This = PROTSINK_THIS(iface);
1103 TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1105 if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) {
1106 IInternetProtocol_Terminate(This->protocol, 0);
1107 stop_binding(This, hrResult, szResult);
1108 }else {
1109 report_result_task_t *task = heap_alloc(sizeof(report_result_task_t));
1111 task->hres = hrResult;
1112 task->str = heap_strdupW(szResult);
1114 push_task(This, &task->header, report_result_proc);
1117 return S_OK;
1120 #undef PROTSINK_THIS
1122 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1123 InternetProtocolSink_QueryInterface,
1124 InternetProtocolSink_AddRef,
1125 InternetProtocolSink_Release,
1126 InternetProtocolSink_Switch,
1127 InternetProtocolSink_ReportProgress,
1128 InternetProtocolSink_ReportData,
1129 InternetProtocolSink_ReportResult
1132 #define BINDINF_THIS(iface) DEFINE_THIS(Binding, InternetBindInfo, iface)
1134 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
1135 REFIID riid, void **ppv)
1137 Binding *This = BINDINF_THIS(iface);
1138 return IBinding_QueryInterface(BINDING(This), riid, ppv);
1141 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
1143 Binding *This = BINDINF_THIS(iface);
1144 return IBinding_AddRef(BINDING(This));
1147 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
1149 Binding *This = BINDINF_THIS(iface);
1150 return IBinding_Release(BINDING(This));
1153 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
1154 DWORD *grfBINDF, BINDINFO *pbindinfo)
1156 Binding *This = BINDINF_THIS(iface);
1158 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
1160 *grfBINDF = This->bindf;
1162 memcpy(pbindinfo, &This->bindinfo, sizeof(BINDINFO));
1164 if(pbindinfo->szExtraInfo || pbindinfo->szCustomVerb)
1165 FIXME("copy strings\n");
1167 if(pbindinfo->stgmedData.pUnkForRelease)
1168 IUnknown_AddRef(pbindinfo->stgmedData.pUnkForRelease);
1170 if(pbindinfo->pUnk)
1171 IUnknown_AddRef(pbindinfo->pUnk);
1173 return S_OK;
1176 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
1177 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
1179 Binding *This = BINDINF_THIS(iface);
1181 TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
1183 switch(ulStringType) {
1184 case BINDSTRING_ACCEPT_MIMES: {
1185 static const WCHAR wszMimes[] = {'*','/','*',0};
1187 if(!ppwzStr || !pcElFetched)
1188 return E_INVALIDARG;
1190 ppwzStr[0] = CoTaskMemAlloc(sizeof(wszMimes));
1191 memcpy(ppwzStr[0], wszMimes, sizeof(wszMimes));
1192 *pcElFetched = 1;
1193 return S_OK;
1195 case BINDSTRING_USER_AGENT: {
1196 IInternetBindInfo *bindinfo = NULL;
1197 HRESULT hres;
1199 hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo,
1200 (void**)&bindinfo);
1201 if(FAILED(hres))
1202 return hres;
1204 hres = IInternetBindInfo_GetBindString(bindinfo, ulStringType, ppwzStr,
1205 cEl, pcElFetched);
1206 IInternetBindInfo_Release(bindinfo);
1208 return hres;
1212 FIXME("not supported string type %d\n", ulStringType);
1213 return E_NOTIMPL;
1216 #undef BINDF_THIS
1218 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
1219 InternetBindInfo_QueryInterface,
1220 InternetBindInfo_AddRef,
1221 InternetBindInfo_Release,
1222 InternetBindInfo_GetBindInfo,
1223 InternetBindInfo_GetBindString
1226 #define SERVPROV_THIS(iface) DEFINE_THIS(Binding, ServiceProvider, iface)
1228 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface,
1229 REFIID riid, void **ppv)
1231 Binding *This = SERVPROV_THIS(iface);
1232 return IBinding_QueryInterface(BINDING(This), riid, ppv);
1235 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
1237 Binding *This = SERVPROV_THIS(iface);
1238 return IBinding_AddRef(BINDING(This));
1241 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
1243 Binding *This = SERVPROV_THIS(iface);
1244 return IBinding_Release(BINDING(This));
1247 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
1248 REFGUID guidService, REFIID riid, void **ppv)
1250 Binding *This = SERVPROV_THIS(iface);
1251 HRESULT hres;
1253 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1255 if(This->service_provider) {
1256 hres = IServiceProvider_QueryService(This->service_provider, guidService,
1257 riid, ppv);
1258 if(SUCCEEDED(hres))
1259 return hres;
1262 WARN("unknown service %s\n", debugstr_guid(guidService));
1263 return E_NOTIMPL;
1266 #undef SERVPROV_THIS
1268 static const IServiceProviderVtbl ServiceProviderVtbl = {
1269 ServiceProvider_QueryInterface,
1270 ServiceProvider_AddRef,
1271 ServiceProvider_Release,
1272 ServiceProvider_QueryService
1275 static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback)
1277 IUnknown *unk;
1278 HRESULT hres;
1280 hres = IBindCtx_GetObjectParam(pbc, bscb_holderW, &unk);
1281 if(SUCCEEDED(hres)) {
1282 hres = IUnknown_QueryInterface(unk, &IID_IBindStatusCallback, (void**)callback);
1283 IUnknown_Release(unk);
1286 return SUCCEEDED(hres) ? S_OK : MK_E_SYNTAX;
1289 static BOOL is_urlmon_protocol(LPCWSTR url)
1291 static const WCHAR wszCdl[] = {'c','d','l'};
1292 static const WCHAR wszFile[] = {'f','i','l','e'};
1293 static const WCHAR wszFtp[] = {'f','t','p'};
1294 static const WCHAR wszGopher[] = {'g','o','p','h','e','r'};
1295 static const WCHAR wszHttp[] = {'h','t','t','p'};
1296 static const WCHAR wszHttps[] = {'h','t','t','p','s'};
1297 static const WCHAR wszMk[] = {'m','k'};
1299 static const struct {
1300 LPCWSTR scheme;
1301 int len;
1302 } protocol_list[] = {
1303 {wszCdl, sizeof(wszCdl) /sizeof(WCHAR)},
1304 {wszFile, sizeof(wszFile) /sizeof(WCHAR)},
1305 {wszFtp, sizeof(wszFtp) /sizeof(WCHAR)},
1306 {wszGopher, sizeof(wszGopher)/sizeof(WCHAR)},
1307 {wszHttp, sizeof(wszHttp) /sizeof(WCHAR)},
1308 {wszHttps, sizeof(wszHttps) /sizeof(WCHAR)},
1309 {wszMk, sizeof(wszMk) /sizeof(WCHAR)}
1312 int i, len = strlenW(url);
1314 for(i=0; i < sizeof(protocol_list)/sizeof(protocol_list[0]); i++) {
1315 if(len >= protocol_list[i].len
1316 && !memcmp(url, protocol_list[i].scheme, protocol_list[i].len*sizeof(WCHAR)))
1317 return TRUE;
1320 return FALSE;
1323 static HRESULT Binding_Create(IMoniker *mon, Binding *binding_ctx, LPCWSTR url, IBindCtx *pbc,
1324 BOOL to_obj, REFIID riid, Binding **binding)
1326 Binding *ret;
1327 HRESULT hres;
1329 if(!to_obj && !IsEqualGUID(&IID_IStream, riid)) {
1330 FIXME("Unsupported riid %s\n", debugstr_guid(riid));
1331 return E_NOTIMPL;
1334 URLMON_LockModule();
1336 ret = heap_alloc_zero(sizeof(Binding));
1338 ret->lpBindingVtbl = &BindingVtbl;
1339 ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
1340 ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
1341 ret->lpServiceProviderVtbl = &ServiceProviderVtbl;
1343 ret->ref = 1;
1345 ret->to_object = to_obj;
1346 ret->iid = *riid;
1347 ret->apartment_thread = GetCurrentThreadId();
1348 ret->notif_hwnd = get_notif_hwnd();
1349 ret->report_mime = !binding_ctx;
1350 ret->download_state = BEFORE_DOWNLOAD;
1352 if(to_obj) {
1353 IBindCtx_AddRef(pbc);
1354 ret->bctx = pbc;
1357 if(mon) {
1358 IMoniker_AddRef(mon);
1359 ret->mon = mon;
1362 ret->bindinfo.cbSize = sizeof(BINDINFO);
1364 InitializeCriticalSection(&ret->section);
1365 ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": Binding.section");
1367 hres = get_callback(pbc, &ret->callback);
1368 if(FAILED(hres)) {
1369 WARN("Could not get IBindStatusCallback\n");
1370 IBinding_Release(BINDING(ret));
1371 return hres;
1374 IBindStatusCallback_QueryInterface(ret->callback, &IID_IServiceProvider,
1375 (void**)&ret->service_provider);
1377 if(binding_ctx) {
1378 ret->protocol = binding_ctx->protocol;
1379 IInternetProtocol_AddRef(ret->protocol);
1380 }else {
1381 hres = create_binding_protocol(url, TRUE, &ret->protocol);
1382 if(FAILED(hres)) {
1383 WARN("Could not get protocol handler\n");
1384 IBinding_Release(BINDING(ret));
1385 return hres;
1389 hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo);
1390 if(FAILED(hres)) {
1391 WARN("GetBindInfo failed: %08x\n", hres);
1392 IBinding_Release(BINDING(ret));
1393 return hres;
1396 TRACE("bindf %08x\n", ret->bindf);
1397 dump_BINDINFO(&ret->bindinfo);
1399 ret->bindf |= BINDF_FROMURLMON;
1400 if(to_obj)
1401 ret->bindinfo.dwOptions |= 0x100000;
1403 if(!is_urlmon_protocol(url))
1404 ret->bindf |= BINDF_NEEDFILE;
1406 ret->url = heap_strdupW(url);
1408 if(binding_ctx) {
1409 ret->stream = binding_ctx->stream;
1410 IStream_AddRef(STREAM(ret->stream));
1411 ret->clipboard_format = binding_ctx->clipboard_format;
1412 }else {
1413 ret->stream = create_stream(ret->protocol);
1415 ret->stgmed.tymed = TYMED_ISTREAM;
1416 ret->stgmed.u.pstm = STREAM(ret->stream);
1417 ret->stgmed.pUnkForRelease = (IUnknown*)BINDING(ret); /* NOTE: Windows uses other IUnknown */
1419 *binding = ret;
1420 return S_OK;
1423 static HRESULT start_binding(IMoniker *mon, Binding *binding_ctx, LPCWSTR url, IBindCtx *pbc,
1424 BOOL to_obj, REFIID riid, Binding **ret)
1426 Binding *binding = NULL;
1427 HRESULT hres;
1428 MSG msg;
1430 hres = Binding_Create(mon, binding_ctx, url, pbc, to_obj, riid, &binding);
1431 if(FAILED(hres))
1432 return hres;
1434 hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, BINDING(binding));
1435 if(FAILED(hres)) {
1436 WARN("OnStartBinding failed: %08x\n", hres);
1437 stop_binding(binding, 0x800c0008, NULL);
1438 IBinding_Release(BINDING(binding));
1439 return hres;
1442 if(binding_ctx) {
1443 set_binding_sink(binding->protocol, PROTSINK(binding));
1444 report_data(binding, 0, 0, 0);
1445 }else {
1446 hres = IInternetProtocol_Start(binding->protocol, url, PROTSINK(binding),
1447 BINDINF(binding), 0, 0);
1449 TRACE("start ret %08x\n", hres);
1451 if(FAILED(hres)) {
1452 stop_binding(binding, hres, NULL);
1453 IBinding_Release(BINDING(binding));
1455 return hres;
1459 while(!(binding->bindf & BINDF_ASYNCHRONOUS) &&
1460 !(binding->state & BINDING_STOPPED)) {
1461 MsgWaitForMultipleObjects(0, NULL, FALSE, 5000, QS_POSTMESSAGE);
1462 while (PeekMessageW(&msg, binding->notif_hwnd, WM_USER, WM_USER+117, PM_REMOVE|PM_NOYIELD)) {
1463 TranslateMessage(&msg);
1464 DispatchMessageW(&msg);
1468 *ret = binding;
1469 return S_OK;
1472 HRESULT bind_to_storage(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
1474 Binding *binding = NULL, *binding_ctx;
1475 HRESULT hres;
1477 *ppv = NULL;
1479 binding_ctx = get_bctx_binding(pbc);
1481 hres = start_binding(NULL, binding_ctx, url, pbc, FALSE, riid, &binding);
1482 if(binding_ctx)
1483 IBinding_Release(BINDING(binding_ctx));
1484 if(FAILED(hres))
1485 return hres;
1487 if(binding->hres != S_OK) {
1488 hres = SUCCEEDED(binding->hres) ? S_OK : binding->hres;
1489 }else if(binding->stream->init_buf) {
1490 if((binding->state & BINDING_STOPPED) && (binding->state & BINDING_LOCKED))
1491 IInternetProtocol_UnlockRequest(binding->protocol);
1493 IStream_AddRef(STREAM(binding->stream));
1494 *ppv = binding->stream;
1496 hres = S_OK;
1497 }else {
1498 hres = MK_S_ASYNCHRONOUS;
1501 IBinding_Release(BINDING(binding));
1503 return hres;
1506 HRESULT bind_to_object(IMoniker *mon, LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
1508 Binding *binding;
1509 HRESULT hres;
1511 *ppv = NULL;
1513 hres = start_binding(mon, NULL, url, pbc, TRUE, riid, &binding);
1514 if(FAILED(hres))
1515 return hres;
1517 if(binding->hres != S_OK) {
1518 hres = SUCCEEDED(binding->hres) ? S_OK : binding->hres;
1519 }else if(binding->bindf & BINDF_ASYNCHRONOUS) {
1520 hres = MK_S_ASYNCHRONOUS;
1521 }else {
1522 *ppv = binding->obj;
1523 IUnknown_AddRef(binding->obj);
1524 hres = S_OK;
1527 IBinding_Release(BINDING(binding));
1529 return hres;