Beginning of true BindToStorage implementation.

This commit is contained in:
Jacek Caban 2005-11-14 15:12:43 +00:00 committed by Alexandre Julliard
parent 8056092909
commit 0dcf2a4589
5 changed files with 841 additions and 43 deletions

View File

@ -8,6 +8,7 @@ IMPORTS = cabinet ole32 shlwapi wininet user32 advapi32 kernel32 ntdll
EXTRALIBS = -luuid
C_SRCS = \
binding.c \
file.c \
format.c \
ftp.c \

534
dlls/urlmon/binding.c Normal file
View File

@ -0,0 +1,534 @@
/*
* Copyright 2005 Jacek Caban
*
* 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
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#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 IBindingVtbl *lpBindingVtbl;
const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl;
const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
const IServiceProviderVtbl *lpServiceProviderVtbl;
LONG ref;
IBindStatusCallback *callback;
IInternetProtocol *protocol;
IStream *stream;
BINDINFO bindinfo;
DWORD bindf;
LPWSTR mime;
LPWSTR url;
} Binding;
#define BINDING(x) ((IBinding*) &(x)->lpBindingVtbl)
#define PROTSINK(x) ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl)
#define BINDINF(x) ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
#define SERVPROV(x) ((IServiceProvider*) &(x)->lpServiceProviderVtbl)
#define BINDING_THIS(iface) DEFINE_THIS(Binding, Binding, iface)
static HRESULT WINAPI Binding_QueryInterface(IBinding *iface, REFIID riid, void **ppv)
{
Binding *This = BINDING_THIS(iface);
*ppv = NULL;
if(IsEqualGUID(&IID_IUnknown, riid)) {
TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
*ppv = BINDING(This);
}else if(IsEqualGUID(&IID_IBinding, riid)) {
TRACE("(%p)->(IID_IBinding %p)\n", This, ppv);
*ppv = BINDING(This);
}else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
*ppv = PROTSINK(This);
}else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
*ppv = BINDINF(This);
}else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
*ppv = SERVPROV(This);
}
if(*ppv)
return S_OK;
WARN("Unsupported interface %s\n", debugstr_guid(riid));
return E_NOINTERFACE;
}
static ULONG WINAPI Binding_AddRef(IBinding *iface)
{
Binding *This = BINDING_THIS(iface);
LONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) ref=%ld\n", This, ref);
return ref;
}
static ULONG WINAPI Binding_Release(IBinding *iface)
{
Binding *This = BINDING_THIS(iface);
LONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) ref=%ld\n", This, ref);
if(!ref) {
if(This->callback)
IBindStatusCallback_Release(This->callback);
if(This->protocol)
IInternetProtocol_Release(This->protocol);
if(This->stream)
IStream_Release(This->stream);
ReleaseBindInfo(&This->bindinfo);
HeapFree(GetProcessHeap(), 0, This->mime);
HeapFree(GetProcessHeap(), 0, This->url);
HeapFree(GetProcessHeap(), 0, This);
}
return ref;
}
static HRESULT WINAPI Binding_Abort(IBinding *iface)
{
Binding *This = BINDING_THIS(iface);
FIXME("(%p)\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI Binding_Suspend(IBinding *iface)
{
Binding *This = BINDING_THIS(iface);
FIXME("(%p)\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI Binding_Resume(IBinding *iface)
{
Binding *This = BINDING_THIS(iface);
FIXME("(%p)\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI Binding_SetPriority(IBinding *iface, LONG nPriority)
{
Binding *This = BINDING_THIS(iface);
FIXME("(%p)->(%ld)\n", This, nPriority);
return E_NOTIMPL;
}
static HRESULT WINAPI Binding_GetPriority(IBinding *iface, LONG *pnPriority)
{
Binding *This = BINDING_THIS(iface);
FIXME("(%p)->(%p)\n", This, pnPriority);
return E_NOTIMPL;
}
static HRESULT WINAPI Binding_GetBindResult(IBinding *iface, CLSID *pclsidProtocol,
DWORD *pdwResult, LPOLESTR *pszResult, DWORD *pdwReserved)
{
Binding *This = BINDING_THIS(iface);
FIXME("(%p)->(%p %p %p %p)\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved);
return E_NOTIMPL;
}
#undef BINDING_THIS
static const IBindingVtbl BindingVtbl = {
Binding_QueryInterface,
Binding_AddRef,
Binding_Release,
Binding_Abort,
Binding_Suspend,
Binding_Resume,
Binding_SetPriority,
Binding_GetPriority,
Binding_GetBindResult
};
#define PROTSINK_THIS(iface) DEFINE_THIS(Binding, InternetProtocolSink, iface)
static HRESULT WINAPI InternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
REFIID riid, void **ppv)
{
Binding *This = PROTSINK_THIS(iface);
return IBinding_QueryInterface(BINDING(This), riid, ppv);
}
static ULONG WINAPI InternetProtocolSink_AddRef(IInternetProtocolSink *iface)
{
Binding *This = PROTSINK_THIS(iface);
return IBinding_AddRef(BINDING(This));
}
static ULONG WINAPI InternetProtocolSink_Release(IInternetProtocolSink *iface)
{
Binding *This = PROTSINK_THIS(iface);
return IBinding_Release(BINDING(This));
}
static HRESULT WINAPI InternetProtocolSink_Switch(IInternetProtocolSink *iface,
PROTOCOLDATA *pProtocolData)
{
Binding *This = PROTSINK_THIS(iface);
FIXME("(%p)->(%p)\n", This, pProtocolData);
return E_NOTIMPL;
}
static HRESULT WINAPI InternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
ULONG ulStatusCode, LPCWSTR szStatusText)
{
Binding *This = PROTSINK_THIS(iface);
TRACE("(%p)->(%lu %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
switch(ulStatusCode) {
case BINDSTATUS_MIMETYPEAVAILABLE: {
int len = strlenW(szStatusText)+1;
This->mime = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
memcpy(This->mime, szStatusText, len*sizeof(WCHAR));
break;
}
default:
FIXME("Unhandled status code %ld\n", ulStatusCode);
return E_NOTIMPL;
};
return S_OK;
}
static HRESULT WINAPI InternetProtocolSink_ReportData(IInternetProtocolSink *iface,
DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
{
Binding *This = PROTSINK_THIS(iface);
DWORD read = 0, cread;
STGMEDIUM stgmed;
BYTE buf[1024];
TRACE("(%p)->(%ld %lu %lu)\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(grfBSCF & BSCF_LASTDATANOTIFICATION)
IBindStatusCallback_OnProgress(This->callback, ulProgress, ulProgressMax,
BINDSTATUS_ENDDOWNLOADDATA, This->url);
if(grfBSCF & BSCF_FIRSTDATANOTIFICATION)
IInternetProtocol_LockRequest(This->protocol, 0);
do {
cread = 0;
IInternetProtocol_Read(This->protocol, buf, sizeof(buf), &cread);
IStream_Write(This->stream, buf, read, NULL);
read += cread;
}while(cread);
stgmed.tymed = TYMED_ISTREAM;
stgmed.u.pstm = This->stream;
IBindStatusCallback_OnDataAvailable(This->callback, grfBSCF, read,
NULL /* FIXME */, &stgmed);
if(grfBSCF & BSCF_LASTDATANOTIFICATION)
IBindStatusCallback_OnStopBinding(This->callback, S_OK, NULL);
return S_OK;
}
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;
}
#undef PROTSINK_THIS
static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
InternetProtocolSink_QueryInterface,
InternetProtocolSink_AddRef,
InternetProtocolSink_Release,
InternetProtocolSink_Switch,
InternetProtocolSink_ReportProgress,
InternetProtocolSink_ReportData,
InternetProtocolSink_ReportResult
};
#define BINDINF_THIS(iface) DEFINE_THIS(Binding, InternetBindInfo, iface)
static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
REFIID riid, void **ppv)
{
Binding *This = BINDINF_THIS(iface);
return IBinding_QueryInterface(BINDING(This), riid, ppv);
}
static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
{
Binding *This = BINDINF_THIS(iface);
return IBinding_AddRef(BINDING(This));
}
static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
{
Binding *This = BINDINF_THIS(iface);
return IBinding_Release(BINDING(This));
}
static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
DWORD *grfBINDF, BINDINFO *pbindinfo)
{
Binding *This = BINDINF_THIS(iface);
TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
*grfBINDF = This->bindf;
memcpy(pbindinfo, &This->bindinfo, sizeof(BINDINFO));
if(pbindinfo->szExtraInfo || pbindinfo->szCustomVerb)
FIXME("copy strings\n");
if(pbindinfo->pUnk)
IUnknown_AddRef(pbindinfo->pUnk);
return S_OK;
}
static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
{
Binding *This = BINDINF_THIS(iface);
FIXME("(%p)->(%ld %p %ld %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
return E_NOTIMPL;
}
#undef BINDF_THIS
static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
InternetBindInfo_QueryInterface,
InternetBindInfo_AddRef,
InternetBindInfo_Release,
InternetBindInfo_GetBindInfo,
InternetBindInfo_GetBindString
};
#define SERVPROV_THIS(iface) DEFINE_THIS(Binding, ServiceProvider, iface)
static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface,
REFIID riid, void **ppv)
{
Binding *This = SERVPROV_THIS(iface);
return IBinding_QueryInterface(BINDING(This), riid, ppv);
}
static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
{
Binding *This = SERVPROV_THIS(iface);
return IBinding_AddRef(BINDING(This));
}
static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
{
Binding *This = SERVPROV_THIS(iface);
return IBinding_Release(BINDING(This));
}
static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
REFGUID guidService, REFIID riid, void **ppv)
{
Binding *This = SERVPROV_THIS(iface);
FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
return E_NOTIMPL;
}
#undef SERVPROV_THIS
static const IServiceProviderVtbl ServiceProviderVtbl = {
ServiceProvider_QueryInterface,
ServiceProvider_AddRef,
ServiceProvider_Release,
ServiceProvider_QueryService
};
static HRESULT get_callback(IBindCtx *pbc, IBindStatusCallback **callback)
{
HRESULT hres;
static WCHAR wszBSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
hres = IBindCtx_GetObjectParam(pbc, wszBSCBHolder, (IUnknown**)callback);
if(FAILED(hres))
return INET_E_DATA_NOT_AVAILABLE;
return S_OK;
}
static HRESULT get_protocol(Binding *This, LPCWSTR url)
{
IUnknown *unk = NULL;
IClassFactory *cf = NULL;
HRESULT hres;
hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetProtocol,
(void**)&This->protocol);
if(SUCCEEDED(hres))
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);
if(FAILED(hres))
return hres;
hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&This->protocol);
IClassFactory_Release(cf);
return hres;
}
static HRESULT Binding_Create(LPCWSTR url, IBindCtx *pbc, REFIID riid, Binding **binding)
{
Binding *ret;
int len;
HRESULT hres;
if(!IsEqualGUID(&IID_IStream, riid)) {
FIXME("Unsupported riid %s\n", debugstr_guid(riid));
return E_NOTIMPL;
}
ret = HeapAlloc(GetProcessHeap(), 0, sizeof(Binding));
ret->lpBindingVtbl = &BindingVtbl;
ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
ret->lpServiceProviderVtbl = &ServiceProviderVtbl;
ret->ref = 1;
ret->callback = NULL;
ret->protocol = NULL;
ret->stream = NULL;
ret->mime = NULL;
ret->url = NULL;
memset(&ret->bindinfo, 0, sizeof(BINDINFO));
ret->bindinfo.cbSize = sizeof(BINDINFO);
ret->bindf = 0;
hres = get_callback(pbc, &ret->callback);
if(FAILED(hres)) {
WARN("Could not get IBindStatusCallback\n");
IBinding_Release(BINDING(ret));
return hres;
}
hres = get_protocol(ret, url);
if(FAILED(hres)) {
WARN("Could not get protocol handler\n");
IBinding_Release(BINDING(ret));
return hres;
}
hres = IBindStatusCallback_GetBindInfo(ret->callback, &ret->bindf, &ret->bindinfo);
if(FAILED(hres)) {
WARN("GetBindInfo failed: %08lx\n", hres);
IBinding_Release(BINDING(ret));
return hres;
}
ret->bindf |= (BINDF_FROMURLMON|BINDF_NEEDFILE);
len = strlenW(url)+1;
ret->url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
memcpy(ret->url, url, len*sizeof(WCHAR));
CreateStreamOnHGlobal(NULL, TRUE, &ret->stream);
*binding = ret;
return S_OK;
}
HRESULT start_binding(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv)
{
Binding *binding = NULL;
HRESULT hres;
*ppv = NULL;
hres = Binding_Create(url, pbc, riid, &binding);
if(FAILED(hres))
return hres;
hres = IBindStatusCallback_OnStartBinding(binding->callback, 0, BINDING(binding));
if(FAILED(hres)) {
WARN("OnStartBinding failed: %08lx\n", hres);
IBindStatusCallback_OnStopBinding(binding->callback, 0x800c0008, NULL);
IBinding_Release(BINDING(binding));
return hres;
}
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);
IBindStatusCallback_OnStopBinding(binding->callback, S_OK, NULL);
}
IStream_AddRef(binding->stream);
*ppv = binding->stream;
IBinding_Release(BINDING(binding));
return hres;
}

