PageRenderTime 114ms CodeModel.GetById 18ms app.highlight 87ms RepoModel.GetById 2ms app.codeStats 0ms

/thirdparty/wtl/atlprint.h

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