[PATCH 1/1] Add basic bind callback for moniker binding
Nikolay Sivov
nsivov at codeweavers.com
Wed Sep 29 22:47:09 CDT 2010
---
dlls/msxml3/httprequest.c | 332 +++++++++++++++++++++++++++++++++++++++++-
dlls/msxml3/msxml_private.h | 3 +
dlls/msxml3/tests/domdoc.c | 34 ++++-
3 files changed, 359 insertions(+), 10 deletions(-)
diff --git a/dlls/msxml3/httprequest.c b/dlls/msxml3/httprequest.c
index e0f7701..504b6b3 100644
--- a/dlls/msxml3/httprequest.c
+++ b/dlls/msxml3/httprequest.c
@@ -41,6 +41,8 @@ static const WCHAR MethodGetW[] = {'G','E','T',0};
static const WCHAR MethodPutW[] = {'P','U','T',0};
static const WCHAR MethodPostW[] = {'P','O','S','T',0};
+typedef struct BindStatusCallback BindStatusCallback;
+
struct reqheader
{
struct list entry;
@@ -57,7 +59,7 @@ enum READYSTATE
STATE_COMPLETED = 4
};
-typedef struct _httprequest
+typedef struct
{
const struct IXMLHTTPRequestVtbl *lpVtbl;
LONG ref;
@@ -73,6 +75,9 @@ typedef struct _httprequest
/* credentials */
BSTR user;
BSTR password;
+
+ /* bind callback */
+ BindStatusCallback *bsc;
} httprequest;
static inline httprequest *impl_from_IXMLHTTPRequest( IXMLHTTPRequest *iface )
@@ -80,6 +85,300 @@ static inline httprequest *impl_from_IXMLHTTPRequest( IXMLHTTPRequest *iface )
return (httprequest *)((char*)iface - FIELD_OFFSET(httprequest, lpVtbl));
}
+struct BindStatusCallback
+{
+ const IBindStatusCallbackVtbl *lpBindStatusCallbackVtbl;
+ const IHttpNegotiateVtbl *lpHttpNegotiateVtbl;
+ LONG ref;
+
+ IBinding *binding;
+ const httprequest *request;
+};
+
+#define STATUSCLB(x) ((IBindStatusCallback*) &(x)->lpBindStatusCallbackVtbl)
+#define STATUSCLB_THIS(iface) DEFINE_THIS(BindStatusCallback, BindStatusCallback, iface)
+
+void BindStatusCallback_Detach(BindStatusCallback *bsc)
+{
+ if (bsc)
+ {
+ if (bsc->binding) IBinding_Abort(bsc->binding);
+ bsc->request = NULL;
+ IBindStatusCallback_Release(STATUSCLB(bsc));
+ }
+}
+
+static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
+ REFIID riid, void **ppv)
+{
+ BindStatusCallback *This = STATUSCLB_THIS(iface);
+
+ *ppv = NULL;
+
+ TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
+
+ if (IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IBindStatusCallback, riid))
+ {
+ *ppv = &This->lpBindStatusCallbackVtbl;
+ }
+ else if (IsEqualGUID(&IID_IServiceProvider, riid) ||
+ IsEqualGUID(&IID_IBindStatusCallbackEx, riid))
+ {
+ return E_NOINTERFACE;
+ }
+
+ if (*ppv)
+ {
+ IBindStatusCallback_AddRef(iface);
+ return S_OK;
+ }
+
+ FIXME("Unsupported riid = %s\n", debugstr_guid(riid));
+
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
+{
+ BindStatusCallback *This = STATUSCLB_THIS(iface);
+ LONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("(%p) ref = %d\n", This, ref);
+
+ return ref;
+}
+
+static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
+{
+ BindStatusCallback *This = STATUSCLB_THIS(iface);
+ LONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p) ref = %d\n", This, ref);
+
+ if (!ref)
+ {
+ if (This->binding) IBinding_Release(This->binding);
+ heap_free(This);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
+ DWORD reserved, IBinding *pbind)
+{
+ BindStatusCallback *This = STATUSCLB_THIS(iface);
+
+ TRACE("(%p)->(%d %p)\n", This, reserved, pbind);
+
+ if (!pbind) return E_INVALIDARG;
+
+ This->binding = pbind;
+ IBinding_AddRef(pbind);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pPriority)
+{
+ BindStatusCallback *This = STATUSCLB_THIS(iface);
+
+ TRACE("(%p)->(%p)\n", This, pPriority);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
+{
+ BindStatusCallback *This = STATUSCLB_THIS(iface);
+
+ TRACE("(%p)->(%d)\n", This, reserved);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
+ ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
+{
+ BindStatusCallback *This = STATUSCLB_THIS(iface);
+
+ TRACE("%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
+ debugstr_w(szStatusText));
+
+ return S_OK;
+}
+
+static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
+ HRESULT hr, LPCWSTR error)
+{
+ BindStatusCallback *This = STATUSCLB_THIS(iface);
+
+ TRACE("(%p)->(0x%08x %s)\n", This, hr, debugstr_w(error));
+
+ return S_OK;
+}
+
+static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
+ DWORD *bind_flags, BINDINFO *pbindinfo)
+{
+ BindStatusCallback *This = STATUSCLB_THIS(iface);
+
+ TRACE("(%p)->(%p %p)\n", This, bind_flags, pbindinfo);
+
+ *bind_flags = 0;
+ if (This->request->async) *bind_flags |= BINDF_ASYNCHRONOUS;
+
+ if (This->request->verb != BINDVERB_GET)
+ {
+ FIXME("only GET verb supported. Got %d\n", This->request->verb);
+ return E_FAIL;
+ }
+
+ pbindinfo->dwBindVerb = This->request->verb;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
+ DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
+{
+ BindStatusCallback *This = STATUSCLB_THIS(iface);
+
+ FIXME("(%p)->(%08x %d %p %p): stub\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
+ REFIID riid, IUnknown *punk)
+{
+ BindStatusCallback *This = STATUSCLB_THIS(iface);
+
+ FIXME("(%p)->(%s %p): stub\n", This, debugstr_guid(riid), punk);
+
+ return E_NOTIMPL;
+}
+
+#undef STATUSCLB_THIS
+
+static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
+ BindStatusCallback_QueryInterface,
+ BindStatusCallback_AddRef,
+ BindStatusCallback_Release,
+ BindStatusCallback_OnStartBinding,
+ BindStatusCallback_GetPriority,
+ BindStatusCallback_OnLowResource,
+ BindStatusCallback_OnProgress,
+ BindStatusCallback_OnStopBinding,
+ BindStatusCallback_GetBindInfo,
+ BindStatusCallback_OnDataAvailable,
+ BindStatusCallback_OnObjectAvailable
+};
+
+#define HTTPNEG_THIS(iface) DEFINE_THIS(BindStatusCallback, HttpNegotiate, iface)
+
+static HRESULT WINAPI BSCHttpNegotiate_QueryInterface(IHttpNegotiate *iface,
+ REFIID riid, void **ppv)
+{
+ BindStatusCallback *This = HTTPNEG_THIS(iface);
+ return IBindStatusCallback_QueryInterface(STATUSCLB(This), riid, ppv);
+}
+
+static ULONG WINAPI BSCHttpNegotiate_AddRef(IHttpNegotiate *iface)
+{
+ BindStatusCallback *This = HTTPNEG_THIS(iface);
+ return IBindStatusCallback_AddRef(STATUSCLB(This));
+}
+
+static ULONG WINAPI BSCHttpNegotiate_Release(IHttpNegotiate *iface)
+{
+ BindStatusCallback *This = HTTPNEG_THIS(iface);
+ return IBindStatusCallback_Release(STATUSCLB(This));
+}
+
+static HRESULT WINAPI BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate *iface,
+ LPCWSTR url, LPCWSTR headers, DWORD reserved, LPWSTR *add_headers)
+{
+ BindStatusCallback *This = HTTPNEG_THIS(iface);
+
+ FIXME("(%p)->(%s %s %d %p): stub\n", This, debugstr_w(url), debugstr_w(headers), reserved, add_headers);
+
+ *add_headers = NULL;
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BSCHttpNegotiate_OnResponse(IHttpNegotiate *iface, DWORD code,
+ LPCWSTR resp_headers, LPCWSTR req_headers, LPWSTR *add_reqheaders)
+{
+ BindStatusCallback *This = HTTPNEG_THIS(iface);
+
+ TRACE("(%p)->(%d %s %s %p)\n", This, code, debugstr_w(resp_headers),
+ debugstr_w(req_headers), add_reqheaders);
+
+ return S_OK;
+}
+
+#undef HTTPNEG2_THIS
+
+static const IHttpNegotiateVtbl BSCHttpNegotiateVtbl = {
+ BSCHttpNegotiate_QueryInterface,
+ BSCHttpNegotiate_AddRef,
+ BSCHttpNegotiate_Release,
+ BSCHttpNegotiate_BeginningTransaction,
+ BSCHttpNegotiate_OnResponse
+};
+
+static HRESULT BindStatusCallback_create(const httprequest* This, BindStatusCallback **obj)
+{
+ BindStatusCallback *bsc;
+ IBindCtx *pbc;
+ HRESULT hr;
+
+ hr = CreateBindCtx(0, &pbc);
+ if (hr != S_OK) return hr;
+
+ bsc = heap_alloc(sizeof(*bsc));
+ if (!bsc)
+ {
+ IBindCtx_Release(pbc);
+ return E_OUTOFMEMORY;
+ }
+
+ bsc->lpBindStatusCallbackVtbl = &BindStatusCallbackVtbl;
+ bsc->lpHttpNegotiateVtbl = &BSCHttpNegotiateVtbl;
+ bsc->ref = 1;
+ bsc->request = This;
+ bsc->binding = NULL;
+
+ hr = RegisterBindStatusCallback(pbc, STATUSCLB(bsc), NULL, 0);
+ if (hr == S_OK)
+ {
+ IMoniker *moniker;
+
+ hr = CreateURLMoniker(NULL, This->url, &moniker);
+ if (hr == S_OK)
+ {
+ IStream *stream;
+
+ hr = IMoniker_BindToStorage(moniker, pbc, NULL, &IID_IStream, (void**)&stream);
+ IMoniker_Release(moniker);
+ if (stream) IStream_Release(stream);
+ }
+ IBindCtx_Release(pbc);
+ }
+
+ if (FAILED(hr))
+ {
+ IBindStatusCallback_Release(STATUSCLB(bsc));
+ bsc = NULL;
+ }
+
+ *obj = bsc;
+ return hr;
+}
+
/* TODO: process OnChange callback */
static void httprequest_setreadystate(httprequest *This, READYSTATE state)
{
@@ -111,15 +410,18 @@ static HRESULT WINAPI httprequest_QueryInterface(IXMLHTTPRequest *iface, REFIID
static ULONG WINAPI httprequest_AddRef(IXMLHTTPRequest *iface)
{
httprequest *This = impl_from_IXMLHTTPRequest( iface );
- return InterlockedIncrement( &This->ref );
+ ULONG ref = InterlockedIncrement( &This->ref );
+ TRACE("(%p)->(%u)\n", This, ref );
+ return ref;
}
static ULONG WINAPI httprequest_Release(IXMLHTTPRequest *iface)
{
httprequest *This = impl_from_IXMLHTTPRequest( iface );
- ULONG ref;
+ ULONG ref = InterlockedDecrement( &This->ref );
+
+ TRACE("(%p)->(%u)\n", This, ref );
- ref = InterlockedDecrement( &This->ref );
if ( ref == 0 )
{
struct reqheader *header, *header2;
@@ -136,6 +438,9 @@ static ULONG WINAPI httprequest_Release(IXMLHTTPRequest *iface)
SysFreeString(header->value);
}
+ /* detach callback object */
+ BindStatusCallback_Detach(This->bsc);
+
heap_free( This );
}
@@ -319,10 +624,20 @@ static HRESULT WINAPI httprequest_getAllResponseHeaders(IXMLHTTPRequest *iface,
static HRESULT WINAPI httprequest_send(IXMLHTTPRequest *iface, VARIANT varBody)
{
httprequest *This = impl_from_IXMLHTTPRequest( iface );
+ BindStatusCallback *bsc = NULL;
+ HRESULT hr;
- FIXME("stub (%p)\n", This);
+ TRACE("(%p)\n", This);
- return E_NOTIMPL;
+ if (This->state != STATE_LOADING) return E_FAIL;
+
+ hr = BindStatusCallback_create(This, &bsc);
+ if (FAILED(hr)) return hr;
+
+ BindStatusCallback_Detach(This->bsc);
+ This->bsc = bsc;
+
+ return hr;
}
static HRESULT WINAPI httprequest_abort(IXMLHTTPRequest *iface)
@@ -434,7 +749,7 @@ static const struct IXMLHTTPRequestVtbl dimimpl_vtbl =
httprequest_put_onreadystatechange
};
-HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, LPVOID *ppObj)
+HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
{
httprequest *req;
HRESULT hr = S_OK;
@@ -452,6 +767,7 @@ HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, LPVOID *ppObj)
req->verb = -1;
req->url = req->user = req->password = NULL;
req->state = STATE_UNINITIALIZED;
+ req->bsc = NULL;
list_init(&req->reqheaders);
*ppObj = &req->lpVtbl;
@@ -463,7 +779,7 @@ HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, LPVOID *ppObj)
#else
-HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, LPVOID *ppObj)
+HRESULT XMLHTTPRequest_create(IUnknown *pUnkOuter, void **ppObj)
{
MESSAGE("This program tried to use a XMLHTTPRequest object, but\n"
"libxml2 support was not present at compile time.\n");
diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h
index a1b3b9d..8fe7dfd 100644
--- a/dlls/msxml3/msxml_private.h
+++ b/dlls/msxml3/msxml_private.h
@@ -106,6 +106,9 @@ BOOL dispex_query_interface(DispatchEx*,REFIID,void**);
#include <libxml/parser.h>
#endif
+#define DEFINE_THIS2(cls,ifc,iface) ((cls*)((BYTE*)(iface)-offsetof(cls,ifc)))
+#define DEFINE_THIS(cls,ifc,iface) DEFINE_THIS2(cls,lp ## ifc ## Vtbl,iface)
+
/* constructors */
extern IUnknown *create_domdoc( xmlNodePtr document );
extern IUnknown *create_xmldoc( void );
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c
index d9587a0..5d64b16 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -2877,10 +2877,13 @@ static void test_removeNamedItem(void)
static void test_XMLHTTP(void)
{
static const WCHAR wszBody[] = {'m','o','d','e','=','T','e','s','t',0};
- static WCHAR wszPOST[] = {'P','O','S','T',0};
- static WCHAR wszUrl[] = {'h','t','t','p',':','/','/',
+ static const WCHAR wszPOST[] = {'P','O','S','T',0};
+ static const WCHAR wszUrl[] = {'h','t','t','p',':','/','/',
'c','r','o','s','s','o','v','e','r','.','c','o','d','e','w','e','a','v','e','r','s','.','c','o','m','/',
'p','o','s','t','t','e','s','t','.','p','h','p',0};
+ static const WCHAR xmltestW[] = {'h','t','t','p',':','/','/',
+ 'c','r','o','s','s','o','v','e','r','.','c','o','d','e','w','e','a','v','e','r','s','.','c','o','m','/',
+ 'x','m','l','t','e','s','t','.','x','m','l',0};
static const WCHAR wszExpectedResponse[] = {'F','A','I','L','E','D',0};
IXMLHttpRequest *pXMLHttpRequest;
BSTR bstrResponse, method, url;
@@ -2909,6 +2912,10 @@ static void test_XMLHTTP(void)
method = SysAllocString(wszPOST);
url = SysAllocString(wszUrl);
+ /* send before open */
+ hr = IXMLHttpRequest_send(pXMLHttpRequest, dummy);
+ ok(hr == E_FAIL || broken(hr == E_UNEXPECTED) /* win9x, win2k */, "got 0x%08x\n", hr);
+
/* invalid parameters */
hr = IXMLHttpRequest_open(pXMLHttpRequest, NULL, NULL, async, dummy, dummy);
ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
@@ -2967,6 +2974,10 @@ static void test_XMLHTTP(void)
return;
}
todo_wine ok(hr == S_OK, "IXMLHttpRequest_send should have succeeded instead of failing with 0x%08x\n", hr);
+
+ hr = IXMLHttpRequest_send(pXMLHttpRequest, varbody);
+ ok(hr == E_FAIL || broken(hr == E_UNEXPECTED) /* win9x, win2k */, "got 0x%08x\n", hr);
+
VariantClear(&varbody);
hr = IXMLHttpRequest_get_responseText(pXMLHttpRequest, &bstrResponse);
@@ -2979,6 +2990,25 @@ static void test_XMLHTTP(void)
SysFreeString(bstrResponse);
}
+ /* GET request */
+ url = SysAllocString(xmltestW);
+
+ hr = IXMLHttpRequest_open(pXMLHttpRequest, _bstr_("GET"), url, async, dummy, dummy);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+
+ V_VT(&varbody) = VT_EMPTY;
+
+ hr = IXMLHttpRequest_send(pXMLHttpRequest, varbody);
+ if (hr == INET_E_RESOURCE_NOT_FOUND)
+ {
+ skip("No connection could be made with crossover.codeweavers.com\n");
+ IXMLHttpRequest_Release(pXMLHttpRequest);
+ return;
+ }
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+
+ SysFreeString(url);
+
IXMLHttpRequest_Release(pXMLHttpRequest);
free_bstrs();
}
--
1.5.6.5
--------------060700010903010307080302--
More information about the wine-patches
mailing list