1 // Windows Template Library - WTL version 10.0
2 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.
3 //
4 // This file is a part of the Windows Template Library.
5 // The use and distribution terms for this software are covered by the
6 // Microsoft Public License (http://opensource.org/licenses/MS-PL)
7 // which can be found in the file MS-PL.txt at the root folder.
8 
9 #ifndef __ATLPRINT_H__
10 #define __ATLPRINT_H__
11 
12 #pragma once
13 
14 #ifndef __ATLAPP_H__
15 	#error atlprint.h requires atlapp.h to be included first
16 #endif
17 
18 #ifndef __ATLWIN_H__
19 	#error atlprint.h requires atlwin.h to be included first
20 #endif
21 
22 #include <winspool.h>
23 
24 
25 ///////////////////////////////////////////////////////////////////////////////
26 // Classes in this file:
27 //
28 // CPrinterInfo<t_nInfo>
29 // CPrinterT<t_bManaged>
30 // CDevModeT<t_bManaged>
31 // CPrinterDC
32 // CPrintJobInfo
33 // CPrintJob
34 // CPrintPreview
35 // CPrintPreviewWindowImpl<T, TBase, TWinTraits>
36 // CPrintPreviewWindow
37 // CZoomPrintPreviewWindowImpl<T, TBase, TWinTraits>
38 // CZoomPrintPreviewWindow
39 
40 namespace WTL
41 {
42 
43 ///////////////////////////////////////////////////////////////////////////////
44 // CPrinterInfo - This class wraps all of the PRINTER_INFO_* structures
45 //                and provided by ::GetPrinter.
46 
47 template <unsigned int t_nInfo>
48 class _printer_info
49 {
50 public:
51 	typedef void infotype;
52 };
53 
54 template <> class _printer_info<1> { public: typedef PRINTER_INFO_1 infotype; };
55 template <> class _printer_info<2> { public: typedef PRINTER_INFO_2 infotype; };
56 template <> class _printer_info<3> { public: typedef PRINTER_INFO_3 infotype; };
57 template <> class _printer_info<4> { public: typedef PRINTER_INFO_4 infotype; };
58 template <> class _printer_info<5> { public: typedef PRINTER_INFO_5 infotype; };
59 template <> class _printer_info<6> { public: typedef PRINTER_INFO_6 infotype; };
60 template <> class _printer_info<7> { public: typedef PRINTER_INFO_7 infotype; };
61 template <> class _printer_info<8> { public: typedef PRINTER_INFO_8 infotype; };
62 template <> class _printer_info<9> { public: typedef PRINTER_INFO_9 infotype; };
63 
64 
65 template <unsigned int t_nInfo>
66 class CPrinterInfo
67 {
68 public:
69 // Data members
70 	typename _printer_info<t_nInfo>::infotype* m_pi;
71 
72 // Constructor/destructor
CPrinterInfo()73 	CPrinterInfo() : m_pi(NULL)
74 	{ }
75 
CPrinterInfo(HANDLE hPrinter)76 	CPrinterInfo(HANDLE hPrinter) : m_pi(NULL)
77 	{
78 		GetPrinterInfo(hPrinter);
79 	}
80 
~CPrinterInfo()81 	~CPrinterInfo()
82 	{
83 		Cleanup();
84 	}
85 
86 // Operations
GetPrinterInfo(HANDLE hPrinter)87 	bool GetPrinterInfo(HANDLE hPrinter)
88 	{
89 		Cleanup();
90 		return GetPrinterInfoHelper(hPrinter, (BYTE**)&m_pi, t_nInfo);
91 	}
92 
93 // Implementation
Cleanup()94 	void Cleanup()
95 	{
96 		delete [] (BYTE*)m_pi;
97 		m_pi = NULL;
98 	}
99 
GetPrinterInfoHelper(HANDLE hPrinter,BYTE ** pi,int nIndex)100 	static bool GetPrinterInfoHelper(HANDLE hPrinter, BYTE** pi, int nIndex)
101 	{
102 		ATLASSERT(pi != NULL);
103 		DWORD dw = 0;
104 		BYTE* pb = NULL;
105 		::GetPrinter(hPrinter, nIndex, NULL, 0, &dw);
106 		if (dw > 0)
107 		{
108 			ATLTRY(pb = new BYTE[dw]);
109 			if (pb != NULL)
110 			{
111 				memset(pb, 0, dw);
112 				DWORD dwNew;
113 				if (!::GetPrinter(hPrinter, nIndex, pb, dw, &dwNew))
114 				{
115 					delete [] pb;
116 					pb = NULL;
117 				}
118 			}
119 		}
120 		*pi = pb;
121 		return (pb != NULL);
122 	}
123 };
124 
125 
126 ///////////////////////////////////////////////////////////////////////////////
127 // CPrinter - Wrapper class for a HANDLE to a printer
128 
129 template <bool t_bManaged>
130 class CPrinterT
131 {
132 public:
133 // Data members
134 	HANDLE m_hPrinter;
135 
136 // Constructor/destructor
m_hPrinter(hPrinter)137 	CPrinterT(HANDLE hPrinter = NULL) : m_hPrinter(hPrinter)
138 	{ }
139 
~CPrinterT()140 	~CPrinterT()
141 	{
142 		ClosePrinter();
143 	}
144 
145 // Operations
146 	CPrinterT& operator =(HANDLE hPrinter)
147 	{
148 		if (hPrinter != m_hPrinter)
149 		{
150 			ClosePrinter();
151 			m_hPrinter = hPrinter;
152 		}
153 		return *this;
154 	}
155 
IsNull()156 	bool IsNull() const { return (m_hPrinter == NULL); }
157 
158 	bool OpenPrinter(HANDLE hDevNames, const DEVMODE* pDevMode = NULL)
159 	{
160 		bool b = false;
161 		DEVNAMES* pdn = (DEVNAMES*)::GlobalLock(hDevNames);
162 		if (pdn != NULL)
163 		{
164 			LPTSTR lpszPrinterName = (LPTSTR)pdn + pdn->wDeviceOffset;
165 			b = OpenPrinter(lpszPrinterName, pDevMode);
166 			::GlobalUnlock(hDevNames);
167 		}
168 		return b;
169 	}
170 
171 	bool OpenPrinter(LPCTSTR lpszPrinterName, const DEVMODE* pDevMode = NULL)
172 	{
173 		ClosePrinter();
174 		PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE };
175 		::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs);
176 
177 		return (m_hPrinter != NULL);
178 	}
179 
OpenPrinter(LPCTSTR lpszPrinterName,PRINTER_DEFAULTS * pprintdefs)180 	bool OpenPrinter(LPCTSTR lpszPrinterName, PRINTER_DEFAULTS* pprintdefs)
181 	{
182 		ClosePrinter();
183 		::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, pprintdefs);
184 		return (m_hPrinter != NULL);
185 	}
186 
187 	bool OpenDefaultPrinter(const DEVMODE* pDevMode = NULL)
188 	{
189 		ClosePrinter();
190 
191 		DWORD cchBuff = 0;
192 		::GetDefaultPrinter(NULL, &cchBuff);
193 		TCHAR* pszBuff = new TCHAR[cchBuff];
194 		BOOL bRet = ::GetDefaultPrinter(pszBuff, &cchBuff);
195 		if(bRet != FALSE)
196 		{
197 			PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE };
198 			::OpenPrinter(pszBuff, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs);
199 		}
200 		delete [] pszBuff;
201 
202 		return m_hPrinter != NULL;
203 	}
204 
ClosePrinter()205 	void ClosePrinter()
206 	{
207 		if (m_hPrinter != NULL)
208 		{
209 			if (t_bManaged)
210 				::ClosePrinter(m_hPrinter);
211 			m_hPrinter = NULL;
212 		}
213 	}
214 
215 	bool PrinterProperties(HWND hWnd = NULL)
216 	{
217 		if (hWnd == NULL)
218 			hWnd = ::GetActiveWindow();
219 		return !!::PrinterProperties(hWnd, m_hPrinter);
220 	}
221 
CopyToHDEVNAMES()222 	HANDLE CopyToHDEVNAMES() const
223 	{
224 		HANDLE hDevNames = NULL;
225 		CPrinterInfo<5> pinfon5;
226 		CPrinterInfo<2> pinfon2;
227 		LPTSTR lpszPrinterName = NULL;
228 		LPTSTR lpszPortName = NULL;
229 		// Some printers fail for PRINTER_INFO_5 in some situations
230 		if(pinfon5.GetPrinterInfo(m_hPrinter))
231 		{
232 			lpszPrinterName = pinfon5.m_pi->pPrinterName;
233 			lpszPortName = pinfon5.m_pi->pPortName;
234 		}
235 		else if(pinfon2.GetPrinterInfo(m_hPrinter))
236 		{
237 			lpszPrinterName = pinfon2.m_pi->pPrinterName;
238 			lpszPortName = pinfon2.m_pi->pPortName;
239 		}
240 
241 		if(lpszPrinterName != NULL)
242 		{
243 			int nLen = sizeof(DEVNAMES) + (lstrlen(lpszPrinterName) + 1 + lstrlen(lpszPortName) + 1) * sizeof(TCHAR);
244 			hDevNames = ::GlobalAlloc(GMEM_MOVEABLE, nLen);
245 			BYTE* pv = (BYTE*)::GlobalLock(hDevNames);
246 			DEVNAMES* pdev = (DEVNAMES*)pv;
247 			if(pv != NULL)
248 			{
249 				memset(pv, 0, nLen);
250 				pdev->wDeviceOffset = sizeof(DEVNAMES);
251 				pv = pv + sizeof(DEVNAMES); // now points to end
252 				ATL::Checked::tcscpy_s((LPTSTR)pv, lstrlen(lpszPrinterName) + 1, lpszPrinterName);
253 				pdev->wOutputOffset = (WORD)(sizeof(DEVNAMES) + (lstrlen(lpszPrinterName) + 1) * sizeof(TCHAR));
254 				pv = pv + (lstrlen(lpszPrinterName) + 1) * sizeof(TCHAR);
255 				ATL::Checked::tcscpy_s((LPTSTR)pv, lstrlen(lpszPortName) + 1, lpszPortName);
256 				::GlobalUnlock(hDevNames);
257 			}
258 		}
259 
260 		return hDevNames;
261 	}
262 
263 	HDC CreatePrinterDC(const DEVMODE* pdm = NULL) const
264 	{
265 		CPrinterInfo<5> pinfo5;
266 		CPrinterInfo<2> pinfo2;
267 		HDC hDC = NULL;
268 		LPTSTR lpszPrinterName = NULL;
269 		// Some printers fail for PRINTER_INFO_5 in some situations
270 		if (pinfo5.GetPrinterInfo(m_hPrinter))
271 			lpszPrinterName = pinfo5.m_pi->pPrinterName;
272 		else if (pinfo2.GetPrinterInfo(m_hPrinter))
273 			lpszPrinterName = pinfo2.m_pi->pPrinterName;
274 		if (lpszPrinterName != NULL)
275 			hDC = ::CreateDC(NULL, lpszPrinterName, NULL, pdm);
276 		return hDC;
277 	}
278 
279 	HDC CreatePrinterIC(const DEVMODE* pdm = NULL) const
280 	{
281 		CPrinterInfo<5> pinfo5;
282 		CPrinterInfo<2> pinfo2;
283 		HDC hDC = NULL;
284 		LPTSTR lpszPrinterName = NULL;
285 		// Some printers fail for PRINTER_INFO_5 in some situations
286 		if (pinfo5.GetPrinterInfo(m_hPrinter))
287 			lpszPrinterName = pinfo5.m_pi->pPrinterName;
288 		else if (pinfo2.GetPrinterInfo(m_hPrinter))
289 			lpszPrinterName = pinfo2.m_pi->pPrinterName;
290 		if (lpszPrinterName != NULL)
291 			hDC = ::CreateIC(NULL, lpszPrinterName, NULL, pdm);
292 		return hDC;
293 	}
294 
Attach(HANDLE hPrinter)295 	void Attach(HANDLE hPrinter)
296 	{
297 		ClosePrinter();
298 		m_hPrinter = hPrinter;
299 	}
300 
Detach()301 	HANDLE Detach()
302 	{
303 		HANDLE hPrinter = m_hPrinter;
304 		m_hPrinter = NULL;
305 		return hPrinter;
306 	}
307 
HANDLE()308 	operator HANDLE() const { return m_hPrinter; }
309 };
310 
311 typedef CPrinterT<false>   CPrinterHandle;
312 typedef CPrinterT<true>    CPrinter;
313 
314 
315 ///////////////////////////////////////////////////////////////////////////////
316 // CDevMode - Wrapper class for DEVMODE
317 
318 template <bool t_bManaged>
319 class CDevModeT
320 {
321 public:
322 // Data members
323 	HANDLE m_hDevMode;
324 	DEVMODE* m_pDevMode;
325 
326 // Constructor/destructor
m_hDevMode(hDevMode)327 	CDevModeT(HANDLE hDevMode = NULL) : m_hDevMode(hDevMode)
328 	{
329 		m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL;
330 	}
331 
~CDevModeT()332 	~CDevModeT()
333 	{
334 		Cleanup();
335 	}
336 
337 // Operations
338 	CDevModeT<t_bManaged>& operator =(HANDLE hDevMode)
339 	{
340 		Attach(hDevMode);
341 		return *this;
342 	}
343 
Attach(HANDLE hDevModeNew)344 	void Attach(HANDLE hDevModeNew)
345 	{
346 		Cleanup();
347 		m_hDevMode = hDevModeNew;
348 		m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL;
349 	}
350 
Detach()351 	HANDLE Detach()
352 	{
353 		if (m_hDevMode != NULL)
354 			::GlobalUnlock(m_hDevMode);
355 		HANDLE hDevMode = m_hDevMode;
356 		m_hDevMode = NULL;
357 		return hDevMode;
358 	}
359 
IsNull()360 	bool IsNull() const { return (m_hDevMode == NULL); }
361 
CopyFromPrinter(HANDLE hPrinter)362 	bool CopyFromPrinter(HANDLE hPrinter)
363 	{
364 		CPrinterInfo<2> pinfo;
365 		bool b = pinfo.GetPrinterInfo(hPrinter);
366 		if (b)
367 		 b = CopyFromDEVMODE(pinfo.m_pi->pDevMode);
368 		return b;
369 	}
370 
CopyFromDEVMODE(const DEVMODE * pdm)371 	bool CopyFromDEVMODE(const DEVMODE* pdm)
372 	{
373 		if (pdm == NULL)
374 			return false;
375 		int nSize = pdm->dmSize + pdm->dmDriverExtra;
376 		HANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize);
377 		if (h != NULL)
378 		{
379 			void* p = ::GlobalLock(h);
380 			ATL::Checked::memcpy_s(p, nSize, pdm, nSize);
381 			::GlobalUnlock(h);
382 		}
383 		Attach(h);
384 		return (h != NULL);
385 	}
386 
CopyFromHDEVMODE(HANDLE hdm)387 	bool CopyFromHDEVMODE(HANDLE hdm)
388 	{
389 		bool b = false;
390 		if (hdm != NULL)
391 		{
392 			DEVMODE* pdm = (DEVMODE*)::GlobalLock(hdm);
393 			b = CopyFromDEVMODE(pdm);
394 			::GlobalUnlock(hdm);
395 		}
396 		return b;
397 	}
398 
CopyToHDEVMODE()399 	HANDLE CopyToHDEVMODE()
400 	{
401 		if ((m_hDevMode == NULL) || (m_pDevMode == NULL))
402 			return NULL;
403 		int nSize = m_pDevMode->dmSize + m_pDevMode->dmDriverExtra;
404 		HANDLE h = ::GlobalAlloc(GMEM_MOVEABLE, nSize);
405 		if (h != NULL)
406 		{
407 			void* p = ::GlobalLock(h);
408 			ATL::Checked::memcpy_s(p, nSize, m_pDevMode, nSize);
409 			::GlobalUnlock(h);
410 		}
411 		return h;
412 	}
413 
414 	// If this devmode was for another printer, this will create a new devmode
415 	// based on the existing devmode, but retargeted at the new printer
UpdateForNewPrinter(HANDLE hPrinter)416 	bool UpdateForNewPrinter(HANDLE hPrinter)
417 	{
418 		bool bRet = false;
419 		LONG nLen = ::DocumentProperties(NULL, hPrinter, NULL, NULL, NULL, 0);
420 		ATL::CTempBuffer<DEVMODE, _WTL_STACK_ALLOC_THRESHOLD> buff;
421 		DEVMODE* pdm = buff.AllocateBytes(nLen);
422 		if(pdm != NULL)
423 		{
424 			memset(pdm, 0, nLen);
425 			LONG l = ::DocumentProperties(NULL, hPrinter, NULL, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);
426 			if (l == IDOK)
427 				bRet = CopyFromDEVMODE(pdm);
428 		}
429 
430 		return bRet;
431 	}
432 
433 	bool DocumentProperties(HANDLE hPrinter, HWND hWnd = NULL)
434 	{
435 		CPrinterInfo<1> pi;
436 		pi.GetPrinterInfo(hPrinter);
437 		if (hWnd == NULL)
438 			hWnd = ::GetActiveWindow();
439 
440 		bool bRet = false;
441 		LONG nLen = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, NULL, NULL, 0);
442 		ATL::CTempBuffer<DEVMODE, _WTL_STACK_ALLOC_THRESHOLD> buff;
443 		DEVMODE* pdm = buff.AllocateBytes(nLen);
444 		if(pdm != NULL)
445 		{
446 			memset(pdm, 0, nLen);
447 			LONG l = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, pdm, m_pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER | DM_PROMPT);
448 			if (l == IDOK)
449 				bRet = CopyFromDEVMODE(pdm);
450 		}
451 
452 		return bRet;
453 	}
454 
HANDLE()455 	operator HANDLE() const { return m_hDevMode; }
456 
457 	operator DEVMODE*() const { return m_pDevMode; }
458 
459 // Implementation
Cleanup()460 	void Cleanup()
461 	{
462 		if (m_hDevMode != NULL)
463 		{
464 			::GlobalUnlock(m_hDevMode);
465 			if(t_bManaged)
466 				::GlobalFree(m_hDevMode);
467 			m_hDevMode = NULL;
468 		}
469 	}
470 };
471 
472 typedef CDevModeT<false>   CDevModeHandle;
473 typedef CDevModeT<true>    CDevMode;
474 
475 
476 ///////////////////////////////////////////////////////////////////////////////
477 // CPrinterDC
478 
479 class CPrinterDC : public CDC
480 {
481 public:
482 // Constructors/destructor
CPrinterDC()483 	CPrinterDC()
484 	{
485 		CPrinter printer;
486 		printer.OpenDefaultPrinter();
487 		Attach(printer.CreatePrinterDC());
488 		ATLASSERT(m_hDC != NULL);
489 	}
490 
491 	CPrinterDC(HANDLE hPrinter, const DEVMODE* pdm = NULL)
492 	{
493 		CPrinterHandle p;
494 		p.Attach(hPrinter);
495 		Attach(p.CreatePrinterDC(pdm));
496 		ATLASSERT(m_hDC != NULL);
497 	}
498 
~CPrinterDC()499 	~CPrinterDC()
500 	{
501 		DeleteDC();
502 	}
503 };
504 
505 
506 ///////////////////////////////////////////////////////////////////////////////
507 // CPrintJob - Wraps a set of tasks for a specific printer (StartDoc/EndDoc)
508 //             Handles aborting, background printing
509 
510 // Defines callbacks used by CPrintJob (not a COM interface)
511 class ATL_NO_VTABLE IPrintJobInfo
512 {
513 public:
514 	virtual void BeginPrintJob(HDC hDC) = 0;                // allocate handles needed, etc.
515 	virtual void EndPrintJob(HDC hDC, bool bAborted) = 0;   // free handles, etc.
516 	virtual void PrePrintPage(UINT nPage, HDC hDC) = 0;
517 	virtual bool PrintPage(UINT nPage, HDC hDC) = 0;
518 	virtual void PostPrintPage(UINT nPage, HDC hDC) = 0;
519 	// If you want per page devmodes, return the DEVMODE* to use for nPage.
520 	// You can optimize by only returning a new DEVMODE* when it is different
521 	// from the one for nLastPage, otherwise return NULL.
522 	// When nLastPage==0, the current DEVMODE* will be the default passed to
523 	// StartPrintJob.
524 	// Note: During print preview, nLastPage will always be "0".
525 	virtual DEVMODE* GetNewDevModeForPage(UINT nLastPage, UINT nPage) = 0;
526 	virtual bool IsValidPage(UINT nPage) = 0;
527 };
528 
529 // Provides a default implementatin for IPrintJobInfo
530 // Typically, MI'd into a document or view class
531 class ATL_NO_VTABLE CPrintJobInfo : public IPrintJobInfo
532 {
533 public:
BeginPrintJob(HDC)534 	virtual void BeginPrintJob(HDC /*hDC*/)   // allocate handles needed, etc
535 	{
536 	}
537 
EndPrintJob(HDC,bool)538 	virtual void EndPrintJob(HDC /*hDC*/, bool /*bAborted*/)   // free handles, etc
539 	{
540 	}
541 
PrePrintPage(UINT,HDC hDC)542 	virtual void PrePrintPage(UINT /*nPage*/, HDC hDC)
543 	{
544 		m_nPJState = ::SaveDC(hDC);
545 	}
546 
547 	virtual bool PrintPage(UINT /*nPage*/, HDC /*hDC*/) = 0;
548 
PostPrintPage(UINT,HDC hDC)549 	virtual void PostPrintPage(UINT /*nPage*/, HDC hDC)
550 	{
551 		RestoreDC(hDC, m_nPJState);
552 	}
553 
GetNewDevModeForPage(UINT,UINT)554 	virtual DEVMODE* GetNewDevModeForPage(UINT /*nLastPage*/, UINT /*nPage*/)
555 	{
556 		return NULL;
557 	}
558 
IsValidPage(UINT)559 	virtual bool IsValidPage(UINT /*nPage*/)
560 	{
561 		return true;
562 	}
563 
564 // Implementation - data
565 	int m_nPJState;
566 };
567 
568 
569 class CPrintJob
570 {
571 public:
572 // Data members
573 	CPrinterHandle m_printer;
574 	IPrintJobInfo* m_pInfo;
575 	DEVMODE* m_pDefDevMode;
576 	DOCINFO m_docinfo;
577 	int m_nJobID;
578 	bool m_bCancel;
579 	bool m_bComplete;
580 	unsigned long m_nStartPage;
581 	unsigned long m_nEndPage;
582 
583 // Constructor/destructor
CPrintJob()584 	CPrintJob() : m_nJobID(0), m_bCancel(false), m_bComplete(true)
585 	{ }
586 
~CPrintJob()587 	~CPrintJob()
588 	{
589 		ATLASSERT(IsJobComplete()); // premature destruction?
590 	}
591 
592 // Operations
IsJobComplete()593 	bool IsJobComplete() const
594 	{
595 		return m_bComplete;
596 	}
597 
598 	bool StartPrintJob(bool bBackground, HANDLE hPrinter, DEVMODE* pDefaultDevMode,
599 			IPrintJobInfo* pInfo, LPCTSTR lpszDocName,
600 			unsigned long nStartPage, unsigned long nEndPage,
601 			bool bPrintToFile = false, LPCTSTR lpstrOutputFile = NULL)
602 	{
603 		ATLASSERT(m_bComplete); // previous job not done yet?
604 		if (pInfo == NULL)
605 			return false;
606 
607 		memset(&m_docinfo, 0, sizeof(m_docinfo));
608 		m_docinfo.cbSize = sizeof(m_docinfo);
609 		m_docinfo.lpszDocName = lpszDocName;
610 		m_pInfo = pInfo;
611 		m_nStartPage = nStartPage;
612 		m_nEndPage = nEndPage;
613 		m_printer.Attach(hPrinter);
614 		m_pDefDevMode = pDefaultDevMode;
615 		m_bComplete = false;
616 
617 		if(bPrintToFile)
618 			m_docinfo.lpszOutput = (lpstrOutputFile != NULL) ? lpstrOutputFile : _T("FILE:");
619 
620 		if (!bBackground)
621 		{
622 			m_bComplete = true;
623 			return StartHelper();
624 		}
625 
626 		// Create a thread and return
627 		DWORD dwThreadID = 0;
628 #ifdef _MT
629 		HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, (UINT (WINAPI*)(void*))StartProc, this, 0, (UINT*)&dwThreadID);
630 #else
631 		HANDLE hThread = ::CreateThread(NULL, 0, StartProc, (void*)this, 0, &dwThreadID);
632 #endif
633 		if (hThread == NULL)
634 			return false;
635 
636 		::CloseHandle(hThread);
637 
638 		return true;
639 	}
640 
641 // Implementation
StartProc(void * p)642 	static DWORD WINAPI StartProc(void* p)
643 	{
644 		CPrintJob* pThis = (CPrintJob*)p;
645 		pThis->StartHelper();
646 		pThis->m_bComplete = true;
647 		return 0;
648 	}
649 
StartHelper()650 	bool StartHelper()
651 	{
652 		CDC dcPrinter;
653 		dcPrinter.Attach(m_printer.CreatePrinterDC(m_pDefDevMode));
654 		if (dcPrinter.IsNull())
655 			return false;
656 
657 		m_nJobID = ::StartDoc(dcPrinter, &m_docinfo);
658 		if (m_nJobID <= 0)
659 			return false;
660 
661 		m_pInfo->BeginPrintJob(dcPrinter);
662 
663 		// print all the pages now
664 		unsigned long nLastPage = 0;
665 		for (unsigned long nPage = m_nStartPage; nPage <= m_nEndPage; nPage++)
666 		{
667 			if (!m_pInfo->IsValidPage(nPage))
668 				break;
669 			DEVMODE* pdm = m_pInfo->GetNewDevModeForPage(nLastPage, nPage);
670 			if (pdm != NULL)
671 				dcPrinter.ResetDC(pdm);
672 			dcPrinter.StartPage();
673 			m_pInfo->PrePrintPage(nPage, dcPrinter);
674 			if (!m_pInfo->PrintPage(nPage, dcPrinter))
675 				m_bCancel = true;
676 			m_pInfo->PostPrintPage(nPage, dcPrinter);
677 			dcPrinter.EndPage();
678 			if (m_bCancel)
679 				break;
680 			nLastPage = nPage;
681 		}
682 
683 		m_pInfo->EndPrintJob(dcPrinter, m_bCancel);
684 		if (m_bCancel)
685 			::AbortDoc(dcPrinter);
686 		else
687 			::EndDoc(dcPrinter);
688 		m_nJobID = 0;
689 		return true;
690 	}
691 
692 	// Cancels a print job. Can be called asynchronously.
CancelPrintJob()693 	void CancelPrintJob()
694 	{
695 		m_bCancel = true;
696 	}
697 };
698 
699 
700 ///////////////////////////////////////////////////////////////////////////////
701 // CPrintPreview - Adds print preview support to an existing window
702 
703 class CPrintPreview
704 {
705 public:
706 // Data members
707 	IPrintJobInfo* m_pInfo;
708 	CPrinterHandle m_printer;
709 	CEnhMetaFile m_meta;
710 	DEVMODE* m_pDefDevMode;
711 	DEVMODE* m_pCurDevMode;
712 	SIZE m_sizeCurPhysOffset;
713 
714 // Constructor
CPrintPreview()715 	CPrintPreview() : m_pInfo(NULL), m_pDefDevMode(NULL), m_pCurDevMode(NULL)
716 	{
717 		m_sizeCurPhysOffset.cx = 0;
718 		m_sizeCurPhysOffset.cy = 0;
719 	}
720 
721 // Operations
SetPrintPreviewInfo(HANDLE hPrinter,DEVMODE * pDefaultDevMode,IPrintJobInfo * pji)722 	void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, IPrintJobInfo* pji)
723 	{
724 		m_printer.Attach(hPrinter);
725 		m_pDefDevMode = pDefaultDevMode;
726 		m_pInfo = pji;
727 		m_nCurPage = 0;
728 		m_pCurDevMode = NULL;
729 	}
730 
SetEnhMetaFile(HENHMETAFILE hEMF)731 	void SetEnhMetaFile(HENHMETAFILE hEMF)
732 	{
733 		m_meta = hEMF;
734 	}
735 
SetPage(int nPage)736 	void SetPage(int nPage)
737 	{
738 		if (!m_pInfo->IsValidPage(nPage))
739 			return;
740 		m_nCurPage = nPage;
741 		m_pCurDevMode = m_pInfo->GetNewDevModeForPage(0, nPage);
742 		if (m_pCurDevMode == NULL)
743 			m_pCurDevMode = m_pDefDevMode;
744 		CDC dcPrinter = m_printer.CreatePrinterDC(m_pCurDevMode);
745 
746 		int iWidth = dcPrinter.GetDeviceCaps(PHYSICALWIDTH);
747 		int iHeight = dcPrinter.GetDeviceCaps(PHYSICALHEIGHT);
748 		int nLogx = dcPrinter.GetDeviceCaps(LOGPIXELSX);
749 		int nLogy = dcPrinter.GetDeviceCaps(LOGPIXELSY);
750 
751 		RECT rcMM = { 0, 0, ::MulDiv(iWidth, 2540, nLogx), ::MulDiv(iHeight, 2540, nLogy) };
752 
753 		m_sizeCurPhysOffset.cx = dcPrinter.GetDeviceCaps(PHYSICALOFFSETX);
754 		m_sizeCurPhysOffset.cy = dcPrinter.GetDeviceCaps(PHYSICALOFFSETY);
755 
756 		CEnhMetaFileDC dcMeta(dcPrinter, &rcMM);
757 		m_pInfo->PrePrintPage(nPage, dcMeta);
758 		m_pInfo->PrintPage(nPage, dcMeta);
759 		m_pInfo->PostPrintPage(nPage, dcMeta);
760 		m_meta.Attach(dcMeta.Close());
761 	}
762 
GetPageRect(RECT & rc,LPRECT prc)763 	void GetPageRect(RECT& rc, LPRECT prc)
764 	{
765 		int x1 = rc.right-rc.left;
766 		int y1 = rc.bottom - rc.top;
767 		if ((x1 < 0) || (y1 < 0))
768 			return;
769 
770 		CEnhMetaFileInfo emfinfo(m_meta);
771 		ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader();
772 
773 		// Compute whether we are OK vertically or horizontally
774 		int x2 = pmh->szlDevice.cx;
775 		int y2 = pmh->szlDevice.cy;
776 		int y1p = MulDiv(x1, y2, x2);
777 		int x1p = MulDiv(y1, x2, y2);
778 		ATLASSERT((x1p <= x1) || (y1p <= y1));
779 		if (x1p <= x1)
780 		{
781 			prc->left = rc.left + (x1 - x1p) / 2;
782 			prc->right = prc->left + x1p;
783 			prc->top = rc.top;
784 			prc->bottom = rc.bottom;
785 		}
786 		else
787 		{
788 			prc->left = rc.left;
789 			prc->right = rc.right;
790 			prc->top = rc.top + (y1 - y1p) / 2;
791 			prc->bottom = prc->top + y1p;
792 		}
793 	}
794 
795 // Painting helpers
DoPaint(CDCHandle dc)796 	void DoPaint(CDCHandle dc)
797 	{
798 		// this one is not used
799 	}
800 
DoPaint(CDCHandle dc,RECT & rc)801 	void DoPaint(CDCHandle dc, RECT& rc)
802 	{
803 		CEnhMetaFileInfo emfinfo(m_meta);
804 		ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader();
805 		int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx);
806 		int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy);
807 
808 		dc.OffsetWindowOrg(-nOffsetX, -nOffsetY);
809 		dc.PlayMetaFile(m_meta, &rc);
810 	}
811 
812 // Implementation - data
813 	int m_nCurPage;
814 };
815 
816 
817 ///////////////////////////////////////////////////////////////////////////////
818 // CPrintPreviewWindow - Implements a print preview window
819 
820 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
821 class ATL_NO_VTABLE CPrintPreviewWindowImpl : public ATL::CWindowImpl<T, TBase, TWinTraits>, public CPrintPreview
822 {
823 public:
824 	DECLARE_WND_CLASS_EX2(NULL, T, CS_VREDRAW | CS_HREDRAW, -1)
825 
826 	enum { m_cxOffset = 10, m_cyOffset = 10 };
827 
828 // Constructor
CPrintPreviewWindowImpl()829 	CPrintPreviewWindowImpl() : m_nMinPage(0), m_nMaxPage(0)
830 	{ }
831 
832 // Operations
SetPrintPreviewInfo(HANDLE hPrinter,DEVMODE * pDefaultDevMode,IPrintJobInfo * pji,int nMinPage,int nMaxPage)833 	void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode,
834 		IPrintJobInfo* pji, int nMinPage, int nMaxPage)
835 	{
836 		CPrintPreview::SetPrintPreviewInfo(hPrinter, pDefaultDevMode, pji);
837 		m_nMinPage = nMinPage;
838 		m_nMaxPage = nMaxPage;
839 	}
840 
NextPage()841 	bool NextPage()
842 	{
843 		if (m_nCurPage == m_nMaxPage)
844 			return false;
845 		SetPage(m_nCurPage + 1);
846 		this->Invalidate();
847 		return true;
848 	}
849 
PrevPage()850 	bool PrevPage()
851 	{
852 		if (m_nCurPage == m_nMinPage)
853 			return false;
854 		if (m_nCurPage == 0)
855 			return false;
856 		SetPage(m_nCurPage - 1);
857 		this->Invalidate();
858 		return true;
859 	}
860 
861 // Message map and handlers
862 	BEGIN_MSG_MAP(CPrintPreviewWindowImpl)
MESSAGE_HANDLER(WM_ERASEBKGND,OnEraseBkgnd)863 		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
864 		MESSAGE_HANDLER(WM_PAINT, OnPaint)
865 		MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
866 	END_MSG_MAP()
867 
868 	LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
869 	{
870 		return 1;   // no need for the background
871 	}
872 
OnPaint(UINT,WPARAM wParam,LPARAM,BOOL &)873 	LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
874 	{
875 		T* pT = static_cast<T*>(this);
876 		RECT rc = {};
877 
878 		if(wParam != NULL)
879 		{
880 			pT->DoPrePaint((HDC)wParam, rc);
881 			pT->DoPaint((HDC)wParam, rc);
882 		}
883 		else
884 		{
885 			CPaintDC dc(this->m_hWnd);
886 			pT->DoPrePaint(dc.m_hDC, rc);
887 			pT->DoPaint(dc.m_hDC, rc);
888 		}
889 
890 		return 0;
891 	}
892 
893 // Painting helper
DoPrePaint(CDCHandle dc,RECT & rc)894 	void DoPrePaint(CDCHandle dc, RECT& rc)
895 	{
896 		RECT rcClient = {};
897 		this->GetClientRect(&rcClient);
898 		RECT rcArea = rcClient;
899 		T* pT = static_cast<T*>(this);
900 		(void)pT;   // avoid level 4 warning
901 		::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset);
902 		if (rcArea.left > rcArea.right)
903 			rcArea.right = rcArea.left;
904 		if (rcArea.top > rcArea.bottom)
905 			rcArea.bottom = rcArea.top;
906 		GetPageRect(rcArea, &rc);
907 		CRgn rgn1, rgn2;
908 		rgn1.CreateRectRgnIndirect(&rc);
909 		rgn2.CreateRectRgnIndirect(&rcClient);
910 		rgn2.CombineRgn(rgn1, RGN_DIFF);
911 		dc.SelectClipRgn(rgn2);
912 		dc.FillRect(&rcClient, COLOR_BTNSHADOW);
913 		dc.SelectClipRgn(NULL);
914 		dc.FillRect(&rc, (HBRUSH)::GetStockObject(WHITE_BRUSH));
915 	}
916 
917 // Implementation - data
918 	int m_nMinPage;
919 	int m_nMaxPage;
920 };
921 
922 
923 class CPrintPreviewWindow : public CPrintPreviewWindowImpl<CPrintPreviewWindow>
924 {
925 public:
926 	DECLARE_WND_CLASS_EX(_T("WTL_PrintPreview"), CS_VREDRAW | CS_HREDRAW, -1)
927 };
928 
929 
930 ///////////////////////////////////////////////////////////////////////////////
931 // CZoomPrintPreviewWindowImpl - Implements print preview window with zooming
932 
933 #ifdef __ATLSCRL_H__
934 
935 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
936 class ATL_NO_VTABLE CZoomPrintPreviewWindowImpl : public CPrintPreviewWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T >
937 {
938 public:
939 	bool m_bSized;
940 
CZoomPrintPreviewWindowImpl()941 	CZoomPrintPreviewWindowImpl()
942 	{
943 		this->SetScrollExtendedStyle(SCRL_DISABLENOSCROLL);
944 		InitZoom();
945 	}
946 
947 	// should be called to reset data members before recreating window
InitZoom()948 	void InitZoom()
949 	{
950 		m_bSized = false;
951 		this->m_nZoomMode = ZOOMMODE_OFF;
952 		this->m_fZoomScaleMin = 1.0;
953 		this->m_fZoomScale = 1.0;
954 	}
955 
956 	BEGIN_MSG_MAP(CZoomPrintPreviewWindowImpl)
MESSAGE_HANDLER(WM_SETCURSOR,CZoomScrollImpl<T>::OnSetCursor)957 		MESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor)
958 		MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)
959 		MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)
960 		MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)
961 		MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)
962 		MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)
963 		MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown)
964 		MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove)
965 		MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp)
966 		MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged)
967 		MESSAGE_HANDLER(WM_SIZE, OnSize)
968 		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
969 		MESSAGE_HANDLER(WM_PAINT, OnPaint)
970 		MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
971 	ALT_MSG_MAP(1)
972 		COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)
973 		COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)
974 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)
975 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)
976 		COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)
977 		COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)
978 		COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)
979 		COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)
980 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)
981 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)
982 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)
983 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)
984 	END_MSG_MAP()
985 
986 	LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
987 	{
988 		SIZE sizeClient = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
989 		POINT ptOffset = this->m_ptOffset;
990 		SIZE sizeAll = this->m_sizeAll;
991 		this->SetScrollSize(sizeClient);
992 		if(sizeAll.cx > 0)
993 			ptOffset.x = ::MulDiv(ptOffset.x, this->m_sizeAll.cx, sizeAll.cx);
994 		if(sizeAll.cy > 0)
995 			ptOffset.y = ::MulDiv(ptOffset.y, this->m_sizeAll.cy, sizeAll.cy);
996 		this->SetScrollOffset(ptOffset);
997 		CScrollImpl< T >::OnSize(uMsg, wParam, lParam, bHandled);
998 		if(!m_bSized)
999 		{
1000 			m_bSized = true;
1001 			T* pT = static_cast<T*>(this);
1002 			pT->ShowScrollBar(SB_HORZ, TRUE);
1003 			pT->ShowScrollBar(SB_VERT, TRUE);
1004 		}
1005 		return 0;
1006 	}
1007 
OnEraseBkgnd(UINT,WPARAM,LPARAM,BOOL &)1008 	LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1009 	{
1010 		return 1;
1011 	}
1012 
OnPaint(UINT,WPARAM wParam,LPARAM,BOOL &)1013 	LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1014 	{
1015 		T* pT = static_cast<T*>(this);
1016 		RECT rc = {};
1017 
1018 		if(wParam != NULL)
1019 		{
1020 			CDCHandle dc = (HDC)wParam;
1021 			int nMapModeSav = dc.GetMapMode();
1022 			dc.SetMapMode(MM_ANISOTROPIC);
1023 			SIZE szWindowExt = { 0, 0 };
1024 			dc.SetWindowExt(this->m_sizeLogAll, &szWindowExt);
1025 			SIZE szViewportExt = { 0, 0 };
1026 			dc.SetViewportExt(this->m_sizeAll, &szViewportExt);
1027 			POINT ptViewportOrg = { 0, 0 };
1028 			dc.SetViewportOrg(-this->m_ptOffset.x, -this->m_ptOffset.y, &ptViewportOrg);
1029 
1030 			pT->DoPrePaint(dc, rc);
1031 			pT->DoPaint(dc, rc);
1032 
1033 			dc.SetMapMode(nMapModeSav);
1034 			dc.SetWindowExt(szWindowExt);
1035 			dc.SetViewportExt(szViewportExt);
1036 			dc.SetViewportOrg(ptViewportOrg);
1037 		}
1038 		else
1039 		{
1040 			CPaintDC dc(pT->m_hWnd);
1041 			pT->PrepareDC(dc.m_hDC);
1042 			pT->DoPrePaint(dc.m_hDC, rc);
1043 			pT->DoPaint(dc.m_hDC, rc);
1044 		}
1045 
1046 		return 0;
1047 	}
1048 
1049 	// Painting helpers
DoPaint(CDCHandle dc)1050 	void DoPaint(CDCHandle dc)
1051 	{
1052 		// this one is not used
1053 	}
1054 
DoPrePaint(CDCHandle dc,RECT & rc)1055 	void DoPrePaint(CDCHandle dc, RECT& rc)
1056 	{
1057 		RECT rcClient = {};
1058 		this->GetClientRect(&rcClient);
1059 		RECT rcArea = rcClient;
1060 		T* pT = static_cast<T*>(this);
1061 		(void)pT;   // avoid level 4 warning
1062 		::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset);
1063 		if (rcArea.left > rcArea.right)
1064 			rcArea.right = rcArea.left;
1065 		if (rcArea.top > rcArea.bottom)
1066 			rcArea.bottom = rcArea.top;
1067 		this->GetPageRect(rcArea, &rc);
1068 		HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW));
1069 		dc.PatBlt(rcClient.left, rcClient.top, rc.left - rcClient.left, rcClient.bottom - rcClient.top, PATCOPY);
1070 		dc.PatBlt(rc.left, rcClient.top, rc.right - rc.left, rc.top - rcClient.top, PATCOPY);
1071 		dc.PatBlt(rc.right, rcClient.top, rcClient.right - rc.right, rcClient.bottom - rcClient.top, PATCOPY);
1072 		dc.PatBlt(rc.left, rc.bottom, rc.right - rc.left, rcClient.bottom - rc.bottom, PATCOPY);
1073 		dc.SelectBrush((HBRUSH)::GetStockObject(WHITE_BRUSH));
1074 		dc.PatBlt(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY);
1075 		dc.SelectBrush(::GetSysColorBrush(COLOR_3DDKSHADOW));
1076 		dc.PatBlt(rc.right, rc.top + 4, 4, rc.bottom - rc.top, PATCOPY);
1077 		dc.PatBlt(rc.left + 4, rc.bottom, rc.right - rc.left, 4, PATCOPY);
1078 		dc.SelectBrush(hbrOld);
1079 	}
1080 
DoPaint(CDCHandle dc,RECT & rc)1081 	void DoPaint(CDCHandle dc, RECT& rc)
1082 	{
1083 		CEnhMetaFileInfo emfinfo(this->m_meta);
1084 		ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader();
1085 		int nOffsetX = MulDiv(this->m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx);
1086 		int nOffsetY = MulDiv(this->m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy);
1087 
1088 		dc.OffsetWindowOrg(-nOffsetX, -nOffsetY);
1089 		dc.PlayMetaFile(this->m_meta, &rc);
1090 	}
1091 };
1092 
1093 class CZoomPrintPreviewWindow : public CZoomPrintPreviewWindowImpl<CZoomPrintPreviewWindow>
1094 {
1095 public:
1096 	DECLARE_WND_CLASS_EX(_T("WTL_ZoomPrintPreview"), CS_VREDRAW | CS_HREDRAW, -1)
1097 };
1098 
1099 #endif // __ATLSCRL_H__
1100 
1101 } // namespace WTL
1102 
1103 #endif // __ATLPRINT_H__
1104