atlprint.h 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125
  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) / sizeof(TCHAR);
  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) / sizeof(TCHAR) + lstrlen(lpszPrinterName) + 1);
  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. CPrintJobInfo() : m_nPJState(0)
  460. { }
  461. virtual void BeginPrintJob(HDC /*hDC*/) // allocate handles needed, etc
  462. {
  463. }
  464. virtual void EndPrintJob(HDC /*hDC*/, bool /*bAborted*/) // free handles, etc
  465. {
  466. }
  467. virtual void PrePrintPage(UINT /*nPage*/, HDC hDC)
  468. {
  469. m_nPJState = ::SaveDC(hDC);
  470. }
  471. virtual bool PrintPage(UINT /*nPage*/, HDC /*hDC*/) = 0;
  472. virtual void PostPrintPage(UINT /*nPage*/, HDC hDC)
  473. {
  474. RestoreDC(hDC, m_nPJState);
  475. }
  476. virtual DEVMODE* GetNewDevModeForPage(UINT /*nLastPage*/, UINT /*nPage*/)
  477. {
  478. return NULL;
  479. }
  480. virtual bool IsValidPage(UINT /*nPage*/)
  481. {
  482. return true;
  483. }
  484. // Implementation - data
  485. int m_nPJState;
  486. };
  487. class CPrintJob
  488. {
  489. public:
  490. // Data members
  491. CPrinterHandle m_printer;
  492. IPrintJobInfo* m_pInfo;
  493. DEVMODE* m_pDefDevMode;
  494. DOCINFO m_docinfo;
  495. int m_nJobID;
  496. bool m_bCancel;
  497. bool m_bComplete;
  498. unsigned long m_nStartPage;
  499. unsigned long m_nEndPage;
  500. // Constructor/destructor
  501. CPrintJob() : m_pInfo(NULL), m_pDefDevMode(NULL), m_nJobID(0), m_bCancel(false), m_bComplete(true), m_nStartPage(0), m_nEndPage(0)
  502. {
  503. memset(&m_docinfo, 0, sizeof(m_docinfo));
  504. }
  505. ~CPrintJob()
  506. {
  507. ATLASSERT(IsJobComplete()); // premature destruction?
  508. }
  509. // Operations
  510. bool IsJobComplete() const
  511. {
  512. return m_bComplete;
  513. }
  514. bool StartPrintJob(bool bBackground, HANDLE hPrinter, DEVMODE* pDefaultDevMode,
  515. IPrintJobInfo* pInfo, LPCTSTR lpszDocName,
  516. unsigned long nStartPage, unsigned long nEndPage,
  517. bool bPrintToFile = false, LPCTSTR lpstrOutputFile = NULL)
  518. {
  519. ATLASSERT(m_bComplete); // previous job not done yet?
  520. if (pInfo == NULL)
  521. return false;
  522. memset(&m_docinfo, 0, sizeof(m_docinfo));
  523. m_docinfo.cbSize = sizeof(m_docinfo);
  524. m_docinfo.lpszDocName = lpszDocName;
  525. m_pInfo = pInfo;
  526. m_nStartPage = nStartPage;
  527. m_nEndPage = nEndPage;
  528. m_printer.Attach(hPrinter);
  529. m_pDefDevMode = pDefaultDevMode;
  530. m_bComplete = false;
  531. if(bPrintToFile)
  532. m_docinfo.lpszOutput = (lpstrOutputFile != NULL) ? lpstrOutputFile : _T("FILE:");
  533. if (!bBackground)
  534. {
  535. m_bComplete = true;
  536. return StartHelper();
  537. }
  538. // Create a thread and return
  539. DWORD dwThreadID = 0;
  540. #ifdef _MT
  541. HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, (UINT (WINAPI*)(void*))StartProc, this, 0, (UINT*)&dwThreadID);
  542. #else
  543. HANDLE hThread = ::CreateThread(NULL, 0, StartProc, (void*)this, 0, &dwThreadID);
  544. #endif
  545. if (hThread == NULL)
  546. return false;
  547. ::CloseHandle(hThread);
  548. return true;
  549. }
  550. // Implementation
  551. static DWORD WINAPI StartProc(void* p)
  552. {
  553. CPrintJob* pThis = (CPrintJob*)p;
  554. pThis->StartHelper();
  555. pThis->m_bComplete = true;
  556. return 0;
  557. }
  558. bool StartHelper()
  559. {
  560. CDC dcPrinter;
  561. dcPrinter.Attach(m_printer.CreatePrinterDC(m_pDefDevMode));
  562. if (dcPrinter.IsNull())
  563. return false;
  564. m_nJobID = ::StartDoc(dcPrinter, &m_docinfo);
  565. if (m_nJobID <= 0)
  566. return false;
  567. m_pInfo->BeginPrintJob(dcPrinter);
  568. // print all the pages now
  569. unsigned long nLastPage = 0;
  570. for (unsigned long nPage = m_nStartPage; nPage <= m_nEndPage; nPage++)
  571. {
  572. if (!m_pInfo->IsValidPage(nPage))
  573. break;
  574. DEVMODE* pdm = m_pInfo->GetNewDevModeForPage(nLastPage, nPage);
  575. if (pdm != NULL)
  576. dcPrinter.ResetDC(pdm);
  577. dcPrinter.StartPage();
  578. m_pInfo->PrePrintPage(nPage, dcPrinter);
  579. if (!m_pInfo->PrintPage(nPage, dcPrinter))
  580. m_bCancel = true;
  581. m_pInfo->PostPrintPage(nPage, dcPrinter);
  582. dcPrinter.EndPage();
  583. if (m_bCancel)
  584. break;
  585. nLastPage = nPage;
  586. }
  587. m_pInfo->EndPrintJob(dcPrinter, m_bCancel);
  588. if (m_bCancel)
  589. ::AbortDoc(dcPrinter);
  590. else
  591. ::EndDoc(dcPrinter);
  592. m_nJobID = 0;
  593. return true;
  594. }
  595. // Cancels a print job. Can be called asynchronously.
  596. void CancelPrintJob()
  597. {
  598. m_bCancel = true;
  599. }
  600. };
  601. ///////////////////////////////////////////////////////////////////////////////
  602. // CPrintPreview - Adds print preview support to an existing window
  603. class CPrintPreview
  604. {
  605. public:
  606. // Data members
  607. IPrintJobInfo* m_pInfo;
  608. CPrinterHandle m_printer;
  609. CEnhMetaFile m_meta;
  610. DEVMODE* m_pDefDevMode;
  611. DEVMODE* m_pCurDevMode;
  612. SIZE m_sizeCurPhysOffset;
  613. // Implementation - data
  614. int m_nCurPage;
  615. // Constructor
  616. CPrintPreview() : m_pInfo(NULL), m_pDefDevMode(NULL), m_pCurDevMode(NULL), m_nCurPage(0)
  617. {
  618. m_sizeCurPhysOffset.cx = 0;
  619. m_sizeCurPhysOffset.cy = 0;
  620. }
  621. // Operations
  622. void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode, IPrintJobInfo* pji)
  623. {
  624. m_printer.Attach(hPrinter);
  625. m_pDefDevMode = pDefaultDevMode;
  626. m_pInfo = pji;
  627. m_nCurPage = 0;
  628. m_pCurDevMode = NULL;
  629. }
  630. void SetEnhMetaFile(HENHMETAFILE hEMF)
  631. {
  632. m_meta = hEMF;
  633. }
  634. void SetPage(int nPage)
  635. {
  636. if (!m_pInfo->IsValidPage(nPage))
  637. return;
  638. m_nCurPage = nPage;
  639. m_pCurDevMode = m_pInfo->GetNewDevModeForPage(0, nPage);
  640. if (m_pCurDevMode == NULL)
  641. m_pCurDevMode = m_pDefDevMode;
  642. CDC dcPrinter = m_printer.CreatePrinterDC(m_pCurDevMode);
  643. int iWidth = dcPrinter.GetDeviceCaps(PHYSICALWIDTH);
  644. int iHeight = dcPrinter.GetDeviceCaps(PHYSICALHEIGHT);
  645. int nLogx = dcPrinter.GetDeviceCaps(LOGPIXELSX);
  646. int nLogy = dcPrinter.GetDeviceCaps(LOGPIXELSY);
  647. RECT rcMM = { 0, 0, ::MulDiv(iWidth, 2540, nLogx), ::MulDiv(iHeight, 2540, nLogy) };
  648. m_sizeCurPhysOffset.cx = dcPrinter.GetDeviceCaps(PHYSICALOFFSETX);
  649. m_sizeCurPhysOffset.cy = dcPrinter.GetDeviceCaps(PHYSICALOFFSETY);
  650. CEnhMetaFileDC dcMeta(dcPrinter, &rcMM);
  651. m_pInfo->PrePrintPage(nPage, dcMeta);
  652. m_pInfo->PrintPage(nPage, dcMeta);
  653. m_pInfo->PostPrintPage(nPage, dcMeta);
  654. m_meta.Attach(dcMeta.Close());
  655. }
  656. void GetPageRect(RECT& rc, LPRECT prc)
  657. {
  658. int x1 = rc.right-rc.left;
  659. int y1 = rc.bottom - rc.top;
  660. if ((x1 < 0) || (y1 < 0))
  661. return;
  662. CEnhMetaFileInfo emfinfo(m_meta);
  663. ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader();
  664. if(pmh == NULL)
  665. {
  666. ATLASSERT(FALSE);
  667. return;
  668. }
  669. // Compute whether we are OK vertically or horizontally
  670. int x2 = pmh->szlDevice.cx;
  671. int y2 = pmh->szlDevice.cy;
  672. int y1p = MulDiv(x1, y2, x2);
  673. int x1p = MulDiv(y1, x2, y2);
  674. ATLASSERT((x1p <= x1) || (y1p <= y1));
  675. if (x1p <= x1)
  676. {
  677. prc->left = rc.left + (x1 - x1p) / 2;
  678. prc->right = prc->left + x1p;
  679. prc->top = rc.top;
  680. prc->bottom = rc.bottom;
  681. }
  682. else
  683. {
  684. prc->left = rc.left;
  685. prc->right = rc.right;
  686. prc->top = rc.top + (y1 - y1p) / 2;
  687. prc->bottom = prc->top + y1p;
  688. }
  689. }
  690. // Painting helpers
  691. void DoPaint(CDCHandle dc)
  692. {
  693. // this one is not used
  694. }
  695. void DoPaint(CDCHandle dc, RECT& rc)
  696. {
  697. CEnhMetaFileInfo emfinfo(m_meta);
  698. ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader();
  699. if(pmh == NULL)
  700. {
  701. ATLASSERT(FALSE);
  702. return;
  703. }
  704. int nOffsetX = MulDiv(m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx);
  705. int nOffsetY = MulDiv(m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy);
  706. dc.OffsetWindowOrg(-nOffsetX, -nOffsetY);
  707. dc.PlayMetaFile(m_meta, &rc);
  708. }
  709. };
  710. ///////////////////////////////////////////////////////////////////////////////
  711. // CPrintPreviewWindow - Implements a print preview window
  712. template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
  713. class ATL_NO_VTABLE CPrintPreviewWindowImpl : public ATL::CWindowImpl<T, TBase, TWinTraits>, public CPrintPreview
  714. {
  715. public:
  716. DECLARE_WND_CLASS_EX2(NULL, T, CS_VREDRAW | CS_HREDRAW, -1)
  717. enum { m_cxOffset = 10, m_cyOffset = 10 };
  718. // Constructor
  719. CPrintPreviewWindowImpl() : m_nMinPage(0), m_nMaxPage(0)
  720. { }
  721. // Operations
  722. void SetPrintPreviewInfo(HANDLE hPrinter, DEVMODE* pDefaultDevMode,
  723. IPrintJobInfo* pji, int nMinPage, int nMaxPage)
  724. {
  725. CPrintPreview::SetPrintPreviewInfo(hPrinter, pDefaultDevMode, pji);
  726. m_nMinPage = nMinPage;
  727. m_nMaxPage = nMaxPage;
  728. }
  729. bool NextPage()
  730. {
  731. if (m_nCurPage == m_nMaxPage)
  732. return false;
  733. SetPage(m_nCurPage + 1);
  734. this->Invalidate();
  735. return true;
  736. }
  737. bool PrevPage()
  738. {
  739. if (m_nCurPage == m_nMinPage)
  740. return false;
  741. if (m_nCurPage == 0)
  742. return false;
  743. SetPage(m_nCurPage - 1);
  744. this->Invalidate();
  745. return true;
  746. }
  747. // Message map and handlers
  748. BEGIN_MSG_MAP(CPrintPreviewWindowImpl)
  749. MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
  750. MESSAGE_HANDLER(WM_PAINT, OnPaint)
  751. MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
  752. END_MSG_MAP()
  753. LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  754. {
  755. return 1; // no need for the background
  756. }
  757. LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  758. {
  759. T* pT = static_cast<T*>(this);
  760. RECT rc = {};
  761. if(wParam != NULL)
  762. {
  763. pT->DoPrePaint((HDC)wParam, rc);
  764. pT->DoPaint((HDC)wParam, rc);
  765. }
  766. else
  767. {
  768. CPaintDC dc(this->m_hWnd);
  769. pT->DoPrePaint(dc.m_hDC, rc);
  770. pT->DoPaint(dc.m_hDC, rc);
  771. }
  772. return 0;
  773. }
  774. // Painting helper
  775. void DoPrePaint(CDCHandle dc, RECT& rc)
  776. {
  777. RECT rcClient = {};
  778. this->GetClientRect(&rcClient);
  779. RECT rcArea = rcClient;
  780. T* pT = static_cast<T*>(this);
  781. (void)pT; // avoid level 4 warning
  782. ::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset);
  783. if (rcArea.left > rcArea.right)
  784. rcArea.right = rcArea.left;
  785. if (rcArea.top > rcArea.bottom)
  786. rcArea.bottom = rcArea.top;
  787. GetPageRect(rcArea, &rc);
  788. CRgn rgn1, rgn2;
  789. rgn1.CreateRectRgnIndirect(&rc);
  790. rgn2.CreateRectRgnIndirect(&rcClient);
  791. rgn2.CombineRgn(rgn1, RGN_DIFF);
  792. dc.SelectClipRgn(rgn2);
  793. dc.FillRect(&rcClient, COLOR_BTNSHADOW);
  794. dc.SelectClipRgn(NULL);
  795. dc.FillRect(&rc, (HBRUSH)::GetStockObject(WHITE_BRUSH));
  796. }
  797. // Implementation - data
  798. int m_nMinPage;
  799. int m_nMaxPage;
  800. };
  801. class CPrintPreviewWindow : public CPrintPreviewWindowImpl<CPrintPreviewWindow>
  802. {
  803. public:
  804. DECLARE_WND_CLASS_EX(_T("WTL_PrintPreview"), CS_VREDRAW | CS_HREDRAW, -1)
  805. };
  806. ///////////////////////////////////////////////////////////////////////////////
  807. // CZoomPrintPreviewWindowImpl - Implements print preview window with zooming
  808. #ifdef __ATLSCRL_H__
  809. template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
  810. class ATL_NO_VTABLE CZoomPrintPreviewWindowImpl : public CPrintPreviewWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T >
  811. {
  812. public:
  813. bool m_bSized;
  814. CZoomPrintPreviewWindowImpl()
  815. {
  816. this->SetScrollExtendedStyle(SCRL_DISABLENOSCROLL);
  817. InitZoom();
  818. }
  819. // should be called to reset data members before recreating window
  820. void InitZoom()
  821. {
  822. m_bSized = false;
  823. this->m_nZoomMode = ZOOMMODE_OFF;
  824. this->m_fZoomScaleMin = 1.0;
  825. this->m_fZoomScale = 1.0;
  826. }
  827. BEGIN_MSG_MAP(CZoomPrintPreviewWindowImpl)
  828. MESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor)
  829. MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)
  830. MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)
  831. MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)
  832. MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)
  833. MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)
  834. MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown)
  835. MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove)
  836. MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp)
  837. MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged)
  838. MESSAGE_HANDLER(WM_SIZE, OnSize)
  839. MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
  840. MESSAGE_HANDLER(WM_PAINT, OnPaint)
  841. MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
  842. ALT_MSG_MAP(1)
  843. COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)
  844. COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)
  845. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)
  846. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)
  847. COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)
  848. COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)
  849. COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)
  850. COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)
  851. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)
  852. COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)
  853. COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)
  854. COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)
  855. END_MSG_MAP()
  856. LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  857. {
  858. SIZE sizeClient = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
  859. POINT ptOffset = this->m_ptOffset;
  860. SIZE sizeAll = this->m_sizeAll;
  861. this->SetScrollSize(sizeClient);
  862. if(sizeAll.cx > 0)
  863. ptOffset.x = ::MulDiv(ptOffset.x, this->m_sizeAll.cx, sizeAll.cx);
  864. if(sizeAll.cy > 0)
  865. ptOffset.y = ::MulDiv(ptOffset.y, this->m_sizeAll.cy, sizeAll.cy);
  866. this->SetScrollOffset(ptOffset);
  867. CScrollImpl< T >::OnSize(uMsg, wParam, lParam, bHandled);
  868. if(!m_bSized)
  869. {
  870. m_bSized = true;
  871. T* pT = static_cast<T*>(this);
  872. pT->ShowScrollBar(SB_HORZ, TRUE);
  873. pT->ShowScrollBar(SB_VERT, TRUE);
  874. }
  875. return 0;
  876. }
  877. LRESULT OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  878. {
  879. return 1;
  880. }
  881. LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  882. {
  883. T* pT = static_cast<T*>(this);
  884. RECT rc = {};
  885. if(wParam != NULL)
  886. {
  887. CDCHandle dc = (HDC)wParam;
  888. int nMapModeSav = dc.GetMapMode();
  889. dc.SetMapMode(MM_ANISOTROPIC);
  890. SIZE szWindowExt = { 0, 0 };
  891. dc.SetWindowExt(this->m_sizeLogAll, &szWindowExt);
  892. SIZE szViewportExt = { 0, 0 };
  893. dc.SetViewportExt(this->m_sizeAll, &szViewportExt);
  894. POINT ptViewportOrg = { 0, 0 };
  895. dc.SetViewportOrg(-this->m_ptOffset.x, -this->m_ptOffset.y, &ptViewportOrg);
  896. pT->DoPrePaint(dc, rc);
  897. pT->DoPaint(dc, rc);
  898. dc.SetMapMode(nMapModeSav);
  899. dc.SetWindowExt(szWindowExt);
  900. dc.SetViewportExt(szViewportExt);
  901. dc.SetViewportOrg(ptViewportOrg);
  902. }
  903. else
  904. {
  905. CPaintDC dc(pT->m_hWnd);
  906. pT->PrepareDC(dc.m_hDC);
  907. pT->DoPrePaint(dc.m_hDC, rc);
  908. pT->DoPaint(dc.m_hDC, rc);
  909. }
  910. return 0;
  911. }
  912. // Painting helpers
  913. void DoPaint(CDCHandle dc)
  914. {
  915. // this one is not used
  916. }
  917. void DoPrePaint(CDCHandle dc, RECT& rc)
  918. {
  919. RECT rcClient = {};
  920. this->GetClientRect(&rcClient);
  921. RECT rcArea = rcClient;
  922. T* pT = static_cast<T*>(this);
  923. (void)pT; // avoid level 4 warning
  924. ::InflateRect(&rcArea, -pT->m_cxOffset, -pT->m_cyOffset);
  925. if (rcArea.left > rcArea.right)
  926. rcArea.right = rcArea.left;
  927. if (rcArea.top > rcArea.bottom)
  928. rcArea.bottom = rcArea.top;
  929. this->GetPageRect(rcArea, &rc);
  930. HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW));
  931. dc.PatBlt(rcClient.left, rcClient.top, rc.left - rcClient.left, rcClient.bottom - rcClient.top, PATCOPY);
  932. dc.PatBlt(rc.left, rcClient.top, rc.right - rc.left, rc.top - rcClient.top, PATCOPY);
  933. dc.PatBlt(rc.right, rcClient.top, rcClient.right - rc.right, rcClient.bottom - rcClient.top, PATCOPY);
  934. dc.PatBlt(rc.left, rc.bottom, rc.right - rc.left, rcClient.bottom - rc.bottom, PATCOPY);
  935. dc.SelectBrush((HBRUSH)::GetStockObject(WHITE_BRUSH));
  936. dc.PatBlt(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY);
  937. dc.SelectBrush(::GetSysColorBrush(COLOR_3DDKSHADOW));
  938. dc.PatBlt(rc.right, rc.top + 4, 4, rc.bottom - rc.top, PATCOPY);
  939. dc.PatBlt(rc.left + 4, rc.bottom, rc.right - rc.left, 4, PATCOPY);
  940. dc.SelectBrush(hbrOld);
  941. }
  942. void DoPaint(CDCHandle dc, RECT& rc)
  943. {
  944. CEnhMetaFileInfo emfinfo(this->m_meta);
  945. ENHMETAHEADER* pmh = emfinfo.GetEnhMetaFileHeader();
  946. if(pmh == NULL)
  947. {
  948. ATLASSERT(FALSE);
  949. return;
  950. }
  951. int nOffsetX = MulDiv(this->m_sizeCurPhysOffset.cx, rc.right-rc.left, pmh->szlDevice.cx);
  952. int nOffsetY = MulDiv(this->m_sizeCurPhysOffset.cy, rc.bottom-rc.top, pmh->szlDevice.cy);
  953. dc.OffsetWindowOrg(-nOffsetX, -nOffsetY);
  954. dc.PlayMetaFile(this->m_meta, &rc);
  955. }
  956. };
  957. class CZoomPrintPreviewWindow : public CZoomPrintPreviewWindowImpl<CZoomPrintPreviewWindow>
  958. {
  959. public:
  960. DECLARE_WND_CLASS_EX(_T("WTL_ZoomPrintPreview"), CS_VREDRAW | CS_HREDRAW, -1)
  961. };
  962. #endif // __ATLSCRL_H__
  963. } // namespace WTL
  964. #endif // __ATLPRINT_H__