1825 lines
48 KiB
C++
1825 lines
48 KiB
C++
/*++
|
|
|
|
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;
|
|
}
|