From 2db9bb4bbbd5a1f99da683b06e435d3fd43f732e Mon Sep 17 00:00:00 2001 From: Dmitry Chapyshev Date: Sat, 23 May 2009 10:20:22 +0000 Subject: [PATCH] - Sync shlwapi, traffic, urlmon with Wine 1.1.22 svn path=/trunk/; revision=41060 --- reactos/dll/win32/shlwapi/ordinal.c | 24 +- reactos/dll/win32/shlwapi/shlwapi.spec | 2 +- reactos/dll/win32/traffic/traffic.spec | 2 +- reactos/dll/win32/traffic/traffic_main.c | 12 + reactos/dll/win32/urlmon/binding.c | 350 ++-------- reactos/dll/win32/urlmon/bindprot.c | 775 ++++++++++++++++++++--- reactos/dll/win32/urlmon/file.c | 7 +- reactos/dll/win32/urlmon/ftp.c | 11 +- reactos/dll/win32/urlmon/gopher.c | 9 +- reactos/dll/win32/urlmon/http.c | 11 +- reactos/dll/win32/urlmon/mk.c | 8 +- reactos/dll/win32/urlmon/protproxy.c | 290 +++++++++ reactos/dll/win32/urlmon/session.c | 30 + reactos/dll/win32/urlmon/urlmon.rbuild | 1 + reactos/dll/win32/urlmon/urlmon_main.c | 85 ++- reactos/dll/win32/urlmon/urlmon_main.h | 29 + 16 files changed, 1203 insertions(+), 443 deletions(-) create mode 100644 reactos/dll/win32/urlmon/protproxy.c diff --git a/reactos/dll/win32/shlwapi/ordinal.c b/reactos/dll/win32/shlwapi/ordinal.c index cc193b5d4c3..c18d1ea1db8 100644 --- a/reactos/dll/win32/shlwapi/ordinal.c +++ b/reactos/dll/win32/shlwapi/ordinal.c @@ -1081,11 +1081,11 @@ HRESULT WINAPI IUnknown_Exec(IUnknown* lpUnknown, REFGUID pguidCmdGroup, */ LONG WINAPI SHSetWindowBits(HWND hwnd, INT offset, UINT wMask, UINT wFlags) { - LONG ret = GetWindowLongPtrA(hwnd, offset); + LONG ret = GetWindowLongA(hwnd, offset); LONG newFlags = (wFlags & wMask) | (ret & ~wFlags); if (newFlags != ret) - ret = SetWindowLongPtrA(hwnd, offset, newFlags); + ret = SetWindowLongA(hwnd, offset, newFlags); return ret; } @@ -2913,6 +2913,26 @@ static HRESULT SHLWAPI_InvokeByIID( return S_OK; } +/************************************************************************* + * IConnectionPoint_InvokeWithCancel [SHLWAPI.283] + */ +HRESULT WINAPI IConnectionPoint_InvokeWithCancel( IConnectionPoint* iCP, + DISPID dispId, DISPPARAMS* dispParams, + DWORD unknown1, DWORD unknown2 ) +{ + IID iid; + HRESULT result; + + FIXME("(%p)->(0x%x %p %x %x) partial stub\n", iCP, dispId, dispParams, unknown1, unknown2); + + result = IConnectionPoint_GetConnectionInterface(iCP, &iid); + if (SUCCEEDED(result)) + result = SHLWAPI_InvokeByIID(iCP, &iid, dispId, dispParams); + + return result; +} + + /************************************************************************* * @ [SHLWAPI.284] * diff --git a/reactos/dll/win32/shlwapi/shlwapi.spec b/reactos/dll/win32/shlwapi/shlwapi.spec index 0b1cd4c569d..d9cc3a5f842 100644 --- a/reactos/dll/win32/shlwapi/shlwapi.spec +++ b/reactos/dll/win32/shlwapi/shlwapi.spec @@ -280,7 +280,7 @@ 280 stdcall -noname SHRegGetIntW(ptr wstr long) 281 stdcall -noname SHPackDispParamsV(ptr ptr long ptr) 282 varargs -noname SHPackDispParams(ptr ptr long) -283 stub -noname IConnectionPoint_InvokeWithCancel +283 stdcall -noname IConnectionPoint_InvokeWithCancel(ptr long long long long) 284 stdcall -noname IConnectionPoint_SimpleInvoke(ptr long ptr) 285 stdcall -noname IConnectionPoint_OnChanged(ptr long) 286 varargs -noname IUnknown_CPContainerInvokeParam(ptr ptr long ptr long) diff --git a/reactos/dll/win32/traffic/traffic.spec b/reactos/dll/win32/traffic/traffic.spec index eed26e88ad8..4638af31b01 100644 --- a/reactos/dll/win32/traffic/traffic.spec +++ b/reactos/dll/win32/traffic/traffic.spec @@ -15,7 +15,7 @@ @ stub TcQueryFlowA @ stub TcQueryFlowW @ stub TcQueryInterface -@ stub TcRegisterClient +@ stdcall TcRegisterClient(long ptr ptr ptr) @ stub TcSetFlowA @ stub TcSetFlowW @ stub TcSetInterface diff --git a/reactos/dll/win32/traffic/traffic_main.c b/reactos/dll/win32/traffic/traffic_main.c index 421be6c0bff..6efea899dda 100644 --- a/reactos/dll/win32/traffic/traffic_main.c +++ b/reactos/dll/win32/traffic/traffic_main.c @@ -21,6 +21,7 @@ #include "windef.h" #include "winbase.h" +#include "traffic.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(traffic); @@ -42,3 +43,14 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) return TRUE; } + +/***************************************************************************** + * TcRegisterClient [TRAFFIC.@] + */ +ULONG WINAPI TcRegisterClient(ULONG version, HANDLE context, + PTCI_CLIENT_FUNC_LIST list, PHANDLE buffer) +{ + FIXME("(%u %p %p %p) stub\n", version, context, list, buffer); + if(buffer) *buffer = INVALID_HANDLE_VALUE; + return ERROR_CALL_NOT_IMPLEMENTED; +} diff --git a/reactos/dll/win32/urlmon/binding.c b/reactos/dll/win32/urlmon/binding.c index 28d0802174b..ba6f564813b 100644 --- a/reactos/dll/win32/urlmon/binding.c +++ b/reactos/dll/win32/urlmon/binding.c @@ -78,7 +78,7 @@ typedef enum { struct Binding { const IBindingVtbl *lpBindingVtbl; - const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl; + const IInternetProtocolSinkVtbl *lpIInternetProtocolSinkVtbl; const IInternetBindInfoVtbl *lpInternetBindInfoVtbl; const IWinInetHttpInfoVtbl *lpWinInetHttpInfoVtbl; const IServiceProviderVtbl *lpServiceProviderVtbl; @@ -100,23 +100,18 @@ struct Binding { LPWSTR url; IID iid; BOOL report_mime; - DWORD continue_call; DWORD state; HRESULT hres; download_state_t download_state; IUnknown *obj; IMoniker *mon; IBindCtx *bctx; - - DWORD apartment_thread; HWND notif_hwnd; - task_header_t *task_queue_head, *task_queue_tail; CRITICAL_SECTION section; }; #define BINDING(x) ((IBinding*) &(x)->lpBindingVtbl) -#define PROTSINK(x) ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl) #define BINDINF(x) ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl) #define INETINFO(x) ((IWinInetHttpInfo*) &(x)->lpWinInetHttpInfoVtbl) #define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl) @@ -124,43 +119,6 @@ struct Binding { #define STREAM(x) ((IStream*) &(x)->lpStreamVtbl) #define HTTPNEG2(x) ((IHttpNegotiate2*) &(x)->lpHttpNegotiate2Vtbl) -#define WM_MK_CONTINUE (WM_USER+101) - -static void push_task(Binding *binding, task_header_t *task, task_proc_t proc) -{ - task->proc = proc; - task->next = NULL; - - EnterCriticalSection(&binding->section); - - if(binding->task_queue_tail) { - binding->task_queue_tail->next = task; - binding->task_queue_tail = task; - }else { - binding->task_queue_tail = binding->task_queue_head = task; - } - - LeaveCriticalSection(&binding->section); -} - -static task_header_t *pop_task(Binding *binding) -{ - task_header_t *ret; - - EnterCriticalSection(&binding->section); - - ret = binding->task_queue_head; - if(ret) { - binding->task_queue_head = ret->next; - if(!binding->task_queue_head) - binding->task_queue_tail = NULL; - } - - LeaveCriticalSection(&binding->section); - - return ret; -} - static void fill_stgmed_buffer(stgmed_buf_t *buf) { DWORD read = 0; @@ -175,59 +133,6 @@ static void fill_stgmed_buffer(stgmed_buf_t *buf) buf->init = TRUE; } -static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - if(msg == WM_MK_CONTINUE) { - Binding *binding = (Binding*)lParam; - task_header_t *task; - - while((task = pop_task(binding))) { - binding->continue_call++; - task->proc(binding, task); - binding->continue_call--; - } - - IBinding_Release(BINDING(binding)); - return 0; - } - - return DefWindowProcW(hwnd, msg, wParam, lParam); -} - -static HWND get_notif_hwnd(void) -{ - static ATOM wnd_class = 0; - HWND hwnd; - - static const WCHAR wszURLMonikerNotificationWindow[] = - {'U','R','L',' ','M','o','n','i','k','e','r',' ', - 'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0}; - - if(!wnd_class) { - static WNDCLASSEXW wndclass = { - sizeof(wndclass), 0, - notif_wnd_proc, 0, 0, - NULL, NULL, NULL, NULL, NULL, - wszURLMonikerNotificationWindow, - NULL - }; - - wndclass.hInstance = URLMON_hInstance; - - wnd_class = RegisterClassExW(&wndclass); - if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS) - wnd_class = 1; - } - - hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow, - wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE, - NULL, URLMON_hInstance, NULL); - - TRACE("hwnd = %p\n", hwnd); - - return hwnd; -} - static void dump_BINDINFO(BINDINFO *bi) { static const char * const BINDINFOF_str[] = { @@ -272,73 +177,17 @@ static void dump_BINDINFO(BINDINFO *bi) ); } -static void set_binding_mime(Binding *binding, LPCWSTR mime) +static void mime_available(Binding *This, LPCWSTR mime) { - EnterCriticalSection(&binding->section); + heap_free(This->mime); + This->mime = heap_strdupW(mime); - if(binding->report_mime) { - heap_free(binding->mime); - binding->mime = heap_strdupW(mime); - } - - LeaveCriticalSection(&binding->section); -} - -static void handle_mime_available(Binding *binding, BOOL verify) -{ - BOOL report_mime; - - EnterCriticalSection(&binding->section); - report_mime = binding->report_mime; - binding->report_mime = FALSE; - LeaveCriticalSection(&binding->section); - - if(!report_mime) + if(!This->mime || !This->report_mime) return; - if(verify) { - LPWSTR mime = NULL; + IBindStatusCallback_OnProgress(This->callback, 0, 0, BINDSTATUS_MIMETYPEAVAILABLE, This->mime); - fill_stgmed_buffer(binding->stgmed_buf); - FindMimeFromData(NULL, binding->url, binding->stgmed_buf->buf, - min(binding->stgmed_buf->size, 255), binding->mime, 0, &mime, 0); - - heap_free(binding->mime); - binding->mime = heap_strdupW(mime); - CoTaskMemFree(mime); - } - - IBindStatusCallback_OnProgress(binding->callback, 0, 0, BINDSTATUS_MIMETYPEAVAILABLE, binding->mime); - - binding->clipboard_format = RegisterClipboardFormatW(binding->mime); -} - -typedef struct { - task_header_t header; - BOOL verify; -} mime_available_task_t; - -static void mime_available_proc(Binding *binding, task_header_t *t) -{ - mime_available_task_t *task = (mime_available_task_t*)t; - - handle_mime_available(binding, task->verify); - - heap_free(task); -} - -static void mime_available(Binding *This, LPCWSTR mime, BOOL verify) -{ - if(mime) - set_binding_mime(This, mime); - - if(GetCurrentThreadId() == This->apartment_thread) { - handle_mime_available(This, verify); - }else { - mime_available_task_t *task = heap_alloc(sizeof(task_header_t)); - task->verify = verify; - push_task(This, &task->header, mime_available_proc); - } + This->clipboard_format = RegisterClipboardFormatW(This->mime); } static void stop_binding(Binding *binding, HRESULT hres, LPCWSTR str) @@ -957,8 +806,8 @@ static ULONG WINAPI Binding_Release(IBinding *iface) TRACE("(%p) ref=%d\n", This, ref); if(!ref) { - if (This->notif_hwnd) - DestroyWindow( This->notif_hwnd ); + if(This->notif_hwnd) + release_notif_hwnd(This->notif_hwnd); if(This->mon) IMoniker_Release(This->mon); if(This->callback) @@ -1066,7 +915,7 @@ static const IBindingVtbl BindingVtbl = { Binding_GetBindResult }; -#define PROTSINK_THIS(iface) DEFINE_THIS(Binding, InternetProtocolSink, iface) +#define PROTSINK_THIS(iface) DEFINE_THIS(Binding, IInternetProtocolSink, iface) static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface, REFIID riid, void **ppv) @@ -1087,92 +936,21 @@ static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface) return IBinding_Release(BINDING(This)); } -typedef struct { - task_header_t header; - PROTOCOLDATA data; -} switch_task_t; - -static void switch_proc(Binding *binding, task_header_t *t) -{ - switch_task_t *task = (switch_task_t*)t; - - IInternetProtocol_Continue(binding->protocol, &task->data); - - heap_free(task); -} - static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOLDATA *pProtocolData) { Binding *This = PROTSINK_THIS(iface); - switch_task_t *task; - TRACE("(%p)->(%p)\n", This, pProtocolData); + WARN("(%p)->(%p)\n", This, pProtocolData); - task = heap_alloc(sizeof(switch_task_t)); - task->data = *pProtocolData; - - push_task(This, &task->header, switch_proc); - - IBinding_AddRef(BINDING(This)); - PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This); - - return S_OK; -} - -typedef struct { - task_header_t header; - - Binding *binding; - ULONG progress; - ULONG progress_max; - ULONG status_code; - LPWSTR status_text; -} on_progress_task_t; - -static void on_progress_proc(Binding *binding, task_header_t *t) -{ - on_progress_task_t *task = (on_progress_task_t*)t; - - IBindStatusCallback_OnProgress(binding->callback, task->progress, - task->progress_max, task->status_code, task->status_text); - - heap_free(task->status_text); - heap_free(task); + return E_FAIL; } static void on_progress(Binding *This, ULONG progress, ULONG progress_max, ULONG status_code, LPCWSTR status_text) { - on_progress_task_t *task; - - if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) { - IBindStatusCallback_OnProgress(This->callback, progress, progress_max, - status_code, status_text); - return; - } - - task = heap_alloc(sizeof(on_progress_task_t)); - - task->progress = progress; - task->progress_max = progress_max; - task->status_code = status_code; - - if(status_text) { - DWORD size = (strlenW(status_text)+1)*sizeof(WCHAR); - - task->status_text = heap_alloc(size); - memcpy(task->status_text, status_text, size); - }else { - task->status_text = NULL; - } - - push_task(This, &task->header, on_progress_proc); - - if(GetCurrentThreadId() != This->apartment_thread) { - IBinding_AddRef(BINDING(This)); - PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This); - } + IBindStatusCallback_OnProgress(This->callback, progress, progress_max, + status_code, status_text); } static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface, @@ -1192,22 +970,26 @@ static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink case BINDSTATUS_BEGINDOWNLOADDATA: fill_stgmed_buffer(This->stgmed_buf); break; - case BINDSTATUS_MIMETYPEAVAILABLE: - set_binding_mime(This, szStatusText); - break; case BINDSTATUS_SENDINGREQUEST: on_progress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, szStatusText); break; case BINDSTATUS_PROTOCOLCLASSID: break; + case BINDSTATUS_MIMETYPEAVAILABLE: case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE: - mime_available(This, szStatusText, FALSE); + mime_available(This, szStatusText); break; case BINDSTATUS_CACHEFILENAMEAVAILABLE: heap_free(This->stgmed_buf->cache_file); This->stgmed_buf->cache_file = heap_strdupW(szStatusText); break; - case BINDSTATUS_DIRECTBIND: + case BINDSTATUS_DECODING: + IBindStatusCallback_OnProgress(This->callback, 0, 0, BINDSTATUS_DECODING, szStatusText); + break; + case BINDSTATUS_LOADINGMIMEHANDLER: + on_progress(This, 0, 0, BINDSTATUS_LOADINGMIMEHANDLER, szStatusText); + break; + case BINDSTATUS_DIRECTBIND: /* FIXME: Handle BINDSTATUS_DIRECTBIND in BindProtocol */ This->report_mime = FALSE; break; case BINDSTATUS_ACCEPTRANGES: @@ -1230,12 +1012,6 @@ static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progres if(This->download_state == END_DOWNLOAD || (This->state & BINDING_STOPPED)) return; - if(GetCurrentThreadId() != This->apartment_thread) - FIXME("called from worker thread\n"); - - if(This->report_mime) - mime_available(This, NULL, TRUE); - if(This->download_state == BEFORE_DOWNLOAD) { fill_stgmed_buffer(This->stgmed_buf); @@ -1288,22 +1064,6 @@ static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progres } } -typedef struct { - task_header_t header; - DWORD bscf; - ULONG progress; - ULONG progress_max; -} report_data_task_t; - -static void report_data_proc(Binding *binding, task_header_t *t) -{ - report_data_task_t *task = (report_data_task_t*)t; - - report_data(binding, task->bscf, task->progress, task->progress_max); - - heap_free(task); -} - static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface, DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax) { @@ -1311,42 +1071,10 @@ static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *ifa TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax); - if(GetCurrentThreadId() != This->apartment_thread) - FIXME("called from worked hread\n"); - - if(This->continue_call) { - report_data_task_t *task = heap_alloc(sizeof(report_data_task_t)); - task->bscf = grfBSCF; - task->progress = ulProgress; - task->progress_max = ulProgressMax; - - push_task(This, &task->header, report_data_proc); - }else { - report_data(This, grfBSCF, ulProgress, ulProgressMax); - } - + report_data(This, grfBSCF, ulProgress, ulProgressMax); return S_OK; } -typedef struct { - task_header_t header; - - HRESULT hres; - LPWSTR str; -} report_result_task_t; - -static void report_result_proc(Binding *binding, task_header_t *t) -{ - report_result_task_t *task = (report_result_task_t*)t; - - IInternetProtocol_Terminate(binding->protocol, 0); - - stop_binding(binding, task->hres, task->str); - - heap_free(task->str); - heap_free(task); -} - static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface, HRESULT hrResult, DWORD dwError, LPCWSTR szResult) { @@ -1354,18 +1082,8 @@ static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *i TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult)); - if(GetCurrentThreadId() == This->apartment_thread && !This->continue_call) { - IInternetProtocol_Terminate(This->protocol, 0); - stop_binding(This, hrResult, szResult); - }else { - report_result_task_t *task = heap_alloc(sizeof(report_result_task_t)); - - task->hres = hrResult; - task->str = heap_strdupW(szResult); - - push_task(This, &task->header, report_result_proc); - } - + IInternetProtocol_Terminate(This->protocol, 0); + stop_binding(This, hrResult, szResult); return S_OK; } @@ -1459,6 +1177,17 @@ static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface, return hres; } + case BINDSTRING_URL: { + DWORD size = (strlenW(This->url)+1) * sizeof(WCHAR); + + if(!ppwzStr || !pcElFetched) + return E_INVALIDARG; + + *ppwzStr = CoTaskMemAlloc(size); + memcpy(*ppwzStr, This->url, size); + *pcElFetched = 1; + return S_OK; + } } FIXME("not supported string type %d\n", ulStringType); @@ -1630,7 +1359,7 @@ static HRESULT Binding_Create(IMoniker *mon, Binding *binding_ctx, LPCWSTR url, ret = heap_alloc_zero(sizeof(Binding)); ret->lpBindingVtbl = &BindingVtbl; - ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl; + ret->lpIInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl; ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl; ret->lpWinInetHttpInfoVtbl = &WinInetHttpInfoVtbl; ret->lpServiceProviderVtbl = &ServiceProviderVtbl; @@ -1639,7 +1368,6 @@ static HRESULT Binding_Create(IMoniker *mon, Binding *binding_ctx, LPCWSTR url, ret->to_object = to_obj; ret->iid = *riid; - ret->apartment_thread = GetCurrentThreadId(); ret->notif_hwnd = get_notif_hwnd(); ret->report_mime = !binding_ctx; ret->download_state = BEFORE_DOWNLOAD; @@ -1749,7 +1477,7 @@ static HRESULT start_binding(IMoniker *mon, Binding *binding_ctx, LPCWSTR url, I report_data(binding, 0, 0, 0); }else { hres = IInternetProtocol_Start(binding->protocol, url, PROTSINK(binding), - BINDINF(binding), 0, 0); + BINDINF(binding), PI_APARTMENTTHREADED|PI_MIMEVERIFICATION, 0); TRACE("start ret %08x\n", hres); diff --git a/reactos/dll/win32/urlmon/bindprot.c b/reactos/dll/win32/urlmon/bindprot.c index 1f245943b3b..f63824bcc77 100644 --- a/reactos/dll/win32/urlmon/bindprot.c +++ b/reactos/dll/win32/urlmon/bindprot.c @@ -1,5 +1,5 @@ /* - * Copyright 2007 Jacek Caban for CodeWeavers + * Copyright 2007-2009 Jacek Caban for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,16 +21,30 @@ WINE_DEFAULT_DEBUG_CHANNEL(urlmon); -typedef struct { - const IInternetProtocolVtbl *lpInternetProtocolVtbl; - const IInternetBindInfoVtbl *lpInternetBindInfoVtbl; - const IInternetPriorityVtbl *lpInternetPriorityVtbl; - const IServiceProviderVtbl *lpServiceProviderVtbl; - const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl; +typedef struct BindProtocol BindProtocol; + +struct _task_header_t; + +typedef void (*task_proc_t)(BindProtocol*,struct _task_header_t*); + +typedef struct _task_header_t { + task_proc_t proc; + struct _task_header_t *next; +} task_header_t; + +struct BindProtocol { + const IInternetProtocolVtbl *lpIInternetProtocolVtbl; + const IInternetBindInfoVtbl *lpInternetBindInfoVtbl; + const IInternetPriorityVtbl *lpInternetPriorityVtbl; + const IServiceProviderVtbl *lpServiceProviderVtbl; + const IInternetProtocolSinkVtbl *lpIInternetProtocolSinkVtbl; + + const IInternetProtocolVtbl *lpIInternetProtocolHandlerVtbl; LONG ref; IInternetProtocol *protocol; + IInternetProtocol *protocol_handler; IInternetBindInfo *bind_info; IInternetProtocolSink *protocol_sink; IServiceProvider *service_provider; @@ -39,16 +53,240 @@ typedef struct { LONG priority; BOOL reported_result; + BOOL reported_mime; BOOL from_urlmon; -} BindProtocol; + DWORD pi; + + DWORD apartment_thread; + HWND notif_hwnd; + DWORD continue_call; + + CRITICAL_SECTION section; + task_header_t *task_queue_head, *task_queue_tail; + + BYTE *buf; + DWORD buf_size; + LPWSTR mime; + LPWSTR url; + ProtocolProxy *filter_proxy; +}; -#define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl) #define BINDINFO(x) ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl) #define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl) #define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl) -#define PROTSINK(x) ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl) -#define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocol, iface) +#define PROTOCOLHANDLER(x) ((IInternetProtocol*) &(x)->lpIInternetProtocolHandlerVtbl) + +#define BUFFER_SIZE 2048 +#define MIME_TEST_SIZE 255 + +#define WM_MK_CONTINUE (WM_USER+101) +#define WM_MK_RELEASE (WM_USER+102) + +static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) { + case WM_MK_CONTINUE: { + BindProtocol *This = (BindProtocol*)lParam; + task_header_t *task; + + while(1) { + EnterCriticalSection(&This->section); + + task = This->task_queue_head; + if(task) { + This->task_queue_head = task->next; + if(!This->task_queue_head) + This->task_queue_tail = NULL; + } + + LeaveCriticalSection(&This->section); + + if(!task) + break; + + This->continue_call++; + task->proc(This, task); + This->continue_call--; + } + + IInternetProtocol_Release(PROTOCOL(This)); + return 0; + } + case WM_MK_RELEASE: { + tls_data_t *data = get_tls_data(); + + if(!--data->notif_hwnd_cnt) { + DestroyWindow(hwnd); + data->notif_hwnd = NULL; + } + } + } + + return DefWindowProcW(hwnd, msg, wParam, lParam); +} + +HWND get_notif_hwnd(void) +{ + static ATOM wnd_class = 0; + tls_data_t *tls_data; + + static const WCHAR wszURLMonikerNotificationWindow[] = + {'U','R','L',' ','M','o','n','i','k','e','r',' ', + 'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0}; + + tls_data = get_tls_data(); + if(!tls_data) + return NULL; + + if(tls_data->notif_hwnd_cnt) { + tls_data->notif_hwnd_cnt++; + return tls_data->notif_hwnd; + } + + if(!wnd_class) { + static WNDCLASSEXW wndclass = { + sizeof(wndclass), 0, + notif_wnd_proc, 0, 0, + NULL, NULL, NULL, NULL, NULL, + wszURLMonikerNotificationWindow, + NULL + }; + + wndclass.hInstance = URLMON_hInstance; + + wnd_class = RegisterClassExW(&wndclass); + if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS) + wnd_class = 1; + } + + tls_data->notif_hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow, + wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE, + NULL, URLMON_hInstance, NULL); + if(tls_data->notif_hwnd) + tls_data->notif_hwnd_cnt++; + + TRACE("hwnd = %p\n", tls_data->notif_hwnd); + + return tls_data->notif_hwnd; +} + +void release_notif_hwnd(HWND hwnd) +{ + tls_data_t *data = get_tls_data(); + + if(!data) + return; + + if(data->notif_hwnd != hwnd) { + PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0); + return; + } + + if(!--data->notif_hwnd_cnt) { + DestroyWindow(data->notif_hwnd); + data->notif_hwnd = NULL; + } +} + +static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc) +{ + BOOL do_post = FALSE; + + task->proc = proc; + task->next = NULL; + + EnterCriticalSection(&This->section); + + if(This->task_queue_tail) { + This->task_queue_tail->next = task; + This->task_queue_tail = task; + }else { + This->task_queue_tail = This->task_queue_head = task; + do_post = TRUE; + } + + LeaveCriticalSection(&This->section); + + if(do_post) { + IInternetProtocol_AddRef(PROTOCOL(This)); + PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This); + } +} + +static inline BOOL do_direct_notif(BindProtocol *This) +{ + return !(This->pi & PI_APARTMENTTHREADED) || (This->apartment_thread == GetCurrentThreadId() && !This->continue_call); +} + +static HRESULT handle_mime_filter(BindProtocol *This, IInternetProtocol *mime_filter, LPCWSTR mime) +{ + PROTOCOLFILTERDATA filter_data = { sizeof(PROTOCOLFILTERDATA), NULL, NULL, NULL, 0 }; + IInternetProtocolSink *protocol_sink, *old_sink; + ProtocolProxy *filter_proxy; + HRESULT hres; + + hres = IInternetProtocol_QueryInterface(mime_filter, &IID_IInternetProtocolSink, (void**)&protocol_sink); + if(FAILED(hres)) + return hres; + + hres = create_protocol_proxy(PROTOCOLHANDLER(This), This->protocol_sink, &filter_proxy); + if(FAILED(hres)) { + IInternetProtocolSink_Release(protocol_sink); + return hres; + } + + old_sink = This->protocol_sink; + This->protocol_sink = protocol_sink; + This->filter_proxy = filter_proxy; + + IInternetProtocol_AddRef(mime_filter); + This->protocol_handler = mime_filter; + + filter_data.pProtocol = PROTOCOL(filter_proxy); + hres = IInternetProtocol_Start(mime_filter, mime, PROTSINK(filter_proxy), BINDINFO(This), + PI_FILTER_MODE|PI_FORCE_ASYNC, (HANDLE_PTR)&filter_data); + if(FAILED(hres)) { + IInternetProtocolSink_Release(old_sink); + return hres; + } + + IInternetProtocolSink_ReportProgress(old_sink, BINDSTATUS_LOADINGMIMEHANDLER, NULL); + IInternetProtocolSink_Release(old_sink); + + This->pi &= ~PI_MIMEVERIFICATION; /* FIXME: more tests */ + return S_OK; +} + +static void mime_available(BindProtocol *This, LPCWSTR mime, BOOL verified) +{ + IInternetProtocol *mime_filter; + HRESULT hres; + + heap_free(This->mime); + This->mime = NULL; + + mime_filter = get_mime_filter(mime); + if(mime_filter) { + TRACE("Got mime filter for %s\n", debugstr_w(mime)); + + hres = handle_mime_filter(This, mime_filter, mime); + IInternetProtocol_Release(mime_filter); + if(FAILED(hres)) + FIXME("MIME filter failed: %08x\n", hres); + }else { + This->mime = heap_strdupW(mime); + + if(verified || !(This->pi & PI_MIMEVERIFICATION)) { + This->reported_mime = TRUE; + + if(This->protocol_sink) + IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime); + } + } +} + +#define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocol, iface) static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) { @@ -111,8 +349,19 @@ static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface) IInternetProtocol_Release(This->protocol); if(This->bind_info) IInternetBindInfo_Release(This->bind_info); + if(This->protocol_handler && This->protocol_handler != PROTOCOLHANDLER(This)) + IInternetProtocol_Release(This->protocol_handler); + if(This->filter_proxy) + IInternetProtocol_Release(PROTOCOL(This->filter_proxy)); set_binding_sink(PROTOCOL(This), NULL); + + if(This->notif_hwnd) + release_notif_hwnd(This->notif_hwnd); + DeleteCriticalSection(&This->section); + + heap_free(This->mime); + heap_free(This->url); heap_free(This); URLMON_UnlockModule(); @@ -126,6 +375,160 @@ static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl DWORD grfPI, HANDLE_PTR dwReserved) { BindProtocol *This = PROTOCOL_THIS(iface); + + TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink, + pOIBindInfo, grfPI, dwReserved); + + return IInternetProtocol_Start(This->protocol_handler, szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved); +} + +static HRESULT WINAPI BindProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData) +{ + BindProtocol *This = PROTOCOL_THIS(iface); + + TRACE("(%p)->(%p)\n", This, pProtocolData); + + return IInternetProtocol_Continue(This->protocol_handler, pProtocolData); +} + +static HRESULT WINAPI BindProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason, + DWORD dwOptions) +{ + BindProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions); + return E_NOTIMPL; +} + +static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions) +{ + BindProtocol *This = PROTOCOL_THIS(iface); + + TRACE("(%p)->(%08x)\n", This, dwOptions); + + return IInternetProtocol_Terminate(This->protocol_handler, dwOptions); +} + +static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocol *iface) +{ + BindProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI BindProtocol_Resume(IInternetProtocol *iface) +{ + BindProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI BindProtocol_Read(IInternetProtocol *iface, void *pv, + ULONG cb, ULONG *pcbRead) +{ + BindProtocol *This = PROTOCOL_THIS(iface); + + TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); + + if(pcbRead) + *pcbRead = 0; + return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead); +} + +static HRESULT WINAPI BindProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove, + DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) +{ + BindProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); + return E_NOTIMPL; +} + +static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions) +{ + BindProtocol *This = PROTOCOL_THIS(iface); + + TRACE("(%p)->(%08x)\n", This, dwOptions); + + return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions); +} + +static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface) +{ + BindProtocol *This = PROTOCOL_THIS(iface); + + TRACE("(%p)\n", This); + + return IInternetProtocol_UnlockRequest(This->protocol_handler); +} + +void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink) +{ + BindProtocol *This = PROTOCOL_THIS(bind_protocol); + IInternetProtocolSink *prev_sink; + IServiceProvider *service_provider = NULL; + + if(sink) + IInternetProtocolSink_AddRef(sink); + prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink); + if(prev_sink) + IInternetProtocolSink_Release(prev_sink); + + if(sink) + IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider); + service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider); + if(service_provider) + IServiceProvider_Release(service_provider); +} + +IWinInetInfo *get_wininet_info(IInternetProtocol *bind_protocol) +{ + BindProtocol *This = PROTOCOL_THIS(bind_protocol); + + return This->wininet_info; +} + +#undef PROTOCOL_THIS + +static const IInternetProtocolVtbl BindProtocolVtbl = { + BindProtocol_QueryInterface, + BindProtocol_AddRef, + BindProtocol_Release, + BindProtocol_Start, + BindProtocol_Continue, + BindProtocol_Abort, + BindProtocol_Terminate, + BindProtocol_Suspend, + BindProtocol_Resume, + BindProtocol_Read, + BindProtocol_Seek, + BindProtocol_LockRequest, + BindProtocol_UnlockRequest +}; + +#define PROTOCOLHANDLER_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocolHandler, iface) + +static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) +{ + ERR("should not be called\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface) +{ + BindProtocol *This = PROTOCOLHANDLER_THIS(iface); + return IInternetProtocol_AddRef(PROTOCOL(This)); +} + +static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface) +{ + BindProtocol *This = PROTOCOLHANDLER_THIS(iface); + return IInternetProtocol_Release(PROTOCOL(This)); +} + +static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl, + IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, + DWORD grfPI, HANDLE_PTR dwReserved) +{ + BindProtocol *This = PROTOCOLHANDLER_THIS(iface); IInternetProtocol *protocol = NULL; IInternetPriority *priority; IServiceProvider *service_provider; @@ -140,6 +543,9 @@ static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl if(!szUrl || !pOIProtSink || !pOIBindInfo) return E_INVALIDARG; + This->pi = grfPI; + This->url = heap_strdupW(szUrl); + hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider, (void**)&service_provider); if(SUCCEEDED(hres)) { @@ -199,26 +605,26 @@ static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl return IInternetProtocol_Start(protocol, szUrl, PROTSINK(This), BINDINFO(This), 0, 0); } -static HRESULT WINAPI BindProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData) +static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData) { - BindProtocol *This = PROTOCOL_THIS(iface); + BindProtocol *This = PROTOCOLHANDLER_THIS(iface); TRACE("(%p)->(%p)\n", This, pProtocolData); return IInternetProtocol_Continue(This->protocol, pProtocolData); } -static HRESULT WINAPI BindProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason, +static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason, DWORD dwOptions) { - BindProtocol *This = PROTOCOL_THIS(iface); + BindProtocol *This = PROTOCOLHANDLER_THIS(iface); FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions); return E_NOTIMPL; } -static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions) +static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions) { - BindProtocol *This = PROTOCOL_THIS(iface); + BindProtocol *This = PROTOCOLHANDLER_THIS(iface); TRACE("(%p)->(%08x)\n", This, dwOptions); @@ -227,6 +633,11 @@ static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwO IInternetProtocol_Terminate(This->protocol, 0); + if(This->filter_proxy) { + IInternetProtocol_Release(PROTOCOL(This->filter_proxy)); + This->filter_proxy = NULL; + } + set_binding_sink(PROTOCOL(This), NULL); if(This->bind_info) { @@ -237,103 +648,96 @@ static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwO return S_OK; } -static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocol *iface) +static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface) { - BindProtocol *This = PROTOCOL_THIS(iface); + BindProtocol *This = PROTOCOLHANDLER_THIS(iface); FIXME("(%p)\n", This); return E_NOTIMPL; } -static HRESULT WINAPI BindProtocol_Resume(IInternetProtocol *iface) +static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface) { - BindProtocol *This = PROTOCOL_THIS(iface); + BindProtocol *This = PROTOCOLHANDLER_THIS(iface); FIXME("(%p)\n", This); return E_NOTIMPL; } -static HRESULT WINAPI BindProtocol_Read(IInternetProtocol *iface, void *pv, +static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv, ULONG cb, ULONG *pcbRead) { - BindProtocol *This = PROTOCOL_THIS(iface); + BindProtocol *This = PROTOCOLHANDLER_THIS(iface); ULONG read = 0; - HRESULT hres; + HRESULT hres = S_OK; TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); - hres = IInternetProtocol_Read(This->protocol, pv, cb, &read); + if(This->buf) { + read = min(cb, This->buf_size); + memcpy(pv, This->buf, read); + + if(read == This->buf_size) { + heap_free(This->buf); + This->buf = NULL; + }else { + memmove(This->buf, This->buf+cb, This->buf_size-cb); + } + + This->buf_size -= read; + } + + if(read < cb) { + ULONG cread = 0; + + hres = IInternetProtocol_Read(This->protocol, (BYTE*)pv+read, cb-read, &cread); + read += cread; + } *pcbRead = read; return hres; } -static HRESULT WINAPI BindProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove, +static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) { - BindProtocol *This = PROTOCOL_THIS(iface); + BindProtocol *This = PROTOCOLHANDLER_THIS(iface); FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); return E_NOTIMPL; } -static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions) +static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions) { - BindProtocol *This = PROTOCOL_THIS(iface); + BindProtocol *This = PROTOCOLHANDLER_THIS(iface); TRACE("(%p)->(%08x)\n", This, dwOptions); return IInternetProtocol_LockRequest(This->protocol, dwOptions); } -static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface) +static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface) { - BindProtocol *This = PROTOCOL_THIS(iface); + BindProtocol *This = PROTOCOLHANDLER_THIS(iface); TRACE("(%p)\n", This); return IInternetProtocol_UnlockRequest(This->protocol); } -void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink) -{ - BindProtocol *This = PROTOCOL_THIS(bind_protocol); - IInternetProtocolSink *prev_sink; - IServiceProvider *service_provider = NULL; - - if(sink) - IInternetProtocolSink_AddRef(sink); - prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink); - if(prev_sink) - IInternetProtocolSink_Release(prev_sink); - - if(sink) - IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider); - service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider); - if(service_provider) - IServiceProvider_Release(service_provider); -} - -IWinInetInfo *get_wininet_info(IInternetProtocol *bind_protocol) -{ - BindProtocol *This = PROTOCOL_THIS(bind_protocol); - - return This->wininet_info; -} - #undef PROTOCOL_THIS -static const IInternetProtocolVtbl BindProtocolVtbl = { - BindProtocol_QueryInterface, - BindProtocol_AddRef, - BindProtocol_Release, - BindProtocol_Start, - BindProtocol_Continue, - BindProtocol_Abort, - BindProtocol_Terminate, - BindProtocol_Suspend, - BindProtocol_Resume, - BindProtocol_Read, - BindProtocol_Seek, - BindProtocol_LockRequest, - BindProtocol_UnlockRequest +static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = { + ProtocolHandler_QueryInterface, + ProtocolHandler_AddRef, + ProtocolHandler_Release, + ProtocolHandler_Start, + ProtocolHandler_Continue, + ProtocolHandler_Abort, + ProtocolHandler_Terminate, + ProtocolHandler_Suspend, + ProtocolHandler_Resume, + ProtocolHandler_Read, + ProtocolHandler_Seek, + ProtocolHandler_LockRequest, + ProtocolHandler_UnlockRequest }; #define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface) @@ -447,7 +851,7 @@ static const IInternetPriorityVtbl InternetPriorityVtbl = { }; -#define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocolSink, iface) +#define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, IInternetProtocolSink, iface) static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface, REFIID riid, void **ppv) @@ -468,6 +872,20 @@ static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface) return IInternetProtocol_Release(PROTOCOL(This)); } +typedef struct { + task_header_t header; + PROTOCOLDATA data; +} switch_task_t; + +static void switch_proc(BindProtocol *bind, task_header_t *t) +{ + switch_task_t *task = (switch_task_t*)t; + + IInternetProtocol_Continue(bind->protocol_handler, &task->data); + + heap_free(task); +} + static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOLDATA *pProtocolData) { @@ -478,14 +896,71 @@ static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState, pProtocolData->pData, pProtocolData->cbData); + if(!do_direct_notif(This)) { + switch_task_t *task; + + task = heap_alloc(sizeof(switch_task_t)); + if(!task) + return E_OUTOFMEMORY; + + task->data = *pProtocolData; + + push_task(This, &task->header, switch_proc); + return S_OK; + } + if(!This->protocol_sink) { - IInternetProtocol_Continue(This->protocol, pProtocolData); + IInternetProtocol_Continue(This->protocol_handler, pProtocolData); return S_OK; } return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData); } +static void report_progress(BindProtocol *This, ULONG status_code, LPCWSTR status_text) +{ + switch(status_code) { + case BINDSTATUS_FINDINGRESOURCE: + case BINDSTATUS_CONNECTING: + case BINDSTATUS_BEGINDOWNLOADDATA: + case BINDSTATUS_SENDINGREQUEST: + case BINDSTATUS_CACHEFILENAMEAVAILABLE: + case BINDSTATUS_DIRECTBIND: + case BINDSTATUS_ACCEPTRANGES: + if(This->protocol_sink) + IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text); + break; + + case BINDSTATUS_MIMETYPEAVAILABLE: + mime_available(This, status_text, FALSE); + break; + + case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE: + mime_available(This, status_text, TRUE); + break; + + default: + FIXME("unsupported ulStatusCode %u\n", status_code); + } +} + +typedef struct { + task_header_t header; + + ULONG status_code; + LPWSTR status_text; +} on_progress_task_t; + +static void on_progress_proc(BindProtocol *This, task_header_t *t) +{ + on_progress_task_t *task = (on_progress_task_t*)t; + + report_progress(This, task->status_code, task->status_text); + + heap_free(task->status_text); + heap_free(task); +} + static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface, ULONG ulStatusCode, LPCWSTR szStatusText) { @@ -493,31 +968,75 @@ static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSin TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText)); - switch(ulStatusCode) { - case BINDSTATUS_FINDINGRESOURCE: - case BINDSTATUS_CONNECTING: - case BINDSTATUS_BEGINDOWNLOADDATA: - case BINDSTATUS_SENDINGREQUEST: - case BINDSTATUS_CACHEFILENAMEAVAILABLE: - case BINDSTATUS_DIRECTBIND: - case BINDSTATUS_ACCEPTRANGES: - case BINDSTATUS_MIMETYPEAVAILABLE: - if(!This->protocol_sink) - return S_OK; - return IInternetProtocolSink_ReportProgress(This->protocol_sink, - ulStatusCode, szStatusText); + if(do_direct_notif(This)) { + report_progress(This, ulStatusCode, szStatusText); + }else { + on_progress_task_t *task; - case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE: - if(!This->protocol_sink) - return S_OK; - return IInternetProtocolSink_ReportProgress(This->protocol_sink, - This->from_urlmon ? BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE : BINDSTATUS_MIMETYPEAVAILABLE, - szStatusText); - default: - FIXME("unsupported ulStatusCode %u\n", ulStatusCode); + task = heap_alloc(sizeof(on_progress_task_t)); + + task->status_code = ulStatusCode; + task->status_text = heap_strdupW(szStatusText); + + push_task(This, &task->header, on_progress_proc); } - return E_NOTIMPL; + return S_OK; +} + +static HRESULT report_data(BindProtocol *This, DWORD bscf, ULONG progress, ULONG progress_max) +{ + if(!This->protocol_sink) + return S_OK; + + if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) { + DWORD read = 0; + LPWSTR mime; + HRESULT hres; + + if(!This->buf) { + This->buf = heap_alloc(BUFFER_SIZE); + if(!This->buf) + return E_OUTOFMEMORY; + } + + do { + read = 0; + hres = IInternetProtocol_Read(This->protocol, This->buf+This->buf_size, + BUFFER_SIZE-This->buf_size, &read); + if(FAILED(hres) && hres != E_PENDING) + return hres; + This->buf_size += read; + }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK); + + if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE) + return S_OK; + + hres = FindMimeFromData(NULL, This->url, This->buf, min(This->buf_size, MIME_TEST_SIZE), + This->mime, 0, &mime, 0); + if(FAILED(hres)) + return hres; + + mime_available(This, mime, TRUE); + CoTaskMemFree(mime); + } + + return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max); +} + +typedef struct { + task_header_t header; + DWORD bscf; + ULONG progress; + ULONG progress_max; +} report_data_task_t; + +static void report_data_proc(BindProtocol *This, task_header_t *t) +{ + report_data_task_t *task = (report_data_task_t*)t; + + report_data(This, task->bscf, task->progress, task->progress_max); + heap_free(task); } static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface, @@ -530,7 +1049,41 @@ static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *i if(!This->protocol_sink) return S_OK; - return IInternetProtocolSink_ReportData(This->protocol_sink, grfBSCF, ulProgress, ulProgressMax); + if(!do_direct_notif(This)) { + report_data_task_t *task; + + task = heap_alloc(sizeof(report_data_task_t)); + if(!task) + return E_OUTOFMEMORY; + + task->bscf = grfBSCF; + task->progress = ulProgress; + task->progress_max = ulProgressMax; + + push_task(This, &task->header, report_data_proc); + return S_OK; + } + + return report_data(This, grfBSCF, ulProgress, ulProgressMax); +} + +typedef struct { + task_header_t header; + + HRESULT hres; + DWORD err; + LPWSTR str; +} report_result_task_t; + +static void report_result_proc(BindProtocol *This, task_header_t *t) +{ + report_result_task_t *task = (report_result_task_t*)t; + + if(This->protocol_sink) + IInternetProtocolSink_ReportResult(This->protocol_sink, task->hres, task->err, task->str); + + heap_free(task->str); + heap_free(task); } static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface, @@ -545,6 +1098,21 @@ static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink This->reported_result = TRUE; + if(!do_direct_notif(This)) { + report_result_task_t *task; + + task = heap_alloc(sizeof(report_result_task_t)); + if(!task) + return E_OUTOFMEMORY; + + task->hres = hrResult; + task->err = dwError; + task->str = heap_strdupW(szResult); + + push_task(This, &task->header, report_result_proc); + return S_OK; + } + return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult); } @@ -607,14 +1175,19 @@ HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol { BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol)); - ret->lpInternetProtocolVtbl = &BindProtocolVtbl; - ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl; - ret->lpInternetPriorityVtbl = &InternetPriorityVtbl; - ret->lpServiceProviderVtbl = &ServiceProviderVtbl; - ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl; + ret->lpIInternetProtocolVtbl = &BindProtocolVtbl; + ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl; + ret->lpInternetPriorityVtbl = &InternetPriorityVtbl; + ret->lpServiceProviderVtbl = &ServiceProviderVtbl; + ret->lpIInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl; + ret->lpIInternetProtocolHandlerVtbl = &InternetProtocolHandlerVtbl; ret->ref = 1; ret->from_urlmon = from_urlmon; + ret->apartment_thread = GetCurrentThreadId(); + ret->notif_hwnd = get_notif_hwnd(); + ret->protocol_handler = PROTOCOLHANDLER(ret); + InitializeCriticalSection(&ret->section); URLMON_LockModule(); diff --git a/reactos/dll/win32/urlmon/file.c b/reactos/dll/win32/urlmon/file.c index 1e3db1681ee..ed4802b8a3b 100644 --- a/reactos/dll/win32/urlmon/file.c +++ b/reactos/dll/win32/urlmon/file.c @@ -22,7 +22,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(urlmon); typedef struct { - const IInternetProtocolVtbl *lpInternetProtocolVtbl; + const IInternetProtocolVtbl *lpIInternetProtocolVtbl; const IInternetPriorityVtbl *lpInternetPriorityVtbl; HANDLE file; @@ -31,10 +31,9 @@ typedef struct { LONG ref; } FileProtocol; -#define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl) #define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl) -#define PROTOCOL_THIS(iface) DEFINE_THIS(FileProtocol, InternetProtocol, iface) +#define PROTOCOL_THIS(iface) DEFINE_THIS(FileProtocol, IInternetProtocol, iface) static HRESULT WINAPI FileProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) { @@ -360,7 +359,7 @@ HRESULT FileProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj) ret = heap_alloc(sizeof(FileProtocol)); - ret->lpInternetProtocolVtbl = &FileProtocolVtbl; + ret->lpIInternetProtocolVtbl = &FileProtocolVtbl; ret->lpInternetPriorityVtbl = &FilePriorityVtbl; ret->file = NULL; ret->priority = 0; diff --git a/reactos/dll/win32/urlmon/ftp.c b/reactos/dll/win32/urlmon/ftp.c index c6789e583c3..c27e7008733 100644 --- a/reactos/dll/win32/urlmon/ftp.c +++ b/reactos/dll/win32/urlmon/ftp.c @@ -24,14 +24,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(urlmon); typedef struct { Protocol base; - const IInternetProtocolVtbl *lpInternetProtocolVtbl; + const IInternetProtocolVtbl *lpIInternetProtocolVtbl; const IInternetPriorityVtbl *lpInternetPriorityVtbl; const IWinInetHttpInfoVtbl *lpWinInetHttpInfoVtbl; LONG ref; } FtpProtocol; -#define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl) #define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl) #define INETHTTPINFO(x) ((IWinInetHttpInfo*) &(x)->lpWinInetHttpInfoVtbl) @@ -80,7 +79,7 @@ static const ProtocolVtbl AsyncProtocolVtbl = { FtpProtocol_close_connection }; -#define PROTOCOL_THIS(iface) DEFINE_THIS(FtpProtocol, InternetProtocol, iface) +#define PROTOCOL_THIS(iface) DEFINE_THIS(FtpProtocol, IInternetProtocol, iface) static HRESULT WINAPI FtpProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) { @@ -360,9 +359,9 @@ HRESULT FtpProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj) ret = heap_alloc_zero(sizeof(FtpProtocol)); ret->base.vtbl = &AsyncProtocolVtbl; - ret->lpInternetProtocolVtbl = &FtpProtocolVtbl; - ret->lpInternetPriorityVtbl = &FtpPriorityVtbl; - ret->lpWinInetHttpInfoVtbl = &WinInetHttpInfoVtbl; + ret->lpIInternetProtocolVtbl = &FtpProtocolVtbl; + ret->lpInternetPriorityVtbl = &FtpPriorityVtbl; + ret->lpWinInetHttpInfoVtbl = &WinInetHttpInfoVtbl; ret->ref = 1; *ppobj = PROTOCOL(ret); diff --git a/reactos/dll/win32/urlmon/gopher.c b/reactos/dll/win32/urlmon/gopher.c index f2abcddc8ed..fa5c14cf9ed 100644 --- a/reactos/dll/win32/urlmon/gopher.c +++ b/reactos/dll/win32/urlmon/gopher.c @@ -24,13 +24,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(urlmon); typedef struct { Protocol base; - const IInternetProtocolVtbl *lpInternetProtocolVtbl; + const IInternetProtocolVtbl *lpIInternetProtocolVtbl; const IInternetPriorityVtbl *lpInternetPriorityVtbl; LONG ref; } GopherProtocol; -#define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl) #define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl) #define ASYNCPROTOCOL_THIS(iface) DEFINE_THIS2(GopherProtocol, base, iface) @@ -67,7 +66,7 @@ static const ProtocolVtbl AsyncProtocolVtbl = { GopherProtocol_close_connection }; -#define PROTOCOL_THIS(iface) DEFINE_THIS(GopherProtocol, InternetProtocol, iface) +#define PROTOCOL_THIS(iface) DEFINE_THIS(GopherProtocol, IInternetProtocol, iface) static HRESULT WINAPI GopherProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) { @@ -289,8 +288,8 @@ HRESULT GopherProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj) ret = heap_alloc_zero(sizeof(GopherProtocol)); ret->base.vtbl = &AsyncProtocolVtbl; - ret->lpInternetProtocolVtbl = &GopherProtocolVtbl; - ret->lpInternetPriorityVtbl = &GopherPriorityVtbl; + ret->lpIInternetProtocolVtbl = &GopherProtocolVtbl; + ret->lpInternetPriorityVtbl = &GopherPriorityVtbl; ret->ref = 1; *ppobj = PROTOCOL(ret); diff --git a/reactos/dll/win32/urlmon/http.c b/reactos/dll/win32/urlmon/http.c index 9c11d4104c2..272b338779c 100644 --- a/reactos/dll/win32/urlmon/http.c +++ b/reactos/dll/win32/urlmon/http.c @@ -32,7 +32,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(urlmon); typedef struct { Protocol base; - const IInternetProtocolVtbl *lpInternetProtocolVtbl; + const IInternetProtocolVtbl *lpIInternetProtocolVtbl; const IInternetPriorityVtbl *lpInternetPriorityVtbl; const IWinInetHttpInfoVtbl *lpWinInetHttpInfoVtbl; @@ -43,7 +43,6 @@ typedef struct { LONG ref; } HttpProtocol; -#define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl) #define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl) #define INETHTTPINFO(x) ((IWinInetHttpInfo*) &(x)->lpWinInetHttpInfoVtbl) @@ -309,7 +308,7 @@ static const ProtocolVtbl AsyncProtocolVtbl = { HttpProtocol_close_connection }; -#define PROTOCOL_THIS(iface) DEFINE_THIS(HttpProtocol, InternetProtocol, iface) +#define PROTOCOL_THIS(iface) DEFINE_THIS(HttpProtocol, IInternetProtocol, iface) static HRESULT WINAPI HttpProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) { @@ -590,9 +589,9 @@ static HRESULT create_http_protocol(BOOL https, void **ppobj) return E_OUTOFMEMORY; ret->base.vtbl = &AsyncProtocolVtbl; - ret->lpInternetProtocolVtbl = &HttpProtocolVtbl; - ret->lpInternetPriorityVtbl = &HttpPriorityVtbl; - ret->lpWinInetHttpInfoVtbl = &WinInetHttpInfoVtbl; + ret->lpIInternetProtocolVtbl = &HttpProtocolVtbl; + ret->lpInternetPriorityVtbl = &HttpPriorityVtbl; + ret->lpWinInetHttpInfoVtbl = &WinInetHttpInfoVtbl; ret->https = https; ret->ref = 1; diff --git a/reactos/dll/win32/urlmon/mk.c b/reactos/dll/win32/urlmon/mk.c index 934eeda8ef7..0befe5c34c6 100644 --- a/reactos/dll/win32/urlmon/mk.c +++ b/reactos/dll/win32/urlmon/mk.c @@ -22,16 +22,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(urlmon); typedef struct { - const IInternetProtocolVtbl *lpInternetProtocolVtbl; + const IInternetProtocolVtbl *lpIInternetProtocolVtbl; LONG ref; IStream *stream; } MkProtocol; -#define PROTOCOL_THIS(iface) DEFINE_THIS(MkProtocol, InternetProtocol, iface) - -#define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl) +#define PROTOCOL_THIS(iface) DEFINE_THIS(MkProtocol, IInternetProtocol, iface) static HRESULT WINAPI MkProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) { @@ -293,7 +291,7 @@ HRESULT MkProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj) ret = heap_alloc(sizeof(MkProtocol)); - ret->lpInternetProtocolVtbl = &MkProtocolVtbl; + ret->lpIInternetProtocolVtbl = &MkProtocolVtbl; ret->ref = 1; ret->stream = NULL; diff --git a/reactos/dll/win32/urlmon/protproxy.c b/reactos/dll/win32/urlmon/protproxy.c new file mode 100644 index 00000000000..c3d64c48221 --- /dev/null +++ b/reactos/dll/win32/urlmon/protproxy.c @@ -0,0 +1,290 @@ +/* + * Copyright 2009 Jacek Caban for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "urlmon_main.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(urlmon); + +#define PROTOCOL_THIS(iface) DEFINE_THIS(ProtocolProxy, IInternetProtocol, iface) + +static HRESULT WINAPI ProtocolProxy_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) +{ + ProtocolProxy *This = PROTOCOL_THIS(iface); + + *ppv = NULL; + if(IsEqualGUID(&IID_IUnknown, riid)) { + TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); + *ppv = PROTOCOL(This); + }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) { + TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv); + *ppv = PROTOCOL(This); + }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) { + TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv); + *ppv = PROTOCOL(This); + }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) { + TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv); + *ppv = PROTSINK(This); + } + + if(*ppv) { + IInternetProtocol_AddRef(iface); + return S_OK; + } + + WARN("not supported interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI ProtocolProxy_AddRef(IInternetProtocol *iface) +{ + ProtocolProxy *This = PROTOCOL_THIS(iface); + LONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p) ref=%d\n", This, ref); + return ref; +} + +static ULONG WINAPI ProtocolProxy_Release(IInternetProtocol *iface) +{ + ProtocolProxy *This = PROTOCOL_THIS(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + if(!ref) { + if(This->protocol_sink) + IInternetProtocolSink_Release(This->protocol_sink); + if(This->protocol) + IInternetProtocol_Release(This->protocol); + + heap_free(This); + + URLMON_UnlockModule(); + } + + return ref; +} + +static HRESULT WINAPI ProtocolProxy_Start(IInternetProtocol *iface, LPCWSTR szUrl, + IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, + DWORD grfPI, HANDLE_PTR dwReserved) +{ + ProtocolProxy *This = PROTOCOL_THIS(iface); + + TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink, + pOIBindInfo, grfPI, dwReserved); + + return IInternetProtocol_Start(This->protocol, szUrl, pOIProtSink, pOIBindInfo, grfPI, dwReserved); +} + +static HRESULT WINAPI ProtocolProxy_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData) +{ + ProtocolProxy *This = PROTOCOL_THIS(iface); + + TRACE("(%p)->(%p)\n", This, pProtocolData); + + return IInternetProtocol_Continue(This->protocol, pProtocolData); +} + +static HRESULT WINAPI ProtocolProxy_Abort(IInternetProtocol *iface, HRESULT hrReason, + DWORD dwOptions) +{ + ProtocolProxy *This = PROTOCOL_THIS(iface); + FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions); + return E_NOTIMPL; +} + +static HRESULT WINAPI ProtocolProxy_Terminate(IInternetProtocol *iface, DWORD dwOptions) +{ + ProtocolProxy *This = PROTOCOL_THIS(iface); + + TRACE("(%p)->(%08x)\n", This, dwOptions); + + return IInternetProtocol_Terminate(This->protocol, dwOptions); +} + +static HRESULT WINAPI ProtocolProxy_Suspend(IInternetProtocol *iface) +{ + ProtocolProxy *This = PROTOCOL_THIS(iface); + FIXME("(%p)\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI ProtocolProxy_Resume(IInternetProtocol *iface) +{ + ProtocolProxy *This = PROTOCOL_THIS(iface); + FIXME("(%p)\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI ProtocolProxy_Read(IInternetProtocol *iface, void *pv, + ULONG cb, ULONG *pcbRead) +{ + ProtocolProxy *This = PROTOCOL_THIS(iface); + + TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); + + return IInternetProtocol_Read(This->protocol, pv, cb, pcbRead); +} + +static HRESULT WINAPI ProtocolProxy_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove, + DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) +{ + ProtocolProxy *This = PROTOCOL_THIS(iface); + FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); + return E_NOTIMPL; +} + +static HRESULT WINAPI ProtocolProxy_LockRequest(IInternetProtocol *iface, DWORD dwOptions) +{ + ProtocolProxy *This = PROTOCOL_THIS(iface); + + TRACE("(%p)->(%08x)\n", This, dwOptions); + + return IInternetProtocol_LockRequest(This->protocol, dwOptions); +} + +static HRESULT WINAPI ProtocolProxy_UnlockRequest(IInternetProtocol *iface) +{ + ProtocolProxy *This = PROTOCOL_THIS(iface); + + TRACE("(%p)\n", This); + + return IInternetProtocol_UnlockRequest(This->protocol); +} + +#undef PROTOCOL_THIS + +static const IInternetProtocolVtbl ProtocolProxyVtbl = { + ProtocolProxy_QueryInterface, + ProtocolProxy_AddRef, + ProtocolProxy_Release, + ProtocolProxy_Start, + ProtocolProxy_Continue, + ProtocolProxy_Abort, + ProtocolProxy_Terminate, + ProtocolProxy_Suspend, + ProtocolProxy_Resume, + ProtocolProxy_Read, + ProtocolProxy_Seek, + ProtocolProxy_LockRequest, + ProtocolProxy_UnlockRequest +}; + +#define PROTSINK_THIS(iface) DEFINE_THIS(ProtocolProxy, IInternetProtocolSink, iface) + +static HRESULT WINAPI ProtocolProxySink_QueryInterface(IInternetProtocolSink *iface, + REFIID riid, void **ppv) +{ + ProtocolProxy *This = PROTSINK_THIS(iface); + return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv); +} + +static ULONG WINAPI ProtocolProxySink_AddRef(IInternetProtocolSink *iface) +{ + ProtocolProxy *This = PROTSINK_THIS(iface); + return IInternetProtocol_AddRef(PROTOCOL(This)); +} + +static ULONG WINAPI ProtocolProxySink_Release(IInternetProtocolSink *iface) +{ + ProtocolProxy *This = PROTSINK_THIS(iface); + return IInternetProtocol_Release(PROTOCOL(This)); +} + +static HRESULT WINAPI ProtocolProxySink_Switch(IInternetProtocolSink *iface, + PROTOCOLDATA *pProtocolData) +{ + ProtocolProxy *This = PROTSINK_THIS(iface); + + TRACE("(%p)->(%p)\n", This, pProtocolData); + + return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData); +} + +static HRESULT WINAPI ProtocolProxySink_ReportProgress(IInternetProtocolSink *iface, + ULONG ulStatusCode, LPCWSTR szStatusText) +{ + ProtocolProxy *This = PROTSINK_THIS(iface); + + TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText)); + + switch(ulStatusCode) { + case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE: + IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, szStatusText); + break; + default: + IInternetProtocolSink_ReportProgress(This->protocol_sink, ulStatusCode, szStatusText); + } + + return S_OK; +} + +static HRESULT WINAPI ProtocolProxySink_ReportData(IInternetProtocolSink *iface, + DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax) +{ + ProtocolProxy *This = PROTSINK_THIS(iface); + + TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax); + + return IInternetProtocolSink_ReportData(This->protocol_sink, grfBSCF, ulProgress, ulProgressMax); +} + +static HRESULT WINAPI ProtocolProxySink_ReportResult(IInternetProtocolSink *iface, + HRESULT hrResult, DWORD dwError, LPCWSTR szResult) +{ + ProtocolProxy *This = PROTSINK_THIS(iface); + + TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult)); + + return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult); +} + +#undef PROTSINK_THIS + +static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = { + ProtocolProxySink_QueryInterface, + ProtocolProxySink_AddRef, + ProtocolProxySink_Release, + ProtocolProxySink_Switch, + ProtocolProxySink_ReportProgress, + ProtocolProxySink_ReportData, + ProtocolProxySink_ReportResult +}; + +HRESULT create_protocol_proxy(IInternetProtocol *protocol, IInternetProtocolSink *protocol_sink, ProtocolProxy **ret) +{ + ProtocolProxy *sink; + + sink = heap_alloc(sizeof(ProtocolProxy)); + if(!sink) + return E_OUTOFMEMORY; + + sink->lpIInternetProtocolVtbl = &ProtocolProxyVtbl; + sink->lpIInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl; + sink->ref = 1; + + IInternetProtocol_AddRef(protocol); + sink->protocol = protocol; + + IInternetProtocolSink_AddRef(protocol_sink); + sink->protocol_sink = protocol_sink; + + *ret = sink; + return S_OK; +} diff --git a/reactos/dll/win32/urlmon/session.c b/reactos/dll/win32/urlmon/session.c index 9cacde7ae91..933202c352d 100644 --- a/reactos/dll/win32/urlmon/session.c +++ b/reactos/dll/win32/urlmon/session.c @@ -264,6 +264,36 @@ HRESULT get_protocol_handler(LPCWSTR url, CLSID *clsid, BOOL *urlmon_protocol, I return get_protocol_cf(schema, schema_len, clsid, ret); } +IInternetProtocol *get_mime_filter(LPCWSTR mime) +{ + IClassFactory *cf = NULL; + IInternetProtocol *ret; + mime_filter *iter; + HRESULT hres; + + EnterCriticalSection(&session_cs); + + for(iter = mime_filter_list; iter; iter = iter->next) { + if(!strcmpW(iter->mime, mime)) { + cf = iter->cf; + break; + } + } + + LeaveCriticalSection(&session_cs); + + if(!cf) + return NULL; + + hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&ret); + if(FAILED(hres)) { + WARN("CreateInstance failed: %08x\n", hres); + return NULL; + } + + return ret; +} + static HRESULT WINAPI InternetSession_QueryInterface(IInternetSession *iface, REFIID riid, void **ppv) { diff --git a/reactos/dll/win32/urlmon/urlmon.rbuild b/reactos/dll/win32/urlmon/urlmon.rbuild index a9df130d3ab..fd15a7b0ab4 100644 --- a/reactos/dll/win32/urlmon/urlmon.rbuild +++ b/reactos/dll/win32/urlmon/urlmon.rbuild @@ -21,6 +21,7 @@ mimefilter.c mk.c protocol.c + protproxy.c regsvr.c sec_mgr.c session.c diff --git a/reactos/dll/win32/urlmon/urlmon_main.c b/reactos/dll/win32/urlmon/urlmon_main.c index 8561937643a..3203753f923 100644 --- a/reactos/dll/win32/urlmon/urlmon_main.c +++ b/reactos/dll/win32/urlmon/urlmon_main.c @@ -36,9 +36,88 @@ LONG URLMON_refCount = 0; HINSTANCE URLMON_hInstance = 0; static HMODULE hCabinet = NULL; +static DWORD urlmon_tls; static void init_session(BOOL); +static struct list tls_list = LIST_INIT(tls_list); + +static CRITICAL_SECTION tls_cs; +static CRITICAL_SECTION_DEBUG tls_cs_dbg = +{ + 0, 0, &tls_cs, + { &tls_cs_dbg.ProcessLocksList, &tls_cs_dbg.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": tls") } +}; + +static CRITICAL_SECTION tls_cs = { &tls_cs_dbg, -1, 0, 0, 0, 0 }; + +tls_data_t *get_tls_data(void) +{ + tls_data_t *data; + + if(!urlmon_tls) { + DWORD tls = TlsAlloc(); + tls = InterlockedCompareExchange((LONG*)&urlmon_tls, tls, 0); + if(tls != urlmon_tls) + TlsFree(tls); + } + + data = TlsGetValue(urlmon_tls); + if(!data) { + data = heap_alloc_zero(sizeof(tls_data_t)); + if(!data) + return NULL; + + EnterCriticalSection(&tls_cs); + list_add_tail(&tls_list, &data->entry); + LeaveCriticalSection(&tls_cs); + + TlsSetValue(urlmon_tls, data); + } + + return data; +} + +static void free_tls_list(void) +{ + tls_data_t *data; + + if(!urlmon_tls) + return; + + while(!list_empty(&tls_list)) { + data = LIST_ENTRY(list_head(&tls_list), tls_data_t, entry); + list_remove(&data->entry); + heap_free(data); + } + + TlsFree(urlmon_tls); +} + +static void detach_thread(void) +{ + tls_data_t *data; + + if(!urlmon_tls) + return; + + data = TlsGetValue(urlmon_tls); + if(!data) + return; + + EnterCriticalSection(&tls_cs); + list_remove(&data->entry); + LeaveCriticalSection(&tls_cs); + + if(data->notif_hwnd) { + WARN("notif_hwnd not destroyed\n"); + DestroyWindow(data->notif_hwnd); + } + + heap_free(data); +} + /*********************************************************************** * DllMain (URLMON.init) */ @@ -48,7 +127,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) switch(fdwReason) { case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hinstDLL); URLMON_hInstance = hinstDLL; init_session(TRUE); break; @@ -58,8 +136,13 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) FreeLibrary(hCabinet); hCabinet = NULL; init_session(FALSE); + free_tls_list(); URLMON_hInstance = 0; break; + + case DLL_THREAD_DETACH: + detach_thread(); + break; } return TRUE; } diff --git a/reactos/dll/win32/urlmon/urlmon_main.h b/reactos/dll/win32/urlmon/urlmon_main.h index 1ee2eec313e..e5501e01adc 100644 --- a/reactos/dll/win32/urlmon/urlmon_main.h +++ b/reactos/dll/win32/urlmon/urlmon_main.h @@ -34,6 +34,7 @@ #include "wininet.h" #include "wine/unicode.h" +#include "wine/list.h" extern HINSTANCE URLMON_hInstance; extern HRESULT SecManagerImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); @@ -59,6 +60,7 @@ static inline void URLMON_UnlockModule(void) { InterlockedDecrement( &URLMON_ref IInternetProtocolInfo *get_protocol_info(LPCWSTR); HRESULT get_protocol_handler(LPCWSTR,CLSID*,BOOL*,IClassFactory**); +IInternetProtocol *get_mime_filter(LPCWSTR); BOOL is_registered_protocol(LPCWSTR); void register_urlmon_namespace(IClassFactory*,REFIID,LPCWSTR,BOOL); @@ -106,6 +108,33 @@ HRESULT protocol_lock_request(Protocol*); HRESULT protocol_unlock_request(Protocol*); void protocol_close_connection(Protocol*); +typedef struct { + const IInternetProtocolVtbl *lpIInternetProtocolVtbl; + const IInternetProtocolSinkVtbl *lpIInternetProtocolSinkVtbl; + + LONG ref; + + IInternetProtocolSink *protocol_sink; + IInternetProtocol *protocol; +} ProtocolProxy; + +#define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpIInternetProtocolVtbl) +#define PROTSINK(x) ((IInternetProtocolSink*) &(x)->lpIInternetProtocolSinkVtbl) + +HRESULT create_protocol_proxy(IInternetProtocol*,IInternetProtocolSink*,ProtocolProxy**); + +typedef struct { + HWND notif_hwnd; + DWORD notif_hwnd_cnt; + + struct list entry; +} tls_data_t; + +tls_data_t *get_tls_data(void); + +HWND get_notif_hwnd(void); +void release_notif_hwnd(HWND); + static inline void *heap_alloc(size_t len) { return HeapAlloc(GetProcessHeap(), 0, len);