msxml: Better ref counting

Huw D M Davies h.davies1 at physics.ox.ac.uk
Fri Nov 18 06:52:18 CST 2005


        Huw Davies <huw at codeweavers.com>
        Ref count the xmlDocPtr.
        If two nodes refer to the same xmlNodePtr don't return same object.
-- 
Huw Davies
huw at codeweavers.com
Index: dlls/msxml3/domdoc.c
===================================================================
RCS file: /home/wine/wine/dlls/msxml3/domdoc.c,v
retrieving revision 1.18
diff -u -p -r1.18 domdoc.c
--- dlls/msxml3/domdoc.c	8 Nov 2005 19:59:36 -0000	1.18
+++ dlls/msxml3/domdoc.c	18 Nov 2005 12:47:03 -0000
@@ -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));
Index: dlls/msxml3/msxml_private.h
===================================================================
RCS file: /home/wine/wine/dlls/msxml3/msxml_private.h,v
retrieving revision 1.12
diff -u -p -r1.12 msxml_private.h
--- dlls/msxml3/msxml_private.h	8 Nov 2005 19:59:36 -0000	1.12
+++ dlls/msxml3/msxml_private.h	18 Nov 2005 12:47:03 -0000
@@ -43,6 +43,8 @@ xmlNodePtr xmlNodePtr_from_domnode( IXML
 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,
Index: dlls/msxml3/node.c
===================================================================
RCS file: /home/wine/wine/dlls/msxml3/node.c,v
retrieving revision 1.15
diff -u -p -r1.15 node.c
--- dlls/msxml3/node.c	8 Nov 2005 19:59:36 -0000	1.15
+++ dlls/msxml3/node.c	18 Nov 2005 12:47:03 -0000
@@ -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 nod
 
     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;
-    }
+    This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
+    if ( !This )
+        return NULL;
 
-    /*
-     * Try adding a reference to the IXMLDOMNode implementation
-     * containing the document's root element.
-     */
-    if ( node->type != XML_DOCUMENT_NODE )
+    if ( node->type == XML_DOCUMENT_NODE )
     {
-        IXMLDOMNode *root = NULL;
-
-        root = node->doc->_private;
-        assert( root );
-        IXMLDOMNode_AddRef( root );
-    }
-    else
         assert( node->doc == (xmlDocPtr) node );
+        node->doc->_private = 0;
+    }
 
-    This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
-    if ( !This )
-        return NULL;
+    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;
 }
 
Index: dlls/msxml3/nodelist.c
===================================================================
RCS file: /home/wine/wine/dlls/msxml3/nodelist.c,v
retrieving revision 1.7
diff -u -p -r1.7 nodelist.c
--- dlls/msxml3/nodelist.c	8 Nov 2005 19:59:36 -0000	1.7
+++ dlls/msxml3/nodelist.c	18 Nov 2005 12:47:03 -0000
@@ -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( xmlNod
     nodelist->current = node;
     xlst_info_init( &nodelist->xinfo );
 
+    xmldoc_add_ref( node->doc );
+
     return nodelist;
 }
 
Index: dlls/msxml3/nodemap.c
===================================================================
RCS file: /home/wine/wine/dlls/msxml3/nodemap.c,v
retrieving revision 1.9
diff -u -p -r1.9 nodemap.c
--- dlls/msxml3/nodemap.c	8 Nov 2005 19:59:36 -0000	1.9
+++ dlls/msxml3/nodemap.c	18 Nov 2005 12:47:03 -0000
@@ -331,6 +331,7 @@ IXMLDOMNamedNodeMap *create_nodemap( IXM
     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;
 }
Index: dlls/msxml3/tests/domdoc.c
===================================================================
RCS file: /home/wine/wine/dlls/msxml3/tests/domdoc.c,v
retrieving revision 1.11
diff -u -p -r1.11 domdoc.c
--- dlls/msxml3/tests/domdoc.c	10 Nov 2005 11:39:07 -0000	1.11
+++ dlls/msxml3/tests/domdoc.c	18 Nov 2005 12:47:03 -0000
@@ -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();
 }



More information about the wine-patches mailing list