- Merge the remaining portion of the wlan-bringup branch
[reactos.git] / reactos / dll / win32 / 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 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "ole2.h"
30 #include "msxml2.h"
31 #include "wininet.h"
32 #include "winreg.h"
33 #include "shlwapi.h"
34 #include "ocidl.h"
35
36 #include "wine/debug.h"
37
38 #include "msxml_private.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
41
42 #ifdef HAVE_LIBXML2
43
44 /* FIXME: IXMLDocument needs to implement
45 * - IXMLError
46 * - IPersistMoniker
47 */
48
49 typedef struct _xmldoc
50 {
51 const IXMLDocumentVtbl *lpVtbl;
52 const IPersistStreamInitVtbl *lpvtblIPersistStreamInit;
53 LONG ref;
54 HRESULT error;
55
56 /* IXMLDocument */
57 xmlDocPtr xmldoc;
58
59 /* IPersistStream */
60 IStream *stream;
61 } xmldoc;
62
63 static inline xmldoc *impl_from_IXMLDocument(IXMLDocument *iface)
64 {
65 return (xmldoc *)((char*)iface - FIELD_OFFSET(xmldoc, lpVtbl));
66 }
67
68 static inline xmldoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
69 {
70 return (xmldoc *)((char*)iface - FIELD_OFFSET(xmldoc, lpvtblIPersistStreamInit));
71 }
72
73 static HRESULT WINAPI xmldoc_QueryInterface(IXMLDocument *iface, REFIID riid, void** ppvObject)
74 {
75 xmldoc *This = impl_from_IXMLDocument(iface);
76
77 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
78
79 if (IsEqualGUID(riid, &IID_IUnknown) ||
80 IsEqualGUID(riid, &IID_IXMLDocument) ||
81 IsEqualGUID(riid, &IID_IXMLDOMDocument))
82 {
83 *ppvObject = iface;
84 }
85 else if (IsEqualGUID(&IID_IPersistStreamInit, riid) ||
86 IsEqualGUID(&IID_IPersistStream, riid))
87 {
88 *ppvObject = &(This->lpvtblIPersistStreamInit);
89 }
90 else
91 {
92 FIXME("interface %s not implemented\n", debugstr_guid(riid));
93 return E_NOINTERFACE;
94 }
95
96 IXMLDocument_AddRef(iface);
97
98 return S_OK;
99 }
100
101 static ULONG WINAPI xmldoc_AddRef(IXMLDocument *iface)
102 {
103 xmldoc *This = impl_from_IXMLDocument(iface);
104 TRACE("%p\n", This);
105 return InterlockedIncrement(&This->ref);
106 }
107
108 static ULONG WINAPI xmldoc_Release(IXMLDocument *iface)
109 {
110 xmldoc *This = impl_from_IXMLDocument(iface);
111 LONG ref;
112
113 TRACE("%p\n", This);
114
115 ref = InterlockedDecrement(&This->ref);
116 if (ref == 0)
117 {
118 xmlFreeDoc(This->xmldoc);
119 if (This->stream) IStream_Release(This->stream);
120 heap_free(This);
121 }
122
123 return ref;
124 }
125
126 static HRESULT WINAPI xmldoc_GetTypeInfoCount(IXMLDocument *iface, UINT* pctinfo)
127 {
128 xmldoc *This = impl_from_IXMLDocument(iface);
129
130 TRACE("(%p)->(%p)\n", This, pctinfo);
131
132 *pctinfo = 1;
133
134 return S_OK;
135 }
136
137 static HRESULT WINAPI xmldoc_GetTypeInfo(IXMLDocument *iface, UINT iTInfo,
138 LCID lcid, ITypeInfo** ppTInfo)
139 {
140 xmldoc *This = impl_from_IXMLDocument(iface);
141 HRESULT hr;
142
143 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
144
145 hr = get_typeinfo(IXMLDocument_tid, ppTInfo);
146
147 return hr;
148 }
149
150 static HRESULT WINAPI xmldoc_GetIDsOfNames(IXMLDocument *iface, REFIID riid,
151 LPOLESTR* rgszNames, UINT cNames,
152 LCID lcid, DISPID* rgDispId)
153 {
154 xmldoc *This = impl_from_IXMLDocument(iface);
155 ITypeInfo *typeinfo;
156 HRESULT hr;
157
158 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
159 lcid, rgDispId);
160
161 if(!rgszNames || cNames == 0 || !rgDispId)
162 return E_INVALIDARG;
163
164 hr = get_typeinfo(IXMLDocument_tid, &typeinfo);
165 if(SUCCEEDED(hr))
166 {
167 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
168 ITypeInfo_Release(typeinfo);
169 }
170
171 return hr;
172 }
173
174 static HRESULT WINAPI xmldoc_Invoke(IXMLDocument *iface, DISPID dispIdMember,
175 REFIID riid, LCID lcid, WORD wFlags,
176 DISPPARAMS* pDispParams, VARIANT* pVarResult,
177 EXCEPINFO* pExcepInfo, UINT* puArgErr)
178 {
179 xmldoc *This = impl_from_IXMLDocument(iface);
180 ITypeInfo *typeinfo;
181 HRESULT hr;
182
183 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
184 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
185
186 hr = get_typeinfo(IXMLDocument_tid, &typeinfo);
187 if(SUCCEEDED(hr))
188 {
189 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
190 pVarResult, pExcepInfo, puArgErr);
191 ITypeInfo_Release(typeinfo);
192 }
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 const struct IBindStatusCallbackVtbl *lpVtbl;
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 FIXME("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, (IBindStatusCallback *)&xmldoc_bsc, 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, %p)\n", iface, ppElem);
507
508 if (!ppElem)
509 return E_INVALIDARG;
510
511 *ppElem = NULL;
512
513 if (V_VT(&vType) != VT_I4)
514 return E_INVALIDARG;
515
516 if(type_msxml_to_libxml(V_I4(&vType)) == -1)
517 return E_NOTIMPL;
518
519 node = xmlNewNode(NULL, empty);
520 node->type = type_msxml_to_libxml(V_I4(&vType));
521
522 /* FIXME: create xmlNodePtr based on vType and var1 */
523 return XMLElement_create((IUnknown *)iface, node, (LPVOID *)ppElem, TRUE);
524 }
525
526 static const struct IXMLDocumentVtbl xmldoc_vtbl =
527 {
528 xmldoc_QueryInterface,
529 xmldoc_AddRef,
530 xmldoc_Release,
531 xmldoc_GetTypeInfoCount,
532 xmldoc_GetTypeInfo,
533 xmldoc_GetIDsOfNames,
534 xmldoc_Invoke,
535 xmldoc_get_root,
536 xmldoc_get_fileSize,
537 xmldoc_put_fileModifiedDate,
538 xmldoc_get_fileUpdatedDate,
539 xmldoc_get_URL,
540 xmldoc_put_URL,
541 xmldoc_get_mimeType,
542 xmldoc_get_readyState,
543 xmldoc_get_charset,
544 xmldoc_put_charset,
545 xmldoc_get_version,
546 xmldoc_get_doctype,
547 xmldoc_get_dtdURl,
548 xmldoc_createElement
549 };
550
551 /************************************************************************
552 * xmldoc implementation of IPersistStreamInit.
553 */
554 static HRESULT WINAPI xmldoc_IPersistStreamInit_QueryInterface(
555 IPersistStreamInit *iface, REFIID riid, LPVOID *ppvObj)
556 {
557 xmldoc *this = impl_from_IPersistStreamInit(iface);
558 return IXMLDocument_QueryInterface((IXMLDocument *)this, riid, ppvObj);
559 }
560
561 static ULONG WINAPI xmldoc_IPersistStreamInit_AddRef(
562 IPersistStreamInit *iface)
563 {
564 xmldoc *this = impl_from_IPersistStreamInit(iface);
565 return IXMLDocument_AddRef((IXMLDocument *)this);
566 }
567
568 static ULONG WINAPI xmldoc_IPersistStreamInit_Release(
569 IPersistStreamInit *iface)
570 {
571 xmldoc *this = impl_from_IPersistStreamInit(iface);
572 return IXMLDocument_Release((IXMLDocument *)this);
573 }
574
575 static HRESULT WINAPI xmldoc_IPersistStreamInit_GetClassID(
576 IPersistStreamInit *iface, CLSID *classid)
577 {
578 xmldoc *this = impl_from_IPersistStreamInit(iface);
579 TRACE("(%p,%p)\n", this, classid);
580
581 if (!classid) return E_POINTER;
582
583 *classid = CLSID_XMLDocument;
584 return S_OK;
585 }
586
587 static HRESULT WINAPI xmldoc_IPersistStreamInit_IsDirty(
588 IPersistStreamInit *iface)
589 {
590 FIXME("(%p): stub!\n", iface);
591 return E_NOTIMPL;
592 }
593
594 xmlDocPtr parse_xml(char *ptr, int len)
595 {
596 #ifdef HAVE_XMLREADMEMORY
597 return xmlReadMemory(ptr, len, NULL, NULL,
598 XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NOBLANKS);
599 #else
600 return xmlParseMemory(ptr, len);
601 #endif
602 }
603
604 static HRESULT WINAPI xmldoc_IPersistStreamInit_Load(
605 IPersistStreamInit *iface, LPSTREAM pStm)
606 {
607 xmldoc *This = impl_from_IPersistStreamInit(iface);
608 HRESULT hr;
609 HGLOBAL hglobal;
610 DWORD read, written, len;
611 BYTE buf[4096];
612 char *ptr;
613
614 TRACE("(%p, %p)\n", iface, pStm);
615
616 if (!pStm)
617 return E_INVALIDARG;
618
619 /* release previously allocated stream */
620 if (This->stream) IStream_Release(This->stream);
621 hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
622 if (FAILED(hr))
623 return hr;
624
625 do
626 {
627 IStream_Read(pStm, buf, sizeof(buf), &read);
628 hr = IStream_Write(This->stream, buf, read, &written);
629 } while(SUCCEEDED(hr) && written != 0 && read != 0);
630
631 if (FAILED(hr))
632 {
633 ERR("Failed to copy stream\n");
634 return hr;
635 }
636
637 hr = GetHGlobalFromStream(This->stream, &hglobal);
638 if (FAILED(hr))
639 return hr;
640
641 len = GlobalSize(hglobal);
642 ptr = GlobalLock(hglobal);
643 if (len != 0)
644 {
645 xmlFreeDoc(This->xmldoc);
646 This->xmldoc = parse_xml(ptr, len);
647 }
648 GlobalUnlock(hglobal);
649
650 if (!This->xmldoc)
651 {
652 ERR("Failed to parse xml\n");
653 return E_FAIL;
654 }
655
656 return S_OK;
657 }
658
659 static HRESULT WINAPI xmldoc_IPersistStreamInit_Save(
660 IPersistStreamInit *iface, LPSTREAM pStm, BOOL fClearDirty)
661 {
662 FIXME("(%p, %p, %d): stub!\n", iface, pStm, fClearDirty);
663 return E_NOTIMPL;
664 }
665
666 static HRESULT WINAPI xmldoc_IPersistStreamInit_GetSizeMax(
667 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
668 {
669 xmldoc *This = impl_from_IPersistStreamInit(iface);
670 TRACE("(%p, %p)\n", This, pcbSize);
671 return E_NOTIMPL;
672 }
673
674 static HRESULT WINAPI xmldoc_IPersistStreamInit_InitNew(
675 IPersistStreamInit *iface)
676 {
677 xmldoc *This = impl_from_IPersistStreamInit(iface);
678 TRACE("(%p)\n", This);
679 return S_OK;
680 }
681
682 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
683 {
684 xmldoc_IPersistStreamInit_QueryInterface,
685 xmldoc_IPersistStreamInit_AddRef,
686 xmldoc_IPersistStreamInit_Release,
687 xmldoc_IPersistStreamInit_GetClassID,
688 xmldoc_IPersistStreamInit_IsDirty,
689 xmldoc_IPersistStreamInit_Load,
690 xmldoc_IPersistStreamInit_Save,
691 xmldoc_IPersistStreamInit_GetSizeMax,
692 xmldoc_IPersistStreamInit_InitNew
693 };
694
695 HRESULT XMLDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj)
696 {
697 xmldoc *doc;
698
699 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
700
701 doc = heap_alloc(sizeof (*doc));
702 if(!doc)
703 return E_OUTOFMEMORY;
704
705 doc->lpVtbl = &xmldoc_vtbl;
706 doc->lpvtblIPersistStreamInit = &xmldoc_IPersistStreamInit_VTable;
707 doc->ref = 1;
708 doc->error = S_OK;
709 doc->xmldoc = NULL;
710 doc->stream = NULL;
711
712 *ppObj = &doc->lpVtbl;
713
714 TRACE("returning iface %p\n", *ppObj);
715 return S_OK;
716 }
717
718 #else
719
720 HRESULT XMLDocument_create(IUnknown *pUnkOuter, LPVOID *ppObj)
721 {
722 MESSAGE("This program tried to use an XMLDocument object, but\n"
723 "libxml2 support was not present at compile time.\n");
724 return E_NOTIMPL;
725 }
726
727 #endif