From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/Makefile.in | 2 + dlls/localspl/cups.c | 288 ++++++++++++++++++++++++++++++- dlls/localspl/localmon.c | 24 ++- dlls/localspl/localspl_private.h | 2 + dlls/localspl/provider.c | 3 +- 5 files changed, 310 insertions(+), 9 deletions(-)
diff --git a/dlls/localspl/Makefile.in b/dlls/localspl/Makefile.in index 61ca097d9e4..837467211ef 100644 --- a/dlls/localspl/Makefile.in +++ b/dlls/localspl/Makefile.in @@ -1,6 +1,8 @@ MODULE = localspl.dll UNIXLIB = localspl.so IMPORTS = spoolss user32 advapi32 +UNIX_CFLAGS = $(CUPS_CFLAGS) +UNIX_LIBS = $(APPLICATIONSERVICES_LIBS)
EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/localspl/cups.c b/dlls/localspl/cups.c index 47362c1f138..bc0f9c1d317 100644 --- a/dlls/localspl/cups.c +++ b/dlls/localspl/cups.c @@ -27,10 +27,14 @@ #include <stdarg.h> #include <stdlib.h> #include <unistd.h> +#include <dlfcn.h> #include <fcntl.h> #include <errno.h> #include <signal.h> #include <sys/wait.h> +#ifdef HAVE_CUPS_CUPS_H +#include <cups/cups.h> +#endif
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -40,6 +44,32 @@
WINE_DEFAULT_DEBUG_CHANNEL(localspl);
+#ifdef SONAME_LIBCUPS + +static void *libcups_handle; + +#define CUPS_FUNCS \ + DO_FUNC(cupsAddOption); \ + DO_FUNC(cupsCreateJob); \ + DO_FUNC(cupsFinishDocument); \ + DO_FUNC(cupsFreeDests); \ + DO_FUNC(cupsFreeOptions); \ + DO_FUNC(cupsGetOption); \ + DO_FUNC(cupsParseOptions); \ + DO_FUNC(cupsStartDocument); \ + DO_FUNC(cupsWriteRequestData) +#define CUPS_OPT_FUNCS \ + DO_FUNC(cupsGetNamedDest); \ + DO_FUNC(cupsLastErrorString) + +#define DO_FUNC(f) static typeof(f) *p##f +CUPS_FUNCS; +#undef DO_FUNC +static cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *); +static const char * (*pcupsLastErrorString)(void); + +#endif /* SONAME_LIBCUPS */ + typedef struct _doc_t { BOOL (*write_doc)(struct _doc_t *, const BYTE *buf, unsigned int size); @@ -56,6 +86,23 @@ typedef struct _doc_t { int fd; } unixname; + struct + { + char *queue; + char *doc_title; + enum + { + doc_parse_header = 0, + doc_parse_options, + doc_create_job, + doc_initialized, + } state; + BOOL restore_ps_header; + int num_options; + cups_option_t *options; + int buf_len; + char buf[257]; /* DSC max of 256 + '\0' */ + } cups; }; } doc_t;
@@ -178,10 +225,242 @@ static BOOL lpr_start_doc(doc_t *doc, const WCHAR *printer_name) return pipe_start_doc(doc, cmd); }
+#ifdef SONAME_LIBCUPS +static int get_cups_default_options(const char *printer, int num_options, cups_option_t **options) +{ + cups_dest_t *dest; + int i; + + if (!pcupsGetNamedDest) return num_options; + + dest = pcupsGetNamedDest(NULL, printer, NULL); + if (!dest) return num_options; + + for (i = 0; i < dest->num_options; i++) + { + if (!pcupsGetOption(dest->options[i].name, num_options, *options)) + num_options = pcupsAddOption(dest->options[i].name, + dest->options[i].value, num_options, options); + } + + pcupsFreeDests(1, dest); + return num_options; +} + +static BOOL cups_gets(doc_t *doc, const BYTE **buf, unsigned int *size) +{ + BYTE b; + + while(doc->cups.buf_len < sizeof(doc->cups.buf) && *size) + { + b = (*buf)[0]; + doc->cups.buf[doc->cups.buf_len++] = b; + (*buf)++; + (*size)--; + + if (b == '\n') + return TRUE; + } + return FALSE; +} + +static BOOL cups_write(const char *buf, unsigned int size) +{ + if (!size) + return TRUE; + + if (pcupsWriteRequestData(CUPS_HTTP_DEFAULT, buf, size) != HTTP_STATUS_CONTINUE) + { + if (pcupsLastErrorString) + WARN("cupsWriteRequestData failed: %s\n", debugstr_a(pcupsLastErrorString())); + return FALSE; + } + return TRUE; +} + +static BOOL cups_write_doc(doc_t *doc, const BYTE *buf, unsigned int size) +{ + const char ps_adobe[] = "%!PS-Adobe-3.0\n"; + const char cups_job[] = "%cupsJobTicket:"; + + if (doc->cups.state == doc_parse_header) + { + if (!cups_gets(doc, &buf, &size)) + { + if (doc->cups.buf_len != sizeof(doc->cups.buf)) + return TRUE; + doc->cups.state = doc_create_job; + } + else if (!strncmp(doc->cups.buf, ps_adobe, sizeof(ps_adobe) - 1)) + { + doc->cups.restore_ps_header = TRUE; + doc->cups.state = doc_parse_options; + doc->cups.buf_len = 0; + } + else + { + doc->cups.state = doc_create_job; + } + } + + /* Explicitly set CUPS options based on any %cupsJobTicket lines. + * The CUPS scheduler only looks for these in Print-File requests, and since + * we use Create-Job / Send-Document, the ticket lines don't get parsed. + */ + if (doc->cups.state == doc_parse_options) + { + while (1) + { + if (!cups_gets(doc, &buf, &size)) + { + if (doc->cups.buf_len != sizeof(doc->cups.buf)) + return TRUE; + doc->cups.state = doc_create_job; + break; + } + else if (!strncmp(doc->cups.buf, cups_job, sizeof(cups_job) - 1)) + { + doc->cups.buf[doc->cups.buf_len - 1] = 0; + doc->cups.num_options = pcupsParseOptions(doc->cups.buf + sizeof(cups_job) - 1, + doc->cups.num_options, &doc->cups.options); + doc->cups.buf_len = 0; + } + else + { + doc->cups.state = doc_create_job; + break; + } + } + } + + if (doc->cups.state == doc_create_job) + { + const char *format; + int i, job_id; + + doc->cups.num_options = get_cups_default_options(doc->cups.queue, + doc->cups.num_options, &doc->cups.options); + + TRACE("printing via cups with options:\n"); + for (i = 0; i < doc->cups.num_options; i++) + TRACE("\t%d: %s = %s\n", i, doc->cups.options[i].name, doc->cups.options[i].value); + + if (pcupsGetOption("raw", doc->cups.num_options, doc->cups.options)) + format = CUPS_FORMAT_RAW; + else if (!(format = pcupsGetOption("document-format", doc->cups.num_options, doc->cups.options))) + format = CUPS_FORMAT_AUTO; + + job_id = pcupsCreateJob(CUPS_HTTP_DEFAULT, doc->cups.queue, + doc->cups.doc_title, doc->cups.num_options, doc->cups.options); + if (!job_id) + { + if (pcupsLastErrorString) + WARN("cupsCreateJob failed: %s\n", debugstr_a(pcupsLastErrorString())); + return FALSE; + } + + if (pcupsStartDocument(CUPS_HTTP_DEFAULT, doc->cups.queue, job_id, + doc->cups.doc_title, format, TRUE) != HTTP_STATUS_CONTINUE) + { + if (pcupsLastErrorString) + WARN("cupsStartDocument failed: %s\n", debugstr_a(pcupsLastErrorString())); + return FALSE; + } + + doc->cups.state = doc_initialized; + } + + if (doc->cups.restore_ps_header) + { + if (!cups_write(ps_adobe, sizeof(ps_adobe) - 1)) + return FALSE; + doc->cups.restore_ps_header = FALSE; + } + + if (doc->cups.buf_len) + { + if (!cups_write(doc->cups.buf, doc->cups.buf_len)) + return FALSE; + doc->cups.buf_len = 0; + } + + return cups_write((const char *)buf, size); +} + +static BOOL cups_end_doc(doc_t *doc) +{ + if (doc->cups.buf_len) + { + if (doc->cups.state != doc_initialized) + doc->cups.state = doc_create_job; + cups_write_doc(doc, NULL, 0); + } + + if (doc->cups.state == doc_initialized) + pcupsFinishDocument(CUPS_HTTP_DEFAULT, doc->cups.queue); + + free(doc->cups.queue); + free(doc->cups.doc_title); + pcupsFreeOptions(doc->cups.num_options, doc->cups.options); + return TRUE; +} +#endif + +static BOOL cups_start_doc(doc_t *doc, const WCHAR *printer_name, const WCHAR *document_title) +{ +#ifdef SONAME_LIBCUPS + if (pcupsWriteRequestData) + { + int len; + + doc->write_doc = cups_write_doc; + doc->end_doc = cups_end_doc; + + len = wcslen(printer_name); + doc->cups.queue = malloc(len * 3 + 1); + ntdll_wcstoumbs(printer_name, len + 1, doc->cups.queue, len * 3 + 1, FALSE); + + len = wcslen(document_title); + doc->cups.doc_title = malloc(len * 3 + 1); + ntdll_wcstoumbs(document_title, len + 1, doc->cups.doc_title, len + 3 + 1, FALSE); + + return TRUE; + } +#endif + + return lpr_start_doc(doc, printer_name); +} + +static NTSTATUS process_attach(void *args) +{ +#ifdef SONAME_LIBCUPS + libcups_handle = dlopen(SONAME_LIBCUPS, RTLD_NOW); + TRACE("%p: %s loaded\n", libcups_handle, SONAME_LIBCUPS); + if (!libcups_handle) return STATUS_DLL_NOT_FOUND; + +#define DO_FUNC(x) \ + p##x = dlsym(libcups_handle, #x); \ + if (!p##x) \ + { \ + ERR("failed to load symbol %s\n", #x); \ + libcups_handle = NULL; \ + return STATUS_ENTRYPOINT_NOT_FOUND; \ + } + CUPS_FUNCS; +#undef DO_FUNC +#define DO_FUNC(x) p##x = dlsym(libcups_handle, #x) + CUPS_OPT_FUNCS; +#undef DO_FUNC + return STATUS_SUCCESS; +#else /* SONAME_LIBCUPS */ + return STATUS_NOT_SUPPORTED; +#endif /* SONAME_LIBCUPS */ +} + static NTSTATUS start_doc(void *args) { const struct start_doc_params *params = args; - doc_t *doc = malloc(sizeof(*doc)); + doc_t *doc = calloc(1, sizeof(*doc)); BOOL ret = FALSE;
if (!doc) return STATUS_NO_MEMORY; @@ -192,6 +471,9 @@ static NTSTATUS start_doc(void *args) ret = unixname_start_doc(doc, params->port); else if (params->type == PORT_IS_LPR) ret = lpr_start_doc(doc, params->port + 4 /* strlen("lpr:") */); + else if (params->type == PORT_IS_CUPS) + ret = cups_start_doc(doc, params->port + 5 /*strlen("cups:") */, + params->document_title);
if (ret) *params->doc = (size_t)doc; @@ -221,6 +503,7 @@ static NTSTATUS end_doc(void *args)
const unixlib_entry_t __wine_unix_call_funcs[] = { + process_attach, start_doc, write_doc, end_doc, @@ -236,6 +519,7 @@ static NTSTATUS wow64_start_doc(void *args) { unsigned int type; const PTR32 port; + const PTR32 document_title; INT64 *doc; } const *params32 = args;
@@ -243,6 +527,7 @@ static NTSTATUS wow64_start_doc(void *args) { params32->type, ULongToPtr(params32->port), + ULongToPtr(params32->document_title), params32->doc, };
@@ -270,6 +555,7 @@ static NTSTATUS wow64_write_doc(void *args)
const unixlib_entry_t __wine_unix_call_wow64_funcs[] = { + process_attach, wow64_start_doc, wow64_write_doc, end_doc, diff --git a/dlls/localspl/localmon.c b/dlls/localspl/localmon.c index 8cef23787e7..ce0b7c9caea 100644 --- a/dlls/localspl/localmon.c +++ b/dlls/localspl/localmon.c @@ -96,7 +96,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls( hinstDLL ); localspl_instance = hinstDLL; - return !__wine_init_unix_call(); + if (__wine_init_unix_call()) + return FALSE; + UNIX_CALL(process_attach, NULL); + break; } return TRUE; } @@ -506,8 +509,7 @@ static BOOL WINAPI localmon_StartDocPort(HANDLE hport, WCHAR *printer_name, TRACE("(%p %s %ld %ld %p)\n", hport, debugstr_w(printer_name), job_id, level, doc_info);
- if (port->type == PORT_IS_PIPE || port->type == PORT_IS_UNIXNAME || - port->type == PORT_IS_LPR) + if (port->type >= PORT_IS_WINE) { struct start_doc_params params;
@@ -516,6 +518,7 @@ static BOOL WINAPI localmon_StartDocPort(HANDLE hport, WCHAR *printer_name,
params.type = port->type; params.port = port->nameW; + params.document_title = doc_info ? doc_info->pDocName : NULL; params.doc = &port->doc_handle; return UNIX_CALL(start_doc, ¶ms); } @@ -547,12 +550,17 @@ static BOOL WINAPI localmon_WritePort(HANDLE hport, BYTE *buf, DWORD size,
TRACE("(%p %p %lu %p)\n", hport, buf, size, written);
- if (port->type == PORT_IS_PIPE || port->type == PORT_IS_UNIXNAME || - port->type == PORT_IS_LPR) + if (port->type >= PORT_IS_WINE) { struct write_doc_params params; BOOL ret;
+ if (!port->doc_handle) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + params.doc = port->doc_handle; params.buf = buf; params.size = size; @@ -570,11 +578,13 @@ static BOOL WINAPI localmon_EndDocPort(HANDLE hport)
TRACE("(%p)\n", hport);
- if (port->type == PORT_IS_PIPE || port->type == PORT_IS_UNIXNAME || - port->type == PORT_IS_LPR) + if (port->type >= PORT_IS_WINE) { struct end_doc_params params;
+ if (!port->doc_handle) + return TRUE; + params.doc = port->doc_handle; port->doc_handle = 0; return UNIX_CALL(end_doc, ¶ms); diff --git a/dlls/localspl/localspl_private.h b/dlls/localspl/localspl_private.h index b76071f049a..89abc46ce14 100644 --- a/dlls/localspl/localspl_private.h +++ b/dlls/localspl/localspl_private.h @@ -171,6 +171,7 @@ struct start_doc_params { unsigned int type; const WCHAR *port; + const WCHAR *document_title; INT64 *doc; };
@@ -190,6 +191,7 @@ struct end_doc_params
enum cups_funcs { + unix_process_attach, unix_start_doc, unix_write_doc, unix_end_doc, diff --git a/dlls/localspl/provider.c b/dlls/localspl/provider.c index 7b5a94b52f6..fd7827e1f28 100644 --- a/dlls/localspl/provider.c +++ b/dlls/localspl/provider.c @@ -988,7 +988,8 @@ static monitor_t * monitor_load_by_port(LPCWSTR portname) TRACE("(%s)\n", debugstr_w(portname));
/* wine specific ports */ - if (portname[0] == '|' || portname[0] == '/') + if (portname[0] == '|' || portname[0] == '/' || + !wcsncmp(portname, L"LPR:", 4) || !wcsncmp(portname, L"CUPS:", 5)) return monitor_load(L"Local Port", NULL);
/* Try the Local Monitor first */
From: Piotr Caban piotr@codeweavers.com
--- dlls/localspl/localmon.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/dlls/localspl/localmon.c b/dlls/localspl/localmon.c index ce0b7c9caea..e1e7153600d 100644 --- a/dlls/localspl/localmon.c +++ b/dlls/localspl/localmon.c @@ -66,6 +66,7 @@ typedef struct { struct list entry; DWORD type; HANDLE hfile; + DWORD thread_id; INT64 doc_handle; WCHAR nameW[1]; } port_t; @@ -516,6 +517,8 @@ static BOOL WINAPI localmon_StartDocPort(HANDLE hport, WCHAR *printer_name, if (port->doc_handle) return TRUE;
+ port->thread_id = GetCurrentThreadId(); + params.type = port->type; params.port = port->nameW; params.document_title = doc_info ? doc_info->pDocName : NULL; @@ -561,6 +564,13 @@ static BOOL WINAPI localmon_WritePort(HANDLE hport, BYTE *buf, DWORD size, return FALSE; }
+ if (port->type == PORT_IS_CUPS && port->thread_id != GetCurrentThreadId()) + { + FIXME("used from other thread\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; + } + params.doc = port->doc_handle; params.buf = buf; params.size = size; @@ -585,6 +595,13 @@ static BOOL WINAPI localmon_EndDocPort(HANDLE hport) if (!port->doc_handle) return TRUE;
+ if (port->type == PORT_IS_CUPS && port->thread_id != GetCurrentThreadId()) + { + FIXME("used from other thread\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; + } + params.doc = port->doc_handle; port->doc_handle = 0; return UNIX_CALL(end_doc, ¶ms);
From: Piotr Caban piotr@codeweavers.com
--- dlls/winspool.drv/cups.c | 281 +-------------- dlls/winspool.drv/info.c | 699 +++++-------------------------------- dlls/winspool.drv/wspool.h | 9 - 3 files changed, 99 insertions(+), 890 deletions(-)
diff --git a/dlls/winspool.drv/cups.c b/dlls/winspool.drv/cups.c index 766f5c9bb09..6d2d9fa1c8e 100644 --- a/dlls/winspool.drv/cups.c +++ b/dlls/winspool.drv/cups.c @@ -115,34 +115,23 @@
WINE_DEFAULT_DEBUG_CHANNEL(winspool);
-static const WCHAR CUPS_Port[] = { 'C','U','P','S',':',0 }; -static const WCHAR LPR_Port[] = { 'L','P','R',':',0 }; - #ifdef SONAME_LIBCUPS
static void *libcups_handle;
#define CUPS_FUNCS \ - DO_FUNC(cupsAddOption); \ DO_FUNC(cupsFreeDests); \ - DO_FUNC(cupsFreeOptions); \ DO_FUNC(cupsGetDests); \ - DO_FUNC(cupsGetOption); \ - DO_FUNC(cupsParseOptions); \ - DO_FUNC(cupsPrintFile) + DO_FUNC(cupsGetOption); #define CUPS_OPT_FUNCS \ - DO_FUNC(cupsGetNamedDest); \ DO_FUNC(cupsGetPPD); \ - DO_FUNC(cupsGetPPD3); \ - DO_FUNC(cupsLastErrorString) + DO_FUNC(cupsGetPPD3);
#define DO_FUNC(f) static typeof(f) *p##f CUPS_FUNCS; #undef DO_FUNC -static cups_dest_t * (*pcupsGetNamedDest)(http_t *, const char *, const char *); static const char * (*pcupsGetPPD)(const char *); static http_status_t (*pcupsGetPPD3)(http_t *, const char *, time_t *, char *, size_t); -static const char * (*pcupsLastErrorString)(void);
#endif /* SONAME_LIBCUPS */
@@ -282,56 +271,6 @@ static http_status_t cupsGetPPD3_wrapper( http_t *http, const char *name, time_t } return HTTP_OK; } - -/***************************************************************************** - * get_cups_jobs_ticket_options - * - * Explicitly set CUPS options based on any %cupsJobTicket lines. - * The CUPS scheduler only looks for these in Print-File requests, and since - * cupsPrintFile uses Create-Job / Send-Document, the ticket lines don't get - * parsed. - */ -static int get_cups_job_ticket_options( const char *file, int num_options, cups_option_t **options ) -{ - FILE *fp = fopen( file, "r" ); - char buf[257]; /* DSC max of 256 + '\0' */ - const char *ps_adobe = "%!PS-Adobe-"; - const char *cups_job = "%cupsJobTicket:"; - - if (!fp) return num_options; - if (!fgets( buf, sizeof(buf), fp )) goto end; - if (strncmp( buf, ps_adobe, strlen( ps_adobe ) )) goto end; - while (fgets( buf, sizeof(buf), fp )) - { - if (strncmp( buf, cups_job, strlen( cups_job ) )) break; - num_options = pcupsParseOptions( buf + strlen( cups_job ), num_options, options ); - } - -end: - fclose( fp ); - return num_options; -} - -static int get_cups_default_options( const char *printer, int num_options, cups_option_t **options ) -{ - cups_dest_t *dest; - int i; - - if (!pcupsGetNamedDest) return num_options; - - dest = pcupsGetNamedDest( NULL, printer, NULL ); - if (!dest) return num_options; - - for (i = 0; i < dest->num_options; i++) - { - if (!pcupsGetOption( dest->options[i].name, num_options, *options )) - num_options = pcupsAddOption( dest->options[i].name, dest->options[i].value, - num_options, options ); - } - - pcupsFreeDests( 1, dest ); - return num_options; -} #endif /* SONAME_LIBCUPS */
static NTSTATUS enum_printers( void *args ) @@ -486,206 +425,12 @@ end: #endif }
-/***************************************************************************** - * schedule_pipe - */ -static BOOL schedule_pipe( const WCHAR *cmd, const WCHAR *filename ) -{ - char *unixname, *cmdA; - DWORD len; - int fds[2] = { -1, -1 }, file_fd = -1, no_read; - BOOL ret = FALSE; - char buf[1024]; - pid_t pid, wret; - int status; - - if (!(unixname = get_unix_file_name( filename ))) return FALSE; - - len = wcslen( cmd ); - cmdA = malloc( len * 3 + 1); - ntdll_wcstoumbs( cmd, len + 1, cmdA, len * 3 + 1, FALSE ); - - TRACE( "printing with: %s\n", cmdA ); - - if ((file_fd = open( unixname, O_RDONLY )) == -1) goto end; - - if (pipe( fds )) - { - ERR( "pipe() failed!\n" ); - goto end; - } - - if ((pid = fork()) == 0) - { - close( 0 ); - dup2( fds[0], 0 ); - close( fds[1] ); - - /* reset signals that we previously set to SIG_IGN */ - signal( SIGPIPE, SIG_DFL ); - - execl( "/bin/sh", "/bin/sh", "-c", cmdA, NULL ); - _exit( 1 ); - } - else if (pid == -1) - { - ERR( "fork() failed!\n" ); - goto end; - } - - close( fds[0] ); - fds[0] = -1; - while ((no_read = read( file_fd, buf, sizeof(buf) )) > 0) - write( fds[1], buf, no_read ); - - close( fds[1] ); - fds[1] = -1; - - /* reap child */ - do { - wret = waitpid( pid, &status, 0 ); - } while (wret < 0 && errno == EINTR); - if (wret < 0) - { - ERR( "waitpid() failed!\n" ); - goto end; - } - if (!WIFEXITED(status) || WEXITSTATUS(status)) - { - ERR( "child process failed! %d\n", status ); - goto end; - } - - ret = TRUE; - -end: - if (file_fd != -1) close( file_fd ); - if (fds[0] != -1) close( fds[0] ); - if (fds[1] != -1) close( fds[1] ); - - free( cmdA ); - free( unixname ); - return ret; -} - -/***************************************************************************** - * schedule_unixfile - */ -static BOOL schedule_unixfile( const WCHAR *output, const WCHAR *filename ) -{ - char *unixname, *outputA; - DWORD len; - BOOL ret; - - if (!(unixname = get_unix_file_name( filename ))) return FALSE; - - len = wcslen( output ); - outputA = malloc( len * 3 + 1); - ntdll_wcstoumbs( output, len + 1, outputA, len * 3 + 1, FALSE ); - - ret = copy_file( unixname, outputA ); - - free( outputA ); - free( unixname ); - return ret; -} - -/***************************************************************************** - * schedule_lpr - */ -static BOOL schedule_lpr( const WCHAR *printer_name, const WCHAR *filename ) -{ - static const WCHAR lpr[] = { 'l','p','r',' ','-','P',''' }; - static const WCHAR quote[] = { ''',0 }; - int printer_len = wcslen( printer_name ); - WCHAR *cmd; - BOOL ret; - - cmd = malloc( printer_len * sizeof(WCHAR) + sizeof(lpr) + sizeof(quote) ); - memcpy( cmd, lpr, sizeof(lpr) ); - memcpy( cmd + ARRAY_SIZE(lpr), printer_name, printer_len * sizeof(WCHAR) ); - memcpy( cmd + ARRAY_SIZE(lpr) + printer_len, quote, sizeof(quote) ); - - ret = schedule_pipe( cmd, filename ); - - free( cmd ); - return ret; -} - -/***************************************************************************** - * schedule_cups - */ -static BOOL schedule_cups( const WCHAR *printer_name, const WCHAR *filename, const WCHAR *document_title ) -{ -#ifdef SONAME_LIBCUPS - if (pcupsPrintFile) - { - char *unixname, *queue, *unix_doc_title; - cups_option_t *options = NULL; - int num_options = 0, i; - DWORD len; - BOOL ret; - - if (!(unixname = get_unix_file_name( filename ))) return FALSE; - len = wcslen( printer_name ); - queue = malloc( len * 3 + 1); - ntdll_wcstoumbs( printer_name, len + 1, queue, len * 3 + 1, FALSE ); - - len = wcslen( document_title ); - unix_doc_title = malloc( len * 3 + 1 ); - ntdll_wcstoumbs( document_title, len + 1, unix_doc_title, len + 3 + 1, FALSE ); - - num_options = get_cups_job_ticket_options( unixname, num_options, &options ); - num_options = get_cups_default_options( queue, num_options, &options ); - - TRACE( "printing via cups with options:\n" ); - for (i = 0; i < num_options; i++) - TRACE( "\t%d: %s = %s\n", i, options[i].name, options[i].value ); - - ret = pcupsPrintFile( queue, unixname, unix_doc_title, num_options, options ); - if (ret == 0 && pcupsLastErrorString) - WARN( "cupsPrintFile failed with error %s\n", debugstr_a( pcupsLastErrorString() ) ); - - pcupsFreeOptions( num_options, options ); - - free( unix_doc_title ); - free( queue ); - free( unixname ); - return ret; - } - else -#endif - { - return schedule_lpr( printer_name, filename ); - } -} - -static NTSTATUS schedule_job( void *args ) -{ - const struct schedule_job_params *params = args; - - if (params->wine_port[0] == '|') - return schedule_pipe( params->wine_port + 1, params->filename ); - - if (params->wine_port[0]) - return schedule_unixfile( params->wine_port, params->filename ); - - if (!wcsncmp( params->port, LPR_Port, ARRAY_SIZE(LPR_Port) - 1 )) - return schedule_lpr( params->port + ARRAY_SIZE(LPR_Port) - 1, params->filename ); - - if (!wcsncmp( params->port, CUPS_Port, ARRAY_SIZE(CUPS_Port) - 1 )) - return schedule_cups( params->port + ARRAY_SIZE(CUPS_Port) - 1, params->filename, params->document_title ); - - return FALSE; -} - const unixlib_entry_t __wine_unix_call_funcs[] = { process_attach, enum_printers, get_default_page_size, get_ppd, - schedule_job, };
#ifdef _WIN64 @@ -770,34 +515,12 @@ static NTSTATUS wow64_get_ppd( void *args ) return get_ppd( ¶ms ); }
-static NTSTATUS wow64_schedule_job( void *args ) -{ - struct - { - PTR32 filename; - PTR32 port; - PTR32 document_title; - PTR32 wine_port; - } const *params32 = args; - - struct schedule_job_params params = - { - ULongToPtr( params32->filename ), - ULongToPtr( params32->port ), - ULongToPtr( params32->document_title ), - ULongToPtr( params32->wine_port ) - }; - - return schedule_job( ¶ms ); -} - const unixlib_entry_t __wine_unix_call_wow64_funcs[] = { process_attach, wow64_enum_printers, wow64_get_default_page_size, wow64_get_ppd, - wow64_schedule_job, };
#endif /* _WIN64 */ diff --git a/dlls/winspool.drv/info.c b/dlls/winspool.drv/info.c index 2cf8ab076dc..cfdf66f4d21 100644 --- a/dlls/winspool.drv/info.c +++ b/dlls/winspool.drv/info.c @@ -75,31 +75,12 @@ typedef struct { HANDLE hf; } started_doc_t;
-typedef struct { - struct list jobs; - LONG ref; -} jobqueue_t; - typedef struct { LPWSTR name; - LPWSTR printername; HANDLE backend_printer; - jobqueue_t *queue; started_doc_t *doc; - DEVMODEW *devmode; } opened_printer_t;
-typedef struct { - struct list entry; - DWORD job_id; - WCHAR *filename; - WCHAR *portname; - WCHAR *document_title; - WCHAR *printer_name; - LPDEVMODEW devmode; -} job_t; - - typedef struct { LPCWSTR envname; LPCWSTR subdir; @@ -141,7 +122,6 @@ typedef struct {
static opened_printer_t **printer_handles; static UINT nb_printer_handles; -static LONG next_job_id = 1;
static const WCHAR * const May_Delete_Value = L"WineMayDeleteMe";
@@ -240,16 +220,6 @@ static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src ) return NULL; }
-static DEVMODEW *dup_devmode( const DEVMODEW *dm ) -{ - DEVMODEW *ret; - - if (!dm) return NULL; - ret = malloc( dm->dmSize + dm->dmDriverExtra ); - if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra ); - return ret; -} - /* stringWtoA * Converts Unicode string to Ansi (possibly in place). */ @@ -985,9 +955,7 @@ static LPCWSTR get_basename_from_name(LPCWSTR name) static void free_printer_entry( opened_printer_t *printer ) { /* the queue is shared, so don't free that here */ - free( printer->printername ); free( printer->name ); - free( printer->devmode ); free( printer ); }
@@ -1000,11 +968,10 @@ static void free_printer_entry( opened_printer_t *printer ) */ static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault) { - UINT_PTR handle = nb_printer_handles, i; - jobqueue_t *queue = NULL; opened_printer_t *printer = NULL; LPWSTR servername; LPCWSTR printername; + UINT_PTR handle;
if ((backend == NULL) && !load_backend()) return NULL;
@@ -1027,17 +994,10 @@ static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault
EnterCriticalSection(&printer_handles_cs);
- for (i = 0; i < nb_printer_handles; i++) + for (handle = 0; handle < nb_printer_handles; handle++) { - if (!printer_handles[i]) - { - if(handle == nb_printer_handles) - handle = i; - } - else if (!queue && name && printer_handles[i]->name && !wcscmp( name, printer_handles[i]->name )) - { - queue = printer_handles[i]->queue; - } + if (!printer_handles[handle]) + break; }
if (handle >= nb_printer_handles) @@ -1074,9 +1034,6 @@ static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault goto end; }
- /* clone the base name. This is NULL for the printserver */ - printer->printername = wcsdup(printername); - /* clone the full name */ printer->name = wcsdup(name); if (name && (!printer->name)) { @@ -1084,31 +1041,12 @@ static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault goto end; }
- if (pDefault && pDefault->pDevMode) - printer->devmode = dup_devmode( pDefault->pDevMode ); - - if(queue) - printer->queue = queue; - else - { - printer->queue = malloc(sizeof(*queue)); - if (!printer->queue) { - handle = 0; - goto end; - } - list_init(&printer->queue->jobs); - printer->queue->ref = 0; - } - InterlockedIncrement(&printer->queue->ref); - printer_handles[handle] = printer; handle++; end: LeaveCriticalSection(&printer_handles_cs); - if (!handle && printer) { - if (!queue) free(printer->queue); + if (!handle && printer) free_printer_entry( printer ); - }
return (HANDLE)handle; } @@ -1210,26 +1148,6 @@ void WINSPOOL_LoadSystemPrinters(void) return; }
-/****************************************************************** - * get_job - * - * Get the pointer to the specified job. - * Should hold the printer_handles_cs before calling. - */ -static job_t *get_job(HANDLE hprn, DWORD JobId) -{ - opened_printer_t *printer = get_opened_printer(hprn); - job_t *job; - - if(!printer) return NULL; - LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry) - { - if(job->job_id == JobId) - return job; - } - return NULL; -} - /****************************************************************** * convert_printerinfo_W_to_A [internal] * @@ -2508,66 +2426,19 @@ BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPD /***************************************************************************** * AddJobW [WINSPOOL.@] */ -BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded) +BOOL WINAPI AddJobW(HANDLE printer, DWORD level, LPBYTE data, DWORD size, DWORD *needed) { - opened_printer_t *printer; - job_t *job; - BOOL ret = FALSE; - static const WCHAR spool_path[] = L"spool\PRINTERS\"; - WCHAR path[MAX_PATH], filename[MAX_PATH]; - DWORD len; - ADDJOB_INFO_1W *addjob; + HANDLE handle = get_backend_handle(printer);
- TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded); + TRACE("(%p, %ld, %p, %ld, %p)\n", printer, level, data, size, needed);
- EnterCriticalSection(&printer_handles_cs); - - printer = get_opened_printer(hPrinter); - - if(!printer) { + if (!handle) + { SetLastError(ERROR_INVALID_HANDLE); - goto end; - } - - if(Level != 1) { - SetLastError(ERROR_INVALID_LEVEL); - goto end; + return FALSE; }
- job = malloc(sizeof(*job)); - if(!job) - goto end; - - job->job_id = InterlockedIncrement(&next_job_id); - - len = GetSystemDirectoryW(path, ARRAY_SIZE(path)); - if(path[len - 1] != '\') - path[len++] = '\'; - memcpy( path + len, spool_path, sizeof(spool_path) ); - swprintf( filename, ARRAY_SIZE(filename), L"%s%05d.SPL", path, job->job_id ); - - len = wcslen( filename ); - job->filename = malloc((len + 1) * sizeof(WCHAR)); - memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR)); - job->portname = NULL; - job->document_title = wcsdup( L"Local Downlevel Document" ); - job->printer_name = wcsdup( printer->name ); - job->devmode = dup_devmode( printer->devmode ); - list_add_tail(&printer->queue->jobs, &job->entry); - - *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob); - if(*pcbNeeded <= cbBuf) { - addjob = (ADDJOB_INFO_1W*)pData; - addjob->JobId = job->job_id; - addjob->Path = (WCHAR *)(addjob + 1); - memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR)); - ret = TRUE; - } else - SetLastError(ERROR_INSUFFICIENT_BUFFER); - -end: - LeaveCriticalSection(&printer_handles_cs); - return ret; + return backend->fpAddJob(handle, level, data, size, needed); }
/***************************************************************************** @@ -2897,23 +2768,11 @@ BOOL WINAPI ClosePrinter(HANDLE hPrinter)
if(printer) { - struct list *cursor, *cursor2; - TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
if(printer->doc) EndDocPrinter(hPrinter);
- if(InterlockedDecrement(&printer->queue->ref) == 0) - { - LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs) - { - job_t *job = LIST_ENTRY(cursor, job_t, entry); - ScheduleJob(hPrinter, job->job_id); - } - free(printer->queue); - } - if (printer->backend_printer) { backend->fpClosePrinter(printer->backend_printer); } @@ -3210,84 +3069,48 @@ BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, /***************************************************************************** * SetJobW [WINSPOOL.@] */ -BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, - LPBYTE pJob, DWORD Command) +BOOL WINAPI SetJobW(HANDLE printer, DWORD job_id, DWORD level, + LPBYTE data, DWORD command) { - BOOL ret = FALSE; - job_t *job; + HANDLE handle = get_backend_handle(printer);
- TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command); - FIXME("Ignoring everything other than document title\n"); + TRACE("(%p, %ld, %ld, %p, %ld)\n", printer, job_id, level, data, command);
- EnterCriticalSection(&printer_handles_cs); - job = get_job(hPrinter, JobId); - if(!job) - goto end; - - switch(Level) + if (!handle) { - case 0: - break; - case 1: - { - JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob; - free(job->document_title); - job->document_title = wcsdup(info1->pDocument); - break; - } - case 2: - { - JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob; - free(job->document_title); - job->document_title = wcsdup(info2->pDocument); - free(job->devmode); - job->devmode = dup_devmode( info2->pDevMode ); - break; - } - case 3: - break; - default: - SetLastError(ERROR_INVALID_LEVEL); - goto end; + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; } - ret = TRUE; -end: - LeaveCriticalSection(&printer_handles_cs); - return ret; + + return backend->fpSetJob(handle, job_id, level, data, command); }
/***************************************************************************** * EndDocPrinter [WINSPOOL.@] */ -BOOL WINAPI EndDocPrinter(HANDLE hPrinter) +BOOL WINAPI EndDocPrinter(HANDLE hprinter) { - opened_printer_t *printer; - BOOL ret = FALSE; - TRACE("(%p)\n", hPrinter); + opened_printer_t *printer = get_opened_printer(hprinter);
- EnterCriticalSection(&printer_handles_cs); + TRACE("(%p)\n", printer);
- printer = get_opened_printer(hPrinter); - if(!printer) + if (!printer || !printer->backend_printer) { SetLastError(ERROR_INVALID_HANDLE); - goto end; + return FALSE; }
- if(!printer->doc) + if (!printer->doc) { SetLastError(ERROR_SPL_NO_STARTDOC); - goto end; + return FALSE; }
CloseHandle(printer->doc->hf); - ScheduleJob(hPrinter, printer->doc->job_id); free(printer->doc); printer->doc = NULL; - ret = TRUE; -end: - LeaveCriticalSection(&printer_handles_cs); - return ret; + + return backend->fpEndDocPrinter(printer->backend_printer); }
/***************************************************************************** @@ -3339,78 +3162,71 @@ DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo) return ret; }
+static size_t get_spool_filename(DWORD job_id, WCHAR *buf, size_t len) +{ + static const WCHAR spool_path[] = L"spool\PRINTERS\"; + size_t ret; + + ret = GetSystemDirectoryW(NULL, 0) + ARRAY_SIZE(spool_path) + 10; + if (len < ret) + return ret; + + ret = GetSystemDirectoryW(buf, ret); + if (buf[ret - 1] != '\') + buf[ret++] = '\'; + memcpy(buf + ret, spool_path, sizeof(spool_path)); + ret += ARRAY_SIZE(spool_path) - 1; + swprintf(buf + ret, 10, L"%05d.SPL", job_id); + ret += 10; + return ret; +} + /***************************************************************************** * StartDocPrinterW [WINSPOOL.@] */ -DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo) +DWORD WINAPI StartDocPrinterW(HANDLE hprinter, DWORD level, BYTE *doc_info) { - DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo; - opened_printer_t *printer; - BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)]; - ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf; - JOB_INFO_1W job_info; - DWORD needed, ret = 0; + opened_printer_t *printer = get_opened_printer(hprinter); + DOC_INFO_1W *info = (DOC_INFO_1W *)doc_info; + WCHAR filename[MAX_PATH]; + HANDLE handle; + DWORD job_id; HANDLE hf; - WCHAR *filename; - job_t *job;
- TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n", - hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile), - debugstr_w(doc->pDatatype)); + TRACE("(%p, %ld, %p {%s, %s, %s})\n", printer, level, doc_info, + debugstr_w(info->pDocName), debugstr_w(info->pOutputFile), + debugstr_w(info->pDatatype));
- if(Level < 1 || Level > 3) + if (!printer || !printer->backend_printer) { - SetLastError(ERROR_INVALID_LEVEL); + SetLastError(ERROR_INVALID_HANDLE); return 0; } + handle = printer->backend_printer;
- EnterCriticalSection(&printer_handles_cs); - printer = get_opened_printer(hPrinter); - if(!printer) - { - SetLastError(ERROR_INVALID_HANDLE); - goto end; - } + job_id = backend->fpStartDocPrinter(handle, level, doc_info); + if (!job_id) + return 0;
- if(printer->doc) + /* TODO: remove when WritePrinter is implemented in providor */ + if (get_spool_filename(job_id, filename, ARRAY_SIZE(filename)) > ARRAY_SIZE(filename)) { - SetLastError(ERROR_INVALID_PRINTER_STATE); - goto end; + backend->fpEndDocPrinter(handle); + SetLastError(ERROR_INTERNAL_ERROR); + return 0; } - - /* Even if we're printing to a file we still add a print job, we'll - just ignore the spool file name */ - - if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed)) + hf = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hf == INVALID_HANDLE_VALUE) { - ERR("AddJob failed gle %lu\n", GetLastError()); - goto end; + backend->fpEndDocPrinter(handle); + return 0; }
- /* use pOutputFile only, when it is a real filename */ - if ((doc->pOutputFile) && is_local_file(doc->pOutputFile)) - filename = doc->pOutputFile; - else - filename = addjob->Path; - - hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if(hf == INVALID_HANDLE_VALUE) - goto end; - - memset(&job_info, 0, sizeof(job_info)); - job_info.pDocument = doc->pDocName; - SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0); - printer->doc = malloc(sizeof(*printer->doc)); + printer->doc->job_id = job_id; printer->doc->hf = hf; - ret = printer->doc->job_id = addjob->JobId; - job = get_job(hPrinter, ret); - job->portname = wcsdup(doc->pOutputFile); - -end: - LeaveCriticalSection(&printer_handles_cs); - - return ret; + return job_id; }
/***************************************************************************** @@ -7487,244 +7303,6 @@ BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo ) return TRUE; }
-/***************************************************************************** - * string_to_buf - * - * Copies a unicode string into a buffer. The buffer will either contain unicode or - * ansi depending on the unicode parameter. - */ -static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode) -{ - if(!str) - { - *size = 0; - return TRUE; - } - - if(unicode) - { - *size = (wcslen( str ) + 1) * sizeof(WCHAR); - if(*size <= cb) - { - memcpy(ptr, str, *size); - return TRUE; - } - return FALSE; - } - else - { - *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL); - if(*size <= cb) - { - WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL); - return TRUE; - } - return FALSE; - } -} - -/***************************************************************************** - * get_job_info_1 - */ -static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf, - LPDWORD pcbNeeded, BOOL unicode) -{ - DWORD size, left = cbBuf; - BOOL space = (cbBuf > 0); - LPBYTE ptr = buf; - - *pcbNeeded = 0; - - if(space) - { - ji1->JobId = job->job_id; - } - - string_to_buf(job->document_title, ptr, left, &size, unicode); - if(space && size <= left) - { - ji1->pDocument = (LPWSTR)ptr; - ptr += size; - left -= size; - } - else - space = FALSE; - *pcbNeeded += size; - - if (job->printer_name) - { - string_to_buf(job->printer_name, ptr, left, &size, unicode); - if(space && size <= left) - { - ji1->pPrinterName = (LPWSTR)ptr; - ptr += size; - left -= size; - } - else - space = FALSE; - *pcbNeeded += size; - } - - return space; -} - -/***************************************************************************** - * get_job_info_2 - */ -static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf, - LPDWORD pcbNeeded, BOOL unicode) -{ - DWORD size, left = cbBuf; - DWORD shift; - BOOL space = (cbBuf > 0); - LPBYTE ptr = buf; - LPDEVMODEA dmA = NULL; - LPDEVMODEW devmode; - - *pcbNeeded = 0; - - if(space) - { - ji2->JobId = job->job_id; - } - - string_to_buf(job->document_title, ptr, left, &size, unicode); - if(space && size <= left) - { - ji2->pDocument = (LPWSTR)ptr; - ptr += size; - left -= size; - } - else - space = FALSE; - *pcbNeeded += size; - - if (job->printer_name) - { - string_to_buf(job->printer_name, ptr, left, &size, unicode); - if(space && size <= left) - { - ji2->pPrinterName = (LPWSTR)ptr; - ptr += size; - left -= size; - } - else - space = FALSE; - *pcbNeeded += size; - } - - if (job->devmode) - { - if (!unicode) - { - dmA = DEVMODEWtoA(job->devmode, NULL); - devmode = (LPDEVMODEW) dmA; - if (dmA) size = dmA->dmSize + dmA->dmDriverExtra; - } - else - { - devmode = job->devmode; - size = devmode->dmSize + devmode->dmDriverExtra; - } - - if (!devmode) - FIXME("Can't convert DEVMODE W to A\n"); - else - { - /* align DEVMODE to a DWORD boundary */ - shift = (4 - (*pcbNeeded & 3)) & 3; - size += shift; - - if (size <= left) - { - ptr += shift; - memcpy(ptr, devmode, size-shift); - ji2->pDevMode = (LPDEVMODEW)ptr; - if (!unicode) free(dmA); - ptr += size-shift; - left -= size; - } - else - space = FALSE; - *pcbNeeded +=size; - } - } - - return space; -} - -/***************************************************************************** - * get_job_info - */ -static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob, - DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode) -{ - BOOL ret = FALSE; - DWORD needed = 0, size; - job_t *job; - LPBYTE ptr = pJob; - - TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded); - - EnterCriticalSection(&printer_handles_cs); - job = get_job(hPrinter, JobId); - if(!job) - goto end; - - switch(Level) - { - case 1: - size = sizeof(JOB_INFO_1W); - if(cbBuf >= size) - { - cbBuf -= size; - ptr += size; - memset(pJob, 0, size); - } - else - cbBuf = 0; - ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode); - needed += size; - break; - - case 2: - size = sizeof(JOB_INFO_2W); - if(cbBuf >= size) - { - cbBuf -= size; - ptr += size; - memset(pJob, 0, size); - } - else - cbBuf = 0; - ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode); - needed += size; - break; - - case 3: - size = sizeof(JOB_INFO_3); - if(cbBuf >= size) - { - cbBuf -= size; - memset(pJob, 0, size); - ret = TRUE; - } - else - cbBuf = 0; - needed = size; - break; - - default: - SetLastError(ERROR_INVALID_LEVEL); - goto end; - } - if(pcbNeeded) - *pcbNeeded = needed; -end: - LeaveCriticalSection(&printer_handles_cs); - return ret; -} - static inline const DWORD *job_string_info(DWORD level) { static const DWORD info_1[] = @@ -7794,10 +7372,20 @@ BOOL WINAPI GetJobA(HANDLE printer, DWORD job_id, DWORD level, BYTE *data, * GetJobW [WINSPOOL.@] * */ -BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob, - DWORD cbBuf, LPDWORD pcbNeeded) +BOOL WINAPI GetJobW(HANDLE printer, DWORD job_id, DWORD level, BYTE *data, + DWORD size, DWORD *needed) { - return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE); + HANDLE handle = get_backend_handle(printer); + + TRACE("(%p, %ld, %ld, %p, %ld, %p)\n", printer, job_id, level, data, size, needed); + + if (!handle) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + return backend->fpGetJob(handle, job_id, level, data, size, needed); }
static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) @@ -7874,116 +7462,23 @@ static BOOL get_filename(LPWSTR *filename) file_dlg_proc, (LPARAM)filename) == IDOK; }
-/***************************************************************************** - * schedule_file - */ -static BOOL schedule_file(LPCWSTR filename) -{ - LPWSTR output = NULL; - - if(get_filename(&output)) - { - BOOL r; - TRACE("copy to %s\n", debugstr_w(output)); - r = CopyFileW(filename, output, FALSE); - free(output); - return r; - } - return FALSE; -} - /***************************************************************************** * ScheduleJob [WINSPOOL.@] * */ -BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID ) +BOOL WINAPI ScheduleJob(HANDLE printer, DWORD job_id) { - opened_printer_t *printer; - BOOL ret = FALSE; - struct list *cursor, *cursor2; + HANDLE handle = get_backend_handle(printer);
- TRACE("(%p, %lx)\n", hPrinter, dwJobID); - EnterCriticalSection(&printer_handles_cs); - printer = get_opened_printer(hPrinter); - if(!printer) - goto end; + TRACE("(%p, %lx)\n", printer, job_id);
- LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs) + if (!handle) { - job_t *job = LIST_ENTRY(cursor, job_t, entry); - HANDLE hf; - - if(job->job_id != dwJobID) continue; - - hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - if(hf != INVALID_HANDLE_VALUE) - { - PRINTER_INFO_5W *pi5 = NULL; - LPWSTR portname = job->portname; - UNICODE_STRING nt_name; - DWORD needed; - HKEY hkey; - WCHAR output[1024]; - - if (!portname) - { - GetPrinterW(hPrinter, 5, NULL, 0, &needed); - pi5 = malloc(needed); - GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed); - portname = pi5->pPortName; - } - TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename), - debugstr_w(portname)); - - if (!wcsncmp( portname, L"FILE:", ARRAY_SIZE(L"FILE:") - 1 )) - { - ret = schedule_file( job->filename ); - } - else if (isalpha(portname[0]) && portname[1] == ':') - { - TRACE( "copying to %s\n", debugstr_w( portname ) ); - ret = CopyFileW( job->filename, portname, FALSE ); - } - else if (RtlDosPathNameToNtPathName_U( job->filename, &nt_name, NULL, NULL )) - { - struct schedule_job_params params = - { - .filename = nt_name.Buffer, - .port = portname, - .document_title = job->document_title, - .wine_port = output - }; - - output[0] = 0; - /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */ - if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Software\Wine\Printing\Spooler", &hkey )) - { - DWORD type, count = sizeof(output); - RegQueryValueExW( hkey, portname, NULL, &type, (BYTE *)output, &count ); - RegCloseKey( hkey ); - } - ret = UNIX_CALL( schedule_job, ¶ms ); - RtlFreeUnicodeString( &nt_name ); - } - else ret = FALSE; - - if (!ret) FIXME( "can't schedule to port %s\n", debugstr_w( portname ) ); - free(pi5); - CloseHandle(hf); - DeleteFileW(job->filename); - } - list_remove(cursor); - free(job->document_title); - free(job->printer_name); - free(job->portname); - free(job->filename); - free(job->devmode); - free(job); - break; + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; } -end: - LeaveCriticalSection(&printer_handles_cs); - return ret; + + return backend->fpScheduleJob(handle, job_id); }
/***************************************************************************** diff --git a/dlls/winspool.drv/wspool.h b/dlls/winspool.drv/wspool.h index 63b8ccae466..47e9e213c0d 100644 --- a/dlls/winspool.drv/wspool.h +++ b/dlls/winspool.drv/wspool.h @@ -64,14 +64,6 @@ struct get_ppd_params const WCHAR *ppd; };
-struct schedule_job_params -{ - const WCHAR *filename; - const WCHAR *port; - const WCHAR *document_title; - const WCHAR *wine_port; -}; - #define UNIX_CALL( func, params ) WINE_UNIX_CALL( unix_ ## func, params )
enum cups_funcs @@ -80,5 +72,4 @@ enum cups_funcs unix_enum_printers, unix_get_default_page_size, unix_get_ppd, - unix_schedule_job, };
This merge request was approved by Huw Davies.
This is crashing here:
``` tools/runtest -q -P wine -T . -M winspool.drv -p dlls/winspool.drv/tests/i386-windows/winspool.drv_test.exe info && touch dlls/winspool.drv/tests/i386-windows/info.ok wine: Unhandled page fault on read access to FFFFFFFF at address 7BC415A2 (thread 0184), starting debugger... Unhandled exception: page fault on read access to 0xffffffff in 32-bit code (0x7bc415a2). Register dump: CS:0023 SS:002b DS:002b ES:002b FS:0063 GS:006b EIP:7bc415a2 ESP:0066def0 EBP:0066e188 EFLAGS:00010286( R- -- I S - -P- ) EAX:00000000 EBX:0066e214 ECX:0066e1a0 EDX:0066e214 ESI:ffffffff EDI:00000000 Stack dump: 0x0066def0: 00000000 0066df68 0000006a 00000000 0x0066df00: 00000000 00000000 000003ca 651557be 0x0066df10: 0066df50 00000000 0066df40 0066df50 0x0066df20: 00000060 0066df68 0066df68 00000000 0x0066df30: 0066df50 00000000 0066df50 00000400 0x0066df40: 02020212 02120202 00660202 00000000 Backtrace: =>0 0x7bc415a2 RtlDosPathNameToNtPathName_U_WithStatus+0x62(dos_path=<couldn't compute location>, ntpath=<couldn't compute location>, file_part=<couldn't compute location>, cd=<couldn't compute location>) [Z:\home\julliard\wine\wine\dlls\ntdll\path.c:196] in ntdll (0x0066e188) 1 0x7bc41c31 RtlDosPathNameToNtPathName_U+0x31(dos_path=<couldn't compute location>, ntpath=<couldn't compute location>, file_part=<couldn't compute location>, cd=<couldn't compute location>) [Z:\home\julliard\wine\wine\dlls\ntdll\path.c:309] in ntdll (0x0066e1b8) 2 0x7b01925f DeleteFileW+0x4a(path=<couldn't compute location>) [Z:\home\julliard\wine\wine\dlls\kernelbase\file.c:977] in kernelbase (0x0066e368) 3 0x6515074b list_remove(hprinter=<couldn't compute location>, job_id=<couldn't compute location>) [Z:\home\julliard\wine\wine\include\wine\list.h:100] in localspl (0x0066fc08) 4 0x6515074b free_job(hprinter=<couldn't compute location>, job_id=<couldn't compute location>) [Z:\home\julliard\wine\wine\dlls\localspl\provider.c:3339] in localspl (0x0066fc08) 5 0x6515074b fpScheduleJob+0x32b(hprinter=<couldn't compute location>, job_id=<couldn't compute location>) [Z:\home\julliard\wine\wine\dlls\localspl\provider.c:3339] in localspl (0x0066fc08) 6 0x64197d41 ScheduleJob+0x71(printer=<couldn't compute location>, job_id=<couldn't compute location>) [Z:\home\julliard\wine\wine\dlls\winspool.drv\info.c:7481] in winspool (0x0066fc58) 7 0x0040aa8e test_OpenPrinter_defaults+0x4c0() [Z:\home\julliard\wine\wine\dlls\winspool.drv\tests\info.c:2960] in winspool.drv_test (0x0066fdb8) 8 0x0040aa8e func_info+0x177e() [Z:\home\julliard\wine\wine\dlls\winspool.drv\tests\info.c:3051] in winspool.drv_test (0x0066fdb8) 9 0x0040cd73 run_test+0xe3(name="info") [Z:\home\julliard\wine\wine\include\wine\test.h:720] in winspool.drv_test (0x0066fe18) 10 0x0040ea8e main+0x21e(argc=<couldn't compute location>, argv=<couldn't compute location>) [Z:\home\julliard\wine\wine\include\wine\test.h:833] in winspool.drv_test (0x0066fee8) 11 0x0040e81f mainCRTStartup+0x7f() [Z:\home\julliard\wine\wine\dlls\msvcrt\crt_main.c:60] in winspool.drv_test (0x0066ff30) 12 0x7b62a250 in kernel32 (+0x2a250) (0x0066ff48) 13 0x7bc5cf47 in ntdll (+0x5cf47) (0x0066ff5c) 14 0x7bc5d770 RtlCreateUserThread(entry=0040E7A0, arg=7FFD1000) [Z:\home\julliard\wine\wine\dlls\ntdll\thread.c:306] in ntdll (0x0066ffec) 0x7bc415a2 RtlDosPathNameToNtPathName_U_WithStatus+0x62 [Z:\home\julliard\wine\wine\dlls\ntdll\path.c:196] in ntdll: cmpw $0,0x0(%esi) 196 if (!dos_path || !*dos_path) ```