1874 lines
42 KiB
C
1874 lines
42 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
docevent.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Implementation of DrvDocumentEvent
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Fax driver user interface
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
01/13/96 -davidx-
|
|||
|
Created it.
|
|||
|
|
|||
|
mm/dd/yy -author-
|
|||
|
description
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "faxui.h"
|
|||
|
#include "tapiutil.h"
|
|||
|
#include <gdispool.h>
|
|||
|
#include "prtcovpg.h"
|
|||
|
#include "jobtag.h"
|
|||
|
#include "faxreg.h"
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Data structure passed in during CREATEDCPRE document event
|
|||
|
//
|
|||
|
|
|||
|
typedef struct {
|
|||
|
|
|||
|
LPTSTR pDriverName; // driver name
|
|||
|
LPTSTR pPrinterName; // printer name
|
|||
|
PDEVMODE pdmInput; // input devmode
|
|||
|
ULONG fromCreateIC; // whether called from CreateIC
|
|||
|
|
|||
|
} CREATEDCDATA, *PCREATEDCDATA;
|
|||
|
|
|||
|
//
|
|||
|
// Data structure passed in during ESCAPE document event
|
|||
|
//
|
|||
|
|
|||
|
typedef struct {
|
|||
|
|
|||
|
ULONG iEscape; // nEscape parameter passed to ExtEscape
|
|||
|
ULONG cbInput; // cbInput parameter passed to ExtEscape
|
|||
|
LPCSTR pInput; // pszInData parameter passed to ExtEscape
|
|||
|
|
|||
|
} ESCAPEDATA, *PESCAPEDATA;
|
|||
|
|
|||
|
//
|
|||
|
// Check if a document event requires a device context
|
|||
|
//
|
|||
|
|
|||
|
#define DocEventRequiresDC(iEsc) \
|
|||
|
((iEsc) >= DOCUMENTEVENT_RESETDCPRE && (iEsc) <= DOCUMENTEVENT_LAST)
|
|||
|
|
|||
|
//
|
|||
|
// Present the Send Fax Wizard to the user
|
|||
|
//
|
|||
|
|
|||
|
BOOL
|
|||
|
SendFaxWizard(
|
|||
|
PUSERMEM pUserMem
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
DoFirstTimeInitStuff(
|
|||
|
HWND hwnd,
|
|||
|
BOOL WarnOnPrint
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
PUSERMEM
|
|||
|
GetPDEVUserMem(
|
|||
|
HDC hdc
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Retrieve a pointer to the user mode memory structure associated with a PDEV
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hdc - Specifies the printer device context
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Pointer to user mode memory structure, NULL if there is an error
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PUSERMEM pUserMem;
|
|||
|
|
|||
|
//
|
|||
|
// Get a pointer to the user mode memory structure associated
|
|||
|
// with the specified device context
|
|||
|
//
|
|||
|
|
|||
|
EnterDrvSem();
|
|||
|
|
|||
|
pUserMem = gUserMemList;
|
|||
|
|
|||
|
while (pUserMem && hdc != pUserMem->hdc)
|
|||
|
pUserMem = pUserMem->pNext;
|
|||
|
|
|||
|
LeaveDrvSem();
|
|||
|
|
|||
|
//
|
|||
|
// Make sure the user memory structure is valid
|
|||
|
//
|
|||
|
|
|||
|
if (pUserMem) {
|
|||
|
|
|||
|
if (! ValidPDEVUserMem(pUserMem)) {
|
|||
|
|
|||
|
Error(("Corrupted user mode memory structure\n"));
|
|||
|
pUserMem = NULL;
|
|||
|
}
|
|||
|
|
|||
|
} else
|
|||
|
Error(("DC has no associated user mode memory structure\n"));
|
|||
|
|
|||
|
return pUserMem;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
FreeRecipientList(
|
|||
|
PUSERMEM pUserMem
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Free up the list of recipients associated with each fax job
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pUserMem - Points to the user mode memory structure
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NONE
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PRECIPIENT pNextRecipient, pFreeRecipient;
|
|||
|
|
|||
|
//
|
|||
|
// Free the list of recipients
|
|||
|
//
|
|||
|
|
|||
|
pNextRecipient = pUserMem->pRecipients;
|
|||
|
|
|||
|
while (pNextRecipient) {
|
|||
|
|
|||
|
pFreeRecipient = pNextRecipient;
|
|||
|
pNextRecipient = pNextRecipient->pNext;
|
|||
|
FreeRecipient(pFreeRecipient);
|
|||
|
}
|
|||
|
|
|||
|
pUserMem->pRecipients = NULL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
FreePDEVUserMem(
|
|||
|
PUSERMEM pUserMem
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Free up the user mode memory associated with each PDEV
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pUserMem - Points to the user mode memory structure
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NONE
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
if (pUserMem) {
|
|||
|
|
|||
|
FreeRecipientList(pUserMem);
|
|||
|
|
|||
|
MemFree(pUserMem->pPrinterName);
|
|||
|
MemFree(pUserMem->pSubject);
|
|||
|
MemFree(pUserMem->pNoteMessage);
|
|||
|
MemFree(pUserMem->pEnvVar);
|
|||
|
MemFree(pUserMem->pPrintFile);
|
|||
|
MemFree(pUserMem);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
INT
|
|||
|
DocEventCreateDCPre(
|
|||
|
HANDLE hPrinter,
|
|||
|
HDC hdc,
|
|||
|
PCREATEDCDATA pCreateDCData,
|
|||
|
PDEVMODE *ppdmOutput
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Handle CREATEDCPRE document event
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hPrinter - Handle to the printer object
|
|||
|
hdc - Specifies the printer device context
|
|||
|
pCreateDCData - Pointer to CREATEDCDATA structure passed in from GDI
|
|||
|
ppdmOutput - Buffer for returning a devmode pointer
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Return value for DrvDocumentEvent
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PUSERMEM pUserMem;
|
|||
|
PPRINTER_INFO_2 pPrinterInfo2 = NULL;
|
|||
|
|
|||
|
Verbose(("Document event: CREATEDCPRE%s\n", pCreateDCData->fromCreateIC ? "*" : ""));
|
|||
|
*ppdmOutput = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate space for user mode memory data structure
|
|||
|
//
|
|||
|
|
|||
|
if ((pUserMem = MemAllocZ(sizeof(USERMEM))) == NULL ||
|
|||
|
(pPrinterInfo2 = MyGetPrinter(hPrinter, 2)) == NULL ||
|
|||
|
(pUserMem->pPrinterName = DuplicateString(pPrinterInfo2->pPrinterName)) == NULL)
|
|||
|
{
|
|||
|
Error(("Memory allocation failed\n"));
|
|||
|
MemFree(pUserMem);
|
|||
|
MemFree(pPrinterInfo2);
|
|||
|
return DOCUMENTEVENT_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Merge the input devmode with the driver and system defaults
|
|||
|
//
|
|||
|
|
|||
|
pUserMem->hPrinter = hPrinter;
|
|||
|
pUserMem->isLocalPrinter = (pPrinterInfo2->pServerName == NULL);
|
|||
|
GetCombinedDevmode(&pUserMem->devmode, pCreateDCData->pdmInput, hPrinter, pPrinterInfo2, FALSE);
|
|||
|
MemFree(pPrinterInfo2);
|
|||
|
|
|||
|
//
|
|||
|
// Special code path for EFC server printing - if FAXDM_EFC_SERVER bit is
|
|||
|
// set in DMPRIVATE.flags, then we'll bypass the fax wizard and let the
|
|||
|
// job through without any intervention.
|
|||
|
//
|
|||
|
|
|||
|
if (pUserMem->devmode.dmPrivate.flags & FAXDM_NO_WIZARD) {
|
|||
|
pUserMem->directPrinting = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Mark the private fields of our devmode
|
|||
|
//
|
|||
|
|
|||
|
MarkPDEVUserMem(pUserMem);
|
|||
|
|
|||
|
*ppdmOutput = (PDEVMODE) &pUserMem->devmode;
|
|||
|
return DOCUMENTEVENT_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
INT
|
|||
|
DocEventResetDCPre(
|
|||
|
HDC hdc,
|
|||
|
PUSERMEM pUserMem,
|
|||
|
PDEVMODE pdmInput,
|
|||
|
PDEVMODE *ppdmOutput
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Handle RESETDCPRE document event
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hdc - Specifies the printer device context
|
|||
|
pUserMem - Points to the user mode memory structure
|
|||
|
pdmInput - Points to the input devmode passed to ResetDC
|
|||
|
ppdmOutput - Buffer for returning a devmode pointer
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Return value for DrvDocumentEvent
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
if (pdmInput == (PDEVMODE) &pUserMem->devmode) {
|
|||
|
|
|||
|
//
|
|||
|
// ResetDC was called by ourselves - assume the devmode is already valid
|
|||
|
//
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Merge the input devmode with driver and system default
|
|||
|
//
|
|||
|
|
|||
|
GetCombinedDevmode(&pUserMem->devmode, pdmInput, pUserMem->hPrinter, NULL, TRUE);
|
|||
|
|
|||
|
//
|
|||
|
// Mark the private fields of our devmode
|
|||
|
//
|
|||
|
|
|||
|
MarkPDEVUserMem(pUserMem);
|
|||
|
}
|
|||
|
|
|||
|
*ppdmOutput = (PDEVMODE) &pUserMem->devmode;
|
|||
|
return DOCUMENTEVENT_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
IsPrintingToFile(
|
|||
|
LPCTSTR pDestStr
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Check if the destination of a print job is a file.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pDestStr - Job destination specified in DOCINFO.lpszOutput
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if the destination is a disk file, FALSE otherwse
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD fileAttrs, fileType;
|
|||
|
HANDLE hFile;
|
|||
|
|
|||
|
//
|
|||
|
// If the destination is NULL, then we're not printing to file
|
|||
|
//
|
|||
|
// Otherwise, attempt to use the destination string as the name of a file.
|
|||
|
// If we failed to get file attributes or the name refers to a directory,
|
|||
|
// then we're not printing to file.
|
|||
|
//
|
|||
|
|
|||
|
if (pDestStr == NULL) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// make sure it's not a directory
|
|||
|
//
|
|||
|
fileAttrs = GetFileAttributes(pDestStr);
|
|||
|
if (fileAttrs != 0xffffffff) {
|
|||
|
if (fileAttrs & FILE_ATTRIBUTE_DIRECTORY) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// check if file exists...if it doesn't try to create it.
|
|||
|
//
|
|||
|
hFile = CreateFile(pDestStr, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
|
|||
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|||
|
hFile = CreateFile(pDestStr, 0, 0, NULL, CREATE_NEW, 0, NULL);
|
|||
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// verify that this file is really a disk file, not a link to LPT1 or something evil like that
|
|||
|
//
|
|||
|
fileType = GetFileType(hFile);
|
|||
|
CloseHandle(hFile);
|
|||
|
if ((fileType & FILE_TYPE_DISK)==0) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// it must be a file
|
|||
|
//
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
INT
|
|||
|
DocEventStartDocPre(
|
|||
|
HDC hdc,
|
|||
|
PUSERMEM pUserMem,
|
|||
|
LPDOCINFO pDocInfo
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Handle STARTDOCPRE document event
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hdc - Specifies the printer device context
|
|||
|
pUserMem - Points to the user mode memory structure
|
|||
|
pDocInfo - Points to DOCINFO structure that was passed in from GDI
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Return value for DrvDocumentEvent
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// Initialize user mode memory structure
|
|||
|
//
|
|||
|
|
|||
|
pUserMem->pageCount = 0;
|
|||
|
FreeRecipientList(pUserMem);
|
|||
|
|
|||
|
//
|
|||
|
// Present the fax wizard here if necessary
|
|||
|
//
|
|||
|
|
|||
|
if (pDocInfo && IsPrintingToFile(pDocInfo->lpszOutput)) {
|
|||
|
|
|||
|
//
|
|||
|
// Printing to file case: don't get involved
|
|||
|
//
|
|||
|
|
|||
|
Warning(("Printing direct: %ws\n", pDocInfo->lpszOutput));
|
|||
|
pUserMem->jobType = JOBTYPE_DIRECT;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// check to see if we should print to file
|
|||
|
//
|
|||
|
|
|||
|
LPTSTR pEnvVar;
|
|||
|
DWORD EnvSize;
|
|||
|
|
|||
|
EnvSize = GetEnvironmentVariable( FAX_ENVVAR_PRINT_FILE, NULL, 0 );
|
|||
|
if (EnvSize) {
|
|||
|
pEnvVar = (LPTSTR) MemAllocZ( EnvSize * sizeof(TCHAR) );
|
|||
|
if (pEnvVar) {
|
|||
|
if (GetEnvironmentVariable( FAX_ENVVAR_PRINT_FILE, pEnvVar, EnvSize )) {
|
|||
|
pUserMem->directPrinting = TRUE;
|
|||
|
pUserMem->pPrintFile = pEnvVar;
|
|||
|
pUserMem->jobType = JOBTYPE_DIRECT;
|
|||
|
pDocInfo->lpszOutput = pEnvVar;
|
|||
|
return DOCUMENTEVENT_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Normal fax print job. Present the send fax wizard.
|
|||
|
// If the user selected cancel, then return -2 to GDI.
|
|||
|
//
|
|||
|
if (!DoFirstTimeInitStuff(NULL, TRUE) ||
|
|||
|
! SendFaxWizard(pUserMem)) {
|
|||
|
|
|||
|
SetLastError(ERROR_CANCELLED);
|
|||
|
return -2;
|
|||
|
}
|
|||
|
|
|||
|
Assert(pUserMem->pRecipients);
|
|||
|
pUserMem->jobType = JOBTYPE_NORMAL;
|
|||
|
}
|
|||
|
|
|||
|
return DOCUMENTEVENT_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
FreeCoverPageFields(
|
|||
|
PCOVERPAGEFIELDS pCPFields
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Free up memory used to hold the cover page information
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pCPFields - Points to a COVERPAGEFIELDS structure
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NONE
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
if (pCPFields == NULL)
|
|||
|
return;
|
|||
|
|
|||
|
//
|
|||
|
// NOTE: We don't need to free the following fields here because they're
|
|||
|
// allocated and freed elsewhere and we're only using a copy of the pointer:
|
|||
|
// RecName
|
|||
|
// RecFaxNumber
|
|||
|
// Note
|
|||
|
// Subject
|
|||
|
//
|
|||
|
|
|||
|
MemFree(pCPFields->SdrName);
|
|||
|
MemFree(pCPFields->SdrFaxNumber);
|
|||
|
MemFree(pCPFields->SdrCompany);
|
|||
|
MemFree(pCPFields->SdrAddress);
|
|||
|
MemFree(pCPFields->SdrTitle);
|
|||
|
MemFree(pCPFields->SdrDepartment);
|
|||
|
MemFree(pCPFields->SdrOfficeLocation);
|
|||
|
MemFree(pCPFields->SdrHomePhone);
|
|||
|
MemFree(pCPFields->SdrOfficePhone);
|
|||
|
|
|||
|
MemFree(pCPFields->NumberOfPages);
|
|||
|
MemFree(pCPFields->TimeSent);
|
|||
|
|
|||
|
MemFree(pCPFields);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
PCOVERPAGEFIELDS
|
|||
|
CollectCoverPageFields(
|
|||
|
PUSERMEM pUserMem,
|
|||
|
DWORD pageCount
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Collect cover page information into a COVERPAGEFIELDS structure
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pUserMem - Pointer to user mode data structure
|
|||
|
pageCount - Total number of pages (including cover pages)
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Pointer to a COVERPAGEFIELDS structure, NULL if there is an error
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#define FillCoverPageField(field, pValueName) { \
|
|||
|
buffer = GetRegistryString(hRegKey, pValueName, TEXT("")); \
|
|||
|
if (! IsEmptyString(buffer)) { \
|
|||
|
pCPFields->field = DuplicateString(buffer); \
|
|||
|
MemFree(buffer); \
|
|||
|
} \
|
|||
|
}
|
|||
|
|
|||
|
{
|
|||
|
PCOVERPAGEFIELDS pCPFields;
|
|||
|
LPTSTR buffer;
|
|||
|
HKEY hRegKey;
|
|||
|
INT dateTimeLen;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate memory to hold the top level structure
|
|||
|
// and open the user info registry key for reading
|
|||
|
//
|
|||
|
|
|||
|
if (! (pCPFields = MemAllocZ(sizeof(COVERPAGEFIELDS))) ||
|
|||
|
! (hRegKey = GetUserInfoRegKey(REGKEY_FAX_USERINFO, REG_READWRITE)))
|
|||
|
{
|
|||
|
FreeCoverPageFields(pCPFields);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Read sender information from the registry
|
|||
|
//
|
|||
|
|
|||
|
pCPFields->ThisStructSize = sizeof(COVERPAGEFIELDS);
|
|||
|
|
|||
|
FillCoverPageField(SdrName, REGVAL_FULLNAME);
|
|||
|
FillCoverPageField(SdrCompany, REGVAL_COMPANY);
|
|||
|
FillCoverPageField(SdrAddress, REGVAL_ADDRESS);
|
|||
|
FillCoverPageField(SdrTitle, REGVAL_TITLE);
|
|||
|
FillCoverPageField(SdrDepartment, REGVAL_DEPT);
|
|||
|
FillCoverPageField(SdrOfficeLocation, REGVAL_OFFICE);
|
|||
|
FillCoverPageField(SdrHomePhone, REGVAL_HOME_PHONE);
|
|||
|
FillCoverPageField(SdrOfficePhone, REGVAL_OFFICE_PHONE);
|
|||
|
FillCoverPageField(SdrFaxNumber, REGVAL_FAX_NUMBER);
|
|||
|
|
|||
|
RegCloseKey(hRegKey);
|
|||
|
|
|||
|
//
|
|||
|
// Number of pages and current local system time
|
|||
|
//
|
|||
|
|
|||
|
if (pCPFields->NumberOfPages = MemAllocZ(sizeof(TCHAR) * 16))
|
|||
|
wsprintf(pCPFields->NumberOfPages, TEXT("%d"), pageCount);
|
|||
|
|
|||
|
//
|
|||
|
// When the fax was sent
|
|||
|
//
|
|||
|
|
|||
|
dateTimeLen = 128;
|
|||
|
|
|||
|
if (pCPFields->TimeSent = MemAllocZ(sizeof(TCHAR) * dateTimeLen)) {
|
|||
|
|
|||
|
LPTSTR p = pCPFields->TimeSent;
|
|||
|
INT cch;
|
|||
|
|
|||
|
GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, p, dateTimeLen);
|
|||
|
|
|||
|
cch = _tcslen(p);
|
|||
|
p += cch;
|
|||
|
|
|||
|
if (++cch < dateTimeLen) {
|
|||
|
|
|||
|
*p++ = ' ';
|
|||
|
dateTimeLen -= cch;
|
|||
|
|
|||
|
GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, p, dateTimeLen);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return pCPFields;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
FaxTimeToJobTime(
|
|||
|
DWORD faxTime
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Convert fax time to spooler job time:
|
|||
|
Fax time is a DWORD whose low-order WORD represents hour value and
|
|||
|
high-order WORD represents minute value. Spooler job time is a DWORD
|
|||
|
value expressing minutes ellapsed since 12:00 AM GMT.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
faxTime - Specifies the fax time to be converted
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Spooler job time corresponding to the input fax time
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
TIME_ZONE_INFORMATION timeZoneInfo;
|
|||
|
LONG jobTime;
|
|||
|
|
|||
|
//
|
|||
|
// Convert fax time to minutes pass midnight
|
|||
|
//
|
|||
|
|
|||
|
jobTime = LOWORD(faxTime) * 60 + HIWORD(faxTime);
|
|||
|
|
|||
|
//
|
|||
|
// Take time zone information in account - Add one full
|
|||
|
// day to take care of the case where the bias is negative.
|
|||
|
//
|
|||
|
|
|||
|
switch (GetTimeZoneInformation(&timeZoneInfo)) {
|
|||
|
|
|||
|
case TIME_ZONE_ID_DAYLIGHT:
|
|||
|
|
|||
|
jobTime += timeZoneInfo.DaylightBias;
|
|||
|
|
|||
|
case TIME_ZONE_ID_STANDARD:
|
|||
|
case TIME_ZONE_ID_UNKNOWN:
|
|||
|
|
|||
|
jobTime += timeZoneInfo.Bias + MINUTES_PER_DAY;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
Error(("GetTimeZoneInformation failed: %d\n", GetLastError()));
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Make sure the time value is less than one day
|
|||
|
//
|
|||
|
|
|||
|
return jobTime % MINUTES_PER_DAY;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
PVOID
|
|||
|
MyGetJob(
|
|||
|
HANDLE hPrinter,
|
|||
|
DWORD level,
|
|||
|
DWORD jobId
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Wrapper function for spooler API GetJob
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hPrinter - Handle to the printer object
|
|||
|
level - Level of JOB_INFO structure interested
|
|||
|
jobId - Specifies the job ID
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Pointer to a JOB_INFO structure, NULL if there is an error
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PBYTE pJobInfo = NULL;
|
|||
|
DWORD cbNeeded;
|
|||
|
|
|||
|
if (!GetJob(hPrinter, jobId, level, NULL, 0, &cbNeeded) &&
|
|||
|
GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
|
|||
|
(pJobInfo = MemAlloc(cbNeeded)) &&
|
|||
|
GetJob(hPrinter, jobId, level, pJobInfo, cbNeeded, &cbNeeded))
|
|||
|
{
|
|||
|
return pJobInfo;
|
|||
|
}
|
|||
|
|
|||
|
Error(("GetJob failed: %d\n", GetLastError()));
|
|||
|
MemFree(pJobInfo);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
SetJobInfoAndTime(
|
|||
|
HANDLE hPrinter,
|
|||
|
DWORD jobId,
|
|||
|
LPTSTR pJobParam,
|
|||
|
PDMPRIVATE pdmPrivate
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Change the devmode and start/stop times associated with a cover page job
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hPrinter - Specifies the printer object
|
|||
|
jobId - Specifies the job ID
|
|||
|
pJobParam - Specifies the fax job parameters
|
|||
|
pdmPrivate - Specifies private devmode information
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if successful, FALSE if there is an error
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
JOB_INFO_2 *pJobInfo2;
|
|||
|
BOOL result = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Get the current job information
|
|||
|
//
|
|||
|
|
|||
|
if (pJobInfo2 = MyGetJob(hPrinter, 2, jobId)) {
|
|||
|
|
|||
|
//
|
|||
|
// set the time to send to be now, always
|
|||
|
//
|
|||
|
|
|||
|
Warning(("Fax job parameters: %ws\n", pJobParam));
|
|||
|
pJobInfo2->pParameters = pJobParam;
|
|||
|
pJobInfo2->Position = JOB_POSITION_UNSPECIFIED;
|
|||
|
pJobInfo2->pDevMode = NULL;
|
|||
|
pJobInfo2->UntilTime = pJobInfo2->StartTime;
|
|||
|
|
|||
|
if (! (result = SetJob(hPrinter, jobId, 2, (PBYTE) pJobInfo2, 0))) {
|
|||
|
Error(("SetJob failed: %d\n", GetLastError()));
|
|||
|
}
|
|||
|
|
|||
|
MemFree(pJobInfo2);
|
|||
|
}
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
ChainFaxJobs(
|
|||
|
HANDLE hPrinter,
|
|||
|
DWORD parentJobId,
|
|||
|
DWORD childJobId
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Tell the spooler to chain up two print jobs
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hPrinter - Specifies the printer object
|
|||
|
parentJobId - Specifies the job to chain from
|
|||
|
childJobId - Specifies the job to chain to
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if successful, FALSE if there is an error
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
JOB_INFO_3 jobInfo3 = { parentJobId, childJobId };
|
|||
|
|
|||
|
Warning(("Chaining cover page job to body job: %d => %d\n", parentJobId, childJobId));
|
|||
|
|
|||
|
return SetJob(hPrinter, parentJobId, 3, (PBYTE) &jobInfo3, 0);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
LPTSTR
|
|||
|
GetJobName(
|
|||
|
HANDLE hPrinter,
|
|||
|
DWORD jobId
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Return the name of the specified print job
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hPrinter - Specifies the printer object
|
|||
|
jobId - Specifies the fax body job
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Pointer to the job name string, NULL if there is an error
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
JOB_INFO_1 *pJobInfo1;
|
|||
|
LPTSTR pJobName;
|
|||
|
|
|||
|
//
|
|||
|
// Get the information about the specified job and
|
|||
|
// return a copy of the job name string
|
|||
|
//
|
|||
|
|
|||
|
if (pJobInfo1 = MyGetJob(hPrinter, 1, jobId)) {
|
|||
|
|
|||
|
pJobName = DuplicateString(pJobInfo1->pDocument);
|
|||
|
MemFree(pJobInfo1);
|
|||
|
|
|||
|
} else
|
|||
|
pJobName = NULL;
|
|||
|
|
|||
|
return pJobName;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
LPTSTR
|
|||
|
ComposeFaxJobName(
|
|||
|
LPTSTR pBodyDocName,
|
|||
|
LPTSTR pRecipientName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Compose the document name string for a cover page job
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pBodyDocName - Specifies the name of the body job
|
|||
|
pRecipient - Specifies the recipient's name
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Pointer to cover page job name string, NULL if there is an error
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#define DOCNAME_FORMAT_STRING TEXT("%s - %s")
|
|||
|
|
|||
|
{
|
|||
|
LPTSTR pCoverJobName;
|
|||
|
|
|||
|
if (pBodyDocName == NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// If the body job name is NULL somehow, then simply
|
|||
|
// use the recipient's name as the cover page job name.
|
|||
|
//
|
|||
|
|
|||
|
pCoverJobName = DuplicateString(pRecipientName);
|
|||
|
|
|||
|
} else if (pCoverJobName = MemAlloc(SizeOfString(DOCNAME_FORMAT_STRING) +
|
|||
|
SizeOfString(pBodyDocName) +
|
|||
|
SizeOfString(pRecipientName)))
|
|||
|
{
|
|||
|
//
|
|||
|
// Otherwise, the cover page job name is generated by
|
|||
|
// concatenating the recipient's name with the body job name.
|
|||
|
//
|
|||
|
|
|||
|
wsprintf(pCoverJobName, DOCNAME_FORMAT_STRING, pRecipientName, pBodyDocName);
|
|||
|
}
|
|||
|
|
|||
|
return pCoverJobName;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
LPTSTR
|
|||
|
GetBaseNoteFilename(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Get the name of base cover page file in system32 directory
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
argument-name - description of argument
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Pointer to name of base cover page file
|
|||
|
NULL if there is an error
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#define BASENOTE_FILENAME TEXT("\\basenote.cov")
|
|||
|
|
|||
|
{
|
|||
|
TCHAR systemDir[MAX_PATH];
|
|||
|
LPTSTR pBaseNoteName = NULL;
|
|||
|
COVDOCINFO covDocInfo;
|
|||
|
|
|||
|
if (GetSystemDirectory(systemDir, MAX_PATH) &&
|
|||
|
(pBaseNoteName = MemAlloc(SizeOfString(systemDir) + SizeOfString(BASENOTE_FILENAME))))
|
|||
|
{
|
|||
|
_tcscpy(pBaseNoteName, systemDir);
|
|||
|
_tcscat(pBaseNoteName, BASENOTE_FILENAME);
|
|||
|
Verbose(("Base cover page filename: %ws\n", pBaseNoteName));
|
|||
|
|
|||
|
if (PrintCoverPage(NULL, NULL, pBaseNoteName, &covDocInfo) ||
|
|||
|
! (covDocInfo.Flags & COVFP_NOTE) ||
|
|||
|
! (covDocInfo.Flags & COVFP_SUBJECT))
|
|||
|
{
|
|||
|
Error(("Invalid base cover page file: %ws\n", pBaseNoteName));
|
|||
|
MemFree(pBaseNoteName);
|
|||
|
pBaseNoteName = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return pBaseNoteName;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
LPTSTR
|
|||
|
ComposeFaxJobParameter(
|
|||
|
PUSERMEM pUserMem,
|
|||
|
PCOVERPAGEFIELDS pCPFields
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Assemble fax job parameters into a single tagged string
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pUserMem - Points to user mode memory structure
|
|||
|
pCPFields - Points to cover page field information
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Pointer to fax job parameter string, NULL if there is an error
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#define NUM_JOBPARAM_TAGS 10
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// Tags used to pass information about fax jobs
|
|||
|
//
|
|||
|
|
|||
|
static LPTSTR faxtagNames[NUM_JOBPARAM_TAGS] = {
|
|||
|
|
|||
|
FAXTAG_RECIPIENT_NUMBER,
|
|||
|
FAXTAG_RECIPIENT_NAME,
|
|||
|
FAXTAG_TSID,
|
|||
|
FAXTAG_SENDER_NAME,
|
|||
|
FAXTAG_SENDER_COMPANY,
|
|||
|
FAXTAG_SENDER_DEPT,
|
|||
|
FAXTAG_BILLING_CODE,
|
|||
|
FAXTAG_EMAIL_NAME,
|
|||
|
FAXTAG_WHEN_TO_SEND,
|
|||
|
FAXTAG_SEND_AT_TIME
|
|||
|
};
|
|||
|
|
|||
|
LPTSTR faxtagValues[NUM_JOBPARAM_TAGS] = {
|
|||
|
|
|||
|
pCPFields->RecFaxNumber,
|
|||
|
pCPFields->RecName,
|
|||
|
pCPFields->SdrFaxNumber,
|
|||
|
pCPFields->SdrName,
|
|||
|
pCPFields->SdrCompany,
|
|||
|
pCPFields->SdrDepartment,
|
|||
|
pUserMem->devmode.dmPrivate.billingCode,
|
|||
|
pUserMem->devmode.dmPrivate.emailAddress,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
};
|
|||
|
|
|||
|
LPTSTR pJobParam, p;
|
|||
|
INT index, size;
|
|||
|
TCHAR SendAtTime[16];
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// create the sendattime string
|
|||
|
//
|
|||
|
|
|||
|
if (pUserMem->devmode.dmPrivate.whenToSend == SENDFAX_AT_CHEAP) {
|
|||
|
faxtagValues[8] = TEXT("cheap");
|
|||
|
}
|
|||
|
|
|||
|
if (pUserMem->devmode.dmPrivate.whenToSend == SENDFAX_AT_TIME) {
|
|||
|
|
|||
|
wsprintf( SendAtTime, TEXT("%02d:%02d"),
|
|||
|
pUserMem->devmode.dmPrivate.sendAtTime.Hour,
|
|||
|
pUserMem->devmode.dmPrivate.sendAtTime.Minute
|
|||
|
);
|
|||
|
|
|||
|
faxtagValues[8] = TEXT("at");
|
|||
|
faxtagValues[9] = SendAtTime;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Figure out the total length of the tagged string
|
|||
|
//
|
|||
|
|
|||
|
for (index=size=0; index < NUM_JOBPARAM_TAGS; index++) {
|
|||
|
|
|||
|
if (faxtagValues[index] && !IsEmptyString(faxtagValues[index]))
|
|||
|
size += SizeOfString(faxtagNames[index]) + SizeOfString(faxtagValues[index]);
|
|||
|
}
|
|||
|
|
|||
|
if (size == 0 || (pJobParam = p = MemAlloc(size)) == NULL)
|
|||
|
return NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Assemble fax job parameters into a single tagged string
|
|||
|
//
|
|||
|
|
|||
|
for (index=0; index < NUM_JOBPARAM_TAGS; index++) {
|
|||
|
|
|||
|
if (faxtagValues[index] && !IsEmptyString(faxtagValues[index])) {
|
|||
|
|
|||
|
_tcscpy(p, faxtagNames[index]);
|
|||
|
p += _tcslen(p);
|
|||
|
|
|||
|
_tcscpy(p, faxtagValues[index]);
|
|||
|
p += _tcslen(p);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return pJobParam;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
DoCoverPageRendering(
|
|||
|
HDC hdc,
|
|||
|
PUSERMEM pUserMem
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Render a cover page for each recipient
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hdc - Handle to the current printer device context
|
|||
|
pUserMem - Points to user mode memory structure
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if successful, FALSE otherwise
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCOVERPAGEFIELDS pCPFields;
|
|||
|
PRECIPIENT pRecipient;
|
|||
|
DOCINFO docinfo;
|
|||
|
INT newJobId, lastJobId, cCoverPagesSent;
|
|||
|
LPTSTR pBaseNoteName = NULL;
|
|||
|
PDMPRIVATE pdmPrivate = &pUserMem->devmode.dmPrivate;
|
|||
|
HANDLE hPrinter = pUserMem->hPrinter;
|
|||
|
DWORD bodyJobId = pUserMem->jobId;
|
|||
|
LPTSTR pBodyDocName, pJobParam;
|
|||
|
BOOL sendCoverPage;
|
|||
|
DWORD pageCount;
|
|||
|
|
|||
|
//
|
|||
|
// Determine if we need a cover page or not
|
|||
|
//
|
|||
|
|
|||
|
if ((sendCoverPage = pdmPrivate->sendCoverPage) && IsEmptyString(pUserMem->coverPage)) {
|
|||
|
|
|||
|
Warning(("Missing cover page file\n"));
|
|||
|
sendCoverPage = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if we need an extra cover page for rendering note/subject fields
|
|||
|
//
|
|||
|
|
|||
|
pageCount = pUserMem->pageCount;
|
|||
|
|
|||
|
if (sendCoverPage)
|
|||
|
pageCount++;
|
|||
|
|
|||
|
if (((pUserMem->pSubject && !(pUserMem->noteSubjectFlag & COVFP_SUBJECT)) ||
|
|||
|
(pUserMem->pNoteMessage && !(pUserMem->noteSubjectFlag & COVFP_NOTE))) &&
|
|||
|
(pBaseNoteName = GetBaseNoteFilename()))
|
|||
|
{
|
|||
|
pageCount++;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Collect cover page information
|
|||
|
//
|
|||
|
|
|||
|
if ((pCPFields = CollectCoverPageFields(pUserMem, pageCount)) == NULL) {
|
|||
|
|
|||
|
Error(("Couldn't collect cover page information\n"));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Fill out a DOCINFO structure which is passed to StartDoc
|
|||
|
//
|
|||
|
|
|||
|
memset(&docinfo, 0, sizeof(docinfo));
|
|||
|
docinfo.cbSize = sizeof(docinfo);
|
|||
|
|
|||
|
pBodyDocName = GetJobName(hPrinter, bodyJobId);
|
|||
|
|
|||
|
//
|
|||
|
// We assume the fax body job has already been paused
|
|||
|
// Use a separate cover page for each recipient
|
|||
|
//
|
|||
|
|
|||
|
lastJobId = cCoverPagesSent = 0;
|
|||
|
|
|||
|
for (pRecipient=pUserMem->pRecipients; pRecipient; pRecipient=pRecipient->pNext) {
|
|||
|
|
|||
|
//
|
|||
|
// Fill out other fields of cover page information
|
|||
|
//
|
|||
|
|
|||
|
pCPFields->Subject = pUserMem->pSubject;
|
|||
|
pCPFields->Note = pUserMem->pNoteMessage;
|
|||
|
|
|||
|
//
|
|||
|
// Get recipient's name and fax number
|
|||
|
//
|
|||
|
|
|||
|
pCPFields->RecName = pRecipient->pName;
|
|||
|
pCPFields->RecFaxNumber = pRecipient->pAddress;
|
|||
|
|
|||
|
//
|
|||
|
// Start a cover page job
|
|||
|
//
|
|||
|
|
|||
|
docinfo.lpszDocName = ComposeFaxJobName(pBodyDocName, pRecipient->pName);
|
|||
|
pJobParam = ComposeFaxJobParameter(pUserMem, pCPFields);
|
|||
|
|
|||
|
if ((newJobId = StartDoc(hdc, &docinfo)) > 0) {
|
|||
|
|
|||
|
BOOL rendered = FALSE;
|
|||
|
COVDOCINFO covDocInfo;
|
|||
|
|
|||
|
//
|
|||
|
// Pass fax job parameters using JOB_INFO_2.pParameters field.
|
|||
|
//
|
|||
|
|
|||
|
if (! SetJob(hPrinter, newJobId, 0, NULL, JOB_CONTROL_PAUSE) ||
|
|||
|
! SetJobInfoAndTime(hPrinter,
|
|||
|
newJobId,
|
|||
|
pJobParam ? pJobParam : pCPFields->RecFaxNumber,
|
|||
|
pdmPrivate))
|
|||
|
{
|
|||
|
Error(("Couldn't modify the fax job\n"));
|
|||
|
|
|||
|
} else if (! sendCoverPage) {
|
|||
|
|
|||
|
//
|
|||
|
// If the user chose not to include cover page,
|
|||
|
// the cover page job will be empty
|
|||
|
//
|
|||
|
|
|||
|
rendered = TRUE;
|
|||
|
|
|||
|
} else if (StartPage(hdc) > 0) {
|
|||
|
|
|||
|
//
|
|||
|
// Call the library function to render the cover page.
|
|||
|
//
|
|||
|
|
|||
|
rendered = PrintCoverPage( hdc, pCPFields, pUserMem->coverPage, &covDocInfo );
|
|||
|
if (rendered) {
|
|||
|
Error(("PrintCoverPage failed: %d\n", rendered ));
|
|||
|
rendered = FALSE;
|
|||
|
} else {
|
|||
|
rendered = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
EndPage(hdc);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Chain the cover page job to the fax body job if no error occured
|
|||
|
//
|
|||
|
|
|||
|
if (rendered && ChainFaxJobs(hPrinter, newJobId, bodyJobId)) {
|
|||
|
|
|||
|
//
|
|||
|
// Check if we need an extra page for note/subject fields
|
|||
|
//
|
|||
|
|
|||
|
if (pBaseNoteName) {
|
|||
|
|
|||
|
if (StartPage(hdc) > 0) {
|
|||
|
|
|||
|
DWORD ec;
|
|||
|
|
|||
|
if (pUserMem->noteSubjectFlag & COVFP_SUBJECT)
|
|||
|
pCPFields->Subject = NULL;
|
|||
|
|
|||
|
if (pUserMem->noteSubjectFlag & COVFP_NOTE)
|
|||
|
pCPFields->Note = NULL;
|
|||
|
|
|||
|
ec = PrintCoverPage(hdc, pCPFields, pBaseNoteName, &covDocInfo);
|
|||
|
if (ec) {
|
|||
|
Error(("PrintCoverPage failed: %d\n", ec));
|
|||
|
}
|
|||
|
|
|||
|
EndPage(hdc);
|
|||
|
|
|||
|
} else
|
|||
|
Error(("StartPage failed: %d\n", GetLastError()));
|
|||
|
}
|
|||
|
|
|||
|
if (lastJobId != 0)
|
|||
|
SetJob(hPrinter, lastJobId, 0, NULL, JOB_CONTROL_RESUME);
|
|||
|
|
|||
|
lastJobId = newJobId;
|
|||
|
EndDoc(hdc);
|
|||
|
cCoverPagesSent++;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
AbortDoc(hdc);
|
|||
|
newJobId = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
MemFree((PVOID)docinfo.lpszDocName);
|
|||
|
MemFree((PVOID)pJobParam);
|
|||
|
|
|||
|
//
|
|||
|
// Indicate to the user about the fact that we failed to render the
|
|||
|
// for the current recipient
|
|||
|
//
|
|||
|
|
|||
|
if (newJobId <= 0)
|
|||
|
DisplayMessageDialog(NULL, 0, 0, IDS_CPRENDER_FAILED, pRecipient->pName);
|
|||
|
}
|
|||
|
|
|||
|
MemFree(pBaseNoteName);
|
|||
|
MemFree(pBodyDocName);
|
|||
|
FreeCoverPageFields(pCPFields);
|
|||
|
|
|||
|
//
|
|||
|
// Resume the last cover page job if it's paused and
|
|||
|
// delete the fax body job if no cover page jobs were sent
|
|||
|
//
|
|||
|
|
|||
|
if (lastJobId != 0)
|
|||
|
SetJob(hPrinter, lastJobId, 0, NULL, JOB_CONTROL_RESUME);
|
|||
|
|
|||
|
if (cCoverPagesSent > 0)
|
|||
|
SetJob(hPrinter, bodyJobId, 0, NULL, JOB_CONTROL_RESUME);
|
|||
|
else {
|
|||
|
|
|||
|
Error(("Fax job deleted due to an error\n"));
|
|||
|
SetJob(hPrinter, bodyJobId, 0, NULL, JOB_CONTROL_DELETE);
|
|||
|
}
|
|||
|
|
|||
|
return cCoverPagesSent > 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
INT
|
|||
|
DocEventEndDocPost(
|
|||
|
HDC hdc,
|
|||
|
PUSERMEM pUserMem
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Handle ENDDOCPOST document event
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hdc - Specifies the printer device context
|
|||
|
pUserMem - Points to the user mode memory structure
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Return value for DrvDocumentEvent
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
INT result = DOCUMENTEVENT_SUCCESS;
|
|||
|
|
|||
|
switch (pUserMem->jobType) {
|
|||
|
|
|||
|
case JOBTYPE_NORMAL:
|
|||
|
|
|||
|
Warning(("Number of pages printed: %d\n", pUserMem->pageCount));
|
|||
|
|
|||
|
if (! pUserMem->directPrinting) {
|
|||
|
|
|||
|
HDC hdcCP = NULL;
|
|||
|
DWORD dmFlags, dmFields;
|
|||
|
SHORT dmPaperSize, dmOrientation;
|
|||
|
PDEVMODE pdmPublic;
|
|||
|
PDMPRIVATE pdmPrivate;
|
|||
|
|
|||
|
//
|
|||
|
// Generate a cover page for each recipient and associate
|
|||
|
// the cover page job with the main body. Create a new DC
|
|||
|
// to rendering the cover page instead of using the existing DC.
|
|||
|
//
|
|||
|
|
|||
|
pdmPublic = &pUserMem->devmode.dmPublic;
|
|||
|
pdmPrivate = &pUserMem->devmode.dmPrivate;
|
|||
|
|
|||
|
dmFlags = pdmPrivate->flags;
|
|||
|
pdmPrivate->flags |= FAXDM_NO_WIZARD;
|
|||
|
|
|||
|
if (pUserMem->cpPaperSize) {
|
|||
|
|
|||
|
dmFields = pdmPublic->dmFields;
|
|||
|
pdmPublic->dmFields &= ~(DM_PAPERWIDTH|DM_PAPERLENGTH|DM_FORMNAME);
|
|||
|
pdmPublic->dmFields |= DM_PAPERSIZE;
|
|||
|
|
|||
|
dmPaperSize = pdmPublic->dmPaperSize;
|
|||
|
pdmPublic->dmPaperSize = pUserMem->cpPaperSize;
|
|||
|
|
|||
|
dmOrientation = pdmPublic->dmOrientation;
|
|||
|
pdmPublic->dmOrientation = pUserMem->cpOrientation;
|
|||
|
}
|
|||
|
|
|||
|
if (! (hdcCP = CreateDC(NULL,
|
|||
|
pUserMem->pPrinterName,
|
|||
|
NULL,
|
|||
|
(PDEVMODE) &pUserMem->devmode)) ||
|
|||
|
! DoCoverPageRendering(hdcCP, pUserMem))
|
|||
|
{
|
|||
|
result = DOCUMENTEVENT_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
if (hdcCP != NULL)
|
|||
|
DeleteDC(hdcCP);
|
|||
|
|
|||
|
if (pUserMem->cpPaperSize) {
|
|||
|
|
|||
|
pdmPublic->dmFields = dmFields;
|
|||
|
pdmPublic->dmPaperSize = dmPaperSize;
|
|||
|
pdmPublic->dmOrientation = dmOrientation;
|
|||
|
}
|
|||
|
|
|||
|
pdmPrivate->flags = dmFlags;
|
|||
|
|
|||
|
//
|
|||
|
// Free up the list of recipients
|
|||
|
//
|
|||
|
|
|||
|
FreeRecipientList(pUserMem);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
INT
|
|||
|
DrvDocumentEvent(
|
|||
|
HANDLE hPrinter,
|
|||
|
HDC hdc,
|
|||
|
INT iEsc,
|
|||
|
ULONG cbIn,
|
|||
|
PULONG pjIn,
|
|||
|
ULONG cbOut,
|
|||
|
PULONG pjOut
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Hook into GDI at various points during the output process
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hPrinter - Specifies the printer object
|
|||
|
hdc - Handle to the printer DC
|
|||
|
iEsc - Why this function is called (see notes below)
|
|||
|
cbIn - Size of the input buffer
|
|||
|
pjIn - Pointer to the input buffer
|
|||
|
cbOut - Size of the output buffer
|
|||
|
pjOut - Pointer to the output buffer
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DOCUMENTEVENT_SUCCESS - success
|
|||
|
DOCUMENTEVENT_UNSUPPORTED - iEsc is not supported
|
|||
|
DOCUMENTEVENT_FAILURE - an error occured
|
|||
|
|
|||
|
NOTE:
|
|||
|
|
|||
|
DOCUMENTEVENT_CREATEDCPRE
|
|||
|
input - pointer to a CREATEDCDATA structure
|
|||
|
output - pointer to a devmode that's passed to DrvEnablePDEV
|
|||
|
return value -
|
|||
|
DOCUMENTEVENT_FAILURE causes CreateDC to fail and nothing else is called
|
|||
|
|
|||
|
DOCUMENTEVENT_CREATEDCPOST
|
|||
|
hdc - NULL if if something failed since CREATEDCPRE
|
|||
|
input - pointer to the devmode pointer returned by CREATEDCPRE
|
|||
|
return value - ignored
|
|||
|
|
|||
|
DOCUMENTEVENT_RESETDCPRE
|
|||
|
input - pointer to the input devmode passed to ResetDC
|
|||
|
output - pointer to a devmode that's passed to the kernel driver
|
|||
|
return value -
|
|||
|
DOCUMENTEVENT_FAILURE causes ResetDC to fail
|
|||
|
and CREATEDCPOST will not be called in that case
|
|||
|
|
|||
|
DOCUMENTEVENT_RESETDCPOST
|
|||
|
return value - ignored
|
|||
|
|
|||
|
DOCUMENTEVENT_STARTDOCPRE
|
|||
|
input - pointer to a DOCINFOW structure
|
|||
|
return value -
|
|||
|
DOCUMENTEVENT_FAILURE causes StartDoc to fail
|
|||
|
and DrvStartDoc will not be called in this case
|
|||
|
|
|||
|
DOCUMENTEVENT_STARTDOCPOST
|
|||
|
return value - ignored
|
|||
|
|
|||
|
DOCUMENTEVENT_STARTPAGE
|
|||
|
return value -
|
|||
|
DOCUMENTEVENT_FAILURE causes StartPage to fail
|
|||
|
and DrvStartPage will not be called in this case
|
|||
|
|
|||
|
DOCUMENTEVENT_ENDPAGE
|
|||
|
return value - ignored and DrvEndPage always called
|
|||
|
|
|||
|
DOCUMENTEVENT_ENDDOCPRE
|
|||
|
return value - ignored and DrvEndDoc always called
|
|||
|
|
|||
|
DOCUMENTEVENT_ENDDOCPOST
|
|||
|
return value - ignored
|
|||
|
|
|||
|
DOCUMENTEVENT_ABORTDOC
|
|||
|
return value - ignored
|
|||
|
|
|||
|
DOCUMENTEVENT_DELETEDC
|
|||
|
return value - ignored
|
|||
|
|
|||
|
DOCUMENTEVENT_ESCAPE
|
|||
|
input - pointer to a ESCAPEDATA structure
|
|||
|
cbOut, pjOut - cbOutput and lpszOutData parameters passed to ExtEscape
|
|||
|
return value - ignored
|
|||
|
|
|||
|
DOCUMENTEVENT_SPOOLED
|
|||
|
This flag bit is ORed with other iEsc values if the document is
|
|||
|
spooled as metafile rather than printed directly to port.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PUSERMEM pUserMem = NULL;
|
|||
|
PDEVMODE pDevmode;
|
|||
|
INT result = DOCUMENTEVENT_SUCCESS;
|
|||
|
|
|||
|
Verbose(("Entering DrvDocumentEvent: %d...\n", iEsc));
|
|||
|
|
|||
|
//
|
|||
|
// Metafile spooling on fax jobs is not currently supported
|
|||
|
//
|
|||
|
|
|||
|
Assert((iEsc & DOCUMENTEVENT_SPOOLED) == 0);
|
|||
|
|
|||
|
//
|
|||
|
// Check if the document event requires a device context
|
|||
|
//
|
|||
|
|
|||
|
if (DocEventRequiresDC(iEsc)) {
|
|||
|
|
|||
|
if (!hdc || !(pUserMem = GetPDEVUserMem(hdc))) {
|
|||
|
|
|||
|
Error(("Invalid device context: hdc = %x, iEsc = %d\n", hdc, iEsc));
|
|||
|
return DOCUMENTEVENT_FAILURE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
switch (iEsc) {
|
|||
|
|
|||
|
case DOCUMENTEVENT_CREATEDCPRE:
|
|||
|
|
|||
|
Assert(cbIn >= sizeof(CREATEDCDATA) && pjIn && cbOut >= sizeof(PDEVMODE) && pjOut);
|
|||
|
result = DocEventCreateDCPre(hPrinter, hdc, (PCREATEDCDATA) pjIn, (PDEVMODE *) pjOut);
|
|||
|
break;
|
|||
|
|
|||
|
case DOCUMENTEVENT_CREATEDCPOST:
|
|||
|
|
|||
|
//
|
|||
|
// Handle CREATEDCPOST document event:
|
|||
|
// If CreateDC succeeded, then associate the user mode memory structure
|
|||
|
// with the device context. Otherwise, free the user mode memory structure.
|
|||
|
//
|
|||
|
|
|||
|
Assert(cbIn >= sizeof(PVOID) && pjIn);
|
|||
|
pDevmode = *((PDEVMODE *) pjIn);
|
|||
|
Assert(CurrentVersionDevmode(pDevmode));
|
|||
|
|
|||
|
pUserMem = ((PDRVDEVMODE) pDevmode)->dmPrivate.pUserMem;
|
|||
|
Assert(ValidPDEVUserMem(pUserMem));
|
|||
|
|
|||
|
if (hdc) {
|
|||
|
|
|||
|
pUserMem->hdc = hdc;
|
|||
|
|
|||
|
EnterDrvSem();
|
|||
|
pUserMem->pNext = gUserMemList;
|
|||
|
gUserMemList = pUserMem;
|
|||
|
LeaveDrvSem();
|
|||
|
|
|||
|
} else
|
|||
|
FreePDEVUserMem(pUserMem);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case DOCUMENTEVENT_RESETDCPRE:
|
|||
|
|
|||
|
Verbose(("Document event: RESETDCPRE\n"));
|
|||
|
Assert(cbIn >= sizeof(PVOID) && pjIn && cbOut >= sizeof(PDEVMODE) && pjOut);
|
|||
|
result = DocEventResetDCPre(hdc, pUserMem, *((PDEVMODE *) pjIn), (PDEVMODE *) pjOut);
|
|||
|
break;
|
|||
|
|
|||
|
case DOCUMENTEVENT_STARTDOCPRE:
|
|||
|
//
|
|||
|
// if printing a fax attachment then enable direct printing
|
|||
|
//
|
|||
|
|
|||
|
if (pUserMem->hMutex == NULL) {
|
|||
|
pUserMem->hMutex = OpenMutex(MUTEX_ALL_ACCESS,FALSE,FAXXP_MUTEX_NAME);
|
|||
|
if (pUserMem->hMutex) {
|
|||
|
if (WaitForSingleObject( pUserMem->hMutex, 0) == WAIT_OBJECT_0) {
|
|||
|
pUserMem->directPrinting = TRUE;
|
|||
|
}
|
|||
|
else {
|
|||
|
CloseHandle( pUserMem->hMutex ) ;
|
|||
|
pUserMem->hMutex = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// normal case if we're bringing up the send wizard
|
|||
|
//
|
|||
|
|
|||
|
if (! pUserMem->directPrinting) {
|
|||
|
|
|||
|
Assert(cbIn >= sizeof(PVOID) && pjIn);
|
|||
|
result = DocEventStartDocPre(hdc, pUserMem, *((LPDOCINFO *) pjIn));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// we're doing direct printing -- check if this is invoked via mapi-spooler
|
|||
|
//
|
|||
|
else if (pUserMem->hMutex) {
|
|||
|
//
|
|||
|
// we own the mutex...make sure we can open the shared memory region.
|
|||
|
//
|
|||
|
pUserMem->pEnvVar = OpenFileMapping(FILE_MAP_ALL_ACCESS,FALSE,FAXXP_MEM_NAME);
|
|||
|
if (!pUserMem->pEnvVar) {
|
|||
|
ReleaseMutex( pUserMem->hMutex );
|
|||
|
CloseHandle( pUserMem->hMutex );
|
|||
|
pUserMem->hMutex = NULL;
|
|||
|
} else {
|
|||
|
//
|
|||
|
// we own the mutex and we have the shared memory region open.
|
|||
|
//
|
|||
|
|
|||
|
// check if we are printing to a file or are doing direct printing for
|
|||
|
// the mapi spooler.
|
|||
|
//
|
|||
|
LPTSTR filename;
|
|||
|
|
|||
|
filename = (LPTSTR)MapViewOfFile(
|
|||
|
pUserMem->pEnvVar,
|
|||
|
FILE_MAP_WRITE,
|
|||
|
0,
|
|||
|
0,
|
|||
|
0
|
|||
|
);
|
|||
|
|
|||
|
if (!filename) {
|
|||
|
Error(("Failed to map a view of the file: %d\n", pUserMem->pEnvVar));
|
|||
|
return DOCUMENTEVENT_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
if (filename && *filename) {
|
|||
|
//
|
|||
|
// this is really the filename we want to print to.
|
|||
|
//
|
|||
|
pUserMem->directPrinting = TRUE;
|
|||
|
pUserMem->pPrintFile = DuplicateString(filename);
|
|||
|
pUserMem->jobType = JOBTYPE_DIRECT;
|
|||
|
(*((LPDOCINFO *) pjIn))->lpszOutput = pUserMem->pPrintFile;
|
|||
|
}
|
|||
|
|
|||
|
UnmapViewOfFile( filename );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case DOCUMENTEVENT_STARTDOCPOST:
|
|||
|
|
|||
|
if (!pUserMem->directPrinting && pUserMem->jobType == JOBTYPE_NORMAL) {
|
|||
|
|
|||
|
//
|
|||
|
// Job ID is passed in from GDI
|
|||
|
//
|
|||
|
|
|||
|
Assert(cbIn >= sizeof(DWORD) && pjIn);
|
|||
|
pUserMem->jobId = *((LPDWORD) pjIn);
|
|||
|
|
|||
|
//
|
|||
|
// Tell spooler to pause the fax body job so that
|
|||
|
// we can associate cover pages with it later
|
|||
|
//
|
|||
|
|
|||
|
if (! SetJob(pUserMem->hPrinter, pUserMem->jobId, 0, NULL, JOB_CONTROL_PAUSE)) {
|
|||
|
|
|||
|
Error(("Couldn't pause fax body job: %d\n", pUserMem->jobId));
|
|||
|
return DOCUMENTEVENT_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
} else if (pUserMem->pEnvVar) {
|
|||
|
|
|||
|
LPDWORD pJobId;
|
|||
|
|
|||
|
//
|
|||
|
// Job ID is passed in from GDI
|
|||
|
//
|
|||
|
|
|||
|
Assert(cbIn >= sizeof(DWORD) && pjIn);
|
|||
|
pUserMem->jobId = *((LPDWORD) pjIn);
|
|||
|
|
|||
|
if (!pUserMem->pPrintFile) {
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Tell spooler to pause the fax job
|
|||
|
// so that the mapi fax transport provider
|
|||
|
// can chain this job
|
|||
|
//
|
|||
|
|
|||
|
if (! SetJob(pUserMem->hPrinter, pUserMem->jobId, 0, NULL, JOB_CONTROL_PAUSE)) {
|
|||
|
|
|||
|
Error(("Couldn't pause fax body job: %d\n", pUserMem->jobId));
|
|||
|
return DOCUMENTEVENT_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
pJobId = (LPDWORD)MapViewOfFile(
|
|||
|
pUserMem->pEnvVar,
|
|||
|
FILE_MAP_WRITE,
|
|||
|
0,
|
|||
|
0,
|
|||
|
0
|
|||
|
);
|
|||
|
if (!pJobId) {
|
|||
|
Error(("Failed to map a view of the file: %d\n", pUserMem->jobId));
|
|||
|
return DOCUMENTEVENT_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
*pJobId = (DWORD) pUserMem->jobId;
|
|||
|
|
|||
|
UnmapViewOfFile( pJobId );
|
|||
|
CloseHandle( pUserMem->pEnvVar );
|
|||
|
pUserMem->pEnvVar = NULL;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case DOCUMENTEVENT_ENDPAGE:
|
|||
|
|
|||
|
if (! pUserMem->directPrinting)
|
|||
|
pUserMem->pageCount++;
|
|||
|
break;
|
|||
|
|
|||
|
case DOCUMENTEVENT_ENDDOCPOST:
|
|||
|
|
|||
|
if (! pUserMem->directPrinting)
|
|||
|
result = DocEventEndDocPost(hdc, pUserMem);
|
|||
|
else if (pUserMem->hMutex) {
|
|||
|
HANDLE hEvent = NULL;
|
|||
|
|
|||
|
hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, FAXXP_EVENT_NAME);
|
|||
|
if (hEvent) {
|
|||
|
SetEvent(hEvent);
|
|||
|
CloseHandle(hEvent) ;
|
|||
|
}
|
|||
|
|
|||
|
ReleaseMutex(pUserMem->hMutex);
|
|||
|
CloseHandle(pUserMem->hMutex);
|
|||
|
pUserMem->hMutex = NULL;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case DOCUMENTEVENT_DELETEDC:
|
|||
|
|
|||
|
EnterDrvSem();
|
|||
|
|
|||
|
if (pUserMem == gUserMemList)
|
|||
|
gUserMemList = gUserMemList->pNext;
|
|||
|
else {
|
|||
|
|
|||
|
PUSERMEM p;
|
|||
|
|
|||
|
if (p = gUserMemList) {
|
|||
|
|
|||
|
while (p->pNext && p->pNext != pUserMem)
|
|||
|
p = p->pNext;
|
|||
|
|
|||
|
if (p->pNext != NULL)
|
|||
|
p->pNext = pUserMem->pNext;
|
|||
|
else
|
|||
|
Error(("Orphaned user mode memory structure!!!\n"));
|
|||
|
|
|||
|
} else
|
|||
|
Error(("gUserMemList shouldn't be NULL!!!\n"));
|
|||
|
}
|
|||
|
|
|||
|
LeaveDrvSem();
|
|||
|
FreePDEVUserMem(pUserMem);
|
|||
|
break;
|
|||
|
|
|||
|
case DOCUMENTEVENT_ABORTDOC:
|
|||
|
case DOCUMENTEVENT_RESETDCPOST:
|
|||
|
case DOCUMENTEVENT_STARTPAGE:
|
|||
|
case DOCUMENTEVENT_ENDDOCPRE:
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case DOCUMENTEVENT_ESCAPE:
|
|||
|
default:
|
|||
|
|
|||
|
Verbose(("Unsupported DrvDocumentEvent escape: %d\n", iEsc));
|
|||
|
result = DOCUMENTEVENT_UNSUPPORTED;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|