[MSXML3]
[reactos.git] / reactos / dll / win32 / msxml3 / mxwriter.c
index 6aad6c6..511f45f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *    MXWriter implementation
  *
- * Copyright 2011-2013 Nikolay Sivov for CodeWeavers
+ * Copyright 2011-2014 Nikolay Sivov for CodeWeavers
  * Copyright 2011 Thomas Mullaly
  *
  * This library is free software; you can redistribute it and/or
@@ -122,6 +122,13 @@ typedef struct
     ISAXContentHandler ISAXContentHandler_iface;
     ISAXLexicalHandler ISAXLexicalHandler_iface;
     ISAXDeclHandler    ISAXDeclHandler_iface;
+    ISAXDTDHandler     ISAXDTDHandler_iface;
+    ISAXErrorHandler   ISAXErrorHandler_iface;
+    IVBSAXDeclHandler  IVBSAXDeclHandler_iface;
+    IVBSAXLexicalHandler IVBSAXLexicalHandler_iface;
+    IVBSAXContentHandler IVBSAXContentHandler_iface;
+    IVBSAXDTDHandler     IVBSAXDTDHandler_iface;
+    IVBSAXErrorHandler   IVBSAXErrorHandler_iface;
 
     LONG ref;
     MSXML_VERSION class_version;
@@ -373,11 +380,14 @@ static void close_output_buffer(mxwriter *This)
     get_code_page(This->xml_enc, &This->buffer->code_page);
 }
 
-/* escapes special characters like:
+/* Escapes special characters like:
    '<' -> "&lt;"
    '&' -> "&amp;"
    '"' -> "&quot;"
    '>' -> "&gt;"
+
+   On call 'len' contains a length of 'str' in chars or -1 if it's null terminated.
+   After a call it's updated with actual new length if it wasn't -1 initially.
 */
 static WCHAR *get_escaped_string(const WCHAR *str, escape_mode mode, int *len)
 {
@@ -609,16 +619,51 @@ static inline mxwriter *impl_from_ISAXContentHandler(ISAXContentHandler *iface)
     return CONTAINING_RECORD(iface, mxwriter, ISAXContentHandler_iface);
 }
 
+static inline mxwriter *impl_from_IVBSAXContentHandler(IVBSAXContentHandler *iface)
+{
+    return CONTAINING_RECORD(iface, mxwriter, IVBSAXContentHandler_iface);
+}
+
 static inline mxwriter *impl_from_ISAXLexicalHandler(ISAXLexicalHandler *iface)
 {
     return CONTAINING_RECORD(iface, mxwriter, ISAXLexicalHandler_iface);
 }
 
+static inline mxwriter *impl_from_IVBSAXLexicalHandler(IVBSAXLexicalHandler *iface)
+{
+    return CONTAINING_RECORD(iface, mxwriter, IVBSAXLexicalHandler_iface);
+}
+
 static inline mxwriter *impl_from_ISAXDeclHandler(ISAXDeclHandler *iface)
 {
     return CONTAINING_RECORD(iface, mxwriter, ISAXDeclHandler_iface);
 }
 
