Implement URLMonikerImpl_BindToStorage.

This commit is contained in:
Troy Rollo 2005-05-04 10:36:54 +00:00 committed by Alexandre Julliard
parent 9d86716ef6
commit caf6fa9531
4 changed files with 749 additions and 88 deletions

View File

@ -10,6 +10,7 @@ C_SRCS = \
regsvr.c \ regsvr.c \
sec_mgr.c \ sec_mgr.c \
umon.c \ umon.c \
umstream.c \
urlmon_main.c urlmon_main.c
SUBDIRS = tests SUBDIRS = tests

View File

@ -61,6 +61,10 @@ typedef struct URLMonikerImpl{
HWND hwndCallback; HWND hwndCallback;
IBindCtx *pBC; IBindCtx *pBC;
HINTERNET hinternet, hconnect, hrequest; HINTERNET hinternet, hconnect, hrequest;
HANDLE hCacheFile;
IUMCacheStream *pstrCache;
IBindStatusCallback *pbscb;
DWORD total_read, expected_size;
} URLMonikerImpl; } URLMonikerImpl;
/******************************************************************************* /*******************************************************************************
@ -126,6 +130,15 @@ static ULONG WINAPI URLMonikerImpl_Release(IMoniker* iface)
if (!refCount) { if (!refCount) {
HeapFree(GetProcessHeap(),0,This->URLName); HeapFree(GetProcessHeap(),0,This->URLName);
HeapFree(GetProcessHeap(),0,This); HeapFree(GetProcessHeap(),0,This);
if (This->hCacheFile)
CloseHandle(This->hCacheFile);
if (This->pstrCache)
{
UMCloseCacheFileStream(This->pstrCache);
IStream_Release((IStream *)This->pstrCache);
}
if (This->pbscb)
IBindStatusCallback_Release(This->pbscb);
} }
URLMON_UnlockModule(); URLMON_UnlockModule();
@ -133,6 +146,105 @@ static ULONG WINAPI URLMonikerImpl_Release(IMoniker* iface)
return refCount; return refCount;
} }
static void URLMonikerImpl_CloseCacheDownload(URLMonikerImpl *This)
{
CloseHandle(This->hCacheFile);
This->hCacheFile = 0;
UMCloseCacheFileStream(This->pstrCache);
IStream_Release((IStream *)This->pstrCache);
This->pstrCache = 0;
}
static HRESULT URLMonikerImpl_MoreCacheData(URLMonikerImpl *This, char *buf, DWORD dwBytes)
{
DWORD written;
if (WriteFile(This->hCacheFile, buf, dwBytes, &written, NULL) && written == dwBytes)
{
HRESULT hr;
This->total_read += written;
hr = IBindStatusCallback_OnProgress(This->pbscb,
This->total_read + written,
This->expected_size,
(This->total_read == written) ?
BINDSTATUS_BEGINDOWNLOADDATA :
BINDSTATUS_DOWNLOADINGDATA,
NULL);
if (!hr)
{
STGMEDIUM stg;
FORMATETC fmt;
fmt.cfFormat = 0;
fmt.ptd = NULL;
fmt.dwAspect = 0;
fmt.lindex = -1;
fmt.tymed = TYMED_ISTREAM;
stg.tymed = TYMED_ISTREAM;
stg.u.pstm = (IStream *)This->pstrCache;
stg.pUnkForRelease = NULL;
hr = IBindStatusCallback_OnDataAvailable(This->pbscb,
(This->total_read == written) ?
BSCF_FIRSTDATANOTIFICATION :
BSCF_INTERMEDIATEDATANOTIFICATION,
This->total_read + written,
&fmt,
&stg);
}
if (written < dwBytes)
return STG_E_MEDIUMFULL;
else
return hr;
}
return HRESULT_FROM_WIN32(GetLastError());
}
static void URLMonikerImpl_FinishedDownload(URLMonikerImpl *This, HRESULT hr)
{
STGMEDIUM stg;
FORMATETC fmt;
fmt.ptd = NULL;
fmt.dwAspect = 0;
fmt.lindex = -1;
fmt.tymed = TYMED_ISTREAM;
stg.tymed = TYMED_ISTREAM;
stg.u.pstm = (IStream *)This->pstrCache;
stg.pUnkForRelease = NULL;
IBindStatusCallback_OnProgress(This->pbscb, This->total_read, This->expected_size, BINDSTATUS_ENDDOWNLOADDATA, NULL);
IBindStatusCallback_OnDataAvailable(This->pbscb, BSCF_LASTDATANOTIFICATION, This->total_read, &fmt, &stg);
if (hr)
{
WCHAR *pwchError = 0;
FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, (DWORD) hr,
0, (LPWSTR) &pwchError,
0, NULL);
if (!pwchError)
{
static WCHAR achFormat[] = { '%', '0', '8', 'x', 0 };
pwchError =(WCHAR *) LocalAlloc(LMEM_FIXED, sizeof(WCHAR) * 9);
wsprintfW(pwchError, achFormat, hr);
}
IBindStatusCallback_OnStopBinding(This->pbscb, hr, pwchError);
LocalFree(pwchError);
}
else
{
IBindStatusCallback_OnStopBinding(This->pbscb, hr, NULL);
}
IBindStatusCallback_Release(This->pbscb);
This->pbscb = 0;
}
/****************************************************************************** /******************************************************************************
* URLMoniker_GetClassID * URLMoniker_GetClassID
******************************************************************************/ ******************************************************************************/
@ -310,6 +422,8 @@ static void CALLBACK URLMON_InternetCallback(HINTERNET hinet, /*DWORD_PTR*/ DWOR
return; return;
} }
#endif #endif
/****************************************************************************** /******************************************************************************
* URLMoniker_BindToStorage * URLMoniker_BindToStorage
******************************************************************************/ ******************************************************************************/
@ -321,12 +435,10 @@ static HRESULT WINAPI URLMonikerImpl_BindToStorage(IMoniker* iface,
{ {
URLMonikerImpl *This = (URLMonikerImpl *)iface; URLMonikerImpl *This = (URLMonikerImpl *)iface;
HRESULT hres; HRESULT hres;
IBindStatusCallback *pbscb;
BINDINFO bi; BINDINFO bi;
DWORD bindf; DWORD bindf;
IStream *pstr; WCHAR szFileName[MAX_PATH + 1];
FIXME("(%p)->(%p,%p,%s,%p): stub\n",This,pbc,pmkToLeft,debugstr_guid(riid),ppvObject);
if(pmkToLeft) { if(pmkToLeft) {
FIXME("pmkToLeft != NULL\n"); FIXME("pmkToLeft != NULL\n");
return E_NOTIMPL; return E_NOTIMPL;
@ -336,36 +448,46 @@ static HRESULT WINAPI URLMonikerImpl_BindToStorage(IMoniker* iface,
return E_NOTIMPL; return E_NOTIMPL;
} }
/* FIXME This is a bad hack (tm). We should clearly download to a temporary file. hres = UMCreateStreamOnCacheFile(This->URLName, 0, szFileName, &This->hCacheFile, &This->pstrCache);
We also need to implement IStream ourselves so that IStream_Read can return
E_PENDING */
hres = CreateStreamOnHGlobal(0, TRUE, &pstr);
if(SUCCEEDED(hres)) { if(SUCCEEDED(hres)) {
TRACE("Created dummy stream...\n"); TRACE("Created stream...\n");
hres = IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown**)&pbscb); *ppvObject = (void *) This->pstrCache;
IStream_AddRef((IStream *) This->pstrCache);
hres = IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown**)&This->pbscb);
if(SUCCEEDED(hres)) { if(SUCCEEDED(hres)) {
TRACE("Got IBindStatusCallback...\n"); TRACE("Got IBindStatusCallback...\n");
memset(&bi, 0, sizeof(bi)); memset(&bi, 0, sizeof(bi));
bi.cbSize = sizeof(bi); bi.cbSize = sizeof(bi);
bindf = 0; bindf = 0;
hres = IBindStatusCallback_GetBindInfo(pbscb, &bindf, &bi); hres = IBindStatusCallback_GetBindInfo(This->pbscb, &bindf, &bi);
if(SUCCEEDED(hres)) { if(SUCCEEDED(hres)) {
WCHAR *urlcopy, *tmpwc;
URL_COMPONENTSW url; URL_COMPONENTSW url;
WCHAR *host, *path; WCHAR *host, *path, *user, *pass;
DWORD len, lensz = sizeof(len), total_read = 0; DWORD lensz = sizeof(This->expected_size);
LARGE_INTEGER last_read_pos; DWORD dwService = 0;
FORMATETC fmt; BOOL bSuccess;
STGMEDIUM stg;
TRACE("got bindinfo. bindf = %08lx extrainfo = %s bindinfof = %08lx bindverb = %08lx iid %s\n", TRACE("got bindinfo. bindf = %08lx extrainfo = %s bindinfof = %08lx bindverb = %08lx iid %s\n",
bindf, debugstr_w(bi.szExtraInfo), bi.grfBindInfoF, bi.dwBindVerb, debugstr_guid(&bi.iid)); bindf, debugstr_w(bi.szExtraInfo), bi.grfBindInfoF, bi.dwBindVerb, debugstr_guid(&bi.iid));
hres = IBindStatusCallback_OnStartBinding(pbscb, 0, (IBinding*)&This->lpvtbl2); hres = IBindStatusCallback_OnStartBinding(This->pbscb, 0, (IBinding*)&This->lpvtbl2);
TRACE("OnStartBinding rets %08lx\n", hres); 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(This->URLName) + 1));
lstrcpyW(urlcopy, This->URLName);
for (tmpwc = urlcopy; *tmpwc && *tmpwc != '#' && *tmpwc != '?'; ++tmpwc)
if (*tmpwc == '\\')
*tmpwc = '/';
#if 0 #if 0
if(!registered_wndclass) { if(!registered_wndclass) {
WNDCLASSA urlmon_wndclass = {0, URLMON_WndProc,0, 0, URLMON_hInstance, 0, 0, 0, NULL, "URLMON_Callback_Window_Class"}; WNDCLASSA urlmon_wndclass = {0, URLMON_WndProc,0, 0, URLMON_hInstance, 0, 0, 0, NULL, "URLMON_Callback_Window_Class"};
@ -377,81 +499,226 @@ static HRESULT WINAPI URLMonikerImpl_BindToStorage(IMoniker* iface,
URLMON_hInstance, NULL); URLMON_hInstance, NULL);
#endif #endif
This->expected_size = 0;
This->total_read = 0;
memset(&url, 0, sizeof(url)); memset(&url, 0, sizeof(url));
url.dwStructSize = sizeof(url); url.dwStructSize = sizeof(url);
url.dwSchemeLength = url.dwHostNameLength = url.dwUrlPathLength = 1; url.dwSchemeLength = url.dwHostNameLength = url.dwUrlPathLength = url.dwUserNameLength = url.dwPasswordLength = 1;
InternetCrackUrlW(This->URLName, 0, 0, &url); InternetCrackUrlW(urlcopy, 0, 0, &url);
host = HeapAlloc(GetProcessHeap(), 0, (url.dwHostNameLength + 1) * sizeof(WCHAR)); host = HeapAlloc(GetProcessHeap(), 0, (url.dwHostNameLength + 1) * sizeof(WCHAR));
memcpy(host, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR)); memcpy(host, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR));
host[url.dwHostNameLength] = '\0'; host[url.dwHostNameLength] = '\0';
path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR)); path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR));
memcpy(path, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR)); memcpy(path, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR));
path[url.dwUrlPathLength] = '\0'; path[url.dwUrlPathLength] = '\0';
if (url.dwUserNameLength)
{
user = HeapAlloc(GetProcessHeap(), 0, ((url.dwUserNameLength + 1) * sizeof(WCHAR)));
memcpy(user, url.lpszUserName, url.dwUserNameLength * sizeof(WCHAR));
user[url.dwUserNameLength] = 0;
}
else
{
user = 0;
}
if (url.dwPasswordLength)
{
pass = HeapAlloc(GetProcessHeap(), 0, ((url.dwPasswordLength + 1) * sizeof(WCHAR)));
memcpy(pass, url.lpszPassword, url.dwPasswordLength * sizeof(WCHAR));
pass[url.dwPasswordLength] = 0;
}
else
{
pass = 0;
}
switch ((DWORD) url.nScheme)
{
case INTERNET_SCHEME_FTP:
case INTERNET_SCHEME_GOPHER:
case INTERNET_SCHEME_HTTP:
case INTERNET_SCHEME_HTTPS:
This->hinternet = InternetOpenA("User Agent", 0, NULL, NULL, 0 /*INTERNET_FLAG_ASYNC*/); This->hinternet = InternetOpenA("User Agent", 0, NULL, NULL, 0 /*INTERNET_FLAG_ASYNC*/);
/* InternetSetStatusCallback(This->hinternet, URLMON_InternetCallback);*/ /* InternetSetStatusCallback(This->hinternet, URLMON_InternetCallback);*/
if (!This->hinternet)
{
hres = HRESULT_FROM_WIN32(GetLastError());
break;
}
This->hconnect = InternetConnectW(This->hinternet, host, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, switch ((DWORD) url.nScheme)
INTERNET_SERVICE_HTTP, 0, (DWORD)This); {
case INTERNET_SCHEME_FTP:
if (!url.nPort)
url.nPort = INTERNET_DEFAULT_FTP_PORT;
dwService = INTERNET_SERVICE_FTP;
break;
case INTERNET_SCHEME_GOPHER:
if (!url.nPort)
url.nPort = INTERNET_DEFAULT_GOPHER_PORT;
dwService = INTERNET_SERVICE_GOPHER;
break;
case INTERNET_SCHEME_HTTP:
if (!url.nPort)
url.nPort = INTERNET_DEFAULT_HTTP_PORT;
dwService = INTERNET_SERVICE_HTTP;
break;
case INTERNET_SCHEME_HTTPS:
if (!url.nPort)
url.nPort = INTERNET_DEFAULT_HTTPS_PORT;
dwService = INTERNET_SERVICE_HTTP;
break;
}
This->hconnect = InternetConnectW(This->hinternet, host, url.nPort, user, pass,
dwService, 0, (DWORD)This);
if (!This->hconnect)
{
hres = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(This->hinternet);
break;
}
hres = IBindStatusCallback_OnProgress(This->pbscb, 0, 0, 0x22, NULL);
hres = IBindStatusCallback_OnProgress(This->pbscb, 0, 0, BINDSTATUS_FINDINGRESOURCE, NULL);
hres = IBindStatusCallback_OnProgress(This->pbscb, 0, 0, BINDSTATUS_CONNECTING, NULL);
hres = IBindStatusCallback_OnProgress(This->pbscb, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL);
bSuccess = FALSE;
switch (dwService)
{
case INTERNET_SERVICE_GOPHER:
This->hrequest = GopherOpenFileW(This->hconnect,
path,
0,
INTERNET_FLAG_RELOAD,
0);
if (This->hrequest)
bSuccess = TRUE;
else
hres = HRESULT_FROM_WIN32(GetLastError());
break;
case INTERNET_SERVICE_FTP:
This->hrequest = FtpOpenFileW(This->hconnect,
path,
GENERIC_READ,
FTP_TRANSFER_TYPE_BINARY |
INTERNET_FLAG_TRANSFER_BINARY |
INTERNET_FLAG_RELOAD,
0);
if (This->hrequest)
bSuccess = TRUE;
else
hres = HRESULT_FROM_WIN32(GetLastError());
break;
case INTERNET_SERVICE_HTTP:
This->hrequest = HttpOpenRequestW(This->hconnect, NULL, path, NULL, NULL, NULL, 0, (DWORD)This); This->hrequest = HttpOpenRequestW(This->hconnect, NULL, path, NULL, NULL, NULL, 0, (DWORD)This);
if (!This->hrequest)
{
hres = HRESULT_FROM_WIN32(GetLastError());
}
else if (!HttpSendRequestW(This->hrequest, NULL, 0, NULL, 0))
{
hres = HRESULT_FROM_WIN32(GetLastError());
InternetCloseHandle(This->hrequest);
}
else
{
HttpQueryInfoW(This->hrequest,
HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
&This->expected_size,
&lensz,
NULL);
bSuccess = TRUE;
}
break;
}
if(bSuccess)
{
TRACE("res = %ld gle = %08lx url len = %ld\n", hres, GetLastError(), This->expected_size);
hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, 0x22, NULL); IBindStatusCallback_OnProgress(This->pbscb, 0, 0, BINDSTATUS_CACHEFILENAMEAVAILABLE, szFileName);
hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, BINDSTATUS_FINDINGRESOURCE, NULL);
hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, BINDSTATUS_CONNECTING, NULL);
hres = IBindStatusCallback_OnProgress(pbscb, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL);
hres = E_OUTOFMEMORY; /* FIXME */
if(HttpSendRequestW(This->hrequest, NULL, 0, NULL, 0)) {
len = 0;
HttpQueryInfoW(This->hrequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &len, &lensz, NULL);
TRACE("res = %ld gle = %08lx url len = %ld\n", hres, GetLastError(), len);
last_read_pos.u.LowPart = last_read_pos.u.HighPart = 0;
fmt.cfFormat = 0;
fmt.ptd = NULL;
fmt.dwAspect = 0;
fmt.lindex = -1;
fmt.tymed = TYMED_ISTREAM;
stg.tymed = TYMED_ISTREAM;
stg.u.pstm = pstr;
stg.pUnkForRelease = NULL;
while(1) { while(1) {
char buf[4096]; char buf[4096];
DWORD bufread; DWORD bufread;
DWORD written;
if(InternetReadFile(This->hrequest, buf, sizeof(buf), &bufread)) { if(InternetReadFile(This->hrequest, buf, sizeof(buf), &bufread)) {
TRACE("read %ld bytes %s...\n", bufread, debugstr_an(buf, 10)); TRACE("read %ld bytes %s...\n", bufread, debugstr_an(buf, 10));
if(bufread == 0) break; if(bufread == 0) break;
IStream_Write(pstr, buf, bufread, &written); hres = URLMonikerImpl_MoreCacheData(This, buf, bufread);
total_read += bufread;
IStream_Seek(pstr, last_read_pos, STREAM_SEEK_SET, NULL);
hres = IBindStatusCallback_OnProgress(pbscb, total_read, len, (total_read == bufread) ?
BINDSTATUS_BEGINDOWNLOADDATA :
BINDSTATUS_DOWNLOADINGDATA, NULL);
hres = IBindStatusCallback_OnDataAvailable(pbscb,
(total_read == bufread) ? BSCF_FIRSTDATANOTIFICATION :
BSCF_INTERMEDIATEDATANOTIFICATION,
total_read, &fmt, &stg);
last_read_pos.u.LowPart += bufread; /* FIXME */
} else } else
break; break;
} break;
hres = IBindStatusCallback_OnProgress(pbscb, total_read, len, BINDSTATUS_ENDDOWNLOADDATA, NULL);
hres = IBindStatusCallback_OnDataAvailable(pbscb, BSCF_LASTDATANOTIFICATION, total_read, &fmt, &stg);
TRACE("OnDataAvail rets %08lx\n", hres);
hres = IBindStatusCallback_OnStopBinding(pbscb, S_OK, NULL);
TRACE("OnStop rets %08lx\n", hres);
hres = S_OK;
} }
InternetCloseHandle(This->hrequest); InternetCloseHandle(This->hrequest);
hres = S_OK;
}
InternetCloseHandle(This->hconnect); InternetCloseHandle(This->hconnect);
InternetCloseHandle(This->hinternet); InternetCloseHandle(This->hinternet);
IBindStatusCallback_Release(pbscb); break;
case INTERNET_SCHEME_FILE:
path = This->URLName + 5; /* Skip the "file:" part */
if ((path[0] != '/' && path[0] != '\\') ||
(path[1] != '/' && path[1] != '\\'))
{
hres = E_FAIL;
}
else
{
HANDLE h;
path += 2;
if (path[0] == '/' || path[0] == '\\')
++path;
h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
if (h == (HANDLE) HFILE_ERROR)
{
hres = HRESULT_FROM_WIN32(GetLastError());
}
else
{
char buf[4096];
DWORD bufread;
IBindStatusCallback_OnProgress(This->pbscb, 0, 0, BINDSTATUS_CACHEFILENAMEAVAILABLE, szFileName);
while (ReadFile(h, buf, sizeof(buf), &bufread, NULL) && bufread > 0)
hres = URLMonikerImpl_MoreCacheData(This, buf, bufread);
CloseHandle(h);
hres = S_OK;
}
}
break;
default:
FIXME("Unsupported URI scheme");
break;
}
URLMonikerImpl_CloseCacheDownload(This);
URLMonikerImpl_FinishedDownload(This, hres);
if (user)
HeapFree(GetProcessHeap(), 0, user);
if (pass)
HeapFree(GetProcessHeap(), 0, pass);
HeapFree(GetProcessHeap(), 0, path);
HeapFree(GetProcessHeap(), 0, host);
HeapFree(GetProcessHeap(), 0, urlcopy);
} }
} }
} }
*ppvObject = (VOID*)pstr;
return hres; return hres;
} }

