|  | /* | 
|  | * XML Document implementation | 
|  | * | 
|  | * Copyright 2007 James Hawkins | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #define COBJMACROS | 
|  |  | 
|  | #include "config.h" | 
|  |  | 
|  | #include <stdarg.h> | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winuser.h" | 
|  | #include "ole2.h" | 
|  | #include "msxml2.h" | 
|  | #include "wininet.h" | 
|  | #include "winreg.h" | 
|  | #include "shlwapi.h" | 
|  | #include "ocidl.h" | 
|  |  | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | #include "msxml_private.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(msxml); | 
|  |  | 
|  | #ifdef HAVE_LIBXML2 | 
|  |  | 
|  | /* FIXME: IXMLDocument needs to implement | 
|  | *   - IXMLError | 
|  | *   - IPersistMoniker | 
|  | *   - IPersistStream | 
|  | */ | 
|  |  | 
|  | typedef struct _xmldoc | 
|  | { | 
|  | const IXMLDocumentVtbl       *lpVtbl; | 
|  | const IPersistStreamInitVtbl *lpvtblIPersistStreamInit; | 
|  | LONG ref; | 
|  | HRESULT error; | 
|  |  | 
|  | /* IXMLDocument */ | 
|  | IXMLElement *root; | 
|  | xmlDocPtr xmldoc; | 
|  |  | 
|  | /* IPersistStream */ | 
|  | IStream *stream; | 
|  | } xmldoc; | 
|  |  | 
|  | static inline xmldoc *impl_from_IXMLDocument(IXMLDocument *iface) | 
|  | { | 
|  | return (xmldoc *)((char*)iface - FIELD_OFFSET(xmldoc, lpVtbl)); | 
|  | } | 
|  |  | 
|  | static inline xmldoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface) | 
|  | { | 
|  | return (xmldoc *)((char*)iface - FIELD_OFFSET(xmldoc, lpvtblIPersistStreamInit)); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_QueryInterface(IXMLDocument *iface, REFIID riid, void** ppvObject) | 
|  | { | 
|  | xmldoc *This = impl_from_IXMLDocument(iface); | 
|  |  | 
|  | TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject); | 
|  |  | 
|  | if (IsEqualGUID(riid, &IID_IUnknown) || | 
|  | IsEqualGUID(riid, &IID_IXMLDocument)) | 
|  | { | 
|  | *ppvObject = iface; | 
|  | } | 
|  | else if (IsEqualGUID(&IID_IPersistStreamInit, riid)) | 
|  | { | 
|  | *ppvObject = (IPersistStreamInit *)&(This->lpvtblIPersistStreamInit); | 
|  | } | 
|  | else | 
|  | { | 
|  | FIXME("interface %s not implemented\n", debugstr_guid(riid)); | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | IXMLDocument_AddRef(iface); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI xmldoc_AddRef(IXMLDocument *iface) | 
|  | { | 
|  | xmldoc *This = impl_from_IXMLDocument(iface); | 
|  | TRACE("%p\n", This); | 
|  | return InterlockedIncrement(&This->ref); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI xmldoc_Release(IXMLDocument *iface) | 
|  | { | 
|  | xmldoc *This = impl_from_IXMLDocument(iface); | 
|  | LONG ref; | 
|  |  | 
|  | TRACE("%p\n", This); | 
|  |  | 
|  | ref = InterlockedDecrement(&This->ref); | 
|  | if (ref == 0) | 
|  | { | 
|  | xmlFreeDoc(This->xmldoc); | 
|  | if (This->stream) IStream_Release(This->stream); | 
|  | HeapFree(GetProcessHeap(), 0, This); | 
|  | } | 
|  |  | 
|  | return ref; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_GetTypeInfoCount(IXMLDocument *iface, UINT* pctinfo) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_GetTypeInfo(IXMLDocument *iface, UINT iTInfo, | 
|  | LCID lcid, ITypeInfo** ppTInfo) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_GetIDsOfNames(IXMLDocument *iface, REFIID riid, | 
|  | LPOLESTR* rgszNames, UINT cNames, | 
|  | LCID lcid, DISPID* rgDispId) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_Invoke(IXMLDocument *iface, DISPID dispIdMember, | 
|  | REFIID riid, LCID lcid, WORD wFlags, | 
|  | DISPPARAMS* pDispParams, VARIANT* pVarResult, | 
|  | EXCEPINFO* pExcepInfo, UINT* puArgErr) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_get_root(IXMLDocument *iface, IXMLElement **p) | 
|  | { | 
|  | xmldoc *This = impl_from_IXMLDocument(iface); | 
|  |  | 
|  | TRACE("(%p, %p)\n", iface, p); | 
|  |  | 
|  | if (!p) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | *p = This->root; | 
|  | if (!*p) | 
|  | return E_FAIL; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_get_fileSize(IXMLDocument *iface, BSTR *p) | 
|  | { | 
|  | FIXME("(%p, %p): stub\n", iface, p); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_put_fileModifiedDate(IXMLDocument *iface, BSTR *p) | 
|  | { | 
|  | FIXME("(%p, %p): stub\n", iface, p); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_get_fileUpdatedDate(IXMLDocument *iface, BSTR *p) | 
|  | { | 
|  | FIXME("(%p, %p): stub\n", iface, p); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_get_URL(IXMLDocument *iface, BSTR *p) | 
|  | { | 
|  | FIXME("(%p, %p): stub\n", iface, p); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | typedef struct { | 
|  | const struct IBindStatusCallbackVtbl *lpVtbl; | 
|  | } bsc; | 
|  |  | 
|  | static HRESULT WINAPI bsc_QueryInterface( | 
|  | IBindStatusCallback *iface, | 
|  | REFIID riid, | 
|  | LPVOID *ppobj ) | 
|  | { | 
|  | if (IsEqualGUID(riid, &IID_IUnknown) || | 
|  | IsEqualGUID(riid, &IID_IBindStatusCallback)) | 
|  | { | 
|  | IBindStatusCallback_AddRef( iface ); | 
|  | *ppobj = iface; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | FIXME("interface %s not implemented\n", debugstr_guid(riid)); | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI bsc_AddRef( | 
|  | IBindStatusCallback *iface ) | 
|  | { | 
|  | return 2; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI bsc_Release( | 
|  | IBindStatusCallback *iface ) | 
|  | { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI bsc_OnStartBinding( | 
|  | IBindStatusCallback* iface, | 
|  | DWORD dwReserved, | 
|  | IBinding* pib) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI bsc_GetPriority( | 
|  | IBindStatusCallback* iface, | 
|  | LONG* pnPriority) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI bsc_OnLowResource( | 
|  | IBindStatusCallback* iface, | 
|  | DWORD reserved) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI bsc_OnProgress( | 
|  | IBindStatusCallback* iface, | 
|  | ULONG ulProgress, | 
|  | ULONG ulProgressMax, | 
|  | ULONG ulStatusCode, | 
|  | LPCWSTR szStatusText) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI bsc_OnStopBinding( | 
|  | IBindStatusCallback* iface, | 
|  | HRESULT hresult, | 
|  | LPCWSTR szError) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI bsc_GetBindInfo( | 
|  | IBindStatusCallback* iface, | 
|  | DWORD* grfBINDF, | 
|  | BINDINFO* pbindinfo) | 
|  | { | 
|  | *grfBINDF = BINDF_RESYNCHRONIZE; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI bsc_OnDataAvailable( | 
|  | IBindStatusCallback* iface, | 
|  | DWORD grfBSCF, | 
|  | DWORD dwSize, | 
|  | FORMATETC* pformatetc, | 
|  | STGMEDIUM* pstgmed) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI bsc_OnObjectAvailable( | 
|  | IBindStatusCallback* iface, | 
|  | REFIID riid, | 
|  | IUnknown* punk) | 
|  | { | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static const struct IBindStatusCallbackVtbl bsc_vtbl = | 
|  | { | 
|  | bsc_QueryInterface, | 
|  | bsc_AddRef, | 
|  | bsc_Release, | 
|  | bsc_OnStartBinding, | 
|  | bsc_GetPriority, | 
|  | bsc_OnLowResource, | 
|  | bsc_OnProgress, | 
|  | bsc_OnStopBinding, | 
|  | bsc_GetBindInfo, | 
|  | bsc_OnDataAvailable, | 
|  | bsc_OnObjectAvailable | 
|  | }; | 
|  |  | 
|  | static bsc xmldoc_bsc = { &bsc_vtbl }; | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_put_URL(IXMLDocument *iface, BSTR p) | 
|  | { | 
|  | WCHAR url[INTERNET_MAX_URL_LENGTH]; | 
|  | IStream *stream; | 
|  | IBindCtx *bctx; | 
|  | IMoniker *moniker; | 
|  | IPersistStreamInit *persist; | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p, %s)\n", iface, debugstr_w(p)); | 
|  |  | 
|  | if (!p) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | if (!PathIsURLW(p)) | 
|  | { | 
|  | WCHAR fullpath[MAX_PATH]; | 
|  | DWORD needed = sizeof(url) / sizeof(WCHAR); | 
|  |  | 
|  | if (!PathSearchAndQualifyW(p, fullpath, sizeof(fullpath) / sizeof(WCHAR))) | 
|  | { | 
|  | ERR("can't find path\n"); | 
|  | return E_FAIL; | 
|  | } | 
|  |  | 
|  | if (FAILED(UrlCreateFromPathW(fullpath, url, &needed, 0))) | 
|  | { | 
|  | ERR("can't create url from path\n"); | 
|  | return E_FAIL; | 
|  | } | 
|  |  | 
|  | p = url; | 
|  | } | 
|  |  | 
|  | hr = CreateURLMoniker(NULL, p, &moniker); | 
|  | if (FAILED(hr)) | 
|  | return hr; | 
|  |  | 
|  | CreateAsyncBindCtx(0, (IBindStatusCallback *)&xmldoc_bsc, 0, &bctx); | 
|  |  | 
|  | hr = IMoniker_BindToStorage(moniker, bctx, NULL, &IID_IStream, (LPVOID *)&stream); | 
|  | IBindCtx_Release(bctx); | 
|  | IMoniker_Release(moniker); | 
|  | if (FAILED(hr)) | 
|  | return hr; | 
|  |  | 
|  | hr = IXMLDocument_QueryInterface(iface, &IID_IPersistStreamInit, (LPVOID *)&persist); | 
|  | if (FAILED(hr)) | 
|  | { | 
|  | IStream_Release(stream); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | hr = IPersistStreamInit_Load(persist, stream); | 
|  | IPersistStreamInit_Release(persist); | 
|  | IStream_Release(stream); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_get_mimeType(IXMLDocument *iface, BSTR *p) | 
|  | { | 
|  | FIXME("(%p, %p): stub\n", iface, p); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_get_readyState(IXMLDocument *iface, long *p) | 
|  | { | 
|  | FIXME("(%p, %p): stub\n", iface, p); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_get_charset(IXMLDocument *iface, BSTR *p) | 
|  | { | 
|  | FIXME("(%p, %p): stub\n", iface, p); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_put_charset(IXMLDocument *iface, BSTR p) | 
|  | { | 
|  | FIXME("(%p, %p): stub\n", iface, p); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_get_version(IXMLDocument *iface, BSTR *p) | 
|  | { | 
|  | FIXME("(%p, %p): stub\n", iface, p); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_get_doctype(IXMLDocument *iface, BSTR *p) | 
|  | { | 
|  | FIXME("(%p, %p): stub\n", iface, p); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_get_dtdURl(IXMLDocument *iface, BSTR *p) | 
|  | { | 
|  | FIXME("(%p, %p): stub\n", iface, p); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static xmlElementType type_msxml_to_libxml(long type) | 
|  | { | 
|  | switch (type) | 
|  | { | 
|  | case XMLELEMTYPE_ELEMENT: | 
|  | return XML_ELEMENT_NODE; | 
|  | case XMLELEMTYPE_TEXT: | 
|  | return XML_TEXT_NODE; | 
|  | case XMLELEMTYPE_COMMENT: | 
|  | return XML_COMMENT_NODE; | 
|  | case XMLELEMTYPE_DOCUMENT: | 
|  | return XML_DOCUMENT_NODE; | 
|  | case XMLELEMTYPE_DTD: | 
|  | return XML_DTD_NODE; | 
|  | case XMLELEMTYPE_PI: | 
|  | return XML_PI_NODE; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | return -1; /* FIXME: what is OTHER in msxml? */ | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_createElement(IXMLDocument *iface, VARIANT vType, | 
|  | VARIANT var1, IXMLElement **ppElem) | 
|  | { | 
|  | xmlNodePtr node; | 
|  | static const xmlChar empty[] = "\0"; | 
|  |  | 
|  | TRACE("(%p, %p)\n", iface, ppElem); | 
|  |  | 
|  | if (!ppElem) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | *ppElem = NULL; | 
|  |  | 
|  | node = xmlNewNode(NULL, empty); | 
|  |  | 
|  | if (V_VT(&vType) != VT_I4) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | node->type = type_msxml_to_libxml(V_I4(&vType)); | 
|  |  | 
|  | /* FIXME: create xmlNodePtr based on vType and var1 */ | 
|  | return XMLElement_create((IUnknown *)iface, node, (LPVOID *)ppElem); | 
|  | } | 
|  |  | 
|  | static const struct IXMLDocumentVtbl xmldoc_vtbl = | 
|  | { | 
|  | xmldoc_QueryInterface, | 
|  | xmldoc_AddRef, | 
|  | xmldoc_Release, | 
|  | xmldoc_GetTypeInfoCount, | 
|  | xmldoc_GetTypeInfo, | 
|  | xmldoc_GetIDsOfNames, | 
|  | xmldoc_Invoke, | 
|  | xmldoc_get_root, | 
|  | xmldoc_get_fileSize, | 
|  | xmldoc_put_fileModifiedDate, | 
|  | xmldoc_get_fileUpdatedDate, | 
|  | xmldoc_get_URL, | 
|  | xmldoc_put_URL, | 
|  | xmldoc_get_mimeType, | 
|  | xmldoc_get_readyState, | 
|  | xmldoc_get_charset, | 
|  | xmldoc_put_charset, | 
|  | xmldoc_get_version, | 
|  | xmldoc_get_doctype, | 
|  | xmldoc_get_dtdURl, | 
|  | xmldoc_createElement | 
|  | }; | 
|  |  | 
|  | /************************************************************************ | 
|  | * xmldoc implementation of IPersistStreamInit. | 
|  | */ | 
|  | static HRESULT WINAPI xmldoc_IPersistStreamInit_QueryInterface( | 
|  | IPersistStreamInit *iface, REFIID riid, LPVOID *ppvObj) | 
|  | { | 
|  | xmldoc *this = impl_from_IPersistStreamInit(iface); | 
|  | return IXMLDocument_QueryInterface((IXMLDocument *)this, riid, ppvObj); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI xmldoc_IPersistStreamInit_AddRef( | 
|  | IPersistStreamInit *iface) | 
|  | { | 
|  | xmldoc *this = impl_from_IPersistStreamInit(iface); | 
|  | return IXMLDocument_AddRef((IXMLDocument *)this); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI xmldoc_IPersistStreamInit_Release( | 
|  | IPersistStreamInit *iface) | 
|  | { | 
|  | xmldoc *this = impl_from_IPersistStreamInit(iface); | 
|  | return IXMLDocument_Release((IXMLDocument *)this); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_IPersistStreamInit_GetClassID( | 
|  | IPersistStreamInit *iface, CLSID *classid) | 
|  | { | 
|  | FIXME("(%p,%p): stub!\n", iface, classid); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_IPersistStreamInit_IsDirty( | 
|  | IPersistStreamInit *iface) | 
|  | { | 
|  | FIXME("(%p): stub!\n", iface); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static xmlDocPtr parse_xml(char *ptr, int len) | 
|  | { | 
|  | #ifdef HAVE_XMLREADMEMORY | 
|  | return xmlReadMemory(ptr, len, NULL, NULL, | 
|  | XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS); | 
|  | #else | 
|  | return xmlParseMemory(ptr, len); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_IPersistStreamInit_Load( | 
|  | IPersistStreamInit *iface, LPSTREAM pStm) | 
|  | { | 
|  | xmldoc *This = impl_from_IPersistStreamInit(iface); | 
|  | xmlNodePtr xmlnode; | 
|  | HRESULT hr; | 
|  | HGLOBAL hglobal; | 
|  | DWORD read, written, len; | 
|  | BYTE buf[4096]; | 
|  | char *ptr; | 
|  |  | 
|  | TRACE("(%p, %p)\n", iface, pStm); | 
|  |  | 
|  | if (!pStm) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream); | 
|  | if (FAILED(hr)) | 
|  | return hr; | 
|  |  | 
|  | do | 
|  | { | 
|  | IStream_Read(pStm, buf, sizeof(buf), &read); | 
|  | hr = IStream_Write(This->stream, buf, read, &written); | 
|  | } while(SUCCEEDED(hr) && written != 0 && read != 0); | 
|  |  | 
|  | if (FAILED(hr)) | 
|  | { | 
|  | ERR("Failed to copy stream\n"); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | hr = GetHGlobalFromStream(This->stream, &hglobal); | 
|  | if (FAILED(hr)) | 
|  | return hr; | 
|  |  | 
|  | len = GlobalSize(hglobal); | 
|  | ptr = GlobalLock(hglobal); | 
|  | if (len != 0) | 
|  | This->xmldoc = parse_xml(ptr, len); | 
|  | GlobalUnlock(hglobal); | 
|  |  | 
|  | if (!This->xmldoc) | 
|  | { | 
|  | ERR("Failed to parse xml\n"); | 
|  | return E_FAIL; | 
|  | } | 
|  |  | 
|  | xmlnode = xmlDocGetRootElement(This->xmldoc); | 
|  | return XMLElement_create((IUnknown *)This, xmlnode, (LPVOID *)&This->root); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_IPersistStreamInit_Save( | 
|  | IPersistStreamInit *iface, LPSTREAM pStm, BOOL fClearDirty) | 
|  | { | 
|  | FIXME("(%p, %p, %d): stub!\n", iface, pStm, fClearDirty); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_IPersistStreamInit_GetSizeMax( | 
|  | IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize) | 
|  | { | 
|  | FIXME("(%p, %p): stub!\n", iface, pcbSize); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI xmldoc_IPersistStreamInit_InitNew( | 
|  | IPersistStreamInit *iface) | 
|  | { | 
|  | FIXME("(%p): stub!\n", iface); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable = | 
|  | { | 
|  | xmldoc_IPersistStreamInit_QueryInterface, | 
|  | xmldoc_IPersistStreamInit_AddRef, | 
|  | xmldoc_IPersistStreamInit_Release, | 
|  | xmldoc_IPersistStreamInit_GetClassID, | 
|  | xmldoc_IPersistStreamInit_IsDirty, | 
|  | xmldoc_IPersistStreamInit_Load, | 
|  | xmldoc_IPersistStreamInit_Save, | 
|  | xmldoc_IPersistStreamInit_GetSizeMax, | 
|  | xmldoc_IPersistStreamInit_InitNew | 
|  | }; | 
|  |  | 
|  | HRESULT XMLDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj) | 
|  | { | 
|  | xmldoc *doc; | 
|  |  | 
|  | TRACE("(%p,%p)\n", pUnkOuter, ppObj); | 
|  |  | 
|  | doc = HeapAlloc(GetProcessHeap(), 0, sizeof (*doc)); | 
|  | if(!doc) | 
|  | return E_OUTOFMEMORY; | 
|  |  | 
|  | doc->lpVtbl = &xmldoc_vtbl; | 
|  | doc->lpvtblIPersistStreamInit = &xmldoc_IPersistStreamInit_VTable; | 
|  | doc->ref = 1; | 
|  | doc->error = S_OK; | 
|  | doc->root = NULL; | 
|  | doc->xmldoc = NULL; | 
|  | doc->stream = NULL; | 
|  |  | 
|  | *ppObj = &doc->lpVtbl; | 
|  |  | 
|  | TRACE("returning iface %p\n", *ppObj); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | #else | 
|  |  | 
|  | HRESULT XMLDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj) | 
|  | { | 
|  | MESSAGE("This program tried to use an XMLDocument object, but\n" | 
|  | "libxml2 support was not present at compile time.\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | #endif |