msxml3: Added IDispatchEx support for SAXReader.
[wine/multimedia.git] / dlls / msxml3 / tests / saxreader.c
blobfbb1bd293df5641034786d0ca620fa0cb76a3044
1 /*
2 * XML test
4 * Copyright 2008 Piotr Caban
5 * Copyright 2011 Thomas Mullaly
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
23 #define CONST_VTABLE
25 #include <stdio.h>
26 #include <assert.h>
28 #include "windows.h"
29 #include "ole2.h"
30 #include "msxml2.h"
31 #include "msxml2did.h"
32 #include "ocidl.h"
33 #include "dispex.h"
35 #include "wine/test.h"
37 #define EXPECT_HR(hr,hr_exp) \
38 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
40 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
41 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
43 ULONG rc = IUnknown_AddRef(obj);
44 IUnknown_Release(obj);
45 ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1);
48 static BSTR alloc_str_from_narrow(const char *str)
50 int len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
51 BSTR ret = SysAllocStringLen(NULL, len - 1); /* NUL character added automatically */
52 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
53 return ret;
56 static BSTR alloced_bstrs[512];
57 static int alloced_bstrs_count;
59 static BSTR _bstr_(const char *str)
61 assert(alloced_bstrs_count < sizeof(alloced_bstrs)/sizeof(alloced_bstrs[0]));
62 alloced_bstrs[alloced_bstrs_count] = alloc_str_from_narrow(str);
63 return alloced_bstrs[alloced_bstrs_count++];
66 static void free_bstrs(void)
68 int i;
69 for (i = 0; i < alloced_bstrs_count; i++)
70 SysFreeString(alloced_bstrs[i]);
71 alloced_bstrs_count = 0;
74 typedef enum _CH {
75 CH_ENDTEST,
76 CH_PUTDOCUMENTLOCATOR,
77 CH_STARTDOCUMENT,
78 CH_ENDDOCUMENT,
79 CH_STARTPREFIXMAPPING,
80 CH_ENDPREFIXMAPPING,
81 CH_STARTELEMENT,
82 CH_ENDELEMENT,
83 CH_CHARACTERS,
84 CH_IGNORABLEWHITESPACE,
85 CH_PROCESSINGINSTRUCTION,
86 CH_SKIPPEDENTITY,
87 EH_ERROR,
88 EH_FATALERROR,
89 EG_IGNORABLEWARNING
90 } CH;
92 static const WCHAR szSimpleXML[] = {
93 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','\"','1','.','0','\"',' ','?','>','\n',
94 '<','B','a','n','k','A','c','c','o','u','n','t','>','\n',
95 ' ',' ',' ','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\n',
96 ' ',' ',' ','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\n',
97 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\n','\0'
100 static const WCHAR szCarriageRetTest[] = {
101 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"','?','>','\r','\n',
102 '<','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n',
103 '\t','<','N','u','m','b','e','r','>','1','2','3','4','<','/','N','u','m','b','e','r','>','\r','\n',
104 '\t','<','N','a','m','e','>','C','a','p','t','a','i','n',' ','A','h','a','b','<','/','N','a','m','e','>','\r','\n',
105 '<','/','B','a','n','k','A','c','c','o','u','n','t','>','\r','\n','\0'
108 static const WCHAR szUtf16XML[] = {
109 '<','?','x','m','l',' ','v','e','r','s','i','o','n','=','"','1','.','0','"',' ',
110 'e','n','c','o','d','i','n','g','=','"','U','T','F','-','1','6','"',' ',
111 's','t','a','n','d','a','l','o','n','e','=','"','n','o','"','?','>','\r','\n'
114 static const CHAR szUtf16BOM[] = {0xff, 0xfe};
116 static const CHAR szUtf8XML[] =
117 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n";
119 static const CHAR szTestXML[] =
120 "<?xml version=\"1.0\" ?>\n"
121 "<BankAccount>\n"
122 " <Number>1234</Number>\n"
123 " <Name>Captain Ahab</Name>\n"
124 "</BankAccount>\n";
126 static const CHAR szTestAttributes[] =
127 "<?xml version=\"1.0\" ?>\n"
128 "<document xmlns:test=\"prefix_test\" xmlns=\"prefix\" test:arg1=\"arg1\" arg2=\"arg2\" test:ar3=\"arg3\">\n"
129 "<node1 xmlns:p=\"test\" />"
130 "</document>\n";
132 typedef struct _contenthandlercheck {
133 CH id;
134 int line;
135 int column;
136 int line_v6;
137 int column_v6;
138 const char *arg1;
139 const char *arg2;
140 const char *arg3;
141 HRESULT ret;
142 } content_handler_test;
144 static content_handler_test contentHandlerTest1[] = {
145 { CH_PUTDOCUMENTLOCATOR, 0, 0, 1, 0 },
146 { CH_STARTDOCUMENT, 0, 0, 1, 22 },
147 { CH_STARTELEMENT, 2, 14, 2, 13, "", "BankAccount", "BankAccount" },
148 { CH_CHARACTERS, 2, 14, 3, 4, "\n " },
149 { CH_STARTELEMENT, 3, 12, 3, 11, "", "Number", "Number" },
150 { CH_CHARACTERS, 3, 12, 3, 16, "1234" },
151 { CH_ENDELEMENT, 3, 18, 3, 24, "", "Number", "Number" },
152 { CH_CHARACTERS, 3, 25, 4, 4, "\n " },
153 { CH_STARTELEMENT, 4, 10, 4, 9, "", "Name", "Name" },
154 { CH_CHARACTERS, 4, 10, 4, 22, "Captain Ahab" },
155 { CH_ENDELEMENT, 4, 24, 4, 28, "", "Name", "Name" },
156 { CH_CHARACTERS, 4, 29, 5, 1, "\n" },
157 { CH_ENDELEMENT, 5, 3, 5, 14, "", "BankAccount", "BankAccount" },
158 { CH_ENDDOCUMENT, 0, 0, 6, 0 },
159 { CH_ENDTEST }
162 static content_handler_test contentHandlerTest2[] = {
163 { CH_PUTDOCUMENTLOCATOR, 0, 0, 1, 0 },
164 { CH_STARTDOCUMENT, 0, 0, 1, 21 },
165 { CH_STARTELEMENT, 2, 14, 2, 13, "", "BankAccount", "BankAccount" },
166 { CH_CHARACTERS, 2, 14, 3, 0, "\n" },
167 { CH_CHARACTERS, 2, 16, 3, 2, "\t" },
168 { CH_STARTELEMENT, 3, 10, 3, 9, "", "Number", "Number" },
169 { CH_CHARACTERS, 3, 10, 3, 14, "1234" },
170 { CH_ENDELEMENT, 3, 16, 3, 22, "", "Number", "Number" },
171 { CH_CHARACTERS, 3, 23, 4, 0, "\n" },
172 { CH_CHARACTERS, 3, 25, 4, 2, "\t" },
173 { CH_STARTELEMENT, 4, 8, 4, 7, "", "Name", "Name" },
174 { CH_CHARACTERS, 4, 8, 4, 20, "Captain Ahab" },
175 { CH_ENDELEMENT, 4, 22, 4, 26, "", "Name", "Name" },
176 { CH_CHARACTERS, 4, 27, 5, 0, "\n" },
177 { CH_ENDELEMENT, 5, 3, 5, 14, "", "BankAccount", "BankAccount" },
178 { CH_ENDDOCUMENT, 0, 0, 6, 0 },
179 { CH_ENDTEST }
182 static content_handler_test contentHandlerTestError[] = {
183 { CH_PUTDOCUMENTLOCATOR, 0, 0, 1, 0, NULL, NULL, NULL, E_FAIL },
184 { EH_FATALERROR, 0, 0, 0, 0, NULL, NULL, NULL, E_FAIL },
185 { CH_ENDTEST }
188 static content_handler_test contentHandlerTestCallbackResults[] = {
189 { CH_PUTDOCUMENTLOCATOR, 0, 0, 1, 0, NULL, NULL, NULL, S_FALSE },
190 { CH_STARTDOCUMENT, 0, 0, 1, 22, NULL, NULL, NULL, S_FALSE },
191 { EH_FATALERROR, 0, 0, 0, 0, NULL, NULL, NULL, S_FALSE },
192 { CH_ENDTEST }
195 static content_handler_test contentHandlerTestCallbackResult6[] = {
196 { CH_PUTDOCUMENTLOCATOR, 0, 0, 1, 0, NULL, NULL, NULL, S_FALSE },
197 { CH_STARTDOCUMENT, 0, 0, 1, 22, NULL, NULL, NULL, S_FALSE },
198 { CH_STARTELEMENT, 2, 14, 2, 13, "", "BankAccount", "BankAccount", S_FALSE },
199 { CH_CHARACTERS, 2, 14, 3, 4, "\n ", NULL, NULL, S_FALSE },
200 { CH_STARTELEMENT, 3, 12, 3, 11, "", "Number", "Number", S_FALSE },
201 { CH_CHARACTERS, 3, 12, 3, 16, "1234", NULL, NULL, S_FALSE },
202 { CH_ENDELEMENT, 3, 18, 3, 24, "", "Number", "Number", S_FALSE },
203 { CH_CHARACTERS, 3, 25, 4, 4, "\n ", NULL, NULL, S_FALSE },
204 { CH_STARTELEMENT, 4, 10, 4, 9, "", "Name", "Name", S_FALSE },
205 { CH_CHARACTERS, 4, 10, 4, 22, "Captain Ahab", NULL, NULL, S_FALSE },
206 { CH_ENDELEMENT, 4, 24, 4, 28, "", "Name", "Name", S_FALSE },
207 { CH_CHARACTERS, 4, 29, 5, 1, "\n", NULL, NULL, S_FALSE },
208 { CH_ENDELEMENT, 5, 3, 5, 14, "", "BankAccount", "BankAccount", S_FALSE },
209 { CH_ENDDOCUMENT, 0, 0, 6, 0, NULL, NULL, NULL, S_FALSE },
210 { CH_ENDTEST }
213 static content_handler_test contentHandlerTestAttributes[] = {
214 { CH_PUTDOCUMENTLOCATOR, 0, 0, 1, 0 },
215 { CH_STARTDOCUMENT, 0, 0, 1, 22 },
216 { CH_STARTPREFIXMAPPING, 2, 96, 2, 95, "test", "prefix_test" },
217 { CH_STARTPREFIXMAPPING, 2, 96, 2, 95, "", "prefix" },
218 { CH_STARTELEMENT, 2, 96, 2, 95, "prefix", "document", "document" },
219 { CH_CHARACTERS, 2, 96, 3, 1, "\n" },
220 { CH_STARTPREFIXMAPPING, 3, 25, 3, 24, "p", "test" },
221 { CH_STARTELEMENT, 3, 25, 3, 24, "prefix", "node1", "node1" },
222 { CH_ENDELEMENT, 3, 25, 3, 24, "prefix", "node1", "node1" },
223 { CH_ENDPREFIXMAPPING, 3, 25, 3, 24, "p" },
224 { CH_ENDELEMENT, 3, 27, 3, 35, "prefix", "document", "document" },
225 { CH_ENDPREFIXMAPPING, 3, 27, 3, 35, "" },
226 { CH_ENDPREFIXMAPPING, 3, 27, 3, 35, "test" },
227 { CH_ENDDOCUMENT, 0, 0, 4, 0 },
228 { CH_ENDTEST }
231 static content_handler_test contentHandlerTestAttributes6[] = {
232 { CH_PUTDOCUMENTLOCATOR, 0, 0, 1, 0 },
233 { CH_STARTDOCUMENT, 0, 0, 1, 22 },
234 { CH_STARTPREFIXMAPPING, 2, 96, 2, 95, "test", "prefix_test" },
235 { CH_STARTPREFIXMAPPING, 2, 96, 2, 95, "", "prefix" },
236 { CH_STARTELEMENT, 2, 96, 2, 95, "prefix", "document", "document" },
237 { CH_CHARACTERS, 2, 96, 3, 1, "\n" },
238 { CH_STARTPREFIXMAPPING, 3, 25, 3, 24, "p", "test" },
239 { CH_STARTELEMENT, 3, 25, 3, 24, "prefix", "node1", "node1" },
240 { CH_ENDELEMENT, 3, 25, 3, 24, "prefix", "node1", "node1" },
241 { CH_ENDPREFIXMAPPING, 3, 25, 3, 24, "p" },
242 { CH_ENDELEMENT, 3, 27, 3, 35, "prefix", "document", "document" },
243 { CH_ENDPREFIXMAPPING, 3, 27, 3, 35, "test" },
244 { CH_ENDPREFIXMAPPING, 3, 27, 3, 35, "" },
245 { CH_ENDDOCUMENT, 0, 0, 4, 0 },
246 { CH_ENDTEST }
249 static content_handler_test *expectCall;
250 static ISAXLocator *locator;
251 int msxml_version;
253 static void test_saxstr(unsigned line, const WCHAR *szStr, int nStr, const char *szTest)
255 WCHAR buf[1024];
256 int len;
258 if(!szTest) {
259 ok_(__FILE__,line) (szStr == NULL, "szStr != NULL\n");
260 ok_(__FILE__,line) (nStr == 0, "nStr = %d, expected 0\n", nStr);
261 return;
264 len = strlen(szTest);
265 ok_(__FILE__,line) (len == nStr, "nStr = %d, expected %d (%s)\n", nStr, len, szTest);
266 if(len != nStr)
267 return;
269 MultiByteToWideChar(CP_ACP, 0, szTest, -1, buf, sizeof(buf)/sizeof(WCHAR));
270 ok_(__FILE__,line) (!memcmp(szStr, buf, len*sizeof(WCHAR)), "unexpected szStr %s, expected %s\n",
271 wine_dbgstr_wn(szStr, nStr), szTest);
274 static BOOL test_expect_call(CH id)
276 ok(expectCall->id == id, "unexpected call %d, expected %d\n", id, expectCall->id);
277 return expectCall->id == id;
280 static void test_locator(unsigned line, int loc_line, int loc_column)
282 int rcolumn, rline;
283 ISAXLocator_getLineNumber(locator, &rline);
284 ISAXLocator_getColumnNumber(locator, &rcolumn);
286 ok_(__FILE__,line) (rline == loc_line,
287 "unexpected line %d, expected %d\n", rline, loc_line);
288 ok_(__FILE__,line) (rcolumn == loc_column,
289 "unexpected column %d, expected %d\n", rcolumn, loc_column);
292 static HRESULT WINAPI contentHandler_QueryInterface(
293 ISAXContentHandler* iface,
294 REFIID riid,
295 void **ppvObject)
297 *ppvObject = NULL;
299 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXContentHandler))
301 *ppvObject = iface;
303 else
305 return E_NOINTERFACE;
308 return S_OK;
311 static ULONG WINAPI contentHandler_AddRef(
312 ISAXContentHandler* iface)
314 return 2;
317 static ULONG WINAPI contentHandler_Release(
318 ISAXContentHandler* iface)
320 return 1;
323 static HRESULT WINAPI contentHandler_putDocumentLocator(
324 ISAXContentHandler* iface,
325 ISAXLocator *pLocator)
327 ISAXAttributes *attr;
328 HRESULT hres;
330 if(!test_expect_call(CH_PUTDOCUMENTLOCATOR))
331 return E_FAIL;
333 locator = pLocator;
334 test_locator(__LINE__, msxml_version>=6 ? expectCall->line_v6 : expectCall->line,
335 msxml_version>=6 ? expectCall->column_v6 : expectCall->column);
337 if(msxml_version >= 6) {
338 hres = ISAXLocator_QueryInterface(pLocator, &IID_ISAXAttributes, (void**)&attr);
339 ok(hres == S_OK, "QueryInterface failed: %x\n", hres);
340 ISAXAttributes_Release(attr);
343 return (expectCall++)->ret;
346 static ISAXAttributes *test_attr_ptr;
347 static HRESULT WINAPI contentHandler_startDocument(
348 ISAXContentHandler* iface)
350 if(!test_expect_call(CH_STARTDOCUMENT))
351 return E_FAIL;
353 test_attr_ptr = NULL;
354 test_locator(__LINE__, msxml_version>=6 ? expectCall->line_v6 : expectCall->line,
355 msxml_version>=6 ? expectCall->column_v6 : expectCall->column);
357 return (expectCall++)->ret;
360 static HRESULT WINAPI contentHandler_endDocument(
361 ISAXContentHandler* iface)
363 if(!test_expect_call(CH_ENDDOCUMENT))
364 return E_FAIL;
366 test_locator(__LINE__, msxml_version>=6 ? expectCall->line_v6 : expectCall->line,
367 msxml_version>=6 ? expectCall->column_v6 : expectCall->column);
369 return (expectCall++)->ret;
372 static HRESULT WINAPI contentHandler_startPrefixMapping(
373 ISAXContentHandler* iface,
374 const WCHAR *pPrefix,
375 int nPrefix,
376 const WCHAR *pUri,
377 int nUri)
379 if(!test_expect_call(CH_STARTPREFIXMAPPING))
380 return E_FAIL;
382 test_saxstr(__LINE__, pPrefix, nPrefix, expectCall->arg1);
383 test_saxstr(__LINE__, pUri, nUri, expectCall->arg2);
384 test_locator(__LINE__, msxml_version>=6 ? expectCall->line_v6 : expectCall->line,
385 msxml_version>=6 ? expectCall->column_v6 : expectCall->column);
387 return (expectCall++)->ret;
390 static HRESULT WINAPI contentHandler_endPrefixMapping(
391 ISAXContentHandler* iface,
392 const WCHAR *pPrefix,
393 int nPrefix)
395 if(!test_expect_call(CH_ENDPREFIXMAPPING))
396 return E_FAIL;
398 test_saxstr(__LINE__, pPrefix, nPrefix, expectCall->arg1);
399 test_locator(__LINE__, msxml_version>=6 ? expectCall->line_v6 : expectCall->line,
400 msxml_version>=6 ? expectCall->column_v6 : expectCall->column);
402 return (expectCall++)->ret;
405 static HRESULT WINAPI contentHandler_startElement(
406 ISAXContentHandler* iface,
407 const WCHAR *pNamespaceUri,
408 int nNamespaceUri,
409 const WCHAR *pLocalName,
410 int nLocalName,
411 const WCHAR *pQName,
412 int nQName,
413 ISAXAttributes *pAttr)
415 int len;
416 HRESULT hres;
418 if(!test_expect_call(CH_STARTELEMENT))
419 return E_FAIL;
421 test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, expectCall->arg1);
422 test_saxstr(__LINE__, pLocalName, nLocalName, expectCall->arg2);
423 test_saxstr(__LINE__, pQName, nQName, expectCall->arg3);
424 test_locator(__LINE__, msxml_version>=6 ? expectCall->line_v6 : expectCall->line,
425 msxml_version>=6 ? expectCall->column_v6 : expectCall->column);
427 if(!test_attr_ptr)
428 test_attr_ptr = pAttr;
429 ok(test_attr_ptr == pAttr, "Multiple ISAXAttributes instances are used (%p %p)\n", test_attr_ptr, pAttr);
431 if(expectCall == contentHandlerTestAttributes+4) {
432 const WCHAR *uri_ptr = NULL;
433 int i;
434 /* msxml3 returns attributes and namespaces in the input order */
435 hres = ISAXAttributes_getLength(pAttr, &len);
436 ok(hres == S_OK, "getLength returned %x\n", hres);
437 ok(len == 5, "Incorrect number of attributes: %d\n", len);
438 ok(msxml_version < 6, "wrong msxml_version: %d\n", msxml_version);
440 for(i=0; i<len; i++) {
441 hres = ISAXAttributes_getName(pAttr, i, &pNamespaceUri, &nNamespaceUri,
442 &pLocalName, &nLocalName, &pQName, &nQName);
443 ok(hres == S_OK, "getName returned %x\n", hres);
445 if(nQName == 4) {
446 todo_wine ok(i==3, "Incorrect attributes order\n");
447 test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, "");
448 test_saxstr(__LINE__, pLocalName, nLocalName, "arg2");
449 test_saxstr(__LINE__, pQName, nQName, "arg2");
450 } else if(nQName == 5) {
451 todo_wine ok(i==1, "Incorrect attributes order\n");
452 test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, "");
453 test_saxstr(__LINE__, pLocalName, nLocalName, "");
454 test_saxstr(__LINE__, pQName, nQName, "xmlns");
455 } else if(nQName == 8) {
456 todo_wine ok(i==4, "Incorrect attributes order\n");
457 test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, "prefix_test");
458 test_saxstr(__LINE__, pLocalName, nLocalName, "ar3");
459 test_saxstr(__LINE__, pQName, nQName, "test:ar3");
460 ok(uri_ptr == pNamespaceUri, "Incorrect NamespaceUri pointer\n");
461 } else if(nQName == 9) {
462 todo_wine ok(i==2, "Incorrect attributes order\n");
463 test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, "prefix_test");
464 test_saxstr(__LINE__, pLocalName, nLocalName, "arg1");
465 test_saxstr(__LINE__, pQName, nQName, "test:arg1");
466 uri_ptr = pNamespaceUri;
467 } else if(nQName == 10) {
468 todo_wine ok(i==0, "Incorrect attributes order\n");
469 test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, "");
470 test_saxstr(__LINE__, pLocalName, nLocalName, "");
471 test_saxstr(__LINE__, pQName, nQName, "xmlns:test");
472 } else {
473 ok(0, "Unexpected attribute\n");
476 } else if(expectCall == contentHandlerTestAttributes6+4) {
477 const WCHAR *uri_ptr;
479 /* msxml6 returns attributes first and then namespaces */
480 hres = ISAXAttributes_getLength(pAttr, &len);
481 ok(hres == S_OK, "getLength returned %x\n", hres);
482 ok(len == 5, "Incorrect number of attributes: %d\n", len);
483 ok(msxml_version >= 6, "wrong msxml_version: %d\n", msxml_version);
485 hres = ISAXAttributes_getName(pAttr, 0, &pNamespaceUri, &nNamespaceUri,
486 &pLocalName, &nLocalName, &pQName, &nQName);
487 ok(hres == S_OK, "getName returned %x\n", hres);
488 test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, "prefix_test");
489 test_saxstr(__LINE__, pLocalName, nLocalName, "arg1");
490 test_saxstr(__LINE__, pQName, nQName, "test:arg1");
491 uri_ptr = pNamespaceUri;
493 hres = ISAXAttributes_getName(pAttr, 1, &pNamespaceUri, &nNamespaceUri,
494 &pLocalName, &nLocalName, &pQName, &nQName);
495 ok(hres == S_OK, "getName returned %x\n", hres);
496 test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, "");
497 test_saxstr(__LINE__, pLocalName, nLocalName, "arg2");
498 test_saxstr(__LINE__, pQName, nQName, "arg2");
500 hres = ISAXAttributes_getName(pAttr, 2, &pNamespaceUri, &nNamespaceUri,
501 &pLocalName, &nLocalName, &pQName, &nQName);
502 ok(hres == S_OK, "getName returned %x\n", hres);
503 test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, "prefix_test");
504 test_saxstr(__LINE__, pLocalName, nLocalName, "ar3");
505 test_saxstr(__LINE__, pQName, nQName, "test:ar3");
506 ok(uri_ptr == pNamespaceUri, "Incorrect NamespaceUri pointer\n");
508 hres = ISAXAttributes_getName(pAttr, 3, &pNamespaceUri, &nNamespaceUri,
509 &pLocalName, &nLocalName, &pQName, &nQName);
510 ok(hres == S_OK, "getName returned %x\n", hres);
511 test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, "http://www.w3.org/2000/xmlns/");
512 test_saxstr(__LINE__, pLocalName, nLocalName, "");
513 test_saxstr(__LINE__, pQName, nQName, "xmlns:test");
515 hres = ISAXAttributes_getName(pAttr, 4, &pNamespaceUri, &nNamespaceUri,
516 &pLocalName, &nLocalName, &pQName, &nQName);
517 ok(hres == S_OK, "getName returned %x\n", hres);
518 test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, "http://www.w3.org/2000/xmlns/");
519 test_saxstr(__LINE__, pLocalName, nLocalName, "");
520 test_saxstr(__LINE__, pQName, nQName, "xmlns");
523 return (expectCall++)->ret;
526 static HRESULT WINAPI contentHandler_endElement(
527 ISAXContentHandler* iface,
528 const WCHAR *pNamespaceUri,
529 int nNamespaceUri,
530 const WCHAR *pLocalName,
531 int nLocalName,
532 const WCHAR *pQName,
533 int nQName)
535 if(!test_expect_call(CH_ENDELEMENT))
536 return E_FAIL;
538 test_saxstr(__LINE__, pNamespaceUri, nNamespaceUri, expectCall->arg1);
539 test_saxstr(__LINE__, pLocalName, nLocalName, expectCall->arg2);
540 test_saxstr(__LINE__, pQName, nQName, expectCall->arg3);
541 test_locator(__LINE__, msxml_version>=6 ? expectCall->line_v6 : expectCall->line,
542 msxml_version>=6 ? expectCall->column_v6 : expectCall->column);
544 return (expectCall++)->ret;
547 static HRESULT WINAPI contentHandler_characters(
548 ISAXContentHandler* iface,
549 const WCHAR *pChars,
550 int nChars)
552 if(!test_expect_call(CH_CHARACTERS))
553 return E_FAIL;
555 test_saxstr(__LINE__, pChars, nChars, expectCall->arg1);
556 test_locator(__LINE__, msxml_version>=6 ? expectCall->line_v6 : expectCall->line,
557 msxml_version>=6 ? expectCall->column_v6 : expectCall->column);
559 return (expectCall++)->ret;
562 static HRESULT WINAPI contentHandler_ignorableWhitespace(
563 ISAXContentHandler* iface,
564 const WCHAR *pChars,
565 int nChars)
567 if(!test_expect_call(CH_IGNORABLEWHITESPACE))
568 return E_FAIL;
570 test_saxstr(__LINE__, pChars, nChars, expectCall->arg1);
571 test_locator(__LINE__, msxml_version>=6 ? expectCall->line_v6 : expectCall->line,
572 msxml_version>=6 ? expectCall->column_v6 : expectCall->column);
574 return (expectCall++)->ret;
577 static HRESULT WINAPI contentHandler_processingInstruction(
578 ISAXContentHandler* iface,
579 const WCHAR *pTarget,
580 int nTarget,
581 const WCHAR *pData,
582 int nData)
584 if(!test_expect_call(CH_PROCESSINGINSTRUCTION))
585 return E_FAIL;
587 test_saxstr(__LINE__, pTarget, nTarget, expectCall->arg1);
588 test_saxstr(__LINE__, pData, nData, expectCall->arg2);
589 test_locator(__LINE__, msxml_version>=6 ? expectCall->line_v6 : expectCall->line,
590 msxml_version>=6 ? expectCall->column_v6 : expectCall->column);
592 return (expectCall++)->ret;
595 static HRESULT WINAPI contentHandler_skippedEntity(
596 ISAXContentHandler* iface,
597 const WCHAR *pName,
598 int nName)
600 if(!test_expect_call(CH_SKIPPEDENTITY))
601 return E_FAIL;
603 test_saxstr(__LINE__, pName, nName, expectCall->arg1);
604 test_locator(__LINE__, msxml_version>=6 ? expectCall->line_v6 : expectCall->line,
605 msxml_version>=6 ? expectCall->column_v6 : expectCall->column);
607 return (expectCall++)->ret;
611 static const ISAXContentHandlerVtbl contentHandlerVtbl =
613 contentHandler_QueryInterface,
614 contentHandler_AddRef,
615 contentHandler_Release,
616 contentHandler_putDocumentLocator,
617 contentHandler_startDocument,
618 contentHandler_endDocument,
619 contentHandler_startPrefixMapping,
620 contentHandler_endPrefixMapping,
621 contentHandler_startElement,
622 contentHandler_endElement,
623 contentHandler_characters,
624 contentHandler_ignorableWhitespace,
625 contentHandler_processingInstruction,
626 contentHandler_skippedEntity
629 static ISAXContentHandler contentHandler = { &contentHandlerVtbl };
631 static HRESULT WINAPI isaxerrorHandler_QueryInterface(
632 ISAXErrorHandler* iface,
633 REFIID riid,
634 void **ppvObject)
636 *ppvObject = NULL;
638 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXErrorHandler))
640 *ppvObject = iface;
642 else
644 return E_NOINTERFACE;
647 return S_OK;
650 static ULONG WINAPI isaxerrorHandler_AddRef(
651 ISAXErrorHandler* iface)
653 return 2;
656 static ULONG WINAPI isaxerrorHandler_Release(
657 ISAXErrorHandler* iface)
659 return 1;
662 static HRESULT WINAPI isaxerrorHandler_error(
663 ISAXErrorHandler* iface,
664 ISAXLocator *pLocator,
665 const WCHAR *pErrorMessage,
666 HRESULT hrErrorCode)
668 ok(0, "unexpected call\n");
669 return S_OK;
672 static HRESULT WINAPI isaxerrorHandler_fatalError(
673 ISAXErrorHandler* iface,
674 ISAXLocator *pLocator,
675 const WCHAR *pErrorMessage,
676 HRESULT hrErrorCode)
678 if(!test_expect_call(EH_FATALERROR))
679 return E_FAIL;
681 ok(hrErrorCode == expectCall->ret, "hrErrorCode = %x, expected %x\n", hrErrorCode, expectCall->ret);
683 expectCall++;
684 return S_OK;
687 static HRESULT WINAPI isaxerrorHanddler_ignorableWarning(
688 ISAXErrorHandler* iface,
689 ISAXLocator *pLocator,
690 const WCHAR *pErrorMessage,
691 HRESULT hrErrorCode)
693 ok(0, "unexpected call\n");
694 return S_OK;
697 static const ISAXErrorHandlerVtbl errorHandlerVtbl =
699 isaxerrorHandler_QueryInterface,
700 isaxerrorHandler_AddRef,
701 isaxerrorHandler_Release,
702 isaxerrorHandler_error,
703 isaxerrorHandler_fatalError,
704 isaxerrorHanddler_ignorableWarning
707 static ISAXErrorHandler errorHandler = { &errorHandlerVtbl };
709 static HRESULT WINAPI isaxattributes_QueryInterface(
710 ISAXAttributes* iface,
711 REFIID riid,
712 void **ppvObject)
714 *ppvObject = NULL;
716 if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ISAXAttributes))
718 *ppvObject = iface;
720 else
722 return E_NOINTERFACE;
725 return S_OK;
728 static ULONG WINAPI isaxattributes_AddRef(ISAXAttributes* iface)
730 return 2;
733 static ULONG WINAPI isaxattributes_Release(ISAXAttributes* iface)
735 return 1;
738 static HRESULT WINAPI isaxattributes_getLength(ISAXAttributes* iface, int *length)
740 *length = 2;
741 return S_OK;
744 static HRESULT WINAPI isaxattributes_getURI(
745 ISAXAttributes* iface,
746 int nIndex,
747 const WCHAR **pUrl,
748 int *pUriSize)
750 ok(0, "unexpected call\n");
751 return E_NOTIMPL;
754 static HRESULT WINAPI isaxattributes_getLocalName(
755 ISAXAttributes* iface,
756 int nIndex,
757 const WCHAR **pLocalName,
758 int *pLocalNameLength)
760 ok(0, "unexpected call\n");
761 return E_NOTIMPL;
764 static HRESULT WINAPI isaxattributes_getQName(
765 ISAXAttributes* iface,
766 int nIndex,
767 const WCHAR **pQName,
768 int *pQNameLength)
770 static const WCHAR attr1W[] = {'a',':','a','t','t','r','1','j','u','n','k',0};
771 static const WCHAR attr2W[] = {'a','t','t','r','2','j','u','n','k',0};
773 ok(nIndex == 0 || nIndex == 1, "invalid index received %d\n", nIndex);
775 *pQName = (nIndex == 0) ? attr1W : attr2W;
776 *pQNameLength = (nIndex == 0) ? 7 : 5;
778 return S_OK;
781 static HRESULT WINAPI isaxattributes_getName(
782 ISAXAttributes* iface,
783 int nIndex,
784 const WCHAR **pUri,
785 int * pUriLength,
786 const WCHAR ** pLocalName,
787 int * pLocalNameSize,
788 const WCHAR ** pQName,
789 int * pQNameLength)
791 ok(0, "unexpected call\n");
792 return E_NOTIMPL;
795 static HRESULT WINAPI isaxattributes_getIndexFromName(
796 ISAXAttributes* iface,
797 const WCHAR * pUri,
798 int cUriLength,
799 const WCHAR * pLocalName,
800 int cocalNameLength,
801 int * index)
803 ok(0, "unexpected call\n");
804 return E_NOTIMPL;
807 static HRESULT WINAPI isaxattributes_getIndexFromQName(
808 ISAXAttributes* iface,
809 const WCHAR * pQName,
810 int nQNameLength,
811 int * index)
813 ok(0, "unexpected call\n");
814 return E_NOTIMPL;
817 static HRESULT WINAPI isaxattributes_getType(
818 ISAXAttributes* iface,
819 int nIndex,
820 const WCHAR ** pType,
821 int * pTypeLength)
823 ok(0, "unexpected call\n");
824 return E_NOTIMPL;
827 static HRESULT WINAPI isaxattributes_getTypeFromName(
828 ISAXAttributes* iface,
829 const WCHAR * pUri,
830 int nUri,
831 const WCHAR * pLocalName,
832 int nLocalName,
833 const WCHAR ** pType,
834 int * nType)
836 ok(0, "unexpected call\n");
837 return E_NOTIMPL;
840 static HRESULT WINAPI isaxattributes_getTypeFromQName(
841 ISAXAttributes* iface,
842 const WCHAR * pQName,
843 int nQName,
844 const WCHAR ** pType,
845 int * nType)
847 ok(0, "unexpected call\n");
848 return E_NOTIMPL;
851 static HRESULT WINAPI isaxattributes_getValue(
852 ISAXAttributes* iface,
853 int nIndex,
854 const WCHAR ** pValue,
855 int * nValue)
857 static const WCHAR attrval1W[] = {'a','1','j','u','n','k',0};
858 static const WCHAR attrval2W[] = {'a','2','j','u','n','k',0};
860 ok(nIndex == 0 || nIndex == 1, "invalid index received %d\n", nIndex);
862 *pValue = (nIndex == 0) ? attrval1W : attrval2W;
863 *nValue = 2;
865 return S_OK;
868 static HRESULT WINAPI isaxattributes_getValueFromName(
869 ISAXAttributes* iface,
870 const WCHAR * pUri,
871 int nUri,
872 const WCHAR * pLocalName,
873 int nLocalName,
874 const WCHAR ** pValue,
875 int * nValue)
877 ok(0, "unexpected call\n");
878 return E_NOTIMPL;
881 static HRESULT WINAPI isaxattributes_getValueFromQName(
882 ISAXAttributes* iface,
883 const WCHAR * pQName,
884 int nQName,
885 const WCHAR ** pValue,
886 int * nValue)
888 ok(0, "unexpected call\n");
889 return E_NOTIMPL;
892 static const ISAXAttributesVtbl SAXAttributesVtbl =
894 isaxattributes_QueryInterface,
895 isaxattributes_AddRef,
896 isaxattributes_Release,
897 isaxattributes_getLength,
898 isaxattributes_getURI,
899 isaxattributes_getLocalName,
900 isaxattributes_getQName,
901 isaxattributes_getName,
902 isaxattributes_getIndexFromName,
903 isaxattributes_getIndexFromQName,
904 isaxattributes_getType,
905 isaxattributes_getTypeFromName,
906 isaxattributes_getTypeFromQName,
907 isaxattributes_getValue,
908 isaxattributes_getValueFromName,
909 isaxattributes_getValueFromQName
912 static ISAXAttributes saxattributes = { &SAXAttributesVtbl };
914 static int handler_addrefcalled;
916 static HRESULT WINAPI isaxlexical_QueryInterface(ISAXLexicalHandler* iface, REFIID riid, void **ppvObject)
918 *ppvObject = NULL;
920 if(IsEqualGUID(riid, &IID_IUnknown) ||
921 IsEqualGUID(riid, &IID_ISAXLexicalHandler))
923 *ppvObject = iface;
925 else
927 return E_NOINTERFACE;
930 return S_OK;
933 static ULONG WINAPI isaxlexical_AddRef(ISAXLexicalHandler* iface)
935 handler_addrefcalled++;
936 return 2;
939 static ULONG WINAPI isaxlexical_Release(ISAXLexicalHandler* iface)
941 return 1;
944 static HRESULT WINAPI isaxlexical_startDTD(ISAXLexicalHandler* iface,
945 const WCHAR * pName, int nName, const WCHAR * pPublicId,
946 int nPublicId, const WCHAR * pSystemId, int nSystemId)
948 ok(0, "call not expected\n");
949 return E_NOTIMPL;
952 static HRESULT WINAPI isaxlexical_endDTD(ISAXLexicalHandler* iface)
954 ok(0, "call not expected\n");
955 return E_NOTIMPL;
958 static HRESULT WINAPI isaxlexical_startEntity(ISAXLexicalHandler *iface,
959 const WCHAR * pName, int nName)
961 ok(0, "call not expected\n");
962 return E_NOTIMPL;
965 static HRESULT WINAPI isaxlexical_endEntity(ISAXLexicalHandler *iface,
966 const WCHAR * pName, int nName)
968 ok(0, "call not expected\n");
969 return E_NOTIMPL;
972 static HRESULT WINAPI isaxlexical_startCDATA(ISAXLexicalHandler *iface)
974 ok(0, "call not expected\n");
975 return E_NOTIMPL;
978 static HRESULT WINAPI isaxlexical_endCDATA(ISAXLexicalHandler *iface)
980 ok(0, "call not expected\n");
981 return E_NOTIMPL;
984 static HRESULT WINAPI isaxlexical_comment(ISAXLexicalHandler *iface,
985 const WCHAR * pChars, int nChars)
987 ok(0, "call not expected\n");
988 return E_NOTIMPL;
991 static const ISAXLexicalHandlerVtbl SAXLexicalHandlerVtbl =
993 isaxlexical_QueryInterface,
994 isaxlexical_AddRef,
995 isaxlexical_Release,
996 isaxlexical_startDTD,
997 isaxlexical_endDTD,
998 isaxlexical_startEntity,
999 isaxlexical_endEntity,
1000 isaxlexical_startCDATA,
1001 isaxlexical_endCDATA,
1002 isaxlexical_comment
1005 static ISAXLexicalHandler saxlexicalhandler = { &SAXLexicalHandlerVtbl };
1007 static HRESULT WINAPI isaxdecl_QueryInterface(ISAXDeclHandler* iface, REFIID riid, void **ppvObject)
1009 *ppvObject = NULL;
1011 if(IsEqualGUID(riid, &IID_IUnknown) ||
1012 IsEqualGUID(riid, &IID_ISAXDeclHandler))
1014 *ppvObject = iface;
1016 else
1018 return E_NOINTERFACE;
1021 return S_OK;
1024 static ULONG WINAPI isaxdecl_AddRef(ISAXDeclHandler* iface)
1026 handler_addrefcalled++;
1027 return 2;
1030 static ULONG WINAPI isaxdecl_Release(ISAXDeclHandler* iface)
1032 return 1;
1035 static HRESULT WINAPI isaxdecl_elementDecl(ISAXDeclHandler* iface,
1036 const WCHAR * pName, int nName, const WCHAR * pModel, int nModel)
1038 ok(0, "call not expected\n");
1039 return E_NOTIMPL;
1042 static HRESULT WINAPI isaxdecl_attributeDecl(ISAXDeclHandler* iface,
1043 const WCHAR * pElementName, int nElementName, const WCHAR * pAttributeName,
1044 int nAttributeName, const WCHAR * pType, int nType, const WCHAR * pValueDefault,
1045 int nValueDefault, const WCHAR * pValue, int nValue)
1047 ok(0, "call not expected\n");
1048 return E_NOTIMPL;
1051 static HRESULT WINAPI isaxdecl_internalEntityDecl(ISAXDeclHandler* iface,
1052 const WCHAR * pName, int nName, const WCHAR * pValue, int nValue)
1054 ok(0, "call not expected\n");
1055 return E_NOTIMPL;
1058 static HRESULT WINAPI isaxdecl_externalEntityDecl(ISAXDeclHandler* iface,
1059 const WCHAR * pName, int nName, const WCHAR * pPublicId, int nPublicId,
1060 const WCHAR * pSystemId, int nSystemId)
1062 ok(0, "call not expected\n");
1063 return E_NOTIMPL;
1066 static const ISAXDeclHandlerVtbl SAXDeclHandlerVtbl =
1068 isaxdecl_QueryInterface,
1069 isaxdecl_AddRef,
1070 isaxdecl_Release,
1071 isaxdecl_elementDecl,
1072 isaxdecl_attributeDecl,
1073 isaxdecl_internalEntityDecl,
1074 isaxdecl_externalEntityDecl
1077 static ISAXDeclHandler saxdeclhandler = { &SAXDeclHandlerVtbl };
1079 typedef struct mxwriter_write_test_t {
1080 BOOL last;
1081 const BYTE *data;
1082 DWORD cb;
1083 BOOL null_written;
1084 BOOL fail_write;
1085 } mxwriter_write_test;
1087 typedef struct mxwriter_stream_test_t {
1088 VARIANT_BOOL bom;
1089 const char *encoding;
1090 mxwriter_write_test expected_writes[4];
1091 } mxwriter_stream_test;
1093 static const mxwriter_write_test *current_write_test;
1094 static DWORD current_stream_test_index;
1096 static HRESULT WINAPI istream_QueryInterface(IStream *iface, REFIID riid, void **ppvObject)
1098 *ppvObject = NULL;
1100 if(IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_IUnknown))
1101 *ppvObject = iface;
1102 else
1103 return E_NOINTERFACE;
1105 return S_OK;
1108 static ULONG WINAPI istream_AddRef(IStream *iface)
1110 return 2;
1113 static ULONG WINAPI istream_Release(IStream *iface)
1115 return 1;
1118 static HRESULT WINAPI istream_Read(IStream *iface, void *pv, ULONG cb, ULONG *pcbRead)
1120 ok(0, "unexpected call\n");
1121 return E_NOTIMPL;
1124 static HRESULT WINAPI istream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *pcbWritten)
1126 BOOL fail = FALSE;
1128 ok(pv != NULL, "pv == NULL\n");
1130 if(current_write_test->last) {
1131 ok(0, "Too many Write calls made on test %d\n", current_stream_test_index);
1132 return E_FAIL;
1135 fail = current_write_test->fail_write;
1137 ok(current_write_test->cb == cb, "Expected %d, but got %d on test %d\n",
1138 current_write_test->cb, cb, current_stream_test_index);
1140 if(!pcbWritten)
1141 ok(current_write_test->null_written, "pcbWritten was NULL on test %d\n", current_stream_test_index);
1142 else
1143 ok(!memcmp(current_write_test->data, pv, cb), "Unexpected data on test %d\n", current_stream_test_index);
1145 ++current_write_test;
1147 if(pcbWritten)
1148 *pcbWritten = cb;
1150 return fail ? E_FAIL : S_OK;
1153 static HRESULT WINAPI istream_Seek(IStream *iface, LARGE_INTEGER dlibMove, DWORD dwOrigin,
1154 ULARGE_INTEGER *plibNewPosition)
1156 ok(0, "unexpected call\n");
1157 return E_NOTIMPL;
1160 static HRESULT WINAPI istream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize)
1162 ok(0, "unexpected call\n");
1163 return E_NOTIMPL;
1166 static HRESULT WINAPI istream_CopyTo(IStream *iface, IStream *pstm, ULARGE_INTEGER cb,
1167 ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *plibWritten)
1169 ok(0, "unexpected call\n");
1170 return E_NOTIMPL;
1173 static HRESULT WINAPI istream_Commit(IStream *iface, DWORD grfCommitFlags)
1175 ok(0, "unexpected call\n");
1176 return E_NOTIMPL;
1179 static HRESULT WINAPI istream_Revert(IStream *iface)
1181 ok(0, "unexpected call\n");
1182 return E_NOTIMPL;
1185 static HRESULT WINAPI istream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1186 ULARGE_INTEGER cb, DWORD dwLockType)
1188 ok(0, "unexpected call\n");
1189 return E_NOTIMPL;
1192 static HRESULT WINAPI istream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset,
1193 ULARGE_INTEGER cb, DWORD dwLockType)
1195 ok(0, "unexpected call\n");
1196 return E_NOTIMPL;
1199 static HRESULT WINAPI istream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag)
1201 ok(0, "unexpected call\n");
1202 return E_NOTIMPL;
1205 static HRESULT WINAPI istream_Clone(IStream *iface, IStream **ppstm)
1207 ok(0, "unexpected call\n");
1208 return E_NOTIMPL;
1211 static const IStreamVtbl StreamVtbl = {
1212 istream_QueryInterface,
1213 istream_AddRef,
1214 istream_Release,
1215 istream_Read,
1216 istream_Write,
1217 istream_Seek,
1218 istream_SetSize,
1219 istream_CopyTo,
1220 istream_Commit,
1221 istream_Revert,
1222 istream_LockRegion,
1223 istream_UnlockRegion,
1224 istream_Stat,
1225 istream_Clone
1228 static IStream mxstream = { &StreamVtbl };
1230 static void test_saxreader(int version)
1232 HRESULT hr;
1233 ISAXXMLReader *reader = NULL;
1234 VARIANT var;
1235 ISAXContentHandler *lpContentHandler;
1236 ISAXErrorHandler *lpErrorHandler;
1237 SAFEARRAY *pSA;
1238 SAFEARRAYBOUND SADim[1];
1239 char *pSAData = NULL;
1240 IStream *iStream;
1241 ULARGE_INTEGER liSize;
1242 LARGE_INTEGER liPos;
1243 ULONG bytesWritten;
1244 HANDLE file;
1245 static const CHAR testXmlA[] = "test.xml";
1246 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
1247 IXMLDOMDocument *domDocument;
1248 BSTR bstrData;
1249 VARIANT_BOOL vBool;
1251 msxml_version = version;
1252 if(version == 3) {
1253 hr = CoCreateInstance(&CLSID_SAXXMLReader30, NULL, CLSCTX_INPROC_SERVER,
1254 &IID_ISAXXMLReader, (LPVOID*)&reader);
1255 } else if(version == 6) {
1256 hr = CoCreateInstance(&CLSID_SAXXMLReader60, NULL, CLSCTX_INPROC_SERVER,
1257 &IID_ISAXXMLReader, (LPVOID*)&reader);
1258 if(hr == REGDB_E_CLASSNOTREG) {
1259 win_skip("SAXXMLReader6 not registered\n");
1260 return;
1262 } else {
1263 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
1264 &IID_ISAXXMLReader, (LPVOID*)&reader);
1266 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1268 if(version != 6) {
1269 hr = ISAXXMLReader_getContentHandler(reader, NULL);
1270 ok(hr == E_POINTER, "Expected E_POINTER, got %08x\n", hr);
1272 hr = ISAXXMLReader_getErrorHandler(reader, NULL);
1273 ok(hr == E_POINTER, "Expected E_POINTER, got %08x\n", hr);
1276 hr = ISAXXMLReader_getContentHandler(reader, &lpContentHandler);
1277 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1278 ok(lpContentHandler == NULL, "Expected %p, got %p\n", NULL, lpContentHandler);
1280 hr = ISAXXMLReader_getErrorHandler(reader, &lpErrorHandler);
1281 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1282 ok(lpErrorHandler == NULL, "Expected %p, got %p\n", NULL, lpErrorHandler);
1284 hr = ISAXXMLReader_putContentHandler(reader, NULL);
1285 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1287 hr = ISAXXMLReader_putContentHandler(reader, &contentHandler);
1288 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1290 hr = ISAXXMLReader_putErrorHandler(reader, &errorHandler);
1291 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1293 hr = ISAXXMLReader_getContentHandler(reader, &lpContentHandler);
1294 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1295 ok(lpContentHandler == &contentHandler, "Expected %p, got %p\n", &contentHandler, lpContentHandler);
1297 V_VT(&var) = VT_BSTR;
1298 V_BSTR(&var) = SysAllocString(szSimpleXML);
1300 expectCall = contentHandlerTest1;
1301 hr = ISAXXMLReader_parse(reader, var);
1302 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1303 test_expect_call(CH_ENDTEST);
1305 VariantClear(&var);
1307 SADim[0].lLbound= 0;
1308 SADim[0].cElements= sizeof(szTestXML)-1;
1309 pSA = SafeArrayCreate(VT_UI1, 1, SADim);
1310 SafeArrayAccessData(pSA, (void**)&pSAData);
1311 memcpy(pSAData, szTestXML, sizeof(szTestXML)-1);
1312 SafeArrayUnaccessData(pSA);
1313 V_VT(&var) = VT_ARRAY|VT_UI1;
1314 V_ARRAY(&var) = pSA;
1316 expectCall = contentHandlerTest1;
1317 hr = ISAXXMLReader_parse(reader, var);
1318 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1319 test_expect_call(CH_ENDTEST);
1321 SafeArrayDestroy(pSA);
1323 CreateStreamOnHGlobal(NULL, TRUE, &iStream);
1324 liSize.QuadPart = strlen(szTestXML);
1325 IStream_SetSize(iStream, liSize);
1326 IStream_Write(iStream, szTestXML, strlen(szTestXML), &bytesWritten);
1327 liPos.QuadPart = 0;
1328 IStream_Seek(iStream, liPos, STREAM_SEEK_SET, NULL);
1329 V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
1330 V_UNKNOWN(&var) = (IUnknown*)iStream;
1332 expectCall = contentHandlerTest1;
1333 hr = ISAXXMLReader_parse(reader, var);
1334 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1335 test_expect_call(CH_ENDTEST);
1337 IStream_Release(iStream);
1339 CreateStreamOnHGlobal(NULL, TRUE, &iStream);
1340 liSize.QuadPart = strlen(szTestAttributes);
1341 IStream_SetSize(iStream, liSize);
1342 IStream_Write(iStream, szTestAttributes, strlen(szTestAttributes), &bytesWritten);
1343 liPos.QuadPart = 0;
1344 IStream_Seek(iStream, liPos, STREAM_SEEK_SET, NULL);
1345 V_VT(&var) = VT_UNKNOWN|VT_DISPATCH;
1346 V_UNKNOWN(&var) = (IUnknown*)iStream;
1348 if(version >= 6)
1349 expectCall = contentHandlerTestAttributes6;
1350 else
1351 expectCall = contentHandlerTestAttributes;
1352 hr = ISAXXMLReader_parse(reader, var);
1353 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1354 test_expect_call(CH_ENDTEST);
1356 IStream_Release(iStream);
1358 V_VT(&var) = VT_BSTR;
1359 V_BSTR(&var) = SysAllocString(szCarriageRetTest);
1361 expectCall = contentHandlerTest2;
1362 hr = ISAXXMLReader_parse(reader, var);
1363 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1364 test_expect_call(CH_ENDTEST);
1366 VariantClear(&var);
1368 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1369 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
1370 WriteFile(file, szTestXML, sizeof(szTestXML)-1, &bytesWritten, NULL);
1371 CloseHandle(file);
1373 expectCall = contentHandlerTest1;
1374 hr = ISAXXMLReader_parseURL(reader, testXmlW);
1375 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1376 test_expect_call(CH_ENDTEST);
1378 expectCall = contentHandlerTestError;
1379 hr = ISAXXMLReader_parseURL(reader, testXmlW);
1380 ok(hr == E_FAIL, "Expected E_FAIL, got %08x\n", hr);
1381 test_expect_call(CH_ENDTEST);
1383 if(version >= 6)
1384 expectCall = contentHandlerTestCallbackResult6;
1385 else
1386 expectCall = contentHandlerTestCallbackResults;
1387 hr = ISAXXMLReader_parseURL(reader, testXmlW);
1388 ok(hr == (version>=6 ? S_OK : S_FALSE), "Expected S_FALSE, got %08x\n", hr);
1389 test_expect_call(CH_ENDTEST);
1391 DeleteFileA(testXmlA);
1393 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
1394 &IID_IXMLDOMDocument, (LPVOID*)&domDocument);
1395 if(FAILED(hr))
1397 skip("Failed to create DOMDocument instance\n");
1398 return;
1400 bstrData = SysAllocString(szSimpleXML);
1401 hr = IXMLDOMDocument_loadXML(domDocument, bstrData, &vBool);
1402 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1403 V_VT(&var) = VT_UNKNOWN;
1404 V_UNKNOWN(&var) = (IUnknown*)domDocument;
1406 expectCall = contentHandlerTest2;
1407 hr = ISAXXMLReader_parse(reader, var);
1408 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1409 test_expect_call(CH_ENDTEST);
1410 IXMLDOMDocument_Release(domDocument);
1412 ISAXXMLReader_Release(reader);
1413 SysFreeString(bstrData);
1416 struct saxreader_props_test_t
1418 const char *prop_name;
1419 IUnknown *iface;
1422 static const struct saxreader_props_test_t props_test_data[] = {
1423 { "http://xml.org/sax/properties/lexical-handler", (IUnknown*)&saxlexicalhandler },
1424 { "http://xml.org/sax/properties/declaration-handler", (IUnknown*)&saxdeclhandler },
1425 { 0 }
1428 static void test_saxreader_properties(void)
1430 const struct saxreader_props_test_t *ptr = props_test_data;
1431 ISAXXMLReader *reader;
1432 HRESULT hr;
1434 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
1435 &IID_ISAXXMLReader, (void**)&reader);
1436 EXPECT_HR(hr, S_OK);
1438 hr = ISAXXMLReader_getProperty(reader, _bstr_("http://xml.org/sax/properties/lexical-handler"), NULL);
1439 EXPECT_HR(hr, E_POINTER);
1441 while (ptr->prop_name)
1443 VARIANT v;
1445 V_VT(&v) = VT_EMPTY;
1446 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
1447 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
1448 EXPECT_HR(hr, S_OK);
1449 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
1450 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
1452 V_VT(&v) = VT_UNKNOWN;
1453 V_UNKNOWN(&v) = ptr->iface;
1454 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
1455 EXPECT_HR(hr, S_OK);
1457 V_VT(&v) = VT_EMPTY;
1458 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
1459 handler_addrefcalled = 0;
1460 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
1461 EXPECT_HR(hr, S_OK);
1462 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
1463 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
1464 ok(handler_addrefcalled == 1, "AddRef called %d times\n", handler_addrefcalled);
1465 VariantClear(&v);
1467 V_VT(&v) = VT_EMPTY;
1468 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
1469 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
1470 EXPECT_HR(hr, S_OK);
1472 V_VT(&v) = VT_EMPTY;
1473 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
1474 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
1475 EXPECT_HR(hr, S_OK);
1476 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
1477 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
1479 V_VT(&v) = VT_UNKNOWN;
1480 V_UNKNOWN(&v) = ptr->iface;
1481 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
1482 EXPECT_HR(hr, S_OK);
1484 /* only VT_EMPTY seems to be valid to reset property */
1485 V_VT(&v) = VT_I4;
1486 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
1487 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
1488 EXPECT_HR(hr, E_INVALIDARG);
1490 V_VT(&v) = VT_EMPTY;
1491 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
1492 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
1493 EXPECT_HR(hr, S_OK);
1494 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
1495 ok(V_UNKNOWN(&v) == ptr->iface, "got %p\n", V_UNKNOWN(&v));
1496 VariantClear(&v);
1498 V_VT(&v) = VT_UNKNOWN;
1499 V_UNKNOWN(&v) = NULL;
1500 hr = ISAXXMLReader_putProperty(reader, _bstr_(ptr->prop_name), v);
1501 EXPECT_HR(hr, S_OK);
1503 V_VT(&v) = VT_EMPTY;
1504 V_UNKNOWN(&v) = (IUnknown*)0xdeadbeef;
1505 hr = ISAXXMLReader_getProperty(reader, _bstr_(ptr->prop_name), &v);
1506 EXPECT_HR(hr, S_OK);
1507 ok(V_VT(&v) == VT_UNKNOWN, "got %d\n", V_VT(&v));
1508 ok(V_UNKNOWN(&v) == NULL, "got %p\n", V_UNKNOWN(&v));
1510 ptr++;
1513 ISAXXMLReader_Release(reader);
1514 free_bstrs();
1517 struct feature_ns_entry_t {
1518 const GUID *guid;
1519 const char *clsid;
1520 VARIANT_BOOL value;
1523 static const struct feature_ns_entry_t feature_ns_entry_data[] = {
1524 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", VARIANT_TRUE },
1525 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", VARIANT_TRUE },
1526 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", VARIANT_TRUE },
1527 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", VARIANT_TRUE },
1528 { 0 }
1531 static void test_saxreader_features(void)
1533 const struct feature_ns_entry_t *entry = feature_ns_entry_data;
1534 ISAXXMLReader *reader;
1536 while (entry->guid)
1538 VARIANT_BOOL value;
1539 HRESULT hr;
1541 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
1542 if (hr != S_OK)
1544 win_skip("can't create %s instance\n", entry->clsid);
1545 entry++;
1546 continue;
1549 value = 0xc;
1550 hr = ISAXXMLReader_getFeature(reader, _bstr_("http://xml.org/sax/features/namespaces"), &value);
1551 EXPECT_HR(hr, S_OK);
1553 ok(entry->value == value, "%s: got wrong default value %x, expected %x\n", entry->clsid, value, entry->value);
1555 ISAXXMLReader_Release(reader);
1557 entry++;
1561 /* UTF-8 data with UTF-8 BOM and UTF-16 in prolog */
1562 static const CHAR UTF8BOMTest[] =
1563 "\xEF\xBB\xBF<?xml version = \"1.0\" encoding = \"UTF-16\"?>\n"
1564 "<a></a>\n";
1566 struct enc_test_entry_t {
1567 const GUID *guid;
1568 const char *clsid;
1569 const char *data;
1570 HRESULT hr;
1571 int todo;
1574 static const struct enc_test_entry_t encoding_test_data[] = {
1575 { &CLSID_SAXXMLReader, "CLSID_SAXXMLReader", UTF8BOMTest, 0xc00ce56f, 1 },
1576 { &CLSID_SAXXMLReader30, "CLSID_SAXXMLReader30", UTF8BOMTest, 0xc00ce56f, 1 },
1577 { &CLSID_SAXXMLReader40, "CLSID_SAXXMLReader40", UTF8BOMTest, S_OK, 0 },
1578 { &CLSID_SAXXMLReader60, "CLSID_SAXXMLReader60", UTF8BOMTest, S_OK, 0 },
1579 { 0 }
1582 static void test_encoding(void)
1584 const struct enc_test_entry_t *entry = encoding_test_data;
1585 static const WCHAR testXmlW[] = {'t','e','s','t','.','x','m','l',0};
1586 static const CHAR testXmlA[] = "test.xml";
1587 ISAXXMLReader *reader;
1588 DWORD written;
1589 HANDLE file;
1590 HRESULT hr;
1592 while (entry->guid)
1594 hr = CoCreateInstance(entry->guid, NULL, CLSCTX_INPROC_SERVER, &IID_ISAXXMLReader, (void**)&reader);
1595 if (hr != S_OK)
1597 win_skip("can't create %s instance\n", entry->clsid);
1598 entry++;
1599 continue;
1602 file = CreateFileA(testXmlA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1603 ok(file != INVALID_HANDLE_VALUE, "Could not create file: %u\n", GetLastError());
1604 WriteFile(file, UTF8BOMTest, sizeof(UTF8BOMTest)-1, &written, NULL);
1605 CloseHandle(file);
1607 hr = ISAXXMLReader_parseURL(reader, testXmlW);
1608 if (entry->todo)
1609 todo_wine ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
1610 else
1611 ok(hr == entry->hr, "Expected 0x%08x, got 0x%08x. CLSID %s\n", entry->hr, hr, entry->clsid);
1613 DeleteFileA(testXmlA);
1614 ISAXXMLReader_Release(reader);
1616 entry++;
1620 static void test_mxwriter_contenthandler(void)
1622 ISAXContentHandler *handler;
1623 IMXWriter *writer, *writer2;
1624 HRESULT hr;
1626 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1627 &IID_IMXWriter, (void**)&writer);
1628 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1630 EXPECT_REF(writer, 1);
1632 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&handler);
1633 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1634 EXPECT_REF(writer, 2);
1635 EXPECT_REF(handler, 2);
1637 hr = ISAXContentHandler_QueryInterface(handler, &IID_IMXWriter, (void**)&writer2);
1638 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1639 ok(writer2 == writer, "got %p, expected %p\n", writer2, writer);
1640 EXPECT_REF(writer, 3);
1641 EXPECT_REF(writer2, 3);
1642 IMXWriter_Release(writer2);
1644 ISAXContentHandler_Release(handler);
1645 IMXWriter_Release(writer);
1648 struct msxmlsupported_data_t
1650 const GUID *clsid;
1651 const char *name;
1652 BOOL supported;
1655 static struct msxmlsupported_data_t msxmlsupported_data[] =
1657 { &CLSID_MXXMLWriter, "MXXMLWriter" },
1658 { &CLSID_MXXMLWriter30, "MXXMLWriter30" },
1659 { &CLSID_MXXMLWriter40, "MXXMLWriter40" },
1660 { &CLSID_MXXMLWriter60, "MXXMLWriter60" },
1661 { NULL }
1664 static BOOL is_mxwriter_supported(const GUID *clsid, const struct msxmlsupported_data_t *table)
1666 while (table->clsid)
1668 if (table->clsid == clsid) return table->supported;
1669 table++;
1671 return FALSE;
1674 struct mxwriter_props_t
1676 const GUID *clsid;
1677 VARIANT_BOOL bom;
1678 VARIANT_BOOL disable_escape;
1679 VARIANT_BOOL indent;
1680 VARIANT_BOOL omitdecl;
1681 VARIANT_BOOL standalone;
1682 const char *encoding;
1685 static const struct mxwriter_props_t mxwriter_default_props[] =
1687 { &CLSID_MXXMLWriter, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
1688 { &CLSID_MXXMLWriter30, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
1689 { &CLSID_MXXMLWriter40, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
1690 { &CLSID_MXXMLWriter60, VARIANT_TRUE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, VARIANT_FALSE, "UTF-16" },
1691 { NULL }
1694 static void test_mxwriter_default_properties(const struct mxwriter_props_t *table)
1696 int i = 0;
1698 while (table->clsid)
1700 IMXWriter *writer;
1701 VARIANT_BOOL b;
1702 BSTR encoding;
1703 HRESULT hr;
1705 if (!is_mxwriter_supported(table->clsid, msxmlsupported_data))
1707 table++;
1708 i++;
1709 continue;
1712 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
1713 &IID_IMXWriter, (void**)&writer);
1714 EXPECT_HR(hr, S_OK);
1716 b = !table->bom;
1717 hr = IMXWriter_get_byteOrderMark(writer, &b);
1718 EXPECT_HR(hr, S_OK);
1719 ok(table->bom == b, "test %d: got BOM %d, expected %d\n", i, b, table->bom);
1721 b = !table->disable_escape;
1722 hr = IMXWriter_get_disableOutputEscaping(writer, &b);
1723 EXPECT_HR(hr, S_OK);
1724 ok(table->disable_escape == b, "test %d: got disable escape %d, expected %d\n", i, b,
1725 table->disable_escape);
1727 b = !table->indent;
1728 hr = IMXWriter_get_indent(writer, &b);
1729 EXPECT_HR(hr, S_OK);
1730 ok(table->indent == b, "test %d: got indent %d, expected %d\n", i, b, table->indent);
1732 b = !table->omitdecl;
1733 hr = IMXWriter_get_omitXMLDeclaration(writer, &b);
1734 EXPECT_HR(hr, S_OK);
1735 ok(table->omitdecl == b, "test %d: got omitdecl %d, expected %d\n", i, b, table->omitdecl);
1737 b = !table->standalone;
1738 hr = IMXWriter_get_standalone(writer, &b);
1739 EXPECT_HR(hr, S_OK);
1740 ok(table->standalone == b, "test %d: got standalone %d, expected %d\n", i, b, table->standalone);
1742 hr = IMXWriter_get_encoding(writer, &encoding);
1743 EXPECT_HR(hr, S_OK);
1744 ok(!lstrcmpW(encoding, _bstr_(table->encoding)), "test %d: got encoding %s, expected %s\n",
1745 i, wine_dbgstr_w(encoding), table->encoding);
1746 SysFreeString(encoding);
1748 IMXWriter_Release(writer);
1750 table++;
1751 i++;
1755 static void test_mxwriter_properties(void)
1757 static const WCHAR utf16W[] = {'U','T','F','-','1','6',0};
1758 static const WCHAR emptyW[] = {0};
1759 static const WCHAR testW[] = {'t','e','s','t',0};
1760 IMXWriter *writer;
1761 VARIANT_BOOL b;
1762 HRESULT hr;
1763 BSTR str, str2;
1765 test_mxwriter_default_properties(mxwriter_default_props);
1767 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1768 &IID_IMXWriter, (void**)&writer);
1769 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1771 hr = IMXWriter_get_disableOutputEscaping(writer, NULL);
1772 ok(hr == E_POINTER, "got %08x\n", hr);
1774 hr = IMXWriter_get_byteOrderMark(writer, NULL);
1775 ok(hr == E_POINTER, "got %08x\n", hr);
1777 hr = IMXWriter_get_indent(writer, NULL);
1778 ok(hr == E_POINTER, "got %08x\n", hr);
1780 hr = IMXWriter_get_omitXMLDeclaration(writer, NULL);
1781 ok(hr == E_POINTER, "got %08x\n", hr);
1783 hr = IMXWriter_get_standalone(writer, NULL);
1784 ok(hr == E_POINTER, "got %08x\n", hr);
1786 /* set and check */
1787 hr = IMXWriter_put_standalone(writer, VARIANT_TRUE);
1788 ok(hr == S_OK, "got %08x\n", hr);
1790 b = VARIANT_FALSE;
1791 hr = IMXWriter_get_standalone(writer, &b);
1792 ok(hr == S_OK, "got %08x\n", hr);
1793 ok(b == VARIANT_TRUE, "got %d\n", b);
1795 hr = IMXWriter_get_encoding(writer, NULL);
1796 ok(hr == E_POINTER, "got %08x\n", hr);
1798 /* UTF-16 is a default setting apparently */
1799 str = (void*)0xdeadbeef;
1800 hr = IMXWriter_get_encoding(writer, &str);
1801 ok(hr == S_OK, "got %08x\n", hr);
1802 ok(lstrcmpW(str, utf16W) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
1804 str2 = (void*)0xdeadbeef;
1805 hr = IMXWriter_get_encoding(writer, &str2);
1806 ok(hr == S_OK, "got %08x\n", hr);
1807 ok(str != str2, "expected newly allocated, got same %p\n", str);
1809 SysFreeString(str2);
1810 SysFreeString(str);
1812 /* put empty string */
1813 str = SysAllocString(emptyW);
1814 hr = IMXWriter_put_encoding(writer, str);
1815 ok(hr == E_INVALIDARG, "got %08x\n", hr);
1816 SysFreeString(str);
1818 str = (void*)0xdeadbeef;
1819 hr = IMXWriter_get_encoding(writer, &str);
1820 ok(hr == S_OK, "got %08x\n", hr);
1821 ok(!lstrcmpW(str, emptyW) == 0, "expected empty string, got %s\n", wine_dbgstr_w(str));
1822 SysFreeString(str);
1824 /* invalid encoding name */
1825 str = SysAllocString(testW);
1826 hr = IMXWriter_put_encoding(writer, str);
1827 ok(hr == E_INVALIDARG, "got %08x\n", hr);
1828 SysFreeString(str);
1830 hr = IMXWriter_get_version(writer, NULL);
1831 ok(hr == E_POINTER, "got %08x\n", hr);
1832 /* default version is 'surprisingly' 1.0 */
1833 hr = IMXWriter_get_version(writer, &str);
1834 ok(hr == S_OK, "got %08x\n", hr);
1835 ok(!lstrcmpW(str, _bstr_("1.0")), "got %s\n", wine_dbgstr_w(str));
1836 SysFreeString(str);
1838 /* store version string as is */
1839 hr = IMXWriter_put_version(writer, NULL);
1840 ok(hr == E_INVALIDARG, "got %08x\n", hr);
1842 hr = IMXWriter_put_version(writer, _bstr_("1.0"));
1843 ok(hr == S_OK, "got %08x\n", hr);
1845 hr = IMXWriter_put_version(writer, _bstr_(""));
1846 ok(hr == S_OK, "got %08x\n", hr);
1847 hr = IMXWriter_get_version(writer, &str);
1848 ok(hr == S_OK, "got %08x\n", hr);
1849 ok(!lstrcmpW(str, _bstr_("")), "got %s\n", wine_dbgstr_w(str));
1850 SysFreeString(str);
1852 hr = IMXWriter_put_version(writer, _bstr_("a.b"));
1853 ok(hr == S_OK, "got %08x\n", hr);
1854 hr = IMXWriter_get_version(writer, &str);
1855 ok(hr == S_OK, "got %08x\n", hr);
1856 ok(!lstrcmpW(str, _bstr_("a.b")), "got %s\n", wine_dbgstr_w(str));
1857 SysFreeString(str);
1859 hr = IMXWriter_put_version(writer, _bstr_("2.0"));
1860 ok(hr == S_OK, "got %08x\n", hr);
1861 hr = IMXWriter_get_version(writer, &str);
1862 ok(hr == S_OK, "got %08x\n", hr);
1863 ok(!lstrcmpW(str, _bstr_("2.0")), "got %s\n", wine_dbgstr_w(str));
1864 SysFreeString(str);
1866 IMXWriter_Release(writer);
1867 free_bstrs();
1870 static void test_mxwriter_flush(void)
1872 ISAXContentHandler *content;
1873 IMXWriter *writer;
1874 LARGE_INTEGER pos;
1875 ULARGE_INTEGER pos2;
1876 IStream *stream;
1877 VARIANT dest;
1878 HRESULT hr;
1880 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1881 &IID_IMXWriter, (void**)&writer);
1882 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1884 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1885 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1886 EXPECT_REF(stream, 1);
1888 /* detach when nothing was attached */
1889 V_VT(&dest) = VT_EMPTY;
1890 hr = IMXWriter_put_output(writer, dest);
1891 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1893 /* attach stream */
1894 V_VT(&dest) = VT_UNKNOWN;
1895 V_UNKNOWN(&dest) = (IUnknown*)stream;
1896 hr = IMXWriter_put_output(writer, dest);
1897 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1898 todo_wine EXPECT_REF(stream, 3);
1900 /* detach setting VT_EMPTY destination */
1901 V_VT(&dest) = VT_EMPTY;
1902 hr = IMXWriter_put_output(writer, dest);
1903 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1904 EXPECT_REF(stream, 1);
1906 V_VT(&dest) = VT_UNKNOWN;
1907 V_UNKNOWN(&dest) = (IUnknown*)stream;
1908 hr = IMXWriter_put_output(writer, dest);
1909 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1911 /* flush() doesn't detach a stream */
1912 hr = IMXWriter_flush(writer);
1913 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1914 todo_wine EXPECT_REF(stream, 3);
1916 pos.QuadPart = 0;
1917 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
1918 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1919 ok(pos2.QuadPart == 0, "expected stream beginning\n");
1921 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1922 ok(hr == S_OK, "got %08x\n", hr);
1924 hr = ISAXContentHandler_startDocument(content);
1925 ok(hr == S_OK, "got %08x\n", hr);
1927 pos.QuadPart = 0;
1928 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
1929 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1930 ok(pos2.QuadPart != 0, "expected stream beginning\n");
1932 /* already started */
1933 hr = ISAXContentHandler_startDocument(content);
1934 ok(hr == S_OK, "got %08x\n", hr);
1936 hr = ISAXContentHandler_endDocument(content);
1937 ok(hr == S_OK, "got %08x\n", hr);
1939 /* flushed on endDocument() */
1940 pos.QuadPart = 0;
1941 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
1942 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1943 ok(pos2.QuadPart != 0, "expected stream position moved\n");
1945 ISAXContentHandler_Release(content);
1946 IStream_Release(stream);
1947 IMXWriter_Release(writer);
1950 static void test_mxwriter_startenddocument(void)
1952 ISAXContentHandler *content;
1953 IMXWriter *writer;
1954 VARIANT dest;
1955 HRESULT hr;
1957 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1958 &IID_IMXWriter, (void**)&writer);
1959 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1961 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
1962 ok(hr == S_OK, "got %08x\n", hr);
1964 hr = ISAXContentHandler_startDocument(content);
1965 ok(hr == S_OK, "got %08x\n", hr);
1967 hr = ISAXContentHandler_endDocument(content);
1968 ok(hr == S_OK, "got %08x\n", hr);
1970 V_VT(&dest) = VT_EMPTY;
1971 hr = IMXWriter_get_output(writer, &dest);
1972 ok(hr == S_OK, "got %08x\n", hr);
1973 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1974 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
1975 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1976 VariantClear(&dest);
1978 /* now try another startDocument */
1979 hr = ISAXContentHandler_startDocument(content);
1980 ok(hr == S_OK, "got %08x\n", hr);
1981 /* and get duplicated prolog */
1982 V_VT(&dest) = VT_EMPTY;
1983 hr = IMXWriter_get_output(writer, &dest);
1984 ok(hr == S_OK, "got %08x\n", hr);
1985 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
1986 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"
1987 "<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
1988 "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
1989 VariantClear(&dest);
1991 ISAXContentHandler_Release(content);
1992 IMXWriter_Release(writer);
1994 /* now with omitted declaration */
1995 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
1996 &IID_IMXWriter, (void**)&writer);
1997 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
1999 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2000 ok(hr == S_OK, "got %08x\n", hr);
2002 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2003 ok(hr == S_OK, "got %08x\n", hr);
2005 hr = ISAXContentHandler_startDocument(content);
2006 ok(hr == S_OK, "got %08x\n", hr);
2008 hr = ISAXContentHandler_endDocument(content);
2009 ok(hr == S_OK, "got %08x\n", hr);
2011 V_VT(&dest) = VT_EMPTY;
2012 hr = IMXWriter_get_output(writer, &dest);
2013 ok(hr == S_OK, "got %08x\n", hr);
2014 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2015 ok(!lstrcmpW(_bstr_(""), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2016 VariantClear(&dest);
2018 ISAXContentHandler_Release(content);
2019 IMXWriter_Release(writer);
2021 free_bstrs();
2024 enum startendtype
2026 StartElement,
2027 EndElement,
2028 StartEndElement
2031 struct writer_startendelement_t {
2032 const GUID *clsid;
2033 enum startendtype type;
2034 const char *uri;
2035 const char *local_name;
2036 const char *qname;
2037 const char *output;
2038 HRESULT hr;
2039 ISAXAttributes *attr;
2042 static const struct writer_startendelement_t writer_startendelement[] = {
2043 /* 0 */
2044 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2045 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2046 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2047 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, NULL, "<>", S_OK },
2048 { &CLSID_MXXMLWriter, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2049 /* 5 */
2050 { &CLSID_MXXMLWriter30, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2051 { &CLSID_MXXMLWriter40, StartElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2052 { &CLSID_MXXMLWriter60, StartElement, "uri", NULL, NULL, "<>", S_OK },
2053 { &CLSID_MXXMLWriter, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2054 { &CLSID_MXXMLWriter30, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2055 /* 10 */
2056 { &CLSID_MXXMLWriter40, StartElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2057 { &CLSID_MXXMLWriter60, StartElement, NULL, "local", NULL, "<>", S_OK },
2058 { &CLSID_MXXMLWriter, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2059 { &CLSID_MXXMLWriter30, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2060 { &CLSID_MXXMLWriter40, StartElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2061 /* 15 */
2062 { &CLSID_MXXMLWriter60, StartElement, NULL, NULL, "qname", "<qname>", S_OK },
2063 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2064 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2065 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2066 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "qname", "<qname>", S_OK },
2067 /* 20 */
2068 { &CLSID_MXXMLWriter, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2069 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2070 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2071 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", NULL, "<>", S_OK },
2072 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2073 /* 25 */
2074 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2075 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2076 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local>", S_OK },
2077 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2078 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2079 /* 30 */
2080 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2081 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local2", "<uri:local2>", S_OK },
2082 /* endElement tests */
2083 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2084 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2085 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, NULL, NULL, E_INVALIDARG },
2086 /* 35 */
2087 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, NULL, "</>", S_OK },
2088 { &CLSID_MXXMLWriter, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2089 { &CLSID_MXXMLWriter30, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2090 { &CLSID_MXXMLWriter40, EndElement, "uri", NULL, NULL, NULL, E_INVALIDARG },
2091 { &CLSID_MXXMLWriter60, EndElement, "uri", NULL, NULL, "</>", S_OK },
2092 /* 40 */
2093 { &CLSID_MXXMLWriter, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2094 { &CLSID_MXXMLWriter30, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2095 { &CLSID_MXXMLWriter40, EndElement, NULL, "local", NULL, NULL, E_INVALIDARG },
2096 { &CLSID_MXXMLWriter60, EndElement, NULL, "local", NULL, "</>", S_OK },
2097 { &CLSID_MXXMLWriter, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2098 /* 45 */
2099 { &CLSID_MXXMLWriter30, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2100 { &CLSID_MXXMLWriter40, EndElement, NULL, NULL, "qname", NULL, E_INVALIDARG },
2101 { &CLSID_MXXMLWriter60, EndElement, NULL, NULL, "qname", "</qname>", S_OK },
2102 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2103 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2104 /* 50 */
2105 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2106 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "qname", "</qname>", S_OK },
2107 { &CLSID_MXXMLWriter, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2108 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2109 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", NULL, NULL, E_INVALIDARG },
2110 /* 55 */
2111 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", NULL, "</>", S_OK },
2112 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2113 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2114 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2115 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local", "</uri:local>", S_OK },
2116 /* 60 */
2117 { &CLSID_MXXMLWriter, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2118 { &CLSID_MXXMLWriter30, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2119 { &CLSID_MXXMLWriter40, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2120 { &CLSID_MXXMLWriter60, EndElement, "uri", "local", "uri:local2", "</uri:local2>", S_OK },
2122 /* with attributes */
2123 { &CLSID_MXXMLWriter, StartElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\">", S_OK, &saxattributes },
2124 /* 65 */
2125 { &CLSID_MXXMLWriter30, StartElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\">", S_OK, &saxattributes },
2126 { &CLSID_MXXMLWriter40, StartElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\">", S_OK, &saxattributes },
2127 { &CLSID_MXXMLWriter60, StartElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\">", S_OK, &saxattributes },
2128 /* empty elements */
2129 { &CLSID_MXXMLWriter, StartEndElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\"/>", S_OK, &saxattributes },
2130 { &CLSID_MXXMLWriter30, StartEndElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\"/>", S_OK, &saxattributes },
2131 /* 70 */
2132 { &CLSID_MXXMLWriter40, StartEndElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\"/>", S_OK, &saxattributes },
2133 { &CLSID_MXXMLWriter60, StartEndElement, "uri", "local", "uri:local", "<uri:local a:attr1=\"a1\" attr2=\"a2\"/>", S_OK, &saxattributes },
2134 { &CLSID_MXXMLWriter, StartEndElement, "", "", "", "</>", S_OK },
2135 { &CLSID_MXXMLWriter30, StartEndElement, "", "", "", "</>", S_OK },
2136 { &CLSID_MXXMLWriter40, StartEndElement, "", "", "", "</>", S_OK },
2137 /* 75 */
2138 { &CLSID_MXXMLWriter60, StartEndElement, "", "", "", "</>", S_OK },
2139 { NULL }
2142 static void get_supported_mxwriter_data(struct msxmlsupported_data_t *table)
2144 while (table->clsid)
2146 IMXWriter *writer;
2147 HRESULT hr;
2149 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2150 &IID_IMXWriter, (void**)&writer);
2151 if (hr == S_OK) IMXWriter_Release(writer);
2153 table->supported = hr == S_OK;
2154 if (hr != S_OK) win_skip("class %s not supported\n", table->name);
2156 table++;
2160 static void test_mxwriter_startendelement_batch(const struct writer_startendelement_t *table)
2162 int i = 0;
2164 while (table->clsid)
2166 ISAXContentHandler *content;
2167 IMXWriter *writer;
2168 HRESULT hr;
2170 if (!is_mxwriter_supported(table->clsid, msxmlsupported_data))
2172 table++;
2173 i++;
2174 continue;
2177 hr = CoCreateInstance(table->clsid, NULL, CLSCTX_INPROC_SERVER,
2178 &IID_IMXWriter, (void**)&writer);
2179 EXPECT_HR(hr, S_OK);
2181 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2182 EXPECT_HR(hr, S_OK);
2184 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2185 EXPECT_HR(hr, S_OK);
2187 hr = ISAXContentHandler_startDocument(content);
2188 EXPECT_HR(hr, S_OK);
2190 if (table->type == StartElement)
2192 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), lstrlen(table->uri),
2193 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname), table->attr);
2194 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
2196 else if (table->type == EndElement)
2198 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), lstrlen(table->uri),
2199 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname));
2200 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
2202 else
2204 hr = ISAXContentHandler_startElement(content, _bstr_(table->uri), lstrlen(table->uri),
2205 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname), table->attr);
2206 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
2207 hr = ISAXContentHandler_endElement(content, _bstr_(table->uri), lstrlen(table->uri),
2208 _bstr_(table->local_name), lstrlen(table->local_name), _bstr_(table->qname), lstrlen(table->qname));
2209 ok(hr == table->hr, "test %d: got 0x%08x, expected 0x%08x\n", i, hr, table->hr);
2212 /* test output */
2213 if (hr == S_OK)
2215 VARIANT dest;
2217 V_VT(&dest) = VT_EMPTY;
2218 hr = IMXWriter_get_output(writer, &dest);
2219 EXPECT_HR(hr, S_OK);
2220 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2221 ok(!lstrcmpW(_bstr_(table->output), V_BSTR(&dest)),
2222 "test %d: got wrong content %s, expected %s\n", i, wine_dbgstr_w(V_BSTR(&dest)), table->output);
2223 VariantClear(&dest);
2226 ISAXContentHandler_Release(content);
2227 IMXWriter_Release(writer);
2229 table++;
2230 i++;
2233 free_bstrs();
2236 static void test_mxwriter_startendelement(void)
2238 ISAXContentHandler *content;
2239 IMXWriter *writer;
2240 VARIANT dest;
2241 HRESULT hr;
2243 test_mxwriter_startendelement_batch(writer_startendelement);
2245 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2246 &IID_IMXWriter, (void**)&writer);
2247 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
2249 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2250 ok(hr == S_OK, "got %08x\n", hr);
2252 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2253 ok(hr == S_OK, "got %08x\n", hr);
2255 hr = ISAXContentHandler_startDocument(content);
2256 ok(hr == S_OK, "got %08x\n", hr);
2258 /* all string pointers should be not null */
2259 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_("b"), 1, _bstr_(""), 0, NULL);
2260 ok(hr == S_OK, "got %08x\n", hr);
2262 V_VT(&dest) = VT_EMPTY;
2263 hr = IMXWriter_get_output(writer, &dest);
2264 ok(hr == S_OK, "got %08x\n", hr);
2265 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2266 ok(!lstrcmpW(_bstr_("<>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2267 VariantClear(&dest);
2269 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1, NULL);
2270 ok(hr == S_OK, "got %08x\n", hr);
2272 V_VT(&dest) = VT_EMPTY;
2273 hr = IMXWriter_get_output(writer, &dest);
2274 ok(hr == S_OK, "got %08x\n", hr);
2275 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2276 ok(!lstrcmpW(_bstr_("<><b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2277 VariantClear(&dest);
2279 hr = ISAXContentHandler_endElement(content, NULL, 0, NULL, 0, _bstr_("a:b"), 3);
2280 EXPECT_HR(hr, E_INVALIDARG);
2282 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, _bstr_("a:b"), 3);
2283 EXPECT_HR(hr, E_INVALIDARG);
2285 /* only local name is an error too */
2286 hr = ISAXContentHandler_endElement(content, NULL, 0, _bstr_("b"), 1, NULL, 0);
2287 EXPECT_HR(hr, E_INVALIDARG);
2289 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("b"), 1);
2290 EXPECT_HR(hr, S_OK);
2292 V_VT(&dest) = VT_EMPTY;
2293 hr = IMXWriter_get_output(writer, &dest);
2294 EXPECT_HR(hr, S_OK);
2295 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2296 ok(!lstrcmpW(_bstr_("<><b></b>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2297 VariantClear(&dest);
2299 hr = ISAXContentHandler_endDocument(content);
2300 EXPECT_HR(hr, S_OK);
2302 V_VT(&dest) = VT_EMPTY;
2303 hr = IMXWriter_put_output(writer, dest);
2304 EXPECT_HR(hr, S_OK);
2306 hr = ISAXContentHandler_startDocument(content);
2307 EXPECT_HR(hr, S_OK);
2309 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abcdef"), 3, NULL);
2310 EXPECT_HR(hr, S_OK);
2312 V_VT(&dest) = VT_EMPTY;
2313 hr = IMXWriter_get_output(writer, &dest);
2314 EXPECT_HR(hr, S_OK);
2315 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2316 ok(!lstrcmpW(_bstr_("<abc>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2317 VariantClear(&dest);
2319 ISAXContentHandler_endDocument(content);
2320 IMXWriter_flush(writer);
2322 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("abdcdef"), 3);
2323 EXPECT_HR(hr, S_OK);
2324 V_VT(&dest) = VT_EMPTY;
2325 hr = IMXWriter_get_output(writer, &dest);
2326 EXPECT_HR(hr, S_OK);
2327 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2328 ok(!lstrcmpW(_bstr_("<abc></abd>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2329 VariantClear(&dest);
2331 ISAXContentHandler_Release(content);
2332 IMXWriter_Release(writer);
2333 free_bstrs();
2336 static void test_mxwriter_characters(void)
2338 static const WCHAR chardataW[] = {'T','E','S','T','C','H','A','R','D','A','T','A',' ','.',0};
2339 ISAXContentHandler *content;
2340 IMXWriter *writer;
2341 VARIANT dest;
2342 HRESULT hr;
2344 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2345 &IID_IMXWriter, (void**)&writer);
2346 EXPECT_HR(hr, S_OK);
2348 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2349 EXPECT_HR(hr, S_OK);
2351 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2352 EXPECT_HR(hr, S_OK);
2354 hr = ISAXContentHandler_startDocument(content);
2355 EXPECT_HR(hr, S_OK);
2357 hr = ISAXContentHandler_characters(content, NULL, 0);
2358 EXPECT_HR(hr, E_INVALIDARG);
2360 hr = ISAXContentHandler_characters(content, chardataW, 0);
2361 EXPECT_HR(hr, S_OK);
2363 hr = ISAXContentHandler_characters(content, chardataW, sizeof(chardataW)/sizeof(WCHAR) - 1);
2364 EXPECT_HR(hr, S_OK);
2366 V_VT(&dest) = VT_EMPTY;
2367 hr = IMXWriter_get_output(writer, &dest);
2368 EXPECT_HR(hr, S_OK);
2369 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2370 ok(!lstrcmpW(_bstr_("TESTCHARDATA ."), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2371 VariantClear(&dest);
2373 hr = ISAXContentHandler_endDocument(content);
2374 EXPECT_HR(hr, S_OK);
2376 ISAXContentHandler_Release(content);
2377 IMXWriter_Release(writer);
2379 /* try empty characters data to see if element is closed */
2380 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2381 &IID_IMXWriter, (void**)&writer);
2382 EXPECT_HR(hr, S_OK);
2384 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2385 EXPECT_HR(hr, S_OK);
2387 hr = IMXWriter_put_omitXMLDeclaration(writer, VARIANT_TRUE);
2388 EXPECT_HR(hr, S_OK);
2390 hr = ISAXContentHandler_startDocument(content);
2391 EXPECT_HR(hr, S_OK);
2393 hr = ISAXContentHandler_startElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1, NULL);
2394 EXPECT_HR(hr, S_OK);
2396 hr = ISAXContentHandler_characters(content, chardataW, 0);
2397 EXPECT_HR(hr, S_OK);
2399 hr = ISAXContentHandler_endElement(content, _bstr_(""), 0, _bstr_(""), 0, _bstr_("a"), 1);
2400 EXPECT_HR(hr, S_OK);
2402 V_VT(&dest) = VT_EMPTY;
2403 hr = IMXWriter_get_output(writer, &dest);
2404 EXPECT_HR(hr, S_OK);
2405 ok(V_VT(&dest) == VT_BSTR, "got %d\n", V_VT(&dest));
2406 ok(!lstrcmpW(_bstr_("<a></a>"), V_BSTR(&dest)), "got wrong content %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2407 VariantClear(&dest);
2409 ISAXContentHandler_Release(content);
2410 IMXWriter_Release(writer);
2412 free_bstrs();
2415 static const mxwriter_stream_test mxwriter_stream_tests[] = {
2417 VARIANT_TRUE,"UTF-16",
2419 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
2420 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
2421 {TRUE}
2425 VARIANT_FALSE,"UTF-16",
2427 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
2428 {TRUE}
2432 VARIANT_TRUE,"UTF-8",
2434 {FALSE,(const BYTE*)szUtf8XML,sizeof(szUtf8XML)-1},
2435 /* For some reason Windows makes an empty write call when UTF-8 encoding is used
2436 * and the writer is released.
2438 {FALSE,NULL,0},
2439 {TRUE}
2443 VARIANT_TRUE,"UTF-16",
2445 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE},
2446 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
2447 {TRUE}
2451 VARIANT_TRUE,"UTF-16",
2453 {FALSE,(const BYTE*)szUtf16BOM,sizeof(szUtf16BOM),TRUE,TRUE},
2454 {FALSE,(const BYTE*)szUtf16XML,sizeof(szUtf16XML)},
2455 {TRUE}
2460 static void test_mxwriter_stream(void)
2462 IMXWriter *writer;
2463 ISAXContentHandler *content;
2464 HRESULT hr;
2465 VARIANT dest;
2466 IStream *stream;
2467 LARGE_INTEGER pos;
2468 ULARGE_INTEGER pos2;
2469 DWORD test_count = sizeof(mxwriter_stream_tests)/sizeof(mxwriter_stream_tests[0]);
2471 for(current_stream_test_index = 0; current_stream_test_index < test_count; ++current_stream_test_index) {
2472 const mxwriter_stream_test *test = mxwriter_stream_tests+current_stream_test_index;
2474 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2475 &IID_IMXWriter, (void**)&writer);
2476 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
2478 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2479 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
2481 hr = IMXWriter_put_encoding(writer, _bstr_(test->encoding));
2482 ok(hr == S_OK, "put_encoding failed with %08x on test %d\n", hr, current_stream_test_index);
2484 V_VT(&dest) = VT_UNKNOWN;
2485 V_UNKNOWN(&dest) = (IUnknown*)&mxstream;
2486 hr = IMXWriter_put_output(writer, dest);
2487 ok(hr == S_OK, "put_output failed with %08x on test %d\n", hr, current_stream_test_index);
2488 VariantClear(&dest);
2490 hr = IMXWriter_put_byteOrderMark(writer, test->bom);
2491 ok(hr == S_OK, "put_byteOrderMark failed with %08x on test %d\n", hr, current_stream_test_index);
2493 current_write_test = test->expected_writes;
2495 hr = ISAXContentHandler_startDocument(content);
2496 ok(hr == S_OK, "startDocument failed with %08x on test %d\n", hr, current_stream_test_index);
2498 hr = ISAXContentHandler_endDocument(content);
2499 ok(hr == S_OK, "endDocument failed with %08x on test %d\n", hr, current_stream_test_index);
2501 ISAXContentHandler_Release(content);
2502 IMXWriter_Release(writer);
2504 ok(current_write_test->last, "The last %d write calls on test %d were missed\n",
2505 (int)(current_write_test-test->expected_writes), current_stream_test_index);
2508 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2509 &IID_IMXWriter, (void**)&writer);
2510 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
2512 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2513 ok(hr == S_OK, "CreateStreamOnHGlobal failed: %08x\n", hr);
2515 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2516 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
2518 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
2519 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
2521 V_VT(&dest) = VT_UNKNOWN;
2522 V_UNKNOWN(&dest) = (IUnknown*)stream;
2523 hr = IMXWriter_put_output(writer, dest);
2524 ok(hr == S_OK, "put_output failed: %08x\n", hr);
2526 hr = ISAXContentHandler_startDocument(content);
2527 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
2529 /* Setting output of the mxwriter causes the current output to be flushed,
2530 * and the writer to start over.
2532 V_VT(&dest) = VT_EMPTY;
2533 hr = IMXWriter_put_output(writer, dest);
2534 ok(hr == S_OK, "put_output failed: %08x\n", hr);
2536 pos.QuadPart = 0;
2537 hr = IStream_Seek(stream, pos, STREAM_SEEK_CUR, &pos2);
2538 ok(hr == S_OK, "Seek failed: %08x\n", hr);
2539 ok(pos2.QuadPart != 0, "expected stream position moved\n");
2541 hr = ISAXContentHandler_startDocument(content);
2542 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
2544 hr = ISAXContentHandler_endDocument(content);
2545 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
2547 V_VT(&dest) = VT_EMPTY;
2548 hr = IMXWriter_get_output(writer, &dest);
2549 ok(hr == S_OK, "get_output failed: %08x\n", hr);
2550 ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
2551 ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
2552 "Got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2553 VariantClear(&dest);
2555 ISAXContentHandler_Release(content);
2556 IMXWriter_Release(writer);
2558 free_bstrs();
2561 static void test_mxwriter_encoding(void)
2563 IMXWriter *writer;
2564 ISAXContentHandler *content;
2565 HRESULT hr;
2566 VARIANT dest;
2568 hr = CoCreateInstance(&CLSID_MXXMLWriter, NULL, CLSCTX_INPROC_SERVER,
2569 &IID_IMXWriter, (void**)&writer);
2570 ok(hr == S_OK, "CoCreateInstance failed: %08x\n", hr);
2572 hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
2573 ok(hr == S_OK, "QueryInterface(ISAXContentHandler) failed: %08x\n", hr);
2575 hr = IMXWriter_put_encoding(writer, _bstr_("UTF-8"));
2576 ok(hr == S_OK, "put_encoding failed: %08x\n", hr);
2578 hr = ISAXContentHandler_startDocument(content);
2579 ok(hr == S_OK, "startDocument failed: %08x\n", hr);
2581 hr = ISAXContentHandler_endDocument(content);
2582 ok(hr == S_OK, "endDocument failed: %08x\n", hr);
2584 /* The content is always re-encoded to UTF-16 when the output is
2585 * retrieved as a BSTR.
2587 V_VT(&dest) = VT_EMPTY;
2588 hr = IMXWriter_get_output(writer, &dest);
2589 todo_wine ok(hr == S_OK, "get_output failed: %08x\n", hr);
2590 todo_wine ok(V_VT(&dest) == VT_BSTR, "Expected VT_BSTR, got %d\n", V_VT(&dest));
2591 if (V_VT(&dest) == VT_BSTR) todo_wine ok(!lstrcmpW(_bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"no\"?>\r\n"), V_BSTR(&dest)),
2592 "got wrong content: %s\n", wine_dbgstr_w(V_BSTR(&dest)));
2593 VariantClear(&dest);
2595 ISAXContentHandler_Release(content);
2596 IMXWriter_Release(writer);
2598 free_bstrs();
2601 static void test_obj_dispex(IUnknown *obj)
2603 static const WCHAR starW[] = {'*',0};
2604 DISPID dispid = DISPID_SAX_XMLREADER_GETFEATURE;
2605 IDispatchEx *dispex;
2606 IUnknown *unk;
2607 DWORD props;
2608 UINT ticnt;
2609 HRESULT hr;
2610 BSTR name;
2612 hr = IUnknown_QueryInterface(obj, &IID_IDispatchEx, (void**)&dispex);
2613 EXPECT_HR(hr, S_OK);
2614 if (FAILED(hr)) return;
2616 ticnt = 0;
2617 hr = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
2618 EXPECT_HR(hr, S_OK);
2619 ok(ticnt == 1, "ticnt=%u\n", ticnt);
2621 name = SysAllocString(starW);
2622 hr = IDispatchEx_DeleteMemberByName(dispex, name, fdexNameCaseSensitive);
2623 EXPECT_HR(hr, E_NOTIMPL);
2624 SysFreeString(name);
2626 hr = IDispatchEx_DeleteMemberByDispID(dispex, dispid);
2627 EXPECT_HR(hr, E_NOTIMPL);
2629 props = 0;
2630 hr = IDispatchEx_GetMemberProperties(dispex, dispid, grfdexPropCanAll, &props);
2631 EXPECT_HR(hr, E_NOTIMPL);
2632 ok(props == 0, "expected 0 got %d\n", props);
2634 hr = IDispatchEx_GetMemberName(dispex, dispid, &name);
2635 EXPECT_HR(hr, E_NOTIMPL);
2636 if (SUCCEEDED(hr)) SysFreeString(name);
2638 hr = IDispatchEx_GetNextDispID(dispex, fdexEnumDefault, DISPID_SAX_XMLREADER_GETFEATURE, &dispid);
2639 EXPECT_HR(hr, E_NOTIMPL);
2641 hr = IDispatchEx_GetNameSpaceParent(dispex, &unk);
2642 EXPECT_HR(hr, E_NOTIMPL);
2643 if (hr == S_OK && unk) IUnknown_Release(unk);
2645 IDispatchEx_Release(dispex);
2648 static void test_dispex(void)
2650 IVBSAXXMLReader *vbreader;
2651 ISAXXMLReader *reader;
2652 IUnknown *unk;
2653 HRESULT hr;
2655 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2656 &IID_ISAXXMLReader, (void**)&reader);
2657 EXPECT_HR(hr, S_OK);
2659 hr = ISAXXMLReader_QueryInterface(reader, &IID_IUnknown, (void**)&unk);
2660 EXPECT_HR(hr, S_OK);
2661 test_obj_dispex(unk);
2662 IUnknown_Release(unk);
2664 hr = ISAXXMLReader_QueryInterface(reader, &IID_IVBSAXXMLReader, (void**)&vbreader);
2665 EXPECT_HR(hr, S_OK);
2666 hr = IVBSAXXMLReader_QueryInterface(vbreader, &IID_IUnknown, (void**)&unk);
2667 EXPECT_HR(hr, S_OK);
2668 test_obj_dispex(unk);
2669 IUnknown_Release(unk);
2670 IVBSAXXMLReader_Release(vbreader);
2672 ISAXXMLReader_Release(reader);
2675 START_TEST(saxreader)
2677 ISAXXMLReader *reader;
2678 HRESULT hr;
2680 hr = CoInitialize(NULL);
2681 ok(hr == S_OK, "failed to init com\n");
2683 hr = CoCreateInstance(&CLSID_SAXXMLReader, NULL, CLSCTX_INPROC_SERVER,
2684 &IID_ISAXXMLReader, (void**)&reader);
2686 if(FAILED(hr))
2688 skip("Failed to create SAXXMLReader instance\n");
2689 CoUninitialize();
2690 return;
2692 ISAXXMLReader_Release(reader);
2694 test_saxreader(0);
2695 test_saxreader(3);
2696 test_saxreader(6);
2697 test_saxreader_properties();
2698 test_saxreader_features();
2699 test_encoding();
2700 test_dispex();
2702 /* MXXMLWriter tests */
2703 get_supported_mxwriter_data(msxmlsupported_data);
2704 if (is_mxwriter_supported(&CLSID_MXXMLWriter, msxmlsupported_data))
2706 test_mxwriter_contenthandler();
2707 test_mxwriter_startenddocument();
2708 test_mxwriter_startendelement();
2709 test_mxwriter_characters();
2710 test_mxwriter_properties();
2711 test_mxwriter_flush();
2712 test_mxwriter_stream();
2713 test_mxwriter_encoding();
2715 else
2716 win_skip("MXXMLWriter not supported\n");
2718 CoUninitialize();