You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3441 lines
110 KiB
3441 lines
110 KiB
/*++
|
|
|
|
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 "prtcovpg.h"
|
|
#include "jobtag.h"
|
|
#include "faxreg.h"
|
|
#include "faxsendw.h"
|
|
#include "InfoWzrd.h"
|
|
#include "tifflib.h"
|
|
#include "faxutil.h"
|
|
#include "covpg.h"
|
|
|
|
|
|
//
|
|
// Defenitions
|
|
//
|
|
#define SZ_CONT TEXT("...")
|
|
#define SZ_CONT_SIZE (sizeof(SZ_CONT) / sizeof(TCHAR))
|
|
|
|
|
|
//
|
|
// Defined in FaxUI.c
|
|
// Used to block the reentrancy of FxsWzrd.dll
|
|
//
|
|
extern BOOL g_bRunningWizard;
|
|
extern CRITICAL_SECTION g_csRunningWizard;
|
|
extern BOOL g_bInitRunningWizardCS;
|
|
|
|
//
|
|
// 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)
|
|
|
|
static DWORD LaunchFaxWizard(PDOCEVENTUSERMEM pDocEventUserMem);
|
|
static DWORD ShowReentrancyMessage(void);
|
|
|
|
|
|
static void
|
|
ComposeRecipientJobParam(
|
|
LPTSTR lpParamBuf,
|
|
LPDWORD lpdwParamSize,
|
|
const COVERPAGEFIELDS * pCPFields
|
|
);
|
|
|
|
static void
|
|
ComposeSenderJobParam(
|
|
LPTSTR lpParamBuf,
|
|
LPDWORD lpdwParamSize,
|
|
PDOCEVENTUSERMEM pDocEventUserMem,
|
|
const COVERPAGEFIELDS * pCPFields
|
|
);
|
|
|
|
static BOOL
|
|
ComposeFaxJobParameter(
|
|
PDOCEVENTUSERMEM pDocEventUserMem,
|
|
PCOVERPAGEFIELDS pCPFields,
|
|
LPTSTR * lppParamBuf
|
|
);
|
|
|
|
static void
|
|
CloseMappingHandles(
|
|
PDOCEVENTUSERMEM pDocEventUserMem
|
|
);
|
|
|
|
|
|
PDOCEVENTUSERMEM
|
|
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
|
|
|
|
--*/
|
|
|
|
{
|
|
PDOCEVENTUSERMEM pDocEventUserMem;
|
|
|
|
//
|
|
// Get a pointer to the user mode memory structure associated
|
|
// with the specified device context
|
|
//
|
|
|
|
EnterDrvSem();
|
|
|
|
pDocEventUserMem = gDocEventUserMemList;
|
|
|
|
while (pDocEventUserMem && hdc != pDocEventUserMem->hdc)
|
|
pDocEventUserMem = pDocEventUserMem->pNext;
|
|
|
|
LeaveDrvSem();
|
|
|
|
//
|
|
// Make sure the user memory structure is valid
|
|
//
|
|
if (pDocEventUserMem)
|
|
{
|
|
if (! ValidPDEVUserMem(pDocEventUserMem))
|
|
{
|
|
Error(("Corrupted user mode memory structure\n"));
|
|
pDocEventUserMem = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Error(("DC has no associated user mode memory structure\n"));
|
|
}
|
|
return pDocEventUserMem;
|
|
}
|
|
|
|
|
|
static LRESULT
|
|
FaxFreePersonalProfileInformation(
|
|
PFAX_PERSONAL_PROFILE lpPersonalProfileInfo
|
|
)
|
|
{
|
|
if (lpPersonalProfileInfo)
|
|
{
|
|
MemFree(lpPersonalProfileInfo->lptstrName);
|
|
MemFree(lpPersonalProfileInfo->lptstrFaxNumber);
|
|
MemFree(lpPersonalProfileInfo->lptstrCompany);
|
|
MemFree(lpPersonalProfileInfo->lptstrStreetAddress);
|
|
MemFree(lpPersonalProfileInfo->lptstrCity);
|
|
MemFree(lpPersonalProfileInfo->lptstrState);
|
|
MemFree(lpPersonalProfileInfo->lptstrZip);
|
|
MemFree(lpPersonalProfileInfo->lptstrCountry);
|
|
MemFree(lpPersonalProfileInfo->lptstrTitle);
|
|
MemFree(lpPersonalProfileInfo->lptstrDepartment);
|
|
MemFree(lpPersonalProfileInfo->lptstrOfficeLocation);
|
|
MemFree(lpPersonalProfileInfo->lptstrHomePhone);
|
|
MemFree(lpPersonalProfileInfo->lptstrOfficePhone);
|
|
MemFree(lpPersonalProfileInfo->lptstrEmail);
|
|
MemFree(lpPersonalProfileInfo->lptstrBillingCode);
|
|
MemFree(lpPersonalProfileInfo->lptstrTSID);
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|
|
static LRESULT
|
|
FreeRecipientInfo(DWORD * pdwNumberOfRecipients, PFAX_PERSONAL_PROFILE lpRecipientsInfo)
|
|
{
|
|
LRESULT lResult;
|
|
DWORD i;
|
|
|
|
Assert(pdwNumberOfRecipients);
|
|
|
|
if (*pdwNumberOfRecipients==0)
|
|
return ERROR_SUCCESS;
|
|
|
|
Assert(lpRecipientsInfo);
|
|
|
|
for(i=0;i<*pdwNumberOfRecipients;i++)
|
|
{
|
|
if (lResult = FaxFreePersonalProfileInformation(&lpRecipientsInfo[i]) != ERROR_SUCCESS)
|
|
return lResult;
|
|
}
|
|
|
|
MemFree(lpRecipientsInfo);
|
|
|
|
*pdwNumberOfRecipients = 0;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
static DWORD
|
|
CopyRecipientInfo(DWORD dwNumberOfRecipients,
|
|
PFAX_PERSONAL_PROFILE pfppDestination,
|
|
PFAX_PERSONAL_PROFILE pfppSource)
|
|
{
|
|
DWORD dwIndex;
|
|
|
|
Assert(pfppDestination);
|
|
Assert(pfppSource);
|
|
|
|
for(dwIndex=0;dwIndex<dwNumberOfRecipients;dwIndex++)
|
|
{
|
|
if ((pfppDestination[dwIndex].lptstrName = DuplicateString(pfppSource[dwIndex].lptstrName)) == NULL)
|
|
{
|
|
Error(("Memory allocation failed\n"));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
if ((pfppDestination[dwIndex].lptstrFaxNumber = DuplicateString(pfppSource[dwIndex].lptstrFaxNumber)) == NULL)
|
|
{
|
|
Error(("Memory allocation failed\n"));
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
Verbose(("Copied %ws from %ws\n", pfppSource[dwIndex].lptstrName,pfppSource[dwIndex].lptstrFaxNumber));
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
static DWORD
|
|
CopyPersonalProfileInfo( PFAX_PERSONAL_PROFILE pfppDestination,
|
|
PFAX_PERSONAL_PROFILE pfppSource)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Duplicates FAX_PERSONAL_PROFILE structures
|
|
|
|
Arguments:
|
|
|
|
pfppDestination - points to destination structure
|
|
pfppSource - points to source structure
|
|
|
|
Comments:
|
|
Set pfppDestination->dwSizeOfStruct before call to this function
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS
|
|
ERROR_INVALID_PARAMETER
|
|
ERROR_NOT_ENOUGH_MEMORY
|
|
|
|
--*/
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
|
|
Assert(pfppDestination);
|
|
Assert(pfppSource);
|
|
|
|
if (!pfppSource || !pfppDestination || (pfppSource->dwSizeOfStruct != sizeof(FAX_PERSONAL_PROFILE))
|
|
|| (pfppDestination->dwSizeOfStruct != sizeof(FAX_PERSONAL_PROFILE)))
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
ZeroMemory(pfppDestination, sizeof(FAX_PERSONAL_PROFILE));
|
|
|
|
pfppDestination->dwSizeOfStruct = sizeof(FAX_PERSONAL_PROFILE);
|
|
|
|
if (pfppSource->lptstrName && !(pfppDestination->lptstrName = StringDup(pfppSource->lptstrName)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
if (pfppSource->lptstrFaxNumber && !(pfppDestination->lptstrFaxNumber = StringDup(pfppSource->lptstrFaxNumber)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
if (pfppSource->lptstrCompany && !(pfppDestination->lptstrCompany = StringDup(pfppSource->lptstrCompany)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
if (pfppSource->lptstrStreetAddress && !(pfppDestination->lptstrStreetAddress = StringDup(pfppSource->lptstrStreetAddress)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
if (pfppSource->lptstrCity && !(pfppDestination->lptstrCity = StringDup(pfppSource->lptstrCity)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
if (pfppSource->lptstrState && !(pfppDestination->lptstrState = StringDup(pfppSource->lptstrState)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
if (pfppSource->lptstrZip && !(pfppDestination->lptstrZip = StringDup(pfppSource->lptstrZip)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
if (pfppSource->lptstrCountry && !(pfppDestination->lptstrCountry = StringDup(pfppSource->lptstrCountry)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
if (pfppSource->lptstrTitle && !(pfppDestination->lptstrTitle = StringDup(pfppSource->lptstrTitle)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
if (pfppSource->lptstrDepartment && !(pfppDestination->lptstrDepartment = StringDup(pfppSource->lptstrDepartment)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
if (pfppSource->lptstrOfficeLocation && !(pfppDestination->lptstrOfficeLocation = StringDup(pfppSource->lptstrOfficeLocation)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
if (pfppSource->lptstrHomePhone && !(pfppDestination->lptstrHomePhone = StringDup(pfppSource->lptstrHomePhone)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
if (pfppSource->lptstrOfficePhone && !(pfppDestination->lptstrOfficePhone = StringDup(pfppSource->lptstrOfficePhone)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
if (pfppSource->lptstrEmail && !(pfppDestination->lptstrEmail = StringDup(pfppSource->lptstrEmail)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
if (pfppSource->lptstrBillingCode && !(pfppDestination->lptstrBillingCode = StringDup(pfppSource->lptstrBillingCode)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
if (pfppSource->lptstrTSID && !(pfppDestination->lptstrTSID = StringDup(pfppSource->lptstrTSID)))
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
|
|
goto exit;
|
|
|
|
error:
|
|
MemFree(pfppDestination->lptstrName);
|
|
MemFree(pfppDestination->lptstrFaxNumber);
|
|
MemFree(pfppDestination->lptstrCompany);
|
|
MemFree(pfppDestination->lptstrStreetAddress);
|
|
MemFree(pfppDestination->lptstrCity);
|
|
MemFree(pfppDestination->lptstrState);
|
|
MemFree(pfppDestination->lptstrZip);
|
|
MemFree(pfppDestination->lptstrCountry);
|
|
MemFree(pfppDestination->lptstrTitle);
|
|
MemFree(pfppDestination->lptstrDepartment);
|
|
MemFree(pfppDestination->lptstrOfficeLocation);
|
|
MemFree(pfppDestination->lptstrHomePhone);
|
|
MemFree(pfppDestination->lptstrOfficePhone);
|
|
MemFree(pfppDestination->lptstrEmail);
|
|
MemFree(pfppDestination->lptstrBillingCode);
|
|
MemFree(pfppDestination->lptstrTSID);
|
|
|
|
exit:
|
|
return dwResult;
|
|
}
|
|
|
|
VOID
|
|
FreePDEVUserMem(
|
|
PDOCEVENTUSERMEM pDocEventUserMem
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free up the user mode memory associated with each PDEV and delete preview file if created.
|
|
|
|
Arguments:
|
|
|
|
pDocEventUserMem - Points to the user mode memory structure
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
if (pDocEventUserMem) {
|
|
|
|
FreeRecipientInfo(&pDocEventUserMem->dwNumberOfRecipients,pDocEventUserMem->lpRecipientsInfo);
|
|
FaxFreePersonalProfileInformation(pDocEventUserMem->lpSenderInfo);
|
|
|
|
//
|
|
// Free our mapping file resources (if allocated)
|
|
//
|
|
CloseMappingHandles(pDocEventUserMem);
|
|
|
|
//
|
|
// If we created a preview file, and for some reason it wasn't deleted than delete it.
|
|
//
|
|
if (pDocEventUserMem->szPreviewFile[0] != TEXT('\0'))
|
|
{
|
|
if (!DeleteFile(pDocEventUserMem->szPreviewFile))
|
|
{
|
|
Error(("DeleteFile() failed. Error code: %d.\n", GetLastError()));
|
|
}
|
|
}
|
|
|
|
MemFree(pDocEventUserMem->lpSenderInfo);
|
|
MemFree(pDocEventUserMem->lptstrServerName);
|
|
MemFree(pDocEventUserMem->lptstrPrinterName);
|
|
MemFree(pDocEventUserMem->pSubject);
|
|
MemFree(pDocEventUserMem->pNoteMessage);
|
|
MemFree(pDocEventUserMem->pPrintFile);
|
|
MemFree(pDocEventUserMem->pReceiptAddress);
|
|
MemFree(pDocEventUserMem->pPriority);
|
|
MemFree(pDocEventUserMem->pReceiptFlags);
|
|
MemFree(pDocEventUserMem);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
CloseMappingHandles(PDOCEVENTUSERMEM pDocEventUserMem)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free any resources that were used for the preview mapping
|
|
|
|
Arguments:
|
|
|
|
pDocEventUserMem - Points to the user mode memory structure
|
|
|
|
Return Value: --
|
|
|
|
--*/
|
|
|
|
{
|
|
if (pDocEventUserMem->pPreviewTiffPage)
|
|
{
|
|
UnmapViewOfFile(pDocEventUserMem->pPreviewTiffPage);
|
|
pDocEventUserMem->pPreviewTiffPage = NULL;
|
|
}
|
|
if (pDocEventUserMem->hMapping)
|
|
{
|
|
if (!CloseHandle(pDocEventUserMem->hMapping))
|
|
{
|
|
Error(("CloseHandle() failed: %d.\n", GetLastError()));
|
|
// Try to continue...
|
|
}
|
|
pDocEventUserMem->hMapping = NULL;
|
|
}
|
|
if (INVALID_HANDLE_VALUE != pDocEventUserMem->hMappingFile)
|
|
{
|
|
if (!CloseHandle(pDocEventUserMem->hMappingFile))
|
|
{
|
|
Error(("CloseHandle() failed: %d.\n", GetLastError()));
|
|
// Try to continue...
|
|
}
|
|
pDocEventUserMem->hMappingFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
CreateTiffPageMapping(PDOCEVENTUSERMEM pDocEventUserMem)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a temperary file of size MAX_TIFF_PAGE_SIZE, and maps a view to it. This mapping serves
|
|
as a communication channel between the UI and Graphics driver parts to transfer preview pages.
|
|
|
|
The page starts with a MAP_TIFF_PAGE_HEADER structure that has the following fields:
|
|
cb - The structure size
|
|
dwDataSize - The number of bytes of the raw TIFF data constructing the next page
|
|
iPageCount - The page number currently printed
|
|
bPreview - TRUE if everything until now is OK. FALSE if print preview is disabled or
|
|
aborted (by either driver parts).
|
|
|
|
The cb and iPageCount fields are used to validate the mapping: cb should always be the structure
|
|
size and iPageCount should be the same as our internal page count (pDocEventUserMem->pageCount)
|
|
when a new page is retrieved.
|
|
The bPreview field is used to abort the print preview operation by either driver parts.
|
|
|
|
This function sets the hMappingFile, hMapping, pPreviewTiffPage and devmode.dmPrivate.szMappingFile
|
|
fields of the user memory structure according to success / failure.
|
|
|
|
Arguments:
|
|
|
|
pDocEventUserMem - Points to the user mode memory structure
|
|
|
|
Return Value:
|
|
|
|
Win32 Error codes
|
|
|
|
--*/
|
|
|
|
{
|
|
TCHAR szTmpPath[MAX_PATH];
|
|
DWORD dwRet = ERROR_SUCCESS;
|
|
LPTSTR pszMappingFile = pDocEventUserMem->devmode.dmPrivate.szMappingFile;
|
|
UINT uRet;
|
|
|
|
//
|
|
// Invalidate all mapping handles
|
|
//
|
|
pDocEventUserMem->hMappingFile = INVALID_HANDLE_VALUE;
|
|
pDocEventUserMem->hMapping = NULL;
|
|
pDocEventUserMem->pPreviewTiffPage = NULL;
|
|
|
|
//
|
|
// Create the path for our mapping file. This path HAS to be under the system32
|
|
// directory or the kernel driver (NT4) won't be able to map the file. My choice is:
|
|
// '%WinDir%\system32\'
|
|
//
|
|
uRet = GetSystemDirectory(szTmpPath, MAX_PATH);
|
|
if (!uRet)
|
|
{
|
|
dwRet = GetLastError();
|
|
goto ErrExit;
|
|
}
|
|
|
|
//
|
|
// Look for %windir%\system32\FxsTmp folder that is created by Setup.
|
|
//
|
|
if (wcslen(szTmpPath) +
|
|
wcslen(FAX_PREVIEW_TMP_DIR) >= MAX_PATH)
|
|
{
|
|
dwRet = ERROR_BUFFER_OVERFLOW;
|
|
goto ErrExit;
|
|
}
|
|
wcscat(szTmpPath, FAX_PREVIEW_TMP_DIR);
|
|
|
|
//
|
|
// Create a NEW file
|
|
//
|
|
if (!GetTempFileName(szTmpPath, FAX_PREFIX, 0, pszMappingFile))
|
|
{
|
|
dwRet = GetLastError();
|
|
Error(("GetTempFileName() failed:%d\n", dwRet));
|
|
goto ErrExit;
|
|
}
|
|
|
|
//
|
|
// Open the new file with shared read / write / delete privileges and FILE_FLAG_DELETE_ON_CLOSE
|
|
// attribute
|
|
//
|
|
if ( INVALID_HANDLE_VALUE == (pDocEventUserMem->hMappingFile = SafeCreateTempFile(
|
|
pszMappingFile,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
|
|
NULL)))
|
|
{
|
|
dwRet = GetLastError();
|
|
Error(("CreateFile() failed: %d.\n", dwRet));
|
|
if (!DeleteFile(pszMappingFile))
|
|
{
|
|
Error(("DeleteFile() failed: %d.\n", GetLastError()));
|
|
}
|
|
goto ErrExit;
|
|
}
|
|
|
|
//
|
|
// Extend the file size to MAX_TIFF_PAGE_SIZE
|
|
//
|
|
dwRet = SetFilePointer(
|
|
pDocEventUserMem->hMappingFile,
|
|
MAX_TIFF_PAGE_SIZE,
|
|
NULL,
|
|
FILE_BEGIN);
|
|
if (INVALID_SET_FILE_POINTER == dwRet)
|
|
{
|
|
dwRet = GetLastError();
|
|
Error(("SetFilePointer() failed:%d\n", dwRet));
|
|
goto ErrExit;
|
|
}
|
|
if (!SetEndOfFile(pDocEventUserMem->hMappingFile))
|
|
{
|
|
dwRet = GetLastError();
|
|
Error(("SetEndOfFile() failed:%d\n", dwRet));
|
|
goto ErrExit;
|
|
}
|
|
|
|
//
|
|
// Create a file mapping of the whole file
|
|
//
|
|
pDocEventUserMem->hMapping = CreateFileMapping(
|
|
pDocEventUserMem->hMappingFile, // handle to file
|
|
NULL, // security
|
|
PAGE_READWRITE, // protection
|
|
0, // high-order DWORD of size
|
|
0, // low-order DWORD of size
|
|
NULL // object name
|
|
);
|
|
if (pDocEventUserMem->hMapping == NULL)
|
|
{
|
|
dwRet = GetLastError();
|
|
Error(("File mapping failed:%d\n", dwRet));
|
|
goto ErrExit;
|
|
}
|
|
|
|
//
|
|
// Open a view
|
|
//
|
|
pDocEventUserMem->pPreviewTiffPage = (PMAP_TIFF_PAGE_HEADER) MapViewOfFile(
|
|
pDocEventUserMem->hMapping, // handle to file-mapping object
|
|
FILE_MAP_WRITE, // access mode
|
|
0, // high-order DWORD of offset
|
|
0, // low-order DWORD of offset
|
|
0 // number of bytes to map
|
|
);
|
|
if (NULL == pDocEventUserMem->pPreviewTiffPage)
|
|
{
|
|
dwRet = GetLastError();
|
|
Error(("MapViewOfFile() failed:%d\n", dwRet));
|
|
goto ErrExit;
|
|
}
|
|
|
|
//
|
|
// Success - set initial header information
|
|
//
|
|
pDocEventUserMem->pPreviewTiffPage->bPreview = FALSE;
|
|
pDocEventUserMem->pPreviewTiffPage->cb = sizeof(MAP_TIFF_PAGE_HEADER);
|
|
pDocEventUserMem->pPreviewTiffPage->dwDataSize = 0;
|
|
pDocEventUserMem->pPreviewTiffPage->iPageCount = 0;
|
|
return ERROR_SUCCESS;
|
|
|
|
ErrExit:
|
|
|
|
//
|
|
// Cleanup
|
|
//
|
|
// IMPORTANT: Set mapping file name to empty string. This signals the graphics dll that
|
|
// there is no mapping file.
|
|
//
|
|
CloseMappingHandles(pDocEventUserMem);
|
|
pszMappingFile[0] = TEXT('\0');
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
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
|
|
|
|
--*/
|
|
{
|
|
PDOCEVENTUSERMEM pDocEventUserMem = NULL;
|
|
PPRINTER_INFO_2 pPrinterInfo2 = NULL;
|
|
DWORD dwRes;
|
|
DWORD dwEnvSize;
|
|
|
|
Assert(pCreateDCData);
|
|
Assert(ppdmOutput);
|
|
|
|
Verbose(("Document event: CREATEDCPRE%s\n", pCreateDCData->fromCreateIC ? "*" : ""));
|
|
*ppdmOutput = NULL;
|
|
|
|
//
|
|
// Allocate space for user mode memory data structure
|
|
//
|
|
|
|
if (((pDocEventUserMem = MemAllocZ(sizeof(DOCEVENTUSERMEM))) == NULL))
|
|
{
|
|
Error(("Memory allocation failed\n"));
|
|
goto Error;
|
|
}
|
|
|
|
ZeroMemory(pDocEventUserMem, sizeof(DOCEVENTUSERMEM));
|
|
|
|
if ((pPrinterInfo2 = MyGetPrinter(hPrinter, 2)) == NULL ||
|
|
(pDocEventUserMem->lptstrPrinterName = DuplicateString(pPrinterInfo2->pPrinterName)) == NULL)
|
|
{
|
|
Error(("Memory allocation failed\n"));
|
|
goto Error;
|
|
}
|
|
|
|
if (pPrinterInfo2->pServerName==NULL)
|
|
{
|
|
pDocEventUserMem->lptstrServerName = NULL;
|
|
}
|
|
else
|
|
{
|
|
LPTSTR pServerName = pPrinterInfo2->pServerName;
|
|
|
|
//
|
|
// Truncate prefix backslashes
|
|
//
|
|
while (*pServerName == TEXT('\\'))
|
|
{
|
|
pServerName++;
|
|
}
|
|
//
|
|
// Save the server name
|
|
//
|
|
if ((pDocEventUserMem->lptstrServerName = DuplicateString(pServerName)) == NULL)
|
|
{
|
|
Error(("Memory allocation failed\n"));
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Merge the input devmode with the driver and system defaults
|
|
//
|
|
|
|
pDocEventUserMem->hPrinter = hPrinter;
|
|
|
|
GetCombinedDevmode(&pDocEventUserMem->devmode,
|
|
pCreateDCData->pdmInput, hPrinter, pPrinterInfo2, FALSE);
|
|
Verbose(("Document event: CREATEDCPRE %x\n", pDocEventUserMem));
|
|
MemFree(pPrinterInfo2);
|
|
pPrinterInfo2 = NULL;
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
//
|
|
// The above comment is not accurate. The flag that turns off the wizard is
|
|
// FAXMDM_NO_WIZARD.
|
|
// This flag is set in the private DEVMODE area (flags field) by FaxStartPrintJob.
|
|
// FaxStartPrintJob already has all the information that the wizard usually provides and it
|
|
// wishes the wizard to not show up. To do that it sets this field and passes the
|
|
// job parameters in the JOB_INFO_2.pParameters string as a tagged string.
|
|
// Note that this is not the same case as when StartDoc is called with a output file name specified.
|
|
// In this case the wizard is not brought up as well.
|
|
//
|
|
if (pDocEventUserMem->devmode.dmPrivate.flags & FAXDM_NO_WIZARD)
|
|
{
|
|
pDocEventUserMem->directPrinting = TRUE;
|
|
}
|
|
//
|
|
// if printing a fax attachment then enable direct printing
|
|
//
|
|
dwEnvSize = GetEnvironmentVariable( FAX_ENVVAR_PRINT_FILE, NULL, 0 );
|
|
if (dwEnvSize)
|
|
{
|
|
pDocEventUserMem->pPrintFile = (LPTSTR) MemAllocZ( dwEnvSize * sizeof(TCHAR) );
|
|
if (NULL == pDocEventUserMem->pPrintFile)
|
|
{
|
|
Error(("Memory allocation failed\n"));
|
|
goto Error;
|
|
}
|
|
|
|
if (0 == GetEnvironmentVariable( FAX_ENVVAR_PRINT_FILE, pDocEventUserMem->pPrintFile, dwEnvSize ))
|
|
{
|
|
Error(("GetEnvironmentVariable failed\n"));
|
|
MemFree (pDocEventUserMem->pPrintFile);
|
|
pDocEventUserMem->pPrintFile = NULL;
|
|
goto Error;
|
|
}
|
|
pDocEventUserMem->bAttachment = TRUE;
|
|
pDocEventUserMem->directPrinting = TRUE;
|
|
}
|
|
|
|
//
|
|
// Create a memory mapped file that will serve as a commincation chanel between both
|
|
// driver parts. This file will provide means of transfering rendered TIFF pages for
|
|
// print preview if it was required by the user
|
|
//
|
|
dwRes = CreateTiffPageMapping(pDocEventUserMem);
|
|
if (ERROR_SUCCESS != dwRes)
|
|
{
|
|
Error(("CreateTiffPageMapping() failed: %d\n", dwRes));
|
|
//
|
|
// We can still continue, but print preview won't be available...
|
|
//
|
|
pDocEventUserMem->bShowPrintPreview = FALSE;
|
|
pDocEventUserMem->bPreviewAborted = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pDocEventUserMem->bShowPrintPreview = TRUE;
|
|
pDocEventUserMem->bPreviewAborted = FALSE;
|
|
}
|
|
//
|
|
// Initialize the TIFF preview file fields
|
|
//
|
|
pDocEventUserMem->szPreviewFile[0] = TEXT('\0');
|
|
pDocEventUserMem->hPreviewFile = INVALID_HANDLE_VALUE;
|
|
//
|
|
// Mark the private fields of our devmode
|
|
//
|
|
//@
|
|
//@ DocEventUserMem.Siganture is allways &DocEventUserMem
|
|
//@ DocEventUserMem.Signature.DocEventUserMem.Signature is allways &DocEventUserMem
|
|
//@ ValidPDEVUserMem checks for this.
|
|
//@
|
|
MarkPDEVUserMem(pDocEventUserMem);
|
|
//@
|
|
//@ This make the driver use the devmode we merged instaed of the
|
|
//@ devmode specified by the caller to CreateDC.
|
|
//@ This way we make sure the driver gets a DEVMODE with per user
|
|
//@ default (W2K) or just hard-code defaults (NT4) for all the fields
|
|
//@ that were not speicified or invalid in the input devmode.
|
|
//@ Note that the system passes to the driver a COPY of the devmode structure
|
|
//@ we return and NOT a pointer to it.
|
|
//@
|
|
*ppdmOutput = (PDEVMODE) &pDocEventUserMem->devmode;
|
|
return DOCUMENTEVENT_SUCCESS;
|
|
|
|
Error:
|
|
MemFree(pPrinterInfo2);
|
|
if (pDocEventUserMem)
|
|
{
|
|
MemFree(pDocEventUserMem->lptstrPrinterName);
|
|
MemFree(pDocEventUserMem->lptstrServerName);
|
|
MemFree(pDocEventUserMem);
|
|
}
|
|
return DOCUMENTEVENT_FAILURE;
|
|
}
|
|
|
|
|
|
INT
|
|
DocEventResetDCPre(
|
|
HDC hdc,
|
|
PDOCEVENTUSERMEM pDocEventUserMem,
|
|
PDEVMODE pdmInput,
|
|
PDEVMODE *ppdmOutput
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle RESETDCPRE document event
|
|
|
|
Arguments:
|
|
|
|
hdc - Specifies the printer device context
|
|
pDocEventUserMem - Points to the user mode memory of DocEvent 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) &pDocEventUserMem->devmode)
|
|
{
|
|
|
|
//
|
|
// ResetDC was called by ourselves - assume the devmode is already valid
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Merge the input devmode with driver and system default
|
|
//
|
|
GetCombinedDevmode(&pDocEventUserMem->devmode,
|
|
pdmInput, pDocEventUserMem->hPrinter, NULL, TRUE);
|
|
//
|
|
// Mark the private fields of our devmode
|
|
//
|
|
MarkPDEVUserMem(pDocEventUserMem);
|
|
}
|
|
*ppdmOutput = (PDEVMODE) &pDocEventUserMem->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 otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD fileAttrs;
|
|
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 = SafeCreateFile(pDestStr, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
hFile = SafeCreateFile(pDestStr, 0, 0, NULL, CREATE_NEW, 0, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
//
|
|
// Verifiy that we did not opened a port handle
|
|
//
|
|
fileAttrs = GetFileAttributes(pDestStr);
|
|
if (!CloseHandle(hFile))
|
|
{
|
|
Error(("CloseHandle() failed: %d.\n", GetLastError()));
|
|
// Try to continue...
|
|
}
|
|
if (0xffffffff == fileAttrs)
|
|
{
|
|
//
|
|
// pDestStr does not point to a valid file
|
|
//
|
|
return FALSE;
|
|
}
|
|
//
|
|
// it must be a file
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD LaunchFaxWizard(PDOCEVENTUSERMEM pDocEventUserMem)
|
|
{
|
|
DWORD hWndOwner = 0;
|
|
DWORD dwFlags = 0;
|
|
LPFAX_SEND_WIZARD_DATA lpInitialData = NULL;
|
|
LPFAX_SEND_WIZARD_DATA lpFaxSendWizardData = NULL;
|
|
INT iResult;
|
|
TCHAR tszNumericData[10]={0};
|
|
DWORD ec = ERROR_SUCCESS;
|
|
HRESULT hRc;
|
|
|
|
if ( !(lpFaxSendWizardData = MemAllocZ(sizeof(FAX_SEND_WIZARD_DATA))) ||
|
|
!(lpInitialData = MemAllocZ(sizeof(FAX_SEND_WIZARD_DATA))) )
|
|
{
|
|
ec = GetLastError();
|
|
Error(("Memory allocation failed\n"));
|
|
goto Error;
|
|
}
|
|
|
|
ZeroMemory(lpInitialData, sizeof(FAX_SEND_WIZARD_DATA));
|
|
lpInitialData->dwSizeOfStruct = sizeof(FAX_SEND_WIZARD_DATA);
|
|
lpInitialData->dwPageCount = pDocEventUserMem->pageCount;
|
|
|
|
ZeroMemory(lpFaxSendWizardData, sizeof(FAX_SEND_WIZARD_DATA));
|
|
lpFaxSendWizardData->dwSizeOfStruct = sizeof(FAX_SEND_WIZARD_DATA);
|
|
|
|
|
|
// prepare structures and parameters
|
|
lpInitialData->tmSchedule.wHour = pDocEventUserMem->devmode.dmPrivate.sendAtTime.Hour;
|
|
lpInitialData->tmSchedule.wMinute = pDocEventUserMem->devmode.dmPrivate.sendAtTime.Minute;
|
|
lpInitialData->lptstrPreviewFile = StringDup(pDocEventUserMem->szPreviewFile);
|
|
if (!lpInitialData->lptstrPreviewFile)
|
|
{
|
|
ec = GetLastError();
|
|
Error(("StringDup() failed (ec: %ld)",ec));
|
|
goto Error;
|
|
}
|
|
|
|
|
|
if (GetEnvironmentVariable(TEXT("NTFaxSendNote"), NULL, 0))
|
|
{
|
|
dwFlags |= FSW_USE_SEND_WIZARD | FSW_FORCE_COVERPAGE;
|
|
}
|
|
|
|
// If the file mapping succeeded enable the preview option
|
|
if (pDocEventUserMem->pPreviewTiffPage &&
|
|
FALSE == pDocEventUserMem->bPreviewAborted)
|
|
{
|
|
dwFlags |= FSW_PRINT_PREVIEW_OPTION;
|
|
}
|
|
|
|
iResult = DOCUMENTEVENT_SUCCESS;
|
|
|
|
hRc = FaxSendWizard( hWndOwner,
|
|
dwFlags,
|
|
pDocEventUserMem->lptstrServerName,
|
|
pDocEventUserMem->lptstrPrinterName,
|
|
lpInitialData,
|
|
pDocEventUserMem->tstrTifName,
|
|
ARR_SIZE(pDocEventUserMem->tstrTifName),
|
|
lpFaxSendWizardData );
|
|
{
|
|
}
|
|
|
|
if (S_FALSE == hRc)
|
|
{
|
|
ec = ERROR_CANCELLED;
|
|
goto Error; // This is not really an error
|
|
}
|
|
|
|
if (S_OK != hRc)
|
|
{
|
|
Error(("FaxSendWizard() failed (hRc: %ld)",hRc));
|
|
ec = ERROR_GEN_FAILURE;
|
|
goto Error;
|
|
}
|
|
|
|
//
|
|
// Unpack result structures:
|
|
//
|
|
|
|
pDocEventUserMem->devmode.dmPrivate.sendAtTime.Hour = lpFaxSendWizardData->tmSchedule.wHour ;
|
|
pDocEventUserMem->devmode.dmPrivate.sendAtTime.Minute = lpFaxSendWizardData->tmSchedule.wMinute ;
|
|
pDocEventUserMem->devmode.dmPrivate.whenToSend = lpFaxSendWizardData->dwScheduleAction;
|
|
|
|
|
|
Assert ((lpFaxSendWizardData->Priority >= FAX_PRIORITY_TYPE_LOW) &&
|
|
(lpFaxSendWizardData->Priority <= FAX_PRIORITY_TYPE_HIGH));
|
|
if (0 > _snwprintf (tszNumericData,
|
|
sizeof (tszNumericData) / sizeof (tszNumericData[0]) - 1,
|
|
TEXT("%d"),
|
|
lpFaxSendWizardData->Priority))
|
|
{
|
|
ec = ERROR_BUFFER_OVERFLOW;
|
|
goto Error;
|
|
}
|
|
|
|
pDocEventUserMem->pPriority = DuplicateString(tszNumericData);
|
|
if (!pDocEventUserMem->pPriority)
|
|
{
|
|
ec = GetLastError();
|
|
goto Error;
|
|
}
|
|
|
|
if (0 > _snwprintf (tszNumericData,
|
|
sizeof (tszNumericData) / sizeof (tszNumericData[0]) - 1,
|
|
TEXT("%d"),
|
|
lpFaxSendWizardData->dwReceiptDeliveryType))
|
|
{
|
|
ec = ERROR_BUFFER_OVERFLOW;
|
|
goto Error;
|
|
}
|
|
|
|
pDocEventUserMem->pReceiptFlags = DuplicateString(tszNumericData);
|
|
if (!pDocEventUserMem->pReceiptFlags)
|
|
{
|
|
ec = GetLastError();
|
|
goto Error;
|
|
}
|
|
|
|
if (lpFaxSendWizardData->szReceiptDeliveryAddress)
|
|
{
|
|
if (!(pDocEventUserMem->pReceiptAddress
|
|
= DuplicateString(lpFaxSendWizardData->szReceiptDeliveryAddress)))
|
|
{
|
|
ec = GetLastError();
|
|
Error(("DuplicateString() failed (ec: %ld)",ec));
|
|
goto Error;
|
|
}
|
|
}
|
|
if (lpFaxSendWizardData->lpSenderInfo->lptstrBillingCode)
|
|
_tcscpy(pDocEventUserMem->devmode.dmPrivate.billingCode,
|
|
lpFaxSendWizardData->lpSenderInfo->lptstrBillingCode);
|
|
|
|
if (lpFaxSendWizardData->lpCoverPageInfo->lptstrCoverPageFileName)
|
|
_tcscpy(pDocEventUserMem->coverPage,
|
|
lpFaxSendWizardData->lpCoverPageInfo->lptstrCoverPageFileName );
|
|
pDocEventUserMem->bServerCoverPage =
|
|
lpFaxSendWizardData->lpCoverPageInfo->bServerBased;
|
|
|
|
if (lpFaxSendWizardData->lpCoverPageInfo->lptstrSubject)
|
|
{
|
|
if (!(pDocEventUserMem->pSubject
|
|
= DuplicateString(lpFaxSendWizardData->lpCoverPageInfo->lptstrSubject)))
|
|
{
|
|
ec = GetLastError();
|
|
Error(("DuplicateString() failed (ec: %ld)",ec));
|
|
goto Error;
|
|
}
|
|
}
|
|
if (lpFaxSendWizardData->lpCoverPageInfo->lptstrNote)
|
|
{
|
|
if (!(pDocEventUserMem->pNoteMessage
|
|
= DuplicateString(lpFaxSendWizardData->lpCoverPageInfo->lptstrNote)))
|
|
{
|
|
ec = GetLastError();
|
|
Error(("DuplicateString() failed (ec: %ld)",ec));
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
Assert(lpFaxSendWizardData->dwNumberOfRecipients);
|
|
pDocEventUserMem->dwNumberOfRecipients = lpFaxSendWizardData->dwNumberOfRecipients;
|
|
|
|
if (!SetEnvironmentVariable( _T("ScanTifName"), pDocEventUserMem->tstrTifName ))
|
|
{
|
|
Error(("SetEnvironmentVariable failed. ec = 0x%X",GetLastError()));
|
|
}
|
|
|
|
// copy recipients
|
|
if ( pDocEventUserMem->dwNumberOfRecipients && (pDocEventUserMem->lpRecipientsInfo =
|
|
MemAllocZ(sizeof(FAX_PERSONAL_PROFILE)*pDocEventUserMem->dwNumberOfRecipients)) == NULL)
|
|
{
|
|
ec = GetLastError();
|
|
Error(("Memory allocation failed (ec: %ld)",ec));
|
|
goto Error;
|
|
}
|
|
|
|
if ((ec = CopyRecipientInfo(pDocEventUserMem->dwNumberOfRecipients,
|
|
pDocEventUserMem->lpRecipientsInfo,
|
|
lpFaxSendWizardData->lpRecipientsInfo)) != ERROR_SUCCESS)
|
|
{
|
|
|
|
Error(("CopyRecipientInfo failed (ec: %ld)",ec));
|
|
goto Error;
|
|
}
|
|
|
|
if (lpFaxSendWizardData->lpSenderInfo)
|
|
{
|
|
if ((pDocEventUserMem->lpSenderInfo = MemAllocZ(sizeof(FAX_PERSONAL_PROFILE))) == NULL)
|
|
{
|
|
|
|
ec = GetLastError();
|
|
Error(("MemAlloc() failed (ec: %ld)",ec));
|
|
goto Error;
|
|
}
|
|
pDocEventUserMem->lpSenderInfo->dwSizeOfStruct = sizeof(FAX_PERSONAL_PROFILE);
|
|
if ((ec = CopyPersonalProfileInfo( pDocEventUserMem->lpSenderInfo,
|
|
lpFaxSendWizardData->lpSenderInfo)) != ERROR_SUCCESS)
|
|
{
|
|
Error(("CopyRecipientInfo failed (ec: %ld)", ec));
|
|
goto Error;
|
|
}
|
|
|
|
}
|
|
|
|
Assert(pDocEventUserMem->lpRecipientsInfo);
|
|
pDocEventUserMem->jobType = JOBTYPE_NORMAL;
|
|
Assert(ERROR_SUCCESS == ec);
|
|
goto Exit;
|
|
Error:
|
|
Assert(ERROR_SUCCESS != ec);
|
|
FreeRecipientInfo(&pDocEventUserMem->dwNumberOfRecipients,pDocEventUserMem->lpRecipientsInfo);
|
|
pDocEventUserMem->lpRecipientsInfo = NULL;
|
|
FaxFreePersonalProfileInformation(pDocEventUserMem->lpSenderInfo);
|
|
MemFree(pDocEventUserMem->lpSenderInfo);
|
|
pDocEventUserMem->lpSenderInfo = NULL;
|
|
MemFree(pDocEventUserMem->pSubject);
|
|
pDocEventUserMem->pSubject = NULL;
|
|
MemFree(pDocEventUserMem->pNoteMessage);
|
|
pDocEventUserMem->pNoteMessage = NULL;
|
|
MemFree(pDocEventUserMem->pPrintFile);
|
|
pDocEventUserMem->pPrintFile = NULL;
|
|
MemFree(pDocEventUserMem->pReceiptAddress);
|
|
pDocEventUserMem->pReceiptAddress = NULL;
|
|
MemFree(pDocEventUserMem->pPriority);
|
|
pDocEventUserMem->pPriority = NULL;
|
|
MemFree(pDocEventUserMem->pReceiptFlags);
|
|
pDocEventUserMem->pReceiptFlags = NULL;
|
|
|
|
Exit:
|
|
if (lpInitialData)
|
|
{
|
|
//
|
|
// Note: One should NOT call FaxFreeSendWizardData on lpInitialData.
|
|
// The reason is that FaxSendWizard used a different allocator
|
|
// then we do. Thus we just free the individual fields we
|
|
// allocated.
|
|
MemFree(lpInitialData->lptstrPreviewFile);
|
|
}
|
|
FaxFreeSendWizardData(lpFaxSendWizardData);
|
|
MemFree (lpInitialData);
|
|
MemFree (lpFaxSendWizardData);
|
|
return ec;
|
|
}
|
|
|
|
|
|
INT
|
|
DocEventStartDocPre(
|
|
HDC hdc,
|
|
PDOCEVENTUSERMEM pDocEventUserMem,
|
|
LPDOCINFO pDocInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle STARTDOCPRE document event.
|
|
|
|
This events occurs when StartDoc is called. GDI will call this event just before calling kernel mode GDI.
|
|
|
|
If the printing is to a file:
|
|
set the job type to JOBTYPE_DIRECT (pDocEventUserMem->JobType)
|
|
and return successfully with DOCUMENTEVENT_SUCCESS.
|
|
If the printing is not to a file:
|
|
Bring up the send fax wizard.
|
|
The send fax wizard will update the relevant pUserMem members for recipient list, subject, note , etc.
|
|
Indicate that this is a normal job be setting
|
|
pDocEventUserMem->jobType = JOBTYPE_NORMAL;
|
|
|
|
|
|
Arguments:
|
|
|
|
hdc - Specifies the printer device context
|
|
pDocEventUserMem - 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
|
|
//
|
|
|
|
DWORD hWndOwner = 0;
|
|
DWORD dwFlags = 0;
|
|
|
|
pDocEventUserMem->pageCount = 0;
|
|
FreeRecipientInfo(&pDocEventUserMem->dwNumberOfRecipients,pDocEventUserMem->lpRecipientsInfo);
|
|
|
|
//
|
|
// Present the fax wizard here if necessary
|
|
//
|
|
//
|
|
//If DOCINFO has a file name specified and this is indeed a file name
|
|
//(not a directory or something like LPT1:) then we need to print directly to the
|
|
//file and we do not bring up the send wizard.
|
|
//
|
|
|
|
if (pDocInfo && IsPrintingToFile(pDocInfo->lpszOutput))
|
|
{
|
|
|
|
//
|
|
// Printing to file case: don't get involved
|
|
//
|
|
|
|
Warning(("Printing direct: %ws\n", pDocInfo->lpszOutput));
|
|
pDocEventUserMem->jobType = JOBTYPE_DIRECT;
|
|
pDocEventUserMem->directPrinting = TRUE;
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Normal fax print job. Present the send fax wizard.
|
|
// If the user selected cancel, then return -2 to GDI.
|
|
//
|
|
//
|
|
// The wizard will update information in pUserMem.
|
|
// This includes the recipient list , selected cover page, subject text , note text
|
|
// and when to print the fax.
|
|
//
|
|
|
|
//
|
|
// Make sure we don't leave any open files
|
|
//
|
|
if (INVALID_HANDLE_VALUE != pDocEventUserMem->hPreviewFile)
|
|
{
|
|
//
|
|
// We should never get here with an open file handle. But if so, close the handle
|
|
// (TODO: This file will be opened with delete on close).
|
|
//
|
|
Assert(FALSE);
|
|
CloseHandle(pDocEventUserMem->hPreviewFile);
|
|
pDocEventUserMem->hPreviewFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
//
|
|
// Create a temporary TIFF file for preview
|
|
//
|
|
if (FALSE == pDocEventUserMem->bPreviewAborted)
|
|
{
|
|
if (GenerateUniqueFileName(
|
|
NULL, // Create in the system temporary directory
|
|
FAX_TIF_FILE_EXT,
|
|
pDocEventUserMem->szPreviewFile,
|
|
MAX_PATH))
|
|
{
|
|
pDocEventUserMem->hPreviewFile = CreateFile(
|
|
pDocEventUserMem->szPreviewFile,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_TEMPORARY,
|
|
NULL);
|
|
if (INVALID_HANDLE_VALUE != pDocEventUserMem->hPreviewFile)
|
|
{
|
|
//
|
|
// Success. Signal the graphics driver we want print preview
|
|
//
|
|
|
|
// If we enabled the preview option to the user it means everything is OK
|
|
Assert(pDocEventUserMem->pPreviewTiffPage);
|
|
pDocEventUserMem->pPreviewTiffPage->bPreview = TRUE;
|
|
pDocEventUserMem->bShowPrintPreview = TRUE;
|
|
}
|
|
else
|
|
{
|
|
Error(("Failed opening file.Error: %d.\n", GetLastError()));
|
|
if (!DeleteFile(pDocEventUserMem->szPreviewFile))
|
|
{
|
|
Error(("DeleteFile() failed: %d.\n", GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Error(("Failed creating temporary preview file\n"));
|
|
}
|
|
|
|
//
|
|
// If we failed creating the file abort preview operation
|
|
//
|
|
if (INVALID_HANDLE_VALUE == pDocEventUserMem->hPreviewFile)
|
|
{
|
|
//
|
|
// Set file name to empty string so we won't try to delete the file twice when
|
|
// the DC is deleted
|
|
//
|
|
pDocEventUserMem->szPreviewFile[0] = TEXT('\0');
|
|
|
|
//
|
|
// Abort preview (note that the preview is still disabled in the mapping).
|
|
//
|
|
pDocEventUserMem->bPreviewAborted = TRUE;
|
|
}
|
|
}
|
|
|
|
pDocEventUserMem->jobType = JOBTYPE_NORMAL;
|
|
}
|
|
|
|
return DOCUMENTEVENT_SUCCESS;
|
|
}
|
|
|
|
|
|
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 elapsed 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
|
|
|
|
Sets JOB_INFO_2:pParameters to the provided pJobParam string that contains the fax job parameters
|
|
to be convyed to the fax print monitor.
|
|
|
|
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));
|
|
|
|
//
|
|
// Set the pParameters field of JOB_INFO_2 to the tagged string with the job
|
|
// information. This mechanism is used to pass the fax related job information
|
|
// to the fax monitor.
|
|
//
|
|
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 = NULL;
|
|
|
|
//
|
|
// Get the information about the specified job and
|
|
// return a copy of the job name string
|
|
//
|
|
|
|
if (pJobInfo1 = MyGetJob(hPrinter, 1, jobId))
|
|
{
|
|
if ( (pJobInfo1->pDocument) &&
|
|
((pJobName = DuplicateString(pJobInfo1->pDocument)) == NULL) )
|
|
{
|
|
Error(("DuplicateString(%s) failed.", pJobInfo1->pDocument));
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
MemFree(pJobInfo1);
|
|
}
|
|
|
|
return pJobName;
|
|
}
|
|
|
|
|
|
|
|
|
|
//*********************************************************************************
|
|
//* Name: ComposeFaxJobName()
|
|
//* Author: Ronen Barenboim
|
|
//* Date: April 22, 1999
|
|
//*********************************************************************************
|
|
//* DESCRIPTION:
|
|
//* Creates the document name for a print job by composing the document
|
|
//* body name with the recipient name (in case of a single recipient) or
|
|
//* the word "Broadcast" in case of a multiple recipient job.
|
|
//* The job name has the format <Recipient Name> - <Body Name> where
|
|
//* <Recipient Name> is "Broadcast" in the case a multiple recipient
|
|
//* tranmission.
|
|
//*
|
|
//* PARAMETERS:
|
|
//* [IN] PDOCEVENTUSERMEM pDocEventUserMem
|
|
//* A pointer to a USERMEM structure that contains information on the recipients.
|
|
//* Note that USERMEM.nRecipientCount must be valid (calculated) before calling
|
|
//* this function.
|
|
//*
|
|
//* [IN] LPTSTR pBodyDocName
|
|
//* The name of the document.
|
|
//*
|
|
//* RETURN VALUE:
|
|
//* Pointer to a newly allocated string that contains the composed name.
|
|
//* The caller must free the memory occupied by the string by calling
|
|
//* MemFree().
|
|
//* If the function fails the return value is NULL.
|
|
//*********************************************************************************
|
|
LPTSTR
|
|
ComposeFaxJobName(
|
|
PDOCEVENTUSERMEM pDocEventUserMem,
|
|
LPTSTR pBodyDocName
|
|
)
|
|
|
|
#define DOCNAME_FORMAT_STRING TEXT("%s - %s")
|
|
|
|
{
|
|
|
|
LPTSTR pCoverJobName;
|
|
LPTSTR pRecipientName;
|
|
#define MAX_BROADCAST_STRING_LEN 256
|
|
TCHAR szBroadcast[MAX_BROADCAST_STRING_LEN];
|
|
|
|
Assert(pDocEventUserMem);
|
|
|
|
if (pDocEventUserMem->dwNumberOfRecipients > 1) {
|
|
if (!LoadString(g_hResource,
|
|
IDS_BROADCAST_RECIPIENT,
|
|
szBroadcast,
|
|
sizeof(szBroadcast)/sizeof(TCHAR)))
|
|
{
|
|
Error(("Failed to load broadcast recipient string. (ec: %lc)",GetLastError()));
|
|
return NULL;
|
|
}
|
|
else {
|
|
pRecipientName = szBroadcast;
|
|
}
|
|
} else {
|
|
Assert(pDocEventUserMem->lpRecipientsInfo);
|
|
Assert(pDocEventUserMem->lpRecipientsInfo[0].lptstrName);
|
|
pRecipientName = pDocEventUserMem->lpRecipientsInfo[0].lptstrName;
|
|
}
|
|
|
|
|
|
if (pBodyDocName == NULL) {
|
|
//
|
|
// No body. job name is just the recipient name.
|
|
//
|
|
if ((pCoverJobName = DuplicateString(pRecipientName)) == NULL)
|
|
{
|
|
Error(("DuplicateString(%s) failed", pRecipientName));
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
DWORD dwSize;
|
|
|
|
dwSize = SizeOfString(DOCNAME_FORMAT_STRING) +
|
|
SizeOfString(pBodyDocName) +
|
|
SizeOfString(pRecipientName);
|
|
pCoverJobName = MemAlloc(dwSize);
|
|
if (pCoverJobName)
|
|
{
|
|
//
|
|
// Body name specified. 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);
|
|
}
|
|
else
|
|
{
|
|
Error((
|
|
"Failed to allocate %ld bytes for pCoverJobName (ec: %ld)",
|
|
dwSize,
|
|
GetLastError()));
|
|
|
|
}
|
|
|
|
}
|
|
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;
|
|
}
|
|
|
|
|
|
//*********************************************************************************
|
|
//* Name: ComposeFaxJobParameter()
|
|
//* Author: Ronen Barenboim
|
|
//* Date: March 23, 1999
|
|
//*********************************************************************************
|
|
//* DESCRIPTION:
|
|
//* Generates the tagged parameter string that carries the job parameters
|
|
//* (sender information, cover page information ,recipient information)
|
|
//* to the fax monitor on the fax server (using JOB_INFO_2.pParameters).
|
|
//* PARAMETERS:
|
|
//* pDocEventUserMem
|
|
//* A pointer to a USERMEM structure from which some of the information
|
|
//* is collected.
|
|
//* pCPFields
|
|
//* A pointer to a COVERPAGEFIELS structure from which sender and cover
|
|
//* page information is collected.
|
|
//* lppParamBuf
|
|
//* The address of a pointer varialbe that will accept the address of the
|
|
//* buffer this function will allocated for the resulting tagged string.
|
|
//* The caller of this function must free this buffer using MemFree().
|
|
//* RETURN VALUE:
|
|
//* TRUE
|
|
//* If successful.
|
|
//* FALSE
|
|
//* If failed.
|
|
//*********************************************************************************
|
|
BOOL
|
|
ComposeFaxJobParameter(
|
|
PDOCEVENTUSERMEM pDocEventUserMem,
|
|
PCOVERPAGEFIELDS pCPFields,
|
|
LPTSTR * lppParamBuf
|
|
)
|
|
{
|
|
DWORD dwBufSize;
|
|
DWORD dwPartialBufSize;
|
|
DWORD dwLeftBufferSize;
|
|
LPTSTR lptstrBuf;
|
|
UINT i;
|
|
|
|
Assert(pDocEventUserMem);
|
|
Assert(pCPFields);
|
|
Assert(lppParamBuf);
|
|
|
|
//
|
|
// Calculate the parameter buffer we need to allocated
|
|
//
|
|
dwBufSize=0;
|
|
|
|
//
|
|
// Calcualte non recipient params string size
|
|
//
|
|
ComposeSenderJobParam(NULL, &dwPartialBufSize, pDocEventUserMem, pCPFields); // void return value
|
|
dwBufSize=dwBufSize+dwPartialBufSize;
|
|
|
|
//
|
|
// Go over each recipient and calculate the total required buffer size
|
|
//
|
|
for (i=0;i<pDocEventUserMem->dwNumberOfRecipients;i++)
|
|
{
|
|
//
|
|
// Get recipient's name and fax number
|
|
//
|
|
Assert(pDocEventUserMem->lpRecipientsInfo[i].lptstrName);
|
|
pCPFields->RecName = pDocEventUserMem->lpRecipientsInfo[i].lptstrName;
|
|
Assert(pDocEventUserMem->lpRecipientsInfo[i].lptstrFaxNumber);
|
|
pCPFields->RecFaxNumber = pDocEventUserMem->lpRecipientsInfo[i].lptstrFaxNumber;
|
|
ComposeRecipientJobParam(NULL, &dwPartialBufSize, pCPFields);
|
|
dwBufSize=dwBufSize+dwPartialBufSize; //keep space for the seperating NULL
|
|
}
|
|
//
|
|
// Don't forget the space for the terminating NULL (the ComposeX functions do not include
|
|
// it in the size they report).
|
|
//
|
|
dwBufSize=dwBufSize+sizeof(TCHAR); // dwBufSize is size in BYTES so we must calc the byte size of a TCHAR
|
|
//
|
|
// Allocate the required buffer
|
|
//
|
|
lptstrBuf=MemAlloc(dwBufSize);
|
|
if (!lptstrBuf) {
|
|
Error(("Failed to allocate buffer of size %ld for parameter buffer (ec: 0x%0X)",dwBufSize,GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Write the parameters into the buffer
|
|
//
|
|
dwLeftBufferSize = dwBufSize;
|
|
dwPartialBufSize = dwBufSize;
|
|
*lppParamBuf=lptstrBuf;
|
|
ComposeSenderJobParam(lptstrBuf, &dwPartialBufSize, pDocEventUserMem, pCPFields);
|
|
lptstrBuf+=(dwPartialBufSize/sizeof(TCHAR)); // The reported size is in bytes !!!
|
|
Assert (dwLeftBufferSize >= dwPartialBufSize);
|
|
dwLeftBufferSize -= dwPartialBufSize;
|
|
for (i=0;i<pDocEventUserMem->dwNumberOfRecipients;i++)
|
|
{
|
|
//
|
|
// Get recipient's name and fax number
|
|
//
|
|
pCPFields->RecName = pDocEventUserMem->lpRecipientsInfo[i].lptstrName;
|
|
pCPFields->RecFaxNumber = pDocEventUserMem->lpRecipientsInfo[i].lptstrFaxNumber;
|
|
dwPartialBufSize = dwLeftBufferSize;
|
|
ComposeRecipientJobParam(lptstrBuf, &dwPartialBufSize, pCPFields);
|
|
lptstrBuf+=(dwPartialBufSize/sizeof(TCHAR)); // The reported size is in bytes !!!
|
|
Assert (dwLeftBufferSize >= dwPartialBufSize);
|
|
dwLeftBufferSize -= dwPartialBufSize;
|
|
}
|
|
//
|
|
// No need to add a terminating NULL since ParamTagsToString allways appends a NULL terminated string
|
|
// to the existing string (it uses _tcscpy).
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
//*********************************************************************************
|
|
//* Name: ComposeRecipientJobParam()
|
|
//* Author: Ronen Barenboim
|
|
//* Date: March 23, 1999
|
|
//*********************************************************************************
|
|
//* DESCRIPTION:
|
|
//* Creates a taged parameter string containing recipient information.
|
|
//*
|
|
//* PARAMETERS:
|
|
//* lpParamBuf
|
|
//* Pointer to the string buffer where the tagged string is written.
|
|
//* lpdwParamSize
|
|
//* Pointer to a DWORD where the function reports the size of the parameter
|
|
//* string in BYTES.
|
|
//* If this parameter is NULL then the function does not generate
|
|
//* the string but only reports its size.
|
|
//* The size does NOT include the terminating NULL char.
|
|
//* pCPFields
|
|
//* Pointer to a COVERPAGEFIELDS structure from which the recipient
|
|
//* information is collected.
|
|
//* RETURN VALUE:
|
|
//* None.
|
|
//*********************************************************************************
|
|
void
|
|
ComposeRecipientJobParam(
|
|
LPTSTR lpParamBuf,
|
|
LPDWORD lpdwParamSize,
|
|
const COVERPAGEFIELDS * pCPFields
|
|
)
|
|
|
|
{
|
|
|
|
|
|
FAX_TAG_MAP_ENTRY tagMap[] =
|
|
{
|
|
|
|
//
|
|
// Recipient info
|
|
//
|
|
{ FAXTAG_NEW_RECORD, FAXTAG_NEW_RECORD_VALUE}, // Parameters record start indication
|
|
{ FAXTAG_RECIPIENT_NAME, pCPFields->RecName },
|
|
{ FAXTAG_RECIPIENT_NUMBER, pCPFields->RecFaxNumber },
|
|
{ FAXTAG_RECIPIENT_COMPANY, pCPFields->RecCompany },
|
|
{ FAXTAG_RECIPIENT_STREET, pCPFields->RecStreetAddress },
|
|
{ FAXTAG_RECIPIENT_CITY, pCPFields->RecCity },
|
|
{ FAXTAG_RECIPIENT_STATE, pCPFields->RecState },
|
|
{ FAXTAG_RECIPIENT_ZIP, pCPFields->RecZip },
|
|
{ FAXTAG_RECIPIENT_COUNTRY, pCPFields->RecCountry },
|
|
{ FAXTAG_RECIPIENT_TITLE, pCPFields->RecTitle },
|
|
{ FAXTAG_RECIPIENT_DEPT, pCPFields->RecDepartment },
|
|
{ FAXTAG_RECIPIENT_OFFICE_LOCATION, pCPFields->RecOfficeLocation },
|
|
{ FAXTAG_RECIPIENT_HOME_PHONE, pCPFields->RecHomePhone },
|
|
{ FAXTAG_RECIPIENT_OFFICE_PHONE, pCPFields->RecOfficePhone },
|
|
|
|
};
|
|
|
|
|
|
DWORD dwTagCount;
|
|
|
|
Assert(pCPFields);
|
|
Assert(lpdwParamSize);
|
|
|
|
dwTagCount=sizeof(tagMap)/sizeof(FAX_TAG_MAP_ENTRY);
|
|
|
|
ParamTagsToString(tagMap, dwTagCount, lpParamBuf, lpdwParamSize );
|
|
}
|
|
|
|
|
|
|
|
|
|
//*********************************************************************************
|
|
//* Name: ComposeSenderJobParam()
|
|
//* Author: Ronen Barenboim
|
|
//* Date: March 23, 1999
|
|
//*********************************************************************************
|
|
//* DESCRIPTION:
|
|
//* Creates a taged parameter string containing cover page information, sender
|
|
//* information and the number of recipients in the tranmission.
|
|
//*
|
|
//* PARAMETERS:
|
|
//* lpParamBuf
|
|
//* Pointer to the string buffer where the tagged string is written.
|
|
//* lpdwParamSize
|
|
//* Pointer to a DWORD where the function reports the size of the parameter
|
|
//* string in BYTES.
|
|
//* If this parameter is NULL then the function does not generate
|
|
//* the string but only reports its size.
|
|
//* The size does NOT include the terminating NULL char.
|
|
//* pDocEventUserMem
|
|
//* Pointer to a USERMEM structure from which some of information
|
|
//* is collected.
|
|
//* pCPFields
|
|
//* Pointer to a COVERPAGEFIELDS structure from which the cover page
|
|
//* and sender information is collected.
|
|
//*
|
|
//* RETURN VALUE:
|
|
//* None.
|
|
//*********************************************************************************
|
|
void
|
|
ComposeSenderJobParam(
|
|
LPTSTR lpParamBuf,
|
|
LPDWORD lpdwParamSize,
|
|
PDOCEVENTUSERMEM pDocEventUserMem,
|
|
const COVERPAGEFIELDS * pCPFields)
|
|
{
|
|
|
|
#define FAXTAG_SERVER_COVERPAGE_IDX 9
|
|
#define FAXTAG_TSID_IDX 3
|
|
|
|
TCHAR lptstrRecipientCount[11];
|
|
|
|
|
|
FAX_TAG_MAP_ENTRY tagMap[] =
|
|
{
|
|
{ FAXTAG_NEW_RECORD, FAXTAG_NEW_RECORD_VALUE},
|
|
{ FAXTAG_WHEN_TO_SEND, NULL },
|
|
{ FAXTAG_SEND_AT_TIME, NULL },
|
|
{ FAXTAG_TSID, pCPFields->SdrFaxNumber },
|
|
{ FAXTAG_BILLING_CODE, pDocEventUserMem->devmode.dmPrivate.billingCode },
|
|
{ FAXTAG_RECEIPT_TYPE, pDocEventUserMem->pReceiptFlags },
|
|
{ FAXTAG_RECEIPT_ADDR, pDocEventUserMem->pReceiptAddress },
|
|
{ FAXTAG_PRIORITY, pDocEventUserMem->pPriority },
|
|
{ FAXTAG_COVERPAGE_NAME, pDocEventUserMem->coverPage },
|
|
{ FAXTAG_SERVER_COVERPAGE, NULL },
|
|
{ FAXTAG_PAGE_COUNT, pCPFields->NumberOfPages},
|
|
{ FAXTAG_SENDER_NAME, pCPFields->SdrName },
|
|
{ FAXTAG_SENDER_NUMBER, pCPFields->SdrFaxNumber},
|
|
{ FAXTAG_SENDER_COMPANY, pCPFields->SdrCompany },
|
|
{ FAXTAG_SENDER_TITLE, pCPFields->SdrTitle },
|
|
{ FAXTAG_SENDER_DEPT, pCPFields->SdrDepartment },
|
|
{ FAXTAG_SENDER_OFFICE_LOCATION , pCPFields->SdrOfficeLocation },
|
|
{ FAXTAG_SENDER_HOME_PHONE, pCPFields->SdrHomePhone },
|
|
{ FAXTAG_SENDER_OFFICE_PHONE, pCPFields->SdrOfficePhone },
|
|
{ FAXTAG_SENDER_STREET, pDocEventUserMem->lpSenderInfo->lptstrStreetAddress },
|
|
{ FAXTAG_SENDER_CITY, pDocEventUserMem->lpSenderInfo->lptstrCity },
|
|
{ FAXTAG_SENDER_STATE, pDocEventUserMem->lpSenderInfo->lptstrState },
|
|
{ FAXTAG_SENDER_ZIP, pDocEventUserMem->lpSenderInfo->lptstrZip },
|
|
{ FAXTAG_SENDER_COUNTRY, pDocEventUserMem->lpSenderInfo->lptstrCountry },
|
|
{ FAXTAG_SENDER_EMAIL, pDocEventUserMem->lpSenderInfo->lptstrEmail },
|
|
{ FAXTAG_NOTE, pDocEventUserMem->pNoteMessage },
|
|
{ FAXTAG_SUBJECT, pDocEventUserMem->pSubject},
|
|
{ FAXTAG_RECIPIENT_COUNT, lptstrRecipientCount}
|
|
};
|
|
|
|
|
|
|
|
TCHAR SendAtTime[16];
|
|
DWORD dwTagCount;
|
|
|
|
|
|
if (pDocEventUserMem->bServerCoverPage)
|
|
{
|
|
tagMap[FAXTAG_SERVER_COVERPAGE_IDX].lptstrValue=TEXT("1");
|
|
} else
|
|
{
|
|
tagMap[FAXTAG_SERVER_COVERPAGE_IDX].lptstrValue=NULL;
|
|
}
|
|
|
|
//
|
|
// create the sendattime string
|
|
//
|
|
|
|
if (pDocEventUserMem->devmode.dmPrivate.whenToSend == JSA_DISCOUNT_PERIOD) {
|
|
tagMap[1].lptstrValue=TEXT("cheap");
|
|
}
|
|
|
|
if (pDocEventUserMem->devmode.dmPrivate.whenToSend == JSA_SPECIFIC_TIME) {
|
|
|
|
wsprintf( SendAtTime, TEXT("%02d:%02d"),
|
|
pDocEventUserMem->devmode.dmPrivate.sendAtTime.Hour,
|
|
pDocEventUserMem->devmode.dmPrivate.sendAtTime.Minute
|
|
);
|
|
|
|
tagMap[1].lptstrValue= TEXT("at");
|
|
tagMap[2].lptstrValue= SendAtTime;
|
|
}
|
|
|
|
wsprintf( lptstrRecipientCount, TEXT("%10d"),pDocEventUserMem->dwNumberOfRecipients);
|
|
//
|
|
// Figure out the total length of the tagged string
|
|
//
|
|
dwTagCount=sizeof(tagMap)/sizeof(FAX_TAG_MAP_ENTRY);
|
|
|
|
ParamTagsToString(tagMap, dwTagCount, lpParamBuf, lpdwParamSize );
|
|
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//* Name: WriteCoverPageToPrintJob
|
|
//* Author: Ronen Barenboim (Feb-99)
|
|
//*****************************************************************************
|
|
//* DESCRIPTION:
|
|
//* Reads the content of the specified cover page template and writes it
|
|
//* to the specified printer.
|
|
//* The user should call StartDocPrinter() and StartPagePrinter()
|
|
//* before calling this function.
|
|
//* PARAMETERS:
|
|
//* [IN] HANDLE hPrinter:
|
|
//* A handle to the printer to which the cover page template
|
|
//* should be written.
|
|
//* [IN] LPCTSTR lpctstrCoverPageFile:
|
|
//* The full path to the cover page file whose content is to be
|
|
//* written to the printer.
|
|
//* RETURN VALUE:
|
|
//* FALSE: If the function failed.
|
|
//* TRUE: Otherwise.
|
|
//*****************************************************************************
|
|
BOOL WriteCoverPageToPrintJob(HANDLE hPrinter, LPCTSTR lpctstrCoverPageFile)
|
|
{
|
|
#define BUF_SIZE 64*1024 // Buffer size for read operation
|
|
PCHAR chBuf=NULL; // Read operation buffer
|
|
BOOL bRes; // The result of the function
|
|
HANDLE hCoverFile; // Handle to the cover page file
|
|
DWORD dwBytesRead; // The number of bytes actually read at each cycle
|
|
|
|
Assert(hPrinter);
|
|
Assert(lpctstrCoverPageFile);
|
|
|
|
bRes=FALSE;
|
|
hCoverFile=INVALID_HANDLE_VALUE;
|
|
|
|
//
|
|
// Open the cover page template file for reading
|
|
//
|
|
hCoverFile=CreateFile(
|
|
lpctstrCoverPageFile,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
0);
|
|
if (INVALID_HANDLE_VALUE == hCoverFile )
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
chBuf = MemAlloc(BUF_SIZE);
|
|
if (NULL == chBuf)
|
|
{
|
|
Error(("Failed to allocate read operation buffer"));
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
//Read the file and write it into the print job
|
|
//
|
|
do {
|
|
bRes=ReadFile(hCoverFile,chBuf,sizeof(CHAR)*BUF_SIZE,&dwBytesRead,NULL) ;
|
|
if (!bRes) {
|
|
Error(("Failed to read cover page file into print job (cover page file: %s ec: %d\n)",
|
|
lpctstrCoverPageFile,
|
|
GetLastError())
|
|
);
|
|
break;
|
|
|
|
} else {
|
|
Verbose(("Success reading cover page file %s. %d bytes read.\n",lpctstrCoverPageFile,dwBytesRead));
|
|
}
|
|
|
|
if (dwBytesRead) {
|
|
//
|
|
// If dwBytesRead != 0 we are NOT at the enf of the file.
|
|
//
|
|
DWORD dwWritten;
|
|
|
|
bRes=WritePrinter(hPrinter,(LPVOID)chBuf,dwBytesRead,&dwWritten);
|
|
if (!bRes) {
|
|
Error(("Failed to write to printer (ec = %d)", GetLastError()));
|
|
} else
|
|
{
|
|
Verbose(("Success writing to printer. %d bytes written.\n",dwWritten));
|
|
}
|
|
}
|
|
} while (dwBytesRead); // While not EOF
|
|
|
|
Exit:
|
|
//
|
|
//Close the cover page file
|
|
//
|
|
if (INVALID_HANDLE_VALUE!=hCoverFile)
|
|
{
|
|
if (!CloseHandle(hCoverFile))
|
|
{
|
|
Error(("CloseHandle() failed: %d.\n", GetLastError()));
|
|
}
|
|
}
|
|
|
|
if (NULL != chBuf)
|
|
{
|
|
MemFree(chBuf);
|
|
}
|
|
return bRes;
|
|
}
|
|
|
|
|
|
|
|
//*****************************************************************************
|
|
//* Name: DoCoverPageRendering
|
|
//* Author: Ronen Barenboim (Feb-99)
|
|
//*****************************************************************************
|
|
//* DESCRIPTION:
|
|
//* Creates the cover page print job and attaches it to the body print job.
|
|
//* The cover page job is created even when a cover page is NOT specified.
|
|
//* It contains all the job parameters for the job as a tagged string
|
|
//* placed in JOB_INFO_2.pParameters. This contains the information for the
|
|
//* sender, cover page, job parameters and ALL recipients.
|
|
//*
|
|
//* The content of the job is empty if no cover page is specified or
|
|
//* The cover page is server based.
|
|
//* For personal cover pages the content of the cover page template is written
|
|
//* into the job as "RAW" data. The print monitor on the server will extract this
|
|
//* data to reconstruct the cover page file on the server.
|
|
//*
|
|
//* PARAMETERS:
|
|
//* [IN] PDOCEVENTUSERMEM pDocEventUserMem:
|
|
//* A pointer to a USERMEM structure containing the context information
|
|
//* for the print job.
|
|
//* RETURN VALUE:
|
|
//* FALSE: If the function failed.
|
|
//* TRUE: Otherwise.
|
|
//*****************************************************************************
|
|
BOOL
|
|
DoCoverPageRendering(
|
|
PDOCEVENTUSERMEM pDocEventUserMem
|
|
)
|
|
{
|
|
PCOVERPAGEFIELDS pCPFields=NULL;
|
|
DOC_INFO_1 docinfo;
|
|
INT newJobId=0;
|
|
INT lastJobId=0;
|
|
INT cCoverPagesSent=0;
|
|
PDMPRIVATE pdmPrivate = &pDocEventUserMem->devmode.dmPrivate;
|
|
HANDLE hPrinter = pDocEventUserMem->hPrinter;
|
|
DWORD bodyJobId = pDocEventUserMem->jobId;
|
|
LPTSTR pBodyDocName=NULL;
|
|
LPTSTR pJobParam=NULL;
|
|
BOOL sendCoverPage;
|
|
DWORD pageCount;
|
|
|
|
|
|
//
|
|
// Fill out a DOCINFO structure which is passed to StartDoc
|
|
//
|
|
|
|
memset(&docinfo, 0, sizeof(docinfo));
|
|
//docinfo.cbSize = sizeof(docinfo);
|
|
|
|
|
|
//
|
|
// Determine if we need a cover page or not
|
|
//
|
|
|
|
if ( (sendCoverPage = pdmPrivate->sendCoverPage) && IsEmptyString(pDocEventUserMem->coverPage)) {
|
|
|
|
Warning(("Missing cover page file\n"));
|
|
sendCoverPage = FALSE;
|
|
}
|
|
|
|
pageCount = pDocEventUserMem->pageCount;
|
|
|
|
//
|
|
// Collect cover page information into a newly allocated pCPFields. pCPFields will be
|
|
// passed to ComposeFaxJobParameters() to provide the values for the job tags.
|
|
//
|
|
|
|
if ((pCPFields = CollectCoverPageFields(pDocEventUserMem->lpSenderInfo,pageCount)) == NULL) {
|
|
|
|
Error(("Couldn't collect cover page information\n"));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
|
|
pBodyDocName = GetJobName(hPrinter, bodyJobId);
|
|
if (!pBodyDocName) {
|
|
Error(("GetJobName failed (ec: %ld)", GetLastError()));
|
|
Assert(FALSE);
|
|
//
|
|
// We continue inspite of the error. We can handle a NULL body doc name.
|
|
//
|
|
}
|
|
|
|
//
|
|
// We assume the fax body job has already been paused
|
|
// Use a separate cover page for each recipient
|
|
//
|
|
|
|
newJobId = 0;
|
|
docinfo.pDocName = NULL;
|
|
pJobParam = NULL;
|
|
//
|
|
// Start a cover page job
|
|
//
|
|
|
|
//
|
|
// The cover page job document name is "<BODY_NAME> - COVERPAGE"
|
|
//
|
|
|
|
docinfo.pOutputFile=NULL;
|
|
docinfo.pDatatype=TEXT("RAW"); // Since we write the template into the job we want to bypass the driver.
|
|
|
|
//
|
|
// Create the tagged string of job parameters to be placed into JOB_INFO_2:pParameters.
|
|
// The parameters include the parameters found at the FAX_JOB_PARAM client API structure.
|
|
// pJobParam is ALLOCATED.
|
|
//
|
|
if (!ComposeFaxJobParameter(pDocEventUserMem, pCPFields,&pJobParam)) {
|
|
Error(("ComposeFaxJobParameter failed. (ec: 0x%X)",GetLastError()));
|
|
goto Error;
|
|
}
|
|
Assert(pJobParam); // Should be allocated now.
|
|
|
|
docinfo.pDocName = ComposeFaxJobName(pDocEventUserMem,pBodyDocName);//pBodyDocName, TEXT("COVERPAGE"));
|
|
|
|
if (!docinfo.pDocName) {
|
|
Error(("ComposeFaxJobName failed. Body: %s (ec: %ld)",pBodyDocName,GetLastError()));
|
|
//
|
|
// we can do with no document name.
|
|
//
|
|
}
|
|
|
|
|
|
if ((newJobId = StartDocPrinter(hPrinter,1, (LPBYTE)&docinfo)) !=0) {
|
|
BOOL rendered = FALSE;
|
|
//
|
|
// Pass fax job parameters using JOB_INFO_2.pParameters field.
|
|
//
|
|
|
|
//
|
|
// Pause the new cover page job.
|
|
//
|
|
|
|
if (!SetJob(hPrinter, newJobId, 0, NULL, JOB_CONTROL_PAUSE)) {
|
|
Error(("Failed to pause job id: %d (ec: %ld)",newJobId,GetLastError()));
|
|
Assert(FALSE);
|
|
goto Error;
|
|
}
|
|
|
|
if (!SetJobInfoAndTime(hPrinter,
|
|
newJobId,
|
|
pJobParam,
|
|
pdmPrivate)) {
|
|
Error(("SetJobInfoAndTime failed. Job id : %d.",newJobId));
|
|
Assert(FALSE);
|
|
goto Error;
|
|
}
|
|
|
|
if (! sendCoverPage || pDocEventUserMem->bServerCoverPage) {
|
|
//
|
|
// If the user chose not to include cover page or a server side cover page was specified
|
|
// the cover page job will be empty
|
|
// Note that even if there is no cover page to send we still create a cover page print job
|
|
// and link it to the body.
|
|
// The cover print job is used to convery sender/recipient information. The fax print monitor will
|
|
// use the job parameters string placed in JOB_INFO_2:pParameters to get this information at the server.
|
|
//
|
|
rendered = TRUE;
|
|
|
|
} else {
|
|
if (StartPagePrinter(hPrinter)) {
|
|
//
|
|
// Write the content of the cover page template into the print job.
|
|
// The print monitor on the server will extract this information to get
|
|
// the cover page template and render the cover page on the server.
|
|
//
|
|
rendered=WriteCoverPageToPrintJob(hPrinter,pDocEventUserMem->coverPage);
|
|
|
|
if (!rendered) {
|
|
Error(("WriteCoverPageToPrintJob failed: %d\n", rendered ));
|
|
//
|
|
// Must call EndPagePrinter if error was encounterd or not.
|
|
//
|
|
}
|
|
|
|
if (!EndPagePrinter(hPrinter)) {
|
|
Error(("EndPagePrinter failed. (ec: %ld)",GetLastError()));
|
|
goto Error;
|
|
}
|
|
|
|
if (!rendered) {
|
|
goto Error;
|
|
}
|
|
|
|
|
|
} else {
|
|
Error(("StartPagePrinter failed. (ec: %ld)",GetLastError()));
|
|
rendered=FALSE;
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Chain the cover page job to the fax body job if no error occured.
|
|
//
|
|
// Chain the cover page job to the BODY job.
|
|
// The cover page job is the parent job. The body is the child job.
|
|
// Note that multiple cover page
|
|
// Jobs will be chained to the same BODY job.
|
|
// also note the cover page jobs are not chained to each other. Just to the body.
|
|
//
|
|
|
|
if (rendered) {
|
|
if (ChainFaxJobs(hPrinter, newJobId, bodyJobId)) {
|
|
if (lastJobId != 0) {
|
|
if (!SetJob(hPrinter, lastJobId, 0, NULL, JOB_CONTROL_RESUME)) {
|
|
Error(("Failed to resume job with id: %d",lastJobId));
|
|
Assert(FALSE);
|
|
goto Error;
|
|
}
|
|
}
|
|
lastJobId = newJobId;
|
|
if (!EndDocPrinter(hPrinter)) {
|
|
Error(("EndPagePrinter failed. (ec: %ld)",GetLastError()));
|
|
Assert(FALSE);
|
|
goto Error;
|
|
}
|
|
cCoverPagesSent++;
|
|
} else {
|
|
Error(("ChainFaxJobs for CoverJobId=%d BodyJobId=%d has failed. Aborting job.",newJobId, bodyJobId));
|
|
goto Error;
|
|
}
|
|
|
|
} else {
|
|
Error(("Cover page template not written into job (rendered=FALSE). Aborting job."));
|
|
goto Error;
|
|
}
|
|
} else {
|
|
Error(("StartDocPrinter failed. (ec: %ld)",GetLastError()));
|
|
goto Error;
|
|
}
|
|
goto Exit;
|
|
|
|
|
|
Error:
|
|
Error(("Cover page job failed"));
|
|
if (0!=newJobId) {
|
|
//
|
|
// This means that an error was detected after we created the job.
|
|
// Note that if StartDocPrinter failed this code is not executed.
|
|
//
|
|
Error(("Aborting cover page job. JobId = %d",newJobId));
|
|
if (!AbortPrinter(hPrinter)) {
|
|
Error(("AbortPrinter failed (ec: %ld)",GetLastError()));
|
|
}
|
|
}
|
|
|
|
|
|
Exit:
|
|
|
|
if (docinfo.pDocName) {
|
|
MemFree((PVOID)docinfo.pDocName);
|
|
}
|
|
|
|
if (pJobParam) {
|
|
MemFree((PVOID)pJobParam);
|
|
}
|
|
|
|
if (pBodyDocName) {
|
|
MemFree(pBodyDocName);
|
|
}
|
|
if (pCPFields) {
|
|
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) {
|
|
|
|
if (!SetJob(hPrinter, lastJobId, 0, NULL, JOB_CONTROL_RESUME)) {
|
|
Error(("Failed to resume last job id : %d",lastJobId));
|
|
Assert(FALSE);
|
|
}
|
|
|
|
}
|
|
|
|
if (cCoverPagesSent > 0) {
|
|
if (!SetJob(hPrinter, bodyJobId, 0, NULL, JOB_CONTROL_RESUME)) {
|
|
Error(("Failed to resume body job with id: %d",bodyJobId));
|
|
Assert(FALSE);
|
|
}
|
|
|
|
} else {
|
|
Error(("No recipient jobs created. Fax job deleted due to an error.\n"));
|
|
if (!SetJob(hPrinter, bodyJobId, 0, NULL, JOB_CONTROL_DELETE)) {
|
|
Error(("Failed to delete body job with id: %d",bodyJobId));
|
|
Assert(FALSE);
|
|
}
|
|
|
|
}
|
|
|
|
return cCoverPagesSent > 0;
|
|
}
|
|
INT
|
|
DocEventEndDocPost(
|
|
HDC hdc,
|
|
PDOCEVENTUSERMEM pDocEventUserMem
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle ENDDOCPOST document event
|
|
|
|
Arguments:
|
|
|
|
hdc - Specifies the printer device context
|
|
pDocEventUserMem - Points to the user mode memory structure
|
|
|
|
Return Value:
|
|
|
|
Return value for DrvDocumentEvent
|
|
|
|
--*/
|
|
|
|
{
|
|
INT result = DOCUMENTEVENT_SUCCESS;
|
|
|
|
switch (pDocEventUserMem->jobType)
|
|
{
|
|
case JOBTYPE_NORMAL:
|
|
|
|
Warning(("Number of pages printed: %d\n", pDocEventUserMem->pageCount));
|
|
|
|
if (! pDocEventUserMem->directPrinting)
|
|
{
|
|
LRESULT ec;
|
|
BOOL bAllowed = FALSE;
|
|
|
|
//
|
|
// check if there is already running instance of Fax Wizard
|
|
//
|
|
|
|
if(!g_bInitRunningWizardCS)
|
|
{
|
|
Assert(FALSE);
|
|
result = DOCUMENTEVENT_FAILURE;
|
|
break;
|
|
}
|
|
|
|
EnterCriticalSection(&g_csRunningWizard);
|
|
if (!g_bRunningWizard)
|
|
{
|
|
//
|
|
// no running instance of Fax Wizard
|
|
//
|
|
g_bRunningWizard = TRUE;
|
|
bAllowed = TRUE;
|
|
}
|
|
LeaveCriticalSection(&g_csRunningWizard);
|
|
|
|
if (!bAllowed)
|
|
{
|
|
//
|
|
// there is running instance of Fax Wizard
|
|
// show popup to user and stop processing
|
|
//
|
|
ShowReentrancyMessage();
|
|
result = DOCUMENTEVENT_FAILURE;
|
|
break;
|
|
}
|
|
|
|
ec = LaunchFaxWizard(pDocEventUserMem);
|
|
|
|
//
|
|
// Let other threads to launch Fax Wizard
|
|
//
|
|
EnterCriticalSection(&g_csRunningWizard);
|
|
g_bRunningWizard = FALSE;
|
|
LeaveCriticalSection(&g_csRunningWizard);
|
|
|
|
if (ERROR_SUCCESS == ec)
|
|
{
|
|
//
|
|
// Generate a cover page for each recipient and associate
|
|
// the cover page job with the main body.
|
|
// The job will contain the cover page template data and the
|
|
// recipient parameters.
|
|
if (! DoCoverPageRendering(pDocEventUserMem))
|
|
{
|
|
Error(("DoCoverPageRendering failed."));
|
|
result = DOCUMENTEVENT_FAILURE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = DOCUMENTEVENT_FAILURE;
|
|
}
|
|
|
|
//
|
|
// Free up the list of recipients
|
|
//
|
|
FreeRecipientInfo(&pDocEventUserMem->dwNumberOfRecipients, pDocEventUserMem->lpRecipientsInfo);
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (DOCUMENTEVENT_SUCCESS != result)
|
|
{
|
|
//
|
|
// Cancel the job ignoring errors
|
|
//
|
|
if (!SetJob(
|
|
pDocEventUserMem->hPrinter,
|
|
pDocEventUserMem->jobId,
|
|
0,
|
|
NULL,
|
|
JOB_CONTROL_DELETE))
|
|
{
|
|
Error(("Failed to cancel job. JobId: %ld (ec: %ld)",
|
|
pDocEventUserMem->jobId,
|
|
GetLastError()));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
AppendPreviewPage(PDOCEVENTUSERMEM pDocEventUserMem)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Append the next document page to the temporary preview file
|
|
|
|
Arguments:
|
|
|
|
pDocEventUserMem
|
|
|
|
Return Value:
|
|
|
|
TRUE on success
|
|
|
|
Note:
|
|
|
|
If this routine is called for page 0, it just checks that the graphics driver hasn't
|
|
cancled the print preview option and validates the mapping structures.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwWritten;
|
|
|
|
// If we get here print preview should be enabled an all preview handles valid
|
|
Assert(FALSE == pDocEventUserMem->bPreviewAborted);
|
|
Assert(INVALID_HANDLE_VALUE != pDocEventUserMem->hPreviewFile);
|
|
Assert(NULL != pDocEventUserMem->pPreviewTiffPage);
|
|
|
|
//
|
|
// Validate preview mapping
|
|
//
|
|
|
|
// The size of the header should be correct
|
|
if (sizeof(MAP_TIFF_PAGE_HEADER) != pDocEventUserMem->pPreviewTiffPage->cb)
|
|
{
|
|
Error(("Preview mapping corrupted\n"));
|
|
pDocEventUserMem->bPreviewAborted = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
// Check if the preview operation hasn't beed cancled by the graphics driver
|
|
if (FALSE == pDocEventUserMem->pPreviewTiffPage->bPreview)
|
|
{
|
|
Error(("Preview aborted by graphics driver\n"));
|
|
pDocEventUserMem->bPreviewAborted = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// If we are called prior to the first sent page just return
|
|
//
|
|
if (!pDocEventUserMem->pageCount)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Validate correct page number:
|
|
//
|
|
// The graphics driver increments the page count on the call to DrvStartPage(), while we
|
|
// increment the page count on the ENDPAGE event.
|
|
//
|
|
// As this function is called by the STARTPAGE event handler (before 'DrvStartPage' is called
|
|
// again in the graphics driver) or by the ENDDOCPOST event handler, the page number set by
|
|
// the graphics driver in the mapping should be equal to our page count in this stage.
|
|
//
|
|
if (pDocEventUserMem->pageCount != pDocEventUserMem->pPreviewTiffPage->iPageCount)
|
|
{
|
|
Error(("Wrong preview page: %d. Page expected: %d.\n",
|
|
pDocEventUserMem->pPreviewTiffPage->iPageCount,
|
|
pDocEventUserMem->pageCount));
|
|
pDocEventUserMem->bPreviewAborted = TRUE;
|
|
pDocEventUserMem->pPreviewTiffPage->bPreview = FALSE;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Append new page to temporary preview file
|
|
//
|
|
|
|
if (0 == pDocEventUserMem->pPreviewTiffPage->dwDataSize)
|
|
{
|
|
//
|
|
// Nothing to add (?!). It is impossible to get an empty TIFF page
|
|
//
|
|
Error(("Recieved empty preview page: %d.\n", pDocEventUserMem->pageCount));
|
|
Assert(FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
if (!WriteFile(
|
|
pDocEventUserMem->hPreviewFile,
|
|
pDocEventUserMem->pPreviewTiffPage + 1,
|
|
pDocEventUserMem->pPreviewTiffPage->dwDataSize,
|
|
&dwWritten,
|
|
NULL) || dwWritten != pDocEventUserMem->pPreviewTiffPage->dwDataSize)
|
|
{
|
|
Error(("Failed appending preview page: %d. Error: %d\n",
|
|
pDocEventUserMem->pageCount,
|
|
GetLastError()));
|
|
pDocEventUserMem->bPreviewAborted = TRUE;
|
|
pDocEventUserMem->pPreviewTiffPage->bPreview = FALSE;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDOCEVENTUSERMEM pDocEventUserMem = NULL;
|
|
PDEVMODE pDevmode;
|
|
INT result = DOCUMENTEVENT_SUCCESS;
|
|
HANDLE hMutex;
|
|
|
|
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
|
|
//
|
|
|
|
//
|
|
// Do not execute any code before this initialization
|
|
//
|
|
if(!InitializeDll())
|
|
{
|
|
return DOCUMENTEVENT_FAILURE;
|
|
}
|
|
|
|
|
|
if (DocEventRequiresDC(iEsc))
|
|
{
|
|
if (!hdc || !(pDocEventUserMem = 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));
|
|
|
|
pDocEventUserMem = ((PDRVDEVMODE) pDevmode)->dmPrivate.pUserMem;
|
|
|
|
Assert(ValidPDEVUserMem(pDocEventUserMem));
|
|
|
|
if (hdc)
|
|
{
|
|
pDocEventUserMem->hdc = hdc;
|
|
EnterDrvSem();
|
|
pDocEventUserMem->pNext = gDocEventUserMemList;
|
|
gDocEventUserMemList = pDocEventUserMem;
|
|
LeaveDrvSem();
|
|
|
|
}
|
|
else
|
|
{
|
|
FreePDEVUserMem(pDocEventUserMem);
|
|
}
|
|
break;
|
|
|
|
case DOCUMENTEVENT_RESETDCPRE:
|
|
|
|
Verbose(("Document event: RESETDCPRE\n"));
|
|
Assert(cbIn >= sizeof(PVOID) && pjIn && cbOut >= sizeof(PDEVMODE) && pjOut);
|
|
result = DocEventResetDCPre(hdc, pDocEventUserMem, *((PDEVMODE *) pjIn), (PDEVMODE *) pjOut);
|
|
break;
|
|
|
|
case DOCUMENTEVENT_STARTDOCPRE:
|
|
//
|
|
// normal case if we're bringing up the send wizard
|
|
//
|
|
//
|
|
// When direct printing is requested we don't even call DocEventStartDocPre().
|
|
// When direct printing is requested all the information required to print
|
|
// the job will be provided by the application. For example FaxStartPrintJob()
|
|
// uses direct printing. It provides the fax job parameters directly into
|
|
// JOB_INFO_2.pParameters on its own.
|
|
//
|
|
|
|
if (!pDocEventUserMem->directPrinting)
|
|
{
|
|
Assert(cbIn >= sizeof(PVOID) && pjIn);
|
|
//
|
|
// Check if the printing application is using DDE and did not create new process for printing
|
|
// If it so, the environment variable FAX_ENVVAR_PRINT_FILE was not found
|
|
//
|
|
hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, FAXXP_MEM_MUTEX_NAME);
|
|
if (hMutex)
|
|
{
|
|
if (WaitForSingleObject( hMutex, 1000 * 60 * 5) == WAIT_OBJECT_0)
|
|
{
|
|
HANDLE hSharedMem;
|
|
//
|
|
// we own the mutex...make sure we can open the shared memory region.
|
|
//
|
|
hSharedMem = OpenFileMapping(FILE_MAP_READ, FALSE, FAXXP_MEM_NAME);
|
|
if (NULL == hSharedMem)
|
|
{
|
|
Error(("OpenFileMapping failed error: %d\n", GetLastError()));
|
|
result = DOCUMENTEVENT_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// we own the mutex and we have the shared memory region open.
|
|
//
|
|
|
|
// check if we are printing to a file.
|
|
//
|
|
LPTSTR filename;
|
|
|
|
filename = (LPTSTR)MapViewOfFile(
|
|
hSharedMem,
|
|
FILE_MAP_READ,
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
|
|
if (!filename || IsBadStringPtr(filename, MAX_PATH * 2))
|
|
{
|
|
//
|
|
// Never trust the shared memory region. It might get corrupted by a malicious user.
|
|
//
|
|
Error(("Failed to map a view of the file or pointer is bad: %d\n", hSharedMem));
|
|
result = DOCUMENTEVENT_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// check if this is really the filename we want to print to.
|
|
//
|
|
LPDOCINFO lpDocInfo = *((LPDOCINFO *)pjIn);
|
|
if (lpDocInfo->lpszDocName)
|
|
{
|
|
LPTSTR lptstrSubStr = NULL;
|
|
LPTSTR lptstrTmpInputFile = _tcschr(filename, TEXT('\0'));
|
|
Assert (lptstrTmpInputFile);
|
|
lptstrTmpInputFile = _tcsinc(lptstrTmpInputFile);
|
|
if (IsBadStringPtr(lptstrTmpInputFile, MAX_PATH * 2))
|
|
{
|
|
Error(("Corrupted shared memory buffer\n"));
|
|
result = DOCUMENTEVENT_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
Assert (_tcsclen(lptstrTmpInputFile));
|
|
|
|
lptstrSubStr = _tcsstr(lpDocInfo->lpszDocName, lptstrTmpInputFile);
|
|
if (lptstrSubStr)
|
|
{
|
|
//
|
|
// We assume the shared memory was pointed to us
|
|
//
|
|
pDocEventUserMem->pPrintFile = DuplicateString(filename);
|
|
if (!pDocEventUserMem->pPrintFile)
|
|
{
|
|
Error(("Memory allocation failed\n"));
|
|
result = DOCUMENTEVENT_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// At last - every thing is OK, this is a direct printing from PrintRandomDocument
|
|
// to a application that is using DDE and an instance was already open.
|
|
//
|
|
pDocEventUserMem->directPrinting = TRUE;
|
|
pDocEventUserMem->bAttachment = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// To handle the race conditions between two diffrent instances of the printer driver over the shared memory created by PrintRandomDocument().
|
|
// We are using now two mechanisms for detecting printing of an attachment using PrintRandomDocument().
|
|
// · First we check if an environment variable is set (Set by PrintRandomDocument()). If it is set the driver knows it is an attachment printing.
|
|
// · If it is not set, the driver looks for a mutex controlling a shred memory created by PrintRandomDocument(). If it does not exist it is a printing to the fax server.
|
|
// · If the shared memory exists, the driver compares the document name in the DOCINFO provided by StartDoc, and the input file name in the shared memory.
|
|
// · If there is a match, it is printing of an attachment, else it is a printing to the fax server
|
|
// There is still a hole in this implementation, if there is an open instance of the printing application, and the ShellExecuteEx does not create new process for printing, and the printing application does not set the lpszDocName in StartDoc to contain the input file name.
|
|
Warning (("No lpszDocName in DOCINFO - Could not verify the input file name in shared memory\n"));
|
|
}
|
|
UnmapViewOfFile( filename );
|
|
}
|
|
|
|
if (!CloseHandle( hSharedMem ))
|
|
{
|
|
Error(("CloseHandle() failed: %d.\n", GetLastError()));
|
|
// Try to continue...
|
|
}
|
|
}
|
|
ReleaseMutex( hMutex );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Something went wrong with WaitForSingleObject
|
|
//
|
|
result = DOCUMENTEVENT_FAILURE;
|
|
}
|
|
|
|
if (!CloseHandle( hMutex ))
|
|
{
|
|
Error(("CloseHandle() failed: %d.\n", GetLastError()));
|
|
// Try to continue...
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check again for direct printing
|
|
//
|
|
if (!pDocEventUserMem->directPrinting)
|
|
{
|
|
//
|
|
// client 'point and print' setup
|
|
//
|
|
if (FaxPointAndPrintSetup(pDocEventUserMem->lptstrPrinterName,FALSE, g_hModule))
|
|
{
|
|
Verbose(("FaxPointAndPrintSetup succeeded\n"));
|
|
}
|
|
else
|
|
{
|
|
Error(("FaxPointAndPrintSetup failed: %d\n", GetLastError()));
|
|
}
|
|
|
|
result = DocEventStartDocPre(hdc, pDocEventUserMem, *((LPDOCINFO *) pjIn));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// we're doing direct printing -- check if this is an attachment
|
|
//
|
|
pDocEventUserMem->jobType = JOBTYPE_DIRECT;
|
|
if (TRUE == pDocEventUserMem->bAttachment)
|
|
{
|
|
(*((LPDOCINFO *) pjIn))->lpszOutput = pDocEventUserMem->pPrintFile;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DOCUMENTEVENT_STARTDOCPOST:
|
|
|
|
if (!pDocEventUserMem->directPrinting && pDocEventUserMem->jobType == JOBTYPE_NORMAL)
|
|
{
|
|
//
|
|
// Job ID is passed in from GDI
|
|
//
|
|
//
|
|
// Save the job id returned from StartDoc. This is the job id of the body.
|
|
// Pause the body job so we can attach cover page jobs to it before it starts
|
|
// executing.
|
|
//
|
|
|
|
Assert(cbIn >= sizeof(DWORD) && pjIn);
|
|
pDocEventUserMem->jobId = *((LPDWORD) pjIn);
|
|
|
|
//
|
|
// Tell spooler to pause the fax body job so that
|
|
// we can associate cover pages with it later
|
|
//
|
|
|
|
if (! SetJob(pDocEventUserMem->hPrinter, pDocEventUserMem->jobId, 0, NULL, JOB_CONTROL_PAUSE))
|
|
{
|
|
Error(("Couldn't pause fax body job: %d\n", pDocEventUserMem->jobId));
|
|
return DOCUMENTEVENT_FAILURE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DOCUMENTEVENT_STARTPAGE:
|
|
if (! pDocEventUserMem->directPrinting)
|
|
{
|
|
//
|
|
// Get PREVIOUS preview page (this event is called BEFORE the graphics dll recieved
|
|
// the DrvSendPage() call for this page, so we actually get the previous page).
|
|
//
|
|
// NOTE: This event is recieved before the graphics dll recieves its DrvStartPage()
|
|
// call where it increments the page count and resets the mapping surface. The first
|
|
// time we get this event there is no actual page but we perform validity checking.
|
|
//
|
|
if (pDocEventUserMem->bShowPrintPreview && !pDocEventUserMem->bPreviewAborted)
|
|
{
|
|
if (!AppendPreviewPage(pDocEventUserMem))
|
|
{
|
|
Error(("AppendPreviewPage() failed.\n"));
|
|
Assert(pDocEventUserMem->bPreviewAborted);
|
|
// We can continue with no print preview...
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DOCUMENTEVENT_ENDPAGE:
|
|
if (! pDocEventUserMem->directPrinting)
|
|
{
|
|
pDocEventUserMem->pageCount++;
|
|
}
|
|
break;
|
|
|
|
case DOCUMENTEVENT_ENDDOCPOST:
|
|
if (!pDocEventUserMem->directPrinting)
|
|
{
|
|
//
|
|
// Get the last preview page
|
|
//
|
|
if (pDocEventUserMem->bShowPrintPreview && !pDocEventUserMem->bPreviewAborted)
|
|
{
|
|
if (!AppendPreviewPage(pDocEventUserMem))
|
|
{
|
|
Error(("AppendPreviewPage() failed.\n"));
|
|
Assert(pDocEventUserMem->bPreviewAborted);
|
|
// We can continue with no print preview...
|
|
}
|
|
}
|
|
//
|
|
// Close the preview file
|
|
//
|
|
if (INVALID_HANDLE_VALUE != pDocEventUserMem->hPreviewFile)
|
|
{
|
|
if (!CloseHandle(pDocEventUserMem->hPreviewFile))
|
|
{
|
|
Error(("CloseHandle() failed: %d.\n", GetLastError()));
|
|
// Try to continue...
|
|
}
|
|
pDocEventUserMem->hPreviewFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
//
|
|
// Call the handler
|
|
//
|
|
result = DocEventEndDocPost(hdc, pDocEventUserMem);
|
|
//
|
|
// If we created a preview file, delete it.
|
|
//
|
|
if (pDocEventUserMem->szPreviewFile[0] != TEXT('\0'))
|
|
{
|
|
if (!DeleteFile(pDocEventUserMem->szPreviewFile))
|
|
{
|
|
Error(("DeleteFile() failed. Error code: %d.\n", GetLastError()));
|
|
}
|
|
pDocEventUserMem->szPreviewFile[0] = TEXT('\0');
|
|
}
|
|
}
|
|
|
|
if (TRUE == pDocEventUserMem->bAttachment)
|
|
{
|
|
HANDLE hEndDocEvent;
|
|
LPTSTR szEndDocEventName= NULL;
|
|
LPTSTR lptstrEventName = NULL;
|
|
|
|
Assert (pDocEventUserMem->pPrintFile);
|
|
//
|
|
// Create the EndDoc event name
|
|
//
|
|
szEndDocEventName = (LPTSTR) MemAlloc( SizeOfString(pDocEventUserMem->pPrintFile) + SizeOfString(FAXXP_ATTACH_END_DOC_EVENT) );
|
|
|
|
if (szEndDocEventName)
|
|
{
|
|
_tcscpy (szEndDocEventName, pDocEventUserMem->pPrintFile);
|
|
_tcscat (szEndDocEventName, FAXXP_ATTACH_END_DOC_EVENT);
|
|
|
|
lptstrEventName = _tcsrchr(szEndDocEventName, TEXT('\\'));
|
|
Assert (lptstrEventName);
|
|
lptstrEventName = _tcsinc(lptstrEventName);
|
|
//
|
|
// Send event to the printing application (PrintRandomDocument() that file is ready)
|
|
//
|
|
hEndDocEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, lptstrEventName);
|
|
if (NULL == hEndDocEvent)
|
|
{
|
|
Error(("OpenEvent() failed. Error code: %d.\n", GetLastError()));
|
|
result = DOCUMENTEVENT_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
if (!SetEvent( hEndDocEvent ))
|
|
{
|
|
Error(("SetEvent() failed. Error code: %d.\n", GetLastError()));
|
|
result = DOCUMENTEVENT_FAILURE;
|
|
}
|
|
|
|
if (!CloseHandle(hEndDocEvent))
|
|
{
|
|
Error(("CloseHandle() failed: %d.\n", GetLastError()));
|
|
// Try to continue...
|
|
}
|
|
}
|
|
|
|
MemFree(szEndDocEventName);
|
|
}
|
|
else
|
|
{
|
|
Error(("Memory allocation for szEndDocEventName failed.\n"));
|
|
result = DOCUMENTEVENT_FAILURE;
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case DOCUMENTEVENT_DELETEDC:
|
|
|
|
EnterDrvSem();
|
|
|
|
if (pDocEventUserMem == gDocEventUserMemList)
|
|
{
|
|
gDocEventUserMemList = gDocEventUserMemList->pNext;
|
|
}
|
|
else
|
|
{
|
|
PDOCEVENTUSERMEM p;
|
|
|
|
if (p = gDocEventUserMemList)
|
|
{
|
|
while (p->pNext && p->pNext != pDocEventUserMem)
|
|
{
|
|
p = p->pNext;
|
|
}
|
|
if (p->pNext != NULL)
|
|
{
|
|
p->pNext = pDocEventUserMem->pNext;
|
|
}
|
|
else
|
|
{
|
|
Error(("Orphaned user mode memory structure!!!\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Error(("gDocEventUserMemList shouldn't be NULL!!!\n"));
|
|
}
|
|
}
|
|
LeaveDrvSem();
|
|
FreePDEVUserMem(pDocEventUserMem);
|
|
break;
|
|
|
|
case DOCUMENTEVENT_ABORTDOC:
|
|
if (TRUE == pDocEventUserMem->bAttachment)
|
|
{
|
|
//
|
|
// Send event to the printing application (PrintRandomDocument() that printing was aborted)
|
|
//
|
|
HANDLE hAbortEvent;
|
|
TCHAR szAbortEventName[FAXXP_ATTACH_EVENT_NAME_LEN] = {0};
|
|
LPTSTR lptstrEventName = NULL;
|
|
|
|
Assert (pDocEventUserMem->pPrintFile);
|
|
//
|
|
// Create the Abort event name
|
|
//
|
|
_tcscpy (szAbortEventName, pDocEventUserMem->pPrintFile);
|
|
_tcscat (szAbortEventName, FAXXP_ATTACH_ABORT_EVENT);
|
|
lptstrEventName = _tcsrchr(szAbortEventName, TEXT('\\'));
|
|
Assert (lptstrEventName);
|
|
lptstrEventName = _tcsinc(lptstrEventName);
|
|
|
|
hAbortEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, lptstrEventName);
|
|
if (NULL == hAbortEvent)
|
|
{
|
|
Error(("OpenEvent() failed. Error code: %d.\n", GetLastError()));
|
|
result = DOCUMENTEVENT_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
if (!SetEvent( hAbortEvent ))
|
|
{
|
|
Error(("SetEvent() failed. Error code: %d.\n", GetLastError()));
|
|
result = DOCUMENTEVENT_FAILURE;
|
|
}
|
|
|
|
if (!CloseHandle(hAbortEvent))
|
|
{
|
|
Error(("CloseHandle() failed: %d.\n", GetLastError()));
|
|
// Try to continue...
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DOCUMENTEVENT_RESETDCPOST:
|
|
case DOCUMENTEVENT_ENDDOCPRE:
|
|
break;
|
|
|
|
case DOCUMENTEVENT_ESCAPE:
|
|
default:
|
|
Verbose(("Unsupported DrvDocumentEvent escape: %d\n", iEsc));
|
|
result = DOCUMENTEVENT_UNSUPPORTED;
|
|
break;
|
|
}
|
|
return result;
|
|
} // DrvDocumentEvent
|
|
|
|
|
|
/*
|
|
Function:
|
|
ShowReentrancyMessage
|
|
Purpose:
|
|
The code of FxsWzrd.dll is not re-entrant.
|
|
We prevent its running from different threads inside one process.
|
|
We want to notify user about this.
|
|
|
|
Return Value:
|
|
ERROR_SUCCESS -- success
|
|
Win32 Error Code -- failure
|
|
|
|
Author:
|
|
Iv Vakaluk (IvG) 2-Sept-2002
|
|
*/
|
|
DWORD ShowReentrancyMessage(void)
|
|
{
|
|
DWORD dwRes = ERROR_SUCCESS;
|
|
TCHAR szTitle[MAX_PATH] = {0};
|
|
TCHAR szText[MAX_PATH] = {0};
|
|
|
|
Verbose(("Entering ShowReentrancyMessage()\n"));
|
|
|
|
//
|
|
// Load Title
|
|
//
|
|
if (!LoadString(g_hResource, IDS_REENTRANCY_TITLE, szTitle, sizeof(szTitle)/sizeof(TCHAR)))
|
|
{
|
|
dwRes = GetLastError();
|
|
Error(("LoadString(IDS_REENTRANCY_TITLE) failed: %d.\n", dwRes));
|
|
return dwRes;
|
|
}
|
|
|
|
//
|
|
// Load Message title
|
|
//
|
|
if (!LoadString(g_hResource, IDS_REENTRANCY_TEXT, szText, sizeof(szText)/sizeof(TCHAR)))
|
|
{
|
|
dwRes = GetLastError();
|
|
Error(("LoadString(IDS_REENTRANCY_TEXT) failed: %d.\n", dwRes));
|
|
return dwRes;
|
|
}
|
|
|
|
if (!AlignedMessageBox(NULL, szText, szTitle, MB_OK))
|
|
{
|
|
dwRes = GetLastError();
|
|
Error(("MessageBox() failed: %d.\n", dwRes));
|
|
return dwRes;
|
|
}
|
|
|
|
return dwRes;
|
|
}
|