View File

@ -36,17 +36,23 @@
expect_ ## func = TRUE
#define CHECK_EXPECT(func) \
ok(expect_ ##func, "unexpected call\n"); \
expect_ ## func = FALSE; \
called_ ## func = TRUE
do { \
ok(expect_ ##func, "unexpected call\n"); \
expect_ ## func = FALSE; \
called_ ## func = TRUE; \
}while(0)
#define CHECK_EXPECT2(func) \
ok(expect_ ##func, "unexpected call\n"); \
called_ ## func = TRUE
do { \
ok(expect_ ##func, "unexpected call\n"); \
called_ ## func = TRUE; \
}while(0)
#define CHECK_CALLED(func) \
ok(called_ ## func, "expected " #func "\n"); \
expect_ ## func = called_ ## func = FALSE
do { \
ok(called_ ## func, "expected " #func "\n"); \
expect_ ## func = called_ ## func = FALSE; \
}while(0)
DEFINE_EXPECT(GetBindInfo);
DEFINE_EXPECT(OnStartBinding);
@ -59,13 +65,32 @@ DEFINE_EXPECT(OnProgress_DOWNLOADINGDATA);
DEFINE_EXPECT(OnProgress_ENDDOWNLOADDATA);
DEFINE_EXPECT(OnStopBinding);
DEFINE_EXPECT(OnDataAvailable);
DEFINE_EXPECT(Start);
DEFINE_EXPECT(Read);
DEFINE_EXPECT(LockRequest);
DEFINE_EXPECT(Terminate);
DEFINE_EXPECT(UnlockRequest);
static const WCHAR TEST_URL_1[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/','\0'};
static const WCHAR TEST_PART_URL_1[] = {'/','t','e','s','t','/','\0'};
static const WCHAR WINE_ABOUT_URL[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.',
'o','r','g','/','s','i','t','e','/','a','b','o','u','t',0};
static BOOL stopped_binding = FALSE;
static const WCHAR ABOUT_BLANK[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
static BOOL stopped_binding = FALSE, emulate_protocol = FALSE;
static DWORD read = 0;
static const LPCWSTR urls[] = {
WINE_ABOUT_URL,
ABOUT_BLANK
};
static enum {
HTTP_TEST,
ABOUT_TEST
} test_protocol;
static void test_CreateURLMoniker(LPCWSTR url1, LPCWSTR url2)
{
@ -88,6 +113,181 @@ static void test_create(void)
test_CreateURLMoniker(TEST_URL_1, TEST_PART_URL_1);
}
static HRESULT WINAPI Protocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
{
if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IInternetProtocol, riid)) {
*ppv = iface;
return S_OK;
}
*ppv = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI Protocol_AddRef(IInternetProtocol *iface)
{
return 2;
}
static ULONG WINAPI Protocol_Release(IInternetProtocol *iface)
{
return 1;
}
static HRESULT WINAPI Protocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
DWORD grfPI, DWORD dwReserved)
{
BINDINFO bindinfo, bi = {sizeof(bi), 0};
DWORD bindf;
HRESULT hres;
static const WCHAR wszTextHtml[] = {'t','e','x','t','/','h','t','m','l',0};
CHECK_EXPECT(Start);
read = 0;
ok(szUrl && !lstrcmpW(szUrl, urls[test_protocol]), "wrong url\n");
ok(pOIProtSink != NULL, "pOIProtSink == NULL\n");
ok(pOIBindInfo != NULL, "pOIBindInfo == NULL\n");
ok(grfPI == 0, "grfPI=%ld, expected 0\n", grfPI);
ok(dwReserved == 0, "dwReserved=%ld, expected 0\n", dwReserved);
memset(&bindinfo, 0, sizeof(bindinfo));
bindinfo.cbSize = sizeof(bindinfo);
hres = IInternetBindInfo_GetBindInfo(pOIBindInfo, &bindf, &bindinfo);
ok(hres == S_OK, "GetBindInfo failed: %08lx\n", hres);
ok(bindf == (BINDF_ASYNCHRONOUS|BINDF_ASYNCSTORAGE|BINDF_PULLDATA|
BINDF_FROMURLMON|BINDF_NEEDFILE),
"bindf=%08lx\n", bindf);
ok(!memcmp(&bindinfo, &bi, sizeof(bindinfo)), "wrong bindinfo\n");
hres = IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_MIMETYPEAVAILABLE,
wszTextHtml);
ok(hres == S_OK, "ReportProgress(BINDSTATUS_MIMETYPEAVAILABKE) failed: %08lx\n", hres);
SET_EXPECT(Read);
SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
SET_EXPECT(OnProgress_BEGINDOWNLOADDATA);
SET_EXPECT(OnProgress_ENDDOWNLOADDATA);
SET_EXPECT(LockRequest);
SET_EXPECT(OnDataAvailable);
SET_EXPECT(OnStopBinding);
hres = IInternetProtocolSink_ReportData(pOIProtSink,
BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
13, 13);
ok(hres == S_OK, "ReportData failed: %08lx\n", hres);
CHECK_CALLED(Read);
CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
CHECK_CALLED(LockRequest);
CHECK_CALLED(OnDataAvailable);
CHECK_CALLED(OnStopBinding);
IInternetProtocolSink_ReportResult(pOIProtSink, S_OK, 0, NULL);
return S_OK;
}
static HRESULT WINAPI Protocol_Continue(IInternetProtocol *iface,
PROTOCOLDATA *pProtocolData)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Protocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
DWORD dwOptions)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Protocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
{
CHECK_EXPECT(Terminate);
ok(dwOptions == 0, "dwOptions=%ld, expected 0\n", dwOptions);
return S_OK;
}
static HRESULT WINAPI Protocol_Suspend(IInternetProtocol *iface)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Protocol_Resume(IInternetProtocol *iface)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Protocol_Read(IInternetProtocol *iface, void *pv,
ULONG cb, ULONG *pcbRead)
{
static const char data[] = "<HTML></HTML>";
CHECK_EXPECT2(Read);
if(read) {
*pcbRead = 0;
return S_FALSE;
}
ok(pv != NULL, "pv == NULL\n");
ok(cb != 0, "cb == 0\n");
ok(pcbRead != NULL, "pcbRead == NULL\n");
if(pcbRead) {
ok(*pcbRead == 0, "*pcbRead=%ld, expected 0\n", *pcbRead);
*pcbRead = 13;
read = 13;
}
if(pv)
memcpy(pv, data, sizeof(data));
return S_OK;
}
static HRESULT WINAPI Protocol_Seek(IInternetProtocol *iface,
LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Protocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
{
CHECK_EXPECT(LockRequest);
return S_OK;
}
static HRESULT WINAPI Protocol_UnlockRequest(IInternetProtocol *iface)
{
CHECK_EXPECT(UnlockRequest);
return S_OK;
}
static const IInternetProtocolVtbl ProtocolVtbl = {
Protocol_QueryInterface,
Protocol_AddRef,
Protocol_Release,
Protocol_Start,
Protocol_Continue,
Protocol_Abort,
Protocol_Terminate,
Protocol_Suspend,
Protocol_Resume,
Protocol_Read,
Protocol_Seek,
Protocol_LockRequest,
Protocol_UnlockRequest
};
static IInternetProtocol Protocol = { &ProtocolVtbl };
typedef struct {
const IBindStatusCallbackVtbl *lpVtbl;
LONG ref;
@ -95,8 +295,13 @@ typedef struct {
IStream *pstr;
} statusclb;
static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppvObject)
static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
{
if(emulate_protocol && IsEqualGUID(&IID_IInternetProtocol, riid)) {
*ppv = &Protocol;
return S_OK;
}
return E_NOINTERFACE;
}
@ -167,12 +372,14 @@ static HRESULT WINAPI statusclb_OnProgress(IBindStatusCallback *iface, ULONG ulP
break;
case BINDSTATUS_BEGINDOWNLOADDATA:
CHECK_EXPECT(OnProgress_BEGINDOWNLOADDATA);
ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText\n");
break;
case BINDSTATUS_DOWNLOADINGDATA:
CHECK_EXPECT2(OnProgress_DOWNLOADINGDATA);
break;
case BINDSTATUS_ENDDOWNLOADDATA:
CHECK_EXPECT(OnProgress_ENDDOWNLOADDATA);
ok(!lstrcmpW(szStatusText, urls[test_protocol]), "wrong szStatusText\n");
break;
default:
todo_wine { ok(0, "unexpexted code %ld\n", ulStatusCode); }
@ -211,8 +418,8 @@ static HRESULT WINAPI statusclb_GetBindInfo(IBindStatusCallback *iface, DWORD *g
return S_OK;
}
static HRESULT WINAPI statusclb_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF, DWORD dwSize,
FORMATETC* pformatetc, STGMEDIUM* pstgmed)
static HRESULT WINAPI statusclb_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
{
statusclb *This = (statusclb*)iface;
HRESULT hres;
@ -386,7 +593,7 @@ static void test_BindToStorage(void)
if(previousclb)
IBindStatusCallback_Release(previousclb);
hres = CreateURLMoniker(NULL, WINE_ABOUT_URL, &mon);
hres = CreateURLMoniker(NULL, urls[test_protocol], &mon);
ok(SUCCEEDED(hres), "failed to create moniker: %08lx\n", hres);
if(FAILED(hres)) {
IBindStatusCallback_Release(sclb);
@ -400,30 +607,38 @@ static void test_BindToStorage(void)
IBinding_Release(bind);
hres = IMoniker_GetDisplayName(mon, bctx, NULL, &display_name);
ok(SUCCEEDED(hres), "GetDisplayName failed %08lx\n", hres);
ok(!lstrcmpW(display_name, WINE_ABOUT_URL), "GetDisplayName got wrong name\n");
ok(hres == S_OK, "GetDisplayName failed %08lx\n", hres);
ok(!lstrcmpW(display_name, urls[test_protocol]), "GetDisplayName got wrong name\n");
SET_EXPECT(GetBindInfo);
SET_EXPECT(OnStartBinding);
SET_EXPECT(OnProgress_FINDINGRESOURCE);
SET_EXPECT(OnProgress_CONNECTING);
SET_EXPECT(OnProgress_SENDINGREQUEST);
SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
SET_EXPECT(OnProgress_BEGINDOWNLOADDATA);
SET_EXPECT(OnDataAvailable);
SET_EXPECT(OnProgress_DOWNLOADINGDATA);
SET_EXPECT(OnProgress_ENDDOWNLOADDATA);
SET_EXPECT(OnStopBinding);
if(emulate_protocol) {
SET_EXPECT(Start);
SET_EXPECT(Terminate);
SET_EXPECT(UnlockRequest);
}else {
if(test_protocol == HTTP_TEST) {
SET_EXPECT(OnProgress_FINDINGRESOURCE);
SET_EXPECT(OnProgress_CONNECTING);
SET_EXPECT(OnProgress_SENDINGREQUEST);
}
SET_EXPECT(OnProgress_MIMETYPEAVAILABLE);
SET_EXPECT(OnProgress_BEGINDOWNLOADDATA);
SET_EXPECT(OnDataAvailable);
if(test_protocol == HTTP_TEST)
SET_EXPECT(OnProgress_DOWNLOADINGDATA);
SET_EXPECT(OnProgress_ENDDOWNLOADDATA);
SET_EXPECT(OnStopBinding);
}
hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&unk);
ok(SUCCEEDED(hres), "IMoniker_BindToStorage failed: %08lx\n", hres);
todo_wine {
ok(unk == NULL, "istr should be NULL\n");
}
if(FAILED(hres)) {
IBindStatusCallback_Release(sclb);
IMoniker_Release(mon);
return;
if(test_protocol == HTTP_TEST) {
todo_wine {
ok(unk == NULL, "istr should be NULL\n");
}
}else {
ok(unk != NULL, "unk == NULL\n");
}
if(unk)
IUnknown_Release(unk);
@ -435,25 +650,70 @@ static void test_BindToStorage(void)
CHECK_CALLED(GetBindInfo);
CHECK_CALLED(OnStartBinding);
CHECK_CALLED(OnProgress_FINDINGRESOURCE);
CHECK_CALLED(OnProgress_CONNECTING);
CHECK_CALLED(OnProgress_SENDINGREQUEST);
todo_wine { CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE); }
CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
CHECK_CALLED(OnDataAvailable);
CHECK_CALLED(OnProgress_DOWNLOADINGDATA);
CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
CHECK_CALLED(OnStopBinding);
if(emulate_protocol) {
CHECK_CALLED(Start);
CHECK_CALLED(Terminate);
CHECK_CALLED(UnlockRequest);
}else {
if(test_protocol == HTTP_TEST) {
CHECK_CALLED(OnProgress_FINDINGRESOURCE);
CHECK_CALLED(OnProgress_CONNECTING);
CHECK_CALLED(OnProgress_SENDINGREQUEST);
todo_wine { CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE); }
}else {
CHECK_CALLED(OnProgress_MIMETYPEAVAILABLE);
}
CHECK_CALLED(OnProgress_BEGINDOWNLOADDATA);
CHECK_CALLED(OnDataAvailable);
if(test_protocol == HTTP_TEST)
CHECK_CALLED(OnProgress_DOWNLOADINGDATA);
CHECK_CALLED(OnProgress_ENDDOWNLOADDATA);
CHECK_CALLED(OnStopBinding);
}
ok(IMoniker_Release(mon) == 0, "mon should be destroyed here\n");
ok(IBindCtx_Release(bctx) == 0, "bctx should be destroyed here\n");
ok(IBindStatusCallback_Release(sclb) == 0, "scbl should be destroyed here\n");
}
static void test_BindToStorage_fail(void)
{
IMoniker *mon = NULL;
IBindCtx *bctx = NULL;
IUnknown *unk;
HRESULT hres;
hres = CreateURLMoniker(NULL, ABOUT_BLANK, &mon);
ok(hres == S_OK, "CreateURLMoniker failed: %08lx\n", hres);
if(FAILED(hres))
return;
hres = CreateAsyncBindCtxEx(NULL, 0, NULL, NULL, &bctx, 0);
ok(hres == S_OK, "CreateAsyncBindCtxEx failed: %08lx\n", hres);
hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&unk);
ok(hres == INET_E_DATA_NOT_AVAILABLE,
"hres=%08lx, expected INET_E_DATA_NOT_AVAILABLE\n", hres);
IBindCtx_Release(bctx);
IMoniker_Release(mon);
}
START_TEST(url)
{
test_create();
test_CreateAsyncBindCtx();
test_CreateAsyncBindCtxEx();
emulate_protocol = FALSE;
test_protocol = HTTP_TEST;
test_BindToStorage();
test_protocol = ABOUT_TEST;
test_BindToStorage();
emulate_protocol = TRUE;
test_protocol = ABOUT_TEST;
test_BindToStorage();
test_BindToStorage_fail();
}

View File

@ -198,7 +198,7 @@ static HRESULT Binding_MoreCacheData(Binding *This, char *buf, DWORD dwBytes)
(This->total_read == written) ?
BINDSTATUS_BEGINDOWNLOADDATA :
BINDSTATUS_DOWNLOADINGDATA,
NULL);
This->URLName);
if (!hr)
{
STGMEDIUM stg;
@ -244,7 +244,8 @@ static void Binding_FinishedDownload(Binding *This, HRESULT hr)
stg.u.pstm = (IStream *)This->pstrCache;
stg.pUnkForRelease = NULL;
IBindStatusCallback_OnProgress(This->pbscb, This->total_read, This->expected_size, BINDSTATUS_ENDDOWNLOADDATA, NULL);
IBindStatusCallback_OnProgress(This->pbscb, This->total_read, This->expected_size,
BINDSTATUS_ENDDOWNLOADDATA, This->URLName);
IBindStatusCallback_OnDataAvailable(This->pbscb, BSCF_LASTDATANOTIFICATION, This->total_read, &fmt, &stg);
if (hr)
{
@ -883,9 +884,9 @@ static HRESULT WINAPI URLMonikerImpl_BindToStorage(IMoniker* iface,
|| url.nScheme == INTERNET_SCHEME_FILE)
return URLMonikerImpl_BindToStorage_hack(This->URLName, pbc, pmkToLeft, riid, ppvObject);
FIXME("(%p)->(%p %p %s %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObject);
TRACE("(%p)->(%p %p %s %p)\n", This, pbc, pmkToLeft, debugstr_guid(riid), ppvObject);
return E_NOTIMPL;
return start_binding(This->URLName, pbc, riid, ppvObject);
}
/******************************************************************************

View File

@ -56,4 +56,6 @@ void UMCloseCacheFileStream(IUMCacheStream *pstr);
HRESULT get_protocol_iface(LPCWSTR url, IUnknown **ret);
HRESULT start_binding(LPCWSTR url, IBindCtx *pbc, REFIID riid, void **ppv);
#endif /* __WINE_URLMON_MAIN_H */