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