|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
faxdoc.cpp
Abstract:
This module contains all code necessary to print an exchange message as a fax document.
Author:
Wesley Witt (wesw) 13-Aug-1996
--*/
#include "faxxp.h"
#pragma hdrstop
#ifdef WIN95
#include "mfx.h"
#include "fwprov.h"
#endif
PVOID CXPLogon::MyGetPrinter( LPSTR PrinterName, DWORD Level )
/*++
Routine Description:
Gets the printer data for a specifi printer
Arguments:
PrinterName - Name of the desired printer
Return Value:
Pointer to a printer info structure or NULL for failure.
--*/
{ PVOID PrinterInfo = NULL; HANDLE hPrinter; DWORD Bytes; PRINTER_DEFAULTS PrinterDefaults;
PrinterDefaults.pDatatype = NULL; PrinterDefaults.pDevMode = NULL; PrinterDefaults.DesiredAccess = PRINTER_ACCESS_USE;
if (!OpenPrinter( PrinterName, &hPrinter, &PrinterDefaults )) { goto exit; }
if ((!GetPrinter( hPrinter, Level, NULL, 0, &Bytes )) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) { goto exit; }
PrinterInfo = (LPPRINTER_INFO_2) MemAlloc( Bytes ); if (!PrinterInfo) { goto exit; }
if (!GetPrinter( hPrinter, Level, (LPBYTE) PrinterInfo, Bytes, &Bytes )) { goto exit; }
exit: ClosePrinter( hPrinter ); return PrinterInfo; }
VOID CXPLogon::PrintRichText( HWND hWndRichEdit, HDC hDC, PFAXXP_CONFIG FaxConfig )
/*++
Routine Description:
Prints the rich text contained in a rich text window into a DC.
Arguments:
hWndRichEdit - Window handle for the rich text window hDC - Printer device context
Return Value:
None.
--*/
{ FORMATRANGE fr; LONG lTextOut; LONG lTextAmt; RECT rcTmp;
LPTSTR szText; LPTSTR szChar;
fr.hdc = hDC; fr.hdcTarget = hDC; fr.chrg.cpMin = 0; fr.chrg.cpMax = -1;
//
// Set page rect to phys page size in twips
//
fr.rcPage.top = 0; fr.rcPage.left = 0; fr.rcPage.right = MulDiv(GetDeviceCaps(hDC, PHYSICALWIDTH), 1440, GetDeviceCaps(hDC, LOGPIXELSX)); fr.rcPage.bottom = MulDiv(GetDeviceCaps(hDC, PHYSICALHEIGHT), 1440, GetDeviceCaps(hDC, LOGPIXELSY));
//
// Set up 3/4" horizontal and 1" vertical margins, but leave a minimum of 1"
// printable space in each direction. Otherwise, use full page.
//
fr.rc = fr.rcPage; // start with full page
if (fr.rcPage.right > 2*3*1440/4 + 1440) { fr.rc.right -= (fr.rc.left = 3*1440/4); } if (fr.rcPage.bottom > 3*1440) { fr.rc.bottom -= (fr.rc.top = 1440); }
//
// save the formatting rectangle
//
rcTmp = fr.rc;
SetMapMode( hDC, MM_TEXT );
lTextOut = 0; lTextAmt = (LONG)SendMessage( hWndRichEdit, WM_GETTEXTLENGTH, 0, 0 );
szText = (LPTSTR) MemAlloc((lTextAmt + 1) * sizeof(TCHAR)); if (szText) { SendMessage(hWndRichEdit, WM_GETTEXT, (WPARAM) lTextAmt, (LPARAM) szText);
szChar = szText; while (lTextOut < lTextAmt) { if ((*szChar != ' ') && (*szChar != '\t') && (*szChar != '\r') && (*szChar != '\n')) { break; }
lTextOut++; szChar = CharNext(szChar); }
MemFree(szText);
if (!strlen(szChar)) { lTextAmt = 0; } }
while (lTextOut < lTextAmt) { // Reset margins
fr.rc = rcTmp; StartPage(hDC); lTextOut = (LONG) SendMessage(hWndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr); EndPage(hDC);
fr.chrg.cpMin = lTextOut; fr.chrg.cpMax = -1; }
//
// flush the cache
//
SendMessage(hWndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL); }
extern "C" DWORD CALLBACK EditStreamRead( DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb )
/*++
Routine Description:
Wrapper function for the IStream read method. This function is used to read rich text from an exchange stream.
Arguments:
dwCookie - This pointer for the IStream object pbBuff - Pointer to the data buffer cb - Size of the data buffer pcb - Returned byte count
Return Value:
Return code from IStream::Read
--*/
{ return ((LPSTREAM)dwCookie)->Read( pbBuff, cb, (ULONG*) pcb ); }
BOOL CXPLogon::PrintText( HDC hDC, LPSTREAM lpstmT, PFAXXP_CONFIG FaxConfig )
/*++
Routine Description:
Prints a stream of plain text into the printer DC provided. Note: this code was stolen from notepad.
Arguments:
hDC - Printer DC lpstmT - Stream pointer for rich text. FaxConfig - Fax configuration data
Return Value:
TRUE for success. FALSE for failure.
--*/
{ LPSTR BodyText = NULL; LPSTR lpLine; LPSTR pLineEOL; LPSTR pNextLine; HRESULT hResult; HFONT hFont = NULL; HFONT hPrevFont = NULL; TEXTMETRIC tm; BOOL rVal = TRUE; INT nLinesPerPage; INT dyTop; // width of top border (pixels)
INT dyBottom; // width of bottom border
INT dxLeft; // width of left border
INT dxRight; // width of right border
INT yPrintChar; // height of a character
INT tabSize; // Size of a tab for print device in device units
INT yCurpos = 0; INT xCurpos = 0; INT nPixelsLeft = 0; INT guess = 0; SIZE Size; // to see if text will fit in space left
INT nPrintedLines = 0; BOOL fPageStarted = FALSE; INT iPageNum = 0; INT xPrintRes; // printer resolution in x direction
INT yPrintRes; // printer resolution in y direction
INT yPixInch; // pixels/inch
INT xPixInch; // pixels/inch
INT xPixUnit; // pixels/local measurement unit
INT yPixUnit; // pixels/local measurement unit
BOOL fEnglish; INT Chars; STATSTG Stats; INT PrevBkMode = 0;
hResult = lpstmT->Stat( &Stats, 0 ); if (hResult) { rVal = FALSE; goto exit; }
Chars = (INT) Stats.cbSize.QuadPart; BodyText = (LPSTR) MemAlloc( Chars + 4 ); if (!BodyText) { rVal = FALSE; goto exit; }
hResult = lpstmT->Read( (LPVOID) BodyText, Chars, (LPDWORD) &Chars ); if (hResult) { rVal = FALSE; goto exit; }
lpLine = BodyText;
fEnglish = GetProfileInt( "intl", "iMeasure", 1 );
xPrintRes = GetDeviceCaps( hDC, HORZRES ); yPrintRes = GetDeviceCaps( hDC, VERTRES ); xPixInch = GetDeviceCaps( hDC, LOGPIXELSX ); yPixInch = GetDeviceCaps( hDC, LOGPIXELSY ); //
// compute x and y pixels per local measurement unit
//
if (fEnglish) { xPixUnit= xPixInch; yPixUnit= yPixInch; } else { xPixUnit= CMToInches( xPixInch ); yPixUnit= CMToInches( yPixInch ); }
SetMapMode( hDC, MM_TEXT );
hFont = CreateFontIndirect( &FaxConfig->FontStruct );
hPrevFont = (HFONT) SelectObject( hDC, hFont ); SetBkMode( hDC, TRANSPARENT ); if (!GetTextMetrics( hDC, &tm )) { rVal = FALSE; goto exit; }
yPrintChar = tm.tmHeight + tm.tmExternalLeading; tabSize = tm.tmAveCharWidth * 8;
//
// compute margins in pixels
//
dxLeft = LEFT_MARGIN * xPixUnit; dxRight = RIGHT_MARGIN * xPixUnit; dyTop = TOP_MARGIN * yPixUnit; dyBottom = BOTTOM_MARGIN * yPixUnit;
//
// Number of lines on a page with margins
//
nLinesPerPage = ((yPrintRes - dyTop - dyBottom) / yPrintChar);
while (*lpLine) {
if (*lpLine == '\r') { lpLine += 2; yCurpos += yPrintChar; nPrintedLines++; xCurpos= 0; continue; }
pLineEOL = lpLine; while (*pLineEOL && *pLineEOL != '\r') pLineEOL++;
do { if ((nPrintedLines == 0) && (!fPageStarted)) {
StartPage( hDC ); fPageStarted = TRUE; yCurpos = 0; xCurpos = 0;
}
if (*lpLine == '\t') {
//
// round up to the next tab stop
// if the current position is on the tabstop, goto next one
//
xCurpos = ((xCurpos + tabSize) / tabSize ) * tabSize; lpLine++;
} else {
//
// find end of line or tab
//
pNextLine = lpLine; while ((pNextLine != pLineEOL) && *pNextLine != '\t') pNextLine++;
//
// find out how many characters will fit on line
//
Chars = (INT)(pNextLine - lpLine); nPixelsLeft = xPrintRes - dxRight - dxLeft - xCurpos; GetTextExtentExPoint( hDC, lpLine, Chars, nPixelsLeft, &guess, NULL, &Size );
if (guess) { //
// at least one character fits - print
//
TextOut( hDC, dxLeft+xCurpos, yCurpos+dyTop, lpLine, guess );
xCurpos += Size.cx; // account for printing
lpLine += guess; // printed characters
} else {
//
// no characters fit what's left
// no characters will fit in space left
// if none ever will, just print one
// character to keep progressing through
// input file.
//
if (xCurpos == 0) { if( lpLine != pNextLine ) { //
// print something if not null line
// could use exttextout here to clip
//
TextOut( hDC, dxLeft+xCurpos, yCurpos+dyTop, lpLine, 1 ); lpLine++; } } else { //
// perhaps the next line will get it
//
xCurpos = xPrintRes; // force to next line
} }
//
// move printhead in y-direction
//
if ((xCurpos >= (xPrintRes - dxRight - dxLeft) ) || (lpLine == pLineEOL)) { yCurpos += yPrintChar; nPrintedLines++; xCurpos = 0; }
if (nPrintedLines >= nLinesPerPage) { EndPage( hDC ); fPageStarted = FALSE; nPrintedLines = 0; xCurpos = 0; yCurpos = 0; iPageNum++; }
}
} while( lpLine != pLineEOL );
if (*lpLine == '\r') { lpLine += 1; } if (*lpLine == '\n') { lpLine += 1; }
}
if (fPageStarted) { EndPage( hDC ); }
exit: MemFree( BodyText ); if (hPrevFont) { SelectObject( hDC, hPrevFont ); DeleteObject( hFont ); } if (PrevBkMode) { SetBkMode( hDC, PrevBkMode ); } return rVal; }
DWORD CXPLogon::PrintAttachment( LPSTR FaxPrinterName, LPSTR DocName )
/*++
Routine Description:
Prints a document that is attached to a message
Arguments:
FaxPrinterName - name of the printer to print the attachment on DocName - name of the attachment document
Return Value:
Print job id or zero for failure.
--*/
{ SHELLEXECUTEINFO sei; CHAR Args[MAX_PATH]; CHAR TempDir[MAX_PATH]; HANDLE hMap = NULL; HANDLE hEvent = NULL; HANDLE hMutex = NULL; HANDLE hMutexAttach = NULL; LPDWORD pJobId = NULL; DWORD JobId = 0;
#ifndef WIN95
SECURITY_ATTRIBUTES memsa,mutsa,synsa,eventsa; SECURITY_DESCRIPTOR memsd,mutsd,synsd,eventsd; #endif
//
// serialize access to this function.
// this is necessary because we can't have more than one
// app accessing our shared memory region and mutex
//
hMutexAttach = OpenMutex(MUTEX_ALL_ACCESS,FALSE,FAXRENDER_MUTEX); if (!hMutexAttach) { //
// we need to open this mutex with a NULL dacl so that everyone can access this
//
#ifndef WIN95
synsa.nLength = sizeof(SECURITY_ATTRIBUTES); synsa.bInheritHandle = TRUE; synsa.lpSecurityDescriptor = &synsd;
if(!InitializeSecurityDescriptor(&synsd, SECURITY_DESCRIPTOR_REVISION)) { goto exit; }
if(!SetSecurityDescriptorDacl(&synsd, TRUE, (PACL)NULL, FALSE)) { goto exit; } #endif
hMutexAttach = CreateMutex( #ifndef WIN95
&synsa, #else
NULL, #endif
TRUE, FAXRENDER_MUTEX );
if (!hMutexAttach) { goto exit; } } else { if (WaitForSingleObject( hMutexAttach, 1000* 60 * 5) != WAIT_OBJECT_0) { //
// something went wrong
//
CloseHandle( hMutexAttach ); goto exit; } }
//
// since mapispooler might be running under a different security context,
// we must setup a NULL security descriptor
//
#ifndef WIN95
memsa.nLength = sizeof(SECURITY_ATTRIBUTES); memsa.bInheritHandle = TRUE; memsa.lpSecurityDescriptor = &memsd;
if(!InitializeSecurityDescriptor(&memsd, SECURITY_DESCRIPTOR_REVISION)) { goto exit; }
if(!SetSecurityDescriptorDacl(&memsd, TRUE, (PACL)NULL, FALSE)) { goto exit; }
mutsa.nLength = sizeof(SECURITY_ATTRIBUTES); mutsa.bInheritHandle = TRUE; mutsa.lpSecurityDescriptor = &mutsd;
if(!InitializeSecurityDescriptor(&mutsd, SECURITY_DESCRIPTOR_REVISION)) { goto exit; }
if(!SetSecurityDescriptorDacl(&mutsd, TRUE, (PACL)NULL, FALSE)) { goto exit; }
eventsa.nLength = sizeof(SECURITY_ATTRIBUTES); eventsa.bInheritHandle = TRUE; eventsa.lpSecurityDescriptor = &eventsd;
if(!InitializeSecurityDescriptor(&eventsd, SECURITY_DESCRIPTOR_REVISION)) { goto exit; }
if(!SetSecurityDescriptorDacl(&eventsd, TRUE, (PACL)NULL, FALSE)) { goto exit; } #endif
//
// create the shared memory region for the print jobid
// the jobid is filled in by the fax printer driver
//
hMap = CreateFileMapping( INVALID_HANDLE_VALUE, #ifndef WIN95
&memsa, #else
NULL, #endif
PAGE_READWRITE | SEC_COMMIT, 0, 4096, FAXXP_MEM_NAME ); if (!hMap) { goto exit; }
pJobId = (LPDWORD) MapViewOfFile( hMap, FILE_MAP_WRITE, 0, 0, 0 ); if (!pJobId) { goto exit; }
*pJobId = (DWORD) 0;
//
// get the temp path name and use it for the
// working dir of the launched app
//
GetTempPath( sizeof(TempDir), TempDir );
//
// set the arguments to the app.
// these arguments are either passed on
// the command line with the /pt switch or
// use as variables for substitution in the
// ddeexec value in the registry.
//
// the values are as follows:
// %1 = file name
// %2 = printer name
// %3 = driver name
// %4 = port name
//
// the first argument does not need to be
// supplied in the args array because it is implied,
// shellexecuteex gets it from the lpFile field.
// arguments 3 & 4 are left blank because they
// are win31 artifacts that are not necessary
// any more. each argument must be enclosed
// in double quotes.
//
wsprintf( Args, "\"%s\" \"\" \"\"", FaxPrinterName );
//
// fill in the SHELLEXECUTEINFO structure
//
sei.cbSize = sizeof(sei); sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT; sei.hwnd = NULL; sei.lpVerb = "printto"; sei.lpFile = DocName; sei.lpParameters = Args; sei.lpDirectory = TempDir; sei.nShow = SW_SHOWMINNOACTIVE; sei.hInstApp = NULL; sei.lpIDList = NULL; sei.lpClass = NULL; sei.hkeyClass = NULL; sei.dwHotKey = 0; sei.hIcon = NULL; sei.hProcess = NULL;
//
// create the named mutex for the print driver.
// this is initially unclaimed, and is claimed by the first instance
// of the print driver invoked after this. We do this last in order to
// avoid a situation where we catch the incorrect instance of the print driver
// printing
//
hMutex = CreateMutex( #ifndef WIN95
&mutsa, #else
NULL, #endif
FALSE, FAXXP_MUTEX_NAME ); if (!hMutex) { goto exit; }
//
// create the named event for the print driver.
// this event is signaled when the print driver is finished rendering the document
//
hEvent = CreateEvent( #ifndef WIN95
&eventsa, #else
NULL, #endif
FALSE, FALSE, FAXXP_EVENT_NAME ); if (!hEvent) { goto exit; }
//
// launch the app
//
if (!ShellExecuteEx( &sei )) { goto exit; }
//
// wait for the print driver to finish rendering the document
//
if (WaitForSingleObject( hEvent, 1000 * 60 * 5 ) != WAIT_OBJECT_0) { //
// something went wrong...
//
goto exit; }
//
// wait for the print driver to exit so we can get the document
//
if (WaitForSingleObject( hMutex, 1000 * 60 * 5) != WAIT_OBJECT_0) { //
// something went wrong
//
goto exit; }
ReleaseMutex(hMutex);
//
// save the print jobid
//
JobId = *pJobId;
exit: //
// clean up and leave...
//
if (sei.hProcess) CloseHandle( sei.hProcess ); if (hEvent) CloseHandle( hEvent ); if (hMutex) CloseHandle( hMutex ); if (pJobId) UnmapViewOfFile( pJobId ); if (hMap) CloseHandle( hMap );
if (hMutexAttach) { ReleaseMutex( hMutexAttach ); CloseHandle( hMutexAttach ); }
return JobId; }
DWORD CXPLogon::SendFaxDocument( LPMESSAGE pMsgObj, LPSTREAM lpstmT, BOOL UseRichText, LPSPropValue pMsgProps, LPSPropValue pRecipProps )
/*++
Routine Description:
Prints an exchange message to the fax printer.
Arguments:
lpstmT - Stream pointer for rich text. pMsgProps - Message properties. pRecipProps - Recipient properties.
Return Value:
Zero for success, otherwise error code.
--*/
{ PPRINTER_INFO_2 PrinterInfo = NULL; PRINTER_DEFAULTS PrinterDefaults; HANDLE hPrinter = NULL; HDC hDC = NULL; INT JobId; DWORD Bytes; DWORD ec; DWORD rVal = 0; HRESULT hResult; LPSTREAM lpstm = NULL; EDITSTREAM es = {0}; HWND hWndRichEdit = NULL; LPPROFSECT pProfileObj = NULL; ULONG PropCount = 0; ULONG PropMsgCount = 0; LPSPropValue pPropsAttachTable = NULL; LPSPropValue pPropsAttach = NULL; LPSPropValue pProps = NULL; LPSPropValue pPropsMsg = NULL; FAXXP_CONFIG FaxConfig = {0}; DWORD JobIdAttachment = 0; INT i = 0; LPMAPITABLE AttachmentTable = NULL; LPSRowSet pAttachmentRows = NULL; LPATTACH lpAttach = NULL; LPSTREAM lpstmA = NULL; LPSTR AttachFileName = NULL; CHAR TempPath[MAX_PATH]; CHAR TempFile[MAX_PATH]; CHAR DocFile[MAX_PATH]; HANDLE hFile = INVALID_HANDLE_VALUE; LPSTR DocType = NULL; DWORD LastJobId = 0; PJOB_INFO_1 JobInfo1 = NULL; JOB_INFO_3 JobInfo3; LPSTR p; DWORD Pages = 0; BOOL DeleteAttachFile; LPSTR FileName = NULL; BOOL AllAttachmentsGood = TRUE; MAPINAMEID NameIds[NUM_FAX_MSG_PROPS]; MAPINAMEID *pNameIds[NUM_FAX_MSG_PROPS] = {&NameIds[0], &NameIds[1], &NameIds[2], &NameIds[3]}; LPSPropTagArray MsgPropTags = NULL; LARGE_INTEGER BigZero = {0}; CHAR FullName[128]; HKEY hKey; DWORD RegSize; DWORD RegType; DWORD CountPrinters; #ifdef WIN95
LCID LocaleId; LPSTR lpszBuffer; DWORD BytesWrite; HINSTANCE hinstFwProv; PFWSPJ pfnStartPrintJob; #else
USER_INFO UserInfo = {0}; FAX_PRINT_INFOA FaxPrintInfo = {0}; FAX_CONTEXT_INFO ContextInfo = {0}; FAX_COVERPAGE_INFOA FaxCpInfo = {0};
// char szCoverPageName[MAX_PATH];
#endif // WIN95
//
// get the fax config properties
//
hResult = m_pSupObj->OpenProfileSection( &FaxGuid, MAPI_MODIFY, &pProfileObj ); if (HR_FAILED (hResult)) { rVal = IDS_CANT_ACCESS_PROFILE; goto exit; }
hResult = pProfileObj->GetProps( (LPSPropTagArray) &sptFaxProps, 0, &PropCount, &pProps ); if (FAILED(hResult)) { rVal = IDS_CANT_ACCESS_PROFILE; goto exit; }
FaxConfig.PrinterName = StringDup( pProps[PROP_FAX_PRINTER_NAME].Value.LPSZ ); FaxConfig.CoverPageName = StringDup( pProps[PROP_COVERPAGE_NAME].Value.LPSZ ); FaxConfig.UseCoverPage = pProps[PROP_USE_COVERPAGE].Value.ul; FaxConfig.ServerCoverPage = pProps[PROP_SERVER_COVERPAGE].Value.ul; CopyMemory( &FaxConfig.FontStruct, pProps[PROP_FONT].Value.bin.lpb, pProps[PROP_FONT].Value.bin.cb );
//
// now get the message properties
//
NameIds[MSGPI_FAX_PRINTER_NAME].lpguid = (LPGUID)&PS_PUBLIC_STRINGS; NameIds[MSGPI_FAX_PRINTER_NAME].ulKind = MNID_STRING; NameIds[MSGPI_FAX_PRINTER_NAME].Kind.lpwstrName = MSGPS_FAX_PRINTER_NAME;
NameIds[MSGPI_FAX_COVERPAGE_NAME].lpguid = (LPGUID)&PS_PUBLIC_STRINGS; NameIds[MSGPI_FAX_COVERPAGE_NAME].ulKind = MNID_STRING; NameIds[MSGPI_FAX_COVERPAGE_NAME].Kind.lpwstrName = MSGPS_FAX_COVERPAGE_NAME;
NameIds[MSGPI_FAX_USE_COVERPAGE].lpguid = (LPGUID)&PS_PUBLIC_STRINGS; NameIds[MSGPI_FAX_USE_COVERPAGE].ulKind = MNID_STRING; NameIds[MSGPI_FAX_USE_COVERPAGE].Kind.lpwstrName = MSGPS_FAX_USE_COVERPAGE;
NameIds[MSGPI_FAX_SERVER_COVERPAGE].lpguid = (LPGUID)&PS_PUBLIC_STRINGS; NameIds[MSGPI_FAX_SERVER_COVERPAGE].ulKind = MNID_STRING; NameIds[MSGPI_FAX_SERVER_COVERPAGE].Kind.lpwstrName = MSGPS_FAX_SERVER_COVERPAGE;
hResult = pMsgObj->GetIDsFromNames( NUM_FAX_MSG_PROPS, pNameIds, MAPI_CREATE, &MsgPropTags ); if (FAILED(hResult)) { rVal = IDS_CANT_ACCESS_PROFILE; goto exit; }
MsgPropTags->aulPropTag[MSGPI_FAX_PRINTER_NAME] = PROP_TAG( PT_TSTRING, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_PRINTER_NAME]) ); MsgPropTags->aulPropTag[MSGPI_FAX_COVERPAGE_NAME] = PROP_TAG( PT_TSTRING, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_COVERPAGE_NAME]) ); MsgPropTags->aulPropTag[MSGPI_FAX_USE_COVERPAGE] = PROP_TAG( PT_LONG, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_USE_COVERPAGE]) ); MsgPropTags->aulPropTag[MSGPI_FAX_SERVER_COVERPAGE] = PROP_TAG( PT_LONG, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_SERVER_COVERPAGE]) );
hResult = pMsgObj->GetProps( MsgPropTags, 0, &PropMsgCount, &pPropsMsg ); if (FAILED(hResult)) { rVal = IDS_CANT_ACCESS_PROFILE; goto exit; }
if (PROP_TYPE(pPropsMsg[MSGPI_FAX_PRINTER_NAME].ulPropTag) != PT_ERROR) { MemFree( FaxConfig.PrinterName ); FaxConfig.PrinterName = StringDup( pPropsMsg[MSGPI_FAX_PRINTER_NAME].Value.LPSZ ); }
if (PROP_TYPE(pPropsMsg[MSGPI_FAX_COVERPAGE_NAME].ulPropTag) != PT_ERROR) { MemFree( FaxConfig.CoverPageName ); FaxConfig.CoverPageName = StringDup( pPropsMsg[MSGPI_FAX_COVERPAGE_NAME].Value.LPSZ ); }
if (PROP_TYPE(pPropsMsg[MSGPI_FAX_USE_COVERPAGE].ulPropTag) != PT_ERROR) { FaxConfig.UseCoverPage = pPropsMsg[MSGPI_FAX_USE_COVERPAGE].Value.ul; }
if (PROP_TYPE(pPropsMsg[MSGPI_FAX_SERVER_COVERPAGE].ulPropTag) != PT_ERROR) { FaxConfig.ServerCoverPage = pPropsMsg[MSGPI_FAX_SERVER_COVERPAGE].Value.ul; }
//
// open the printer
//
PrinterInfo = (PPRINTER_INFO_2) MyGetPrinter( FaxConfig.PrinterName, 2 ); if (!PrinterInfo) { PrinterInfo = (PPRINTER_INFO_2) MyEnumPrinters( NULL, 2, &CountPrinters, PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS ); if (PrinterInfo) { for (i=0; i<(int)CountPrinters; i++) { if (strcmp( PrinterInfo[i].pDriverName, FAX_DRIVER_NAME ) == 0) { break; } } } else { CountPrinters = i = 0; } if (i == (int)CountPrinters) { rVal = IDS_NO_FAX_PRINTER; goto exit; }
MemFree( FaxConfig.PrinterName ); FaxConfig.PrinterName = StringDup( PrinterInfo[i].pPrinterName ); MemFree( PrinterInfo ); PrinterInfo = (PPRINTER_INFO_2) MyGetPrinter( FaxConfig.PrinterName, 2 ); if (!PrinterInfo) { rVal = IDS_CANT_ACCESS_PROFILE; goto exit; } }
PrinterDefaults.pDatatype = NULL; PrinterDefaults.pDevMode = NULL; PrinterDefaults.DesiredAccess = PRINTER_ACCESS_USE;
if (!OpenPrinter( FaxConfig.PrinterName, &hPrinter, &PrinterDefaults )) { rVal = IDS_CANT_ACCESS_PRINTER; goto exit; }
//
// get the attachment table, if it is available
//
hResult = pMsgObj->GetAttachmentTable( 0, &AttachmentTable ); if (HR_SUCCEEDED(hResult)) { hResult = HrAddColumns( AttachmentTable, (LPSPropTagArray) &sptAttachTableProps, gpfnAllocateBuffer, gpfnFreeBuffer ); if (HR_SUCCEEDED(hResult)) { hResult = HrQueryAllRows( AttachmentTable, NULL, NULL, NULL, 0, &pAttachmentRows ); if (FAILED(hResult)) { pAttachmentRows = NULL; } else { if (pAttachmentRows->cRows == 0) { MemFree( pAttachmentRows ); pAttachmentRows = NULL; } } } }
if (pAttachmentRows) {
//
// this loop verifies that each document's attachment registration
// supports the printto verb.
//
AllAttachmentsGood = TRUE;
for (i=pAttachmentRows->cRows-1; i>=0; i--) {
pPropsAttachTable = pAttachmentRows->aRow[i].lpProps; lpAttach = NULL; pPropsAttach = NULL;
if (pPropsAttachTable[MSG_ATTACH_METHOD].Value.ul == NO_ATTACHMENT) { goto next_attachment1; }
//
// open the attachment
//
hResult = pMsgObj->OpenAttach( pPropsAttachTable[MSG_ATTACH_NUM].Value.ul, NULL, MAPI_BEST_ACCESS, &lpAttach ); if (FAILED(hResult)) { AllAttachmentsGood = FALSE; goto next_attachment1; }
//
// get the attachment properties
//
hResult = lpAttach->GetProps( (LPSPropTagArray) &sptAttachProps, 0, &PropCount, &pPropsAttach ); if (FAILED(hResult)) { AllAttachmentsGood = FALSE; goto next_attachment1; }
//
// try to get the extension if the file.
// this indicates what type of dicument it is.
// if we cannot get the document type then it is
// impossible to print the document.
//
if (DocType) { MemFree( DocType ); DocType = NULL; }
if (PROP_TYPE(pPropsAttach[MSG_ATTACH_EXTENSION].ulPropTag) == PT_ERROR) { if (PROP_TYPE(pPropsAttach[MSG_ATTACH_LFILENAME].ulPropTag) != PT_ERROR) { p = strchr( pPropsAttach[MSG_ATTACH_LFILENAME].Value.LPSZ, '.' ); if (p) { DocType = StringDup( p ); } } else if (PROP_TYPE(pPropsAttach[MSG_ATTACH_FILENAME].ulPropTag) != PT_ERROR) { p = strchr( pPropsAttach[MSG_ATTACH_FILENAME].Value.LPSZ, '.' ); if (p) { DocType = StringDup( p ); } }
} else { DocType = StringDup( pPropsAttach[MSG_ATTACH_EXTENSION].Value.LPSZ ); }
if (!DocType) { AllAttachmentsGood = FALSE; goto next_attachment1; }
Bytes = sizeof(TempFile); rVal = RegQueryValue( HKEY_CLASSES_ROOT, DocType, TempFile, (PLONG) &Bytes ); if ((rVal != ERROR_SUCCESS) && (rVal != ERROR_INVALID_DATA)) { AllAttachmentsGood = FALSE; goto next_attachment1; }
wsprintf( TempPath, "%s\\shell\\printto\\command", TempFile );
Bytes = sizeof(TempFile); rVal = RegQueryValue( HKEY_CLASSES_ROOT, TempPath, TempFile, (PLONG) &Bytes ); if ((rVal != ERROR_SUCCESS) && (rVal != ERROR_INVALID_DATA)) { AllAttachmentsGood = FALSE; goto next_attachment1; } next_attachment1:
if (lpAttach) { lpAttach->Release(); }
if (pPropsAttach) { MemFree( pPropsAttach ); }
}
if (!AllAttachmentsGood) { rVal = IDS_BAD_ATTACHMENTS; goto exit; }
for (i=pAttachmentRows->cRows-1; i>=0; i--) {
pPropsAttachTable = pAttachmentRows->aRow[i].lpProps; lpAttach = NULL; pPropsAttach = NULL;
if (pPropsAttachTable[MSG_ATTACH_METHOD].Value.ul == NO_ATTACHMENT) { goto next_attachment2; }
//
// open the attachment
//
hResult = pMsgObj->OpenAttach( pPropsAttachTable[MSG_ATTACH_NUM].Value.ul, NULL, MAPI_BEST_ACCESS, &lpAttach ); if (FAILED(hResult)) { goto next_attachment2; }
//
// get the attachment properties
//
hResult = lpAttach->GetProps( (LPSPropTagArray) &sptAttachProps, 0, &PropCount, &pPropsAttach ); if (FAILED(hResult)) { goto next_attachment2; }
//
// try to get the extension if the file.
// this indicates what type of dicument it is.
// if we cannot get the document type then it is
// impossible to print the document.
//
if (DocType) { MemFree( DocType ); DocType = NULL; }
if (PROP_TYPE(pPropsAttach[MSG_ATTACH_EXTENSION].ulPropTag) == PT_ERROR) { if (PROP_TYPE(pPropsAttach[MSG_ATTACH_LFILENAME].ulPropTag) != PT_ERROR) { p = strchr( pPropsAttach[MSG_ATTACH_LFILENAME].Value.LPSZ, '.' ); if (p) { DocType = StringDup( p ); } } else if (PROP_TYPE(pPropsAttach[MSG_ATTACH_FILENAME].ulPropTag) != PT_ERROR) { p = strchr( pPropsAttach[MSG_ATTACH_FILENAME].Value.LPSZ, '.' ); if (p) { DocType = StringDup( p ); } } } else { DocType = StringDup( pPropsAttach[MSG_ATTACH_EXTENSION].Value.LPSZ ); }
if (!DocType) { goto next_attachment2; }
lpstmA = NULL; AttachFileName = NULL; DeleteAttachFile = FALSE;
//
// get the attached file name so that we can resolve any links
//
if (PROP_TYPE(pPropsAttach[MSG_ATTACH_PATHNAME].ulPropTag) != PT_ERROR) { FileName = pPropsAttach[MSG_ATTACH_PATHNAME].Value.LPSZ; } else { FileName = NULL; }
if (_stricmp( DocType, LNK_FILENAME_EXT ) == 0) { if (!FileName) { goto next_attachment2; } if (ResolveShortcut( FileName, DocFile )) { p = strchr( DocFile, '.' ); if (p) { MemFree( DocType ); DocType = StringDup( p ); AttachFileName = StringDup( DocFile ); } } } else if (FileName) { AttachFileName = StringDup( FileName ); }
//
// get the stream object
//
switch( pPropsAttach[MSG_ATTACH_METHOD].Value.ul ) {
case ATTACH_BY_VALUE: hResult = lpAttach->OpenProperty( PR_ATTACH_DATA_BIN, &IID_IStream, 0, 0, (LPUNKNOWN*) &lpstmA ); if (FAILED(hResult)) { goto next_attachment2; } break;
case ATTACH_EMBEDDED_MSG: case ATTACH_OLE: hResult = lpAttach->OpenProperty( PR_ATTACH_DATA_OBJ, &IID_IStreamDocfile, 0, 0, (LPUNKNOWN*) &lpstmA ); if (FAILED(hResult)) { hResult = lpAttach->OpenProperty( PR_ATTACH_DATA_BIN, &IID_IStreamDocfile, 0, 0, (LPUNKNOWN*) &lpstmA ); if (FAILED(hResult)) { hResult = lpAttach->OpenProperty( PR_ATTACH_DATA_OBJ, &IID_IStorage, 0, 0, (LPUNKNOWN*) &lpstmA ); if (FAILED(hResult)) { goto next_attachment2; } } } break;
}
if (lpstmA) {
GetTempPath( sizeof(TempPath), TempPath ); GetTempFileName( TempPath, "Fax", 0, TempFile ); hFile = CreateFile( TempFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL ); if (hFile != INVALID_HANDLE_VALUE) {
#define BLOCK_SIZE (64*1024)
LPBYTE StrmData; DWORD Bytes; DWORD BytesWrite;
StrmData = (LPBYTE) MemAlloc( BLOCK_SIZE );
do {
hResult = lpstmA->Read( StrmData, BLOCK_SIZE, &Bytes ); if (FAILED(hResult)) { break; }
WriteFile( hFile, StrmData, Bytes, &BytesWrite, NULL );
} while (Bytes == BLOCK_SIZE);
CloseHandle( hFile ); MemFree( StrmData );
if (AttachFileName) { MemFree( AttachFileName ); }
strcpy( DocFile, TempFile ); p = strchr( DocFile, '.' ); if (p) { strcpy( p, DocType ); MoveFile( TempFile, DocFile ); AttachFileName = StringDup( DocFile ); } else { AttachFileName = StringDup( TempFile ); }
DeleteAttachFile = TRUE;
}
lpstmA->Release();
}
if (AttachFileName) {
//
// print the attachment
//
JobIdAttachment = PrintAttachment( FaxConfig.PrinterName, AttachFileName ); if (JobIdAttachment) {
GetJob( hPrinter, JobIdAttachment, 1, NULL, 0, &Bytes ); JobInfo1 = (PJOB_INFO_1) MemAlloc( Bytes ); if (JobInfo1) { if (GetJob( hPrinter, JobIdAttachment, 1, (LPBYTE) JobInfo1, Bytes, &Bytes )) { Pages += JobInfo1->TotalPages; } MemFree( JobInfo1 ); }
if (LastJobId) { JobInfo3.JobId = JobIdAttachment; JobInfo3.NextJobId = LastJobId; JobInfo3.Reserved = 0; SetJob( hPrinter, JobIdAttachment, 3, (PBYTE) &JobInfo3, 0 ); SetJob( hPrinter, LastJobId, 0, NULL, JOB_CONTROL_RESUME ); }
LastJobId = JobIdAttachment; }
if (DeleteAttachFile) { DeleteFile( AttachFileName ); }
MemFree( AttachFileName );
} next_attachment2:
if (lpAttach) { lpAttach->Release(); }
if (pPropsAttach) { MemFree( pPropsAttach ); }
}
}
FullName[0] = 0;
ec = RegOpenKey( HKEY_CURRENT_USER, REGKEY_FAX_USERINFO, &hKey ); if (ec == ERROR_SUCCESS) {
RegSize = sizeof(FullName);
ec = RegQueryValueEx( hKey, REGVAL_FULLNAME, 0, &RegType, (LPBYTE) FullName, &RegSize );
RegCloseKey( hKey ); }
#ifdef WIN95
JobId = 0xffffffff;
//
// allocate FaxInfo structure
//
FaxInfo Fax_Info; memset( &Fax_Info, 0, sizeof(FaxInfo) );
//
// provide recipient-specific information
//
strncpy( Fax_Info.Recipients[0].szName, pRecipProps[RECIP_NAME].Value.lpszA, NAME_LEN + 1 );
strncpy( Fax_Info.Recipients[0].szFaxNumber, pRecipProps[RECIP_EMAIL_ADR].Value.lpszA, PHONE_NUMBER_LEN );
Fax_Info.nRecipientCount = 1;
//
// provide cover page information
//
Fax_Info.bSendCoverPage = FaxConfig.UseCoverPage;
if (Fax_Info.bSendCoverPage) { Fax_Info.bLocalCoverPage = ! FaxConfig.ServerCoverPage; strncpy( Fax_Info.szCoverPage, FaxConfig.CoverPageName, MAX_PATH ); strcat( Fax_Info.szCoverPage, ".cov" ); }
strncpy( Fax_Info.szSubject, pMsgProps[MSG_SUBJECT].Value.lpszA, SUBJECT_LEN+1 );
//
// formatted date/time
//
LocaleId = LOCALE_USER_DEFAULT; lpszBuffer = Fax_Info.szTimeSent; Bytes = sizeof( Fax_Info.szTimeSent ); BytesWrite = GetDateFormat( LocaleId, 0x0000, NULL, NULL, lpszBuffer, Bytes );
if (BytesWrite == 0) { rVal = GetLastError(); goto exit; } else if (BytesWrite >= Bytes) { rVal = ERROR_INSUFFICIENT_BUFFER; goto exit; } else { Bytes -= BytesWrite; }
strcat( lpszBuffer, " " ); Bytes -= 1; lpszBuffer = &lpszBuffer[strlen(lpszBuffer)];
if (Bytes == 0) { rVal = ERROR_INSUFFICIENT_BUFFER; goto exit; }
BytesWrite = GetTimeFormat( LocaleId, 0x0000, NULL, NULL, lpszBuffer, Bytes );
if (BytesWrite == 0) { rVal = GetLastError(); goto exit; } else if ( BytesWrite >= Bytes ) { rVal = ERROR_INSUFFICIENT_BUFFER; goto exit; }
//
// Get system code page and other sender info not grabbed from the INI file
//
Fax_Info.CodePage = GetACP();
//
// provide sender-specific information to fax driver
//
hinstFwProv = LoadLibrary( "fwprov.dll" );
if (!hinstFwProv) { rVal = GetLastError(); goto exit; }
//
// initiate fax print job
//
pfnStartPrintJob = (PFWSPJ)GetProcAddress( hinstFwProv, "fwStartPrintJob" );
if (!pfnStartPrintJob) { rVal = GetLastError(); goto exit; }
if (!pfnStartPrintJob( FaxConfig.PrinterName, &Fax_Info, (PDWORD)&JobId, &hDC )) { rVal = GetLastError(); goto exit; }
//
// done with fwprov.dll
//
if (hinstFwProv) { FreeLibrary( hinstFwProv ); }
#else
GetUserInfo( FaxConfig.PrinterName, &UserInfo );
TCHAR DocName[64]; LoadString(FaxXphInstance,IDS_FAX_MESSAGE,DocName,sizeof(DocName)/sizeof(TCHAR));
FaxPrintInfo.SizeOfStruct = sizeof(FAX_PRINT_INFOA); FaxPrintInfo.DocName = DocName; FaxPrintInfo.RecipientName = pRecipProps[RECIP_NAME].Value.lpszA; FaxPrintInfo.RecipientNumber = pRecipProps[RECIP_EMAIL_ADR].Value.lpszA; FaxPrintInfo.SenderName = FullName; FaxPrintInfo.SenderCompany = UserInfo.Company; FaxPrintInfo.SenderDept = UserInfo.Dept; FaxPrintInfo.SenderBillingCode = UserInfo.BillingCode; JobId = 0xffffffff;
if (PrinterInfo->Attributes & PRINTER_ATTRIBUTE_LOCAL) { FaxPrintInfo.DrProfileName = m_ProfileName; FaxPrintInfo.DrEmailAddress = NULL; } else { FaxPrintInfo.DrEmailAddress = m_ProfileName; FaxPrintInfo.DrProfileName = NULL; }
ContextInfo.SizeOfStruct = sizeof(FAX_CONTEXT_INFOW);
ec = FaxStartPrintJob( FaxConfig.PrinterName, &FaxPrintInfo, (LPDWORD) &JobId, &ContextInfo ); if (!ec) { rVal= GetLastError(); goto exit; }
if (FaxConfig.UseCoverPage) {
FaxCpInfo.SizeOfStruct = sizeof(FAX_COVERPAGE_INFOA); FaxCpInfo.CoverPageName = FaxConfig.CoverPageName; FaxCpInfo.UseServerCoverPage = FaxConfig.ServerCoverPage; FaxCpInfo.RecName = pRecipProps[RECIP_NAME].Value.lpszA; FaxCpInfo.RecFaxNumber = pRecipProps[RECIP_EMAIL_ADR].Value.lpszA; FaxCpInfo.Subject = pMsgProps[MSG_SUBJECT].Value.lpszA; FaxCpInfo.Note = NULL; FaxCpInfo.PageCount = Pages + 2;
GetLocalTime( &FaxCpInfo.TimeSent );
ec = FaxPrintCoverPage( &ContextInfo, &FaxCpInfo ); if (!ec) { rVal= GetLastError(); goto exit; } } else if (strlen(pMsgProps[MSG_SUBJECT].Value.lpszA) && !lpstmT) { //
// HACK: try to use the "basenote.cov" coverpage so that we at least print something.
// if they just entered in a subject but no note, then nothing will be printed
//
TCHAR CoverpageName[MAX_PATH]; ExpandEnvironmentStrings(TEXT("%systemroot%\\system32\\basenote.cov"),CoverpageName,sizeof(CoverpageName)); FaxCpInfo.SizeOfStruct = sizeof(FAX_COVERPAGE_INFOA); FaxCpInfo.CoverPageName = CoverpageName; FaxCpInfo.UseServerCoverPage = FALSE; FaxCpInfo.RecName = pRecipProps[RECIP_NAME].Value.lpszA; FaxCpInfo.RecFaxNumber = pRecipProps[RECIP_EMAIL_ADR].Value.lpszA; FaxCpInfo.Subject = pMsgProps[MSG_SUBJECT].Value.lpszA; FaxCpInfo.Note = NULL; FaxCpInfo.PageCount = Pages + 2;
GetLocalTime( &FaxCpInfo.TimeSent );
ec = FaxPrintCoverPage( &ContextInfo, &FaxCpInfo ); //
// don't bail if this fails, it's a hack anyway
//
/*if (!ec) {
rVal= GetLastError(); goto exit; } */ } #endif
if (lpstmT) {
//
// position the stream to the beginning
//
hResult = lpstmT->Seek( BigZero, STREAM_SEEK_SET, NULL ); if (HR_FAILED (hResult)) { rVal = IDS_CANT_ACCESS_MSG_DATA; goto exit; }
if (UseRichText) {
hResult = WrapCompressedRTFStream( lpstmT, 0, &lpstm ); if (HR_FAILED (hResult)) { rVal = IDS_CANT_ACCESS_MSG_DATA; goto exit; }
//
// print the document
//
hWndRichEdit = CreateWindowEx( WS_OVERLAPPED, "RICHEDIT", "", ES_MULTILINE, 0, 0, 0, 0, NULL, NULL, FaxXphInstance, NULL ); if (!hWndRichEdit) { ec = GetLastError(); rVal = IDS_CANT_ACCESS_MSG_DATA; goto exit; }
es.pfnCallback = EditStreamRead; es.dwCookie = (DWORD_PTR) lpstm;
SendMessage( hWndRichEdit, EM_STREAMIN, SF_RTF | SFF_SELECTION | SFF_PLAINRTF, (LPARAM) &es );
if (es.dwError) { ec = es.dwError; rVal = IDS_CANT_ACCESS_MSG_DATA; goto exit; }
#ifdef WIN95
PrintRichText( hWndRichEdit, hDC, &FaxConfig ); #else
PrintRichText( hWndRichEdit, ContextInfo.hDC, &FaxConfig ); #endif
} else {
#ifdef WIN95
PrintText( hDC, lpstmT, &FaxConfig ); #else
PrintText( ContextInfo.hDC, lpstmT, &FaxConfig ); #endif
} }
if (LastJobId) { //
// chain the main body job to the first
// attachment job and resume the attachment job
//
JobInfo3.JobId = JobId; JobInfo3.NextJobId = LastJobId; JobInfo3.Reserved = 0;
if (!SetJob( hPrinter, JobId, 3, (PBYTE) &JobInfo3, 0 )) { DebugPrint(( "SetJob() failed, ec=%d", GetLastError() )); }
if (!SetJob( hPrinter, LastJobId, 0, NULL, JOB_CONTROL_RESUME )) { DebugPrint(( "SetJob() failed, ec=%d", GetLastError() )); }
//
// update the page count
//
GetJob( hPrinter, JobId, 1, NULL, 0, &Bytes ); JobInfo1 = (PJOB_INFO_1) MemAlloc( Bytes ); if (JobInfo1) { JobInfo1->TotalPages += Pages; if (!SetJob( hPrinter, JobId, 1, (PBYTE) JobInfo1, 0 )) { DebugPrint(( "SetJob() failed, ec=%d", GetLastError() )); } MemFree( JobInfo1 ); } }
rVal = 0;
exit: if (pProfileObj) { pProfileObj->Release(); } if (pProps) { MemFree( pProps ); } if (MsgPropTags) { MemFree( MsgPropTags ); } if (pPropsMsg) { MemFree( pPropsMsg ); } if (pAttachmentRows) { MemFree( pAttachmentRows ); } if (AttachmentTable) { AttachmentTable->Release(); } if (lpstm) { lpstm->Release(); } #ifdef WIN95
if (hDC) { EndDoc( hDC ); SetJob( hPrinter, JobId, 0, NULL, JOB_CONTROL_RESUME ); DeleteDC( hDC ); } #else
if (ContextInfo.hDC) { EndDoc( ContextInfo.hDC ); SetJob( hPrinter, JobId, 0, NULL, JOB_CONTROL_RESUME ); DeleteDC( ContextInfo.hDC ); } #endif
if (hPrinter) { ClosePrinter( hPrinter ); } if (hWndRichEdit) { DestroyWindow( hWndRichEdit ); } if (PrinterInfo) { MemFree( PrinterInfo ); } if (FaxConfig.PrinterName) { MemFree( FaxConfig.PrinterName ); } if (FaxConfig.CoverPageName) { MemFree( FaxConfig.CoverPageName ); } if (DocType) { MemFree( DocType ); } return rVal; }
|