diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c index 1e2d8cd33b0..8b3f561dfb0 100644 --- a/dlls/msxml3/domdoc.c +++ b/dlls/msxml3/domdoc.c @@ -171,6 +171,7 @@ typedef struct _domdoc VARIANT_BOOL preserving; IUnknown *node_unk; IXMLDOMNode *node; + IXMLDOMSchemaCollection *schema; HRESULT error; } domdoc; @@ -254,6 +255,7 @@ static ULONG WINAPI domdoc_Release( if ( ref == 0 ) { IUnknown_Release( This->node_unk ); + if(This->schema) IXMLDOMSchemaCollection_Release( This->schema ); HeapFree( GetProcessHeap(), 0, This ); } @@ -1293,7 +1295,7 @@ static HRESULT WINAPI domdoc_put_onTransformNode( } static HRESULT WINAPI domdoc_get_namespaces( - IXMLDOMDocument2* This, + IXMLDOMDocument2* iface, IXMLDOMSchemaCollection** schemaCollection ) { FIXME("\n"); @@ -1301,23 +1303,66 @@ static HRESULT WINAPI domdoc_get_namespaces( } static HRESULT WINAPI domdoc_get_schemas( - IXMLDOMDocument2* This, + IXMLDOMDocument2* iface, VARIANT* var1 ) { - FIXME("\n"); - return E_NOTIMPL; + domdoc *This = impl_from_IXMLDOMDocument2( iface ); + HRESULT hr = S_FALSE; + IXMLDOMSchemaCollection *cur_schema = This->schema; + + TRACE("(%p)->(%p)\n", This, var1); + + VariantInit(var1); /* Test shows we don't call VariantClear here */ + V_VT(var1) = VT_NULL; + + if(cur_schema) + { + hr = IXMLDOMSchemaCollection_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1)); + if(SUCCEEDED(hr)) + V_VT(var1) = VT_DISPATCH; + } + return hr; } static HRESULT WINAPI domdoc_putref_schemas( - IXMLDOMDocument2* This, + IXMLDOMDocument2* iface, VARIANT var1) { - FIXME("\n"); - return E_NOTIMPL; + domdoc *This = impl_from_IXMLDOMDocument2( iface ); + HRESULT hr = E_FAIL; + IXMLDOMSchemaCollection *new_schema = NULL; + + FIXME("(%p): semi-stub\n", This); + switch(V_VT(&var1)) + { + case VT_UNKNOWN: + hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema); + break; + + case VT_DISPATCH: + hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema); + break; + + case VT_NULL: + case VT_EMPTY: + hr = S_OK; + break; + + default: + WARN("Can't get schema from vt %x\n", V_VT(&var1)); + } + + if(SUCCEEDED(hr)) + { + IXMLDOMSchemaCollection *old_schema = InterlockedExchangePointer((void**)&This->schema, new_schema); + if(old_schema) IXMLDOMSchemaCollection_Release(old_schema); + } + + return hr; } static HRESULT WINAPI domdoc_validate( - IXMLDOMDocument2* This, + IXMLDOMDocument2* iface, IXMLDOMParseError** err) { FIXME("\n"); @@ -1325,7 +1370,7 @@ static HRESULT WINAPI domdoc_validate( } static HRESULT WINAPI domdoc_setProperty( - IXMLDOMDocument2* This, + IXMLDOMDocument2* iface, BSTR p, VARIANT var) { @@ -1334,7 +1379,7 @@ static HRESULT WINAPI domdoc_setProperty( } static HRESULT WINAPI domdoc_getProperty( - IXMLDOMDocument2* This, + IXMLDOMDocument2* iface, BSTR p, VARIANT* var) { @@ -1447,6 +1492,7 @@ HRESULT DOMDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj) doc->resolving = 0; doc->preserving = 0; doc->error = S_OK; + doc->schema = NULL; xmldoc = xmlNewDoc(NULL); if(!xmldoc) diff --git a/dlls/msxml3/schema.c b/dlls/msxml3/schema.c index f823e78d672..5d4832178a3 100644 --- a/dlls/msxml3/schema.c +++ b/dlls/msxml3/schema.c @@ -55,6 +55,7 @@ static HRESULT WINAPI schema_cache_QueryInterface( IXMLDOMSchemaCollection *ifac TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject ); if ( IsEqualIID( riid, &IID_IUnknown ) || + IsEqualIID( riid, &IID_IDispatch ) || IsEqualIID( riid, &IID_IXMLDOMSchemaCollection ) ) { *ppvObject = iface; diff --git a/dlls/msxml3/tests/schema.c b/dlls/msxml3/tests/schema.c index 8651aa99818..b012621c96b 100644 --- a/dlls/msxml3/tests/schema.c +++ b/dlls/msxml3/tests/schema.c @@ -86,8 +86,118 @@ void test_schema_refs(void) SysFreeString(str); VariantClear(&v); + V_VT(&v) = VT_INT; + r = IXMLDOMDocument2_get_schemas(doc, &v); + ok(r == S_FALSE, "ret %08x\n", r); + ok(V_VT(&v) == VT_NULL, "vt %x\n", V_VT(&v)); + + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 2, "ref %d\n", ref); + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)schema; + + /* check that putref_schemas takes a ref */ + r = IXMLDOMDocument2_putref_schemas(doc, v); + ok(r == S_OK, "ret %08x\n", r); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 4, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + VariantClear(&v); + + /* refs now 2 */ + V_VT(&v) = VT_INT; + /* check that get_schemas adds a ref */ + r = IXMLDOMDocument2_get_schemas(doc, &v); + ok(r == S_OK, "ret %08x\n", r); + ok(V_VT(&v) == VT_DISPATCH, "vt %x\n", V_VT(&v)); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 4, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + + /* refs now 3 */ + /* get_schemas doesn't release a ref if passed VT_DISPATCH - ie it doesn't call VariantClear() */ + r = IXMLDOMDocument2_get_schemas(doc, &v); + ok(r == S_OK, "ret %08x\n", r); + ok(V_VT(&v) == VT_DISPATCH, "vt %x\n", V_VT(&v)); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 5, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + + /* refs now 4 */ + /* release the two refs returned by get_schemas */ + IXMLDOMSchemaCollection_Release(schema); + IXMLDOMSchemaCollection_Release(schema); + + /* refs now 2 */ + + /* check that taking another ref on the document doesn't change the schema's ref count */ + IXMLDOMDocument2_AddRef(doc); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 3, "ref %d\n", ref); IXMLDOMSchemaCollection_Release(schema); IXMLDOMDocument2_Release(doc); + + + /* refs now 2 */ + /* call putref_schema with some odd variants */ + V_VT(&v) = VT_INT; + r = IXMLDOMDocument2_putref_schemas(doc, v); + ok(r == E_FAIL, "ret %08x\n", r); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 3, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + + /* refs now 2 */ + /* calling with VT_EMPTY releases the schema */ + V_VT(&v) = VT_EMPTY; + r = IXMLDOMDocument2_putref_schemas(doc, v); + ok(r == S_OK, "ret %08x\n", r); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 2, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + + /* refs now 1 */ + /* try setting with VT_UNKNOWN */ + IXMLDOMSchemaCollection_AddRef(schema); + V_VT(&v) = VT_UNKNOWN; + V_UNKNOWN(&v) = (IUnknown*)schema; + r = IXMLDOMDocument2_putref_schemas(doc, v); + ok(r == S_OK, "ret %08x\n", r); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 4, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + VariantClear(&v); + + /* refs now 2 */ + /* calling with VT_NULL releases the schema */ + V_VT(&v) = VT_NULL; + r = IXMLDOMDocument2_putref_schemas(doc, v); + ok(r == S_OK, "ret %08x\n", r); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 2, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + + /* refs now 1 */ + /* set again */ + IXMLDOMSchemaCollection_AddRef(schema); + V_VT(&v) = VT_UNKNOWN; + V_UNKNOWN(&v) = (IUnknown*)schema; + r = IXMLDOMDocument2_putref_schemas(doc, v); + ok(r == S_OK, "ret %08x\n", r); + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 4, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + VariantClear(&v); + + /* refs now 2 */ + + /* release the final ref on the doc which should release its ref on the schema */ + IXMLDOMDocument2_Release(doc); + + ref = IXMLDOMSchemaCollection_AddRef(schema); + ok(ref == 2, "ref %d\n", ref); + IXMLDOMSchemaCollection_Release(schema); + IXMLDOMSchemaCollection_Release(schema); } START_TEST(schema)