From e487196dc2ec499ac11a0e99d9919db799a03f0f Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Mon, 11 May 2009 21:59:31 +0200 Subject: [PATCH] urlmon: Added support for PI_APARTMENTTHREADED to BindProtocol::Switch. --- dlls/urlmon/binding.c | 7 ++- dlls/urlmon/bindprot.c | 117 +++++++++++++++++++++++++++++++++++++- dlls/urlmon/urlmon_main.h | 6 ++ 3 files changed, 126 insertions(+), 4 deletions(-) diff --git a/dlls/urlmon/binding.c b/dlls/urlmon/binding.c index f8ad73a6336..4b8651c60f6 100644 --- a/dlls/urlmon/binding.c +++ b/dlls/urlmon/binding.c @@ -192,6 +192,9 @@ static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM IBinding_Release(BINDING(binding)); return 0; } + case WM_MK_CONTINUE2: + handle_bindprot_task((void*)lParam); + return 0; case WM_MK_RELEASE: { tls_data_t *data = get_tls_data(); @@ -205,7 +208,7 @@ static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM return DefWindowProcW(hwnd, msg, wParam, lParam); } -static HWND get_notif_hwnd(void) +HWND get_notif_hwnd(void) { static ATOM wnd_class = 0; tls_data_t *tls_data; @@ -250,7 +253,7 @@ static HWND get_notif_hwnd(void) return tls_data->notif_hwnd; } -static void release_notif_hwnd(HWND hwnd) +void release_notif_hwnd(HWND hwnd) { tls_data_t *data = get_tls_data(); diff --git a/dlls/urlmon/bindprot.c b/dlls/urlmon/bindprot.c index 1f245943b3b..eaee9b61600 100644 --- a/dlls/urlmon/bindprot.c +++ b/dlls/urlmon/bindprot.c @@ -21,7 +21,18 @@ WINE_DEFAULT_DEBUG_CHANNEL(urlmon); -typedef struct { +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 *lpInternetProtocolVtbl; const IInternetBindInfoVtbl *lpInternetBindInfoVtbl; const IInternetPriorityVtbl *lpInternetPriorityVtbl; @@ -40,7 +51,15 @@ typedef struct { BOOL reported_result; 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; +}; #define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl) #define BINDINFO(x) ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl) @@ -48,6 +67,64 @@ typedef struct { #define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl) #define PROTSINK(x) ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl) +void handle_bindprot_task(void *v) +{ + BindProtocol *This = v; + 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)); +} + +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_CONTINUE2, 0, (LPARAM)This); + } +} + +static BOOL inline do_direct_notif(BindProtocol *This) +{ + return !(This->pi & PI_APARTMENTTHREADED) || (This->apartment_thread == GetCurrentThreadId() && !This->continue_call); +} + #define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocol, iface) static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) @@ -113,6 +190,10 @@ static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface) IInternetBindInfo_Release(This->bind_info); set_binding_sink(PROTOCOL(This), NULL); + + if(This->notif_hwnd) + release_notif_hwnd(This->notif_hwnd); + DeleteCriticalSection(&This->section); heap_free(This); URLMON_UnlockModule(); @@ -140,6 +221,8 @@ static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl if(!szUrl || !pOIProtSink || !pOIBindInfo) return E_INVALIDARG; + This->pi = grfPI; + hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider, (void**)&service_provider); if(SUCCEEDED(hres)) { @@ -468,6 +551,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, &task->data); + + heap_free(task); +} + static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOLDATA *pProtocolData) { @@ -478,6 +575,19 @@ 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); return S_OK; @@ -615,6 +725,9 @@ HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol ret->ref = 1; ret->from_urlmon = from_urlmon; + ret->apartment_thread = GetCurrentThreadId(); + ret->notif_hwnd = get_notif_hwnd(); + InitializeCriticalSection(&ret->section); URLMON_LockModule(); diff --git a/dlls/urlmon/urlmon_main.h b/dlls/urlmon/urlmon_main.h index aa2f276257d..13eb4f38d03 100644 --- a/dlls/urlmon/urlmon_main.h +++ b/dlls/urlmon/urlmon_main.h @@ -116,6 +116,12 @@ typedef struct { tls_data_t *get_tls_data(void); +HWND get_notif_hwnd(void); +void release_notif_hwnd(HWND); + +#define WM_MK_CONTINUE2 (WM_USER+103) +void handle_bindprot_task(void*); + static inline void *heap_alloc(size_t len) { return HeapAlloc(GetProcessHeap(), 0, len);