// Windows Template Library - WTL version 8.0 // Copyright (C) Microsoft Corporation. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php) // which can be found in the file CPL.TXT at the root of this distribution. // By using this software in any fashion, you are agreeing to be bound by // the terms of this license. You must not remove this notice, or // any other, from this software. #ifndef __ATLPRINT_H__ #define __ATLPRINT_H__ #pragma once #ifndef __cplusplus #error ATL requires C++ compilation (use a .cpp suffix) #endif #ifdef _WIN32_WCE #error atlprint.h is not supported on Windows CE #endif #ifndef __ATLAPP_H__ #error atlprint.h requires atlapp.h to be included first #endif #ifndef __ATLWIN_H__ #error atlprint.h requires atlwin.h to be included first #endif /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CPrinterInfo // CPrinterT // CDevModeT // CPrinterDC // CPrintJobInfo // CPrintJob // CPrintPreview // CPrintPreviewWindowImpl // CPrintPreviewWindow // CZoomPrintPreviewWindowImpl // CZoomPrintPreviewWindow namespace WTL { /////////////////////////////////////////////////////////////////////////////// // CPrinterInfo - This class wraps all of the PRINTER_INFO_* structures // and provided by ::GetPrinter. template class _printer_info { public: typedef void infotype; }; template <> class _printer_info<1> { public: typedef PRINTER_INFO_1 infotype; }; template <> class _printer_info<2> { public: typedef PRINTER_INFO_2 infotype; }; template <> class _printer_info<3> { public: typedef PRINTER_INFO_3 infotype; }; template <> class _printer_info<4> { public: typedef PRINTER_INFO_4 infotype; }; template <> class _printer_info<5> { public: typedef PRINTER_INFO_5 infotype; }; template <> class _printer_info<6> { public: typedef PRINTER_INFO_6 infotype; }; template <> class _printer_info<7> { public: typedef PRINTER_INFO_7 infotype; }; // these are not in the old (vc6.0) headers #ifdef _ATL_USE_NEW_PRINTER_INFO template <> class _printer_info<8> { public: typedef PRINTER_INFO_8 infotype; }; template <> class _printer_info<9> { public: typedef PRINTER_INFO_9 infotype; }; #endif // _ATL_USE_NEW_PRINTER_INFO template class CPrinterInfo { public: // Data members typename _printer_info::infotype* m_pi; // Constructor/destructor CPrinterInfo() : m_pi(NULL) { } CPrinterInfo(HANDLE hPrinter) : m_pi(NULL) { GetPrinterInfo(hPrinter); } ~CPrinterInfo() { Cleanup(); } // Operations bool GetPrinterInfo(HANDLE hPrinter) { Cleanup(); return GetPrinterInfoHelper(hPrinter, (BYTE**)&m_pi, t_nInfo); } // Implementation void Cleanup() { delete [] (BYTE*)m_pi; m_pi = NULL; } static bool GetPrinterInfoHelper(HANDLE hPrinter, BYTE** pi, int nIndex) { ATLASSERT(pi != NULL); DWORD dw = 0; BYTE* pb = NULL; ::GetPrinter(hPrinter, nIndex, NULL, 0, &dw); if (dw > 0) { ATLTRY(pb = new BYTE[dw]); if (pb != NULL) { memset(pb, 0, dw); DWORD dwNew; if (!::GetPrinter(hPrinter, nIndex, pb, dw, &dwNew)) { delete [] pb; pb = NULL; } } } *pi = pb; return (pb != NULL); } }; /////////////////////////////////////////////////////////////////////////////// // CPrinter - Wrapper class for a HANDLE to a printer template class CPrinterT { public: // Data members HANDLE m_hPrinter; // Constructor/destructor CPrinterT(HANDLE hPrinter = NULL) : m_hPrinter(hPrinter) { } ~CPrinterT() { ClosePrinter(); } // Operations CPrinterT& operator =(HANDLE hPrinter) { if (hPrinter != m_hPrinter) { ClosePrinter(); m_hPrinter = hPrinter; } return *this; } bool IsNull() const { return (m_hPrinter == NULL); } bool OpenPrinter(HANDLE hDevNames, const DEVMODE* pDevMode = NULL) { bool b = false; DEVNAMES* pdn = (DEVNAMES*)::GlobalLock(hDevNames); if (pdn != NULL) { LPTSTR lpszPrinterName = (LPTSTR)pdn + pdn->wDeviceOffset; b = OpenPrinter(lpszPrinterName, pDevMode); ::GlobalUnlock(hDevNames); } return b; } bool OpenPrinter(LPCTSTR lpszPrinterName, const DEVMODE* pDevMode = NULL) { ClosePrinter(); PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE }; ::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs); return (m_hPrinter != NULL); } bool OpenPrinter(LPCTSTR lpszPrinterName, PRINTER_DEFAULTS* pprintdefs) { ClosePrinter(); ::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, pprintdefs); return (m_hPrinter != NULL); } bool OpenDefaultPrinter(const DEVMODE* pDevMode = NULL) { ClosePrinter(); const int cchBuff = 512; TCHAR buffer[cchBuff]; buffer[0] = 0; ::GetProfileString(_T("windows"), _T("device"), _T(",,,"), buffer, cchBuff); int nLen = lstrlen(buffer); if (nLen != 0) { LPTSTR lpsz = buffer; while (*lpsz) { if (*lpsz == _T(',')) { *lpsz = 0; break; } lpsz = CharNext(lpsz); } PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE }; ::OpenPrinter(buffer, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs); } return m_hPrinter != NULL; } void ClosePrinter() { if (m_hPrinter != NULL) { if (t_bManaged) ::ClosePrinter(m_hPrinter); m_hPrinter = NULL; } } bool PrinterProperties(HWND hWnd = NULL) { if (hWnd == NULL) hWnd = ::GetActiveWindow(); return !!::PrinterProperties(hWnd, m_hPrinter); } HANDLE CopyToHDEVNAMES() const { HANDLE h = NULL; CPrinterInfo<5> pinfon5; CPrinterInfo<2> pinfon2; LPTSTR lpszPrinterName = NULL; // Some printers fail for PRINTER_INFO_5 in some situations if (pinfon5.GetPrinterInfo(m_hPrinter)) lpszPrinterName = pinfon5.m_pi->pPrinterName; else if (pinfon2.GetPrinterInfo(m_hPrinter)) lpszPrinterName = pinfon2.m_pi->pPrinterName; if (lpszPrinterName != NULL) { int nLen = sizeof(DEVNAMES) + (lstrlen(lpszPrinterName) + 1) * sizeof(TCHAR); h = ::GlobalAlloc(GMEM_MOVEABLE, nLen); BYTE* pv = (BYTE*)::GlobalLock(h); DEVNAMES* pdev = (DEVNAMES*)pv; if (pv != NULL) { memset(pv, 0, nLen); pdev->wDeviceOffset = sizeof(DEVNAMES) / sizeof(TCHAR); pv = pv + sizeof(DEVNAMES); // now points to end SecureHelper::strcpy_x((LPTSTR)pv, lstrlen(lpszPrinterName) + 1, lpszPrinterName); ::GlobalUnlock(h); } } return h; } HDC CreatePrinterDC(const DEVMODE* pdm = NULL) const { CPrinterInfo<5> pinfo5; CPrinterInfo<2> pinfo2; HDC hDC = NULL; LPTSTR lpszPrinterName = NULL; // Some printers fail for PRINTER_INFO_5 in some situations if (pinfo5.GetPrinterInfo(m_hPrinter)) lpszPrinterName = pinfo5.m_pi->pPrinterName; else if (pinfo2.GetPrinterInfo(m_hPrinter)) lpszPrinterName = pinfo2.m_pi->pPrinterName; if (lpszPrinterName != NULL) hDC = ::CreateDC(NULL, lpszPrinterName, NULL, pdm); return hDC; } HDC CreatePrinterIC(const DEVMODE* pdm = NULL) const { CPrinterInfo<5> pinfo5; CPrinterInfo<2> pinfo2; HDC hDC = NULL; LPTSTR lpszPrinterName = NULL; // Some printers fail for PRINTER_INFO_5 in some situations if (pinfo5.GetPrinterInfo(m_hPrinter)) lpszPrinterName = pinfo5.m_pi->pPrinterName; else if (pinfo2.GetPrinterInfo(m_hPrinter)) lpszPrinterName = pinfo2.m_pi->pPrinterName; if (lpszPrinterName != NULL) hDC = ::CreateIC(NULL, lpszPrinterName, NULL, pdm); return hDC; } void Attach(HANDLE hPrinter) { ClosePrinter(); m_hPrinter = hPrinter; } HANDLE Detach() { HANDLE hPrinter = m_hPrinter; m_hPrinter = NULL; return hPrinter; } operator HANDLE() const { return m_hPrinter; } }; typedef CPrinterT CPrinterHandle; typedef CPrinterT CPrinter; /////////////////////////////////////////////////////////////////////////////// // CDevMode - Wrapper class for DEVMODE template class CDevModeT { public: // Data members HANDLE m_hDevMode; DEVMODE* m_pDevMode; // Constructor/destructor CDevModeT(HANDLE hDevMode = NULL) : m_hDevMode(hDevMode) { m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL; } ~CDevModeT() { Cleanup(); } // Operations CDevModeT& operator =(HANDLE hDevMode) { Attach(hDevMode); return *this; } void Attach(HANDLE hDevModeNew) { Cleanup(); m_hDevMode = hDevModeNew; m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL; } HANDLE Detach() { if (m_hDevMode != NULL) ::GlobalUnlock(m_hDevMode); HANDLE hDevMode = m_hDevMode; m_hDevMode = NULL; return hDevMode; } bool IsNull() const { return (m_hDevMode == NULL); } bool CopyFromPrinter(HANDLE hPrinter) { CPrinterInfo<2> pinfo; bool b = pinfo.GetPrinterInfo(hPrinter); if (b) b = CopyFromDEVMODE(pinfo.m_pi->pDevMode); return b; } bool CopyFromDEVMODE(const DEVMODE* pdm) { if (pdm == NULL) return false; int nSize = pdm->dmSize + pdm->dmDriverExtra; HANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize); if (h != NULL) { void* p = ::GlobalLock(h); SecureHelper::memcpy_x(p, nSize, pdm, nSize); ::GlobalUnlock(h); } Attach(h); return (h != NULL); } bool CopyFromHDEVMODE(HANDLE hdm) { bool b = false; if (hdm != NULL) { DEVMODE* pdm = (DEVMODE*)::GlobalLock(hdm); b = CopyFromDEVMODE(pdm); ::GlobalUnlock(hdm); } return b; } HANDLE CopyToHDEVMODE() { if ((m_hDevMode == NULL) || (m_pDevMode == NULL)) return NULL; int nSize = m_pDevMode->dmSize + m_pDevMode->dmDriverExtra; HANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize); if (h != NULL) { void* p = ::GlobalLock(h); SecureHelper::memcpy_x(p, nSize, m_pDevMode, nSize); ::GlobalUnlock(h); } return h; } // If this devmode was for another printer, this will create a new devmode // based on the existing devmode, but retargeted at the new printer bool UpdateForNewPrinter(HANDLE hPrinter) { bool bRet = false; LONG nLen = ::DocumentProperties(NULL, hPrinter, NULL, NULL, NULL, 0); CTempBuffer buff; DEVMODE* pdm = buff.AllocateBytes(nLen); if(pdm != NULL) { memset(pdm, 0, nLen); LONG l = ::DocumentProperties(NULL, hPrinter, NULL, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER); if (l == IDOK) bRet = CopyFromDEVMODE(pdm); } return bRet; } bool DocumentProperties(HANDLE hPrinter, HWND hWnd = NULL) { CPrinterInfo<1> pi; pi.GetPrinterInfo(hPrinter); if (hWnd == NULL) hWnd = ::GetActiveWindow(); bool bRet = false; LONG nLen = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, NULL, NULL, 0); CTempBuffer buff; DEVMODE* pdm = buff.AllocateBytes(nLen); if(pdm != NULL) { memset(pdm, 0, nLen); LONG l = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER | DM_PROMPT); if (l == IDOK) bRet = CopyFromDEVMODE(pdm); } return bRet; } operator HANDLE() const { return m_hDevMode; } operator DEVMODE*() const { return m_pDevMode; } // Implementation void Cleanup() { if (m_hDevMode != NULL) { ::GlobalUnlock(m_hDevMode); if(t_bManaged) ::GlobalFree(m_hDevMode); m_hDevMode = NULL; } } }; typedef CDevModeT CDevModeHandle; typedef CDevModeT CDevMode; /////////////////////////////////////////////////////////////////////////////// // CPrinterDC class CPrinterDC : public CDC { public: // Constructors/destructor CPrinterDC() { CPrinter printer; printer.OpenDefaultPrinter(); Attach(printer.CreatePrinterDC()); ATLASSERT(m_hDC != NULL); } CPrinterDC(HANDLE hPrinter, const DEVMODE* pdm = NULL) { CPrinterHandle p; p.Attach(hPrinter); Attach(p.CreatePrinterDC(pdm)); ATLASSERT(m_hDC != NULL); } ~CPrinterDC() { DeleteDC(); } }; /////////////////////////////////////////////////////////////////////////////// // CPrintJob - Wraps a set of tasks for a specific printer (StartDoc/EndDoc) // Handles aborting, background printing // Defines callbacks used by CPrintJob (not a COM interface) class ATL_NO_VTABLE IPrintJobInfo { public: virtual void BeginPrintJob(HDC hDC) = 0; // allocate handles needed, etc. virtual void EndPrintJob(HDC hDC, bool bAborted) = 0; // free handles, etc. virtual void PrePrintPage(UINT nPage, HDC hDC) = 0; virtual bool PrintPage(UINT nPage, HDC hDC) = 0; virtual void PostPrintPage(UINT nPage, HDC hDC) = 0; // If you want per page devmodes, return the DEVMODE* to use for nPage. // You can optimize by only returning a new DEVMODE* when it is different // from the one for nLastPage, otherwise return NULL. // When nLastPage==0, the current DEVMODE* will be the default passed to // StartPrintJob. // Note: During print preview, nLastPage will always be "0". virtual DEVMODE* GetNewDevModeForPage(UINT nLastPage, UINT nPage) = 0; virtual bool IsValidPage(UINT nPage) = 0; }; // Provides a default implementatin for IPrintJobInfo // Typically, MI'd into a document or view class class ATL_NO_VTABLE CPrintJobInfo : public IPrintJobInfo { public: virtual void BeginPrintJob(HDC /*hDC*/) // allocate handles needed, etc { } virtual void EndPrintJob(HDC /*hDC*/, bool /*bAborted*/) // free handles, etc { } virtual void PrePrintPage(UINT /*nPage*/, HDC hDC) { m_nPJState = ::SaveDC(hDC); } virtual bool PrintPage(UINT /*nPage*/, HDC /*hDC*/) = 0; virtual void PostPrintPage(UINT /*nPage*/, HDC hDC) { RestoreDC(hDC, m_nPJState); } virtual DEVMODE* GetNewDevModeForPage(UINT /*nLastPage*/, UINT /*nPage*/) { return NULL; } virtual bool IsValidPage(UINT /*nPage*/) { return true; } // Implementation - data int m_nPJState; }; class CPrintJob { public: // Data members CPrinterHandle m_printer; IPrintJobInfo* m_pInfo; DEVMODE* m_pDefDevMode; DOCINFO m_docinfo; int m_nJobID; bool m_bCancel; bool m_bComplete; unsigned long m_nStartPage; unsigned long m_nEndPage; // Constructor/destructor CPrintJob() : m_nJobID(0), m_bCancel(false), m_bComplete(true) { } ~CPrintJob() { ATLASSERT(IsJobComplete()); // premature destruction? } // Operations bool IsJobComplete() const { return m_bComplete; } bool StartPrintJob(bool bBackground, HANDLE hPrinter, DEVMODE* pDefaultDevMode, IPrintJobInfo* pInfo, LPCTSTR lpszDocName, unsigned long nStartPage, unsigned long nEndPage, bool bPrintToFile = false, LPCTSTR lpstrOutputFile = NULL) { ATLASSERT(m_bComplete); // previous job not done yet? if (pInfo == NULL) return false; memset(&m_docinfo, 0, sizeof(m_docinfo)); m_docinfo.cbSize = sizeof(m_docinfo); m_docinfo.lpszDocName = lpszDocName; m_pInfo = pInfo; m_nStartPage = nStartPage; m_nEndPage = nEndPage; m_printer.Attach(hPrinter); m_pDefDevMode = pDefaultDevMode; m_bComplete = false; if(bPrintToFile) m_docinfo.lpszOutput = (lpstrOutputFile != NULL) ? lpstrOutputFile : _T("FILE:"); if (!bBackground) { m_bComplete = true; return StartHelper(); } // Create a thread and return DWORD dwThreadID = 0; #if !defined(_ATL_MIN_CRT) && defined(_MT) HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, (UINT (WINAPI*)(void*))StartProc, this, 0, (UINT*)&dwThreadID); #else HANDLE hThread = ::CreateThread(NULL, 0, StartProc, (void*)this, 0, &dwThreadID); #endif if (hThread == NULL) return false; ::CloseHandle(hThread); return true; } // Implementation static DWORD WINAPI StartProc(void* p) { CPrintJob* pThis = (CPrintJob*)p; pThis->StartHelper(); pThis->m_bComplete = true; return 0; } bool StartHelper() { CDC dcPrinter; dcPrinter.Attach(m_printer.CreatePrinterDC(m_pDefDevMode)); if (dcPrinter.IsNull()) return false; m_nJobID = ::StartDoc(dcPrinter, &m_docinfo); if (m_nJobID <= 0) return false; m_pInfo->BeginPrintJob(dcPrinter); // print all the pages now unsigned long nLastPage = 0; for (unsigned long nPage = m_nStartPage; nPage <= m_nEndPage; nPage++) { if (!m_pInfo->IsValidPage(nPage)) break; DEVMODE* pdm = m_pInfo->GetNewDevModeForPage(nLastPage, nPage); if (pdm != NULL) dcPrinter.ResetDC(pdm); dcPrinter.StartPage(); m_pInfo->PrePrintPage(nPage, dcPrinter); if (!m_pInfo->PrintPage(nPage, dcPrinter)) m_bCancel = true; m_pInfo->PostPrintPage(nPage, dcPrinter); dcPrinter.EndPage(); if (m_bCancel) break; nLastPage = nPage; } m_pInfo->EndPrintJob(dcPrinter, m_bCancel); if (m_bCancel) ::AbortDoc(dcPrinter); else ::EndDoc(dcPrinter); m_nJobID = 0; return true; } // Cancels a print job. Can be called asynchronously. void CancelPrintJob() { m_bCancel = true; } }; /////////////////////////////////////////////////////////////////////////////// // CPrintPreview - Adds print preview support to an existing window class CPrintPreview { public: // Data members IPrintJobInfo* m_pInfo; CPrinterHandle m_printer; CEnhMetaFile m_meta; DEVMODE* m_pDefDevMode; DEVMODE* m_pCurDevMode; SIZE m_sizeCurPhysOffset; // Constructor CPrintPreview() : m_pInfo(NULL), m_pDefDevMode(NULL), m_pCurDevMode(NULL) { m_sizeCurPhysOffset.cx = 0; m_sizeCurPhysOffset.cy = 0; } // Operations void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, IPrintJobInfo* pji) { m_printer.Attach(hPrinter); m_pDefDevMode = pDefaultDevMode; m_pInfo = pji; m_nCurPage = 0; m_pCurDevMode = NULL; } void SetEnhMetaFile(HENHMETAFILE hEMF) { m_meta = hEMF; } void SetPage(int nPage) { if (!m_pInfo->IsValidPage(nPage)) return; m_nCurPage = nPage; m_pCurDevMode = m_pInfo->GetNewDevModeForPage(0, nPage); if (m_pCurDevMode == NULL) m_pCurDevMode = m_pDefDevMode; CDC dcPrinter = m_printer.CreatePrinterDC(m_pCurDevMode); int iWidth = dcPrinter.GetDeviceCaps(PHYSICALWIDTH); int iHeight = dcPrinter.GetDeviceCaps(PHYSICALHEIGHT); int nLogx = dcPrinter.GetDeviceCaps(LOGPIXELSX); int nLogy = dcPrinter.GetDeviceCaps(LOGPIXELSY); RECT rcMM = { 0, 0, ::MulDiv(iWidth, 2540, nLogx), ::MulDiv(iHeight, 2540, nLogy) }; m_sizeCurPhysOffset.cx = dcPrinter.GetDeviceCaps(PHYSICALOFFSETX); m_sizeCurPhysOffset.cy = dcPrinter.GetDeviceCaps(PHYSICALOFFSETY); CEnhMetaFileDC dcMeta(dcPrinter, &rcMM); m_pInfo->PrePrintPage(nPage, dcMeta); m_pInfo->PrintPage(nPage, dcMeta); m_pInfo->PostPrintPage(nPage, dcMeta); m_meta.Attach(dcMeta.Close()); } void GetPageRect(RECT& rc, LPRECT prc) { int x1 = rc.right-rc.left; int y1 = rc.bottom - rc.top; if ((x1 < 0) || (y1 < 0)) return; CEnhMetaFileInfo emfinfo(m_meta); ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader(); // Compute whether we are OK vertically or horizontally int x2 = pmh->szlDevice.cx; int y2 = pmh->szlDevice.cy; int y1p = MulDiv(x1, y2, x2); int x1p = MulDiv(y1, x2, y2); ATLASSERT((x1p <= x1) || (y1p <= y1)); if (x1p <= x1) { prc->left = rc.left + (x1 - x1p) / 2; prc->right = prc->left + x1p; prc->top = rc.top; prc->bottom = rc.bottom; } else { prc->left = rc.left; prc->right = rc.right; prc->top = rc.top + (y1 - y1p) / 2; prc->bottom = prc->top + y1p; } } // Painting helpers void DoPaint(CDCHandle dc) { // this one is not used } void DoPaint(CDCHandle dc, RECT& rc) { CEnhMetaFileInfo emfinfo(m_meta); ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader(); int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx); int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy); dc.OffsetWindowOrg(-nOffsetX, -nOffsetY); dc.PlayMetaFile(m_meta, &rc); } // Implementation - data int m_nCurPage; }; /////////////////////////////////////////////////////////////////////////////// // CPrintPreviewWindow - Implements a print preview window template class ATL_NO_VTABLE CPrintPreviewWindowImpl : public ATL::CWindowImpl, public CPrintPreview { public: DECLARE_WND_CLASS_EX(NULL, CS_VREDRAW | CS_HREDRAW, -1) enum { m_cxOffset = 10, m_cyOffset = 10 }; // Constructor CPrintPreviewWindowImpl() : m_nMaxPage(0), m_nMinPage(0) { } // Operations void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, IPrintJobInfo* pji, int nMinPage, int nMaxPage) { CPrintPreview::SetPrintPreviewInfo(hPrinter, pDefaultDevMode, pji); m_nMinPage = nMinPage; m_nMaxPage = nMaxPage; } bool NextPage() { if (m_nCurPage == m_nMaxPage) return false; SetPage(m_nCurPage + 1); Invalidate(); return true; } bool PrevPage() { if (m_nCurPage == m_nMinPage) return false; if (m_nCurPage == 0) return false; SetPage(m_nCurPage - 1); Invalidate(); return true; } // Message map and handlers BEGIN_MSG_MAP(CPrintPreviewWindowImpl) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) MESSAGE_HANDLER(WM_PAINT, OnPaint) MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) END_MSG_MAP() LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return 1; // no need for the background } LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); RECT rc = { 0 }; if(wParam != NULL) { pT->DoPrePaint((HDC)wParam, rc); pT->DoPaint((HDC)wParam, rc); } else { CPaintDC dc(m_hWnd); pT->DoPrePaint(dc.m_hDC, rc); pT->DoPaint(dc.m_hDC, rc); } return 0; } // Painting helper void DoPrePaint(CDCHandle dc, RECT& rc) { RECT rcClient = { 0 }; GetClientRect(&rcClient); RECT rcArea = rcClient; T* pT = static_cast(this); pT; // avoid level 4 warning ::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset); if (rcArea.left > rcArea.right) rcArea.right = rcArea.left; if (rcArea.top > rcArea.bottom) rcArea.bottom = rcArea.top; GetPageRect(rcArea, &rc); CRgn rgn1, rgn2; rgn1.CreateRectRgnIndirect(&rc); rgn2.CreateRectRgnIndirect(&rcClient); rgn2.CombineRgn(rgn1, RGN_DIFF); dc.SelectClipRgn(rgn2); dc.FillRect(&rcClient, COLOR_BTNSHADOW); dc.SelectClipRgn(NULL); dc.FillRect(&rc, (HBRUSH)::GetStockObject(WHITE_BRUSH)); } // Implementation - data int m_nMinPage; int m_nMaxPage; }; class CPrintPreviewWindow : public CPrintPreviewWindowImpl { public: DECLARE_WND_CLASS_EX(_T("WTL_PrintPreview"), CS_VREDRAW | CS_HREDRAW, -1) }; /////////////////////////////////////////////////////////////////////////////// // CZoomPrintPreviewWindowImpl - Implements print preview window with zooming #ifdef __ATLSCRL_H__ template class ATL_NO_VTABLE CZoomPrintPreviewWindowImpl : public CPrintPreviewWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T > { public: bool m_bSized; CZoomPrintPreviewWindowImpl() { SetScrollExtendedStyle(SCRL_DISABLENOSCROLL); InitZoom(); } // should be called to reset data members before recreating window void InitZoom() { m_bSized = false; m_nZoomMode = ZOOMMODE_OFF; m_fZoomScaleMin = 1.0; m_fZoomScale = 1.0; } BEGIN_MSG_MAP(CZoomPrintPreviewWindowImpl) MESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor) MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll) MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll) MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel) #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel) #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange) MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown) MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove) MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp) MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) MESSAGE_HANDLER(WM_PAINT, OnPaint) MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) ALT_MSG_MAP(1) COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp) COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown) COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop) COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom) COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft) COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft) COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight) COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft) COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight) END_MSG_MAP() LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { SIZE sizeClient = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; POINT ptOffset = m_ptOffset; SIZE sizeAll = m_sizeAll; SetScrollSize(sizeClient); if(sizeAll.cx > 0) ptOffset.x = ::MulDiv(ptOffset.x, m_sizeAll.cx, sizeAll.cx); if(sizeAll.cy > 0) ptOffset.y = ::MulDiv(ptOffset.y, m_sizeAll.cy, sizeAll.cy); SetScrollOffset(ptOffset); CScrollImpl< T >::OnSize(uMsg, wParam, lParam, bHandled); if(!m_bSized) { m_bSized = true; T* pT = static_cast(this); pT->ShowScrollBar(SB_HORZ, TRUE); pT->ShowScrollBar(SB_VERT, TRUE); } return 0; } LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return 1; } LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); RECT rc = { 0 }; if(wParam != NULL) { CDCHandle dc = (HDC)wParam; int nMapModeSav = dc.GetMapMode(); dc.SetMapMode(MM_ANISOTROPIC); SIZE szWindowExt = { 0, 0 }; dc.SetWindowExt(m_sizeLogAll, &szWindowExt); SIZE szViewportExt = { 0, 0 }; dc.SetViewportExt(m_sizeAll, &szViewportExt); POINT ptViewportOrg = { 0, 0 }; dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg); pT->DoPrePaint(dc, rc); pT->DoPaint(dc, rc); dc.SetMapMode(nMapModeSav); dc.SetWindowExt(szWindowExt); dc.SetViewportExt(szViewportExt); dc.SetViewportOrg(ptViewportOrg); } else { CPaintDC dc(pT->m_hWnd); pT->PrepareDC(dc.m_hDC); pT->DoPrePaint(dc.m_hDC, rc); pT->DoPaint(dc.m_hDC, rc); } return 0; } // Painting helpers void DoPaint(CDCHandle dc) { // this one is not used } void DoPrePaint(CDCHandle dc, RECT& rc) { RECT rcClient; GetClientRect(&rcClient); RECT rcArea = rcClient; T* pT = static_cast(this); pT; // avoid level 4 warning ::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset); if (rcArea.left > rcArea.right) rcArea.right = rcArea.left; if (rcArea.top > rcArea.bottom) rcArea.bottom = rcArea.top; GetPageRect(rcArea, &rc); HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW)); dc.PatBlt(rcClient.left, rcClient.top, rc.left - rcClient.left, rcClient.bottom - rcClient.top, PATCOPY); dc.PatBlt(rc.left, rcClient.top, rc.right - rc.left, rc.top - rcClient.top, PATCOPY); dc.PatBlt(rc.right, rcClient.top, rcClient.right - rc.right, rcClient.bottom - rcClient.top, PATCOPY); dc.PatBlt(rc.left, rc.bottom, rc.right - rc.left, rcClient.bottom - rc.bottom, PATCOPY); dc.SelectBrush((HBRUSH)::GetStockObject(WHITE_BRUSH)); dc.PatBlt(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY); dc.SelectBrush(::GetSysColorBrush(COLOR_3DDKSHADOW)); dc.PatBlt(rc.right, rc.top + 4, 4, rc.bottom - rc.top, PATCOPY); dc.PatBlt(rc.left + 4, rc.bottom, rc.right - rc.left, 4, PATCOPY); dc.SelectBrush(hbrOld); } void DoPaint(CDCHandle dc, RECT& rc) { CEnhMetaFileInfo emfinfo(m_meta); ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader(); int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx); int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy); dc.OffsetWindowOrg(-nOffsetX, -nOffsetY); dc.PlayMetaFile(m_meta, &rc); } }; class CZoomPrintPreviewWindow : public CZoomPrintPreviewWindowImpl { public: DECLARE_WND_CLASS_EX(_T("WTL_ZoomPrintPreview"), CS_VREDRAW | CS_HREDRAW, -1) }; #endif // __ATLSCRL_H__ }; // namespace WTL #endif // __ATLPRINT_H__