Printing using EMF spool files is still missing some features and has some bugs: - ResetDC should generally work on gdi side but is ignored on playback - because of that it wasn't really tested - no support for ExtEscape / Escape yet - DC bounds are incorrect
In order to enable printing using EMF spool files it's needed to change printer print processor to wineps.
-- v3: gdi32: Add GdiIsMetaPrintDC implementation.
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index d09ac4420c3..59f2b8c8cd0 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -237,6 +237,7 @@ typedef struct { WCHAR *port; WCHAR *print_proc; WCHAR *datatype; + DWORD attributes;
CRITICAL_SECTION jobs_cs; struct list jobs; @@ -546,6 +547,17 @@ static WCHAR * reg_query_value(HKEY key, const WCHAR *name) return ret; }
+static DWORD reg_query_dword(HKEY hkey, const WCHAR *name) +{ + DWORD type, val, size = sizeof(size); + + if (RegQueryValueExW(hkey, name, 0, &type, (BYTE*)&val, &size)) + return 0; + if (type != REG_DWORD) + return 0; + return val; +} + static printer_info_t* get_printer_info(const WCHAR *name) { HKEY hkey, hprinter = NULL; @@ -582,6 +594,7 @@ static printer_info_t* get_printer_info(const WCHAR *name) info->port = reg_query_value(hprinter, L"Port"); info->print_proc = reg_query_value(hprinter, L"Print Processor"); info->datatype = reg_query_value(hprinter, L"Datatype"); + info->attributes = reg_query_dword(hprinter, L"Attributes"); RegCloseKey(hprinter);
if (!info->name || !info->port || !info->print_proc || !info->datatype) @@ -3281,6 +3294,7 @@ static DWORD WINAPI fpStartDocPrinter(HANDLE hprinter, DWORD level, BYTE *doc_in { printer_t *printer = (printer_t *)hprinter; DOC_INFO_1W *info = (DOC_INFO_1W *)doc_info; + WCHAR *datatype;
TRACE("(%p %ld %p {pDocName = %s, pOutputFile = %s, pDatatype = %s})\n", hprinter, level, doc_info, debugstr_w(info->pDocName), @@ -3318,6 +3332,21 @@ static DWORD WINAPI fpStartDocPrinter(HANDLE hprinter, DWORD level, BYTE *doc_in return 0; }
+ if (info->pDatatype) + datatype = info->pDatatype; + else if (printer->datatype) + datatype = printer->datatype; + else + datatype = printer->info->datatype; + + if (!datatype || ((printer->info->attributes & PRINTER_ATTRIBUTE_RAW_ONLY) && + wcsicmp(datatype, L"RAW"))) + { + TRACE("non RAW datatype specified on RAW-only printer (%s)\n", debugstr_w(datatype)); + SetLastError(ERROR_INVALID_DATATYPE); + return 0; + } + printer->doc = add_job(printer, info, TRUE); return printer->doc ? printer->doc->id : 0; }
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/provider.c | 243 +++++++++++++++++++++------------------ 1 file changed, 132 insertions(+), 111 deletions(-)
diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index 59f2b8c8cd0..56014461012 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -3290,11 +3290,124 @@ static BOOL WINAPI fpAddJob(HANDLE hprinter, DWORD level, BYTE *data, DWORD size return TRUE; }
+typedef struct { + HMODULE hmod; + WCHAR *name; + BOOL (WINAPI *enum_datatypes)(WCHAR *, WCHAR *, DWORD, + BYTE *, DWORD, DWORD *, DWORD *); + HANDLE (WINAPI *open)(WCHAR *, PRINTPROCESSOROPENDATA *); + BOOL (WINAPI *print)(HANDLE, WCHAR *); + BOOL (WINAPI *close)(HANDLE); +} printproc_t; + +static printproc_t * print_proc_load(const WCHAR *name) +{ + WCHAR *reg_path, path[2 * MAX_PATH]; + printproc_t *ret; + DWORD size, len; + LSTATUS status; + HKEY hkey; + + size = sizeof(fmt_printprocessorsW) + + (wcslen(env_arch.envname) + wcslen(name)) * sizeof(WCHAR); + reg_path = malloc(size); + if (!reg_path) + return NULL; + swprintf(reg_path, size / sizeof(WCHAR), fmt_printprocessorsW, env_arch.envname); + wcscat(reg_path, name); + + status = RegOpenKeyW(HKEY_LOCAL_MACHINE, reg_path, &hkey); + free(reg_path); + if (status != ERROR_SUCCESS) + return NULL; + + if (!fpGetPrintProcessorDirectory(NULL, NULL, 1, (BYTE *)path, sizeof(path), &size)) + { + RegCloseKey(hkey); + return NULL; + } + len = size / sizeof(WCHAR); + path[len - 1] = '\'; + + size = sizeof(path) - len * sizeof(WCHAR); + status = RegQueryValueExW(hkey, L"Driver", NULL, NULL, (BYTE *)(path + len), &size); + RegCloseKey(hkey); + if (status != ERROR_SUCCESS) + return NULL; + + ret = malloc(sizeof(*ret)); + if (!ret) + return NULL; + + TRACE("loading print processor: %s\n", debugstr_w(path)); + + ret->hmod = LoadLibraryW(path); + if (!ret->hmod) + { + free(ret); + return NULL; + } + + ret->enum_datatypes = (void *)GetProcAddress(ret->hmod, "EnumPrintProcessorDatatypesW"); + ret->open = (void *)GetProcAddress(ret->hmod, "OpenPrintProcessor"); + ret->print = (void *)GetProcAddress(ret->hmod, "PrintDocumentOnPrintProcessor"); + ret->close = (void *)GetProcAddress(ret->hmod, "ClosePrintProcessor"); + if (!ret->enum_datatypes || !ret->open || !ret->print || !ret->close) + { + FreeLibrary(ret->hmod); + free(ret); + return NULL; + } + + ret->name = wcsdup(name); + return ret; +} + +static BOOL print_proc_check_datatype(printproc_t *pp, const WCHAR *datatype) +{ + DATATYPES_INFO_1W *types; + DWORD size, no, i; + + if (!datatype) + return FALSE; + + pp->enum_datatypes(NULL, pp->name, 1, NULL, 0, &size, &no); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + return FALSE; + + types = malloc(size); + if (!types) + return FALSE; + + if (!pp->enum_datatypes(NULL, pp->name, 1, (BYTE *)types, size, &size, &no)) + { + free(types); + return FALSE; + } + + for (i = 0; i < no; i++) + { + if (!wcscmp(types[i].pName, datatype)) + break; + } + free(types); + return i < no; +} + +static void print_proc_unload(printproc_t *pp) +{ + FreeLibrary(pp->hmod); + free(pp->name); + free(pp); +} + static DWORD WINAPI fpStartDocPrinter(HANDLE hprinter, DWORD level, BYTE *doc_info) { printer_t *printer = (printer_t *)hprinter; DOC_INFO_1W *info = (DOC_INFO_1W *)doc_info; + BOOL datatype_valid; WCHAR *datatype; + printproc_t *pp;
TRACE("(%p %ld %p {pDocName = %s, pOutputFile = %s, pDatatype = %s})\n", hprinter, level, doc_info, debugstr_w(info->pDocName), @@ -3347,6 +3460,25 @@ static DWORD WINAPI fpStartDocPrinter(HANDLE hprinter, DWORD level, BYTE *doc_in return 0; }
+ pp = print_proc_load(printer->info->print_proc); + if (!pp) + { + WARN("failed to load %s print processor\n", debugstr_w(printer->info->print_proc)); + pp = print_proc_load(L"winprint"); + } + if (!pp) + return 0; + + datatype_valid = print_proc_check_datatype(pp, datatype); + print_proc_unload(pp); + if (!datatype_valid) + { + TRACE("%s datatype not supported by %s\n", debugstr_w(datatype), + debugstr_w(printer->info->print_proc)); + SetLastError(ERROR_INVALID_DATATYPE); + return 0; + } + printer->doc = add_job(printer, info, TRUE); return printer->doc ? printer->doc->id : 0; } @@ -3586,117 +3718,6 @@ static BOOL WINAPI fpGetJob(HANDLE hprinter, DWORD job_id, DWORD level, return ret; }
-typedef struct { - HMODULE hmod; - WCHAR *name; - BOOL (WINAPI *enum_datatypes)(WCHAR *, WCHAR *, DWORD, - BYTE *, DWORD, DWORD *, DWORD *); - HANDLE (WINAPI *open)(WCHAR *, PRINTPROCESSOROPENDATA *); - BOOL (WINAPI *print)(HANDLE, WCHAR *); - BOOL (WINAPI *close)(HANDLE); -} printproc_t; - -static printproc_t * print_proc_load(const WCHAR *name) -{ - WCHAR *reg_path, path[2 * MAX_PATH]; - printproc_t *ret; - DWORD size, len; - LSTATUS status; - HKEY hkey; - - size = sizeof(fmt_printprocessorsW) + - (wcslen(env_arch.envname) + wcslen(name)) * sizeof(WCHAR); - reg_path = malloc(size); - if (!reg_path) - return NULL; - swprintf(reg_path, size / sizeof(WCHAR), fmt_printprocessorsW, env_arch.envname); - wcscat(reg_path, name); - - status = RegOpenKeyW(HKEY_LOCAL_MACHINE, reg_path, &hkey); - free(reg_path); - if (status != ERROR_SUCCESS) - return NULL; - - if (!fpGetPrintProcessorDirectory(NULL, NULL, 1, (BYTE *)path, sizeof(path), &size)) - { - RegCloseKey(hkey); - return NULL; - } - len = size / sizeof(WCHAR); - path[len - 1] = '\'; - - size = sizeof(path) - len * sizeof(WCHAR); - status = RegQueryValueExW(hkey, L"Driver", NULL, NULL, (BYTE *)(path + len), &size); - RegCloseKey(hkey); - if (status != ERROR_SUCCESS) - return NULL; - - ret = malloc(sizeof(*ret)); - if (!ret) - return NULL; - - TRACE("loading print processor: %s\n", debugstr_w(path)); - - ret->hmod = LoadLibraryW(path); - if (!ret->hmod) - { - free(ret); - return NULL; - } - - ret->enum_datatypes = (void *)GetProcAddress(ret->hmod, "EnumPrintProcessorDatatypesW"); - ret->open = (void *)GetProcAddress(ret->hmod, "OpenPrintProcessor"); - ret->print = (void *)GetProcAddress(ret->hmod, "PrintDocumentOnPrintProcessor"); - ret->close = (void *)GetProcAddress(ret->hmod, "ClosePrintProcessor"); - if (!ret->enum_datatypes || !ret->open || !ret->print || !ret->close) - { - FreeLibrary(ret->hmod); - free(ret); - return NULL; - } - - ret->name = wcsdup(name); - return ret; -} - -static BOOL print_proc_check_datatype(printproc_t *pp, const WCHAR *datatype) -{ - DATATYPES_INFO_1W *types; - DWORD size, no, i; - - if (!datatype) - return FALSE; - - pp->enum_datatypes(NULL, pp->name, 1, NULL, 0, &size, &no); - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) - return FALSE; - - types = malloc(size); - if (!types) - return FALSE; - - if (!pp->enum_datatypes(NULL, pp->name, 1, (BYTE *)types, size, &size, &no)) - { - free(types); - return FALSE; - } - - for (i = 0; i < no; i++) - { - if (!wcscmp(types[i].pName, datatype)) - break; - } - free(types); - return i < no; -} - -static void print_proc_unload(printproc_t *pp) -{ - FreeLibrary(pp->hmod); - free(pp->name); - free(pp); -} - static BOOL WINAPI fpScheduleJob(HANDLE hprinter, DWORD job_id) { printer_t *printer = (printer_t *)hprinter;
From: Piotr Caban piotr@codeweavers.com
--- dlls/wineps.drv/printproc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/wineps.drv/printproc.c b/dlls/wineps.drv/printproc.c index 914fc23f69e..9b96b2c1465 100644 --- a/dlls/wineps.drv/printproc.c +++ b/dlls/wineps.drv/printproc.c @@ -3040,6 +3040,7 @@ static BOOL print_metafile(struct pp_data *data, HANDLE hdata) return FALSE;
AbortPath(data->pdev->dev.hdc); + MoveToEx(data->pdev->dev.hdc, 0, 0, NULL); SetBkColor(data->pdev->dev.hdc, RGB(255, 255, 255)); SetBkMode(data->pdev->dev.hdc, OPAQUE); SetMapMode(data->pdev->dev.hdc, MM_TEXT);
From: Piotr Caban piotr@codeweavers.com
--- dlls/gdi32/dc.c | 45 ++++++++++++++++++++++++++++++++++++--------- include/ntgdi.h | 3 +-- 2 files changed, 37 insertions(+), 11 deletions(-)
diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c index 8fa30884baf..6a5bb86d4f1 100644 --- a/dlls/gdi32/dc.c +++ b/dlls/gdi32/dc.c @@ -51,6 +51,11 @@ struct graphics_driver driver_entry_point entry_point; };
+struct print +{ + HANDLE printer; + WCHAR *output; +};
DC_ATTR *get_dc_attr( HDC hdc ) { @@ -200,6 +205,7 @@ HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output, driver_entry_point entry_point = NULL; const WCHAR *display = NULL, *p; WCHAR buf[300], *port = NULL; + struct print *print = NULL; BOOL is_display = FALSE; HANDLE hspool = NULL; DC_ATTR *dc_attr; @@ -249,6 +255,11 @@ HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output, ClosePrinter( hspool ); return 0; } + else if (!(print = HeapAlloc( GetProcessHeap(), 0, sizeof(*print) ))) + { + ClosePrinter( hspool ); + HeapFree( GetProcessHeap(), 0, port ); + }
if (display) { @@ -275,13 +286,15 @@ HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output, memcpy( port, output, output_str.Length ); port[output_str.Length / sizeof(WCHAR)] = 0; } - dc_attr->hspool = HandleToULong( hspool ); - dc_attr->output = (ULONG_PTR)port; + print->printer = hspool; + print->output = port; + dc_attr->print = (UINT_PTR)print; } else if (hspool) { ClosePrinter( hspool ); HeapFree( GetProcessHeap(), 0, port ); + HeapFree( GetProcessHeap(), 0, print ); }
return ret; @@ -392,6 +405,21 @@ DEVMODEW *WINAPI GdiConvertToDevmodeW( const DEVMODEA *dmA ) return dmW; }
+static inline struct print *get_dc_print( DC_ATTR *dc_attr ) +{ + return (struct print *)(UINT_PTR)dc_attr->print; +} + +static void delete_print_dc( DC_ATTR *dc_attr ) +{ + struct print *print = get_dc_print( dc_attr ); + + ClosePrinter( print->printer ); + HeapFree( GetProcessHeap(), 0, print->output ); + HeapFree( GetProcessHeap(), 0, print ); + dc_attr->print = 0; +} + /*********************************************************************** * DeleteDC (GDI32.@) */ @@ -401,10 +429,7 @@ BOOL WINAPI DeleteDC( HDC hdc )
if (is_meta_dc( hdc )) return METADC_DeleteDC( hdc ); if (!(dc_attr = get_dc_attr( hdc ))) return FALSE; - HeapFree( GetProcessHeap(), 0, (WCHAR *)(ULONG_PTR)dc_attr->output ); - dc_attr->output = 0; - if (dc_attr->hspool) ClosePrinter( ULongToHandle(dc_attr->hspool) ); - dc_attr->hspool = 0; + if (dc_attr->print) delete_print_dc( dc_attr ); if (dc_attr->emf) EMFDC_DeleteDC( dc_attr ); return NtGdiDeleteObjectApp( hdc ); } @@ -2192,6 +2217,7 @@ BOOL WINAPI CancelDC(HDC hdc) INT WINAPI StartDocW( HDC hdc, const DOCINFOW *doc ) { WCHAR *output = NULL; + struct print *print; DC_ATTR *dc_attr; ABORTPROC proc; DOCINFOW info; @@ -2218,10 +2244,11 @@ INT WINAPI StartDocW( HDC hdc, const DOCINFOW *doc ) proc = (ABORTPROC)(UINT_PTR)dc_attr->abort_proc; if (proc && !proc( hdc, 0 )) return 0;
- if (dc_attr->hspool) + print = get_dc_print( dc_attr ); + if (print) { - if (!info.lpszOutput) info.lpszOutput = (const WCHAR *)(ULONG_PTR)dc_attr->output; - output = StartDocDlgW( ULongToHandle( dc_attr->hspool ), &info ); + if (!info.lpszOutput) info.lpszOutput = print->output; + output = StartDocDlgW( print->printer, &info ); if (output) info.lpszOutput = output; }
diff --git a/include/ntgdi.h b/include/ntgdi.h index 1aa5cad468f..7d00ced2d19 100644 --- a/include/ntgdi.h +++ b/include/ntgdi.h @@ -198,8 +198,7 @@ typedef struct DC_ATTR RECTL emf_bounds; UINT64 emf; /* client EMF record pointer */ UINT64 abort_proc; /* AbortProc for printing */ - UINT64 hspool; - UINT64 output; + UINT64 print; /* client printer info pointer */ } DC_ATTR;
struct font_enum_entry
From: Piotr Caban piotr@codeweavers.com
--- dlls/gdi32/emfdc.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/dlls/gdi32/emfdc.c b/dlls/gdi32/emfdc.c index 42330a22861..47f48bef9d3 100644 --- a/dlls/gdi32/emfdc.c +++ b/dlls/gdi32/emfdc.c @@ -2384,6 +2384,9 @@ void EMFDC_DeleteDC( DC_ATTR *dc_attr ) struct emf *emf = get_dc_emf( dc_attr ); UINT index;
+ if (emf->dc_brush) DeleteObject( emf->dc_brush ); + if (emf->dc_pen) DeleteObject( emf->dc_pen ); + CloseHandle( emf->file ); HeapFree( GetProcessHeap(), 0, emf->palette ); HeapFree( GetProcessHeap(), 0, emf->emh ); for (index = 0; index < emf->handles_size; index++) @@ -2597,7 +2600,9 @@ HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) RestoreDC( hdc, 1 );
if (emf->dc_brush) DeleteObject( emf->dc_brush ); + emf->dc_brush = 0; if (emf->dc_pen) DeleteObject( emf->dc_pen ); + emf->dc_pen = 0;
emr->emr.iType = EMR_EOF; @@ -2630,6 +2635,7 @@ HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) if (!WriteFile( emf->file, emf->emh, emf->emh->nBytes, NULL, NULL )) { CloseHandle( emf->file ); + emf->file = 0; return 0; } HeapFree( GetProcessHeap(), 0, emf->emh ); @@ -2642,6 +2648,7 @@ HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) }
hmf = EMF_Create_HENHMETAFILE( emf->emh, emf->emh->nBytes, emf->file != 0 ); + emf->file = 0; emf->emh = NULL; /* So it won't be deleted */ DeleteDC( hdc ); return hmf;
From: Piotr Caban piotr@codeweavers.com
--- dlls/gdi32/emfdc.c | 57 +++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 24 deletions(-)
diff --git a/dlls/gdi32/emfdc.c b/dlls/gdi32/emfdc.c index 47f48bef9d3..2e4b0a85de6 100644 --- a/dlls/gdi32/emfdc.c +++ b/dlls/gdi32/emfdc.c @@ -2575,35 +2575,16 @@ HDC WINAPI CreateEnhMetaFileW( HDC hdc, const WCHAR *filename, const RECT *rect, return ret; }
-/****************************************************************** - * CloseEnhMetaFile (GDI32.@) - */ -HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) +static BOOL emf_eof( DC_ATTR *dc_attr ) { + struct emf *emf = get_dc_emf( dc_attr ); UINT size, palette_size; - HENHMETAFILE hmf; - struct emf *emf; - DC_ATTR *dc_attr; EMREOF *emr; - HANDLE mapping = 0; - - TRACE("(%p)\n", hdc ); - - if (!(dc_attr = get_dc_attr( hdc )) || !get_dc_emf( dc_attr )) return 0; - emf = get_dc_emf( dc_attr ); + BOOL ret;
palette_size = emf->palette_used * sizeof(*emf->palette); size = sizeof(*emr) + palette_size; - if (!(emr = HeapAlloc( GetProcessHeap(), 0, size ))) return 0; - - if (dc_attr->save_level) - RestoreDC( hdc, 1 ); - - if (emf->dc_brush) DeleteObject( emf->dc_brush ); - emf->dc_brush = 0; - if (emf->dc_pen) DeleteObject( emf->dc_pen ); - emf->dc_pen = 0; - + if (!(emr = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
emr->emr.iType = EMR_EOF; emr->emr.nSize = size; @@ -2612,8 +2593,9 @@ HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) memcpy( (BYTE *)emr + emr->offPalEntries, emf->palette, palette_size ); /* Set nSizeLast */ ((DWORD *)((BYTE *)emr + size))[-1] = size; - emfdc_record( emf, &emr->emr ); + ret = emfdc_record( emf, &emr->emr ); HeapFree( GetProcessHeap(), 0, emr ); + if (!ret) return FALSE;
emf->emh->rclBounds = dc_attr->emf_bounds;
@@ -2629,6 +2611,33 @@ HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) emf->emh->rclFrame.bottom = emf->emh->rclBounds.bottom * emf->emh->szlMillimeters.cy * 100 / emf->emh->szlDevice.cy; } + return TRUE; +} + +/****************************************************************** + * CloseEnhMetaFile (GDI32.@) + */ +HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) +{ + HENHMETAFILE hmf; + struct emf *emf; + DC_ATTR *dc_attr; + HANDLE mapping = 0; + + TRACE("(%p)\n", hdc ); + + if (!(dc_attr = get_dc_attr( hdc )) || !get_dc_emf( dc_attr )) return 0; + emf = get_dc_emf( dc_attr ); + + if (dc_attr->save_level) + RestoreDC( hdc, 1 ); + + if (emf->dc_brush) DeleteObject( emf->dc_brush ); + emf->dc_brush = 0; + if (emf->dc_pen) DeleteObject( emf->dc_pen ); + emf->dc_pen = 0; + + if (!emf_eof( dc_attr )) return 0;
if (emf->file) /* disk based metafile */ {
From: Piotr Caban piotr@codeweavers.com
--- dlls/gdi32/emfdc.c | 140 +++++++++++++++++++++++++++------------------ 1 file changed, 83 insertions(+), 57 deletions(-)
diff --git a/dlls/gdi32/emfdc.c b/dlls/gdi32/emfdc.c index 2e4b0a85de6..e483b6a3498 100644 --- a/dlls/gdi32/emfdc.c +++ b/dlls/gdi32/emfdc.c @@ -2460,61 +2460,20 @@ HDC WINAPI CreateEnhMetaFileA( HDC hdc, const char *filename, const RECT *rect, return ret; }
-/********************************************************************** - * CreateEnhMetaFileW (GDI32.@) - */ -HDC WINAPI CreateEnhMetaFileW( HDC hdc, const WCHAR *filename, const RECT *rect, - const WCHAR *description ) +static void emf_reset( DC_ATTR *dc_attr, const RECT *rect ) { - HDC ret; - struct emf *emf; - DC_ATTR *dc_attr; - HANDLE file; - DWORD size = 0, length = 0; - - TRACE( "(%p %s %s %s)\n", hdc, debugstr_w(filename), wine_dbgstr_rect(rect), - debugstr_w(description) ); - - if (!(ret = NtGdiCreateMetafileDC( hdc ))) return 0; - - if (!(dc_attr = get_dc_attr( ret )) || !(emf = HeapAlloc( GetProcessHeap(), 0, sizeof(*emf) ))) - { - DeleteDC( ret ); - return 0; - } - - emf->dc_attr = dc_attr; - dc_attr->emf = (UINT_PTR)emf; - - if (description) /* App name\0Title\0\0 */ - { - length = lstrlenW( description ); - length += lstrlenW( description + length + 1 ); - length += 3; - length *= 2; - } - size = sizeof(ENHMETAHEADER) + (length + 3) / 4 * 4; - - if (!(emf->emh = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size))) - { - DeleteDC( ret ); - return 0; - } + struct emf *emf = get_dc_emf( dc_attr ); + HDC hdc = dc_attr_handle( dc_attr );
- emf->handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - HANDLE_LIST_INC * sizeof(emf->handles[0]) ); - emf->handles_size = HANDLE_LIST_INC; + memset( emf->handles, 0, emf->handles_size * sizeof(emf->handles[0]) ); emf->cur_handles = 1; emf->file = 0; + if (emf->dc_brush) DeleteObject( emf->dc_brush ); emf->dc_brush = 0; + if (emf->dc_pen) DeleteObject( emf->dc_pen ); emf->dc_pen = 0; emf->path = FALSE; - emf->palette_size = 0; emf->palette_used = 0; - emf->palette = NULL; - - emf->emh->iType = EMR_HEADER; - emf->emh->nSize = size;
dc_attr->emf_bounds.left = dc_attr->emf_bounds.top = 0; dc_attr->emf_bounds.right = dc_attr->emf_bounds.bottom = -1; @@ -2538,28 +2497,95 @@ HDC WINAPI CreateEnhMetaFileW( HDC hdc, const WCHAR *filename, const RECT *rect, emf->emh->nBytes = emf->emh->nSize; emf->emh->nRecords = 1; emf->emh->nHandles = 1; - emf->emh->sReserved = 0; /* According to docs, this is reserved and must be 0 */ - emf->emh->nDescription = length / 2; - - emf->emh->offDescription = length ? sizeof(ENHMETAHEADER) : 0; - - emf->emh->nPalEntries = 0; /* I guess this should start at 0 */ + emf->emh->nPalEntries = 0;
/* Size in pixels */ - emf->emh->szlDevice.cx = GetDeviceCaps( ret, HORZRES ); - emf->emh->szlDevice.cy = GetDeviceCaps( ret, VERTRES ); + emf->emh->szlDevice.cx = GetDeviceCaps( hdc, HORZRES ); + emf->emh->szlDevice.cy = GetDeviceCaps( hdc, VERTRES );
/* Size in millimeters */ - emf->emh->szlMillimeters.cx = GetDeviceCaps( ret, HORZSIZE ); - emf->emh->szlMillimeters.cy = GetDeviceCaps( ret, VERTSIZE ); + emf->emh->szlMillimeters.cx = GetDeviceCaps( hdc, HORZSIZE ); + emf->emh->szlMillimeters.cy = GetDeviceCaps( hdc, VERTSIZE ); + + emf->emh->cbPixelFormat = 0; + emf->emh->offPixelFormat = 0; + emf->emh->bOpenGL = 0;
/* Size in micrometers */ emf->emh->szlMicrometers.cx = emf->emh->szlMillimeters.cx * 1000; emf->emh->szlMicrometers.cy = emf->emh->szlMillimeters.cy * 1000; +} + +static struct emf *emf_create( HDC hdc, const RECT *rect, const WCHAR *description ) +{ + DWORD size = 0, length = 0; + DC_ATTR *dc_attr; + struct emf *emf; + + if (!(dc_attr = get_dc_attr( hdc )) || !(emf = HeapAlloc( GetProcessHeap(), 0, sizeof(*emf) ))) + return NULL; + + if (description) /* App name\0Title\0\0 */ + { + length = lstrlenW( description ); + length += lstrlenW( description + length + 1 ); + length += 3; + length *= 2; + } + size = sizeof(ENHMETAHEADER) + (length + 3) / 4 * 4; + + if (!(emf->emh = HeapAlloc( GetProcessHeap(), 0, size )) || + !(emf->handles = HeapAlloc( GetProcessHeap(), 0, + HANDLE_LIST_INC * sizeof(emf->handles[0]) ))) + { + HeapFree( GetProcessHeap(), 0, emf->emh ); + HeapFree( GetProcessHeap(), 0, emf ); + return NULL; + } + + emf->dc_attr = dc_attr; + dc_attr->emf = (UINT_PTR)emf; + + emf->handles_size = HANDLE_LIST_INC; + emf->dc_brush = 0; + emf->dc_pen = 0; + emf->palette_size = 0; + emf->palette = NULL; + + emf->emh->iType = EMR_HEADER; + emf->emh->nSize = size; + emf->emh->nDescription = length / 2; + emf->emh->offDescription = length ? sizeof(ENHMETAHEADER) : 0;
memcpy( (char *)emf->emh + sizeof(ENHMETAHEADER), description, length );
+ emf_reset( dc_attr, rect ); + return emf; +} + +/********************************************************************** + * CreateEnhMetaFileW (GDI32.@) + */ +HDC WINAPI CreateEnhMetaFileW( HDC hdc, const WCHAR *filename, const RECT *rect, + const WCHAR *description ) +{ + struct emf *emf; + HANDLE file; + HDC ret; + + TRACE( "(%p %s %s %s)\n", hdc, debugstr_w(filename), wine_dbgstr_rect(rect), + debugstr_w(description) ); + + if (!(ret = NtGdiCreateMetafileDC( hdc ))) return 0; + + emf = emf_create( ret, rect, description ); + if (!emf) + { + DeleteDC( ret ); + return 0; + } + if (filename) /* disk based metafile */ { if ((file = CreateFileW( filename, GENERIC_WRITE | GENERIC_READ, 0,
From: Piotr Caban piotr@codeweavers.com
--- dlls/gdi32/dc.c | 43 ++++++++++ dlls/gdi32/emfdc.c | 181 +++++++++++++++++++++++++++++++++++++++ dlls/gdi32/gdi_private.h | 7 ++ 3 files changed, 231 insertions(+)
diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c index 6a5bb86d4f1..459d0dfb8c1 100644 --- a/dlls/gdi32/dc.c +++ b/dlls/gdi32/dc.c @@ -2216,6 +2216,7 @@ BOOL WINAPI CancelDC(HDC hdc) */ INT WINAPI StartDocW( HDC hdc, const DOCINFOW *doc ) { + DOC_INFO_1W spool_info; WCHAR *output = NULL; struct print *print; DC_ATTR *dc_attr; @@ -2240,6 +2241,7 @@ INT WINAPI StartDocW( HDC hdc, const DOCINFOW *doc ) debugstr_w(info.lpszDatatype), info.fwType);
if (!(dc_attr = get_dc_attr( hdc ))) return SP_ERROR; + if (dc_attr->print && dc_attr->emf) return SP_ERROR;
proc = (ABORTPROC)(UINT_PTR)dc_attr->abort_proc; if (proc && !proc( hdc, 0 )) return 0; @@ -2250,6 +2252,23 @@ INT WINAPI StartDocW( HDC hdc, const DOCINFOW *doc ) if (!info.lpszOutput) info.lpszOutput = print->output; output = StartDocDlgW( print->printer, &info ); if (output) info.lpszOutput = output; + + if (!info.lpszDatatype || !wcsicmp(info.lpszDatatype, L"EMF")) + { + spool_info.pDocName = (WCHAR *)info.lpszDocName; + spool_info.pOutputFile = (WCHAR *)info.lpszOutput; + spool_info.pDatatype = (WCHAR *)L"NT EMF 1.003"; + if ((ret = StartDocPrinterW( print->printer, 1, (BYTE *)&spool_info ))) + { + if (!spool_start_doc( dc_attr, print->printer, &info )) + { + AbortDoc( hdc ); + ret = 0; + } + HeapFree( GetProcessHeap(), 0, output ); + return ret; + } + } }
ret = NtGdiStartDoc( hdc, &info, NULL, 0 ); @@ -2306,6 +2325,12 @@ INT WINAPI StartDocA( HDC hdc, const DOCINFOA *doc ) */ INT WINAPI StartPage( HDC hdc ) { + struct print *print; + DC_ATTR *dc_attr; + + if (!(dc_attr = get_dc_attr( hdc ))) return SP_ERROR; + if ((print = get_dc_print( dc_attr )) && dc_attr->emf) + return spool_start_page( dc_attr, print->printer ); return NtGdiStartPage( hdc ); }
@@ -2314,6 +2339,12 @@ INT WINAPI StartPage( HDC hdc ) */ INT WINAPI EndPage( HDC hdc ) { + struct print *print; + DC_ATTR *dc_attr; + + if (!(dc_attr = get_dc_attr( hdc ))) return SP_ERROR; + if ((print = get_dc_print( dc_attr )) && dc_attr->emf) + return spool_end_page( dc_attr, print->printer ); return NtGdiEndPage( hdc ); }
@@ -2322,6 +2353,12 @@ INT WINAPI EndPage( HDC hdc ) */ INT WINAPI EndDoc( HDC hdc ) { + struct print *print; + DC_ATTR *dc_attr; + + if (!(dc_attr = get_dc_attr( hdc ))) return SP_ERROR; + if ((print = get_dc_print( dc_attr )) && dc_attr->emf) + return spool_end_doc( dc_attr, print->printer ); return NtGdiEndDoc( hdc ); }
@@ -2330,6 +2367,12 @@ INT WINAPI EndDoc( HDC hdc ) */ INT WINAPI AbortDoc( HDC hdc ) { + struct print *print; + DC_ATTR *dc_attr; + + if (!(dc_attr = get_dc_attr( hdc ))) return SP_ERROR; + if ((print = get_dc_print( dc_attr )) && dc_attr->emf) + return spool_abort_doc( dc_attr, print->printer ); return NtGdiAbortDoc( hdc ); }
diff --git a/dlls/gdi32/emfdc.c b/dlls/gdi32/emfdc.c index e483b6a3498..9690bee2a17 100644 --- a/dlls/gdi32/emfdc.c +++ b/dlls/gdi32/emfdc.c @@ -44,8 +44,39 @@ struct emf DWORD palette_size; DWORD palette_used; PALETTEENTRY *palette; + enum + { + DOCUMENT_NOT_STARTED, + NEEDS_START_PAGE, + NEEDS_END_PAGE + } document_state; };
+typedef 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, +} emfspool_record_type; + #define HANDLE_LIST_INC 20 static const RECTL empty_bounds = { 0, 0, -1, -1 };
@@ -2474,6 +2505,7 @@ static void emf_reset( DC_ATTR *dc_attr, const RECT *rect ) emf->dc_pen = 0; emf->path = FALSE; emf->palette_used = 0; + emf->document_state = DOCUMENT_NOT_STARTED;
dc_attr->emf_bounds.left = dc_attr->emf_bounds.top = 0; dc_attr->emf_bounds.right = dc_attr->emf_bounds.bottom = -1; @@ -2688,3 +2720,152 @@ HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) DeleteDC( hdc ); return hmf; } + +BOOL spool_start_doc( DC_ATTR *dc_attr, HANDLE hspool, const DOCINFOW *doc_info ) +{ + struct + { + unsigned int dwVersion; + unsigned int cjSize; + unsigned int dpszDocName; + unsigned int dpszOutput; + } *header; + size_t size = sizeof(*header); + struct emf *emf; + DWORD written; + WCHAR *p; + + TRACE( "(%p %p)\n", dc_attr, hspool ); + + if (doc_info->lpszDocName) + size += (wcslen( doc_info->lpszDocName ) + 1) * sizeof(WCHAR); + if (doc_info->lpszOutput) + size += (wcslen( doc_info->lpszOutput ) + 1) * sizeof(WCHAR); + header = HeapAlloc( GetProcessHeap(), 0, size ); + if (!header) return FALSE; + + header->dwVersion = 0x10000; + header->cjSize = size; + p = (WCHAR *)(header + 1); + if (doc_info->lpszDocName) + { + header->dpszDocName = (BYTE *)p - (BYTE *)header; + wcscpy( p, doc_info->lpszDocName ); + p += wcslen( doc_info->lpszDocName ) + 1; + } + else + { + header->dpszDocName = 0; + } + if (doc_info->lpszOutput) + { + header->dpszOutput = (BYTE *)p - (BYTE *)header; + wcscpy( p, doc_info->lpszOutput ); + } + else + { + header->dpszOutput = 0; + } + if (!WritePrinter( hspool, header, size, &written )) written = 0; + HeapFree( GetProcessHeap(), 0, header ); + if (written != size) return FALSE; + + emf = emf_create( dc_attr_handle(dc_attr), NULL, NULL ); + if (!emf) return FALSE; + emf->document_state = NEEDS_START_PAGE; + return TRUE; +} + +int spool_start_page( DC_ATTR *dc_attr, HANDLE hspool ) +{ + struct emf *emf = get_dc_emf( dc_attr ); + HDC hdc = dc_attr_handle( dc_attr ); + POINT pos = { 0 }; + XFORM xform; + + TRACE( "(%p)\n", dc_attr ); + + /* Save current DC state to EMF */ + /* FIXME: SetTextJustification if needed */ + EMFDC_SelectObject( dc_attr, GetCurrentObject(hdc, OBJ_PEN) ); + EMFDC_SelectObject( dc_attr, GetCurrentObject(hdc, OBJ_BRUSH) ); + EMFDC_SelectObject( dc_attr, GetCurrentObject(hdc, OBJ_FONT) ); + if (GetBkColor( hdc ) != 0xffffff) + EMFDC_SetBkColor( dc_attr, GetBkColor(hdc) ); + if (GetBkMode( hdc ) != OPAQUE) + EMFDC_SetBkMode( dc_attr, GetBkMode(hdc) ); + GetCurrentPositionEx( hdc, &pos ); + if (pos.x || pos.y) + EMFDC_MoveTo( dc_attr, pos.x, pos.y ); + if (GetMapMode( hdc ) != MM_TEXT) + EMFDC_SetMapMode( dc_attr, GetMapMode(hdc) ); + if (GetPolyFillMode( hdc ) != ALTERNATE) + EMFDC_SetPolyFillMode( dc_attr, GetPolyFillMode(hdc) ); + if (GetROP2( hdc ) != R2_COPYPEN) + EMFDC_SetROP2( dc_attr, GetROP2(hdc) ); + if (GetStretchBltMode( hdc ) != BLACKONWHITE) + EMFDC_SetStretchBltMode( dc_attr, GetStretchBltMode(hdc) ); + if (GetTextAlign( hdc ) != (TA_LEFT | TA_TOP)) + EMFDC_SetTextAlign( dc_attr, GetTextAlign(hdc) ); + if (GetTextColor( hdc )) + EMFDC_SetTextColor( dc_attr, GetTextColor(hdc) ); + GetWorldTransform(hdc, &xform); + if (xform.eM11 != 1 || xform.eM22 != 1 || xform.eM12 || xform.eM21 || xform.eDx || xform.eDy) + EMFDC_SetWorldTransform( dc_attr, &xform ); + + emf->document_state = NEEDS_END_PAGE; + return StartPagePrinter( hspool ); +} + +int spool_end_page( DC_ATTR *dc_attr, HANDLE hspool ) +{ + struct record_hdr + { + unsigned int ulID; + unsigned int cjSize; + } record_hdr; + struct + { + struct record_hdr hdr; + LARGE_INTEGER pos; + } metafile_ext; + struct emf *emf = get_dc_emf( dc_attr ); + DWORD written; + + TRACE( "(%p %p)\n", dc_attr, hspool ); + + if (!emf_eof( dc_attr )) return 0; + + record_hdr.ulID = EMRI_METAFILE_DATA; + record_hdr.cjSize = emf->emh->nBytes; + if (!WritePrinter( hspool, &record_hdr, sizeof(record_hdr), &written )) return 0; + if (!WritePrinter( hspool, emf->emh, emf->emh->nBytes, &written )) return 0; + + metafile_ext.hdr.ulID = EMRI_METAFILE_EXT; + metafile_ext.hdr.cjSize = sizeof(metafile_ext) - sizeof(struct record_hdr); + metafile_ext.pos.QuadPart = emf->emh->nBytes + sizeof(record_hdr); + if (!WritePrinter( hspool, &metafile_ext, sizeof(metafile_ext), &written )) return 0; + + emf_reset( dc_attr, NULL ); + emf->document_state = NEEDS_START_PAGE; + return EndPagePrinter( hspool ); +} + +int spool_abort_doc( DC_ATTR *dc_attr, HANDLE hspool ) +{ + TRACE( "(%p %p)\n", dc_attr, hspool ); + + EMFDC_DeleteDC( dc_attr ); + return AbortPrinter( hspool ); +} + +int spool_end_doc( DC_ATTR *dc_attr, HANDLE hspool ) +{ + struct emf *emf = get_dc_emf( dc_attr ); + + TRACE( "(%p %p)\n", dc_attr, hspool ); + + if (emf->document_state == NEEDS_END_PAGE) spool_end_page( dc_attr, hspool ); + EMFDC_DeleteDC( dc_attr ); + return EndDocPrinter( hspool ); +} diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index 4a9c70dcbc3..157e438c687 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -280,6 +280,13 @@ extern BOOL EMFDC_WidenPath( DC_ATTR *dc_attr ) DECLSPEC_HIDDEN; extern HENHMETAFILE EMF_Create_HENHMETAFILE( ENHMETAHEADER *emh, DWORD filesize, BOOL on_disk ) DECLSPEC_HIDDEN;
+extern BOOL spool_start_doc( DC_ATTR *dc_attr, HANDLE hspool, + const DOCINFOW *doc_info ) DECLSPEC_HIDDEN; +extern int spool_start_page( DC_ATTR *dc_attr, HANDLE hspool ) DECLSPEC_HIDDEN; +extern int spool_end_page( DC_ATTR *dc_attr, HANDLE hspool ) DECLSPEC_HIDDEN; +extern int spool_end_doc( DC_ATTR *dc_attr, HANDLE hspool ) DECLSPEC_HIDDEN; +extern int spool_abort_doc( DC_ATTR *dc_attr, HANDLE hspool ) DECLSPEC_HIDDEN; + static inline int get_dib_stride( int width, int bpp ) { return ((width * bpp + 31) >> 3) & ~3;
From: Piotr Caban piotr@codeweavers.com
--- dlls/gdi32/dc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c index 459d0dfb8c1..011bded3523 100644 --- a/dlls/gdi32/dc.c +++ b/dlls/gdi32/dc.c @@ -2408,8 +2408,12 @@ INT WINAPI SetICMMode( HDC hdc, INT mode ) */ BOOL WINAPI GdiIsMetaPrintDC( HDC hdc ) { - FIXME( "%p\n", hdc ); - return FALSE; + DC_ATTR *dc_attr; + + TRACE( "%p\n", hdc ); + + if (!(dc_attr = get_dc_attr( hdc ))) return FALSE; + return dc_attr->print && dc_attr->emf; }
/***********************************************************************
On Thu Apr 27 14:29:49 2023 +0000, Piotr Caban wrote:
It looks like 18961d8fe3993ee6065496b4f8d059ed0f85efe7 needs some more work - StartPage should be also called if direct printing / RAW spooling is used. I will remove this patch for now.
Ok, sounds good.