[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