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/heap.h"
34 #include "wine/debug.h"
36 #include "prntvpt_private.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(prntvpt
);
61 struct resolution resolution
;
82 struct document document
;
92 { L
"psk:ISOA4", DMPAPER_A4
},
95 static int media_to_paper(const WCHAR
*name
)
99 for (i
= 0 ; i
< ARRAY_SIZE(psk_media
); i
++)
100 if (!wcscmp(name
, psk_media
[i
].name
))
101 return psk_media
[i
].paper
;
103 FIXME("%s\n", wine_dbgstr_w(name
));
107 static const WCHAR
*paper_to_media(int paper
)
111 for (i
= 0 ; i
< ARRAY_SIZE(psk_media
); i
++)
112 if (psk_media
[i
].paper
== paper
)
113 return psk_media
[i
].name
;
115 FIXME("%d\n", paper
);
116 return psk_media
[0].name
;
119 static BOOL
is_valid_node_name(const WCHAR
*name
)
121 static const WCHAR
* const psf_names
[] = { L
"psf:ParameterInit", L
"psf:Feature" };
124 for (i
= 0 ; i
< ARRAY_SIZE(psf_names
); i
++)
125 if (!wcscmp(name
, psf_names
[i
])) return TRUE
;
130 static HRESULT
verify_ticket(IXMLDOMDocument2
*doc
)
132 IXMLDOMElement
*element
;
133 IXMLDOMNode
*node
= NULL
;
137 hr
= IXMLDOMDocument2_get_documentElement(doc
, &element
);
138 if (hr
!= S_OK
) return E_PRINTTICKET_FORMAT
;
140 hr
= IXMLDOMElement_get_tagName(element
, &str
);
141 if (hr
!= S_OK
) goto fail
;
142 if (wcscmp(str
, L
"psf:PrintTicket") != 0)
145 if (hr
!= S_OK
) goto fail
;
147 hr
= IXMLDOMElement_get_firstChild(element
, &node
);
148 IXMLDOMElement_Release(element
);
149 if (hr
!= S_OK
) return S_OK
;
154 IXMLDOMNode
*next_node
;
156 hr
= IXMLDOMNode_get_nodeName(node
, &str
);
157 if (hr
!= S_OK
) break;
158 if (!is_valid_node_name(str
))
161 if (hr
!= S_OK
) break;
163 hr
= IXMLDOMNode_QueryInterface(node
, &IID_IXMLDOMElement
, (void **)&element
);
164 if (hr
!= S_OK
) break;
167 hr
= IXMLDOMElement_getAttribute(element
, (BSTR
)L
"name", &var
);
168 IXMLDOMElement_Release(element
);
169 if (hr
!= S_OK
) break;
170 if (V_VT(&var
) != VT_BSTR
)
173 if (hr
!= S_OK
) break;
175 hr
= IXMLDOMNode_get_nextSibling(node
, &next_node
);
182 IXMLDOMNode_Release(node
);
187 if (node
) IXMLDOMNode_Release(node
);
189 return hr
!= S_OK
? E_PRINTTICKET_FORMAT
: S_OK
;
192 static HRESULT
read_int_value(IXMLDOMNode
*node
, int *value
)
198 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Value[@xsi:type='xsd:integer']", &val
);
199 if (hr
!= S_OK
) return hr
;
202 hr
= IXMLDOMNode_get_nodeTypedValue(val
, &var1
);
206 hr
= VariantChangeTypeEx(&var2
, &var1
, 0, 0, VT_I4
);
208 *value
= V_I4(&var2
);
213 IXMLDOMNode_Release(val
);
217 static void read_PageMediaSize(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
219 IXMLDOMNode
*node
, *option
, *child
;
222 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:Feature[@name='psk:PageMediaSize']", &node
);
223 if (hr
!= S_OK
) return;
225 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Option", &option
);
228 IXMLDOMElement
*element
;
230 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
236 hr
= IXMLDOMElement_getAttribute(element
, (BSTR
)L
"name", &var
);
237 if (hr
== S_OK
&& V_VT(&var
) == VT_BSTR
)
239 ticket
->page
.media
.paper
= media_to_paper(V_BSTR(&var
));
240 TRACE("paper: %s => %d\n", wine_dbgstr_w(V_BSTR(&var
)), ticket
->page
.media
.paper
);
244 IXMLDOMElement_Release(element
);
247 hr
= IXMLDOMNode_selectSingleNode(option
, (BSTR
)L
"./psf:ScoredProperty[@name='psk:MediaSizeWidth']", &child
);
250 if (read_int_value(child
, &ticket
->page
.media
.size
.width
) == S_OK
)
251 TRACE("width: %d\n", ticket
->page
.media
.size
.width
);
252 IXMLDOMNode_Release(child
);
255 hr
= IXMLDOMNode_selectSingleNode(option
, (BSTR
)L
"./psf:ScoredProperty[@name='psk:MediaSizeHeight']", &child
);
258 if (read_int_value(child
, &ticket
->page
.media
.size
.height
) == S_OK
)
259 TRACE("height: %d\n", ticket
->page
.media
.size
.height
);
260 IXMLDOMNode_Release(child
);
263 IXMLDOMNode_Release(option
);
266 IXMLDOMNode_Release(node
);
269 static void read_PageOutputColor(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
271 IXMLDOMNode
*node
, *option
;
274 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:Feature[@name='psk:PageOutputColor']", &node
);
275 if (hr
!= S_OK
) return;
277 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Option", &option
);
280 IXMLDOMElement
*element
;
282 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
288 hr
= IXMLDOMElement_getAttribute(element
, (BSTR
)L
"name", &var
);
289 if (hr
== S_OK
&& V_VT(&var
) == VT_BSTR
)
291 if (!wcscmp(V_BSTR(&var
), L
"psk:Color"))
292 ticket
->page
.color
= DMCOLOR_COLOR
;
293 else if (!wcscmp(V_BSTR(&var
), L
"psk:Monochrome"))
294 ticket
->page
.color
= DMCOLOR_MONOCHROME
;
297 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var
)));
298 ticket
->page
.color
= DMCOLOR_MONOCHROME
;
300 TRACE("color: %s => %d\n", wine_dbgstr_w(V_BSTR(&var
)), ticket
->page
.color
);
304 IXMLDOMElement_Release(element
);
308 IXMLDOMNode_Release(node
);
311 static void read_PageScaling(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
313 IXMLDOMNode
*node
, *option
;
317 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:Feature[@name='psk:PageScaling']", &node
);
318 if (hr
!= S_OK
) return;
320 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Option", &option
);
323 IXMLDOMElement
*element
;
325 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
331 hr
= IXMLDOMElement_getAttribute(element
, (BSTR
)L
"name", &var
);
332 if (hr
== S_OK
&& V_VT(&var
) == VT_BSTR
)
334 if (!wcscmp(V_BSTR(&var
), L
"psk:None"))
336 else if (!wcscmp(V_BSTR(&var
), L
"psk:CustomSquare"))
337 scaling
= 0; /* psk:PageScalingScale */
339 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var
)));
343 IXMLDOMElement_Release(element
);
347 IXMLDOMNode_Release(node
);
351 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:ParameterInit[@name='psk:PageScalingScale']", &node
);
354 read_int_value(node
, &scaling
);
355 IXMLDOMNode_Release(node
);
360 ticket
->page
.scaling
= scaling
;
362 ticket
->page
.scaling
= 100;
364 TRACE("page.scaling: %d\n", ticket
->page
.scaling
);
367 static void read_PageResolution(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
369 IXMLDOMNode
*node
, *option
, *child
;
372 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:Feature[@name='psk:PageResolution']", &node
);
373 if (hr
!= S_OK
) return;
375 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Option", &option
);
378 hr
= IXMLDOMNode_selectSingleNode(option
, (BSTR
)L
"./psf:ScoredProperty[@name='psk:ResolutionX']", &child
);
381 if (read_int_value(child
, &ticket
->page
.resolution
.x
) == S_OK
)
382 TRACE("resolution.x: %d\n", ticket
->page
.resolution
.x
);
383 IXMLDOMNode_Release(child
);
386 hr
= IXMLDOMNode_selectSingleNode(option
, (BSTR
)L
"./psf:ScoredProperty[@name='psk:ResolutionY']", &child
);
389 if (read_int_value(child
, &ticket
->page
.resolution
.y
) == S_OK
)
390 TRACE("resolution.y: %d\n", ticket
->page
.resolution
.y
);
391 IXMLDOMNode_Release(child
);
394 IXMLDOMNode_Release(option
);
397 IXMLDOMNode_Release(node
);
400 static void read_PageOrientation(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
402 IXMLDOMNode
*node
, *option
;
405 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:Feature[@name='psk:PageOrientation']", &node
);
406 if (hr
!= S_OK
) return;
408 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Option", &option
);
411 IXMLDOMElement
*element
;
413 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
419 hr
= IXMLDOMElement_getAttribute(element
, (BSTR
)L
"name", &var
);
420 if (hr
== S_OK
&& V_VT(&var
) == VT_BSTR
)
422 if (!wcscmp(V_BSTR(&var
), L
"psk:Portrait"))
423 ticket
->page
.orientation
= DMORIENT_PORTRAIT
;
424 else if (!wcscmp(V_BSTR(&var
), L
"psk:Landscape"))
425 ticket
->page
.orientation
= DMORIENT_LANDSCAPE
;
428 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var
)));
429 ticket
->page
.orientation
= DMORIENT_PORTRAIT
;
431 TRACE("orientation: %s => %d\n", wine_dbgstr_w(V_BSTR(&var
)), ticket
->page
.orientation
);
435 IXMLDOMElement_Release(element
);
439 IXMLDOMNode_Release(node
);
442 static void read_DocumentCollate(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
444 IXMLDOMNode
*node
, *option
;
447 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:Feature[@name='psk:DocumentCollate']", &node
);
448 if (hr
!= S_OK
) return;
450 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Option", &option
);
453 IXMLDOMElement
*element
;
455 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
461 hr
= IXMLDOMElement_getAttribute(element
, (BSTR
)L
"name", &var
);
462 if (hr
== S_OK
&& V_VT(&var
) == VT_BSTR
)
464 if (!wcscmp(V_BSTR(&var
), L
"psk:Collated"))
465 ticket
->document
.collate
= DMCOLLATE_TRUE
;
466 else if (!wcscmp(V_BSTR(&var
), L
"psk:Uncollated"))
467 ticket
->document
.collate
= DMCOLLATE_FALSE
;
470 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var
)));
471 ticket
->document
.collate
= DMCOLLATE_FALSE
;
473 TRACE("document.collate: %s => %d\n", wine_dbgstr_w(V_BSTR(&var
)), ticket
->document
.collate
);
477 IXMLDOMElement_Release(element
);
481 IXMLDOMNode_Release(node
);
484 static void read_JobInputBin(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
486 IXMLDOMNode
*node
, *option
;
489 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:Feature[@name='psk:JobInputBin']", &node
);
490 if (hr
!= S_OK
) return;
492 hr
= IXMLDOMNode_selectSingleNode(node
, (BSTR
)L
"./psf:Option", &option
);
495 IXMLDOMElement
*element
;
497 hr
= IXMLDOMNode_QueryInterface(option
, &IID_IXMLDOMElement
, (void **)&element
);
503 hr
= IXMLDOMElement_getAttribute(element
, (BSTR
)L
"name", &var
);
504 if (hr
== S_OK
&& V_VT(&var
) == VT_BSTR
)
506 if (!wcscmp(V_BSTR(&var
), L
"psk:AutoSelect"))
507 ticket
->job
.input_bin
= DMBIN_AUTO
;
510 FIXME("%s\n", wine_dbgstr_w(V_BSTR(&var
)));
511 ticket
->job
.input_bin
= DMBIN_AUTO
;
513 TRACE("input_bin: %s => %d\n", wine_dbgstr_w(V_BSTR(&var
)), ticket
->job
.input_bin
);
517 IXMLDOMElement_Release(element
);
521 IXMLDOMNode_Release(node
);
524 static void read_JobCopies(IXMLDOMDocument2
*doc
, struct ticket
*ticket
)
529 hr
= IXMLDOMDocument2_selectSingleNode(doc
, (BSTR
)L
"psf:PrintTicket/psf:ParameterInit[@name='psk:JobCopiesAllDocuments']", &node
);
530 if (hr
!= S_OK
) return;
532 if (read_int_value(node
, &ticket
->job
.copies
) == S_OK
)
533 TRACE("job.copies: %d\n", ticket
->job
.copies
);
535 IXMLDOMNode_Release(node
);
538 static void set_SelectionNamespaces(IXMLDOMDocument2
*doc
)
541 IXMLDOMElement
*element
= NULL
;
542 IXMLDOMNamedNodeMap
*map
= NULL
;
549 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, &stream
);
550 if (hr
!= S_OK
) return;
552 hr
= IXMLDOMDocument2_get_documentElement(doc
, &element
);
553 if (hr
!= S_OK
) goto fail
;
555 hr
= IXMLDOMElement_get_attributes(element
, &map
);
556 if (hr
!= S_OK
) goto fail
;
558 hr
= IXMLDOMNamedNodeMap_get_length(map
, &count
);
559 if (hr
!= S_OK
) goto fail
;
561 for (i
= 0; i
< count
; i
++)
565 hr
= IXMLDOMNamedNodeMap_get_item(map
, i
, &node
);
568 hr
= IXMLDOMNode_get_nodeName(node
, &str
);
572 hr
= IXMLDOMNode_get_nodeValue(node
, &var
);
575 if (!wcscmp(str
, L
"xmlns") || !wcsncmp(str
, L
"xmlns:", 6))
577 TRACE("ns[%d]: %s=%s\n", i
, wine_dbgstr_w(str
), wine_dbgstr_w(V_BSTR(&var
)));
578 IStream_Write(stream
, str
, wcslen(str
) * sizeof(WCHAR
), NULL
);
579 IStream_Write(stream
, L
"=\"", 2 * sizeof(WCHAR
), NULL
);
580 IStream_Write(stream
, V_BSTR(&var
), wcslen(V_BSTR(&var
)) * sizeof(WCHAR
), NULL
);
581 IStream_Write(stream
, L
"\" ", 2 * sizeof(WCHAR
), NULL
);
587 IXMLDOMNode_Release(node
);
591 IStream_Write(stream
, L
"", sizeof(WCHAR
), NULL
);
593 hr
= GetHGlobalFromStream(stream
, &hmem
);
594 if (hr
!= S_OK
) goto fail
;
596 str
= GlobalLock(hmem
);
597 V_VT(&var
) = VT_BSTR
;
598 V_BSTR(&var
) = SysAllocString(str
);
599 IXMLDOMDocument2_setProperty(doc
, (BSTR
)L
"SelectionNamespaces", var
);
600 SysFreeString(V_BSTR(&var
));
604 if (map
) IXMLDOMNamedNodeMap_Release(map
);
605 if (element
) IXMLDOMElement_Release(element
);
606 IStream_Release(stream
);
609 static HRESULT
parse_ticket(IStream
*stream
, EPrintTicketScope scope
, struct ticket
*ticket
)
611 IXMLDOMDocument2
*doc
;
616 hr
= CoCreateInstance(&CLSID_DOMDocument30
, NULL
, CLSCTX_INPROC_SERVER
,
617 &IID_IXMLDOMDocument2
, (void **)&doc
);
618 if (hr
!= S_OK
) return hr
;
620 V_VT(&src
) = VT_UNKNOWN
;
621 V_UNKNOWN(&src
) = (IUnknown
*)stream
;
622 hr
= IXMLDOMDocument2_load(doc
, src
, &ret
);
623 if (hr
!= S_OK
) goto fail
;
625 hr
= verify_ticket(doc
);
626 if (hr
!= S_OK
) goto fail
;
628 set_SelectionNamespaces(doc
);
630 /* PageScope is always added */
631 read_PageMediaSize(doc
, ticket
);
632 read_PageOutputColor(doc
, ticket
);
633 read_PageScaling(doc
, ticket
);
634 read_PageResolution(doc
, ticket
);
635 read_PageOrientation(doc
, ticket
);
637 if (scope
> kPTPageScope
)
638 read_DocumentCollate(doc
, ticket
);
640 if (scope
> kPTDocumentScope
)
642 read_JobInputBin(doc
, ticket
);
643 read_JobCopies(doc
, ticket
);
647 IXMLDOMDocument2_Release(doc
);
651 static void ticket_to_devmode(const struct ticket
*ticket
, DEVMODEW
*dm
)
653 memset(dm
, 0, sizeof(*dm
));
655 dm
->dmSize
= sizeof(*dm
);
656 dm
->dmFields
= DM_ORIENTATION
| DM_PAPERSIZE
| DM_PAPERLENGTH
| DM_PAPERWIDTH
| DM_SCALE
|
657 DM_COPIES
| DM_COLOR
| DM_PRINTQUALITY
| DM_YRESOLUTION
| DM_COLLATE
;
658 dm
->u1
.s1
.dmOrientation
= ticket
->page
.orientation
;
659 dm
->u1
.s1
.dmPaperSize
= ticket
->page
.media
.paper
;
660 dm
->u1
.s1
.dmPaperWidth
= ticket
->page
.media
.size
.width
/ 100;
661 dm
->u1
.s1
.dmPaperLength
= ticket
->page
.media
.size
.height
/ 100;
662 dm
->u1
.s1
.dmScale
= ticket
->page
.scaling
;
663 dm
->u1
.s1
.dmCopies
= ticket
->job
.copies
;
664 dm
->dmColor
= ticket
->page
.color
;
665 dm
->u1
.s1
.dmPrintQuality
= ticket
->page
.resolution
.x
;
666 dm
->dmYResolution
= ticket
->page
.resolution
.y
;
667 dm
->dmCollate
= ticket
->document
.collate
;
670 static void devmode_to_ticket(const DEVMODEW
*dm
, struct ticket
*ticket
)
672 if (dm
->dmFields
& DM_ORIENTATION
)
673 ticket
->page
.orientation
= dm
->u1
.s1
.dmOrientation
;
674 if (dm
->dmFields
& DM_PAPERSIZE
)
675 ticket
->page
.media
.paper
= dm
->u1
.s1
.dmPaperSize
;
676 if (dm
->dmFields
& DM_PAPERLENGTH
)
677 ticket
->page
.media
.size
.width
= dm
->u1
.s1
.dmPaperWidth
* 100;
678 if (dm
->dmFields
& DM_PAPERWIDTH
)
679 ticket
->page
.media
.size
.height
= dm
->u1
.s1
.dmPaperLength
* 100;
680 if (dm
->dmFields
& DM_SCALE
)
681 ticket
->page
.scaling
= dm
->u1
.s1
.dmScale
;
682 if (dm
->dmFields
& DM_COPIES
)
683 ticket
->job
.copies
= dm
->u1
.s1
.dmCopies
;
684 if (dm
->dmFields
& DM_COLOR
)
685 ticket
->page
.color
= dm
->dmColor
;
686 if (dm
->dmFields
& DM_PRINTQUALITY
)
688 ticket
->page
.resolution
.x
= dm
->u1
.s1
.dmPrintQuality
;
689 ticket
->page
.resolution
.y
= dm
->u1
.s1
.dmPrintQuality
;
691 if (dm
->dmFields
& DM_YRESOLUTION
)
692 ticket
->page
.resolution
.y
= dm
->dmYResolution
;
693 if (dm
->dmFields
& DM_LOGPIXELS
)
695 ticket
->page
.resolution
.x
= dm
->dmLogPixels
;
696 ticket
->page
.resolution
.y
= dm
->dmLogPixels
;
698 if (dm
->dmFields
& DM_COLLATE
)
699 ticket
->document
.collate
= dm
->dmCollate
;
702 static HRESULT
initialize_ticket(struct prn_provider
*prov
, struct ticket
*ticket
)
704 PRINTER_INFO_2W
*pi2
;
708 GetPrinterW(prov
->hprn
, 2, NULL
, 0, &size
);
709 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
710 return HRESULT_FROM_WIN32(GetLastError());
712 pi2
= heap_alloc(size
);
713 if (!pi2
) return E_OUTOFMEMORY
;
715 if (!GetPrinterW(prov
->hprn
, 2, (LPBYTE
)pi2
, size
, NULL
))
716 hr
= HRESULT_FROM_WIN32(GetLastError());
718 devmode_to_ticket(pi2
->pDevMode
, ticket
);
724 HRESULT WINAPI
PTConvertPrintTicketToDevMode(HPTPROVIDER provider
, IStream
*stream
, EDefaultDevmodeType type
,
725 EPrintTicketScope scope
, ULONG
*size
, PDEVMODEW
*dm
, BSTR
*error
)
727 struct prn_provider
*prov
= (struct prn_provider
*)provider
;
729 struct ticket ticket
;
731 TRACE("%p,%p,%d,%d,%p,%p,%p\n", provider
, stream
, type
, scope
, size
, dm
, error
);
733 if (!is_valid_provider(provider
) || !stream
|| !size
|| !dm
)
736 hr
= initialize_ticket(prov
, &ticket
);
737 if (hr
!= S_OK
) return hr
;
739 hr
= parse_ticket(stream
, scope
, &ticket
);
740 if (hr
!= S_OK
) return hr
;
742 *dm
= heap_alloc(sizeof(**dm
));
743 if (!*dm
) return E_OUTOFMEMORY
;
745 ticket_to_devmode(&ticket
, *dm
);
746 *size
= sizeof(**dm
);
751 static HRESULT
add_attribute(IXMLDOMElement
*element
, const WCHAR
*attr
, const WCHAR
*value
)
757 name
= SysAllocString(attr
);
758 V_VT(&var
) = VT_BSTR
;
759 V_BSTR(&var
) = SysAllocString(value
);
761 hr
= IXMLDOMElement_setAttribute(element
, name
, var
);
764 SysFreeString(V_BSTR(&var
));
769 static HRESULT
create_element(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
771 IXMLDOMDocument
*doc
;
774 hr
= IXMLDOMElement_get_ownerDocument(root
, &doc
);
775 if (hr
!= S_OK
) return hr
;
777 hr
= IXMLDOMDocument_createElement(doc
, (BSTR
)name
, child
);
779 hr
= IXMLDOMElement_appendChild(root
, (IXMLDOMNode
*)*child
, NULL
);
781 IXMLDOMDocument_Release(doc
);
785 static HRESULT
write_int_value(IXMLDOMElement
*root
, int value
)
788 IXMLDOMElement
*child
;
791 hr
= create_element(root
, L
"psf:Value", &child
);
792 if (hr
!= S_OK
) return hr
;
794 hr
= add_attribute(child
, L
"xsi:type", L
"xsd:integer");
795 if (hr
!= S_OK
) return hr
;
799 hr
= IXMLDOMElement_put_nodeTypedValue(child
, var
);
801 IXMLDOMElement_Release(child
);
805 static HRESULT
create_Feature(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
809 hr
= create_element(root
, L
"psf:Feature", child
);
810 if (hr
!= S_OK
) return hr
;
812 return add_attribute(*child
, L
"name", name
);
815 static HRESULT
create_Option(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
819 hr
= create_element(root
, L
"psf:Option", child
);
820 if (hr
!= S_OK
) return hr
;
823 hr
= add_attribute(*child
, L
"name", name
);
828 static HRESULT
create_ParameterInit(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
832 hr
= create_element(root
, L
"psf:ParameterInit", child
);
833 if (hr
!= S_OK
) return hr
;
835 return add_attribute(*child
, L
"name", name
);
838 static HRESULT
create_ParameterRef(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
842 hr
= create_element(root
, L
"psf:ParameterRef", child
);
843 if (hr
!= S_OK
) return hr
;
845 return add_attribute(*child
, L
"name", name
);
848 static HRESULT
create_ParameterDef(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
852 hr
= create_element(root
, L
"psf:ParameterDef", child
);
853 if (hr
!= S_OK
) return hr
;
855 return add_attribute(*child
, L
"name", name
);
858 static HRESULT
create_ScoredProperty(IXMLDOMElement
*root
, const WCHAR
*name
, IXMLDOMElement
**child
)
862 hr
= create_element(root
, L
"psf:ScoredProperty", child
);
863 if (hr
!= S_OK
) return hr
;
865 return add_attribute(*child
, L
"name", name
);
868 static HRESULT
write_PageMediaSize(IXMLDOMElement
*root
, const struct ticket
*ticket
)
870 IXMLDOMElement
*feature
, *option
= NULL
, *property
;
873 hr
= create_Feature(root
, L
"psk:PageMediaSize", &feature
);
874 if (hr
!= S_OK
) return hr
;
876 hr
= create_Option(feature
, paper_to_media(ticket
->page
.media
.paper
), &option
);
877 if (hr
!= S_OK
) goto fail
;
879 hr
= create_ScoredProperty(option
, L
"psk:MediaSizeWidth", &property
);
880 if (hr
!= S_OK
) goto fail
;
881 hr
= write_int_value(property
, ticket
->page
.media
.size
.width
);
882 IXMLDOMElement_Release(property
);
883 if (hr
!= S_OK
) goto fail
;
885 hr
= create_ScoredProperty(option
, L
"psk:MediaSizeHeight", &property
);
886 if (hr
!= S_OK
) goto fail
;
887 hr
= write_int_value(property
, ticket
->page
.media
.size
.height
);
888 IXMLDOMElement_Release(property
);
891 if (option
) IXMLDOMElement_Release(option
);
892 IXMLDOMElement_Release(feature
);
896 static HRESULT
write_PageOutputColor(IXMLDOMElement
*root
, const struct ticket
*ticket
)
898 IXMLDOMElement
*feature
, *option
= NULL
;
901 hr
= create_Feature(root
, L
"psk:PageOutputColor", &feature
);
902 if (hr
!= S_OK
) return hr
;
904 if (ticket
->page
.color
== DMCOLOR_COLOR
)
905 hr
= create_Option(feature
, L
"psk:Color", &option
);
906 else /* DMCOLOR_MONOCHROME */
907 hr
= create_Option(feature
, L
"psk:Monochrome", &option
);
909 if (option
) IXMLDOMElement_Release(option
);
910 IXMLDOMElement_Release(feature
);
914 static HRESULT
write_PageScaling(IXMLDOMElement
*root
, const struct ticket
*ticket
)
916 IXMLDOMElement
*feature
, *option
= NULL
;
919 hr
= create_Feature(root
, L
"psk:PageScaling", &feature
);
920 if (hr
!= S_OK
) return hr
;
922 if (ticket
->page
.scaling
== 100)
924 hr
= create_Option(feature
, L
"psk:None", &option
);
925 if (hr
== S_OK
) IXMLDOMElement_Release(option
);
929 hr
= create_Option(feature
, L
"psk:CustomSquare", &option
);
932 IXMLDOMElement
*property
, *parameter
;
934 hr
= create_ScoredProperty(option
, L
"psk:Scale", &property
);
937 hr
= create_ParameterRef(property
, L
"psk:PageScalingScale", ¶meter
);
940 IXMLDOMElement_Release(parameter
);
942 hr
= create_ParameterInit(root
, L
"psk:PageScalingScale", ¶meter
);
945 hr
= write_int_value(parameter
, ticket
->page
.scaling
);
946 IXMLDOMElement_Release(parameter
);
950 IXMLDOMElement_Release(property
);
953 IXMLDOMElement_Release(option
);
957 IXMLDOMElement_Release(feature
);
961 static HRESULT
write_PageResolution(IXMLDOMElement
*root
, const struct ticket
*ticket
)
963 IXMLDOMElement
*feature
, *option
= NULL
, *property
;
966 hr
= create_Feature(root
, L
"psk:PageResolution", &feature
);
967 if (hr
!= S_OK
) return hr
;
969 hr
= create_Option(feature
, NULL
, &option
);
970 if (hr
!= S_OK
) goto fail
;
972 hr
= create_ScoredProperty(option
, L
"psk:ResolutionX", &property
);
973 if (hr
!= S_OK
) goto fail
;
974 hr
= write_int_value(property
, ticket
->page
.resolution
.x
);
975 IXMLDOMElement_Release(property
);
976 if (hr
!= S_OK
) goto fail
;
978 hr
= create_ScoredProperty(option
, L
"psk:ResolutionY", &property
);
979 if (hr
!= S_OK
) goto fail
;
980 hr
= write_int_value(property
, ticket
->page
.resolution
.y
);
981 IXMLDOMElement_Release(property
);
984 if (option
) IXMLDOMElement_Release(option
);
985 IXMLDOMElement_Release(feature
);
989 static HRESULT
write_PageOrientation(IXMLDOMElement
*root
, const struct ticket
*ticket
)
991 IXMLDOMElement
*feature
, *option
= NULL
;
994 hr
= create_Feature(root
, L
"psk:PageOrientation", &feature
);
995 if (hr
!= S_OK
) return hr
;
997 if (ticket
->page
.orientation
== DMORIENT_PORTRAIT
)
998 hr
= create_Option(feature
, L
"psk:Portrait", &option
);
999 else /* DMORIENT_LANDSCAPE */
1000 hr
= create_Option(feature
, L
"psk:Landscape", &option
);
1002 if (option
) IXMLDOMElement_Release(option
);
1003 IXMLDOMElement_Release(feature
);
1007 static HRESULT
write_DocumentCollate(IXMLDOMElement
*root
, const struct ticket
*ticket
)
1009 IXMLDOMElement
*feature
, *option
= NULL
;
1012 hr
= create_Feature(root
, L
"psk:DocumentCollate", &feature
);
1013 if (hr
!= S_OK
) return hr
;
1015 if (ticket
->document
.collate
== DMCOLLATE_TRUE
)
1016 hr
= create_Option(feature
, L
"psk:Collated", &option
);
1017 else /* DMCOLLATE_FALSE */
1018 hr
= create_Option(feature
, L
"psk:Uncollated", &option
);
1020 if (option
) IXMLDOMElement_Release(option
);
1021 IXMLDOMElement_Release(feature
);
1025 static HRESULT
write_JobInputBin(IXMLDOMElement
*root
, const struct ticket
*ticket
)
1027 IXMLDOMElement
*feature
, *option
= NULL
;
1030 hr
= create_Feature(root
, L
"psk:JobInputBin", &feature
);
1031 if (hr
!= S_OK
) return hr
;
1033 if (ticket
->job
.input_bin
!= DMBIN_AUTO
)
1034 FIXME("job.input_bin: %d\n", ticket
->job
.input_bin
);
1036 hr
= create_Option(feature
, L
"psk:AutoSelect", &option
);
1038 if (option
) IXMLDOMElement_Release(option
);
1039 IXMLDOMElement_Release(feature
);
1043 static HRESULT
write_JobCopies(IXMLDOMElement
*root
, const struct ticket
*ticket
)
1045 IXMLDOMElement
*parameter
;
1048 hr
= create_ParameterInit(root
, L
"psk:JobCopiesAllDocuments", ¶meter
);
1049 if (hr
!= S_OK
) return hr
;
1051 hr
= write_int_value(parameter
, ticket
->job
.copies
);
1053 IXMLDOMElement_Release(parameter
);
1057 static HRESULT
write_attributes(IXMLDOMElement
*element
)
1061 hr
= add_attribute(element
, L
"xmlns:psf", L
"http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework");
1062 if (hr
!= S_OK
) return hr
;
1063 hr
= add_attribute(element
, L
"xmlns:psk", L
"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords");
1064 if (hr
!= S_OK
) return hr
;
1065 hr
= add_attribute(element
, L
"xmlns:xsi", L
"http://www.w3.org/2001/XMLSchema-instance");
1066 if (hr
!= S_OK
) return hr
;
1067 hr
= add_attribute(element
, L
"xmlns:xsd", L
"http://www.w3.org/2001/XMLSchema");
1068 if (hr
!= S_OK
) return hr
;
1070 return add_attribute(element
, L
"version", L
"1");
1073 static HRESULT
write_ticket(IStream
*stream
, const struct ticket
*ticket
, EPrintTicketScope scope
)
1075 static const char xmldecl
[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
1077 IXMLDOMDocument
*doc
;
1078 IXMLDOMElement
*root
= NULL
;
1081 hr
= CoCreateInstance(&CLSID_DOMDocument
, NULL
, CLSCTX_INPROC_SERVER
,
1082 &IID_IXMLDOMDocument
, (void **)&doc
);
1083 if (hr
!= S_OK
) return hr
;
1085 hr
= IXMLDOMDocument_createElement(doc
, (BSTR
)L
"psf:PrintTicket", &root
);
1086 if (hr
!= S_OK
) goto fail
;
1088 hr
= IXMLDOMDocument_appendChild(doc
, (IXMLDOMNode
*)root
, NULL
);
1089 if (hr
!= S_OK
) goto fail
;
1091 hr
= write_attributes(root
);
1092 if (hr
!= S_OK
) goto fail
;
1094 hr
= write_PageMediaSize(root
, ticket
);
1095 if (hr
!= S_OK
) goto fail
;
1096 hr
= write_PageOutputColor(root
, ticket
);
1097 if (hr
!= S_OK
) goto fail
;
1098 hr
= write_PageScaling(root
, ticket
);
1099 if (hr
!= S_OK
) goto fail
;
1100 hr
= write_PageResolution(root
, ticket
);
1101 if (hr
!= S_OK
) goto fail
;
1102 hr
= write_PageOrientation(root
, ticket
);
1103 if (hr
!= S_OK
) goto fail
;
1105 if (scope
>= kPTDocumentScope
)
1107 hr
= write_DocumentCollate(root
, ticket
);
1108 if (hr
!= S_OK
) goto fail
;
1111 if (scope
>= kPTJobScope
)
1113 hr
= write_JobInputBin(root
, ticket
);
1114 if (hr
!= S_OK
) goto fail
;
1115 hr
= write_JobCopies(root
, ticket
);
1116 if (hr
!= S_OK
) goto fail
;
1119 hr
= IStream_Write(stream
, xmldecl
, strlen(xmldecl
), NULL
);
1120 if (hr
!= S_OK
) goto fail
;
1122 V_VT(&var
) = VT_UNKNOWN
;
1123 V_UNKNOWN(&var
) = (IUnknown
*)stream
;
1124 hr
= IXMLDOMDocument_save(doc
, var
);
1127 if (root
) IXMLDOMElement_Release(root
);
1128 IXMLDOMDocument_Release(doc
);
1132 static void dump_fields(DWORD fields
)
1136 #define CHECK_FIELD(flag) \
1139 if (fields & flag) \
1141 if (add_space++) TRACE(" "); \
1148 CHECK_FIELD(DM_ORIENTATION
);
1149 CHECK_FIELD(DM_PAPERSIZE
);
1150 CHECK_FIELD(DM_PAPERLENGTH
);
1151 CHECK_FIELD(DM_PAPERWIDTH
);
1152 CHECK_FIELD(DM_SCALE
);
1153 CHECK_FIELD(DM_POSITION
);
1154 CHECK_FIELD(DM_NUP
);
1155 CHECK_FIELD(DM_DISPLAYORIENTATION
);
1156 CHECK_FIELD(DM_COPIES
);
1157 CHECK_FIELD(DM_DEFAULTSOURCE
);
1158 CHECK_FIELD(DM_PRINTQUALITY
);
1159 CHECK_FIELD(DM_COLOR
);
1160 CHECK_FIELD(DM_DUPLEX
);
1161 CHECK_FIELD(DM_YRESOLUTION
);
1162 CHECK_FIELD(DM_TTOPTION
);
1163 CHECK_FIELD(DM_COLLATE
);
1164 CHECK_FIELD(DM_FORMNAME
);
1165 CHECK_FIELD(DM_LOGPIXELS
);
1166 CHECK_FIELD(DM_BITSPERPEL
);
1167 CHECK_FIELD(DM_PELSWIDTH
);
1168 CHECK_FIELD(DM_PELSHEIGHT
);
1169 CHECK_FIELD(DM_DISPLAYFLAGS
);
1170 CHECK_FIELD(DM_DISPLAYFREQUENCY
);
1171 CHECK_FIELD(DM_ICMMETHOD
);
1172 CHECK_FIELD(DM_ICMINTENT
);
1173 CHECK_FIELD(DM_MEDIATYPE
);
1174 CHECK_FIELD(DM_DITHERTYPE
);
1175 CHECK_FIELD(DM_PANNINGWIDTH
);
1176 CHECK_FIELD(DM_PANNINGHEIGHT
);
1177 if (fields
) TRACE(" %#x", fields
);
1182 /* Dump DEVMODE structure without a device specific part.
1183 * Some applications and drivers fail to specify correct field
1184 * flags (like DM_FORMNAME), so dump everything.
1186 static void dump_devmode(const DEVMODEW
*dm
)
1188 if (!TRACE_ON(prntvpt
)) return;
1190 TRACE("dmDeviceName: %s\n", debugstr_w(dm
->dmDeviceName
));
1191 TRACE("dmSpecVersion: 0x%04x\n", dm
->dmSpecVersion
);
1192 TRACE("dmDriverVersion: 0x%04x\n", dm
->dmDriverVersion
);
1193 TRACE("dmSize: 0x%04x\n", dm
->dmSize
);
1194 TRACE("dmDriverExtra: 0x%04x\n", dm
->dmDriverExtra
);
1195 TRACE("dmFields: 0x%04x\n", dm
->dmFields
);
1196 dump_fields(dm
->dmFields
);
1197 TRACE("dmOrientation: %d\n", dm
->u1
.s1
.dmOrientation
);
1198 TRACE("dmPaperSize: %d\n", dm
->u1
.s1
.dmPaperSize
);
1199 TRACE("dmPaperLength: %d\n", dm
->u1
.s1
.dmPaperLength
);
1200 TRACE("dmPaperWidth: %d\n", dm
->u1
.s1
.dmPaperWidth
);
1201 TRACE("dmScale: %d\n", dm
->u1
.s1
.dmScale
);
1202 TRACE("dmCopies: %d\n", dm
->u1
.s1
.dmCopies
);
1203 TRACE("dmDefaultSource: %d\n", dm
->u1
.s1
.dmDefaultSource
);
1204 TRACE("dmPrintQuality: %d\n", dm
->u1
.s1
.dmPrintQuality
);
1205 TRACE("dmColor: %d\n", dm
->dmColor
);
1206 TRACE("dmDuplex: %d\n", dm
->dmDuplex
);
1207 TRACE("dmYResolution: %d\n", dm
->dmYResolution
);
1208 TRACE("dmTTOption: %d\n", dm
->dmTTOption
);
1209 TRACE("dmCollate: %d\n", dm
->dmCollate
);
1210 TRACE("dmFormName: %s\n", debugstr_w(dm
->dmFormName
));
1211 TRACE("dmLogPixels %u\n", dm
->dmLogPixels
);
1212 TRACE("dmBitsPerPel %u\n", dm
->dmBitsPerPel
);
1213 TRACE("dmPelsWidth %u\n", dm
->dmPelsWidth
);
1214 TRACE("dmPelsHeight %u\n", dm
->dmPelsHeight
);
1217 HRESULT WINAPI
PTConvertDevModeToPrintTicket(HPTPROVIDER provider
, ULONG size
, PDEVMODEW dm
,
1218 EPrintTicketScope scope
, IStream
*stream
)
1220 struct prn_provider
*prov
= (struct prn_provider
*)provider
;
1221 struct ticket ticket
;
1224 TRACE("%p,%u,%p,%d,%p\n", provider
, size
, dm
, scope
, stream
);
1226 if (!is_valid_provider(provider
) || !dm
|| !stream
)
1227 return E_INVALIDARG
;
1231 if (!IsValidDevmodeW(dm
, size
))
1232 return E_INVALIDARG
;
1234 hr
= initialize_ticket(prov
, &ticket
);
1235 if (hr
!= S_OK
) return hr
;
1236 devmode_to_ticket(dm
, &ticket
);
1238 return write_ticket(stream
, &ticket
, scope
);
1241 HRESULT WINAPI
PTMergeAndValidatePrintTicket(HPTPROVIDER provider
, IStream
*base
, IStream
*delta
,
1242 EPrintTicketScope scope
, IStream
*result
, BSTR
*error
)
1244 struct prn_provider
*prov
= (struct prn_provider
*)provider
;
1245 struct ticket ticket
;
1248 TRACE("%p,%p,%p,%d,%p,%p\n", provider
, base
, delta
, scope
, result
, error
);
1250 if (!is_valid_provider(provider
) || !base
|| !result
)
1251 return E_INVALIDARG
;
1253 hr
= initialize_ticket(prov
, &ticket
);
1254 if (hr
!= S_OK
) return hr
;
1256 hr
= parse_ticket(base
, scope
, &ticket
);
1257 if (hr
!= S_OK
) return hr
;
1261 hr
= parse_ticket(delta
, scope
, &ticket
);
1262 if (hr
!= S_OK
) return hr
;
1265 hr
= write_ticket(result
, &ticket
, scope
);
1266 return hr
? hr
: S_PT_NO_CONFLICT
;
1269 static HRESULT
write_PageMediaSize_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1274 IXMLDOMElement
*feature
= NULL
;
1278 count
= DeviceCapabilitiesW(device
, NULL
, DC_PAPERSIZE
, NULL
, NULL
);
1280 return HRESULT_FROM_WIN32(GetLastError());
1282 pt
= heap_alloc(count
* sizeof(*pt
));
1283 if (!pt
) return E_OUTOFMEMORY
;
1285 count
= DeviceCapabilitiesW(device
, NULL
, DC_PAPERSIZE
, (LPWSTR
)pt
, NULL
);
1288 hr
= HRESULT_FROM_WIN32(GetLastError());
1292 hr
= create_Feature(root
, L
"psk:PageMediaSize", &feature
);
1293 if (hr
!= S_OK
) goto fail
;
1295 for (i
= 0; i
< count
; i
++)
1300 if (feature
) IXMLDOMElement_Release(feature
);
1305 static HRESULT
write_PageOutputColor_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1309 IXMLDOMElement
*feature
= NULL
;
1313 color
= DeviceCapabilitiesW(device
, NULL
, DC_COLORDEVICE
, NULL
, NULL
);
1314 TRACE("DC_COLORDEVICE: %d\n", color
);
1316 hr
= create_Feature(root
, L
"psk:PageOutputColor", &feature
);
1317 if (hr
!= S_OK
) goto fail
;
1320 if (feature
) IXMLDOMElement_Release(feature
);
1324 static HRESULT
write_PageScaling_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1327 IXMLDOMElement
*feature
= NULL
;
1331 hr
= create_Feature(root
, L
"psk:PageScaling", &feature
);
1332 if (hr
!= S_OK
) goto fail
;
1335 if (feature
) IXMLDOMElement_Release(feature
);
1339 static HRESULT
write_PageResolution_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1348 IXMLDOMElement
*feature
= NULL
;
1352 count
= DeviceCapabilitiesW(device
, NULL
, DC_ENUMRESOLUTIONS
, NULL
, NULL
);
1354 return HRESULT_FROM_WIN32(GetLastError());
1356 res
= heap_alloc(count
* sizeof(*res
));
1357 if (!res
) return E_OUTOFMEMORY
;
1359 count
= DeviceCapabilitiesW(device
, NULL
, DC_ENUMRESOLUTIONS
, (LPWSTR
)res
, NULL
);
1362 hr
= HRESULT_FROM_WIN32(GetLastError());
1366 hr
= create_Feature(root
, L
"psk:PageResolution", &feature
);
1367 if (hr
!= S_OK
) goto fail
;
1369 for (i
= 0; i
< count
; i
++)
1374 if (feature
) IXMLDOMElement_Release(feature
);
1379 static HRESULT
write_PageOrientation_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1383 IXMLDOMElement
*feature
= NULL
;
1387 landscape
= DeviceCapabilitiesW(device
, NULL
, DC_ORIENTATION
, NULL
, NULL
);
1388 TRACE("DC_ORIENTATION: %d\n", landscape
);
1390 hr
= create_Feature(root
, L
"psk:PageOrientation", &feature
);
1391 if (hr
!= S_OK
) goto fail
;
1394 if (feature
) IXMLDOMElement_Release(feature
);
1398 static HRESULT
write_DocumentCollate_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1402 IXMLDOMElement
*feature
= NULL
;
1406 collate
= DeviceCapabilitiesW(device
, NULL
, DC_COLLATE
, NULL
, NULL
);
1407 TRACE("DC_COLLATE: %d\n", collate
);
1409 hr
= create_Feature(root
, L
"psk:DocumentCollate", &feature
);
1410 if (hr
!= S_OK
) goto fail
;
1413 if (feature
) IXMLDOMElement_Release(feature
);
1417 static HRESULT
write_JobInputBin_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1422 IXMLDOMElement
*feature
= NULL
;
1426 count
= DeviceCapabilitiesW(device
, NULL
, DC_BINS
, NULL
, NULL
);
1428 return HRESULT_FROM_WIN32(GetLastError());
1430 bin
= heap_alloc(count
* sizeof(*bin
));
1431 if (!bin
) return E_OUTOFMEMORY
;
1433 count
= DeviceCapabilitiesW(device
, NULL
, DC_BINS
, (LPWSTR
)bin
, NULL
);
1436 hr
= HRESULT_FROM_WIN32(GetLastError());
1440 hr
= create_Feature(root
, L
"psk:JobInputBin", &feature
);
1441 if (hr
!= S_OK
) goto fail
;
1443 for (i
= 0; i
< count
; i
++)
1448 if (feature
) IXMLDOMElement_Release(feature
);
1453 static HRESULT
write_JobCopies_caps(const WCHAR
*device
, IXMLDOMElement
*root
)
1457 IXMLDOMElement
*feature
= NULL
;
1461 copies
= DeviceCapabilitiesW(device
, NULL
, DC_COPIES
, NULL
, NULL
);
1462 TRACE("DC_COPIES: %d\n", copies
);
1464 hr
= create_ParameterDef(root
, L
"psk:JobCopiesAllDocuments", &feature
);
1465 if (hr
!= S_OK
) goto fail
;
1468 if (feature
) IXMLDOMElement_Release(feature
);
1472 static HRESULT
write_print_capabilities(const WCHAR
*device
, IStream
*stream
)
1474 static const char xmldecl
[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
1476 IXMLDOMDocument
*doc
;
1477 IXMLDOMElement
*root
= NULL
;
1480 hr
= CoCreateInstance(&CLSID_DOMDocument
, NULL
, CLSCTX_INPROC_SERVER
,
1481 &IID_IXMLDOMDocument
, (void **)&doc
);
1482 if (hr
!= S_OK
) return hr
;
1484 hr
= IXMLDOMDocument_createElement(doc
, (BSTR
)L
"psf:PrintCapabilities", &root
);
1485 if (hr
!= S_OK
) goto fail
;
1487 hr
= IXMLDOMDocument_appendChild(doc
, (IXMLDOMNode
*)root
, NULL
);
1488 if (hr
!= S_OK
) goto fail
;
1490 hr
= write_attributes(root
);
1491 if (hr
!= S_OK
) goto fail
;
1493 hr
= write_PageMediaSize_caps(device
, root
);
1494 if (hr
!= S_OK
) goto fail
;
1495 hr
= write_PageOutputColor_caps(device
, root
);
1496 if (hr
!= S_OK
) goto fail
;
1497 hr
= write_PageScaling_caps(device
, root
);
1498 if (hr
!= S_OK
) goto fail
;
1499 hr
= write_PageResolution_caps(device
, root
);
1500 if (hr
!= S_OK
) goto fail
;
1501 hr
= write_PageOrientation_caps(device
, root
);
1502 if (hr
!= S_OK
) goto fail
;
1503 hr
= write_DocumentCollate_caps(device
, root
);
1504 if (hr
!= S_OK
) goto fail
;
1505 hr
= write_JobInputBin_caps(device
, root
);
1506 if (hr
!= S_OK
) goto fail
;
1507 hr
= write_JobCopies_caps(device
, root
);
1508 if (hr
!= S_OK
) goto fail
;
1510 hr
= IStream_Write(stream
, xmldecl
, strlen(xmldecl
), NULL
);
1511 if (hr
!= S_OK
) goto fail
;
1513 V_VT(&var
) = VT_UNKNOWN
;
1514 V_UNKNOWN(&var
) = (IUnknown
*)stream
;
1515 hr
= IXMLDOMDocument_save(doc
, var
);
1518 if (root
) IXMLDOMElement_Release(root
);
1519 IXMLDOMDocument_Release(doc
);
1523 HRESULT WINAPI
PTGetPrintCapabilities(HPTPROVIDER provider
, IStream
*stream
, IStream
*caps
, BSTR
*error
)
1525 struct prn_provider
*prov
= (struct prn_provider
*)provider
;
1526 struct ticket ticket
;
1529 TRACE("%p,%p,%p,%p\n", provider
, stream
, caps
, error
);
1531 if (!is_valid_provider(provider
) || !stream
|| !caps
)
1532 return E_INVALIDARG
;
1534 hr
= parse_ticket(stream
, kPTJobScope
, &ticket
);
1535 if (hr
!= S_OK
) return hr
;
1537 return write_print_capabilities(prov
->name
, caps
);