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