diff --git a/dlls/urlmon/binding.c b/dlls/urlmon/binding.c index b566265572f..e0f3624ff6b 100644 --- a/dlls/urlmon/binding.c +++ b/dlls/urlmon/binding.c @@ -47,6 +47,7 @@ typedef struct { BYTE buf[1024*8]; DWORD size; BOOL init; + HANDLE file; HRESULT hres; LPWSTR cache_file; @@ -101,6 +102,7 @@ struct Binding { LPWSTR redirect_url; IID iid; BOOL report_mime; + BOOL use_cache_file; DWORD state; HRESULT hres; download_state_t download_state; @@ -134,6 +136,20 @@ static void fill_stgmed_buffer(stgmed_buf_t *buf) buf->init = TRUE; } +static void read_protocol_data(stgmed_buf_t *stgmed_buf) +{ + BYTE buf[8192]; + DWORD read; + HRESULT hres; + + fill_stgmed_buffer(stgmed_buf); + if(stgmed_buf->size < sizeof(stgmed_buf->buf)) + return; + + do hres = IInternetProtocol_Read(stgmed_buf->protocol, buf, sizeof(buf), &read); + while(hres == S_OK); +} + static void dump_BINDINFO(BINDINFO *bi) { static const char * const BINDINFOF_str[] = { @@ -339,6 +355,19 @@ static void create_object(Binding *binding) IInternetProtocol_Terminate(binding->protocol, 0); } +static void cache_file_available(Binding *This, const WCHAR *file_name) +{ + heap_free(This->stgmed_buf->cache_file); + This->stgmed_buf->cache_file = heap_strdupW(file_name); + + if(This->use_cache_file) { + This->stgmed_buf->file = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(This->stgmed_buf->file == INVALID_HANDLE_VALUE) + WARN("CreateFile failed: %u\n", GetLastError()); + } +} + #define STGMEDUNK_THIS(iface) DEFINE_THIS(stgmed_buf_t, Unknown, iface) static HRESULT WINAPI StgMedUnk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) @@ -377,6 +406,8 @@ static ULONG WINAPI StgMedUnk_Release(IUnknown *iface) TRACE("(%p) ref=%d\n", This, ref); if(!ref) { + if(This->file != INVALID_HANDLE_VALUE) + CloseHandle(This->file); IInternetProtocol_Release(This->protocol); heap_free(This->cache_file); heap_free(This); @@ -403,6 +434,7 @@ static stgmed_buf_t *create_stgmed_buf(IInternetProtocol *protocol) ret->ref = 1; ret->size = 0; ret->init = FALSE; + ret->file = INVALID_HANDLE_VALUE; ret->hres = S_OK; ret->cache_file = NULL; @@ -488,6 +520,15 @@ static HRESULT WINAPI ProtocolStream_Read(IStream *iface, void *pv, TRACE("(%p)->(%p %d %p)\n", This, pv, cb, pcbRead); + if(This->buf->file != INVALID_HANDLE_VALUE) { + if (!ReadFile(This->buf->file, pv, cb, &read, NULL)) + return INET_E_DOWNLOAD_FAILURE; + + if(pcbRead) + *pcbRead = read; + return read ? S_OK : S_FALSE; + } + if(This->buf->size) { read = cb; @@ -690,16 +731,7 @@ static HRESULT stgmed_file_fill_stgmed(stgmed_obj_t *obj, STGMEDIUM *stgmed) return INET_E_DATA_NOT_AVAILABLE; } - fill_stgmed_buffer(file_obj->buf); - if(file_obj->buf->size == sizeof(file_obj->buf->buf)) { - BYTE buf[1024]; - DWORD read; - HRESULT hres; - - do { - hres = IInternetProtocol_Read(file_obj->buf->protocol, buf, sizeof(buf), &read); - }while(hres == S_OK); - } + read_protocol_data(file_obj->buf); stgmed->tymed = TYMED_FILE; stgmed->u.lpszFileName = file_obj->buf->cache_file; @@ -988,8 +1020,7 @@ static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink mime_available(This, szStatusText); break; case BINDSTATUS_CACHEFILENAMEAVAILABLE: - heap_free(This->stgmed_buf->cache_file); - This->stgmed_buf->cache_file = heap_strdupW(szStatusText); + cache_file_available(This, szStatusText); break; case BINDSTATUS_DECODING: IBindStatusCallback_OnProgress(This->callback, 0, 0, BINDSTATUS_DECODING, szStatusText); @@ -1020,9 +1051,12 @@ static void report_data(Binding *This, DWORD bscf, ULONG progress, ULONG progres if(This->download_state == END_DOWNLOAD || (This->state & BINDING_STOPPED)) return; - if(This->download_state == BEFORE_DOWNLOAD) { + if(This->stgmed_buf->file != INVALID_HANDLE_VALUE) + read_protocol_data(This->stgmed_buf); + else if(This->download_state == BEFORE_DOWNLOAD) fill_stgmed_buffer(This->stgmed_buf); + if(This->download_state == BEFORE_DOWNLOAD) { This->download_state = DOWNLOADING; sent_begindownloaddata = TRUE; IBindStatusCallback_OnProgress(This->callback, progress, progress_max, @@ -1431,8 +1465,12 @@ static HRESULT Binding_Create(IMoniker *mon, Binding *binding_ctx, LPCWSTR url, if(to_obj) ret->bindinfo.dwOptions |= 0x100000; - if(!(ret->bindf & BINDF_ASYNCHRONOUS) || !is_urlmon_protocol(url)) + if(!(ret->bindf & BINDF_ASYNCHRONOUS)) { ret->bindf |= BINDF_NEEDFILE; + ret->use_cache_file = TRUE; + }else if(!is_urlmon_protocol(url)) { + ret->bindf |= BINDF_NEEDFILE; + } ret->url = heap_strdupW(url);