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"
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
{
37 struct _task_header_t
*next
;
41 const IUnknownVtbl
*lpUnknownVtbl
;
45 IInternetProtocol
*protocol
;
55 typedef struct _stgmed_obj_t stgmed_obj_t
;
58 void (*release
)(stgmed_obj_t
*);
59 HRESULT (*fill_stgmed
)(stgmed_obj_t
*,STGMEDIUM
*);
60 void *(*get_result
)(stgmed_obj_t
*);
63 struct _stgmed_obj_t
{
64 const stgmed_obj_vtbl
*vtbl
;
67 #define STGMEDUNK(x) ((IUnknown*) &(x)->lpUnknownVtbl)
75 #define BINDING_LOCKED 0x0001
76 #define BINDING_STOPPED 0x0002
77 #define BINDING_OBJAVAIL 0x0004
80 const IBindingVtbl
*lpBindingVtbl
;
81 const IInternetProtocolSinkVtbl
*lpInternetProtocolSinkVtbl
;
82 const IInternetBindInfoVtbl
*lpInternetBindInfoVtbl
;
83 const IWinInetHttpInfoVtbl
*lpWinInetHttpInfoVtbl
;
84 const IServiceProviderVtbl
*lpServiceProviderVtbl
;
88 IBindStatusCallback
*callback
;
89 IInternetProtocol
*protocol
;
90 IServiceProvider
*service_provider
;
92 stgmed_buf_t
*stgmed_buf
;
93 stgmed_obj_t
*stgmed_obj
;
99 UINT clipboard_format
;
106 download_state_t download_state
;
111 DWORD apartment_thread
;
114 task_header_t
*task_queue_head
, *task_queue_tail
;
115 CRITICAL_SECTION section
;
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)
124 #define STREAM(x) ((IStream*) &(x)->lpStreamVtbl)
125 #define HTTPNEG2(x) ((IHttpNegotiate2*) &(x)->lpHttpNegotiate2Vtbl)
127 #define WM_MK_CONTINUE (WM_USER+101)
129 static void push_task(Binding
*binding
, task_header_t
*task
, task_proc_t proc
)
134 EnterCriticalSection(&binding
->section
);
136 if(binding
->task_queue_tail
) {
137 binding
->task_queue_tail
->next
= task
;
138 binding
->task_queue_tail
= task
;
140 binding
->task_queue_tail
= binding
->task_queue_head
= task
;
143 LeaveCriticalSection(&binding
->section
);
146 static task_header_t
*pop_task(Binding
*binding
)
150 EnterCriticalSection(&binding
->section
);
152 ret
= binding
->task_queue_head
;
154 binding
->task_queue_head
= ret
->next
;
155 if(!binding
->task_queue_head
)
156 binding
->task_queue_tail
= NULL
;
159 LeaveCriticalSection(&binding
->section
);
164 static void fill_stgmed_buffer(stgmed_buf_t
*buf
)
168 if(sizeof(buf
->buf
) == buf
->size
)
171 buf
->hres
= IInternetProtocol_Read(buf
->protocol
, buf
->buf
+buf
->size
,
172 sizeof(buf
->buf
)-buf
->size
, &read
);
178 static LRESULT WINAPI
notif_wnd_proc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
180 if(msg
== WM_MK_CONTINUE
) {
181 Binding
*binding
= (Binding
*)lParam
;
184 while((task
= pop_task(binding
))) {
185 binding
->continue_call
++;
186 task
->proc(binding
, task
);
187 binding
->continue_call
--;
190 IBinding_Release(BINDING(binding
));
194 return DefWindowProcW(hwnd
, msg
, wParam
, lParam
);
197 static HWND
get_notif_hwnd(void)
199 static ATOM wnd_class
= 0;
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};
207 static WNDCLASSEXW wndclass
= {
209 notif_wnd_proc
, 0, 0,
210 NULL
, NULL
, NULL
, NULL
, NULL
,
211 wszURLMonikerNotificationWindow
,
215 wndclass
.hInstance
= URLMON_hInstance
;
217 wnd_class
= RegisterClassExW(&wndclass
);
218 if (!wnd_class
&& GetLastError() == ERROR_CLASS_ALREADY_EXISTS
)
222 hwnd
= CreateWindowExW(0, wszURLMonikerNotificationWindow
,
223 wszURLMonikerNotificationWindow
, 0, 0, 0, 0, 0, HWND_MESSAGE
,
224 NULL
, URLMON_hInstance
, NULL
);
226 TRACE("hwnd = %p\n", hwnd
);
231 static void dump_BINDINFO(BINDINFO
*bi
)
233 static const char * const BINDINFOF_str
[] = {
235 "BINDINFOF_URLENCODESTGMEDDATA",
236 "BINDINFOF_URLENCODEDEXTRAINFO"
239 static const char * const BINDVERB_str
[] = {
253 " %d, %08x, %d, %d\n"
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
275 static void set_binding_mime(Binding
*binding
, LPCWSTR mime
)
277 EnterCriticalSection(&binding
->section
);
279 if(binding
->report_mime
) {
280 heap_free(binding
->mime
);
281 binding
->mime
= heap_strdupW(mime
);
284 LeaveCriticalSection(&binding
->section
);
287 static void handle_mime_available(Binding
*binding
, BOOL verify
)
291 EnterCriticalSection(&binding
->section
);
292 report_mime
= binding
->report_mime
;
293 binding
->report_mime
= FALSE
;
294 LeaveCriticalSection(&binding
->section
);
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);
306 heap_free(binding
->mime
);
307 binding
->mime
= heap_strdupW(mime
);
311 IBindStatusCallback_OnProgress(binding
->callback
, 0, 0, BINDSTATUS_MIMETYPEAVAILABLE
, binding
->mime
);
313 binding
->clipboard_format
= RegisterClipboardFormatW(binding
->mime
);
317 task_header_t header
;
319 } mime_available_task_t
;
321 static void mime_available_proc(Binding
*binding
, task_header_t
*t
)
323 mime_available_task_t
*task
= (mime_available_task_t
*)t
;
325 handle_mime_available(binding
, task
->verify
);
330 static void mime_available(Binding
*This
, LPCWSTR mime
, BOOL verify
)
333 set_binding_mime(This
, mime
);
335 if(GetCurrentThreadId() == This
->apartment_thread
) {
336 handle_mime_available(This
, verify
);
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
);
344 static void stop_binding(Binding
*binding
, HRESULT hres
, LPCWSTR str
)
346 if(binding
->state
& BINDING_LOCKED
) {
347 IInternetProtocol_UnlockRequest(binding
->protocol
);
348 binding
->state
&= ~BINDING_LOCKED
;
351 if(!(binding
->state
& BINDING_STOPPED
)) {
352 binding
->state
|= BINDING_STOPPED
;
354 IBindStatusCallback_OnStopBinding(binding
->callback
, hres
, str
);
355 binding
->hres
= hres
;
359 static LPWSTR
get_mime_clsid(LPCWSTR mime
, CLSID
*clsid
)
361 LPWSTR key_name
, ret
;
362 DWORD res
, type
, size
;
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};
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
);
377 res
= RegOpenKeyW(HKEY_CLASSES_ROOT
, key_name
, &hkey
);
379 if(res
!= ERROR_SUCCESS
) {
380 WARN("Could not open MIME key: %x\n", res
);
384 size
= 50*sizeof(WCHAR
);
385 ret
= heap_alloc(size
);
386 res
= RegQueryValueExW(hkey
, clsidW
, NULL
, &type
, (LPBYTE
)ret
, &size
);
388 if(res
!= ERROR_SUCCESS
) {
389 WARN("Could not get CLSID: %08x\n", res
);
394 hres
= CLSIDFromString(ret
, clsid
);
396 WARN("Could not parse CLSID: %08x\n", hres
);
404 static void load_doc_mon(Binding
*binding
, IPersistMoniker
*persist
)
409 hres
= CreateAsyncBindCtxEx(binding
->bctx
, 0, NULL
, NULL
, &bctx
, 0);
411 WARN("CreateAsyncBindCtxEx failed: %08x\n", hres
);
415 IBindCtx_RevokeObjectParam(bctx
, bscb_holderW
);
416 IBindCtx_RegisterObjectParam(bctx
, cbinding_contextW
, (IUnknown
*)BINDING(binding
));
418 hres
= IPersistMoniker_Load(persist
, binding
->download_state
== END_DOWNLOAD
, binding
->mon
, bctx
, 0x12);
419 IBindCtx_RevokeObjectParam(bctx
, cbinding_contextW
);
420 IBindCtx_Release(bctx
);
422 FIXME("Load failed: %08x\n", hres
);
425 static HRESULT
create_mime_object(Binding
*binding
, const CLSID
*clsid
, LPCWSTR clsid_str
)
427 IPersistMoniker
*persist
;
430 hres
= CoCreateInstance(clsid
, NULL
, CLSCTX_INPROC_SERVER
|CLSCTX_INPROC_HANDLER
,
431 &binding
->iid
, (void**)&binding
->obj
);
433 WARN("CoCreateInstance failed: %08x\n", hres
);
434 return INET_E_CANNOT_INSTANTIATE_OBJECT
;
437 binding
->state
|= BINDING_OBJAVAIL
;
439 hres
= IUnknown_QueryInterface(binding
->obj
, &IID_IPersistMoniker
, (void**)&persist
);
440 if(SUCCEEDED(hres
)) {
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
);
450 load_doc_mon(binding
, persist
);
452 IPersistMoniker_Release(persist
);
454 FIXME("Could not get IPersistMoniker: %08x\n", hres
);
455 /* FIXME: Try query IPersistFile */
458 IBindStatusCallback_OnObjectAvailable(binding
->callback
, &binding
->iid
, binding
->obj
);
463 static void create_object(Binding
*binding
)
470 FIXME("MIME not available\n");
474 if(!(clsid_str
= get_mime_clsid(binding
->mime
, &clsid
))) {
475 FIXME("Could not find object for MIME %s\n", debugstr_w(binding
->mime
));
479 IBindStatusCallback_OnProgress(binding
->callback
, 0, 0, BINDSTATUS_CLASSIDAVAILABLE
, clsid_str
);
480 IBindStatusCallback_OnProgress(binding
->callback
, 0, 0, BINDSTATUS_BEGINSYNCOPERATION
, NULL
);
482 hres
= create_mime_object(binding
, &clsid
, clsid_str
);
483 heap_free(clsid_str
);
485 IBindStatusCallback_OnProgress(binding
->callback
, 0, 0, BINDSTATUS_ENDSYNCOPERATION
, NULL
);
487 stop_binding(binding
, hres
, NULL
);
489 IInternetProtocol_Terminate(binding
->protocol
, 0);
492 #define STGMEDUNK_THIS(iface) DEFINE_THIS(stgmed_buf_t, Unknown, iface)
494 static HRESULT WINAPI
StgMedUnk_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
496 stgmed_buf_t
*This
= STGMEDUNK_THIS(iface
);
500 if(IsEqualGUID(riid
, &IID_IUnknown
)) {
501 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
503 *ppv
= STGMEDUNK(This
);
504 IUnknown_AddRef(STGMEDUNK(This
));
508 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
509 return E_NOINTERFACE
;
512 static ULONG WINAPI
StgMedUnk_AddRef(IUnknown
*iface
)
514 stgmed_buf_t
*This
= STGMEDUNK_THIS(iface
);
515 LONG ref
= InterlockedIncrement(&This
->ref
);
517 TRACE("(%p) ref=%d\n", This
, ref
);
522 static ULONG WINAPI
StgMedUnk_Release(IUnknown
*iface
)
524 stgmed_buf_t
*This
= STGMEDUNK_THIS(iface
);
525 LONG ref
= InterlockedDecrement(&This
->ref
);
527 TRACE("(%p) ref=%d\n", This
, ref
);
530 IInternetProtocol_Release(This
->protocol
);
531 heap_free(This
->cache_file
);
534 URLMON_UnlockModule();
540 #undef STGMEDUNK_THIS
542 static const IUnknownVtbl StgMedUnkVtbl
= {
543 StgMedUnk_QueryInterface
,
548 static stgmed_buf_t
*create_stgmed_buf(IInternetProtocol
*protocol
)
550 stgmed_buf_t
*ret
= heap_alloc(sizeof(*ret
));
552 ret
->lpUnknownVtbl
= &StgMedUnkVtbl
;
557 ret
->cache_file
= NULL
;
559 IInternetProtocol_AddRef(protocol
);
560 ret
->protocol
= protocol
;
568 stgmed_obj_t stgmed_obj
;
569 const IStreamVtbl
*lpStreamVtbl
;
576 #define STREAM_THIS(iface) DEFINE_THIS(ProtocolStream, Stream, iface)
578 static HRESULT WINAPI
ProtocolStream_QueryInterface(IStream
*iface
,
579 REFIID riid
, void **ppv
)
581 ProtocolStream
*This
= STREAM_THIS(iface
);
585 if(IsEqualGUID(&IID_IUnknown
, riid
)) {
586 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppv
);
588 }else if(IsEqualGUID(&IID_ISequentialStream
, riid
)) {
589 TRACE("(%p)->(IID_ISequentialStream %p)\n", This
, ppv
);
591 }else if(IsEqualGUID(&IID_IStream
, riid
)) {
592 TRACE("(%p)->(IID_IStream %p)\n", This
, ppv
);
597 IStream_AddRef(STREAM(This
));
601 WARN("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
602 return E_NOINTERFACE
;
605 static ULONG WINAPI
ProtocolStream_AddRef(IStream
*iface
)
607 ProtocolStream
*This
= STREAM_THIS(iface
);
608 LONG ref
= InterlockedIncrement(&This
->ref
);
610 TRACE("(%p) ref=%d\n", This
, ref
);
615 static ULONG WINAPI
ProtocolStream_Release(IStream
*iface
)
617 ProtocolStream
*This
= STREAM_THIS(iface
);
618 LONG ref
= InterlockedDecrement(&This
->ref
);
620 TRACE("(%p) ref=%d\n", This
, ref
);
623 IUnknown_Release(STGMEDUNK(This
->buf
));
626 URLMON_UnlockModule();
632 static HRESULT WINAPI
ProtocolStream_Read(IStream
*iface
, void *pv
,
633 ULONG cb
, ULONG
*pcbRead
)
635 ProtocolStream
*This
= STREAM_THIS(iface
);
636 DWORD read
= 0, pread
= 0;
639 TRACE("(%p)->(%p %d %p)\n", This
, pv
, cb
, pcbRead
);
641 if(This
->buf
->size
) {
644 if(read
> This
->buf
->size
)
645 read
= This
->buf
->size
;
647 memcpy(pv
, This
->buf
->buf
, read
);
649 if(read
< This
->buf
->size
)
650 memmove(This
->buf
->buf
, This
->buf
->buf
+read
, This
->buf
->size
-read
);
651 This
->buf
->size
-= read
;
660 hres
= This
->buf
->hres
= IInternetProtocol_Read(This
->buf
->protocol
, (PBYTE
)pv
+read
, cb
-read
, &pread
);
662 *pcbRead
= read
+ pread
;
664 if(hres
== E_PENDING
)
666 else if(FAILED(hres
))
667 FIXME("Read failed: %08x\n", hres
);
669 return read
|| pread
? S_OK
: S_FALSE
;
672 static HRESULT WINAPI
ProtocolStream_Write(IStream
*iface
, const void *pv
,
673 ULONG cb
, ULONG
*pcbWritten
)
675 ProtocolStream
*This
= STREAM_THIS(iface
);
677 TRACE("(%p)->(%p %d %p)\n", This
, pv
, cb
, pcbWritten
);
679 return STG_E_ACCESSDENIED
;
682 static HRESULT WINAPI
ProtocolStream_Seek(IStream
*iface
, LARGE_INTEGER dlibMove
,
683 DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
)
685 ProtocolStream
*This
= STREAM_THIS(iface
);
686 FIXME("(%p)->(%d %08x %p)\n", This
, dlibMove
.u
.LowPart
, dwOrigin
, plibNewPosition
);
690 static HRESULT WINAPI
ProtocolStream_SetSize(IStream
*iface
, ULARGE_INTEGER libNewSize
)
692 ProtocolStream
*This
= STREAM_THIS(iface
);
693 FIXME("(%p)->(%d)\n", This
, libNewSize
.u
.LowPart
);
697 static HRESULT WINAPI
ProtocolStream_CopyTo(IStream
*iface
, IStream
*pstm
,
698 ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
)
700 ProtocolStream
*This
= STREAM_THIS(iface
);
701 FIXME("(%p)->(%p %d %p %p)\n", This
, pstm
, cb
.u
.LowPart
, pcbRead
, pcbWritten
);
705 static HRESULT WINAPI
ProtocolStream_Commit(IStream
*iface
, DWORD grfCommitFlags
)
707 ProtocolStream
*This
= STREAM_THIS(iface
);
709 TRACE("(%p)->(%08x)\n", This
, grfCommitFlags
);
714 static HRESULT WINAPI
ProtocolStream_Revert(IStream
*iface
)
716 ProtocolStream
*This
= STREAM_THIS(iface
);
718 TRACE("(%p)\n", This
);
723 static HRESULT WINAPI
ProtocolStream_LockRegion(IStream
*iface
, ULARGE_INTEGER libOffset
,
724 ULARGE_INTEGER cb
, DWORD dwLockType
)
726 ProtocolStream
*This
= STREAM_THIS(iface
);
727 FIXME("(%p)->(%d %d %d)\n", This
, libOffset
.u
.LowPart
, cb
.u
.LowPart
, dwLockType
);
731 static HRESULT WINAPI
ProtocolStream_UnlockRegion(IStream
*iface
,
732 ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
)
734 ProtocolStream
*This
= STREAM_THIS(iface
);
735 FIXME("(%p)->(%d %d %d)\n", This
, libOffset
.u
.LowPart
, cb
.u
.LowPart
, dwLockType
);
739 static HRESULT WINAPI
ProtocolStream_Stat(IStream
*iface
, STATSTG
*pstatstg
,
742 ProtocolStream
*This
= STREAM_THIS(iface
);
743 FIXME("(%p)->(%p %08x)\n", This
, pstatstg
, dwStatFlag
);
747 static HRESULT WINAPI
ProtocolStream_Clone(IStream
*iface
, IStream
**ppstm
)
749 ProtocolStream
*This
= STREAM_THIS(iface
);
750 FIXME("(%p)->(%p)\n", This
, ppstm
);
756 static const IStreamVtbl ProtocolStreamVtbl
= {
757 ProtocolStream_QueryInterface
,
758 ProtocolStream_AddRef
,
759 ProtocolStream_Release
,
761 ProtocolStream_Write
,
763 ProtocolStream_SetSize
,
764 ProtocolStream_CopyTo
,
765 ProtocolStream_Commit
,
766 ProtocolStream_Revert
,
767 ProtocolStream_LockRegion
,
768 ProtocolStream_UnlockRegion
,
773 static void stgmed_stream_release(stgmed_obj_t
*obj
)
775 ProtocolStream
*stream
= (ProtocolStream
*)obj
;
776 IStream_Release(STREAM(stream
));
779 static HRESULT
stgmed_stream_fill_stgmed(stgmed_obj_t
*obj
, STGMEDIUM
*stgmed
)
781 ProtocolStream
*stream
= (ProtocolStream
*)obj
;
783 stgmed
->tymed
= TYMED_ISTREAM
;
784 stgmed
->u
.pstm
= STREAM(stream
);
785 stgmed
->pUnkForRelease
= STGMEDUNK(stream
->buf
);
790 static void *stgmed_stream_get_result(stgmed_obj_t
*obj
)
792 ProtocolStream
*stream
= (ProtocolStream
*)obj
;
794 IStream_AddRef(STREAM(stream
));
795 return STREAM(stream
);
798 static const stgmed_obj_vtbl stgmed_stream_vtbl
= {
799 stgmed_stream_release
,
800 stgmed_stream_fill_stgmed
,
801 stgmed_stream_get_result
805 stgmed_obj_t stgmed_obj
;
809 static stgmed_obj_t
*create_stgmed_stream(stgmed_buf_t
*buf
)
811 ProtocolStream
*ret
= heap_alloc(sizeof(ProtocolStream
));
813 ret
->stgmed_obj
.vtbl
= &stgmed_stream_vtbl
;
814 ret
->lpStreamVtbl
= &ProtocolStreamVtbl
;
817 IUnknown_AddRef(STGMEDUNK(buf
));
822 return &ret
->stgmed_obj
;
825 static void stgmed_file_release(stgmed_obj_t
*obj
)
827 stgmed_file_obj_t
*file_obj
= (stgmed_file_obj_t
*)obj
;
829 IUnknown_Release(STGMEDUNK(file_obj
->buf
));
833 static HRESULT
stgmed_file_fill_stgmed(stgmed_obj_t
*obj
, STGMEDIUM
*stgmed
)
835 stgmed_file_obj_t
*file_obj
= (stgmed_file_obj_t
*)obj
;
837 if(!file_obj
->buf
->cache_file
) {
838 WARN("cache_file not set\n");
839 return INET_E_DATA_NOT_AVAILABLE
;
842 fill_stgmed_buffer(file_obj
->buf
);
843 if(file_obj
->buf
->size
== sizeof(file_obj
->buf
->buf
)) {
849 hres
= IInternetProtocol_Read(file_obj
->buf
->protocol
, buf
, sizeof(buf
), &read
);
850 }while(hres
== S_OK
);
853 stgmed
->tymed
= TYMED_FILE
;
854 stgmed
->u
.lpszFileName
= file_obj
->buf
->cache_file
;
855 stgmed
->pUnkForRelease
= STGMEDUNK(file_obj
->buf
);
860 static void *stgmed_file_get_result(stgmed_obj_t
*obj
)
865 static const stgmed_obj_vtbl stgmed_file_vtbl
= {
867 stgmed_file_fill_stgmed
,
868 stgmed_file_get_result
871 static stgmed_obj_t
*create_stgmed_file(stgmed_buf_t
*buf
)
873 stgmed_file_obj_t
*ret
= heap_alloc(sizeof(*ret
));
875 ret
->stgmed_obj
.vtbl
= &stgmed_file_vtbl
;
877 IUnknown_AddRef(STGMEDUNK(buf
));
880 return &ret
->stgmed_obj
;
883 #define BINDING_THIS(iface) DEFINE_THIS(Binding, Binding, iface)
885 static HRESULT WINAPI
Binding_QueryInterface(IBinding
*iface
, REFIID riid
, void **ppv
)
887 Binding
*This
= BINDING_THIS(iface
);
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
);
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
;
913 *ppv
= INETINFO(This
);
914 }else if(IsEqualGUID(&IID_IWinInetHttpInfo
, riid
)) {
915 IWinInetHttpInfo
*http_info
;
919 TRACE("(%p)->(IID_IWinInetHttpInfo %p)\n", This
, ppv
);
921 info
= get_wininet_info(This
->protocol
);
923 return E_NOINTERFACE
;
925 hres
= IWinInetInfo_QueryInterface(info
, &IID_IWinInetHttpInfo
, (void**)&http_info
);
927 return E_NOINTERFACE
;
929 IWinInetHttpInfo_Release(http_info
);
930 *ppv
= INETINFO(This
);
934 IBinding_AddRef(BINDING(This
));
938 WARN("Unsupported interface %s\n", debugstr_guid(riid
));
939 return E_NOINTERFACE
;
942 static ULONG WINAPI
Binding_AddRef(IBinding
*iface
)
944 Binding
*This
= BINDING_THIS(iface
);
945 LONG ref
= InterlockedIncrement(&This
->ref
);
947 TRACE("(%p) ref=%d\n", This
, ref
);
952 static ULONG WINAPI
Binding_Release(IBinding
*iface
)
954 Binding
*This
= BINDING_THIS(iface
);
955 LONG ref
= InterlockedDecrement(&This
->ref
);
957 TRACE("(%p) ref=%d\n", This
, ref
);
960 if (This
->notif_hwnd
)
961 DestroyWindow( This
->notif_hwnd
);
963 IMoniker_Release(This
->mon
);
965 IBindStatusCallback_Release(This
->callback
);
967 IInternetProtocol_Release(This
->protocol
);
968 if(This
->service_provider
)
969 IServiceProvider_Release(This
->service_provider
);
971 IUnknown_Release(STGMEDUNK(This
->stgmed_buf
));
973 This
->stgmed_obj
->vtbl
->release(This
->stgmed_obj
);
975 IUnknown_Release(This
->obj
);
977 IBindCtx_Release(This
->bctx
);
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
);
987 URLMON_UnlockModule();
993 static HRESULT WINAPI
Binding_Abort(IBinding
*iface
)
995 Binding
*This
= BINDING_THIS(iface
);
996 FIXME("(%p)\n", This
);
1000 static HRESULT WINAPI
Binding_Suspend(IBinding
*iface
)
1002 Binding
*This
= BINDING_THIS(iface
);
1003 FIXME("(%p)\n", This
);
1007 static HRESULT WINAPI
Binding_Resume(IBinding
*iface
)
1009 Binding
*This
= BINDING_THIS(iface
);
1010 FIXME("(%p)\n", This
);
1014 static HRESULT WINAPI
Binding_SetPriority(IBinding
*iface
, LONG nPriority
)
1016 Binding
*This
= BINDING_THIS(iface
);
1017 FIXME("(%p)->(%d)\n", This
, nPriority
);
1021 static HRESULT WINAPI
Binding_GetPriority(IBinding
*iface
, LONG
*pnPriority
)
1023 Binding
*This
= BINDING_THIS(iface
);
1024 FIXME("(%p)->(%p)\n", This
, pnPriority
);
1028 static HRESULT WINAPI
Binding_GetBindResult(IBinding
*iface
, CLSID
*pclsidProtocol
,
1029 DWORD
*pdwResult
, LPOLESTR
*pszResult
, DWORD
*pdwReserved
)
1031 Binding
*This
= BINDING_THIS(iface
);
1032 FIXME("(%p)->(%p %p %p %p)\n", This
, pclsidProtocol
, pdwResult
, pszResult
, pdwReserved
);
1036 static Binding
*get_bctx_binding(IBindCtx
*bctx
)
1042 hres
= IBindCtx_GetObjectParam(bctx
, cbinding_contextW
, &unk
);
1046 hres
= IUnknown_QueryInterface(unk
, &IID_IBinding
, (void*)&binding
);
1047 IUnknown_Release(unk
);
1052 return BINDING_THIS(binding
);
1057 static const IBindingVtbl BindingVtbl
= {
1058 Binding_QueryInterface
,
1064 Binding_SetPriority
,
1065 Binding_GetPriority
,
1066 Binding_GetBindResult
1069 #define PROTSINK_THIS(iface) DEFINE_THIS(Binding, InternetProtocolSink, iface)
1071 static HRESULT WINAPI
InternetProtocolSink_QueryInterface(IInternetProtocolSink
*iface
,
1072 REFIID riid
, void **ppv
)
1074 Binding
*This
= PROTSINK_THIS(iface
);
1075 return IBinding_QueryInterface(BINDING(This
), riid
, ppv
);
1078 static ULONG WINAPI
InternetProtocolSink_AddRef(IInternetProtocolSink
*iface
)
1080 Binding
*This
= PROTSINK_THIS(iface
);
1081 return IBinding_AddRef(BINDING(This
));
1084 static ULONG WINAPI
InternetProtocolSink_Release(IInternetProtocolSink
*iface
)
1086 Binding
*This
= PROTSINK_THIS(iface
);
1087 return IBinding_Release(BINDING(This
));
1091 task_header_t header
;
1095 static void switch_proc(Binding
*binding
, task_header_t
*t
)
1097 switch_task_t
*task
= (switch_task_t
*)t
;
1099 IInternetProtocol_Continue(binding
->protocol
, &task
->data
);
1104 static HRESULT WINAPI
InternetProtocolSink_Switch(IInternetProtocolSink
*iface
,
1105 PROTOCOLDATA
*pProtocolData
)
1107 Binding
*This
= PROTSINK_THIS(iface
);
1108 switch_task_t
*task
;
1110 TRACE("(%p)->(%p)\n", This
, pProtocolData
);
1112 task
= heap_alloc(sizeof(switch_task_t
));
1113 task
->data
= *pProtocolData
;
1115 push_task(This
, &task
->header
, switch_proc
);
1117 IBinding_AddRef(BINDING(This
));
1118 PostMessageW(This
->notif_hwnd
, WM_MK_CONTINUE
, 0, (LPARAM
)This
);
1124 task_header_t header
;
1131 } on_progress_task_t
;
1133 static void on_progress_proc(Binding
*binding
, task_header_t
*t
)
1135 on_progress_task_t
*task
= (on_progress_task_t
*)t
;
1137 IBindStatusCallback_OnProgress(binding
->callback
, task
->progress
,
1138 task
->progress_max
, task
->status_code
, task
->status_text
);
1140 heap_free(task
->status_text
);
1144 static void on_progress(Binding
*This
, ULONG progress
, ULONG progress_max
,
1145 ULONG status_code
, LPCWSTR status_text
)
1147 on_progress_task_t
*task
;
1149 if(GetCurrentThreadId() == This
->apartment_thread
&& !This
->continue_call
) {
1150 IBindStatusCallback_OnProgress(This
->callback
, progress
, progress_max
,
1151 status_code
, status_text
);
1155 task
= heap_alloc(sizeof(on_progress_task_t
));
1157 task
->progress
= progress
;
1158 task
->progress_max
= progress_max
;
1159 task
->status_code
= status_code
;
1162 DWORD size
= (strlenW(status_text
)+1)*sizeof(WCHAR
);
1164 task
->status_text
= heap_alloc(size
);
1165 memcpy(task
->status_text
, status_text
, size
);
1167 task
->status_text
= NULL
;
1170 push_task(This
, &task
->header
, on_progress_proc
);
1172 if(GetCurrentThreadId() != This
->apartment_thread
) {
1173 IBinding_AddRef(BINDING(This
));
1174 PostMessageW(This
->notif_hwnd
, WM_MK_CONTINUE
, 0, (LPARAM
)This
);
1178 static HRESULT WINAPI
InternetProtocolSink_ReportProgress(IInternetProtocolSink
*iface
,
1179 ULONG ulStatusCode
, LPCWSTR szStatusText
)
1181 Binding
*This
= PROTSINK_THIS(iface
);
1183 TRACE("(%p)->(%u %s)\n", This
, ulStatusCode
, debugstr_w(szStatusText
));
1185 switch(ulStatusCode
) {
1186 case BINDSTATUS_FINDINGRESOURCE
:
1187 on_progress(This
, 0, 0, BINDSTATUS_FINDINGRESOURCE
, szStatusText
);
1189 case BINDSTATUS_CONNECTING
:
1190 on_progress(This
, 0, 0, BINDSTATUS_CONNECTING
, szStatusText
);
1192 case BINDSTATUS_BEGINDOWNLOADDATA
:
1193 fill_stgmed_buffer(This
->stgmed_buf
);
1195 case BINDSTATUS_MIMETYPEAVAILABLE
:
1196 set_binding_mime(This
, szStatusText
);
1198 case BINDSTATUS_SENDINGREQUEST
:
1199 on_progress(This
, 0, 0, BINDSTATUS_SENDINGREQUEST
, szStatusText
);
1201 case BINDSTATUS_PROTOCOLCLASSID
:
1203 case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE
:
1204 mime_available(This
, szStatusText
, FALSE
);
1206 case BINDSTATUS_CACHEFILENAMEAVAILABLE
:
1207 heap_free(This
->stgmed_buf
->cache_file
);
1208 This
->stgmed_buf
->cache_file
= heap_strdupW(szStatusText
);
1210 case BINDSTATUS_DIRECTBIND
:
1211 This
->report_mime
= FALSE
;
1213 case BINDSTATUS_ACCEPTRANGES
:
1216 FIXME("Unhandled status code %d\n", ulStatusCode
);
1223 static void report_data(Binding
*This
, DWORD bscf
, ULONG progress
, ULONG progress_max
)
1225 FORMATETC formatetc
= {0, NULL
, 1, -1, TYMED_ISTREAM
};
1226 BOOL sent_begindownloaddata
= FALSE
;
1228 TRACE("(%p)->(%d %u %u)\n", This
, bscf
, progress
, progress_max
);
1230 if(This
->download_state
== END_DOWNLOAD
|| (This
->state
& BINDING_STOPPED
))
1233 if(GetCurrentThreadId() != This
->apartment_thread
)
1234 FIXME("called from worker thread\n");
1236 if(This
->report_mime
)
1237 mime_available(This
, NULL
, TRUE
);
1239 if(This
->download_state
== BEFORE_DOWNLOAD
) {
1240 fill_stgmed_buffer(This
->stgmed_buf
);
1242 This
->download_state
= DOWNLOADING
;
1243 sent_begindownloaddata
= TRUE
;
1244 IBindStatusCallback_OnProgress(This
->callback
, progress
, progress_max
,
1245 BINDSTATUS_BEGINDOWNLOADDATA
, This
->url
);
1247 if(This
->stgmed_buf
->cache_file
)
1248 IBindStatusCallback_OnProgress(This
->callback
, progress
, progress_max
,
1249 BINDSTATUS_CACHEFILENAMEAVAILABLE
, This
->stgmed_buf
->cache_file
);
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
);
1261 if(This
->to_object
) {
1262 if(!(This
->state
& BINDING_OBJAVAIL
))
1263 create_object(This
);
1268 if(!(This
->state
& BINDING_LOCKED
)) {
1269 HRESULT hres
= IInternetProtocol_LockRequest(This
->protocol
, 0);
1271 This
->state
|= BINDING_LOCKED
;
1274 hres
= This
->stgmed_obj
->vtbl
->fill_stgmed(This
->stgmed_obj
, &stgmed
);
1276 stop_binding(This
, hres
, NULL
);
1280 formatetc
.tymed
= stgmed
.tymed
;
1281 formatetc
.cfFormat
= This
->clipboard_format
;
1283 IBindStatusCallback_OnDataAvailable(This
->callback
, bscf
, progress
,
1284 &formatetc
, &stgmed
);
1286 if(This
->download_state
== END_DOWNLOAD
)
1287 stop_binding(This
, S_OK
, NULL
);
1292 task_header_t header
;
1296 } report_data_task_t
;
1298 static void report_data_proc(Binding
*binding
, task_header_t
*t
)
1300 report_data_task_t
*task
= (report_data_task_t
*)t
;
1302 report_data(binding
, task
->bscf
, task
->progress
, task
->progress_max
);
1307 static HRESULT WINAPI
InternetProtocolSink_ReportData(IInternetProtocolSink
*iface
,
1308 DWORD grfBSCF
, ULONG ulProgress
, ULONG ulProgressMax
)
1310 Binding
*This
= PROTSINK_THIS(iface
);
1312 TRACE("(%p)->(%d %u %u)\n", This
, grfBSCF
, ulProgress
, ulProgressMax
);
1314 if(GetCurrentThreadId() != This
->apartment_thread
)
1315 FIXME("called from worked hread\n");
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
;
1323 push_task(This
, &task
->header
, report_data_proc
);
1325 report_data(This
, grfBSCF
, ulProgress
, ulProgressMax
);
1332 task_header_t header
;
1336 } report_result_task_t
;
1338 static void report_result_proc(Binding
*binding
, task_header_t
*t
)
1340 report_result_task_t
*task
= (report_result_task_t
*)t
;
1342 IInternetProtocol_Terminate(binding
->protocol
, 0);
1344 stop_binding(binding
, task
->hres
, task
->str
);
1346 heap_free(task
->str
);
1350 static HRESULT WINAPI
InternetProtocolSink_ReportResult(IInternetProtocolSink
*iface
,
1351 HRESULT hrResult
, DWORD dwError
, LPCWSTR szResult
)
1353 Binding
*This
= PROTSINK_THIS(iface
);
1355 TRACE("(%p)->(%08x %d %s)\n", This
, hrResult
, dwError
, debugstr_w(szResult
));
1357 if(GetCurrentThreadId() == This
->apartment_thread
&& !This
->continue_call
) {
1358 IInternetProtocol_Terminate(This
->protocol
, 0);
1359 stop_binding(This
, hrResult
, szResult
);
1361 report_result_task_t
*task
= heap_alloc(sizeof(report_result_task_t
));
1363 task
->hres
= hrResult
;
1364 task
->str
= heap_strdupW(szResult
);
1366 push_task(This
, &task
->header
, report_result_proc
);
1372 #undef PROTSINK_THIS
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
1384 #define BINDINF_THIS(iface) DEFINE_THIS(Binding, InternetBindInfo, iface)
1386 static HRESULT WINAPI
InternetBindInfo_QueryInterface(IInternetBindInfo
*iface
,
1387 REFIID riid
, void **ppv
)
1389 Binding
*This
= BINDINF_THIS(iface
);
1390 return IBinding_QueryInterface(BINDING(This
), riid
, ppv
);
1393 static ULONG WINAPI
InternetBindInfo_AddRef(IInternetBindInfo
*iface
)
1395 Binding
*This
= BINDINF_THIS(iface
);
1396 return IBinding_AddRef(BINDING(This
));
1399 static ULONG WINAPI
InternetBindInfo_Release(IInternetBindInfo
*iface
)
1401 Binding
*This
= BINDINF_THIS(iface
);
1402 return IBinding_Release(BINDING(This
));
1405 static HRESULT WINAPI
InternetBindInfo_GetBindInfo(IInternetBindInfo
*iface
,
1406 DWORD
*grfBINDF
, BINDINFO
*pbindinfo
)
1408 Binding
*This
= BINDINF_THIS(iface
);
1410 TRACE("(%p)->(%p %p)\n", This
, grfBINDF
, pbindinfo
);
1412 *grfBINDF
= This
->bindf
;
1414 *pbindinfo
= This
->bindinfo
;
1416 if(pbindinfo
->szExtraInfo
|| pbindinfo
->szCustomVerb
)
1417 FIXME("copy strings\n");
1419 if(pbindinfo
->stgmedData
.pUnkForRelease
)
1420 IUnknown_AddRef(pbindinfo
->stgmedData
.pUnkForRelease
);
1423 IUnknown_AddRef(pbindinfo
->pUnk
);
1428 static HRESULT WINAPI
InternetBindInfo_GetBindString(IInternetBindInfo
*iface
,
1429 ULONG ulStringType
, LPOLESTR
*ppwzStr
, ULONG cEl
, ULONG
*pcElFetched
)
1431 Binding
*This
= BINDINF_THIS(iface
);
1433 TRACE("(%p)->(%d %p %d %p)\n", This
, ulStringType
, ppwzStr
, cEl
, pcElFetched
);
1435 switch(ulStringType
) {
1436 case BINDSTRING_ACCEPT_MIMES
: {
1437 static const WCHAR wszMimes
[] = {'*','/','*',0};
1439 if(!ppwzStr
|| !pcElFetched
)
1440 return E_INVALIDARG
;
1442 ppwzStr
[0] = CoTaskMemAlloc(sizeof(wszMimes
));
1443 memcpy(ppwzStr
[0], wszMimes
, sizeof(wszMimes
));
1447 case BINDSTRING_USER_AGENT
: {
1448 IInternetBindInfo
*bindinfo
= NULL
;
1451 hres
= IBindStatusCallback_QueryInterface(This
->callback
, &IID_IInternetBindInfo
,
1456 hres
= IInternetBindInfo_GetBindString(bindinfo
, ulStringType
, ppwzStr
,
1458 IInternetBindInfo_Release(bindinfo
);
1464 FIXME("not supported string type %d\n", ulStringType
);
1470 static const IInternetBindInfoVtbl InternetBindInfoVtbl
= {
1471 InternetBindInfo_QueryInterface
,
1472 InternetBindInfo_AddRef
,
1473 InternetBindInfo_Release
,
1474 InternetBindInfo_GetBindInfo
,
1475 InternetBindInfo_GetBindString
1478 #define INETINFO_THIS(iface) DEFINE_THIS(Binding, WinInetHttpInfo, iface)
1480 static HRESULT WINAPI
WinInetHttpInfo_QueryInterface(IWinInetHttpInfo
*iface
, REFIID riid
, void **ppv
)
1482 Binding
*This
= INETINFO_THIS(iface
);
1483 return IBinding_QueryInterface(BINDING(This
), riid
, ppv
);
1486 static ULONG WINAPI
WinInetHttpInfo_AddRef(IWinInetHttpInfo
*iface
)
1488 Binding
*This
= INETINFO_THIS(iface
);
1489 return IBinding_AddRef(BINDING(This
));
1492 static ULONG WINAPI
WinInetHttpInfo_Release(IWinInetHttpInfo
*iface
)
1494 Binding
*This
= INETINFO_THIS(iface
);
1495 return IBinding_Release(BINDING(This
));
1498 static HRESULT WINAPI
WinInetHttpInfo_QueryOption(IWinInetHttpInfo
*iface
, DWORD dwOption
,
1499 void *pBuffer
, DWORD
*pcbBuffer
)
1501 Binding
*This
= INETINFO_THIS(iface
);
1502 FIXME("(%p)->(%x %p %p)\n", This
, dwOption
, pBuffer
, pcbBuffer
);
1506 static HRESULT WINAPI
WinInetHttpInfo_QueryInfo(IWinInetHttpInfo
*iface
, DWORD dwOption
,
1507 void *pBuffer
, DWORD
*pcbBuffer
, DWORD
*pdwFlags
, DWORD
*pdwReserved
)
1509 Binding
*This
= INETINFO_THIS(iface
);
1510 FIXME("(%p)->(%x %p %p %p %p)\n", This
, dwOption
, pBuffer
, pcbBuffer
, pdwFlags
, pdwReserved
);
1514 #undef INETINFO_THIS
1516 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl
= {
1517 WinInetHttpInfo_QueryInterface
,
1518 WinInetHttpInfo_AddRef
,
1519 WinInetHttpInfo_Release
,
1520 WinInetHttpInfo_QueryOption
,
1521 WinInetHttpInfo_QueryInfo
1524 #define SERVPROV_THIS(iface) DEFINE_THIS(Binding, ServiceProvider, iface)
1526 static HRESULT WINAPI
ServiceProvider_QueryInterface(IServiceProvider
*iface
,
1527 REFIID riid
, void **ppv
)
1529 Binding
*This
= SERVPROV_THIS(iface
);
1530 return IBinding_QueryInterface(BINDING(This
), riid
, ppv
);
1533 static ULONG WINAPI
ServiceProvider_AddRef(IServiceProvider
*iface
)
1535 Binding
*This
= SERVPROV_THIS(iface
);
1536 return IBinding_AddRef(BINDING(This
));
1539 static ULONG WINAPI
ServiceProvider_Release(IServiceProvider
*iface
)
1541 Binding
*This
= SERVPROV_THIS(iface
);
1542 return IBinding_Release(BINDING(This
));
1545 static HRESULT WINAPI
ServiceProvider_QueryService(IServiceProvider
*iface
,
1546 REFGUID guidService
, REFIID riid
, void **ppv
)
1548 Binding
*This
= SERVPROV_THIS(iface
);
1551 TRACE("(%p)->(%s %s %p)\n", This
, debugstr_guid(guidService
), debugstr_guid(riid
), ppv
);
1553 if(This
->service_provider
) {
1554 hres
= IServiceProvider_QueryService(This
->service_provider
, guidService
,
1560 WARN("unknown service %s\n", debugstr_guid(guidService
));
1564 #undef SERVPROV_THIS
1566 static const IServiceProviderVtbl ServiceProviderVtbl
= {
1567 ServiceProvider_QueryInterface
,
1568 ServiceProvider_AddRef
,
1569 ServiceProvider_Release
,
1570 ServiceProvider_QueryService
1573 static HRESULT
get_callback(IBindCtx
*pbc
, IBindStatusCallback
**callback
)
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
);
1584 return SUCCEEDED(hres
) ? S_OK
: INET_E_DATA_NOT_AVAILABLE
;
1587 static BOOL
is_urlmon_protocol(LPCWSTR url
)
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'};
1597 static const struct {
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
)}
1611 int len
= lstrlenW(url
);
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
)))
1622 static HRESULT
Binding_Create(IMoniker
*mon
, Binding
*binding_ctx
, LPCWSTR url
, IBindCtx
*pbc
,
1623 BOOL to_obj
, REFIID riid
, Binding
**binding
)
1628 URLMON_LockModule();
1630 ret
= heap_alloc_zero(sizeof(Binding
));
1632 ret
->lpBindingVtbl
= &BindingVtbl
;
1633 ret
->lpInternetProtocolSinkVtbl
= &InternetProtocolSinkVtbl
;
1634 ret
->lpInternetBindInfoVtbl
= &InternetBindInfoVtbl
;
1635 ret
->lpWinInetHttpInfoVtbl
= &WinInetHttpInfoVtbl
;
1636 ret
->lpServiceProviderVtbl
= &ServiceProviderVtbl
;
1640 ret
->to_object
= to_obj
;
1642 ret
->apartment_thread
= GetCurrentThreadId();
1643 ret
->notif_hwnd
= get_notif_hwnd();
1644 ret
->report_mime
= !binding_ctx
;
1645 ret
->download_state
= BEFORE_DOWNLOAD
;
1648 IBindCtx_AddRef(pbc
);
1653 IMoniker_AddRef(mon
);
1657 ret
->bindinfo
.cbSize
= sizeof(BINDINFO
);
1659 InitializeCriticalSection(&ret
->section
);
1660 ret
->section
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": Binding.section");
1662 hres
= get_callback(pbc
, &ret
->callback
);
1664 WARN("Could not get IBindStatusCallback\n");
1665 IBinding_Release(BINDING(ret
));
1669 IBindStatusCallback_QueryInterface(ret
->callback
, &IID_IServiceProvider
,
1670 (void**)&ret
->service_provider
);
1673 ret
->protocol
= binding_ctx
->protocol
;
1674 IInternetProtocol_AddRef(ret
->protocol
);
1676 hres
= create_binding_protocol(url
, TRUE
, &ret
->protocol
);
1678 WARN("Could not get protocol handler\n");
1679 IBinding_Release(BINDING(ret
));
1684 hres
= IBindStatusCallback_GetBindInfo(ret
->callback
, &ret
->bindf
, &ret
->bindinfo
);
1686 WARN("GetBindInfo failed: %08x\n", hres
);
1687 IBinding_Release(BINDING(ret
));
1691 TRACE("bindf %08x\n", ret
->bindf
);
1692 dump_BINDINFO(&ret
->bindinfo
);
1694 ret
->bindf
|= BINDF_FROMURLMON
;
1696 ret
->bindinfo
.dwOptions
|= 0x100000;
1698 if(!is_urlmon_protocol(url
))
1699 ret
->bindf
|= BINDF_NEEDFILE
;
1701 ret
->url
= heap_strdupW(url
);
1704 ret
->stgmed_buf
= binding_ctx
->stgmed_buf
;
1705 IUnknown_AddRef(STGMEDUNK(ret
->stgmed_buf
));
1706 ret
->clipboard_format
= binding_ctx
->clipboard_format
;
1708 ret
->stgmed_buf
= create_stgmed_buf(ret
->protocol
);
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
);
1719 FIXME("Unsupported riid %s\n", debugstr_guid(riid
));
1720 IBinding_Release(BINDING(ret
));
1728 static HRESULT
start_binding(IMoniker
*mon
, Binding
*binding_ctx
, LPCWSTR url
, IBindCtx
*pbc
,
1729 BOOL to_obj
, REFIID riid
, Binding
**ret
)
1731 Binding
*binding
= NULL
;
1735 hres
= Binding_Create(mon
, binding_ctx
, url
, pbc
, to_obj
, riid
, &binding
);
1739 hres
= IBindStatusCallback_OnStartBinding(binding
->callback
, 0, BINDING(binding
));
1741 WARN("OnStartBinding failed: %08x\n", hres
);
1742 stop_binding(binding
, INET_E_DOWNLOAD_FAILURE
, NULL
);
1743 IBinding_Release(BINDING(binding
));
1748 set_binding_sink(binding
->protocol
, PROTSINK(binding
));
1749 report_data(binding
, 0, 0, 0);
1751 hres
= IInternetProtocol_Start(binding
->protocol
, url
, PROTSINK(binding
),
1752 BINDINF(binding
), 0, 0);
1754 TRACE("start ret %08x\n", hres
);
1756 if(FAILED(hres
) && hres
!= E_PENDING
) {
1757 stop_binding(binding
, hres
, NULL
);
1758 IBinding_Release(BINDING(binding
));
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
);
1777 HRESULT
bind_to_storage(LPCWSTR url
, IBindCtx
*pbc
, REFIID riid
, void **ppv
)
1779 Binding
*binding
= NULL
, *binding_ctx
;
1784 binding_ctx
= get_bctx_binding(pbc
);
1786 hres
= start_binding(NULL
, binding_ctx
, url
, pbc
, FALSE
, riid
, &binding
);
1788 IBinding_Release(BINDING(binding_ctx
));
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
);
1796 *ppv
= binding
->stgmed_obj
->vtbl
->get_result(binding
->stgmed_obj
);
1799 IBinding_Release(BINDING(binding
));
1801 return *ppv
? S_OK
: MK_S_ASYNCHRONOUS
;
1804 HRESULT
bind_to_object(IMoniker
*mon
, LPCWSTR url
, IBindCtx
*pbc
, REFIID riid
, void **ppv
)
1811 hres
= start_binding(mon
, NULL
, url
, pbc
, TRUE
, riid
, &binding
);
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
;
1820 *ppv
= binding
->obj
;
1821 IUnknown_AddRef(binding
->obj
);
1825 IBinding_Release(BINDING(binding
));