msxml: make node object aggregatable

Huw D M Davies h.davies1 at physics.ox.ac.uk
Thu Dec 1 09:39:11 CST 2005


This time without removing the link with libuuid.

        Huw Davies <huw at codeweavers.com>
        Make the node object aggregatable so that the element object
        (and in future all of the other node types) can use it.
-- 
Huw Davies
huw at codeweavers.com
Index: dlls/msxml3/domdoc.c
===================================================================
RCS file: /home/wine/wine/dlls/msxml3/domdoc.c,v
retrieving revision 1.19
diff -u -p -r1.19 domdoc.c
--- dlls/msxml3/domdoc.c	18 Nov 2005 15:05:26 -0000	1.19
+++ dlls/msxml3/domdoc.c	1 Dec 2005 15:24:35 -0000
@@ -23,6 +23,7 @@
 #include "config.h"
 
 #include <stdarg.h>
+#include <assert.h>
 #include "windef.h"
 #include "winbase.h"
 #include "winuser.h"
@@ -43,6 +44,7 @@ typedef struct _domdoc
     const struct IXMLDOMDocumentVtbl *lpVtbl;
     LONG ref;
     VARIANT_BOOL async;
+    IUnknown *node_unk;
     IXMLDOMNode *node;
 } domdoc;
 
@@ -83,12 +85,15 @@ static HRESULT WINAPI domdoc_QueryInterf
     TRACE("%p %s %p\n", This, debugstr_guid( riid ), ppvObject );
 
     if ( IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
-         IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
-         IsEqualGUID( riid, &IID_IDispatch ) ||
          IsEqualGUID( riid, &IID_IUnknown ) )
     {
         *ppvObject = iface;
     }
+    else if ( IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
+              IsEqualGUID( riid, &IID_IDispatch ) )
+    {
+        return IUnknown_QueryInterface(This->node_unk, riid, ppvObject);
+    }
     else
         return E_NOINTERFACE;
 
@@ -118,8 +123,7 @@ static ULONG WINAPI domdoc_Release(
     ref = InterlockedDecrement( &This->ref );
     if ( ref == 0 )
     {
-        if ( This->node )
-            IXMLDOMElement_Release( This->node );
+        IUnknown_Release( This->node_unk );
         HeapFree( GetProcessHeap(), 0, This );
     }
 
@@ -527,6 +531,8 @@ static HRESULT WINAPI domdoc_get_documen
     domdoc *This = impl_from_IXMLDOMDocument( iface );
     xmlDocPtr xmldoc = NULL;
     xmlNodePtr root = NULL;
+    IXMLDOMNode *element_node;
+    HRESULT hr;
 
     TRACE("%p\n", This);
 
@@ -543,9 +549,13 @@ static HRESULT WINAPI domdoc_get_documen
     if ( !root )
         return S_FALSE;
 
-    *DOMElement = create_element( root );
- 
-    return S_OK;
+    element_node = create_node( root );
+    if(!element_node) return S_FALSE;
+
+    hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (LPVOID*)DOMElement);
+    IXMLDOMNode_Release(element_node);
+
+    return hr;
 }
 
 
