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
22 #define NONAMELESSSTRUCT
23 #define NONAMELESSUNION
33 #include "wine/debug.h"
35 #include "prntvpt_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(prntvpt
);
60 struct resolution resolution
;
81 struct document document
;
91 { L
"psk:ISOA4", DMPAPER_A4
},
94 static int media_to_paper(const WCHAR
*name
)
98 for (i
= 0 ; i
< ARRAY_SIZE(psk_media
); i
++)
99 if (!wcscmp(name
, psk_media
[i
].name
))
100 return psk_media
[i
].paper
;
102 FIXME("%s\n", wine_dbgstr_w(name
));
106 static const WCHAR
*paper_to_media(int paper
)
110 for (i
= 0 ; i
< ARRAY_SIZE(psk_media
); i
++)
111 if (psk_media
[i
].paper
== paper
)
112 return psk_media
[i
].name
;
114 FIXME("%d\n", paper
);
115 return psk_media
[0].name
;
118 static BOOL
is_valid_node_name(const WCHAR
*name
)
120 static const WCHAR
* const psf_names
[] = { L
"psf:ParameterInit", L
"psf:Feature" };
123 for (i
= 0 ; i
< ARRAY_SIZE(psf_names
); i
++)
124 if (!wcscmp(name
, psf_names
[i
])) return TRUE
;
129 static HRESULT
verify_ticket(IXMLDOMDocument2
*doc
)
131 IXMLDOMElement
*element
;
132 IXMLDOMNode
*node
= NULL
;
136 hr
= IXMLDOMDocument2_get_documentElement(doc
, &element
);
137 if (hr
!= S_OK
) return E_PRINTTICKET_FORMAT
;
139 hr
= IXMLDOMElement_get_tagName(element
, &str
);
140 if (hr
!= S_OK
) goto fail
;
141 if (wcscmp(str
, L
"psf:PrintTicket") != 0)
144 if (hr
!= S_OK
) goto fail
;
146 hr
= IXMLDOMElement_get_firstChild(element
, &node
);
147 IXMLDOMElement_Release(element
);
148 if (hr
!= S_OK
) return S_OK
;
153 IXMLDOMNode
*next_node
;
155 hr
= IXMLDOMNode_get_nodeName(node
, &str
);
156 if (hr
!= S_OK
) break;
157 if (!is_valid_node_name(str
))
160 if (hr
!= S_OK
) break;
162 hr
= IXMLDOMNode_QueryInterface(node
, &IID_IXMLDOMElement
, (void **)&element
);
163 if (hr
!= S_OK
) break;
166 hr
= IXMLDOMElement_getAttribute(element
, (BSTR
)L
"name", &var
);
167 IXMLDOMElement_Release(element
);
168 if (hr
!= S_OK
) break;
169 if (V_VT(&var
) != VT_BSTR
)
172 if (hr
!= S_OK
) break;
174 hr
= IXMLDOMNode_get_nextSibling(node
, &next_node
);
181 IXMLDOMNode_Release(node
);
186 if (node
) IXMLDOMNode_Release(node
);
188 return hr
!= S_OK
? E_PRINTTICKET_FORMAT
: S_OK
;
191 static HRESULT
read_int_value(IXMLDOMNode
*node
, int *value
)
197 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Value[@xsi:type='xsd:integer']", &val
);
198 if (hr
!= S_OK
) return hr
;
201 hr
= IXMLDOMNode_get_nodeTypedValue(val
, &var1
);
205 hr
= VariantChangeTypeEx(&var2
, &var1
, 0, 0, VT_I4
);
207 *value
= V_I4(&var2
);
212 IXMLDOMNode_Release(val
);
216 static void read_PageMediaSize(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
218 IXMLDOMNode
*node
, *option
, *child
;
221 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:Feature[@name='psk:PageMediaSize']", &node
);
222 if (hr
!= S_OK
) return;
224 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Option", &option
);
227 IXMLDOMElement
*element
;
229 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
235 hr
= IXMLDOMElement_getAttribute(element
, (BSTR
)L
"name", &var
);
236 if (hr
== S_OK
&& V_VT(&var
) == VT_BSTR
)
238 ticket
->page
.media
.paper
= media_to_paper(V_BSTR(&var
));
239 TRACE("paper: %s => %d\n", wine_dbgstr_w(V_BSTR(&var
)), ticket
->page
.media
.paper
);
243 IXMLDOMElement_Release(element
);
246 hr
= IXMLDOMNode_selectSingleNode(option
, (BSTR
)L
"./psf:ScoredProperty[@name='psk:MediaSizeWidth']", &child
);
249 if (read_int_value(child
, &ticket
->page
.media
.size
.width
) == S_OK
)
250 TRACE("width: %d\n", ticket
->page
.media
.size
.width
);
251 IXMLDOMNode_Release(child
);
254 hr
= IXMLDOMNode_selectSingleNode(option
, (BSTR
)L
"./psf:ScoredProperty[@name='psk:MediaSizeHeight']", &child
);
257 if (read_int_value(child
, &ticket
->page
.media
.size
.height
) == S_OK
)
258 TRACE("height: %d\n", ticket
->page
.media
.size
.height
);
259 IXMLDOMNode_Release(child
);
262 IXMLDOMNode_Release(option
);
265 IXMLDOMNode_Release(node
);
268 static void read_PageOutputColor(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
270 IXMLDOMNode
*node
, *option
;
273 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:Feature[@name='psk:PageOutputColor']", &node
);
274 if (hr
!= S_OK
) return;
276 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Option", &option
);
279 IXMLDOMElement
*element
;
281 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
287 hr
= IXMLDOMElement_getAttribute(element
, (BSTR
)L
"name", &var
);
288 if (hr
== S_OK
&& V_VT(&var
) == VT_BSTR
)
290 if (!wcscmp(V_BSTR(&var
), L
"psk:Color"))
291 ticket
->page
.color
= DMCOLOR_COLOR
;
292 else if (!wcscmp(V_BSTR(&var
), L
"psk:Monochrome"))
293 ticket
->page
.color
= DMCOLOR_MONOCHROME
;
296 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var
)));
297 ticket
->page
.color
= DMCOLOR_MONOCHROME
;
299 TRACE("color: %s => %d\n", wine_dbgstr_w(V_BSTR(&var
)), ticket
->page
.color
);
303 IXMLDOMElement_Release(element
);
307 IXMLDOMNode_Release(node
);
310 static void read_PageScaling(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
312 IXMLDOMNode
*node
, *option
;
316 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:Feature[@name='psk:PageScaling']", &node
);
317 if (hr
!= S_OK
) return;
319 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Option", &option
);
322 IXMLDOMElement
*element
;
324 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
330 hr
= IXMLDOMElement_getAttribute(element
, (BSTR
)L
"name", &var
);
331 if (hr
== S_OK
&& V_VT(&var
) == VT_BSTR
)
333 if (!wcscmp(V_BSTR(&var
), L
"psk:None"))
335 else if (!wcscmp(V_BSTR(&var
), L
"psk:CustomSquare"))
336 scaling
= 0; /* psk:PageScalingScale */
338 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var
)));
342 IXMLDOMElement_Release(element
);
346 IXMLDOMNode_Release(node
);
350 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:ParameterInit[@name='psk:PageScalingScale']", &node
);
353 read_int_value(node
, &scaling
);
354 IXMLDOMNode_Release(node
);
359 ticket
->page
.scaling
= scaling
;
361 ticket
->page
.scaling
= 100;
363 TRACE("page.scaling: %d\n", ticket
->page
.scaling
);
366 static void read_PageResolution(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
368 IXMLDOMNode
*node
, *option
, *child
;
371 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:Feature[@name='psk:PageResolution']", &node
);
372 if (hr
!= S_OK
) return;
374 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Option", &option
);
377 hr
= IXMLDOMNode_selectSingleNode(option
, (BSTR
)L
"./psf:ScoredProperty[@name='psk:ResolutionX']", &child
);
380 if (read_int_value(child
, &ticket
->page
.resolution
.x
) == S_OK
)
381 TRACE("resolution.x: %d\n", ticket
->page
.resolution
.x
);
382 IXMLDOMNode_Release(child
);
385 hr
= IXMLDOMNode_selectSingleNode(option
, (BSTR
)L
"./psf:ScoredProperty[@name='psk:ResolutionY']", &child
);
388 if (read_int_value(child
, &ticket
->page
.resolution
.y
) == S_OK
)
389 TRACE("resolution.y: %d\n", ticket
->page
.resolution
.y
);
390 IXMLDOMNode_Release(child
);
393 IXMLDOMNode_Release(option
);
396 IXMLDOMNode_Release(node
);
399 static void read_PageOrientation(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
401 IXMLDOMNode
*node
, *option
;
404 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:Feature[@name='psk:PageOrientation']", &node
);
405 if (hr
!= S_OK
) return;
407 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Option", &option
);
410 IXMLDOMElement
*element
;
412 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
418 hr
= IXMLDOMElement_getAttribute(element
, (BSTR
)L
"name", &var
);
419 if (hr
== S_OK
&& V_VT(&var
) == VT_BSTR
)
421 if (!wcscmp(V_BSTR(&var
), L
"psk:Portrait"))
422 ticket
->page
.orientation
= DMORIENT_PORTRAIT
;
423 else if (!wcscmp(V_BSTR(&var
), L
"psk:Landscape"))
424 ticket
->page
.orientation
= DMORIENT_LANDSCAPE
;
427 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var
)));
428 ticket
->page
.orientation
= DMORIENT_PORTRAIT
;
430 TRACE("orientation: %s => %d\n", wine_dbgstr_w(V_BSTR(&var
)), ticket
->page
.orientation
);
434 IXMLDOMElement_Release(element
);
438 IXMLDOMNode_Release(node
);
441 static void read_DocumentCollate(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
443 IXMLDOMNode
*node
, *option
;
446 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:Feature[@name='psk:DocumentCollate']", &node
);
447 if (hr
!= S_OK
) return;
449 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Option", &option
);
452 IXMLDOMElement
*element
;
454 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
460 hr
= IXMLDOMElement_getAttribute(element
, (BSTR
)L
"name", &var
);
461 if (hr
== S_OK
&& V_VT(&var
) == VT_BSTR
)
463 if (!wcscmp(V_BSTR(&var
), L
"psk:Collated"))
464 ticket
->document
.collate
= DMCOLLATE_TRUE
;
465 else if (!wcscmp(V_BSTR(&var
), L
"psk:Uncollated"))
466 ticket
->document
.collate
= DMCOLLATE_FALSE
;
469 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var
)));
470 ticket
->document
.collate
= DMCOLLATE_FALSE
;
472 TRACE("document.collate: %s => %d\n", wine_dbgstr_w(V_BSTR(&var
)), ticket
->document
.collate
);
476 IXMLDOMElement_Release(element
);
480 IXMLDOMNode_Release(node
);
483 static void read_JobInputBin(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
485 IXMLDOMNode
*node
, *option
;
488 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:Feature[@name='psk:JobInputBin']", &node
);
489 if (hr
!= S_OK
) return;
491 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Option", &option
);
494 IXMLDOMElement
*element
;
496 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
502 hr
= IXMLDOMElement_getAttribute(element
, (BSTR
)L
"name", &var
);
503 if (hr
== S_OK
&& V_VT(&var
) == VT_BSTR
)
505 if (!wcscmp(V_BSTR(&var
), L
"psk:AutoSelect"))
506 ticket
->job
.input_bin
= DMBIN_AUTO
;
509 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var
)));
510 ticket
->job
.input_bin
= DMBIN_AUTO
;
512 TRACE("input_bin: %s => %d\n", wine_dbgstr_w(V_BSTR(&var
)), ticket
->job
.input_bin
);
516 IXMLDOMElement_Release(element
);
520 IXMLDOMNode_Release(node
);
523 static void read_JobCopies(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
528 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:ParameterInit[@name='psk:JobCopiesAllDocuments']", &node
);
529 if (hr
!= S_OK
) return;
531 if (read_int_value(node
, &ticket
->job
.copies
) == S_OK
)
532 TRACE("job.copies: %d\n", ticket
->job
.copies
);
534 IXMLDOMNode_Release(node
);
537 static void set_SelectionNamespaces(IXMLDOMDocument2
*doc
)
540 IXMLDOMElement
*element
= NULL
;
541 IXMLDOMNamedNodeMap
*map
= NULL
;
548 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stream
);
549 if (hr
!= S_OK
) return;
551 hr
= IXMLDOMDocument2_get_documentElement(doc
, &element
);
552 if (hr
!= S_OK
) goto fail
;
554 hr
= IXMLDOMElement_get_attributes(element
, &map
);
555 if (hr
!= S_OK
) goto fail
;
557 hr
= IXMLDOMNamedNodeMap_get_length(map
, &count
);
558 if (hr
!= S_OK
) goto fail
;
560 for (i
= 0; i
< count
; i
++)
564 hr
= IXMLDOMNamedNodeMap_get_item(map
, i
, &node
);
567 hr
= IXMLDOMNode_get_nodeName(node
, &str
);
571 hr
= IXMLDOMNode_get_nodeValue(node
, &var
);
574 if (!wcscmp(str
, L
"xmlns") || !wcsncmp(str
, L
"xmlns:", 6))
576 TRACE("ns[%ld]: %s=%s\n", i
, wine_dbgstr_w(str
), wine_dbgstr_w(V_BSTR(&var
)));
577 IStream_Write(stream
, str
, wcslen(str
) * sizeof(WCHAR
), NULL
);
578 IStream_Write(stream
, L
"=\"", 2 * sizeof(WCHAR
), NULL
);
579 IStream_Write(stream
, V_BSTR(&var
), wcslen(V_BSTR(&var
)) * sizeof(WCHAR
), NULL
);
580 IStream_Write(stream
, L
"\" ", 2 * sizeof(WCHAR
), NULL
);
586 IXMLDOMNode_Release(node
);
590 IStream_Write(stream
, L
"", sizeof(WCHAR
), NULL
);
592 hr
= GetHGlobalFromStream(stream
, &hmem
);
593 if (hr
!= S_OK
) goto fail
;
595 str
= GlobalLock(hmem
);
596 V_VT(&var
) = VT_BSTR
;
597 V_BSTR(&var
) = SysAllocString(str
);
598 IXMLDOMDocument2_setProperty(doc
, (BSTR
)L
"SelectionNamespaces", var
);
599 SysFreeString(V_BSTR(&var
));
603 if (map
) IXMLDOMNamedNodeMap_Release(map
);
604 if (element
) IXMLDOMElement_Release(element
);
605 IStream_Release(stream
);
608 static HRESULT
parse_ticket(IStream
*stream
, EPrintTicketScope scope
, struct ticket
*ticket
)
610 IXMLDOMDocument2
*doc
;
615 hr
= CoCreateInstance(&CLSID_DOMDocument30
, NULL
, CLSCTX_INPROC_SERVER
,
616 &IID_IXMLDOMDocument2
, (void **)&doc
);
617 if (hr
!= S_OK
) return hr
;
619 V_VT(&src
) = VT_UNKNOWN
;
620 V_UNKNOWN(&src
) = (IUnknown
*)stream
;
621 hr
= IXMLDOMDocument2_load(doc
, src
, &ret
);
622 if (hr
!= S_OK
) goto fail
;
624 hr
= verify_ticket(doc
);
625 if (hr
!= S_OK
) goto fail
;
627 set_SelectionNamespaces(doc
);
629 /* PageScope is always added */
630 read_PageMediaSize(doc
, ticket
);
631 read_PageOutputColor(doc
, ticket
);
632 read_PageScaling(doc
, ticket
);
633 read_PageResolution(doc
, ticket
);
634 read_PageOrientation(doc
, ticket
);
636 if (scope
> kPTPageScope
)
637 read_DocumentCollate(doc
, ticket
);
639 if (scope
> kPTDocumentScope
)
641 read_JobInputBin(doc
, ticket
);
642 read_JobCopies(doc
, ticket
);
646 IXMLDOMDocument2_Release(doc
);
650 static void ticket_to_devmode(const struct ticket
*ticket
, DEVMODEW
*dm
)
652 memset(dm
, 0, sizeof(*dm
));
654 dm
->dmSize
= sizeof(*dm
);
655 dm
->dmFields
= DM_ORIENTATION
| DM_PAPERSIZE
| DM_PAPERLENGTH
| DM_PAPERWIDTH
| DM_SCALE
|
656 DM_COPIES
| DM_COLOR
| DM_PRINTQUALITY
| DM_YRESOLUTION
| DM_COLLATE
;
657 dm
->u1
.s1
.dmOrientation
= ticket
->page
.orientation
;
658 dm
->u1
.s1
.dmPaperSize
= ticket
->page
.media
.paper
;
659 dm
->u1
.s1
.dmPaperWidth
= ticket
->page
.media
.size
.width
/ 100;
660 dm
->u1
.s1
.dmPaperLength
= ticket
->page
.media
.size
.height
/ 100;
661 dm
->u1
.s1
.dmScale
= ticket
->page
.scaling
;
662 dm
->u1
.s1
.dmCopies
= ticket
->job
.copies
;
663 dm
->dmColor
= ticket
->page
.color
;
664 dm
->u1
.s1
.dmPrintQuality
= ticket
->page
.resolution
.x
;
665 dm
->dmYResolution
= ticket
->page
.resolution
.y
;
666 dm
->dmCollate
= ticket
->document
.collate
;
669 static void devmode_to_ticket(const DEVMODEW
*dm
, struct ticket
*ticket
)
671 if (dm
->dmFields
& DM_ORIENTATION
)
672 ticket
->page
.orientation
= dm
->u1
.s1
.dmOrientation
;
673 if (dm
->dmFields
& DM_PAPERSIZE
)
674 ticket
->page
.media
.paper
= dm
->u1
.s1
.dmPaperSize
;
675 if (dm
->dmFields
& DM_PAPERLENGTH
)
676 ticket
->page
.media
.size
.width
= dm
->u1
.s1
.dmPaperWidth
* 100;
677 if (dm
->dmFields
& DM_PAPERWIDTH
)
678 ticket
->page
.media
.size
.height
= dm
->u1
.s1
.dmPaperLength
* 100;
679 if (dm
->dmFields
& DM_SCALE
)
680 ticket
->page
.scaling
= dm
->u1
.s1
.dmScale
;
681 if (dm
->dmFields
& DM_COPIES
)
682 ticket
->job
.copies
= dm
->u1
.s1
.dmCopies
;
683 if (dm
->dmFields
& DM_COLOR
)
684 ticket
->page
.color
= dm
->dmColor
;
685 if (dm
->dmFields
& DM_PRINTQUALITY
)
687 ticket
->page
.resolution
.x
= dm
->u1
.s1
.dmPrintQuality
;
688 ticket
->page
.resolution
.y
= dm
->u1
.s1
.dmPrintQuality
;
690 if (dm
->dmFields
& DM_YRESOLUTION
)
691 ticket
->page
.resolution
.y
= dm
->dmYResolution
;
692 if (dm
->dmFields
& DM_LOGPIXELS
)
694 ticket
->page
.resolution
.x
= dm
->dmLogPixels
;
695 ticket
->page
.resolution
.y
= dm
->dmLogPixels
;
697 if (dm
->dmFields
& DM_COLLATE
)
698 ticket
->document
.collate
= dm
->dmCollate
;
701 static HRESULT
initialize_ticket(struct prn_provider
*prov
, struct ticket
*ticket
)
703 PRINTER_INFO_2W
*pi2
;
707 GetPrinterW(prov
->hprn
, 2, NULL
, 0, &size
);
708 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
709 return HRESULT_FROM_WIN32(GetLastError());
712 if (!pi2
) return E_OUTOFMEMORY
;
714 if (!GetPrinterW(prov
->hprn
, 2, (LPBYTE
)pi2
, size
, NULL
))
715 hr
= HRESULT_FROM_WIN32(GetLastError());
717 devmode_to_ticket(pi2
->pDevMode
, ticket
);
723 HRESULT WINAPI
PTConvertPrintTicketToDevMode(HPTPROVIDER provider
, IStream
*stream
, EDefaultDevmodeType type
,
724 EPrintTicketScope scope
, ULONG
*size
, PDEVMODEW
*dm
, BSTR
*error
)
726 struct prn_provider
*prov
= (struct prn_provider
*)provider
;
728 struct ticket ticket
;
730 TRACE("%p,%p,%d,%d,%p,%p,%p\n", provider
, stream
, type
, scope
, size
, dm
, error
);
732 if (!is_valid_provider(provider
) || !stream
|| !size
|| !dm
)
735 hr
= initialize_ticket(prov
, &ticket
);
736 if (hr
!= S_OK
) return hr
;
738 hr
= parse_ticket(stream
, scope
, &ticket
);
739 if (hr
!= S_OK
) return hr
;
741 *dm
= malloc(sizeof(**dm
));
742 if (!*dm
) return E_OUTOFMEMORY
;
744 ticket_to_devmode(&ticket
, *dm
);
745 *size
= sizeof(**dm
);
750 static HRESULT
add_attribute(IXMLDOMElement
*element
, const WCHAR
*attr
, const WCHAR
*value
)
756 name
= SysAllocString(attr
);
757 V_VT(&var
) = VT_BSTR
;
758 V_BSTR(&var
) = SysAllocString(value
);
760 hr
= IXMLDOMElement_setAttribute(element
, name
, var
);
763 SysFreeString(V_BSTR(&var
));
768 static HRESULT
create_element(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
770 IXMLDOMDocument
*doc
;
773 hr
= IXMLDOMElement_get_ownerDocument(root
, &doc
);
774 if (hr
!= S_OK
) return hr
;
776 hr
= IXMLDOMDocument_createElement(doc
, (BSTR
)name
, child
);
778 hr
= IXMLDOMElement_appendChild(root
, (IXMLDOMNode
*)*child
, NULL
);
780 IXMLDOMDocument_Release(doc
);
784 static HRESULT
write_int_value(IXMLDOMElement
*root
, int value
)
787 IXMLDOMElement
*child
;
790 hr
= create_element(root
, L
"psf:Value", &child
);
791 if (hr
!= S_OK
) return hr
;
793 hr
= add_attribute(child
, L
"xsi:type", L
"xsd:integer");
794 if (hr
!= S_OK
) return hr
;
798 hr
= IXMLDOMElement_put_nodeTypedValue(child
, var
);
800 IXMLDOMElement_Release(child
);
804 static HRESULT
create_Feature(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
808 hr
= create_element(root
, L
"psf:Feature", child
);
809 if (hr
!= S_OK
) return hr
;
811 return add_attribute(*child
, L
"name", name
);
814 static HRESULT
create_Option(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
818 hr
= create_element(root
, L
"psf:Option", child
);
819 if (hr
!= S_OK
) return hr
;
822 hr
= add_attribute(*child
, L
"name", name
);
827 static HRESULT
create_ParameterInit(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
831 hr
= create_element(root
, L
"psf:ParameterInit", child
);
832 if (hr
!= S_OK
) return hr
;
834 return add_attribute(*child
, L
"name", name
);
837 static HRESULT
create_ParameterRef(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
841 hr
= create_element(root
, L
"psf:ParameterRef", child
);
842 if (hr
!= S_OK
) return hr
;
844 return add_attribute(*child
, L
"name", name
);
847 static HRESULT
create_ParameterDef(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
851 hr
= create_element(root
, L
"psf:ParameterDef", child
);
852 if (hr
!= S_OK
) return hr
;
854 return add_attribute(*child
, L
"name", name
);
857 static HRESULT
create_ScoredProperty(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
861 hr
= create_element(root
, L
"psf:ScoredProperty", child
);
862 if (hr
!= S_OK
) return hr
;
864 return add_attribute(*child
, L
"name", name
);
867 static HRESULT
write_PageMediaSize(IXMLDOMElement
*root
, const struct ticket
*ticket
)
869 IXMLDOMElement
*feature
, *option
= NULL
, *property
;
872 hr
= create_Feature(root
, L
"psk:PageMediaSize", &feature
);
873 if (hr
!= S_OK
) return hr
;
875 hr
= create_Option(feature
, paper_to_media(ticket
->page
.media
.paper
), &option
);
876 if (hr
!= S_OK
) goto fail
;
878 hr
= create_ScoredProperty(option
, L
"psk:MediaSizeWidth", &property
);
879 if (hr
!= S_OK
) goto fail
;
880 hr
= write_int_value(property
, ticket
->page
.media
.size
.width
);
881 IXMLDOMElement_Release(property
);
882 if (hr
!= S_OK
) goto fail
;
884 hr
= create_ScoredProperty(option
, L
"psk:MediaSizeHeight", &property
);
885 if (hr
!= S_OK
) goto fail
;
886 hr
= write_int_value(property
, ticket
->page
.media
.size
.height
);
887 IXMLDOMElement_Release(property
);
890 if (option
) IXMLDOMElement_Release(option
);
891 IXMLDOMElement_Release(feature
);
895 static HRESULT
write_PageOutputColor(IXMLDOMElement
*root
, const struct ticket
*ticket
)
897 IXMLDOMElement
*feature
, *option
= NULL
;
900 hr
= create_Feature(root
, L
"psk:PageOutputColor", &feature
);
901 if (hr
!= S_OK
) return hr
;
903 if (ticket
->page
.color
== DMCOLOR_COLOR
)
904 hr
= create_Option(feature
, L
"psk:Color", &option
);
905 else /* DMCOLOR_MONOCHROME */
906 hr
= create_Option(feature
, L
"psk:Monochrome", &option
);
908 if (option
) IXMLDOMElement_Release(option
);
909 IXMLDOMElement_Release(feature
);
913 static HRESULT
write_PageScaling(IXMLDOMElement
*root
, const struct ticket
*ticket
)
915 IXMLDOMElement
*feature
, *option
= NULL
;
918 hr
= create_Feature(root
, L
"psk:PageScaling", &feature
);
919 if (hr
!= S_OK
) return hr
;
921 if (ticket
->page
.scaling
== 100)
923 hr
= create_Option(feature
, L
"psk:None", &option
);
924 if (hr
== S_OK
) IXMLDOMElement_Release(option
);
928 hr
= create_Option(feature
, L
"psk:CustomSquare", &option
);
931 IXMLDOMElement
*property
, *parameter
;
933 hr
= create_ScoredProperty(option
, L
"psk:Scale", &property
);
936 hr
= create_ParameterRef(property
, L
"psk:PageScalingScale", ¶meter
);
939 IXMLDOMElement_Release(parameter
);
941 hr
= create_ParameterInit(root
, L
"psk:PageScalingScale", ¶meter
);
944 hr
= write_int_value(parameter
, ticket
->page
.scaling
);
945 IXMLDOMElement_Release(parameter
);
949 IXMLDOMElement_Release(property
);
952 IXMLDOMElement_Release(option
);
956 IXMLDOMElement_Release(feature
);
960 static HRESULT
write_PageResolution(IXMLDOMElement
*root
, const struct ticket
*ticket
)
962 IXMLDOMElement
*feature
, *option
= NULL
, *property
;
965 hr
= create_Feature(root
, L
"psk:PageResolution", &feature
);
966 if (hr
!= S_OK
) return hr
;
968 hr
= create_Option(feature
, NULL
, &option
);
969 if (hr
!= S_OK
) goto fail
;
971 hr
= create_ScoredProperty(option
, L
"psk:ResolutionX", &property
);
972 if (hr
!= S_OK
) goto fail
;
973 hr
= write_int_value(property
, ticket
->page
.resolution
.x
);
974 IXMLDOMElement_Release(property
);
975 if (hr
!= S_OK
) goto fail
;
977 hr
= create_ScoredProperty(option
, L
"psk:ResolutionY", &property
);
978 if (hr
!= S_OK
) goto fail
;
979 hr
= write_int_value(property
, ticket
->page
.resolution
.y
);
980 IXMLDOMElement_Release(property
);
983 if (option
) IXMLDOMElement_Release(option
);
984 IXMLDOMElement_Release(feature
);
988 static HRESULT
write_PageOrientation(IXMLDOMElement
*root
, const struct ticket
*ticket
)
990 IXMLDOMElement
*feature
, *option
= NULL
;
993 hr
= create_Feature(root
, L
"psk:PageOrientation", &feature
);
994 if (hr
!= S_OK
) return hr
;
996 if (ticket
->page
.orientation
== DMORIENT_PORTRAIT
)
997 hr
= create_Option(feature
, L
"psk:Portrait", &option
);
998 else /* DMORIENT_LANDSCAPE */
999 hr
= create_Option(feature
, L
"psk:Landscape", &option
);
1001 if (option
) IXMLDOMElement_Release(option
);
1002 IXMLDOMElement_Release(feature
);
1006 static HRESULT
write_DocumentCollate(IXMLDOMElement
*root
, const struct ticket
*ticket
)
1008 IXMLDOMElement
*feature
, *option
= NULL
;
1011 hr
= create_Feature(root
, L
"psk:DocumentCollate", &feature
);
1012 if (hr
!= S_OK
) return hr
;
1014 if (ticket
->document
.collate
== DMCOLLATE_TRUE
)
1015 hr
= create_Option(feature
, L
"psk:Collated", &option
);
1016 else /* DMCOLLATE_FALSE */
1017 hr
= create_Option(feature
, L
"psk:Uncollated", &option
);
1019 if (option
) IXMLDOMElement_Release(option
);
1020 IXMLDOMElement_Release(feature
);
1024 static HRESULT
write_JobInputBin(IXMLDOMElement
*root
, const struct ticket
*ticket
)
1026 IXMLDOMElement
*feature
, *option
= NULL
;
1029 hr
= create_Feature(root
, L
"psk:JobInputBin", &feature
);
1030 if (hr
!= S_OK
) return hr
;
1032 if (ticket
->job
.input_bin
!= DMBIN_AUTO
)
1033 FIXME("job.input_bin: %d\n", ticket
->job
.input_bin
);
1035 hr
= create_Option(feature
, L
"psk:AutoSelect", &option
);
1037 if (option
) IXMLDOMElement_Release(option
);
1038 IXMLDOMElement_Release(feature
);
1042 static HRESULT
write_JobCopies(IXMLDOMElement
*root
, const struct ticket
*ticket
)
1044 IXMLDOMElement
*parameter
;
1047 hr
= create_ParameterInit(root
, L
"psk:JobCopiesAllDocuments", ¶meter
);
1048 if (hr
!= S_OK
) return hr
;
1050 hr
= write_int_value(parameter
, ticket
->job
.copies
);
1052 IXMLDOMElement_Release(parameter
);
1056 static HRESULT
write_attributes(IXMLDOMElement
*element
)
1060 hr
= add_attribute(element
, L
"xmlns:psf", L
"http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework");
1061 if (hr
!= S_OK
) return hr
;
1062 hr
= add_attribute(element
, L
"xmlns:psk", L
"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords");
1063 if (hr
!= S_OK
) return hr
;
1064 hr
= add_attribute(element
, L
"xmlns:xsi", L
"http://www.w3.org/2001/XMLSchema-instance");
1065 if (hr
!= S_OK
) return hr
;
1066 hr
= add_attribute(element
, L
"xmlns:xsd", L
"http://www.w3.org/2001/XMLSchema");
1067 if (hr
!= S_OK
) return hr
;
1069 return add_attribute(element
, L
"version", L
"1");
1072 static HRESULT
write_ticket(IStream
*stream
, const struct ticket
*ticket
, EPrintTicketScope scope
)
1074 static const char xmldecl
[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
1076 IXMLDOMDocument
*doc
;
1077 IXMLDOMElement
*root
= NULL
;
1080 hr
= CoCreateInstance(&CLSID_DOMDocument
, NULL
, CLSCTX_INPROC_SERVER
,
1081 &IID_IXMLDOMDocument
, (void **)&doc
);
1082 if (hr
!= S_OK
) return hr
;
1084 hr
= IXMLDOMDocument_createElement(doc
, (BSTR
)L
"psf:PrintTicket", &root
);
1085 if (hr
!= S_OK
) goto fail
;
1087 hr
= IXMLDOMDocument_appendChild(doc
, (IXMLDOMNode
*)root
, NULL
);
1088 if (hr
!= S_OK
) goto fail
;
1090 hr
= write_attributes(root
);
1091 if (hr
!= S_OK
) goto fail
;
1093 hr
= write_PageMediaSize(root
, ticket
);
1094 if (hr
!= S_OK
) goto fail
;
1095 hr
= write_PageOutputColor(root
, ticket
);
1096 if (hr
!= S_OK
) goto fail
;
1097 hr
= write_PageScaling(root
, ticket
);
1098 if (hr
!= S_OK
) goto fail
;
1099 hr
= write_PageResolution(root
, ticket
);
1100 if (hr
!= S_OK
) goto fail
;
1101 hr
= write_PageOrientation(root
, ticket
);
1102 if (hr
!= S_OK
) goto fail
;
1104 if (scope
>= kPTDocumentScope
)
1106 hr
= write_DocumentCollate(root
, ticket
);
1107 if (hr
!= S_OK
) goto fail
;
1110 if (scope
>= kPTJobScope
)
1112 hr
= write_JobInputBin(root
, ticket
);
1113 if (hr
!= S_OK
) goto fail
;
1114 hr
= write_JobCopies(root
, ticket
);
1115 if (hr
!= S_OK
) goto fail
;
1118 hr
= IStream_Write(stream
, xmldecl
, strlen(xmldecl
), NULL
);
1119 if (hr
!= S_OK
) goto fail
;
1121 V_VT(&var
) = VT_UNKNOWN
;
1122 V_UNKNOWN(&var
) = (IUnknown
*)stream
;
1123 hr
= IXMLDOMDocument_save(doc
, var
);
1126 if (root
) IXMLDOMElement_Release(root
);
1127 IXMLDOMDocument_Release(doc
);
1131 static void dump_fields(DWORD fields
)
1135 #define CHECK_FIELD(flag) \
1138 if (fields & flag) \
1140 if (add_space++) TRACE(" "); \
1147 CHECK_FIELD(DM_ORIENTATION
);
1148 CHECK_FIELD(DM_PAPERSIZE
);
1149 CHECK_FIELD(DM_PAPERLENGTH
);
1150 CHECK_FIELD(DM_PAPERWIDTH
);
1151 CHECK_FIELD(DM_SCALE
);
1152 CHECK_FIELD(DM_POSITION
);
1153 CHECK_FIELD(DM_NUP
);
1154 CHECK_FIELD(DM_DISPLAYORIENTATION
);
1155 CHECK_FIELD(DM_COPIES
);
1156 CHECK_FIELD(DM_DEFAULTSOURCE
);
1157 CHECK_FIELD(DM_PRINTQUALITY
);
1158 CHECK_FIELD(DM_COLOR
);
1159 CHECK_FIELD(DM_DUPLEX
);
1160 CHECK_FIELD(DM_YRESOLUTION
);
1161 CHECK_FIELD(DM_TTOPTION
);
1162 CHECK_FIELD(DM_COLLATE
);
1163 CHECK_FIELD(DM_FORMNAME
);
1164 CHECK_FIELD(DM_LOGPIXELS
);
1165 CHECK_FIELD(DM_BITSPERPEL
);
1166 CHECK_FIELD(DM_PELSWIDTH
);
1167 CHECK_FIELD(DM_PELSHEIGHT
);
1168 CHECK_FIELD(DM_DISPLAYFLAGS
);
1169 CHECK_FIELD(DM_DISPLAYFREQUENCY
);
1170 CHECK_FIELD(DM_ICMMETHOD
);
1171 CHECK_FIELD(DM_ICMINTENT
);
1172 CHECK_FIELD(DM_MEDIATYPE
);
1173 CHECK_FIELD(DM_DITHERTYPE
);
1174 CHECK_FIELD(DM_PANNINGWIDTH
);
1175 CHECK_FIELD(DM_PANNINGHEIGHT
);
1176 if (fields
) TRACE(" %#lx", fields
);
1181 /* Dump DEVMODE structure without a device specific part.
1182 * Some applications and drivers fail to specify correct field
1183 * flags (like DM_FORMNAME), so dump everything.
1185 static void dump_devmode(const DEVMODEW
*dm
)
1187 if (!TRACE_ON(prntvpt
)) return;
1189 TRACE("dmDeviceName: %s\n", debugstr_w(dm
->dmDeviceName
));
1190 TRACE("dmSpecVersion: 0x%04x\n", dm
->dmSpecVersion
);
1191 TRACE("dmDriverVersion: 0x%04x\n", dm
->dmDriverVersion
);
1192 TRACE("dmSize: 0x%04x\n", dm
->dmSize
);
1193 TRACE("dmDriverExtra: 0x%04x\n", dm
->dmDriverExtra
);
1194 TRACE("dmFields: 0x%04lx\n", dm
->dmFields
);
1195 dump_fields(dm
->dmFields
);
1196 TRACE("dmOrientation: %d\n", dm
->u1
.s1
.dmOrientation
);
1197 TRACE("dmPaperSize: %d\n", dm
->u1
.s1
.dmPaperSize
);
1198 TRACE("dmPaperLength: %d\n", dm
->u1
.s1
.dmPaperLength
);
1199 TRACE("dmPaperWidth: %d\n", dm
->u1
.s1
.dmPaperWidth
);
1200 TRACE("dmScale: %d\n", dm
->u1
.s1
.dmScale
);
1201 TRACE("dmCopies: %d\n", dm
->u1
.s1
.dmCopies
);
1202 TRACE("dmDefaultSource: %d\n", dm
->u1
.s1
.dmDefaultSource
);
1203 TRACE("dmPrintQuality: %d\n", dm
->u1
.s1
.dmPrintQuality
);
1204 TRACE("dmColor: %d\n", dm
->dmColor
);
1205 TRACE("dmDuplex: %d\n", dm
->dmDuplex
);
1206 TRACE("dmYResolution: %d\n", dm
->dmYResolution
);
1207 TRACE("dmTTOption: %d\n", dm
->dmTTOption
);
1208 TRACE("dmCollate: %d\n", dm
->dmCollate
);
1209 TRACE("dmFormName: %s\n", debugstr_w(dm
->dmFormName
));
1210 TRACE("dmLogPixels %u\n", dm
->dmLogPixels
);
1211 TRACE("dmBitsPerPel %lu\n", dm
->dmBitsPerPel
);
1212 TRACE("dmPelsWidth %lu\n", dm
->dmPelsWidth
);
1213 TRACE("dmPelsHeight %lu\n", dm
->dmPelsHeight
);
1216 HRESULT WINAPI
PTConvertDevModeToPrintTicket(HPTPROVIDER provider
, ULONG size
, PDEVMODEW dm
,
1217 EPrintTicketScope scope
, IStream
*stream
)
1219 struct prn_provider
*prov
= (struct prn_provider
*)provider
;
1220 struct ticket ticket
;
1223 TRACE("%p,%lu,%p,%d,%p\n", provider
, size
, dm
, scope
, stream
);
1225 if (!is_valid_provider(provider
) || !dm
|| !stream
)
1226 return E_INVALIDARG
;
1230 if (!IsValidDevmodeW(dm
, size
))
1231 return E_INVALIDARG
;
1233 hr
= initialize_ticket(prov
, &ticket
);
1234 if (hr
!= S_OK
) return hr
;
1235 devmode_to_ticket(dm
, &ticket
);
1237 return write_ticket(stream
, &ticket
, scope
);
1240 HRESULT WINAPI
PTMergeAndValidatePrintTicket(HPTPROVIDER provider
, IStream
*base
, IStream
*delta
,
1241 EPrintTicketScope scope
, IStream
*result
, BSTR
*error
)
1243 struct prn_provider
*prov
= (struct prn_provider
*)provider
;
1244 struct ticket ticket
;
1247 TRACE("%p,%p,%p,%d,%p,%p\n", provider
, base
, delta
, scope
, result
, error
);
1249 if (!is_valid_provider(provider
) || !base
|| !result
)
1250 return E_INVALIDARG
;
1252 hr
= initialize_ticket(prov
, &ticket
);
1253 if (hr
!= S_OK
) return hr
;
1255 hr
= parse_ticket(base
, scope
, &ticket
);
1256 if (hr
!= S_OK
) return hr
;
1260 hr
= parse_ticket(delta
, scope
, &ticket
);
1261 if (hr
!= S_OK
) return hr
;
1264 hr
= write_ticket(result
, &ticket
, scope
);
1265 return hr
? hr
: S_PT_NO_CONFLICT
;
1268 static HRESULT
write_PageMediaSize_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1273 IXMLDOMElement
*feature
= NULL
;
1277 count
= DeviceCapabilitiesW(device
, NULL
, DC_PAPERSIZE
, NULL
, NULL
);
1279 return HRESULT_FROM_WIN32(GetLastError());
1281 pt
= calloc(count
, sizeof(*pt
));
1282 if (!pt
) return E_OUTOFMEMORY
;
1284 count
= DeviceCapabilitiesW(device
, NULL
, DC_PAPERSIZE
, (LPWSTR
)pt
, NULL
);
1287 hr
= HRESULT_FROM_WIN32(GetLastError());
1291 hr
= create_Feature(root
, L
"psk:PageMediaSize", &feature
);
1292 if (hr
!= S_OK
) goto fail
;
1294 for (i
= 0; i
< count
; i
++)
1299 if (feature
) IXMLDOMElement_Release(feature
);
1304 static HRESULT
write_PageOutputColor_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1308 IXMLDOMElement
*feature
= NULL
;
1312 color
= DeviceCapabilitiesW(device
, NULL
, DC_COLORDEVICE
, NULL
, NULL
);
1313 TRACE("DC_COLORDEVICE: %d\n", color
);
1315 hr
= create_Feature(root
, L
"psk:PageOutputColor", &feature
);
1316 if (hr
!= S_OK
) goto fail
;
1319 if (feature
) IXMLDOMElement_Release(feature
);
1323 static HRESULT
write_PageScaling_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1326 IXMLDOMElement
*feature
= NULL
;
1330 hr
= create_Feature(root
, L
"psk:PageScaling", &feature
);
1331 if (hr
!= S_OK
) goto fail
;
1334 if (feature
) IXMLDOMElement_Release(feature
);
1338 static HRESULT
write_PageResolution_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1347 IXMLDOMElement
*feature
= NULL
;
1351 count
= DeviceCapabilitiesW(device
, NULL
, DC_ENUMRESOLUTIONS
, NULL
, NULL
);
1353 return HRESULT_FROM_WIN32(GetLastError());
1355 res
= calloc(count
, sizeof(*res
));
1356 if (!res
) return E_OUTOFMEMORY
;
1358 count
= DeviceCapabilitiesW(device
, NULL
, DC_ENUMRESOLUTIONS
, (LPWSTR
)res
, NULL
);
1361 hr
= HRESULT_FROM_WIN32(GetLastError());
1365 hr
= create_Feature(root
, L
"psk:PageResolution", &feature
);
1366 if (hr
!= S_OK
) goto fail
;
1368 for (i
= 0; i
< count
; i
++)
1373 if (feature
) IXMLDOMElement_Release(feature
);
1378 static HRESULT
write_PageOrientation_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1382 IXMLDOMElement
*feature
= NULL
;
1386 landscape
= DeviceCapabilitiesW(device
, NULL
, DC_ORIENTATION
, NULL
, NULL
);
1387 TRACE("DC_ORIENTATION: %d\n", landscape
);
1389 hr
= create_Feature(root
, L
"psk:PageOrientation", &feature
);
1390 if (hr
!= S_OK
) goto fail
;
1393 if (feature
) IXMLDOMElement_Release(feature
);
1397 static HRESULT
write_DocumentCollate_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1401 IXMLDOMElement
*feature
= NULL
;
1405 collate
= DeviceCapabilitiesW(device
, NULL
, DC_COLLATE
, NULL
, NULL
);
1406 TRACE("DC_COLLATE: %d\n", collate
);
1408 hr
= create_Feature(root
, L
"psk:DocumentCollate", &feature
);
1409 if (hr
!= S_OK
) goto fail
;
1412 if (feature
) IXMLDOMElement_Release(feature
);
1416 static HRESULT
write_JobInputBin_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1421 IXMLDOMElement
*feature
= NULL
;
1425 count
= DeviceCapabilitiesW(device
, NULL
, DC_BINS
, NULL
, NULL
);
1427 return HRESULT_FROM_WIN32(GetLastError());
1429 bin
= calloc(count
, sizeof(*bin
));
1430 if (!bin
) return E_OUTOFMEMORY
;
1432 count
= DeviceCapabilitiesW(device
, NULL
, DC_BINS
, (LPWSTR
)bin
, NULL
);
1435 hr
= HRESULT_FROM_WIN32(GetLastError());
1439 hr
= create_Feature(root
, L
"psk:JobInputBin", &feature
);
1440 if (hr
!= S_OK
) goto fail
;
1442 for (i
= 0; i
< count
; i
++)
1447 if (feature
) IXMLDOMElement_Release(feature
);
1452 static HRESULT
write_JobCopies_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1456 IXMLDOMElement
*feature
= NULL
;
1460 copies
= DeviceCapabilitiesW(device
, NULL
, DC_COPIES
, NULL
, NULL
);
1461 TRACE("DC_COPIES: %d\n", copies
);
1463 hr
= create_ParameterDef(root
, L
"psk:JobCopiesAllDocuments", &feature
);
1464 if (hr
!= S_OK
) goto fail
;
1467 if (feature
) IXMLDOMElement_Release(feature
);
1471 static HRESULT
write_print_capabilities(const WCHAR
*device
, IStream
*stream
)
1473 static const char xmldecl
[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
1475 IXMLDOMDocument
*doc
;
1476 IXMLDOMElement
*root
= NULL
;
1479 hr
= CoCreateInstance(&CLSID_DOMDocument
, NULL
, CLSCTX_INPROC_SERVER
,
1480 &IID_IXMLDOMDocument
, (void **)&doc
);
1481 if (hr
!= S_OK
) return hr
;
1483 hr
= IXMLDOMDocument_createElement(doc
, (BSTR
)L
"psf:PrintCapabilities", &root
);
1484 if (hr
!= S_OK
) goto fail
;
1486 hr
= IXMLDOMDocument_appendChild(doc
, (IXMLDOMNode
*)root
, NULL
);
1487 if (hr
!= S_OK
) goto fail
;
1489 hr
= write_attributes(root
);
1490 if (hr
!= S_OK
) goto fail
;
1492 hr
= write_PageMediaSize_caps(device
, root
);
1493 if (hr
!= S_OK
) goto fail
;
1494 hr
= write_PageOutputColor_caps(device
, root
);
1495 if (hr
!= S_OK
) goto fail
;
1496 hr
= write_PageScaling_caps(device
, root
);
1497 if (hr
!= S_OK
) goto fail
;
1498 hr
= write_PageResolution_caps(device
, root
);
1499 if (hr
!= S_OK
) goto fail
;
1500 hr
= write_PageOrientation_caps(device
, root
);
1501 if (hr
!= S_OK
) goto fail
;
1502 hr
= write_DocumentCollate_caps(device
, root
);
1503 if (hr
!= S_OK
) goto fail
;
1504 hr
= write_JobInputBin_caps(device
, root
);
1505 if (hr
!= S_OK
) goto fail
;
1506 hr
= write_JobCopies_caps(device
, root
);
1507 if (hr
!= S_OK
) goto fail
;
1509 hr
= IStream_Write(stream
, xmldecl
, strlen(xmldecl
), NULL
);
1510 if (hr
!= S_OK
) goto fail
;
1512 V_VT(&var
) = VT_UNKNOWN
;
1513 V_UNKNOWN(&var
) = (IUnknown
*)stream
;
1514 hr
= IXMLDOMDocument_save(doc
, var
);
1517 if (root
) IXMLDOMElement_Release(root
);
1518 IXMLDOMDocument_Release(doc
);
1522 HRESULT WINAPI
PTGetPrintCapabilities(HPTPROVIDER provider
, IStream
*stream
, IStream
*caps
, BSTR
*error
)
1524 struct prn_provider
*prov
= (struct prn_provider
*)provider
;
1525 struct ticket ticket
;
1528 TRACE("%p,%p,%p,%p\n", provider
, stream
, caps
, error
);
1530 if (!is_valid_provider(provider
) || !stream
|| !caps
)
1531 return E_INVALIDARG
;
1533 hr
= parse_ticket(stream
, kPTJobScope
, &ticket
);
1534 if (hr
!= S_OK
) return hr
;
1536 return write_print_capabilities(prov
->name
, caps
);