380
dlls/urlmon/umstream.c Normal file
View File

@ -0,0 +1,380 @@
/*
* Based on ../shell32/memorystream.c
*
* Copyright 1999 Juergen Schmied
* Copyright 2003 Mike McCormack 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdarg.h>
#define COBJMACROS
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winternl.h"
#include "winuser.h"
#include "objbase.h"
#include "wine/debug.h"
#include "wine/unicode.h"
#include "ole2.h"
#include "urlmon.h"
#include "wininet.h"
#include "shlwapi.h"
#include "urlmon_main.h"
WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
static const IStreamVtbl stvt;
HRESULT UMCreateStreamOnCacheFile(LPCWSTR pszURL,
DWORD dwSize,
LPWSTR pszFileName,
HANDLE *phfile,
IUMCacheStream **ppstr)
{
IUMCacheStream* ucstr;
HANDLE handle;
LPWSTR ext;
LPCWSTR c;
LPCWSTR eloc = 0;
HRESULT hr;
for (c = pszURL; *c && *c != '#' && *c != '?'; ++c)
{
if (*c == '.')
eloc = c + 1;
else if (*c == '/' || *c == '\\')
eloc = 0;
}
if (!eloc)
eloc = c;
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))
hr = HRESULT_FROM_WIN32(GetLastError());
else
hr = 0;
HeapFree(GetProcessHeap(), 0, ext);
if (hr)
return hr;
TRACE("Opening %s\n", debugstr_w(pszFileName) );
handle = CreateFileW( pszFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL );
if( handle == INVALID_HANDLE_VALUE )
return HRESULT_FROM_WIN32(GetLastError());
if (phfile)
{
/* Call CreateFileW again because we need a handle with its own file pointer, and DuplicateHandle will return
* a handle that shares its file pointer with the original.
*/
*phfile = CreateFileW( pszFileName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
if (*phfile == (HANDLE) HFILE_ERROR)
{
DWORD dwError = GetLastError();
CloseHandle(handle);
return HRESULT_FROM_WIN32(dwError);
}
}
ucstr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(IUMCacheStream));
if(ucstr )
{
ucstr->pszURL = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(WCHAR) * (lstrlenW(pszURL) + 1));
if (ucstr->pszURL)
{
ucstr->pszFileName = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(WCHAR) * (lstrlenW(pszFileName) + 1));
if (ucstr->pszFileName)
{
ucstr->lpVtbl=&stvt;
ucstr->ref = 1;
ucstr->handle = handle;
ucstr->closed = 0;
lstrcpyW(ucstr->pszURL, pszURL);
lstrcpyW(ucstr->pszFileName, pszFileName);
*ppstr = ucstr;
return S_OK;
}
HeapFree(GetProcessHeap(), 0, ucstr->pszURL);
}
HeapFree(GetProcessHeap(), 0, ucstr);
}
CloseHandle(handle);
if (phfile)
CloseHandle(*phfile);
return E_OUTOFMEMORY;
}
void UMCloseCacheFileStream(IUMCacheStream *This)
{
if (!This->closed)
{
FILETIME ftZero;
ftZero.dwLowDateTime = ftZero.dwHighDateTime = 0;
This->closed = 1;
CommitUrlCacheEntryW(This->pszURL,
This->pszFileName,
ftZero,
ftZero,
NORMAL_CACHE_ENTRY,
0,
0,
0,
0);
}
}
/**************************************************************************
* IStream_fnQueryInterface
*/
static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface,
REFIID riid,
LPVOID *ppvObj)
{
IUMCacheStream *This = (IUMCacheStream *)iface;
TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
*ppvObj = NULL;
if(IsEqualIID(riid, &IID_IUnknown) ||
IsEqualIID(riid, &IID_IStream))
{
*ppvObj = This;
}
if(*ppvObj)
{
IStream_AddRef((IStream*)*ppvObj);
TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
return S_OK;
}
TRACE("-- Interface: E_NOINTERFACE\n");
return E_NOINTERFACE;
}
/**************************************************************************
* IStream_fnAddRef
*/
static ULONG WINAPI IStream_fnAddRef(IStream *iface)
{
IUMCacheStream *This = (IUMCacheStream *)iface;
ULONG refCount = InterlockedIncrement(&This->ref);
TRACE("(%p)->(count=%lu)\n", This, refCount - 1);
return refCount;
}
/**************************************************************************
* IStream_fnRelease
*/
static ULONG WINAPI IStream_fnRelease(IStream *iface)
{
IUMCacheStream *This = (IUMCacheStream *)iface;
ULONG refCount = InterlockedDecrement(&This->ref);
TRACE("(%p)->(count=%lu)\n", This, refCount + 1);
if (!refCount)
{
TRACE(" destroying UMCacheStream (%p)\n",This);
UMCloseCacheFileStream(This);
CloseHandle(This->handle);
HeapFree(GetProcessHeap(), 0, This->pszFileName);
HeapFree(GetProcessHeap(), 0, This->pszURL);
HeapFree(GetProcessHeap(),0,This);
}
return refCount;
}
static HRESULT WINAPI IStream_fnRead (IStream * iface,
void* pv,
ULONG cb,
ULONG* pcbRead)
{
IUMCacheStream *This = (IUMCacheStream *)iface;
TRACE("(%p)->(%p,0x%08lx,%p)\n",This, pv, cb, pcbRead);
if ( !pv )
return STG_E_INVALIDPOINTER;
if ( ! ReadFile( This->handle, pv, cb, pcbRead, NULL ) )
return S_FALSE;
if (!*pcbRead)
return This->closed ? S_FALSE : E_PENDING;
return S_OK;
}
static HRESULT WINAPI IStream_fnWrite (IStream * iface,
const void* pv,
ULONG cb,
ULONG* pcbWritten)
{
return E_NOTIMPL;
}
static HRESULT WINAPI IStream_fnSeek ( IStream * iface,
LARGE_INTEGER dlibMove,
DWORD dwOrigin,
ULARGE_INTEGER* plibNewPosition)
{
DWORD pos, newposlo, newposhi;
IUMCacheStream *This = (IUMCacheStream *)iface;
TRACE("(%p)\n",This);
pos = dlibMove.QuadPart; /* FIXME: truncates */
newposhi = 0;
newposlo = SetFilePointer( This->handle, pos, &newposhi, dwOrigin );
if( newposlo == INVALID_SET_FILE_POINTER )
return E_FAIL;
if (plibNewPosition)
plibNewPosition->QuadPart = newposlo | ( (LONGLONG)newposhi<<32);
return S_OK;
}
static HRESULT WINAPI IStream_fnSetSize (IStream * iface,
ULARGE_INTEGER libNewSize)
{
IUMCacheStream *This = (IUMCacheStream *)iface;
TRACE("(%p)\n",This);
if( ! SetFilePointer( This->handle, libNewSize.QuadPart, NULL, FILE_BEGIN ) )
return E_FAIL;
if( ! SetEndOfFile( This->handle ) )
return E_FAIL;
return S_OK;
}
static HRESULT WINAPI IStream_fnCopyTo (IStream * iface,
IStream* pstm,
ULARGE_INTEGER cb,
ULARGE_INTEGER* pcbRead,
ULARGE_INTEGER* pcbWritten)
{
IUMCacheStream *This = (IUMCacheStream *)iface;
TRACE("(%p)\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI IStream_fnCommit (IStream * iface,
DWORD grfCommitFlags)
{
IUMCacheStream *This = (IUMCacheStream *)iface;
TRACE("(%p)\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI IStream_fnRevert (IStream * iface)
{
IUMCacheStream *This = (IUMCacheStream *)iface;
TRACE("(%p)\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI IStream_fnLockRegion (IStream * iface,
ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType)
{
IUMCacheStream *This = (IUMCacheStream *)iface;
TRACE("(%p)\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI IStream_fnUnlockRegion (IStream * iface,
ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType)
{
IUMCacheStream *This = (IUMCacheStream *)iface;
TRACE("(%p)\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI IStream_fnStat (IStream * iface,
STATSTG* pstatstg,
DWORD grfStatFlag)
{
IUMCacheStream *This = (IUMCacheStream *)iface;
TRACE("(%p)\n",This);
return E_NOTIMPL;
}
static HRESULT WINAPI IStream_fnClone (IStream * iface,
IStream** ppstm)
{
IUMCacheStream *This = (IUMCacheStream *)iface;
TRACE("(%p)\n",This);
return E_NOTIMPL;
}
static const IStreamVtbl stvt =
{
IStream_fnQueryInterface,
IStream_fnAddRef,
IStream_fnRelease,
IStream_fnRead,
IStream_fnWrite,
IStream_fnSeek,
IStream_fnSetSize,
IStream_fnCopyTo,
IStream_fnCommit,
IStream_fnRevert,
IStream_fnLockRegion,
IStream_fnUnlockRegion,
IStream_fnStat,
IStream_fnClone
};

View File

@ -37,4 +37,17 @@ static inline void URLMON_UnlockModule() { InterlockedDecrement( &URLMON_refCoun
#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
typedef struct
{
const IStreamVtbl *lpVtbl;
DWORD ref;
HANDLE handle;
BOOL closed;
WCHAR *pszFileName;
WCHAR *pszURL;
} IUMCacheStream;
HRESULT UMCreateStreamOnCacheFile(LPCWSTR pszURL, DWORD dwSize, LPWSTR pszFileName, HANDLE *phfile, IUMCacheStream **ppstr);
void UMCloseCacheFileStream(IUMCacheStream *pstr);
#endif /* __WINE_URLMON_MAIN_H */ #endif /* __WINE_URLMON_MAIN_H */