mlang: Fix GetStrCodePages for characters with different codepages.
[wine.git] / dlls / prntvpt / ticket.c
blobbd18544404b206a42567c3a1f74216ee3f3d07a0
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 #include "windef.h"
23 #include "winbase.h"
24 #include "wingdi.h"
25 #include "winspool.h"
26 #include "objbase.h"
27 #include "prntvpt.h"
28 #include "initguid.h"
29 #include "msxml2.h"
30 #include "wine/debug.h"
32 #include "prntvpt_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(prntvpt);
36 struct size
38 int width;
39 int height;
42 struct media
44 int paper;
45 struct size size;
48 struct resolution
50 int x;
51 int y;
54 struct page
56 struct media media;
57 struct resolution resolution;
58 int orientation;
59 int scaling;
60 int color;
63 struct document
65 int collate;
68 struct job
70 int nup;
71 int copies;
72 int input_bin;
75 struct ticket
77 struct job job;
78 struct document document;
79 struct page page;
82 static const struct
84 const WCHAR *name;
85 int paper;
86 } psk_media[] =
88 { L"psk:ISOA4", DMPAPER_A4 },
91 static int media_to_paper(const WCHAR *name)
93 int i;
95 for (i = 0 ; i < ARRAY_SIZE(psk_media); i++)
96 if (!wcscmp(name, psk_media[i].name))
97 return psk_media[i].paper;
99 FIXME("%s\n", wine_dbgstr_w(name));
100 return DMPAPER_A4;
103 static const WCHAR *paper_to_media(int paper)
105 int i;
107 for (i = 0 ; i < ARRAY_SIZE(psk_media); i++)
108 if (psk_media[i].paper == paper)
109 return psk_media[i].name;
111 FIXME("%d\n", paper);
112 return psk_media[0].name;
115 static BOOL is_valid_node_name(const WCHAR *name)
117 static const WCHAR * const psf_names[] = { L"psf:ParameterInit", L"psf:Feature" };
118 int i;
120 for (i = 0 ; i < ARRAY_SIZE(psf_names); i++)
121 if (!wcscmp(name, psf_names[i])) return TRUE;
123 return FALSE;
126 static HRESULT verify_ticket(IXMLDOMDocument2 *doc)
128 IXMLDOMElement *element;
129 IXMLDOMNode *node = NULL;
130 BSTR str;
131 HRESULT hr;
133 hr = IXMLDOMDocument2_get_documentElement(doc, &element);
134 if (hr != S_OK) return E_PRINTTICKET_FORMAT;
136 hr = IXMLDOMElement_get_tagName(element, &str);
137 if (hr != S_OK) goto fail;
138 if (wcscmp(str, L"psf:PrintTicket") != 0)
139 hr = E_FAIL;
140 SysFreeString(str);
141 if (hr != S_OK) goto fail;
143 hr = IXMLDOMElement_get_firstChild(element, &node);
144 IXMLDOMElement_Release(element);
145 if (hr != S_OK) return S_OK;
147 for (;;)
149 VARIANT var;
150 IXMLDOMNode *next_node;
152 hr = IXMLDOMNode_get_nodeName(node, &str);
153 if (hr != S_OK) break;
154 if (!is_valid_node_name(str))
155 hr = E_FAIL;
156 SysFreeString(str);
157 if (hr != S_OK) break;
159 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void **)&element);
160 if (hr != S_OK) break;
162 VariantInit(&var);
163 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
164 IXMLDOMElement_Release(element);
165 if (hr != S_OK) break;
166 if (V_VT(&var) != VT_BSTR)
167 hr = E_FAIL;
168 VariantClear(&var);
169 if (hr != S_OK) break;
171 hr = IXMLDOMNode_get_nextSibling(node, &next_node);
172 if (hr != S_OK)
174 hr = S_OK;
175 break;
178 IXMLDOMNode_Release(node);
179 node = next_node;
182 fail:
183 if (node) IXMLDOMNode_Release(node);
185 return hr != S_OK ? E_PRINTTICKET_FORMAT : S_OK;
188 static HRESULT read_int_value(IXMLDOMNode *node, int *value)
190 IXMLDOMNode *val;
191 HRESULT hr;
192 VARIANT var1, var2;
194 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Value[@xsi:type='xsd:integer']", &val);
195 if (hr != S_OK) return hr;
197 VariantInit(&var1);
198 hr = IXMLDOMNode_get_nodeTypedValue(val, &var1);
199 if (hr == S_OK)
201 VariantInit(&var2);
202 hr = VariantChangeTypeEx(&var2, &var1, 0, 0, VT_I4);
203 if (hr == S_OK)
204 *value = V_I4(&var2);
206 VariantClear(&var1);
209 IXMLDOMNode_Release(val);
210 return hr;
213 static void read_PageMediaSize(IXMLDOMDocument2 *doc, struct ticket *ticket)
215 IXMLDOMNode *node, *option, *child;
216 HRESULT hr;
218 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageMediaSize']", &node);
219 if (hr != S_OK) return;
221 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
222 if (hr == S_OK)
224 IXMLDOMElement *element;
226 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
227 if (hr == S_OK)
229 VARIANT var;
231 VariantInit(&var);
232 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
233 if (hr == S_OK && V_VT(&var) == VT_BSTR)
235 ticket->page.media.paper = media_to_paper(V_BSTR(&var));
236 TRACE("paper: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->page.media.paper);
238 VariantClear(&var);
240 IXMLDOMElement_Release(element);
243 hr = IXMLDOMNode_selectSingleNode(option, (BSTR)L"./psf:ScoredProperty[@name='psk:MediaSizeWidth']", &child);
244 if (hr == S_OK)
246 if (read_int_value(child, &ticket->page.media.size.width) == S_OK)
247 TRACE("width: %d\n", ticket->page.media.size.width);
248 IXMLDOMNode_Release(child);
251 hr = IXMLDOMNode_selectSingleNode(option, (BSTR)L"./psf:ScoredProperty[@name='psk:MediaSizeHeight']", &child);
252 if (hr == S_OK)
254 if (read_int_value(child, &ticket->page.media.size.height) == S_OK)
255 TRACE("height: %d\n", ticket->page.media.size.height);
256 IXMLDOMNode_Release(child);
259 IXMLDOMNode_Release(option);
262 IXMLDOMNode_Release(node);
265 static void read_PageOutputColor(IXMLDOMDocument2 *doc, struct ticket *ticket)
267 IXMLDOMNode *node, *option;
268 HRESULT hr;
270 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageOutputColor']", &node);
271 if (hr != S_OK) return;
273 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
274 if (hr == S_OK)
276 IXMLDOMElement *element;
278 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
279 if (hr == S_OK)
281 VARIANT var;
283 VariantInit(&var);
284 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
285 if (hr == S_OK && V_VT(&var) == VT_BSTR)
287 if (!wcscmp(V_BSTR(&var), L"psk:Color"))
288 ticket->page.color = DMCOLOR_COLOR;
289 else if (!wcscmp(V_BSTR(&var), L"psk:Monochrome"))
290 ticket->page.color = DMCOLOR_MONOCHROME;
291 else
293 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var)));
294 ticket->page.color = DMCOLOR_MONOCHROME;
296 TRACE("color: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->page.color);
298 VariantClear(&var);
300 IXMLDOMElement_Release(element);
304 IXMLDOMNode_Release(node);
307 static void read_PageScaling(IXMLDOMDocument2 *doc, struct ticket *ticket)
309 IXMLDOMNode *node, *option;
310 int scaling = 0;
311 HRESULT hr;
313 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageScaling']", &node);
314 if (hr != S_OK) return;
316 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
317 if (hr == S_OK)
319 IXMLDOMElement *element;
321 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
322 if (hr == S_OK)
324 VARIANT var;
326 VariantInit(&var);
327 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
328 if (hr == S_OK && V_VT(&var) == VT_BSTR)
330 if (!wcscmp(V_BSTR(&var), L"psk:None"))
331 scaling = 100;
332 else if (!wcscmp(V_BSTR(&var), L"psk:CustomSquare"))
333 scaling = 0; /* psk:PageScalingScale */
334 else
335 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var)));
337 VariantClear(&var);
339 IXMLDOMElement_Release(element);
343 IXMLDOMNode_Release(node);
345 if (!scaling)
347 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:ParameterInit[@name='psk:PageScalingScale']", &node);
348 if (hr == S_OK)
350 read_int_value(node, &scaling);
351 IXMLDOMNode_Release(node);
355 if (scaling)
356 ticket->page.scaling = scaling;
357 else
358 ticket->page.scaling = 100;
360 TRACE("page.scaling: %d\n", ticket->page.scaling);
363 static void read_PageResolution(IXMLDOMDocument2 *doc, struct ticket *ticket)
365 IXMLDOMNode *node, *option, *child;
366 HRESULT hr;
368 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageResolution']", &node);
369 if (hr != S_OK) return;
371 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
372 if (hr == S_OK)
374 hr = IXMLDOMNode_selectSingleNode(option, (BSTR)L"./psf:ScoredProperty[@name='psk:ResolutionX']", &child);
375 if (hr == S_OK)
377 if (read_int_value(child, &ticket->page.resolution.x) == S_OK)
378 TRACE("resolution.x: %d\n", ticket->page.resolution.x);
379 IXMLDOMNode_Release(child);
382 hr = IXMLDOMNode_selectSingleNode(option, (BSTR)L"./psf:ScoredProperty[@name='psk:ResolutionY']", &child);
383 if (hr == S_OK)
385 if (read_int_value(child, &ticket->page.resolution.y) == S_OK)
386 TRACE("resolution.y: %d\n", ticket->page.resolution.y);
387 IXMLDOMNode_Release(child);
390 IXMLDOMNode_Release(option);
393 IXMLDOMNode_Release(node);
396 static void read_PageOrientation(IXMLDOMDocument2 *doc, struct ticket *ticket)
398 IXMLDOMNode *node, *option;
399 HRESULT hr;
401 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageOrientation']", &node);
402 if (hr != S_OK) return;
404 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
405 if (hr == S_OK)
407 IXMLDOMElement *element;
409 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
410 if (hr == S_OK)
412 VARIANT var;
414 VariantInit(&var);
415 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
416 if (hr == S_OK && V_VT(&var) == VT_BSTR)
418 if (!wcscmp(V_BSTR(&var), L"psk:Portrait"))
419 ticket->page.orientation = DMORIENT_PORTRAIT;
420 else if (!wcscmp(V_BSTR(&var), L"psk:Landscape"))
421 ticket->page.orientation = DMORIENT_LANDSCAPE;
422 else
424 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var)));
425 ticket->page.orientation = DMORIENT_PORTRAIT;
427 TRACE("orientation: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->page.orientation);
429 VariantClear(&var);
431 IXMLDOMElement_Release(element);
435 IXMLDOMNode_Release(node);
438 static void read_DocumentCollate(IXMLDOMDocument2 *doc, struct ticket *ticket)
440 IXMLDOMNode *node, *option;
441 HRESULT hr;
443 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:DocumentCollate']", &node);
444 if (hr != S_OK) return;
446 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
447 if (hr == S_OK)
449 IXMLDOMElement *element;
451 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
452 if (hr == S_OK)
454 VARIANT var;
456 VariantInit(&var);
457 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
458 if (hr == S_OK && V_VT(&var) == VT_BSTR)
460 if (!wcscmp(V_BSTR(&var), L"psk:Collated"))
461 ticket->document.collate = DMCOLLATE_TRUE;
462 else if (!wcscmp(V_BSTR(&var), L"psk:Uncollated"))
463 ticket->document.collate = DMCOLLATE_FALSE;
464 else
466 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var)));
467 ticket->document.collate = DMCOLLATE_FALSE;
469 TRACE("document.collate: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->document.collate);
471 VariantClear(&var);
473 IXMLDOMElement_Release(element);
477 IXMLDOMNode_Release(node);
480 static void read_JobInputBin(IXMLDOMDocument2 *doc, struct ticket *ticket)
482 IXMLDOMNode *node, *option;
483 HRESULT hr;
485 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:JobInputBin']", &node);
486 if (hr != S_OK) return;
488 hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
489 if (hr == S_OK)
491 IXMLDOMElement *element;
493 hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
494 if (hr == S_OK)
496 VARIANT var;
498 VariantInit(&var);
499 hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
500 if (hr == S_OK && V_VT(&var) == VT_BSTR)
502 if (!wcscmp(V_BSTR(&var), L"psk:AutoSelect"))
503 ticket->job.input_bin = DMBIN_AUTO;
504 else
506 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var)));
507 ticket->job.input_bin = DMBIN_AUTO;
509 TRACE("input_bin: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->job.input_bin);
511 VariantClear(&var);
513 IXMLDOMElement_Release(element);
517 IXMLDOMNode_Release(node);
520 static void read_JobCopies(IXMLDOMDocument2 *doc, struct ticket *ticket)
522 IXMLDOMNode *node;
523 HRESULT hr;
525 hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:ParameterInit[@name='psk:JobCopiesAllDocuments']", &node);
526 if (hr != S_OK) return;
528 if (read_int_value(node, &ticket->job.copies) == S_OK)
529 TRACE("job.copies: %d\n", ticket->job.copies);
531 IXMLDOMNode_Release(node);
534 static void set_SelectionNamespaces(IXMLDOMDocument2 *doc)
536 IStream *stream;
537 IXMLDOMElement *element = NULL;
538 IXMLDOMNamedNodeMap *map = NULL;
539 HRESULT hr;
540 LONG count, i;
541 HGLOBAL hmem;
542 BSTR str;
543 VARIANT var;
545 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
546 if (hr != S_OK) return;
548 hr = IXMLDOMDocument2_get_documentElement(doc, &element);
549 if (hr != S_OK) goto fail;
551 hr = IXMLDOMElement_get_attributes(element, &map);
552 if (hr != S_OK) goto fail;
554 hr = IXMLDOMNamedNodeMap_get_length(map, &count);
555 if (hr != S_OK) goto fail;
557 for (i = 0; i < count; i++)
559 IXMLDOMNode *node;
561 hr = IXMLDOMNamedNodeMap_get_item(map, i, &node);
562 if (hr == S_OK)
564 hr = IXMLDOMNode_get_nodeName(node, &str);
565 if (hr == S_OK)
567 VariantInit(&var);
568 hr = IXMLDOMNode_get_nodeValue(node, &var);
569 if (hr == S_OK)
571 if (!wcscmp(str, L"xmlns") || !wcsncmp(str, L"xmlns:", 6))
573 TRACE("ns[%ld]: %s=%s\n", i, wine_dbgstr_w(str), wine_dbgstr_w(V_BSTR(&var)));
574 IStream_Write(stream, str, wcslen(str) * sizeof(WCHAR), NULL);
575 IStream_Write(stream, L"=\"", 2 * sizeof(WCHAR), NULL);
576 IStream_Write(stream, V_BSTR(&var), wcslen(V_BSTR(&var)) * sizeof(WCHAR), NULL);
577 IStream_Write(stream, L"\" ", 2 * sizeof(WCHAR), NULL);
579 VariantClear(&var);
581 SysFreeString(str);
583 IXMLDOMNode_Release(node);
587 IStream_Write(stream, L"", sizeof(WCHAR), NULL);
589 hr = GetHGlobalFromStream(stream, &hmem);
590 if (hr != S_OK) goto fail;
592 str = GlobalLock(hmem);
593 V_VT(&var) = VT_BSTR;
594 V_BSTR(&var) = SysAllocString(str);
595 IXMLDOMDocument2_setProperty(doc, (BSTR)L"SelectionNamespaces", var);
596 SysFreeString(V_BSTR(&var));
597 GlobalUnlock(hmem);
599 fail:
600 if (map) IXMLDOMNamedNodeMap_Release(map);
601 if (element) IXMLDOMElement_Release(element);
602 IStream_Release(stream);
605 static HRESULT parse_ticket(IStream *stream, EPrintTicketScope scope, struct ticket *ticket)
607 IXMLDOMDocument2 *doc;
608 VARIANT src;
609 VARIANT_BOOL ret;
610 HRESULT hr;
612 hr = CoCreateInstance(&CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER,
613 &IID_IXMLDOMDocument2, (void **)&doc);
614 if (hr != S_OK) return hr;
616 V_VT(&src) = VT_UNKNOWN;
617 V_UNKNOWN(&src) = (IUnknown *)stream;
618 hr = IXMLDOMDocument2_load(doc, src, &ret);
619 if (hr != S_OK) goto fail;
621 hr = verify_ticket(doc);
622 if (hr != S_OK) goto fail;
624 set_SelectionNamespaces(doc);
626 /* PageScope is always added */
627 read_PageMediaSize(doc, ticket);
628 read_PageOutputColor(doc, ticket);
629 read_PageScaling(doc, ticket);
630 read_PageResolution(doc, ticket);
631 read_PageOrientation(doc, ticket);
633 if (scope > kPTPageScope)
634 read_DocumentCollate(doc, ticket);
636 if (scope > kPTDocumentScope)
638 read_JobInputBin(doc, ticket);
639 read_JobCopies(doc, ticket);
642 fail:
643 IXMLDOMDocument2_Release(doc);
644 return hr;
647 static void ticket_to_devmode(const struct ticket *ticket, DEVMODEW *dm)
649 memset(dm, 0, sizeof(*dm));
651 dm->dmSize = sizeof(*dm);
652 dm->dmFields = DM_ORIENTATION | DM_PAPERSIZE | DM_PAPERLENGTH | DM_PAPERWIDTH | DM_SCALE |
653 DM_COPIES | DM_COLOR | DM_PRINTQUALITY | DM_YRESOLUTION | DM_COLLATE;
654 dm->dmOrientation = ticket->page.orientation;
655 dm->dmPaperSize = ticket->page.media.paper;
656 dm->dmPaperWidth = ticket->page.media.size.width / 100;
657 dm->dmPaperLength = ticket->page.media.size.height / 100;
658 dm->dmScale = ticket->page.scaling;
659 dm->dmCopies = ticket->job.copies;
660 dm->dmColor = ticket->page.color;
661 dm->dmPrintQuality = ticket->page.resolution.x;
662 dm->dmYResolution = ticket->page.resolution.y;
663 dm->dmCollate = ticket->document.collate;
666 static void devmode_to_ticket(const DEVMODEW *dm, struct ticket *ticket)
668 if (dm->dmFields & DM_ORIENTATION)
669 ticket->page.orientation = dm->dmOrientation;
670 if (dm->dmFields & DM_PAPERSIZE)
671 ticket->page.media.paper = dm->dmPaperSize;
672 if (dm->dmFields & DM_PAPERLENGTH)
673 ticket->page.media.size.width = dm->dmPaperWidth * 100;
674 if (dm->dmFields & DM_PAPERWIDTH)
675 ticket->page.media.size.height = dm->dmPaperLength * 100;
676 if (dm->dmFields & DM_SCALE)
677 ticket->page.scaling = dm->dmScale;
678 if (dm->dmFields & DM_COPIES)
679 ticket->job.copies = dm->dmCopies;
680 if (dm->dmFields & DM_COLOR)
681 ticket->page.color = dm->dmColor;
682 if (dm->dmFields & DM_PRINTQUALITY)
684 ticket->page.resolution.x = dm->dmPrintQuality;
685 ticket->page.resolution.y = dm->dmPrintQuality;
687 if (dm->dmFields & DM_YRESOLUTION)
688 ticket->page.resolution.y = dm->dmYResolution;
689 if (dm->dmFields & DM_LOGPIXELS)
691 ticket->page.resolution.x = dm->dmLogPixels;
692 ticket->page.resolution.y = dm->dmLogPixels;
694 if (dm->dmFields & DM_COLLATE)
695 ticket->document.collate = dm->dmCollate;
698 static HRESULT initialize_ticket(struct prn_provider *prov, struct ticket *ticket)
700 PRINTER_INFO_2W *pi2;
701 DWORD size;
702 HRESULT hr = S_OK;
704 GetPrinterW(prov->hprn, 2, NULL, 0, &size);
705 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
706 return HRESULT_FROM_WIN32(GetLastError());
708 pi2 = malloc(size);
709 if (!pi2) return E_OUTOFMEMORY;
711 if (!GetPrinterW(prov->hprn, 2, (LPBYTE)pi2, size, NULL))
712 hr = HRESULT_FROM_WIN32(GetLastError());
713 else
714 devmode_to_ticket(pi2->pDevMode, ticket);
716 free(pi2);
717 return hr;
720 HRESULT WINAPI PTConvertPrintTicketToDevMode(HPTPROVIDER provider, IStream *stream, EDefaultDevmodeType type,
721 EPrintTicketScope scope, ULONG *size, PDEVMODEW *dm, BSTR *error)
723 struct prn_provider *prov = (struct prn_provider *)provider;
724 HRESULT hr;
725 struct ticket ticket;
727 TRACE("%p,%p,%d,%d,%p,%p,%p\n", provider, stream, type, scope, size, dm, error);
729 if (!is_valid_provider(provider) || !stream || !size || !dm)
730 return E_INVALIDARG;
732 hr = initialize_ticket(prov, &ticket);
733 if (hr != S_OK) return hr;
735 hr = parse_ticket(stream, scope, &ticket);
736 if (hr != S_OK) return hr;
738 *dm = malloc(sizeof(**dm));
739 if (!*dm) return E_OUTOFMEMORY;
741 ticket_to_devmode(&ticket, *dm);
742 *size = sizeof(**dm);
744 return S_OK;
747 static HRESULT add_attribute(IXMLDOMElement *element, const WCHAR *attr, const WCHAR *value)
749 VARIANT var;
750 BSTR name;
751 HRESULT hr;
753 name = SysAllocString(attr);
754 V_VT(&var) = VT_BSTR;
755 V_BSTR(&var) = SysAllocString(value);
757 hr = IXMLDOMElement_setAttribute(element, name, var);
759 SysFreeString(name);
760 SysFreeString(V_BSTR(&var));
762 return hr;
765 static HRESULT create_element(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
767 IXMLDOMDocument *doc;
768 HRESULT hr;
770 hr = IXMLDOMElement_get_ownerDocument(root, &doc);
771 if (hr != S_OK) return hr;
773 hr = IXMLDOMDocument_createElement(doc, (BSTR)name, child);
774 if (hr == S_OK)
775 hr = IXMLDOMElement_appendChild(root, (IXMLDOMNode *)*child, NULL);
777 IXMLDOMDocument_Release(doc);
778 return hr;
781 static HRESULT write_int_value(IXMLDOMElement *root, int value)
783 HRESULT hr;
784 IXMLDOMElement *child;
785 VARIANT var;
787 hr = create_element(root, L"psf:Value", &child);
788 if (hr != S_OK) return hr;
790 hr = add_attribute(child, L"xsi:type", L"xsd:integer");
791 if (hr != S_OK) return hr;
793 V_VT(&var) = VT_I4;
794 V_I4(&var) = value;
795 hr = IXMLDOMElement_put_nodeTypedValue(child, var);
797 IXMLDOMElement_Release(child);
798 return hr;
801 static HRESULT create_Feature(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
803 HRESULT hr;
805 hr = create_element(root, L"psf:Feature", child);
806 if (hr != S_OK) return hr;
808 return add_attribute(*child, L"name", name);
811 static HRESULT create_Option(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
813 HRESULT hr;
815 hr = create_element(root, L"psf:Option", child);
816 if (hr != S_OK) return hr;
818 if (name)
819 hr = add_attribute(*child, L"name", name);
821 return hr;
824 static HRESULT create_ParameterInit(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
826 HRESULT hr;
828 hr = create_element(root, L"psf:ParameterInit", child);
829 if (hr != S_OK) return hr;
831 return add_attribute(*child, L"name", name);
834 static HRESULT create_ParameterRef(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
836 HRESULT hr;
838 hr = create_element(root, L"psf:ParameterRef", child);
839 if (hr != S_OK) return hr;
841 return add_attribute(*child, L"name", name);
844 static HRESULT create_ParameterDef(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
846 HRESULT hr;
848 hr = create_element(root, L"psf:ParameterDef", child);
849 if (hr != S_OK) return hr;
851 return add_attribute(*child, L"name", name);
854 static HRESULT create_ScoredProperty(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
856 HRESULT hr;
858 hr = create_element(root, L"psf:ScoredProperty", child);
859 if (hr != S_OK) return hr;
861 return add_attribute(*child, L"name", name);
864 static HRESULT write_PageMediaSize(IXMLDOMElement *root, const struct ticket *ticket)
866 IXMLDOMElement *feature, *option = NULL, *property;
867 HRESULT hr;
869 hr = create_Feature(root, L"psk:PageMediaSize", &feature);
870 if (hr != S_OK) return hr;
872 hr = create_Option(feature, paper_to_media(ticket->page.media.paper), &option);
873 if (hr != S_OK) goto fail;
875 hr = create_ScoredProperty(option, L"psk:MediaSizeWidth", &property);
876 if (hr != S_OK) goto fail;
877 hr = write_int_value(property, ticket->page.media.size.width);
878 IXMLDOMElement_Release(property);
879 if (hr != S_OK) goto fail;
881 hr = create_ScoredProperty(option, L"psk:MediaSizeHeight", &property);
882 if (hr != S_OK) goto fail;
883 hr = write_int_value(property, ticket->page.media.size.height);
884 IXMLDOMElement_Release(property);
886 fail:
887 if (option) IXMLDOMElement_Release(option);
888 IXMLDOMElement_Release(feature);
889 return hr;
892 static HRESULT write_PageOutputColor(IXMLDOMElement *root, const struct ticket *ticket)
894 IXMLDOMElement *feature, *option = NULL;
895 HRESULT hr;
897 hr = create_Feature(root, L"psk:PageOutputColor", &feature);
898 if (hr != S_OK) return hr;
900 if (ticket->page.color == DMCOLOR_COLOR)
901 hr = create_Option(feature, L"psk:Color", &option);
902 else /* DMCOLOR_MONOCHROME */
903 hr = create_Option(feature, L"psk:Monochrome", &option);
905 if (option) IXMLDOMElement_Release(option);
906 IXMLDOMElement_Release(feature);
907 return hr;
910 static HRESULT write_PageScaling(IXMLDOMElement *root, const struct ticket *ticket)
912 IXMLDOMElement *feature, *option = NULL;
913 HRESULT hr;
915 hr = create_Feature(root, L"psk:PageScaling", &feature);
916 if (hr != S_OK) return hr;
918 if (ticket->page.scaling == 100)
920 hr = create_Option(feature, L"psk:None", &option);
921 if (hr == S_OK) IXMLDOMElement_Release(option);
923 else
925 hr = create_Option(feature, L"psk:CustomSquare", &option);
926 if (hr == S_OK)
928 IXMLDOMElement *property, *parameter;
930 hr = create_ScoredProperty(option, L"psk:Scale", &property);
931 if (hr == S_OK)
933 hr = create_ParameterRef(property, L"psk:PageScalingScale", &parameter);
934 if (hr == S_OK)
936 IXMLDOMElement_Release(parameter);
938 hr = create_ParameterInit(root, L"psk:PageScalingScale", &parameter);
939 if (hr == S_OK)
941 hr = write_int_value(parameter, ticket->page.scaling);
942 IXMLDOMElement_Release(parameter);
946 IXMLDOMElement_Release(property);
949 IXMLDOMElement_Release(option);
953 IXMLDOMElement_Release(feature);
954 return hr;
957 static HRESULT write_PageResolution(IXMLDOMElement *root, const struct ticket *ticket)
959 IXMLDOMElement *feature, *option = NULL, *property;
960 HRESULT hr;
962 hr = create_Feature(root, L"psk:PageResolution", &feature);
963 if (hr != S_OK) return hr;
965 hr = create_Option(feature, NULL, &option);
966 if (hr != S_OK) goto fail;
968 hr = create_ScoredProperty(option, L"psk:ResolutionX", &property);
969 if (hr != S_OK) goto fail;
970 hr = write_int_value(property, ticket->page.resolution.x);
971 IXMLDOMElement_Release(property);
972 if (hr != S_OK) goto fail;
974 hr = create_ScoredProperty(option, L"psk:ResolutionY", &property);
975 if (hr != S_OK) goto fail;
976 hr = write_int_value(property, ticket->page.resolution.y);
977 IXMLDOMElement_Release(property);
979 fail:
980 if (option) IXMLDOMElement_Release(option);
981 IXMLDOMElement_Release(feature);
982 return hr;
985 static HRESULT write_PageOrientation(IXMLDOMElement *root, const struct ticket *ticket)
987 IXMLDOMElement *feature, *option = NULL;
988 HRESULT hr;
990 hr = create_Feature(root, L"psk:PageOrientation", &feature);
991 if (hr != S_OK) return hr;
993 if (ticket->page.orientation == DMORIENT_PORTRAIT)
994 hr = create_Option(feature, L"psk:Portrait", &option);
995 else /* DMORIENT_LANDSCAPE */
996 hr = create_Option(feature, L"psk:Landscape", &option);
998 if (option) IXMLDOMElement_Release(option);
999 IXMLDOMElement_Release(feature);
1000 return hr;
1003 static HRESULT write_DocumentCollate(IXMLDOMElement *root, const struct ticket *ticket)
1005 IXMLDOMElement *feature, *option = NULL;
1006 HRESULT hr;
1008 hr = create_Feature(root, L"psk:DocumentCollate", &feature);
1009 if (hr != S_OK) return hr;
1011 if (ticket->document.collate == DMCOLLATE_TRUE)
1012 hr = create_Option(feature, L"psk:Collated", &option);
1013 else /* DMCOLLATE_FALSE */
1014 hr = create_Option(feature, L"psk:Uncollated", &option);
1016 if (option) IXMLDOMElement_Release(option);
1017 IXMLDOMElement_Release(feature);
1018 return hr;
1021 static HRESULT write_JobInputBin(IXMLDOMElement *root, const struct ticket *ticket)
1023 IXMLDOMElement *feature, *option = NULL;
1024 HRESULT hr;
1026 hr = create_Feature(root, L"psk:JobInputBin", &feature);
1027 if (hr != S_OK) return hr;
1029 if (ticket->job.input_bin != DMBIN_AUTO)
1030 FIXME("job.input_bin: %d\n", ticket->job.input_bin);
1032 hr = create_Option(feature, L"psk:AutoSelect", &option);
1034 if (option) IXMLDOMElement_Release(option);
1035 IXMLDOMElement_Release(feature);
1036 return hr;
1039 static HRESULT write_JobCopies(IXMLDOMElement *root, const struct ticket *ticket)
1041 IXMLDOMElement *parameter;
1042 HRESULT hr;
1044 hr = create_ParameterInit(root, L"psk:JobCopiesAllDocuments", &parameter);
1045 if (hr != S_OK) return hr;
1047 hr = write_int_value(parameter, ticket->job.copies);
1049 IXMLDOMElement_Release(parameter);
1050 return hr;
1053 static HRESULT write_attributes(IXMLDOMElement *element)
1055 HRESULT hr;
1057 hr = add_attribute(element, L"xmlns:psf", L"http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework");
1058 if (hr != S_OK) return hr;
1059 hr = add_attribute(element, L"xmlns:psk", L"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords");
1060 if (hr != S_OK) return hr;
1061 hr = add_attribute(element, L"xmlns:xsi", L"http://www.w3.org/2001/XMLSchema-instance");
1062 if (hr != S_OK) return hr;
1063 hr = add_attribute(element, L"xmlns:xsd", L"http://www.w3.org/2001/XMLSchema");
1064 if (hr != S_OK) return hr;
1066 return add_attribute(element, L"version", L"1");
1069 static HRESULT write_ticket(IStream *stream, const struct ticket *ticket, EPrintTicketScope scope)
1071 static const char xmldecl[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
1072 HRESULT hr;
1073 IXMLDOMDocument *doc;
1074 IXMLDOMElement *root = NULL;
1075 VARIANT var;
1077 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
1078 &IID_IXMLDOMDocument, (void **)&doc);
1079 if (hr != S_OK) return hr;
1081 hr = IXMLDOMDocument_createElement(doc, (BSTR)L"psf:PrintTicket", &root);
1082 if (hr != S_OK) goto fail;
1084 hr = IXMLDOMDocument_appendChild(doc, (IXMLDOMNode *)root, NULL);
1085 if (hr != S_OK) goto fail;
1087 hr = write_attributes(root);
1088 if (hr != S_OK) goto fail;
1090 hr = write_PageMediaSize(root, ticket);
1091 if (hr != S_OK) goto fail;
1092 hr = write_PageOutputColor(root, ticket);
1093 if (hr != S_OK) goto fail;
1094 hr = write_PageScaling(root, ticket);
1095 if (hr != S_OK) goto fail;
1096 hr = write_PageResolution(root, ticket);
1097 if (hr != S_OK) goto fail;
1098 hr = write_PageOrientation(root, ticket);
1099 if (hr != S_OK) goto fail;
1101 if (scope >= kPTDocumentScope)
1103 hr = write_DocumentCollate(root, ticket);
1104 if (hr != S_OK) goto fail;
1107 if (scope >= kPTJobScope)
1109 hr = write_JobInputBin(root, ticket);
1110 if (hr != S_OK) goto fail;
1111 hr = write_JobCopies(root, ticket);
1112 if (hr != S_OK) goto fail;
1115 hr = IStream_Write(stream, xmldecl, strlen(xmldecl), NULL);
1116 if (hr != S_OK) goto fail;
1118 V_VT(&var) = VT_UNKNOWN;
1119 V_UNKNOWN(&var) = (IUnknown *)stream;
1120 hr = IXMLDOMDocument_save(doc, var);
1122 fail:
1123 if (root) IXMLDOMElement_Release(root);
1124 IXMLDOMDocument_Release(doc);
1125 return hr;
1128 static void dump_fields(DWORD fields)
1130 int add_space = 0;
1132 #define CHECK_FIELD(flag) \
1133 do \
1135 if (fields & flag) \
1137 if (add_space++) TRACE(" "); \
1138 TRACE(#flag); \
1139 fields &= ~flag; \
1142 while (0)
1144 CHECK_FIELD(DM_ORIENTATION);
1145 CHECK_FIELD(DM_PAPERSIZE);
1146 CHECK_FIELD(DM_PAPERLENGTH);
1147 CHECK_FIELD(DM_PAPERWIDTH);
1148 CHECK_FIELD(DM_SCALE);
1149 CHECK_FIELD(DM_POSITION);
1150 CHECK_FIELD(DM_NUP);
1151 CHECK_FIELD(DM_DISPLAYORIENTATION);
1152 CHECK_FIELD(DM_COPIES);
1153 CHECK_FIELD(DM_DEFAULTSOURCE);
1154 CHECK_FIELD(DM_PRINTQUALITY);
1155 CHECK_FIELD(DM_COLOR);
1156 CHECK_FIELD(DM_DUPLEX);
1157 CHECK_FIELD(DM_YRESOLUTION);
1158 CHECK_FIELD(DM_TTOPTION);
1159 CHECK_FIELD(DM_COLLATE);
1160 CHECK_FIELD(DM_FORMNAME);
1161 CHECK_FIELD(DM_LOGPIXELS);
1162 CHECK_FIELD(DM_BITSPERPEL);
1163 CHECK_FIELD(DM_PELSWIDTH);
1164 CHECK_FIELD(DM_PELSHEIGHT);
1165 CHECK_FIELD(DM_DISPLAYFLAGS);
1166 CHECK_FIELD(DM_DISPLAYFREQUENCY);
1167 CHECK_FIELD(DM_ICMMETHOD);
1168 CHECK_FIELD(DM_ICMINTENT);
1169 CHECK_FIELD(DM_MEDIATYPE);
1170 CHECK_FIELD(DM_DITHERTYPE);
1171 CHECK_FIELD(DM_PANNINGWIDTH);
1172 CHECK_FIELD(DM_PANNINGHEIGHT);
1173 if (fields) TRACE(" %#lx", fields);
1174 TRACE("\n");
1175 #undef CHECK_FIELD
1178 /* Dump DEVMODE structure without a device specific part.
1179 * Some applications and drivers fail to specify correct field
1180 * flags (like DM_FORMNAME), so dump everything.
1182 static void dump_devmode(const DEVMODEW *dm)
1184 if (!TRACE_ON(prntvpt)) return;
1186 TRACE("dmDeviceName: %s\n", debugstr_w(dm->dmDeviceName));
1187 TRACE("dmSpecVersion: 0x%04x\n", dm->dmSpecVersion);
1188 TRACE("dmDriverVersion: 0x%04x\n", dm->dmDriverVersion);
1189 TRACE("dmSize: 0x%04x\n", dm->dmSize);
1190 TRACE("dmDriverExtra: 0x%04x\n", dm->dmDriverExtra);
1191 TRACE("dmFields: 0x%04lx\n", dm->dmFields);
1192 dump_fields(dm->dmFields);
1193 TRACE("dmOrientation: %d\n", dm->dmOrientation);
1194 TRACE("dmPaperSize: %d\n", dm->dmPaperSize);
1195 TRACE("dmPaperLength: %d\n", dm->dmPaperLength);
1196 TRACE("dmPaperWidth: %d\n", dm->dmPaperWidth);
1197 TRACE("dmScale: %d\n", dm->dmScale);
1198 TRACE("dmCopies: %d\n", dm->dmCopies);
1199 TRACE("dmDefaultSource: %d\n", dm->dmDefaultSource);
1200 TRACE("dmPrintQuality: %d\n", dm->dmPrintQuality);
1201 TRACE("dmColor: %d\n", dm->dmColor);
1202 TRACE("dmDuplex: %d\n", dm->dmDuplex);
1203 TRACE("dmYResolution: %d\n", dm->dmYResolution);
1204 TRACE("dmTTOption: %d\n", dm->dmTTOption);
1205 TRACE("dmCollate: %d\n", dm->dmCollate);
1206 TRACE("dmFormName: %s\n", debugstr_w(dm->dmFormName));
1207 TRACE("dmLogPixels %u\n", dm->dmLogPixels);
1208 TRACE("dmBitsPerPel %lu\n", dm->dmBitsPerPel);
1209 TRACE("dmPelsWidth %lu\n", dm->dmPelsWidth);
1210 TRACE("dmPelsHeight %lu\n", dm->dmPelsHeight);
1213 HRESULT WINAPI PTConvertDevModeToPrintTicket(HPTPROVIDER provider, ULONG size, PDEVMODEW dm,
1214 EPrintTicketScope scope, IStream *stream)
1216 struct prn_provider *prov = (struct prn_provider *)provider;
1217 struct ticket ticket;
1218 HRESULT hr;
1220 TRACE("%p,%lu,%p,%d,%p\n", provider, size, dm, scope, stream);
1222 if (!is_valid_provider(provider) || !dm || !stream)
1223 return E_INVALIDARG;
1225 dump_devmode(dm);
1227 if (!IsValidDevmodeW(dm, size))
1228 return E_INVALIDARG;
1230 hr = initialize_ticket(prov, &ticket);
1231 if (hr != S_OK) return hr;
1232 devmode_to_ticket(dm, &ticket);
1234 return write_ticket(stream, &ticket, scope);
1237 HRESULT WINAPI PTMergeAndValidatePrintTicket(HPTPROVIDER provider, IStream *base, IStream *delta,
1238 EPrintTicketScope scope, IStream *result, BSTR *error)
1240 struct prn_provider *prov = (struct prn_provider *)provider;
1241 struct ticket ticket;
1242 HRESULT hr;
1244 TRACE("%p,%p,%p,%d,%p,%p\n", provider, base, delta, scope, result, error);
1246 if (!is_valid_provider(provider) || !base || !result)
1247 return E_INVALIDARG;
1249 hr = initialize_ticket(prov, &ticket);
1250 if (hr != S_OK) return hr;
1252 hr = parse_ticket(base, scope, &ticket);
1253 if (hr != S_OK) return hr;
1255 if (delta)
1257 hr = parse_ticket(delta, scope, &ticket);
1258 if (hr != S_OK) return hr;
1261 hr = write_ticket(result, &ticket, scope);
1262 return hr ? hr : S_PT_NO_CONFLICT;
1265 static HRESULT write_PageMediaSize_caps(const WCHAR *device, IXMLDOMElement *root)
1267 HRESULT hr = S_OK;
1268 int count, i;
1269 POINT *pt;
1270 IXMLDOMElement *feature = NULL;
1272 FIXME("stub\n");
1274 count = DeviceCapabilitiesW(device, NULL, DC_PAPERSIZE, NULL, NULL);
1275 if (count <= 0)
1276 return HRESULT_FROM_WIN32(GetLastError());
1278 pt = calloc(count, sizeof(*pt));
1279 if (!pt) return E_OUTOFMEMORY;
1281 count = DeviceCapabilitiesW(device, NULL, DC_PAPERSIZE, (LPWSTR)pt, NULL);
1282 if (count <= 0)
1284 hr = HRESULT_FROM_WIN32(GetLastError());
1285 goto fail;
1288 hr = create_Feature(root, L"psk:PageMediaSize", &feature);
1289 if (hr != S_OK) goto fail;
1291 for (i = 0; i < count; i++)
1295 fail:
1296 if (feature) IXMLDOMElement_Release(feature);
1297 free(pt);
1298 return hr;
1301 static HRESULT write_PageOutputColor_caps(const WCHAR *device, IXMLDOMElement *root)
1303 HRESULT hr = S_OK;
1304 int color;
1305 IXMLDOMElement *feature = NULL;
1307 FIXME("stub\n");
1309 color = DeviceCapabilitiesW(device, NULL, DC_COLORDEVICE, NULL, NULL);
1310 TRACE("DC_COLORDEVICE: %d\n", color);
1312 hr = create_Feature(root, L"psk:PageOutputColor", &feature);
1313 if (hr != S_OK) goto fail;
1315 fail:
1316 if (feature) IXMLDOMElement_Release(feature);
1317 return hr;
1320 static HRESULT write_PageScaling_caps(const WCHAR *device, IXMLDOMElement *root)
1322 HRESULT hr = S_OK;
1323 IXMLDOMElement *feature = NULL;
1325 FIXME("stub\n");
1327 hr = create_Feature(root, L"psk:PageScaling", &feature);
1328 if (hr != S_OK) goto fail;
1330 fail:
1331 if (feature) IXMLDOMElement_Release(feature);
1332 return hr;
1335 static HRESULT write_PageResolution_caps(const WCHAR *device, IXMLDOMElement *root)
1337 HRESULT hr = S_OK;
1338 int count, i;
1339 struct
1341 LONG x;
1342 LONG y;
1343 } *res;
1344 IXMLDOMElement *feature = NULL;
1346 FIXME("stub\n");
1348 count = DeviceCapabilitiesW(device, NULL, DC_ENUMRESOLUTIONS, NULL, NULL);
1349 if (count <= 0)
1350 return HRESULT_FROM_WIN32(GetLastError());
1352 res = calloc(count, sizeof(*res));
1353 if (!res) return E_OUTOFMEMORY;
1355 count = DeviceCapabilitiesW(device, NULL, DC_ENUMRESOLUTIONS, (LPWSTR)res, NULL);
1356 if (count <= 0)
1358 hr = HRESULT_FROM_WIN32(GetLastError());
1359 goto fail;
1362 hr = create_Feature(root, L"psk:PageResolution", &feature);
1363 if (hr != S_OK) goto fail;
1365 for (i = 0; i < count; i++)
1369 fail:
1370 if (feature) IXMLDOMElement_Release(feature);
1371 free(res);
1372 return hr;
1375 static HRESULT write_PageOrientation_caps(const WCHAR *device, IXMLDOMElement *root)
1377 HRESULT hr = S_OK;
1378 int landscape;
1379 IXMLDOMElement *feature = NULL;
1381 FIXME("stub\n");
1383 landscape = DeviceCapabilitiesW(device, NULL, DC_ORIENTATION, NULL, NULL);
1384 TRACE("DC_ORIENTATION: %d\n", landscape);
1386 hr = create_Feature(root, L"psk:PageOrientation", &feature);
1387 if (hr != S_OK) goto fail;
1389 fail:
1390 if (feature) IXMLDOMElement_Release(feature);
1391 return hr;
1394 static HRESULT write_DocumentCollate_caps(const WCHAR *device, IXMLDOMElement *root)
1396 HRESULT hr = S_OK;
1397 int collate;
1398 IXMLDOMElement *feature = NULL;
1400 FIXME("stub\n");
1402 collate = DeviceCapabilitiesW(device, NULL, DC_COLLATE, NULL, NULL);
1403 TRACE("DC_COLLATE: %d\n", collate);
1405 hr = create_Feature(root, L"psk:DocumentCollate", &feature);
1406 if (hr != S_OK) goto fail;
1408 fail:
1409 if (feature) IXMLDOMElement_Release(feature);
1410 return hr;
1413 static HRESULT write_JobInputBin_caps(const WCHAR *device, IXMLDOMElement *root)
1415 HRESULT hr = S_OK;
1416 int count, i;
1417 WORD *bin;
1418 IXMLDOMElement *feature = NULL;
1420 FIXME("stub\n");
1422 count = DeviceCapabilitiesW(device, NULL, DC_BINS, NULL, NULL);
1423 if (count <= 0)
1424 return HRESULT_FROM_WIN32(GetLastError());
1426 bin = calloc(count, sizeof(*bin));
1427 if (!bin) return E_OUTOFMEMORY;
1429 count = DeviceCapabilitiesW(device, NULL, DC_BINS, (LPWSTR)bin, NULL);
1430 if (count <= 0)
1432 hr = HRESULT_FROM_WIN32(GetLastError());
1433 goto fail;
1436 hr = create_Feature(root, L"psk:JobInputBin", &feature);
1437 if (hr != S_OK) goto fail;
1439 for (i = 0; i < count; i++)
1443 fail:
1444 if (feature) IXMLDOMElement_Release(feature);
1445 free(bin);
1446 return hr;
1449 static HRESULT write_JobCopies_caps(const WCHAR *device, IXMLDOMElement *root)
1451 HRESULT hr = S_OK;
1452 int copies;
1453 IXMLDOMElement *feature = NULL;
1455 FIXME("stub\n");
1457 copies = DeviceCapabilitiesW(device, NULL, DC_COPIES, NULL, NULL);
1458 TRACE("DC_COPIES: %d\n", copies);
1460 hr = create_ParameterDef(root, L"psk:JobCopiesAllDocuments", &feature);
1461 if (hr != S_OK) goto fail;
1463 fail:
1464 if (feature) IXMLDOMElement_Release(feature);
1465 return hr;
1468 static HRESULT write_print_capabilities(const WCHAR *device, IStream *stream)
1470 static const char xmldecl[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
1471 HRESULT hr;
1472 IXMLDOMDocument *doc;
1473 IXMLDOMElement *root = NULL;
1474 VARIANT var;
1476 hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
1477 &IID_IXMLDOMDocument, (void **)&doc);
1478 if (hr != S_OK) return hr;
1480 hr = IXMLDOMDocument_createElement(doc, (BSTR)L"psf:PrintCapabilities", &root);
1481 if (hr != S_OK) goto fail;
1483 hr = IXMLDOMDocument_appendChild(doc, (IXMLDOMNode *)root, NULL);
1484 if (hr != S_OK) goto fail;
1486 hr = write_attributes(root);
1487 if (hr != S_OK) goto fail;
1489 hr = write_PageMediaSize_caps(device, root);
1490 if (hr != S_OK) goto fail;
1491 hr = write_PageOutputColor_caps(device, root);
1492 if (hr != S_OK) goto fail;
1493 hr = write_PageScaling_caps(device, root);
1494 if (hr != S_OK) goto fail;
1495 hr = write_PageResolution_caps(device, root);
1496 if (hr != S_OK) goto fail;
1497 hr = write_PageOrientation_caps(device, root);
1498 if (hr != S_OK) goto fail;
1499 hr = write_DocumentCollate_caps(device, root);
1500 if (hr != S_OK) goto fail;
1501 hr = write_JobInputBin_caps(device, root);
1502 if (hr != S_OK) goto fail;
1503 hr = write_JobCopies_caps(device, root);
1504 if (hr != S_OK) goto fail;
1506 hr = IStream_Write(stream, xmldecl, strlen(xmldecl), NULL);
1507 if (hr != S_OK) goto fail;
1509 V_VT(&var) = VT_UNKNOWN;
1510 V_UNKNOWN(&var) = (IUnknown *)stream;
1511 hr = IXMLDOMDocument_save(doc, var);
1513 fail:
1514 if (root) IXMLDOMElement_Release(root);
1515 IXMLDOMDocument_Release(doc);
1516 return hr;
1519 HRESULT WINAPI PTGetPrintCapabilities(HPTPROVIDER provider, IStream *stream, IStream *caps, BSTR *error)
1521 struct prn_provider *prov = (struct prn_provider *)provider;
1522 struct ticket ticket;
1523 HRESULT hr;
1525 TRACE("%p,%p,%p,%p\n", provider, stream, caps, error);
1527 if (!is_valid_provider(provider) || !stream || !caps)
1528 return E_INVALIDARG;
1530 hr = parse_ticket(stream, kPTJobScope, &ticket);
1531 if (hr != S_OK) return hr;
1533 return write_print_capabilities(prov->name, caps);