diff --git a/dlls/msxml3/domdoc.c b/dlls/msxml3/domdoc.c index 958531d8d3a..8d46084a926 100644 --- a/dlls/msxml3/domdoc.c +++ b/dlls/msxml3/domdoc.c @@ -46,6 +46,26 @@ typedef struct _domdoc IXMLDOMNode *node; } domdoc; +LONG xmldoc_add_ref(xmlDocPtr doc) +{ + LONG ref = InterlockedIncrement((LONG*)&doc->_private); + TRACE("%ld\n", ref); + return ref; +} + +LONG xmldoc_release(xmlDocPtr doc) +{ + LONG ref = InterlockedDecrement((LONG*)&doc->_private); + TRACE("%ld\n", ref); + if(ref == 0) + { + TRACE("freeing docptr %p\n", doc); + xmlFreeDoc(doc); + } + + return ref; +} + static inline domdoc *impl_from_IXMLDOMDocument( IXMLDOMDocument *iface ) { return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpVtbl)); diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h index 88abeef4a7b..238d5990d25 100644 --- a/dlls/msxml3/msxml_private.h +++ b/dlls/msxml3/msxml_private.h @@ -43,6 +43,8 @@ xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type ); extern xmlChar *xmlChar_from_wchar( LPWSTR str ); extern BSTR bstr_from_xmlChar( const xmlChar *buf ); +extern LONG xmldoc_add_ref( xmlDocPtr doc ); +extern LONG xmldoc_release( xmlDocPtr doc ); #endif extern IXMLDOMParseError *create_parseError( LONG code, BSTR url, BSTR reason, BSTR srcText, diff --git a/dlls/msxml3/node.c b/dlls/msxml3/node.c index bea300eeeab..3911e9c5951 100644 --- a/dlls/msxml3/node.c +++ b/dlls/msxml3/node.c @@ -102,19 +102,8 @@ static ULONG WINAPI xmlnode_Release( ref = InterlockedDecrement( &This->ref ); if ( ref == 0 ) { - if( This->node->type == XML_DOCUMENT_NODE ) - { - xmlFreeDoc( (xmlDocPtr) This->node ); - } - else - { - IXMLDOMNode *root; - assert( This->node->doc ); - root = This->node->doc->_private; - assert( root ); - IXMLDOMNode_Release( root ); - This->node->_private = NULL; - } + assert( This->node->doc ); + xmldoc_release( This->node->doc ); HeapFree( GetProcessHeap(), 0, This ); } @@ -720,40 +709,22 @@ IXMLDOMNode *create_node( xmlNodePtr node ) assert( node->doc ); - /* if an interface already exists for this node, return it */ - if ( node->_private ) - { - IXMLDOMNode *n = node->_private; - IXMLDOMNode_AddRef( n ); - return n; - } - - /* - * Try adding a reference to the IXMLDOMNode implementation - * containing the document's root element. - */ - if ( node->type != XML_DOCUMENT_NODE ) - { - IXMLDOMNode *root = NULL; - - root = node->doc->_private; - assert( root ); - IXMLDOMNode_AddRef( root ); - } - else - assert( node->doc == (xmlDocPtr) node ); - This = HeapAlloc( GetProcessHeap(), 0, sizeof *This ); if ( !This ) return NULL; + if ( node->type == XML_DOCUMENT_NODE ) + { + assert( node->doc == (xmlDocPtr) node ); + node->doc->_private = 0; + } + + xmldoc_add_ref( node->doc ); + This->lpVtbl = &xmlnode_vtbl; This->ref = 1; This->node = node; - /* remember which interface we associated with this node */ - node->_private = This; - return (IXMLDOMNode*) &This->lpVtbl; } diff --git a/dlls/msxml3/nodelist.c b/dlls/msxml3/nodelist.c index 36c9e1c0787..db4e3701c98 100644 --- a/dlls/msxml3/nodelist.c +++ b/dlls/msxml3/nodelist.c @@ -191,6 +191,7 @@ static ULONG WINAPI xmlnodelist_Release( if ( ref == 0 ) { free_xslt_info( &This->xinfo ); + xmldoc_release( This->node->doc ); HeapFree( GetProcessHeap(), 0, This ); } @@ -374,6 +375,8 @@ static xmlnodelist *new_nodelist( xmlNodePtr node ) nodelist->current = node; xlst_info_init( &nodelist->xinfo ); + xmldoc_add_ref( node->doc ); + return nodelist; } diff --git a/dlls/msxml3/nodemap.c b/dlls/msxml3/nodemap.c index ba471a654eb..65806676c15 100644 --- a/dlls/msxml3/nodemap.c +++ b/dlls/msxml3/nodemap.c @@ -331,6 +331,7 @@ IXMLDOMNamedNodeMap *create_nodemap( IXMLDOMNode *node ) nodemap->ref = 1; IXMLDOMNode_AddRef( node ); + /* Since we AddRef a node here, we don't need to call xmldoc_add_ref() */ return (IXMLDOMNamedNodeMap*) &nodemap->lpVtbl; } diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c index c3b054c1608..1405b992bb0 100644 --- a/dlls/msxml3/tests/domdoc.c +++ b/dlls/msxml3/tests/domdoc.c @@ -505,6 +505,82 @@ void test_domnode( void ) IXMLDOMDocument_Release( doc ); } +static void test_refs(void) +{ + HRESULT r; + BSTR str; + VARIANT_BOOL b; + IXMLDOMDocument *doc = NULL; + IXMLDOMElement *element = NULL; + IXMLDOMNode *node = NULL, *node2; + IXMLDOMNodeList *node_list = NULL; + LONG ref; + + r = CoCreateInstance( &CLSID_DOMDocument, NULL, + CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc ); + if( r != S_OK ) + return; + + str = SysAllocString( szComplete4 ); + r = IXMLDOMDocument_loadXML( doc, str, &b ); + ok( r == S_OK, "loadXML failed\n"); + ok( b == VARIANT_TRUE, "failed to load XML string\n"); + SysFreeString( str ); + + ref = IXMLDOMDocument_AddRef( doc ); + ok( ref == 2, "ref %ld\n", ref ); + ref = IXMLDOMDocument_AddRef( doc ); + ok( ref == 3, "ref %ld\n", ref ); + IXMLDOMDocument_Release( doc ); + IXMLDOMDocument_Release( doc ); + + r = IXMLDOMDocument_get_documentElement( doc, &element ); + ok( r == S_OK, "should be a document element\n"); + ok( element != NULL, "should be an element\n"); + + ref = IXMLDOMDocument_AddRef( doc ); + ok( ref == 2, "ref %ld\n", ref ); + IXMLDOMDocument_Release( doc ); + + r = IXMLDOMElement_get_childNodes( element, &node_list ); + ok( r == S_OK, "rets %08lx\n", r); + ref = IXMLDOMNodeList_AddRef( node_list ); + ok( ref == 2, "ref %ld\n", ref ); + IXMLDOMNodeList_Release( node_list ); + + IXMLDOMNodeList_get_item( node_list, 0, &node ); + ok( r == S_OK, "rets %08lx\n", r); + + IXMLDOMNodeList_get_item( node_list, 0, &node2 ); + ok( r == S_OK, "rets %08lx\n", r); + + ref = IXMLDOMNode_AddRef( node ); + ok( ref == 2, "ref %ld\n", ref ); + IXMLDOMNode_Release( node ); + + ref = IXMLDOMNode_Release( node ); + ok( ref == 0, "ref %ld\n", ref ); + ref = IXMLDOMNode_Release( node2 ); + ok( ref == 0, "ref %ld\n", ref ); + + ref = IXMLDOMNodeList_Release( node_list ); + ok( ref == 0, "ref %ld\n", ref ); + + ok( node != node2, "node %p node2 %p\n", node, node2 ); + + ref = IXMLDOMDocument_Release( doc ); + ok( ref == 0, "ref %ld\n", ref ); + + ref = IXMLDOMElement_AddRef( element ); + todo_wine { + ok( ref == 3, "ref %ld\n", ref ); + } + + IXMLDOMElement_Release( element ); + IXMLDOMElement_Release( element ); + +} + START_TEST(domdoc) { HRESULT r; @@ -514,6 +590,7 @@ START_TEST(domdoc) test_domdoc(); test_domnode(); + test_refs(); CoUninitialize(); }