From: Piotr Caban piotr@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_ */
From: Piotr Caban piotr@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
From: Piotr Caban piotr@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
From: Piotr Caban piotr@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
From: Piotr Caban piotr@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; + } }
From: Piotr Caban piotr@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);
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 ==
```suggestion:-0+0 if (sh->devmodes_no - 2 >= 0 && sh->devmodes[sh->devmodes_no - 2].page == ```