atlprint.h 28 KB

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