1 // Windows Template Library - WTL version 9.10
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 #ifdef _WIN32_WCE
15 	#error atlprint.h is not supported on Windows CE
16 #endif
17 
18 #ifndef __ATLAPP_H__
19 	#error atlprint.h requires atlapp.h to be included first
20 #endif
21 
22 #ifndef __ATLWIN_H__
23 	#error atlprint.h requires atlwin.h to be included first
24 #endif
25 
26 
27 ///////////////////////////////////////////////////////////////////////////////
28 // Classes in this file:
29 //
30 // CPrinterInfo<t_nInfo>
31 // CPrinterT<t_bManaged>
32 // CDevModeT<t_bManaged>
33 // CPrinterDC
34 // CPrintJobInfo
35 // CPrintJob
36 // CPrintPreview
37 // CPrintPreviewWindowImpl<T, TBase, TWinTraits>
38 // CPrintPreviewWindow
39 // CZoomPrintPreviewWindowImpl<T, TBase, TWinTraits>
40 // CZoomPrintPreviewWindow
41 
42 namespace WTL
43 {
44 
45 ///////////////////////////////////////////////////////////////////////////////
46 // CPrinterInfo - This class wraps all of the PRINTER_INFO_* structures
47 //                and provided by ::GetPrinter.
48 
49 template <unsigned int t_nInfo>
50 class _printer_info
51 {
52 public:
53 	typedef void infotype;
54 };
55 
56 template <> class _printer_info<1> { public: typedef PRINTER_INFO_1 infotype; };
57 template <> class _printer_info<2> { public: typedef PRINTER_INFO_2 infotype; };
58 template <> class _printer_info<3> { public: typedef PRINTER_INFO_3 infotype; };
59 template <> class _printer_info<4> { public: typedef PRINTER_INFO_4 infotype; };
60 template <> class _printer_info<5> { public: typedef PRINTER_INFO_5 infotype; };
61 template <> class _printer_info<6> { public: typedef PRINTER_INFO_6 infotype; };
62 template <> class _printer_info<7> { public: typedef PRINTER_INFO_7 infotype; };
63 // these are not in the old (vc6.0) headers
64 #ifdef _ATL_USE_NEW_PRINTER_INFO
65 template <> class _printer_info<8> { public: typedef PRINTER_INFO_8 infotype; };
66 template <> class _printer_info<9> { public: typedef PRINTER_INFO_9 infotype; };
67 #endif // _ATL_USE_NEW_PRINTER_INFO
68 
69 
70 template <unsigned int t_nInfo>
71 class CPrinterInfo
72 {
73 public:
74 // Data members
75 	typename _printer_info<t_nInfo>::infotype* m_pi;
76 
77 // Constructor/destructor
CPrinterInfo()78 	CPrinterInfo() : m_pi(NULL)
79 	{ }
80 
CPrinterInfo(HANDLE hPrinter)81 	CPrinterInfo(HANDLE hPrinter) : m_pi(NULL)
82 	{
83 		GetPrinterInfo(hPrinter);
84 	}
85 
~CPrinterInfo()86 	~CPrinterInfo()
87 	{
88 		Cleanup();
89 	}
90 
91 // Operations
GetPrinterInfo(HANDLE hPrinter)92 	bool GetPrinterInfo(HANDLE hPrinter)
93 	{
94 		Cleanup();
95 		return GetPrinterInfoHelper(hPrinter, (BYTE**)&m_pi, t_nInfo);
96 	}
97 
98 // Implementation
Cleanup()99 	void Cleanup()
100 	{
101 		delete [] (BYTE*)m_pi;
102 		m_pi = NULL;
103 	}
104 
GetPrinterInfoHelper(HANDLE hPrinter,BYTE ** pi,int nIndex)105 	static bool GetPrinterInfoHelper(HANDLE hPrinter, BYTE** pi, int nIndex)
106 	{
107 		ATLASSERT(pi != NULL);
108 		DWORD dw = 0;
109 		BYTE* pb = NULL;
110 		::GetPrinter(hPrinter, nIndex, NULL, 0, &dw);
111 		if (dw > 0)
112 		{
113 			ATLTRY(pb = new BYTE[dw]);
114 			if (pb != NULL)
115 			{
116 				memset(pb, 0, dw);
117 				DWORD dwNew;
118 				if (!::GetPrinter(hPrinter, nIndex, pb, dw, &dwNew))
119 				{
120 					delete [] pb;
121 					pb = NULL;
122 				}
123 			}
124 		}
125 		*pi = pb;
126 		return (pb != NULL);
127 	}
128 };
129 
130 
131 ///////////////////////////////////////////////////////////////////////////////
132 // CPrinter - Wrapper class for a HANDLE to a printer
133 
134 template <bool t_bManaged>
135 class CPrinterT
136 {
137 public:
138 // Data members
139 	HANDLE m_hPrinter;
140 
141 // Constructor/destructor
m_hPrinter(hPrinter)142 	CPrinterT(HANDLE hPrinter = NULL) : m_hPrinter(hPrinter)
143 	{ }
144 
~CPrinterT()145 	~CPrinterT()
146 	{
147 		ClosePrinter();
148 	}
149 
150 // Operations
151 	CPrinterT& operator =(HANDLE hPrinter)
152 	{
153 		if (hPrinter != m_hPrinter)
154 		{
155 			ClosePrinter();
156 			m_hPrinter = hPrinter;
157 		}
158 		return *this;
159 	}
160 
IsNull()161 	bool IsNull() const { return (m_hPrinter == NULL); }
162 
163 	bool OpenPrinter(HANDLE hDevNames, const DEVMODE* pDevMode = NULL)
164 	{
165 		bool b = false;
166 		DEVNAMES* pdn = (DEVNAMES*)::GlobalLock(hDevNames);
167 		if (pdn != NULL)
168 		{
169 			LPTSTR lpszPrinterName = (LPTSTR)pdn + pdn->wDeviceOffset;
170 			b = OpenPrinter(lpszPrinterName, pDevMode);
171 			::GlobalUnlock(hDevNames);
172 		}
173 		return b;
174 	}
175 
176 	bool OpenPrinter(LPCTSTR lpszPrinterName, const DEVMODE* pDevMode = NULL)
177 	{
178 		ClosePrinter();
179 		PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE };
180 		::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs);
181 
182 		return (m_hPrinter != NULL);
183 	}
184 
OpenPrinter(LPCTSTR lpszPrinterName,PRINTER_DEFAULTS * pprintdefs)185 	bool OpenPrinter(LPCTSTR lpszPrinterName, PRINTER_DEFAULTS* pprintdefs)
186 	{
187 		ClosePrinter();
188 		::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, pprintdefs);
189 		return (m_hPrinter != NULL);
190 	}
191 
192 	bool OpenDefaultPrinter(const DEVMODE* pDevMode = NULL)
193 	{
194 		ClosePrinter();
195 		const int cchBuff = 512;
196 		TCHAR buffer[cchBuff] = { 0 };
197 		::GetProfileString(_T("windows"), _T("device"), _T(",,,"), buffer, cchBuff);
198 		int nLen = lstrlen(buffer);
199 		if (nLen != 0)
200 		{
201 			LPTSTR lpsz = buffer;
202 			while (*lpsz)
203 			{
204 				if (*lpsz == _T(','))
205 				{
206 					*lpsz = 0;
207 					break;
208 				}
209 				lpsz = CharNext(lpsz);
210 			}
211 			PRINTER_DEFAULTS pdefs = { NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE };
212 			::OpenPrinter(buffer, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs);
213 		}
214 		return m_hPrinter != NULL;
215 	}
216 
ClosePrinter()217 	void ClosePrinter()
218 	{
219 		if (m_hPrinter != NULL)
220 		{
221 			if (t_bManaged)
222 				::ClosePrinter(m_hPrinter);
223 			m_hPrinter = NULL;
224 		}
225 	}
226 
227 	bool PrinterProperties(HWND hWnd = NULL)
228 	{
229 		if (hWnd == NULL)
230 			hWnd = ::GetActiveWindow();
231 		return !!::PrinterProperties(hWnd, m_hPrinter);
232 	}
233 
CopyToHDEVNAMES()234 	HANDLE CopyToHDEVNAMES() const
235 	{
236 		HANDLE h = NULL;
237 		CPrinterInfo<5> pinfon5;
238 		CPrinterInfo<2> pinfon2;
239 		LPTSTR lpszPrinterName = NULL;
240 		// Some printers fail for PRINTER_INFO_5 in some situations
241 		if (pinfon5.GetPrinterInfo(m_hPrinter))
242 			lpszPrinterName = pinfon5.m_pi->pPrinterName;
243 		else if (pinfon2.GetPrinterInfo(m_hPrinter))
244 			lpszPrinterName = pinfon2.m_pi->pPrinterName;
245 		if (lpszPrinterName != NULL)
246 		{
247 			int nLen = sizeof(DEVNAMES) + (lstrlen(lpszPrinterName) + 1) * sizeof(TCHAR);
248 			h = ::GlobalAlloc(GMEM_MOVEABLE, nLen);
249 			BYTE* pv = (BYTE*)::GlobalLock(h);
250 			DEVNAMES* pdev = (DEVNAMES*)pv;
251 			if (pv != NULL)
252 			{
253 				memset(pv, 0, nLen);
254 				pdev->wDeviceOffset = sizeof(DEVNAMES) / sizeof(TCHAR);
255 				pv = pv + sizeof(DEVNAMES); // now points to end
256 				SecureHelper::strcpy_x((LPTSTR)pv, lstrlen(lpszPrinterName) + 1, lpszPrinterName);
257 				::GlobalUnlock(h);
258 			}
259 		}
260 		return h;
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 			SecureHelper::memcpy_x(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 			SecureHelper::memcpy_x(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 		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 		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 #if !defined(_ATL_MIN_CRT) && defined(_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_EX(NULL, CS_VREDRAW | CS_HREDRAW, -1)
825 
826 	enum { m_cxOffset = 10, m_cyOffset = 10 };
827 
828 // Constructor
CPrintPreviewWindowImpl()829 	CPrintPreviewWindowImpl() : m_nMaxPage(0), m_nMinPage(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 		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 		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 = { 0 };
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(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 = { 0 };
897 		GetClientRect(&rcClient);
898 		RECT rcArea = rcClient;
899 		T* pT = static_cast<T*>(this);
900 		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 		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 		m_nZoomMode = ZOOMMODE_OFF;
952 		m_fZoomScaleMin = 1.0;
953 		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 #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
962 		MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)
963 #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))
964 		MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)
965 		MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)
966 		MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown)
967 		MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove)
968 		MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp)
969 		MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged)
970 		MESSAGE_HANDLER(WM_SIZE, OnSize)
971 		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
972 		MESSAGE_HANDLER(WM_PAINT, OnPaint)
973 		MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
974 	ALT_MSG_MAP(1)
975 		COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)
976 		COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)
977 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)
978 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)
979 		COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)
980 		COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)
981 		COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)
982 		COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)
983 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)
984 		COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)
985 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)
986 		COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)
987 	END_MSG_MAP()
988 
989 	LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
990 	{
991 		SIZE sizeClient = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
992 		POINT ptOffset = m_ptOffset;
993 		SIZE sizeAll = m_sizeAll;
994 		SetScrollSize(sizeClient);
995 		if(sizeAll.cx > 0)
996 			ptOffset.x = ::MulDiv(ptOffset.x, m_sizeAll.cx, sizeAll.cx);
997 		if(sizeAll.cy > 0)
998 			ptOffset.y = ::MulDiv(ptOffset.y, m_sizeAll.cy, sizeAll.cy);
999 		SetScrollOffset(ptOffset);
1000 		CScrollImpl< T >::OnSize(uMsg, wParam, lParam, bHandled);
1001 		if(!m_bSized)
1002 		{
1003 			m_bSized = true;
1004 			T* pT = static_cast<T*>(this);
1005 			pT->ShowScrollBar(SB_HORZ, TRUE);
1006 			pT->ShowScrollBar(SB_VERT, TRUE);
1007 		}
1008 		return 0;
1009 	}
1010 
OnEraseBkgnd(UINT,WPARAM,LPARAM,BOOL &)1011 	LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1012 	{
1013 		return 1;
1014 	}
1015 
OnPaint(UINT,WPARAM wParam,LPARAM,BOOL &)1016 	LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1017 	{
1018 		T* pT = static_cast<T*>(this);
1019 		RECT rc = { 0 };
1020 
1021 		if(wParam != NULL)
1022 		{
1023 			CDCHandle dc = (HDC)wParam;
1024 			int nMapModeSav = dc.GetMapMode();
1025 			dc.SetMapMode(MM_ANISOTROPIC);
1026 			SIZE szWindowExt = { 0, 0 };
1027 			dc.SetWindowExt(m_sizeLogAll, &szWindowExt);
1028 			SIZE szViewportExt = { 0, 0 };
1029 			dc.SetViewportExt(m_sizeAll, &szViewportExt);
1030 			POINT ptViewportOrg = { 0, 0 };
1031 			dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg);
1032 
1033 			pT->DoPrePaint(dc, rc);
1034 			pT->DoPaint(dc, rc);
1035 
1036 			dc.SetMapMode(nMapModeSav);
1037 			dc.SetWindowExt(szWindowExt);
1038 			dc.SetViewportExt(szViewportExt);
1039 			dc.SetViewportOrg(ptViewportOrg);
1040 		}
1041 		else
1042 		{
1043 			CPaintDC dc(pT->m_hWnd);
1044 			pT->PrepareDC(dc.m_hDC);
1045 			pT->DoPrePaint(dc.m_hDC, rc);
1046 			pT->DoPaint(dc.m_hDC, rc);
1047 		}
1048 
1049 		return 0;
1050 	}
1051 
1052 	// Painting helpers
DoPaint(CDCHandle dc)1053 	void DoPaint(CDCHandle dc)
1054 	{
1055 		// this one is not used
1056 	}
1057 
DoPrePaint(CDCHandle dc,RECT & rc)1058 	void DoPrePaint(CDCHandle dc, RECT& rc)
1059 	{
1060 		RECT rcClient = { 0 };
1061 		GetClientRect(&rcClient);
1062 		RECT rcArea = rcClient;
1063 		T* pT = static_cast<T*>(this);
1064 		pT;   // avoid level 4 warning
1065 		::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset);
1066 		if (rcArea.left > rcArea.right)
1067 			rcArea.right = rcArea.left;
1068 		if (rcArea.top > rcArea.bottom)
1069 			rcArea.bottom = rcArea.top;
1070 		GetPageRect(rcArea, &rc);
1071 		HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW));
1072 		dc.PatBlt(rcClient.left, rcClient.top, rc.left - rcClient.left, rcClient.bottom - rcClient.top, PATCOPY);
1073 		dc.PatBlt(rc.left, rcClient.top, rc.right - rc.left, rc.top - rcClient.top, PATCOPY);
1074 		dc.PatBlt(rc.right, rcClient.top, rcClient.right - rc.right, rcClient.bottom - rcClient.top, PATCOPY);
1075 		dc.PatBlt(rc.left, rc.bottom, rc.right - rc.left, rcClient.bottom - rc.bottom, PATCOPY);
1076 		dc.SelectBrush((HBRUSH)::GetStockObject(WHITE_BRUSH));
1077 		dc.PatBlt(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY);
1078 		dc.SelectBrush(::GetSysColorBrush(COLOR_3DDKSHADOW));
1079 		dc.PatBlt(rc.right, rc.top + 4, 4, rc.bottom - rc.top, PATCOPY);
1080 		dc.PatBlt(rc.left + 4, rc.bottom, rc.right - rc.left, 4, PATCOPY);
1081 		dc.SelectBrush(hbrOld);
1082 	}
1083 
DoPaint(CDCHandle dc,RECT & rc)1084 	void DoPaint(CDCHandle dc, RECT& rc)
1085 	{
1086 		CEnhMetaFileInfo emfinfo(m_meta);
1087 		ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader();
1088 		int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx);
1089 		int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy);
1090 
1091 		dc.OffsetWindowOrg(-nOffsetX, -nOffsetY);
1092 		dc.PlayMetaFile(m_meta, &rc);
1093 	}
1094 };
1095 
1096 class CZoomPrintPreviewWindow : public CZoomPrintPreviewWindowImpl<CZoomPrintPreviewWindow>
1097 {
1098 public:
1099 	DECLARE_WND_CLASS_EX(_T("WTL_ZoomPrintPreview"), CS_VREDRAW | CS_HREDRAW, -1)
1100 };
1101 
1102 #endif // __ATLSCRL_H__
1103 
1104 }; // namespace WTL
1105 
1106 #endif // __ATLPRINT_H__
1107