[PATCH v2 01/12] prntvpt: Implement PTConvertDevModeToPrintTicket.

Dmitry Timoshkov dmitry at baikal.ru
Wed Jun 17 00:21:55 CDT 2020


v2: Split into smaller parts.

Signed-off-by: Dmitry Timoshkov <dmitry at baikal.ru>
---
 dlls/prntvpt/prntvpt.spec |   2 +-
 dlls/prntvpt/ticket.c     | 318 ++++++++++++++++++++++++++++++++++++++
 include/prntvpt.h         |   1 +
 3 files changed, 320 insertions(+), 1 deletion(-)

diff --git a/dlls/prntvpt/prntvpt.spec b/dlls/prntvpt/prntvpt.spec
index ce8a0e591c..bae26fab9d 100644
--- a/dlls/prntvpt/prntvpt.spec
+++ b/dlls/prntvpt/prntvpt.spec
@@ -6,7 +6,7 @@
 @ stub PTGetPrintCapabilities
 @ stub PTMergeAndValidatePrintTicket
 @ stdcall PTConvertPrintTicketToDevMode(ptr ptr long long ptr ptr ptr)
-@ stub PTConvertDevModeToPrintTicket
+@ stdcall PTConvertDevModeToPrintTicket(ptr long ptr long ptr)
 @ stdcall PTReleaseMemory(ptr)
 @ stub ConvertDevModeToPrintTicketThunk2
 @ stub ConvertDevModeToPrintTicketThunk
diff --git a/dlls/prntvpt/ticket.c b/dlls/prntvpt/ticket.c
index 36e343bbf2..548da5977c 100644
--- a/dlls/prntvpt/ticket.c
+++ b/dlls/prntvpt/ticket.c
@@ -102,6 +102,18 @@ static int media_to_paper(const WCHAR *name)
     return DMPAPER_A4;
 }
 
