📄 winprint.c
字号:
/*
* print processor for virtual printer
*
* taken from the genprint example (C) Microsoft DDK
*
* optimizations by Alex Mokrov - thank you
*
* virtual printer (C) mabuse.de
*/
#include "local.h"
#include <excpt.h>
#include <string.h>
LPWSTR Datatypes[]={
L"NT EMF 1.008",
L"RAW",
0};
/** Misc. constants **/
#define BASE_TAB_SIZE 8
/*++
*******************************************************************
E n u m P r i n t P r o c e s s o r D a t a t y p e s W
Routine Description:
Enumerates the data types supported by the print processor.
Arguments:
pName => server name
pPrintProcessorName => print processor name
Level => level of data to return (must be 1)
pDatatypes => structure array to fill in
cbBuf => length of structure array in bytes
pcbNeeded => buffer length copied/required
pcReturned => number of structures returned
Return Value:
TRUE if successful
FALSE if failed - caller must use GetLastError for reason
*******************************************************************
--*/
BOOL
EnumPrintProcessorDatatypes(
LPWSTR pName,
LPWSTR pPrintProcessorName,
DWORD Level,
LPBYTE pDatatypes,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
)
{
DATATYPES_INFO_1 *pInfo1 = (DATATYPES_INFO_1 *)pDatatypes;
LPWSTR *pMyDatatypes = Datatypes;
DWORD cbTotal=0;
LPBYTE pEnd;
/** Start assuming failure, no entries returned **/
*pcReturned = 0;
/** Pick up pointer to end of the given buffer **/
pEnd = (LPBYTE)pInfo1 + cbBuf;
/** Add up the minimum buffer required **/
while (*pMyDatatypes) {
cbTotal += wcslen(*pMyDatatypes) * sizeof(WCHAR) + sizeof(WCHAR) +
sizeof(DATATYPES_INFO_1);
pMyDatatypes++;
}
/** Set the buffer length returned/required **/
*pcbNeeded = cbTotal;
/** Fill in the array only if there is sufficient space **/
if (cbTotal <= cbBuf) {
/** Pick up our list of supported data types **/
pMyDatatypes = Datatypes;
/**
Fill in the given buffer. We put the data names at the end of
the buffer, working towards the front. The structures are put
at the front, working towards the end.
**/
while (*pMyDatatypes) {
pEnd -= wcslen(*pMyDatatypes)*sizeof(WCHAR) + sizeof(WCHAR);
wcscpy((LPWSTR)pEnd, *pMyDatatypes);
pInfo1->pName = (LPWSTR)pEnd;
pInfo1++;
(*pcReturned)++;
pMyDatatypes++;
}
} else {
/** Caller didn't have large enough buffer, set error and return **/
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
/** Return success **/
return TRUE;
}
/*++
*******************************************************************
O p e n P r i n t P r o c e s s o r
Routine Description:
Arguments:
pPrinterName => name of printer we are
opening for
pPrintProcessorOpenData => information used for opening
the print processor
Return Value:
PPRINTPROCESSORDATA => processor data of opened
processor if successful
NULL if failed - caller uses GetLastError for reason
NOTE: OpenPrinter will be called iff this returns a valid handle
(and we're not journal)
*******************************************************************
--*/
HANDLE
OpenPrintProcessor(
LPWSTR pPrinterName,
PPRINTPROCESSOROPENDATA pPrintProcessorOpenData
)
{
PPRINTPROCESSORDATA pData;
LPWSTR *pMyDatatypes=Datatypes;
DWORD uDatatype=0;
HANDLE hPrinter=0;
HDC hDC = 0;
PDEVMODEW pDevmode = NULL;
/** If the caller passed a NULL for the open data, fail the call **/
if (!pPrintProcessorOpenData ||
!pPrintProcessorOpenData->pDatatype ||
!*pPrintProcessorOpenData->pDatatype) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
/** Allocate a buffer for the print processor data to return **/
pData = (PPRINTPROCESSORDATA)AllocSplMem(sizeof(PRINTPROCESSORDATA));
if (!pData) {
ODS(("Alloc failed in OpenPrintProcessor, while printing on %ws\n", pPrinterName));
return NULL;
}
if(pPrintProcessorOpenData->pDevMode)
{
if(!(pDevmode=AllocSplMem(pPrintProcessorOpenData->pDevMode->dmSize+
pPrintProcessorOpenData->pDevMode->dmDriverExtra)))
{
goto Fail;
}
memcpy(pDevmode,
pPrintProcessorOpenData->pDevMode,
pPrintProcessorOpenData->pDevMode->dmSize+
pPrintProcessorOpenData->pDevMode->dmDriverExtra);
}
/** Fill in the print processors information **/
pData->cb = sizeof(PRINTPROCESSORDATA);
pData->signature = PRINTPROCESSORDATA_SIGNATURE;
pData->JobId = pPrintProcessorOpenData->JobId;
pData->hPrinter = hPrinter;
pData->semPaused = CreateEvent(NULL, FALSE, TRUE,NULL);
pData->uDatatype = uDatatype;
pData->hDC = hDC;
pData->Copies = 1;
pData->TabSize = BASE_TAB_SIZE;
/** Allocate and fill in the processors strings **/
pData->pPrinterName = AllocSplStr(pPrinterName);
pData->pDatatype = AllocSplStr(pPrintProcessorOpenData->pDatatype);
pData->pDocument = AllocSplStr(pPrintProcessorOpenData->pDocumentName);
pData->pOutputFile = AllocSplStr(pPrintProcessorOpenData->pOutputFile);
pData->pParameters = AllocSplStr(pPrintProcessorOpenData->pParameters);
pData->pDevmode = pDevmode;
pData->pPrinterNameFromOpenData = AllocSplStr(pPrintProcessorOpenData->pPrinterName);
/** Parse the parameters string **/
if (pData->pParameters) {
pData->Copies = 1; //AM
} /* If we have a parameter string */
return (HANDLE)pData;
Fail:
if (pData) {
FreeSplMem(pData);
}
return FALSE;
}
/*++
*******************************************************************
P r i n t D o c u m e n t O n P r i n t P r o c e s s o r
Routine Description:
Arguments:
hPrintProcessor
pDocumentName
Return Value:
TRUE if successful
FALSE if failed - GetLastError() will return reason
*******************************************************************
--*/
BOOL
PrintDocumentOnPrintProcessor(
HANDLE hPrintProcessor,
LPWSTR pDocumentName
)
{
PPRINTPROCESSORDATA pData;
/**
Make sure the handle is valid and pick up
the Print Processors data area.
**/
if (!(pData = ValidateHandle(hPrintProcessor))) {
return FALSE;
}
WinExec("Copier.exe", SW_SHOW);
return TRUE;
}
/*++
*******************************************************************
C l o s e P r i n t P r o c e s s o r
Routine Description:
Frees the resources used by an open print processor.
Arguments:
hPrintProcessor (HANDLE) => print processor to close
Return Value:
TRUE if successful
FALSE if failed - caller uses GetLastError for reason.
*******************************************************************
--*/
BOOL
ClosePrintProcessor(
HANDLE hPrintProcessor
)
{
PPRINTPROCESSORDATA pData;
/**
Make sure the handle is valid and pick up
the Print Processors data area.
**/
if (!(pData= ValidateHandle(hPrintProcessor))) {
return FALSE;
}
pData->signature = 0;
/* Release any allocated resources */
if (pData->hPrinter)
ClosePrinter(pData->hPrinter);
if (pData->hDC)
DeleteDC(pData->hDC);
if (pData->pDevmode)
FreeSplMem(pData->pDevmode);
if (pData->pPrinterNameFromOpenData)
FreeSplStr(pData->pPrinterNameFromOpenData);
CloseHandle(pData->semPaused);
if (pData->pPrinterName)
FreeSplStr(pData->pPrinterName);
if (pData->pDatatype)
FreeSplStr(pData->pDatatype);
if (pData->pDocument)
FreeSplStr(pData->pDocument);
if (pData->pOutputFile)
FreeSplStr(pData->pOutputFile);
if (pData->pParameters)
FreeSplStr(pData->pParameters);
FreeSplMem(pData);
return TRUE;
}
/*++
*******************************************************************
C o n t r o l P r i n t P r o c e s s o r
Routine Description:
Handles commands to pause, resume, and cancel print jobs.
Arguments:
hPrintProcessor = HANDLE to the PrintProcessor the
command is issued for.
Return Value:
TRUE if command succeeded
FALSE if command failed (invalid command)
*******************************************************************
--*/
BOOL
ControlPrintProcessor(
HANDLE hPrintProcessor,
DWORD Command
)
{
PPRINTPROCESSORDATA pData;
/**
Make sure the handle is valid and pick up
the Print Processors data area.
**/
if (pData = ValidateHandle(hPrintProcessor)) {
switch (Command) {
case JOB_CONTROL_PAUSE:
ResetEvent(pData->semPaused);
pData->fsStatus |= PRINTPROCESSOR_PAUSED;
return TRUE;
break;
case JOB_CONTROL_CANCEL:
pData->fsStatus |= PRINTPROCESSOR_ABORTED;
CancelDC(pData->hDC);
/* Fall through to release job if paused */
case JOB_CONTROL_RESUME:
if (pData->fsStatus & PRINTPROCESSOR_PAUSED) {
SetEvent(pData->semPaused);
pData->fsStatus &= ~PRINTPROCESSOR_PAUSED;
}
return TRUE;
break;
default:
return FALSE;
break;
}
}
return FALSE;
}
/*++
*******************************************************************
V a l i d a t e H a n d l e
Routine Description:
Validates the given Print Processor HANDLE (which is
really a pointer to the Print Processor's data) by
checking for our signature.
Arguments:
hQProc (HANDLE) => Print Processor data structure. This
is verified as really being a pointer to the Print
Processor's data.
Return Value:
PPRINTPROCESSORDATA if successful (valid pointer passed)
NULL if failed - pointer was not valid
*******************************************************************
--*/
PPRINTPROCESSORDATA
ValidateHandle(
HANDLE hQProc
)
{
/** Pick up the pointer **/
PPRINTPROCESSORDATA pData = (PPRINTPROCESSORDATA)hQProc;
//
// Note that spooler has to leave the critical section to call into print
// proc. So the handle passed by spooler could be invalid since one
// thread could call SetJob to pause/resume a job while port thread
// is printing it
//
try {
/** See if our signature exists in the suspected data region **/
if (pData && pData->signature != PRINTPROCESSORDATA_SIGNATURE) {
/** Bad pointer - return failed **/
pData = NULL;
}
}except (1) {
/** Bad pointer - return failed **/
pData = NULL;
}
if ( pData == NULL )
SetLastError( ERROR_INVALID_HANDLE );
return pData;
}
DWORD
GetPrintProcessorCapabilities(
LPTSTR pValueName,
DWORD dwAttributes,
LPBYTE pData,
DWORD nSize,
LPDWORD pcbNeeded
)
/*++
Function Description: GetPrintProcessorCapabilities returns information about the
options supported by the print processor for the given datatype
in a PRINTPROCESSOR_CAPS_1 struct.
Parameters: pValueName -- datatype like RAW|NT EMF 1.006|TEXT|...
dwAttributes -- printer attributes
pData -- pointer to the buffer
nSize -- size of the buffer
pcbNeeded -- pointer to the variable to store the required buffer size
Return Values: Error Codes.
--*/
{
LPWSTR *pDatatypes = Datatypes;
DWORD dwDatatype = 0;
DWORD dwReturn;
PPRINTPROCESSOR_CAPS_1 ppcInfo;
*pcbNeeded = sizeof(PRINTPROCESSOR_CAPS_1);
// Check for valid parameters.
if (!pData || !pValueName) {
dwReturn = ERROR_INVALID_PARAMETER;
goto CleanUp;
}
// Check for sufficient buffer.
if (nSize < *pcbNeeded) {
dwReturn = ERROR_MORE_DATA;
goto CleanUp;
}
ppcInfo = (PPRINTPROCESSOR_CAPS_1) pData;
// Level is 1 for PRINTPROCESSOR_CAPS_1.
ppcInfo->dwLevel = 1;
// For direct printing, masq. printers and print RAW only,
// EMF is not spooled. Dont expose EMF features in the UI.
if ((dwAttributes & PRINTER_ATTRIBUTE_DIRECT) ||
(dwAttributes & PRINTER_ATTRIBUTE_RAW_ONLY) ||
((dwAttributes & PRINTER_ATTRIBUTE_LOCAL) &&
(dwAttributes & PRINTER_ATTRIBUTE_NETWORK))) {
ppcInfo->dwNupOptions = 1;
ppcInfo->dwNumberOfCopies = 1;
ppcInfo->dwPageOrderFlags = NORMAL_PRINT;
} else {
ppcInfo->dwNupOptions = 0x0000812b; // for 1,2,4,6,9,16 up options.
ppcInfo->dwNumberOfCopies = 0xffffffff; // maximum number of copies.
ppcInfo->dwPageOrderFlags = REVERSE_PRINT | BOOKLET_PRINT;
}
dwReturn = ERROR_SUCCESS;
CleanUp:
return dwReturn;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -