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