diff --git a/dlls/msxml3/selection.c b/dlls/msxml3/selection.c index e0f30c32b04..c90c8c296b5 100644 --- a/dlls/msxml3/selection.c +++ b/dlls/msxml3/selection.c @@ -58,6 +58,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml); int registerNamespaces(xmlXPathContextPtr ctxt); xmlChar* XSLPattern_to_XPath(xmlXPathContextPtr ctxt, xmlChar const* xslpat_str); +typedef struct _enumvariant +{ + IEnumVARIANT IEnumVARIANT_iface; + LONG ref; + + IXMLDOMSelection *selection; + BOOL own; +} enumvariant; + typedef struct _domselection { DispatchEx dispex; @@ -66,6 +75,7 @@ typedef struct _domselection xmlNodePtr node; xmlXPathObjectPtr result; int resultPos; + IEnumVARIANT *enumvariant; } domselection; static inline domselection *impl_from_IXMLDOMSelection( IXMLDOMSelection *iface ) @@ -73,6 +83,13 @@ static inline domselection *impl_from_IXMLDOMSelection( IXMLDOMSelection *iface return CONTAINING_RECORD(iface, domselection, IXMLDOMSelection_iface); } +static inline enumvariant *impl_from_IEnumVARIANT( IEnumVARIANT *iface ) +{ + return CONTAINING_RECORD(iface, enumvariant, IEnumVARIANT_iface); +} + +static HRESULT create_enumvariant(IXMLDOMSelection*, BOOL, IUnknown**); + static HRESULT WINAPI domselection_QueryInterface( IXMLDOMSelection *iface, REFIID riid, @@ -91,7 +108,17 @@ static HRESULT WINAPI domselection_QueryInterface( { *ppvObject = &This->IXMLDOMSelection_iface; } - else if(dispex_query_interface(&This->dispex, riid, ppvObject)) + else if (IsEqualGUID( riid, &IID_IEnumVARIANT )) + { + if (!This->enumvariant) + { + HRESULT hr = create_enumvariant(iface, FALSE, (IUnknown**)&This->enumvariant); + if (FAILED(hr)) return hr; + } + + return IEnumVARIANT_QueryInterface(This->enumvariant, &IID_IEnumVARIANT, ppvObject); + } + else if (dispex_query_interface(&This->dispex, riid, ppvObject)) { return *ppvObject ? S_OK : E_NOINTERFACE; } @@ -127,6 +154,7 @@ static ULONG WINAPI domselection_Release( { xmlXPathFreeObject(This->result); xmldoc_release(This->node->doc); + if (This->enumvariant) IEnumVARIANT_Release(This->enumvariant); heap_free(This); } @@ -293,8 +321,10 @@ static HRESULT WINAPI domselection_get__newEnum( IUnknown** ppUnk) { domselection *This = impl_from_IXMLDOMSelection( iface ); - FIXME("(%p)->(%p)\n", This, ppUnk); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, ppUnk); + + return create_enumvariant(iface, TRUE, ppUnk); } static HRESULT WINAPI domselection_get_expr( @@ -425,6 +455,118 @@ static const struct IXMLDOMSelectionVtbl domselection_vtbl = domselection_setProperty }; +/* IEnumVARIANT support */ +static HRESULT WINAPI enumvariant_QueryInterface( + IEnumVARIANT *iface, + REFIID riid, + void** ppvObject ) +{ + enumvariant *This = impl_from_IEnumVARIANT( iface ); + + TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject); + + *ppvObject = NULL; + + if ( IsEqualGUID( riid, &IID_IUnknown ) || + IsEqualGUID( riid, &IID_IEnumVARIANT )) + { + *ppvObject = &This->IEnumVARIANT_iface; + } + else + return IXMLDOMSelection_QueryInterface(This->selection, riid, ppvObject); + + IEnumVARIANT_AddRef( iface ); + + return S_OK; +} + +static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface ) +{ + enumvariant *This = impl_from_IEnumVARIANT( iface ); + ULONG ref = InterlockedIncrement( &This->ref ); + TRACE("(%p)->(%d)\n", This, ref); + return ref; +} + +static ULONG WINAPI enumvariant_Release(IEnumVARIANT *iface ) +{ + enumvariant *This = impl_from_IEnumVARIANT( iface ); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(%d)\n", This, ref); + if ( ref == 0 ) + { + if (This->own) IXMLDOMSelection_Release(This->selection); + heap_free(This); + } + + return ref; +} + +static HRESULT WINAPI enumvariant_Next( + IEnumVARIANT *iface, + ULONG celt, + VARIANT *rgvar, + ULONG *pceltFetched) +{ + enumvariant *This = impl_from_IEnumVARIANT( iface ); + FIXME("(%p)->(%u %p %p): stub\n", This, celt, rgvar, pceltFetched); + return E_NOTIMPL; +} + +static HRESULT WINAPI enumvariant_Skip( + IEnumVARIANT *iface, + ULONG celt) +{ + enumvariant *This = impl_from_IEnumVARIANT( iface ); + FIXME("(%p)->(%u): stub\n", This, celt); + return E_NOTIMPL; +} + +static HRESULT WINAPI enumvariant_Reset(IEnumVARIANT *iface) +{ + enumvariant *This = impl_from_IEnumVARIANT( iface ); + FIXME("(%p): stub\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI enumvariant_Clone( + IEnumVARIANT *iface, IEnumVARIANT **ppenum) +{ + enumvariant *This = impl_from_IEnumVARIANT( iface ); + FIXME("(%p)->(%p): stub\n", This, ppenum); + return E_NOTIMPL; +} + +static const struct IEnumVARIANTVtbl EnumVARIANTVtbl = +{ + enumvariant_QueryInterface, + enumvariant_AddRef, + enumvariant_Release, + enumvariant_Next, + enumvariant_Skip, + enumvariant_Reset, + enumvariant_Clone +}; + +static HRESULT create_enumvariant(IXMLDOMSelection *selection, BOOL own, IUnknown **penum) +{ + enumvariant *This; + + This = heap_alloc(sizeof(enumvariant)); + if (!This) return E_OUTOFMEMORY; + + This->IEnumVARIANT_iface.lpVtbl = &EnumVARIANTVtbl; + This->ref = 0; + This->selection = selection; + This->own = own; + + if (This->own) + IXMLDOMSelection_AddRef(selection); + + return IEnumVARIANT_QueryInterface(&This->IEnumVARIANT_iface, &IID_IUnknown, (void**)penum); +} + static HRESULT domselection_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid) { domselection *This = impl_from_IXMLDOMSelection( (IXMLDOMSelection*)iface ); @@ -622,6 +764,7 @@ HRESULT create_selection(xmlNodePtr node, xmlChar* query, IXMLDOMNodeList **out) This->ref = 1; This->resultPos = 0; This->node = node; + This->enumvariant = NULL; xmldoc_add_ref(This->node->doc); ctxt->error = query_serror; diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c index c12aa5c9547..0acfa25c34f 100644 --- a/dlls/msxml3/tests/domdoc.c +++ b/dlls/msxml3/tests/domdoc.c @@ -9964,7 +9964,9 @@ static void test_get_attributes(void) static void test_selection(void) { - IXMLDOMSelection *selection; + IXMLDOMSelection *selection, *selection2; + IEnumVARIANT *enum1, *enum2, *enum3; + IDispatch *disp; IXMLDOMNodeList *list; IXMLDOMDocument *doc; VARIANT_BOOL b; @@ -9982,6 +9984,85 @@ static void test_selection(void) EXPECT_HR(hr, S_OK); IXMLDOMSelection_Release(selection); + /* IEnumVARIANT tests */ + enum1 = NULL; + hr = IXMLDOMSelection_QueryInterface(selection, &IID_IEnumVARIANT, (void**)&enum1); + EXPECT_HR(hr, S_OK); + ok(enum1 != NULL, "got %p\n", enum1); + EXPECT_REF(enum1, 2); + + enum3 = NULL; + hr = IXMLDOMSelection_QueryInterface(selection, &IID_IEnumVARIANT, (void**)&enum3); + EXPECT_HR(hr, S_OK); + ok(enum3 != NULL, "got %p\n", enum3); + ok(enum1 == enum3, "got %p and %p\n", enum1, enum3); + EXPECT_REF(enum1, 3); + IEnumVARIANT_Release(enum3); + + EXPECT_REF(selection, 1); + EXPECT_REF(enum1, 2); + + enum2 = NULL; + hr = IXMLDOMSelection_get__newEnum(selection, (IUnknown**)&enum2); + EXPECT_HR(hr, S_OK); + ok(enum2 != NULL, "got %p\n", enum2); + + EXPECT_REF(selection, 2); + EXPECT_REF(enum1, 2); + EXPECT_REF(enum2, 1); + + ok(enum1 != enum2, "got %p, %p\n", enum1, enum2); + + selection2 = NULL; + hr = IEnumVARIANT_QueryInterface(enum1, &IID_IXMLDOMSelection, (void**)&selection2); + EXPECT_HR(hr, S_OK); + ok(selection2 == selection, "got %p and %p\n", selection, selection2); + EXPECT_REF(selection, 3); + EXPECT_REF(enum1, 2); + + IXMLDOMSelection_Release(selection2); + + hr = IEnumVARIANT_QueryInterface(enum1, &IID_IDispatch, (void**)&disp); + EXPECT_HR(hr, S_OK); + EXPECT_REF(selection, 3); + IDispatch_Release(disp); + + hr = IEnumVARIANT_QueryInterface(enum1, &IID_IEnumVARIANT, (void**)&enum3); + EXPECT_HR(hr, S_OK); + ok(enum3 == enum1, "got %p and %p\n", enum3, enum1); + EXPECT_REF(selection, 2); + EXPECT_REF(enum1, 3); + + IEnumVARIANT_Release(enum1); + IEnumVARIANT_Release(enum2); + + enum1 = NULL; + hr = IXMLDOMSelection_get__newEnum(selection, (IUnknown**)&enum1); + EXPECT_HR(hr, S_OK); + ok(enum1 != NULL, "got %p\n", enum1); + EXPECT_REF(enum1, 1); + EXPECT_REF(selection, 2); + + enum2 = NULL; + hr = IXMLDOMSelection_get__newEnum(selection, (IUnknown**)&enum2); + EXPECT_HR(hr, S_OK); + ok(enum2 != NULL, "got %p\n", enum2); + EXPECT_REF(enum2, 1); + EXPECT_REF(selection, 3); + + ok(enum1 != enum2, "got %p, %p\n", enum1, enum2); + + IEnumVARIANT_AddRef(enum1); + EXPECT_REF(selection, 3); + EXPECT_REF(enum1, 2); + EXPECT_REF(enum2, 1); + IEnumVARIANT_Release(enum1); + + IEnumVARIANT_Release(enum1); + IEnumVARIANT_Release(enum2); + + EXPECT_REF(selection, 1); + IXMLDOMNodeList_Release(list); hr = IXMLDOMDocument_get_childNodes(doc, &list);