diff --git a/reactos/dll/win32/urlmon/binding.c b/reactos/dll/win32/urlmon/binding.c index c7fe45178b5..aaadbd87638 100644 --- a/reactos/dll/win32/urlmon/binding.c +++ b/reactos/dll/win32/urlmon/binding.c @@ -1,5 +1,5 @@ /* - * Copyright 2005 Jacek Caban + * Copyright 2005-2007 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 @@ -13,7 +13,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -34,9 +34,46 @@ WINE_DEFAULT_DEBUG_CHANNEL(urlmon); -typedef struct ProtocolStream ProtocolStream; +typedef struct Binding Binding; + +struct _task_header_t; + +typedef void (*task_proc_t)(Binding*, struct _task_header_t*); + +typedef struct _task_header_t { + task_proc_t proc; + struct _task_header_t *next; +} task_header_t; typedef struct { + const IHttpNegotiate2Vtbl *lpHttpNegotiate2Vtbl; + + LONG ref; + + IHttpNegotiate *http_negotiate; + IHttpNegotiate2 *http_negotiate2; +} HttpNegotiate2Wrapper; + +typedef struct { + const IStreamVtbl *lpStreamVtbl; + + LONG ref; + + IInternetProtocol *protocol; + + BYTE buf[1024*8]; + DWORD buf_size; + BOOL init_buf; + HRESULT hres; +} ProtocolStream; + +typedef enum { + BEFORE_DOWNLOAD, + DOWNLOADING, + END_DOWNLOAD +} download_state_t; + +struct Binding { const IBindingVtbl *lpBindingVtbl; const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl; const IInternetBindInfoVtbl *lpInternetBindInfoVtbl; @@ -48,22 +85,24 @@ typedef struct { IInternetProtocol *protocol; IServiceProvider *service_provider; ProtocolStream *stream; + HttpNegotiate2Wrapper *httpneg2_wrapper; BINDINFO bindinfo; DWORD bindf; LPWSTR mime; LPWSTR url; -} Binding; + BOOL report_mime; + DWORD continue_call; + BOOL request_locked; + download_state_t download_state; -struct ProtocolStream { - const IStreamVtbl *lpStreamVtbl; + DWORD apartment_thread; + HWND notif_hwnd; - LONG ref; + STGMEDIUM stgmed; - IInternetProtocol *protocol; - - BYTE buf[1024*8]; - DWORD buf_size; + task_header_t *task_queue_head, *task_queue_tail; + CRITICAL_SECTION section; }; #define BINDING(x) ((IBinding*) &(x)->lpBindingVtbl) @@ -72,78 +111,301 @@ struct ProtocolStream { #define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl) #define STREAM(x) ((IStream*) &(x)->lpStreamVtbl) +#define HTTPNEG2(x) ((IHttpNegotiate2*) &(x)->lpHttpNegotiate2Vtbl) -static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface, - REFIID riid, void **ppv) +#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; + 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_stream_buffer(ProtocolStream *This) +{ + DWORD read = 0; + + if(sizeof(This->buf) == This->buf_size) + return; + + This->hres = IInternetProtocol_Read(This->protocol, This->buf+This->buf_size, + sizeof(This->buf)-This->buf_size, &read); + This->buf_size += read; + if(read > 0) + This->init_buf = 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[] = { + "#0", + "BINDINFOF_URLENCODESTGMEDDATA", + "BINDINFOF_URLENCODEDEXTRAINFO" + }; + + static const char * const BINDVERB_str[] = { + "BINDVERB_GET", + "BINDVERB_POST", + "BINDVERB_PUT", + "BINDVERB_CUSTOM" + }; + + TRACE("\n" + "BINDINFO = {\n" + " %d, %s,\n" + " {%d, %p, %p},\n" + " %s,\n" + " %s,\n" + " %s,\n" + " %d, %08x, %d, %d\n" + " {%d %p %x},\n" + " %s\n" + " %p, %d\n" + "}\n", + + bi->cbSize, debugstr_w(bi->szExtraInfo), + bi->stgmedData.tymed, bi->stgmedData.u.hGlobal, bi->stgmedData.pUnkForRelease, + bi->grfBindInfoF > BINDINFOF_URLENCODEDEXTRAINFO + ? "unknown" : BINDINFOF_str[bi->grfBindInfoF], + bi->dwBindVerb > BINDVERB_CUSTOM + ? "unknown" : BINDVERB_str[bi->dwBindVerb], + debugstr_w(bi->szCustomVerb), + bi->cbstgmedData, bi->dwOptions, bi->dwOptionsFlags, bi->dwCodePage, + bi->securityAttributes.nLength, + bi->securityAttributes.lpSecurityDescriptor, + bi->securityAttributes.bInheritHandle, + debugstr_guid(&bi->iid), + bi->pUnk, bi->dwReserved + ); +} + +#define HTTPNEG2_THIS(iface) DEFINE_THIS(HttpNegotiate2Wrapper, HttpNegotiate2, iface) + +static HRESULT WINAPI HttpNegotiate2Wrapper_QueryInterface(IHttpNegotiate2 *iface, + REFIID riid, void **ppv) +{ + HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface); + *ppv = NULL; if(IsEqualGUID(&IID_IUnknown, riid)) { TRACE("(IID_IUnknown %p)\n", ppv); - *ppv = iface; + *ppv = HTTPNEG2(This); }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) { TRACE("(IID_IHttpNegotiate %p)\n", ppv); - *ppv = iface; + *ppv = HTTPNEG2(This); }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) { TRACE("(IID_IHttpNegotiate2 %p)\n", ppv); - *ppv = iface; + *ppv = HTTPNEG2(This); } if(*ppv) { - IHttpNegotiate2_AddRef(iface); + IHttpNegotiate2_AddRef(HTTPNEG2(This)); return S_OK; } - WARN("Unsupported interface %s\n", debugstr_guid(riid)); + WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); return E_NOINTERFACE; } -static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate2 *iface) +static ULONG WINAPI HttpNegotiate2Wrapper_AddRef(IHttpNegotiate2 *iface) { - URLMON_LockModule(); - return 2; + HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + return ref; } -static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface) +static ULONG WINAPI HttpNegotiate2Wrapper_Release(IHttpNegotiate2 *iface) { - URLMON_UnlockModule(); - return 1; + HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + if(!ref) { + if (This->http_negotiate) + IHttpNegotiate_Release(This->http_negotiate); + if (This->http_negotiate2) + IHttpNegotiate2_Release(This->http_negotiate2); + HeapFree(GetProcessHeap(), 0, This); + + URLMON_UnlockModule(); + } + + return ref; } -static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface, +static HRESULT WINAPI HttpNegotiate2Wrapper_BeginningTransaction(IHttpNegotiate2 *iface, LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders) { - FIXME("(%s %s %ld %p)\n", debugstr_w(szURL), debugstr_w(szHeaders), dwReserved, + HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface); + + TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders), dwReserved, pszAdditionalHeaders); - return E_NOTIMPL; + + if(This->http_negotiate) + return IHttpNegotiate_BeginningTransaction(This->http_negotiate, szURL, szHeaders, + dwReserved, pszAdditionalHeaders); + + *pszAdditionalHeaders = NULL; + return S_OK; } -static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode, +static HRESULT WINAPI HttpNegotiate2Wrapper_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode, LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders) { - FIXME("(%ld %s %s %p)\n", dwResponseCode, debugstr_w(szResponseHeaders), + HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface); + LPWSTR szAdditionalRequestHeaders = NULL; + HRESULT hres = S_OK; + + TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders), debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders); - return E_NOTIMPL; + + /* IHttpNegotiate2_OnResponse expects pszAdditionalHeaders to be non-NULL when it is + * implemented as part of IBindStatusCallback, but it is NULL when called directly from + * IProtocol */ + if(!pszAdditionalRequestHeaders) + pszAdditionalRequestHeaders = &szAdditionalRequestHeaders; + + if(This->http_negotiate) + { + hres = IHttpNegotiate_OnResponse(This->http_negotiate, dwResponseCode, szResponseHeaders, + szRequestHeaders, pszAdditionalRequestHeaders); + if(pszAdditionalRequestHeaders == &szAdditionalRequestHeaders && + szAdditionalRequestHeaders) + CoTaskMemFree(szAdditionalRequestHeaders); + } + else + { + *pszAdditionalRequestHeaders = NULL; + } + + return hres; } -static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface, +static HRESULT WINAPI HttpNegotiate2Wrapper_GetRootSecurityId(IHttpNegotiate2 *iface, BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved) { - FIXME("(%p %p %ld)\n", pbSecurityId, pcbSecurityId, dwReserved); - return E_NOTIMPL; + HttpNegotiate2Wrapper *This = HTTPNEG2_THIS(iface); + + TRACE("(%p)->(%p %p %ld)\n", This, pbSecurityId, pcbSecurityId, dwReserved); + + if (This->http_negotiate2) + return IHttpNegotiate2_GetRootSecurityId(This->http_negotiate2, pbSecurityId, + pcbSecurityId, dwReserved); + + /* That's all we have to do here */ + return E_FAIL; } -static const IHttpNegotiate2Vtbl HttpNegotiate2Vtbl = { - HttpNegotiate_QueryInterface, - HttpNegotiate_AddRef, - HttpNegotiate_Release, - HttpNegotiate_BeginningTransaction, - HttpNegotiate_OnResponse, - HttpNegotiate_GetRootSecurityId +#undef HTTPNEG2_THIS + +static const IHttpNegotiate2Vtbl HttpNegotiate2WrapperVtbl = { + HttpNegotiate2Wrapper_QueryInterface, + HttpNegotiate2Wrapper_AddRef, + HttpNegotiate2Wrapper_Release, + HttpNegotiate2Wrapper_BeginningTransaction, + HttpNegotiate2Wrapper_OnResponse, + HttpNegotiate2Wrapper_GetRootSecurityId }; -static IHttpNegotiate2 HttpNegotiate = { &HttpNegotiate2Vtbl }; +static HttpNegotiate2Wrapper *create_httpneg2_wrapper(void) +{ + HttpNegotiate2Wrapper *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(HttpNegotiate2Wrapper)); + + ret->lpHttpNegotiate2Vtbl = &HttpNegotiate2WrapperVtbl; + ret->ref = 1; + ret->http_negotiate = NULL; + ret->http_negotiate2 = NULL; + + URLMON_LockModule(); + + return ret; +} #define STREAM_THIS(iface) DEFINE_THIS(ProtocolStream, Stream, iface) @@ -179,7 +441,7 @@ static ULONG WINAPI ProtocolStream_AddRef(IStream *iface) ProtocolStream *This = STREAM_THIS(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%ld\n", This, ref); + TRACE("(%p) ref=%d\n", This, ref); return ref; } @@ -189,7 +451,7 @@ static ULONG WINAPI ProtocolStream_Release(IStream *iface) ProtocolStream *This = STREAM_THIS(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%ld\n", This, ref); + TRACE("(%p) ref=%d\n", This, ref); if(!ref) { IInternetProtocol_Release(This->protocol); @@ -207,7 +469,7 @@ static HRESULT WINAPI ProtocolStream_Read(IStream *iface, void *pv, ProtocolStream *This = STREAM_THIS(iface); DWORD read = 0, pread = 0; - TRACE("(%p)->(%p %ld %p)\n", This, pv, cb, pcbRead); + TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbRead); if(This->buf_size) { read = cb; @@ -227,9 +489,14 @@ static HRESULT WINAPI ProtocolStream_Read(IStream *iface, void *pv, return S_OK; } - IInternetProtocol_Read(This->protocol, (PBYTE)pv+read, cb-read, &pread); + This->hres = IInternetProtocol_Read(This->protocol, (PBYTE)pv+read, cb-read, &pread); *pcbRead = read + pread; + if(This->hres == E_PENDING) + return E_PENDING; + else if(FAILED(This->hres)) + FIXME("Read failed: %08x\n", This->hres); + return read || pread ? S_OK : S_FALSE; } @@ -238,7 +505,7 @@ static HRESULT WINAPI ProtocolStream_Write(IStream *iface, const void *pv, { ProtocolStream *This = STREAM_THIS(iface); - TRACE("(%p)->(%p %ld %p)\n", This, pv, cb, pcbWritten); + TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbWritten); return STG_E_ACCESSDENIED; } @@ -247,14 +514,14 @@ static HRESULT WINAPI ProtocolStream_Seek(IStream *iface, LARGE_INTEGER dlibMove DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) { ProtocolStream *This = STREAM_THIS(iface); - FIXME("(%p)->(%ld %08lx %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); + FIXME("(%p)->(%d %08x %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); return E_NOTIMPL; } static HRESULT WINAPI ProtocolStream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize) { ProtocolStream *This = STREAM_THIS(iface); - FIXME("(%p)->(%ld)\n", This, libNewSize.u.LowPart); + FIXME("(%p)->(%d)\n", This, libNewSize.u.LowPart); return E_NOTIMPL; } @@ -262,7 +529,7 @@ static HRESULT WINAPI ProtocolStream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) { ProtocolStream *This = STREAM_THIS(iface); - FIXME("(%p)->(%p %ld %p %p)\n", This, pstm, cb.u.LowPart, pcbRead, pcbWritten); + FIXME("(%p)->(%p %d %p %p)\n", This, pstm, cb.u.LowPart, pcbRead, pcbWritten); return E_NOTIMPL; } @@ -270,7 +537,7 @@ static HRESULT WINAPI ProtocolStream_Commit(IStream *iface, DWORD grfCommitFlags { ProtocolStream *This = STREAM_THIS(iface); - TRACE("(%p)->(%08lx)\n", This, grfCommitFlags); + TRACE("(%p)->(%08x)\n", This, grfCommitFlags); return E_NOTIMPL; } @@ -288,7 +555,7 @@ static HRESULT WINAPI ProtocolStream_LockRegion(IStream *iface, ULARGE_INTEGER l ULARGE_INTEGER cb, DWORD dwLockType) { ProtocolStream *This = STREAM_THIS(iface); - FIXME("(%p)->(%ld %ld %ld)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType); + FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType); return E_NOTIMPL; } @@ -296,7 +563,7 @@ static HRESULT WINAPI ProtocolStream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { ProtocolStream *This = STREAM_THIS(iface); - FIXME("(%p)->(%ld %ld %ld)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType); + FIXME("(%p)->(%d %d %d)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType); return E_NOTIMPL; } @@ -304,7 +571,7 @@ static HRESULT WINAPI ProtocolStream_Stat(IStream *iface, STATSTG *pstatstg, DWORD dwStatFlag) { ProtocolStream *This = STREAM_THIS(iface); - FIXME("(%p)->(%p %08lx)\n", This, pstatstg, dwStatFlag); + FIXME("(%p)->(%p %08x)\n", This, pstatstg, dwStatFlag); return E_NOTIMPL; } @@ -343,6 +610,8 @@ static ProtocolStream *create_stream(IInternetProtocol *protocol) ret->lpStreamVtbl = &ProtocolStreamVtbl; ret->ref = 1; ret->buf_size = 0; + ret->init_buf = FALSE; + ret->hres = S_OK; IInternetProtocol_AddRef(protocol); ret->protocol = protocol; @@ -352,15 +621,6 @@ static ProtocolStream *create_stream(IInternetProtocol *protocol) return ret; } -static void fill_stream_buffer(ProtocolStream *This) -{ - DWORD read = 0; - - IInternetProtocol_Read(This->protocol, This->buf+This->buf_size, - sizeof(This->buf)-This->buf_size, &read); - This->buf_size += read; -} - static HRESULT WINAPI Binding_QueryInterface(IBinding *iface, REFIID riid, void **ppv) { Binding *This = BINDING_THIS(iface); @@ -398,7 +658,7 @@ static ULONG WINAPI Binding_AddRef(IBinding *iface) Binding *This = BINDING_THIS(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%ld\n", This, ref); + TRACE("(%p) ref=%d\n", This, ref); return ref; } @@ -408,9 +668,11 @@ static ULONG WINAPI Binding_Release(IBinding *iface) Binding *This = BINDING_THIS(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%ld\n", This, ref); + TRACE("(%p) ref=%d\n", This, ref); if(!ref) { + if (This->notif_hwnd) + DestroyWindow( This->notif_hwnd ); if(This->callback) IBindStatusCallback_Release(This->callback); if(This->protocol) @@ -419,8 +681,12 @@ static ULONG WINAPI Binding_Release(IBinding *iface) IServiceProvider_Release(This->service_provider); if(This->stream) IStream_Release(STREAM(This->stream)); + if(This->httpneg2_wrapper) + IHttpNegotiate2_Release(HTTPNEG2(This->httpneg2_wrapper)); ReleaseBindInfo(&This->bindinfo); + This->section.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->section); HeapFree(GetProcessHeap(), 0, This->mime); HeapFree(GetProcessHeap(), 0, This->url); @@ -456,7 +722,7 @@ static HRESULT WINAPI Binding_Resume(IBinding *iface) static HRESULT WINAPI Binding_SetPriority(IBinding *iface, LONG nPriority) { Binding *This = BINDING_THIS(iface); - FIXME("(%p)->(%ld)\n", This, nPriority); + FIXME("(%p)->(%d)\n", This, nPriority); return E_NOTIMPL; } @@ -510,12 +776,92 @@ 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); + + HeapFree(GetProcessHeap(), 0, task); +} + static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface, PROTOCOLDATA *pProtocolData) { Binding *This = PROTSINK_THIS(iface); - FIXME("(%p)->(%p)\n", This, pProtocolData); - return E_NOTIMPL; + switch_task_t *task; + + TRACE("(%p)->(%p)\n", This, pProtocolData); + + task = HeapAlloc(GetProcessHeap(), 0, 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); + + HeapFree(GetProcessHeap(), 0, task->status_text); + HeapFree(GetProcessHeap(), 0, task); +} + +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 = HeapAlloc(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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); + } } static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface, @@ -523,9 +869,18 @@ static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink { Binding *This = PROTSINK_THIS(iface); - TRACE("(%p)->(%lu %s)\n", This, ulStatusCode, debugstr_w(szStatusText)); + TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText)); switch(ulStatusCode) { + case BINDSTATUS_FINDINGRESOURCE: + on_progress(This, 0, 0, BINDSTATUS_FINDINGRESOURCE, szStatusText); + break; + case BINDSTATUS_CONNECTING: + on_progress(This, 0, 0, BINDSTATUS_CONNECTING, szStatusText); + break; + case BINDSTATUS_BEGINDOWNLOADDATA: + fill_stream_buffer(This->stream); + break; case BINDSTATUS_MIMETYPEAVAILABLE: { int len = strlenW(szStatusText)+1; This->mime = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); @@ -533,73 +888,147 @@ static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink break; } case BINDSTATUS_SENDINGREQUEST: - IBindStatusCallback_OnProgress(This->callback, 0, 0, BINDSTATUS_SENDINGREQUEST, - szStatusText); + on_progress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, szStatusText); break; case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE: - IBindStatusCallback_OnProgress(This->callback, 0, 0, - BINDSTATUS_MIMETYPEAVAILABLE, szStatusText); + This->report_mime = FALSE; + on_progress(This, 0, 0, BINDSTATUS_MIMETYPEAVAILABLE, szStatusText); break; case BINDSTATUS_CACHEFILENAMEAVAILABLE: break; + case BINDSTATUS_DIRECTBIND: + This->report_mime = FALSE; + break; default: - FIXME("Unhandled status code %ld\n", ulStatusCode); + FIXME("Unhandled status code %d\n", ulStatusCode); return E_NOTIMPL; }; return S_OK; } +static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progress_max) +{ + FORMATETC formatetc = {0, NULL, 1, -1, TYMED_ISTREAM}; + + TRACE("(%p)->(%d %u %u)\n", This, bscf, progress, progress_max); + + if(This->download_state == END_DOWNLOAD) + return; + + if(GetCurrentThreadId() != This->apartment_thread) + FIXME("called from worked hread\n"); + + if(This->report_mime) { + LPWSTR mime; + + This->report_mime = FALSE; + + fill_stream_buffer(This->stream); + + FindMimeFromData(NULL, This->url, This->stream->buf, + min(This->stream->buf_size, 255), This->mime, 0, &mime, 0); + + IBindStatusCallback_OnProgress(This->callback, progress, progress_max, + BINDSTATUS_MIMETYPEAVAILABLE, mime); + } + + if(This->download_state == BEFORE_DOWNLOAD) { + fill_stream_buffer(This->stream); + + This->download_state = DOWNLOADING; + IBindStatusCallback_OnProgress(This->callback, progress, progress_max, + BINDSTATUS_BEGINDOWNLOADDATA, This->url); + } + + if(This->stream->hres == S_FALSE || (bscf & BSCF_LASTDATANOTIFICATION)) { + IBindStatusCallback_OnProgress(This->callback, progress, progress_max, + BINDSTATUS_ENDDOWNLOADDATA, This->url); + } + + if(!This->request_locked) { + HRESULT hres = IInternetProtocol_LockRequest(This->protocol, 0); + This->request_locked = SUCCEEDED(hres); + } + + fill_stream_buffer(This->stream); + + IBindStatusCallback_OnDataAvailable(This->callback, bscf, This->stream->buf_size, + &formatetc, &This->stgmed); + + if(This->stream->hres == S_FALSE) { + This->download_state = END_DOWNLOAD; + IBindStatusCallback_OnStopBinding(This->callback, S_OK, NULL); + } +} + +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); + + HeapFree(GetProcessHeap(), 0, task); +} + static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface, DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax) { Binding *This = PROTSINK_THIS(iface); - STGMEDIUM stgmed; - FORMATETC formatetc; - TRACE("(%p)->(%ld %lu %lu)\n", This, grfBSCF, ulProgress, ulProgressMax); + TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax); - if(grfBSCF & BSCF_FIRSTDATANOTIFICATION) { - if(This->mime) - IBindStatusCallback_OnProgress(This->callback, ulProgress, ulProgressMax, - BINDSTATUS_MIMETYPEAVAILABLE, This->mime); - IBindStatusCallback_OnProgress(This->callback, ulProgress, ulProgressMax, - BINDSTATUS_BEGINDOWNLOADDATA, This->url); + if(GetCurrentThreadId() != This->apartment_thread) + FIXME("called from worked hread\n"); + + if(This->continue_call) { + report_data_task_t *task = HeapAlloc(GetProcessHeap(), 0, 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); } - if(grfBSCF & BSCF_LASTDATANOTIFICATION) - IBindStatusCallback_OnProgress(This->callback, ulProgress, ulProgressMax, - BINDSTATUS_ENDDOWNLOADDATA, This->url); - - if(grfBSCF & BSCF_FIRSTDATANOTIFICATION) - IInternetProtocol_LockRequest(This->protocol, 0); - - fill_stream_buffer(This->stream); - - stgmed.tymed = TYMED_ISTREAM; - stgmed.u.pstm = STREAM(This->stream); - - formatetc.cfFormat = 0; /* FIXME */ - formatetc.ptd = NULL; - formatetc.dwAspect = 1; - formatetc.lindex = -1; - formatetc.tymed = TYMED_ISTREAM; - - IBindStatusCallback_OnDataAvailable(This->callback, grfBSCF, This->stream->buf_size, - &formatetc, &stgmed); - - if(grfBSCF & BSCF_LASTDATANOTIFICATION) - IBindStatusCallback_OnStopBinding(This->callback, S_OK, NULL); - return S_OK; } +static void report_result_proc(Binding *binding, task_header_t *t) +{ + IInternetProtocol_Terminate(binding->protocol, 0); + + if(binding->request_locked) { + IInternetProtocol_UnlockRequest(binding->protocol); + binding->request_locked = FALSE; + } + + HeapFree(GetProcessHeap(), 0, t); +} + static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface, HRESULT hrResult, DWORD dwError, LPCWSTR szResult) { Binding *This = PROTSINK_THIS(iface); - FIXME("(%p)->(%08lx %ld %s)\n", This, hrResult, dwError, debugstr_w(szResult)); - return E_NOTIMPL; + + 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); + }else { + task_header_t *task = HeapAlloc(GetProcessHeap(), 0, sizeof(task_header_t)); + push_task(This, task, report_result_proc); + } + + return S_OK; } #undef PROTSINK_THIS @@ -649,6 +1078,9 @@ static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface, if(pbindinfo->szExtraInfo || pbindinfo->szCustomVerb) FIXME("copy strings\n"); + if(pbindinfo->stgmedData.pUnkForRelease) + IUnknown_AddRef(pbindinfo->stgmedData.pUnkForRelease); + if(pbindinfo->pUnk) IUnknown_AddRef(pbindinfo->pUnk); @@ -660,7 +1092,7 @@ static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface, { Binding *This = BINDINF_THIS(iface); - TRACE("(%p)->(%ld %p %ld %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched); + TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched); switch(ulStringType) { case BINDSTRING_ACCEPT_MIMES: { @@ -691,7 +1123,7 @@ static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface, } } - FIXME("not supported string type %ld\n", ulStringType); + FIXME("not supported string type %d\n", ulStringType); return E_NOTIMPL; } @@ -742,8 +1174,20 @@ static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, } if(IsEqualGUID(&IID_IHttpNegotiate, guidService) - || IsEqualGUID(&IID_IHttpNegotiate2, guidService)) - return IHttpNegotiate2_QueryInterface(&HttpNegotiate, riid, ppv); + || IsEqualGUID(&IID_IHttpNegotiate2, guidService)) { + if(!This->httpneg2_wrapper) { + WARN("HttpNegotiate2Wrapper expected to be non-NULL\n"); + } else { + if(IsEqualGUID(&IID_IHttpNegotiate, guidService)) + IBindStatusCallback_QueryInterface(This->callback, riid, + (void **)&This->httpneg2_wrapper->http_negotiate); + else + IBindStatusCallback_QueryInterface(This->callback, riid, + (void **)&This->httpneg2_wrapper->http_negotiate2); + + return IHttpNegotiate2_QueryInterface(HTTPNEG2(This->httpneg2_wrapper), riid, ppv); + } + } WARN("unknown service %s\n", debugstr_guid(guidService)); return E_NOTIMPL; @@ -773,7 +1217,6 @@ static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback) static HRESULT get_protocol(Binding *This, LPCWSTR url) { - IUnknown *unk = NULL; IClassFactory *cf = NULL; HRESULT hres; @@ -789,12 +1232,7 @@ static HRESULT get_protocol(Binding *This, LPCWSTR url) return S_OK; } - hres = get_protocol_iface(url, &unk); - if(FAILED(hres)) - return hres; - - hres = IUnknown_QueryInterface(unk, &IID_IClassFactory, (void**)&cf); - IUnknown_Release(unk); + hres = get_protocol_handler(url, NULL, &cf); if(FAILED(hres)) return hres; @@ -804,14 +1242,46 @@ static HRESULT get_protocol(Binding *This, LPCWSTR url) return hres; } +static BOOL is_urlmon_protocol(LPCWSTR url) +{ + static const WCHAR wszCdl[] = {'c','d','l'}; + static const WCHAR wszFile[] = {'f','i','l','e'}; + static const WCHAR wszFtp[] = {'f','t','p'}; + static const WCHAR wszGopher[] = {'g','o','p','h','e','r'}; + static const WCHAR wszHttp[] = {'h','t','t','p'}; + static const WCHAR wszHttps[] = {'h','t','t','p','s'}; + static const WCHAR wszMk[] = {'m','k'}; + + static const struct { + LPCWSTR scheme; + int len; + } protocol_list[] = { + {wszCdl, sizeof(wszCdl) /sizeof(WCHAR)}, + {wszFile, sizeof(wszFile) /sizeof(WCHAR)}, + {wszFtp, sizeof(wszFtp) /sizeof(WCHAR)}, + {wszGopher, sizeof(wszGopher)/sizeof(WCHAR)}, + {wszHttp, sizeof(wszHttp) /sizeof(WCHAR)}, + {wszHttps, sizeof(wszHttps) /sizeof(WCHAR)}, + {wszMk, sizeof(wszMk) /sizeof(WCHAR)} + }; + + int i, len = strlenW(url); + + for(i=0; i < sizeof(protocol_list)/sizeof(protocol_list[0]); i++) { + if(len >= protocol_list[i].len + && !memcmp(url, protocol_list[i].scheme, protocol_list[i].len*sizeof(WCHAR))) + return TRUE; + } + + return FALSE; +} + static HRESULT Binding_Create(LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding **binding) { Binding *ret; int len; HRESULT hres; - static const WCHAR wszFile[] = {'f','i','l','e',':'}; - if(!IsEqualGUID(&IID_IStream, riid)) { FIXME("Unsupported riid %s\n", debugstr_guid(riid)); return E_NOTIMPL; @@ -832,13 +1302,24 @@ static HRESULT Binding_Create(LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding * ret->protocol = NULL; ret->service_provider = NULL; ret->stream = NULL; + ret->httpneg2_wrapper = NULL; ret->mime = NULL; ret->url = NULL; + ret->apartment_thread = GetCurrentThreadId(); + ret->notif_hwnd = get_notif_hwnd(); + ret->report_mime = TRUE; + ret->continue_call = 0; + ret->request_locked = FALSE; + ret->download_state = BEFORE_DOWNLOAD; + ret->task_queue_head = ret->task_queue_tail = NULL; memset(&ret->bindinfo, 0, sizeof(BINDINFO)); ret->bindinfo.cbSize = sizeof(BINDINFO); ret->bindf = 0; + InitializeCriticalSection(&ret->section); + ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": Binding.section"); + hres = get_callback(pbc, &ret->callback); if(FAILED(hres)) { WARN("Could not get IBindStatusCallback\n"); @@ -858,22 +1339,28 @@ static HRESULT Binding_Create(LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding * hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo); if(FAILED(hres)) { - WARN("GetBindInfo failed: %08lx\n", hres); + WARN("GetBindInfo failed: %08x\n", hres); IBinding_Release(BINDING(ret)); return hres; } + dump_BINDINFO(&ret->bindinfo); + ret->bindf |= BINDF_FROMURLMON; - len = strlenW(url)+1; - - if(len < sizeof(wszFile)/sizeof(WCHAR) || memcmp(wszFile, url, sizeof(wszFile))) + if(!is_urlmon_protocol(url)) ret->bindf |= BINDF_NEEDFILE; + len = strlenW(url)+1; ret->url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); memcpy(ret->url, url, len*sizeof(WCHAR)); ret->stream = create_stream(ret->protocol); + ret->stgmed.tymed = TYMED_ISTREAM; + ret->stgmed.u.pstm = STREAM(ret->stream); + ret->stgmed.pUnkForRelease = (IUnknown*)BINDING(ret); /* NOTE: Windows uses other IUnknown */ + + ret->httpneg2_wrapper = create_httpneg2_wrapper(); *binding = ret; return S_OK; @@ -892,7 +1379,7 @@ HRESULT start_binding(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv) hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, BINDING(binding)); if(FAILED(hres)) { - WARN("OnStartBinding failed: %08lx\n", hres); + WARN("OnStartBinding failed: %08x\n", hres); IBindStatusCallback_OnStopBinding(binding->callback, 0x800c0008, NULL); IBinding_Release(BINDING(binding)); return hres; @@ -900,17 +1387,28 @@ HRESULT start_binding(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv) hres = IInternetProtocol_Start(binding->protocol, url, PROTSINK(binding), BINDINF(binding), 0, 0); - IInternetProtocol_Terminate(binding->protocol, 0); - if(SUCCEEDED(hres)) { - IInternetProtocol_UnlockRequest(binding->protocol); - }else { - WARN("Start failed: %08lx\n", hres); + if(FAILED(hres)) { + WARN("Start failed: %08x\n", hres); + + IInternetProtocol_Terminate(binding->protocol, 0); IBindStatusCallback_OnStopBinding(binding->callback, S_OK, NULL); + IBinding_Release(BINDING(binding)); + + return hres; } - IStream_AddRef(STREAM(binding->stream)); - *ppv = binding->stream; + if(binding->stream->init_buf) { + if(binding->request_locked) + IInternetProtocol_UnlockRequest(binding->protocol); + + IStream_AddRef(STREAM(binding->stream)); + *ppv = binding->stream; + + hres = S_OK; + }else { + hres = MK_S_ASYNCHRONOUS; + } IBinding_Release(BINDING(binding)); diff --git a/reactos/dll/win32/urlmon/bindprot.c b/reactos/dll/win32/urlmon/bindprot.c new file mode 100644 index 00000000000..6b175f630c6 --- /dev/null +++ b/reactos/dll/win32/urlmon/bindprot.c @@ -0,0 +1,500 @@ +/* + * Copyright 2007 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 + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "ole2.h" +#include "urlmon.h" +#include "urlmon_main.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(urlmon); + +typedef struct { + const IInternetProtocolVtbl *lpInternetProtocolVtbl; + const IInternetBindInfoVtbl *lpInternetBindInfoVtbl; + const IInternetPriorityVtbl *lpInternetPriorityVtbl; + const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl; + + LONG ref; + + IInternetProtocol *protocol; + IInternetBindInfo *bind_info; + IInternetProtocolSink *protocol_sink; + + LONG priority; +} BindProtocol; + +#define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl) +#define BINDINFO(x) ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl) +#define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl) +#define PROTSINK(x) ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl) + +#define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocol, iface) + +static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) +{ + BindProtocol *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_IInternetBindInfo, riid)) { + TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv); + *ppv = BINDINFO(This); + }else if(IsEqualGUID(&IID_IInternetPriority, riid)) { + TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv); + *ppv = PRIORITY(This); + }else if(IsEqualGUID(&IID_IAuthenticate, riid)) { + FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv); + }else if(IsEqualGUID(&IID_IServiceProvider, riid)) { + FIXME("(%p)->(IID_IServiceProvider %p)\n", This, ppv); + }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 BindProtocol_AddRef(IInternetProtocol *iface) +{ + BindProtocol *This = PROTOCOL_THIS(iface); + LONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p) ref=%d\n", This, ref); + return ref; +} + +static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface) +{ + BindProtocol *This = PROTOCOL_THIS(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + if(!ref) { + if(This->protocol) + IInternetProtocol_Release(This->protocol); + if(This->bind_info) + IInternetBindInfo_Release(This->bind_info); + if(This->protocol_sink) + IInternetProtocolSink_Release(This->protocol_sink); + + HeapFree(GetProcessHeap(), 0, This); + + URLMON_UnlockModule(); + } + + return ref; +} + +static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, + IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, + DWORD grfPI, DWORD dwReserved) +{ + BindProtocol *This = PROTOCOL_THIS(iface); + IInternetProtocol *protocol = NULL; + IInternetPriority *priority; + IServiceProvider *service_provider; + CLSID clsid = IID_NULL; + LPOLESTR clsid_str; + HRESULT hres; + + TRACE("(%p)->(%s %p %p %08x %d)\n", This, debugstr_w(szUrl), pOIProtSink, + pOIBindInfo, grfPI, dwReserved); + + if(!szUrl || !pOIProtSink || !pOIBindInfo) + return E_INVALIDARG; + + hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider, + (void**)&service_provider); + if(SUCCEEDED(hres)) { + /* FIXME: What's protocol CLSID here? */ + IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol, + &IID_IInternetProtocol, (void**)&protocol); + IServiceProvider_Release(service_provider); + } + + if(!protocol) { + IClassFactory *cf; + IUnknown *unk; + + hres = get_protocol_handler(szUrl, &clsid, &cf); + if(FAILED(hres)) + return hres; + + hres = IClassFactory_CreateInstance(cf, (IUnknown*)BINDINFO(This), + &IID_IUnknown, (void**)&unk); + IClassFactory_Release(cf); + if(FAILED(hres)) + return hres; + + hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol); + IUnknown_Release(unk); + if(FAILED(hres)) + return hres; + } + + StringFromCLSID(&clsid, &clsid_str); + IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str); + CoTaskMemFree(clsid_str); + + This->protocol = protocol; + + IInternetBindInfo_AddRef(pOIBindInfo); + This->bind_info = pOIBindInfo; + + IInternetProtocolSink_AddRef(pOIProtSink); + This->protocol_sink = pOIProtSink; + + hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority); + if(SUCCEEDED(hres)) { + IInternetPriority_SetPriority(priority, This->priority); + IInternetPriority_Release(priority); + } + + return IInternetProtocol_Start(protocol, szUrl, PROTSINK(This), BINDINFO(This), 0, 0); +} + +static HRESULT WINAPI BindProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData) +{ + BindProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)->(%p)\n", This, pProtocolData); + return E_NOTIMPL; +} + +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); + + IInternetProtocol_Terminate(This->protocol, 0); + return S_OK; +} + +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); + ULONG read = 0; + HRESULT hres; + + TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); + + hres = IInternetProtocol_Read(This->protocol, pv, cb, &read); + + *pcbRead = read; + return hres; +} + +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); + FIXME("(%p)->(%08x)\n", This, dwOptions); + return E_NOTIMPL; +} + +static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface) +{ + BindProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)\n", This); + return E_NOTIMPL; +} + +#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 BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface) + +static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface, + REFIID riid, void **ppv) +{ + BindProtocol *This = BINDINFO_THIS(iface); + return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv); +} + +static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface) +{ + BindProtocol *This = BINDINFO_THIS(iface); + return IBinding_AddRef(PROTOCOL(This)); +} + +static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface) +{ + BindProtocol *This = BINDINFO_THIS(iface); + return IBinding_Release(PROTOCOL(This)); +} + +static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface, + DWORD *grfBINDF, BINDINFO *pbindinfo) +{ + BindProtocol *This = BINDINFO_THIS(iface); + HRESULT hres; + + TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo); + + hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo); + if(FAILED(hres)) { + WARN("GetBindInfo failed: %08x\n", hres); + return hres; + } + + *grfBINDF |= BINDF_FROMURLMON; + return hres; +} + +static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface, + ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched) +{ + BindProtocol *This = BINDINFO_THIS(iface); + FIXME("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched); + return E_NOTIMPL; +} + +#undef BINDFO_THIS + +static const IInternetBindInfoVtbl InternetBindInfoVtbl = { + BindInfo_QueryInterface, + BindInfo_AddRef, + BindInfo_Release, + BindInfo_GetBindInfo, + BindInfo_GetBindString +}; + +#define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface) + +static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface, + REFIID riid, void **ppv) +{ + BindProtocol *This = PRIORITY_THIS(iface); + return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv); +} + +static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface) +{ + BindProtocol *This = PRIORITY_THIS(iface); + return IInternetProtocol_AddRef(PROTOCOL(This)); +} + +static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface) +{ + BindProtocol *This = PRIORITY_THIS(iface); + return IInternetProtocol_Release(PROTOCOL(This)); +} + +static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority) +{ + BindProtocol *This = PRIORITY_THIS(iface); + + TRACE("(%p)->(%d)\n", This, nPriority); + + This->priority = nPriority; + return S_OK; +} + +static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority) +{ + BindProtocol *This = PRIORITY_THIS(iface); + + TRACE("(%p)->(%p)\n", This, pnPriority); + + *pnPriority = This->priority; + return S_OK; +} + +#undef PRIORITY_THIS + +static const IInternetPriorityVtbl InternetPriorityVtbl = { + InternetPriority_QueryInterface, + InternetPriority_AddRef, + InternetPriority_Release, + InternetPriority_SetPriority, + InternetPriority_GetPriority + +}; + +#define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocolSink, iface) + +static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface, + REFIID riid, void **ppv) +{ + BindProtocol *This = PROTSINK_THIS(iface); + return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv); +} + +static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface) +{ + BindProtocol *This = PROTSINK_THIS(iface); + return IInternetProtocol_AddRef(PROTOCOL(This)); +} + +static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface) +{ + BindProtocol *This = PROTSINK_THIS(iface); + return IInternetProtocol_Release(PROTOCOL(This)); +} + +static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface, + PROTOCOLDATA *pProtocolData) +{ + BindProtocol *This = PROTSINK_THIS(iface); + FIXME("(%p)->(%p)\n", This, pProtocolData); + return E_NOTIMPL; +} + +static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface, + ULONG ulStatusCode, LPCWSTR szStatusText) +{ + BindProtocol *This = PROTSINK_THIS(iface); + + TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText)); + + switch(ulStatusCode) { + case BINDSTATUS_SENDINGREQUEST: + return IInternetProtocolSink_ReportProgress(This->protocol_sink, + ulStatusCode, NULL); + case BINDSTATUS_CACHEFILENAMEAVAILABLE: + return IInternetProtocolSink_ReportProgress(This->protocol_sink, + ulStatusCode, szStatusText); + case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE: + return IInternetProtocolSink_ReportProgress(This->protocol_sink, + BINDSTATUS_MIMETYPEAVAILABLE, szStatusText); + default: + FIXME("unsupported ulStatusCode %u\n", ulStatusCode); + } + + return E_NOTIMPL; +} + +static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface, + DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax) +{ + BindProtocol *This = PROTSINK_THIS(iface); + + TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax); + + return S_OK; +} + +static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *iface, + HRESULT hrResult, DWORD dwError, LPCWSTR szResult) +{ + BindProtocol *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 = { + InternetProtocolSink_QueryInterface, + InternetProtocolSink_AddRef, + InternetProtocolSink_Release, + InternetProtocolSink_Switch, + InternetProtocolSink_ReportProgress, + InternetProtocolSink_ReportData, + InternetProtocolSink_ReportResult +}; + +HRESULT create_binding_protocol(LPCWSTR url, IInternetProtocol **protocol) +{ + BindProtocol *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(BindProtocol)); + + ret->lpInternetProtocolVtbl = &BindProtocolVtbl; + ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl; + ret->lpInternetPriorityVtbl = &InternetPriorityVtbl; + ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl; + + ret->ref = 1; + ret->protocol = NULL; + ret->bind_info = NULL; + ret->protocol_sink = NULL; + ret->priority = 0; + + URLMON_LockModule(); + + *protocol = PROTOCOL(ret); + return S_OK; +} diff --git a/reactos/dll/win32/urlmon/file.c b/reactos/dll/win32/urlmon/file.c index fcdb772b89a..8d7b444b9d6 100644 --- a/reactos/dll/win32/urlmon/file.c +++ b/reactos/dll/win32/urlmon/file.c @@ -13,7 +13,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -78,7 +78,7 @@ static ULONG WINAPI FileProtocol_AddRef(IInternetProtocol *iface) { FileProtocol *This = PROTOCOL_THIS(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%ld\n", This, ref); + TRACE("(%p) ref=%d\n", This, ref); return ref; } @@ -87,7 +87,7 @@ static ULONG WINAPI FileProtocol_Release(IInternetProtocol *iface) FileProtocol *This = PROTOCOL_THIS(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%ld\n", This, ref); + TRACE("(%p) ref=%d\n", This, ref); if(!ref) { if(This->file) @@ -117,12 +117,18 @@ static HRESULT WINAPI FileProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl static const WCHAR wszFile[] = {'f','i','l','e',':'}; - TRACE("(%p)->(%s %p %p %08lx %ld)\n", This, debugstr_w(szUrl), pOIProtSink, + TRACE("(%p)->(%s %p %p %08x %d)\n", This, debugstr_w(szUrl), pOIProtSink, pOIBindInfo, grfPI, dwReserved); memset(&bindinfo, 0, sizeof(bindinfo)); bindinfo.cbSize = sizeof(BINDINFO); - IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo); + hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &grfBINDF, &bindinfo); + if(FAILED(hres)) { + WARN("GetBindInfo failed: %08x\n", hres); + return hres; + } + + ReleaseBindInfo(&bindinfo); if(lstrlenW(szUrl) < sizeof(wszFile)/sizeof(WCHAR) || memcmp(szUrl, wszFile, sizeof(wszFile))) @@ -198,7 +204,7 @@ static HRESULT WINAPI FileProtocol_Abort(IInternetProtocol *iface, HRESULT hrRea DWORD dwOptions) { FileProtocol *This = PROTOCOL_THIS(iface); - FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions); + FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions); return E_NOTIMPL; } @@ -206,7 +212,7 @@ static HRESULT WINAPI FileProtocol_Terminate(IInternetProtocol *iface, DWORD dwO { FileProtocol *This = PROTOCOL_THIS(iface); - TRACE("(%p)->(%08lx)\n", This, dwOptions); + TRACE("(%p)->(%08x)\n", This, dwOptions); return S_OK; } @@ -231,7 +237,7 @@ static HRESULT WINAPI FileProtocol_Read(IInternetProtocol *iface, void *pv, FileProtocol *This = PROTOCOL_THIS(iface); DWORD read = 0; - TRACE("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead); + TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); if(!This->file) return INET_E_DATA_NOT_AVAILABLE; @@ -245,10 +251,10 @@ static HRESULT WINAPI FileProtocol_Read(IInternetProtocol *iface, void *pv, } static HRESULT WINAPI FileProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove, - DWORD dwOrgin, ULARGE_INTEGER *plibNewPosition) + DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) { FileProtocol *This = PROTOCOL_THIS(iface); - FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.u.LowPart, dwOrgin, plibNewPosition); + FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); return E_NOTIMPL; } @@ -256,7 +262,7 @@ static HRESULT WINAPI FileProtocol_LockRequest(IInternetProtocol *iface, DWORD d { FileProtocol *This = PROTOCOL_THIS(iface); - TRACE("(%p)->(%08lx)\n", This, dwOptions); + TRACE("(%p)->(%08x)\n", This, dwOptions); return S_OK; } @@ -313,7 +319,7 @@ static HRESULT WINAPI FilePriority_SetPriority(IInternetPriority *iface, LONG nP { FileProtocol *This = PRIORITY_THIS(iface); - TRACE("(%p)->(%ld)\n", This, nPriority); + TRACE("(%p)->(%d)\n", This, nPriority); This->priority = nPriority; return S_OK; diff --git a/reactos/dll/win32/urlmon/format.c b/reactos/dll/win32/urlmon/format.c index 309c8cd3b1b..0a0a97d5cf0 100644 --- a/reactos/dll/win32/urlmon/format.c +++ b/reactos/dll/win32/urlmon/format.c @@ -13,7 +13,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -66,7 +66,7 @@ static ULONG WINAPI EnumFORMATETC_AddRef(IEnumFORMATETC *iface) { ENUMF_THIS(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%ld\n", This, ref); + TRACE("(%p) ref=%d\n", This, ref); return ref; } @@ -75,7 +75,7 @@ static ULONG WINAPI EnumFORMATETC_Release(IEnumFORMATETC *iface) ENUMF_THIS(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%ld\n", This, ref); + TRACE("(%p) ref=%d\n", This, ref); if(!ref) { HeapFree(GetProcessHeap(), 0, This->fetc); @@ -93,7 +93,7 @@ static HRESULT WINAPI EnumFORMATETC_Next(IEnumFORMATETC *iface, ULONG celt, ENUMF_THIS(iface); ULONG cnt; - TRACE("(%p)->(%ld %p %p)\n", This, celt, rgelt, pceltFetched); + TRACE("(%p)->(%d %p %p)\n", This, celt, rgelt, pceltFetched); if(!rgelt) return E_INVALIDARG; @@ -119,7 +119,7 @@ static HRESULT WINAPI EnumFORMATETC_Skip(IEnumFORMATETC *iface, ULONG celt) { ENUMF_THIS(iface); - TRACE("(%p)->(%ld)\n", This, celt); + TRACE("(%p)->(%d)\n", This, celt); This->it += celt; return This->it > This->fetc_cnt ? S_FALSE : S_OK; @@ -197,7 +197,7 @@ HRESULT WINAPI CreateFormatEnumerator(UINT cfmtetc, FORMATETC *rgfmtetc, */ HRESULT WINAPI RegisterFormatEnumerator(LPBC pBC, IEnumFORMATETC *pEFetc, DWORD reserved) { - TRACE("(%p %p %ld)\n", pBC, pEFetc, reserved); + TRACE("(%p %p %d)\n", pBC, pEFetc, reserved); if(reserved) WARN("reserved != 0\n"); diff --git a/reactos/dll/win32/urlmon/ftp.c b/reactos/dll/win32/urlmon/ftp.c index ef1cceb1036..6db8fe5af0a 100644 --- a/reactos/dll/win32/urlmon/ftp.c +++ b/reactos/dll/win32/urlmon/ftp.c @@ -13,7 +13,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -69,7 +69,7 @@ static ULONG WINAPI FtpProtocol_AddRef(IInternetProtocol *iface) { FtpProtocol *This = PROTOCOL_THIS(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%ld\n", This, ref); + TRACE("(%p) ref=%d\n", This, ref); return ref; } @@ -78,7 +78,7 @@ static ULONG WINAPI FtpProtocol_Release(IInternetProtocol *iface) FtpProtocol *This = PROTOCOL_THIS(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%ld\n", This, ref); + TRACE("(%p) ref=%d\n", This, ref); if(!ref) { HeapFree(GetProcessHeap(), 0, This); @@ -94,7 +94,7 @@ static HRESULT WINAPI FtpProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, DWORD grfPI, DWORD dwReserved) { FtpProtocol *This = PROTOCOL_THIS(iface); - FIXME("(%p)->(%s %p %p %08lx %ld)\n", This, debugstr_w(szUrl), pOIProtSink, + FIXME("(%p)->(%s %p %p %08x %d)\n", This, debugstr_w(szUrl), pOIProtSink, pOIBindInfo, grfPI, dwReserved); return E_NOTIMPL; } @@ -110,14 +110,14 @@ static HRESULT WINAPI FtpProtocol_Abort(IInternetProtocol *iface, HRESULT hrReas DWORD dwOptions) { FtpProtocol *This = PROTOCOL_THIS(iface); - FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions); + FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions); return E_NOTIMPL; } static HRESULT WINAPI FtpProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions) { FtpProtocol *This = PROTOCOL_THIS(iface); - FIXME("(%p)->(%08lx)\n", This, dwOptions); + FIXME("(%p)->(%08x)\n", This, dwOptions); return E_NOTIMPL; } @@ -139,22 +139,22 @@ static HRESULT WINAPI FtpProtocol_Read(IInternetProtocol *iface, void *pv, ULONG cb, ULONG *pcbRead) { FtpProtocol *This = PROTOCOL_THIS(iface); - FIXME("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead); + FIXME("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); return E_NOTIMPL; } static HRESULT WINAPI FtpProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove, - DWORD dwOrgin, ULARGE_INTEGER *plibNewPosition) + DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) { FtpProtocol *This = PROTOCOL_THIS(iface); - FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.u.LowPart, dwOrgin, plibNewPosition); + FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); return E_NOTIMPL; } static HRESULT WINAPI FtpProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions) { FtpProtocol *This = PROTOCOL_THIS(iface); - FIXME("(%p)->(%08lx)\n", This, dwOptions); + FIXME("(%p)->(%08x)\n", This, dwOptions); return E_NOTIMPL; } diff --git a/reactos/dll/win32/urlmon/http.c b/reactos/dll/win32/urlmon/http.c index 4f33572c62c..8dc343264d9 100644 --- a/reactos/dll/win32/urlmon/http.c +++ b/reactos/dll/win32/urlmon/http.c @@ -1,5 +1,6 @@ /* * Copyright 2005 Jacek Caban + * Copyright 2007 Misha Koshelev * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -13,7 +14,12 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* + * TODO: + * - Handle redirects as native. */ #include @@ -25,21 +31,212 @@ #include "winuser.h" #include "ole2.h" #include "urlmon.h" +#include "wininet.h" #include "urlmon_main.h" #include "wine/debug.h" +#include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(urlmon); +/* Flags are needed for, among other things, return HRESULTs from the Read function + * to conform to native. For example, Read returns: + * + * 1. E_PENDING if called before the request has completed, + * (flags = 0) + * 2. S_FALSE after all data has been read and S_OK has been reported, + * (flags = FLAG_REQUEST_COMPLETE | FLAG_ALL_DATA_READ | FLAG_RESULT_REPORTED) + * 3. INET_E_DATA_NOT_AVAILABLE if InternetQueryDataAvailable fails. The first time + * this occurs, INET_E_DATA_NOT_AVAILABLE will also be reported to the sink, + * (flags = FLAG_REQUEST_COMPLETE) + * but upon subsequent calls to Read no reporting will take place, yet + * InternetQueryDataAvailable will still be called, and, on failure, + * INET_E_DATA_NOT_AVAILABLE will still be returned. + * (flags = FLAG_REQUEST_COMPLETE | FLAG_RESULT_REPORTED) + * + * FLAG_FIRST_DATA_REPORTED and FLAG_LAST_DATA_REPORTED are needed for proper + * ReportData reporting. For example, if OnResponse returns S_OK, Continue will + * report BSCF_FIRSTDATANOTIFICATION, and when all data has been read Read will + * report BSCF_INTERMEDIATEDATANOTIFICATION|BSCF_LASTDATANOTIFICATION. However, + * if OnResponse does not return S_OK, Continue will not report data, and Read + * will report BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION when all + * data has been read. + */ +#define FLAG_REQUEST_COMPLETE 0x1 +#define FLAG_FIRST_CONTINUE_COMPLETE 0x2 +#define FLAG_FIRST_DATA_REPORTED 0x4 +#define FLAG_ALL_DATA_READ 0x8 +#define FLAG_LAST_DATA_REPORTED 0x10 +#define FLAG_RESULT_REPORTED 0x20 + typedef struct { const IInternetProtocolVtbl *lpInternetProtocolVtbl; const IInternetPriorityVtbl *lpInternetPriorityVtbl; + DWORD flags, grfBINDF; + BINDINFO bind_info; + IInternetProtocolSink *protocol_sink; + IHttpNegotiate *http_negotiate; + HINTERNET internet, connect, request; + LPWSTR full_header; + HANDLE lock; + ULONG current_position, content_length, available_bytes; LONG priority; LONG ref; } HttpProtocol; +/* Default headers from native */ +static const WCHAR wszHeaders[] = {'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g', + ':',' ','g','z','i','p',',',' ','d','e','f','l','a','t','e',0}; + +/* + * Helpers + */ + +static void HTTPPROTOCOL_ReportResult(HttpProtocol *This, HRESULT hres) +{ + if (!(This->flags & FLAG_RESULT_REPORTED) && + This->protocol_sink) + { + This->flags |= FLAG_RESULT_REPORTED; + IInternetProtocolSink_ReportResult(This->protocol_sink, hres, 0, NULL); + } +} + +static void HTTPPROTOCOL_ReportData(HttpProtocol *This) +{ + DWORD bscf; + if (!(This->flags & FLAG_LAST_DATA_REPORTED) && + This->protocol_sink) + { + if (This->flags & FLAG_FIRST_DATA_REPORTED) + { + bscf = BSCF_INTERMEDIATEDATANOTIFICATION; + } + else + { + This->flags |= FLAG_FIRST_DATA_REPORTED; + bscf = BSCF_FIRSTDATANOTIFICATION; + } + if (This->flags & FLAG_ALL_DATA_READ && + !(This->flags & FLAG_LAST_DATA_REPORTED)) + { + This->flags |= FLAG_LAST_DATA_REPORTED; + bscf |= BSCF_LASTDATANOTIFICATION; + } + IInternetProtocolSink_ReportData(This->protocol_sink, bscf, + This->current_position+This->available_bytes, + This->content_length); + } +} + +static void HTTPPROTOCOL_AllDataRead(HttpProtocol *This) +{ + if (!(This->flags & FLAG_ALL_DATA_READ)) + This->flags |= FLAG_ALL_DATA_READ; + HTTPPROTOCOL_ReportData(This); + HTTPPROTOCOL_ReportResult(This, S_OK); +} + +static void HTTPPROTOCOL_Close(HttpProtocol *This) +{ + if (This->protocol_sink) + { + IInternetProtocolSink_Release(This->protocol_sink); + This->protocol_sink = 0; + } + if (This->http_negotiate) + { + IHttpNegotiate_Release(This->http_negotiate); + This->http_negotiate = 0; + } + if (This->request) + { + InternetCloseHandle(This->request); + This->request = 0; + } + if (This->connect) + { + InternetCloseHandle(This->connect); + This->connect = 0; + } + if (This->internet) + { + InternetCloseHandle(This->internet); + This->internet = 0; + } + if (This->full_header) + { + if (This->full_header != wszHeaders) + HeapFree(GetProcessHeap(), 0, This->full_header); + This->full_header = 0; + } + if (This->bind_info.cbSize) + { + ReleaseBindInfo(&This->bind_info); + memset(&This->bind_info, 0, sizeof(This->bind_info)); + } + This->flags = 0; +} + +static void CALLBACK HTTPPROTOCOL_InternetStatusCallback( + HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus, + LPVOID lpvStatusInformation, DWORD dwStatusInformationLength) +{ + HttpProtocol *This = (HttpProtocol *)dwContext; + PROTOCOLDATA data; + ULONG ulStatusCode; + + switch (dwInternetStatus) + { + case INTERNET_STATUS_RESOLVING_NAME: + ulStatusCode = BINDSTATUS_FINDINGRESOURCE; + break; + case INTERNET_STATUS_CONNECTING_TO_SERVER: + ulStatusCode = BINDSTATUS_CONNECTING; + break; + case INTERNET_STATUS_SENDING_REQUEST: + ulStatusCode = BINDSTATUS_SENDINGREQUEST; + break; + case INTERNET_STATUS_REQUEST_COMPLETE: + This->flags |= FLAG_REQUEST_COMPLETE; + /* PROTOCOLDATA same as native */ + memset(&data, 0, sizeof(data)); + data.dwState = 0xf1000000; + if (This->flags & FLAG_FIRST_CONTINUE_COMPLETE) + data.pData = (LPVOID)BINDSTATUS_ENDDOWNLOADCOMPONENTS; + else + data.pData = (LPVOID)BINDSTATUS_DOWNLOADINGDATA; + if (This->grfBINDF & BINDF_FROMURLMON) + IInternetProtocolSink_Switch(This->protocol_sink, &data); + else + IInternetProtocol_Continue((IInternetProtocol *)This, &data); + return; + default: + WARN("Unhandled Internet status callback %d\n", dwInternetStatus); + return; + } + + IInternetProtocolSink_ReportProgress(This->protocol_sink, ulStatusCode, (LPWSTR)lpvStatusInformation); +} + +static inline LPWSTR strndupW(LPWSTR string, int len) +{ + LPWSTR ret = NULL; + if (string && + (ret = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR))) != NULL) + { + memcpy(ret, string, len*sizeof(WCHAR)); + ret[len] = 0; + } + return ret; +} + +/* + * Interface implementations + */ + #define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl) #define PRIORITY(x) ((IInternetPriority*) &(x)->lpInternetPriorityVtbl) @@ -77,7 +274,7 @@ static ULONG WINAPI HttpProtocol_AddRef(IInternetProtocol *iface) { HttpProtocol *This = PROTOCOL_THIS(iface); LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%ld\n", This, ref); + TRACE("(%p) ref=%d\n", This, ref); return ref; } @@ -86,9 +283,10 @@ static ULONG WINAPI HttpProtocol_Release(IInternetProtocol *iface) HttpProtocol *This = PROTOCOL_THIS(iface); LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%ld\n", This, ref); + TRACE("(%p) ref=%d\n", This, ref); if(!ref) { + HTTPPROTOCOL_Close(This); HeapFree(GetProcessHeap(), 0, This); URLMON_UnlockModule(); @@ -102,31 +300,409 @@ static HRESULT WINAPI HttpProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl DWORD grfPI, DWORD dwReserved) { HttpProtocol *This = PROTOCOL_THIS(iface); - FIXME("(%p)->(%s %p %p %08lx %ld)\n", This, debugstr_w(szUrl), pOIProtSink, + URL_COMPONENTSW url; + DWORD len = 0, request_flags = INTERNET_FLAG_KEEP_CONNECTION; + ULONG num = 0; + IServiceProvider *service_provider = 0; + IHttpNegotiate2 *http_negotiate2 = 0; + LPWSTR host = 0, path = 0, user = 0, pass = 0, addl_header = 0, + post_cookie = 0, optional = 0; + BYTE security_id[512]; + LPOLESTR user_agent, accept_mimes[257]; + HRESULT hres; + + static const WCHAR wszHttp[] = {'h','t','t','p',':'}; + static const WCHAR wszBindVerb[BINDVERB_CUSTOM][5] = + {{'G','E','T',0}, + {'P','O','S','T',0}, + {'P','U','T',0}}; + + TRACE("(%p)->(%s %p %p %08x %d)\n", This, debugstr_w(szUrl), pOIProtSink, pOIBindInfo, grfPI, dwReserved); - return E_NOTIMPL; + + memset(&This->bind_info, 0, sizeof(This->bind_info)); + This->bind_info.cbSize = sizeof(BINDINFO); + hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &This->grfBINDF, &This->bind_info); + if (hres != S_OK) + { + WARN("GetBindInfo failed: %08x\n", hres); + goto done; + } + + if (lstrlenW(szUrl) < sizeof(wszHttp)/sizeof(WCHAR) + || memcmp(szUrl, wszHttp, sizeof(wszHttp))) + { + hres = MK_E_SYNTAX; + goto done; + } + + memset(&url, 0, sizeof(url)); + url.dwStructSize = sizeof(url); + url.dwSchemeLength = url.dwHostNameLength = url.dwUrlPathLength = url.dwUserNameLength = + url.dwPasswordLength = 1; + if (!InternetCrackUrlW(szUrl, 0, 0, &url)) + { + hres = MK_E_SYNTAX; + goto done; + } + host = strndupW(url.lpszHostName, url.dwHostNameLength); + path = strndupW(url.lpszUrlPath, url.dwUrlPathLength); + user = strndupW(url.lpszUserName, url.dwUserNameLength); + pass = strndupW(url.lpszPassword, url.dwPasswordLength); + if (!url.nPort) + url.nPort = INTERNET_DEFAULT_HTTP_PORT; + + if(!(This->grfBINDF & BINDF_FROMURLMON)) + IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_DIRECTBIND, NULL); + + hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_USER_AGENT, &user_agent, + 1, &num); + if (hres != S_OK || !num) + { + CHAR null_char = 0; + LPSTR user_agenta = NULL; + len = 0; + if ((hres = ObtainUserAgentString(0, &null_char, &len)) != E_OUTOFMEMORY) + { + WARN("ObtainUserAgentString failed: %08x\n", hres); + } + else if (!(user_agenta = HeapAlloc(GetProcessHeap(), 0, len*sizeof(CHAR)))) + { + WARN("Out of memory\n"); + } + else if ((hres = ObtainUserAgentString(0, user_agenta, &len)) != S_OK) + { + WARN("ObtainUserAgentString failed: %08x\n", hres); + } + else + { + if (!(user_agent = CoTaskMemAlloc((len)*sizeof(WCHAR)))) + WARN("Out of memory\n"); + else + MultiByteToWideChar(CP_ACP, 0, user_agenta, -1, user_agent, len*sizeof(WCHAR)); + } + HeapFree(GetProcessHeap(), 0, user_agenta); + } + + This->internet = InternetOpenW(user_agent, 0, NULL, NULL, INTERNET_FLAG_ASYNC); + if (!This->internet) + { + WARN("InternetOpen failed: %d\n", GetLastError()); + hres = INET_E_NO_SESSION; + goto done; + } + + IInternetProtocolSink_AddRef(pOIProtSink); + This->protocol_sink = pOIProtSink; + + /* Native does not check for success of next call, so we won't either */ + InternetSetStatusCallbackW(This->internet, HTTPPROTOCOL_InternetStatusCallback); + + This->connect = InternetConnectW(This->internet, host, url.nPort, user, + pass, INTERNET_SERVICE_HTTP, 0, (DWORD)This); + if (!This->connect) + { + WARN("InternetConnect failed: %d\n", GetLastError()); + hres = INET_E_CANNOT_CONNECT; + goto done; + } + + num = sizeof(accept_mimes)/sizeof(accept_mimes[0])-1; + hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_ACCEPT_MIMES, + accept_mimes, + num, &num); + if (hres != S_OK) + { + WARN("GetBindString BINDSTRING_ACCEPT_MIMES failed: %08x\n", hres); + hres = INET_E_NO_VALID_MEDIA; + goto done; + } + accept_mimes[num] = 0; + + if (This->grfBINDF & BINDF_NOWRITECACHE) + request_flags |= INTERNET_FLAG_NO_CACHE_WRITE; + This->request = HttpOpenRequestW(This->connect, This->bind_info.dwBindVerb < BINDVERB_CUSTOM ? + wszBindVerb[This->bind_info.dwBindVerb] : + This->bind_info.szCustomVerb, + path, NULL, NULL, (LPCWSTR *)accept_mimes, + request_flags, (DWORD)This); + if (!This->request) + { + WARN("HttpOpenRequest failed: %d\n", GetLastError()); + hres = INET_E_RESOURCE_NOT_FOUND; + goto done; + } + + hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider, + (void **)&service_provider); + if (hres != S_OK) + { + WARN("IInternetProtocolSink_QueryInterface IID_IServiceProvider failed: %08x\n", hres); + goto done; + } + + hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate, + &IID_IHttpNegotiate, (void **)&This->http_negotiate); + if (hres != S_OK) + { + WARN("IServiceProvider_QueryService IID_IHttpNegotiate failed: %08x\n", hres); + goto done; + } + + hres = IHttpNegotiate_BeginningTransaction(This->http_negotiate, szUrl, wszHeaders, + 0, &addl_header); + if (hres != S_OK) + { + WARN("IHttpNegotiate_BeginningTransaction failed: %08x\n", hres); + goto done; + } + else if (addl_header == NULL) + { + This->full_header = (LPWSTR)wszHeaders; + } + else + { + int len_addl_header = lstrlenW(addl_header); + This->full_header = HeapAlloc(GetProcessHeap(), 0, + len_addl_header*sizeof(WCHAR)+sizeof(wszHeaders)); + if (!This->full_header) + { + WARN("Out of memory\n"); + hres = E_OUTOFMEMORY; + goto done; + } + lstrcpyW(This->full_header, addl_header); + lstrcpyW(&This->full_header[len_addl_header], wszHeaders); + } + + hres = IServiceProvider_QueryService(service_provider, &IID_IHttpNegotiate2, + &IID_IHttpNegotiate2, (void **)&http_negotiate2); + if (hres != S_OK) + { + WARN("IServiceProvider_QueryService IID_IHttpNegotiate2 failed: %08x\n", hres); + /* No goto done as per native */ + } + else + { + len = sizeof(security_id)/sizeof(security_id[0]); + hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, security_id, &len, 0); + if (hres != S_OK) + { + WARN("IHttpNegotiate2_GetRootSecurityId failed: %08x\n", hres); + /* No goto done as per native */ + } + } + + /* FIXME: Handle security_id. Native calls undocumented function IsHostInProxyBypassList. */ + + if (This->bind_info.dwBindVerb == BINDVERB_POST) + { + num = 0; + hres = IInternetBindInfo_GetBindString(pOIBindInfo, BINDSTRING_POST_COOKIE, &post_cookie, + 1, &num); + if (hres == S_OK && num && + !InternetSetOptionW(This->request, INTERNET_OPTION_SECONDARY_CACHE_KEY, + post_cookie, lstrlenW(post_cookie))) + { + WARN("InternetSetOption INTERNET_OPTION_SECONDARY_CACHE_KEY failed: %d\n", + GetLastError()); + } + } + + if (This->bind_info.dwBindVerb != BINDVERB_GET) + { + /* Native does not use GlobalLock/GlobalUnlock, so we won't either */ + if (This->bind_info.stgmedData.tymed != TYMED_HGLOBAL) + WARN("Expected This->bind_info.stgmedData.tymed to be TYMED_HGLOBAL, not %d\n", + This->bind_info.stgmedData.tymed); + else + optional = (LPWSTR)This->bind_info.stgmedData.hGlobal; + } + if (!HttpSendRequestW(This->request, This->full_header, lstrlenW(This->full_header), + optional, + optional ? This->bind_info.cbstgmedData : 0) && + GetLastError() != ERROR_IO_PENDING) + { + WARN("HttpSendRequest failed: %d\n", GetLastError()); + hres = INET_E_DOWNLOAD_FAILURE; + goto done; + } + + hres = S_OK; +done: + if (hres != S_OK) + { + IInternetProtocolSink_ReportResult(pOIProtSink, hres, 0, NULL); + HTTPPROTOCOL_Close(This); + } + + CoTaskMemFree(post_cookie); + CoTaskMemFree(addl_header); + if (http_negotiate2) + IHttpNegotiate2_Release(http_negotiate2); + if (service_provider) + IServiceProvider_Release(service_provider); + + while (num(%p)\n", This, pProtocolData); - return E_NOTIMPL; + DWORD len = sizeof(DWORD), status_code; + LPWSTR response_headers = 0, content_type = 0, content_length = 0; + + static const WCHAR wszDefaultContentType[] = + {'t','e','x','t','/','h','t','m','l',0}; + + TRACE("(%p)->(%p)\n", This, pProtocolData); + + if (!pProtocolData) + { + WARN("Expected pProtocolData to be non-NULL\n"); + return S_OK; + } + else if (!This->request) + { + WARN("Expected request to be non-NULL\n"); + return S_OK; + } + else if (!This->http_negotiate) + { + WARN("Expected IHttpNegotiate pointer to be non-NULL\n"); + return S_OK; + } + else if (!This->protocol_sink) + { + WARN("Expected IInternetProtocolSink pointer to be non-NULL\n"); + return S_OK; + } + + if (pProtocolData->pData == (LPVOID)BINDSTATUS_DOWNLOADINGDATA) + { + if (!HttpQueryInfoW(This->request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, + &status_code, &len, NULL)) + { + WARN("HttpQueryInfo failed: %d\n", GetLastError()); + } + else + { + len = 0; + if ((!HttpQueryInfoW(This->request, HTTP_QUERY_RAW_HEADERS_CRLF, response_headers, &len, + NULL) && + GetLastError() != ERROR_INSUFFICIENT_BUFFER) || + !(response_headers = HeapAlloc(GetProcessHeap(), 0, len)) || + !HttpQueryInfoW(This->request, HTTP_QUERY_RAW_HEADERS_CRLF, response_headers, &len, + NULL)) + { + WARN("HttpQueryInfo failed: %d\n", GetLastError()); + } + else + { + HRESULT hres = IHttpNegotiate_OnResponse(This->http_negotiate, status_code, + response_headers, NULL, NULL); + if (hres != S_OK) + { + WARN("IHttpNegotiate_OnResponse failed: %08x\n", hres); + goto done; + } + } + } + + len = 0; + if ((!HttpQueryInfoW(This->request, HTTP_QUERY_CONTENT_TYPE, content_type, &len, NULL) && + GetLastError() != ERROR_INSUFFICIENT_BUFFER) || + !(content_type = HeapAlloc(GetProcessHeap(), 0, len)) || + !HttpQueryInfoW(This->request, HTTP_QUERY_CONTENT_TYPE, content_type, &len, NULL)) + { + WARN("HttpQueryInfo failed: %d\n", GetLastError()); + IInternetProtocolSink_ReportProgress(This->protocol_sink, + (This->grfBINDF & BINDF_FROMURLMON) ? + BINDSTATUS_MIMETYPEAVAILABLE : + BINDSTATUS_RAWMIMETYPE, + wszDefaultContentType); + } + else + { + IInternetProtocolSink_ReportProgress(This->protocol_sink, + (This->grfBINDF & BINDF_FROMURLMON) ? + BINDSTATUS_MIMETYPEAVAILABLE : + BINDSTATUS_RAWMIMETYPE, + content_type); + } + + len = 0; + if ((!HttpQueryInfoW(This->request, HTTP_QUERY_CONTENT_LENGTH, content_length, &len, NULL) && + GetLastError() != ERROR_INSUFFICIENT_BUFFER) || + !(content_length = HeapAlloc(GetProcessHeap(), 0, len)) || + !HttpQueryInfoW(This->request, HTTP_QUERY_CONTENT_LENGTH, content_length, &len, NULL)) + { + WARN("HttpQueryInfo failed: %d\n", GetLastError()); + This->content_length = 0; + } + else + { + This->content_length = atoiW(content_length); + } + + This->flags |= FLAG_FIRST_CONTINUE_COMPLETE; + } + + if (pProtocolData->pData >= (LPVOID)BINDSTATUS_DOWNLOADINGDATA) + { + if (!InternetQueryDataAvailable(This->request, &This->available_bytes, 0, 0)) + { + if (GetLastError() == ERROR_IO_PENDING) + { + This->flags &= ~FLAG_REQUEST_COMPLETE; + } + else + { + WARN("InternetQueryDataAvailable failed: %d\n", GetLastError()); + HTTPPROTOCOL_ReportResult(This, INET_E_DATA_NOT_AVAILABLE); + } + } + else + { + HTTPPROTOCOL_ReportData(This); + } + } + +done: + HeapFree(GetProcessHeap(), 0, response_headers); + HeapFree(GetProcessHeap(), 0, content_type); + HeapFree(GetProcessHeap(), 0, content_length); + + /* Returns S_OK on native */ + return S_OK; } static HRESULT WINAPI HttpProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason, DWORD dwOptions) { HttpProtocol *This = PROTOCOL_THIS(iface); - FIXME("(%p)->(%08lx %08lx)\n", This, hrReason, dwOptions); + FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions); return E_NOTIMPL; } static HRESULT WINAPI HttpProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions) { HttpProtocol *This = PROTOCOL_THIS(iface); - FIXME("(%p)->(%08lx)\n", This, dwOptions); - return E_NOTIMPL; + + TRACE("(%p)->(%08x)\n", This, dwOptions); + HTTPPROTOCOL_Close(This); + + return S_OK; } static HRESULT WINAPI HttpProtocol_Suspend(IInternetProtocol *iface) @@ -147,30 +723,116 @@ static HRESULT WINAPI HttpProtocol_Read(IInternetProtocol *iface, void *pv, ULONG cb, ULONG *pcbRead) { HttpProtocol *This = PROTOCOL_THIS(iface); - FIXME("(%p)->(%p %lu %p)\n", This, pv, cb, pcbRead); - return E_NOTIMPL; + ULONG read = 0, len = 0; + HRESULT hres = S_FALSE; + + TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); + + if (!(This->flags & FLAG_REQUEST_COMPLETE)) + { + hres = E_PENDING; + } + else while (!(This->flags & FLAG_ALL_DATA_READ) && + read < cb) + { + if (This->available_bytes == 0) + { + /* InternetQueryDataAvailable may immediately fork and perform its asynchronous + * read, so clear the flag _before_ calling so it does not incorrectly get cleared + * after the status callback is called */ + This->flags &= ~FLAG_REQUEST_COMPLETE; + if (!InternetQueryDataAvailable(This->request, &This->available_bytes, 0, 0)) + { + if (GetLastError() == ERROR_IO_PENDING) + { + hres = E_PENDING; + } + else + { + WARN("InternetQueryDataAvailable failed: %d\n", GetLastError()); + hres = INET_E_DATA_NOT_AVAILABLE; + HTTPPROTOCOL_ReportResult(This, hres); + } + goto done; + } + else if (This->available_bytes == 0) + { + HTTPPROTOCOL_AllDataRead(This); + } + } + else + { + if (!InternetReadFile(This->request, ((BYTE *)pv)+read, + This->available_bytes > cb-read ? + cb-read : This->available_bytes, &len)) + { + WARN("InternetReadFile failed: %d\n", GetLastError()); + hres = INET_E_DOWNLOAD_FAILURE; + HTTPPROTOCOL_ReportResult(This, hres); + goto done; + } + else if (len == 0) + { + HTTPPROTOCOL_AllDataRead(This); + } + else + { + read += len; + This->current_position += len; + This->available_bytes -= len; + } + } + } + + /* Per MSDN this should be if (read == cb), but native returns S_OK + * if any bytes were read, so we will too */ + if (read) + hres = S_OK; + +done: + if (pcbRead) + *pcbRead = read; + + if (hres != E_PENDING) + This->flags |= FLAG_REQUEST_COMPLETE; + + return hres; } static HRESULT WINAPI HttpProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove, - DWORD dwOrgin, ULARGE_INTEGER *plibNewPosition) + DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) { HttpProtocol *This = PROTOCOL_THIS(iface); - FIXME("(%p)->(%ld %ld %p)\n", This, dlibMove.u.LowPart, dwOrgin, plibNewPosition); + FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); return E_NOTIMPL; } static HRESULT WINAPI HttpProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions) { HttpProtocol *This = PROTOCOL_THIS(iface); - FIXME("(%p)->(%08lx)\n", This, dwOptions); - return E_NOTIMPL; + + TRACE("(%p)->(%08x)\n", This, dwOptions); + + if (!InternetLockRequestFile(This->request, &This->lock)) + WARN("InternetLockRequest failed: %d\n", GetLastError()); + + return S_OK; } static HRESULT WINAPI HttpProtocol_UnlockRequest(IInternetProtocol *iface) { HttpProtocol *This = PROTOCOL_THIS(iface); - FIXME("(%p)\n", This); - return E_NOTIMPL; + + TRACE("(%p)\n", This); + + if (This->lock) + { + if (!InternetUnlockRequestFile(This->lock)) + WARN("InternetUnlockRequest failed: %d\n", GetLastError()); + This->lock = 0; + } + + return S_OK; } #undef PROTOCOL_THIS @@ -199,7 +861,7 @@ static HRESULT WINAPI HttpPriority_SetPriority(IInternetPriority *iface, LONG nP { HttpProtocol *This = PRIORITY_THIS(iface); - TRACE("(%p)->(%ld)\n", This, nPriority); + TRACE("(%p)->(%d)\n", This, nPriority); This->priority = nPriority; return S_OK; @@ -253,10 +915,16 @@ HRESULT HttpProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj) ret->lpInternetProtocolVtbl = &HttpProtocolVtbl; ret->lpInternetPriorityVtbl = &HttpPriorityVtbl; - - ret->ref = 1; - + ret->flags = ret->grfBINDF = 0; + memset(&ret->bind_info, 0, sizeof(ret->bind_info)); + ret->protocol_sink = 0; + ret->http_negotiate = 0; + ret->internet = ret->connect = ret->request = 0; + ret->full_header = 0; + ret->lock = 0; + ret->current_position = ret->content_length = ret->available_bytes = 0; ret->priority = 0; + ret->ref = 1; *ppobj = PROTOCOL(ret); diff --git a/reactos/dll/win32/urlmon/internet.c b/reactos/dll/win32/urlmon/internet.c index 94b733051fe..26269823610 100644 --- a/reactos/dll/win32/urlmon/internet.c +++ b/reactos/dll/win32/urlmon/internet.c @@ -13,7 +13,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -39,7 +39,7 @@ static HRESULT parse_schema(LPCWSTR url, DWORD flags, LPWSTR result, DWORD size, WCHAR *ptr; DWORD len = 0; - TRACE("(%s %08lx %p %ld %p)\n", debugstr_w(url), flags, result, size, rsize); + TRACE("(%s %08x %p %d %p)\n", debugstr_w(url), flags, result, size, rsize); if(flags) ERR("wrong flags\n"); @@ -61,20 +61,30 @@ static HRESULT parse_schema(LPCWSTR url, DWORD flags, LPWSTR result, DWORD size, return S_OK; } -static IInternetProtocolInfo *get_protocol_info(LPCWSTR url) +static HRESULT parse_canonicalize_url(LPCWSTR url, DWORD flags, LPWSTR result, + DWORD size, DWORD *rsize) { - IInternetProtocolInfo *ret = NULL; - IUnknown *unk; + IInternetProtocolInfo *protocol_info; + DWORD prsize = size; HRESULT hres; - hres = get_protocol_iface(url, &unk); - if(FAILED(hres)) - return NULL; + TRACE("(%s %08x %p %d %p)\n", debugstr_w(url), flags, result, size, rsize); - IUnknown_QueryInterface(unk, &IID_IInternetProtocolInfo, (void**)&ret); - IUnknown_Release(unk); + protocol_info = get_protocol_info(url); - return ret; + if(protocol_info) { + hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_CANONICALIZE, + flags, result, size, rsize, 0); + IInternetProtocolInfo_Release(protocol_info); + if(SUCCEEDED(hres)) + return hres; + } + + hres = UrlCanonicalizeW(url, result, &prsize, flags); + + if(rsize) + *rsize = prsize; + return hres; } static HRESULT parse_security_url(LPCWSTR url, DWORD flags, LPWSTR result, DWORD size, DWORD *rsize) @@ -82,13 +92,14 @@ static HRESULT parse_security_url(LPCWSTR url, DWORD flags, LPWSTR result, DWORD IInternetProtocolInfo *protocol_info; HRESULT hres; - TRACE("(%s %08lx %p %ld %p)\n", debugstr_w(url), flags, result, size, rsize); + TRACE("(%s %08x %p %d %p)\n", debugstr_w(url), flags, result, size, rsize); protocol_info = get_protocol_info(url); if(protocol_info) { hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_SECURITY_URL, flags, result, size, rsize, 0); + IInternetProtocolInfo_Release(protocol_info); return hres; } @@ -101,13 +112,14 @@ static HRESULT parse_encode(LPCWSTR url, DWORD flags, LPWSTR result, DWORD size, DWORD prsize; HRESULT hres; - TRACE("(%s %08lx %p %ld %p)\n", debugstr_w(url), flags, result, size, rsize); + TRACE("(%s %08x %p %d %p)\n", debugstr_w(url), flags, result, size, rsize); protocol_info = get_protocol_info(url); if(protocol_info) { hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_ENCODE, flags, result, size, rsize, 0); + IInternetProtocolInfo_Release(protocol_info); if(SUCCEEDED(hres)) return hres; } @@ -127,13 +139,14 @@ static HRESULT parse_path_from_url(LPCWSTR url, DWORD flags, LPWSTR result, DWOR DWORD prsize; HRESULT hres; - TRACE("(%s %08lx %p %ld %p)\n", debugstr_w(url), flags, result, size, rsize); + TRACE("(%s %08x %p %d %p)\n", debugstr_w(url), flags, result, size, rsize); protocol_info = get_protocol_info(url); if(protocol_info) { hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_PATH_FROM_URL, flags, result, size, rsize, 0); + IInternetProtocolInfo_Release(protocol_info); if(SUCCEEDED(hres)) return hres; } @@ -152,13 +165,14 @@ static HRESULT parse_security_domain(LPCWSTR url, DWORD flags, LPWSTR result, IInternetProtocolInfo *protocol_info; HRESULT hres; - TRACE("(%s %08lx %p %ld %p)\n", debugstr_w(url), flags, result, size, rsize); + TRACE("(%s %08x %p %d %p)\n", debugstr_w(url), flags, result, size, rsize); protocol_info = get_protocol_info(url); if(protocol_info) { hres = IInternetProtocolInfo_ParseUrl(protocol_info, url, PARSE_SECURITY_DOMAIN, flags, result, size, rsize, 0); + IInternetProtocolInfo_Release(protocol_info); if(SUCCEEDED(hres)) return hres; } @@ -173,9 +187,11 @@ HRESULT WINAPI CoInternetParseUrl(LPCWSTR pwzUrl, PARSEACTION ParseAction, DWORD LPWSTR pszResult, DWORD cchResult, DWORD *pcchResult, DWORD dwReserved) { if(dwReserved) - WARN("dwReserved = %ld\n", dwReserved); + WARN("dwReserved = %d\n", dwReserved); switch(ParseAction) { + case PARSE_CANONICALIZE: + return parse_canonicalize_url(pwzUrl, dwFlags, pszResult, cchResult, pcchResult); case PARSE_SECURITY_URL: return parse_security_url(pwzUrl, dwFlags, pszResult, cchResult, pcchResult); case PARSE_ENCODE: @@ -204,7 +220,7 @@ HRESULT WINAPI CoInternetCombineUrl(LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD size = cchResult; HRESULT hres; - TRACE("(%s,%s,0x%08lx,%p,%ld,%p,%ld)\n", debugstr_w(pwzBaseUrl), + TRACE("(%s,%s,0x%08x,%p,%d,%p,%d)\n", debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl), dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved); @@ -213,6 +229,7 @@ HRESULT WINAPI CoInternetCombineUrl(LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, if(protocol_info) { hres = IInternetProtocolInfo_CombineUrl(protocol_info, pwzBaseUrl, pwzRelativeUrl, dwCombineFlags, pwzResult, cchResult, pcchResult, dwReserved); + IInternetProtocolInfo_Release(protocol_info); if(SUCCEEDED(hres)) return hres; } @@ -225,3 +242,25 @@ HRESULT WINAPI CoInternetCombineUrl(LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, return hres; } + +/************************************************************************** + * CoInternetCompareUrl (URLMON.@) + */ +HRESULT WINAPI CoInternetCompareUrl(LPCWSTR pwzUrl1, LPCWSTR pwzUrl2, DWORD dwCompareFlags) +{ + IInternetProtocolInfo *protocol_info; + HRESULT hres; + + TRACE("(%s,%s,%08x)\n", debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags); + + protocol_info = get_protocol_info(pwzUrl1); + + if(protocol_info) { + hres = IInternetProtocolInfo_CompareUrl(protocol_info, pwzUrl1, pwzUrl2, dwCompareFlags); + IInternetProtocolInfo_Release(protocol_info); + if(SUCCEEDED(hres)) + return hres; + } + + return UrlCompareW(pwzUrl1, pwzUrl2, dwCompareFlags) ? S_FALSE : S_OK; +} diff --git a/reactos/dll/win32/urlmon/mk.c b/reactos/dll/win32/urlmon/mk.c new file mode 100644 index 00000000000..2af01f2a0fc --- /dev/null +++ b/reactos/dll/win32/urlmon/mk.c @@ -0,0 +1,322 @@ +/* + * Copyright 2007 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 + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "ole2.h" +#include "urlmon.h" +#include "urlmon_main.h" + +#include "wine/debug.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(urlmon); + +typedef struct { + const IInternetProtocolVtbl *lpInternetProtocolVtbl; + + LONG ref; + + IStream *stream; +} MkProtocol; + +#define PROTOCOL_THIS(iface) DEFINE_THIS(MkProtocol, InternetProtocol, iface) + +#define PROTOCOL(x) ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl) + +static HRESULT WINAPI MkProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv) +{ + MkProtocol *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); + } + + if(*ppv) { + IInternetProtocol_AddRef(iface); + return S_OK; + } + + WARN("not supported interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI MkProtocol_AddRef(IInternetProtocol *iface) +{ + MkProtocol *This = PROTOCOL_THIS(iface); + LONG ref = InterlockedIncrement(&This->ref); + TRACE("(%p) ref=%d\n", This, ref); + return ref; +} + +static ULONG WINAPI MkProtocol_Release(IInternetProtocol *iface) +{ + MkProtocol *This = PROTOCOL_THIS(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + if(!ref) { + if(This->stream) + IStream_Release(This->stream); + + HeapFree(GetProcessHeap(), 0, This); + + URLMON_UnlockModule(); + } + + return ref; +} + +static HRESULT report_result(IInternetProtocolSink *sink, HRESULT hres, DWORD dwError) +{ + IInternetProtocolSink_ReportResult(sink, hres, dwError, NULL); + return hres; +} + +static HRESULT WINAPI MkProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl, + IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo, + DWORD grfPI, DWORD dwReserved) +{ + MkProtocol *This = PROTOCOL_THIS(iface); + IParseDisplayName *pdn; + IMoniker *mon; + LPWSTR mime, progid, display_name; + LPCWSTR ptr, ptr2; + BINDINFO bindinfo; + STATSTG statstg; + DWORD bindf=0, eaten=0, len; + CLSID clsid; + HRESULT hres; + + static const WCHAR wszMK[] = {'m','k',':'}; + + TRACE("(%p)->(%s %p %p %08x %d)\n", This, debugstr_w(szUrl), pOIProtSink, + pOIBindInfo, grfPI, dwReserved); + + memset(&bindinfo, 0, sizeof(bindinfo)); + bindinfo.cbSize = sizeof(BINDINFO); + hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &bindf, &bindinfo); + if(FAILED(hres)) { + WARN("GetBindInfo failed: %08x\n", hres); + return hres; + } + + ReleaseBindInfo(&bindinfo); + + if(strncmpiW(szUrl, wszMK, sizeof(wszMK)/sizeof(WCHAR))) + return MK_E_SYNTAX; + + IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_DIRECTBIND, NULL); + IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_SENDINGREQUEST, NULL); + + hres = FindMimeFromData(NULL, szUrl, NULL, 0, NULL, 0, &mime, 0); + if(SUCCEEDED(hres)) { + IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE, mime); + CoTaskMemFree(mime); + } + + ptr2 = szUrl + sizeof(wszMK)/sizeof(WCHAR); + if(*ptr2 != '@') + return report_result(pOIProtSink, INET_E_RESOURCE_NOT_FOUND, ERROR_INVALID_PARAMETER); + ptr2++; + + ptr = strchrW(ptr2, ':'); + if(!ptr) + return report_result(pOIProtSink, INET_E_RESOURCE_NOT_FOUND, ERROR_INVALID_PARAMETER); + + progid = HeapAlloc(GetProcessHeap(), 0, (ptr-ptr2+1)*sizeof(WCHAR)); + memcpy(progid, ptr2, (ptr-ptr2)*sizeof(WCHAR)); + progid[ptr-ptr2] = 0; + hres = CLSIDFromProgID(progid, &clsid); + HeapFree(GetProcessHeap(), 0, progid); + if(FAILED(hres)) + return report_result(pOIProtSink, INET_E_RESOURCE_NOT_FOUND, ERROR_INVALID_PARAMETER); + + hres = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, + &IID_IParseDisplayName, (void**)&pdn); + if(FAILED(hres)) { + WARN("Could not create object %s\n", debugstr_guid(&clsid)); + return report_result(pOIProtSink, hres, ERROR_INVALID_PARAMETER); + } + + len = strlenW(--ptr2); + display_name = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR)); + memcpy(display_name, ptr2, (len+1)*sizeof(WCHAR)); + hres = IParseDisplayName_ParseDisplayName(pdn, NULL /* FIXME */, display_name, &eaten, &mon); + HeapFree(GetProcessHeap(), 0, display_name); + IParseDisplayName_Release(pdn); + if(FAILED(hres)) { + WARN("ParseDisplayName failed: %08x\n", hres); + return report_result(pOIProtSink, hres, ERROR_INVALID_PARAMETER); + } + + if(This->stream) { + IStream_Release(This->stream); + This->stream = NULL; + } + + hres = IMoniker_BindToStorage(mon, NULL /* FIXME */, NULL, &IID_IStream, (void**)&This->stream); + IMoniker_Release(mon); + if(FAILED(hres)) { + WARN("BindToStorage failed: %08x\n", hres); + return report_result(pOIProtSink, hres, ERROR_INVALID_PARAMETER); + } + + hres = IStream_Stat(This->stream, &statstg, STATFLAG_NONAME); + if(FAILED(hres)) { + WARN("Stat failed: %08x\n", hres); + return report_result(pOIProtSink, hres, ERROR_INVALID_PARAMETER); + } + + IInternetProtocolSink_ReportData(pOIProtSink, + BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION, + statstg.cbSize.u.LowPart, statstg.cbSize.u.LowPart); + + return report_result(pOIProtSink, S_OK, ERROR_SUCCESS); +} + +static HRESULT WINAPI MkProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData) +{ + MkProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)->(%p)\n", This, pProtocolData); + return E_NOTIMPL; +} + +static HRESULT WINAPI MkProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason, + DWORD dwOptions) +{ + MkProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions); + return E_NOTIMPL; +} + +static HRESULT WINAPI MkProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions) +{ + MkProtocol *This = PROTOCOL_THIS(iface); + + TRACE("(%p)->(%08x)\n", This, dwOptions); + + return S_OK; +} + +static HRESULT WINAPI MkProtocol_Suspend(IInternetProtocol *iface) +{ + MkProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI MkProtocol_Resume(IInternetProtocol *iface) +{ + MkProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI MkProtocol_Read(IInternetProtocol *iface, void *pv, + ULONG cb, ULONG *pcbRead) +{ + MkProtocol *This = PROTOCOL_THIS(iface); + + TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); + + if(!This->stream) + return E_FAIL; + + return IStream_Read(This->stream, pv, cb, pcbRead); +} + +static HRESULT WINAPI MkProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove, + DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) +{ + MkProtocol *This = PROTOCOL_THIS(iface); + FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition); + return E_NOTIMPL; +} + +static HRESULT WINAPI MkProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions) +{ + MkProtocol *This = PROTOCOL_THIS(iface); + + TRACE("(%p)->(%08x)\n", This, dwOptions); + + return S_OK; +} + +static HRESULT WINAPI MkProtocol_UnlockRequest(IInternetProtocol *iface) +{ + MkProtocol *This = PROTOCOL_THIS(iface); + + TRACE("(%p)\n", This); + + return S_OK; +} + +#undef PROTOCOL_THIS + +static const IInternetProtocolVtbl MkProtocolVtbl = { + MkProtocol_QueryInterface, + MkProtocol_AddRef, + MkProtocol_Release, + MkProtocol_Start, + MkProtocol_Continue, + MkProtocol_Abort, + MkProtocol_Terminate, + MkProtocol_Suspend, + MkProtocol_Resume, + MkProtocol_Read, + MkProtocol_Seek, + MkProtocol_LockRequest, + MkProtocol_UnlockRequest +}; + +HRESULT MkProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj) +{ + MkProtocol *ret; + + TRACE("(%p %p)\n", pUnkOuter, ppobj); + + URLMON_LockModule(); + + ret = HeapAlloc(GetProcessHeap(), 0, sizeof(MkProtocol)); + + ret->lpInternetProtocolVtbl = &MkProtocolVtbl; + ret->ref = 1; + ret->stream = NULL; + + /* NOTE: + * Native returns NULL ppobj and S_OK in CreateInstance if called with IID_IUnknown riid. + */ + *ppobj = PROTOCOL(ret); + + return S_OK; +} diff --git a/reactos/dll/win32/urlmon/regsvr.c b/reactos/dll/win32/urlmon/regsvr.c index c04803bc72b..64eb1a78dc2 100644 --- a/reactos/dll/win32/urlmon/regsvr.c +++ b/reactos/dll/win32/urlmon/regsvr.c @@ -15,10 +15,9 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#define COM_NO_WINDOWS_H #include #include #include @@ -155,7 +154,7 @@ static HRESULT register_interfaces(struct regsvr_interface const *list) } if (list->base_iid) { - register_key_guid(iid_key, base_ifa_keyname, list->base_iid); + res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid); if (res != ERROR_SUCCESS) goto error_close_iid_key; } @@ -177,12 +176,12 @@ static HRESULT register_interfaces(struct regsvr_interface const *list) } if (list->ps_clsid) { - register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); + res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); if (res != ERROR_SUCCESS) goto error_close_iid_key; } if (list->ps_clsid32) { - register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); + res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); if (res != ERROR_SUCCESS) goto error_close_iid_key; } @@ -557,6 +556,18 @@ static struct regsvr_coclass const coclass_list[] = { "urlmon.dll", "Apartment" }, + { &CLSID_InternetSecurityManager, + "Security Manager", + NULL, + "urlmon.dll", + "Both" + }, + { &CLSID_InternetZoneManager, + "URL Zone Manager", + NULL, + "urlmon.dll", + "Both" + }, { NULL } /* list terminator */ }; @@ -572,9 +583,14 @@ static struct regsvr_interface const interface_list[] = { * register_inf */ -#define INF_SET_CLSID(clsid) \ - pse[i].pszName = "CLSID_" #clsid; \ - clsids[i++] = &CLSID_ ## clsid; +#define INF_SET_CLSID(clsid) \ + do \ + { \ + static CHAR name[] = "CLSID_" #clsid; \ + \ + pse[i].pszName = name; \ + clsids[i++] = &CLSID_ ## clsid; \ + } while (0) static HRESULT register_inf(BOOL doregister) { @@ -587,7 +603,7 @@ static HRESULT register_inf(BOOL doregister) int i = 0; static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0}; - + INF_SET_CLSID(CdlProtocol); INF_SET_CLSID(FileProtocol); INF_SET_CLSID(FtpProtocol); @@ -598,7 +614,7 @@ static HRESULT register_inf(BOOL doregister) for(i = 0; i < sizeof(pse)/sizeof(pse[0]); i++) { pse[i].pszValue = HeapAlloc(GetProcessHeap(), 0, 39); - sprintf(pse[i].pszValue, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + sprintf(pse[i].pszValue, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", clsids[i]->Data1, clsids[i]->Data2, clsids[i]->Data3, clsids[i]->Data4[0], clsids[i]->Data4[1], clsids[i]->Data4[2], clsids[i]->Data4[3], clsids[i]->Data4[4], clsids[i]->Data4[5], clsids[i]->Data4[6], clsids[i]->Data4[7]); diff --git a/reactos/dll/win32/urlmon/rsrc.rc b/reactos/dll/win32/urlmon/rsrc.rc index af3b5462e9c..d71b2faff0d 100644 --- a/reactos/dll/win32/urlmon/rsrc.rc +++ b/reactos/dll/win32/urlmon/rsrc.rc @@ -13,9 +13,10 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +/* @makedep: urlmon.inf */ REGINST REGINST urlmon.inf #include "version.rc" diff --git a/reactos/dll/win32/urlmon/sec_mgr.c b/reactos/dll/win32/urlmon/sec_mgr.c index d2ac8e98f14..609ca4f7ddd 100644 --- a/reactos/dll/win32/urlmon/sec_mgr.c +++ b/reactos/dll/win32/urlmon/sec_mgr.c @@ -16,7 +16,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -68,6 +68,8 @@ static HRESULT map_url_to_zone(LPCWSTR url, DWORD *zone) 'P','r','o','t','o','c','o','l','D','e','f','a','u','l','t','s',0}; static const WCHAR wszFile[] = {'f','i','l','e',0}; + *zone = -1; + hres = CoInternetParseUrl(url, PARSE_SCHEMA, 0, schema, sizeof(schema)/sizeof(WCHAR), &size, 0); if(FAILED(hres)) return hres; @@ -97,6 +99,7 @@ static HRESULT map_url_to_zone(LPCWSTR url, DWORD *zone) size = sizeof(DWORD); res = RegQueryValueExW(hkey, schema, NULL, NULL, (PBYTE)zone, &size); + RegCloseKey(hkey); if(res == ERROR_SUCCESS) return S_OK; @@ -108,6 +111,7 @@ static HRESULT map_url_to_zone(LPCWSTR url, DWORD *zone) size = sizeof(DWORD); res = RegQueryValueExW(hkey, schema, NULL, NULL, (PBYTE)zone, &size); + RegCloseKey(hkey); if(res == ERROR_SUCCESS) return S_OK; @@ -150,7 +154,7 @@ static ULONG WINAPI SecManagerImpl_AddRef(IInternetSecurityManager* iface) SecManagerImpl *This = SECMGR_THIS(iface); ULONG refCount = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%lu\n", This, refCount); + TRACE("(%p) ref=%u\n", This, refCount); return refCount; } @@ -160,7 +164,7 @@ static ULONG WINAPI SecManagerImpl_Release(IInternetSecurityManager* iface) SecManagerImpl *This = SECMGR_THIS(iface); ULONG refCount = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%lu\n", This, refCount); + TRACE("(%p) ref=%u\n", This, refCount); /* destroy the object if there's no more reference on it */ if (!refCount){ @@ -238,7 +242,7 @@ static HRESULT WINAPI SecManagerImpl_MapUrlToZone(IInternetSecurityManager *ifac DWORD size; HRESULT hres; - TRACE("(%p)->(%s %p %08lx)\n", iface, debugstr_w(pwszUrl), pdwZone, dwFlags); + TRACE("(%p)->(%s %p %08x)\n", iface, debugstr_w(pwszUrl), pdwZone, dwFlags); if(This->custom_manager) { hres = IInternetSecurityManager_MapUrlToZone(This->custom_manager, @@ -251,7 +255,7 @@ static HRESULT WINAPI SecManagerImpl_MapUrlToZone(IInternetSecurityManager *ifac return E_INVALIDARG; if(dwFlags) - FIXME("not supported flags: %08lx\n", dwFlags); + FIXME("not supported flags: %08x\n", dwFlags); size = (strlenW(pwszUrl)+16) * sizeof(WCHAR); url = HeapAlloc(GetProcessHeap(), 0, size); @@ -358,7 +362,7 @@ static HRESULT WINAPI SecManagerImpl_ProcessUrlAction(IInternetSecurityManager * SecManagerImpl *This = SECMGR_THIS(iface); HRESULT hres; - TRACE("(%p)->(%s %08lx %p %08lx %p %08lx %08lx %08lx)\n", iface, debugstr_w(pwszUrl), dwAction, + TRACE("(%p)->(%s %08x %p %08x %p %08x %08x %08x)\n", iface, debugstr_w(pwszUrl), dwAction, pPolicy, cbPolicy, pContext, cbContext, dwFlags, dwReserved); if(This->custom_manager) { @@ -382,7 +386,7 @@ static HRESULT WINAPI SecManagerImpl_QueryCustomPolicy(IInternetSecurityManager SecManagerImpl *This = SECMGR_THIS(iface); HRESULT hres; - TRACE("(%p)->(%s %s %p %p %p %08lx %08lx )\n", iface, debugstr_w(pwszUrl), debugstr_guid(guidKey), + TRACE("(%p)->(%s %s %p %p %p %08x %08x )\n", iface, debugstr_w(pwszUrl), debugstr_guid(guidKey), ppPolicy, pcbPolicy, pContext, cbContext, dwReserved); if(This->custom_manager) { @@ -402,7 +406,7 @@ static HRESULT WINAPI SecManagerImpl_SetZoneMapping(IInternetSecurityManager *if SecManagerImpl *This = SECMGR_THIS(iface); HRESULT hres; - TRACE("(%p)->(%08lx %s %08lx)\n", iface, dwZone, debugstr_w(pwszPattern),dwFlags); + TRACE("(%p)->(%08x %s %08x)\n", iface, dwZone, debugstr_w(pwszPattern),dwFlags); if(This->custom_manager) { hres = IInternetSecurityManager_SetZoneMapping(This->custom_manager, dwZone, @@ -421,7 +425,7 @@ static HRESULT WINAPI SecManagerImpl_GetZoneMappings(IInternetSecurityManager *i SecManagerImpl *This = SECMGR_THIS(iface); HRESULT hres; - TRACE("(%p)->(%08lx %p %08lx)\n", iface, dwZone, ppenumString,dwFlags); + TRACE("(%p)->(%08x %p %08x)\n", iface, dwZone, ppenumString,dwFlags); if(This->custom_manager) { hres = IInternetSecurityManager_GetZoneMappings(This->custom_manager, dwZone, @@ -551,7 +555,7 @@ static ULONG WINAPI ZoneMgrImpl_AddRef(IInternetZoneManager* iface) ZoneMgrImpl* This = (ZoneMgrImpl*)iface; ULONG refCount = InterlockedIncrement(&This->ref); - TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); + TRACE("(%p)->(ref before=%u)\n",This, refCount - 1); return refCount; } @@ -564,7 +568,7 @@ static ULONG WINAPI ZoneMgrImpl_Release(IInternetZoneManager* iface) ZoneMgrImpl* This = (ZoneMgrImpl*)iface; ULONG refCount = InterlockedDecrement(&This->ref); - TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); + TRACE("(%p)->(ref before=%u)\n",This, refCount + 1); if(!refCount) { HeapFree(GetProcessHeap(), 0, This); @@ -581,7 +585,7 @@ static HRESULT WINAPI ZoneMgrImpl_GetZoneAttributes(IInternetZoneManager* iface, DWORD dwZone, ZONEATTRIBUTES* pZoneAttributes) { - FIXME("(%p)->(%ld %p) stub\n", iface, dwZone, pZoneAttributes); + FIXME("(%p)->(%d %p) stub\n", iface, dwZone, pZoneAttributes); return E_NOTIMPL; } @@ -592,7 +596,7 @@ static HRESULT WINAPI ZoneMgrImpl_SetZoneAttributes(IInternetZoneManager* iface, DWORD dwZone, ZONEATTRIBUTES* pZoneAttributes) { - FIXME("(%p)->(%08lx %p) stub\n", iface, dwZone, pZoneAttributes); + FIXME("(%p)->(%08x %p) stub\n", iface, dwZone, pZoneAttributes); return E_NOTIMPL; } @@ -606,7 +610,7 @@ static HRESULT WINAPI ZoneMgrImpl_GetZoneCustomPolicy(IInternetZoneManager* ifac DWORD* pcbPolicy, URLZONEREG ulrZoneReg) { - FIXME("(%p)->(%08lx %s %p %p %08x) stub\n", iface, dwZone, debugstr_guid(guidKey), + FIXME("(%p)->(%08x %s %p %p %08x) stub\n", iface, dwZone, debugstr_guid(guidKey), ppPolicy, pcbPolicy, ulrZoneReg); return E_NOTIMPL; } @@ -621,7 +625,7 @@ static HRESULT WINAPI ZoneMgrImpl_SetZoneCustomPolicy(IInternetZoneManager* ifac DWORD cbPolicy, URLZONEREG ulrZoneReg) { - FIXME("(%p)->(%08lx %s %p %08lx %08x) stub\n", iface, dwZone, debugstr_guid(guidKey), + FIXME("(%p)->(%08x %s %p %08x %08x) stub\n", iface, dwZone, debugstr_guid(guidKey), ppPolicy, cbPolicy, ulrZoneReg); return E_NOTIMPL; } @@ -640,7 +644,7 @@ static HRESULT WINAPI ZoneMgrImpl_GetZoneActionPolicy(IInternetZoneManager* ifac static const WCHAR wszFormat[] = {'%','l','X',0}; - TRACE("(%p)->(%ld %08lx %p %ld %d)\n", iface, dwZone, dwAction, pPolicy, + TRACE("(%p)->(%d %08x %p %d %d)\n", iface, dwZone, dwAction, pPolicy, cbPolicy, urlZoneReg); if(!pPolicy) @@ -658,7 +662,7 @@ static HRESULT WINAPI ZoneMgrImpl_GetZoneActionPolicy(IInternetZoneManager* ifac }else if(res == ERROR_FILE_NOT_FOUND) { hres = E_FAIL; }else if(res != ERROR_SUCCESS) { - ERR("RegQueryValue failed: %ld\n", res); + ERR("RegQueryValue failed: %d\n", res); hres = E_UNEXPECTED; } @@ -677,7 +681,7 @@ static HRESULT WINAPI ZoneMgrImpl_SetZoneActionPolicy(IInternetZoneManager* ifac DWORD cbPolicy, URLZONEREG urlZoneReg) { - FIXME("(%p)->(%08lx %08lx %p %08lx %08x) stub\n", iface, dwZone, dwAction, pPolicy, + FIXME("(%p)->(%08x %08x %p %08x %08x) stub\n", iface, dwZone, dwAction, pPolicy, cbPolicy, urlZoneReg); return E_NOTIMPL; } @@ -692,7 +696,7 @@ static HRESULT WINAPI ZoneMgrImpl_PromptAction(IInternetZoneManager* iface, LPCWSTR pwszText, DWORD dwPromptFlags) { - FIXME("%p %08lx %p %s %s %08lx\n", iface, dwAction, hwndParent, + FIXME("%p %08x %p %s %s %08x\n", iface, dwAction, hwndParent, debugstr_w(pwszUrl), debugstr_w(pwszText), dwPromptFlags ); return E_NOTIMPL; } @@ -706,7 +710,7 @@ static HRESULT WINAPI ZoneMgrImpl_LogAction(IInternetZoneManager* iface, LPCWSTR pwszText, DWORD dwLogFlags) { - FIXME("(%p)->(%08lx %s %s %08lx) stub\n", iface, dwAction, debugstr_w(pwszUrl), + FIXME("(%p)->(%08x %s %s %08x) stub\n", iface, dwAction, debugstr_w(pwszUrl), debugstr_w(pwszText), dwLogFlags); return E_NOTIMPL; } @@ -719,7 +723,7 @@ static HRESULT WINAPI ZoneMgrImpl_CreateZoneEnumerator(IInternetZoneManager* ifa DWORD* pdwCount, DWORD dwFlags) { - FIXME("(%p)->(%p %p %08lx) stub\n", iface, pdwEnum, pdwCount, dwFlags); + FIXME("(%p)->(%p %p %08x) stub\n", iface, pdwEnum, pdwCount, dwFlags); return E_NOTIMPL; } @@ -731,7 +735,7 @@ static HRESULT WINAPI ZoneMgrImpl_GetZoneAt(IInternetZoneManager* iface, DWORD dwIndex, DWORD* pdwZone) { - FIXME("(%p)->(%08lx %08lx %p) stub\n", iface, dwEnum, dwIndex, pdwZone); + FIXME("(%p)->(%08x %08x %p) stub\n", iface, dwEnum, dwIndex, pdwZone); return E_NOTIMPL; } @@ -741,7 +745,7 @@ static HRESULT WINAPI ZoneMgrImpl_GetZoneAt(IInternetZoneManager* iface, static HRESULT WINAPI ZoneMgrImpl_DestroyZoneEnumerator(IInternetZoneManager* iface, DWORD dwEnum) { - FIXME("(%p)->(%08lx) stub\n", iface, dwEnum); + FIXME("(%p)->(%08x) stub\n", iface, dwEnum); return E_NOTIMPL; } @@ -753,7 +757,7 @@ static HRESULT WINAPI ZoneMgrImpl_CopyTemplatePoliciesToZone(IInternetZoneManage DWORD dwZone, DWORD dwReserved) { - FIXME("(%p)->(%08lx %08lx %08lx) stub\n", iface, dwTemplate, dwZone, dwReserved); + FIXME("(%p)->(%08x %08x %08x) stub\n", iface, dwTemplate, dwZone, dwReserved); return E_NOTIMPL; } @@ -799,7 +803,7 @@ HRESULT ZoneMgrImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj) HRESULT WINAPI CoInternetCreateSecurityManager( IServiceProvider *pSP, IInternetSecurityManager **ppSM, DWORD dwReserved ) { - TRACE("%p %p %ld\n", pSP, ppSM, dwReserved ); + TRACE("%p %p %d\n", pSP, ppSM, dwReserved ); if(pSP) FIXME("pSP not supported\n"); @@ -812,6 +816,6 @@ HRESULT WINAPI CoInternetCreateSecurityManager( IServiceProvider *pSP, */ HRESULT WINAPI CoInternetCreateZoneManager(IServiceProvider* pSP, IInternetZoneManager** ppZM, DWORD dwReserved) { - TRACE("(%p %p %lx)\n", pSP, ppZM, dwReserved); + TRACE("(%p %p %x)\n", pSP, ppZM, dwReserved); return ZoneMgrImpl_Construct(NULL, (void**)ppZM); } diff --git a/reactos/dll/win32/urlmon/session.c b/reactos/dll/win32/urlmon/session.c index e4ea06127ac..a57a8dce82e 100644 --- a/reactos/dll/win32/urlmon/session.c +++ b/reactos/dll/win32/urlmon/session.c @@ -1,5 +1,5 @@ /* - * Copyright 2005 Jacek Caban + * Copyright 2005-2006 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 @@ -13,7 +13,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -29,14 +29,37 @@ #include "urlmon_main.h" #include "wine/debug.h" +#include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(urlmon); -HRESULT get_protocol_iface(LPCWSTR url, IUnknown **ret) +typedef struct name_space { + LPWSTR protocol; + IClassFactory *cf; + CLSID clsid; + + struct name_space *next; +} name_space; + +static name_space *name_space_list = NULL; + +static name_space *find_name_space(LPCWSTR protocol) { - WCHAR schema[64], str_clsid[64]; + name_space *iter; + + for(iter = name_space_list; iter; iter = iter->next) { + if(!strcmpW(iter->protocol, protocol)) + return iter; + } + + return NULL; +} + +static HRESULT get_protocol_cf(LPCWSTR schema, DWORD schema_len, CLSID *pclsid, IClassFactory **ret) +{ + WCHAR str_clsid[64]; HKEY hkey = NULL; - DWORD res, type, size, schema_len; + DWORD res, type, size; CLSID clsid; LPWSTR wszKey; HRESULT hres; @@ -45,11 +68,6 @@ HRESULT get_protocol_iface(LPCWSTR url, IUnknown **ret) {'P','R','O','T','O','C','O','L','S','\\','H','a','n','d','l','e','r','\\'}; static const WCHAR wszCLSID[] = {'C','L','S','I','D',0}; - hres = CoInternetParseUrl(url, PARSE_SCHEMA, 0, schema, sizeof(schema)/sizeof(schema[0]), - &schema_len, 0); - if(FAILED(hres) || !schema_len) - return E_FAIL; - wszKey = HeapAlloc(GetProcessHeap(), 0, sizeof(wszProtocolsKey)+(schema_len+1)*sizeof(WCHAR)); memcpy(wszKey, wszProtocolsKey, sizeof(wszProtocolsKey)); memcpy(wszKey + sizeof(wszProtocolsKey)/sizeof(WCHAR), schema, (schema_len+1)*sizeof(WCHAR)); @@ -57,7 +75,7 @@ HRESULT get_protocol_iface(LPCWSTR url, IUnknown **ret) res = RegOpenKeyW(HKEY_CLASSES_ROOT, wszKey, &hkey); HeapFree(GetProcessHeap(), 0, wszKey); if(res != ERROR_SUCCESS) { - TRACE("Could not open key %s\n", debugstr_w(wszKey)); + TRACE("Could not open protocol handler key\n"); return E_FAIL; } @@ -65,17 +83,81 @@ HRESULT get_protocol_iface(LPCWSTR url, IUnknown **ret) res = RegQueryValueExW(hkey, wszCLSID, NULL, &type, (LPBYTE)str_clsid, &size); RegCloseKey(hkey); if(res != ERROR_SUCCESS || type != REG_SZ) { - WARN("Could not get protocol CLSID res=%ld\n", res); + WARN("Could not get protocol CLSID res=%d\n", res); return E_FAIL; } hres = CLSIDFromString(str_clsid, &clsid); if(FAILED(hres)) { - WARN("CLSIDFromString failed: %08lx\n", hres); + WARN("CLSIDFromString failed: %08x\n", hres); return hres; } - return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IUnknown, (void**)ret); + if(pclsid) + *pclsid = clsid; + + return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IClassFactory, (void**)ret); +} + +IInternetProtocolInfo *get_protocol_info(LPCWSTR url) +{ + IInternetProtocolInfo *ret = NULL; + IClassFactory *cf; + name_space *ns; + WCHAR schema[64]; + DWORD schema_len; + HRESULT hres; + + hres = CoInternetParseUrl(url, PARSE_SCHEMA, 0, schema, sizeof(schema)/sizeof(schema[0]), + &schema_len, 0); + if(FAILED(hres) || !schema_len) + return NULL; + + ns = find_name_space(schema); + if(ns) { + hres = IClassFactory_QueryInterface(ns->cf, &IID_IInternetProtocolInfo, (void**)&ret); + if(SUCCEEDED(hres)) + return ret; + + hres = IClassFactory_CreateInstance(ns->cf, NULL, &IID_IInternetProtocolInfo, (void**)&ret); + if(SUCCEEDED(hres)) + return ret; + } + + hres = get_protocol_cf(schema, schema_len, NULL, &cf); + if(FAILED(hres)) + return NULL; + + hres = IClassFactory_QueryInterface(cf, &IID_IInternetProtocolInfo, (void**)&ret); + if(FAILED(hres)) + IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocolInfo, (void**)&ret); + IClassFactory_Release(cf); + + return ret; +} + +HRESULT get_protocol_handler(LPCWSTR url, CLSID *clsid, IClassFactory **ret) +{ + name_space *ns; + WCHAR schema[64]; + DWORD schema_len; + HRESULT hres; + + hres = CoInternetParseUrl(url, PARSE_SCHEMA, 0, schema, sizeof(schema)/sizeof(schema[0]), + &schema_len, 0); + if(FAILED(hres) || !schema_len) + return schema_len ? hres : E_FAIL; + + ns = find_name_space(schema); + if(ns) { + *ret = ns->cf; + IClassFactory_AddRef(*ret); + if(clsid) + *clsid = ns->clsid; + return S_OK; + } + + return get_protocol_cf(schema, schema_len, clsid, ret); } static HRESULT WINAPI InternetSession_QueryInterface(IInternetSession *iface, @@ -111,16 +193,64 @@ static HRESULT WINAPI InternetSession_RegisterNameSpace(IInternetSession *iface, IClassFactory *pCF, REFCLSID rclsid, LPCWSTR pwzProtocol, ULONG cPatterns, const LPCWSTR *ppwzPatterns, DWORD dwReserved) { - FIXME("(%p %s %s %ld %p %ld)\n", pCF, debugstr_guid(rclsid), debugstr_w(pwzProtocol), - cPatterns, ppwzPatterns, dwReserved); - return E_NOTIMPL; + name_space *new_name_space; + int size; + + TRACE("(%p %s %s %d %p %d)\n", pCF, debugstr_guid(rclsid), debugstr_w(pwzProtocol), + cPatterns, ppwzPatterns, dwReserved); + + if(cPatterns || ppwzPatterns) + FIXME("patterns not supported\n"); + if(dwReserved) + WARN("dwReserved = %d\n", dwReserved); + + if(!pCF || !pwzProtocol) + return E_INVALIDARG; + + new_name_space = HeapAlloc(GetProcessHeap(), 0, sizeof(name_space)); + + size = (strlenW(pwzProtocol)+1)*sizeof(WCHAR); + new_name_space->protocol = HeapAlloc(GetProcessHeap(), 0, size); + memcpy(new_name_space->protocol, pwzProtocol, size); + + IClassFactory_AddRef(pCF); + new_name_space->cf = pCF; + new_name_space->clsid = *rclsid; + + new_name_space->next = name_space_list; + name_space_list = new_name_space; + return S_OK; } static HRESULT WINAPI InternetSession_UnregisterNameSpace(IInternetSession *iface, IClassFactory *pCF, LPCWSTR pszProtocol) { - FIXME("(%p %s)\n", pCF, debugstr_w(pszProtocol)); - return E_NOTIMPL; + name_space *iter, *last = NULL; + + TRACE("(%p %s)\n", pCF, debugstr_w(pszProtocol)); + + if(!pCF || !pszProtocol) + return E_INVALIDARG; + + for(iter = name_space_list; iter; iter = iter->next) { + if(iter->cf == pCF && !strcmpW(iter->protocol, pszProtocol)) + break; + last = iter; + } + + if(!iter) + return S_OK; + + if(last) + last->next = iter->next; + else + name_space_list = iter->next; + + IClassFactory_Release(iter->cf); + HeapFree(GetProcessHeap(), 0, iter->protocol); + HeapFree(GetProcessHeap(), 0, iter); + + return S_OK; } static HRESULT WINAPI InternetSession_RegisterMimeFilter(IInternetSession *iface, @@ -141,15 +271,19 @@ static HRESULT WINAPI InternetSession_CreateBinding(IInternetSession *iface, LPBC pBC, LPCWSTR szUrl, IUnknown *pUnkOuter, IUnknown **ppUnk, IInternetProtocol **ppOInetProt, DWORD dwOption) { - FIXME("(%p %s %p %p %p %08lx)\n", pBC, debugstr_w(szUrl), pUnkOuter, ppUnk, + TRACE("(%p %s %p %p %p %08x)\n", pBC, debugstr_w(szUrl), pUnkOuter, ppUnk, ppOInetProt, dwOption); - return E_NOTIMPL; + + if(pBC || pUnkOuter || ppUnk || dwOption) + FIXME("Unsupported arguments\n"); + + return create_binding_protocol(szUrl, ppOInetProt); } static HRESULT WINAPI InternetSession_SetSessionOption(IInternetSession *iface, DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength, DWORD dwReserved) { - FIXME("(%08lx %p %ld %ld)\n", dwOption, pBuffer, dwBufferLength, dwReserved); + FIXME("(%08x %p %d %d)\n", dwOption, pBuffer, dwBufferLength, dwReserved); return E_NOTIMPL; } @@ -186,13 +320,69 @@ static IInternetSession InternetSession = { &InternetSessionVtbl }; HRESULT WINAPI CoInternetGetSession(DWORD dwSessionMode, IInternetSession **ppIInternetSession, DWORD dwReserved) { - TRACE("(%ld %p %ld)\n", dwSessionMode, ppIInternetSession, dwReserved); + TRACE("(%d %p %d)\n", dwSessionMode, ppIInternetSession, dwReserved); if(dwSessionMode) - ERR("dwSessionMode=%ld\n", dwSessionMode); + ERR("dwSessionMode=%d\n", dwSessionMode); if(dwReserved) - ERR("dwReserved=%ld\n", dwReserved); + ERR("dwReserved=%d\n", dwReserved); + IInternetSession_AddRef(&InternetSession); *ppIInternetSession = &InternetSession; return S_OK; } + +/************************************************************************** + * UrlMkGetSessionOption (URLMON.@) + */ +static BOOL get_url_encoding(HKEY root, DWORD *encoding) +{ + DWORD size = sizeof(DWORD), res, type; + HKEY hkey; + + static const WCHAR wszKeyName[] = + {'S','O','F','T','W','A','R','E', + '\\','M','i','c','r','o','s','o','f','t', + '\\','W','i','n','d','o','w','s', + '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n', + '\\','I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0}; + static const WCHAR wszUrlEncoding[] = {'U','r','l','E','n','c','o','d','i','n','g',0}; + + res = RegOpenKeyW(root, wszKeyName, &hkey); + if(res != ERROR_SUCCESS) + return FALSE; + + res = RegQueryValueExW(hkey, wszUrlEncoding, NULL, &type, (LPBYTE)encoding, &size); + RegCloseKey(hkey); + + return res == ERROR_SUCCESS; +} + +HRESULT WINAPI UrlMkGetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength, + DWORD* pdwBufferLength, DWORD dwReserved) +{ + TRACE("(%x, %p, %d, %p)\n", dwOption, pBuffer, dwBufferLength, pdwBufferLength); + + if(dwReserved) + WARN("dwReserved = %d\n", dwReserved); + + switch(dwOption) { + case URLMON_OPTION_URL_ENCODING: { + DWORD encoding = 0; + + if(!pBuffer || dwBufferLength < sizeof(DWORD) || !pdwBufferLength) + return E_INVALIDARG; + + if(!get_url_encoding(HKEY_CURRENT_USER, &encoding)) + get_url_encoding(HKEY_LOCAL_MACHINE, &encoding); + + *pdwBufferLength = sizeof(DWORD); + *(DWORD*)pBuffer = encoding ? URL_ENCODING_DISABLE_UTF8 : URL_ENCODING_ENABLE_UTF8; + return S_OK; + } + default: + FIXME("unsupported option %x\n", dwOption); + } + + return E_INVALIDARG; +} diff --git a/reactos/dll/win32/urlmon/umon.c b/reactos/dll/win32/urlmon/umon.c index 79f30b79a4f..b8c6bfeffff 100644 --- a/reactos/dll/win32/urlmon/umon.c +++ b/reactos/dll/win32/urlmon/umon.c @@ -17,10 +17,9 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#define COM_NO_WINDOWS_H #include #include @@ -45,7 +44,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(urlmon); /* native urlmon.dll uses this key, too */ -static const WCHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 }; +static WCHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 }; /*static BOOL registered_wndclass = FALSE;*/ @@ -89,7 +88,7 @@ static ULONG WINAPI Binding_AddRef(IBinding* iface) Binding *This = (Binding*)iface; ULONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) ref=%ld\n", This, ref); + TRACE("(%p) ref=%d\n", This, ref); return ref; } @@ -99,7 +98,7 @@ static ULONG WINAPI Binding_Release(IBinding* iface) Binding *This = (Binding*)iface; ULONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) ref=%ld\n",This, ref); + TRACE("(%p) ref=%d\n",This, ref); if(!ref) { HeapFree(GetProcessHeap(), 0, This->URLName); @@ -161,7 +160,7 @@ static HRESULT WINAPI Binding_SetPriority(IBinding* iface, LONG nPriority) { Binding *This = (Binding*)iface; - FIXME("(%p)->(%ld): stub\n", This, nPriority); + FIXME("(%p)->(%d): stub\n", This, nPriority); return E_NOTIMPL; } @@ -340,7 +339,7 @@ static ULONG WINAPI URLMonikerImpl_AddRef(IMoniker* iface) URLMonikerImpl *This = (URLMonikerImpl *)iface; ULONG refCount = InterlockedIncrement(&This->ref); - TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); + TRACE("(%p) ref=%u\n",This, refCount); return refCount; } @@ -353,7 +352,7 @@ static ULONG WINAPI URLMonikerImpl_Release(IMoniker* iface) URLMonikerImpl *This = (URLMonikerImpl *)iface; ULONG refCount = InterlockedDecrement(&This->ref); - TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); + TRACE("(%p) ref=%u\n",This, refCount); /* destroy the object if there's no more reference on it */ if (!refCount) { @@ -411,23 +410,23 @@ static HRESULT WINAPI URLMonikerImpl_Load(IMoniker* iface,IStream* pStm) URLMonikerImpl *This = (URLMonikerImpl *)iface; HRESULT res; - ULONG len; + ULONG size; ULONG got; TRACE("(%p,%p)\n",This,pStm); if(!pStm) return E_INVALIDARG; - res = IStream_Read(pStm, &len, sizeof(ULONG), &got); + res = IStream_Read(pStm, &size, sizeof(ULONG), &got); if(SUCCEEDED(res)) { if(got == sizeof(ULONG)) { HeapFree(GetProcessHeap(), 0, This->URLName); - This->URLName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(len+1)); + This->URLName=HeapAlloc(GetProcessHeap(),0,size); if(!This->URLName) res = E_OUTOFMEMORY; else { - res = IStream_Read(pStm, This->URLName, len, NULL); - This->URLName[len] = 0; + res = IStream_Read(pStm, This->URLName, size, NULL); + This->URLName[size/sizeof(WCHAR) - 1] = 0; } } else @@ -446,16 +445,16 @@ static HRESULT WINAPI URLMonikerImpl_Save(IMoniker* iface, URLMonikerImpl *This = (URLMonikerImpl *)iface; HRESULT res; - ULONG len; + ULONG size; TRACE("(%p,%p,%d)\n",This,pStm,fClearDirty); if(!pStm) return E_INVALIDARG; - len = strlenW(This->URLName); - res=IStream_Write(pStm,&len,sizeof(ULONG),NULL); + size = (strlenW(This->URLName) + 1)*sizeof(WCHAR); + res=IStream_Write(pStm,&size,sizeof(ULONG),NULL); if(SUCCEEDED(res)) - res=IStream_Write(pStm,&This->URLName,len*sizeof(WCHAR),NULL); + res=IStream_Write(pStm,This->URLName,size,NULL); return res; } @@ -473,8 +472,7 @@ static HRESULT WINAPI URLMonikerImpl_GetSizeMax(IMoniker* iface, if(!pcbSize) return E_INVALIDARG; - pcbSize->u.LowPart = sizeof(ULONG) + (strlenW(This->URLName) * sizeof(WCHAR)); - pcbSize->u.HighPart = 0; + pcbSize->QuadPart = sizeof(ULONG) + ((strlenW(This->URLName)+1) * sizeof(WCHAR)); return S_OK; } @@ -542,7 +540,7 @@ static HRESULT URLMonikerImpl_BindToStorage_hack(LPCWSTR URLName, *ppvObject = (void *) bind->pstrCache; IStream_AddRef((IStream *) bind->pstrCache); - hres = IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown**)&bind->pbscb); + hres = IBindCtx_GetObjectParam(pbc, BSCBHolder, (IUnknown**)&bind->pbscb); if(SUCCEEDED(hres)) { TRACE("Got IBindStatusCallback...\n"); @@ -551,28 +549,16 @@ static HRESULT URLMonikerImpl_BindToStorage_hack(LPCWSTR URLName, bindf = 0; hres = IBindStatusCallback_GetBindInfo(bind->pbscb, &bindf, &bi); if(SUCCEEDED(hres)) { - WCHAR *urlcopy, *tmpwc; URL_COMPONENTSW url; WCHAR *host, *path, *user, *pass; DWORD lensz = sizeof(bind->expected_size); DWORD dwService = 0; BOOL bSuccess; - TRACE("got bindinfo. bindf = %08lx extrainfo = %s bindinfof = %08lx bindverb = %08lx iid %s\n", + TRACE("got bindinfo. bindf = %08x extrainfo = %s bindinfof = %08x bindverb = %08x iid %s\n", bindf, debugstr_w(bi.szExtraInfo), bi.grfBindInfoF, bi.dwBindVerb, debugstr_guid(&bi.iid)); hres = IBindStatusCallback_OnStartBinding(bind->pbscb, 0, (IBinding*)bind); - TRACE("OnStartBinding rets %08lx\n", hres); - - /* This class will accept URLs with the backslash in them. But InternetCrackURL will not - it - * requires forward slashes (this is the behaviour of Microsoft's INETAPI). So we need to make - * a copy of the URL here and change the backslash to a forward slash everywhere it appears - - * but only before any '#' or '?', after which backslash should be left alone. - */ - urlcopy = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (lstrlenW(bind->URLName) + 1)); - lstrcpyW(urlcopy, bind->URLName); - for (tmpwc = urlcopy; *tmpwc && *tmpwc != '#' && *tmpwc != '?'; ++tmpwc) - if (*tmpwc == '\\') - *tmpwc = '/'; + TRACE("OnStartBinding rets %08x\n", hres); bind->expected_size = 0; bind->total_read = 0; @@ -580,7 +566,7 @@ static HRESULT URLMonikerImpl_BindToStorage_hack(LPCWSTR URLName, memset(&url, 0, sizeof(url)); url.dwStructSize = sizeof(url); url.dwSchemeLength = url.dwHostNameLength = url.dwUrlPathLength = url.dwUserNameLength = url.dwPasswordLength = 1; - InternetCrackUrlW(urlcopy, 0, ICU_ESCAPE, &url); + InternetCrackUrlW(URLName, 0, ICU_ESCAPE, &url); host = HeapAlloc(GetProcessHeap(), 0, (url.dwHostNameLength + 1) * sizeof(WCHAR)); memcpy(host, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR)); host[url.dwHostNameLength] = '\0'; @@ -712,7 +698,7 @@ static HRESULT URLMonikerImpl_BindToStorage_hack(LPCWSTR URLName, } if(bSuccess) { - TRACE("res = %ld gle = %08lx url len = %ld\n", hres, GetLastError(), bind->expected_size); + TRACE("res = %d gle = %u url len = %d\n", hres, GetLastError(), bind->expected_size); IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_CACHEFILENAMEAVAILABLE, szFileName); @@ -720,7 +706,7 @@ static HRESULT URLMonikerImpl_BindToStorage_hack(LPCWSTR URLName, char buf[4096]; DWORD bufread; if(InternetReadFile(bind->hrequest, buf, sizeof(buf), &bufread)) { - TRACE("read %ld bytes %s...\n", bufread, debugstr_an(buf, 10)); + TRACE("read %d bytes %s...\n", bufread, debugstr_an(buf, 10)); if(bufread == 0) break; hres = Binding_MoreCacheData(bind, buf, bufread); } else @@ -734,16 +720,13 @@ static HRESULT URLMonikerImpl_BindToStorage_hack(LPCWSTR URLName, InternetCloseHandle(bind->hinternet); } while(0); - Binding_CloseCacheDownload(bind); Binding_FinishedDownload(bind, hres); + Binding_CloseCacheDownload(bind); - if (user) - HeapFree(GetProcessHeap(), 0, user); - if (pass) - HeapFree(GetProcessHeap(), 0, pass); + HeapFree(GetProcessHeap(), 0, user); + HeapFree(GetProcessHeap(), 0, pass); HeapFree(GetProcessHeap(), 0, path); HeapFree(GetProcessHeap(), 0, host); - HeapFree(GetProcessHeap(), 0, urlcopy); } } } @@ -768,7 +751,7 @@ static HRESULT WINAPI URLMonikerImpl_BindToStorage(IMoniker* iface, bret = InternetCrackUrlW(This->URLName, 0, ICU_ESCAPE, &url); if(!bret) { - ERR("InternetCrackUrl failed: %ld\n", GetLastError()); + ERR("InternetCrackUrl failed: %u\n", GetLastError()); return E_FAIL; } @@ -794,7 +777,7 @@ static HRESULT WINAPI URLMonikerImpl_Reduce(IMoniker* iface, { URLMonikerImpl *This = (URLMonikerImpl *)iface; - TRACE("(%p,%p,%ld,%p,%p)\n",This,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); + TRACE("(%p,%p,%d,%p,%p)\n",This,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); if(!ppmkReduced) return E_INVALIDARG; @@ -1062,43 +1045,34 @@ static const IMonikerVtbl VT_URLMonikerImpl = static HRESULT URLMonikerImpl_Construct(URLMonikerImpl* This, LPCOLESTR lpszLeftURLName, LPCOLESTR lpszURLName) { HRESULT hres; - DWORD sizeStr = INTERNET_MAX_URL_LENGTH; + DWORD sizeStr = 0; TRACE("(%p,%s,%s)\n",This,debugstr_w(lpszLeftURLName),debugstr_w(lpszURLName)); This->lpvtbl = &VT_URLMonikerImpl; This->ref = 0; - sizeStr = lstrlenW(lpszURLName)+1; + This->URLName = HeapAlloc(GetProcessHeap(), 0, INTERNET_MAX_URL_LENGTH*sizeof(WCHAR)); + if(lpszLeftURLName) - sizeStr += strlenW(lpszLeftURLName)+32; + hres = CoInternetCombineUrl(lpszLeftURLName, lpszURLName, URL_FILE_USE_PATHURL, + This->URLName, INTERNET_MAX_URL_LENGTH, &sizeStr, 0); + else + hres = CoInternetParseUrl(lpszURLName, PARSE_CANONICALIZE, URL_FILE_USE_PATHURL, + This->URLName, INTERNET_MAX_URL_LENGTH, &sizeStr, 0); - This->URLName = HeapAlloc(GetProcessHeap(), 0, sizeStr*sizeof(WCHAR)); - - if(lpszLeftURLName) { - hres = CoInternetCombineUrl(lpszLeftURLName, lpszURLName, 0, This->URLName, sizeStr, - &sizeStr, 0); - if(FAILED(hres)) { - HeapFree(GetProcessHeap(), 0, This->URLName); - return hres; - } - }else { - /* FIXME: - * We probably should use CoInternetParseUrl or something similar here. - */ - - static const WCHAR wszFile[] = {'f','i','l','e',':','/','/',}; - - /* file protocol is a special case */ - if(sizeStr > sizeof(wszFile)/sizeof(WCHAR) - && !memcmp(lpszURLName, wszFile, sizeof(wszFile))) - UrlCanonicalizeW(lpszURLName, This->URLName, &sizeStr, URL_FILE_USE_PATHURL); - else - strcpyW(This->URLName,lpszURLName); + if(FAILED(hres)) { + HeapFree(GetProcessHeap(), 0, This->URLName); + return hres; } URLMON_LockModule(); + if(sizeStr != INTERNET_MAX_URL_LENGTH) + This->URLName = HeapReAlloc(GetProcessHeap(), 0, This->URLName, (sizeStr+1)*sizeof(WCHAR)); + + TRACE("URLName = %s\n", debugstr_w(This->URLName)); + return S_OK; } @@ -1108,7 +1082,7 @@ static HRESULT URLMonikerImpl_Construct(URLMonikerImpl* This, LPCOLESTR lpszLeft HRESULT WINAPI CreateAsyncBindCtx(DWORD reserved, IBindStatusCallback *callback, IEnumFORMATETC *format, IBindCtx **pbind) { - TRACE("(%08lx %p %p %p)\n", reserved, callback, format, pbind); + TRACE("(%08x %p %p %p)\n", reserved, callback, format, pbind); if(!callback) return E_INVALIDARG; @@ -1128,18 +1102,18 @@ HRESULT WINAPI CreateAsyncBindCtxEx(IBindCtx *ibind, DWORD options, BIND_OPTS bindopts; IBindCtx *bctx; - TRACE("(%p %08lx %p %p %p %ld)\n", ibind, options, callback, format, pbind, reserved); + TRACE("(%p %08x %p %p %p %d)\n", ibind, options, callback, format, pbind, reserved); if(!pbind) return E_INVALIDARG; if(options) - FIXME("not supported options %08lx", options); + FIXME("not supported options %08x\n", options); if(format) FIXME("format is not supported\n"); if(reserved) - WARN("reserved=%ld\n", reserved); + WARN("reserved=%d\n", reserved); hres = CreateBindCtx(0, &bctx); if(FAILED(hres)) @@ -1161,7 +1135,7 @@ HRESULT WINAPI CreateAsyncBindCtxEx(IBindCtx *ibind, DWORD options, /*********************************************************************** - * CreateURLMoniker (URLMON.@) + * CreateURLMonikerEx (URLMON.@) * * Create a url moniker. * @@ -1169,20 +1143,22 @@ HRESULT WINAPI CreateAsyncBindCtxEx(IBindCtx *ibind, DWORD options, * pmkContext [I] Context * szURL [I] Url to create the moniker for * ppmk [O] Destination for created moniker. + * dwFlags [I] Flags. * * RETURNS * Success: S_OK. ppmk contains the created IMoniker object. * Failure: MK_E_SYNTAX if szURL is not a valid url, or * E_OUTOFMEMORY if memory allocation fails. */ -HRESULT WINAPI CreateURLMoniker(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk) +HRESULT WINAPI CreateURLMonikerEx(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk, DWORD dwFlags) { URLMonikerImpl *obj; HRESULT hres; - IID iid = IID_IMoniker; LPOLESTR lefturl = NULL; - TRACE("(%p, %s, %p)\n", pmkContext, debugstr_w(szURL), ppmk); + TRACE("(%p, %s, %p, %08x)\n", pmkContext, debugstr_w(szURL), ppmk, dwFlags); + + if (dwFlags & URL_MK_UNIFORM) FIXME("ignoring flag URL_MK_UNIFORM\n"); if(!(obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj)))) return E_OUTOFMEMORY; @@ -1201,12 +1177,32 @@ HRESULT WINAPI CreateURLMoniker(IMoniker *pmkContext, LPCWSTR szURL, IMoniker ** hres = URLMonikerImpl_Construct(obj, lefturl, szURL); CoTaskMemFree(lefturl); if(SUCCEEDED(hres)) - hres = URLMonikerImpl_QueryInterface((IMoniker*)obj, &iid, (void**)ppmk); + hres = URLMonikerImpl_QueryInterface((IMoniker*)obj, &IID_IMoniker, (void**)ppmk); else HeapFree(GetProcessHeap(), 0, obj); return hres; } +/********************************************************************** + * CreateURLMoniker (URLMON.@) + * + * Create a url moniker. + * + * PARAMS + * pmkContext [I] Context + * szURL [I] Url to create the moniker for + * ppmk [O] Destination for created moniker. + * + * RETURNS + * Success: S_OK. ppmk contains the created IMoniker object. + * Failure: MK_E_SYNTAX if szURL is not a valid url, or + * E_OUTOFMEMORY if memory allocation fails. + */ +HRESULT WINAPI CreateURLMoniker(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk) +{ + return CreateURLMonikerEx(pmkContext, szURL, ppmk, URL_MK_LEGACY); +} + /*********************************************************************** * CoInternetQueryInfo (URLMON.@) * @@ -1222,7 +1218,7 @@ HRESULT WINAPI CoInternetQueryInfo(LPCWSTR pwzUrl, QUERYOPTION QueryOption, DWORD dwQueryFlags, LPVOID pvBuffer, DWORD cbBuffer, DWORD * pcbBuffer, DWORD dwReserved) { - FIXME("(%s, %x, %lx, %p, %lx, %p, %lx): stub\n", debugstr_w(pwzUrl), + FIXME("(%s, %x, %x, %p, %x, %p, %x): stub\n", debugstr_w(pwzUrl), QueryOption, dwQueryFlags, pvBuffer, cbBuffer, pcbBuffer, dwReserved); return S_OK; } @@ -1304,21 +1300,21 @@ HRESULT WINAPI RegisterBindStatusCallback( { IBindStatusCallback *prev; - TRACE("(%p,%p,%p,%lu)\n", pbc, pbsc, ppbscPrevious, dwReserved); + TRACE("(%p,%p,%p,%u)\n", pbc, pbsc, ppbscPrevious, dwReserved); if (pbc == NULL || pbsc == NULL) return E_INVALIDARG; - if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown **)&prev))) + if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, BSCBHolder, (IUnknown **)&prev))) { - IBindCtx_RevokeObjectParam(pbc, (LPOLESTR)BSCBHolder); + IBindCtx_RevokeObjectParam(pbc, BSCBHolder); if (ppbscPrevious) *ppbscPrevious = prev; else IBindStatusCallback_Release(prev); } - return IBindCtx_RegisterObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown *)pbsc); + return IBindCtx_RegisterObjectParam(pbc, BSCBHolder, (IUnknown *)pbsc); } /*********************************************************************** @@ -1346,11 +1342,11 @@ HRESULT WINAPI RevokeBindStatusCallback( if (pbc == NULL || pbsc == NULL) return E_INVALIDARG; - if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown **)&callback))) + if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, BSCBHolder, (IUnknown **)&callback))) { if (callback == pbsc) { - IBindCtx_RevokeObjectParam(pbc, (LPOLESTR)BSCBHolder); + IBindCtx_RevokeObjectParam(pbc, BSCBHolder); hr = S_OK; } IBindStatusCallback_Release(pbsc); @@ -1385,7 +1381,7 @@ HRESULT WINAPI URLDownloadToFileA(LPUNKNOWN pCaller, UNICODE_STRING szURL_w, szFileName_w; if ((szURL == NULL) || (szFileName == NULL)) { - FIXME("(%p,%s,%s,%08lx,%p) cannot accept NULL strings !\n", pCaller, debugstr_a(szURL), debugstr_a(szFileName), dwReserved, lpfnCB); + FIXME("(%p,%s,%s,%08x,%p) cannot accept NULL strings !\n", pCaller, debugstr_a(szURL), debugstr_a(szFileName), dwReserved, lpfnCB); return E_INVALIDARG; /* The error code is not specified in this case... */ } @@ -1402,7 +1398,7 @@ HRESULT WINAPI URLDownloadToFileA(LPUNKNOWN pCaller, } } - FIXME("(%p,%s,%s,%08lx,%p) could not allocate W strings !\n", pCaller, szURL, szFileName, dwReserved, lpfnCB); + FIXME("(%p,%s,%s,%08x,%p) could not allocate W strings !\n", pCaller, szURL, szFileName, dwReserved, lpfnCB); return E_OUTOFMEMORY; } @@ -1440,7 +1436,7 @@ HRESULT WINAPI URLDownloadToFileW(LPUNKNOWN pCaller, static const WCHAR wszAppName[]={'u','r','l','m','o','n','.','d','l','l',0}; /* Note: all error codes would need to be checked agains real Windows behaviour... */ - TRACE("(%p,%s,%s,%08lx,%p) stub!\n", pCaller, debugstr_w(szURL), debugstr_w(szFileName), dwReserved, lpfnCB); + TRACE("(%p,%s,%s,%08x,%p) stub!\n", pCaller, debugstr_w(szURL), debugstr_w(szFileName), dwReserved, lpfnCB); if ((szURL == NULL) || (szFileName == NULL)) { FIXME(" cannot accept NULL strings !\n"); @@ -1496,7 +1492,7 @@ HRESULT WINAPI URLDownloadToFileW(LPUNKNOWN pCaller, if (HttpQueryInfoW(hreq, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &total_size, &arg_size, NULL)) { - TRACE(" total size : %ld\n", total_size); + TRACE(" total size : %d\n", total_size); } hfile = CreateFileW(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, @@ -1583,7 +1579,7 @@ HRESULT WINAPI URLDownloadToCacheFileA(LPUNKNOWN lpUnkCaller, LPCSTR szURL, LPST int len; HRESULT hres; - TRACE("(%p %s %p %ld %ld %p)\n", lpUnkCaller, debugstr_a(szURL), szFileName, + TRACE("(%p %s %p %d %d %p)\n", lpUnkCaller, debugstr_a(szURL), szFileName, dwBufLength, dwReserved, pBSC); if(szURL) { @@ -1613,9 +1609,46 @@ HRESULT WINAPI URLDownloadToCacheFileA(LPUNKNOWN lpUnkCaller, LPCSTR szURL, LPST HRESULT WINAPI URLDownloadToCacheFileW(LPUNKNOWN lpUnkCaller, LPCWSTR szURL, LPWSTR szFileName, DWORD dwBufLength, DWORD dwReserved, LPBINDSTATUSCALLBACK pBSC) { - FIXME("(%p %s %p %ld %ld %p)\n", lpUnkCaller, debugstr_w(szURL), szFileName, - dwBufLength, dwReserved, pBSC); - return E_NOTIMPL; + WCHAR cache_path[MAX_PATH + 1]; + FILETIME expire, modified; + HRESULT hr; + LPWSTR ext; + + static WCHAR header[] = { + 'H','T','T','P','/','1','.','0',' ','2','0','0',' ', + 'O','K','\\','r','\\','n','\\','r','\\','n',0 + }; + + TRACE("(%p, %s, %p, %d, %d, %p)\n", lpUnkCaller, debugstr_w(szURL), + szFileName, dwBufLength, dwReserved, pBSC); + + if (!szURL || !szFileName) + return E_INVALIDARG; + + ext = PathFindExtensionW(szURL); + + if (!CreateUrlCacheEntryW(szURL, 0, ext, cache_path, 0)) + return E_FAIL; + + hr = URLDownloadToFileW(lpUnkCaller, szURL, cache_path, 0, pBSC); + if (FAILED(hr)) + return hr; + + expire.dwHighDateTime = 0; + expire.dwLowDateTime = 0; + modified.dwHighDateTime = 0; + modified.dwLowDateTime = 0; + + if (!CommitUrlCacheEntryW(szURL, cache_path, expire, modified, NORMAL_CACHE_ENTRY, + header, sizeof(header), NULL, NULL)) + return E_FAIL; + + if (lstrlenW(cache_path) > dwBufLength) + return E_OUTOFMEMORY; + + lstrcpyW(szFileName, cache_path); + + return S_OK; } /*********************************************************************** diff --git a/reactos/dll/win32/urlmon/umstream.c b/reactos/dll/win32/urlmon/umstream.c index cb2869b571f..cd5e1538720 100644 --- a/reactos/dll/win32/urlmon/umstream.c +++ b/reactos/dll/win32/urlmon/umstream.c @@ -16,7 +16,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -49,32 +49,30 @@ HRESULT UMCreateStreamOnCacheFile(LPCWSTR pszURL, { IUMCacheStream* ucstr; HANDLE handle; - LPWSTR ext; - LPCWSTR c; - LPCWSTR eloc = 0; + DWORD size; + LPWSTR url, c, ext = NULL; HRESULT hr; - for (c = pszURL; *c && *c != '#' && *c != '?'; ++c) + size = (strlenW(pszURL)+1)*sizeof(WCHAR); + url = HeapAlloc(GetProcessHeap(), 0, size); + memcpy(url, pszURL, size); + + for (c = url; *c && *c != '#' && *c != '?'; ++c) { if (*c == '.') - eloc = c + 1; - else if (*c == '/' || *c == '\\') - eloc = 0; + ext = c+1; + else if(*c == '/') + ext = NULL; } - if (!eloc) - eloc = c; + *c = 0; - ext = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (c - eloc + 1)); - memcpy(ext, eloc, sizeof(WCHAR) * (c - eloc)); - ext[c - eloc] = 0; - - if(!CreateUrlCacheEntryW(pszURL, dwSize, ext, pszFileName, 0)) + if(!CreateUrlCacheEntryW(url, dwSize, ext, pszFileName, 0)) hr = HRESULT_FROM_WIN32(GetLastError()); else hr = 0; - HeapFree(GetProcessHeap(), 0, ext); + HeapFree(GetProcessHeap(), 0, url); if (hr) return hr; @@ -193,7 +191,7 @@ static ULONG WINAPI IStream_fnAddRef(IStream *iface) IUMCacheStream *This = (IUMCacheStream *)iface; ULONG refCount = InterlockedIncrement(&This->ref); - TRACE("(%p)->(count=%lu)\n", This, refCount - 1); + TRACE("(%p)->(count=%u)\n", This, refCount - 1); return refCount; } @@ -206,7 +204,7 @@ static ULONG WINAPI IStream_fnRelease(IStream *iface) IUMCacheStream *This = (IUMCacheStream *)iface; ULONG refCount = InterlockedDecrement(&This->ref); - TRACE("(%p)->(count=%lu)\n", This, refCount + 1); + TRACE("(%p)->(count=%u)\n", This, refCount + 1); if (!refCount) { @@ -228,7 +226,7 @@ static HRESULT WINAPI IStream_fnRead (IStream * iface, ULONG dwBytesRead; IUMCacheStream *This = (IUMCacheStream *)iface; - TRACE("(%p)->(%p,0x%08lx,%p)\n",This, pv, cb, pcbRead); + TRACE("(%p)->(%p,0x%08x,%p)\n",This, pv, cb, pcbRead); if ( !pv ) return STG_E_INVALIDPOINTER; diff --git a/reactos/dll/win32/urlmon/urlmon.rbuild b/reactos/dll/win32/urlmon/urlmon.rbuild index b61105a9ed7..4c47a87ec86 100644 --- a/reactos/dll/win32/urlmon/urlmon.rbuild +++ b/reactos/dll/win32/urlmon/urlmon.rbuild @@ -1,29 +1,31 @@ + . include/reactos/wine + 0x600 0x501 0x501 - wine - uuid - ntdll - kernel32 - advapi32 - user32 ole32 shlwapi - cabinet wininet + user32 + advapi32 + kernel32 + ntdll + uuid binding.c + bindprot.c file.c format.c ftp.c http.c internet.c + mk.c regsvr.c sec_mgr.c session.c diff --git a/reactos/dll/win32/urlmon/urlmon.spec b/reactos/dll/win32/urlmon/urlmon.spec index 46e5f28a2d1..c72c0ebb5ef 100644 --- a/reactos/dll/win32/urlmon/urlmon.spec +++ b/reactos/dll/win32/urlmon/urlmon.spec @@ -26,13 +26,14 @@ @ stdcall CreateAsyncBindCtxEx(ptr long ptr ptr ptr long) @ stdcall CreateFormatEnumerator(long ptr ptr) @ stdcall CreateURLMoniker(ptr wstr ptr) +@ stdcall CreateURLMonikerEx(ptr wstr ptr long) @ stdcall -private DllCanUnloadNow() @ stdcall -private DllGetClassObject(ptr ptr ptr) @ stdcall -private DllInstall(long wstr) @ stdcall -private DllRegisterServer() @ stdcall -private DllRegisterServerEx() @ stdcall -private DllUnregisterServer() -@ stdcall Extract(long ptr) cabinet.Extract +@ stdcall Extract(long ptr) @ stdcall FaultInIEFeature(long ptr ptr long) @ stub FindMediaType @ stub FindMediaTypeClass diff --git a/reactos/dll/win32/urlmon/urlmon_main.c b/reactos/dll/win32/urlmon/urlmon_main.c index c94eb70a9f7..bbd7cc59208 100644 --- a/reactos/dll/win32/urlmon/urlmon_main.c +++ b/reactos/dll/win32/urlmon/urlmon_main.c @@ -15,7 +15,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -28,34 +28,42 @@ #define NO_SHLWAPI_REG #include "shlwapi.h" - #include "wine/debug.h" #include "wine/unicode.h" #include "winuser.h" #include "urlmon.h" #include "urlmon_main.h" +#include "ole2.h" WINE_DEFAULT_DEBUG_CHANNEL(urlmon); LONG URLMON_refCount = 0; HINSTANCE URLMON_hInstance = 0; +static HMODULE hCabinet = NULL; + +static void init_session(BOOL); /*********************************************************************** * DllMain (URLMON.init) */ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) { - TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad); + TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad); switch(fdwReason) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hinstDLL); URLMON_hInstance = hinstDLL; + init_session(TRUE); break; case DLL_PROCESS_DETACH: + if (hCabinet) + FreeLibrary(hCabinet); + hCabinet = NULL; + init_session(FALSE); URLMON_hInstance = 0; break; } @@ -88,69 +96,51 @@ HRESULT WINAPI DllCanUnloadNow(void) * Urlmon ClassFactory */ typedef struct { - IClassFactory ITF_IClassFactory; + const IClassFactoryVtbl *lpClassFactoryVtbl; - LONG ref; HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj); -} IClassFactoryImpl; +} ClassFactory; -struct object_creation_info -{ - const CLSID *clsid; - HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj); -}; - -static const struct object_creation_info object_creation[] = -{ - { &CLSID_FileProtocol, FileProtocol_Construct }, - { &CLSID_FtpProtocol, FtpProtocol_Construct }, - { &CLSID_HttpProtocol, HttpProtocol_Construct }, - { &CLSID_InternetSecurityManager, &SecManagerImpl_Construct }, - { &CLSID_InternetZoneManager, ZoneMgrImpl_Construct } -}; +#define CLASSFACTORY(x) ((IClassFactory*) &(x)->lpClassFactoryVtbl) -static HRESULT WINAPI -CF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) +static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppv) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + *ppv = NULL; - if (IsEqualGUID(riid, &IID_IUnknown) - || IsEqualGUID(riid, &IID_IClassFactory)) - { - IClassFactory_AddRef(iface); - *ppobj = This; + if(IsEqualGUID(riid, &IID_IUnknown)) { + TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv); + *ppv = iface; + }else if(IsEqualGUID(riid, &IID_IClassFactory)) { + TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv); + *ppv = iface; + } + + if(*ppv) { + IUnknown_AddRef((IUnknown*)*ppv); return S_OK; } - WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj); + WARN("(%p)->(%s,%p),not found\n", iface, debugstr_guid(riid), ppv); return E_NOINTERFACE; } -static ULONG WINAPI CF_AddRef(LPCLASSFACTORY iface) +static ULONG WINAPI CF_AddRef(IClassFactory *iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - return InterlockedIncrement(&This->ref); + URLMON_LockModule(); + return 2; } -static ULONG WINAPI CF_Release(LPCLASSFACTORY iface) +static ULONG WINAPI CF_Release(IClassFactory *iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - ULONG ref = InterlockedDecrement(&This->ref); - - if (ref == 0) { - HeapFree(GetProcessHeap(), 0, This); - URLMON_UnlockModule(); - } - - return ref; + URLMON_UnlockModule(); + return 1; } -static HRESULT WINAPI CF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter, +static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *pOuter, REFIID riid, LPVOID *ppobj) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + ClassFactory *This = (ClassFactory*)iface; HRESULT hres; LPUNKNOWN punk; @@ -176,7 +166,7 @@ static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock) return S_OK; } -static const IClassFactoryVtbl CF_Vtbl = +static const IClassFactoryVtbl ClassFactoryVtbl = { CF_QueryInterface, CF_AddRef, @@ -185,6 +175,70 @@ static const IClassFactoryVtbl CF_Vtbl = CF_LockServer }; +static const ClassFactory FileProtocolCF = + { &ClassFactoryVtbl, FileProtocol_Construct}; +static const ClassFactory FtpProtocolCF = + { &ClassFactoryVtbl, FtpProtocol_Construct}; +static const ClassFactory HttpProtocolCF = + { &ClassFactoryVtbl, HttpProtocol_Construct}; +static const ClassFactory MkProtocolCF = + { &ClassFactoryVtbl, MkProtocol_Construct}; +static const ClassFactory SecurityManagerCF = + { &ClassFactoryVtbl, SecManagerImpl_Construct}; +static const ClassFactory ZoneManagerCF = + { &ClassFactoryVtbl, ZoneMgrImpl_Construct}; + +struct object_creation_info +{ + const CLSID *clsid; + IClassFactory *cf; + LPCWSTR protocol; +}; + +static const WCHAR wszFile[] = {'f','i','l','e',0}; +static const WCHAR wszFtp[] = {'f','t','p',0}; +static const WCHAR wszHttp[] = {'h','t','t','p',0}; +static const WCHAR wszMk[] = {'m','k',0}; + +static const struct object_creation_info object_creation[] = +{ + { &CLSID_FileProtocol, CLASSFACTORY(&FileProtocolCF), wszFile }, + { &CLSID_FtpProtocol, CLASSFACTORY(&FtpProtocolCF), wszFtp }, + { &CLSID_HttpProtocol, CLASSFACTORY(&HttpProtocolCF), wszHttp }, + { &CLSID_MkProtocol, CLASSFACTORY(&MkProtocolCF), wszMk }, + { &CLSID_InternetSecurityManager, CLASSFACTORY(&SecurityManagerCF), NULL }, + { &CLSID_InternetZoneManager, CLASSFACTORY(&ZoneManagerCF), NULL } +}; + +static void init_session(BOOL init) +{ + IInternetSession *session; + int i; + + CoInternetGetSession(0, &session, 0); + + for(i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) { + if(object_creation[i].protocol) { + if(init) + { + IInternetSession_RegisterNameSpace(session, object_creation[i].cf, + object_creation[i].clsid, object_creation[i].protocol, 0, NULL, 0); + /* make sure that the AddRef on the class factory doesn't keep us loaded */ + URLMON_UnlockModule(); + } + else + { + /* make sure that the Release on the class factory doesn't unload us */ + URLMON_LockModule(); + IInternetSession_UnregisterNameSpace(session, object_creation[i].cf, + object_creation[i].protocol); + } + } + } + + IInternetSession_Release(session); +} + /******************************************************************************* * DllGetClassObject [URLMON.@] * Retrieves class object from a DLL object @@ -206,38 +260,17 @@ static const IClassFactoryVtbl CF_Vtbl = HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) { int i; - IClassFactoryImpl *factory; TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); - if ( !IsEqualGUID( &IID_IClassFactory, riid ) - && ! IsEqualGUID( &IID_IUnknown, riid) ) - return E_NOINTERFACE; - for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) { if (IsEqualGUID(object_creation[i].clsid, rclsid)) - break; + return IClassFactory_QueryInterface(object_creation[i].cf, riid, ppv); } - if (i == sizeof(object_creation)/sizeof(object_creation[0])) - { - FIXME("%s: no class found.\n", debugstr_guid(rclsid)); - return CLASS_E_CLASSNOTAVAILABLE; - } - - factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory)); - if (factory == NULL) return E_OUTOFMEMORY; - - factory->ITF_IClassFactory.lpVtbl = &CF_Vtbl; - factory->ref = 1; - factory->pfnCreateInstance = object_creation[i].pfnCreateInstance; - - *ppv = &(factory->ITF_IClassFactory); - - URLMON_LockModule(); - - return S_OK; + FIXME("%s: no class found.\n", debugstr_guid(rclsid)); + return CLASS_E_CLASSNOTAVAILABLE; } @@ -257,18 +290,7 @@ HRESULT WINAPI DllRegisterServerEx(void) HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength, DWORD Reserved) { - FIXME("(%#lx, %p, %#lx): stub\n", dwOption, pBuffer, dwBufferLength); - - return S_OK; -} - -/************************************************************************** - * UrlMkGetSessionOption (URLMON.@) - */ -HRESULT WINAPI UrlMkGetSessionOption(DWORD dwOption, LPVOID pBuffer, DWORD dwBufferLength, - DWORD* pdwBufferLength, DWORD dwReserved) -{ - FIXME("(%#lx, %p, %#lx, %p): stub\n", dwOption, pBuffer, dwBufferLength, pdwBufferLength); + FIXME("(%#x, %p, %#x): stub\n", dwOption, pBuffer, dwBufferLength); return S_OK; } @@ -280,25 +302,24 @@ static const CHAR Agent[] = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" */ HRESULT WINAPI ObtainUserAgentString(DWORD dwOption, LPSTR pcszUAOut, DWORD *cbSize) { - FIXME("(%ld, %p, %p): stub\n", dwOption, pcszUAOut, cbSize); + FIXME("(%d, %p, %p): stub\n", dwOption, pcszUAOut, cbSize); - if(dwOption) { - ERR("dwOption: %ld, must be zero\n", dwOption); + if (pcszUAOut == NULL || cbSize == NULL) + return E_INVALIDARG; + + if (*cbSize < sizeof(Agent)) + { + *cbSize = sizeof(Agent); + return E_OUTOFMEMORY; } if (sizeof(Agent) < *cbSize) *cbSize = sizeof(Agent); - lstrcpynA(pcszUAOut, Agent, *cbSize); + lstrcpynA(pcszUAOut, Agent, *cbSize); return S_OK; } -HRESULT WINAPI CoInternetCompareUrl(LPCWSTR pwzUrl1, LPCWSTR pwzUrl2, DWORD dwCompareFlags) -{ - TRACE("(%s,%s,%08lx)\n", debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags); - return UrlCompareW(pwzUrl1, pwzUrl2, dwCompareFlags)==0?S_OK:S_FALSE; -} - /************************************************************************** * IsValidURL (URLMON.@) * @@ -319,7 +340,7 @@ HRESULT WINAPI CoInternetCompareUrl(LPCWSTR pwzUrl1, LPCWSTR pwzUrl2, DWORD dwCo */ HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved) { - FIXME("(%p, %s, %ld): stub\n", pBC, debugstr_w(szURL), dwReserved); + FIXME("(%p, %s, %d): stub\n", pBC, debugstr_w(szURL), dwReserved); if (pBC != NULL || dwReserved != 0) return E_INVALIDARG; @@ -335,7 +356,7 @@ HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved) HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec, QUERYCONTEXT *pQuery, DWORD flags ) { - FIXME("%p %p %p %08lx\n", hwnd, pClassSpec, pQuery, flags); + FIXME("%p %p %p %08x\n", hwnd, pClassSpec, pQuery, flags); return E_NOTIMPL; } @@ -347,7 +368,7 @@ HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWOR LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved, REFIID riid, LPVOID *ppv ) { - FIXME("(%s %s %ld %ld %s %p %ld %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL), + FIXME("(%s %s %d %d %s %p %d %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL), dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved, debugstr_guid(riid), ppv); return E_NOINTERFACE; @@ -366,15 +387,25 @@ HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWOR */ void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo) { + DWORD size; + TRACE("(%p)\n", pbindinfo); - if(!pbindinfo) + if(!pbindinfo || !(size = pbindinfo->cbSize)) return; CoTaskMemFree(pbindinfo->szExtraInfo); + ReleaseStgMedium(&pbindinfo->stgmedData); - if(pbindinfo->pUnk) + if(offsetof(BINDINFO, szExtraInfo) < size) + CoTaskMemFree(pbindinfo->szCustomVerb); + + + if(pbindinfo->pUnk && offsetof(BINDINFO, pUnk) < size) IUnknown_Release(pbindinfo->pUnk); + + memset(pbindinfo, 0, size); + pbindinfo->cbSize = size; } /*********************************************************************** @@ -382,24 +413,133 @@ void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo) * * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided. */ +static BOOL text_html_filter(const BYTE *b, DWORD size) +{ + int i; + + if(size < 5) + return FALSE; + + for(i=0; i < size-5; i++) { + if(b[i] == '<' + && (b[i+1] == 'h' || b[i+1] == 'H') + && (b[i+2] == 't' || b[i+2] == 'T') + && (b[i+3] == 'm' || b[i+3] == 'M') + && (b[i+4] == 'l' || b[i+4] == 'L')) + return TRUE; + } + + return FALSE; +} + +static BOOL image_gif_filter(const BYTE *b, DWORD size) +{ + return size >= 6 + && (b[0] == 'G' || b[0] == 'g') + && (b[1] == 'I' || b[1] == 'i') + && (b[2] == 'F' || b[2] == 'f') + && b[3] == '8' + && (b[4] == '7' || b[4] == '9') + && (b[5] == 'A' || b[5] == 'a'); +} + +static BOOL image_pjpeg_filter(const BYTE *b, DWORD size) +{ + return size > 2 && b[0] == 0xff && b[1] == 0xd8; +} + +static BOOL image_tiff_filter(const BYTE *b, DWORD size) +{ + return size > 2 && b[0] == 0x4d && b[1] == 0x4d; +} + +static BOOL image_xpng_filter(const BYTE *b, DWORD size) +{ + static const BYTE xpng_header[] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a}; + return size > sizeof(xpng_header) && !memcmp(b, xpng_header, sizeof(xpng_header)); +} + +static BOOL image_bmp_filter(const BYTE *b, DWORD size) +{ + return size >= 14 + && b[0] == 0x42 && b[1] == 0x4d + && *(const DWORD *)(b+6) == 0; +} + +static BOOL video_avi_filter(const BYTE *b, DWORD size) +{ + return size > 12 + && b[0] == 'R' && b[1] == 'I' && b[2] == 'F' && b[3] == 'F' + && b[8] == 'A' && b[9] == 'V' && b[10] == 'I' && b[11] == 0x20; +} + +static BOOL video_mpeg_filter(const BYTE *b, DWORD size) +{ + return size > 4 + && !b[0] && !b[1] && b[2] == 0x01 + && (b[3] == 0xb3 || b[3] == 0xba); +} + +static BOOL application_pdf_filter(const BYTE *b, DWORD size) +{ + return size > 4 && b[0] == 0x25 && b[1] == 0x50 && b[2] == 0x44 && b[3] == 0x46; +} + +static BOOL application_xzip_filter(const BYTE *b, DWORD size) +{ + return size > 2 && b[0] == 0x50 && b[1] == 0x4b; +} + +static BOOL application_xgzip_filter(const BYTE *b, DWORD size) +{ + return size > 2 && b[0] == 0x1f && b[1] == 0x8b; +} + +static BOOL application_java_filter(const BYTE *b, DWORD size) +{ + return size > 4 && b[0] == 0xca && b[1] == 0xfe && b[2] == 0xba && b[3] == 0xbe; +} + +static BOOL application_xmsdownload(const BYTE *b, DWORD size) +{ + return size > 2 && b[0] == 'M' && b[1] == 'Z'; +} + +static BOOL text_plain_filter(const BYTE *b, DWORD size) +{ + const BYTE *ptr; + + for(ptr = b; ptr < b+size-1; ptr++) { + if(*ptr < 0x20 && *ptr != '\n' && *ptr != '\r' && *ptr != '\t') + return FALSE; + } + + return TRUE; +} + +static BOOL application_octet_stream_filter(const BYTE *b, DWORD size) +{ + return TRUE; +} + HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer, DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags, LPWSTR* ppwzMimeOut, DWORD dwReserved) { - TRACE("(%p,%s,%p,%ld,%s,0x%lx,%p,0x%lx)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize, + TRACE("(%p,%s,%p,%d,%s,0x%x,%p,0x%x)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize, debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved); if(dwMimeFlags) - WARN("dwMimeFlags=%08lx\n", dwMimeFlags); + WARN("dwMimeFlags=%08x\n", dwMimeFlags); if(dwReserved) - WARN("dwReserved=%ld\n", dwReserved); + WARN("dwReserved=%d\n", dwReserved); /* pBC seams to not be used */ if(!ppwzMimeOut || (!pwzUrl && !pBuffer)) return E_INVALIDARG; - if(pwzMimeProposed && (!pwzUrl || !pBuffer || (pBuffer && !cbSize))) { + if(pwzMimeProposed && (!pBuffer || (pBuffer && !cbSize))) { DWORD len; if(!pwzMimeProposed) @@ -412,23 +552,91 @@ HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer, } if(pBuffer) { - UCHAR *ptr = pBuffer; + const BYTE *buf = pBuffer; DWORD len; - LPCWSTR ret; + LPCWSTR ret = NULL; + int i; - static const WCHAR wszAppOctetStream[] = {'a','p','p','l','i','c','a','t','i','o','n','/', - 'o','c','t','e','t','-','s','t','r','e','a','m','\0'}; + static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0}; + static const WCHAR wszImageGif[] = {'i','m','a','g','e','/','g','i','f',0}; + static const WCHAR wszImagePjpeg[] = {'i','m','a','g','e','/','p','j','p','e','g',0}; + static const WCHAR wszImageTiff[] = {'i','m','a','g','e','/','t','i','f','f',0}; + static const WCHAR wszImageXPng[] = {'i','m','a','g','e','/','x','-','p','n','g',0}; + static const WCHAR wszImageBmp[] = {'i','m','a','g','e','/','b','m','p',0}; + static const WCHAR wszVideoAvi[] = {'v','i','d','e','o','/','a','v','i',0}; + static const WCHAR wszVideoMpeg[] = {'v','i','d','e','o','/','m','p','e','g',0}; + static const WCHAR wszAppPdf[] = {'a','p','p','l','i','c','a','t','i','o','n','/', + 'p','d','f',0}; + static const WCHAR wszAppXZip[] = {'a','p','p','l','i','c','a','t','i','o','n','/', + 'x','-','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0}; + static const WCHAR wszAppXGzip[] = {'a','p','p','l','i','c','a','t','i','o','n','/', + 'x','-','g','z','i','p','-','c','o','m','p','r','e','s','s','e','d',0}; + static const WCHAR wszAppJava[] = {'a','p','p','l','i','c','a','t','i','o','n','/', + 'j','a','v','a',0}; + static const WCHAR wszAppXMSDownload[] = {'a','p','p','l','i','c','a','t','i','o','n','/', + 'x','-','m','s','d','o','w','n','l','o','a','d',0}; static const WCHAR wszTextPlain[] = {'t','e','x','t','/','p','l','a','i','n','\0'}; + static const WCHAR wszAppOctetStream[] = {'a','p','p','l','i','c','a','t','i','o','n','/', + 'o','c','t','e','t','-','s','t','r','e','a','m','\0'}; + + static const struct { + LPCWSTR mime; + BOOL (*filter)(const BYTE *,DWORD); + } mime_filters[] = { + {wszTextHtml, text_html_filter}, + {wszImageGif, image_gif_filter}, + {wszImagePjpeg, image_pjpeg_filter}, + {wszImageTiff, image_tiff_filter}, + {wszImageXPng, image_xpng_filter}, + {wszImageBmp, image_bmp_filter}, + {wszVideoAvi, video_avi_filter}, + {wszVideoMpeg, video_mpeg_filter}, + {wszAppPdf, application_pdf_filter}, + {wszAppXZip, application_xzip_filter}, + {wszAppXGzip, application_xgzip_filter}, + {wszAppJava, application_java_filter}, + {wszAppXMSDownload, application_xmsdownload}, + {wszTextPlain, text_plain_filter}, + {wszAppOctetStream, application_octet_stream_filter} + }; if(!cbSize) return E_FAIL; - ret = wszTextPlain; - for(ptr = pBuffer; ptr < (UCHAR*)pBuffer+cbSize-1; ptr++) { - if(*ptr < 0x20 && *ptr != '\n' && *ptr != '\r' && *ptr != '\t') { - ret = wszAppOctetStream; - break; + if(pwzMimeProposed && strcmpW(pwzMimeProposed, wszAppOctetStream)) { + for(i=0; i < sizeof(mime_filters)/sizeof(*mime_filters); i++) { + if(!strcmpW(pwzMimeProposed, mime_filters[i].mime)) + break; } + + if(i == sizeof(mime_filters)/sizeof(*mime_filters) + || mime_filters[i].filter(buf, cbSize)) { + len = strlenW(pwzMimeProposed)+1; + *ppwzMimeOut = CoTaskMemAlloc(len*sizeof(WCHAR)); + memcpy(*ppwzMimeOut, pwzMimeProposed, len*sizeof(WCHAR)); + return S_OK; + } + } + + i=0; + while(!ret) { + if(mime_filters[i].filter(buf, cbSize)) + ret = mime_filters[i].mime; + i++; + } + + TRACE("found %s for data\n" + "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + debugstr_w(ret), buf[0],buf[1],buf[2],buf[3], buf[4],buf[5],buf[6],buf[7], + buf[8],buf[9],buf[10],buf[11], buf[12],buf[13],buf[14],buf[15]); + + if(pwzMimeProposed) { + if(i == sizeof(mime_filters)/sizeof(*mime_filters)) + ret = pwzMimeProposed; + + /* text/html is a special case */ + if(!strcmpW(pwzMimeProposed, wszTextHtml) && !strcmpW(ret, wszTextPlain)) + ret = wszTextHtml; } len = strlenW(ret)+1; @@ -452,13 +660,13 @@ HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer, res = RegOpenKeyW(HKEY_CLASSES_ROOT, ptr, &hkey); if(res != ERROR_SUCCESS) - return E_FAIL; + return HRESULT_FROM_WIN32(res); size = sizeof(mime); res = RegQueryValueExW(hkey, wszContentType, NULL, NULL, (LPBYTE)mime, &size); RegCloseKey(hkey); if(res != ERROR_SUCCESS) - return E_FAIL; + return HRESULT_FROM_WIN32(res); *ppwzMimeOut = CoTaskMemAlloc(size); memcpy(*ppwzMimeOut, mime, size); @@ -467,3 +675,20 @@ HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer, return E_FAIL; } + +/*********************************************************************** + * Extract (URLMON.@) + */ +HRESULT WINAPI Extract(void *dest, LPCSTR szCabName) +{ + HRESULT (WINAPI *pExtract)(void *, LPCSTR); + + if (!hCabinet) + hCabinet = LoadLibraryA("cabinet.dll"); + + if (!hCabinet) return HRESULT_FROM_WIN32(GetLastError()); + pExtract = (void *)GetProcAddress(hCabinet, "Extract"); + if (!pExtract) return HRESULT_FROM_WIN32(GetLastError()); + + return pExtract(dest, szCabName); +} diff --git a/reactos/dll/win32/urlmon/urlmon_main.h b/reactos/dll/win32/urlmon/urlmon_main.h index 97197ade68e..46ec6714b9f 100644 --- a/reactos/dll/win32/urlmon/urlmon_main.h +++ b/reactos/dll/win32/urlmon/urlmon_main.h @@ -13,7 +13,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __WINE_URLMON_MAIN_H @@ -30,6 +30,7 @@ extern HRESULT ZoneMgrImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); extern HRESULT FileProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); extern HRESULT HttpProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); extern HRESULT FtpProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); +extern HRESULT MkProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); /********************************************************************** * Dll lifetime tracking declaration for urlmon.dll @@ -54,8 +55,11 @@ typedef struct HRESULT UMCreateStreamOnCacheFile(LPCWSTR pszURL, DWORD dwSize, LPWSTR pszFileName, HANDLE *phfile, IUMCacheStream **ppstr); void UMCloseCacheFileStream(IUMCacheStream *pstr); -HRESULT get_protocol_iface(LPCWSTR url, IUnknown **ret); +IInternetProtocolInfo *get_protocol_info(LPCWSTR url); +HRESULT get_protocol_handler(LPCWSTR url, CLSID *clsid, IClassFactory **ret); HRESULT start_binding(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv); +HRESULT create_binding_protocol(LPCWSTR url, IInternetProtocol **protocol); + #endif /* __WINE_URLMON_MAIN_H */ diff --git a/reactos/dll/win32/urlmon/version.rc b/reactos/dll/win32/urlmon/version.rc index 4f532951a83..10cc7216ccd 100644 --- a/reactos/dll/win32/urlmon/version.rc +++ b/reactos/dll/win32/urlmon/version.rc @@ -15,7 +15,7 @@ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define WINE_FILENAME_STR "urlmon.dll"