mf/topoloader: Move node connection responsibility to connection function.
[wine/zf.git] / dlls / prntvpt / ticket.c
blob13aaf80423fdf9a2f1d5fcab7c3ea3f795e5ae29
1 /*
2 * Copyright 2019 Dmitry Timoshkov
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
21 #define COBJMACROS
22 #define NONAMELESSSTRUCT
23 #define NONAMELESSUNION
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winspool.h"
29 #include "objbase.h"
30 #include "prntvpt.h"
31 #include "initguid.h"
32 #include "msxml2.h"
33 #include "wine/heap.h"
34 #include "wine/debug.h"
36 #include "prntvpt_private.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(prntvpt);
40 struct size
42 int width;
43 int height;
46 struct media
48 int paper;
49 struct size size;
52 struct resolution
54 int x;
55 int y;
58 struct page
60 struct media media;
61 struct resolution resolution;
62 int orientation;
63 int scaling;
64 int color;
67 struct document
69 int collate;
72 struct job
74 int nup;
75 int copies;
76 int input_bin;
79 struct ticket
81 struct job job;
82 struct document document;
83 struct page page;
86 static const struct
88 const WCHAR *name;
89 int paper;
90 } psk_media[] =
92 { L"psk:ISOA4", DMPAPER_A4 },
95 static int media_to_paper(const WCHAR *name)
97 int i;
99 for (i = 0 ; i < ARRAY_SIZE(psk_media); i++)
100 if (!wcscmp(name, psk_media[i].name))
101 return psk_media[i].paper;
103 FIXME("%s\n", wine_dbgstr_w(name));
104 return DMPAPER_A4;
107 static const WCHAR *paper_to_media(int paper)
109 int i;
111 for (i = 0 ; i < ARRAY_SIZE(psk_media); i++)
112 if (psk_media[i].paper == paper)
113 return psk_media[i].name;
115 FIXME("%d\n", paper);
116 return psk_media[0].name;
119 static BOOL is_valid_node_name(const WCHAR *name)
121 static const WCHAR * const psf_names[] = { L"psf:ParameterInit", L"psf:Feature" };
122 int i;
124 for (i = 0 ; i < ARRAY_SIZE(psf_names); i++)
125 if (!wcscmp(name, psf_names[i])) return TRUE;
127 return FALSE;
130 static HRESULT verify_ticket(IXMLDOMDocument2 *doc)
132 IXMLDOMElement *element;
133 IXMLDOMNode *node = NULL;
134 BSTR str;
135 HRESULT hr;
137 hr = IXMLDOMDocument2_get_documentElement(doc, &element);
138 if (hr != S_OK) return E_PRINTTICKET_FORMAT;
140 hr = IXMLDOMElement_get_tagName(element, &str);
141 if (hr != S_OK) goto fail;
142 if (wcscmp(str, L"psf:PrintTicket") != 0)
143 hr = E_FAIL;
144 SysFreeString(str);
145 if (hr != S_OK) goto fail;
147 hr = IXMLDOMElement_get_firstChild(element, &node);
148 IXMLDOMElement_Release(element);
149 if (hr != S_OK) return S_OK;
151 for (;;)
153 VARIANT var;
154 IXMLDOMNode *next_node;
156 hr = IXMLDOMNode_get_nodeName(node, &str);
157 if (hr != S_OK) break;
158 if (!is_valid_node_name(str))
159 hr = E_FAIL;
160 SysFreeString(str);
161 if (hr != S_OK) break;
163 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void **)&element);
164 if (hr != S_OK) break;
166 VariantInit(&var);
167 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
168 IXMLDOMElement_Release(element);
169 if (hr != S_OK) break;
170 if (V_VT(&var) != VT_BSTR)
171 hr = E_FAIL;
172 VariantClear(&var);
173 if (hr != S_OK) break;
175 hr = IXMLDOMNode_get_nextSibling(node, &next_node);
176 if (hr != S_OK)
178 hr = S_OK;
179 break;
182 IXMLDOMNode_Release(node);
183 node = next_node;
186 fail:
187 if (node) IXMLDOMNode_Release(node);
189 return hr != S_OK ? E_PRINTTICKET_FORMAT : S_OK;
192 static HRESULT read_int_value(IXMLDOMNode *node, int *value)
194 IXMLDOMNode *val;
195 HRESULT hr;
196 VARIANT var1, var2;
198 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Value[@xsi:type='xsd:integer']", &val);
199 if (hr != S_OK) return hr;
201 VariantInit(&var1);
202 hr = IXMLDOMNode_get_nodeTypedValue(val, &var1);
203 if (hr == S_OK)
205 VariantInit(&var2);
206 hr = VariantChangeTypeEx(&var2, &var1, 0, 0, VT_I4);
207 if (hr == S_OK)
208 *value = V_I4(&var2);
210 VariantClear(&var1);
213 IXMLDOMNode_Release(val);
214 return hr;
217 static void read_PageMediaSize(IXMLDOMDocument2 *doc, struct ticket *ticket)
219 IXMLDOMNode *node, *option, *child;
220 HRESULT hr;
222 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageMediaSize']", &node);
223 if (hr != S_OK) return;
225 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
226 if (hr == S_OK)
228 IXMLDOMElement *element;
230 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
231 if (hr == S_OK)
233 VARIANT var;
235 VariantInit(&var);
236 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
237 if (hr == S_OK && V_VT(&var) == VT_BSTR)
239 ticket->page.media.paper = media_to_paper(V_BSTR(&var));
240 TRACE("paper: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->page.media.paper);
242 VariantClear(&var);
244 IXMLDOMElement_Release(element);
247 hr = IXMLDOMNode_selectSingleNode(option, (BSTR)L"./psf:ScoredProperty[@name='psk:MediaSizeWidth']", &child);
248 if (hr == S_OK)
250 if (read_int_value(child, &ticket->page.media.size.width) == S_OK)
251 TRACE("width: %d\n", ticket->page.media.size.width);
252 IXMLDOMNode_Release(child);
255 hr = IXMLDOMNode_selectSingleNode(option, (BSTR)L"./psf:ScoredProperty[@name='psk:MediaSizeHeight']", &child);
256 if (hr == S_OK)
258 if (read_int_value(child, &ticket->page.media.size.height) == S_OK)
259 TRACE("height: %d\n", ticket->page.media.size.height);
260 IXMLDOMNode_Release(child);
263 IXMLDOMNode_Release(option);
266 IXMLDOMNode_Release(node);
269 static void read_PageOutputColor(IXMLDOMDocument2 *doc, struct ticket *ticket)
271 IXMLDOMNode *node, *option;
272 HRESULT hr;
274 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageOutputColor']", &node);
275 if (hr != S_OK) return;
277 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
278 if (hr == S_OK)
280 IXMLDOMElement *element;
282 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
283 if (hr == S_OK)
285 VARIANT var;
287 VariantInit(&var);
288 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
289 if (hr == S_OK && V_VT(&var) == VT_BSTR)
291 if (!wcscmp(V_BSTR(&var), L"psk:Color"))
292 ticket->page.color = DMCOLOR_COLOR;
293 else if (!wcscmp(V_BSTR(&var), L"psk:Monochrome"))
294 ticket->page.color = DMCOLOR_MONOCHROME;
295 else
297 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var)));
298 ticket->page.color = DMCOLOR_MONOCHROME;
300 TRACE("color: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->page.color);
302 VariantClear(&var);
304 IXMLDOMElement_Release(element);
308 IXMLDOMNode_Release(node);
311 static void read_PageScaling(IXMLDOMDocument2 *doc, struct ticket *ticket)
313 IXMLDOMNode *node, *option;
314 int scaling = 0;
315 HRESULT hr;
317 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageScaling']", &node);
318 if (hr != S_OK) return;
320 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
321 if (hr == S_OK)
323 IXMLDOMElement *element;
325 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
326 if (hr == S_OK)
328 VARIANT var;
330 VariantInit(&var);
331 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
332 if (hr == S_OK && V_VT(&var) == VT_BSTR)
334 if (!wcscmp(V_BSTR(&var), L"psk:None"))
335 scaling = 100;
336 else if (!wcscmp(V_BSTR(&var), L"psk:CustomSquare"))
337 scaling = 0; /* psk:PageScalingScale */
338 else
339 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var)));
341 VariantClear(&var);
343 IXMLDOMElement_Release(element);
347 IXMLDOMNode_Release(node);
349 if (!scaling)
351 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:ParameterInit[@name='psk:PageScalingScale']", &node);
352 if (hr == S_OK)
354 read_int_value(node, &scaling);
355 IXMLDOMNode_Release(node);
359 if (scaling)
360 ticket->page.scaling = scaling;
361 else
362 ticket->page.scaling = 100;
364 TRACE("page.scaling: %d\n", ticket->page.scaling);
367 static void read_PageResolution(IXMLDOMDocument2 *doc, struct ticket *ticket)
369 IXMLDOMNode *node, *option, *child;
370 HRESULT hr;
372 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageResolution']", &node);
373 if (hr != S_OK) return;
375 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
376 if (hr == S_OK)
378 hr = IXMLDOMNode_selectSingleNode(option, (BSTR)L"./psf:ScoredProperty[@name='psk:ResolutionX']", &child);
379 if (hr == S_OK)
381 if (read_int_value(child, &ticket->page.resolution.x) == S_OK)
382 TRACE("resolution.x: %d\n", ticket->page.resolution.x);
383 IXMLDOMNode_Release(child);
386 hr = IXMLDOMNode_selectSingleNode(option, (BSTR)L"./psf:ScoredProperty[@name='psk:ResolutionY']", &child);
387 if (hr == S_OK)
389 if (read_int_value(child, &ticket->page.resolution.y) == S_OK)
390 TRACE("resolution.y: %d\n", ticket->page.resolution.y);
391 IXMLDOMNode_Release(child);
394 IXMLDOMNode_Release(option);
397 IXMLDOMNode_Release(node);
400 static void read_PageOrientation(IXMLDOMDocument2 *doc, struct ticket *ticket)
402 IXMLDOMNode *node, *option;
403 HRESULT hr;
405 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageOrientation']", &node);
406 if (hr != S_OK) return;
408 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
409 if (hr == S_OK)
411 IXMLDOMElement *element;
413 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
414 if (hr == S_OK)
416 VARIANT var;
418 VariantInit(&var);
419 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
420 if (hr == S_OK && V_VT(&var) == VT_BSTR)
422 if (!wcscmp(V_BSTR(&var), L"psk:Portrait"))
423 ticket->page.orientation = DMORIENT_PORTRAIT;
424 else if (!wcscmp(V_BSTR(&var), L"psk:Landscape"))
425 ticket->page.orientation = DMORIENT_LANDSCAPE;
426 else
428 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var)));
429 ticket->page.orientation = DMORIENT_PORTRAIT;
431 TRACE("orientation: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->page.orientation);
433 VariantClear(&var);
435 IXMLDOMElement_Release(element);
439 IXMLDOMNode_Release(node);
442 static void read_DocumentCollate(IXMLDOMDocument2 *doc, struct ticket *ticket)
444 IXMLDOMNode *node, *option;
445 HRESULT hr;
447 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:DocumentCollate']", &node);
448 if (hr != S_OK) return;
450 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
451 if (hr == S_OK)
453 IXMLDOMElement *element;
455 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
456 if (hr == S_OK)
458 VARIANT var;
460 VariantInit(&var);
461 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
462 if (hr == S_OK && V_VT(&var) == VT_BSTR)
464 if (!wcscmp(V_BSTR(&var), L"psk:Collated"))
465 ticket->document.collate = DMCOLLATE_TRUE;
466 else if (!wcscmp(V_BSTR(&var), L"psk:Uncollated"))
467 ticket->document.collate = DMCOLLATE_FALSE;
468 else
470 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var)));
471 ticket->document.collate = DMCOLLATE_FALSE;
473 TRACE("document.collate: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->document.collate);
475 VariantClear(&var);
477 IXMLDOMElement_Release(element);
481 IXMLDOMNode_Release(node);
484 static void read_JobInputBin(IXMLDOMDocument2 *doc, struct ticket *ticket)
486 IXMLDOMNode *node, *option;
487 HRESULT hr;
489 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:JobInputBin']", &node);
490 if (hr != S_OK) return;
492 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
493 if (hr == S_OK)
495 IXMLDOMElement *element;
497 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
498 if (hr == S_OK)
500 VARIANT var;
502 VariantInit(&var);
503 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
504 if (hr == S_OK && V_VT(&var) == VT_BSTR)
506 if (!wcscmp(V_BSTR(&var), L"psk:AutoSelect"))
507 ticket->job.input_bin = DMBIN_AUTO;
508 else
510 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var)));
511 ticket->job.input_bin = DMBIN_AUTO;
513 TRACE("input_bin: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->job.input_bin);
515 VariantClear(&var);
517 IXMLDOMElement_Release(element);
521 IXMLDOMNode_Release(node);
524 static void read_JobCopies(IXMLDOMDocument2 *doc, struct ticket *ticket)
526 IXMLDOMNode *node;
527 HRESULT hr;
529 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:ParameterInit[@name='psk:JobCopiesAllDocuments']", &node);
530 if (hr != S_OK) return;
532 if (read_int_value(node, &ticket->job.copies) == S_OK)
533 TRACE("job.copies: %d\n", ticket->job.copies);
535 IXMLDOMNode_Release(node);
538 static void set_SelectionNamespaces(IXMLDOMDocument2 *doc)
540 IStream *stream;
541 IXMLDOMElement *element = NULL;
542 IXMLDOMNamedNodeMap *map = NULL;
543 HRESULT hr;
544 LONG count, i;
545 HGLOBAL hmem;
546 BSTR str;
547 VARIANT var;
549 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
550 if (hr != S_OK) return;
552 hr = IXMLDOMDocument2_get_documentElement(doc, &element);
553 if (hr != S_OK) goto fail;
555 hr = IXMLDOMElement_get_attributes(element, &map);
556 if (hr != S_OK) goto fail;
558 hr = IXMLDOMNamedNodeMap_get_length(map, &count);
559 if (hr != S_OK) goto fail;
561 for (i = 0; i < count; i++)
563 IXMLDOMNode *node;
565 hr = IXMLDOMNamedNodeMap_get_item(map, i, &node);
566 if (hr == S_OK)
568 hr = IXMLDOMNode_get_nodeName(node, &str);
569 if (hr == S_OK)
571 VariantInit(&var);
572 hr = IXMLDOMNode_get_nodeValue(node, &var);
573 if (hr == S_OK)
575 if (!wcscmp(str, L"xmlns") || !wcsncmp(str, L"xmlns:", 6))
577 TRACE("ns[%d]: %s=%s\n", i, wine_dbgstr_w(str), wine_dbgstr_w(V_BSTR(&var)));
578 IStream_Write(stream, str, wcslen(str) * sizeof(WCHAR), NULL);
579 IStream_Write(stream, L"=\"", 2 * sizeof(WCHAR), NULL);
580 IStream_Write(stream, V_BSTR(&var), wcslen(V_BSTR(&var)) * sizeof(WCHAR), NULL);
581 IStream_Write(stream, L"\" ", 2 * sizeof(WCHAR), NULL);
583 VariantClear(&var);
585 SysFreeString(str);
587 IXMLDOMNode_Release(node);
591 IStream_Write(stream, L"", sizeof(WCHAR), NULL);
593 hr = GetHGlobalFromStream(stream, &hmem);
594 if (hr != S_OK) goto fail;
596 str = GlobalLock(hmem);
597 V_VT(&var) = VT_BSTR;
598 V_BSTR(&var) = SysAllocString(str);
599 IXMLDOMDocument2_setProperty(doc, (BSTR)L"SelectionNamespaces", var);
600 SysFreeString(V_BSTR(&var));
601 GlobalUnlock(hmem);
603 fail:
604 if (map) IXMLDOMNamedNodeMap_Release(map);
605 if (element) IXMLDOMElement_Release(element);
606 IStream_Release(stream);
609 static HRESULT parse_ticket(IStream *stream, EPrintTicketScope scope, struct ticket *ticket)
611 IXMLDOMDocument2 *doc;
612 VARIANT src;
613 VARIANT_BOOL ret;
614 HRESULT hr;
616 hr = CoCreateInstance(&CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER,
617 &IID_IXMLDOMDocument2, (void **)&doc);
618 if (hr != S_OK) return hr;
620 V_VT(&src) = VT_UNKNOWN;
621 V_UNKNOWN(&src) = (IUnknown *)stream;
622 hr = IXMLDOMDocument2_load(doc, src, &ret);
623 if (hr != S_OK) goto fail;
625 hr = verify_ticket(doc);
626 if (hr != S_OK) goto fail;
628 set_SelectionNamespaces(doc);
630 /* PageScope is always added */
631 read_PageMediaSize(doc, ticket);
632 read_PageOutputColor(doc, ticket);
633 read_PageScaling(doc, ticket);
634 read_PageResolution(doc, ticket);
635 read_PageOrientation(doc, ticket);
637 if (scope > kPTPageScope)
638 read_DocumentCollate(doc, ticket);
640 if (scope > kPTDocumentScope)
642 read_JobInputBin(doc, ticket);
643 read_JobCopies(doc, ticket);
646 fail:
647 IXMLDOMDocument2_Release(doc);
648 return hr;
651 static void ticket_to_devmode(const struct ticket *ticket, DEVMODEW *dm)
653 memset(dm, 0, sizeof(*dm));
655 dm->dmSize = sizeof(*dm);
656 dm->dmFields = DM_ORIENTATION | DM_PAPERSIZE | DM_PAPERLENGTH | DM_PAPERWIDTH | DM_SCALE |
657 DM_COPIES | DM_COLOR | DM_PRINTQUALITY | DM_YRESOLUTION | DM_COLLATE;
658 dm->u1.s1.dmOrientation = ticket->page.orientation;
659 dm->u1.s1.dmPaperSize = ticket->page.media.paper;
660 dm->u1.s1.dmPaperWidth = ticket->page.media.size.width / 100;
661 dm->u1.s1.dmPaperLength = ticket->page.media.size.height / 100;
662 dm->u1.s1.dmScale = ticket->page.scaling;
663 dm->u1.s1.dmCopies = ticket->job.copies;
664 dm->dmColor = ticket->page.color;
665 dm->u1.s1.dmPrintQuality = ticket->page.resolution.x;
666 dm->dmYResolution = ticket->page.resolution.y;
667 dm->dmCollate = ticket->document.collate;
670 static void devmode_to_ticket(const DEVMODEW *dm, struct ticket *ticket)
672 if (dm->dmFields & DM_ORIENTATION)
673 ticket->page.orientation = dm->u1.s1.dmOrientation;
674 if (dm->dmFields & DM_PAPERSIZE)
675 ticket->page.media.paper = dm->u1.s1.dmPaperSize;
676 if (dm->dmFields & DM_PAPERLENGTH)
677 ticket->page.media.size.width = dm->u1.s1.dmPaperWidth * 100;
678 if (dm->dmFields & DM_PAPERWIDTH)
679 ticket->page.media.size.height = dm->u1.s1.dmPaperLength * 100;
680 if (dm->dmFields & DM_SCALE)
681 ticket->page.scaling = dm->u1.s1.dmScale;
682 if (dm->dmFields & DM_COPIES)
683 ticket->job.copies = dm->u1.s1.dmCopies;
684 if (dm->dmFields & DM_COLOR)
685 ticket->page.color = dm->dmColor;
686 if (dm->dmFields & DM_PRINTQUALITY)
688 ticket->page.resolution.x = dm->u1.s1.dmPrintQuality;
689 ticket->page.resolution.y = dm->u1.s1.dmPrintQuality;
691 if (dm->dmFields & DM_YRESOLUTION)
692 ticket->page.resolution.y = dm->dmYResolution;
693 if (dm->dmFields & DM_LOGPIXELS)
695 ticket->page.resolution.x = dm->dmLogPixels;
696 ticket->page.resolution.y = dm->dmLogPixels;
698 if (dm->dmFields & DM_COLLATE)
699 ticket->document.collate = dm->dmCollate;
702 static HRESULT initialize_ticket(struct prn_provider *prov, struct ticket *ticket)
704 PRINTER_INFO_2W *pi2;
705 DWORD size;
706 HRESULT hr = S_OK;
708 GetPrinterW(prov->hprn, 2, NULL, 0, &size);
709 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
710 return HRESULT_FROM_WIN32(GetLastError());
712 pi2 = heap_alloc(size);
713 if (!pi2) return E_OUTOFMEMORY;
715 if (!GetPrinterW(prov->hprn, 2, (LPBYTE)pi2, size, NULL))
716 hr = HRESULT_FROM_WIN32(GetLastError());
717 else
718 devmode_to_ticket(pi2->pDevMode, ticket);
720 heap_free(pi2);
721 return hr;
724 HRESULT WINAPI PTConvertPrintTicketToDevMode(HPTPROVIDER provider, IStream *stream, EDefaultDevmodeType type,
725 EPrintTicketScope scope, ULONG *size, PDEVMODEW *dm, BSTR *error)
727 struct prn_provider *prov = (struct prn_provider *)provider;
728 HRESULT hr;
729 struct ticket ticket;
731 TRACE("%p,%p,%d,%d,%p,%p,%p\n", provider, stream, type, scope, size, dm, error);
733 if (!is_valid_provider(provider) || !stream || !size || !dm)
734 return E_INVALIDARG;
736 hr = initialize_ticket(prov, &ticket);
737 if (hr != S_OK) return hr;
739 hr = parse_ticket(stream, scope, &ticket);
740 if (hr != S_OK) return hr;
742 *dm = heap_alloc(sizeof(**dm));
743 if (!*dm) return E_OUTOFMEMORY;
745 ticket_to_devmode(&ticket, *dm);
746 *size = sizeof(**dm);
748 return S_OK;
751 static HRESULT add_attribute(IXMLDOMElement *element, const WCHAR *attr, const WCHAR *value)
753 VARIANT var;
754 BSTR name;
755 HRESULT hr;
757 name = SysAllocString(attr);
758 V_VT(&var) = VT_BSTR;
759 V_BSTR(&var) = SysAllocString(value);
761 hr = IXMLDOMElement_setAttribute(element, name, var);
763 SysFreeString(name);
764 SysFreeString(V_BSTR(&var));
766 return hr;
769 static HRESULT create_element(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
771 IXMLDOMDocument *doc;
772 HRESULT hr;
774 hr = IXMLDOMElement_get_ownerDocument(root, &doc);
775 if (hr != S_OK) return hr;
777 hr = IXMLDOMDocument_createElement(doc, (BSTR)name, child);
778 if (hr == S_OK)
779 hr = IXMLDOMElement_appendChild(root, (IXMLDOMNode *)*child, NULL);
781 IXMLDOMDocument_Release(doc);
782 return hr;
785 static HRESULT write_int_value(IXMLDOMElement *root, int value)
787 HRESULT hr;
788 IXMLDOMElement *child;
789 VARIANT var;
791 hr = create_element(root, L"psf:Value", &child);
792 if (hr != S_OK) return hr;
794 hr = add_attribute(child, L"xsi:type", L"xsd:integer");
795 if (hr != S_OK) return hr;
797 V_VT(&var) = VT_I4;
798 V_I4(&var) = value;
799 hr = IXMLDOMElement_put_nodeTypedValue(child, var);
801 IXMLDOMElement_Release(child);
802 return hr;
805 static HRESULT create_Feature(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
807 HRESULT hr;
809 hr = create_element(root, L"psf:Feature", child);
810 if (hr != S_OK) return hr;
812 return add_attribute(*child, L"name", name);
815 static HRESULT create_Option(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
817 HRESULT hr;
819 hr = create_element(root, L"psf:Option", child);
820 if (hr != S_OK) return hr;
822 if (name)
823 hr = add_attribute(*child, L"name", name);
825 return hr;
828 static HRESULT create_ParameterInit(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
830 HRESULT hr;
832 hr = create_element(root, L"psf:ParameterInit", child);
833 if (hr != S_OK) return hr;
835 return add_attribute(*child, L"name", name);
838 static HRESULT create_ParameterRef(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
840 HRESULT hr;
842 hr = create_element(root, L"psf:ParameterRef", child);
843 if (hr != S_OK) return hr;
845 return add_attribute(*child, L"name", name);
848 static HRESULT create_ParameterDef(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
850 HRESULT hr;
852 hr = create_element(root, L"psf:ParameterDef", child);
853 if (hr != S_OK) return hr;
855 return add_attribute(*child, L"name", name);
858 static HRESULT create_ScoredProperty(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
860 HRESULT hr;
862 hr = create_element(root, L"psf:ScoredProperty", child);
863 if (hr != S_OK) return hr;
865 return add_attribute(*child, L"name", name);
868 static HRESULT write_PageMediaSize(IXMLDOMElement *root, const struct ticket *ticket)
870 IXMLDOMElement *feature, *option = NULL, *property;
871 HRESULT hr;
873 hr = create_Feature(root, L"psk:PageMediaSize", &feature);
874 if (hr != S_OK) return hr;
876 hr = create_Option(feature, paper_to_media(ticket->page.media.paper), &option);
877 if (hr != S_OK) goto fail;
879 hr = create_ScoredProperty(option, L"psk:MediaSizeWidth", &property);
880 if (hr != S_OK) goto fail;
881 hr = write_int_value(property, ticket->page.media.size.width);
882 IXMLDOMElement_Release(property);
883 if (hr != S_OK) goto fail;
885 hr = create_ScoredProperty(option, L"psk:MediaSizeHeight", &property);
886 if (hr != S_OK) goto fail;
887 hr = write_int_value(property, ticket->page.media.size.height);
888 IXMLDOMElement_Release(property);
890 fail:
891 if (option) IXMLDOMElement_Release(option);
892 IXMLDOMElement_Release(feature);
893 return hr;
896 static HRESULT write_PageOutputColor(IXMLDOMElement *root, const struct ticket *ticket)
898 IXMLDOMElement *feature, *option = NULL;
899 HRESULT hr;
901 hr = create_Feature(root, L"psk:PageOutputColor", &feature);
902 if (hr != S_OK) return hr;
904 if (ticket->page.color == DMCOLOR_COLOR)
905 hr = create_Option(feature, L"psk:Color", &option);
906 else /* DMCOLOR_MONOCHROME */
907 hr = create_Option(feature, L"psk:Monochrome", &option);
909 if (option) IXMLDOMElement_Release(option);
910 IXMLDOMElement_Release(feature);
911 return hr;
914 static HRESULT write_PageScaling(IXMLDOMElement *root, const struct ticket *ticket)
916 IXMLDOMElement *feature, *option = NULL;
917 HRESULT hr;
919 hr = create_Feature(root, L"psk:PageScaling", &feature);
920 if (hr != S_OK) return hr;
922 if (ticket->page.scaling == 100)
924 hr = create_Option(feature, L"psk:None", &option);
925 if (hr == S_OK) IXMLDOMElement_Release(option);
927 else
929 hr = create_Option(feature, L"psk:CustomSquare", &option);
930 if (hr == S_OK)
932 IXMLDOMElement *property, *parameter;
934 hr = create_ScoredProperty(option, L"psk:Scale", &property);
935 if (hr == S_OK)
937 hr = create_ParameterRef(property, L"psk:PageScalingScale", &parameter);
938 if (hr == S_OK)
940 IXMLDOMElement_Release(parameter);
942 hr = create_ParameterInit(root, L"psk:PageScalingScale", &parameter);
943 if (hr == S_OK)
945 hr = write_int_value(parameter, ticket->page.scaling);
946 IXMLDOMElement_Release(parameter);
950 IXMLDOMElement_Release(property);
953 IXMLDOMElement_Release(option);
957 IXMLDOMElement_Release(feature);
958 return hr;
961 static HRESULT write_PageResolution(IXMLDOMElement *root, const struct ticket *ticket)
963 IXMLDOMElement *feature, *option = NULL, *property;
964 HRESULT hr;
966 hr = create_Feature(root, L"psk:PageResolution", &feature);
967 if (hr != S_OK) return hr;
969 hr = create_Option(feature, NULL, &option);
970 if (hr != S_OK) goto fail;
972 hr = create_ScoredProperty(option, L"psk:ResolutionX", &property);
973 if (hr != S_OK) goto fail;
974 hr = write_int_value(property, ticket->page.resolution.x);
975 IXMLDOMElement_Release(property);
976 if (hr != S_OK) goto fail;
978 hr = create_ScoredProperty(option, L"psk:ResolutionY", &property);
979 if (hr != S_OK) goto fail;
980 hr = write_int_value(property, ticket->page.resolution.y);
981 IXMLDOMElement_Release(property);
983 fail:
984 if (option) IXMLDOMElement_Release(option);
985 IXMLDOMElement_Release(feature);
986 return hr;
989 static HRESULT write_PageOrientation(IXMLDOMElement *root, const struct ticket *ticket)
991 IXMLDOMElement *feature, *option = NULL;
992 HRESULT hr;
994 hr = create_Feature(root, L"psk:PageOrientation", &feature);
995 if (hr != S_OK) return hr;
997 if (ticket->page.orientation == DMORIENT_PORTRAIT)
998 hr = create_Option(feature, L"psk:Portrait", &option);
999 else /* DMORIENT_LANDSCAPE */
1000 hr = create_Option(feature, L"psk:Landscape", &option);
1002 if (option) IXMLDOMElement_Release(option);
1003 IXMLDOMElement_Release(feature);
1004 return hr;
1007 static HRESULT write_DocumentCollate(IXMLDOMElement *root, const struct ticket *ticket)
1009 IXMLDOMElement *feature, *option = NULL;
1010 HRESULT hr;
1012 hr = create_Feature(root, L"psk:DocumentCollate", &feature);
1013 if (hr != S_OK) return hr;
1015 if (ticket->document.collate == DMCOLLATE_TRUE)
1016 hr = create_Option(feature, L"psk:Collated", &option);
1017 else /* DMCOLLATE_FALSE */
1018 hr = create_Option(feature, L"psk:Uncollated", &option);
1020 if (option) IXMLDOMElement_Release(option);
1021 IXMLDOMElement_Release(feature);
1022 return hr;
1025 static HRESULT write_JobInputBin(IXMLDOMElement *root, const struct ticket *ticket)
1027 IXMLDOMElement *feature, *option = NULL;
1028 HRESULT hr;
1030 hr = create_Feature(root, L"psk:JobInputBin", &feature);
1031 if (hr != S_OK) return hr;
1033 if (ticket->job.input_bin != DMBIN_AUTO)
1034 FIXME("job.input_bin: %d\n", ticket->job.input_bin);
1036 hr = create_Option(feature, L"psk:AutoSelect", &option);
1038 if (option) IXMLDOMElement_Release(option);
1039 IXMLDOMElement_Release(feature);
1040 return hr;
1043 static HRESULT write_JobCopies(IXMLDOMElement *root, const struct ticket *ticket)
1045 IXMLDOMElement *parameter;
1046 HRESULT hr;
1048 hr = create_ParameterInit(root, L"psk:JobCopiesAllDocuments", &parameter);
1049 if (hr != S_OK) return hr;
1051 hr = write_int_value(parameter, ticket->job.copies);
1053 IXMLDOMElement_Release(parameter);
1054 return hr;
1057 static HRESULT write_attributes(IXMLDOMElement *element)
1059 HRESULT hr;
1061 hr = add_attribute(element, L"xmlns:psf", L"http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework");
1062 if (hr != S_OK) return hr;
1063 hr = add_attribute(element, L"xmlns:psk", L"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords");
1064 if (hr != S_OK) return hr;
1065 hr = add_attribute(element, L"xmlns:xsi", L"http://www.w3.org/2001/XMLSchema-instance");
1066 if (hr != S_OK) return hr;
1067 hr = add_attribute(element, L"xmlns:xsd", L"http://www.w3.org/2001/XMLSchema");
1068 if (hr != S_OK) return hr;
1070 return add_attribute(element, L"version", L"1");
1073 static HRESULT write_ticket(IStream *stream, const struct ticket *ticket, EPrintTicketScope scope)
1075 static const char xmldecl[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
1076 HRESULT hr;
1077 IXMLDOMDocument *doc;
1078 IXMLDOMElement *root = NULL;
1079 VARIANT var;
1081 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
1082 &IID_IXMLDOMDocument, (void **)&doc);
1083 if (hr != S_OK) return hr;
1085 hr = IXMLDOMDocument_createElement(doc, (BSTR)L"psf:PrintTicket", &root);
1086 if (hr != S_OK) goto fail;
1088 hr = IXMLDOMDocument_appendChild(doc, (IXMLDOMNode *)root, NULL);
1089 if (hr != S_OK) goto fail;
1091 hr = write_attributes(root);
1092 if (hr != S_OK) goto fail;
1094 hr = write_PageMediaSize(root, ticket);
1095 if (hr != S_OK) goto fail;
1096 hr = write_PageOutputColor(root, ticket);
1097 if (hr != S_OK) goto fail;
1098 hr = write_PageScaling(root, ticket);
1099 if (hr != S_OK) goto fail;
1100 hr = write_PageResolution(root, ticket);
1101 if (hr != S_OK) goto fail;
1102 hr = write_PageOrientation(root, ticket);
1103 if (hr != S_OK) goto fail;
1105 if (scope >= kPTDocumentScope)
1107 hr = write_DocumentCollate(root, ticket);
1108 if (hr != S_OK) goto fail;
1111 if (scope >= kPTJobScope)
1113 hr = write_JobInputBin(root, ticket);
1114 if (hr != S_OK) goto fail;
1115 hr = write_JobCopies(root, ticket);
1116 if (hr != S_OK) goto fail;
1119 hr = IStream_Write(stream, xmldecl, strlen(xmldecl), NULL);
1120 if (hr != S_OK) goto fail;
1122 V_VT(&var) = VT_UNKNOWN;
1123 V_UNKNOWN(&var) = (IUnknown *)stream;
1124 hr = IXMLDOMDocument_save(doc, var);
1126 fail:
1127 if (root) IXMLDOMElement_Release(root);
1128 IXMLDOMDocument_Release(doc);
1129 return hr;
1132 static void dump_fields(DWORD fields)
1134 int add_space = 0;
1136 #define CHECK_FIELD(flag) \
1137 do \
1139 if (fields & flag) \
1141 if (add_space++) TRACE(" "); \
1142 TRACE(#flag); \
1143 fields &= ~flag; \
1146 while (0)
1148 CHECK_FIELD(DM_ORIENTATION);
1149 CHECK_FIELD(DM_PAPERSIZE);
1150 CHECK_FIELD(DM_PAPERLENGTH);
1151 CHECK_FIELD(DM_PAPERWIDTH);
1152 CHECK_FIELD(DM_SCALE);
1153 CHECK_FIELD(DM_POSITION);
1154 CHECK_FIELD(DM_NUP);
1155 CHECK_FIELD(DM_DISPLAYORIENTATION);
1156 CHECK_FIELD(DM_COPIES);
1157 CHECK_FIELD(DM_DEFAULTSOURCE);
1158 CHECK_FIELD(DM_PRINTQUALITY);
1159 CHECK_FIELD(DM_COLOR);
1160 CHECK_FIELD(DM_DUPLEX);
1161 CHECK_FIELD(DM_YRESOLUTION);
1162 CHECK_FIELD(DM_TTOPTION);
1163 CHECK_FIELD(DM_COLLATE);
1164 CHECK_FIELD(DM_FORMNAME);
1165 CHECK_FIELD(DM_LOGPIXELS);
1166 CHECK_FIELD(DM_BITSPERPEL);
1167 CHECK_FIELD(DM_PELSWIDTH);
1168 CHECK_FIELD(DM_PELSHEIGHT);
1169 CHECK_FIELD(DM_DISPLAYFLAGS);
1170 CHECK_FIELD(DM_DISPLAYFREQUENCY);
1171 CHECK_FIELD(DM_ICMMETHOD);
1172 CHECK_FIELD(DM_ICMINTENT);
1173 CHECK_FIELD(DM_MEDIATYPE);
1174 CHECK_FIELD(DM_DITHERTYPE);
1175 CHECK_FIELD(DM_PANNINGWIDTH);
1176 CHECK_FIELD(DM_PANNINGHEIGHT);
1177 if (fields) TRACE(" %#x", fields);
1178 TRACE("\n");
1179 #undef CHECK_FIELD
1182 /* Dump DEVMODE structure without a device specific part.
1183 * Some applications and drivers fail to specify correct field
1184 * flags (like DM_FORMNAME), so dump everything.
1186 static void dump_devmode(const DEVMODEW *dm)
1188 if (!TRACE_ON(prntvpt)) return;
1190 TRACE("dmDeviceName: %s\n", debugstr_w(dm->dmDeviceName));
1191 TRACE("dmSpecVersion: 0x%04x\n", dm->dmSpecVersion);
1192 TRACE("dmDriverVersion: 0x%04x\n", dm->dmDriverVersion);
1193 TRACE("dmSize: 0x%04x\n", dm->dmSize);
1194 TRACE("dmDriverExtra: 0x%04x\n", dm->dmDriverExtra);
1195 TRACE("dmFields: 0x%04x\n", dm->dmFields);
1196 dump_fields(dm->dmFields);
1197 TRACE("dmOrientation: %d\n", dm->u1.s1.dmOrientation);
1198 TRACE("dmPaperSize: %d\n", dm->u1.s1.dmPaperSize);
1199 TRACE("dmPaperLength: %d\n", dm->u1.s1.dmPaperLength);
1200 TRACE("dmPaperWidth: %d\n", dm->u1.s1.dmPaperWidth);
1201 TRACE("dmScale: %d\n", dm->u1.s1.dmScale);
1202 TRACE("dmCopies: %d\n", dm->u1.s1.dmCopies);
1203 TRACE("dmDefaultSource: %d\n", dm->u1.s1.dmDefaultSource);
1204 TRACE("dmPrintQuality: %d\n", dm->u1.s1.dmPrintQuality);
1205 TRACE("dmColor: %d\n", dm->dmColor);
1206 TRACE("dmDuplex: %d\n", dm->dmDuplex);
1207 TRACE("dmYResolution: %d\n", dm->dmYResolution);
1208 TRACE("dmTTOption: %d\n", dm->dmTTOption);
1209 TRACE("dmCollate: %d\n", dm->dmCollate);
1210 TRACE("dmFormName: %s\n", debugstr_w(dm->dmFormName));
1211 TRACE("dmLogPixels %u\n", dm->dmLogPixels);
1212 TRACE("dmBitsPerPel %u\n", dm->dmBitsPerPel);
1213 TRACE("dmPelsWidth %u\n", dm->dmPelsWidth);
1214 TRACE("dmPelsHeight %u\n", dm->dmPelsHeight);
1217 HRESULT WINAPI PTConvertDevModeToPrintTicket(HPTPROVIDER provider, ULONG size, PDEVMODEW dm,
1218 EPrintTicketScope scope, IStream *stream)
1220 struct prn_provider *prov = (struct prn_provider *)provider;
1221 struct ticket ticket;
1222 HRESULT hr;
1224 TRACE("%p,%u,%p,%d,%p\n", provider, size, dm, scope, stream);
1226 if (!is_valid_provider(provider) || !dm || !stream)
1227 return E_INVALIDARG;
1229 dump_devmode(dm);
1231 if (!IsValidDevmodeW(dm, size))
1232 return E_INVALIDARG;
1234 hr = initialize_ticket(prov, &ticket);
1235 if (hr != S_OK) return hr;
1236 devmode_to_ticket(dm, &ticket);
1238 return write_ticket(stream, &ticket, scope);
1241 HRESULT WINAPI PTMergeAndValidatePrintTicket(HPTPROVIDER provider, IStream *base, IStream *delta,
1242 EPrintTicketScope scope, IStream *result, BSTR *error)
1244 struct prn_provider *prov = (struct prn_provider *)provider;
1245 struct ticket ticket;
1246 HRESULT hr;
1248 TRACE("%p,%p,%p,%d,%p,%p\n", provider, base, delta, scope, result, error);
1250 if (!is_valid_provider(provider) || !base || !result)
1251 return E_INVALIDARG;
1253 hr = initialize_ticket(prov, &ticket);
1254 if (hr != S_OK) return hr;
1256 hr = parse_ticket(base, scope, &ticket);
1257 if (hr != S_OK) return hr;
1259 if (delta)
1261 hr = parse_ticket(delta, scope, &ticket);
1262 if (hr != S_OK) return hr;
1265 hr = write_ticket(result, &ticket, scope);
1266 return hr ? hr : S_PT_NO_CONFLICT;
1269 static HRESULT write_PageMediaSize_caps(const WCHAR *device, IXMLDOMElement *root)
1271 HRESULT hr = S_OK;
1272 int count, i;
1273 POINT *pt;
1274 IXMLDOMElement *feature = NULL;
1276 FIXME("stub\n");
1278 count = DeviceCapabilitiesW(device, NULL, DC_PAPERSIZE, NULL, NULL);
1279 if (count <= 0)
1280 return HRESULT_FROM_WIN32(GetLastError());
1282 pt = heap_alloc(count * sizeof(*pt));
1283 if (!pt) return E_OUTOFMEMORY;
1285 count = DeviceCapabilitiesW(device, NULL, DC_PAPERSIZE, (LPWSTR)pt, NULL);
1286 if (count <= 0)
1288 hr = HRESULT_FROM_WIN32(GetLastError());
1289 goto fail;
1292 hr = create_Feature(root, L"psk:PageMediaSize", &feature);
1293 if (hr != S_OK) goto fail;
1295 for (i = 0; i < count; i++)
1299 fail:
1300 if (feature) IXMLDOMElement_Release(feature);
1301 heap_free(pt);
1302 return hr;
1305 static HRESULT write_PageOutputColor_caps(const WCHAR *device, IXMLDOMElement *root)
1307 HRESULT hr = S_OK;
1308 int color;
1309 IXMLDOMElement *feature = NULL;
1311 FIXME("stub\n");
1313 color = DeviceCapabilitiesW(device, NULL, DC_COLORDEVICE, NULL, NULL);
1314 TRACE("DC_COLORDEVICE: %d\n", color);
1316 hr = create_Feature(root, L"psk:PageOutputColor", &feature);
1317 if (hr != S_OK) goto fail;
1319 fail:
1320 if (feature) IXMLDOMElement_Release(feature);
1321 return hr;
1324 static HRESULT write_PageScaling_caps(const WCHAR *device, IXMLDOMElement *root)
1326 HRESULT hr = S_OK;
1327 IXMLDOMElement *feature = NULL;
1329 FIXME("stub\n");
1331 hr = create_Feature(root, L"psk:PageScaling", &feature);
1332 if (hr != S_OK) goto fail;
1334 fail:
1335 if (feature) IXMLDOMElement_Release(feature);
1336 return hr;
1339 static HRESULT write_PageResolution_caps(const WCHAR *device, IXMLDOMElement *root)
1341 HRESULT hr = S_OK;
1342 int count, i;
1343 struct
1345 LONG x;
1346 LONG y;
1347 } *res;
1348 IXMLDOMElement *feature = NULL;
1350 FIXME("stub\n");
1352 count = DeviceCapabilitiesW(device, NULL, DC_ENUMRESOLUTIONS, NULL, NULL);
1353 if (count <= 0)
1354 return HRESULT_FROM_WIN32(GetLastError());
1356 res = heap_alloc(count * sizeof(*res));
1357 if (!res) return E_OUTOFMEMORY;
1359 count = DeviceCapabilitiesW(device, NULL, DC_ENUMRESOLUTIONS, (LPWSTR)res, NULL);
1360 if (count <= 0)
1362 hr = HRESULT_FROM_WIN32(GetLastError());
1363 goto fail;
1366 hr = create_Feature(root, L"psk:PageResolution", &feature);
1367 if (hr != S_OK) goto fail;
1369 for (i = 0; i < count; i++)
1373 fail:
1374 if (feature) IXMLDOMElement_Release(feature);
1375 heap_free(res);
1376 return hr;
1379 static HRESULT write_PageOrientation_caps(const WCHAR *device, IXMLDOMElement *root)
1381 HRESULT hr = S_OK;
1382 int landscape;
1383 IXMLDOMElement *feature = NULL;
1385 FIXME("stub\n");
1387 landscape = DeviceCapabilitiesW(device, NULL, DC_ORIENTATION, NULL, NULL);
1388 TRACE("DC_ORIENTATION: %d\n", landscape);
1390 hr = create_Feature(root, L"psk:PageOrientation", &feature);
1391 if (hr != S_OK) goto fail;
1393 fail:
1394 if (feature) IXMLDOMElement_Release(feature);
1395 return hr;
1398 static HRESULT write_DocumentCollate_caps(const WCHAR *device, IXMLDOMElement *root)
1400 HRESULT hr = S_OK;
1401 int collate;
1402 IXMLDOMElement *feature = NULL;
1404 FIXME("stub\n");
1406 collate = DeviceCapabilitiesW(device, NULL, DC_COLLATE, NULL, NULL);
1407 TRACE("DC_COLLATE: %d\n", collate);
1409 hr = create_Feature(root, L"psk:DocumentCollate", &feature);
1410 if (hr != S_OK) goto fail;
1412 fail:
1413 if (feature) IXMLDOMElement_Release(feature);
1414 return hr;
1417 static HRESULT write_JobInputBin_caps(const WCHAR *device, IXMLDOMElement *root)
1419 HRESULT hr = S_OK;
1420 int count, i;
1421 WORD *bin;
1422 IXMLDOMElement *feature = NULL;
1424 FIXME("stub\n");
1426 count = DeviceCapabilitiesW(device, NULL, DC_BINS, NULL, NULL);
1427 if (count <= 0)
1428 return HRESULT_FROM_WIN32(GetLastError());
1430 bin = heap_alloc(count * sizeof(*bin));
1431 if (!bin) return E_OUTOFMEMORY;
1433 count = DeviceCapabilitiesW(device, NULL, DC_BINS, (LPWSTR)bin, NULL);
1434 if (count <= 0)
1436 hr = HRESULT_FROM_WIN32(GetLastError());
1437 goto fail;
1440 hr = create_Feature(root, L"psk:JobInputBin", &feature);
1441 if (hr != S_OK) goto fail;
1443 for (i = 0; i < count; i++)
1447 fail:
1448 if (feature) IXMLDOMElement_Release(feature);
1449 heap_free(bin);
1450 return hr;
1453 static HRESULT write_JobCopies_caps(const WCHAR *device, IXMLDOMElement *root)
1455 HRESULT hr = S_OK;
1456 int copies;
1457 IXMLDOMElement *feature = NULL;
1459 FIXME("stub\n");
1461 copies = DeviceCapabilitiesW(device, NULL, DC_COPIES, NULL, NULL);
1462 TRACE("DC_COPIES: %d\n", copies);
1464 hr = create_ParameterDef(root, L"psk:JobCopiesAllDocuments", &feature);
1465 if (hr != S_OK) goto fail;
1467 fail:
1468 if (feature) IXMLDOMElement_Release(feature);
1469 return hr;
1472 static HRESULT write_print_capabilities(const WCHAR *device, IStream *stream)
1474 static const char xmldecl[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
1475 HRESULT hr;
1476 IXMLDOMDocument *doc;
1477 IXMLDOMElement *root = NULL;
1478 VARIANT var;
1480 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
1481 &IID_IXMLDOMDocument, (void **)&doc);
1482 if (hr != S_OK) return hr;
1484 hr = IXMLDOMDocument_createElement(doc, (BSTR)L"psf:PrintCapabilities", &root);
1485 if (hr != S_OK) goto fail;
1487 hr = IXMLDOMDocument_appendChild(doc, (IXMLDOMNode *)root, NULL);
1488 if (hr != S_OK) goto fail;
1490 hr = write_attributes(root);
1491 if (hr != S_OK) goto fail;
1493 hr = write_PageMediaSize_caps(device, root);
1494 if (hr != S_OK) goto fail;
1495 hr = write_PageOutputColor_caps(device, root);
1496 if (hr != S_OK) goto fail;
1497 hr = write_PageScaling_caps(device, root);
1498 if (hr != S_OK) goto fail;
1499 hr = write_PageResolution_caps(device, root);
1500 if (hr != S_OK) goto fail;
1501 hr = write_PageOrientation_caps(device, root);
1502 if (hr != S_OK) goto fail;
1503 hr = write_DocumentCollate_caps(device, root);
1504 if (hr != S_OK) goto fail;
1505 hr = write_JobInputBin_caps(device, root);
1506 if (hr != S_OK) goto fail;
1507 hr = write_JobCopies_caps(device, root);
1508 if (hr != S_OK) goto fail;
1510 hr = IStream_Write(stream, xmldecl, strlen(xmldecl), NULL);
1511 if (hr != S_OK) goto fail;
1513 V_VT(&var) = VT_UNKNOWN;
1514 V_UNKNOWN(&var) = (IUnknown *)stream;
1515 hr = IXMLDOMDocument_save(doc, var);
1517 fail:
1518 if (root) IXMLDOMElement_Release(root);
1519 IXMLDOMDocument_Release(doc);
1520 return hr;
1523 HRESULT WINAPI PTGetPrintCapabilities(HPTPROVIDER provider, IStream *stream, IStream *caps, BSTR *error)
1525 struct prn_provider *prov = (struct prn_provider *)provider;
1526 struct ticket ticket;
1527 HRESULT hr;
1529 TRACE("%p,%p,%p,%p\n", provider, stream, caps, error);
1531 if (!is_valid_provider(provider) || !stream || !caps)
1532 return E_INVALIDARG;
1534 hr = parse_ticket(stream, kPTJobScope, &ticket);
1535 if (hr != S_OK) return hr;
1537 return write_print_capabilities(prov->name, caps);