msxml3: Remove unused variable.
[wine] / dlls / msxml3 / xmldoc.c
1 /*
2  * XML Document implementation
3  *
4  * Copyright 2007 James Hawkins
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22
23 #include "config.h"
24
25 #include <stdarg.h>
26 #ifdef HAVE_LIBXML2
27 # include <libxml/parser.h>
28 # include <libxml/xmlerror.h>
29 #endif
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winuser.h"
34 #include "ole2.h"
35 #include "msxml6.h"
36 #include "wininet.h"
37 #include "winreg.h"
38 #include "shlwapi.h"
39 #include "ocidl.h"
40
41 #include "wine/debug.h"
42
43 #include "msxml_private.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
46
47 #ifdef HAVE_LIBXML2
48
49 /* FIXME: IXMLDocument needs to implement
50  *   - IXMLError
51  *   - IPersistMoniker
52  */
53
54 typedef struct _xmldoc
55 {
56     IXMLDocument IXMLDocument_iface;
57     IPersistStreamInit IPersistStreamInit_iface;
58     LONG ref;
59     HRESULT error;
60
61     /* IXMLDocument */
62     xmlDocPtr xmldoc;
63
64     /* IPersistStream */
65     IStream *stream;
66 } xmldoc;
67
68 static inline xmldoc *impl_from_IXMLDocument(IXMLDocument *iface)
69 {
70     return CONTAINING_RECORD(iface, xmldoc, IXMLDocument_iface);
71 }
72
73 static inline xmldoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
74 {
75     return CONTAINING_RECORD(iface, xmldoc, IPersistStreamInit_iface);
76 }
77
78 static HRESULT WINAPI xmldoc_QueryInterface(IXMLDocument *iface, REFIID riid, void** ppvObject)
79 {
80     xmldoc *This = impl_from_IXMLDocument(iface);
81
82     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
83
84     if (IsEqualGUID(riid, &IID_IUnknown)  ||
85         IsEqualGUID(riid, &IID_IDispatch) ||
86         IsEqualGUID(riid, &IID_IXMLDocument))
87     {
88         *ppvObject = iface;
89     }
90     else if (IsEqualGUID(&IID_IPersistStreamInit, riid) ||
91              IsEqualGUID(&IID_IPersistStream, riid))
92     {
93         *ppvObject = &This->IPersistStreamInit_iface;
94     }
95     else
96     {
97         FIXME("interface %s not implemented\n", debugstr_guid(riid));
98         *ppvObject = NULL;
99         return E_NOINTERFACE;
100     }
101
102     IXMLDocument_AddRef(iface);
103
104     return S_OK;
105 }
106
107 static ULONG WINAPI xmldoc_AddRef(IXMLDocument *iface)
108 {
109     xmldoc *This = impl_from_IXMLDocument(iface);
110     ULONG ref = InterlockedIncrement(&This->ref);
111     TRACE("(%p)->(%d)\n", This, ref);
112     return ref;
113 }
114
115 static ULONG WINAPI xmldoc_Release(IXMLDocument *iface)
116 {
117     xmldoc *This = impl_from_IXMLDocument(iface);
118     LONG ref = InterlockedDecrement(&This->ref);
119
120     TRACE("(%p)->(%d)\n", This, ref);
121
122     if (ref == 0)
123     {
124         xmlFreeDoc(This->xmldoc);
125         if (This->stream) IStream_Release(This->stream);
126         heap_free(This);
127     }
128
129     return ref;
130 }
131
132 static HRESULT WINAPI xmldoc_GetTypeInfoCount(IXMLDocument *iface, UINT* pctinfo)
133 {
134     xmldoc *This = impl_from_IXMLDocument(iface);
135
136     TRACE("(%p)->(%p)\n", This, pctinfo);
137
138     *pctinfo = 1;
139
140     return S_OK;
141 }
142
143 static HRESULT WINAPI xmldoc_GetTypeInfo(IXMLDocument *iface, UINT iTInfo,
144                                          LCID lcid, ITypeInfo** ti)
145 {
146     xmldoc *This = impl_from_IXMLDocument(iface);
147     HRESULT hr;
148
149     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ti);
150
151     hr = get_typeinfo(IXMLDocument_tid, ti);
152     ITypeInfo_AddRef(*ti);
153     return hr;
154 }
155
156 static HRESULT WINAPI xmldoc_GetIDsOfNames(IXMLDocument *iface, REFIID riid,
157                                            LPOLESTR* rgszNames, UINT cNames,
158                                            LCID lcid, DISPID* rgDispId)
159 {
160     xmldoc *This = impl_from_IXMLDocument(iface);
161     ITypeInfo *typeinfo;
162     HRESULT hr;
163
164     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
165           lcid, rgDispId);
166
167     if(!rgszNames || cNames == 0 || !rgDispId)
168         return E_INVALIDARG;
169
170     hr = get_typeinfo(IXMLDocument_tid, &typeinfo);
171     if(SUCCEEDED(hr))
172         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
173
174     return hr;
175 }
176
177 static HRESULT WINAPI xmldoc_Invoke(IXMLDocument *iface, DISPID dispIdMember,
178                                     REFIID riid, LCID lcid, WORD wFlags,
179                                     DISPPARAMS* pDispParams, VARIANT* pVarResult,
180                                     EXCEPINFO* pExcepInfo, UINT* puArgErr)
181 {
182     xmldoc *This = impl_from_IXMLDocument(iface);
183     ITypeInfo *typeinfo;
184     HRESULT hr;
185
186     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
187           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
188
189     hr = get_typeinfo(IXMLDocument_tid, &typeinfo);
190     if(SUCCEEDED(hr))
191         hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDocument_iface, dispIdMember, wFlags,
192                 pDispParams, pVarResult, pExcepInfo, puArgErr);
193
194     return hr;
195 }
196
197 static HRESULT WINAPI xmldoc_get_root(IXMLDocument *iface, IXMLElement **p)
198 {
199     xmldoc *This = impl_from_IXMLDocument(iface);
200     xmlNodePtr root;
201
202     TRACE("(%p, %p)\n", iface, p);
203
204     if (!p)
205         return E_INVALIDARG;
206
207     *p = NULL;
208
209     if (!(root = xmlDocGetRootElement(This->xmldoc)))
210         return E_FAIL;
211
212     return XMLElement_create((IUnknown *)This, root, (LPVOID *)p, FALSE);
213 }
214
215 static HRESULT WINAPI xmldoc_get_fileSize(IXMLDocument *iface, BSTR *p)
216 {
217     FIXME("(%p, %p): stub\n", iface, p);
218     return E_NOTIMPL;
219 }
220
221 static HRESULT WINAPI xmldoc_put_fileModifiedDate(IXMLDocument *iface, BSTR *p)
222 {
223     FIXME("(%p, %p): stub\n", iface, p);
224     return E_NOTIMPL;
225 }
226
227 static HRESULT WINAPI xmldoc_get_fileUpdatedDate(IXMLDocument *iface, BSTR *p)
228 {
229     FIXME("(%p, %p): stub\n", iface, p);
230     return E_NOTIMPL;
231 }
232
233 static HRESULT WINAPI xmldoc_get_URL(IXMLDocument *iface, BSTR *p)
234 {
235     FIXME("(%p, %p): stub\n", iface, p);
236     return E_NOTIMPL;
237 }
238
239 typedef struct {
240     IBindStatusCallback IBindStatusCallback_iface;
241 } bsc;
242
243 static HRESULT WINAPI bsc_QueryInterface(
244     IBindStatusCallback *iface,
245     REFIID riid,
246     LPVOID *ppobj )
247 {
248     if (IsEqualGUID(riid, &IID_IUnknown) ||
249         IsEqualGUID(riid, &IID_IBindStatusCallback))
250     {
251         IBindStatusCallback_AddRef( iface );
252         *ppobj = iface;
253         return S_OK;
254     }
255
256     TRACE("interface %s not implemented\n", debugstr_guid(riid));
257     return E_NOINTERFACE;
258 }
259
260 static ULONG WINAPI bsc_AddRef(
261     IBindStatusCallback *iface )
262 {
263     return 2;
264 }
265
266 static ULONG WINAPI bsc_Release(
267     IBindStatusCallback *iface )
268 {
269     return 1;
270 }
271
272 static HRESULT WINAPI bsc_OnStartBinding(
273         IBindStatusCallback* iface,
274         DWORD dwReserved,
275         IBinding* pib)
276 {
277     return S_OK;
278 }
279
280 static HRESULT WINAPI bsc_GetPriority(
281         IBindStatusCallback* iface,
282         LONG* pnPriority)
283 {
284     return S_OK;
285 }
286
287 static HRESULT WINAPI bsc_OnLowResource(
288         IBindStatusCallback* iface,
289         DWORD reserved)
290 {
291     return S_OK;
292 }
293
294 static HRESULT WINAPI bsc_OnProgress(
295         IBindStatusCallback* iface,
296         ULONG ulProgress,
297         ULONG ulProgressMax,
298         ULONG ulStatusCode,
299         LPCWSTR szStatusText)
300 {
301     return S_OK;
302 }
303
304 static HRESULT WINAPI bsc_OnStopBinding(
305         IBindStatusCallback* iface,
306         HRESULT hresult,
307         LPCWSTR szError)
308 {
309     return S_OK;
310 }
311
312 static HRESULT WINAPI bsc_GetBindInfo(
313         IBindStatusCallback* iface,
314         DWORD* grfBINDF,
315         BINDINFO* pbindinfo)
316 {
317     *grfBINDF = BINDF_RESYNCHRONIZE;
318
319     return S_OK;
320 }
321
322 static HRESULT WINAPI bsc_OnDataAvailable(
323         IBindStatusCallback* iface,
324         DWORD grfBSCF,
325         DWORD dwSize,
326         FORMATETC* pformatetc,
327         STGMEDIUM* pstgmed)
328 {
329     return S_OK;
330 }
331
332 static HRESULT WINAPI bsc_OnObjectAvailable(
333         IBindStatusCallback* iface,
334         REFIID riid,
335         IUnknown* punk)
336 {
337     return S_OK;
338 }
339
340 static const struct IBindStatusCallbackVtbl bsc_vtbl =
341 {
342     bsc_QueryInterface,
343     bsc_AddRef,
344     bsc_Release,
345     bsc_OnStartBinding,
346     bsc_GetPriority,
347     bsc_OnLowResource,
348     bsc_OnProgress,
349     bsc_OnStopBinding,
350     bsc_GetBindInfo,
351     bsc_OnDataAvailable,
352     bsc_OnObjectAvailable
353 };
354
355 static bsc xmldoc_bsc = { { &bsc_vtbl } };
356
357 static HRESULT WINAPI xmldoc_put_URL(IXMLDocument *iface, BSTR p)
358 {
359     WCHAR url[INTERNET_MAX_URL_LENGTH];
360     IStream *stream;
361     IBindCtx *bctx;
362     IMoniker *moniker;
363     IPersistStreamInit *persist;
364     HRESULT hr;
365
366     TRACE("(%p, %s)\n", iface, debugstr_w(p));
367
368     if (!p)
369         return E_INVALIDARG;
370
371     if (!PathIsURLW(p))
372     {
373         WCHAR fullpath[MAX_PATH];
374         DWORD needed = sizeof(url) / sizeof(WCHAR);
375
376         if (!PathSearchAndQualifyW(p, fullpath, sizeof(fullpath) / sizeof(WCHAR)))
377         {
378             ERR("can't find path\n");
379             return E_FAIL;
380         }
381
382         if (FAILED(UrlCreateFromPathW(fullpath, url, &needed, 0)))
383         {
384             ERR("can't create url from path\n");
385             return E_FAIL;
386         }
387
388         p = url;
389     }
390
391     hr = CreateURLMoniker(NULL, p, &moniker);
392     if (FAILED(hr))
393         return hr;
394
395     CreateAsyncBindCtx(0, &xmldoc_bsc.IBindStatusCallback_iface, 0, &bctx);
396
397     hr = IMoniker_BindToStorage(moniker, bctx, NULL, &IID_IStream, (LPVOID *)&stream);
398     IBindCtx_Release(bctx);
399     IMoniker_Release(moniker);
400     if (FAILED(hr))
401         return hr;
402
403     hr = IXMLDocument_QueryInterface(iface, &IID_IPersistStreamInit, (LPVOID *)&persist);
404     if (FAILED(hr))
405     {
406         IStream_Release(stream);
407         return hr;
408     }
409
410     hr = IPersistStreamInit_Load(persist, stream);
411     IPersistStreamInit_Release(persist);
412     IStream_Release(stream);
413
414     return hr;
415 }
416
417 static HRESULT WINAPI xmldoc_get_mimeType(IXMLDocument *iface, BSTR *p)
418 {
419     FIXME("(%p, %p): stub\n", iface, p);
420     return E_NOTIMPL;
421 }
422
423 static HRESULT WINAPI xmldoc_get_readyState(IXMLDocument *iface, LONG *p)
424 {
425     FIXME("(%p, %p): stub\n", iface, p);
426     return E_NOTIMPL;
427 }
428
429 static HRESULT WINAPI xmldoc_get_charset(IXMLDocument *iface, BSTR *p)
430 {
431     FIXME("(%p, %p): stub\n", iface, p);
432     return E_NOTIMPL;
433 }
434
435 static HRESULT WINAPI xmldoc_put_charset(IXMLDocument *iface, BSTR p)
436 {
437     FIXME("(%p, %p): stub\n", iface, p);
438     return E_NOTIMPL;
439 }
440
441 static HRESULT WINAPI xmldoc_get_version(IXMLDocument *iface, BSTR *p)
442 {
443     xmldoc *This = impl_from_IXMLDocument(iface);
444
445     TRACE("(%p, %p)\n", This, p);
446
447     if (!p) return E_INVALIDARG;
448     *p = bstr_from_xmlChar(This->xmldoc->version);
449
450     return S_OK;
451 }
452
453 static HRESULT WINAPI xmldoc_get_doctype(IXMLDocument *iface, BSTR *p)
454 {
455     xmldoc *This = impl_from_IXMLDocument(iface);
456     xmlDtd *dtd;
457
458     TRACE("(%p, %p)\n", This, p);
459
460     if (!p) return E_INVALIDARG;
461
462     dtd = xmlGetIntSubset(This->xmldoc);
463     if (!dtd) return S_FALSE;
464
465     *p = bstr_from_xmlChar(dtd->name);
466     CharUpperBuffW(*p, SysStringLen(*p));
467
468     return S_OK;
469 }
470
471 static HRESULT WINAPI xmldoc_get_dtdURl(IXMLDocument *iface, BSTR *p)
472 {
473     FIXME("(%p, %p): stub\n", iface, p);
474     return E_NOTIMPL;
475 }
476
477 static xmlElementType type_msxml_to_libxml(LONG type)
478 {
479     switch (type)
480     {
481         case XMLELEMTYPE_ELEMENT:
482             return XML_ELEMENT_NODE;
483         case XMLELEMTYPE_TEXT:
484             return XML_TEXT_NODE;
485         case XMLELEMTYPE_COMMENT:
486             return XML_COMMENT_NODE;
487         case XMLELEMTYPE_DOCUMENT:
488             return XML_DOCUMENT_NODE;
489         case XMLELEMTYPE_DTD:
490             return XML_DTD_NODE;
491         case XMLELEMTYPE_PI:
492             return XML_PI_NODE;
493         default:
494             break;
495     }
496
497     return -1; /* FIXME: what is OTHER in msxml? */
498 }
499
500 static HRESULT WINAPI xmldoc_createElement(IXMLDocument *iface, VARIANT vType,
501                                            VARIANT var1, IXMLElement **ppElem)
502 {
503     xmlNodePtr node;
504     static const xmlChar empty[] = "\0";
505
506     TRACE("(%p)->(%s %s %p)\n", iface, debugstr_variant(&vType),
507         debugstr_variant(&var1), ppElem);
508
509     if (!ppElem)
510         return E_INVALIDARG;
511
512     *ppElem = NULL;
513
514     if (V_VT(&vType) != VT_I4)
515         return E_INVALIDARG;
516
517     if(type_msxml_to_libxml(V_I4(&vType)) == -1)
518         return E_NOTIMPL;
519
520     node = xmlNewNode(NULL, empty);
521     node->type = type_msxml_to_libxml(V_I4(&vType));
522
523     /* FIXME: create xmlNodePtr based on vType and var1 */
524     return XMLElement_create((IUnknown *)iface, node, (LPVOID *)ppElem, TRUE);
525 }
526
527 static const struct IXMLDocumentVtbl xmldoc_vtbl =
528 {
529     xmldoc_QueryInterface,
530     xmldoc_AddRef,
531     xmldoc_Release,
532     xmldoc_GetTypeInfoCount,
533     xmldoc_GetTypeInfo,
534     xmldoc_GetIDsOfNames,
535     xmldoc_Invoke,
536     xmldoc_get_root,
537     xmldoc_get_fileSize,
538     xmldoc_put_fileModifiedDate,
539     xmldoc_get_fileUpdatedDate,
540     xmldoc_get_URL,
541     xmldoc_put_URL,
542     xmldoc_get_mimeType,
543     xmldoc_get_readyState,
544     xmldoc_get_charset,
545     xmldoc_put_charset,
546     xmldoc_get_version,
547     xmldoc_get_doctype,
548     xmldoc_get_dtdURl,
549     xmldoc_createElement
550 };
551
552 /************************************************************************
553  * xmldoc implementation of IPersistStreamInit.
554  */
555 static HRESULT WINAPI xmldoc_IPersistStreamInit_QueryInterface(
556     IPersistStreamInit *iface, REFIID riid, LPVOID *ppvObj)
557 {
558     xmldoc *this = impl_from_IPersistStreamInit(iface);
559     return IXMLDocument_QueryInterface(&this->IXMLDocument_iface, riid, ppvObj);
560 }
561
562 static ULONG WINAPI xmldoc_IPersistStreamInit_AddRef(
563     IPersistStreamInit *iface)
564 {
565     xmldoc *this = impl_from_IPersistStreamInit(iface);
566     return IXMLDocument_AddRef(&this->IXMLDocument_iface);
567 }
568
569 static ULONG WINAPI xmldoc_IPersistStreamInit_Release(
570     IPersistStreamInit *iface)
571 {
572     xmldoc *this = impl_from_IPersistStreamInit(iface);
573     return IXMLDocument_Release(&this->IXMLDocument_iface);
574 }
575
576 static HRESULT WINAPI xmldoc_IPersistStreamInit_GetClassID(
577     IPersistStreamInit *iface, CLSID *classid)
578 {
579     xmldoc *this = impl_from_IPersistStreamInit(iface);
580     TRACE("(%p,%p)\n", this, classid);
581
582     if (!classid) return E_POINTER;
583
584     *classid = CLSID_XMLDocument;
585     return S_OK;
586 }
587
588 static HRESULT WINAPI xmldoc_IPersistStreamInit_IsDirty(
589     IPersistStreamInit *iface)
590 {
591     FIXME("(%p): stub!\n", iface);
592     return E_NOTIMPL;
593 }
594
595 static xmlDocPtr parse_xml(char *ptr, int len)
596 {
597 #ifdef HAVE_XMLREADMEMORY
598     return xmlReadMemory(ptr, len, NULL, NULL,
599                          XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS);
600 #else
601     return xmlParseMemory(ptr, len);
602 #endif
603 }
604
605 static HRESULT WINAPI xmldoc_IPersistStreamInit_Load(
606     IPersistStreamInit *iface, LPSTREAM pStm)
607 {
608     xmldoc *This = impl_from_IPersistStreamInit(iface);
609     HRESULT hr;
610     HGLOBAL hglobal;
611     DWORD read, written, len;
612     BYTE buf[4096];
613     char *ptr;
614
615     TRACE("(%p, %p)\n", iface, pStm);
616
617     if (!pStm)
618         return E_INVALIDARG;
619
620     /* release previously allocated stream */
621     if (This->stream) IStream_Release(This->stream);
622     hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
623     if (FAILED(hr))
624         return hr;
625
626     do
627     {
628         IStream_Read(pStm, buf, sizeof(buf), &read);
629         hr = IStream_Write(This->stream, buf, read, &written);
630     } while(SUCCEEDED(hr) && written != 0 && read != 0);
631
632     if (FAILED(hr))
633     {
634         ERR("Failed to copy stream\n");
635         return hr;
636     }
637
638     hr = GetHGlobalFromStream(This->stream, &hglobal);
639     if (FAILED(hr))
640         return hr;
641
642     len = GlobalSize(hglobal);
643     ptr = GlobalLock(hglobal);
644     if (len != 0)
645     {
646         xmlFreeDoc(This->xmldoc);
647         This->xmldoc = parse_xml(ptr, len);
648     }
649     GlobalUnlock(hglobal);
650
651     if (!This->xmldoc)
652     {
653         ERR("Failed to parse xml\n");
654         return E_FAIL;
655     }
656
657     return S_OK;
658 }
659
660 static HRESULT WINAPI xmldoc_IPersistStreamInit_Save(
661     IPersistStreamInit *iface, LPSTREAM pStm, BOOL fClearDirty)
662 {
663     FIXME("(%p, %p, %d): stub!\n", iface, pStm, fClearDirty);
664     return E_NOTIMPL;
665 }
666
667 static HRESULT WINAPI xmldoc_IPersistStreamInit_GetSizeMax(
668     IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
669 {
670     xmldoc *This = impl_from_IPersistStreamInit(iface);
671     TRACE("(%p, %p)\n", This, pcbSize);
672     return E_NOTIMPL;
673 }
674
675 static HRESULT WINAPI xmldoc_IPersistStreamInit_InitNew(
676     IPersistStreamInit *iface)
677 {
678     xmldoc *This = impl_from_IPersistStreamInit(iface);
679     TRACE("(%p)\n", This);
680     return S_OK;
681 }
682
683 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
684 {
685   xmldoc_IPersistStreamInit_QueryInterface,
686   xmldoc_IPersistStreamInit_AddRef,
687   xmldoc_IPersistStreamInit_Release,
688   xmldoc_IPersistStreamInit_GetClassID,
689   xmldoc_IPersistStreamInit_IsDirty,
690   xmldoc_IPersistStreamInit_Load,
691   xmldoc_IPersistStreamInit_Save,
692   xmldoc_IPersistStreamInit_GetSizeMax,
693   xmldoc_IPersistStreamInit_InitNew
694 };
695
696 HRESULT XMLDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj)
697 {
698     xmldoc *doc;
699
700     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
701
702     doc = heap_alloc(sizeof (*doc));
703     if(!doc)
704         return E_OUTOFMEMORY;
705
706     doc->IXMLDocument_iface.lpVtbl = &xmldoc_vtbl;
707     doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
708     doc->ref = 1;
709     doc->error = S_OK;
710     doc->xmldoc = NULL;
711     doc->stream = NULL;
712
713     *ppObj = &doc->IXMLDocument_iface;
714
715     TRACE("returning iface %p\n", *ppObj);
716     return S_OK;
717 }
718
719 #else
720
721 HRESULT XMLDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj)
722 {
723     MESSAGE("This program tried to use an XMLDocument object, but\n"
724             "libxml2 support was not present at compile time.\n");
725     return E_NOTIMPL;
726 }
727
728 #endif