@@ -729,11 +739,11 @@ static HRESULT WINAPI domdoc_load(
 
     TRACE("type %d\n", V_VT(&xmlSource) );
 
-    if ( This->node )
-    {
-        IXMLDOMNode_Release( This->node );
-        This->node = NULL;
-    }
+    *isSuccessful = VARIANT_FALSE;
+
+    assert( This->node );
+
+    attach_xmlnode(This->node, NULL);
 
     switch( V_VT(&xmlSource) )
     {
@@ -745,17 +755,10 @@ static HRESULT WINAPI domdoc_load(
         return S_FALSE;
 
     xmldoc = doread( filename );
-    if ( !xmldoc ) {
-        *isSuccessful = VARIANT_FALSE;
-        return S_FALSE;
-    }
+    if ( !xmldoc ) return S_FALSE;
 
-    This->node = create_node( (xmlNodePtr) xmldoc );
-    if ( !This->node )
-    {
-        *isSuccessful = VARIANT_FALSE;
-        return S_FALSE;
-    }
+    xmldoc->_private = 0;
+    attach_xmlnode(This->node, (xmlNodePtr) xmldoc);
 
     *isSuccessful = VARIANT_TRUE;
     return S_OK;
@@ -850,11 +853,9 @@ static HRESULT WINAPI domdoc_loadXML(
 
     TRACE("%p %s %p\n", This, debugstr_w( bstrXML ), isSuccessful );
 
-    if ( This->node )
-    {
-        IXMLDOMNode_Release( This->node );
-        This->node = NULL;
-    }
+    assert ( This->node );
+
+    attach_xmlnode( This->node, NULL );
 
     if ( !isSuccessful )
         return S_FALSE;
@@ -869,11 +870,12 @@ static HRESULT WINAPI domdoc_loadXML(
 
     xmldoc = doparse( str, len );
     HeapFree( GetProcessHeap(), 0, str );
-
-    This->node = create_node( (xmlNodePtr) xmldoc );
-    if( !This->node )
+    if ( !xmldoc )
         return S_FALSE;
 
+    xmldoc->_private = 0;
+    attach_xmlnode( This->node, (xmlNodePtr) xmldoc );
+
     *isSuccessful = VARIANT_TRUE;
     return S_OK;
 }
@@ -1049,6 +1051,9 @@ const struct IXMLDOMDocumentVtbl domdoc_
 HRESULT DOMDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj)
 {
     domdoc *doc;
+    HRESULT hr;
+
+    TRACE("(%p,%p)\n", pUnkOuter, ppObj);
 
     doc = HeapAlloc( GetProcessHeap(), 0, sizeof (*doc) );
     if( !doc )
@@ -1057,10 +1062,27 @@ HRESULT DOMDocument_create(IUnknown *pUn
     doc->lpVtbl = &domdoc_vtbl;
     doc->ref = 1;
     doc->async = 0;
-    doc->node = NULL;
+
+    doc->node_unk = create_basic_node( NULL, (IUnknown*)&doc->lpVtbl );
+    if(!doc->node_unk)
+    {
+        HeapFree(GetProcessHeap(), 0, doc);
+        return E_FAIL;
+    }
+
+    hr = IUnknown_QueryInterface(doc->node_unk, &IID_IXMLDOMNode, (LPVOID*)&doc->node);
+    if(FAILED(hr))
+    {
+        IUnknown_Release(doc->node_unk);
+        HeapFree( GetProcessHeap(), 0, doc );
+        return E_FAIL;
+    }
+    /* The ref on doc->node is actually looped back into this object, so release it */
+    IXMLDOMNode_Release(doc->node);
 
     *ppObj = &doc->lpVtbl;
 
+    TRACE("returning iface %p\n", *ppObj);
     return S_OK;
 }
 
Index: dlls/msxml3/element.c
===================================================================
RCS file: /home/wine/wine/dlls/msxml3/element.c,v
retrieving revision 1.11
diff -u -p -r1.11 element.c
--- dlls/msxml3/element.c	8 Nov 2005 19:59:36 -0000	1.11
+++ dlls/msxml3/element.c	1 Dec 2005 15:24:35 -0000
@@ -41,6 +41,7 @@ typedef struct _domelem
 {
     const struct IXMLDOMElementVtbl *lpVtbl;
     LONG ref;
+    IUnknown *node_unk;
     IXMLDOMNode *node;
 } domelem;
 
@@ -59,15 +60,19 @@ static HRESULT WINAPI domelem_QueryInter
     REFIID riid,
     void** ppvObject )
 {
-    TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
+    domelem *This = impl_from_IXMLDOMElement( iface );
+    TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
 
     if ( IsEqualGUID( riid, &IID_IXMLDOMElement ) ||
-         IsEqualGUID( riid, &IID_IUnknown ) ||
-         IsEqualGUID( riid, &IID_IDispatch ) ||
-         IsEqualGUID( riid, &IID_IXMLDOMNode ) )
+         IsEqualGUID( riid, &IID_IUnknown ) )
     {
         *ppvObject = iface;
     }
+    else if ( IsEqualGUID( riid, &IID_IDispatch ) ||
+              IsEqualGUID( riid, &IID_IXMLDOMNode ) )
+    {
+        return IUnknown_QueryInterface(This->node_unk, riid, ppvObject);
+    }
     else
         return E_NOINTERFACE;
 
@@ -92,7 +97,7 @@ static ULONG WINAPI domelem_Release(
     ref = InterlockedDecrement( &This->ref );
     if ( ref == 0 )
     {
-        IXMLDOMNode_Release( This->node );
+        IUnknown_Release( This->node_unk );
         HeapFree( GetProcessHeap(), 0, This );
     }
 
@@ -568,25 +573,36 @@ static const struct IXMLDOMElementVtbl d
     domelem_normalize,
 };
 
-IXMLDOMElement* create_element( xmlNodePtr element )
+IUnknown* create_element( xmlNodePtr element )
 {
     domelem *This;
+    HRESULT hr;
 
     This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
     if ( !This )
         return NULL;
 
     This->lpVtbl = &domelem_vtbl;
-    This->node = create_node( element );
     This->ref = 1;
 
-    if ( !This->node )
+    This->node_unk = create_basic_node( element, (IUnknown*)&This->lpVtbl );
+    if(!This->node_unk)
+    {
+        HeapFree(GetProcessHeap(), 0, This);
+        return NULL;
+    }
+
+    hr = IUnknown_QueryInterface(This->node_unk, &IID_IXMLDOMNode, (LPVOID*)&This->node);
+    if(FAILED(hr))
     {
+        IUnknown_Release(This->node_unk);
         HeapFree( GetProcessHeap(), 0, This );
         return NULL;
     }
+    /* The ref on This->node is actually looped back into this object, so release it */
+    IXMLDOMNode_Release(This->node);
 
-    return (IXMLDOMElement*) &This->lpVtbl;
+    return (IUnknown*) &This->lpVtbl;
 }
 
 #endif
Index: dlls/msxml3/msxml_private.h
===================================================================
RCS file: /home/wine/wine/dlls/msxml3/msxml_private.h,v
retrieving revision 1.13
diff -u -p -r1.13 msxml_private.h
--- dlls/msxml3/msxml_private.h	18 Nov 2005 15:05:26 -0000	1.13
+++ dlls/msxml3/msxml_private.h	1 Dec 2005 15:24:35 -0000
@@ -31,11 +31,14 @@
 extern IUnknown         *create_domdoc( void );
 extern IUnknown         *create_xmldoc( void );
 extern IXMLDOMNode      *create_node( xmlNodePtr node );
-extern IXMLDOMElement   *create_element( xmlNodePtr element );
+extern IUnknown         *create_basic_node( xmlNodePtr node, IUnknown *pUnkOuter );
+extern IUnknown         *create_element( xmlNodePtr element );
 extern IXMLDOMNodeList  *create_nodelist( xmlNodePtr node );
 extern IXMLDOMNamedNodeMap *create_nodemap( IXMLDOMNode *node );
 extern IXMLDOMNodeList  *create_filtered_nodelist( xmlNodePtr, const xmlChar * );
 
+extern void attach_xmlnode( IXMLDOMNode *node, xmlNodePtr xmlnode );
+
 /* data accessors */
 xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type );
 
Index: dlls/msxml3/node.c
===================================================================
RCS file: /home/wine/wine/dlls/msxml3/node.c,v
retrieving revision 1.16
diff -u -p -r1.16 node.c
--- dlls/msxml3/node.c	18 Nov 2005 15:05:26 -0000	1.16
+++ dlls/msxml3/node.c	1 Dec 2005 15:24:35 -0000
@@ -42,6 +42,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml);
 typedef struct _xmlnode
 {
     const struct IXMLDOMNodeVtbl *lpVtbl;
+    const struct IUnknownVtbl *lpInternalUnkVtbl;
+    IUnknown *pUnkOuter;
     LONG ref;
     xmlNodePtr node;
 } xmlnode;
@@ -51,6 +53,11 @@ static inline xmlnode *impl_from_IXMLDOM
     return (xmlnode *)((char*)iface - FIELD_OFFSET(xmlnode, lpVtbl));
 }
 
