Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

828 lines
21 KiB

  1. // WTL Version 3.1
  2. // Copyright (C) 1997-2000 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This file is a part of Windows Template Library.
  6. // The code and information is provided "as-is" without
  7. // warranty of any kind, either expressed or implied.
  8. #ifndef __ATLPRINT_H__
  9. #define __ATLPRINT_H__
  10. #pragma once
  11. #ifndef __cplusplus
  12. #error ATL requires C++ compilation (use a .cpp suffix)
  13. #endif
  14. #ifndef __ATLAPP_H__
  15. #error atlprint.h requires atlapp.h to be included first
  16. #endif
  17. #ifndef __ATLWIN_H__
  18. #error atlprint.h requires atlwin.h to be included first
  19. #endif
  20. namespace WTL
  21. {
  22. /////////////////////////////////////////////////////////////////////////////
  23. // Forward declarations
  24. template <unsigned int t_nInfo> class CPrinterInfo;
  25. template <bool t_bManaged> class CPrinterT;
  26. template <bool t_bManaged> class CDevModeT;
  27. class CPrinterDC;
  28. class CPrintJobInfo;
  29. class CPrintJob;
  30. class CPrintPreview;
  31. template <class T, class TBase = CWindow, class TWinTraits = CControlWinTraits> class CPrintPreviewWindowImpl;
  32. class CPrintPreviewWindow;
  33. /////////////////////////////////////////////////////////////////////////////
  34. template <unsigned int t_nInfo>
  35. class _printer_info
  36. {
  37. public:
  38. typedef void infotype;
  39. };
  40. template <> class _printer_info<1> {public: typedef PRINTER_INFO_1 infotype;};
  41. template <> class _printer_info<2> {public: typedef PRINTER_INFO_2 infotype;};
  42. template <> class _printer_info<3> {public: typedef PRINTER_INFO_3 infotype;};
  43. template <> class _printer_info<4> {public: typedef PRINTER_INFO_4 infotype;};
  44. template <> class _printer_info<5> {public: typedef PRINTER_INFO_5 infotype;};
  45. template <> class _printer_info<6> {public: typedef PRINTER_INFO_6 infotype;};
  46. template <> class _printer_info<7> {public: typedef PRINTER_INFO_7 infotype;};
  47. // these are not in the old (vc6.0) headers
  48. #ifdef _ATL_USE_NEW_PRINTER_INFO
  49. template <> class _printer_info<8> {public: typedef PRINTER_INFO_8 infotype;};
  50. template <> class _printer_info<9> {public: typedef PRINTER_INFO_9 infotype;};
  51. #endif //_ATL_USE_NEW_PRINTER_INFO
  52. //This class wraps all of the PRINTER_INFO_* structures
  53. //and provided by ::GetPrinter.
  54. template <unsigned int t_nInfo>
  55. class CPrinterInfo
  56. {
  57. public:
  58. // Data members
  59. _printer_info<t_nInfo>::infotype* m_pi;
  60. // Constructor/destructor
  61. CPrinterInfo() : m_pi(NULL)
  62. { }
  63. CPrinterInfo(HANDLE hPrinter) : m_pi(NULL)
  64. {
  65. GetPrinterInfo(hPrinter);
  66. }
  67. ~CPrinterInfo()
  68. {
  69. Cleanup();
  70. }
  71. // Operations
  72. bool GetPrinterInfo(HANDLE hPrinter)
  73. {
  74. Cleanup();
  75. return GetPrinterInfoHelper(hPrinter, (BYTE**)&m_pi, t_nInfo);
  76. }
  77. // Implementation
  78. void Cleanup()
  79. {
  80. delete [] (BYTE*)m_pi;
  81. m_pi = NULL;
  82. }
  83. static bool GetPrinterInfoHelper(HANDLE hPrinter, BYTE** pi, int nIndex)
  84. {
  85. ATLASSERT(pi != NULL);
  86. DWORD dw = 0;
  87. BYTE* pb = NULL;
  88. ::GetPrinter(hPrinter, nIndex, NULL, 0, &dw);
  89. if (dw > 0)
  90. {
  91. ATLTRY(pb = new BYTE[dw]);
  92. if (pb != NULL)
  93. {
  94. memset(pb, 0, dw);
  95. DWORD dwNew;
  96. if (!::GetPrinter(hPrinter, nIndex, pb, dw, &dwNew))
  97. {
  98. delete [] pb;
  99. pb = NULL;
  100. }
  101. }
  102. }
  103. *pi = pb;
  104. return (pb != NULL);
  105. }
  106. };
  107. //Provides a wrapper class for a HANDLE to a printer.
  108. template <bool t_bManaged>
  109. class CPrinterT
  110. {
  111. public:
  112. // Data members
  113. HANDLE m_hPrinter;
  114. // Constructor/destructor
  115. CPrinterT(HANDLE hPrinter = NULL) : m_hPrinter(hPrinter)
  116. { }
  117. ~CPrinterT()
  118. {
  119. ClosePrinter();
  120. }
  121. // Operations
  122. CPrinterT& operator=(HANDLE hPrinter)
  123. {
  124. if (hPrinter != m_hPrinter)
  125. {
  126. ClosePrinter();
  127. m_hPrinter = hPrinter;
  128. }
  129. return *this;
  130. }
  131. bool IsNull() const { return (m_hPrinter == NULL); }
  132. bool OpenPrinter(HANDLE hDevNames, const DEVMODE* pDevMode = NULL)
  133. {
  134. bool b = false;
  135. DEVNAMES* pdn = (DEVNAMES*)::GlobalLock(hDevNames);
  136. if (pdn != NULL)
  137. {
  138. LPTSTR lpszPrinterName = (LPTSTR)pdn + pdn->wDeviceOffset;
  139. b = OpenPrinter(lpszPrinterName, pDevMode);
  140. ::GlobalUnlock(hDevNames);
  141. }
  142. return b;
  143. }
  144. bool OpenPrinter(LPCTSTR lpszPrinterName, const DEVMODE* pDevMode = NULL)
  145. {
  146. ClosePrinter();
  147. PRINTER_DEFAULTS pdefs = {NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE};
  148. ::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter,
  149. (pDevMode == NULL) ? NULL : &pdefs);
  150. return (m_hPrinter != NULL);
  151. }
  152. bool OpenPrinter(LPCTSTR lpszPrinterName, PRINTER_DEFAULTS* pprintdefs)
  153. {
  154. ClosePrinter();
  155. ::OpenPrinter((LPTSTR) lpszPrinterName, &m_hPrinter, pprintdefs);
  156. return (m_hPrinter != NULL);
  157. }
  158. bool OpenDefaultPrinter(const DEVMODE* pDevMode = NULL)
  159. {
  160. ClosePrinter();
  161. TCHAR buffer[512];
  162. buffer[0] = 0;
  163. ::GetProfileString(_T("windows"), _T("device"), _T(",,,"), buffer, sizeof(buffer));
  164. int nLen = lstrlen(buffer);
  165. if (nLen != 0)
  166. {
  167. LPTSTR lpsz = buffer;
  168. while (*lpsz)
  169. {
  170. if (*lpsz == ',')
  171. {
  172. *lpsz = 0;
  173. break;
  174. }
  175. lpsz = CharNext(lpsz);
  176. }
  177. PRINTER_DEFAULTS pdefs = {NULL, (DEVMODE*)pDevMode, PRINTER_ACCESS_USE};
  178. ::OpenPrinter(buffer, &m_hPrinter, (pDevMode == NULL) ? NULL : &pdefs);
  179. }
  180. return m_hPrinter != NULL;
  181. }
  182. void ClosePrinter()
  183. {
  184. if (m_hPrinter != NULL)
  185. {
  186. if (t_bManaged)
  187. ::ClosePrinter(m_hPrinter);
  188. m_hPrinter = NULL;
  189. }
  190. }
  191. bool PrinterProperties(HWND hWnd = NULL)
  192. {
  193. if (hWnd == NULL)
  194. hWnd = ::GetActiveWindow();
  195. return !!::PrinterProperties(hWnd, m_hPrinter);
  196. }
  197. HANDLE CopyToHDEVNAMES() const
  198. {
  199. HANDLE h = NULL;
  200. CPrinterInfo<5> pinfon5;
  201. CPrinterInfo<2> pinfon2;
  202. LPTSTR lpszPrinterName = NULL;
  203. //Some printers fail for PRINTER_INFO_5 in some situations
  204. if (pinfon5.GetPrinterInfo(m_hPrinter))
  205. lpszPrinterName = pinfon5.m_pi->pPrinterName;
  206. else if (pinfon2.GetPrinterInfo(m_hPrinter))
  207. lpszPrinterName = pinfon2.m_pi->pPrinterName;
  208. if (lpszPrinterName != NULL)
  209. {
  210. int nLen = sizeof(DEVNAMES)+ (lstrlen(lpszPrinterName)+1)*sizeof(TCHAR);
  211. h = GlobalAlloc(GMEM_MOVEABLE, nLen);
  212. BYTE* pv = (BYTE*)GlobalLock(h);
  213. DEVNAMES* pdev = (DEVNAMES*)pv;
  214. if (pv != NULL)
  215. {
  216. memset(pv, 0, nLen);
  217. pdev->wDeviceOffset = sizeof(DEVNAMES)/sizeof(TCHAR);
  218. pv = pv + sizeof(DEVNAMES); //now points to end
  219. lstrcpy((LPTSTR)pv, lpszPrinterName);
  220. GlobalUnlock(h);
  221. }
  222. }
  223. return h;
  224. }
  225. HDC CreatePrinterDC(const DEVMODE* pdm = NULL)
  226. {
  227. CPrinterInfo<5> pinfo5;
  228. CPrinterInfo<2> pinfo2;
  229. HDC hDC = NULL;
  230. LPTSTR lpszPrinterName = NULL;
  231. //Some printers fail for PRINTER_INFO_5 in some situations
  232. if (pinfo5.GetPrinterInfo(m_hPrinter))
  233. lpszPrinterName = pinfo5.m_pi->pPrinterName;
  234. else if (pinfo2.GetPrinterInfo(m_hPrinter))
  235. lpszPrinterName = pinfo2.m_pi->pPrinterName;
  236. if (lpszPrinterName != NULL)
  237. hDC = ::CreateDC(NULL, lpszPrinterName, NULL, pdm);
  238. return hDC;
  239. }
  240. HDC CreatePrinterIC(const DEVMODE* pdm = NULL)
  241. {
  242. CPrinterInfo<5> pinfo5;
  243. CPrinterInfo<2> pinfo2;
  244. HDC hDC = NULL;
  245. LPTSTR lpszPrinterName = NULL;
  246. //Some printers fail for PRINTER_INFO_5 in some situations
  247. if (pinfo5.GetPrinterInfo(m_hPrinter))
  248. lpszPrinterName = pinfo5.m_pi->pPrinterName;
  249. else if (pinfo2.GetPrinterInfo(m_hPrinter))
  250. lpszPrinterName = pinfo2.m_pi->pPrinterName;
  251. if (lpszPrinterName != NULL)
  252. hDC = ::CreateIC(NULL, lpszPrinterName, NULL, pdm);
  253. return hDC;
  254. }
  255. void Attach(HANDLE hPrinter)
  256. {
  257. ClosePrinter();
  258. m_hPrinter = hPrinter;
  259. }
  260. HANDLE Detach()
  261. {
  262. HANDLE hPrinter = m_hPrinter;
  263. m_hPrinter = NULL;
  264. return hPrinter;
  265. }
  266. operator HANDLE() const {return m_hPrinter;}
  267. };
  268. typedef CPrinterT<false> CPrinterHandle;
  269. typedef CPrinterT<true> CPrinter;
  270. template <bool t_bManaged>
  271. class CDevModeT
  272. {
  273. public:
  274. // Data members
  275. HANDLE m_hDevMode;
  276. DEVMODE* m_pDevMode;
  277. // Constructor/destructor
  278. CDevModeT(HANDLE hDevMode = NULL) : m_hDevMode(hDevMode)
  279. {
  280. m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)GlobalLock(m_hDevMode) : NULL;
  281. }
  282. ~CDevModeT()
  283. {
  284. Cleanup();
  285. }
  286. // Operations
  287. CDevModeT<t_bManaged>& operator=(HANDLE hDevMode)
  288. {
  289. Attach(hDevMode);
  290. return *this;
  291. }
  292. void Attach(HANDLE hDevModeNew)
  293. {
  294. Cleanup();
  295. m_hDevMode = hDevModeNew;
  296. m_pDevMode = (m_hDevMode != NULL) ? (DEVMODE*)GlobalLock(m_hDevMode) : NULL;
  297. }
  298. HANDLE Detach()
  299. {
  300. if (m_hDevMode != NULL)
  301. GlobalUnlock(m_hDevMode);
  302. HANDLE hDevMode = m_hDevMode;
  303. m_hDevMode = NULL;
  304. return hDevMode;
  305. }
  306. bool IsNull() const { return (m_hDevMode == NULL); }
  307. bool CopyFromPrinter(HANDLE hPrinter)
  308. {
  309. CPrinterInfo<2> pinfo;
  310. bool b = pinfo.GetPrinterInfo(hPrinter);
  311. if (b)
  312. b = CopyFromDEVMODE(pinfo.m_pi->pDevMode);
  313. return b;
  314. }
  315. bool CopyFromDEVMODE(const DEVMODE* pdm)
  316. {
  317. if (pdm == NULL)
  318. return false;
  319. int nSize = pdm->dmSize + pdm->dmDriverExtra;
  320. HANDLE h = GlobalAlloc(GMEM_MOVEABLE, nSize);
  321. if (h != NULL)
  322. {
  323. void* p = GlobalLock(h);
  324. memcpy(p, pdm, nSize);
  325. GlobalUnlock(h);
  326. }
  327. Attach(h);
  328. return (h != NULL);
  329. }
  330. bool CopyFromHDEVMODE(HANDLE hdm)
  331. {
  332. bool b = false;
  333. if (hdm != NULL)
  334. {
  335. DEVMODE* pdm = (DEVMODE*)GlobalLock(hdm);
  336. b = CopyFromDEVMODE(pdm);
  337. GlobalUnlock(hdm);
  338. }
  339. return b;
  340. }
  341. HANDLE CopyToHDEVMODE()
  342. {
  343. if ((m_hDevMode == NULL) || (m_pDevMode == NULL))
  344. return NULL;
  345. int nSize = m_pDevMode->dmSize + m_pDevMode->dmDriverExtra;
  346. HANDLE h = GlobalAlloc(GMEM_MOVEABLE, nSize);
  347. if (h != NULL)
  348. {
  349. void* p = GlobalLock(h);
  350. memcpy(p, m_pDevMode, nSize);
  351. }
  352. return h;
  353. }
  354. //If this devmode was for another printer, this will create a new devmode
  355. //based on the existing devmode, but retargeted at the new printer
  356. bool UpdateForNewPrinter(HANDLE hPrinter)
  357. {
  358. LONG nLen = ::DocumentProperties(NULL, hPrinter, NULL, NULL, NULL, 0);
  359. DEVMODE* pdm = (DEVMODE*) alloca(nLen);
  360. memset(pdm, 0, nLen);
  361. LONG l = ::DocumentProperties(NULL, hPrinter, NULL, pdm, m_pDevMode,
  362. DM_IN_BUFFER|DM_OUT_BUFFER);
  363. bool b = false;
  364. if (l == IDOK)
  365. b = CopyFromDEVMODE(pdm);
  366. return b;
  367. }
  368. bool DocumentProperties(HANDLE hPrinter, HWND hWnd = NULL)
  369. {
  370. CPrinterInfo<1> pi;
  371. pi.GetPrinterInfo(hPrinter);
  372. if (hWnd == NULL)
  373. hWnd = ::GetActiveWindow();
  374. LONG nLen = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, NULL, NULL, 0);
  375. DEVMODE* pdm = (DEVMODE*) alloca(nLen);
  376. memset(pdm, 0, nLen);
  377. LONG l = ::DocumentProperties(hWnd, hPrinter, pi.m_pi->pName, pdm,
  378. m_pDevMode, DM_IN_BUFFER|DM_OUT_BUFFER|DM_PROMPT);
  379. bool b = false;
  380. if (l == IDOK)
  381. b = CopyFromDEVMODE(pdm);
  382. return b;
  383. }
  384. operator HANDLE() const {return m_hDevMode;}
  385. operator DEVMODE*() const {return m_pDevMode;}
  386. // Implementation
  387. void Cleanup()
  388. {
  389. if (m_hDevMode != NULL)
  390. {
  391. GlobalUnlock(m_hDevMode);
  392. if(t_bManaged)
  393. GlobalFree(m_hDevMode);
  394. m_hDevMode = NULL;
  395. }
  396. }
  397. };
  398. typedef CDevModeT<false> CDevModeHandle;
  399. typedef CDevModeT<true> CDevMode;
  400. class CPrinterDC : public CDC
  401. {
  402. public:
  403. // Constructors/destructor
  404. CPrinterDC()
  405. {
  406. CPrinter printer;
  407. printer.OpenDefaultPrinter();
  408. Attach(printer.CreatePrinterDC());
  409. ATLASSERT(m_hDC != NULL);
  410. }
  411. CPrinterDC(HANDLE hPrinter, const DEVMODE* pdm = NULL)
  412. {
  413. CPrinterHandle p;
  414. p.Attach(hPrinter);
  415. Attach(p.CreatePrinterDC(pdm));
  416. ATLASSERT(m_hDC != NULL);
  417. }
  418. ~CPrinterDC()
  419. {
  420. DeleteDC();
  421. }
  422. };
  423. //Defines callbacks used by CPrintJob (not a COM interface)
  424. class ATL_NO_VTABLE IPrintJobInfo
  425. {
  426. public:
  427. virtual void BeginPrintJob(HDC hDC) = 0; //allocate handles needed, etc
  428. virtual void EndPrintJob(HDC hDC, bool bAborted) = 0; // free handles, etc
  429. virtual void PrePrintPage(UINT nPage, HDC hDC) = 0;
  430. virtual bool PrintPage(UINT nPage, HDC hDC) = 0;
  431. virtual void PostPrintPage(UINT nPage, HDC hDC) = 0;
  432. // If you want per page devmodes, return the DEVMODE* to use for nPage
  433. // You can optimize by only returning a new DEVMODE* when it is different
  434. // from the one for nLastPage, otherwise return NULL.
  435. // When nLastPage==0, the current DEVMODE* will be the default passed to
  436. // StartPrintJob.
  437. // Note: During print preview, nLastPage will always be "0".
  438. virtual DEVMODE* GetNewDevModeForPage(UINT nLastPage, UINT nPage) = 0;
  439. virtual bool IsValidPage(UINT nPage) = 0;
  440. };
  441. //Provides a default implementatin for IPrintJobInfo
  442. //Typically, MI'd into a document or view class
  443. class ATL_NO_VTABLE CPrintJobInfo : public IPrintJobInfo
  444. {
  445. public:
  446. virtual void BeginPrintJob(HDC /*hDC*/) //allocate handles needed, etc
  447. {
  448. }
  449. virtual void EndPrintJob(HDC /*hDC*/, bool /*bAborted*/) // free handles, etc
  450. {
  451. }
  452. virtual void PrePrintPage(UINT /*nPage*/, HDC hDC)
  453. {
  454. m_nPJState = ::SaveDC(hDC);
  455. }
  456. virtual bool PrintPage(UINT /*nPage*/, HDC /*hDC*/) = 0;
  457. virtual void PostPrintPage(UINT /*nPage*/, HDC hDC)
  458. {
  459. RestoreDC(hDC, m_nPJState);
  460. }
  461. virtual DEVMODE* GetNewDevModeForPage(UINT /*nLastPage*/, UINT /*nPage*/)
  462. {
  463. return NULL;
  464. }
  465. virtual bool IsValidPage(UINT /*nPage*/)
  466. {
  467. return true;
  468. }
  469. private:
  470. int m_nPJState;
  471. };
  472. //Wraps a set of tasks for a specific printer (StartDoc/EndDoc)
  473. //Handles aborting, background printing
  474. class CPrintJob
  475. {
  476. public:
  477. CPrinterHandle m_printer;
  478. IPrintJobInfo* m_pInfo;
  479. DEVMODE* m_pDefDevMode;
  480. DOCINFO m_docinfo;
  481. DWORD m_dwJobID;
  482. bool m_bCancel;
  483. bool m_bComplete;
  484. unsigned long m_nStartPage;
  485. unsigned long m_nEndPage;
  486. CPrintJob()
  487. {
  488. m_dwJobID = 0;
  489. m_bCancel = false;
  490. m_bComplete = true;
  491. }
  492. ~CPrintJob()
  493. {
  494. ATLASSERT(IsJobComplete()); //premature destruction?
  495. }
  496. bool IsJobComplete() const { return m_bComplete; }
  497. bool StartPrintJob(bool bBackground, HANDLE hPrinter, DEVMODE* pDefaultDevMode,
  498. IPrintJobInfo* pInfo, LPCTSTR lpszDocName,
  499. unsigned long nStartPage, unsigned long nEndPage)
  500. {
  501. ATLASSERT(m_bComplete); //previous job not done yet?
  502. if (pInfo == NULL)
  503. return false;
  504. memset(&m_docinfo, 0, sizeof(m_docinfo));
  505. m_docinfo.cbSize = sizeof(m_docinfo);
  506. m_docinfo.lpszDocName = lpszDocName;
  507. m_pInfo = pInfo;
  508. m_nStartPage = nStartPage;
  509. m_nEndPage = nEndPage;
  510. m_printer.Attach(hPrinter);
  511. m_pDefDevMode = pDefaultDevMode;
  512. m_bComplete = false;
  513. if (!bBackground)
  514. {
  515. m_bComplete = true;
  516. return StartHelper();
  517. }
  518. //Create a thread and return
  519. DWORD dwThreadID = 0;
  520. HANDLE hThread = CreateThread(NULL, 0, StartProc, (void*)this, 0, &dwThreadID);
  521. CloseHandle(hThread);
  522. return (hThread != NULL);
  523. }
  524. // Implementation
  525. static DWORD WINAPI StartProc(void* p)
  526. {
  527. CPrintJob* pThis = (CPrintJob*)p;
  528. pThis->StartHelper();
  529. pThis->m_bComplete = true;
  530. return 0;
  531. }
  532. bool StartHelper()
  533. {
  534. CDC dcPrinter;
  535. dcPrinter.Attach(m_printer.CreatePrinterDC(m_pDefDevMode));
  536. if (dcPrinter.IsNull())
  537. return false;
  538. m_dwJobID = ::StartDoc(dcPrinter, &m_docinfo);
  539. if (m_dwJobID == 0)
  540. return false;
  541. m_pInfo->BeginPrintJob(dcPrinter);
  542. //print all the pages now
  543. unsigned long nPage;
  544. unsigned long nLastPage=0;
  545. for (nPage = m_nStartPage; nPage <= m_nEndPage; nPage++)
  546. {
  547. if (!m_pInfo->IsValidPage(nPage))
  548. break;
  549. DEVMODE* pdm = m_pInfo->GetNewDevModeForPage(nLastPage, nPage);
  550. if (pdm != NULL)
  551. dcPrinter.ResetDC(pdm);
  552. dcPrinter.StartPage();
  553. m_pInfo->PrePrintPage(nPage, dcPrinter);
  554. if (!m_pInfo->PrintPage(nPage, dcPrinter))
  555. m_bCancel = true;
  556. m_pInfo->PostPrintPage(nPage, dcPrinter);
  557. dcPrinter.EndPage();
  558. if (m_bCancel)
  559. break;
  560. nLastPage = nPage;
  561. }
  562. m_pInfo->EndPrintJob(dcPrinter, m_bCancel);
  563. if (m_bCancel)
  564. ::AbortDoc(dcPrinter);
  565. else
  566. ::EndDoc(dcPrinter);
  567. m_dwJobID = 0;
  568. return true;
  569. }
  570. //Cancels a print job. Can be called asynchronously.
  571. bool CancelPrintJob()
  572. {
  573. m_bCancel = 1;
  574. }
  575. };
  576. // Adds print preview support to an existing window
  577. class CPrintPreview
  578. {
  579. public:
  580. // Data members
  581. IPrintJobInfo* m_pInfo;
  582. CPrinterHandle m_printer;
  583. CEnhMetaFile m_meta;
  584. DEVMODE* m_pDefDevMode;
  585. DEVMODE* m_pCurDevMode;
  586. SIZE m_sizeCurPhysOffset;
  587. // Constructor
  588. CPrintPreview() : m_pInfo(NULL), m_pDefDevMode(NULL), m_pCurDevMode(NULL)
  589. {
  590. m_sizeCurPhysOffset.cx = 0;
  591. m_sizeCurPhysOffset.cy = 0;
  592. }
  593. // Operations
  594. void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, IPrintJobInfo* pji)
  595. {
  596. m_printer.Attach(hPrinter);
  597. m_pDefDevMode = pDefaultDevMode;
  598. m_pInfo = pji;
  599. m_nCurPage = 0;
  600. m_pCurDevMode = NULL;
  601. }
  602. void SetEnhMetaFile(HENHMETAFILE hEMF)
  603. {
  604. m_meta = hEMF;
  605. }
  606. void SetPage(int nPage)
  607. {
  608. if (!m_pInfo->IsValidPage(nPage))
  609. return;
  610. m_nCurPage = nPage;
  611. m_pCurDevMode = m_pInfo->GetNewDevModeForPage(0, nPage);
  612. if (m_pCurDevMode == NULL)
  613. m_pCurDevMode = m_pDefDevMode;
  614. CDC dcPrinter = m_printer.CreatePrinterDC(m_pCurDevMode);
  615. int iWidth = dcPrinter.GetDeviceCaps(PHYSICALWIDTH);
  616. int iHeight = dcPrinter.GetDeviceCaps(PHYSICALHEIGHT);
  617. int nLogx = dcPrinter.GetDeviceCaps(LOGPIXELSX);
  618. int nLogy = dcPrinter.GetDeviceCaps(LOGPIXELSY);
  619. RECT rcMM = {0,0, MulDiv(iWidth, 2540, nLogx), MulDiv(iHeight, 2540, nLogy)};
  620. m_sizeCurPhysOffset.cx = dcPrinter.GetDeviceCaps(PHYSICALOFFSETX);
  621. m_sizeCurPhysOffset.cy = dcPrinter.GetDeviceCaps(PHYSICALOFFSETY);
  622. CEnhMetaFileDC dcMeta(dcPrinter, &rcMM);
  623. m_pInfo->PrePrintPage(nPage, dcMeta);
  624. m_pInfo->PrintPage(nPage, dcMeta);
  625. m_pInfo->PostPrintPage(nPage, dcMeta);
  626. m_meta.Attach(dcMeta.Close());
  627. }
  628. void GetPageRect(RECT& rc, LPRECT prc)
  629. {
  630. int x1 = rc.right-rc.left;
  631. int y1 = rc.bottom - rc.top;
  632. if ((x1 < 0) || (y1 < 0))
  633. return;
  634. CEnhMetaFileInfo emfinfo(m_meta);
  635. ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader();
  636. //Compute whether we are OK vertically or horizontally
  637. int x2 = pmh->szlDevice.cx;
  638. int y2 = pmh->szlDevice.cy;
  639. int y1p = MulDiv(x1, y2, x2);
  640. int x1p = MulDiv(y1, x2, y2);
  641. ATLASSERT( (x1p <= x1) || (y1p <= y1));
  642. if (x1p <= x1)
  643. {
  644. prc->left = rc.left + (x1 - x1p)/2;
  645. prc->right = prc->left + x1p;
  646. prc->top = rc.top;
  647. prc->bottom = rc.bottom;
  648. }
  649. else
  650. {
  651. prc->left = rc.left;
  652. prc->right = rc.right;
  653. prc->top = rc.top + (y1 - y1p)/2;
  654. prc->bottom = prc->top + y1p;
  655. }
  656. }
  657. // Painting helper
  658. void DoPaint(CDCHandle dc, RECT& rc)
  659. {
  660. CEnhMetaFileInfo emfinfo(m_meta);
  661. ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader();
  662. int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx);
  663. int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy);
  664. dc.OffsetWindowOrg(-nOffsetX, -nOffsetY);
  665. dc.PlayMetaFile(m_meta, &rc);
  666. }
  667. // Implementation - data
  668. int m_nCurPage;
  669. };
  670. template <class T, class TBase = CWindow, class TWinTraits = CControlWinTraits>
  671. class ATL_NO_VTABLE CPrintPreviewWindowImpl : public CWindowImpl<T, TBase, TWinTraits>, public CPrintPreview
  672. {
  673. public:
  674. DECLARE_WND_CLASS_EX(NULL, CS_VREDRAW | CS_HREDRAW, -1)
  675. enum { m_cxOffset = 10, m_cyOffset = 10 };
  676. // Constructor
  677. CPrintPreviewWindowImpl() : m_nMaxPage(0), m_nMinPage(0)
  678. { }
  679. // Operations
  680. void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode,
  681. IPrintJobInfo* pji, int nMinPage, int nMaxPage)
  682. {
  683. CPrintPreview::SetPrintPreviewInfo(hPrinter, pDefaultDevMode, pji);
  684. m_nMinPage = nMinPage;
  685. m_nMaxPage = nMaxPage;
  686. }
  687. bool NextPage()
  688. {
  689. if (m_nCurPage == m_nMaxPage)
  690. return false;
  691. SetPage(m_nCurPage + 1);
  692. Invalidate();
  693. return true;
  694. }
  695. bool PrevPage()
  696. {
  697. if (m_nCurPage == m_nMinPage)
  698. return false;
  699. if (m_nCurPage == 0)
  700. return false;
  701. SetPage(m_nCurPage - 1);
  702. Invalidate();
  703. return true;
  704. }
  705. // Message map and handlers
  706. BEGIN_MSG_MAP(CPrintPreviewWindowImpl)
  707. MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
  708. MESSAGE_HANDLER(WM_PAINT, OnPaint)
  709. END_MSG_MAP()
  710. LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  711. {
  712. return 1; // no need for the background
  713. }
  714. LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  715. {
  716. T* pT = static_cast<T*>(this);
  717. CPaintDC dc(m_hWnd);
  718. RECT rcClient;
  719. GetClientRect(&rcClient);
  720. RECT rcArea = rcClient;
  721. ::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset);
  722. if (rcArea.left > rcArea.right)
  723. rcArea.right = rcArea.left;
  724. if (rcArea.top > rcArea.bottom)
  725. rcArea.bottom = rcArea.top;
  726. RECT rc;
  727. GetPageRect(rcArea, &rc);
  728. CRgn rgn1, rgn2;
  729. rgn1.CreateRectRgnIndirect(&rc);
  730. rgn2.CreateRectRgnIndirect(&rcClient);
  731. rgn2.CombineRgn(rgn1, RGN_DIFF);
  732. dc.SelectClipRgn(rgn2);
  733. dc.FillRect(&rcClient, (HBRUSH)LongToPtr(COLOR_BTNSHADOW+1));
  734. dc.SelectClipRgn(NULL);
  735. dc.FillRect(&rc, (HBRUSH)GetStockObject(WHITE_BRUSH));
  736. pT->DoPaint(dc.m_hDC, rc);
  737. return 0;
  738. }
  739. // Implementation - data
  740. int m_nMinPage;
  741. int m_nMaxPage;
  742. };
  743. class CPrintPreviewWindow : public CPrintPreviewWindowImpl<CPrintPreviewWindow>
  744. {
  745. public:
  746. DECLARE_WND_CLASS_EX(_T("WTL_PrintPreview"), CS_VREDRAW | CS_HREDRAW, -1)
  747. };
  748. }; //namespace WTL
  749. #endif // __ATLPRINT_H__