+static inline mxwriter *impl_from_IVBSAXDeclHandler(IVBSAXDeclHandler *iface)
+{
+    return CONTAINING_RECORD(iface, mxwriter, IVBSAXDeclHandler_iface);
+}
+
+static inline mxwriter *impl_from_ISAXDTDHandler(ISAXDTDHandler *iface)
+{
+    return CONTAINING_RECORD(iface, mxwriter, ISAXDTDHandler_iface);
+}
+
+static inline mxwriter *impl_from_IVBSAXDTDHandler(IVBSAXDTDHandler *iface)
+{
+    return CONTAINING_RECORD(iface, mxwriter, IVBSAXDTDHandler_iface);
+}
+
+static inline mxwriter *impl_from_ISAXErrorHandler(ISAXErrorHandler *iface)
+{
+    return CONTAINING_RECORD(iface, mxwriter, ISAXErrorHandler_iface);
+}
+
+static inline mxwriter *impl_from_IVBSAXErrorHandler(IVBSAXErrorHandler *iface)
+{
+    return CONTAINING_RECORD(iface, mxwriter, IVBSAXErrorHandler_iface);
+}
+
 static HRESULT WINAPI mxwriter_QueryInterface(IMXWriter *iface, REFIID riid, void **obj)
 {
     mxwriter *This = impl_from_IMXWriter( iface );
@@ -645,6 +690,34 @@ static HRESULT WINAPI mxwriter_QueryInterface(IMXWriter *iface, REFIID riid, voi
     {
         *obj = &This->ISAXDeclHandler_iface;
     }
+    else if ( IsEqualGUID( riid, &IID_ISAXDTDHandler ) )
+    {
+        *obj = &This->ISAXDTDHandler_iface;
+    }
+    else if ( IsEqualGUID( riid, &IID_ISAXErrorHandler ) )
+    {
+        *obj = &This->ISAXErrorHandler_iface;
+    }
+    else if ( IsEqualGUID( riid, &IID_IVBSAXDeclHandler ) )
+    {
+        *obj = &This->IVBSAXDeclHandler_iface;
+    }
+    else if ( IsEqualGUID( riid, &IID_IVBSAXLexicalHandler ) )
+    {
+        *obj = &This->IVBSAXLexicalHandler_iface;
+    }
+    else if ( IsEqualGUID( riid, &IID_IVBSAXContentHandler ) )
+    {
+        *obj = &This->IVBSAXContentHandler_iface;
+    }
+    else if ( IsEqualGUID( riid, &IID_IVBSAXDTDHandler ) )
+    {
+        *obj = &This->IVBSAXDTDHandler_iface;
+    }
+    else if ( IsEqualGUID( riid, &IID_IVBSAXErrorHandler ) )
+    {
+        *obj = &This->IVBSAXErrorHandler_iface;
+    }
     else if (dispex_query_interface(&This->dispex, riid, obj))
     {
         return *obj ? S_OK : E_NOINTERFACE;
@@ -688,7 +761,6 @@ static ULONG WINAPI mxwriter_Release(IMXWriter *iface)
         SysFreeString(This->encoding);
 
         SysFreeString(This->element);
-        release_dispex(&This->dispex);
         heap_free(This);
     }
 
@@ -1067,8 +1139,8 @@ static HRESULT WINAPI SAXContentHandler_startPrefixMapping(
     int nuri)
 {
     mxwriter *This = impl_from_ISAXContentHandler( iface );
-    FIXME("(%p)->(%s %s)\n", This, debugstr_wn(prefix, nprefix), debugstr_wn(uri, nuri));
-    return E_NOTIMPL;
+    TRACE("(%p)->(%s %s)\n", This, debugstr_wn(prefix, nprefix), debugstr_wn(uri, nuri));
+    return S_OK;
 }
 
 static HRESULT WINAPI SAXContentHandler_endPrefixMapping(
@@ -1077,8 +1149,42 @@ static HRESULT WINAPI SAXContentHandler_endPrefixMapping(
     int nprefix)
 {
     mxwriter *This = impl_from_ISAXContentHandler( iface );
-    FIXME("(%p)->(%s)\n", This, debugstr_wn(prefix, nprefix));
-    return E_NOTIMPL;
+    TRACE("(%p)->(%s)\n", This, debugstr_wn(prefix, nprefix));
+    return S_OK;
+}
+
+static void mxwriter_write_attribute(mxwriter *writer, const WCHAR *qname, int qname_len,
+    const WCHAR *value, int value_len, BOOL escape)
+{
+    static const WCHAR eqW[] = {'='};
+
+    /* space separator in front of every attribute */
+    write_output_buffer(writer->buffer, spaceW, 1);
+    write_output_buffer(writer->buffer, qname, qname_len);
+    write_output_buffer(writer->buffer, eqW, 1);
+
+    if (escape)
+    {
+        WCHAR *escaped = get_escaped_string(value, EscapeValue, &value_len);
+        write_output_buffer_quoted(writer->buffer, escaped, value_len);
+        heap_free(escaped);
+    }
+    else
+        write_output_buffer_quoted(writer->buffer, value, value_len);
+}
+
+static void mxwriter_write_starttag(mxwriter *writer, const WCHAR *qname, int len)
+{
+    static const WCHAR ltW[] = {'<'};
+
+    close_element_starttag(writer);
+    set_element_name(writer, qname ? qname : emptyW, qname ? len : 0);
+
+    write_node_indent(writer);
+
+    write_output_buffer(writer->buffer, ltW, 1);
+    write_output_buffer(writer->buffer, qname ? qname : emptyW, qname ? len : 0);
+    writer_inc_indent(writer);
 }
 
 static HRESULT WINAPI SAXContentHandler_startElement(
@@ -1092,7 +1198,6 @@ static HRESULT WINAPI SAXContentHandler_startElement(
     ISAXAttributes *attr)
 {
     mxwriter *This = impl_from_ISAXContentHandler( iface );
-    static const WCHAR ltW[] = {'<'};
 
     TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_wn(namespaceUri, nnamespaceUri),
         debugstr_wn(local_name, nlocal_name), debugstr_wn(QName, nQName), attr);
@@ -1101,15 +1206,7 @@ static HRESULT WINAPI SAXContentHandler_startElement(
         (nQName == -1 && This->class_version == MSXML6))
         return E_INVALIDARG;
 
-    close_element_starttag(This);
-    set_element_name(This, QName ? QName  : emptyW,
-                           QName ? nQName : 0);
-
-    write_node_indent(This);
-
-    write_output_buffer(This->buffer, ltW, 1);
-    write_output_buffer(This->buffer, QName, nQName);
-    writer_inc_indent(This);
+    mxwriter_write_starttag(This, QName, nQName);
 
     if (attr)
     {
@@ -1124,31 +1221,16 @@ static HRESULT WINAPI SAXContentHandler_startElement(
 
         for (i = 0; i < length; i++)
         {
-            static const WCHAR eqW[] = {'='};
-            const WCHAR *str;
-            int len = 0;
+            int qname_len = 0, value_len = 0;
+            const WCHAR *qname, *value;
 
-            hr = ISAXAttributes_getQName(attr, i, &str, &len);
+            hr = ISAXAttributes_getQName(attr, i, &qname, &qname_len);
             if (FAILED(hr)) return hr;
 
-            /* space separator in front of every attribute */
-            write_output_buffer(This->buffer, spaceW, 1);
-            write_output_buffer(This->buffer, str, len);
-
-            write_output_buffer(This->buffer, eqW, 1);
-
-            len = 0;
-            hr = ISAXAttributes_getValue(attr, i, &str, &len);
+            hr = ISAXAttributes_getValue(attr, i, &value, &value_len);
             if (FAILED(hr)) return hr;
 
-            if (escape)
-            {
-                WCHAR *escaped = get_escaped_string(str, EscapeValue, &len);
-                write_output_buffer_quoted(This->buffer, escaped, len);
-                heap_free(escaped);
-            }
-            else
-                write_output_buffer_quoted(This->buffer, str, len);
+            mxwriter_write_attribute(This, qname, qname_len, value, value_len, escape);
         }
     }
 
@@ -1628,6 +1710,743 @@ static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl = {
     SAXDeclHandler_externalEntityDecl
 };
 
+/*** IVBSAXDeclHandler ***/
+static HRESULT WINAPI VBSAXDeclHandler_QueryInterface(IVBSAXDeclHandler *iface,
+    REFIID riid, void **obj)
+{
+    mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
+    return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
+}
+
+static ULONG WINAPI VBSAXDeclHandler_AddRef(IVBSAXDeclHandler *iface)
+{
+    mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
+    return IMXWriter_AddRef(&This->IMXWriter_iface);
+}
+
+static ULONG WINAPI VBSAXDeclHandler_Release(IVBSAXDeclHandler *iface)
+{
+    mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
+    return IMXWriter_Release(&This->IMXWriter_iface);
+}
+
+static HRESULT WINAPI VBSAXDeclHandler_GetTypeInfoCount(IVBSAXDeclHandler *iface, UINT* pctinfo)
+{
+    mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
+    return IMXWriter_GetTypeInfoCount(&This->IMXWriter_iface, pctinfo);
+}
+
+static HRESULT WINAPI VBSAXDeclHandler_GetTypeInfo(IVBSAXDeclHandler *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
+{
+    mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
+    return IMXWriter_GetTypeInfo(&This->IMXWriter_iface, iTInfo, lcid, ppTInfo);
+}
+
+static HRESULT WINAPI VBSAXDeclHandler_GetIDsOfNames(IVBSAXDeclHandler *iface, REFIID riid, LPOLESTR* rgszNames,
+    UINT cNames, LCID lcid, DISPID* rgDispId )
+{
+    mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
+    return IMXWriter_GetIDsOfNames(&This->IMXWriter_iface, riid, rgszNames, cNames, lcid, rgDispId);
+}
+
+static HRESULT WINAPI VBSAXDeclHandler_Invoke(IVBSAXDeclHandler *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
+    WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr )
+{
+    mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
+    return IMXWriter_Invoke(&This->IMXWriter_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult,
+        pExcepInfo, puArgErr);
+}
+
+static HRESULT WINAPI VBSAXDeclHandler_elementDecl(IVBSAXDeclHandler *iface, BSTR *name, BSTR *model)
+{
+    mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
+
+    TRACE("(%p)->(%p %p)\n", This, name, model);
+
+    if (!name || !model)
+        return E_POINTER;
+
+    return ISAXDeclHandler_elementDecl(&This->ISAXDeclHandler_iface, *name, -1, *model, -1);
+}
+
+static HRESULT WINAPI VBSAXDeclHandler_attributeDecl(IVBSAXDeclHandler *iface,
+    BSTR *element, BSTR *attr, BSTR *type, BSTR *default_value, BSTR *value)
+{
+    mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
+
+    TRACE("(%p)->(%p %p %p %p %p)\n", This, element, attr, type, default_value, value);
+
+    if (!element || !attr || !type || !default_value || !value)
+        return E_POINTER;
+
+    return ISAXDeclHandler_attributeDecl(&This->ISAXDeclHandler_iface, *element, -1, *attr, -1, *type, -1,
+        *default_value, -1, *value, -1);
+}
+
+static HRESULT WINAPI VBSAXDeclHandler_internalEntityDecl(IVBSAXDeclHandler *iface, BSTR *name, BSTR *value)
+{
+    mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
+
+    TRACE("(%p)->(%p %p)\n", This, name, value);
+
+    if (!name || !value)
+        return E_POINTER;
+
+    return ISAXDeclHandler_internalEntityDecl(&This->ISAXDeclHandler_iface, *name, -1, *value, -1);
+}
+
+static HRESULT WINAPI VBSAXDeclHandler_externalEntityDecl(IVBSAXDeclHandler *iface,
+    BSTR *name, BSTR *publicid, BSTR *systemid)
+{
+    mxwriter *This = impl_from_IVBSAXDeclHandler( iface );
+
+    TRACE("(%p)->(%p %p %p)\n", This, name, publicid, systemid);
+
+    if (!name || !publicid || !systemid)
+        return E_POINTER;
+
+    return ISAXDeclHandler_externalEntityDecl(&This->ISAXDeclHandler_iface, *name, -1, *publicid, -1, *systemid, -1);
+}
+
+static const IVBSAXDeclHandlerVtbl VBSAXDeclHandlerVtbl = {
+    VBSAXDeclHandler_QueryInterface,
+    VBSAXDeclHandler_AddRef,
+    VBSAXDeclHandler_Release,
+    VBSAXDeclHandler_GetTypeInfoCount,
+    VBSAXDeclHandler_GetTypeInfo,
+    VBSAXDeclHandler_GetIDsOfNames,
+    VBSAXDeclHandler_Invoke,
+    VBSAXDeclHandler_elementDecl,
+    VBSAXDeclHandler_attributeDecl,
+    VBSAXDeclHandler_internalEntityDecl,
+    VBSAXDeclHandler_externalEntityDecl
+};
+
+/*** IVBSAXLexicalHandler ***/
+static HRESULT WINAPI VBSAXLexicalHandler_QueryInterface(IVBSAXLexicalHandler *iface,
+    REFIID riid, void **obj)
+{
+    mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
+    return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
+}
+
+static ULONG WINAPI VBSAXLexicalHandler_AddRef(IVBSAXLexicalHandler *iface)
+{
+    mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
+    return IMXWriter_AddRef(&This->IMXWriter_iface);
+}
+
+static ULONG WINAPI VBSAXLexicalHandler_Release(IVBSAXLexicalHandler *iface)
+{
+    mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
+    return IMXWriter_Release(&This->IMXWriter_iface);
+}
+
+static HRESULT WINAPI VBSAXLexicalHandler_GetTypeInfoCount(IVBSAXLexicalHandler *iface, UINT* pctinfo)
+{
+    mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
+    return IMXWriter_GetTypeInfoCount(&This->IMXWriter_iface, pctinfo);
+}
+
+static HRESULT WINAPI VBSAXLexicalHandler_GetTypeInfo(IVBSAXLexicalHandler *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
+{
+    mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
+    return IMXWriter_GetTypeInfo(&This->IMXWriter_iface, iTInfo, lcid, ppTInfo);
+}
+
+static HRESULT WINAPI VBSAXLexicalHandler_GetIDsOfNames(IVBSAXLexicalHandler *iface, REFIID riid, LPOLESTR* rgszNames,
+    UINT cNames, LCID lcid, DISPID* rgDispId )
+{
+    mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
+    return IMXWriter_GetIDsOfNames(&This->IMXWriter_iface, riid, rgszNames, cNames, lcid, rgDispId);
+}
+
+static HRESULT WINAPI VBSAXLexicalHandler_Invoke(IVBSAXLexicalHandler *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
+    WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr )
+{
+    mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
+    return IMXWriter_Invoke(&This->IMXWriter_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult,
+        pExcepInfo, puArgErr);
+}
+
+static HRESULT WINAPI VBSAXLexicalHandler_startDTD(IVBSAXLexicalHandler *iface, BSTR *name, BSTR *publicId, BSTR *systemId)
+{
+    mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
+
+    TRACE("(%p)->(%p %p %p)\n", This, name, publicId, systemId);
+
+    if (!name || !publicId || !systemId)
+        return E_POINTER;
+
+    return ISAXLexicalHandler_startDTD(&This->ISAXLexicalHandler_iface, *name, -1, *publicId, -1, *systemId, -1);
+}
+
+static HRESULT WINAPI VBSAXLexicalHandler_endDTD(IVBSAXLexicalHandler *iface)
+{
+    mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
+    return ISAXLexicalHandler_endDTD(&This->ISAXLexicalHandler_iface);
+}
+
+static HRESULT WINAPI VBSAXLexicalHandler_startEntity(IVBSAXLexicalHandler *iface, BSTR *name)
+{
+    mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
+
+    TRACE("(%p)->(%p)\n", This, name);
+
+    if (!name)
+        return E_POINTER;
+
+    return ISAXLexicalHandler_startEntity(&This->ISAXLexicalHandler_iface, *name, -1);
+}
+
+static HRESULT WINAPI VBSAXLexicalHandler_endEntity(IVBSAXLexicalHandler *iface, BSTR *name)
+{
+    mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
+
+    TRACE("(%p)->(%p)\n", This, name);
+
+    if (!name)
+        return E_POINTER;
+
+    return ISAXLexicalHandler_endEntity(&This->ISAXLexicalHandler_iface, *name, -1);
+}
+
+static HRESULT WINAPI VBSAXLexicalHandler_startCDATA(IVBSAXLexicalHandler *iface)
+{
+    mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
+    return ISAXLexicalHandler_startCDATA(&This->ISAXLexicalHandler_iface);
+}
+
+static HRESULT WINAPI VBSAXLexicalHandler_endCDATA(IVBSAXLexicalHandler *iface)
+{
+    mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
+    return ISAXLexicalHandler_endCDATA(&This->ISAXLexicalHandler_iface);
+}
+
+static HRESULT WINAPI VBSAXLexicalHandler_comment(IVBSAXLexicalHandler *iface, BSTR *chars)
+{
+    mxwriter *This = impl_from_IVBSAXLexicalHandler( iface );
+
+    TRACE("(%p)->(%p)\n", This, chars);
+
+    if (!chars)
+        return E_POINTER;
+
+    return ISAXLexicalHandler_comment(&This->ISAXLexicalHandler_iface, *chars, -1);
+}
+
+static const IVBSAXLexicalHandlerVtbl VBSAXLexicalHandlerVtbl = {
+    VBSAXLexicalHandler_QueryInterface,
+    VBSAXLexicalHandler_AddRef,
+    VBSAXLexicalHandler_Release,
+    VBSAXLexicalHandler_GetTypeInfoCount,
+    VBSAXLexicalHandler_GetTypeInfo,
+    VBSAXLexicalHandler_GetIDsOfNames,
+    VBSAXLexicalHandler_Invoke,
+    VBSAXLexicalHandler_startDTD,
+    VBSAXLexicalHandler_endDTD,
+    VBSAXLexicalHandler_startEntity,
+    VBSAXLexicalHandler_endEntity,
+    VBSAXLexicalHandler_startCDATA,
+    VBSAXLexicalHandler_endCDATA,
+    VBSAXLexicalHandler_comment
+};
+
+/*** IVBSAXContentHandler ***/
+static HRESULT WINAPI VBSAXContentHandler_QueryInterface(IVBSAXContentHandler *iface, REFIID riid, void **obj)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+    return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
+}
+
+static ULONG WINAPI VBSAXContentHandler_AddRef(IVBSAXContentHandler *iface)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+    return IMXWriter_AddRef(&This->IMXWriter_iface);
+}
+
+static ULONG WINAPI VBSAXContentHandler_Release(IVBSAXContentHandler *iface)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+    return IMXWriter_Release(&This->IMXWriter_iface);
+}
+
+static HRESULT WINAPI VBSAXContentHandler_GetTypeInfoCount(IVBSAXContentHandler *iface, UINT* pctinfo)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+    return IMXWriter_GetTypeInfoCount(&This->IMXWriter_iface, pctinfo);
+}
+
+static HRESULT WINAPI VBSAXContentHandler_GetTypeInfo(IVBSAXContentHandler *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+    return IMXWriter_GetTypeInfo(&This->IMXWriter_iface, iTInfo, lcid, ppTInfo);
+}
+
+static HRESULT WINAPI VBSAXContentHandler_GetIDsOfNames(IVBSAXContentHandler *iface, REFIID riid, LPOLESTR* rgszNames,
+    UINT cNames, LCID lcid, DISPID* rgDispId )
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+    return IMXWriter_GetIDsOfNames(&This->IMXWriter_iface, riid, rgszNames, cNames, lcid, rgDispId);
+}
+
+static HRESULT WINAPI VBSAXContentHandler_Invoke(IVBSAXContentHandler *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
+    WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr )
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+    return IMXWriter_Invoke(&This->IMXWriter_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult,
+        pExcepInfo, puArgErr);
+}
+
+static HRESULT WINAPI VBSAXContentHandler_putref_documentLocator(IVBSAXContentHandler *iface, IVBSAXLocator *locator)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+    TRACE("(%p)->(%p)\n", This, locator);
+    return S_OK;
+}
+
+static HRESULT WINAPI VBSAXContentHandler_startDocument(IVBSAXContentHandler *iface)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+    return ISAXContentHandler_startDocument(&This->ISAXContentHandler_iface);
+}
+
+static HRESULT WINAPI VBSAXContentHandler_endDocument(IVBSAXContentHandler *iface)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+    return ISAXContentHandler_endDocument(&This->ISAXContentHandler_iface);
+}
+
+static HRESULT WINAPI VBSAXContentHandler_startPrefixMapping(IVBSAXContentHandler *iface, BSTR *prefix, BSTR *uri)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+
+    TRACE("(%p)->(%p %p)\n", This, prefix, uri);
+
+    if (!prefix || !uri)
+        return E_POINTER;
+
+    return ISAXContentHandler_startPrefixMapping(&This->ISAXContentHandler_iface, *prefix, -1, *uri, -1);
+}
+
+static HRESULT WINAPI VBSAXContentHandler_endPrefixMapping(IVBSAXContentHandler *iface, BSTR *prefix)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+
+    TRACE("(%p)->(%p)\n", This, prefix);
+
+    if (!prefix)
+        return E_POINTER;
+
+    return ISAXContentHandler_endPrefixMapping(&This->ISAXContentHandler_iface, *prefix, -1);
+}
+
+static HRESULT WINAPI VBSAXContentHandler_startElement(IVBSAXContentHandler *iface,
+    BSTR *namespaceURI, BSTR *localName, BSTR *QName, IVBSAXAttributes *attrs)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+
+    TRACE("(%p)->(%p %p %p %p)\n", This, namespaceURI, localName, QName, attrs);
+
+    if (!namespaceURI || !localName || !QName)
+        return E_POINTER;
+
+    TRACE("(%s %s %s)\n", debugstr_w(*namespaceURI), debugstr_w(*localName), debugstr_w(*QName));
+
+    mxwriter_write_starttag(This, *QName, SysStringLen(*QName));
+
+    if (attrs)
+    {
+        int length, i, escape;
+        HRESULT hr;
+
+        hr = IVBSAXAttributes_get_length(attrs, &length);
+        if (FAILED(hr)) return hr;
+
+        escape = This->props[MXWriter_DisableEscaping] == VARIANT_FALSE ||
+            (This->class_version == MSXML4 || This->class_version == MSXML6);
+
+        for (i = 0; i < length; i++)
+        {
+            BSTR qname, value;
+
+            hr = IVBSAXAttributes_getQName(attrs, i, &qname);
+            if (FAILED(hr)) return hr;
+
+            hr = IVBSAXAttributes_getValue(attrs, i, &value);
+            if (FAILED(hr))
+            {
+                SysFreeString(qname);
+                return hr;
+            }
+
+            mxwriter_write_attribute(This, qname, SysStringLen(qname), value, SysStringLen(value), escape);
+            SysFreeString(qname);
+            SysFreeString(value);
+        }
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI VBSAXContentHandler_endElement(IVBSAXContentHandler *iface, BSTR *namespaceURI,
+    BSTR *localName, BSTR *QName)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+
+    TRACE("(%p)->(%p %p %p)\n", This, namespaceURI, localName, QName);
+
+    if (!namespaceURI || !localName || !QName)
+        return E_POINTER;
+
+    return ISAXContentHandler_endElement(&This->ISAXContentHandler_iface,
+        *namespaceURI, SysStringLen(*namespaceURI),
+        *localName, SysStringLen(*localName),
+        *QName, SysStringLen(*QName));
+}
+
+static HRESULT WINAPI VBSAXContentHandler_characters(IVBSAXContentHandler *iface, BSTR *chars)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+
+    TRACE("(%p)->(%p)\n", This, chars);
+
+    if (!chars)
+        return E_POINTER;
+
+    return ISAXContentHandler_characters(&This->ISAXContentHandler_iface, *chars, -1);
+}
+
+static HRESULT WINAPI VBSAXContentHandler_ignorableWhitespace(IVBSAXContentHandler *iface, BSTR *chars)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+
+    TRACE("(%p)->(%p)\n", This, chars);
+
+    if (!chars)
+        return E_POINTER;
+
+    return ISAXContentHandler_ignorableWhitespace(&This->ISAXContentHandler_iface, *chars, -1);
+}
+
+static HRESULT WINAPI VBSAXContentHandler_processingInstruction(IVBSAXContentHandler *iface,
+    BSTR *target, BSTR *data)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+
+    TRACE("(%p)->(%p %p)\n", This, target, data);
+
+    if (!target || !data)
+        return E_POINTER;
+
+    return ISAXContentHandler_processingInstruction(&This->ISAXContentHandler_iface, *target, -1, *data, -1);
+}
+
+static HRESULT WINAPI VBSAXContentHandler_skippedEntity(IVBSAXContentHandler *iface, BSTR *name)
+{
+    mxwriter *This = impl_from_IVBSAXContentHandler( iface );
+
+    TRACE("(%p)->(%p)\n", This, name);
+
+    if (!name)
+        return E_POINTER;
+
+    return ISAXContentHandler_skippedEntity(&This->ISAXContentHandler_iface, *name, -1);
+}
+
+static const IVBSAXContentHandlerVtbl VBSAXContentHandlerVtbl = {
+    VBSAXContentHandler_QueryInterface,
+    VBSAXContentHandler_AddRef,
+    VBSAXContentHandler_Release,
+    VBSAXContentHandler_GetTypeInfoCount,
+    VBSAXContentHandler_GetTypeInfo,
+    VBSAXContentHandler_GetIDsOfNames,
+    VBSAXContentHandler_Invoke,
+    VBSAXContentHandler_putref_documentLocator,
+    VBSAXContentHandler_startDocument,
+    VBSAXContentHandler_endDocument,
+    VBSAXContentHandler_startPrefixMapping,
+    VBSAXContentHandler_endPrefixMapping,
+    VBSAXContentHandler_startElement,
+    VBSAXContentHandler_endElement,
+    VBSAXContentHandler_characters,
+    VBSAXContentHandler_ignorableWhitespace,
+    VBSAXContentHandler_processingInstruction,
+    VBSAXContentHandler_skippedEntity
+};
+
+static HRESULT WINAPI SAXDTDHandler_QueryInterface(ISAXDTDHandler *iface, REFIID riid, void **obj)
+{
+    mxwriter *This = impl_from_ISAXDTDHandler( iface );
+    return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
+}
+
+static ULONG WINAPI SAXDTDHandler_AddRef(ISAXDTDHandler *iface)
+{
+    mxwriter *This = impl_from_ISAXDTDHandler( iface );
+    return IMXWriter_AddRef(&This->IMXWriter_iface);
+}
+
+static ULONG WINAPI SAXDTDHandler_Release(ISAXDTDHandler *iface)
+{
+    mxwriter *This = impl_from_ISAXDTDHandler( iface );
+    return IMXWriter_Release(&This->IMXWriter_iface);
+}
+
+static HRESULT WINAPI SAXDTDHandler_notationDecl(ISAXDTDHandler *iface,
+    const WCHAR *name, INT nname,
+    const WCHAR *publicid, INT npublicid,
+    const WCHAR *systemid, INT nsystemid)
+{
+    mxwriter *This = impl_from_ISAXDTDHandler( iface );
+    FIXME("(%p)->(%s:%d, %s:%d, %s:%d): stub\n", This, debugstr_wn(name, nname), nname,
+        debugstr_wn(publicid, npublicid), npublicid, debugstr_wn(systemid, nsystemid), nsystemid);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAXDTDHandler_unparsedEntityDecl(ISAXDTDHandler *iface,
+    const WCHAR *name, INT nname,
+    const WCHAR *publicid, INT npublicid,
+    const WCHAR *systemid, INT nsystemid,
+    const WCHAR *notation, INT nnotation)
+{
+    mxwriter *This = impl_from_ISAXDTDHandler( iface );
+    FIXME("(%p)->(%s:%d, %s:%d, %s:%d, %s:%d): stub\n", This, debugstr_wn(name, nname), nname,
+        debugstr_wn(publicid, npublicid), npublicid, debugstr_wn(systemid, nsystemid), nsystemid,
+        debugstr_wn(notation, nnotation), nnotation);
+    return E_NOTIMPL;
+}
+
+static const ISAXDTDHandlerVtbl SAXDTDHandlerVtbl = {
+    SAXDTDHandler_QueryInterface,
+    SAXDTDHandler_AddRef,
+    SAXDTDHandler_Release,
+    SAXDTDHandler_notationDecl,
+    SAXDTDHandler_unparsedEntityDecl
+};
+
+/*** IVBSAXDTDHandler ***/
+static HRESULT WINAPI VBSAXDTDHandler_QueryInterface(IVBSAXDTDHandler *iface, REFIID riid, void **obj)
+{
+    mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
+    return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
+}
+
+static ULONG WINAPI VBSAXDTDHandler_AddRef(IVBSAXDTDHandler *iface)
+{
+    mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
+    return IMXWriter_AddRef(&This->IMXWriter_iface);
+}
+
+static ULONG WINAPI VBSAXDTDHandler_Release(IVBSAXDTDHandler *iface)
+{
+    mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
+    return IMXWriter_Release(&This->IMXWriter_iface);
+}
+
+static HRESULT WINAPI VBSAXDTDHandler_GetTypeInfoCount(IVBSAXDTDHandler *iface, UINT* pctinfo)
+{
+    mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
+    return IMXWriter_GetTypeInfoCount(&This->IMXWriter_iface, pctinfo);
+}
+
+static HRESULT WINAPI VBSAXDTDHandler_GetTypeInfo(IVBSAXDTDHandler *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
+{
+    mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
+    return IMXWriter_GetTypeInfo(&This->IMXWriter_iface, iTInfo, lcid, ppTInfo);
+}
+
+static HRESULT WINAPI VBSAXDTDHandler_GetIDsOfNames(IVBSAXDTDHandler *iface, REFIID riid, LPOLESTR* rgszNames,
+    UINT cNames, LCID lcid, DISPID* rgDispId )
+{
+    mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
+    return IMXWriter_GetIDsOfNames(&This->IMXWriter_iface, riid, rgszNames, cNames, lcid, rgDispId);
+}
+
+static HRESULT WINAPI VBSAXDTDHandler_Invoke(IVBSAXDTDHandler *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
+    WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr )
+{
+    mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
+    return IMXWriter_Invoke(&This->IMXWriter_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult,
+        pExcepInfo, puArgErr);
+}
+
+static HRESULT WINAPI VBSAXDTDHandler_notationDecl(IVBSAXDTDHandler *iface, BSTR *name, BSTR *publicId, BSTR *systemId)
+{
+    mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
+
+    TRACE("(%p)->(%p %p %p)\n", This, name, publicId, systemId);
+
+    if (!name || !publicId || !systemId)
+        return E_POINTER;
+
+    return ISAXDTDHandler_notationDecl(&This->ISAXDTDHandler_iface, *name, -1, *publicId, -1, *systemId, -1);
+}
+
+static HRESULT WINAPI VBSAXDTDHandler_unparsedEntityDecl(IVBSAXDTDHandler *iface, BSTR *name, BSTR *publicId,
+    BSTR *systemId, BSTR *notation)
+{
+    mxwriter *This = impl_from_IVBSAXDTDHandler( iface );
+
+    TRACE("(%p)->(%p %p %p %p)\n", This, name, publicId, systemId, notation);
+
+    if (!name || !publicId || !systemId || !notation)
+        return E_POINTER;
+
+    return ISAXDTDHandler_unparsedEntityDecl(&This->ISAXDTDHandler_iface, *name, -1, *publicId, -1,
+        *systemId, -1, *notation, -1);
+}
+
+static const IVBSAXDTDHandlerVtbl VBSAXDTDHandlerVtbl = {
+    VBSAXDTDHandler_QueryInterface,
+    VBSAXDTDHandler_AddRef,
+    VBSAXDTDHandler_Release,
+    VBSAXDTDHandler_GetTypeInfoCount,
+    VBSAXDTDHandler_GetTypeInfo,
+    VBSAXDTDHandler_GetIDsOfNames,
+    VBSAXDTDHandler_Invoke,
+    VBSAXDTDHandler_notationDecl,
+    VBSAXDTDHandler_unparsedEntityDecl
+};
+
+/* ISAXErrorHandler */
+static HRESULT WINAPI SAXErrorHandler_QueryInterface(ISAXErrorHandler *iface, REFIID riid, void **obj)
+{
+    mxwriter *This = impl_from_ISAXErrorHandler( iface );
+    return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
+}
+
+static ULONG WINAPI SAXErrorHandler_AddRef(ISAXErrorHandler *iface)
+{
+    mxwriter *This = impl_from_ISAXErrorHandler( iface );
+    return IMXWriter_AddRef(&This->IMXWriter_iface);
+}
+
+static ULONG WINAPI SAXErrorHandler_Release(ISAXErrorHandler *iface)
+{
+    mxwriter *This = impl_from_ISAXErrorHandler( iface );
+    return IMXWriter_Release(&This->IMXWriter_iface);
+}
+
+static HRESULT WINAPI SAXErrorHandler_error(ISAXErrorHandler *iface,
+    ISAXLocator *locator, const WCHAR *message, HRESULT hr)
+{
+    mxwriter *This = impl_from_ISAXErrorHandler( iface );
+
+    FIXME("(%p)->(%p %s 0x%08x)\n", This, locator, debugstr_w(message), hr);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAXErrorHandler_fatalError(ISAXErrorHandler *iface,
+    ISAXLocator *locator, const WCHAR *message, HRESULT hr)
+{
+    mxwriter *This = impl_from_ISAXErrorHandler( iface );
+
+    FIXME("(%p)->(%p %s 0x%08x)\n", This, locator, debugstr_w(message), hr);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SAXErrorHandler_ignorableWarning(ISAXErrorHandler *iface,
+    ISAXLocator *locator, const WCHAR *message, HRESULT hr)
+{
+    mxwriter *This = impl_from_ISAXErrorHandler( iface );
+
+    FIXME("(%p)->(%p %s 0x%08x)\n", This, locator, debugstr_w(message), hr);
+
+    return E_NOTIMPL;
+}
+
+static const ISAXErrorHandlerVtbl SAXErrorHandlerVtbl = {
+    SAXErrorHandler_QueryInterface,
+    SAXErrorHandler_AddRef,
+    SAXErrorHandler_Release,
+    SAXErrorHandler_error,
+    SAXErrorHandler_fatalError,
+    SAXErrorHandler_ignorableWarning
+};
+
+/*** IVBSAXErrorHandler ***/
+static HRESULT WINAPI VBSAXErrorHandler_QueryInterface(IVBSAXErrorHandler *iface, REFIID riid, void **obj)
+{
+    mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
+    return IMXWriter_QueryInterface(&This->IMXWriter_iface, riid, obj);
+}
+
+static ULONG WINAPI VBSAXErrorHandler_AddRef(IVBSAXErrorHandler *iface)
+{
+    mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
+    return IMXWriter_AddRef(&This->IMXWriter_iface);
+}
+
+static ULONG WINAPI VBSAXErrorHandler_Release(IVBSAXErrorHandler *iface)
+{
+    mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
+    return IMXWriter_Release(&This->IMXWriter_iface);
+}
+
+static HRESULT WINAPI VBSAXErrorHandler_GetTypeInfoCount(IVBSAXErrorHandler *iface, UINT* pctinfo)
+{
+    mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
+    return IMXWriter_GetTypeInfoCount(&This->IMXWriter_iface, pctinfo);
+}
+
+static HRESULT WINAPI VBSAXErrorHandler_GetTypeInfo(IVBSAXErrorHandler *iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
+{
+    mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
+    return IMXWriter_GetTypeInfo(&This->IMXWriter_iface, iTInfo, lcid, ppTInfo);
+}
+
+static HRESULT WINAPI VBSAXErrorHandler_GetIDsOfNames(IVBSAXErrorHandler *iface, REFIID riid, LPOLESTR* rgszNames,
+    UINT cNames, LCID lcid, DISPID* rgDispId )
+{
+    mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
+    return IMXWriter_GetIDsOfNames(&This->IMXWriter_iface, riid, rgszNames, cNames, lcid, rgDispId);
+}
+
+static HRESULT WINAPI VBSAXErrorHandler_Invoke(IVBSAXErrorHandler *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
+    WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr )
+{
+    mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
+    return IMXWriter_Invoke(&This->IMXWriter_iface, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult,
+        pExcepInfo, puArgErr);
+}
+
+static HRESULT WINAPI VBSAXErrorHandler_error(IVBSAXErrorHandler *iface, IVBSAXLocator *locator, BSTR *message, LONG code)
+{
+    mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
+    FIXME("(%p)->(%p %p %x): stub\n", This, locator, message, code);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI VBSAXErrorHandler_fatalError(IVBSAXErrorHandler *iface, IVBSAXLocator *locator, BSTR *message, LONG code)
+{
+    mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
+    FIXME("(%p)->(%p %p %x): stub\n", This, locator, message, code);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI VBSAXErrorHandler_ignorableWarning(IVBSAXErrorHandler *iface, IVBSAXLocator *locator, BSTR *message, LONG code)
+{
+    mxwriter *This = impl_from_IVBSAXErrorHandler( iface );
+    FIXME("(%p)->(%p %p %x): stub\n", This, locator, message, code);
+    return E_NOTIMPL;
+}
+
+static const IVBSAXErrorHandlerVtbl VBSAXErrorHandlerVtbl = {
+    VBSAXErrorHandler_QueryInterface,
+    VBSAXErrorHandler_AddRef,
+    VBSAXErrorHandler_Release,
+    VBSAXErrorHandler_GetTypeInfoCount,
+    VBSAXErrorHandler_GetTypeInfo,
+    VBSAXErrorHandler_GetIDsOfNames,
+    VBSAXErrorHandler_Invoke,
+    VBSAXErrorHandler_error,
+    VBSAXErrorHandler_fatalError,
+    VBSAXErrorHandler_ignorableWarning
+};
+
 static const tid_t mxwriter_iface_tids[] = {
     IMXWriter_tid,
     0
@@ -1640,15 +2459,13 @@ static dispex_static_data_t mxwriter_dispex = {
     mxwriter_iface_tids
 };
 
-HRESULT MXWriter_create(MSXML_VERSION version, IUnknown *outer, void **ppObj)
+HRESULT MXWriter_create(MSXML_VERSION version, void **ppObj)
 {
     static const WCHAR version10W[] = {'1','.','0',0};
     mxwriter *This;
     HRESULT hr;
 
-    TRACE("(%p, %p)\n", outer, ppObj);
-
-    if (outer) FIXME("support aggregation, outer\n");
+    TRACE("(%p)\n", ppObj);
 
     This = heap_alloc( sizeof (*This) );
     if(!This)
@@ -1658,6 +2475,13 @@ HRESULT MXWriter_create(MSXML_VERSION version, IUnknown *outer, void **ppObj)
     This->ISAXContentHandler_iface.lpVtbl = &SAXContentHandlerVtbl;
     This->ISAXLexicalHandler_iface.lpVtbl = &SAXLexicalHandlerVtbl;
     This->ISAXDeclHandler_iface.lpVtbl = &SAXDeclHandlerVtbl;
+    This->ISAXDTDHandler_iface.lpVtbl = &SAXDTDHandlerVtbl;
+    This->ISAXErrorHandler_iface.lpVtbl = &SAXErrorHandlerVtbl;
+    This->IVBSAXDeclHandler_iface.lpVtbl = &VBSAXDeclHandlerVtbl;
+    This->IVBSAXLexicalHandler_iface.lpVtbl = &VBSAXLexicalHandlerVtbl;
+    This->IVBSAXContentHandler_iface.lpVtbl = &VBSAXContentHandlerVtbl;
+    This->IVBSAXDTDHandler_iface.lpVtbl = &VBSAXDTDHandlerVtbl;
+    This->IVBSAXErrorHandler_iface.lpVtbl = &VBSAXErrorHandlerVtbl;
     This->ref = 1;
     This->class_version = version;
 
@@ -1762,7 +2586,6 @@ static ULONG WINAPI MXAttributes_Release(IMXAttributes *iface)
             SysFreeString(This->attr[i].value);
         }
 
-        release_dispex(&This->dispex);
         heap_free(This->attr);
         heap_free(This);
     }
@@ -2373,25 +3196,61 @@ static HRESULT WINAPI VBSAXAttributes_get_length(IVBSAXAttributes* iface, int *l
 static HRESULT WINAPI VBSAXAttributes_getURI(IVBSAXAttributes* iface, int index, BSTR *uri)
 {
     mxattributes *This = impl_from_IVBSAXAttributes( iface );
+    const WCHAR *uriW;
+    HRESULT hr;
     int len;
 
-    return ISAXAttributes_getURI(&This->ISAXAttributes_iface, index, (const WCHAR**)uri, &len);
+    TRACE("(%p)->(%d %p)\n", This, index, uri);
+
+    if (!uri)
+        return E_POINTER;
+
+    *uri = NULL;
+    hr = ISAXAttributes_getURI(&This->ISAXAttributes_iface, index, &uriW, &len);
+    if (FAILED(hr))
+        return hr;
+
+    return return_bstrn(uriW, len, uri);
 }
 
 static HRESULT WINAPI VBSAXAttributes_getLocalName(IVBSAXAttributes* iface, int index, BSTR *name)
 {
     mxattributes *This = impl_from_IVBSAXAttributes( iface );
+    const WCHAR *nameW;
+    HRESULT hr;
     int len;
 
-    return ISAXAttributes_getLocalName(&This->ISAXAttributes_iface, index, (const WCHAR**)name, &len);
+    TRACE("(%p)->(%d %p)\n", This, index, name);
+
+    if (!name)
+        return E_POINTER;
+
+    *name = NULL;
+    hr = ISAXAttributes_getLocalName(&This->ISAXAttributes_iface, index, &nameW, &len);
+    if (FAILED(hr))
+        return hr;
+
+    return return_bstrn(nameW, len, name);
 }
 
 static HRESULT WINAPI VBSAXAttributes_getQName(IVBSAXAttributes* iface, int index, BSTR *qname)
 {
     mxattributes *This = impl_from_IVBSAXAttributes( iface );
+    const WCHAR *qnameW;
+    HRESULT hr;
     int len;
 
-    return ISAXAttributes_getQName(&This->ISAXAttributes_iface, index, (const WCHAR**)qname, &len);
+    TRACE("(%p)->(%d %p)\n", This, index, qname);
+
+    if (!qname)
+        return E_POINTER;
+
+    *qname = NULL;
+    hr = ISAXAttributes_getQName(&This->ISAXAttributes_iface, index, &qnameW, &len);
+    if (FAILED(hr))
+        return hr;
+
+    return return_bstrn(qnameW, len, qname);
 }
 
 static HRESULT WINAPI VBSAXAttributes_getIndexFromName(IVBSAXAttributes* iface, BSTR uri, BSTR name, int *index)
@@ -2408,58 +3267,130 @@ static HRESULT WINAPI VBSAXAttributes_getIndexFromQName(IVBSAXAttributes* iface,
             SysStringLen(qname), index);
 }
 
-static HRESULT WINAPI VBSAXAttributes_getType(IVBSAXAttributes* iface, int index,BSTR *type)
+static HRESULT WINAPI VBSAXAttributes_getType(IVBSAXAttributes* iface, int index, BSTR *type)
 {
     mxattributes *This = impl_from_IVBSAXAttributes( iface );
+    const WCHAR *typeW;
+    HRESULT hr;
     int len;
 
-    return ISAXAttributes_getType(&This->ISAXAttributes_iface, index, (const WCHAR**)type, &len);
+    TRACE("(%p)->(%d %p)\n", This, index, type);
+
+    if (!type)
+        return E_POINTER;
+
+    *type = NULL;
+    hr = ISAXAttributes_getType(&This->ISAXAttributes_iface, index, &typeW, &len);
+    if (FAILED(hr))
+        return hr;
+
+    return return_bstrn(typeW, len, type);
 }
 
 static HRESULT WINAPI VBSAXAttributes_getTypeFromName(IVBSAXAttributes* iface, BSTR uri,
     BSTR name, BSTR *type)
 {
     mxattributes *This = impl_from_IVBSAXAttributes( iface );
+    const WCHAR *typeW;
+    HRESULT hr;
     int len;
 
-    return ISAXAttributes_getTypeFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
-            name, SysStringLen(name), (const WCHAR**)type, &len);
+    TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(uri), debugstr_w(name), type);
+
+    if (!type)
+        return E_POINTER;
+
+    *type = NULL;
+    hr = ISAXAttributes_getTypeFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
+            name, SysStringLen(name), &typeW, &len);
+    if (FAILED(hr))
+        return hr;
+
+    return return_bstrn(typeW, len, type);
 }
 
 static HRESULT WINAPI VBSAXAttributes_getTypeFromQName(IVBSAXAttributes* iface, BSTR qname, BSTR *type)
 {
     mxattributes *This = impl_from_IVBSAXAttributes( iface );
+    const WCHAR *typeW;
+    HRESULT hr;
     int len;
 
-    return ISAXAttributes_getTypeFromQName(&This->ISAXAttributes_iface, qname, SysStringLen(qname),
-            (const WCHAR**)type, &len);
+    TRACE("(%p)->(%s %p)\n", This, debugstr_w(qname), type);
+
+    if (!type)
+        return E_POINTER;
+
+    *type = NULL;
+    hr = ISAXAttributes_getTypeFromQName(&This->ISAXAttributes_iface, qname, SysStringLen(qname),
+            &typeW, &len);
+    if (FAILED(hr))
+        return hr;
+
+    return return_bstrn(typeW, len, type);
 }
 
 static HRESULT WINAPI VBSAXAttributes_getValue(IVBSAXAttributes* iface, int index, BSTR *value)
 {
     mxattributes *This = impl_from_IVBSAXAttributes( iface );
+    const WCHAR *valueW;
+    HRESULT hr;
     int len;
 
-    return ISAXAttributes_getValue(&This->ISAXAttributes_iface, index, (const WCHAR**)value, &len);
+    TRACE("(%p)->(%d %p)\n", This, index, value);
+
+    if (!value)
+        return E_POINTER;
+
+    *value = NULL;
+    hr = ISAXAttributes_getValue(&This->ISAXAttributes_iface, index, &valueW, &len);
+    if (FAILED(hr))
+        return hr;
+
+    return return_bstrn(valueW, len, value);
 }
 
 static HRESULT WINAPI VBSAXAttributes_getValueFromName(IVBSAXAttributes* iface, BSTR uri, BSTR name,
     BSTR *value)
 {
     mxattributes *This = impl_from_IVBSAXAttributes( iface );
+    const WCHAR *valueW;
+    HRESULT hr;
     int len;
 
-    return ISAXAttributes_getValueFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
-            name, SysStringLen(name), (const WCHAR**)value, &len);
+    TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(uri), debugstr_w(name), value);
+
+    if (!value)
+        return E_POINTER;
+
+    *value = NULL;
+    hr = ISAXAttributes_getValueFromName(&This->ISAXAttributes_iface, uri, SysStringLen(uri),
+            name, SysStringLen(name), &valueW, &len);
+    if (FAILED(hr))
+        return hr;
+
+    return return_bstrn(valueW, len, value);
 }
 
 static HRESULT WINAPI VBSAXAttributes_getValueFromQName(IVBSAXAttributes* iface, BSTR qname, BSTR *value)
 {
     mxattributes *This = impl_from_IVBSAXAttributes( iface );
+    const WCHAR *valueW;
+    HRESULT hr;
     int len;
 
-    return ISAXAttributes_getValueFromQName(&This->ISAXAttributes_iface, qname, SysStringLen(qname),
-        (const WCHAR**)value, &len);
+    TRACE("(%p)->(%s %p)\n", This, debugstr_w(qname), value);
+
+    if (!value)
+        return E_POINTER;
+
+    *value = NULL;
+    hr = ISAXAttributes_getValueFromQName(&This->ISAXAttributes_iface, qname, SysStringLen(qname),
+        &valueW, &len);
+    if (FAILED(hr))
+        return hr;
+
+    return return_bstrn(valueW, len, value);
 }
 
 static const struct IVBSAXAttributesVtbl VBSAXAttributesVtbl =
@@ -2497,12 +3428,12 @@ static dispex_static_data_t mxattrs_dispex = {
     mxattrs_iface_tids
 };
 
-HRESULT SAXAttributes_create(MSXML_VERSION version, IUnknown *outer, void **ppObj)
+HRESULT SAXAttributes_create(MSXML_VERSION version, void **ppObj)
 {
     static const int default_count = 10;
     mxattributes *This;
 
-    TRACE("(%p, %p)\n", outer, ppObj);
+    TRACE("(%p)\n", ppObj);
 
     This = heap_alloc( sizeof (*This) );
     if( !This )