Figure 1 Printing Return Codes
Return Code | Description | |
SP_ERROR | The print job was aborted for an unspecified reason | |
SP_APPABORT | The print job was aborted because the user clicked the Cancel button in the dialog box that displays the status of the print job | |
SP_USERABORT | The print job was aborted because the user canceled it through the operating system shell | |
SP_OUTOFDISK | The system is out of disk space, so no further printer data can be spooled | |
SP_OUTOFMEMORY | The system is out of memory, so no further printer data can be spooled |
Figure 2 CView Print Overridables
Function | Description |
CView::OnPreparePrinting | Called at the very onset of a print job. Override to call CView::DoPreparePrinting and provide the framework with the page count (if known) and other information about the print job. |
CView::OnBeginPrinting | Called just before printing begins. Override to allocate fonts and other resources required for printing. |
CView::OnPrepareDC | Called before each page is printed. Override to set the viewport origin or clipping region to print the current page if OnDraw will be used to produce the printed output. |
CView::OnPrint | Called to print one page of the document. A page number and printer DC are supplied to you by the framework. Override to print headers, footers, and other page elements that aren't drawn by the view's OnDraw function or to print each page without relying on OnDraw. |
CView::OnEndPrinting | Called when printing is finished. Override to deallocate resources allocated in OnBeginPrinting. |
Figure 4 EZPrint
Resource.h
//***********************************************************************
//
// Resource.h (EZPrint)
//
//***********************************************************************
#define IDR_MAINFRAME 100
EZPrint.rc
//***********************************************************************
//
// EZPrint.rc
//
//***********************************************************************
#include <afxres.h>
#include "Resource.h"
IDR_MAINFRAME MENU
BEGIN
POPUP "&File" {
MENUITEM "&Print...\tCtrl+P", ID_FILE_PRINT
MENUITEM "Print Pre&view", ID_FILE_PRINT_PREVIEW
MENUITEM "P&rint Setup...", ID_FILE_PRINT_SETUP
MENUITEM SEPARATOR
MENUITEM "E&xit", ID_APP_EXIT
}
END
IDR_MAINFRAME ACCELERATORS
BEGIN
"P", ID_FILE_PRINT, VIRTKEY, CONTROL
END
STRINGTABLE
BEGIN
IDR_MAINFRAME "EZPrint"
END
EZPrint.h
//***********************************************************************
//
// EZPrint.h
//
//***********************************************************************
class CPrintApp : public CWinApp
{
public:
virtual BOOL InitInstance ();
protected:
DECLARE_MESSAGE_MAP ()
};
EZPrint.cpp
//***********************************************************************
//
// EZPrint.cpp
//
//***********************************************************************
#include <afxwin.h>
#include "Resource.h"
#include "EZPrint.h"
#include "EZPrintDoc.h"
#include "EZPrintView.h"
CPrintApp myApp;
BEGIN_MESSAGE_MAP (CPrintApp, CWinApp)
ON_COMMAND (ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP ()
BOOL CPrintApp::InitInstance ()
{
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate (
IDR_MAINFRAME,
RUNTIME_CLASS (CPrintDoc),
RUNTIME_CLASS (CFrameWnd),
RUNTIME_CLASS (CPrintView)
);
AddDocTemplate (pDocTemplate);
CCommandLineInfo cmdInfo;
ParseCommandLine (cmdInfo);
if (!ProcessShellCommand (cmdInfo))
return FALSE;
return TRUE;
}
EZPrintDoc.h
//***********************************************************************
//
// EZPrintDoc.h
//
//***********************************************************************
class CPrintDoc : public CDocument
{
DECLARE_DYNCREATE (CPrintDoc)
};
EZPrintDoc.cpp
//***********************************************************************
//
// EZPrintDoc.cpp
//
//***********************************************************************
#include <afxwin.h>
#include "EZPrintDoc.h"
IMPLEMENT_DYNCREATE (CPrintDoc, CDocument)
EZPrintView.h
//***********************************************************************
//
// EZPrintView.h
//
//***********************************************************************
class CPrintView : public CView
{
DECLARE_DYNCREATE (CPrintView)
protected:
virtual void OnDraw (CDC*);
virtual BOOL OnPreparePrinting (CPrintInfo*);
DECLARE_MESSAGE_MAP ()
};
EZPrintView.cpp
//***********************************************************************
//
// EZPrintView.cpp
//
//***********************************************************************
#include <afxwin.h>
#include <afxext.h>
#include "EZPrintView.h"
IMPLEMENT_DYNCREATE (CPrintView, CView)
BEGIN_MESSAGE_MAP (CPrintView, CView)
ON_COMMAND (ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND (ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP ()
void CPrintView::OnDraw (CDC* pDC)
{
CPen pen (PS_SOLID, 50, RGB (0, 0, 255));
CBrush brush (RGB (255, 255, 0));
pDC->SetMapMode (MM_LOMETRIC);
CPen* pOldPen = pDC->SelectObject (&pen);
CBrush* pOldBrush = pDC->SelectObject (&brush);
pDC->Ellipse (100, -100, 1100, -1100);
pDC->SelectObject (pOldBrush);
pDC->SelectObject (pOldPen);
}
BOOL CPrintView::OnPreparePrinting (CPrintInfo* pInfo)
{
pInfo->SetMaxPage (1);
return DoPreparePrinting (pInfo);
}
Figure 8 HexDump
Resource.h
//***********************************************************************
//
// Resource.h (HexDump)
//
//***********************************************************************
#define IDR_MAINFRAME 100
HexDump.rc
//***********************************************************************
//
// HexDump.rc
//
//***********************************************************************
#include <afxres.h>
#include "Resource.h"
IDR_MAINFRAME MENU
BEGIN
POPUP "&File" {
MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN
MENUITEM SEPARATOR
MENUITEM "&Print...\tCtrl+P", ID_FILE_PRINT
MENUITEM "Print Pre&view", ID_FILE_PRINT_PREVIEW
MENUITEM "P&rint Setup...", ID_FILE_PRINT_SETUP
MENUITEM SEPARATOR
MENUITEM "Recent File", ID_FILE_MRU_FILE1
MENUITEM SEPARATOR
MENUITEM "E&xit", ID_APP_EXIT
}
END
IDR_MAINFRAME ACCELERATORS
BEGIN
"O", ID_FILE_OPEN, VIRTKEY, CONTROL
"P", ID_FILE_PRINT, VIRTKEY, CONTROL
END
STRINGTABLE
BEGIN
IDR_MAINFRAME "HexDump"
END
HexDump.h
//***********************************************************************
//
// HexDump.h
//
//***********************************************************************
class CHexDumpApp : public CWinApp
{
public:
virtual BOOL InitInstance ();
protected:
DECLARE_MESSAGE_MAP ()
};
HexDump.cpp
//***********************************************************************
//
// HexDump.cpp
//
//***********************************************************************
#include <afxwin.h>
#include "Resource.h"
#include "HexDump.h"
#include "HexDoc.h"
#include "HexView.h"
CHexDumpApp myApp;
BEGIN_MESSAGE_MAP (CHexDumpApp, CWinApp)
ON_COMMAND (ID_FILE_OPEN, CWinApp::OnFileOpen)
ON_COMMAND (ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP ()
BOOL CHexDumpApp::InitInstance ()
{
SetRegistryKey ("Programming Windows 95 with MFC");
LoadStdProfileSettings ();
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate (
IDR_MAINFRAME,
RUNTIME_CLASS (CHexDoc),
RUNTIME_CLASS (CFrameWnd),
RUNTIME_CLASS (CHexView)
);
AddDocTemplate (pDocTemplate);
CCommandLineInfo cmdInfo;
ParseCommandLine (cmdInfo);
if (!ProcessShellCommand (cmdInfo))
return FALSE;
m_pMainWnd->DragAcceptFiles ();
return TRUE;
}
HexDoc.h
//***********************************************************************
//
// HexDoc.h
//
//***********************************************************************
class CHexDoc : public CDocument
{
DECLARE_DYNCREATE (CHexDoc)
private:
UINT m_nDocLength;
BYTE* m_pFileData;
public:
CHexDoc ();
virtual void DeleteContents ();
virtual void Serialize (CArchive&);
UINT GetBytes (UINT, UINT, PVOID);
UINT GetDocumentLength ();
};
HexDoc.cpp
//***********************************************************************
//
// HexDoc.cpp
//
//***********************************************************************
#include <afxwin.h>
#include "HexDoc.h"
IMPLEMENT_DYNCREATE (CHexDoc, CDocument)
CHexDoc::CHexDoc ()
{
m_nDocLength = 0;
m_pFileData = NULL;
}
void CHexDoc::DeleteContents ()
{
if (m_pFileData != NULL) {
delete[] m_pFileData;
m_pFileData = NULL;
m_nDocLength = 0;
}
}
void CHexDoc::Serialize (CArchive& ar)
{
if (ar.IsLoading ()) {
CFile* pFile = ar.GetFile ();
m_nDocLength = (UINT) pFile->GetLength ();
// Allocate a buffer for the file data
try {
m_pFileData = new BYTE[m_nDocLength];
}
catch (CMemoryException* e) {
m_nDocLength = 0;
throw e;
}
// Read the file data into the buffer
try {
pFile->Read (m_pFileData, m_nDocLength);
}
catch (CFileException* e) {
delete[] m_pFileData;
m_pFileData = NULL;
m_nDocLength = 0;
throw e;
}
}
}
UINT CHexDoc::GetBytes (UINT nIndex, UINT nCount, PVOID pBuffer)
{
if (nIndex >= m_nDocLength)
return 0;
UINT nLength = nCount;
if ((nIndex + nCount) > m_nDocLength)
nLength = m_nDocLength - nIndex;
::CopyMemory (pBuffer, m_pFileData + nIndex, nLength);
return nLength;
}
UINT CHexDoc::GetDocumentLength ()
{
return m_nDocLength;
}
HexView.h
//***********************************************************************
//
// HexView.h
//
//***********************************************************************
class CHexView : public CScrollView
{
DECLARE_DYNCREATE (CHexView)
private:
CFont m_screenFont;
CFont m_printerFont;
UINT m_cyScreen;
UINT m_cyPrinter;
UINT m_cxOffset;
UINT m_cxWidth;
UINT m_nLinesTotal;
UINT m_nLinesPerPage;
CHexDoc* GetDocument () { return (CHexDoc*) m_pDocument; }
void FormatLine (UINT, CString&);
void PrintPageHeader (CDC*, UINT);
void PrintPage (CDC*, UINT);
public:
virtual void OnInitialUpdate ();
protected:
virtual void OnDraw (CDC*);
virtual BOOL OnPreparePrinting (CPrintInfo*);
virtual void OnBeginPrinting (CDC*, CPrintInfo*);
virtual void OnPrint (CDC*, CPrintInfo*);
virtual void OnEndPrinting (CDC*, CPrintInfo*);
afx_msg int OnCreate (LPCREATESTRUCT);
DECLARE_MESSAGE_MAP ()
};
HexView.cpp
//***********************************************************************
//
// HexView.cpp
//
//***********************************************************************
#include <afxwin.h>
#include <afxext.h>
#include "HexDoc.h"
#include "HexView.h"
#define PRINTMARGIN 2
IMPLEMENT_DYNCREATE (CHexView, CScrollView)
BEGIN_MESSAGE_MAP (CHexView, CScrollView)
ON_WM_CREATE ()
ON_COMMAND (ID_FILE_PRINT, CScrollView::OnFilePrint)
ON_COMMAND (ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint)
ON_COMMAND (ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview)
END_MESSAGE_MAP ()
int CHexView::OnCreate (LPCREATESTRUCT lpcs)
{
if (CScrollView::OnCreate (lpcs) == -1)
return -1;
CClientDC dc (this);
int nHeight = -((dc.GetDeviceCaps (LOGPIXELSY) * 10) / 72);
m_screenFont.CreateFont (nHeight, 0, 0, 0, FW_NORMAL, 0, 0, 0,
DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Courier New");
TEXTMETRIC tm;
CFont* pOldFont = dc.SelectObject (&m_screenFont);
dc.GetTextMetrics (&tm);
m_cyScreen = tm.tmHeight + tm.tmExternalLeading;
dc.SelectObject (pOldFont);
return 0;
}
void CHexView::OnInitialUpdate ()
{
UINT nDocLength = GetDocument ()->GetDocumentLength ();
m_nLinesTotal = (nDocLength + 15) / 16;
SetScrollSizes (MM_TEXT, CSize (0, m_nLinesTotal * m_cyScreen),
CSize (0, m_cyScreen * 10), CSize (0, m_cyScreen));
ScrollToPosition (CPoint (0, 0));
CScrollView::OnInitialUpdate ();
}
void CHexView::OnDraw (CDC* pDC)
{
if (m_nLinesTotal != 0) {
CRect rect;
pDC->GetClipBox (&rect);
UINT nStart = rect.top / m_cyScreen;
UINT nEnd = min (m_nLinesTotal - 1,
(rect.bottom + m_cyScreen - 1) / m_cyScreen);
CString string;
CFont* pOldFont = pDC->SelectObject (&m_screenFont);
for (UINT i=nStart; i<=nEnd; i++) {
FormatLine (i, string);
pDC->TextOut (2, (i * m_cyScreen) + 2, string);
}
pDC->SelectObject (pOldFont);
}
}
BOOL CHexView::OnPreparePrinting (CPrintInfo* pInfo)
{
return DoPreparePrinting (pInfo);
}
void CHexView::OnBeginPrinting (CDC* pDC, CPrintInfo* pInfo)
{
int nHeight = -((pDC->GetDeviceCaps (LOGPIXELSY) * 10) / 72);
m_printerFont.CreateFont (nHeight, 0, 0, 0, FW_NORMAL, 0, 0, 0,
DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Courier New");
TEXTMETRIC tm;
CFont* pOldFont = pDC->SelectObject (&m_printerFont);
pDC->GetTextMetrics (&tm);
m_cyPrinter = tm.tmHeight + tm.tmExternalLeading;
CSize size = pDC->GetTextExtent ("---------1---------2---------" \
"3---------4---------5---------6---------7---------8-", 81);
pDC->SelectObject (pOldFont);
m_nLinesPerPage = (pDC->GetDeviceCaps (VERTRES) -
(m_cyPrinter * (3 + (2 * PRINTMARGIN)))) / m_cyPrinter;
UINT nMaxPage = max (1, (m_nLinesTotal + (m_nLinesPerPage - 1)) /
m_nLinesPerPage);
pInfo->SetMaxPage (nMaxPage);
m_cxOffset = (pDC->GetDeviceCaps (HORZRES) - size.cx) / 2;
m_cxWidth = size.cx;
}
void CHexView::OnPrint (CDC* pDC, CPrintInfo* pInfo)
{
PrintPageHeader (pDC, pInfo->m_nCurPage);
PrintPage (pDC, pInfo->m_nCurPage);
}
void CHexView::OnEndPrinting (CDC* pDC, CPrintInfo* pInfo)
{
m_printerFont.DeleteObject ();
}
void CHexView::FormatLine (UINT nLine, CString& string)
{
BYTE b[17];
::FillMemory (b, 16, 32);
UINT nCount = GetDocument ()->GetBytes (nLine * 16, 16, b);
string.Format ("%0.8X %0.2X %0.2X %0.2X %0.2X %0.2X %0.2X " \
"%0.2X %0.2X - %0.2X %0.2X %0.2X %0.2X %0.2X %0.2X %0.2X " \
"%0.2X ", nLine * 16,
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]);
for (UINT i=0; i<nCount; i++) {
if (!::IsCharAlphaNumeric (b[i]))
b[i] = 0x2E;
}
b[nCount] = 0;
string += b;
if (nCount < 16) {
UINT pos1 = 59;
UINT pos2 = 60;
UINT j = 16 - nCount;
for (i=0; i<j; i++) {
string.SetAt (pos1, ' ');
string.SetAt (pos2, ' ');
pos1 -= 3;
pos2 -= 3;
if (pos1 == 35) {
string.SetAt (35, ' ');
string.SetAt (36, ' ');
pos1 = 33;
pos2 = 34;
}
}
}
}
void CHexView::PrintPageHeader (CDC* pDC, UINT nPageNumber)
{
CString strHeader = GetDocument ()->GetPathName ();
if (strHeader.GetLength () > 68)
strHeader = GetDocument ()->GetTitle ();
CString strPageNumber;
strPageNumber.Format ("Page %d", nPageNumber);
UINT nSpaces = 81 - strPageNumber.GetLength () -
strHeader.GetLength ();
for (UINT i=0; i<nSpaces; i++)
strHeader += ' ';
strHeader += strPageNumber;
UINT y = m_cyPrinter * PRINTMARGIN;
CFont* pOldFont = pDC->SelectObject (&m_printerFont);
pDC->TextOut (m_cxOffset, y, strHeader);
y += (m_cyPrinter * 3) / 2;
pDC->MoveTo (m_cxOffset, y);
pDC->LineTo (m_cxOffset + m_cxWidth, y);
pDC->SelectObject (pOldFont);
}
void CHexView::PrintPage (CDC* pDC, UINT nPageNumber)
{
if (m_nLinesTotal != 0) {
UINT nStart = (nPageNumber - 1) * m_nLinesPerPage;
UINT nEnd = min (m_nLinesTotal - 1, nStart + m_nLinesPerPage - 1);
CString string;
CFont* pOldFont = pDC->SelectObject (&m_printerFont);
UINT y;
for (UINT i=nStart; i<=nEnd; i++) {
FormatLine (i, string);
y = ((i - nStart) + PRINTMARGIN + 3) * m_cyPrinter;
pDC->TextOut (m_cxOffset, y, string);
}
pDC->SelectObject (pOldFont);
}
}
Figure 9 GetDeviceCaps Values That Query Print Device Parameters
Value | Description |
HORZRES | Returns the width of the printable page area in pixels |
VERTRES | Returns the height of the printable page area in pixels |
HORSIZE | Returns the width of the printable page area in millimeters |
VERTSIZE | Returns the height of the printable page area in millimeters |
LOGPIXELSX | Returns the number of pixels per inch in the horizontal direction (300 for a 300 dpi printer) |
LOGPIXELSY | Returns the number of pixels per inch in the vertical direction (300 for a 300 dpi printer) |
PHYSICALWIDTH | Returns the page width in pixels (2,550 for an 8.5 by 11-inch page on a 300 dpi printer) |
PHYSICALHEIGHT | Returns the page height in pixels (3,350 for an 8.5 by 11-inch page on a 300 dpi printer) |
PHYSICALOFFSETX | Returns the distance in pixels from the left of the page to the beginning of the page's printable area |
PHYSICALOFFSETY | Returns the distance in pixels from the top of the page to the beginning of the page's printable area |
TECHNOLOGY | Returns a value that identifies the type of output device that the DC pertains to (the most common return values are DT_RASDISPLAY for screens, DT_RASPRINTER for printers, and DT_PLOTTER for plotters) |
RASTERCAPS | Returns a series of bit flags identifying the level of GDI support provided by the printer driver (for example, an RC_BITBLT flag indicates that the printer support BitBlts, and RC_STRETCHBLT indicates that the printer supports StretchBlts) |
NUMCOLORS | Returns the number of colors that the printer supports (the return value is 2 for black-and-white printers) |
Figure 10 Enumerating Printers
#include <winspool.h>
·
·
·
DWORD dwSize, dwPrinters;
::EnumPrinters (PRINTER_ENUM_LOCAL, NULL, 5,
NULL, 0, &dwSize, &dwPrinters);
BYTE* pBuffer = new BYTE[dwSize];
::EnumPrinters (PRINTER_ENUM_LOCAL, NULL, 5,
pBuffer, dwSize, &dwSize, &dwPrinters);
if (dwPrinters != 0) {
PRINTER_INFO_5* pPrnInfo = (PRINTER_INFO_5*) pBuffer;
for (UINT i=0; i<dwPrinters; i++) {
pComboBox->AddString (pPrnInfo->pPrinterName);
pPrnInfo++;
}
}
delete[] pBuffer;
If a printer is selected from the combo box and you want to create a device context for it, you can pass the device name copied from the PRINTER_INFO_5 structure to CDC::CreateDC as follows:
CString strPrinterName;
int nIndex = pComboBox->GetCurSel ();
pComboBox->GetLBText (nIndex, strPrinterName);
CDC dc;
dc.CreateDC (NULL, strPrinterName, NULL, NULL);