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