comparison foosdk/wtl/Include/atlprint.h @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
comparison
equal deleted inserted replaced
0:e9bb126753e7 1:20d02a178406
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
73 CPrinterInfo() : m_pi(NULL)
74 { }
75
76 CPrinterInfo(HANDLE hPrinter) : m_pi(NULL)
77 {
78 GetPrinterInfo(hPrinter);
79 }
80
81 ~CPrinterInfo()
82 {
83 Cleanup();
84 }
85
86 // Operations
87 bool GetPrinterInfo(HANDLE hPrinter)
88 {
89 Cleanup();
90 return GetPrinterInfoHelper(hPrinter, (BYTE**)&m_pi, t_nInfo);
91 }
92
93 // Implementation
94 void Cleanup()
95 {
96 delete [] (BYTE*)m_pi;
97 m_pi = NULL;
98 }
99
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
137 CPrinterT(HANDLE hPrinter = NULL) : m_hPrinter(hPrinter)
138 { }
139
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
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
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
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
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
295 void Attach(HANDLE hPrinter)
296 {
297 ClosePrinter();
298 m_hPrinter = hPrinter;
299 }
300
301 HANDLE Detach()
302 {
303 HANDLE hPrinter = m_hPrinter;
304 m_hPrinter = NULL;
305 return hPrinter;
306 }
307
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
327 CDevModeT(HANDLE hDevMode = NULL) : m_hDevMode(hDevMode)
328 {
329 m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)::GlobalLock(m_hDevMode) : NULL;
330 }
331
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
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
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
360 bool IsNull() const { return (m_hDevMode == NULL); }
361
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
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
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
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
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
455 operator HANDLE() const { return m_hDevMode; }
456
457 operator DEVMODE*() const { return m_pDevMode; }
458
459 // Implementation
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
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
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:
534 virtual void BeginPrintJob(HDC /*hDC*/) // allocate handles needed, etc
535 {
536 }
537
538 virtual void EndPrintJob(HDC /*hDC*/, bool /*bAborted*/) // free handles, etc
539 {
540 }
541
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
549 virtual void PostPrintPage(UINT /*nPage*/, HDC hDC)
550 {
551 RestoreDC(hDC, m_nPJState);
552 }
553
554 virtual DEVMODE* GetNewDevModeForPage(UINT /*nLastPage*/, UINT /*nPage*/)
555 {
556 return NULL;
557 }
558
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
584 CPrintJob() : m_nJobID(0), m_bCancel(false), m_bComplete(true)
585 { }
586
587 ~CPrintJob()
588 {
589 ATLASSERT(IsJobComplete()); // premature destruction?
590 }
591
592 // Operations
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
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
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.
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
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
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
731 void SetEnhMetaFile(HENHMETAFILE hEMF)
732 {
733 m_meta = hEMF;
734 }
735
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
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
796 void DoPaint(CDCHandle dc)
797 {
798 // this one is not used
799 }
800
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
829 CPrintPreviewWindowImpl() : m_nMinPage(0), m_nMaxPage(0)
830 { }
831
832 // Operations
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
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
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)
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
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
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
941 CZoomPrintPreviewWindowImpl()
942 {
943 this->SetScrollExtendedStyle(SCRL_DISABLENOSCROLL);
944 InitZoom();
945 }
946
947 // should be called to reset data members before recreating window
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)
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
1008 LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1009 {
1010 return 1;
1011 }
1012
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
1050 void DoPaint(CDCHandle dc)
1051 {
1052 // this one is not used
1053 }
1054
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
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__