523 lines
13 KiB
C
523 lines
13 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
prnsupp.c
|
||
|
||
Abstract:
|
||
|
||
This module contains routines for supporting printing in the NT
|
||
server. Many of these routines are wrappers that send the request
|
||
off to XACTSRV through LPC in order to issue a user-mode API.
|
||
|
||
Author:
|
||
|
||
David Treadwell (davidtr) 05-Nov-1991
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#include "prnsupp.tmh"
|
||
#pragma hdrstop
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text( PAGE, SrvOpenPrinter )
|
||
#pragma alloc_text( PAGE, SrvAddPrintJob )
|
||
#pragma alloc_text( PAGE, SrvSchedulePrintJob )
|
||
#pragma alloc_text( PAGE, SrvClosePrinter )
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
SrvOpenPrinter(
|
||
IN PWCH PrinterName,
|
||
OUT PHANDLE phPrinter,
|
||
OUT PULONG Error
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is a kernel-mode wrapper for the the user-mode API
|
||
OpenPrinter( ). This packages up a call and sends it off to
|
||
Xactsrv, which makes the actual API call.
|
||
|
||
Arguments:
|
||
|
||
Printer - a pointer to a Unicode string of the printer to open
|
||
|
||
Handle - receives a handle, valid only in XACTSRV, that corresponds to
|
||
the Printer open.
|
||
|
||
Error - a Win32 error if one occurred, or NO_ERROR if the operation
|
||
was successful.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - result of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
XACTSRV_REQUEST_MESSAGE requestMessage;
|
||
XACTSRV_REPLY_MESSAGE replyMessage;
|
||
PSZ printerName;
|
||
ULONG printerNameLength;
|
||
|
||
PAGED_CODE( );
|
||
|
||
printerNameLength = wcslen( PrinterName ) * sizeof(WCHAR) + sizeof(WCHAR);
|
||
|
||
printerName = SrvXsAllocateHeap( printerNameLength, &status );
|
||
|
||
if ( printerName == NULL ) {
|
||
*Error = RtlNtStatusToDosErrorNoTeb( status );
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// SrvXsResource is held at this point
|
||
//
|
||
|
||
//
|
||
// Copy over the printer name to the new memory.
|
||
//
|
||
|
||
RtlCopyMemory( printerName, PrinterName, printerNameLength );
|
||
|
||
//
|
||
// Set up the message to send over the port.
|
||
//
|
||
|
||
requestMessage.PortMessage.u1.s1.DataLength =
|
||
sizeof(requestMessage) - sizeof(PORT_MESSAGE);
|
||
requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
|
||
requestMessage.PortMessage.u2.ZeroInit = 0;
|
||
requestMessage.PortMessage.u2.s2.Type = LPC_KERNELMODE_MESSAGE;
|
||
requestMessage.MessageType = XACTSRV_MESSAGE_OPEN_PRINTER;
|
||
requestMessage.Message.OpenPrinter.PrinterName =
|
||
(PCHAR)printerName + SrvXsPortMemoryDelta;
|
||
|
||
//
|
||
// Send the message to XACTSRV so it can call OpenPrinter( ).
|
||
//
|
||
// !!! We may want to put a timeout on this.
|
||
|
||
IF_DEBUG(XACTSRV) {
|
||
SrvPrint2( "SrvOpenPrinter: sending message at %p PrinterName %s\n",
|
||
&requestMessage,
|
||
(PCHAR)requestMessage.Message.OpenPrinter.PrinterName );
|
||
}
|
||
|
||
status = NtRequestWaitReplyPort(
|
||
SrvXsPortHandle,
|
||
(PPORT_MESSAGE)&requestMessage,
|
||
(PPORT_MESSAGE)&replyMessage
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
IF_DEBUG(ERRORS) {
|
||
SrvPrint1( "SrvOpenPrinter: NtRequestWaitReplyPort failed: %X\n",
|
||
status );
|
||
}
|
||
|
||
SrvLogServiceFailure( SRV_SVC_NT_REQ_WAIT_REPLY_PORT, status );
|
||
*Error = ERROR_UNEXP_NET_ERR;
|
||
goto exit;
|
||
}
|
||
|
||
IF_DEBUG(XACTSRV) {
|
||
SrvPrint1( "SrvOpenPrinter: received response at %p\n", &replyMessage );
|
||
}
|
||
|
||
*phPrinter = replyMessage.Message.OpenPrinter.hPrinter;
|
||
*Error = replyMessage.Message.OpenPrinter.Error;
|
||
|
||
exit:
|
||
|
||
SrvXsFreeHeap( printerName );
|
||
|
||
return status;
|
||
|
||
} // SrvOpenPrinter
|
||
|
||
|
||
NTSTATUS
|
||
SrvAddPrintJob (
|
||
IN PWORK_CONTEXT WorkContext,
|
||
IN HANDLE Handle,
|
||
IN OUT PUNICODE_STRING FileName,
|
||
OUT PULONG JobId,
|
||
OUT PULONG Error
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is a kernel-mode wrapper for the user-mode API AddJob( ).
|
||
This API returns a filename to use as a disk spool file and a
|
||
Job ID to identify the print job to the spooler subsystem.
|
||
|
||
Arguments:
|
||
|
||
Handle - the Printer handle.
|
||
|
||
FileName - filled in with the Unicode name of the file to open as
|
||
a spool filed. The MaximumLength and Buffer fields should
|
||
be valid on input and are not changed. Length is changed to
|
||
indicate the length of the NT path name of the file.
|
||
|
||
JobId - filled in with the Job ID of the print job. This value
|
||
is used to call ScheduleJob( ) when the writing of the spool
|
||
file is complete and printing should begin.
|
||
|
||
Error - if AddJob failed in XACTSRV, this is the error code.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - result of operation. If AddJob( ) failed, NTSTATUS =
|
||
STATUS_UNSUCCESSFUL and Error contains the real error code.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
XACTSRV_REQUEST_MESSAGE requestMessage;
|
||
XACTSRV_REPLY_MESSAGE replyMessage;
|
||
ANSI_STRING fileName;
|
||
PCONNECTION connection = WorkContext->Connection;
|
||
PWCH destPtr, sourcePtr, sourceEndPtr;
|
||
|
||
PAGED_CODE( );
|
||
|
||
*Error = NO_ERROR;
|
||
fileName.Buffer = NULL;
|
||
|
||
//
|
||
// Allocate space to hold the buffer for the file name that will be
|
||
// returned.
|
||
//
|
||
|
||
fileName.Buffer = SrvXsAllocateHeap(
|
||
MAXIMUM_FILENAME_LENGTH * sizeof(WCHAR),
|
||
&status
|
||
);
|
||
|
||
if ( fileName.Buffer == NULL ) {
|
||
*Error = RtlNtStatusToDosErrorNoTeb( status );
|
||
return(status);
|
||
}
|
||
|
||
//
|
||
// SrvXsResource is held at this point
|
||
//
|
||
|
||
//
|
||
// Set up the message to send over the port.
|
||
//
|
||
|
||
requestMessage.PortMessage.u1.s1.DataLength =
|
||
sizeof(requestMessage) - sizeof(PORT_MESSAGE);
|
||
requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
|
||
requestMessage.PortMessage.u2.ZeroInit = 0;
|
||
requestMessage.PortMessage.u2.s2.Type = LPC_KERNELMODE_MESSAGE;
|
||
requestMessage.MessageType = XACTSRV_MESSAGE_ADD_JOB_PRINTER;
|
||
requestMessage.Message.AddPrintJob.hPrinter = Handle;
|
||
requestMessage.Message.AddPrintJob.Buffer =
|
||
fileName.Buffer + SrvXsPortMemoryDelta;
|
||
requestMessage.Message.AddPrintJob.BufferLength = MAXIMUM_FILENAME_LENGTH;
|
||
|
||
// Add client machine name for notification
|
||
//
|
||
// Copy the client machine name for XACTSRV, skipping over the
|
||
// initial "\\", and deleting trailing spaces.
|
||
//
|
||
|
||
destPtr = requestMessage.Message.AddPrintJob.ClientMachineName;
|
||
sourcePtr =
|
||
connection->ClientMachineNameString.Buffer + 2;
|
||
sourceEndPtr = sourcePtr
|
||
+ min( connection->ClientMachineNameString.Length,
|
||
sizeof(requestMessage.Message.AddPrintJob.ClientMachineName) /
|
||
sizeof(WCHAR) - 1 );
|
||
|
||
while ( sourcePtr < sourceEndPtr && *sourcePtr != UNICODE_NULL ) {
|
||
*destPtr++ = *sourcePtr++;
|
||
}
|
||
|
||
*destPtr-- = UNICODE_NULL;
|
||
|
||
while ( destPtr >= requestMessage.Message.AddPrintJob.ClientMachineName
|
||
&&
|
||
*destPtr == L' ' ) {
|
||
*destPtr-- = UNICODE_NULL;
|
||
}
|
||
|
||
|
||
//
|
||
// Send the message to XACTSRV so it can call AddJob( ).
|
||
//
|
||
// !!! We may want to put a timeout on this.
|
||
|
||
IF_DEBUG(XACTSRV) {
|
||
SrvPrint1( "SrvAddPrintJob: sending message at %p", &requestMessage );
|
||
}
|
||
|
||
status = IMPERSONATE( WorkContext );
|
||
|
||
if( NT_SUCCESS( status ) ) {
|
||
status = NtRequestWaitReplyPort(
|
||
SrvXsPortHandle,
|
||
(PPORT_MESSAGE)&requestMessage,
|
||
(PPORT_MESSAGE)&replyMessage
|
||
);
|
||
|
||
REVERT( );
|
||
}
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
IF_DEBUG(ERRORS) {
|
||
SrvPrint1( "SrvAddPrintJob: NtRequestWaitReplyPort failed: %X\n",
|
||
status );
|
||
}
|
||
|
||
SrvLogServiceFailure( SRV_SVC_NT_REQ_WAIT_REPLY_PORT, status );
|
||
|
||
*Error = ERROR_UNEXP_NET_ERR;
|
||
goto exit;
|
||
}
|
||
|
||
IF_DEBUG(XACTSRV) {
|
||
SrvPrint1( "SrvAddPrintJob: received response at %p\n", &replyMessage );
|
||
}
|
||
|
||
if ( replyMessage.Message.AddPrintJob.Error != NO_ERROR ) {
|
||
*Error = replyMessage.Message.AddPrintJob.Error;
|
||
status = STATUS_UNSUCCESSFUL;
|
||
goto exit;
|
||
}
|
||
|
||
//
|
||
// Set up return information.
|
||
//
|
||
|
||
*JobId = replyMessage.Message.AddPrintJob.JobId;
|
||
FileName->Length = MIN(replyMessage.Message.AddPrintJob.BufferLength, FileName->MaximumLength );
|
||
RtlCopyMemory( FileName->Buffer, fileName.Buffer, FileName->Length );
|
||
|
||
exit:
|
||
|
||
SrvXsFreeHeap( fileName.Buffer );
|
||
|
||
return status;
|
||
|
||
} // SrvAddPrintJob
|
||
|
||
|
||
NTSTATUS
|
||
SrvSchedulePrintJob (
|
||
IN HANDLE PrinterHandle,
|
||
IN ULONG JobId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is a kernel-mode wrapper for the the user-mode API
|
||
ScheduleJob( ).
|
||
|
||
Arguments:
|
||
|
||
PrinterHandle - a handle to a printer returned by OpenPrinter( ).
|
||
|
||
JobId - the job ID returned to AddJob( ) that identifies this print
|
||
job.
|
||
|
||
Error - if ScheduleJob failed in XACTSRV, this is the error code.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - result of operation. If ScheduleJob( ) failed, NTSTATUS =
|
||
STATUS_UNSUCCESSFUL and Error contains the real error code.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
XACTSRV_REQUEST_MESSAGE requestMessage;
|
||
XACTSRV_REPLY_MESSAGE replyMessage;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// Grab the XsResource
|
||
//
|
||
|
||
(VOID) SrvXsAllocateHeap( 0, &status );
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Set up the message to send over the port.
|
||
//
|
||
|
||
requestMessage.PortMessage.u1.s1.DataLength =
|
||
sizeof(requestMessage) - sizeof(PORT_MESSAGE);
|
||
requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
|
||
requestMessage.PortMessage.u2.ZeroInit = 0;
|
||
requestMessage.PortMessage.u2.s2.Type = LPC_KERNELMODE_MESSAGE;
|
||
requestMessage.MessageType = XACTSRV_MESSAGE_SCHD_JOB_PRINTER;
|
||
requestMessage.Message.SchedulePrintJob.hPrinter = PrinterHandle;
|
||
requestMessage.Message.SchedulePrintJob.JobId = JobId;
|
||
|
||
//
|
||
// Send the message to XACTSRV so it can call ScheduleJob( ).
|
||
//
|
||
// !!! We may want to put a timeout on this.
|
||
|
||
IF_DEBUG(XACTSRV) {
|
||
SrvPrint1( "SrvSchedulePrintJob: sending message at %p", &requestMessage );
|
||
}
|
||
|
||
status = NtRequestWaitReplyPort(
|
||
SrvXsPortHandle,
|
||
(PPORT_MESSAGE)&requestMessage,
|
||
(PPORT_MESSAGE)&replyMessage
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
IF_DEBUG(ERRORS) {
|
||
SrvPrint1( "SrvSchedulePrintJob: NtRequestWaitReplyPort failed: %X\n",
|
||
status );
|
||
}
|
||
|
||
SrvLogServiceFailure( SRV_SVC_NT_REQ_WAIT_REPLY_PORT, status );
|
||
goto exit;
|
||
}
|
||
|
||
IF_DEBUG(XACTSRV) {
|
||
SrvPrint1( "SrvSchedulePrintJob: received response at %p\n",
|
||
&replyMessage );
|
||
}
|
||
|
||
exit:
|
||
|
||
//
|
||
// release the lock
|
||
//
|
||
|
||
SrvXsFreeHeap( NULL );
|
||
|
||
return status;
|
||
|
||
} // SrvSchedulePrintJob
|
||
|
||
|
||
NTSTATUS
|
||
SrvClosePrinter (
|
||
IN HANDLE Handle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is a kernel-mode wrapper for the the user-mode API
|
||
ClosePrinter( ).
|
||
|
||
Arguments:
|
||
|
||
Handle - the Printer handle to close.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - result of operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
XACTSRV_REQUEST_MESSAGE requestMessage;
|
||
XACTSRV_REPLY_MESSAGE replyMessage;
|
||
|
||
PAGED_CODE( );
|
||
|
||
//
|
||
// Grab the XsResource
|
||
//
|
||
|
||
(VOID) SrvXsAllocateHeap( 0, &status );
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// SrvXsResource is held at this point
|
||
//
|
||
|
||
|
||
//
|
||
// Set up the message to send over the port.
|
||
//
|
||
|
||
requestMessage.PortMessage.u1.s1.DataLength =
|
||
sizeof(requestMessage) - sizeof(PORT_MESSAGE);
|
||
requestMessage.PortMessage.u1.s1.TotalLength = sizeof(requestMessage);
|
||
requestMessage.PortMessage.u2.ZeroInit = 0;
|
||
requestMessage.PortMessage.u2.s2.Type = LPC_KERNELMODE_MESSAGE;
|
||
requestMessage.MessageType = XACTSRV_MESSAGE_CLOSE_PRINTER;
|
||
requestMessage.Message.ClosePrinter.hPrinter = Handle;
|
||
|
||
//
|
||
// Send the message to XACTSRV so it can call ClosePrinter( ).
|
||
//
|
||
// !!! We may want to put a timeout on this.
|
||
|
||
IF_DEBUG(XACTSRV) {
|
||
SrvPrint1( "SrvClosePrinter: sending message at %p", &requestMessage );
|
||
}
|
||
|
||
status = NtRequestWaitReplyPort(
|
||
SrvXsPortHandle,
|
||
(PPORT_MESSAGE)&requestMessage,
|
||
(PPORT_MESSAGE)&replyMessage
|
||
);
|
||
|
||
if ( !NT_SUCCESS(status) ) {
|
||
IF_DEBUG(ERRORS) {
|
||
SrvPrint1( "SrvClosePrinter: NtRequestWaitReplyPort failed: %X\n",
|
||
status );
|
||
}
|
||
|
||
SrvLogServiceFailure( SRV_SVC_NT_REQ_WAIT_REPLY_PORT, status );
|
||
goto exit;
|
||
}
|
||
|
||
IF_DEBUG(XACTSRV) {
|
||
SrvPrint1( "SrvClosePrinter: received response at %p\n", &replyMessage );
|
||
}
|
||
|
||
exit:
|
||
|
||
//
|
||
// release the lock
|
||
//
|
||
|
||
SrvXsFreeHeap( NULL );
|
||
|
||
return status;
|
||
|
||
} // SrvClosePrinter
|
||
|