[PATCH 02/10] prntvpt: Implement PTConvertPrintTicketToDevMode.

Dmitry Timoshkov dmitry at baikal.ru
Thu Jun 11 00:59:31 CDT 2020


Signed-off-by: Dmitry Timoshkov <dmitry at baikal.ru>
---
 dlls/prntvpt/Makefile.in  |   5 +-
 dlls/prntvpt/main.c       |   1 +
 dlls/prntvpt/prntvpt.spec |   2 +-
 dlls/prntvpt/ticket.c     | 413 ++++++++++++++++++++++++++++++++++++++
 include/prntvpt.h         |  16 ++
 5 files changed, 434 insertions(+), 3 deletions(-)
 create mode 100644 dlls/prntvpt/ticket.c

diff --git a/dlls/prntvpt/Makefile.in b/dlls/prntvpt/Makefile.in
index a3db8760c2..452faa4fbf 100644
--- a/dlls/prntvpt/Makefile.in
+++ b/dlls/prntvpt/Makefile.in
@@ -1,8 +1,9 @@
 MODULE    = prntvpt.dll
 IMPORTLIB = prntvpt
-IMPORTS   = winspool
+IMPORTS   = winspool ole32 oleaut32
 
 EXTRADLLFLAGS = -mno-cygwin
 
 C_SRCS = \
-	main.c
+	main.c \
+	ticket.c
diff --git a/dlls/prntvpt/main.c b/dlls/prntvpt/main.c
index e150308720..ac44cdc1ee 100644
--- a/dlls/prntvpt/main.c
+++ b/dlls/prntvpt/main.c
@@ -24,6 +24,7 @@
 #include "winbase.h"
 #include "wingdi.h"
 #include "winspool.h"
+#include "objbase.h"
 #include "prntvpt.h"
 #include "wine/heap.h"
 #include "wine/debug.h"
diff --git a/dlls/prntvpt/prntvpt.spec b/dlls/prntvpt/prntvpt.spec
index d785bae9c6..ce8a0e591c 100644
--- a/dlls/prntvpt/prntvpt.spec
+++ b/dlls/prntvpt/prntvpt.spec
@@ -5,7 +5,7 @@
 @ stub BindPTProviderThunk
 @ stub PTGetPrintCapabilities
 @ stub PTMergeAndValidatePrintTicket
-@ stub PTConvertPrintTicketToDevMode
+@ stdcall PTConvertPrintTicketToDevMode(ptr ptr long long ptr ptr ptr)
 @ stub PTConvertDevModeToPrintTicket
 @ stdcall PTReleaseMemory(ptr)
 @ stub ConvertDevModeToPrintTicketThunk2
