1105 lines
26 KiB
C
1105 lines
26 KiB
C
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
print.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the print specific WINFAX API functions.
|
|
|
|
Author:
|
|
|
|
Wesley Witt (wesw) 29-Nov-1996
|
|
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "faxapi.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
LPWSTR Platforms[] =
|
|
{
|
|
L"Windows NT x86",
|
|
L"Windows NT R4000",
|
|
L"Windows NT Alpha_AXP",
|
|
L"Windows NT PowerPC"
|
|
};
|
|
|
|
|
|
|
|
LPWSTR
|
|
AddFaxTag(
|
|
LPWSTR TagStr,
|
|
LPCWSTR FaxTag,
|
|
LPCWSTR Value
|
|
)
|
|
{
|
|
if (!Value) {
|
|
return TagStr;
|
|
}
|
|
wcscat( TagStr, FaxTag );
|
|
wcscat( TagStr, Value );
|
|
return TagStr;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsPrinterFaxPrinter(
|
|
LPWSTR PrinterName
|
|
)
|
|
{
|
|
HANDLE hPrinter = NULL;
|
|
PRINTER_DEFAULTS PrinterDefaults;
|
|
SYSTEM_INFO SystemInfo;
|
|
DWORD Size;
|
|
DWORD Rval = FALSE;
|
|
LPDRIVER_INFO_2 DriverInfo = NULL;
|
|
|
|
|
|
PrinterDefaults.pDatatype = NULL;
|
|
PrinterDefaults.pDevMode = NULL;
|
|
PrinterDefaults.DesiredAccess = PRINTER_READ;
|
|
|
|
if (!OpenPrinter( PrinterName, &hPrinter, &PrinterDefaults )) {
|
|
|
|
DebugPrint(( L"OpenPrinter() failed, ec=%d", GetLastError() ));
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
GetSystemInfo( &SystemInfo );
|
|
|
|
Size = 4096;
|
|
|
|
DriverInfo = (LPDRIVER_INFO_2) MemAlloc( Size );
|
|
if (!DriverInfo) {
|
|
DebugPrint(( L"Memory allocation failed, size=%d", Size ));
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
Rval = GetPrinterDriver(
|
|
hPrinter,
|
|
Platforms[SystemInfo.wProcessorArchitecture],
|
|
2,
|
|
(LPBYTE) DriverInfo,
|
|
Size,
|
|
&Size
|
|
);
|
|
if (!Rval) {
|
|
DebugPrint(( L"GetPrinterDriver() failed, ec=%d", GetLastError() ));
|
|
goto exit;
|
|
}
|
|
|
|
if (_tcscmp( DriverInfo->pName, FAX_DRIVER_NAME ) == 0) {
|
|
Rval = TRUE;
|
|
} else {
|
|
Rval = FALSE;
|
|
}
|
|
|
|
exit:
|
|
|
|
MemFree( DriverInfo );
|
|
ClosePrinter( hPrinter );
|
|
return Rval;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
MemFree(pJobInfo);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
LPWSTR
|
|
GetCpField(
|
|
HKEY hKey,
|
|
LPWSTR SubKey
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves the data for a coverpage field from
|
|
the registry.
|
|
|
|
Arguments:
|
|
|
|
hKey - Registry handle
|
|
SubKey - Subkey name
|
|
|
|
Return Value:
|
|
|
|
Pointer to the coverpage field data.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG rVal;
|
|
DWORD RegSize;
|
|
DWORD RegType;
|
|
LPBYTE Buffer;
|
|
|
|
|
|
rVal = RegQueryValueEx( hKey, SubKey, 0, &RegType, NULL, &RegSize );
|
|
if (rVal != ERROR_SUCCESS) {
|
|
return NULL;
|
|
}
|
|
|
|
Buffer = (LPBYTE) MemAlloc( RegSize );
|
|
if (!Buffer) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return NULL;
|
|
}
|
|
|
|
rVal = RegQueryValueEx( hKey, SubKey, 0, &RegType, Buffer, &RegSize );
|
|
if (rVal != ERROR_SUCCESS) {
|
|
MemFree( Buffer );
|
|
return NULL;
|
|
}
|
|
|
|
return (LPWSTR) Buffer;
|
|
}
|
|
|
|
BOOL
|
|
GetCpFields(
|
|
PCOVERPAGEFIELDS CpFields
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the coverpage field structure and
|
|
fills in the sender information from the registry.
|
|
|
|
Arguments:
|
|
|
|
CpFields - Pointer to a coverpage field structure.
|
|
|
|
Return Value:
|
|
|
|
TRUE for success.
|
|
FALSE for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY hKey;
|
|
LONG rVal;
|
|
|
|
|
|
rVal = RegOpenKey(
|
|
HKEY_CURRENT_USER,
|
|
REGKEY_FAX_USERINFO,
|
|
&hKey
|
|
);
|
|
if (rVal != ERROR_SUCCESS) {
|
|
return FALSE;
|
|
}
|
|
|
|
ZeroMemory( CpFields, sizeof(COVERPAGEFIELDS) );
|
|
CpFields->ThisStructSize = sizeof(COVERPAGEFIELDS);
|
|
|
|
//
|
|
// sender fields
|
|
//
|
|
|
|
CpFields->SdrName = GetCpField( hKey, REGVAL_FULLNAME );
|
|
CpFields->SdrFaxNumber = GetCpField( hKey, REGVAL_FAX_NUMBER );
|
|
CpFields->SdrCompany = GetCpField( hKey, REGVAL_COMPANY );
|
|
CpFields->SdrAddress = GetCpField( hKey, REGVAL_ADDRESS );
|
|
CpFields->SdrTitle = GetCpField( hKey, REGVAL_TITLE );
|
|
CpFields->SdrDepartment = GetCpField( hKey, REGVAL_DEPT );
|
|
CpFields->SdrOfficeLocation = GetCpField( hKey, REGVAL_OFFICE );
|
|
CpFields->SdrHomePhone = GetCpField( hKey, REGVAL_HOME_PHONE );
|
|
CpFields->SdrOfficePhone = GetCpField( hKey, REGVAL_OFFICE_PHONE );
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeCpFields(
|
|
PCOVERPAGEFIELDS CpFields
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees all memory associated with a coverpage field structure.
|
|
|
|
|
|
Arguments:
|
|
|
|
CpFields - Pointer to a coverpage field structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD i;
|
|
LPBYTE *p;
|
|
|
|
for (i = 0; i < NUM_INSERTION_TAGS; i++) {
|
|
p = (LPBYTE *) ((ULONG_PTR)CpFields + sizeof(LPTSTR)*(i+1));
|
|
if (p && *p) MemFree( *p );
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
FaxPrintCoverPageW(
|
|
IN const FAX_CONTEXT_INFO *FaxContextInfo,
|
|
IN const FAX_COVERPAGE_INFOW *CoverPageInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints a coverpage into the printer DC provided.
|
|
|
|
Arguments:
|
|
|
|
FaxContextInfo - contains servername, Printer DC
|
|
CoverPageInfo - Cover page information
|
|
|
|
Return Value:
|
|
|
|
TRUE for success.
|
|
FALSE for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
WCHAR CpName[MAX_PATH];
|
|
WCHAR Buffer[MAX_PATH];
|
|
LPWSTR p;
|
|
COVERPAGEFIELDS CpFields = {0};
|
|
COVDOCINFO CovDocInfo;
|
|
DWORD DateTimeLen;
|
|
DWORD cch;
|
|
LPWSTR s;
|
|
DWORD ec = 0;
|
|
LPCWSTR *src;
|
|
LPCWSTR *dst;
|
|
DWORD i;
|
|
|
|
|
|
|
|
//
|
|
// do a little argument validation
|
|
//
|
|
|
|
if (CoverPageInfo == NULL || CoverPageInfo->SizeOfStruct != sizeof(FAX_COVERPAGE_INFOW) ||
|
|
FaxContextInfo == NULL || FaxContextInfo->hDC == NULL ||
|
|
FaxContextInfo->SizeOfStruct != sizeof (FAX_CONTEXT_INFOW) )
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ValidateCoverpage(CoverPageInfo->CoverPageName,
|
|
FaxContextInfo->ServerName,
|
|
CoverPageInfo->UseServerCoverPage,
|
|
CpName)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// get the coverpage fields
|
|
//
|
|
|
|
GetCpFields( &CpFields );
|
|
|
|
//
|
|
// fixup the recipient name
|
|
//
|
|
|
|
if (CoverPageInfo->RecName) {
|
|
if (CoverPageInfo->RecName[0] == '\'') {
|
|
wcscpy( Buffer, &CoverPageInfo->RecName[1] );
|
|
Buffer[wcslen(Buffer)-1] = 0;
|
|
} else {
|
|
wcscpy( Buffer, CoverPageInfo->RecName );
|
|
}
|
|
} else {
|
|
Buffer[0] = 0;
|
|
}
|
|
|
|
//
|
|
// fill in the coverpage fields with the
|
|
// data that the caller passed in
|
|
//
|
|
|
|
CpFields.RecName = StringDup( Buffer );
|
|
CpFields.RecFaxNumber = StringDup( CoverPageInfo->RecFaxNumber );
|
|
if (CpFields.RecFaxNumber) {
|
|
p = wcsrchr( (LPWSTR) CpFields.RecFaxNumber, L'@' );
|
|
if (p) {
|
|
wcscpy( (LPWSTR) CpFields.RecFaxNumber, p+1 );
|
|
}
|
|
}
|
|
CpFields.Subject = StringDup( CoverPageInfo->Subject );
|
|
CpFields.Note = StringDup( CoverPageInfo->Note ? CoverPageInfo->Note : L"" );
|
|
CpFields.NumberOfPages = StringDup( _itow( CoverPageInfo->PageCount, Buffer, 10 ) );
|
|
|
|
for (i = 0;
|
|
i <= ((LPBYTE)&CoverPageInfo->SdrOfficePhone-(LPBYTE)&CoverPageInfo->RecCompany)/sizeof(LPCWSTR);
|
|
i++) {
|
|
src = (LPCWSTR *) ((LPBYTE)&CoverPageInfo->RecCompany + (i*sizeof(LPCWSTR)));
|
|
dst = (LPCWSTR *) ((LPBYTE)&CpFields.RecCompany + (i*sizeof(LPCWSTR)));
|
|
|
|
if (*dst) {
|
|
MemFree ( (LPBYTE) *dst ) ;
|
|
}
|
|
|
|
*dst = (LPCWSTR) StringDup( *src );
|
|
|
|
}
|
|
|
|
//
|
|
// the time the fax was sent
|
|
//
|
|
|
|
GetLocalTime((LPSYSTEMTIME)&CoverPageInfo->TimeSent);
|
|
|
|
DateTimeLen = sizeof(Buffer);
|
|
s = Buffer;
|
|
|
|
GetDateFormat( LOCALE_USER_DEFAULT, 0, &CoverPageInfo->TimeSent, NULL, s, DateTimeLen );
|
|
|
|
cch = wcslen( s );
|
|
s += cch;
|
|
|
|
if (++cch < DateTimeLen) {
|
|
|
|
*s++ = ' ';
|
|
DateTimeLen -= cch;
|
|
|
|
GetTimeFormat( LOCALE_USER_DEFAULT, 0, &CoverPageInfo->TimeSent, NULL, s, DateTimeLen );
|
|
}
|
|
|
|
CpFields.TimeSent = StringDup( Buffer );
|
|
|
|
//
|
|
// start the coverpage on a new page
|
|
//
|
|
|
|
StartPage( FaxContextInfo->hDC );
|
|
|
|
//
|
|
// print the cover page
|
|
//
|
|
|
|
ec = PrintCoverPage(
|
|
FaxContextInfo->hDC,
|
|
&CpFields,
|
|
CpName,
|
|
&CovDocInfo
|
|
);
|
|
|
|
//
|
|
// end the page
|
|
//
|
|
|
|
EndPage( FaxContextInfo->hDC );
|
|
|
|
FreeCpFields( &CpFields );
|
|
|
|
if (ec != 0) {
|
|
SetLastError( ec );
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
FaxPrintCoverPageA(
|
|
IN const FAX_CONTEXT_INFOA *FaxContextInfo,
|
|
IN const FAX_COVERPAGE_INFOA *CoverPageInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints a coverpage into the printer DC provided.
|
|
|
|
Arguments:
|
|
|
|
FaxContextInfo - fax Printer context info (hdc, etc.)
|
|
CoverPageInfo - Cover page information
|
|
|
|
Return Value:
|
|
|
|
TRUE for success.
|
|
FALSE for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// assume all fields between Subject and RecName are LPCTSTR's
|
|
//
|
|
#define COUNT_CP_FIELDS ((LPBYTE) &CoverPageInfoW.Subject - (LPBYTE)&CoverPageInfoW.RecName)/sizeof(LPCTSTR)
|
|
BOOL Rval;
|
|
FAX_COVERPAGE_INFOW CoverPageInfoW = {0};
|
|
FAX_CONTEXT_INFOW ContextInfoW = {0};
|
|
LPWSTR ServerName = NULL;
|
|
LPWSTR *d;
|
|
LPSTR *s;
|
|
DWORD i;
|
|
|
|
if (!FaxContextInfo || !CoverPageInfo ||
|
|
FaxContextInfo->SizeOfStruct != sizeof(FAX_CONTEXT_INFOA) ||
|
|
CoverPageInfo->SizeOfStruct != sizeof(FAX_COVERPAGE_INFOA)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
ContextInfoW.SizeOfStruct = sizeof(FAX_CONTEXT_INFOW);
|
|
ContextInfoW.hDC = FaxContextInfo->hDC;
|
|
if (FaxContextInfo->ServerName[0] != (CHAR)'\0') {
|
|
ServerName = AnsiStringToUnicodeString( FaxContextInfo->ServerName );
|
|
wcscpy(ContextInfoW.ServerName,ServerName);
|
|
}
|
|
|
|
CoverPageInfoW.SizeOfStruct = sizeof(FAX_COVERPAGE_INFOW);
|
|
CoverPageInfoW.UseServerCoverPage = CoverPageInfo->UseServerCoverPage;
|
|
CoverPageInfoW.PageCount = CoverPageInfo->PageCount;
|
|
CoverPageInfoW.CoverPageName = AnsiStringToUnicodeString( CoverPageInfo->CoverPageName );
|
|
|
|
for (i=0;i<=COUNT_CP_FIELDS;i++) {
|
|
d = (LPWSTR*) ((ULONG_PTR)&CoverPageInfoW.RecName + i*sizeof(LPCWSTR));
|
|
s = (LPSTR *) ((LPBYTE)&CoverPageInfo->RecName + i*sizeof(LPSTR));
|
|
DebugPrint(( TEXT(" source: 0x%08x --> dest: 0x%08x \n"), s, d));
|
|
*d = AnsiStringToUnicodeString( *s );
|
|
}
|
|
|
|
CoverPageInfoW.TimeSent = CoverPageInfo->TimeSent;
|
|
CoverPageInfoW.PageCount = CoverPageInfo->PageCount;
|
|
|
|
Rval = FaxPrintCoverPageW(
|
|
&ContextInfoW,
|
|
&CoverPageInfoW
|
|
);
|
|
|
|
if (CoverPageInfoW.CoverPageName) {
|
|
MemFree( (LPBYTE) CoverPageInfoW.CoverPageName );
|
|
}
|
|
|
|
if (ServerName) {
|
|
MemFree( (LPBYTE) ServerName );
|
|
}
|
|
|
|
for (i = 0; i < COUNT_CP_FIELDS; i++) {
|
|
d = (LPWSTR *)((ULONG_PTR)&CoverPageInfoW.RecName + i*sizeof(LPWSTR));
|
|
if (d && *d)MemFree( (LPBYTE)*d );
|
|
}
|
|
|
|
return Rval;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
FaxStartPrintJobW(
|
|
IN LPCWSTR PrinterName,
|
|
IN const FAX_PRINT_INFOW *PrintInfo,
|
|
OUT LPDWORD FaxJobId,
|
|
OUT PFAX_CONTEXT_INFO FaxContextInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Starts a print job for the specified printer. This
|
|
function provides functionality beyond what the caller
|
|
can provide by using StartDoc(). This function disables
|
|
the display of the fax send wizard and also passes along
|
|
the information that would otherwise be gathered by the
|
|
fax wizard ui.
|
|
|
|
Arguments:
|
|
|
|
PrinterName - Fax printer name (must be a fax printer)
|
|
PrintInfo - Fax print information
|
|
FaxJobId - Job id of the resulting print job
|
|
FaxContextInfo - context information including hdc
|
|
|
|
Return Value:
|
|
|
|
TRUE for success.
|
|
FALSE for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE hPrinter = NULL;
|
|
PDEVMODE DevMode = NULL;
|
|
PDMPRIVATE DevModePrivate = NULL;
|
|
DOCINFO DocInfo;
|
|
PJOB_INFO_2 JobInfo = NULL;
|
|
PPRINTER_INFO_2 PrinterInfo = NULL;
|
|
DWORD dwNeeded = 0;
|
|
HDC hDC = NULL;
|
|
INT JobId = 0;
|
|
LPWSTR FaxTags = NULL;
|
|
LONG Size;
|
|
LPWSTR FaxPrinterName;
|
|
|
|
//
|
|
// do a little argument validation
|
|
//
|
|
|
|
if (PrintInfo == NULL || PrintInfo->SizeOfStruct != sizeof(FAX_PRINT_INFOW) ||
|
|
!FaxJobId || !FaxContextInfo)
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return FALSE;
|
|
}
|
|
|
|
if (PrintInfo->OutputFileName == NULL &&
|
|
(PrintInfo->RecipientNumber == NULL || PrintInfo->RecipientNumber[0] == 0))
|
|
{
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return FALSE;
|
|
}
|
|
|
|
if (PrintInfo->DrProfileName && PrintInfo->DrEmailAddress) {
|
|
SetLastError( ERROR_INVALID_PARAMETER );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// if no printer specified, assume they want a local fax printer
|
|
//
|
|
if (!PrinterName) {
|
|
FaxPrinterName = GetFaxPrinterName();
|
|
if (!FaxPrinterName) {
|
|
SetLastError(ERROR_INVALID_PRINTER_NAME);
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
FaxPrinterName = (LPWSTR) PrinterName;
|
|
}
|
|
//
|
|
// verify that the printer is a fax printer, the only type allowed
|
|
//
|
|
|
|
if (!IsPrinterFaxPrinter( FaxPrinterName )) {
|
|
SetLastError( ERROR_INVALID_PRINTER_NAME );
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// open the printer for normal access (this should always work)
|
|
//
|
|
|
|
if (!OpenPrinter( FaxPrinterName, &hPrinter, NULL )) {
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// get the fax server's name if the fax printer isn't local
|
|
//
|
|
if (!GetPrinter(hPrinter,2,(LPBYTE)PrinterInfo,0,&dwNeeded)) {
|
|
PrinterInfo = MemAlloc( dwNeeded );
|
|
if (!PrinterInfo) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto error_exit;
|
|
}
|
|
}
|
|
|
|
if (!GetPrinter(hPrinter,2,(LPBYTE)PrinterInfo,dwNeeded,&dwNeeded)) {
|
|
goto error_exit;
|
|
}
|
|
|
|
if (PrinterInfo->pServerName)
|
|
wcscpy(FaxContextInfo->ServerName,PrinterInfo->pServerName);
|
|
else
|
|
FaxContextInfo->ServerName[0] = 0;
|
|
|
|
|
|
//
|
|
// get the required size for the DEVMODE
|
|
//
|
|
|
|
Size = DocumentProperties( NULL, hPrinter, NULL, NULL, NULL, 0 );
|
|
if (Size <= 0) {
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// allocate memory for the DEVMODE
|
|
//
|
|
|
|
DevMode = (PDEVMODE) MemAlloc( Size );
|
|
if (!DevMode) {
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// get the default document properties
|
|
//
|
|
|
|
if (DocumentProperties( NULL, hPrinter, NULL, DevMode, NULL, DM_OUT_BUFFER ) != IDOK) {
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// be sure we are dealing with the correct DEVMODE
|
|
//
|
|
|
|
if (DevMode->dmDriverExtra < sizeof(DMPRIVATE)) {
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// set the private DEVMODE pointer
|
|
//
|
|
|
|
DevModePrivate = (PDMPRIVATE) ((LPBYTE) DevMode + DevMode->dmSize);
|
|
|
|
//
|
|
// set the necessary stuff in the DEVMODE
|
|
//
|
|
|
|
DevModePrivate->sendCoverPage = FALSE;
|
|
DevModePrivate->flags |= FAXDM_NO_WIZARD;
|
|
DevModePrivate->flags &= ~FAXDM_DRIVER_DEFAULT;
|
|
|
|
//
|
|
// create the device context
|
|
//
|
|
|
|
hDC = CreateDC( L"WINSPOOL", FaxPrinterName, NULL, DevMode );
|
|
if (!hDC) {
|
|
goto error_exit;
|
|
}
|
|
|
|
//
|
|
// set the document information
|
|
//
|
|
|
|
DocInfo.cbSize = sizeof(DOCINFO);
|
|
DocInfo.lpszDocName = PrintInfo->DocName;
|
|
DocInfo.lpszOutput = PrintInfo->OutputFileName;
|
|
DocInfo.lpszDatatype = NULL;
|
|
DocInfo.fwType = 0;
|
|
|
|
//
|
|
// start the print job
|
|
//
|
|
|
|
JobId = StartDoc( hDC, &DocInfo );
|
|
if (JobId <= 0) {
|
|
goto error_exit;
|
|
}
|
|
|
|
if (PrintInfo->OutputFileName == NULL) {
|
|
|
|
//
|
|
// HACK HACK -> pause the print job
|
|
//
|
|
|
|
if (FaxJobId && *FaxJobId == 0xffffffff) {
|
|
SetJob( hPrinter, JobId, 0, NULL, JOB_CONTROL_PAUSE );
|
|
}
|
|
|
|
//
|
|
// allocate memory for the fax tags
|
|
//
|
|
|
|
FaxTags = (LPWSTR) MemAlloc( 4096 );
|
|
if (!FaxTags) {
|
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// set the job tags
|
|
// this is how we communicate the information to
|
|
// the print driver that would otherwise be
|
|
// provided by the fax print wizard
|
|
//
|
|
|
|
JobInfo = MyGetJob( hPrinter, 2, JobId );
|
|
if (!JobInfo) {
|
|
goto error_exit;
|
|
}
|
|
|
|
AddFaxTag( FaxTags, FAXTAG_RECIPIENT_NUMBER, PrintInfo->RecipientNumber );
|
|
AddFaxTag( FaxTags, FAXTAG_RECIPIENT_NAME, PrintInfo->RecipientName );
|
|
AddFaxTag( FaxTags, FAXTAG_SENDER_NAME, PrintInfo->SenderName );
|
|
AddFaxTag( FaxTags, FAXTAG_SENDER_NAME, PrintInfo->SenderName );
|
|
AddFaxTag( FaxTags, FAXTAG_SENDER_COMPANY, PrintInfo->SenderCompany );
|
|
AddFaxTag( FaxTags, FAXTAG_SENDER_DEPT, PrintInfo->SenderDept );
|
|
AddFaxTag( FaxTags, FAXTAG_BILLING_CODE, PrintInfo->SenderBillingCode );
|
|
|
|
if (PrintInfo->DrProfileName) {
|
|
AddFaxTag( FaxTags, FAXTAG_PROFILE_NAME, PrintInfo->DrProfileName );
|
|
AddFaxTag( FaxTags, FAXTAG_EMAIL_NAME, L"inbox" );
|
|
|
|
} else if (PrintInfo->DrEmailAddress) {
|
|
AddFaxTag( FaxTags, FAXTAG_PROFILE_NAME, PrintInfo->DrEmailAddress );
|
|
AddFaxTag( FaxTags, FAXTAG_EMAIL_NAME, L"email" );
|
|
}
|
|
|
|
//
|
|
// set these fields or the spooler will
|
|
// return ACCESS_DENIED for a non-admin client
|
|
//
|
|
|
|
JobInfo->Position = JOB_POSITION_UNSPECIFIED;
|
|
JobInfo->pDevMode = NULL;
|
|
|
|
//
|
|
// set our new fax tags
|
|
//
|
|
|
|
JobInfo->pParameters = FaxTags;
|
|
|
|
if (!SetJob( hPrinter, JobId, 2, (LPBYTE) JobInfo, 0 )) {
|
|
goto error_exit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// clean up and return to the caller
|
|
//
|
|
|
|
ClosePrinter( hPrinter);
|
|
MemFree( PrinterInfo);
|
|
MemFree( DevMode );
|
|
MemFree( FaxTags );
|
|
MemFree( JobInfo );
|
|
|
|
if (!PrinterName) {
|
|
MemFree (FaxPrinterName);
|
|
}
|
|
|
|
if (FaxJobId) {
|
|
*FaxJobId = JobId;
|
|
}
|
|
FaxContextInfo->hDC = hDC;
|
|
|
|
return TRUE;
|
|
|
|
error_exit:
|
|
if (hPrinter) {
|
|
ClosePrinter( hPrinter);
|
|
}
|
|
if (PrinterInfo) {
|
|
MemFree( PrinterInfo);
|
|
}
|
|
if (JobId) {
|
|
EndDoc( hDC );
|
|
}
|
|
if (hDC) {
|
|
DeleteDC( hDC );
|
|
}
|
|
if (DevMode) {
|
|
MemFree( DevMode );
|
|
}
|
|
if (FaxTags) {
|
|
MemFree( FaxTags );
|
|
}
|
|
if (JobInfo) {
|
|
MemFree( JobInfo );
|
|
}
|
|
|
|
if (!PrinterName) {
|
|
MemFree (FaxPrinterName);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
FaxStartPrintJobA(
|
|
IN LPCSTR PrinterName,
|
|
IN const FAX_PRINT_INFOA *PrintInfo,
|
|
OUT LPDWORD JobId,
|
|
OUT FAX_CONTEXT_INFOA *FaxContextInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Starts a print job for the specified printer. This
|
|
function provides functionality beyond what the caller
|
|
can provide by using StartDoc(). This function disables
|
|
the display of the fax send wizard and also passes along
|
|
the information that would otherwise be gathered by the
|
|
fax wizard ui.
|
|
|
|
Arguments:
|
|
|
|
PrinterName - Fax printer name (must be a fax printer)
|
|
PrintInfo - Fax print information
|
|
FaxJobId - Job id of the resulting print job
|
|
FaxContextInfo - device context information (hdc, etc.)
|
|
|
|
Return Value:
|
|
|
|
TRUE for success.
|
|
FALSE for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL Rval;
|
|
FAX_PRINT_INFOW PrintInfoW;
|
|
FAX_CONTEXT_INFOW ContextInfoW;
|
|
LPSTR ServerName;
|
|
LPWSTR PrinterNameW = NULL;
|
|
|
|
if (!PrintInfo || !JobId || !FaxContextInfo ||
|
|
(PrintInfo->SizeOfStruct != sizeof(FAX_PRINT_INFOA))) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (PrinterName) {
|
|
PrinterNameW = AnsiStringToUnicodeString( PrinterName );
|
|
}
|
|
|
|
ZeroMemory( &ContextInfoW, sizeof(FAX_CONTEXT_INFOW) );
|
|
ContextInfoW.SizeOfStruct = sizeof(FAX_CONTEXT_INFOW) ;
|
|
|
|
ZeroMemory( &PrintInfoW, sizeof(FAX_PRINT_INFOW) );
|
|
|
|
PrintInfoW.SizeOfStruct = sizeof(FAX_PRINT_INFOW);
|
|
PrintInfoW.DocName = AnsiStringToUnicodeString( PrintInfo->DocName );
|
|
PrintInfoW.RecipientName = AnsiStringToUnicodeString( PrintInfo->RecipientName );
|
|
PrintInfoW.RecipientNumber = AnsiStringToUnicodeString( PrintInfo->RecipientNumber );
|
|
PrintInfoW.SenderName = AnsiStringToUnicodeString( PrintInfo->SenderName );
|
|
PrintInfoW.SenderCompany = AnsiStringToUnicodeString( PrintInfo->SenderCompany );
|
|
PrintInfoW.SenderDept = AnsiStringToUnicodeString( PrintInfo->SenderDept );
|
|
PrintInfoW.SenderBillingCode = AnsiStringToUnicodeString( PrintInfo->SenderBillingCode );
|
|
PrintInfoW.DrProfileName = AnsiStringToUnicodeString( PrintInfo->DrProfileName );
|
|
PrintInfoW.DrEmailAddress = AnsiStringToUnicodeString( PrintInfo->DrEmailAddress );
|
|
PrintInfoW.OutputFileName = AnsiStringToUnicodeString( PrintInfo->OutputFileName );
|
|
|
|
Rval = FaxStartPrintJobW(
|
|
(LPWSTR) PrinterNameW,
|
|
&PrintInfoW,
|
|
JobId,
|
|
&ContextInfoW
|
|
);
|
|
|
|
MemFree( (LPBYTE) PrinterNameW );
|
|
MemFree( (LPBYTE) PrintInfoW.DocName );
|
|
MemFree( (LPBYTE) PrintInfoW.RecipientName );
|
|
MemFree( (LPBYTE) PrintInfoW.RecipientNumber );
|
|
MemFree( (LPBYTE) PrintInfoW.SenderName );
|
|
MemFree( (LPBYTE) PrintInfoW.SenderCompany );
|
|
MemFree( (LPBYTE) PrintInfoW.SenderDept );
|
|
MemFree( (LPBYTE) PrintInfoW.SenderBillingCode );
|
|
|
|
ServerName = UnicodeStringToAnsiString( ContextInfoW.ServerName);
|
|
if (ServerName) {
|
|
strcpy(FaxContextInfo->ServerName,ServerName);
|
|
}
|
|
else
|
|
FaxContextInfo->ServerName[0] = 0;
|
|
|
|
FaxContextInfo->SizeOfStruct = sizeof(FAX_CONTEXT_INFOA);
|
|
FaxContextInfo->hDC = ContextInfoW.hDC;
|
|
|
|
MemFree( (LPBYTE) ServerName );
|
|
|
|
return Rval;
|
|
}
|
|
|
|
BOOL
|
|
ValidateCoverpage(
|
|
LPCWSTR CoverPageName,
|
|
LPCWSTR ServerName,
|
|
BOOL ServerCoverpage,
|
|
LPWSTR ResolvedName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine tries to validate that that coverpage specified by the user actually exists where
|
|
they say it does, and that it is indeed a coverpage (or a resolvable link to one)
|
|
|
|
Please see the SDK for documentation on the rules for how server coverpages work, etc.
|
|
Arguments:
|
|
|
|
CoverpageName - contains name of coverpage
|
|
ServerName - name of the server, if any (can be null)
|
|
ServerCoverpage - indicates if this coverpage is on the server, or in the server location for
|
|
coverpages locally
|
|
ResolvedName - a pointer to buffer (should be MAX_PATH large at least) to receive the
|
|
resolved coverpage name. If NULL, then this param is ignored
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if coverpage can be used.
|
|
FALSE if the coverpage is invalid or cannot be used.
|
|
|
|
--*/
|
|
|
|
{
|
|
LPWSTR p;
|
|
DWORD ec = 0;
|
|
WCHAR CpDir[MAX_PATH];
|
|
WCHAR Buffer[MAX_PATH];
|
|
|
|
if (!CoverPageName) {
|
|
ec = ERROR_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
|
|
wcsncpy(CpDir,CoverPageName,MAX_PATH);
|
|
p = wcschr(CpDir, L'\\' );
|
|
if (p) {
|
|
|
|
//
|
|
// the coverpage file name contains a path so just use it.
|
|
//
|
|
|
|
if (GetFileAttributes( CpDir ) == 0xffffffff) {
|
|
ec = ERROR_FILE_NOT_FOUND;
|
|
goto exit;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// the coverpage file name does not contain
|
|
// a path so we must construct a full path name
|
|
//
|
|
|
|
if (ServerCoverpage) {
|
|
if (!ServerName || ServerName[0] == 0)
|
|
ec = GetServerCpDir( NULL, CpDir, sizeof(CpDir) );
|
|
else
|
|
ec = GetServerCpDir( ServerName, CpDir, sizeof(CpDir) );
|
|
} else {
|
|
ec = GetClientCpDir( CpDir, sizeof(CpDir) );
|
|
}
|
|
|
|
if (!ec) {
|
|
ec = ERROR_FILE_NOT_FOUND;
|
|
goto exit;
|
|
}
|
|
|
|
ec = 0;
|
|
ConcatenatePaths(CpDir, CoverPageName);
|
|
|
|
if (wcschr( CpDir, '.' ) == NULL) {
|
|
wcscat( CpDir, CP_FILENAME_EXT );
|
|
}
|
|
|
|
if (GetFileAttributes( CpDir ) == 0xffffffff) {
|
|
p = wcschr( CpDir, '.' );
|
|
if (p) {
|
|
wcscpy( p, CP_SHORTCUT_EXT );
|
|
if (GetFileAttributes( CpDir ) == 0xffffffff) {
|
|
ec = ERROR_FILE_NOT_FOUND;
|
|
goto exit;
|
|
}
|
|
} else {
|
|
ec = ERROR_FILE_NOT_FOUND;
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// if the file is really a shortcut, then resolve it
|
|
//
|
|
|
|
if (IsCoverPageShortcut( CpDir )) {
|
|
if (!ResolveShortcut( CpDir, Buffer )) {
|
|
DebugPrint(( TEXT("Cover page file is really a link, but resolution is not possible") ));
|
|
ec = ERROR_FILE_NOT_FOUND;
|
|
goto exit;
|
|
} else {
|
|
if (ResolvedName) {
|
|
wcscpy(ResolvedName,Buffer);
|
|
}
|
|
}
|
|
} else {
|
|
if (ResolvedName) {
|
|
wcscpy( ResolvedName, CpDir );
|
|
}
|
|
}
|
|
|
|
exit:
|
|
if (ec) {
|
|
SetLastError(ec);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|