|
|
/*++
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; }
|