+static const WCHAR *paper_to_media(int paper)
+{
+    int i;
+
+    for (i = 0 ; i < ARRAY_SIZE(psk_media); i++)
+        if (psk_media[i].paper == paper)
+            return psk_media[i].name;
+
+    FIXME("%d\n", paper);
+    return psk_media[0].name;
+}
+
 static BOOL is_valid_node_name(const WCHAR *name)
 {
     static const WCHAR * const psf_names[] = { L"psf:ParameterInit", L"psf:Feature" };
@@ -693,3 +705,309 @@ HRESULT WINAPI PTConvertPrintTicketToDevMode(HPTPROVIDER provider, IStream *stre
 
     return S_OK;
 }
+
+static void devmode_to_ticket(const DEVMODEW *dm, struct ticket *ticket)
+{
+    if (dm->dmFields & DM_ORIENTATION)
+        ticket->page.orientation = dm->u1.s1.dmOrientation;
+    if (dm->dmFields & DM_PAPERSIZE)
+        ticket->page.media.paper = dm->u1.s1.dmPaperSize;
+    if (dm->dmFields & DM_PAPERLENGTH)
+        ticket->page.media.size.width = dm->u1.s1.dmPaperWidth * 100;
+    if (dm->dmFields & DM_PAPERWIDTH)
+        ticket->page.media.size.height = dm->u1.s1.dmPaperLength * 100;
+    if (dm->dmFields & DM_SCALE)
+        ticket->page.scaling = dm->u1.s1.dmScale;
+    if (dm->dmFields & DM_COPIES)
+        ticket->job.copies = dm->u1.s1.dmCopies;
+    if (dm->dmFields & DM_COLOR)
+        ticket->page.color = dm->dmColor;
+    if (dm->dmFields & DM_PRINTQUALITY)
+    {
+        ticket->page.resolution.x = dm->u1.s1.dmPrintQuality;
+        ticket->page.resolution.y = dm->u1.s1.dmPrintQuality;
+    }
+    if (dm->dmFields & DM_YRESOLUTION)
+        ticket->page.resolution.y = dm->dmYResolution;
+    if (dm->dmFields & DM_LOGPIXELS)
+    {
+        ticket->page.resolution.x = dm->dmLogPixels;
+        ticket->page.resolution.y = dm->dmLogPixels;
+    }
+    if (dm->dmFields & DM_COLLATE)
+        ticket->document.collate = dm->dmCollate;
+}
+
+static HRESULT add_attribute(IXMLDOMElement *element, const WCHAR *attr, const WCHAR *value)
+{
+    VARIANT var;
+    BSTR name;
+    HRESULT hr;
+
+    name = SysAllocString(attr);
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = SysAllocString(value);
+
+    hr = IXMLDOMElement_setAttribute(element, name, var);
+
+    SysFreeString(name);
+    SysFreeString(V_BSTR(&var));
+
+    return hr;
+}
+
+static HRESULT create_element(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
+{
+    IXMLDOMDocument *doc;
+    HRESULT hr;
+
+    hr = IXMLDOMElement_get_ownerDocument(root, &doc);
+    if (hr != S_OK) return hr;
+
+    hr = IXMLDOMDocument_createElement(doc, (BSTR)name, child);
+    if (hr == S_OK)
+        hr = IXMLDOMElement_appendChild(root, (IXMLDOMNode *)*child, NULL);
+
+    IXMLDOMDocument_Release(doc);
+    return hr;
+}
+
+static HRESULT write_int_value(IXMLDOMElement *root, int value)
+{
+    HRESULT hr;
+    IXMLDOMElement *child;
+    VARIANT var;
+
+    hr = create_element(root, L"psf:Value", &child);
+    if (hr != S_OK) return hr;
+
+    hr = add_attribute(child, L"xsi:type", L"xsd:integer");
+    if (hr != S_OK) return hr;
+
+    V_VT(&var) = VT_I4;
+    V_I4(&var) = value;
+    hr = IXMLDOMElement_put_nodeTypedValue(child, var);
+
+    IXMLDOMElement_Release(child);
+    return hr;
+}
+
+static HRESULT create_Feature(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
+{
+    HRESULT hr;
+
+    hr = create_element(root, L"psf:Feature", child);
+    if (hr != S_OK) return hr;
+
+    return add_attribute(*child, L"name", name);
+}
+
+static HRESULT create_Option(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
+{
+    HRESULT hr;
+
+    hr = create_element(root, L"psf:Option", child);
+    if (hr != S_OK) return hr;
+
+    if (name)
+        hr = add_attribute(*child, L"name", name);
+
+    return hr;
+}
+
+static HRESULT create_ScoredProperty(IXMLDOMElement *root, const WCHAR *name, IXMLDOMElement **child)
+{
+    HRESULT hr;
+
+    hr = create_element(root, L"psf:ScoredProperty", child);
+    if (hr != S_OK) return hr;
+
+    return add_attribute(*child, L"name", name);
+}
+
+static HRESULT write_PageMediaSize(IXMLDOMElement *root, const struct ticket *ticket)
+{
+    IXMLDOMElement *feature, *option = NULL, *property;
+    HRESULT hr;
+
+    hr = create_Feature(root, L"psk:PageMediaSize", &feature);
+    if (hr != S_OK) return hr;
+
+    hr = create_Option(feature, paper_to_media(ticket->page.media.paper), &option);
+    if (hr != S_OK) goto fail;
+
+    hr = create_ScoredProperty(option, L"psk:MediaSizeWidth", &property);
+    if (hr != S_OK) goto fail;
+    hr = write_int_value(property, ticket->page.media.size.width);
+    IXMLDOMElement_Release(property);
+    if (hr != S_OK) goto fail;
+
+    hr = create_ScoredProperty(option, L"psk:MediaSizeHeight", &property);
+    if (hr != S_OK) goto fail;
+    hr = write_int_value(property, ticket->page.media.size.height);
+    IXMLDOMElement_Release(property);
+
+fail:
+    if (option) IXMLDOMElement_Release(option);
+    IXMLDOMElement_Release(feature);
+    return hr;
+}
+
+static HRESULT write_attributes(IXMLDOMElement *element)
+{
+    HRESULT hr;
+
+    hr = add_attribute(element, L"xmlns:psf", L"http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework");
+    if (hr != S_OK) return hr;
+    hr = add_attribute(element, L"xmlns:psk", L"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords");
+    if (hr != S_OK) return hr;
+    hr = add_attribute(element, L"xmlns:xsi", L"http://www.w3.org/2001/XMLSchema-instance");
+    if (hr != S_OK) return hr;
+    hr = add_attribute(element, L"xmlns:xsd", L"http://www.w3.org/2001/XMLSchema");
+    if (hr != S_OK) return hr;
+
+    return add_attribute(element, L"version", L"1");
+}
+
+static HRESULT write_ticket(IStream *stream, const struct ticket *ticket, EPrintTicketScope scope)
+{
+    static const char xmldecl[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
+    HRESULT hr;
+    IXMLDOMDocument *doc;
+    IXMLDOMElement *root = NULL;
+    VARIANT var;
+
+    hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
+                          &IID_IXMLDOMDocument, (void **)&doc);
+    if (hr != S_OK) return hr;
+
+    hr = IXMLDOMDocument_createElement(doc, (BSTR)L"psf:PrintTicket", &root);
+    if (hr != S_OK) goto fail;
+
+    hr = IXMLDOMDocument_appendChild(doc, (IXMLDOMNode *)root, NULL);
+    if (hr != S_OK) goto fail;
+
+    hr = write_attributes(root);
+    if (hr != S_OK) goto fail;
+
+    hr = write_PageMediaSize(root, ticket);
+    if (hr != S_OK) goto fail;
+
+    hr = IStream_Write(stream, xmldecl, strlen(xmldecl), NULL);
+    if (hr != S_OK) goto fail;
+
+    V_VT(&var) = VT_UNKNOWN;
+    V_UNKNOWN(&var) = (IUnknown *)stream;
+    hr = IXMLDOMDocument_save(doc, var);
+
+fail:
+    if (root) IXMLDOMElement_Release(root);
+    IXMLDOMDocument_Release(doc);
+    return hr;
+}
+
+static void dump_fields(DWORD fields)
+{
+    int add_space = 0;
+
+#define CHECK_FIELD(flag) \
+do \
+{ \
+    if (fields & flag) \
+    { \
+        if (add_space++) TRACE(" "); \
+        TRACE(#flag); \
+        fields &= ~flag; \
+    } \
+} \
+while (0)
+
+    CHECK_FIELD(DM_ORIENTATION);
+    CHECK_FIELD(DM_PAPERSIZE);
+    CHECK_FIELD(DM_PAPERLENGTH);
+    CHECK_FIELD(DM_PAPERWIDTH);
+    CHECK_FIELD(DM_SCALE);
+    CHECK_FIELD(DM_POSITION);
+    CHECK_FIELD(DM_NUP);
+    CHECK_FIELD(DM_DISPLAYORIENTATION);
+    CHECK_FIELD(DM_COPIES);
+    CHECK_FIELD(DM_DEFAULTSOURCE);
+    CHECK_FIELD(DM_PRINTQUALITY);
+    CHECK_FIELD(DM_COLOR);
+    CHECK_FIELD(DM_DUPLEX);
+    CHECK_FIELD(DM_YRESOLUTION);
+    CHECK_FIELD(DM_TTOPTION);
+    CHECK_FIELD(DM_COLLATE);
+    CHECK_FIELD(DM_FORMNAME);
+    CHECK_FIELD(DM_LOGPIXELS);
+    CHECK_FIELD(DM_BITSPERPEL);
+    CHECK_FIELD(DM_PELSWIDTH);
+    CHECK_FIELD(DM_PELSHEIGHT);
+    CHECK_FIELD(DM_DISPLAYFLAGS);
+    CHECK_FIELD(DM_DISPLAYFREQUENCY);
+    CHECK_FIELD(DM_ICMMETHOD);
+    CHECK_FIELD(DM_ICMINTENT);
+    CHECK_FIELD(DM_MEDIATYPE);
+    CHECK_FIELD(DM_DITHERTYPE);
+    CHECK_FIELD(DM_PANNINGWIDTH);
+    CHECK_FIELD(DM_PANNINGHEIGHT);
+    if (fields) TRACE(" %#x", fields);
+    TRACE("\n");
+#undef CHECK_FIELD
+}
+
+/* Dump DEVMODE structure without a device specific part.
+ * Some applications and drivers fail to specify correct field
+ * flags (like DM_FORMNAME), so dump everything.
+ */
+static void dump_devmode(const DEVMODEW *dm)
+{
+    if (!TRACE_ON(prntvpt)) return;
+
+    TRACE("dmDeviceName: %s\n", debugstr_w(dm->dmDeviceName));
+    TRACE("dmSpecVersion: 0x%04x\n", dm->dmSpecVersion);
+    TRACE("dmDriverVersion: 0x%04x\n", dm->dmDriverVersion);
+    TRACE("dmSize: 0x%04x\n", dm->dmSize);
+    TRACE("dmDriverExtra: 0x%04x\n", dm->dmDriverExtra);
+    TRACE("dmFields: 0x%04x\n", dm->dmFields);
+    dump_fields(dm->dmFields);
+    TRACE("dmOrientation: %d\n", dm->u1.s1.dmOrientation);
+    TRACE("dmPaperSize: %d\n", dm->u1.s1.dmPaperSize);
+    TRACE("dmPaperLength: %d\n", dm->u1.s1.dmPaperLength);
+    TRACE("dmPaperWidth: %d\n", dm->u1.s1.dmPaperWidth);
+    TRACE("dmScale: %d\n", dm->u1.s1.dmScale);
+    TRACE("dmCopies: %d\n", dm->u1.s1.dmCopies);
+    TRACE("dmDefaultSource: %d\n", dm->u1.s1.dmDefaultSource);
+    TRACE("dmPrintQuality: %d\n", dm->u1.s1.dmPrintQuality);
+    TRACE("dmColor: %d\n", dm->dmColor);
+    TRACE("dmDuplex: %d\n", dm->dmDuplex);
+    TRACE("dmYResolution: %d\n", dm->dmYResolution);
+    TRACE("dmTTOption: %d\n", dm->dmTTOption);
+    TRACE("dmCollate: %d\n", dm->dmCollate);
+    TRACE("dmFormName: %s\n", debugstr_w(dm->dmFormName));
+    TRACE("dmLogPixels %u\n", dm->dmLogPixels);
+    TRACE("dmBitsPerPel %u\n", dm->dmBitsPerPel);
+    TRACE("dmPelsWidth %u\n", dm->dmPelsWidth);
+    TRACE("dmPelsHeight %u\n", dm->dmPelsHeight);
+}
+
+HRESULT WINAPI PTConvertDevModeToPrintTicket(HPTPROVIDER provider, ULONG size, PDEVMODEW dm,
+                                             EPrintTicketScope scope, IStream *stream)
+{
+    struct ticket ticket;
+
+    TRACE("%p,%u,%p,%d,%p\n", provider, size, dm, scope, stream);
+
+    if (!provider || !dm || !stream)
+        return E_INVALIDARG;
+
+    dump_devmode(dm);
+
+    if (!IsValidDevmodeW(dm, size))
+        return E_INVALIDARG;
+
+    initialize_ticket(&ticket);
+    devmode_to_ticket(dm, &ticket);
+
+    return write_ticket(stream, &ticket, scope);
+}
diff --git a/include/prntvpt.h b/include/prntvpt.h
index e1855badd1..f1d7edc350 100644
--- a/include/prntvpt.h
+++ b/include/prntvpt.h
@@ -43,6 +43,7 @@ typedef enum
 HRESULT WINAPI PTOpenProvider(const WCHAR *printer, DWORD version, HPTPROVIDER *provider);
 HRESULT WINAPI PTOpenProviderEx(const WCHAR *printer, DWORD max_version, DWORD pref_version, HPTPROVIDER *provider, DWORD *used_version);
 HRESULT WINAPI PTCloseProvider(HPTPROVIDER);
+HRESULT WINAPI PTConvertDevModeToPrintTicket(HPTPROVIDER, ULONG, PDEVMODEW, EPrintTicketScope, IStream *);
 HRESULT WINAPI PTConvertPrintTicketToDevMode(HPTPROVIDER, IStream *, EDefaultDevmodeType, EPrintTicketScope, ULONG *, PDEVMODEW *, BSTR *);
 HRESULT WINAPI PTReleaseMemory(PVOID);
 
-- 
2.26.2




More information about the wine-devel mailing list