mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
448 lines
12 KiB
448 lines
12 KiB
// This is a part of the Microsoft Foundation Classes C++ library.
|
|
// Copyright (C) 1992-1995 Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// This source code is only intended as a supplement to the
|
|
// Microsoft Foundation Classes Reference and related
|
|
// electronic documentation provided with the library.
|
|
// See these sources for detailed information regarding the
|
|
// Microsoft Foundation Classes product.
|
|
|
|
#include "stdafx.h"
|
|
#ifdef _MAC
|
|
#include <macname1.h>
|
|
#include <Events.h>
|
|
#include <macname2.h>
|
|
#endif
|
|
|
|
#ifdef AFX_PRINT_SEG
|
|
#pragma code_seg(AFX_PRINT_SEG)
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Printing Dialog
|
|
|
|
class CPrintingDialog : public CDialog
|
|
{
|
|
public:
|
|
//{{AFX_DATA(CPrintingDialog)
|
|
enum { IDD = AFX_IDD_PRINTDLG };
|
|
//}}AFX_DATA
|
|
CPrintingDialog::CPrintingDialog(CWnd* pParent)
|
|
{
|
|
#ifdef _MAC
|
|
// Note! set m_pView *before* CDialog::Create so that
|
|
// CPrintingDialog::OnInitDialog can use it.
|
|
m_pView = pParent;
|
|
#endif
|
|
Create(CPrintingDialog::IDD, pParent); // modeless !
|
|
_afxWinState->m_bUserAbort = FALSE;
|
|
}
|
|
virtual ~CPrintingDialog() { }
|
|
|
|
virtual BOOL OnInitDialog();
|
|
virtual void OnCancel();
|
|
|
|
protected:
|
|
#ifdef _MAC
|
|
CWnd* m_pView; // the view being printed
|
|
|
|
afx_msg int OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message);
|
|
#endif
|
|
|
|
#ifdef _MAC
|
|
//{{AFX_MSG(CPrintingDialog)
|
|
//}}AFX_MSG
|
|
DECLARE_MESSAGE_MAP()
|
|
#endif
|
|
};
|
|
|
|
#ifdef _MAC
|
|
BEGIN_MESSAGE_MAP(CPrintingDialog, CDialog)
|
|
//{{AFX_MSG_MAP(CPrintingDialog)
|
|
ON_WM_MOUSEACTIVATE()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
#endif
|
|
|
|
BOOL CALLBACK _AfxAbortProc(HDC, int)
|
|
{
|
|
_AFX_WIN_STATE* pWinState = _afxWinState;
|
|
|
|
#ifdef _MAC
|
|
EventRecord er;
|
|
BOOL fNewMessages;
|
|
|
|
// Look for an event, and if we find one, see if WLM cares about it.
|
|
// If so, remove it from the queue (and then ignore it, since we've
|
|
// already told WLM about it by calling QueueEvent). We also remove
|
|
// the event from the queue if it's an activateEvt for a non-WLM
|
|
// window, since this will probably be an activate for the printer
|
|
// driver's status window, which we want to flush from the queue so
|
|
// that it doesn't block events for WLM windows.
|
|
|
|
while (EventAvail(everyEvent, &er) &&
|
|
(QueueEvent(&er, &fNewMessages) || er.what == activateEvt))
|
|
{
|
|
GetNextEvent(everyEvent, &er);
|
|
}
|
|
|
|
// It's harder for us to depend on a cmd-. or escape keypress getting
|
|
// picked up by the EventAvail, since the user could easily click in
|
|
// the printer status window, producing a non-WLM event that would hide
|
|
// the keypress. Therefore we also explicitly check for the keypress.
|
|
|
|
if (GetAsyncKeyState(VK_CANCEL))
|
|
{
|
|
TRACE0("saw an async VK_CANCEL\n");
|
|
pWinState->m_bUserAbort = TRUE;
|
|
}
|
|
#endif
|
|
|
|
MSG msg;
|
|
while (!pWinState->m_bUserAbort &&
|
|
#ifndef _MAC
|
|
::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE))
|
|
#else
|
|
// don't grab any new messages from the Mac event queue
|
|
::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE | PM_NOEVENTS))
|
|
#endif
|
|
{
|
|
if (!AfxGetThread()->PumpMessage())
|
|
return FALSE; // terminate if WM_QUIT received
|
|
}
|
|
return !pWinState->m_bUserAbort;
|
|
}
|
|
|
|
BOOL CPrintingDialog::OnInitDialog()
|
|
{
|
|
#ifdef _MAC
|
|
// prime the state of the VK_CANCEL key
|
|
GetAsyncKeyState(VK_CANCEL);
|
|
#endif
|
|
SetWindowText(AfxGetAppName());
|
|
#ifndef _MAC
|
|
CenterWindow();
|
|
#else
|
|
CenterWindow(m_pView->GetParentFrame());
|
|
#endif
|
|
return CDialog::OnInitDialog();
|
|
}
|
|
|
|
void CPrintingDialog::OnCancel()
|
|
{
|
|
_afxWinState->m_bUserAbort = TRUE; // flag that user aborted print
|
|
CDialog::OnCancel();
|
|
}
|
|
|
|
#ifdef _MAC
|
|
int CPrintingDialog::OnMouseActivate(CWnd* pDesktopWnd, UINT, UINT)
|
|
{
|
|
UNUSED(pDesktopWnd); // not used in release build
|
|
ASSERT(pDesktopWnd == this);
|
|
|
|
// if the printer driver has opened its own status window, we don't
|
|
// want to activate our printing status window when it's clicked
|
|
|
|
return MA_NOACTIVATE;
|
|
}
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CView printing commands
|
|
|
|
BOOL CView::DoPreparePrinting(CPrintInfo* pInfo)
|
|
{
|
|
ASSERT(pInfo != NULL);
|
|
ASSERT(pInfo->m_pPD != NULL);
|
|
|
|
CWinApp* pApp = AfxGetApp();
|
|
if (pInfo->m_bPreview || pInfo->m_bDirect)
|
|
{
|
|
if (pInfo->m_pPD->m_pd.hDC == NULL)
|
|
{
|
|
// if no printer set then, get default printer DC and create DC without calling
|
|
// print dialog.
|
|
if (!pApp->GetPrinterDeviceDefaults(&pInfo->m_pPD->m_pd))
|
|
{
|
|
// bring up dialog to alert the user they need to install a printer.
|
|
if (pApp->DoPrintDialog(pInfo->m_pPD) != IDOK)
|
|
return FALSE;
|
|
}
|
|
|
|
if (pInfo->m_pPD->m_pd.hDC == NULL)
|
|
{
|
|
// call CreatePrinterDC if DC was not created by above
|
|
if (pInfo->m_pPD->CreatePrinterDC() == NULL)
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// set up From and To page range from Min and Max
|
|
pInfo->m_pPD->m_pd.nFromPage = (WORD)pInfo->GetMinPage();
|
|
pInfo->m_pPD->m_pd.nToPage = (WORD)pInfo->GetMaxPage();
|
|
}
|
|
else
|
|
{
|
|
// otherwise, bring up the print dialog and allow user to change things
|
|
|
|
// preset From-To range same as Min-Max range
|
|
pInfo->m_pPD->m_pd.nFromPage = (WORD)pInfo->GetMinPage();
|
|
pInfo->m_pPD->m_pd.nToPage = (WORD)pInfo->GetMaxPage();
|
|
|
|
if (pApp->DoPrintDialog(pInfo->m_pPD) != IDOK)
|
|
return FALSE; // do not print
|
|
}
|
|
|
|
ASSERT(pInfo->m_pPD != NULL);
|
|
ASSERT(pInfo->m_pPD->m_pd.hDC != NULL);
|
|
|
|
pInfo->m_nNumPreviewPages = pApp->m_nNumPreviewPages;
|
|
VERIFY(pInfo->m_strPageDesc.LoadString(AFX_IDS_PREVIEWPAGEDESC));
|
|
return TRUE;
|
|
}
|
|
|
|
void CView::OnFilePrint()
|
|
{
|
|
// get default print info
|
|
CPrintInfo printInfo;
|
|
ASSERT(printInfo.m_pPD != NULL); // must be set
|
|
|
|
if (GetCurrentMessage()->wParam == ID_FILE_PRINT_DIRECT)
|
|
{
|
|
CCommandLineInfo* pCmdInfo = AfxGetApp()->m_pCmdInfo;
|
|
|
|
if (pCmdInfo != NULL)
|
|
{
|
|
if (pCmdInfo->m_nShellCommand == CCommandLineInfo::FilePrintTo)
|
|
{
|
|
printInfo.m_pPD->m_pd.hDC = ::CreateDC(pCmdInfo->m_strDriverName,
|
|
pCmdInfo->m_strPrinterName, pCmdInfo->m_strPortName, NULL);
|
|
if (printInfo.m_pPD->m_pd.hDC == NULL)
|
|
{
|
|
AfxMessageBox(AFX_IDP_FAILED_TO_START_PRINT);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
printInfo.m_bDirect = TRUE;
|
|
}
|
|
|
|
if (OnPreparePrinting(&printInfo))
|
|
{
|
|
// hDC must be set (did you remember to call DoPreparePrinting?)
|
|
ASSERT(printInfo.m_pPD->m_pd.hDC != NULL);
|
|
|
|
// gather file to print to if print-to-file selected
|
|
CString strOutput;
|
|
if (printInfo.m_pPD->m_pd.Flags & PD_PRINTTOFILE)
|
|
{
|
|
// construct CFileDialog for browsing
|
|
CString strDef(MAKEINTRESOURCE(AFX_IDS_PRINTDEFAULTEXT));
|
|
CString strPrintDef(MAKEINTRESOURCE(AFX_IDS_PRINTDEFAULT));
|
|
CString strFilter(MAKEINTRESOURCE(AFX_IDS_PRINTFILTER));
|
|
CString strCaption(MAKEINTRESOURCE(AFX_IDS_PRINTCAPTION));
|
|
CFileDialog dlg(FALSE, strDef, strPrintDef,
|
|
OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, strFilter);
|
|
dlg.m_ofn.lpstrTitle = strCaption;
|
|
|
|
if (dlg.DoModal() != IDOK)
|
|
return;
|
|
|
|
// set output device to resulting path name
|
|
strOutput = dlg.GetPathName();
|
|
}
|
|
|
|
// set up document info and start the document printing process
|
|
CString strTitle;
|
|
CDocument* pDoc = GetDocument();
|
|
if (pDoc != NULL)
|
|
strTitle = pDoc->GetTitle();
|
|
else
|
|
GetParentFrame()->GetWindowText(strTitle);
|
|
if (strTitle.GetLength() > 31)
|
|
strTitle.ReleaseBuffer(31);
|
|
DOCINFO docInfo;
|
|
memset(&docInfo, 0, sizeof(DOCINFO));
|
|
docInfo.cbSize = sizeof(DOCINFO);
|
|
docInfo.lpszDocName = strTitle;
|
|
CString strPortName;
|
|
int nFormatID;
|
|
if (strOutput.IsEmpty())
|
|
{
|
|
docInfo.lpszOutput = NULL;
|
|
strPortName = printInfo.m_pPD->GetPortName();
|
|
nFormatID = AFX_IDS_PRINTONPORT;
|
|
}
|
|
else
|
|
{
|
|
docInfo.lpszOutput = strOutput;
|
|
AfxGetFileTitle(strOutput,
|
|
strPortName.GetBuffer(_MAX_PATH), _MAX_PATH);
|
|
nFormatID = AFX_IDS_PRINTTOFILE;
|
|
}
|
|
|
|
// setup the printing DC
|
|
CDC dcPrint;
|
|
dcPrint.Attach(printInfo.m_pPD->m_pd.hDC); // attach printer dc
|
|
dcPrint.m_bPrinting = TRUE;
|
|
OnBeginPrinting(&dcPrint, &printInfo);
|
|
dcPrint.SetAbortProc(_AfxAbortProc);
|
|
|
|
// disable main window while printing & init printing status dialog
|
|
AfxGetMainWnd()->EnableWindow(FALSE);
|
|
CPrintingDialog dlgPrintStatus(this);
|
|
|
|
CString strTemp;
|
|
dlgPrintStatus.SetDlgItemText(AFX_IDC_PRINT_DOCNAME, strTitle);
|
|
#ifndef _MAC
|
|
dlgPrintStatus.SetDlgItemText(AFX_IDC_PRINT_PRINTERNAME,
|
|
printInfo.m_pPD->GetDeviceName());
|
|
AfxFormatString1(strTemp, nFormatID, strPortName);
|
|
dlgPrintStatus.SetDlgItemText(AFX_IDC_PRINT_PORTNAME, strTemp);
|
|
#endif
|
|
dlgPrintStatus.ShowWindow(SW_SHOW);
|
|
dlgPrintStatus.UpdateWindow();
|
|
|
|
// start document printing process
|
|
if (dcPrint.StartDoc(&docInfo) == SP_ERROR)
|
|
{
|
|
// enable main window before proceeding
|
|
AfxGetMainWnd()->EnableWindow(TRUE);
|
|
|
|
// cleanup and show error message
|
|
OnEndPrinting(&dcPrint, &printInfo);
|
|
dlgPrintStatus.DestroyWindow();
|
|
dcPrint.Detach(); // will be cleaned up by CPrintInfo destructor
|
|
AfxMessageBox(AFX_IDP_FAILED_TO_START_PRINT);
|
|
return;
|
|
}
|
|
|
|
// Guarantee values are in the valid range
|
|
UINT nEndPage = printInfo.GetToPage();
|
|
UINT nStartPage = printInfo.GetFromPage();
|
|
|
|
if (nEndPage < printInfo.GetMinPage())
|
|
nEndPage = printInfo.GetMinPage();
|
|
if (nEndPage > printInfo.GetMaxPage())
|
|
nEndPage = printInfo.GetMaxPage();
|
|
|
|
if (nStartPage < printInfo.GetMinPage())
|
|
nStartPage = printInfo.GetMinPage();
|
|
if (nStartPage > printInfo.GetMaxPage())
|
|
nStartPage = printInfo.GetMaxPage();
|
|
|
|
int nStep = (nEndPage >= nStartPage) ? 1 : -1;
|
|
nEndPage = (nEndPage == 0xffff) ? 0xffff : nEndPage + nStep;
|
|
|
|
VERIFY(strTemp.LoadString(AFX_IDS_PRINTPAGENUM));
|
|
|
|
// begin page printing loop
|
|
BOOL bError = FALSE;
|
|
for (printInfo.m_nCurPage = nStartPage;
|
|
printInfo.m_nCurPage != nEndPage; printInfo.m_nCurPage += nStep)
|
|
{
|
|
OnPrepareDC(&dcPrint, &printInfo);
|
|
|
|
// check for end of print
|
|
if (!printInfo.m_bContinuePrinting)
|
|
break;
|
|
|
|
// write current page
|
|
TCHAR szBuf[80];
|
|
wsprintf(szBuf, strTemp, printInfo.m_nCurPage);
|
|
dlgPrintStatus.SetDlgItemText(AFX_IDC_PRINT_PAGENUM, szBuf);
|
|
|
|
// set up drawing rect to entire page (in logical coordinates)
|
|
printInfo.m_rectDraw.SetRect(0, 0,
|
|
dcPrint.GetDeviceCaps(HORZRES),
|
|
dcPrint.GetDeviceCaps(VERTRES));
|
|
dcPrint.DPtoLP(&printInfo.m_rectDraw);
|
|
|
|
// attempt to start the current page
|
|
if (dcPrint.StartPage() < 0)
|
|
{
|
|
bError = TRUE;
|
|
break;
|
|
}
|
|
|
|
// must call OnPrepareDC on newer versions of Windows because
|
|
// StartPage now resets the device attributes.
|
|
if (afxData.bMarked4)
|
|
OnPrepareDC(&dcPrint, &printInfo);
|
|
|
|
ASSERT(printInfo.m_bContinuePrinting);
|
|
|
|
// page successfully started, so now render the page
|
|
OnPrint(&dcPrint, &printInfo);
|
|
if (dcPrint.EndPage() < 0 || !_AfxAbortProc(dcPrint.m_hDC, 0))
|
|
{
|
|
bError = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// cleanup document printing process
|
|
if (!bError)
|
|
dcPrint.EndDoc();
|
|
else
|
|
dcPrint.AbortDoc();
|
|
|
|
AfxGetMainWnd()->EnableWindow(); // enable main window
|
|
|
|
OnEndPrinting(&dcPrint, &printInfo); // clean up after printing
|
|
dlgPrintStatus.DestroyWindow();
|
|
|
|
dcPrint.Detach(); // will be cleaned up by CPrintInfo destructor
|
|
|
|
#ifdef _MAC
|
|
// It's common for the user to click on the printing status dialog
|
|
// and not have the click be registered because the abort proc
|
|
// wasn't called often enough. For this reason we call _FlushEvents
|
|
// after printing is done so that those events don't get sent
|
|
// through to the document window and cause unintended changes to
|
|
// the document.
|
|
|
|
FlushEvents(everyEvent, 0);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CPrintInfo helper structure
|
|
|
|
CPrintInfo::CPrintInfo()
|
|
{
|
|
m_pPD = new CPrintDialog(FALSE, PD_ALLPAGES | PD_USEDEVMODECOPIES |
|
|
PD_NOSELECTION);
|
|
|
|
ASSERT(m_pPD->m_pd.hDC == NULL);
|
|
|
|
SetMinPage(1); // one based page numbers
|
|
SetMaxPage(0xffff); // unknown how many pages
|
|
|
|
m_nCurPage = 1;
|
|
|
|
m_lpUserData = NULL; // Initialize to no user data
|
|
m_bPreview = FALSE; // initialize to not preview
|
|
m_bDirect = FALSE; // initialize to not direct
|
|
m_bContinuePrinting = TRUE; // Assume it is OK to print
|
|
}
|
|
|
|
CPrintInfo::~CPrintInfo()
|
|
{
|
|
if (m_pPD != NULL && m_pPD->m_pd.hDC != NULL)
|
|
{
|
|
::DeleteDC(m_pPD->m_pd.hDC);
|
|
m_pPD->m_pd.hDC = NULL;
|
|
}
|
|
delete m_pPD;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|