+static inline xmlnode *impl_from_InternalUnknown( IUnknown *iface )
+{
+    return (xmlnode *)((char*)iface - FIELD_OFFSET(xmlnode, lpInternalUnkVtbl));
+}
+
 xmlNodePtr xmlNodePtr_from_domnode( IXMLDOMNode *iface, xmlElementType type )
 {
     xmlnode *This;
@@ -65,49 +72,43 @@ xmlNodePtr xmlNodePtr_from_domnode( IXML
     return This->node;
 }
 
+void attach_xmlnode( IXMLDOMNode *node, xmlNodePtr xml )
+{
+    xmlnode *This = impl_from_IXMLDOMNode( node );
+
+    if(This->node)
+        xmldoc_release(This->node->doc);
+
+    This->node = xml;
+    if(This->node)
+        xmldoc_add_ref(This->node->doc);
+
+    return;
+}
+
 static HRESULT WINAPI xmlnode_QueryInterface(
     IXMLDOMNode *iface,
     REFIID riid,
     void** ppvObject )
 {
-    TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
-
-    if ( IsEqualGUID( riid, &IID_IUnknown ) ||
-         IsEqualGUID( riid, &IID_IDispatch ) ||
-         IsEqualGUID( riid, &IID_IXMLDOMNode ) )
-    {
-        *ppvObject = iface;
-    }
-    else
-        return E_NOINTERFACE;
-
-    IXMLDOMElement_AddRef( iface );
+    xmlnode *This = impl_from_IXMLDOMNode( iface );
+    TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
 
-    return S_OK;
+    return IUnknown_QueryInterface(This->pUnkOuter, riid, ppvObject);
 }
 
 static ULONG WINAPI xmlnode_AddRef(
     IXMLDOMNode *iface )
 {
     xmlnode *This = impl_from_IXMLDOMNode( iface );
-    return InterlockedIncrement( &This->ref );
+    return IUnknown_AddRef(This->pUnkOuter);
 }
 
 static ULONG WINAPI xmlnode_Release(
     IXMLDOMNode *iface )
 {
     xmlnode *This = impl_from_IXMLDOMNode( iface );
-    ULONG ref;
-
-    ref = InterlockedDecrement( &This->ref );
-    if ( ref == 0 )
-    {
-        assert( This->node->doc );
-        xmldoc_release( This->node->doc );
-        HeapFree( GetProcessHeap(), 0, This );
-    }
-
-    return ref;
+    return IUnknown_Release(This->pUnkOuter);
 }
 
 static HRESULT WINAPI xmlnode_GetTypeInfoCount(
@@ -700,32 +701,114 @@ static const struct IXMLDOMNodeVtbl xmln
     xmlnode_transformNodeToObject,
 };
 
-IXMLDOMNode *create_node( xmlNodePtr node )
+static HRESULT WINAPI Internal_QueryInterface(
+    IUnknown *iface,
+    REFIID riid,
+    void** ppvObject )
 {
-    xmlnode *This;
+    xmlnode *This = impl_from_InternalUnknown( iface );
 
-    if ( !node )
-        return NULL;
+    TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);
 
-    assert( node->doc );
 
-    This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
-    if ( !This )
-        return NULL;
+    if ( IsEqualGUID( riid, &IID_IUnknown ))
+        *ppvObject = iface;
+    else if ( IsEqualGUID( riid, &IID_IDispatch ) ||
+              IsEqualGUID( riid, &IID_IXMLDOMNode ) )
+        *ppvObject = &This->lpVtbl;
+    else
+    {
+        *ppvObject = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef( (IUnknown*)*ppvObject );
 
-    if ( node->type == XML_DOCUMENT_NODE )
+    return S_OK;
+}
+
+static ULONG WINAPI Internal_AddRef(
+                 IUnknown *iface )
+{
+    xmlnode *This = impl_from_InternalUnknown( iface );
+    return InterlockedIncrement( &This->ref );
+}
+
+static ULONG WINAPI Internal_Release(
+    IUnknown *iface )
+{
+    xmlnode *This = impl_from_InternalUnknown( iface );
+    ULONG ref;
+
+    ref = InterlockedDecrement( &This->ref );
+    if ( ref == 0 )
     {
-        assert( node->doc == (xmlDocPtr) node );
-        node->doc->_private = 0;
+        assert( This->node->doc );
+        xmldoc_release( This->node->doc );
+        HeapFree( GetProcessHeap(), 0, This );
     }
 
-    xmldoc_add_ref( node->doc );
+    return ref;
+}
+
+static const struct IUnknownVtbl internal_unk_vtbl =
+{
+    Internal_QueryInterface,
+    Internal_AddRef,
+    Internal_Release
+};
+
+IUnknown *create_basic_node( xmlNodePtr node, IUnknown *pUnkOuter )
+{
+    xmlnode *This;
+
+    This = HeapAlloc( GetProcessHeap(), 0, sizeof *This );
+    if ( !This )
+        return NULL;
+
+    if(node)
+        xmldoc_add_ref( node->doc );
 
     This->lpVtbl = &xmlnode_vtbl;
+    This->lpInternalUnkVtbl = &internal_unk_vtbl;
+
+    if(pUnkOuter)
+        This->pUnkOuter = pUnkOuter; /* Don't take a ref on outer Unknown */
+    else
+        This->pUnkOuter = (IUnknown *)&This->lpInternalUnkVtbl;
+
     This->ref = 1;
     This->node = node;
 
-    return (IXMLDOMNode*) &This->lpVtbl;
+    return (IUnknown*)&This->lpInternalUnkVtbl;
 }
 
+IXMLDOMNode *create_node( xmlNodePtr node )
+{
+    IUnknown *pUnk;
+    IXMLDOMNode *ret;
+    HRESULT hr;
+
+    if ( !node )
+        return NULL;
+
+    TRACE("type %d\n", node->type);
+    switch(node->type)
+    {
+    case XML_ELEMENT_NODE:
+        pUnk = create_element( node );
+        break;
+    case XML_DOCUMENT_NODE:
+        ERR("shouldn't be here!\n");
+        return NULL;
+    default:
+        FIXME("only creating basic node for type %d\n", node->type);
+        pUnk = create_basic_node( node, NULL );
+    }
+
+    hr = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMNode, (LPVOID*)&ret);
+    IUnknown_Release(pUnk);
+    if(FAILED(hr)) return NULL;
+    return ret;
+}
 #endif
