crashrpt2
atlprint.h
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 
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 
46 // CPrinterInfo - This class wraps all of the PRINTER_INFO_* structures
47 // and provided by ::GetPrinter.
48 
49 template <unsigned int t_nInfo>
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>
72 {
73 public:
74 // Data members
75  typename _printer_info<t_nInfo>::infotype* m_pi;
76 
77 // Constructor/destructor
78  CPrinterInfo() : m_pi(NULL)
79  { }
80 
81  CPrinterInfo(HANDLE hPrinter) : m_pi(NULL)
82  {
83  GetPrinterInfo(hPrinter);
84  }
85 
86  ~CPrinterInfo()
87  {
88  Cleanup();
89  }
90 
91 // Operations
92  bool GetPrinterInfo(HANDLE hPrinter)
93  {
94  Cleanup();
95  return GetPrinterInfoHelper(hPrinter, (BYTE**)&m_pi, t_nInfo);
96  }
97 
98 // Implementation
99  void Cleanup()
100  {
101  delete [] (BYTE*)m_pi;
102  m_pi = NULL;
103  }
104 
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 
132 // CPrinter - Wrapper class for a HANDLE to a printer
133 
134 template <bool t_bManaged>
136 {
137 public:
138 // Data members
139  HANDLE m_hPrinter;
140 
141 // Constructor/destructor
142  CPrinterT(HANDLE hPrinter = NULL) : m_hPrinter(hPrinter)
143  { }
144 
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 
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 
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 
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 
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 
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 
312 typedef CPrinterT<true> CPrinter;
313 
314 
316 // CDevMode - Wrapper class for DEVMODE
317 
318 template <bool t_bManaged>
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  SecureHelper::memcpy_x(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  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
416  bool UpdateForNewPrinter(HANDLE hPrinter)
417  {
418  bool bRet = false;
419  LONG nLen = ::DocumentProperties(NULL, hPrinter, NULL, NULL, NULL, 0);
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);
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 
473 typedef CDevModeT<true> CDevMode;
474 
475 
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 
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 
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 #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
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 
701 // CPrintPreview - Adds print preview support to an existing window
702 
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 
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
829  CPrintPreviewWindowImpl() : m_nMaxPage(0), m_nMinPage(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  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  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 = { 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
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 
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  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  m_nZoomMode = ZOOMMODE_OFF;
952  m_fZoomScaleMin = 1.0;
953  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 #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 
1011  LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1012  {
1013  return 1;
1014  }
1015 
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
1053  void DoPaint(CDCHandle dc)
1054  {
1055  // this one is not used
1056  }
1057 
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 
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__
Definition: atlprint.h:50
Definition: atlprint.h:71
Definition: atlgdi.h:1005
Definition: atlgdi.h:3615
Definition: atlprint.h:531
Definition: atlprint.h:135
Definition: atlprint.h:569
Definition: atlprint.h:703
Definition: atlapp.h:553
Definition: atlscrl.h:1320
Definition: atlscrl.h:63
Definition: atlapp.h:1455
Definition: atlgdi.h:1209
Definition: atlprint.h:511
Definition: atlgdi.h:3362
Definition: atlprint.h:923
Definition: atlprint.h:479
Definition: atlgdi.h:3462
Definition: atlprint.h:821
Definition: atlprint.h:319