Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1004 lines
28 KiB

/*
Copyright (c) 1992,1993 Microsoft Corporation
Module Name:
psprint.c
Abstract:
This module contains the Print Processor code for the
PStoDIB facility used to translate an incoming raw PostScript
Level 1 data format to DIB's which can then be rendered on an
output device.
The print processor itself is defined as part of the WIN32 spool
subsystem. A print processor dll is placed in a specific directory
(based on the return of GetPrintProcessorDirectory(). The print
processor is then added to the print subsystem by calling AddPrintProcessor()
This is typically done by a setup program. The print subsystem only
enumerates the print processors loaded at startup time. It does this
by calling EnumPrintProcessorDataTypes() for each print processor registered
with the spool subsystem. This information is kept and used to determine
which PrintProcessor to use at print time based on the Datatype.
This print processor exports the 4 required functions. They are:
EnumPrintProcessorDatatypes
OpenPrintProcessor
PrintDocumentOnPrintProcessor
ClosePrintProcessor
ControlPrintProcessor
The basic flow of a job from the spooler standpoint is as follows:
At startup of system:
Print subsystem enumerates all print processors registered in
the system. For each print processor the datatypes are queried
via EnumPrintProcessorDatatypes. This data is then stored
as part of the print spooler information.
A job is submitted via,
OpenPrinter()
StartDocPrinter() (Datatype = PSCRIPT1)
WritePrinter()
WritePrinter()
...
...
EndDocPrinter()
ClosePrinter()
When it comes time to print our job the spooler calls:
handle = OpenPrintProcessor(...)
PrintDocumentOnPrintProcessor( handle , ... )
ClosePrintProcessor( handle )
Optionally:
ControlPrintProcessor - For pausing jobs etc
The basic flow of our print processor is as follows:
EnumPrintProcessorDatatype
This simply returns PSCRIPT1 as a unicode string, this
is the ONLY datatype we support.
OpenPrintProcessor
Here we simply allocate some memory and record the data
passed in to us which is required to succesfully print the
postscript job
PrintDocumentOnPrintProcessor
This is the main worker routine. At this point all the relevant
data for the job is copied into some named shared memory thats
given a unique name based on our thread id. This name is then
passed to the PSEXE process we start via the command line.
PSEXE does all the interaction with PSTODIB when it completes
then PrintDocumentOnPrintProcessor returns. A process is created
because the ported trueimage interpreter was not re-entrant. Thus
there is no way to have multiple threads of the same process using
the interpreter simultaneously without the threads writing over
the interpreters global variables.
ClosePrintProcessor
This code simply cleans up any resources allocated and returns
to the spooler
ControlPrintProcessor
This code controls pausing/un-pausing and aborting a job that
is currently being interpreted. This is done my managing some bits
stored in shared memory that is visible to the exe we started.
Author:
James Bratsanos <[email protected] or mcrafts!jamesb>
Revision History:
15 Sep 1992 Initial Version
06 Dec 1992 Modified to kick off process instead of doing all work
internally
18 Mar 1993 Corrected EnumPrintProcessorDataTypes to return correctly
Notes: Tab stop: 4
--*/
#include <windows.h>
#include <memory.h>
#include <stdarg.h>
#include <stdio.h>
#include <winspool.h>
#include <winsplp.h>
#include "psshmem.h"
#include "psprint.h"
#include "psutl.h"
#include <excpt.h>
#include <string.h>
#include "debug.h"
#include "..\..\lib\psdiblib.h"
/*** EnumPrintProcessorDatatypes
*
* Returns back the different PrintProcessor data types which we
* support. Currently ONLY PSCRIPT1. If the caller passed in a buffer
* that was too small then we returned the required size.
*
* Return Value:
*
* FALSE = Success
* TRUE = Failure
*/
BOOL
EnumPrintProcessorDatatypes(
IN LPTSTR pName,
IN LPTSTR pPrintProcessorName,
IN DWORD Level,
OUT LPBYTE pDatatypes,
IN DWORD cbBuf,
OUT LPDWORD pcbNeeded,
OUT LPDWORD pcReturned
)
{
DATATYPES_INFO_1 *pInfo1 = (DATATYPES_INFO_1 *)pDatatypes;
DWORD cbTotal=0;
LPBYTE pEnd;
*pcReturned = 0;
// If the user passed in a NULL pointer there can be no lentgh
// associated so zero out
if ( pDatatypes == (LPBYTE) NULL ) {
cbBuf = (DWORD) 0;
}
pEnd = (LPBYTE) ( (LPBYTE)pInfo1 + cbBuf);
cbTotal += lstrlen(PSTODIB_DATATYPE) *sizeof(TCHAR) + sizeof(TCHAR) +
sizeof(DATATYPES_INFO_1);
*pcbNeeded = cbTotal;
// If there is room in the buffer return the string
if (cbTotal <= cbBuf) {
pEnd -=(BYTE)( lstrlen(PSTODIB_DATATYPE) *sizeof(TCHAR) + sizeof(TCHAR));
lstrcpy((LPTSTR) pEnd, PSTODIB_DATATYPE);
pInfo1->pName = (LPTSTR) pEnd;
(*pcReturned)++;
} else{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
return( TRUE );
}
/*** OpenPrintProcessor
*
* Returns a HANDLE to an open print processor which is then used
* to uniquely identify this print processor in future function calls
* to PrintDocumentOnPrintProcessor, ClosePrintProcessor and
* ControlPrintProcessor.
*
* Return Value:
*
* NULL = Failure
* !NULL = Success
*/
HANDLE
OpenPrintProcessor(
IN LPTSTR pPrinterName,
IN PPRINTPROCESSOROPENDATA pPrintProcessorOpenData
)
{
PPRINTPROCESSORDATA pData;
HANDLE hHeap;
DWORD uDatatype=0;
HANDLE hPrinter=0;
LPBYTE pEnd;
LPBYTE pBuffer;
HDC hDC;
DWORD dwTotDevMode;
// If for some reason the spool subsystem called us with a datatype other
// than PSCRIPT1 then return back a NULL handle since we dont know
// how to handle anything other than PSCRIPT1
if (lstrcmp( PSTODIB_DATATYPE, pPrintProcessorOpenData->pDatatype) != 0 ) {
SetLastError(ERROR_INVALID_DATATYPE);
return( (HANDLE) NULL );
}
// Allocate some memory for our job instance data
pData = (PPRINTPROCESSORDATA) LocalAlloc( LPTR, sizeof(PRINTPROCESSORDATA));
if (pData == (PPRINTPROCESSORDATA) NULL) {
PsLogEvent(EVENT_PSTODIB_MEM_ALLOC_FAILURE,
0,
NULL,
PSLOG_ERROR);
DBGOUT((TEXT("Memory allocation for local job storage failed")));
SetLastError( ERROR_NOT_ENOUGH_MEMORY);
return((HANDLE)NULL);
}
pData->cb = sizeof(PRINTPROCESSORDATA);
pData->signature = PRINTPROCESSORDATA_SIGNATURE;
pData->JobId = pPrintProcessorOpenData->JobId;
pData->pPrinterName = AllocStringAndCopy(pPrinterName);
pData->pDatatype = AllocStringAndCopy( pPrintProcessorOpenData->pDatatype);
pData->pDocument = AllocStringAndCopy( pPrintProcessorOpenData->pDocumentName);
pData->pParameters = AllocStringAndCopy( pPrintProcessorOpenData->pParameters);
// Now copy the devmode
pData->pDevMode = NULL;
if (pPrintProcessorOpenData->pDevMode != (LPDEVMODE) NULL) {
dwTotDevMode = pPrintProcessorOpenData->pDevMode->dmSize +
pPrintProcessorOpenData->pDevMode->dmDriverExtra;
pData->pDevMode = (LPDEVMODE) LocalAlloc( NONZEROLPTR, dwTotDevMode );
if (pData->pDevMode != NULL) {
memcpy( (PVOID) pData->pDevMode,
(PVOID) pPrintProcessorOpenData->pDevMode,
dwTotDevMode );
pData->dwTotDevmodeSize = dwTotDevMode;
}
}
return( (HANDLE) pData );
}
/*** GenerateSharedMemoryInfo
*
*
* This function copies all the relevant information into some shared
* memory so we can pass the data to PSEXE.
*
* Entry:
* pDAta: Pointer to our internal print processor data that holds all
* required information for the current job we are processing
*
* lpPtr: Pointer to the base of our shared memory area
*
* Return Value:
* None
*
*/
VOID
GenerateSharedMemoryInfo(
IN PPRINTPROCESSORDATA pData,
IN LPVOID lpPtr
)
{
PPSPRINT_SHARED_MEMORY pShared;
pShared = lpPtr;
// Record the starting position of our dynamic data, ie where strings
// of variable length and the raw devmode bytes are stored.
//
pShared->dwNextOffset = sizeof(*pShared);
// Record the size for future reference, ie if something gets added etc
// this serves as a version number of sorts;
//
pShared->dwSize = sizeof(*pShared);
pShared->dwFlags = 0;
// Move the job id over
pShared->dwJobId = pData->JobId;
UTLPSCOPYTOSHARED( pShared,
pData->pPrinterName,
pShared->dwPrinterName,
(lstrlen(pData->pPrinterName) + 1 ) * sizeof(WCHAR) );
UTLPSCOPYTOSHARED( pShared,
pData->pDocument,
pShared->dwDocumentName,
(lstrlen(pData->pDocument) + 1 ) * sizeof(WCHAR));
UTLPSCOPYTOSHARED( pShared,
pData->pPrintDocumentDocName,
pShared->dwPrintDocumentDocName,
(lstrlen(pData->pPrintDocumentDocName) + 1) * sizeof(WCHAR));
UTLPSCOPYTOSHARED( pShared,
pData->pDevMode,
pShared->dwDevmode,
pData->pDevMode->dmSize + pData->pDevMode->dmDriverExtra);
UTLPSCOPYTOSHARED( pShared,
pData->pControlName,
pShared->dwControlName,
(lstrlen(pData->pControlName) + 1) * sizeof(WCHAR));
}
/*** PrintDocumentOnPrintProcessor
*
* This function gathers all required data needed to interpret/print a
* PostScript job, puts it in a shared memory area and kicks off a process
* called psexe to actually interpret/print the job. When PSEXE finally
* terminates this function returns.
*
* Starting a seperate process is done because the PSTODIB code is NOT
* re-entrant and thus requires a seperate data segment (for all its globals)
* for each seperate job were interpreting. Since the spooler is ONE exe
* with multiple threads all threads share the same data segment and thus
* dont provide the functionality we need to implement pstodib. Starting
* a seperate process guarantees a new DATA segment for all globals used
* in the PSTODIB component.
*
*
* Entry:
* hPrintProcessor: The handle we gave the print spooler via
* OpenPrintProcessor.
*
* pDocumentName: The document /printer to read from so we can retrieve
* the data for the current PostScript job we are to
* interpret.
*
* Return Value:
*
* TRUE = Success
* FALSE = Failure
*/
BOOL
PrintDocumentOnPrintProcessor(
HANDLE hPrintProcessor,
LPTSTR pDocumentName
)
{
PPRINTPROCESSORDATA pData;
DOC_INFO_1 DocInfo;
DWORD rc;
DWORD NoRead, NoWritten;
HANDLE hPrinter;
DOCINFO docInfo;
TCHAR szNameOfRegion[100];
TCHAR szBuff[100];
STARTUPINFO startUpInfo;
PROCESS_INFORMATION processInfo;
TCHAR szCmdLine[500];
WCHAR szwControlEventName[33];
DWORD dwProcessExitCode;
DWORD dwProcessPriorityClass;
DWORD dwThreadPriority;
DWORD dwSizeOfSharedMemory = 0;
LPVOID lpBase;
if (!(pData = ValidateHandle(hPrintProcessor))) {
SetLastError(ERROR_INVALID_HANDLE);
DBGOUT((TEXT("handle validation failure, PrintDocumentOnPrintProcessor")));
return FALSE;
}
// Store the document name so it can get copied into shared memory
pData->pPrintDocumentDocName = AllocStringAndCopy(pDocumentName);
wsprintf( szBuff, TEXT("%s%d"), PSTODIB_STRING, GetCurrentThreadId());
lstrcpy( szwControlEventName, szBuff);
lstrcat( szwControlEventName, PSTODIB_EVENT_STRING );
pData->pControlName = AllocStringAndCopy(szwControlEventName);
//
// Create an event to manage pausing/unpausing the print processor
//
pData->semPaused = CreateEvent(NULL, TRUE, TRUE,szwControlEventName);
dwSizeOfSharedMemory = sizeof(PSPRINT_SHARED_MEMORY);
dwSizeOfSharedMemory += ((((pData->pPrinterName?lstrlen(pData->pPrinterName):0) + 1 ) * sizeof(WCHAR))+3) & ~0x03;
dwSizeOfSharedMemory += ((((pData->pDocument?lstrlen(pData->pDocument):0) + 1 ) * sizeof(WCHAR))+3) & ~0x03;
dwSizeOfSharedMemory += ((((pData->pPrintDocumentDocName?lstrlen(pData->pPrintDocumentDocName):0) + 1) * sizeof(WCHAR))+3) & ~0x03;
dwSizeOfSharedMemory += (((pData->pDevMode?pData->pDevMode->dmSize:0) + (pData->pDevMode?pData->pDevMode->dmDriverExtra:0))+3) & ~0x03;
dwSizeOfSharedMemory += ((((pData->pControlName?lstrlen(pData->pControlName):0) + 1) * sizeof(WCHAR))+3) & ~0x03;
// Create a shared memory area that we can write to....
pData->hShared = CreateFileMapping( INVALID_HANDLE_VALUE, // out of paging file
NULL,
PAGE_READWRITE,
0,
dwSizeOfSharedMemory,
szBuff );
if (pData->hShared == (HANDLE) NULL) {
//
// Last error should already be set by CreateFileMapping
//
DBGOUT((TEXT("CreateFileMapping failure in psprint")));
return(FALSE);
}
lpBase = (PPSPRINT_SHARED_MEMORY) MapViewOfFile( pData->hShared,
FILE_MAP_WRITE,
0,
0,
dwSizeOfSharedMemory);
if (lpBase == (PPSPRINT_SHARED_MEMORY) NULL) {
//
// Last error should already be set by CreateFileMapping
//
DBGOUT((TEXT("MapViewOfFile failure in psprint")));
return(FALSE);
}
// Put all required information into the shared memory area we created
GenerateSharedMemoryInfo( pData, lpBase );
// Now mark the fact that the shared memory stuff exists
pData->pShared = (PPSPRINT_SHARED_MEMORY) lpBase;
pData->fsStatus |= PRINTPROCESSOR_SHMEM_DEF;
// Generate the string to pass to CreateProcess in order to start up
// PSEXE.
//
// NOTE: A interesting way to debug psexe is to simply start windbg
// first passing in psexe and the normal command line. I found
// this VERY useful during debuging.
//
//wsprintf( szCmdLine, TEXT("windbg %s %s"), PSEXE_STRING, szBuff);
wsprintf( szCmdLine, TEXT("%s %s"), PSEXE_STRING, szBuff);
// Define a STARTUPINFO structure required for CreateProcess. Since
// the new process runs DETACHED and has no console, most of the data is
// default or none.
startUpInfo.cb = sizeof(STARTUPINFO);
startUpInfo.lpReserved = NULL;
startUpInfo.lpDesktop = NULL;
startUpInfo.lpTitle = NULL;
startUpInfo.dwFlags = 0;
startUpInfo.cbReserved2 = 0;
startUpInfo.lpReserved2 = NULL;
// ***** IMPORTANT *****
// Create the process to actually interpret and print the specified
// PostScript job. We create this process suspended, because of the
// way the NT security system works. When CreateProcess is called we
// end up giving the security access token of the spooler process to
// PSEXE, this is incorrect since we want to give PSEXE the security
// access token of the current thread. Since the job needs to access
// resources which the spooler (running in the system context) may not
// have access to but the client (whoever submitted the job) does. To
// do this we need to set the access token of the primary thread of
// PSEXE to whatever access token the current thread has. The way
// this works is to create the process SUSPENDED then set the security
// access token of the primary thread of PSEXE, then Resume the
// thread to let it process our job. We sit blocked on WaitForSingleObject
// until the job completes.
//
//
if(!CreateProcess(NULL,
szCmdLine,
NULL,
NULL,
FALSE,
#ifdef PSCHECKED
CREATE_SUSPENDED | CREATE_NEW_CONSOLE, //DEBUG
#else
CREATE_SUSPENDED | DETACHED_PROCESS,
#endif
NULL,
NULL,
&startUpInfo,
&processInfo ) ) {
//
// Last error should already be set by CreateProcess
//
PsPrintLogEventAndIncludeLastError( EVENT_PSTODIB_STARTPSEXE_FAILED,
TRUE );
DBGOUT((TEXT("Create Process failed")));
return(FALSE);
}
#ifdef OLD_PRIORITY
if (!SetPriorityClass(processInfo.hProcess, IDLE_PRIORITY_CLASS)){
DBGOUT((TEXT("Failed trying to reset the priority class")));
}
#endif
// Just to make sure the thread priority of our new thread matches,
// the spooler and the Priority class of our exe matches the spooler
//
if( (dwProcessPriorityClass = GetPriorityClass( GetCurrentProcess())) != 0 ) {
if (!SetPriorityClass( processInfo.hProcess, dwProcessPriorityClass)) {
PsPrintLogEventAndIncludeLastError( EVENT_PSTODIB_SETPRIORITY_FAILED,
FALSE );
DBGOUT((TEXT("Failed trying to reset priority class for smfpsexe")));
}
} else {
PsPrintLogEventAndIncludeLastError( EVENT_PSTODIB_SETPRIORITY_FAILED,
FALSE );
DBGOUT((TEXT("Cannot retrieve current priority class!")));
}
//
// Grab the current threads priority
//
if ((dwThreadPriority = GetThreadPriority( GetCurrentThread())) !=
THREAD_PRIORITY_ERROR_RETURN ) {
// It worked so set the thread priority
if (!SetThreadPriority( processInfo.hThread, dwThreadPriority)) {
PsPrintLogEventAndIncludeLastError( EVENT_PSTODIB_SETPRIORITY_FAILED,
FALSE );
DBGOUT((TEXT("Setting thread priority failed for sfmpsexe")));
}
} else {
PsPrintLogEventAndIncludeLastError( EVENT_PSTODIB_SETPRIORITY_FAILED,
FALSE );
DBGOUT((TEXT("Cannot retrieve thread priority, sfmpsprt.dll")));
}
// Why the #if 0 below....
// NT-Spooler always runs under LocalSystem. If macprint also runs as LocalSystem,
// then setting security token is a no-op. If macprint runs in some user's account then
// we run into the following problem: user32.dll fails to initialize because this new
// process running under user's context tries to access winsta0 and fails because it's got
// no privileges (only LocalSystem, not even admins get this priv). If we don't put this
// user's token, we don't lose anything except one case: if the port is configured to go to
// a unc name (e.g. \\foobar\share) where LocalSystem won't have priv, but the user will.
// But this case is a generic problem in NT-Spooler, so it's an ok compromise
//
// p.s. another solution considered: create this process with a different winsta (pass an
// empty string for lpDesktop parm above, instead of NULL). This works ok except if there
// is any dialog generated - the dialog shows up in the process's winsta, not on the desktop
// which causes the job to "hang" waiting for input! A common case of a dialog appearing is
// if the port configured is FILE.
#if 0
// Set the security access token of the primary thread of PSEXE, the
// reason for that the spooler is imporsonating the client which
// submitted the job when we get here. Since we are kicking off another
// process to do the real work for us, this new process primary thread
// must have the same privelege as the current thread (namely the client
// which submitted the job). This relies on the fact the Spooler is
// imporsonating and thus we will fail the job if the access token
// transfer fails.
//
if ( !PsUtlSetThreadToken( processInfo.hThread )) {
/*
* PsPrintLogEventAndIncludeLastError( EVENT_PSTODIB_SECURITY_PROBLEM,
* TRUE );
*/
DBGOUT((TEXT("Failed trying to reset the thread token")));
//
// The code that sets the abort flag used to force the job
// to abort. Since this behaviour does not mimick the spooler
// we will take it out. This always caused any pstodib jobs
// which hung around past a reboot to fail.
//
// JSB 6-25-93
//
//pData->pShared->dwFlags |= PS_SHAREDMEM_SECURITY_ABORT;
}
#endif
//
// Now that we have/have not set the thread security access token for PSEXE
// let it run its course
//
ResumeThread( processInfo.hThread);
//
// Now wait for the Interpreter to complete for any reason since
// the spool subsystem does not expect us to return from
// PrintDocumentOnPrintProcessor until the job is complete
//
WaitForSingleObject( processInfo.hProcess, INFINITE);
// Get the termination reason
GetExitCodeProcess( processInfo.hProcess, &dwProcessExitCode);
// Close the handles which are not required any more
//
CloseHandle( processInfo.hProcess );
CloseHandle( processInfo.hThread );
// Clean up resources used by shared memory
//
return( (dwProcessExitCode == 0) ? TRUE : FALSE );
}
/*** PsLocalFree
*
* This function simply verifies the handle is not null and calls localfree
*
* Entry:
* lpPtr: The pointer to free if not null
*
* Exit:
* none;
*
*/
VOID PsLocalFree( IN LPVOID lpPtr )
{
if (lpPtr != (LPVOID) NULL) {
LocalFree( (HLOCAL) lpPtr);
}
}
/*** ClosePrintProcessor
*
* This functions simply cleans up any resources we used during our
* job and returs:
*
* Entry:
* hPrintProcessor: The handle we returned to the spooler in the
* OpenPrintProcessor call.
*
* Exit:
* True = Success
* False = failure;
*
*/
BOOL
ClosePrintProcessor(
IN HANDLE hPrintProcessor
)
{
PPRINTPROCESSORDATA pData;
HANDLE hHeap;
pData = ValidateHandle(hPrintProcessor);
if (!pData) {
SetLastError(ERROR_INVALID_HANDLE);
DBGOUT((TEXT("Invalid handle to closeprintprocessor, psprint")));
return FALSE;
}
pData->fsStatus &= ~PRINTPROCESSOR_SHMEM_DEF;
if (pData->pShared != (PPSPRINT_SHARED_MEMORY) NULL) {
UnmapViewOfFile( (LPVOID) pData->pShared );
}
if (pData->hShared != (HANDLE) NULL) {
CloseHandle( pData->hShared );
}
pData->signature = 0;
/* Release any allocated resources */
if( pData->semPaused != (HANDLE) NULL ) {
CloseHandle(pData->semPaused);
}
PsLocalFree( (LPVOID) pData->pPrinterName);
PsLocalFree( (LPVOID) pData->pDatatype );
PsLocalFree( (LPVOID) pData->pDocument );
PsLocalFree( (LPVOID) pData->pParameters);
PsLocalFree( (LPVOID) pData->pControlName);
PsLocalFree( (LPVOID) pData->pDevMode );
PsLocalFree( (LPVOID) pData->pPrintDocumentDocName );
PsLocalFree( (LPVOID) pData );
return TRUE;
}
/* ControlPrintProcessor
*
* This function controls pausing/unpausing of the print processor as well
* aborting the current job, mainly this routine either sets/clears a named
* event that the psexe program responds to, or sets a bit in some shared
* memory to tell psexe to abort the current job
*
* Entry:
* hPrintProcessor: The handle we returned to the spooler in the
* OpenPrintProcessor call.
*
* Command: JOB_CONTROL_* (PAUSE,CANCEL,RESUME) as defined by
* the Win32 print processor specification
*
* Exit:
* TRUE: Request was satisfied
* FALSE: Request was NOT satisfied
*
*/
BOOL
ControlPrintProcessor(
IN HANDLE hPrintProcessor,
IN DWORD Command
)
{
PPRINTPROCESSORDATA pData;
if (pData = ValidateHandle(hPrintProcessor)) {
switch (Command) {
case JOB_CONTROL_PAUSE:
ResetEvent(pData->semPaused);
return(TRUE);
break;
case JOB_CONTROL_CANCEL:
if (pData->fsStatus & PRINTPROCESSOR_SHMEM_DEF) {
// shared memory is defined so update the bit in the shared
// memory areay that signal aborting of the job
// shared memory that define our state
pData->pShared->dwFlags |= PS_SHAREDMEM_ABORTED;
}
/**** Intentional fall through to release job if paused */
case JOB_CONTROL_RESUME:
SetEvent(pData->semPaused);
return(TRUE);
break;
default:
return(FALSE);
break;
}
} else {
DBGOUT((TEXT("ControlPrintProcessor was passed an invalid handle, psprint")));
}
return( FALSE );
}
// NOT IMPLEMENTED BY SPOOLER YET, as of 3/14/93
BOOL
InstallPrintProcessor(
HWND hWnd
)
{
MessageBox(hWnd, TEXT("SfmPsPrint"), TEXT("Print Processor Setup"), MB_OK);
return TRUE;
}
/* ValidateHandle
*
* Helper function which verifies the passed in handle is really a
* handle to our own internal data structure
*
* Entry
*
* hQProc: Handle to our internal data structure
*
* Exit:
*
* NULL: Not a valid internal data structure
* !NULL: A valid pointer to our internal data structure
*
*/
PPRINTPROCESSORDATA
ValidateHandle(
HANDLE hQProc
)
{
PPRINTPROCESSORDATA pData = (PPRINTPROCESSORDATA)hQProc;
if (pData && pData->signature == PRINTPROCESSORDATA_SIGNATURE)
return( pData );
else {
return( NULL );
}
}
#ifdef MYPSDEBUG
/* DbgPsPrint
*
* Debuger message facility which also pops up a message box
*
* Entry:
* wprintf style format/ var arg data
*
* Exit:
* nothing (void function)
*
*/
VOID
DbgPsPrint(
PTCHAR ptchFormat, ...
)
{
va_list marker;
TCHAR buffer[512];
va_start( marker, ptchFormat );
wvsprintf( buffer, ptchFormat, marker );
va_end( marker );
OutputDebugString( buffer );
MessageBox( (HWND) NULL, (LPTSTR) &buffer, TEXT("SFMPsPrint"), MB_OK);
}
#endif
/* AllocStringAndCopy
*
* Helper function which allocates some memory and copies the source
* string into it
*
* Entry:
* lpSrc: Pointer to string to copy
*
* Exit:
* NULL: Failure
* !NULL: Pointer to newly allocated memory with string copied into it
*
*/
LPTSTR
AllocStringAndCopy(
LPTSTR lpSrc
)
{
LPTSTR pRetString=(LPTSTR)NULL;
// Allocate the memory for the string
if (lpSrc) {
pRetString = (LPTSTR) LocalAlloc(LPTR, (lstrlen(lpSrc) + 1) * sizeof(TCHAR));
if (pRetString != (LPTSTR) NULL) {
lstrcpy( pRetString, lpSrc );
} else{
PsLogEvent(EVENT_PSTODIB_MEM_ALLOC_FAILURE,
0,
NULL,
PSLOG_ERROR);
}
}
return(pRetString);
}
VOID
PsPrintLogEventAndIncludeLastError(
IN DWORD dwErrorEvent,
IN BOOL bError )
{
TCHAR atBuff[20];
TCHAR *aStrs[2];
wsprintf( atBuff,TEXT("%d"), GetLastError());
aStrs[0] = atBuff;
PsLogEvent( dwErrorEvent,
1,
aStrs,
PSLOG_ERROR );
}