480 lines
13 KiB
C++
480 lines
13 KiB
C++
// Print.cpp - Functions to handle MSInfo printing of the text report.
|
|
//
|
|
// Copyright (c) 1998-1999 Microsoft Corporation
|
|
|
|
#include "stdafx.h"
|
|
#include "DataSrc.h"
|
|
#include "Resource.h"
|
|
#include "DataObj.h"
|
|
#include "CompData.h"
|
|
#include <afxext.h>
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/*
|
|
* PreparePrintDialog - Do all initialization required before the print
|
|
* dialog is displayed, most notably calculating the page count.
|
|
*
|
|
* History: a-jsari 3/17/98 Initial version
|
|
*/
|
|
|
|
BOOL CDataSource::RefreshPrintData(CPrintDialog * pdlgPrint, CFolder * pfolSelection)
|
|
{
|
|
// FIX: Make calculation of line length device independent.
|
|
|
|
LPTSTR szLine;
|
|
int cLength = 84;
|
|
int cLineCount = 57;
|
|
unsigned short cPage = 0;
|
|
CFolder * pPrintRoot = NULL;
|
|
|
|
if (pdlgPrint->PrintSelection() && pfolSelection)
|
|
pPrintRoot = pfolSelection;
|
|
else
|
|
pPrintRoot = GetRootNode();
|
|
|
|
if (m_pPrintContent != NULL)
|
|
delete m_pPrintContent;
|
|
m_pPrintContent = new CMSInfoMemoryFile();
|
|
ASSERT(m_pPrintContent != NULL);
|
|
if (m_pPrintContent == NULL)
|
|
::AfxThrowMemoryException();
|
|
|
|
if (m_pPrintInfo != NULL) {
|
|
// Set this pointer to NULL so it doesn't delete the
|
|
// pointer we're storing internally.
|
|
m_pPrintInfo->m_pPD = NULL;
|
|
// This prevents the delete below from asserting.
|
|
m_pPrintInfo->m_strPageDesc = _T("");
|
|
delete m_pPrintInfo;
|
|
m_pPrintInfo = NULL;
|
|
}
|
|
|
|
m_pPrintInfo = new CPrintInfo;
|
|
ASSERT(m_pPrintInfo != NULL);
|
|
if (m_pPrintInfo == NULL) {
|
|
delete m_pPrintContent;
|
|
m_pPrintContent = NULL;
|
|
::AfxThrowMemoryException();
|
|
}
|
|
|
|
m_pPrintInfo->m_nCurPage = 0;
|
|
m_pPrintInfo->m_pPD = pdlgPrint;
|
|
if (FAILED(WriteOutput(m_pPrintContent, pPrintRoot)))
|
|
return FALSE;
|
|
m_pPrintContent->SeekToBegin();
|
|
szLine = new TCHAR[cLength + 1];
|
|
m_fEndOfFile = FALSE;
|
|
while (!m_fEndOfFile) {
|
|
int iLine = cLineCount;
|
|
++cPage;
|
|
while (iLine--) {
|
|
GetLine(szLine, cLength);
|
|
if (m_fEndOfFile)
|
|
goto WhileEnd;
|
|
}
|
|
}
|
|
WhileEnd:
|
|
delete [] szLine;
|
|
|
|
pdlgPrint->m_pd.nMaxPage = cPage;
|
|
if (pdlgPrint->m_pd.nToPage > pdlgPrint->m_pd.nMaxPage)
|
|
pdlgPrint->m_pd.nToPage = pdlgPrint->m_pd.nMaxPage;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* PrintReport - Send the report data to the printer.
|
|
*
|
|
* History: a-jsari 12/9/97 Initial version.
|
|
*/
|
|
BOOL CDataSource::PrintReport(CPrintDialog *pdlgPrint, CFolder *pfolSelection)
|
|
{
|
|
BOOL fReturn;
|
|
|
|
do {
|
|
int nResult = BeginPrinting(pdlgPrint, pfolSelection);
|
|
if (nResult < 0)
|
|
break;
|
|
m_pPrintContent->SeekToBegin();
|
|
while (m_pPrintInfo->m_bContinuePrinting)
|
|
PrintPage(pdlgPrint);
|
|
EndPrinting();
|
|
fReturn = TRUE;
|
|
} while (FALSE);
|
|
delete m_pPrintContent;
|
|
m_pPrintContent = NULL;
|
|
delete m_pPrintInfo;
|
|
m_pPrintInfo = NULL;
|
|
return fReturn;
|
|
}
|
|
|
|
/*
|
|
* BeginPrinting - Do the initialization required to print the file.
|
|
*
|
|
* History: a-jsari 12/30/97 Thieved from msishell's msiview.cpp,
|
|
* modified to allow page ranges.
|
|
*/
|
|
int CDataSource::BeginPrinting(CPrintDialog *pdlgPrint, CFolder *pfolSelection)
|
|
{
|
|
ASSERT(m_pPrintContent != NULL);
|
|
if (m_pPrintContent == NULL) {
|
|
m_fEndOfFile = TRUE;
|
|
m_pPrintInfo->m_bContinuePrinting = FALSE;
|
|
::AfxThrowMemoryException();
|
|
}
|
|
|
|
if (m_pDC != NULL) {
|
|
delete m_pDC;
|
|
m_pDC = NULL;
|
|
}
|
|
|
|
m_pDC = new CDC;
|
|
ASSERT(m_pDC != NULL);
|
|
if (m_pDC == NULL) ::AfxThrowMemoryException();
|
|
|
|
if (m_pprinterFont != NULL) {
|
|
delete m_pprinterFont;
|
|
m_pprinterFont = NULL;
|
|
}
|
|
|
|
m_pprinterFont = new CFont;
|
|
ASSERT(m_pprinterFont != NULL);
|
|
if (m_pprinterFont == NULL) ::AfxThrowMemoryException();
|
|
|
|
#if 0
|
|
m_strHeaderLeft = pScope->MachineName();
|
|
#endif
|
|
|
|
CString strFormat;
|
|
COleDateTime datetime;
|
|
|
|
strFormat.LoadString(IDS_PRINT_HDR_RIGHT_CURRENT);
|
|
datetime = COleDateTime::GetCurrentTime();
|
|
m_strHeaderRight = datetime.Format(strFormat);
|
|
|
|
m_strFooterCenter.LoadString(IDS_PRINT_FTR_CTR);
|
|
|
|
// Reset the end of file member.
|
|
|
|
m_fEndOfFile = FALSE;
|
|
|
|
// Create the font for printing. Read font information from string
|
|
// resources, to allow the localizers to control what font is
|
|
// used for printing. Set the variables for the default font to use.
|
|
|
|
int nHeight = 10;
|
|
int nWeight = FW_NORMAL;
|
|
BYTE nCharSet = DEFAULT_CHARSET;
|
|
BYTE nPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
|
|
CString strFace = "Courier New";
|
|
|
|
// Load string resources to see if we should use other values
|
|
// than the defaults.
|
|
|
|
CString strHeight, strWeight, strCharSet, strPitchAndFamily, strFaceName;
|
|
strHeight.LoadString(IDS_PRINT_FONT_HEIGHT);
|
|
strWeight.LoadString(IDS_PRINT_FONT_WEIGHT);
|
|
strCharSet.LoadString(IDS_PRINT_FONT_CHARSET);
|
|
strPitchAndFamily.LoadString(IDS_PRINT_FONT_PITCHANDFAMILY);
|
|
strFaceName.LoadString(IDS_PRINT_FONT_FACENAME);
|
|
|
|
if (!strHeight.IsEmpty() && ::_ttol(strHeight))
|
|
nHeight = ::_ttoi(strHeight);
|
|
|
|
if (!strWeight.IsEmpty())
|
|
nWeight = ::_ttoi(strWeight);
|
|
|
|
if (!strCharSet.IsEmpty())
|
|
nCharSet = (BYTE) ::_ttoi(strCharSet);
|
|
|
|
if (!strPitchAndFamily.IsEmpty())
|
|
nPitchAndFamily = (BYTE) ::_ttoi(strPitchAndFamily);
|
|
|
|
strFaceName.TrimLeft();
|
|
if (!strFaceName.IsEmpty() && strFaceName != CString("facename"))
|
|
strFace = strFaceName;
|
|
|
|
CString strDriver = pdlgPrint->GetDriverName();
|
|
CString strDevice = pdlgPrint->GetDeviceName();
|
|
CString strPort = pdlgPrint->GetPortName();
|
|
LPDEVMODE pdevMode = pdlgPrint->GetDevMode();
|
|
VERIFY(m_pDC->CreateDC(strDriver, strDevice, strPort, pdevMode));
|
|
|
|
// Convert the height from points to a value specific to the printer.
|
|
|
|
nHeight = -((m_pDC->GetDeviceCaps (LOGPIXELSY) * nHeight) / 72);
|
|
|
|
// Create the font object.
|
|
|
|
VERIFY(m_pprinterFont->CreateFont(nHeight, 0, 0, 0, nWeight, 0, 0, 0,
|
|
nCharSet, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS,
|
|
DEFAULT_QUALITY, nPitchAndFamily, strFace));
|
|
|
|
m_pPrintInfo->m_rectDraw.SetRect(0, 0, m_pDC->GetDeviceCaps(HORZRES),
|
|
m_pDC->GetDeviceCaps(VERTRES));
|
|
m_pDC->DPtoLP(&m_pPrintInfo->m_rectDraw);
|
|
|
|
m_pPrintInfo->m_bContinuePrinting = TRUE;
|
|
|
|
CString strDocName;
|
|
CString strOutput;
|
|
DOCINFO diJob;
|
|
diJob.cbSize = sizeof(DOCINFO);
|
|
diJob.lpszDocName = strDocName;
|
|
diJob.lpszOutput = strOutput;
|
|
return m_pDC->StartDoc(&diJob);
|
|
}
|
|
|
|
/*
|
|
* OnEndPrinting - Clean up anything we allocated for the print job. Specifically,
|
|
* delete the CMemFile holding the content.
|
|
*
|
|
* History: a-jsari 12/30/97 Thieved from MSIShell's msiview.cpp
|
|
*/
|
|
void CDataSource::EndPrinting()
|
|
{
|
|
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
|
|
if (m_pPrintContent != NULL)
|
|
{
|
|
delete m_pPrintContent;
|
|
m_pPrintContent = NULL;
|
|
}
|
|
|
|
int nResult = m_pDC->EndDoc();
|
|
ASSERT(nResult >= 0);
|
|
|
|
if (nResult < 0) {
|
|
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
|
|
CString strError, strTitle;
|
|
|
|
switch(nResult) {
|
|
case SP_OUTOFDISK:
|
|
VERIFY(strError.LoadString(IDS_PRINT_NODISK));
|
|
break;
|
|
case SP_OUTOFMEMORY:
|
|
VERIFY(strError.LoadString(IDS_PRINT_NOMEMORY));
|
|
break;
|
|
case SP_USERABORT:
|
|
VERIFY(strError.LoadString(IDS_PRINT_USERABORTED));
|
|
break;
|
|
case SP_ERROR:
|
|
default:
|
|
VERIFY(strError.LoadString(IDS_PRINT_GENERIC));
|
|
break;
|
|
}
|
|
strTitle.LoadString(IDS_DESCRIPTION);
|
|
::MessageBox( ::AfxGetMainWnd()->GetSafeHwnd(), strError, strTitle, MB_OK);
|
|
}
|
|
|
|
VERIFY(m_pprinterFont->DeleteObject());
|
|
VERIFY(m_pDC->DeleteDC());
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// In this function, we use two rectangles: rectOuter is what we consider
|
|
// the printable area of the page, and includes headers and footers.
|
|
// rectInner is the rectange we actually print the content in (doesn't
|
|
// include headers or footers).
|
|
//
|
|
// TBD: add header and footer
|
|
// TBD: add error checking
|
|
// TBD: fix intelegence issues and speed this up
|
|
// TBD: insure that 80 columns will always fit
|
|
//---------------------------------------------------------------------------
|
|
|
|
#define TOP_MARGIN 2540/2 // HIMETRIC for 1/2 inch
|
|
#define BOTTOM_MARGIN 2540/2 // HIMETRIC for 1/2 inch
|
|
#define LEFT_MARGIN 2540/2 // HIMETRIC for 1/2 inch
|
|
#define RIGHT_MARGIN 2540/2 // HIMETRIC for 1/2 inch
|
|
|
|
/*
|
|
* GetLine - Copy a line of data from m_pPrintContent into szLineBuffer.
|
|
*
|
|
* History: a-jsari 3/16/98 Initial version.
|
|
*/
|
|
void CDataSource::GetLine(LPTSTR szLineBuffer, int cSize)
|
|
{
|
|
for (int i = 0; i < cSize; i++)
|
|
{
|
|
try {
|
|
m_pPrintContent->ReadTchar(szLineBuffer[i]);
|
|
} catch (...)
|
|
{
|
|
m_pPrintInfo->m_bContinuePrinting = FALSE;
|
|
m_fEndOfFile = TRUE;
|
|
szLineBuffer[i] = '\0';
|
|
break;
|
|
}
|
|
if (szLineBuffer[i] == '\t')
|
|
{
|
|
// Convert tabs into spaces for printing.
|
|
|
|
szLineBuffer[i] = ' ';
|
|
}
|
|
else if (szLineBuffer[i] == '\r')
|
|
{
|
|
i--;
|
|
}
|
|
else if (szLineBuffer[i] == '\n')
|
|
{
|
|
szLineBuffer[i] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* GetTextSize - Get the sizes of the text.
|
|
*
|
|
* History: a-jsari 3/16/98 Initial version.
|
|
*/
|
|
void CDataSource::GetTextSize(int &cLineLength, int &cCharHeight, CRect &rectOuter, CRect &rectText)
|
|
{
|
|
TEXTMETRIC tm;
|
|
|
|
m_pDC->GetTextMetrics(&tm);
|
|
cCharHeight = tm.tmHeight + tm.tmExternalLeading;
|
|
|
|
// Take the actual print area (in pInfo) and adjust it for the
|
|
// header and footer.
|
|
|
|
rectOuter = m_pPrintInfo->m_rectDraw;
|
|
|
|
CSize sizeLeftTop(LEFT_MARGIN, TOP_MARGIN);
|
|
CSize sizeRightBottom(RIGHT_MARGIN, BOTTOM_MARGIN);
|
|
m_pDC->HIMETRICtoDP(&sizeLeftTop);
|
|
m_pDC->HIMETRICtoDP(&sizeRightBottom);
|
|
rectOuter.DeflateRect(sizeLeftTop.cx, sizeLeftTop.cy, sizeRightBottom.cx, sizeRightBottom.cy);
|
|
|
|
rectText = rectOuter;
|
|
rectText.DeflateRect(0, cCharHeight * 4);
|
|
|
|
// Get the number of characters which will fit on a line (use the average, because this
|
|
// might not be a monospaced font). Note: it's possible that text could be cut off
|
|
// if a line consisted of very wide characters. This is unlikely because the font
|
|
// used SHOULD be monospace (for alignment of text, etc.).
|
|
|
|
cLineLength = rectText.Width() / tm.tmAveCharWidth;
|
|
}
|
|
|
|
/*
|
|
* PrintPage - Write one page to the printer Device Context.
|
|
*
|
|
* History: a-jsari 12/30/97 Thieved from msishell's msiview.cpp.
|
|
*/
|
|
void CDataSource::PrintPage(CPrintDialog *pdlgPrint)
|
|
{
|
|
int cLineLength;
|
|
int cy = 0, cyCharHeight;
|
|
LPTSTR szLineBuffer;
|
|
CRect rectOuter, rectInner;
|
|
|
|
ASSERT(m_pPrintContent != NULL);
|
|
if (m_pPrintContent == NULL)
|
|
{
|
|
m_fEndOfFile = TRUE;
|
|
m_pPrintInfo->m_bContinuePrinting = FALSE;
|
|
return;
|
|
}
|
|
|
|
// Select the font used for printing.
|
|
|
|
CGdiObject* pOldFont = m_pDC->SelectObject(m_pprinterFont);
|
|
|
|
// this makes a small font: CGdiObject *pOldFont = pDC->SelectStockObject(ANSI_FIXED_FONT);
|
|
|
|
// Compute the height of each character (we'll need the text metric).
|
|
GetTextSize(cLineLength, cyCharHeight, rectOuter, rectInner);
|
|
|
|
++m_pPrintInfo->m_nCurPage;
|
|
if (!(pdlgPrint->PrintAll() || pdlgPrint->PrintSelection())
|
|
&& m_pPrintInfo->m_nCurPage > m_pPrintInfo->GetToPage()) {
|
|
m_pPrintInfo->m_bContinuePrinting = FALSE;
|
|
m_pDC->SelectObject(pOldFont);
|
|
return;
|
|
}
|
|
|
|
// Allocate the buffer of character to hold a single line of the print out.
|
|
szLineBuffer = new TCHAR[cLineLength + 1];
|
|
szLineBuffer[cLineLength] = (TCHAR)'\0';
|
|
|
|
if (pdlgPrint->PrintAll() || pdlgPrint->PrintSelection()
|
|
|| m_pPrintInfo->m_nCurPage >= m_pPrintInfo->GetFromPage()) {
|
|
m_pDC->StartPage();
|
|
|
|
// Draw the header.
|
|
|
|
m_pDC->TextOut(rectOuter.left, rectOuter.top, m_strHeaderLeft);
|
|
|
|
int cxHeaderRight = rectOuter.right - m_pDC->GetTextExtent(m_strHeaderRight).cx;
|
|
m_pDC->TextOut(cxHeaderRight, rectOuter.top, m_strHeaderRight);
|
|
}
|
|
|
|
// Process the output a line at a time, until either we have emptied out
|
|
// the memfile, or we have gotten to the bottom of this page.
|
|
|
|
while (!m_fEndOfFile)
|
|
{
|
|
if (cy + cyCharHeight > rectInner.Height())
|
|
break;
|
|
|
|
GetLine(szLineBuffer, cLineLength);
|
|
|
|
if (pdlgPrint->PrintAll() || pdlgPrint->PrintSelection()
|
|
|| m_pPrintInfo->m_nCurPage >= m_pPrintInfo->GetFromPage())
|
|
m_pDC->TextOut(rectInner.left, rectInner.top + cy, szLineBuffer, ::_tcslen(szLineBuffer));
|
|
cy += cyCharHeight;
|
|
}
|
|
|
|
if (pdlgPrint->PrintAll() || pdlgPrint->PrintSelection()
|
|
|| m_pPrintInfo->m_nCurPage >= m_pPrintInfo->GetFromPage()) {
|
|
// Draw the footer.
|
|
CString strActualFooter;
|
|
strActualFooter.Format(m_strFooterCenter, m_pPrintInfo->m_nCurPage);
|
|
int cxFooterCenter = (rectOuter.Width() - m_pDC->GetTextExtent(strActualFooter).cx) / 2;
|
|
m_pDC->TextOut(rectOuter.left + cxFooterCenter, rectOuter.bottom - cyCharHeight, strActualFooter);
|
|
|
|
int nResult = m_pDC->EndPage();
|
|
ASSERT(nResult >= 0);
|
|
}
|
|
|
|
#if 0
|
|
if (nResult < 0) {
|
|
AFX_MANAGE_STATE(::AfxGetStaticModuleState());
|
|
CString strError;
|
|
|
|
switch (nResult) {
|
|
case SP_APPABORT:
|
|
VERIFY(strError.LoadString(IDS_PRINT_APPABORTED));
|
|
break;
|
|
case SP_USERABORT:
|
|
VERIFY(strError.LoadString(IDS_PRINT_USERABORTED));
|
|
break;
|
|
case SP_OUTOFDISK:
|
|
VERIFY(strError.LoadString(IDS_PRINT_NODISK));
|
|
break;
|
|
case SP_OUTOFMEMORY:
|
|
VERIFY(strError.LoadString(IDS_PRINT_NOMEMORY));
|
|
break;
|
|
case SP_ERROR:
|
|
default:
|
|
VERIFY(strError.LoadString(IDS_PRINT_GENERIC));
|
|
break;
|
|
}
|
|
strTitle.LoadString(IDS_DESCRIPTION)
|
|
::MessageBox( ::AfxGetMainWnd()->GetSafeHwnd(), strError, strTitle, MB_OK);
|
|
}
|
|
// Clean up.
|
|
#endif
|
|
|
|
delete [] szLineBuffer;
|
|
m_pDC->SelectObject(pOldFont);
|
|
}
|
|
|