/thirdparty/wtl/atlprint.h

http://crashrpt.googlecode.com/ · C Header · 1108 lines · 862 code · 154 blank · 92 comment · 119 complexity · c42f42fd79be947d027648589d54bae6 MD5 · raw file

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