diff --git a/dlls/prntvpt/ticket.c b/dlls/prntvpt/ticket.c
new file mode 100644
index 0000000000..8c0f87699a
--- /dev/null
+++ b/dlls/prntvpt/ticket.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright 2019 Dmitry Timoshkov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#define COBJMACROS
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winspool.h"
+#include "objbase.h"
+#include "prntvpt.h"
+#include "initguid.h"
+#include "msxml2.h"
+#include "wine/heap.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(prntvpt);
+
+struct size
+{
+    int width;
+    int height;
+};
+
+struct media
+{
+    int paper;
+    struct size size;
+};
+
+struct resolution
+{
+    int x;
+    int y;
+};
+
+struct page
+{
+    struct media media;
+    struct resolution resolution;
+    int orientation;
+    int scaling;
+    int color;
+};
+
+struct document
+{
+    int collate;
+};
+
+struct job
+{
+    int nup;
+    int copies;
+    int input_bin;
+};
+
+struct ticket
+{
+    struct job job;
+    struct document document;
+    struct page page;
+};
+
+static const struct
+{
+    const WCHAR *name;
+    int paper;
+} psk_media[] =
+{
+    { L"psk:ISOA4", DMPAPER_A4 },
+};
+
+static int media_to_paper(const WCHAR *name)
+{
+    int i;
+
+    for (i = 0 ; i < ARRAY_SIZE(psk_media); i++)
+        if (!wcscmp(name, psk_media[i].name))
+            return psk_media[i].paper;
+
+    FIXME("%s\n", wine_dbgstr_w(name));
+    return DMPAPER_A4;
+}
+
+static BOOL is_valid_node_name(const WCHAR *name)
+{
+    static const WCHAR * const psf_names[] = { L"psf:ParameterInit", L"psf:Feature" };
+    int i;
+
+    for (i = 0 ; i < ARRAY_SIZE(psf_names); i++)
+        if (!wcscmp(name, psf_names[i])) return TRUE;
+
+    return FALSE;
+}
+
+static HRESULT verify_ticket(IXMLDOMDocument2 *doc)
+{
+    IXMLDOMElement *element;
+    IXMLDOMNode *node = NULL;
+    BSTR str;
+    HRESULT hr;
+
+    hr = IXMLDOMDocument2_get_documentElement(doc, &element);
+    if (hr != S_OK) return E_PRINTTICKET_FORMAT;
+
+    hr = IXMLDOMElement_get_tagName(element, &str);
+    if (hr != S_OK) goto fail;
+    if (wcscmp(str, L"psf:PrintTicket") != 0)
+        hr = E_FAIL;
+    SysFreeString(str);
+    if (hr != S_OK) goto fail;
+
+    hr = IXMLDOMElement_get_firstChild(element, &node);
+    IXMLDOMElement_Release(element);
+    if (hr != S_OK) return S_OK;
+
+    for (;;)
+    {
+        VARIANT var;
+        IXMLDOMNode *next_node;
+
+        hr = IXMLDOMNode_get_nodeName(node, &str);
+        if (hr != S_OK) break;
+        if (!is_valid_node_name(str))
+            hr = E_FAIL;
+        SysFreeString(str);
+        if (hr != S_OK) break;
+
+        hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void **)&element);
+        if (hr != S_OK) break;
+
+        VariantInit(&var);
+        hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
+        IXMLDOMElement_Release(element);
+        if (hr != S_OK) break;
+        if (V_VT(&var) != VT_BSTR)
+            hr = E_FAIL;
+        VariantClear(&var);
+        if (hr != S_OK) break;
+
+        hr = IXMLDOMNode_get_nextSibling(node, &next_node);
+        if (hr != S_OK)
+        {
+            hr = S_OK;
+            break;
+        }
+
+        IXMLDOMNode_Release(node);
+        node = next_node;
+    }
+
+fail:
+    if (node) IXMLDOMNode_Release(node);
+
+    return hr != S_OK ? E_PRINTTICKET_FORMAT : S_OK;
+}
+
+static HRESULT read_int_value(IXMLDOMNode *node, int *value)
+{
+    IXMLDOMNode *val;
+    HRESULT hr;
+    VARIANT var1, var2;
+
+    hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Value[@xsi:type='xsd:integer']", &val);
+    if (hr != S_OK) return hr;
+
+    VariantInit(&var1);
+    hr = IXMLDOMNode_get_nodeTypedValue(val, &var1);
+    if (hr == S_OK)
+    {
+        VariantInit(&var2);
+        hr = VariantChangeTypeEx(&var2, &var1, 0, 0, VT_I4);
+        if (hr == S_OK)
+            *value = V_I4(&var2);
+
+        VariantClear(&var1);
+    }
+
+    IXMLDOMNode_Release(val);
+    return hr;
+}
+
+static void read_PageMediaSize(IXMLDOMDocument2 *doc, struct ticket *ticket)
+{
+    IXMLDOMNode *node, *option, *child;
+    HRESULT hr;
+
+    hr = IXMLDOMDocument2_selectSingleNode(doc, (BSTR)L"psf:PrintTicket/psf:Feature[@name='psk:PageMediaSize']", &node);
+    if (hr != S_OK) return;
+
+    hr = IXMLDOMNode_selectSingleNode(node, (BSTR)L"./psf:Option", &option);
+    if (hr == S_OK)
+    {
+        IXMLDOMElement *element;
+
+        hr = IXMLDOMNode_QueryInterface(option, &IID_IXMLDOMElement, (void **)&element);
+        if (hr == S_OK)
+        {
+            VARIANT var;
+
+            VariantInit(&var);
+            hr = IXMLDOMElement_getAttribute(element, (BSTR)L"name", &var);
+            if (hr == S_OK && V_VT(&var) == VT_BSTR)
+            {
+                ticket->page.media.paper = media_to_paper(V_BSTR(&var));
+                TRACE("paper: %s => %d\n", wine_dbgstr_w(V_BSTR(&var)), ticket->page.media.paper);
+            }
+            VariantClear(&var);
+
+            IXMLDOMElement_Release(element);
+        }
+
+        hr = IXMLDOMNode_selectSingleNode(option, (BSTR)L"./psf:ScoredProperty[@name='psk:MediaSizeWidth']", &child);
+        if (hr == S_OK)
+        {
+            if (read_int_value(child, &ticket->page.media.size.width) == S_OK)
+                TRACE("width: %d\n", ticket->page.media.size.width);
+            IXMLDOMNode_Release(child);
+        }
+
+        hr = IXMLDOMNode_selectSingleNode(option, (BSTR)L"./psf:ScoredProperty[@name='psk:MediaSizeHeight']", &child);
+        if (hr == S_OK)
+        {
+            if (read_int_value(child, &ticket->page.media.size.height) == S_OK)
+                TRACE("height: %d\n", ticket->page.media.size.height);
+            IXMLDOMNode_Release(child);
+        }
+
+        IXMLDOMNode_Release(option);
+    }
+
+    IXMLDOMNode_Release(node);
+}
+
+static void set_SelectionNamespaces(IXMLDOMDocument2 *doc)
+{
+    IStream *stream;
+    IXMLDOMElement *element = NULL;
+    IXMLDOMNamedNodeMap *map = NULL;
+    HRESULT hr;
+    LONG count, i;
+    HGLOBAL hmem;
+    BSTR str;
+    VARIANT var;
+
+    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
+    if (hr != S_OK) return;
+
+    hr = IXMLDOMDocument2_get_documentElement(doc, &element);
+    if (hr != S_OK) goto fail;
+
+    hr = IXMLDOMElement_get_attributes(element, &map);
+    if (hr != S_OK) goto fail;
+
+    hr = IXMLDOMNamedNodeMap_get_length(map, &count);
+    if (hr != S_OK) goto fail;
+
+    for (i = 0; i < count; i++)
+    {
+        IXMLDOMNode *node;
+
+        hr = IXMLDOMNamedNodeMap_get_item(map, i, &node);
+        if (hr == S_OK)
+        {
+            hr = IXMLDOMNode_get_nodeName(node, &str);
+            if (hr == S_OK)
+            {
+                VariantInit(&var);
+                hr = IXMLDOMNode_get_nodeValue(node, &var);
+                if (hr == S_OK)
+                {
+                    if (!wcscmp(str, L"xmlns") || !wcsncmp(str, L"xmlns:", 6))
+                    {
+                        TRACE("ns[%d]: %s=%s\n", i, wine_dbgstr_w(str), wine_dbgstr_w(V_BSTR(&var)));
+                        IStream_Write(stream, str, wcslen(str) * sizeof(WCHAR), NULL);
+                        IStream_Write(stream, L"=\"", 2 * sizeof(WCHAR), NULL);
+                        IStream_Write(stream, V_BSTR(&var), wcslen(V_BSTR(&var)) * sizeof(WCHAR), NULL);
+                        IStream_Write(stream, L"\" ", 2 * sizeof(WCHAR), NULL);
+                    }
+                    VariantClear(&var);
+                }
+                SysFreeString(str);
+            }
+            IXMLDOMNode_Release(node);
+        }
+    }
+
+    IStream_Write(stream, L"", sizeof(WCHAR), NULL);
+
+    hr = GetHGlobalFromStream(stream, &hmem);
+    if (hr != S_OK) goto fail;
+
+    str = GlobalLock(hmem);
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = SysAllocString(str);
+    IXMLDOMDocument2_setProperty(doc, (BSTR)L"SelectionNamespaces", var);
+    SysFreeString(V_BSTR(&var));
+    GlobalUnlock(hmem);
+
+fail:
+    if (map) IXMLDOMNamedNodeMap_Release(map);
+    if (element) IXMLDOMElement_Release(element);
+    IStream_Release(stream);
+}
+
+static HRESULT parse_ticket(IStream *stream, EPrintTicketScope scope, struct ticket *ticket)
+{
+    IXMLDOMDocument2 *doc;
+    VARIANT src;
+    VARIANT_BOOL ret;
+    HRESULT hr;
+
+    hr = CoCreateInstance(&CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER,
+                          &IID_IXMLDOMDocument2, (void **)&doc);
+    if (hr != S_OK) return hr;
+
+    V_VT(&src) = VT_UNKNOWN;
+    V_UNKNOWN(&src) = (IUnknown *)stream;
+    hr = IXMLDOMDocument2_load(doc, src, &ret);
+    if (hr != S_OK) goto fail;
+
+    hr = verify_ticket(doc);
+    if (hr != S_OK) goto fail;
+
+    set_SelectionNamespaces(doc);
+
+    /* PageScope is always added */
+    read_PageMediaSize(doc, ticket);
+
+fail:
+    IXMLDOMDocument2_Release(doc);
+    return hr;
+}
+
+static void ticket_to_devmode(const struct ticket *ticket, DEVMODEW *dm)
+{
+    memset(dm, 0, sizeof(*dm));
+
+    dm->dmSize = sizeof(*dm);
+    dm->dmFields = DM_ORIENTATION | DM_PAPERSIZE | DM_PAPERLENGTH | DM_PAPERWIDTH | DM_SCALE |
+                   DM_COPIES | DM_COLOR | DM_PRINTQUALITY | DM_YRESOLUTION | DM_COLLATE;
+    dm->u1.s1.dmOrientation = ticket->page.orientation;
+    dm->u1.s1.dmPaperSize = ticket->page.media.paper;
+    dm->u1.s1.dmPaperWidth = ticket->page.media.size.width / 100;
+    dm->u1.s1.dmPaperLength = ticket->page.media.size.height / 100;
+    dm->u1.s1.dmScale = ticket->page.scaling;
+    dm->u1.s1.dmCopies = ticket->job.copies;
+    dm->dmColor = ticket->page.color;
+    dm->u1.s1.dmPrintQuality = ticket->page.resolution.x;
+    dm->dmYResolution = ticket->page.resolution.y;
+    dm->dmCollate = ticket->document.collate;
+}
+
+static void initialize_ticket(struct ticket *ticket)
+{
+    ticket->job.nup = 0;
+    ticket->job.copies = 1;
+    ticket->job.input_bin = DMBIN_AUTO;
+    ticket->document.collate = DMCOLLATE_FALSE;
+    ticket->page.media.paper = DMPAPER_A4;
+    ticket->page.media.size.width = 210000;
+    ticket->page.media.size.height = 297000;
+    ticket->page.resolution.x = 600;
+    ticket->page.resolution.y = 600;
+    ticket->page.orientation = DMORIENT_PORTRAIT;
+    ticket->page.scaling = 100;
+    ticket->page.color = DMCOLOR_MONOCHROME;
+}
+
+HRESULT WINAPI PTConvertPrintTicketToDevMode(HPTPROVIDER provider, IStream *stream, EDefaultDevmodeType type,
+                                             EPrintTicketScope scope, ULONG *size, PDEVMODEW *dm, BSTR *error)
+{
+    HRESULT hr;
+    struct ticket ticket;
+
+    TRACE("%p,%p,%d,%d,%p,%p,%p\n", provider, stream, type, scope, size, dm, error);
+
+    if (!provider || !stream || !size || !dm)
+        return E_INVALIDARG;
+
+    initialize_ticket(&ticket);
+
+    hr = parse_ticket(stream, scope, &ticket);
+    if (hr != S_OK) return hr;
+
+    *dm = heap_alloc(sizeof(**dm));
+    if (!dm) return E_OUTOFMEMORY;
+
+    ticket_to_devmode(&ticket, *dm);
+    *size = sizeof(**dm);
+
+    return S_OK;
+}
diff --git a/include/prntvpt.h b/include/prntvpt.h
index a3c28ef6d4..e1855badd1 100644
--- a/include/prntvpt.h
+++ b/include/prntvpt.h
@@ -25,9 +25,25 @@ extern "C" {
 
 DECLARE_HANDLE(HPTPROVIDER);
 
+#define E_PRINTTICKET_FORMAT 0x80040003
+
+typedef enum
+{
+    kPTPageScope,
+    kPTDocumentScope,
+    kPTJobScope
+} EPrintTicketScope;
+
+typedef enum
+{
+    kUserDefaultDevmode,
+    kPrinterDefaultDevmode
+} EDefaultDevmodeType;
+
 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 PTConvertPrintTicketToDevMode(HPTPROVIDER, IStream *, EDefaultDevmodeType, EPrintTicketScope, ULONG *, PDEVMODEW *, BSTR *);
 HRESULT WINAPI PTReleaseMemory(PVOID);
 
 #ifdef __cplusplus
-- 
2.26.2




More information about the wine-devel mailing list