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
30 #include "wine/debug.h"
32 #include "prntvpt_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(prntvpt
);
57 struct resolution resolution
;
78 struct document document
;
88 { L
"psk:ISOA4", DMPAPER_A4
},
91 static int media_to_paper(const WCHAR
*name
)
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
));
103 static const WCHAR
*paper_to_media(int paper
)
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" };
120 for (i
= 0 ; i
< ARRAY_SIZE(psf_names
); i
++)
121 if (!wcscmp(name
, psf_names
[i
])) return TRUE
;
126 static HRESULT
verify_ticket(IXMLDOMDocument2
*doc
)
128 IXMLDOMElement
*element
;
129 IXMLDOMNode
*node
= NULL
;
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)
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
;
150 IXMLDOMNode
*next_node
;
152 hr
= IXMLDOMNode_get_nodeName(node
, &str
);
153 if (hr
!= S_OK
) break;
154 if (!is_valid_node_name(str
))
157 if (hr
!= S_OK
) break;
159 hr
= IXMLDOMNode_QueryInterface(node
, &IID_IXMLDOMElement
, (void **)&element
);
160 if (hr
!= S_OK
) break;
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
)
169 if (hr
!= S_OK
) break;
171 hr
= IXMLDOMNode_get_nextSibling(node
, &next_node
);
178 IXMLDOMNode_Release(node
);
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
)
194 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Value[@xsi:type='xsd:integer']", &val
);
195 if (hr
!= S_OK
) return hr
;
198 hr
= IXMLDOMNode_get_nodeTypedValue(val
, &var1
);
202 hr
= VariantChangeTypeEx(&var2
, &var1
, 0, 0, VT_I4
);
204 *value
= V_I4(&var2
);
209 IXMLDOMNode_Release(val
);
213 static void read_PageMediaSize(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
215 IXMLDOMNode
*node
, *option
, *child
;
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
);
224 IXMLDOMElement
*element
;
226 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
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
);
240 IXMLDOMElement_Release(element
);
243 hr
= IXMLDOMNode_selectSingleNode(option
, (BSTR
)L
"./psf:ScoredProperty[@name='psk:MediaSizeWidth']", &child
);
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
);
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
;
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
);
276 IXMLDOMElement
*element
;
278 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
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
;
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
);
300 IXMLDOMElement_Release(element
);
304 IXMLDOMNode_Release(node
);
307 static void read_PageScaling(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
309 IXMLDOMNode
*node
, *option
;
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
);
319 IXMLDOMElement
*element
;
321 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
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"))
332 else if (!wcscmp(V_BSTR(&var
), L
"psk:CustomSquare"))
333 scaling
= 0; /* psk:PageScalingScale */
335 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var
)));
339 IXMLDOMElement_Release(element
);
343 IXMLDOMNode_Release(node
);
347 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:ParameterInit[@name='psk:PageScalingScale']", &node
);
350 read_int_value(node
, &scaling
);
351 IXMLDOMNode_Release(node
);
356 ticket
->page
.scaling
= scaling
;
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
;
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
);
374 hr
= IXMLDOMNode_selectSingleNode(option
, (BSTR
)L
"./psf:ScoredProperty[@name='psk:ResolutionX']", &child
);
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
);
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
;
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
);
407 IXMLDOMElement
*element
;
409 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
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
;
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
);
431 IXMLDOMElement_Release(element
);
435 IXMLDOMNode_Release(node
);
438 static void read_DocumentCollate(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
440 IXMLDOMNode
*node
, *option
;
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
);
449 IXMLDOMElement
*element
;
451 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
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
;
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
);
473 IXMLDOMElement_Release(element
);
477 IXMLDOMNode_Release(node
);
480 static void read_JobInputBin(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
482 IXMLDOMNode
*node
, *option
;
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
);
491 IXMLDOMElement
*element
;
493 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
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
;
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
);
513 IXMLDOMElement_Release(element
);
517 IXMLDOMNode_Release(node
);
520 static void read_JobCopies(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
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
)
537 IXMLDOMElement
*element
= NULL
;
538 IXMLDOMNamedNodeMap
*map
= NULL
;
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
++)
561 hr
= IXMLDOMNamedNodeMap_get_item(map
, i
, &node
);
564 hr
= IXMLDOMNode_get_nodeName(node
, &str
);
568 hr
= IXMLDOMNode_get_nodeValue(node
, &var
);
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
);
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
));
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
;
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
);
643 IXMLDOMDocument2_Release(doc
);
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
;
704 GetPrinterW(prov
->hprn
, 2, NULL
, 0, &size
);
705 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
706 return HRESULT_FROM_WIN32(GetLastError());
709 if (!pi2
) return E_OUTOFMEMORY
;
711 if (!GetPrinterW(prov
->hprn
, 2, (LPBYTE
)pi2
, size
, NULL
))
712 hr
= HRESULT_FROM_WIN32(GetLastError());
714 devmode_to_ticket(pi2
->pDevMode
, ticket
);
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
;
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
)
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
);
747 static HRESULT
add_attribute(IXMLDOMElement
*element
, const WCHAR
*attr
, const WCHAR
*value
)
753 name
= SysAllocString(attr
);
754 V_VT(&var
) = VT_BSTR
;
755 V_BSTR(&var
) = SysAllocString(value
);
757 hr
= IXMLDOMElement_setAttribute(element
, name
, var
);
760 SysFreeString(V_BSTR(&var
));
765 static HRESULT
create_element(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
767 IXMLDOMDocument
*doc
;
770 hr
= IXMLDOMElement_get_ownerDocument(root
, &doc
);
771 if (hr
!= S_OK
) return hr
;
773 hr
= IXMLDOMDocument_createElement(doc
, (BSTR
)name
, child
);
775 hr
= IXMLDOMElement_appendChild(root
, (IXMLDOMNode
*)*child
, NULL
);
777 IXMLDOMDocument_Release(doc
);
781 static HRESULT
write_int_value(IXMLDOMElement
*root
, int value
)
784 IXMLDOMElement
*child
;
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
;
795 hr
= IXMLDOMElement_put_nodeTypedValue(child
, var
);
797 IXMLDOMElement_Release(child
);
801 static HRESULT
create_Feature(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
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
)
815 hr
= create_element(root
, L
"psf:Option", child
);
816 if (hr
!= S_OK
) return hr
;
819 hr
= add_attribute(*child
, L
"name", name
);
824 static HRESULT
create_ParameterInit(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
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
)
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
)
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
)
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
;
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
);
887 if (option
) IXMLDOMElement_Release(option
);
888 IXMLDOMElement_Release(feature
);
892 static HRESULT
write_PageOutputColor(IXMLDOMElement
*root
, const struct ticket
*ticket
)
894 IXMLDOMElement
*feature
, *option
= NULL
;
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
);
910 static HRESULT
write_PageScaling(IXMLDOMElement
*root
, const struct ticket
*ticket
)
912 IXMLDOMElement
*feature
, *option
= NULL
;
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
);
925 hr
= create_Option(feature
, L
"psk:CustomSquare", &option
);
928 IXMLDOMElement
*property
, *parameter
;
930 hr
= create_ScoredProperty(option
, L
"psk:Scale", &property
);
933 hr
= create_ParameterRef(property
, L
"psk:PageScalingScale", ¶meter
);
936 IXMLDOMElement_Release(parameter
);
938 hr
= create_ParameterInit(root
, L
"psk:PageScalingScale", ¶meter
);
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
);
957 static HRESULT
write_PageResolution(IXMLDOMElement
*root
, const struct ticket
*ticket
)
959 IXMLDOMElement
*feature
, *option
= NULL
, *property
;
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
);
980 if (option
) IXMLDOMElement_Release(option
);
981 IXMLDOMElement_Release(feature
);
985 static HRESULT
write_PageOrientation(IXMLDOMElement
*root
, const struct ticket
*ticket
)
987 IXMLDOMElement
*feature
, *option
= NULL
;
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
);
1003 static HRESULT
write_DocumentCollate(IXMLDOMElement
*root
, const struct ticket
*ticket
)
1005 IXMLDOMElement
*feature
, *option
= NULL
;
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
);
1021 static HRESULT
write_JobInputBin(IXMLDOMElement
*root
, const struct ticket
*ticket
)
1023 IXMLDOMElement
*feature
, *option
= NULL
;
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
);
1039 static HRESULT
write_JobCopies(IXMLDOMElement
*root
, const struct ticket
*ticket
)
1041 IXMLDOMElement
*parameter
;
1044 hr
= create_ParameterInit(root
, L
"psk:JobCopiesAllDocuments", ¶meter
);
1045 if (hr
!= S_OK
) return hr
;
1047 hr
= write_int_value(parameter
, ticket
->job
.copies
);
1049 IXMLDOMElement_Release(parameter
);
1053 static HRESULT
write_attributes(IXMLDOMElement
*element
)
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";
1073 IXMLDOMDocument
*doc
;
1074 IXMLDOMElement
*root
= NULL
;
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
);
1123 if (root
) IXMLDOMElement_Release(root
);
1124 IXMLDOMDocument_Release(doc
);
1128 static void dump_fields(DWORD fields
)
1132 #define CHECK_FIELD(flag) \
1135 if (fields & flag) \
1137 if (add_space++) TRACE(" "); \
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
);
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
;
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
;
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
;
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
;
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
)
1270 IXMLDOMElement
*feature
= NULL
;
1274 count
= DeviceCapabilitiesW(device
, NULL
, DC_PAPERSIZE
, NULL
, NULL
);
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
);
1284 hr
= HRESULT_FROM_WIN32(GetLastError());
1288 hr
= create_Feature(root
, L
"psk:PageMediaSize", &feature
);
1289 if (hr
!= S_OK
) goto fail
;
1291 for (i
= 0; i
< count
; i
++)
1296 if (feature
) IXMLDOMElement_Release(feature
);
1301 static HRESULT
write_PageOutputColor_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1305 IXMLDOMElement
*feature
= NULL
;
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
;
1316 if (feature
) IXMLDOMElement_Release(feature
);
1320 static HRESULT
write_PageScaling_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1323 IXMLDOMElement
*feature
= NULL
;
1327 hr
= create_Feature(root
, L
"psk:PageScaling", &feature
);
1328 if (hr
!= S_OK
) goto fail
;
1331 if (feature
) IXMLDOMElement_Release(feature
);
1335 static HRESULT
write_PageResolution_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1344 IXMLDOMElement
*feature
= NULL
;
1348 count
= DeviceCapabilitiesW(device
, NULL
, DC_ENUMRESOLUTIONS
, NULL
, NULL
);
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
);
1358 hr
= HRESULT_FROM_WIN32(GetLastError());
1362 hr
= create_Feature(root
, L
"psk:PageResolution", &feature
);
1363 if (hr
!= S_OK
) goto fail
;
1365 for (i
= 0; i
< count
; i
++)
1370 if (feature
) IXMLDOMElement_Release(feature
);
1375 static HRESULT
write_PageOrientation_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1379 IXMLDOMElement
*feature
= NULL
;
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
;
1390 if (feature
) IXMLDOMElement_Release(feature
);
1394 static HRESULT
write_DocumentCollate_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1398 IXMLDOMElement
*feature
= NULL
;
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
;
1409 if (feature
) IXMLDOMElement_Release(feature
);
1413 static HRESULT
write_JobInputBin_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1418 IXMLDOMElement
*feature
= NULL
;
1422 count
= DeviceCapabilitiesW(device
, NULL
, DC_BINS
, NULL
, NULL
);
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
);
1432 hr
= HRESULT_FROM_WIN32(GetLastError());
1436 hr
= create_Feature(root
, L
"psk:JobInputBin", &feature
);
1437 if (hr
!= S_OK
) goto fail
;
1439 for (i
= 0; i
< count
; i
++)
1444 if (feature
) IXMLDOMElement_Release(feature
);
1449 static HRESULT
write_JobCopies_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1453 IXMLDOMElement
*feature
= NULL
;
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
;
1464 if (feature
) IXMLDOMElement_Release(feature
);
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";
1472 IXMLDOMDocument
*doc
;
1473 IXMLDOMElement
*root
= NULL
;
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
);
1514 if (root
) IXMLDOMElement_Release(root
);
1515 IXMLDOMDocument_Release(doc
);
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
;
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
);