Index: dlls/msxml3/tests/domdoc.c
===================================================================
RCS file: /home/wine/wine/dlls/msxml3/tests/domdoc.c,v
retrieving revision 1.13
diff -u -p -r1.13 domdoc.c
--- dlls/msxml3/tests/domdoc.c	23 Nov 2005 13:43:51 -0000	1.13
+++ dlls/msxml3/tests/domdoc.c	1 Dec 2005 15:24:36 -0000
@@ -72,11 +72,6 @@ static const WCHAR szdl[] = { 'd','l',0 
 static const WCHAR szlc[] = { 'l','c',0 };
 static const WCHAR szbs[] = { 'b','s',0 };
 
-const GUID CLSID_DOMDocument = 
-    { 0x2933BF90, 0x7B36, 0x11d2, {0xB2,0x0E,0x00,0xC0,0x4F,0x98,0x3E,0x60}};
-const GUID IID_IXMLDOMDocument = 
-    { 0x2933BF81, 0x7B36, 0x11d2, {0xB2,0x0E,0x00,0xC0,0x4F,0x98,0x3E,0x60}};
-
 void test_domdoc( void )
 {
     HRESULT r;
@@ -516,6 +511,7 @@ static void test_refs(void)
     IXMLDOMNode *node = NULL, *node2;
     IXMLDOMNodeList *node_list = NULL;
     LONG ref;
+    IUnknown *unk, *unk2;
 
     r = CoCreateInstance( &CLSID_DOMDocument, NULL, 
         CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (LPVOID*)&doc );
@@ -576,8 +572,21 @@ static void test_refs(void)
     todo_wine {
     ok( ref == 3, "ref %ld\n", ref );
     }
-
     IXMLDOMElement_Release( element );
+
+    /* IUnknown must be unique however we obtain it */
+    r = IXMLDOMElement_QueryInterface( element, &IID_IUnknown, (LPVOID*)&unk );
+    ok( r == S_OK, "rets %08lx\n", r );
+    r = IXMLDOMElement_QueryInterface( element, &IID_IXMLDOMNode, (LPVOID*)&node );
+    ok( r == S_OK, "rets %08lx\n", r );
+    r = IXMLDOMNode_QueryInterface( node, &IID_IUnknown, (LPVOID*)&unk2 );
+    ok( r == S_OK, "rets %08lx\n", r );
+    ok( unk == unk2, "unk %p unk2 %p\n", unk, unk2 );
+
+    IUnknown_Release( unk2 );
+    IUnknown_Release( unk );
+    IXMLDOMNode_Release( node );
+
     IXMLDOMElement_Release( element );
 
 }



More information about the wine-patches mailing list