From df08e9b4f63064e017f6f1058cec87f1fb7a6dd4 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Sat, 19 Feb 2011 17:09:58 +0300 Subject: [PATCH] msxml3: Store document event handler for ready state notification. --- dlls/msxml3/domdoc.c | 54 ++++++++++++++++++++++++++++++++++---- dlls/msxml3/tests/domdoc.c | 51 +++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 5 deletions(-) diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c index f5bfaa40087..417b98840ae 100644 --- a/dlls/msxml3/domdoc.c +++ b/dlls/msxml3/domdoc.c @@ -105,6 +105,13 @@ struct ConnectionPoint DWORD sinks_size; }; +typedef enum { + EVENTID_READYSTATECHANGE = 0, + EVENTID_DATAAVAILABLE, + EVENTID_TRANSFORMNODE, + EVENTID_LAST +} eventid_t; + struct domdoc { xmlnode node; @@ -136,8 +143,37 @@ struct domdoc ConnectionPoint cp_domdocevents; ConnectionPoint cp_propnotif; ConnectionPoint cp_dispatch; + + /* events */ + IDispatch *events[EVENTID_LAST]; }; +static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v) +{ + IDispatch *disp; + + switch (V_VT(v)) + { + case VT_UNKNOWN: + if (V_UNKNOWN(v)) + IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp); + else + disp = NULL; + break; + case VT_DISPATCH: + disp = V_DISPATCH(v); + if (disp) IDispatch_AddRef(disp); + break; + default: + return DISP_E_TYPEMISMATCH; + } + + if (doc->events[eid]) IDispatch_Release(doc->events[eid]); + doc->events[eid] = disp; + + return S_OK; +} + static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface) { return (ConnectionPoint *)((char*)iface - FIELD_OFFSET(ConnectionPoint, lpVtblConnectionPoint)); @@ -909,6 +945,8 @@ static ULONG WINAPI domdoc_Release( if ( ref == 0 ) { + int eid; + if(This->bsc) detach_bsc(This->bsc); @@ -917,6 +955,10 @@ static ULONG WINAPI domdoc_Release( destroy_xmlnode(&This->node); if (This->stream) IStream_Release(This->stream); + + for (eid = 0; eid < EVENTID_LAST; eid++) + if (This->events[eid]) IDispatch_Release(This->events[eid]); + heap_free(This); } @@ -2470,13 +2512,14 @@ static HRESULT WINAPI domdoc_put_preserveWhiteSpace( } -static HRESULT WINAPI domdoc_put_onReadyStateChange( +static HRESULT WINAPI domdoc_put_onreadystatechange( IXMLDOMDocument3 *iface, - VARIANT readyStateChangeSink ) + VARIANT event ) { domdoc *This = impl_from_IXMLDOMDocument3( iface ); - FIXME("%p\n", This); - return E_NOTIMPL; + + TRACE("(%p)->(%s)\n", This, debugstr_variant(&event)); + return set_doc_event(This, EVENTID_READYSTATECHANGE, &event); } @@ -3040,7 +3083,7 @@ static const struct IXMLDOMDocument3Vtbl domdoc_vtbl = domdoc_put_resolveExternals, domdoc_get_preserveWhiteSpace, domdoc_put_preserveWhiteSpace, - domdoc_put_onReadyStateChange, + domdoc_put_onreadystatechange, domdoc_put_onDataAvailable, domdoc_put_onTransformNode, domdoc_get_namespaces, @@ -3402,6 +3445,7 @@ HRESULT DOMDocument_create_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **docu doc->safeopt = 0; doc->bsc = NULL; doc->cp_list = NULL; + memset(doc->events, 0, sizeof(doc->events)); /* events connection points */ ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch); diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c index e38d3b5e950..eee20a6b9f7 100644 --- a/dlls/msxml3/tests/domdoc.c +++ b/dlls/msxml3/tests/domdoc.c @@ -7530,6 +7530,9 @@ static void test_events(void) IConnectionPoint *point; IXMLDOMDocument *doc; HRESULT hr; + VARIANT v; + IDispatch *event; + ULONG ref; doc = create_document(&IID_IXMLDOMDocument); if (!doc) return; @@ -7549,6 +7552,54 @@ static void test_events(void) IConnectionPointContainer_Release(conn); + /* ready state callback */ + VariantInit(&v); + hr = IXMLDOMDocument_put_onreadystatechange(doc, v); + ok(hr == DISP_E_TYPEMISMATCH, "got 0x%08x\n", hr); + + event = create_dispevent(); + V_VT(&v) = VT_UNKNOWN; + V_UNKNOWN(&v) = (IUnknown*)event; + + hr = IXMLDOMDocument_put_onreadystatechange(doc, v); + ok(hr == S_OK, "got 0x%08x\n", hr); + ref = IDispatch_AddRef(event); + IDispatch_Release(event); + ok(ref == 3, "got %d\n", ref); + + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = event; + + hr = IXMLDOMDocument_put_onreadystatechange(doc, v); + ok(hr == S_OK, "got 0x%08x\n", hr); + ref = IDispatch_AddRef(event); + IDispatch_Release(event); + ok(ref == 3, "got %d\n", ref); + + /* VT_NULL doesn't reset event handler */ + V_VT(&v) = VT_NULL; + hr = IXMLDOMDocument_put_onreadystatechange(doc, v); + ok(hr == DISP_E_TYPEMISMATCH, "got 0x%08x\n", hr); + ref = IDispatch_AddRef(event); + IDispatch_Release(event); + ok(ref == 3, "got %d\n", ref); + + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = NULL; + + hr = IXMLDOMDocument_put_onreadystatechange(doc, v); + ok(hr == S_OK, "got 0x%08x\n", hr); + ref = IDispatch_AddRef(event); + IDispatch_Release(event); + ok(ref == 2, "got %d\n", ref); + + V_VT(&v) = VT_UNKNOWN; + V_DISPATCH(&v) = NULL; + hr = IXMLDOMDocument_put_onreadystatechange(doc, v); + ok(hr == S_OK, "got 0x%08x\n", hr); + + IDispatch_Release(event); + IXMLDOMDocument_Release(doc); }