[PATCH 0/6] MR4075: wineps.drv: Use first page DEVMODE to determine number of copies and collation.
From: Piotr Caban <piotr(a)codeweavers.com> --- include/Makefile.in | 1 + include/winppi.h | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 include/winppi.h diff --git a/include/Makefile.in b/include/Makefile.in index ef0c48ed9ef..4fdee0c9b91 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -936,6 +936,7 @@ SOURCES = \ winnt.h \ winnt.rh \ winperf.h \ + winppi.h \ winreg.h \ winresrc.h \ winsafer.h \ diff --git a/include/winppi.h b/include/winppi.h new file mode 100644 index 00000000000..0cb04593c08 --- /dev/null +++ b/include/winppi.h @@ -0,0 +1,39 @@ +/* + * Copyright 2023 Piotr Caban for CodeWeavers + * + * 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 + */ + +#ifndef _WINPPI_ +#define _WINPPI_ + +HANDLE WINAPI GdiGetSpoolFileHandle(LPWSTR pwszPrinterName, + LPDEVMODEW pDevmode, LPWSTR pwszDocName); +BOOL WINAPI GdiDeleteSpoolFileHandle(HANDLE SpoolFileHandle); +DWORD WINAPI GdiGetPageCount(HANDLE SpoolFileHandle); +HDC WINAPI GdiGetDC(HANDLE SpoolFileHandle); +HANDLE WINAPI GdiGetPageHandle(HANDLE SpoolFileHandle, + DWORD Page, LPDWORD pdwPageType); +BOOL WINAPI GdiStartDocEMF(HANDLE SpoolFileHandle, DOCINFOW *pDocInfo); +BOOL WINAPI GdiStartPageEMF(HANDLE SpoolFileHandle); +BOOL WINAPI GdiPlayPageEMF(HANDLE SpoolFileHandle, HANDLE hemf, + RECT *prectDocument, RECT *prectBorder, RECT *prectClip); +BOOL WINAPI GdiEndPageEMF(HANDLE SpoolFileHandle, DWORD dwOptimization); +BOOL WINAPI GdiEndDocEMF(HANDLE SpoolFileHandle); +BOOL WINAPI GdiGetDevmodeForPage(HANDLE SpoolFileHandle, DWORD dwPageNumber, + PDEVMODEW *pCurrDM, PDEVMODEW *pLastDM); +BOOL WINAPI GdiResetDCEMF(HANDLE SpoolFileHandle, PDEVMODEW pCurrDM); + +#endif /* _WINPPI_ */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4075
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/gdi32/dc.c | 10 ++++++++++ dlls/gdi32/gdi32.spec | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c index 21005fa0719..3023f02eb79 100644 --- a/dlls/gdi32/dc.c +++ b/dlls/gdi32/dc.c @@ -2663,3 +2663,13 @@ ULONG WINAPI DdQueryDisplaySettingsUniqueness(void) if (!warn_once++) FIXME( "stub\n" ); return 0; } + +/******************************************************************* + * GdiGetSpoolFileHandle (GDI32.@) + */ +HANDLE WINAPI GdiGetSpoolFileHandle( WCHAR *printer_name, + DEVMODEW *devmode, WCHAR *doc_name ) +{ + FIXME( "%s %p %s\n", wine_dbgstr_w(printer_name), devmode, wine_dbgstr_w(doc_name) ); + return NULL; +} diff --git a/dlls/gdi32/gdi32.spec b/dlls/gdi32/gdi32.spec index 84c294c286f..6045f3c454a 100644 --- a/dlls/gdi32/gdi32.spec +++ b/dlls/gdi32/gdi32.spec @@ -198,7 +198,7 @@ @ stub GdiGetLocalFont # @ stub GdiGetPageCount # @ stub GdiGetPageHandle -# @ stub GdiGetSpoolFileHandle +@ stdcall GdiGetSpoolFileHandle(wstr ptr wstr) @ stdcall GdiGetSpoolMessage(ptr long ptr long) NtGdiGetSpoolMessage @ stdcall GdiGradientFill(long ptr long ptr long long) @ stdcall GdiInitSpool() NtGdiInitSpool -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4075
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/gdi32/dc.c | 9 +++++++++ dlls/gdi32/gdi32.spec | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c index 3023f02eb79..458a58f8ee5 100644 --- a/dlls/gdi32/dc.c +++ b/dlls/gdi32/dc.c @@ -2673,3 +2673,12 @@ HANDLE WINAPI GdiGetSpoolFileHandle( WCHAR *printer_name, FIXME( "%s %p %s\n", wine_dbgstr_w(printer_name), devmode, wine_dbgstr_w(doc_name) ); return NULL; } + +/******************************************************************* + * GdiDeleteSpoolFileHandle (GDI32.@) + */ +BOOL WINAPI GdiDeleteSpoolFileHandle( HANDLE h ) +{ + FIXME( "%p\n", h ); + return FALSE; +} diff --git a/dlls/gdi32/gdi32.spec b/dlls/gdi32/gdi32.spec index 6045f3c454a..c64af92301a 100644 --- a/dlls/gdi32/gdi32.spec +++ b/dlls/gdi32/gdi32.spec @@ -177,7 +177,7 @@ @ stub GdiDciSetDestination @ stub GdiDeleteLocalDC @ stub GdiDeleteLocalObject -# @ stub GdiDeleteSpoolFileHandle +@ stdcall GdiDeleteSpoolFileHandle(ptr) @ stdcall GdiDescribePixelFormat(long long long ptr) NtGdiDescribePixelFormat @ stdcall GdiDllInitialize(ptr long ptr) @ stdcall GdiDrawStream(long long ptr) NtGdiDrawStream -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4075
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/gdi32/dc.c | 9 +++++++++ dlls/gdi32/gdi32.spec | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c index 458a58f8ee5..106dbe4deba 100644 --- a/dlls/gdi32/dc.c +++ b/dlls/gdi32/dc.c @@ -2682,3 +2682,12 @@ BOOL WINAPI GdiDeleteSpoolFileHandle( HANDLE h ) FIXME( "%p\n", h ); return FALSE; } + +/******************************************************************* + * GdiGetDevmodeForPage (GDI32.@) + */ +BOOL WINAPI GdiGetDevmodeForPage( HANDLE h, DWORD page, DEVMODEW **cur, DEVMODEW **prev ) +{ + FIXME( "%p %ld %p %p\n", h, page, cur, prev ); + return FALSE; +} diff --git a/dlls/gdi32/gdi32.spec b/dlls/gdi32/gdi32.spec index c64af92301a..0ad47111eaa 100644 --- a/dlls/gdi32/gdi32.spec +++ b/dlls/gdi32/gdi32.spec @@ -191,7 +191,7 @@ @ stdcall GdiGetCharDimensions(long ptr ptr) @ stdcall GdiGetCodePage(long) # @ stub GdiGetDC -# @ stub GdiGetDevmodeForPage +@ stdcall GdiGetDevmodeForPage(ptr long ptr ptr) @ stub GdiGetLocalBitmap @ stub GdiGetLocalBrush @ stub GdiGetLocalDC -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4075
From: Piotr Caban <piotr(a)codeweavers.com> --- dlls/gdi32/dc.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 208 insertions(+), 6 deletions(-) diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c index 106dbe4deba..69eb4ebce3c 100644 --- a/dlls/gdi32/dc.c +++ b/dlls/gdi32/dc.c @@ -25,6 +25,7 @@ #include "ntuser.h" #include "ddrawgdi.h" #include "winnls.h" +#include "winppi.h" #include "wine/list.h" #include "wine/debug.h" @@ -68,6 +69,47 @@ struct print DEVMODEW *devmode; }; +BOOL WINAPI SeekPrinter( HANDLE, LARGE_INTEGER, LARGE_INTEGER*, DWORD, BOOL ); + +enum +{ + EMRI_METAFILE = 1, + EMRI_ENGINE_FONT, + EMRI_DEVMODE, + EMRI_TYPE1_FONT, + EMRI_PRESTARTPAGE, + EMRI_DESIGNVECTOR, + EMRI_SUBSET_FONT, + EMRI_DELTA_FONT, + EMRI_FORM_METAFILE, + EMRI_BW_METAFILE, + EMRI_BW_FORM_METAFILE, + EMRI_METAFILE_DATA, + EMRI_METAFILE_EXT, + EMRI_BW_METAFILE_EXT, + EMRI_ENGINE_FONT_EXT, + EMRI_TYPE1_FONT_EXT, + EMRI_DESIGNVECTOR_EXT, + EMRI_SUBSET_FONT_EXT, + EMRI_DELTA_FONT_EXT, + EMRI_PS_JOB_DATA, + EMRI_EMBED_FONT_EXT, + EMRI_HEADER = 65536 +}; + +struct spool_handle +{ + HANDLE spool; + + int devmodes_no; + int devmodes_size; + struct + { + int page; + DEVMODEW *devmode; + } *devmodes; +}; + DC_ATTR *get_dc_attr( HDC hdc ) { DWORD type = gdi_handle_type( hdc ); @@ -2670,8 +2712,41 @@ ULONG WINAPI DdQueryDisplaySettingsUniqueness(void) HANDLE WINAPI GdiGetSpoolFileHandle( WCHAR *printer_name, DEVMODEW *devmode, WCHAR *doc_name ) { - FIXME( "%s %p %s\n", wine_dbgstr_w(printer_name), devmode, wine_dbgstr_w(doc_name) ); - return NULL; + struct spool_handle *ret; + HANDLE spool; + + TRACE( "%s %p %s\n", wine_dbgstr_w(printer_name), devmode, wine_dbgstr_w(doc_name) ); + + if (!devmode) return NULL; + if (!OpenPrinterW( doc_name, &spool, NULL )) return NULL; + + ret = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret) ); + if (!ret) + { + ClosePrinter( spool ); + return NULL; + } + ret->spool = spool; + + ret->devmodes = HeapAlloc( GetProcessHeap(), 0, sizeof(*ret->devmodes) * 8); + if (!ret->devmodes) + { + GdiDeleteSpoolFileHandle( ret ); + return NULL; + } + ret->devmodes_size = 8; + + ret->devmodes[0].devmode = HeapAlloc( GetProcessHeap(), 0, + devmode->dmSize + devmode->dmDriverExtra ); + if (!ret->devmodes[0].devmode) + { + GdiDeleteSpoolFileHandle( ret ); + return NULL; + } + memcpy( ret->devmodes[0].devmode, devmode, devmode->dmSize + devmode->dmDriverExtra ); + ret->devmodes[0].page = 0; + ret->devmodes_no = 1; + return ret; } /******************************************************************* @@ -2679,8 +2754,108 @@ HANDLE WINAPI GdiGetSpoolFileHandle( WCHAR *printer_name, */ BOOL WINAPI GdiDeleteSpoolFileHandle( HANDLE h ) { - FIXME( "%p\n", h ); - return FALSE; + struct spool_handle *sh = (struct spool_handle *)h; + int i; + + TRACE( "%p\n", h ); + + if (!sh) + return FALSE; + + ClosePrinter( sh->spool ); + for (i = 0; i < sh->devmodes_no; i++) + HeapFree( GetProcessHeap(), 0, sh->devmodes[i].devmode ); + HeapFree( GetProcessHeap(), 0, sh->devmodes ); + return TRUE; +} + +static BOOL read_emfspool_record( struct spool_handle *sh ) +{ + struct record_hdr + { + unsigned int ulID; + unsigned int cjSize; + } hdr; + LARGE_INTEGER pos; + BOOL ret; + DWORD r; + + if (!sh->spool) return FALSE; + + ret = ReadPrinter( sh->spool, &hdr, sizeof(hdr), &r ); + if (!ret || r != sizeof(hdr)) + { + ClosePrinter( sh->spool ); + sh->spool = NULL; + return FALSE; + } + TRACE( "parsing record %u\n", hdr.ulID ); + + if (hdr.ulID == EMRI_HEADER) + hdr.cjSize -= sizeof(hdr); + + switch (hdr.ulID) + { + case EMRI_DEVMODE: + /* remove unused devmode */ + if (sh->devmodes - 2 >= 0 && sh->devmodes[sh->devmodes_no - 2].page == + sh->devmodes[sh->devmodes_no - 1].page) + { + HeapFree( GetProcessHeap(), 0, sh->devmodes[sh->devmodes_no - 1].devmode ); + sh->devmodes_no--; + } + else if (sh->devmodes_no == sh->devmodes_size) + { + void *alloc = HeapReAlloc( GetProcessHeap(), 0, sh->devmodes, sh->devmodes_size * 2 ); + + if (!alloc) + { + ClosePrinter( sh->spool ); + sh->spool = NULL; + return FALSE; + } + sh->devmodes = alloc; + sh->devmodes_size *= 2; + } + + sh->devmodes[sh->devmodes_no].devmode = HeapAlloc( GetProcessHeap(), 0, hdr.cjSize ); + if (!sh->devmodes[sh->devmodes_no].devmode) + { + ClosePrinter( sh->spool ); + sh->spool = NULL; + return FALSE; + } + + ret = ReadPrinter( sh->spool, sh->devmodes[sh->devmodes_no].devmode, hdr.cjSize, &r ); + if (!ret || r != hdr.cjSize) + { + ClosePrinter( sh->spool ); + sh->spool = NULL; + return FALSE; + } + sh->devmodes[sh->devmodes_no].page = sh->devmodes[sh->devmodes_no - 1].page; + sh->devmodes_no++; + return TRUE; + + case EMRI_METAFILE: + case EMRI_FORM_METAFILE: + case EMRI_BW_METAFILE: + case EMRI_BW_FORM_METAFILE: + case EMRI_METAFILE_EXT: + case EMRI_BW_METAFILE_EXT: + sh->devmodes[sh->devmodes_no - 1].page++; + /* fall through */ + default: + pos.QuadPart = hdr.cjSize; + ret = SeekPrinter( sh->spool, pos, NULL, FILE_CURRENT, FALSE ); + if (!ret) + { + ClosePrinter( sh->spool ); + sh->spool = NULL; + return FALSE; + } + return TRUE; + } } /******************************************************************* @@ -2688,6 +2863,33 @@ BOOL WINAPI GdiDeleteSpoolFileHandle( HANDLE h ) */ BOOL WINAPI GdiGetDevmodeForPage( HANDLE h, DWORD page, DEVMODEW **cur, DEVMODEW **prev ) { - FIXME( "%p %ld %p %p\n", h, page, cur, prev ); - return FALSE; + struct spool_handle *sh = (struct spool_handle *)h; + int i; + + TRACE( "%p %ld %p %p\n", h, page, cur, prev ); + + if (!sh) + return FALSE; + + i = 0; + while (1) + { + if (sh->devmodes[i].page >= page) + { + if (cur) *cur = sh->devmodes[i].devmode; + if (prev) + { + if (!i || sh->devmodes[i - 1].page != page - 1) + *prev = sh->devmodes[i].devmode; + else + *prev = sh->devmodes[i - 1].devmode; + } + return TRUE; + } + + if (i + 1 < sh->devmodes_no) + i++; + else if (!read_emfspool_record( sh )) + return FALSE; + } } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4075
From: Piotr Caban <piotr(a)codeweavers.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55718 --- dlls/wineps.drv/printproc.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index 3de05eea3f5..5f852130ea1 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -23,6 +23,7 @@ #include <windows.h> #include <ntgdi.h> +#include <winppi.h> #include <winspool.h> #include <ddk/winsplp.h> #include <usp10.h> @@ -40,6 +41,7 @@ struct pp_data { DWORD magic; HANDLE hport; + WCHAR *port; WCHAR *doc_name; WCHAR *out_file; @@ -2980,6 +2982,7 @@ HANDLE WINAPI OpenPrintProcessor(WCHAR *port, PRINTPROCESSOROPENDATA *open_data) return NULL; data->magic = PP_MAGIC; data->hport = hport; + data->port = wcsdup(port); data->doc_name = wcsdup(open_data->pDocumentName); data->out_file = wcsdup(open_data->pOutputFile); @@ -3003,6 +3006,7 @@ HANDLE WINAPI OpenPrintProcessor(WCHAR *port, PRINTPROCESSOROPENDATA *open_data) BOOL WINAPI PrintDocumentOnPrintProcessor(HANDLE pp, WCHAR *doc_name) { struct pp_data *data = get_handle_data(pp); + DEVMODEW *devmode = NULL; emfspool_header header; LARGE_INTEGER pos, cur; record_hdr record; @@ -3016,6 +3020,22 @@ BOOL WINAPI PrintDocumentOnPrintProcessor(HANDLE pp, WCHAR *doc_name) if (!data) return FALSE; + spool_data = GdiGetSpoolFileHandle(data->port, + &data->ctx->Devmode->dmPublic, doc_name); + GdiGetDevmodeForPage(spool_data, 1, &devmode, NULL); + if (devmode && devmode->dmFields & DM_COPIES) + { + FIXME("setting number of copies: %d\n", devmode->dmCopies); + data->ctx->Devmode->dmPublic.dmFields |= DM_COPIES; + data->ctx->Devmode->dmPublic.dmCopies = devmode->dmCopies; + } + if (devmode && devmode->dmFields & DM_COLLATE) + { + data->ctx->Devmode->dmPublic.dmFields |= DM_COLLATE; + data->ctx->Devmode->dmPublic.dmCollate = devmode->dmCollate; + } + GdiDeleteSpoolFileHandle(spool_data); + if (!OpenPrinterW(doc_name, &spool_data, NULL)) return FALSE; @@ -3166,6 +3186,7 @@ BOOL WINAPI ClosePrintProcessor(HANDLE pp) return FALSE; ClosePrinter(data->hport); + free(data->port); free(data->doc_name); free(data->out_file); DeleteDC(data->ctx->hdc); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/4075
Hi, It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated. The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=138635 Your paranoid android. === debian11 (build log) === error: patch failed: dlls/gdi32/dc.c:2673 error: patch failed: dlls/gdi32/dc.c:2682 error: patch failed: dlls/gdi32/dc.c:2670 Task: Patch failed to apply === debian11b (build log) === error: patch failed: dlls/gdi32/dc.c:2673 error: patch failed: dlls/gdi32/dc.c:2682 error: patch failed: dlls/gdi32/dc.c:2670 Task: Patch failed to apply
Huw Davies (@huw) commented about dlls/gdi32/dc.c:
+ if (!ret || r != sizeof(hdr)) + { + ClosePrinter( sh->spool ); + sh->spool = NULL; + return FALSE; + } + TRACE( "parsing record %u\n", hdr.ulID ); + + if (hdr.ulID == EMRI_HEADER) + hdr.cjSize -= sizeof(hdr); + + switch (hdr.ulID) + { + case EMRI_DEVMODE: + /* remove unused devmode */ + if (sh->devmodes - 2 >= 0 && sh->devmodes[sh->devmodes_no - 2].page ==
if (sh->devmodes_no - 2 >= 0 && sh->devmodes[sh->devmodes_no - 2].page ==
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/4075#note_48348
participants (4)
-
Huw Davies (@huw) -
Marvin -
Piotr Caban -
Piotr Caban (@piotr)