winspool: Use providor for print jobs implementation.
This commit is contained in:
parent
a04bf6e8a8
commit
e164b8cefb
3 changed files with 105 additions and 896 deletions
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(Level != 1) {
|
||||
SetLastError(ERROR_INVALID_LEVEL);
|
||||
goto end;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
job_id = backend->fpStartDocPrinter(handle, level, doc_info);
|
||||
if (!job_id)
|
||||
return 0;
|
||||
|
||||
/* TODO: remove when WritePrinter is implemented in providor */
|
||||
if (get_spool_filename(job_id, filename, ARRAY_SIZE(filename)) > ARRAY_SIZE(filename))
|
||||
{
|
||||
backend->fpEndDocPrinter(handle);
|
||||
SetLastError(ERROR_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
hf = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hf == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
backend->fpEndDocPrinter(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&printer_handles_cs);
|
||||
printer = get_opened_printer(hPrinter);
|
||||
if(!printer)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_HANDLE);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if(printer->doc)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PRINTER_STATE);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* 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))
|
||||
{
|
||||
ERR("AddJob failed gle %lu\n", GetLastError());
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue