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

3964 lines
120 KiB

  1. //===============================================================
  2. //
  3. // tmpprint.cxx : Implementation of the CTemplatePrinter Peer
  4. //
  5. // Synposis : This class has two major responsibilities
  6. // 1) Providing printer UI (dialogs, &c...) to a print template
  7. // 2) Providing a way for the template document to reach the printer
  8. //
  9. //===============================================================
  10. #include "headers.h"
  11. #pragma MARK_DATA(__FILE__)
  12. #pragma MARK_CODE(__FILE__)
  13. #pragma MARK_CONST(__FILE__)
  14. #ifndef X_TMPPRINT_HXX_
  15. #define X_TMPPRINT_HXX_
  16. #include "tmpprint.hxx"
  17. #endif
  18. #ifndef X_IEXTAG_H_
  19. #define X_IEXTAG_H_
  20. #include "iextag.h"
  21. #endif
  22. #ifndef X_SHLGUID_H_
  23. #define X_SHLGUID_H_
  24. #include <shlguid.h>
  25. #endif
  26. #ifndef X_MSHTMLRC_H_
  27. #define X_MSHTMLRC_H_
  28. #include "mshtmlrc.h" // For default header/footer resource
  29. #endif
  30. #ifndef X_UTILS_HXX_
  31. #define X_UTILS_HXX_
  32. #include "utils.hxx"
  33. #endif
  34. #ifndef X_DLGS_H_
  35. #define X_DLGS_H_
  36. #include "dlgs.h"
  37. #endif
  38. #ifndef X_VRSSCAN_HXX_
  39. #define X_VRSSCAN_HXX_
  40. #include "vrsscan.h"
  41. #endif
  42. #ifndef X_WINSPOOL_H_
  43. #define X_WINSPOOL_H_
  44. #include "winspool.h"
  45. #endif
  46. #ifndef X_WINGDI_H_
  47. #define X_WINGDI_H_
  48. #include "wingdi.h"
  49. #endif
  50. #include <commctrl.h>
  51. #include <commdlg.h>
  52. #include <mshtmcid.h>
  53. #include <mshtmdid.h>
  54. #include <dispex.h>
  55. // NB (greglett)
  56. // We need to define this because we're building with a WINVER of 4, and this is only deifned for NT5
  57. // Remove this as soon as the winver changes.
  58. #define NEED_BECAUSE_COMPILED_AT_WINVER_4
  59. #ifdef NEED_BECAUSE_COMPILED_AT_WINVER_4
  60. #define PD_CURRENTPAGE 0x00400000
  61. #define PD_NOCURRENTPAGE 0x00800000
  62. #endif
  63. // This is defined in transform.hxx, but we can't access that as a peer.
  64. inline int MulDivQuick(int nMultiplicand, int nMultiplier, int nDivisor)
  65. { Assert(nDivisor); return (!nDivisor-1) & MulDiv(nMultiplicand, nMultiplier, nDivisor); }
  66. #define ORIENTPORTRAIT _T("portrait")
  67. #define ORIENTLANDSCAPE _T("landscape")
  68. static const TCHAR *s_aachPrintArg[] =
  69. {
  70. _T("__IE_BrowseDocument"), // PRINTARG_BROWSEDOC
  71. _T("__IE_PrinterCMD_DevNames"), // PRINTARG_DEVNAMES
  72. _T("__IE_PrinterCMD_DevMode"), // PRINTARG_DEVMODE
  73. _T("__IE_PrinterCMD_Printer"), // PRINTARG_PRINTER
  74. _T("__IE_PrinterCMD_Device"), // PRINTARG_DRIVER
  75. _T("__IE_PrinterCMD_Port"), // PRINTARG_PORT
  76. _T("__IE_PrintType"), // PRINTARG_TYPE
  77. };
  78. #define DEVCAP_COPIES 0
  79. #define DEVCAP_COLLATE 1
  80. #define DEVCAP_DUPLEX 2
  81. #define DEVCAP_LAST_RETAIL 3 // Add more retail properties before this!
  82. #ifndef DBG
  83. #define DEVCAP_LAST DEVCAP_LAST_RETAIL
  84. #else
  85. #define DEVCAP_DBG_PRINTERNAME DEVCAP_LAST_RETAIL
  86. #define DEVCAP_LAST DEVCAP_LAST_RETAIL + 1
  87. #endif
  88. static const TCHAR *s_aachDeviceCapabilities[] =
  89. {
  90. _T("copies"),
  91. _T("collate"),
  92. _T("duplex"), // Add more retail properties after this!
  93. #if DBG == 1
  94. _T("printerName"),
  95. #endif
  96. };
  97. //+----------------------------------------------------------------------------
  98. //
  99. // Function : InitMultiByteFromWideChar
  100. //
  101. // Synopsis : Allocates & creates a wide char string from a multi byte string.
  102. //
  103. //-----------------------------------------------------------------------------
  104. LPSTR
  105. InitMultiByteFromWideChar(LPCWSTR pchWide, long cchWide)
  106. {
  107. long cchMulti;
  108. char * pchMulti;
  109. //
  110. // Alloc space on heap for buffer.
  111. //
  112. cchMulti = ::WideCharToMultiByte(CP_ACP, 0, pchWide, cchWide, NULL, 0, NULL, NULL);
  113. Assert(cchMulti > 0);
  114. cchMulti++;
  115. pchMulti = new char[cchMulti];
  116. if (pchMulti)
  117. {
  118. ::WideCharToMultiByte(CP_ACP, 0, pchWide, cchWide, pchMulti, cchMulti, NULL, NULL);
  119. pchMulti[cchMulti - 1] = '\0';
  120. }
  121. return pchMulti;
  122. }
  123. inline LPSTR
  124. InitMultiByteFromWideChar(LPCWSTR pwch)
  125. {
  126. return InitMultiByteFromWideChar(pwch, _tcslen(pwch));
  127. }
  128. //+----------------------------------------------------------------------------
  129. //
  130. // Function : InitWideCharFromMultiByte
  131. //
  132. // Synopsis : Allocates & creates a multibyte string from a widechar string.
  133. //
  134. //-----------------------------------------------------------------------------
  135. LPWSTR
  136. InitWideCharFromMultiByte(LPSTR pchMulti, long cchMulti)
  137. {
  138. long cchWide;
  139. LPWSTR pchWide;
  140. //
  141. // Alloc space on heap for buffer.
  142. //
  143. cchWide = ::MultiByteToWideChar(CP_ACP, 0, pchMulti, cchMulti, NULL, 0);
  144. Assert(cchWide > 0);
  145. cchWide++;
  146. pchWide = new WCHAR[cchWide];
  147. if (pchWide)
  148. {
  149. ::MultiByteToWideChar(CP_ACP, 0, pchMulti, cchMulti, pchWide, cchWide);
  150. pchWide[cchWide - 1] = _T('\0');
  151. }
  152. return pchWide;
  153. }
  154. inline LPWSTR
  155. InitWideCharFromMultiByte(LPSTR pwch)
  156. {
  157. return InitWideCharFromMultiByte(pwch, strlen(pwch));
  158. }
  159. //+----------------------------------------------------------------------------
  160. //
  161. // Function : CreateDevNames
  162. //
  163. // Synopsis : Takes the three strings in a DEVNAMES structure, allocates &
  164. // & creates the structure as a GHND.
  165. //
  166. //-----------------------------------------------------------------------------
  167. HRESULT
  168. CreateDevNames(TCHAR *pchDriver, TCHAR *pchPrinter, TCHAR *pchPort, HGLOBAL *pDN)
  169. {
  170. HRESULT hr = S_OK;
  171. DWORD dwLenDriver, dwLenPrinter, dwLenPort;
  172. DWORD nStructSize;
  173. Assert(pDN);
  174. if (!pchDriver || !pchPrinter || !pchPort)
  175. {
  176. hr = E_FAIL;
  177. goto Cleanup;
  178. }
  179. dwLenDriver = _tcslen(pchDriver) + 1;
  180. dwLenPrinter = _tcslen(pchPrinter) + 1;
  181. dwLenPort = _tcslen(pchPort) + 1;
  182. nStructSize = sizeof(DEVNAMES)
  183. + ((dwLenPrinter + dwLenDriver + dwLenPort) * sizeof(TCHAR));
  184. (*pDN) = ::GlobalAlloc(GHND, nStructSize);
  185. if (!(*pDN))
  186. {
  187. hr = E_FAIL;
  188. goto Cleanup;
  189. }
  190. {
  191. DEVNAMES *pDevNames = ((DEVNAMES *) ::GlobalLock(*pDN));
  192. if (pDevNames)
  193. {
  194. #pragma warning(disable: 4244)
  195. pDevNames->wDriverOffset = sizeof(DEVNAMES) / sizeof(TCHAR);
  196. pDevNames->wDeviceOffset = pDevNames->wDriverOffset + dwLenDriver;
  197. pDevNames->wOutputOffset = pDevNames->wDeviceOffset + dwLenPrinter;
  198. #pragma warning(default: 4244)
  199. _tcscpy((((TCHAR *)pDevNames) + pDevNames->wDriverOffset), pchDriver);
  200. _tcscpy((((TCHAR *)pDevNames) + pDevNames->wDeviceOffset), pchPrinter);
  201. _tcscpy((((TCHAR *)pDevNames) + pDevNames->wOutputOffset), pchPort);
  202. }
  203. ::GlobalUnlock(*pDN);
  204. }
  205. Cleanup:
  206. return hr;
  207. }
  208. //+----------------------------------------------------------------------------
  209. //
  210. // Member : Init - IElementBehavior method impl
  211. //
  212. // Synopsis : peer Interface, initialization
  213. //
  214. //-----------------------------------------------------------------------------
  215. STDMETHODIMP
  216. CTemplatePrinter::Init(IElementBehaviorSite * pPeerSite)
  217. {
  218. HRESULT hr = S_OK;
  219. HKEY hKey = NULL;
  220. if (!pPeerSite)
  221. {
  222. hr = E_POINTER;
  223. goto Cleanup;
  224. }
  225. // cache our peer element
  226. _pPeerSite = pPeerSite;
  227. _pPeerSite->AddRef();
  228. _pPeerSite->QueryInterface(IID_IElementBehaviorSiteOM, (void**)&_pPeerSiteOM);
  229. GetDialogArguments(); // Cache the dialog arguments.
  230. // What order should we obtain default print settings?
  231. // 1. Settings passed in by our host (1a and 1b should be mutually exclusive)
  232. // 1a. A DEVMODE/DEVNAMES
  233. // 1b. A printer (and maybe a port & driver name, too)
  234. // 2. Read defaults from the registry
  235. // 3. Get the default Windows printer, if any.
  236. //
  237. // READ IN A DEVMODE/DEVNAMES
  238. //
  239. {
  240. VARIANT varDM;
  241. VARIANT varDN;
  242. VariantInit(&varDN);
  243. VariantInit(&varDM);
  244. // Only accept arguments in matched pair.
  245. if ( GetDialogArgument(&varDN, PRINTARG_DEVNAMES) == S_OK
  246. && GetDialogArgument(&varDM, PRINTARG_DEVMODE) == S_OK
  247. && V_VT(&varDN) == VT_HANDLE
  248. && V_VT(&varDM) == VT_HANDLE
  249. && V_BYREF(&varDN)
  250. && V_BYREF(&varDM) )
  251. {
  252. RemoveDialogArgument(PRINTARG_DEVNAMES);
  253. RemoveDialogArgument(PRINTARG_DEVMODE);
  254. _hDevNames = V_BYREF(&varDN); // NB We will release this!
  255. _hDevMode = V_BYREF(&varDM); // NB We will release this!
  256. }
  257. VariantClear(&varDN);
  258. VariantClear(&varDM);
  259. }
  260. //
  261. // READ IN A PRINTER/PORT/DRIVER
  262. //
  263. if (!_hDevNames)
  264. {
  265. VARIANT varPrinter;
  266. VARIANT varDriver;
  267. VARIANT varPort;
  268. VariantInit(&varPrinter);
  269. VariantInit(&varDriver);
  270. VariantInit(&varPort);
  271. Assert(!_hDevMode);
  272. if ( GetDialogArgument(&varPrinter, PRINTARG_PRINTER) == S_OK
  273. && V_VT(&varPrinter) == VT_BSTR
  274. && V_BSTR(&varPrinter) )
  275. {
  276. GetDialogArgument(&varDriver, PRINTARG_DRIVER);
  277. GetDialogArgument(&varPort, PRINTARG_PORT);
  278. if (g_fUnicodePlatform)
  279. hr = ReadDeviceUnicode(V_BSTR(&varPrinter),
  280. V_VT(&varDriver) == VT_BSTR ? V_BSTR(&varDriver) : NULL,
  281. V_VT(&varPort) == VT_BSTR ? V_BSTR(&varPort) : NULL );
  282. else
  283. hr = ReadDeviceNonUnicode(V_BSTR(&varPrinter),
  284. V_VT(&varDriver) == VT_BSTR ? V_BSTR(&varDriver) : NULL,
  285. V_VT(&varPort) == VT_BSTR ? V_BSTR(&varPort) : NULL );
  286. }
  287. VariantClear(&varPrinter);
  288. VariantClear(&varDriver);
  289. VariantClear(&varPort);
  290. }
  291. // Get these default settings from the registry, if we can
  292. // 1. Header/Footer
  293. // 2. Margins
  294. // 3. Target device (printer)
  295. // 4. Page size/Paper source information.
  296. if (GetRegPrintOptionsKey(PRINTOPTSUBKEY_PAGESETUP, &hKey) == S_OK)
  297. {
  298. ReadHeaderFooterFromRegistry(hKey);
  299. ReadMarginsFromRegistry(hKey);
  300. RegCloseKey(hKey);
  301. }
  302. // 5. Table of links
  303. if (GetRegPrintOptionsKey(PRINTOPTSUBKEY_MAIN, &hKey) == S_OK)
  304. {
  305. _fPrintTableOfLinks = ReadBoolFromRegistry(hKey, _T("Print_Shortcuts"));
  306. RegCloseKey(hKey);
  307. }
  308. hr = GetDeviceProperties(); // Returns E_FAIL if we don't have a valid printer at this point.
  309. //
  310. // DEFAULT WINDOWS PRINTER
  311. //
  312. if (hr)
  313. hr = GetPrintDialogSettings(FALSE, NULL); // Get printer defaults.
  314. Cleanup:
  315. return hr;
  316. }
  317. //+----------------------------------------------------------------------------
  318. //
  319. // Member : Detach - IElementBehavior method impl
  320. //
  321. // Synopsis : peer Interface, destruction work upon detaching from document
  322. //
  323. //-----------------------------------------------------------------------------
  324. STDMETHODIMP
  325. CTemplatePrinter::Detach()
  326. {
  327. // Abort any currently printing document.
  328. if (_hDC)
  329. {
  330. ::AbortDoc(_hDC);
  331. ::DeleteDC(_hDC);
  332. _hDC = NULL;
  333. }
  334. // Free any cached resources.
  335. if (_hInstResource)
  336. {
  337. MLFreeLibrary(_hInstResource);
  338. _hInstResource = NULL;
  339. }
  340. if (_hInstRatings)
  341. {
  342. FreeLibrary(_hInstRatings);
  343. _hInstRatings = NULL;
  344. }
  345. if (_hInstComctl32)
  346. {
  347. FreeLibrary(_hInstComctl32);
  348. _hInstComctl32 = NULL;
  349. }
  350. ReturnPrintHandles(); // Send our print handles back to the master thread CDoc.
  351. if (_hDevNames)
  352. {
  353. ::GlobalFree(_hDevNames);
  354. _hDevNames = NULL;
  355. }
  356. if (_hDevMode)
  357. {
  358. ::GlobalFree(_hDevMode);
  359. _hDevMode = NULL;
  360. }
  361. // Clear any COM interfaces we currently reference
  362. ClearInterface( &_pevDlgArgs );
  363. ClearInterface( &_pPeerSite );
  364. ClearInterface( &_pPeerSiteOM );
  365. return S_OK;
  366. }
  367. //+----------------------------------------------------------------------------
  368. //
  369. // Member : Notify - IElementBehavior method impl
  370. //
  371. // Synopsis : peer Interface, called for notification of document events.
  372. //
  373. //-----------------------------------------------------------------------------
  374. STDMETHODIMP
  375. CTemplatePrinter::Notify(LONG lEvent, VARIANT *)
  376. {
  377. return S_OK;
  378. }
  379. //+----------------------------------------------------------------------------
  380. //
  381. // Member : (ITemplatePrinter) CTemplatePrinter::printPage
  382. //
  383. // Synopsis : takes the passed element and prints it on its own page
  384. // should be called any number of times after startDoc, and before endDoc.
  385. //
  386. //-----------------------------------------------------------------------------
  387. STDMETHODIMP
  388. CTemplatePrinter::printBlankPage()
  389. {
  390. // No TEMPLATESECURITYCHECK() required because printPage has one.
  391. return printPage(NULL);
  392. }
  393. STDMETHODIMP
  394. CTemplatePrinter::printPage(IDispatch *pElemDisp)
  395. {
  396. TEMPLATESECURITYCHECK()
  397. IHTMLElementRender *pRender = NULL;
  398. HRESULT hr = S_OK;
  399. if (!_hDC)
  400. {
  401. hr = E_FAIL;
  402. goto Cleanup;
  403. }
  404. if (::StartPage(_hDC) <= 0)
  405. {
  406. // Returns a "nonzero" value on success, "zero" on failure.
  407. DWORD dwError = GetLastError();
  408. Assert(FALSE && "error calling StartPage api");
  409. hr = E_FAIL;
  410. goto Cleanup;
  411. }
  412. #ifdef DBG
  413. RECT rcUnprintTest;
  414. SIZE szResTest;
  415. SIZE szPage;
  416. szResTest.cx = ::GetDeviceCaps(_hDC, LOGPIXELSX);
  417. szResTest.cy = ::GetDeviceCaps(_hDC, LOGPIXELSY);
  418. szPage.cx = ::GetDeviceCaps(_hDC, PHYSICALWIDTH);
  419. szPage.cy = ::GetDeviceCaps(_hDC, PHYSICALHEIGHT);
  420. rcUnprintTest.left = ::GetDeviceCaps(_hDC, PHYSICALOFFSETX);
  421. rcUnprintTest.top = ::GetDeviceCaps(_hDC, PHYSICALOFFSETY);
  422. rcUnprintTest.right = szPage.cx - ::GetDeviceCaps(_hDC, HORZRES) - rcUnprintTest.left;
  423. rcUnprintTest.bottom = szPage.cy - ::GetDeviceCaps(_hDC, VERTRES) - rcUnprintTest.top;
  424. Assert( rcUnprintTest.left == _rcUnprintable.left
  425. && rcUnprintTest.right == _rcUnprintable.right
  426. && rcUnprintTest.top == _rcUnprintable.top
  427. && rcUnprintTest.bottom == _rcUnprintable.bottom );
  428. #endif
  429. // If we have been given an element, draw it to the screen.
  430. if (pElemDisp)
  431. {
  432. hr = pElemDisp->QueryInterface(IID_IHTMLElementRender, (void **)&pRender);
  433. if (hr)
  434. goto Cleanup;
  435. ::SetViewportOrgEx(_hDC, -_rcUnprintable.left,-_rcUnprintable.top, NULL);
  436. hr = pRender->DrawToDC(_hDC);
  437. }
  438. if (::EndPage(_hDC) <= 0)
  439. {
  440. // Known issues with EndPage:
  441. // 1. Win95 Fax fails the EndPage API when the "SetUpMyFax" wizard is aborted. dwError=0. (100092)
  442. DWORD dwError = GetLastError();
  443. goto Cleanup;
  444. }
  445. Cleanup:
  446. ReleaseInterface(pRender);
  447. if (hr)
  448. stopDoc();
  449. return hr;
  450. }
  451. //+----------------------------------------------------------------------------
  452. //
  453. // Member : (ITemplatePrinter) CTemplatePrinter::startDoc
  454. //
  455. // Synopsis : Gets/Inits the default printer and starts to print a document.
  456. //
  457. //-----------------------------------------------------------------------------
  458. STDMETHODIMP
  459. CTemplatePrinter::startDoc(BSTR bstrTitle, VARIANT_BOOL * p)
  460. {
  461. TEMPLATESECURITYCHECK()
  462. HRESULT hr = S_OK;
  463. DOCINFO docinfo;
  464. TCHAR achTitle[MAX_JOBNAME];
  465. if (!p)
  466. {
  467. hr = E_POINTER;
  468. goto Cleanup;
  469. }
  470. *p = VB_FALSE;
  471. if ( _hDC
  472. || !_hDevNames
  473. || !_hDevMode)
  474. {
  475. hr = S_FALSE;
  476. goto Cleanup;
  477. }
  478. {
  479. DEVNAMES *pDevNames = ((DEVNAMES *) ::GlobalLock(_hDevNames));
  480. void *pDevMode = ::GlobalLock(_hDevMode);
  481. if (pDevNames && pDevMode)
  482. {
  483. // (greglett) Non-Unicode badness. See comment at definition of _hDevMode
  484. if (g_fUnicodePlatform)
  485. {
  486. if (!_fUsePrinterCopyCollate)
  487. {
  488. // Force template to do its own copies/collation (to prevent both us and the printer from doing so).
  489. ((DEVMODEW *)pDevMode)->dmCollate = FALSE;
  490. ((DEVMODEW *)pDevMode)->dmCopies = 1;
  491. }
  492. else
  493. {
  494. // We might want to check if the hardware supports copy/collation
  495. ((DEVMODEW *)pDevMode)->dmFields |= DM_COPIES | DM_COLLATE;
  496. ((DEVMODEW *)pDevMode)->dmCollate = _fCollate;
  497. ((DEVMODEW *)pDevMode)->dmCopies = _nCopies;
  498. }
  499. _hDC = ::CreateDCW(((TCHAR *)pDevNames) + pDevNames->wDriverOffset,
  500. ((TCHAR *)pDevNames) + pDevNames->wDeviceOffset,
  501. NULL,
  502. (DEVMODEW *) pDevMode);
  503. }
  504. else
  505. {
  506. LPSTR pchDriver = InitMultiByteFromWideChar(((TCHAR *)pDevNames) + pDevNames->wDriverOffset);
  507. LPSTR pchDevice = InitMultiByteFromWideChar(((TCHAR *)pDevNames) + pDevNames->wDeviceOffset);
  508. if (!_fUsePrinterCopyCollate)
  509. {
  510. // Force template to do its own copies/collation (to prevent both us and the printer from doing so).
  511. ((DEVMODEA *)pDevMode)->dmCollate = FALSE;
  512. ((DEVMODEA *)pDevMode)->dmCopies = 1;
  513. }
  514. else
  515. {
  516. // We might want to check if the hardware supports copy/collation
  517. ((DEVMODEA *)pDevMode)->dmFields |= DM_COPIES | DM_COLLATE;
  518. ((DEVMODEA *)pDevMode)->dmCollate = _fCollate;
  519. ((DEVMODEA *)pDevMode)->dmCopies = _nCopies;
  520. }
  521. if (pchDriver && pchDevice)
  522. {
  523. _hDC = ::CreateDCA(pchDriver,
  524. pchDevice,
  525. NULL,
  526. (DEVMODEA *)pDevMode);
  527. }
  528. if (pchDriver)
  529. delete []pchDriver;
  530. if (pchDevice)
  531. delete []pchDevice;
  532. }
  533. }
  534. ::GlobalUnlock(_hDevNames);
  535. ::GlobalUnlock(_hDevMode);
  536. if (!_hDC)
  537. {
  538. DWORD dwError = GetLastError();
  539. Assert(!"Failed to create DC!");
  540. hr = E_FAIL;
  541. goto Cleanup;
  542. }
  543. }
  544. //
  545. // Fill out the DOCINFO structure
  546. //
  547. ::ZeroMemory(&docinfo,sizeof(DOCINFO));
  548. ::ZeroMemory(achTitle,sizeof(TCHAR) * MAX_JOBNAME);
  549. docinfo.cbSize = sizeof(DOCINFO);
  550. docinfo.fwType = 0;
  551. if (bstrTitle)
  552. _tcsncpy(achTitle, bstrTitle, MAX_JOBNAME - 1);
  553. docinfo.lpszDocName = achTitle;
  554. if (_achFileName[0])
  555. docinfo.lpszOutput = _achFileName;
  556. //
  557. // Set up the document so that it can begin accepting pages
  558. //
  559. if (::StartDoc(_hDC, &docinfo) > 0)
  560. *p = VB_TRUE;
  561. #ifdef DBG
  562. else
  563. {
  564. DWORD dwError = GetLastError();
  565. goto Cleanup;
  566. }
  567. #endif
  568. Cleanup:
  569. return hr;
  570. }
  571. //+----------------------------------------------------------------------------
  572. //
  573. // Member : (ITemplatePrinter) CTemplatePrinter::endDoc
  574. //
  575. // Synopsis : 'Finishes' the doc - takes pages printed via printPage and queues the job
  576. //
  577. //-----------------------------------------------------------------------------
  578. STDMETHODIMP
  579. CTemplatePrinter::stopDoc()
  580. {
  581. TEMPLATESECURITYCHECK()
  582. HRESULT hr = S_OK;
  583. if (!_hDC)
  584. goto Cleanup;
  585. if (::EndDoc(_hDC) <=0)
  586. {
  587. DWORD dwError = GetLastError();
  588. Assert(FALSE && "error calling EndDoc API");
  589. hr = E_FAIL;
  590. goto Cleanup;
  591. }
  592. ::DeleteDC(_hDC);
  593. _hDC = NULL;
  594. Cleanup:
  595. return hr;
  596. }
  597. //+----------------------------------------------------------------------------
  598. //
  599. // (ITemplatePrinter) CTemplatePrinter::get/put framesetDocument
  600. //
  601. //-----------------------------------------------------------------------------
  602. STDMETHODIMP
  603. CTemplatePrinter::get_framesetDocument(VARIANT_BOOL * p)
  604. {
  605. return GetFlagSafe(p,_fFramesetDocument);
  606. }
  607. STDMETHODIMP
  608. CTemplatePrinter::put_framesetDocument(VARIANT_BOOL v)
  609. {
  610. PUTFLAGSAFE(_fFramesetDocument, v);
  611. }
  612. //+----------------------------------------------------------------------------
  613. //
  614. // (ITemplatePrinter) CTemplatePrinter::get/put printTableOfLinks
  615. //
  616. //-----------------------------------------------------------------------------
  617. STDMETHODIMP
  618. CTemplatePrinter::get_tableOfLinks(VARIANT_BOOL * p)
  619. {
  620. return GetFlagSafe(p,_fPrintTableOfLinks);
  621. }
  622. STDMETHODIMP
  623. CTemplatePrinter::put_tableOfLinks(VARIANT_BOOL v)
  624. {
  625. PUTFLAGSAFE(_fPrintTableOfLinks, v);
  626. }
  627. //+----------------------------------------------------------------------------
  628. //
  629. // (ITemplatePrinter) CTemplatePrinter::get/put printAllLinkedDocuments
  630. //
  631. //-----------------------------------------------------------------------------
  632. STDMETHODIMP
  633. CTemplatePrinter::get_allLinkedDocuments(VARIANT_BOOL * p)
  634. {
  635. return GetFlagSafe(p, _fPrintAllLinkedDocuments);
  636. }
  637. STDMETHODIMP
  638. CTemplatePrinter::put_allLinkedDocuments(VARIANT_BOOL v)
  639. {
  640. PUTFLAGSAFE(_fPrintAllLinkedDocuments, v);
  641. }
  642. //+----------------------------------------------------------------------------
  643. //
  644. // (ITemplatePrinter) CTemplatePrinter::get/put printFrameActive
  645. //
  646. //-----------------------------------------------------------------------------
  647. STDMETHODIMP
  648. CTemplatePrinter::get_frameActive(VARIANT_BOOL * p)
  649. {
  650. return GetFlagSafe(p,_fFrameActive);
  651. }
  652. STDMETHODIMP
  653. CTemplatePrinter::put_frameActive(VARIANT_BOOL v)
  654. {
  655. if (!!v)
  656. _fFrameAsShown = FALSE;
  657. PUTFLAGSAFE(_fFrameActive, v);
  658. }
  659. //+----------------------------------------------------------------------------
  660. //
  661. // (ITemplatePrinter2) CTemplatePrinter::get/put printFrameActive
  662. //
  663. //-----------------------------------------------------------------------------
  664. STDMETHODIMP
  665. CTemplatePrinter::get_frameActiveEnabled(VARIANT_BOOL * p)
  666. {
  667. return GetFlagSafe(p,_fFrameActiveEnabled);
  668. }
  669. STDMETHODIMP
  670. CTemplatePrinter::put_frameActiveEnabled(VARIANT_BOOL v)
  671. {
  672. PUTFLAGSAFE(_fFrameActiveEnabled, v);
  673. }
  674. //+----------------------------------------------------------------------------
  675. //
  676. // (ITemplatePrinter) CTemplatePrinter::get/put printFrameAsShown
  677. //
  678. //-----------------------------------------------------------------------------
  679. STDMETHODIMP
  680. CTemplatePrinter::get_frameAsShown(VARIANT_BOOL * p)
  681. {
  682. return GetFlagSafe(p,_fFrameAsShown);
  683. }
  684. STDMETHODIMP
  685. CTemplatePrinter::put_frameAsShown(VARIANT_BOOL v)
  686. {
  687. if (!!v)
  688. _fFrameActive = FALSE;
  689. PUTFLAGSAFE(_fFrameAsShown, v);
  690. }
  691. //+----------------------------------------------------------------------------
  692. //
  693. // (ITemplatePrinter) CTemplatePrinter::get/put printSelection
  694. //
  695. //-----------------------------------------------------------------------------
  696. STDMETHODIMP
  697. CTemplatePrinter::get_selection(VARIANT_BOOL * p)
  698. {
  699. return GetFlagSafe(p,_fPrintSelection);
  700. }
  701. STDMETHODIMP
  702. CTemplatePrinter::put_selection(VARIANT_BOOL v)
  703. {
  704. PUTFLAGSAFE(_fPrintSelection, v);
  705. }
  706. //+----------------------------------------------------------------------------
  707. //
  708. // (ITemplatePrinter2) CTemplatePrinter::get/put printSelectionEnabled
  709. //
  710. //-----------------------------------------------------------------------------
  711. STDMETHODIMP
  712. CTemplatePrinter::get_selectionEnabled(VARIANT_BOOL * p)
  713. {
  714. return GetFlagSafe(p,_fPrintSelectionEnabled);
  715. }
  716. STDMETHODIMP
  717. CTemplatePrinter::put_selectionEnabled(VARIANT_BOOL v)
  718. {
  719. PUTFLAGSAFE(_fPrintSelectionEnabled, v);
  720. }
  721. //+----------------------------------------------------------------------------
  722. //
  723. // (ITemplatePrinter) CTemplatePrinter::get/put printSelectedPages
  724. //
  725. //-----------------------------------------------------------------------------
  726. STDMETHODIMP
  727. CTemplatePrinter::get_selectedPages(VARIANT_BOOL * p)
  728. {
  729. return GetFlagSafe(p,_fPrintSelectedPages);
  730. }
  731. STDMETHODIMP
  732. CTemplatePrinter::put_selectedPages(VARIANT_BOOL v)
  733. {
  734. PUTFLAGSAFE(_fPrintSelectedPages, v);
  735. }
  736. //+----------------------------------------------------------------------------
  737. //
  738. // (ITemplatePrinter) CTemplatePrinter::get/put printCurrentPage
  739. //
  740. //-----------------------------------------------------------------------------
  741. STDMETHODIMP
  742. CTemplatePrinter::get_currentPage(VARIANT_BOOL * p)
  743. {
  744. return GetFlagSafe(p,_fPrintCurrentPage);
  745. }
  746. STDMETHODIMP
  747. CTemplatePrinter::put_currentPage(VARIANT_BOOL v)
  748. {
  749. PUTFLAGSAFE(_fPrintCurrentPage, v);
  750. }
  751. //+----------------------------------------------------------------------------
  752. //
  753. // (ITemplatePrinter) CTemplatePrinter::get/put printCurrentPageAvail
  754. //
  755. //-----------------------------------------------------------------------------
  756. STDMETHODIMP
  757. CTemplatePrinter::get_currentPageAvail(VARIANT_BOOL * p)
  758. {
  759. return GetFlagSafe(p,_fCurrentPageAvail);
  760. }
  761. STDMETHODIMP
  762. CTemplatePrinter::put_currentPageAvail(VARIANT_BOOL v)
  763. {
  764. PUTFLAGSAFE(_fCurrentPageAvail, v);
  765. }
  766. //+----------------------------------------------------------------------------
  767. //
  768. // (ITemplatePrinter) CTemplatePrinter::get/put printCollate
  769. //
  770. //-----------------------------------------------------------------------------
  771. STDMETHODIMP
  772. CTemplatePrinter::get_collate(VARIANT_BOOL * p)
  773. {
  774. return GetFlagSafe(p,_fCollate);
  775. }
  776. STDMETHODIMP
  777. CTemplatePrinter::put_collate(VARIANT_BOOL v)
  778. {
  779. PUTFLAGSAFE(_fCollate, v);
  780. }
  781. //+----------------------------------------------------------------------------
  782. //
  783. // (ITemplatePrinter2) CTemplatePrinter::get/put usePrinterCopyCollate
  784. //
  785. //-----------------------------------------------------------------------------
  786. STDMETHODIMP
  787. CTemplatePrinter::get_usePrinterCopyCollate(VARIANT_BOOL * p)
  788. {
  789. return GetFlagSafe(p,_fUsePrinterCopyCollate);
  790. }
  791. STDMETHODIMP
  792. CTemplatePrinter::put_usePrinterCopyCollate(VARIANT_BOOL v)
  793. {
  794. PUTFLAGSAFE(_fUsePrinterCopyCollate, v);
  795. }
  796. //+----------------------------------------------------------------------------
  797. //
  798. // (ITemplatePrinter) CTemplatePrinter::get_duplex
  799. //
  800. //-----------------------------------------------------------------------------
  801. STDMETHODIMP
  802. CTemplatePrinter::get_duplex(VARIANT_BOOL * p)
  803. {
  804. TEMPLATESECURITYCHECK();
  805. HRESULT hr = S_OK;
  806. if (!p)
  807. {
  808. hr = E_INVALIDARG;
  809. goto Cleanup;
  810. }
  811. *p = VB_FALSE;
  812. if (_hDevMode)
  813. {
  814. void * pDevMode = ::GlobalLock(_hDevMode);
  815. if (pDevMode)
  816. {
  817. // (greglett) Unicode weirdness. DEVMMODEA on Win9x, DEVMODEW on NT.
  818. if ( ( g_fUnicodePlatform
  819. && (((DEVMODEW *)pDevMode)->dmFields & DM_DUPLEX)
  820. && ((DEVMODEW *)pDevMode)->dmDuplex != DMDUP_SIMPLEX )
  821. || ( !g_fUnicodePlatform
  822. && (((DEVMODEA *)pDevMode)->dmFields & DM_DUPLEX)
  823. && ((DEVMODEA *)pDevMode)->dmDuplex != DMDUP_SIMPLEX ) )
  824. {
  825. *p = VB_TRUE;
  826. }
  827. ::GlobalUnlock(_hDevMode);
  828. }
  829. }
  830. Cleanup:
  831. return hr;
  832. }
  833. //+----------------------------------------------------------------------------
  834. //
  835. // (ITemplatePrinter) CTemplatePrinter::get/put copies
  836. //
  837. //-----------------------------------------------------------------------------
  838. STDMETHODIMP
  839. CTemplatePrinter::get_copies(WORD * p)
  840. {
  841. TEMPLATESECURITYCHECK();
  842. HRESULT hr = S_OK;
  843. if (!p)
  844. hr = E_POINTER;
  845. else
  846. *p = _nCopies;
  847. return hr;
  848. }
  849. STDMETHODIMP
  850. CTemplatePrinter::put_copies(WORD v)
  851. {
  852. TEMPLATESECURITYCHECK();
  853. HRESULT hr = S_OK;
  854. if (v < 0)
  855. hr = E_INVALIDARG;
  856. else
  857. _nCopies = v;
  858. ////////////////////////////////////////////////////////////////////
  859. // a-naande 7-30-02 winse 25090
  860. // if the DEVMODE struct isn't null, then the value in dmCopies will supersede
  861. // nCopies in the PRINTDLG struct, so set it to match _nCopies
  862. if(SUCCEEDED(hr) && _hDevMode)
  863. {
  864. void *pDevMode = ::GlobalLock(_hDevMode);
  865. if (pDevMode)
  866. {
  867. if (g_fUnicodePlatform)
  868. {
  869. ((DEVMODEW *)pDevMode)->dmCopies = _nCopies;
  870. }
  871. else
  872. {
  873. ((DEVMODEA *)pDevMode)->dmCopies = _nCopies;
  874. }
  875. ::GlobalUnlock(_hDevMode);
  876. }
  877. }
  878. return hr;
  879. }
  880. //+----------------------------------------------------------------------------
  881. //
  882. // (ITemplatePrinter) CTemplatePrinter::get/put pageFrom
  883. //
  884. //-----------------------------------------------------------------------------
  885. STDMETHODIMP
  886. CTemplatePrinter::get_pageFrom(WORD * p)
  887. {
  888. TEMPLATESECURITYCHECK();
  889. HRESULT hr = S_OK;
  890. if (!p)
  891. hr = E_POINTER;
  892. else
  893. *p = _nPageFrom;
  894. return hr;
  895. }
  896. STDMETHODIMP
  897. CTemplatePrinter::put_pageFrom(WORD v)
  898. {
  899. TEMPLATESECURITYCHECK();
  900. HRESULT hr = S_OK;
  901. if (v < 0)
  902. hr = E_INVALIDARG;
  903. else
  904. _nPageFrom = v;
  905. return hr;
  906. }
  907. //+----------------------------------------------------------------------------
  908. //
  909. // (ITemplatePrinter) CTemplatePrinter::get/put pageTo
  910. //
  911. //-----------------------------------------------------------------------------
  912. STDMETHODIMP
  913. CTemplatePrinter::get_pageTo(WORD * p)
  914. {
  915. TEMPLATESECURITYCHECK();
  916. HRESULT hr = S_OK;
  917. if (!p)
  918. hr = E_POINTER;
  919. else
  920. *p = _nPageTo;
  921. return hr;
  922. }
  923. STDMETHODIMP
  924. CTemplatePrinter::put_pageTo(WORD v)
  925. {
  926. TEMPLATESECURITYCHECK();
  927. HRESULT hr = S_OK;
  928. if (v < 0)
  929. hr = E_INVALIDARG;
  930. else
  931. _nPageTo = v;
  932. return hr;
  933. }
  934. //+----------------------------------------------------------------------------
  935. //
  936. // (ITemplatePrinter) CTemplatePrinter::get/put marginLeft/Right/Top/Bottom
  937. //
  938. //-----------------------------------------------------------------------------
  939. STDMETHODIMP
  940. CTemplatePrinter::get_marginLeft(long * p)
  941. {
  942. TEMPLATESECURITYCHECK();
  943. HRESULT hr = S_OK;
  944. if (!p)
  945. hr = E_POINTER;
  946. else
  947. *p = (_rcMargin.left / 1000);
  948. return hr;
  949. }
  950. STDMETHODIMP
  951. CTemplatePrinter::put_marginLeft(long v)
  952. {
  953. TEMPLATESECURITYCHECK();
  954. HRESULT hr = S_OK;
  955. if (v < 0)
  956. hr = E_INVALIDARG;
  957. else
  958. _rcMargin.left = v * 1000;
  959. return hr;
  960. }
  961. STDMETHODIMP
  962. CTemplatePrinter::get_marginRight(long * p)
  963. {
  964. TEMPLATESECURITYCHECK();
  965. HRESULT hr = S_OK;
  966. if (!p)
  967. hr = E_POINTER;
  968. else
  969. *p = (_rcMargin.right / 1000);
  970. return hr;
  971. }
  972. STDMETHODIMP
  973. CTemplatePrinter::put_marginRight(long v)
  974. {
  975. TEMPLATESECURITYCHECK();
  976. HRESULT hr = S_OK;
  977. if (v < 0)
  978. hr = E_INVALIDARG;
  979. else
  980. _rcMargin.right = v * 1000;
  981. return hr;
  982. }
  983. STDMETHODIMP
  984. CTemplatePrinter::get_marginTop(long * p)
  985. {
  986. TEMPLATESECURITYCHECK();
  987. HRESULT hr = S_OK;
  988. if (!p)
  989. hr = E_POINTER;
  990. else
  991. // Input in 1/100 inches.
  992. *p = (_rcMargin.top / 1000);
  993. return hr;
  994. }
  995. STDMETHODIMP
  996. CTemplatePrinter::put_marginTop(long v)
  997. {
  998. TEMPLATESECURITYCHECK();
  999. HRESULT hr = S_OK;
  1000. if (v < 0)
  1001. hr = E_INVALIDARG;
  1002. else
  1003. // Output in 1/100 inches.
  1004. _rcMargin.top = v * 1000;
  1005. return hr;
  1006. }
  1007. STDMETHODIMP
  1008. CTemplatePrinter::get_marginBottom(long * p)
  1009. {
  1010. TEMPLATESECURITYCHECK();
  1011. HRESULT hr = S_OK;
  1012. if (!p)
  1013. hr = E_POINTER;
  1014. else
  1015. // Input in 1/100 inches.
  1016. *p = (_rcMargin.bottom / 1000);
  1017. return hr;
  1018. }
  1019. STDMETHODIMP
  1020. CTemplatePrinter::put_marginBottom(long v)
  1021. {
  1022. TEMPLATESECURITYCHECK();
  1023. HRESULT hr = S_OK;
  1024. if (v < 0)
  1025. hr = E_INVALIDARG;
  1026. else
  1027. // Output in 1/100 inches.
  1028. _rcMargin.bottom = v * 1000;
  1029. return hr;
  1030. }
  1031. //+----------------------------------------------------------------------------
  1032. //
  1033. // (ITemplatePrinter) CTemplatePrinter::get pageWidth/Height
  1034. //
  1035. //-----------------------------------------------------------------------------
  1036. STDMETHODIMP
  1037. CTemplatePrinter::get_pageWidth(long * p)
  1038. {
  1039. TEMPLATESECURITYCHECK();
  1040. HRESULT hr = S_OK;
  1041. if (!p)
  1042. hr = E_POINTER;
  1043. else
  1044. // Output in 1/100 inches.
  1045. *p = _ptPaperSize.x / 10;
  1046. return hr;
  1047. }
  1048. STDMETHODIMP
  1049. CTemplatePrinter::get_pageHeight(long * p)
  1050. {
  1051. TEMPLATESECURITYCHECK();
  1052. HRESULT hr = S_OK;
  1053. if (!p)
  1054. hr = E_POINTER;
  1055. else
  1056. // Output in 1/100 inches.
  1057. *p = _ptPaperSize.y / 10;
  1058. return hr;
  1059. }
  1060. //+----------------------------------------------------------------------------
  1061. //
  1062. // (ITemplatePrinter2) CTemplatePrinter::get/put orientation
  1063. //
  1064. //-----------------------------------------------------------------------------
  1065. STDMETHODIMP
  1066. CTemplatePrinter::get_orientation(BSTR * p)
  1067. {
  1068. TEMPLATESECURITYCHECK();
  1069. HRESULT hr = S_OK;
  1070. if (!p)
  1071. {
  1072. hr = E_POINTER;
  1073. goto Cleanup;
  1074. }
  1075. *p = NULL;
  1076. if (GetOrientation() == DMORIENT_LANDSCAPE)
  1077. *p = SysAllocString(ORIENTLANDSCAPE);
  1078. else
  1079. *p = SysAllocString(ORIENTPORTRAIT);
  1080. if (!p)
  1081. hr = E_OUTOFMEMORY;
  1082. Cleanup:
  1083. return hr;
  1084. }
  1085. STDMETHODIMP
  1086. CTemplatePrinter::put_orientation(BSTR v)
  1087. {
  1088. TEMPLATESECURITYCHECK();
  1089. HRESULT hr = S_OK;
  1090. if (!v)
  1091. {
  1092. hr = E_INVALIDARG;
  1093. goto Cleanup;
  1094. }
  1095. if (_tcsicmp(v, ORIENTPORTRAIT) == 0)
  1096. SetOrientation(DMORIENT_PORTRAIT);
  1097. else if (_tcsicmp(v, ORIENTLANDSCAPE) == 0)
  1098. SetOrientation(DMORIENT_LANDSCAPE);
  1099. else
  1100. hr = E_INVALIDARG;
  1101. Cleanup:
  1102. return hr;
  1103. }
  1104. //+----------------------------------------------------------------------------
  1105. //
  1106. // (ITemplatePrinter) CTemplatePrinter::get unprintableLeft/Top/Right/Bottom
  1107. //
  1108. //-----------------------------------------------------------------------------
  1109. STDMETHODIMP
  1110. CTemplatePrinter::get_unprintableLeft(long * p)
  1111. {
  1112. TEMPLATESECURITYCHECK();
  1113. HRESULT hr = S_OK;
  1114. if (!p)
  1115. hr = E_POINTER;
  1116. else if (_szResolution.cx == 0)
  1117. *p = 0;
  1118. else
  1119. // Output should be in 1/100 inches, not printer pixels.
  1120. *p = MulDivQuick(_rcUnprintable.left, 100, _szResolution.cx);
  1121. return hr;
  1122. }
  1123. STDMETHODIMP
  1124. CTemplatePrinter::get_unprintableTop(long * p)
  1125. {
  1126. TEMPLATESECURITYCHECK();
  1127. HRESULT hr = S_OK;
  1128. if (!p)
  1129. hr = E_POINTER;
  1130. else if (_szResolution.cy == 0)
  1131. *p = 0;
  1132. else
  1133. // Output should be in 1/100 inches, not printer pixels.
  1134. *p = MulDivQuick(_rcUnprintable.top, 100, _szResolution.cy);
  1135. return hr;
  1136. }
  1137. STDMETHODIMP
  1138. CTemplatePrinter::get_unprintableRight(long * p)
  1139. {
  1140. TEMPLATESECURITYCHECK();
  1141. HRESULT hr = S_OK;
  1142. if (!p)
  1143. hr = E_POINTER;
  1144. else if (_szResolution.cx == 0)
  1145. *p = 0;
  1146. else
  1147. // Output should be in 1/100 inches, not printer pixels.
  1148. *p = MulDivQuick(_rcUnprintable.right, 100, _szResolution.cx);
  1149. return hr;
  1150. }
  1151. STDMETHODIMP
  1152. CTemplatePrinter::get_unprintableBottom(long * p)
  1153. {
  1154. TEMPLATESECURITYCHECK();
  1155. HRESULT hr = S_OK;
  1156. if (!p)
  1157. hr = E_POINTER;
  1158. else if (_szResolution.cy == 0)
  1159. *p = 0;
  1160. else
  1161. // Output should be in 1/100 inches, not printer pixels.
  1162. *p = MulDivQuick(_rcUnprintable.bottom, 100, _szResolution.cy);
  1163. return hr;
  1164. }
  1165. //+----------------------------------------------------------------------------
  1166. //
  1167. // (ITemplatePrinter) CTemplatePrinter::get/put header
  1168. //
  1169. //-----------------------------------------------------------------------------
  1170. STDMETHODIMP
  1171. CTemplatePrinter::get_header(BSTR * p)
  1172. {
  1173. TEMPLATESECURITYCHECK();
  1174. HRESULT hr = S_OK;
  1175. if (!p)
  1176. hr = E_POINTER;
  1177. else
  1178. {
  1179. *p = SysAllocString(_achHeader);
  1180. if (!p)
  1181. hr = E_OUTOFMEMORY;
  1182. }
  1183. return hr;
  1184. }
  1185. STDMETHODIMP
  1186. CTemplatePrinter::put_header(BSTR v)
  1187. {
  1188. TEMPLATESECURITYCHECK();
  1189. HRESULT hr = S_OK;
  1190. TCHAR *achTemp;
  1191. achTemp = v;
  1192. if (! (_tcslen(achTemp) <= ARRAY_SIZE(_achHeader) - 1))
  1193. hr = E_INVALIDARG;
  1194. else
  1195. {
  1196. _fPersistHFToRegistry = FALSE;
  1197. _tcscpy(_achHeader, achTemp);
  1198. }
  1199. return hr;
  1200. }
  1201. //+----------------------------------------------------------------------------
  1202. //
  1203. // (ITemplatePrinter) CTemplatePrinter::get/put footer
  1204. //
  1205. //-----------------------------------------------------------------------------
  1206. STDMETHODIMP
  1207. CTemplatePrinter::get_footer(BSTR * p)
  1208. {
  1209. TEMPLATESECURITYCHECK();
  1210. HRESULT hr = S_OK;
  1211. if (!p)
  1212. hr = E_POINTER;
  1213. else
  1214. {
  1215. *p = SysAllocString(_achFooter);
  1216. if (!p)
  1217. hr = E_OUTOFMEMORY;
  1218. }
  1219. return hr;
  1220. }
  1221. STDMETHODIMP
  1222. CTemplatePrinter::put_footer(BSTR v)
  1223. {
  1224. TEMPLATESECURITYCHECK();
  1225. HRESULT hr = S_OK;
  1226. TCHAR *achTemp;
  1227. achTemp = v;
  1228. if (! (_tcslen(achTemp) <= ARRAY_SIZE(_achFooter) - 1))
  1229. hr = E_INVALIDARG;
  1230. else
  1231. {
  1232. _fPersistHFToRegistry = FALSE;
  1233. _tcscpy(_achFooter, achTemp);
  1234. }
  1235. return hr;
  1236. }
  1237. //+----------------------------------------------------------------------------
  1238. //
  1239. // (ITemplatePrinter2) CTemplatePrinter::deviceSupports
  1240. //
  1241. // Takes a BSTR indicating which property to query (supported values in the
  1242. // defined above).
  1243. // Returns information about that property.
  1244. //
  1245. //-----------------------------------------------------------------------------
  1246. STDMETHODIMP
  1247. CTemplatePrinter::deviceSupports(BSTR bstrProperty, VARIANT * pvar)
  1248. {
  1249. TEMPLATESECURITYCHECK();
  1250. HRESULT hr = S_OK;
  1251. void *pDevMode = NULL;
  1252. DEVNAMES *pDevNames = NULL;
  1253. TCHAR *achDevice = NULL;
  1254. TCHAR *achPort = NULL;
  1255. int i;
  1256. if (!pvar)
  1257. {
  1258. hr = E_INVALIDARG;
  1259. goto Cleanup;
  1260. }
  1261. VariantInit(pvar);
  1262. pDevMode = ::GlobalLock(_hDevMode);
  1263. pDevNames = ((DEVNAMES *) ::GlobalLock(_hDevNames));
  1264. if (!pDevMode || !pDevNames)
  1265. {
  1266. hr = E_FAIL;
  1267. goto Cleanup;
  1268. }
  1269. for (i = 0;
  1270. (i < DEVCAP_LAST) && (_tcsicmp(bstrProperty, s_aachDeviceCapabilities[i]) != 0);
  1271. i++);
  1272. if (i >= DEVCAP_LAST)
  1273. {
  1274. hr = E_INVALIDARG;
  1275. goto Cleanup;
  1276. }
  1277. achDevice = ((TCHAR *)pDevNames) + (pDevNames->wDeviceOffset);
  1278. achPort = ((TCHAR *)pDevNames) + (pDevNames->wOutputOffset);
  1279. switch (i)
  1280. {
  1281. case DEVCAP_COPIES:
  1282. V_VT(pvar) = VT_INT;
  1283. V_INT(pvar) = ::DeviceCapabilities(achDevice, achPort, DC_COPIES, NULL, NULL);
  1284. break;
  1285. case DEVCAP_COLLATE:
  1286. V_VT(pvar) = VT_BOOL;
  1287. V_BOOL(pvar) = (::DeviceCapabilities(achDevice, achPort, DC_COLLATE, NULL, NULL) != 0) ? VB_TRUE : VB_FALSE;
  1288. break;
  1289. case DEVCAP_DUPLEX:
  1290. V_VT(pvar) = VT_BOOL;
  1291. V_BOOL(pvar) = (::DeviceCapabilities(achDevice, achPort, DC_DUPLEX, NULL, NULL) != 0) ? VB_TRUE : VB_FALSE;
  1292. break;
  1293. #if DBG==1
  1294. case DEVCAP_DBG_PRINTERNAME:
  1295. V_BSTR(pvar) = ::SysAllocString(achDevice);
  1296. if (V_BSTR(pvar))
  1297. V_VT(pvar) = VT_BSTR;
  1298. else
  1299. hr = E_OUTOFMEMORY;
  1300. break;
  1301. #endif
  1302. default:
  1303. Assert(FALSE && "Unrecognized DEVCAP_ value.");
  1304. break;
  1305. }
  1306. Cleanup:
  1307. if (pDevNames)
  1308. ::GlobalUnlock(_hDevNames);
  1309. if (pDevMode)
  1310. ::GlobalUnlock(_hDevMode);
  1311. return hr;
  1312. }
  1313. STDMETHODIMP
  1314. CTemplatePrinter::updatePageStatus(long * p)
  1315. {
  1316. TEMPLATESECURITYCHECK();
  1317. VARIANT varHost;
  1318. HRESULT hr = S_OK;
  1319. IOleCommandTarget *pioct = NULL;
  1320. const GUID *pguid = NULL;
  1321. DWORD nCmdId = 0;
  1322. VariantInit(&varHost);
  1323. if (!p)
  1324. {
  1325. hr = E_POINTER;
  1326. goto Cleanup;
  1327. }
  1328. if ( GetDialogArgument(&varHost, PRINTARG_BROWSEDOC) == S_OK
  1329. && V_VT(&varHost) == VT_UNKNOWN
  1330. && V_UNKNOWN(&varHost) )
  1331. {
  1332. VARIANT varIn;
  1333. V_VT(&varIn) = VT_I4;
  1334. V_I4(&varIn) = (*p > 0) ? (*p) : 0;
  1335. hr = V_UNKNOWN(&varHost)->QueryInterface(IID_IOleCommandTarget, (void **)&pioct);
  1336. if (hr)
  1337. goto Cleanup;
  1338. Assert(pioct);
  1339. hr = pioct->Exec(&CGID_MSHTML, IDM_UPDATEPAGESTATUS, 0, &varIn, 0);
  1340. hr = S_OK; // If the host isn't listening, we'll get an OLE error. Don't throw it to script!
  1341. }
  1342. Cleanup:
  1343. ReleaseInterface(pioct);
  1344. VariantClear(&varHost);
  1345. return hr;
  1346. }
  1347. //+----------------------------------------------------------------------------
  1348. //
  1349. // (ITemplatePrinter) CTemplatePrinter::printNonNative
  1350. //
  1351. //-----------------------------------------------------------------------------
  1352. STDMETHODIMP
  1353. CTemplatePrinter::printNonNative(IUnknown* pDoc, VARIANT_BOOL *p)
  1354. {
  1355. TEMPLATESECURITYCHECK();
  1356. HRESULT hr = S_OK;
  1357. IOleCommandTarget *pioct = NULL;
  1358. IPrint *pIPrint = NULL;
  1359. VARIANT varOut;
  1360. VARIANT varIn;
  1361. VariantInit(&varOut);
  1362. if (!pDoc || !p)
  1363. {
  1364. hr = E_POINTER;
  1365. goto Cleanup;
  1366. }
  1367. *p = VB_FALSE;
  1368. hr = pDoc->QueryInterface(IID_IOleCommandTarget, (void **)&pioct);
  1369. if (hr)
  1370. goto Cleanup;
  1371. Assert(pioct);
  1372. V_VT(&varIn) = VT_I4;
  1373. V_I4(&varIn) = IPRINT_DOCUMENT;
  1374. hr = pioct->Exec( &CGID_MSHTML,
  1375. IDM_GETIPRINT,
  1376. NULL,
  1377. &varIn,
  1378. &varOut);
  1379. if ( hr
  1380. || V_VT(&varOut) != VT_UNKNOWN
  1381. || !V_UNKNOWN(&varOut))
  1382. goto Cleanup;
  1383. // We don't get back an IPrint collection unless it has at least one member.
  1384. // At this point, we can claim that we should be printing, and a template does not need to.
  1385. *p = VB_TRUE;
  1386. hr = PrintIPrintCollection(&varOut);
  1387. Cleanup:
  1388. VariantClear(&varOut);
  1389. ReleaseInterface(pioct);
  1390. return hr;
  1391. }
  1392. STDMETHODIMP
  1393. CTemplatePrinter::printNonNativeFrames(IUnknown *pMarkup, VARIANT_BOOL fActiveFrame)
  1394. {
  1395. TEMPLATESECURITYCHECK();
  1396. HRESULT hr = S_OK;
  1397. IOleCommandTarget *pioct = NULL;
  1398. VARIANT varOut;
  1399. VARIANT varIn;
  1400. VARIANT varBrowseDoc;
  1401. if (!pMarkup)
  1402. {
  1403. hr = E_POINTER;
  1404. goto Cleanup;
  1405. }
  1406. VariantInit(&varOut);
  1407. VariantInit(&varIn);
  1408. VariantInit(&varBrowseDoc);
  1409. // Use the browse document if one exists - it will have the WebOC frame.
  1410. // NB (greglett)
  1411. // This assumes that the reference we are passed to the browse doc
  1412. // stays good - including nested frames &c... on the browse doc while the WebOC is still
  1413. // loaded & (if it was selected) active.
  1414. // Yes, this may exhibit unexpected behavior if the user Prints and navigates away.
  1415. // A better solution would be appreciated.
  1416. if ( GetDialogArgument(&varBrowseDoc, PRINTARG_BROWSEDOC) == S_OK
  1417. && V_VT(&varBrowseDoc) == VT_UNKNOWN
  1418. && V_UNKNOWN(&varBrowseDoc) )
  1419. {
  1420. hr = V_UNKNOWN(&varBrowseDoc)->QueryInterface(IID_IOleCommandTarget, (void **)&pioct);
  1421. }
  1422. // Otherwise, use the content document
  1423. if (!pioct)
  1424. {
  1425. hr = pMarkup->QueryInterface(IID_IOleCommandTarget, (void **)&pioct);
  1426. if (hr)
  1427. goto Cleanup;
  1428. }
  1429. Assert(pioct);
  1430. V_VT(&varIn) = VT_I4;
  1431. V_I4(&varIn) = fActiveFrame ? IPRINT_ACTIVEFRAME : IPRINT_ALLFRAMES;
  1432. hr = pioct->Exec( &CGID_MSHTML,
  1433. IDM_GETIPRINT,
  1434. NULL,
  1435. &varIn,
  1436. &varOut);
  1437. if ( hr
  1438. || V_VT(&varOut) != VT_UNKNOWN
  1439. || !V_UNKNOWN(&varOut))
  1440. goto Cleanup;
  1441. hr = PrintIPrintCollection(&varOut);
  1442. Cleanup:
  1443. VariantClear(&varOut);
  1444. VariantClear(&varBrowseDoc);
  1445. ReleaseInterface(pioct);
  1446. return hr;
  1447. }
  1448. HRESULT
  1449. CTemplatePrinter::PrintIPrintCollection(VARIANT * pvarIPrintAry)
  1450. {
  1451. TEMPLATESECURITYCHECK();
  1452. HRESULT hr = S_OK;
  1453. IDispatch * pIPrintAry = NULL;
  1454. IPrint * pIPrint = NULL;
  1455. VARIANT varInvokeOut;
  1456. VARIANT varInvokeParam;
  1457. DISPPARAMS DispParams;
  1458. DVTARGETDEVICE * pTargetDevice = NULL;
  1459. PAGESET * pPageSet = NULL;
  1460. long cIPrint, i;
  1461. long lFirstPage, lPages, lLastPage;
  1462. Assert(V_VT(pvarIPrintAry) == VT_UNKNOWN);
  1463. Assert(V_UNKNOWN(pvarIPrintAry));
  1464. VariantInit(&varInvokeOut);
  1465. VariantInit(&varInvokeParam);
  1466. hr = V_UNKNOWN(pvarIPrintAry)->QueryInterface(IID_IDispatch, (void **)&pIPrintAry);
  1467. if (hr)
  1468. goto Cleanup;
  1469. Assert(pIPrintAry);
  1470. DispParams.cNamedArgs = 0;
  1471. DispParams.rgdispidNamedArgs = NULL;
  1472. DispParams.cArgs = 0;
  1473. DispParams.rgvarg = NULL;
  1474. hr = pIPrintAry->Invoke(DISPID_IHTMLIPRINTCOLLECTION_LENGTH,
  1475. IID_NULL,
  1476. LOCALE_USER_DEFAULT,
  1477. DISPATCH_PROPERTYGET,
  1478. &DispParams,
  1479. &varInvokeOut,
  1480. NULL, NULL);
  1481. if ( hr
  1482. || V_VT(&varInvokeOut) != VT_I4
  1483. || V_I4(&varInvokeOut) <= 0 )
  1484. goto Cleanup;
  1485. cIPrint = V_I4(&varInvokeOut);
  1486. VariantClear(&varInvokeOut);
  1487. hr = CreateIPrintParams(&pTargetDevice, &pPageSet);
  1488. if (hr)
  1489. goto Cleanup;
  1490. lFirstPage = pPageSet->rgPages[0].nFromPage;
  1491. lLastPage = pPageSet->rgPages[0].nToPage;
  1492. DispParams.cArgs = 1;
  1493. DispParams.rgvarg = &varInvokeParam;
  1494. V_VT(&varInvokeParam) = VT_I4;
  1495. for (i = 0; i < cIPrint; i++)
  1496. {
  1497. V_I4(&varInvokeParam) = i;
  1498. hr = pIPrintAry->Invoke(DISPID_IHTMLIPRINTCOLLECTION_ITEM,
  1499. IID_NULL,
  1500. LOCALE_USER_DEFAULT,
  1501. DISPATCH_METHOD,
  1502. &DispParams,
  1503. &varInvokeOut,
  1504. NULL, NULL);
  1505. if ( hr
  1506. || V_VT(&varInvokeOut) != VT_UNKNOWN
  1507. || !V_UNKNOWN(&varInvokeOut))
  1508. {
  1509. VariantClear(&varInvokeOut);
  1510. continue;
  1511. }
  1512. hr = V_UNKNOWN(&varInvokeOut)->QueryInterface(IID_IPrint, (void **)&pIPrint);
  1513. VariantClear(&varInvokeOut);
  1514. if (hr)
  1515. continue;
  1516. Assert(pIPrint);
  1517. hr = pIPrint->Print(
  1518. PRINTFLAG_MAYBOTHERUSER,
  1519. &pTargetDevice,
  1520. &pPageSet,
  1521. NULL,
  1522. NULL,
  1523. lFirstPage,
  1524. &lPages, // out
  1525. &lLastPage // out
  1526. );
  1527. ReleaseInterface(pIPrint);
  1528. pIPrint = NULL;
  1529. }
  1530. hr = S_OK;
  1531. Cleanup:
  1532. if (pTargetDevice)
  1533. ::CoTaskMemFree(pTargetDevice);
  1534. if (pPageSet)
  1535. ::CoTaskMemFree(pPageSet);
  1536. ReleaseInterface(pIPrintAry);
  1537. return hr;
  1538. }
  1539. //+----------------------------------------------------------------------------
  1540. //
  1541. // (ITemplatePrinter) CTemplatePrinter::showPrintDialog, ensurePrintDialogDefaults
  1542. //
  1543. //-----------------------------------------------------------------------------
  1544. STDMETHODIMP
  1545. CTemplatePrinter::ensurePrintDialogDefaults(VARIANT_BOOL *p)
  1546. {
  1547. TEMPLATESECURITYCHECK();
  1548. if (!p)
  1549. return E_POINTER;
  1550. // If we already have default printer information, use it.
  1551. if (_hDevNames && _hDevMode)
  1552. *p = VB_TRUE;
  1553. // Otherwise, go get it.
  1554. else
  1555. GetPrintDialogSettings(FALSE, p);
  1556. return S_OK;
  1557. }
  1558. STDMETHODIMP
  1559. CTemplatePrinter::showPrintDialog(VARIANT_BOOL *p)
  1560. {
  1561. TEMPLATESECURITYCHECK();
  1562. if (!p)
  1563. return E_POINTER;
  1564. GetPrintDialogSettings(TRUE, p);
  1565. return S_OK;
  1566. }
  1567. //+----------------------------------------------------------------------------
  1568. //
  1569. // (ITemplatePrinter) CTemplatePrinter::showPageSetupDialog
  1570. //
  1571. //-----------------------------------------------------------------------------
  1572. STDMETHODIMP
  1573. CTemplatePrinter::showPageSetupDialog(VARIANT_BOOL *p)
  1574. {
  1575. TEMPLATESECURITYCHECK();
  1576. HRESULT hr;
  1577. HWND hWnd;
  1578. BOOL fMetricUnits = FALSE;
  1579. IHTMLEventObj2 *pEvent = NULL; // To populate with dialog parameters
  1580. IDocHostUIHandler *pUIHandler = NULL;
  1581. IOleCommandTarget *pUICommandHandler = NULL;
  1582. HGLOBAL hPageSetup = NULL;
  1583. PAGESETUPDLG * ppagesetupdlg = NULL;
  1584. VARIANT varIn;
  1585. if (!p)
  1586. {
  1587. hr = E_POINTER;
  1588. goto Cleanup;
  1589. }
  1590. *p = VB_FALSE;
  1591. if (_hDC)
  1592. {
  1593. hr = E_FAIL;
  1594. goto Cleanup;
  1595. }
  1596. hPageSetup = ::GlobalAlloc(GHND, sizeof(PAGESETUPDLG));
  1597. if (!hPageSetup)
  1598. {
  1599. hr = E_OUTOFMEMORY;
  1600. goto Cleanup;
  1601. }
  1602. ppagesetupdlg = (PAGESETUPDLG *)::GlobalLock(hPageSetup);
  1603. if (!ppagesetupdlg)
  1604. {
  1605. hr = E_FAIL;
  1606. goto Cleanup;
  1607. }
  1608. hr = InitDialog(&hWnd, &pEvent, &pUICommandHandler);
  1609. if (hr)
  1610. goto Cleanup;
  1611. {
  1612. // Are we using metric or British (US) for margins?
  1613. TCHAR achLocale[32];
  1614. int iLocale = 32;
  1615. fMetricUnits = ( GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IMEASURE, achLocale, iLocale)
  1616. && achLocale[0] == TCHAR('0'));
  1617. }
  1618. // Now, initialize the event's type and expandos.
  1619. {
  1620. BSTR bstrTemp = SysAllocString( L"pagesetup" );
  1621. VARIANT var;
  1622. if (bstrTemp)
  1623. {
  1624. pEvent->put_type( bstrTemp );
  1625. SysFreeString(bstrTemp);
  1626. }
  1627. V_VT(&var) = VT_PTR;
  1628. V_BYREF(&var) = ppagesetupdlg;
  1629. hr = pEvent->setAttribute(_T("pagesetupStruct"), var, 0);
  1630. if (hr)
  1631. goto Cleanup;
  1632. V_VT(&var) = VT_BSTR;
  1633. bstrTemp = SysAllocString(_achHeader);
  1634. if (bstrTemp)
  1635. {
  1636. V_BSTR(&var) = bstrTemp;
  1637. hr = pEvent->setAttribute(_T("pagesetupHeader"), var, 0);
  1638. SysFreeString(bstrTemp);
  1639. }
  1640. bstrTemp = SysAllocString(_achFooter);
  1641. if (bstrTemp)
  1642. {
  1643. V_BSTR(&var) = bstrTemp;
  1644. hr = pEvent->setAttribute(_T("pagesetupFooter"), var, 0);
  1645. SysFreeString(bstrTemp);
  1646. }
  1647. }
  1648. // Fill out PAGESETUPDLG structure
  1649. ::ZeroMemory(ppagesetupdlg, sizeof(PAGESETUPDLG));
  1650. ppagesetupdlg->lStructSize = sizeof(PAGESETUPDLG);
  1651. ppagesetupdlg->hwndOwner = hWnd;
  1652. ppagesetupdlg->hDevMode = _hDevMode;
  1653. ppagesetupdlg->hDevNames = _hDevNames;
  1654. ppagesetupdlg->Flags |= PSD_DEFAULTMINMARGINS;
  1655. if (_ptPaperSize.x != -1)
  1656. {
  1657. ppagesetupdlg->ptPaperSize = _ptPaperSize;
  1658. }
  1659. if (_rcMargin.left != -1)
  1660. {
  1661. ppagesetupdlg->Flags |= PSD_MARGINS;
  1662. ppagesetupdlg->rtMargin = _rcMargin;
  1663. if (fMetricUnits)
  1664. {
  1665. // Margins from PrintInfoBag are in 1/100000" and need to be converted to 1/100 mm.
  1666. ppagesetupdlg->rtMargin.left = MulDivQuick(ppagesetupdlg->rtMargin.left , 2540, 100000);
  1667. ppagesetupdlg->rtMargin.right = MulDivQuick(ppagesetupdlg->rtMargin.right , 2540, 100000);
  1668. ppagesetupdlg->rtMargin.top = MulDivQuick(ppagesetupdlg->rtMargin.top , 2540, 100000);
  1669. ppagesetupdlg->rtMargin.bottom = MulDivQuick(ppagesetupdlg->rtMargin.bottom, 2540, 100000);
  1670. }
  1671. else
  1672. {
  1673. // Margins from PrintInfoBag are in 1/100000" and need to be converted to 1/1000".
  1674. ppagesetupdlg->rtMargin.left = ppagesetupdlg->rtMargin.left / 100;
  1675. ppagesetupdlg->rtMargin.right = ppagesetupdlg->rtMargin.right / 100;
  1676. ppagesetupdlg->rtMargin.top = ppagesetupdlg->rtMargin.top / 100;
  1677. ppagesetupdlg->rtMargin.bottom = ppagesetupdlg->rtMargin.bottom / 100;
  1678. }
  1679. }
  1680. CommCtrlNativeFontSupport();
  1681. V_VT(&varIn) = VT_UNKNOWN;
  1682. V_UNKNOWN(&varIn) = pEvent;
  1683. // Query host to show dialog
  1684. if (pUICommandHandler)
  1685. {
  1686. // We may be marshalling this call across threads. RPC doesn't allow VT_PTRs to cross threads.
  1687. // We work around this by sticking the structure into a GHND contents and pass the VT_HANDLE.
  1688. // We then delegate to the browse document, who will obtain a copy of the GHND pointer and use that for the VT_PTR
  1689. // the struct. (CDoc::DelegateShowPrintingDialog)
  1690. //
  1691. // In theory, we could detect this by looking at the __IE_uPrintFlags to see if it is flagged synchronous to avoid playing with handles.
  1692. // The downside: as with all dialogArguments, anyone could have mucked around with the flags)
  1693. VARIANT var;
  1694. V_VT(&var) = VT_HANDLE;
  1695. V_BYREF(&var) = hPageSetup;
  1696. pEvent->setAttribute(_T("hPageSetup"), var, 0);
  1697. // Delegate call to browse Trident
  1698. hr = pUICommandHandler->Exec(
  1699. NULL, // For Trident
  1700. OLECMDID_SHOWPAGESETUP,
  1701. 0,
  1702. &varIn,
  1703. NULL);
  1704. pEvent->removeAttribute(_T("hPageSetup"), 0, NULL);
  1705. }
  1706. if ( !pUICommandHandler
  1707. || hr == OLECMDERR_E_NOTSUPPORTED
  1708. || hr == OLECMDERR_E_UNKNOWNGROUP
  1709. || hr == E_FAIL
  1710. || hr == E_NOTIMPL )
  1711. {
  1712. ClearInterface(&pUICommandHandler);
  1713. // Create backup UI Handler
  1714. // (greglett) Cache this - CoCreate is expensive.
  1715. hr = CoCreateInstance(CLSID_DocHostUIHandler,
  1716. NULL,
  1717. CLSCTX_INPROC_SERVER,
  1718. IID_IDocHostUIHandler,
  1719. (void**)&pUIHandler);
  1720. if (!pUIHandler)
  1721. goto Cleanup;
  1722. hr = pUIHandler->QueryInterface(IID_IOleCommandTarget,(void**)&pUICommandHandler);
  1723. if (!pUICommandHandler)
  1724. goto Cleanup;
  1725. hr = pUICommandHandler->Exec(
  1726. &CGID_DocHostCommandHandler, // For a dochost object
  1727. OLECMDID_SHOWPAGESETUP,
  1728. 0,
  1729. &varIn,
  1730. NULL);
  1731. }
  1732. // If the dialog was cancelled, or there was a problem showing the dialog,
  1733. // do not update values.
  1734. if (hr)
  1735. goto Cleanup;
  1736. *p = VB_TRUE; // OK was pressed.
  1737. //
  1738. // Retrieve page setup changes from the page setup dialog structure.
  1739. //
  1740. _hDevMode = ppagesetupdlg->hDevMode;
  1741. _hDevNames = ppagesetupdlg->hDevNames;
  1742. GetDeviceProperties();
  1743. if (fMetricUnits)
  1744. {
  1745. // Margins from Page Setup dialog are in 1/100 mm and need to be converted to 1/100000"
  1746. _rcMargin.left = MulDivQuick(ppagesetupdlg->rtMargin.left , 100000, 2540);
  1747. _rcMargin.right = MulDivQuick(ppagesetupdlg->rtMargin.right , 100000, 2540);
  1748. _rcMargin.top = MulDivQuick(ppagesetupdlg->rtMargin.top , 100000, 2540);
  1749. _rcMargin.bottom = MulDivQuick(ppagesetupdlg->rtMargin.bottom, 100000, 2540);
  1750. }
  1751. else
  1752. {
  1753. // Margins from Page Setup dialog are in 1/1000" and need to be converted to 1/100000"
  1754. _rcMargin.left = ppagesetupdlg->rtMargin.left * 100;
  1755. _rcMargin.right = ppagesetupdlg->rtMargin.right * 100;
  1756. _rcMargin.top = ppagesetupdlg->rtMargin.top * 100;
  1757. _rcMargin.bottom = ppagesetupdlg->rtMargin.bottom * 100;
  1758. }
  1759. // (greglett) 99% of OS's use PSD_DEFAULTMINMARGINS to restrict the margins to the printable page area.
  1760. // NT4SP6 without the IE shell extensions doesn't. So, we are forced to do more work for yet another violation of the API documentation.
  1761. // Force margins to be at least as large as the unprintable region.
  1762. // Do we want also to display an error message if they are different? (Otherwise, we change it, and the user doesn't see it.)
  1763. if (_rcMargin.left < MulDivQuick(_rcUnprintable.left, 100000, _szResolution.cx))
  1764. _rcMargin.left = MulDivQuick(_rcUnprintable.left, 100000, _szResolution.cx);
  1765. if (_rcMargin.right < MulDivQuick(_rcUnprintable.right, 100000, _szResolution.cx))
  1766. _rcMargin.right = MulDivQuick(_rcUnprintable.right, 100000, _szResolution.cx);
  1767. if (_rcMargin.top < MulDivQuick(_rcUnprintable.top, 100000, _szResolution.cy))
  1768. _rcMargin.top = MulDivQuick(_rcUnprintable.top, 100000, _szResolution.cy);
  1769. if (_rcMargin.bottom < MulDivQuick(_rcUnprintable.bottom, 100000, _szResolution.cy))
  1770. _rcMargin.bottom = MulDivQuick(_rcUnprintable.bottom, 100000, _szResolution.cy);
  1771. //
  1772. // Read in Trident specific values from the page setup dialog
  1773. //
  1774. {
  1775. VARIANT var;
  1776. TCHAR *pchTemp;
  1777. if ( !pEvent->getAttribute(_T("pagesetupHeader"),0,&var)
  1778. && var.vt == VT_BSTR
  1779. && var.bstrVal)
  1780. {
  1781. pchTemp = var.bstrVal;
  1782. _tcscpy(_achHeader, pchTemp);
  1783. SysFreeString(var.bstrVal);
  1784. }
  1785. else
  1786. _achHeader[0] = _T('\0');
  1787. if ( !pEvent->getAttribute(_T("pagesetupFooter"),0,&var)
  1788. && var.vt == VT_BSTR
  1789. && var.bstrVal)
  1790. {
  1791. pchTemp = var.bstrVal;
  1792. _tcscpy(_achFooter, pchTemp);
  1793. SysFreeString(var.bstrVal);
  1794. }
  1795. else
  1796. _achFooter[0] = _T('\0');
  1797. }
  1798. //
  1799. // Persist results of the page setup dialog out to the registry.
  1800. //
  1801. {
  1802. HKEY keyPageSetup = NULL;
  1803. if (GetRegPrintOptionsKey(PRINTOPTSUBKEY_PAGESETUP,&keyPageSetup) == ERROR_SUCCESS)
  1804. {
  1805. if (_fPersistHFToRegistry)
  1806. {
  1807. WriteHeaderFooterToRegistry(keyPageSetup);
  1808. }
  1809. WriteMarginsToRegistry(keyPageSetup);
  1810. RegCloseKey(keyPageSetup);
  1811. }
  1812. }
  1813. Cleanup:
  1814. ReleaseInterface(pEvent);
  1815. ReleaseInterface(pUIHandler);
  1816. ReleaseInterface(pUICommandHandler);
  1817. if (hPageSetup)
  1818. {
  1819. if (ppagesetupdlg)
  1820. ::GlobalUnlock(hPageSetup);
  1821. ::GlobalFree(hPageSetup);
  1822. }
  1823. return hr;
  1824. }
  1825. //+----------------------------------------------------------------------------
  1826. //
  1827. // Member : CTemplatePrinter::GetPrintDialogSettings
  1828. //
  1829. // Synopsis : 'Finishes' the doc - takes pages printed via printPage and queues the job
  1830. //
  1831. //-----------------------------------------------------------------------------
  1832. HRESULT
  1833. CTemplatePrinter::GetPrintDialogSettings(BOOL fBotherUser, VARIANT_BOOL *pvarfOKOrCancel)
  1834. {
  1835. HRESULT hr;
  1836. HWND hWnd = NULL;
  1837. IHTMLEventObj2 *pEvent = NULL; // To populate with dialog parameters
  1838. IDocHostUIHandler *pUIHandler = NULL;
  1839. IOleCommandTarget *pUICommandHandler = NULL;
  1840. HGLOBAL hPrint = NULL;
  1841. PRINTDLG * pprintdlg = NULL;
  1842. VARIANT varIn;
  1843. int nFontSize;
  1844. void *pDevMode = NULL;
  1845. if (pvarfOKOrCancel)
  1846. *pvarfOKOrCancel = VB_FALSE;
  1847. hPrint = ::GlobalAlloc(GHND, sizeof(PRINTDLG));
  1848. if (!hPrint)
  1849. {
  1850. hr = E_OUTOFMEMORY;
  1851. goto Cleanup;
  1852. }
  1853. pprintdlg = (PRINTDLG *)::GlobalLock(hPrint);
  1854. if (!pprintdlg)
  1855. {
  1856. hr = E_FAIL;
  1857. goto Cleanup;
  1858. }
  1859. if (_hDC)
  1860. {
  1861. hr = E_FAIL;
  1862. goto Cleanup;
  1863. }
  1864. hr = InitDialog(&hWnd, &pEvent, &pUICommandHandler, &nFontSize);
  1865. if (hr)
  1866. goto Cleanup;
  1867. // PrintDlgEx (only available NT5+) fails with a NULL HWND.
  1868. // It is likely that the DHUI that raises the dialog will use PrintDlgEx (our default DHUI in shdocvw does).
  1869. if ( g_dwPlatformID == VER_PLATFORM_WIN32_NT
  1870. && hWnd == NULL )
  1871. hWnd = GetDesktopWindow();
  1872. // PrintDlgEx (only available NT5+) fails with a NULL HWND.
  1873. // It is likely that the DHUI that raises the dialog will use PrintDlgEx (our default DHUI in shdocvw does).
  1874. if ( g_dwPlatformID == VER_PLATFORM_WIN32_NT
  1875. && hWnd == NULL )
  1876. hWnd = GetDesktopWindow();
  1877. // Now, initialize the event's type and expandos.
  1878. {
  1879. BSTR bstrTemp = SysAllocString( L"print" );
  1880. VARIANT var;
  1881. if (bstrTemp)
  1882. {
  1883. pEvent->put_type(bstrTemp);
  1884. SysFreeString(bstrTemp);
  1885. }
  1886. V_VT(&var) = VT_BOOL;
  1887. V_BOOL(&var) = AreRatingsEnabled() ? VB_TRUE : VB_FALSE;
  1888. hr = pEvent->setAttribute(_T("printfAreRatingsEnabled"), var, 0);
  1889. if (hr)
  1890. goto Cleanup;
  1891. V_BOOL(&var) = _fFramesetDocument ? VB_TRUE : VB_FALSE;
  1892. hr = pEvent->setAttribute(_T("printfRootDocumentHasFrameset"), var, 0);
  1893. if (hr)
  1894. goto Cleanup;
  1895. V_BOOL(&var) = _fFrameActive ? VB_TRUE : VB_FALSE;
  1896. hr = pEvent->setAttribute(_T("printfActiveFrame"), var, 0);
  1897. if (hr)
  1898. goto Cleanup;
  1899. V_BOOL(&var) = _fFrameActiveEnabled ? VB_TRUE : VB_FALSE;
  1900. hr = pEvent->setAttribute(_T("printfActiveFrameEnabled"), var, 0);
  1901. if (hr)
  1902. goto Cleanup;
  1903. V_BOOL(&var) = _fFrameAsShown ? VB_TRUE : VB_FALSE;
  1904. hr = pEvent->setAttribute(_T("printfAsShown"), var, 0);
  1905. if (hr)
  1906. goto Cleanup;
  1907. V_BOOL(&var) = _fPrintAllLinkedDocuments ? VB_TRUE : VB_FALSE;
  1908. hr = pEvent->setAttribute(_T("printfLinked"), var, 0);
  1909. if (hr)
  1910. goto Cleanup;
  1911. V_BOOL(&var) = _fPrintSelectionEnabled ? VB_TRUE : VB_FALSE;
  1912. hr = pEvent->setAttribute(_T("printfSelection"), var, 0);
  1913. if (hr)
  1914. goto Cleanup;
  1915. V_BOOL(&var) = _fPrintTableOfLinks ? VB_TRUE : VB_FALSE;
  1916. hr = pEvent->setAttribute(_T("printfShortcutTable"), var, 0);
  1917. if (hr)
  1918. goto Cleanup;
  1919. V_BOOL(&var) = VB_FALSE;
  1920. hr = pEvent->setAttribute(_T("printToFileOk"),var, 0);
  1921. if (hr)
  1922. goto Cleanup;
  1923. V_VT(&var) = VT_INT;
  1924. V_INT(&var) = nFontSize;
  1925. hr = pEvent->setAttribute(_T("printiFontScaling"), var, 0);
  1926. if (hr)
  1927. goto Cleanup;
  1928. V_VT(&var) = VT_PTR;
  1929. V_BYREF(&var) = pprintdlg;
  1930. hr = pEvent->setAttribute(_T("printStruct"), var, 0);
  1931. if (hr)
  1932. goto Cleanup;
  1933. V_VT(&var) = VT_UNKNOWN;
  1934. V_UNKNOWN(&var) = NULL;
  1935. hr = pEvent->setAttribute(_T("printpBodyActiveTarget"), var, 0);
  1936. if (hr)
  1937. goto Cleanup;
  1938. V_VT(&var) = VT_BSTR;
  1939. bstrTemp = SysAllocString(_achFileName);
  1940. if (bstrTemp)
  1941. {
  1942. V_BSTR(&var) = bstrTemp;
  1943. hr = pEvent->setAttribute(_T("printToFileName"), var, 0);
  1944. SysFreeString(bstrTemp);
  1945. }
  1946. }
  1947. //
  1948. // Initialize the PRINTDLG structure
  1949. //
  1950. ::ZeroMemory(pprintdlg, sizeof(PRINTDLG));
  1951. pprintdlg->lStructSize = sizeof(PRINTDLG);
  1952. pprintdlg->hwndOwner = hWnd;
  1953. pprintdlg->hDevMode = _hDevMode;
  1954. pprintdlg->hDevNames = _hDevNames;
  1955. pprintdlg->nCopies = _nCopies;
  1956. pprintdlg->nFromPage = _nPageFrom;
  1957. pprintdlg->nToPage = _nPageTo;
  1958. pprintdlg->nMinPage = 1;
  1959. pprintdlg->nMaxPage = 0xffff;
  1960. pprintdlg->Flags |= (_fPrintSelectionEnabled ? 0 : PD_NOSELECTION);
  1961. pprintdlg->Flags |= (_fCollate ? PD_COLLATE : 0);
  1962. pprintdlg->Flags |= (_fPrintSelectedPages ? PD_PAGENUMS : 0);
  1963. pprintdlg->Flags |= (_fPrintToFile ? PD_PRINTTOFILE : 0);
  1964. pprintdlg->Flags |= (_fCurrentPageAvail ? (_fPrintCurrentPage ? PD_CURRENTPAGE : 0) : PD_NOCURRENTPAGE);
  1965. if (!fBotherUser)
  1966. {
  1967. // this indicates we only want to retrieve the defaults,
  1968. // not to bring up the dialog
  1969. pprintdlg->hDevMode = NULL;
  1970. pprintdlg->hDevNames = NULL;
  1971. pprintdlg->Flags |= PD_RETURNDEFAULT;
  1972. }
  1973. CommCtrlNativeFontSupport();
  1974. V_VT(&varIn) = VT_UNKNOWN;
  1975. V_UNKNOWN(&varIn) = pEvent;
  1976. // Query host to show dialog
  1977. hr = E_FAIL;
  1978. if ( pvarfOKOrCancel // Don't delegate on the ::Init call. Only delegate script calls.
  1979. && pUICommandHandler)
  1980. {
  1981. // We may be marshalling this call across threads. RPC doesn't allow VT_PTRs to cross threads.
  1982. // We work around this by sticking the structure into a GHND contents and pass the VT_HANDLE.
  1983. // We then delegate to the browse document, who will obtain a copy of the GHND pointer and use that for the VT_PTR
  1984. // the struct. (CDoc::DelegateShowPrintingDialog)
  1985. //
  1986. // In theory, we could detect this by looking at the __IE_uPrintFlags to see if it is flagged synchronous to avoid playing with handles.
  1987. // The downside: as with all dialogArguments, anyone could have mucked around with the flags)
  1988. VARIANT var;
  1989. V_VT(&var) = VT_HANDLE;
  1990. V_BYREF(&var) = hPrint;
  1991. pEvent->setAttribute(_T("hPrint"), var, 0);
  1992. // Delegate call to browse Trident
  1993. hr = pUICommandHandler->Exec(
  1994. NULL, // For Trident
  1995. OLECMDID_SHOWPRINT,
  1996. 0,
  1997. &varIn,
  1998. NULL);
  1999. pEvent->removeAttribute(_T("hPrint"), 0, NULL);
  2000. }
  2001. if ( hr == OLECMDERR_E_NOTSUPPORTED
  2002. || hr == OLECMDERR_E_UNKNOWNGROUP
  2003. || hr == E_FAIL
  2004. || hr == E_NOTIMPL )
  2005. {
  2006. ClearInterface(&pUICommandHandler);
  2007. // Create backup UI Handler
  2008. // (greglett) Cache this - CoCreate is expensive.
  2009. hr = CoCreateInstance(CLSID_DocHostUIHandler,
  2010. NULL,
  2011. CLSCTX_INPROC_SERVER,
  2012. IID_IDocHostUIHandler,
  2013. (void**)&pUIHandler);
  2014. if (!pUIHandler)
  2015. goto Cleanup;
  2016. hr = pUIHandler->QueryInterface(IID_IOleCommandTarget,(void**)&pUICommandHandler);
  2017. if (!pUICommandHandler)
  2018. goto Cleanup;
  2019. hr = pUICommandHandler->Exec(
  2020. &CGID_DocHostCommandHandler,
  2021. OLECMDID_SHOWPRINT,
  2022. 0,
  2023. &varIn,
  2024. NULL);
  2025. }
  2026. // If the dialog was cancelled, or there was a problem showing the dialog,
  2027. // do not update values.
  2028. if (FAILED(hr))
  2029. goto Cleanup;
  2030. // this can be false because either init failed for no installed printer
  2031. // or the user clicked cancel.
  2032. if (hr==S_FALSE)
  2033. {
  2034. // Three cases:
  2035. // fBotherUser *pvarfOkOrCancel
  2036. // 1 1 fBotherUser && varfOkOrCancel - We are being called from script. We tried to raise a dialog, and
  2037. // failed or were cancelled - UI has been displayed in the former case.
  2038. // 0 1 We are being called from script. We tried to get default printer info
  2039. // and failed - this is probably because no default it set. As we used
  2040. // to, we need to raise the dialog (despite the fBotherUser) to get enough info.
  2041. // 0 0 We are being called from the init, with no default printer. We will continue
  2042. // through the procedure to get defaults.
  2043. // 1 0 Never occurs.
  2044. Assert(!(!pvarfOKOrCancel && fBotherUser));
  2045. if (fBotherUser)
  2046. {
  2047. hr = S_OK;
  2048. goto Cleanup;
  2049. }
  2050. else if (pvarfOKOrCancel)
  2051. {
  2052. hr = GetPrintDialogSettings(TRUE, pvarfOKOrCancel);
  2053. goto Cleanup;
  2054. }
  2055. // Otherwise, we need to set the default values.
  2056. else
  2057. hr = S_OK;
  2058. }
  2059. else if (pvarfOKOrCancel)
  2060. *pvarfOKOrCancel = VB_TRUE; // OK was pressed.
  2061. //
  2062. // Take base print dialog return values and store them.
  2063. //
  2064. _hDevMode = pprintdlg->hDevMode;
  2065. _hDevNames = pprintdlg->hDevNames;
  2066. _nCopies = (fBotherUser) ? pprintdlg->nCopies : 1; // bug in printDLG
  2067. _nPageFrom = pprintdlg->nFromPage;
  2068. _nPageTo = pprintdlg->nToPage;
  2069. _fPrintSelectedPages = (!!(pprintdlg->Flags & PD_PAGENUMS));
  2070. _fPrintSelection = (!!(pprintdlg->Flags & PD_SELECTION));
  2071. _fCollate = (!!(pprintdlg->Flags & PD_COLLATE));
  2072. _fPrintToFile = (!!(pprintdlg->Flags & PD_PRINTTOFILE));
  2073. _fPrintCurrentPage = (!!(pprintdlg->Flags & PD_CURRENTPAGE));
  2074. // Collate/Copy information is in both the struct and the DEVMODE.
  2075. // The DEVMODE bits instruct the printer to do its own copy/collate information.
  2076. // This means that only one copy of the document is uploaded to the printer/server, and the printer itself does the replication/duplex work.
  2077. if (_hDevMode)
  2078. {
  2079. pDevMode = ::GlobalLock(_hDevMode);
  2080. if (pDevMode)
  2081. {
  2082. // (greglett) DEVMODE is returned A on Win9x platforms, not W. <sigh>
  2083. if (g_fUnicodePlatform)
  2084. {
  2085. if (((DEVMODEW *)pDevMode)->dmFields & DM_COLLATE)
  2086. _fCollate = (((DEVMODEW *)pDevMode)->dmCollate == DMCOLLATE_TRUE) || _fCollate;
  2087. if ( ((DEVMODEW *)pDevMode)->dmFields & DM_COPIES
  2088. && ((DEVMODEW *)pDevMode)->dmCopies > _nCopies )
  2089. _nCopies = ((DEVMODEW *)pDevMode)->dmCopies;
  2090. }
  2091. else
  2092. {
  2093. if (((DEVMODEA *)pDevMode)->dmFields & DM_COLLATE)
  2094. _fCollate = (((DEVMODEA *)pDevMode)->dmCollate == DMCOLLATE_TRUE) || _fCollate;
  2095. if ( ((DEVMODEA *)pDevMode)->dmFields & DM_COPIES
  2096. && ((DEVMODEA *)pDevMode)->dmCopies > _nCopies )
  2097. _nCopies = ((DEVMODEA *)pDevMode)->dmCopies;
  2098. }
  2099. ::GlobalUnlock(_hDevMode);
  2100. }
  2101. }
  2102. GetDeviceProperties();
  2103. // Read in changes to the Trident specific print options.
  2104. {
  2105. VARIANT var;
  2106. // Read changed values from event object
  2107. if (!pEvent->getAttribute(_T("printfLinked"),0,&var))
  2108. {
  2109. Assert(var.vt == VT_BOOL);
  2110. _fPrintAllLinkedDocuments = var.boolVal;
  2111. }
  2112. if (!pEvent->getAttribute(_T("printfActiveFrame"), 0, &var))
  2113. {
  2114. Assert(var.vt == VT_BOOL);
  2115. _fFrameActive = var.boolVal;
  2116. }
  2117. if (!pEvent->getAttribute(_T("printfAsShown"), 0, &var))
  2118. {
  2119. Assert(var.vt == VT_BOOL);
  2120. _fFrameAsShown = var.boolVal;
  2121. }
  2122. if (!pEvent->getAttribute(_T("printfShortcutTable"), 0, &var))
  2123. {
  2124. Assert(var.vt == VT_BOOL);
  2125. _fPrintTableOfLinks = var.boolVal;
  2126. }
  2127. }
  2128. if (_fPrintToFile)
  2129. {
  2130. // assume failure, treating as canceling
  2131. VARIANT var;
  2132. hr = S_FALSE;
  2133. if ( !pEvent->getAttribute(_T("printToFileOK"), 0, &var)
  2134. && var.boolVal)
  2135. {
  2136. if ( !pEvent->getAttribute(_T("printToFileName"), 0, &var)
  2137. && var.vt == VT_BSTR)
  2138. {
  2139. TCHAR * pchFullPath = var.bstrVal;
  2140. _tcscpy(_achFileName, pchFullPath);
  2141. SysFreeString(var.bstrVal);
  2142. // (greglett) Code used to update Trident's default save path here. (pre 5.5)
  2143. // Not being internal, we can't do that anymore.
  2144. hr = S_OK;
  2145. }
  2146. }
  2147. if (hr != S_OK)
  2148. *pvarfOKOrCancel = VB_FALSE;
  2149. }
  2150. Cleanup:
  2151. ReleaseInterface(pUIHandler);
  2152. ReleaseInterface(pUICommandHandler);
  2153. ReleaseInterface(pEvent);
  2154. if (hPrint)
  2155. {
  2156. if (pprintdlg)
  2157. ::GlobalUnlock(hPrint);
  2158. ::GlobalFree(hPrint);
  2159. }
  2160. return hr;
  2161. }
  2162. //+----------------------------------------------------------------------------
  2163. //
  2164. // Member : CTemplatePrinter::InitDialog
  2165. //
  2166. // Synopsis : Does all the COM schtick to get the appropriate interfaces to show
  2167. // a dialog.
  2168. //
  2169. // Parameters: hWnd: Will try to fill with Trident's hWnd. May return as NULL with S_OK.
  2170. // ppEventObj2: Will create an IHTMLEventObj2. Must be created if S_OK is returned.
  2171. // ppUIHandler: Will return Trident's UI Handler. May return NULL with S_OK.
  2172. //
  2173. //-----------------------------------------------------------------------------
  2174. HRESULT
  2175. CTemplatePrinter::InitDialog(HWND *phWnd, IHTMLEventObj2 **ppEventObj2, IOleCommandTarget **ppUIHandler, int *pnFontScale)
  2176. {
  2177. HRESULT hr;
  2178. IHTMLElement *pElement = NULL;
  2179. IDispatch *pDispatch = NULL;
  2180. IHTMLDocument2 *pDoc = NULL;
  2181. IOleWindow *pDocWin = NULL;
  2182. IHTMLEventObj *pEventObj = NULL;
  2183. VARIANT varHost;
  2184. Assert(phWnd);
  2185. Assert(ppEventObj2);
  2186. Assert(ppUIHandler);
  2187. VariantInit(&varHost);
  2188. *phWnd = NULL;
  2189. *ppEventObj2 = NULL;
  2190. *ppUIHandler = NULL;
  2191. if (pnFontScale)
  2192. *pnFontScale = 2;
  2193. if (!_pPeerSiteOM)
  2194. {
  2195. hr = E_FAIL;
  2196. goto Cleanup;
  2197. }
  2198. if (!phWnd || !ppEventObj2 || !ppUIHandler)
  2199. {
  2200. hr = E_POINTER;
  2201. goto Cleanup;
  2202. }
  2203. hr = _pPeerSite->GetElement(&pElement);
  2204. if (hr)
  2205. goto Cleanup;
  2206. Assert(pElement);
  2207. hr = pElement->get_document(&pDispatch);
  2208. if (hr)
  2209. goto Cleanup;
  2210. Assert(pDispatch);
  2211. hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void**) &pDoc);
  2212. if (hr)
  2213. goto Cleanup;
  2214. hr = pDoc->QueryInterface(IID_IOleWindow, (void **)&pDocWin);
  2215. if (!hr)
  2216. {
  2217. Assert(pDocWin);
  2218. pDocWin->GetWindow(phWnd);
  2219. }
  2220. // Create an event object to pass to our host with the print information
  2221. hr = _pPeerSiteOM->CreateEventObject(&pEventObj);
  2222. if (hr)
  2223. goto Cleanup;
  2224. Assert(pEventObj);
  2225. // Now get the appropriate interface to populate the event object with parameters
  2226. // for the dialog.
  2227. hr = pEventObj->QueryInterface(IID_IHTMLEventObj2, (void**)ppEventObj2);
  2228. if (hr)
  2229. goto Cleanup;
  2230. Assert(ppEventObj2);
  2231. // Get the instance of the Trident Host UI browse document, if it exists.
  2232. // We use this to delegate to our host.
  2233. if ( GetDialogArgument(&varHost, PRINTARG_BROWSEDOC) == S_OK
  2234. && V_VT(&varHost) == VT_UNKNOWN
  2235. && V_UNKNOWN(&varHost) )
  2236. {
  2237. hr = V_UNKNOWN(&varHost)->QueryInterface(IID_IOleCommandTarget, (void **)ppUIHandler);
  2238. Assert(*ppUIHandler);
  2239. }
  2240. Cleanup:
  2241. ReleaseInterface(pElement);
  2242. ReleaseInterface(pDispatch);
  2243. ReleaseInterface(pDoc);
  2244. ReleaseInterface(pDocWin);
  2245. ReleaseInterface(pEventObj);
  2246. VariantClear(&varHost);
  2247. return hr;
  2248. }
  2249. //+----------------------------------------------------------------------------
  2250. //
  2251. // Member : CTemplatePrinter::ReturnPrintHandles
  2252. //
  2253. // Synopsis : Show our print handles to the browse instance of Trident.
  2254. //
  2255. //-----------------------------------------------------------------------------
  2256. void
  2257. CTemplatePrinter::ReturnPrintHandles()
  2258. {
  2259. HRESULT hr;
  2260. VARIANT varHost;
  2261. VARIANT varIn;
  2262. SAFEARRAYBOUND sabound;
  2263. IOleCommandTarget * pioct = NULL;
  2264. SAFEARRAY * psa = NULL;
  2265. long lArg = 0;
  2266. VariantInit(&varHost);
  2267. VariantInit(&varIn);
  2268. if (!_hDevNames || !_hDevMode)
  2269. goto Cleanup;
  2270. //
  2271. // Get handle back to the browse document to update its print handles.
  2272. //
  2273. if ( GetDialogArgument(&varHost, PRINTARG_BROWSEDOC) != S_OK
  2274. || V_VT(&varHost) != VT_UNKNOWN
  2275. || !V_UNKNOWN(&varHost) )
  2276. goto Cleanup;
  2277. hr = V_UNKNOWN(&varHost)->QueryInterface(IID_IOleCommandTarget, (void **)&pioct);
  2278. if (hr)
  2279. goto Cleanup;
  2280. Assert(pioct);
  2281. //
  2282. // Create a SAFEARRAY filled with our two print handles { DEVNAMES, DEVMODE }
  2283. //
  2284. sabound.cElements = 2;
  2285. sabound.lLbound = 0;
  2286. psa = SafeArrayCreate(VT_HANDLE, 1, &sabound);
  2287. if (!psa)
  2288. goto Cleanup;
  2289. //
  2290. // Bundle the array in the Exec argument...
  2291. //
  2292. V_VT(&varIn) = VT_ARRAY | VT_HANDLE;
  2293. V_ARRAY(&varIn) = psa;
  2294. if ( SafeArrayPutElement(psa, &lArg, &_hDevNames) != S_OK
  2295. || SafeArrayPutElement(psa, &(++lArg), &_hDevMode) != S_OK )
  2296. {
  2297. goto Cleanup;
  2298. }
  2299. //
  2300. // Actually make the call, passing our handles to the browse instance
  2301. //
  2302. pioct->Exec( &CGID_MSHTML,
  2303. IDM_SETPRINTHANDLES,
  2304. NULL,
  2305. &varIn,
  2306. NULL);
  2307. Cleanup:
  2308. VariantClear(&varIn); // Destroys SAFEARRAY.
  2309. VariantClear(&varHost);
  2310. ReleaseInterface(pioct);
  2311. return;
  2312. }
  2313. //+----------------------------------------------------------------------------
  2314. //
  2315. // Member : CTemplatePrinter::GetDialogArgument
  2316. //
  2317. // Synopsis : The dialogArgument on the attached print template has several important expandos.
  2318. // This function gets the dialogArguments and caches a ptr to it.
  2319. //
  2320. // Returens: S_OK: dlgArgs saved
  2321. // E_*: Error encounterd
  2322. //
  2323. //-----------------------------------------------------------------------------
  2324. HRESULT
  2325. CTemplatePrinter::GetDialogArguments()
  2326. {
  2327. HRESULT hr;
  2328. IHTMLElement *pElement = NULL;
  2329. IDispatch *pDispatch = NULL;
  2330. IServiceProvider *pIDocSrvProv = NULL;
  2331. IHTMLDialog *pIHTMLDialog = NULL;
  2332. VARIANT varDlgArgs;
  2333. Assert(_pPeerSite);
  2334. VariantInit(&varDlgArgs);
  2335. hr = _pPeerSite->GetElement(&pElement);
  2336. if (hr)
  2337. goto Cleanup;
  2338. Assert(pElement);
  2339. hr = pElement->get_document(&pDispatch);
  2340. if (hr)
  2341. goto Cleanup;
  2342. Assert(pDispatch);
  2343. hr = pDispatch->QueryInterface(IID_IServiceProvider, (void **)&pIDocSrvProv);
  2344. if (FAILED(hr))
  2345. goto Cleanup;
  2346. Assert(pIDocSrvProv);
  2347. hr = pIDocSrvProv->QueryService(IID_IHTMLDialog, IID_IHTMLDialog, (void**)&pIHTMLDialog);
  2348. if (FAILED(hr))
  2349. goto Cleanup;
  2350. Assert(pIHTMLDialog);
  2351. hr = pIHTMLDialog->get_dialogArguments(&varDlgArgs);
  2352. if (hr)
  2353. goto Cleanup;
  2354. if ( V_VT(&varDlgArgs) != VT_UNKNOWN
  2355. || !V_UNKNOWN(&varDlgArgs) )
  2356. {
  2357. hr = E_FAIL; // Major badness. This MUST be there.
  2358. goto Cleanup;
  2359. }
  2360. hr = V_UNKNOWN(&varDlgArgs)->QueryInterface(IID_IHTMLEventObj2, (void**)&_pevDlgArgs);
  2361. if (hr)
  2362. goto Cleanup;
  2363. Assert(_pevDlgArgs);
  2364. Cleanup:
  2365. ReleaseInterface(pElement);
  2366. ReleaseInterface(pDispatch);
  2367. ReleaseInterface(pIDocSrvProv);
  2368. ReleaseInterface(pIHTMLDialog);
  2369. VariantClear(&varDlgArgs);
  2370. return hr;
  2371. }
  2372. //+----------------------------------------------------------------------------
  2373. //
  2374. // Member : CTemplatePrinter::GetDialogArgument
  2375. //
  2376. // Synopsis : The dialogArgument on the attached print template has several important expandos.
  2377. // Function gets the expando specified by the argument enum
  2378. //
  2379. // Returens: S_OK: expando obtained (might be VT_NULL or VT_EMPTY)
  2380. // E_*: Error encounterd
  2381. //
  2382. //-----------------------------------------------------------------------------
  2383. HRESULT
  2384. CTemplatePrinter::GetDialogArgument(VARIANT *pvar, PRINTARG eArg)
  2385. {
  2386. HRESULT hr = S_OK;
  2387. BSTR bstrTarget = NULL;
  2388. Assert(pvar);
  2389. Assert(eArg >= 0 && eArg < PRINTTYPE_LAST);
  2390. // (greglett) TODO: Implement a caching system for these args. We access some of
  2391. // often, and shouldn't do the (potentially) cross-thread OLE each time.
  2392. if (!_pevDlgArgs)
  2393. return E_FAIL;
  2394. VariantClear(pvar);
  2395. bstrTarget = SysAllocString(s_aachPrintArg[eArg]);
  2396. if (!bstrTarget)
  2397. {
  2398. hr = E_OUTOFMEMORY;
  2399. goto Cleanup;
  2400. }
  2401. hr = _pevDlgArgs->getAttribute(bstrTarget, 0, pvar);
  2402. Cleanup:
  2403. SysFreeString(bstrTarget);
  2404. return hr;
  2405. }
  2406. //+----------------------------------------------------------------------------
  2407. //
  2408. // Member : CTemplatePrinter::RemoveDialogArgument
  2409. //
  2410. // Synopsis : Remove the dialogArgument specified byt he argument enum.
  2411. //
  2412. // Returens: S_OK: expando obtained (might be VT_NULL or VT_EMPTY)
  2413. // E_*: Error encounterd
  2414. //
  2415. //-----------------------------------------------------------------------------
  2416. HRESULT
  2417. CTemplatePrinter::RemoveDialogArgument(PRINTARG eArg)
  2418. {
  2419. HRESULT hr = S_OK;
  2420. BSTR bstrTarget = NULL;
  2421. VARIANT_BOOL fSuccess;
  2422. Assert(eArg >= 0 && eArg > PRINTTYPE_LAST);
  2423. if (!_pevDlgArgs)
  2424. return E_FAIL;
  2425. bstrTarget = SysAllocString(s_aachPrintArg[eArg]);
  2426. if (!bstrTarget)
  2427. {
  2428. hr = E_OUTOFMEMORY;
  2429. goto Cleanup;
  2430. }
  2431. hr = _pevDlgArgs->removeAttribute(bstrTarget, 0, &fSuccess);
  2432. Cleanup:
  2433. SysFreeString(bstrTarget);
  2434. return hr;
  2435. }
  2436. //+----------------------------------------------------------------------------
  2437. //
  2438. // Member : CTemplatePrinter::EnsureMLLoadLibrary
  2439. //
  2440. // Synopsis : Ensure the library with the default header/footer/margins has
  2441. // been loaded and return it.
  2442. //
  2443. //-----------------------------------------------------------------------------
  2444. HINSTANCE
  2445. CTemplatePrinter::EnsureMLLoadLibrary()
  2446. {
  2447. if (!_hInstResource)
  2448. {
  2449. _hInstResource = MLLoadLibrary(_T("shdoclc.dll"), NULL, ML_CROSSCODEPAGE);
  2450. Assert(_hInstResource && "Resource DLL is not loaded!");
  2451. }
  2452. return _hInstResource;
  2453. }
  2454. //+----------------------------------------------------------------------
  2455. //
  2456. // Function: CTemplatePrinter::GetDefaultMargin
  2457. //
  2458. // Purpose: Get default values for the margin from
  2459. // (1) The registry
  2460. // (2) The resource DLL
  2461. // (3) Arbitrary, hard-coded values.
  2462. //
  2463. // Parameters keyOldValues registry key for the margins or NULL
  2464. // pMarginName "margin_top", "margin_bottom", &c...
  2465. // pMarginValue buffer for value
  2466. // cchMargin length of the buffer in TCHARs
  2467. // dwMarginConst const for getting the margin from the resource file
  2468. //-----------------------------------------------------------------------
  2469. HRESULT
  2470. CTemplatePrinter::GetDefaultMargin(HKEY keyOldValues, TCHAR* pMarginName, TCHAR* pMarginValue, DWORD cchMargin, DWORD dwMarginConst)
  2471. {
  2472. HRESULT hr = E_FAIL;
  2473. DWORD cchLen;
  2474. Assert(pMarginName);
  2475. Assert(pMarginValue);
  2476. Assert(cchMargin > 0);
  2477. // First try the passed registry key.
  2478. if (keyOldValues != NULL)
  2479. {
  2480. hr = ReadSubkeyFromRegistry(keyOldValues, pMarginName, pMarginValue, cchMargin);
  2481. }
  2482. // Next try the resource file.
  2483. if (hr)
  2484. {
  2485. cchLen = ::LoadString(EnsureMLLoadLibrary(), dwMarginConst, pMarginValue, cchMargin);
  2486. if (cchLen > 0)
  2487. hr = ERROR_SUCCESS;
  2488. }
  2489. // Lastly, just do hardcoded values.
  2490. if (hr)
  2491. {
  2492. cchLen = _tcslen(_T("0.750000")) + 1;
  2493. if (cchLen <= cchMargin)
  2494. {
  2495. _tcscpy(pMarginValue,_T("0.750000"));
  2496. hr = ERROR_SUCCESS;
  2497. }
  2498. }
  2499. return hr;
  2500. }
  2501. //+---------------------------------------------------------------------------
  2502. //
  2503. // Member: CTemplatePrinter::GetDefaultHeaderFooter
  2504. //
  2505. // Purpose: Get default values for the header/footer from
  2506. // (1) The registry
  2507. // (2) The resource DLL
  2508. // (3) Arbitrary, hard-coded values.
  2509. //
  2510. // Arguments: keyOldValues If Not Null try to read from the IE3 defaults, If NULL or the read
  2511. // was not successfull, get it from the resources
  2512. // pValueName "header" or "footer"
  2513. // pDefault ptr to the default header or footer
  2514. // cbDefault size of the array to hold the header-footer (in TCHAR)
  2515. // pDefaultLiteral default value if there is no def. in resources
  2516. //
  2517. // Returns : None
  2518. //
  2519. //----------------------------------------------------------------------------
  2520. HRESULT
  2521. CTemplatePrinter::GetDefaultHeaderFooter(HKEY keyOldValues,
  2522. TCHAR* pValueName,
  2523. TCHAR* pDefault,
  2524. DWORD cchDefault,
  2525. DWORD dwResourceID,
  2526. TCHAR* pDefaultLiteral)
  2527. {
  2528. HRESULT hr = E_FAIL;
  2529. Assert(pValueName);
  2530. Assert(pDefault);
  2531. Assert(pDefaultLiteral);
  2532. Assert(cchDefault > 0);
  2533. // Try registry for a left/right header/footer first.
  2534. if (keyOldValues != NULL)
  2535. {
  2536. TCHAR achName[32];
  2537. TCHAR achLeft [MAX_DEFAULTHEADFOOT] = _T("");
  2538. TCHAR achRight[MAX_DEFAULTHEADFOOT] = _T("");
  2539. TCHAR achSeparator[3] = _T("&b");
  2540. DWORD cchTotal = 0;
  2541. _tcscpy(achName,pValueName);
  2542. _tcscat(achName,_T("_left"));
  2543. if (!ReadSubkeyFromRegistry(keyOldValues, achName, achLeft, MAX_DEFAULTHEADFOOT))
  2544. cchTotal += _tcslen(achLeft);
  2545. _tcscpy(achName,pValueName);
  2546. _tcscat(achName,_T("_right"));
  2547. if (!ReadSubkeyFromRegistry(keyOldValues, achName, achRight, MAX_DEFAULTHEADFOOT))
  2548. cchTotal += _tcslen(achRight);
  2549. if (cchTotal)
  2550. {
  2551. // Include the null - add it in.
  2552. cchTotal += _tcslen(achSeparator) + 1;
  2553. if (cchTotal <= cchDefault)
  2554. {
  2555. _tcscpy(pDefault,achLeft);
  2556. _tcscat(pDefault,achSeparator);
  2557. _tcscat(pDefault,achRight);
  2558. hr = ERROR_SUCCESS;
  2559. }
  2560. }
  2561. }
  2562. // Concatenate the left/right if it exists and return it.
  2563. if (hr)
  2564. {
  2565. DWORD cchLen;
  2566. cchLen = ::LoadString(EnsureMLLoadLibrary(), dwResourceID, pDefault, cchDefault);
  2567. if (cchLen > 0)
  2568. hr = ERROR_SUCCESS;
  2569. }
  2570. // Otherwise, use the passed default value.
  2571. if (hr)
  2572. {
  2573. if (_tcslen(pDefaultLiteral) + 1 <= cchDefault)
  2574. {
  2575. _tcscpy(pDefault, pDefaultLiteral);
  2576. hr = ERROR_SUCCESS;
  2577. }
  2578. }
  2579. return hr;
  2580. }
  2581. //+---------------------------------------------------------------------------
  2582. //
  2583. // Member: CTemplatePrinter::GetDefaultPageSetupValues
  2584. //
  2585. // Synopsis: Try to get the old page setup values from HKEY_LOCAL_MACHINE. If found copies them into
  2586. // HKEY_CURRENT_USER, if not, copies the default values
  2587. //
  2588. // Arguments: None
  2589. //
  2590. // Returns : S_OK or E_FAIL
  2591. //
  2592. // Summary : ---
  2593. //
  2594. //----------------------------------------------------------------------------
  2595. HRESULT
  2596. CTemplatePrinter::GetDefaultPageSetupValues(HKEY keyExplorer,HKEY * pKeyPrintOptions)
  2597. {
  2598. TCHAR achDefaultHeader[MAX_DEFAULTHEADFOOT];
  2599. TCHAR achDefaultFooter[MAX_DEFAULTHEADFOOT];
  2600. TCHAR achDefaultMarginTop [MAX_MARGINLENGTH];
  2601. TCHAR achDefaultMarginBottom [MAX_MARGINLENGTH];
  2602. TCHAR achDefaultMarginLeft [MAX_MARGINLENGTH];
  2603. TCHAR achDefaultMarginRight [MAX_MARGINLENGTH];
  2604. HKEY keyOldValues;
  2605. HRESULT hr = S_OK;
  2606. if (!pKeyPrintOptions)
  2607. {
  2608. hr = E_POINTER;
  2609. goto Cleanup;
  2610. }
  2611. // Check the default machine registry values
  2612. if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2613. _T("Software\\Microsoft\\Internet Explorer\\PageSetup"),0,
  2614. KEY_ALL_ACCESS,
  2615. &keyOldValues) != ERROR_SUCCESS)
  2616. {
  2617. keyOldValues = NULL;
  2618. }
  2619. GetDefaultHeaderFooter(keyOldValues, _T("header"), (TCHAR*)&achDefaultHeader, MAX_DEFAULTHEADFOOT, IDS_DEFAULTHEADER, _T("&w&bPage &p of &P"));
  2620. GetDefaultHeaderFooter(keyOldValues, _T("footer"), (TCHAR*)&achDefaultFooter, MAX_DEFAULTHEADFOOT, IDS_DEFAULTFOOTER, _T("&u&b&d"));
  2621. GetDefaultMargin(keyOldValues, _T("margin_bottom"), (TCHAR*)&achDefaultMarginBottom, MAX_MARGINLENGTH, IDS_DEFAULTMARGINBOTTOM);
  2622. GetDefaultMargin(keyOldValues, _T("margin_top"), (TCHAR*)&achDefaultMarginTop, MAX_MARGINLENGTH, IDS_DEFAULTMARGINTOP);
  2623. GetDefaultMargin(keyOldValues, _T("margin_left"), (TCHAR*)&achDefaultMarginLeft, MAX_MARGINLENGTH, IDS_DEFAULTMARGINLEFT);
  2624. GetDefaultMargin(keyOldValues, _T("margin_right"), (TCHAR*)&achDefaultMarginRight, MAX_MARGINLENGTH, IDS_DEFAULTMARGINRIGHT);
  2625. ::RegCloseKey(keyOldValues);
  2626. keyOldValues = NULL;
  2627. // Create the new user registry key
  2628. if (::RegCreateKeyEx(keyExplorer,
  2629. _T("PageSetup"),
  2630. 0,
  2631. NULL,
  2632. REG_OPTION_NON_VOLATILE,
  2633. KEY_ALL_ACCESS,
  2634. NULL,
  2635. pKeyPrintOptions,
  2636. NULL) == ERROR_SUCCESS)
  2637. {
  2638. // Put our default values into registry keys.
  2639. WriteSubkeyToRegistry(*pKeyPrintOptions, _T("header"), achDefaultHeader);
  2640. WriteSubkeyToRegistry(*pKeyPrintOptions, _T("footer"), achDefaultFooter);
  2641. WriteSubkeyToRegistry(*pKeyPrintOptions, _T("margin_bottom"), achDefaultMarginBottom);
  2642. WriteSubkeyToRegistry(*pKeyPrintOptions, _T("margin_left"), achDefaultMarginLeft);
  2643. WriteSubkeyToRegistry(*pKeyPrintOptions, _T("margin_right"), achDefaultMarginRight);
  2644. WriteSubkeyToRegistry(*pKeyPrintOptions, _T("margin_top"), achDefaultMarginTop);
  2645. };
  2646. Cleanup:
  2647. return hr;
  2648. }
  2649. //+---------------------------------------------------------------------------
  2650. //
  2651. // Member: CTemplatePrinter::GetRegPrintOptionsKey
  2652. //
  2653. // Synopsis: Get handle of requested key under \HKCU\Software\Microsoft\Internet Explorer
  2654. //
  2655. // Arguments: PrintSubKey - subkey of printoptions root to return key for
  2656. // pKeyPrintOptions - ptr to handle of requested key in registry
  2657. //
  2658. // Returns : S_OK or E_FAIL
  2659. //
  2660. // Summary : First it tries to get the values from "new place"
  2661. // HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\PageSetup
  2662. // If there is no such a key, it creates it and tries to get the values from "old place"
  2663. // HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\PageSetup
  2664. // If successful it copies the values into the "new place"
  2665. // If not, it tries to get the values from the registry,
  2666. // If no luck, it uses the hardcoded strings
  2667. // NOTE : If the procedure returns with S_OK, it guaranties that they will be a
  2668. // "new place" with values.
  2669. //
  2670. //----------------------------------------------------------------------------
  2671. HRESULT
  2672. CTemplatePrinter::GetRegPrintOptionsKey(PRINTOPTIONS_SUBKEY PrintSubKey, HKEY * pKeyPrintOptions)
  2673. {
  2674. HKEY keyExplorer;
  2675. HRESULT hr = E_FAIL;
  2676. if (RegOpenKeyEx(
  2677. HKEY_CURRENT_USER,
  2678. _T("Software\\Microsoft\\Internet Explorer"),
  2679. 0,
  2680. KEY_ALL_ACCESS,
  2681. &keyExplorer) == ERROR_SUCCESS)
  2682. {
  2683. LPTSTR szSubKey = (PrintSubKey == PRINTOPTSUBKEY_MAIN
  2684. ? _T("Main")
  2685. : _T("PageSetup"));
  2686. if (RegOpenKeyEx(keyExplorer,
  2687. szSubKey,
  2688. 0,
  2689. KEY_ALL_ACCESS,
  2690. pKeyPrintOptions) == ERROR_SUCCESS)
  2691. {
  2692. if (PrintSubKey == PRINTOPTSUBKEY_PAGESETUP)
  2693. {
  2694. //
  2695. // For the PageSetup key, we do some additional checks to make
  2696. // sure that (at least) the header and footer keys exist.
  2697. //
  2698. DWORD dwT;
  2699. if ( (RegQueryValueEx(*pKeyPrintOptions, _T("header"), 0, NULL, NULL, &dwT) == ERROR_SUCCESS)
  2700. && (RegQueryValueEx(*pKeyPrintOptions, _T("footer"), 0, NULL, NULL, &dwT) == ERROR_SUCCESS))
  2701. {
  2702. // the header and footer keys exist, we're fine
  2703. hr = S_OK;
  2704. }
  2705. else
  2706. {
  2707. // whoops. fall back...
  2708. hr = GetDefaultPageSetupValues(keyExplorer, pKeyPrintOptions);
  2709. }
  2710. }
  2711. else
  2712. hr = S_OK;
  2713. }
  2714. else
  2715. {
  2716. // For page setup, if we don't have default values, create them.
  2717. if (PrintSubKey == PRINTOPTSUBKEY_PAGESETUP)
  2718. {
  2719. hr = GetDefaultPageSetupValues(keyExplorer, pKeyPrintOptions);
  2720. }
  2721. }
  2722. RegCloseKey(keyExplorer);
  2723. }
  2724. return hr;
  2725. }
  2726. //+----------------------------------------------------------------------------
  2727. //
  2728. // Member : CTemplatePrinter::ReadBoolFromRegistry
  2729. //
  2730. // Synopsis : Takes an open registry key and subkey name, and returns the
  2731. // value as a boolean.
  2732. //
  2733. //-----------------------------------------------------------------------------
  2734. BOOL
  2735. CTemplatePrinter::ReadBoolFromRegistry(HKEY hKey, TCHAR *pSubkeyName)
  2736. {
  2737. TCHAR achBool[MAX_DEFAULTBOOL];
  2738. BOOL fRet = FALSE;
  2739. achBool[0] = '\0';
  2740. if (!ReadSubkeyFromRegistry(hKey, pSubkeyName, achBool, MAX_DEFAULTBOOL))
  2741. {
  2742. fRet = !_tcsicmp(achBool, _T("yes"));
  2743. }
  2744. return fRet;
  2745. }
  2746. //+----------------------------------------------------------------------------
  2747. //
  2748. // Member : CTemplatePrinter::AreRatingsEnabled
  2749. //
  2750. // Synopsis : Checks MS_RATING.DLL to see if ratings are enabled.
  2751. //
  2752. //-----------------------------------------------------------------------------
  2753. BOOL
  2754. CTemplatePrinter::AreRatingsEnabled()
  2755. {
  2756. BOOL fRet = FALSE;
  2757. typedef HRESULT (STDAPICALLTYPE *PFN)(void);
  2758. if (!_hInstRatings)
  2759. LoadLibrary("MSRATING.DLL", &_hInstRatings);
  2760. if (_hInstRatings)
  2761. {
  2762. PFN pfn;
  2763. pfn = (PFN) ::GetProcAddress(_hInstRatings, "RatingEnabledQuery");
  2764. if (!pfn)
  2765. {
  2766. goto Cleanup;
  2767. }
  2768. fRet = !pfn() ? TRUE: FALSE;
  2769. }
  2770. Cleanup:
  2771. return fRet;
  2772. }
  2773. //+----------------------------------------------------------------------------
  2774. //
  2775. // Member : CTemplatePrinter::DecimalTCHARToMargin
  2776. //
  2777. // Synopsis : Takes a decimal representation in 1" and returns a long
  2778. // with that value in 1/100000"
  2779. //
  2780. //-----------------------------------------------------------------------------
  2781. long
  2782. CTemplatePrinter::DecimalTCHARToFixed(TCHAR* pString, int nPowersOfTen)
  2783. {
  2784. TCHAR* p = pString;
  2785. int iLen = _tcslen(pString);
  2786. int i;
  2787. int j = 0;
  2788. int iChar = 0;
  2789. long nRet = 0;
  2790. if (pString == NULL)
  2791. goto Cleanup;
  2792. // Clear leading whitespace
  2793. for (i=0;i<iLen;i++,p++)
  2794. if (*p != _T(' '))
  2795. break;
  2796. // Do the integer part
  2797. for (;i<iLen;i++,p++)
  2798. {
  2799. iChar = *p;
  2800. if ((iChar < _T('0')) || (iChar > _T('9')))
  2801. break;
  2802. nRet = nRet * 10 + (iChar - _T('0'));
  2803. }
  2804. if (iChar == _T('.'))
  2805. {
  2806. // Do the decimal part.
  2807. for (i++,p++; (i+j<iLen && j<5); j++,p++)
  2808. {
  2809. iChar = *p;
  2810. if ((iChar < _T('0')) || (iChar > _T('9')))
  2811. break;
  2812. nRet = nRet * 10 + (iChar - _T('0'));
  2813. }
  2814. }
  2815. // Make sure we are in 1/100000"
  2816. for (;j < nPowersOfTen; j++)
  2817. nRet *= 10;
  2818. Cleanup:
  2819. return nRet;
  2820. }
  2821. BOOL
  2822. CTemplatePrinter::CommCtrlNativeFontSupport()
  2823. {
  2824. BOOL fRet = FALSE;
  2825. typedef BOOL (APIENTRY *PFN)(LPINITCOMMONCONTROLSEX);
  2826. if (!_hInstComctl32)
  2827. LoadLibrary("COMCTL32.DLL", &_hInstComctl32);
  2828. if (_hInstComctl32)
  2829. {
  2830. INITCOMMONCONTROLSEX icc;
  2831. PFN pfn;
  2832. pfn = (PFN) ::GetProcAddress(_hInstComctl32, "InitCommonControlsEx");
  2833. if (!pfn)
  2834. {
  2835. goto Cleanup;
  2836. }
  2837. icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
  2838. icc.dwICC = ICC_NATIVEFNTCTL_CLASS;
  2839. fRet = pfn(&icc);
  2840. }
  2841. Cleanup:
  2842. return fRet;
  2843. }
  2844. //+----------------------------------------------------------------------------
  2845. //
  2846. // Member : CTemplatePrinter::WriteFixedToRegistry
  2847. //
  2848. // Synopsis : Takes an open registry key and subkey name, and writes the
  2849. // passed value to the resulting registry key in whole units.
  2850. //
  2851. //-----------------------------------------------------------------------------
  2852. HRESULT
  2853. CTemplatePrinter::WriteFixedToRegistry(HKEY hKeyPS, const TCHAR* pValueName,LONG nMargin, int nFactor)
  2854. {
  2855. TCHAR achFixed[MAX_MARGINLENGTH];
  2856. // Convert 1/100000" units to a TCHAR representation of decimal in 1" units.
  2857. FixedToDecimalTCHAR(nMargin, achFixed, nFactor);
  2858. return WriteSubkeyToRegistry(hKeyPS, pValueName, achFixed);
  2859. }
  2860. //+----------------------------------------------------------------------------
  2861. //
  2862. // Member : CTemplatePrinter::ReadFixedFromRegistry
  2863. //
  2864. // Synopsis : Takes an open registry key and subkey name, and gets a fixed point value
  2865. //
  2866. //-----------------------------------------------------------------------------
  2867. HRESULT
  2868. CTemplatePrinter::ReadFixedFromRegistry(HKEY hKeyPS, const TCHAR *pValueName, LONG *pFixed, int nPowersOfTen)
  2869. {
  2870. HRESULT hr;
  2871. TCHAR achFixed[MAX_MARGINLENGTH];
  2872. achFixed[0] = '\0';
  2873. Assert(pValueName);
  2874. Assert(pFixed);
  2875. *pFixed = 0;
  2876. hr = ReadSubkeyFromRegistry(hKeyPS, pValueName, achFixed, MAX_MARGINLENGTH);
  2877. if (!hr)
  2878. *pFixed = DecimalTCHARToFixed(achFixed, nPowersOfTen);
  2879. return hr;
  2880. }
  2881. //+----------------------------------------------------------------------------
  2882. //
  2883. // Member : CTemplatePrinter::ReadDeviceUnicode
  2884. //
  2885. // Synopsis : Creates device information given the printer name,
  2886. //
  2887. //-----------------------------------------------------------------------------
  2888. HRESULT
  2889. CTemplatePrinter::ReadDeviceUnicode(TCHAR *pchPrinter, TCHAR *pchDriver, TCHAR *pchPort)
  2890. {
  2891. HRESULT hr = S_OK;
  2892. HANDLE hPrinter = NULL;
  2893. PRINTER_INFO_2 * pPrintInfo = NULL;
  2894. Assert(pchPrinter);
  2895. if ( ::OpenPrinter(pchPrinter, &hPrinter, NULL)
  2896. && hPrinter)
  2897. {
  2898. DWORD nStructSize;
  2899. if (!pchDriver || !pchPort)
  2900. {
  2901. ::GetPrinter(hPrinter, 2, NULL, 0, &nStructSize);
  2902. pPrintInfo = (PRINTER_INFO_2 *) ::GlobalAlloc(GPTR, nStructSize);
  2903. if (!pPrintInfo)
  2904. {
  2905. hr = E_OUTOFMEMORY;
  2906. goto Cleanup;
  2907. }
  2908. if (!::GetPrinter(hPrinter, 2, (byte *)pPrintInfo, nStructSize, &nStructSize))
  2909. {
  2910. hr = E_FAIL;
  2911. goto Cleanup;
  2912. }
  2913. }
  2914. hr = CreateDevNames(pchDriver ? pchDriver : pPrintInfo->pDriverName,
  2915. pchPrinter,
  2916. pchPort ? pchPort : pPrintInfo->pPortName,
  2917. &_hDevNames);
  2918. if (hr)
  2919. goto Cleanup;
  2920. nStructSize = ::DocumentProperties(0, hPrinter, pchPrinter, NULL, NULL, 0);
  2921. if (nStructSize < sizeof(DEVMODE))
  2922. {
  2923. Assert(!"Memory size suggested by DocumentProperties is smaller than DEVMODE");
  2924. nStructSize = sizeof(DEVMODE);
  2925. }
  2926. _hDevMode = ::GlobalAlloc(GHND, nStructSize);
  2927. if (_hDevMode)
  2928. {
  2929. DEVMODE *pDevMode = (DEVMODE *) ::GlobalLock(_hDevMode);
  2930. if (pDevMode)
  2931. {
  2932. ::DocumentProperties(0, hPrinter, pchPrinter, pDevMode, NULL, DM_OUT_BUFFER);
  2933. pDevMode->dmFields &= ~DM_COLLATE;
  2934. pDevMode->dmCollate = DMCOLLATE_FALSE;
  2935. ::GlobalUnlock(_hDevMode);
  2936. }
  2937. else
  2938. {
  2939. ::GlobalFree(_hDevMode);
  2940. _hDevMode = NULL;
  2941. }
  2942. }
  2943. }
  2944. Cleanup:
  2945. if (hPrinter)
  2946. ::ClosePrinter(hPrinter);
  2947. if (pPrintInfo)
  2948. ::GlobalFree(pPrintInfo);
  2949. return hr;
  2950. }
  2951. //+----------------------------------------------------------------------------
  2952. //
  2953. // Member : CTemplatePrinter::ReadDeviceNonUnicode
  2954. //
  2955. // Synopsys : Because non-Unicode platforms (Win9x) don't properly implement
  2956. // many of the printing widechar calls, they need to explicitly
  2957. // make multibyte (A) calls.
  2958. //
  2959. //+----------------------------------------------------------------------------
  2960. HRESULT
  2961. CTemplatePrinter::ReadDeviceNonUnicode(TCHAR *pchPrinterWide, TCHAR *pchDriverWide, TCHAR *pchPortWide)
  2962. {
  2963. HRESULT hr = S_OK;
  2964. HANDLE hPrinter = NULL;
  2965. LPSTR pchPrinter = NULL;
  2966. TCHAR * pchDriverWideLocal = NULL;
  2967. TCHAR * pchPortWideLocal = NULL;
  2968. PRINTER_INFO_2A * pPrintInfo = NULL;
  2969. Assert(pchPrinterWide);
  2970. pchPrinter = InitMultiByteFromWideChar(pchPrinterWide);
  2971. if (!pchPrinter)
  2972. {
  2973. hr = E_FAIL;
  2974. goto Cleanup;
  2975. }
  2976. if ( ::OpenPrinterA(pchPrinter, &hPrinter, NULL)
  2977. && hPrinter )
  2978. {
  2979. DWORD nStructSize;
  2980. if (!pchDriverWide || !pchPortWide)
  2981. {
  2982. ::GetPrinterA(hPrinter, 2, NULL, 0, &nStructSize);
  2983. pPrintInfo = (PRINTER_INFO_2A *)::GlobalAlloc(GPTR, nStructSize);
  2984. if (!pPrintInfo)
  2985. {
  2986. hr = E_OUTOFMEMORY;
  2987. goto Cleanup;
  2988. }
  2989. if (!::GetPrinterA(hPrinter, 2, (byte *)pPrintInfo, nStructSize, &nStructSize))
  2990. {
  2991. hr = E_FAIL;
  2992. goto Cleanup;
  2993. }
  2994. pchDriverWideLocal = InitWideCharFromMultiByte(pPrintInfo->pDriverName);
  2995. pchPortWideLocal = InitWideCharFromMultiByte(pPrintInfo->pPortName);
  2996. }
  2997. hr = CreateDevNames(pchDriverWide ? pchDriverWide : pchDriverWideLocal,
  2998. pchPrinterWide,
  2999. pchPortWide ? pchPortWide : pchPortWideLocal,
  3000. &_hDevNames);
  3001. if (hr)
  3002. goto Cleanup;
  3003. // NB (105850) (mikhaill) -- Windows Millennium's routine DocumentPropertiesA()
  3004. // impudently changes processor state. This happens just once after
  3005. // reboot and cause, in particular, unmasking floating point exception flags.
  3006. // At some later moment processor meet any suspicious condition (overflow,
  3007. // underflow, zero-divide, precision loose, etc) in some innocent routine,
  3008. // generates unhandled exception and eventually crashes.
  3009. // The following fsave/frstor pair is an ugly patch that should be removed
  3010. // after millennium bug fix.
  3011. // Windows Millennium build versions tested: 4.90.2485, 4.90.2491.
  3012. #ifdef _M_IX86
  3013. {
  3014. FLOATING_SAVE_AREA fsa;
  3015. _asm fsave fsa;
  3016. #endif //_M_IX86
  3017. nStructSize = ::DocumentPropertiesA(0, hPrinter, pchPrinter, NULL, NULL, 0);
  3018. #ifdef _M_IX86
  3019. _asm frstor fsa;
  3020. }
  3021. #endif //_M_IX86
  3022. if (nStructSize < sizeof(DEVMODEA))
  3023. {
  3024. Assert(!"Memory size suggested by DocumentProperties is smaller than DEVMODEA");
  3025. nStructSize = sizeof(DEVMODEA);
  3026. }
  3027. _hDevMode = ::GlobalAlloc(GHND, nStructSize);
  3028. if (_hDevMode)
  3029. {
  3030. DEVMODEA *pDevMode = (DEVMODEA *) ::GlobalLock(_hDevMode);
  3031. if (pDevMode)
  3032. {
  3033. // NB (109499) same as 105850 above
  3034. // but appeared in Windows98 (mikhaill 5/7/00)
  3035. #ifdef _M_IX86
  3036. {
  3037. FLOATING_SAVE_AREA fsa;
  3038. _asm fsave fsa;
  3039. #endif //_M_IX86
  3040. ::DocumentPropertiesA(0, hPrinter, pchPrinter, pDevMode, NULL, DM_OUT_BUFFER);
  3041. #ifdef _M_IX86
  3042. _asm frstor fsa;
  3043. }
  3044. #endif //_M_IX86
  3045. pDevMode->dmFields &= ~DM_COLLATE;
  3046. pDevMode->dmCollate = DMCOLLATE_FALSE;
  3047. ::GlobalUnlock(_hDevMode);
  3048. }
  3049. else
  3050. {
  3051. ::GlobalFree(_hDevMode);
  3052. _hDevMode = NULL;
  3053. }
  3054. }
  3055. }
  3056. Cleanup:
  3057. if (hPrinter)
  3058. ::ClosePrinter(hPrinter);
  3059. if (pPrintInfo)
  3060. ::GlobalFree(pPrintInfo);
  3061. if (pchPrinter)
  3062. delete []pchPrinter;
  3063. if (pchDriverWideLocal)
  3064. delete []pchDriverWideLocal;
  3065. if (pchPortWideLocal)
  3066. delete []pchPortWideLocal;
  3067. return hr;
  3068. }
  3069. //+-----------------------------------------------------------------------------
  3070. //
  3071. // Member: CTemplatePrinter::GetDeviceProperties
  3072. //
  3073. // Synopsis : Gets the relevant physical properties of the device currently specified
  3074. // in _hDevNames and _hDevMode
  3075. //
  3076. //------------------------------------------------------------------------------
  3077. HRESULT
  3078. CTemplatePrinter::GetDeviceProperties()
  3079. {
  3080. IHTMLElementRender *pRender = NULL;
  3081. IHTMLElement *pElement = NULL;
  3082. BSTR bstrPrinter = NULL;
  3083. HRESULT hr = E_FAIL;
  3084. if (_hDevNames && _hDevMode)
  3085. {
  3086. DEVNAMES *pDevNames = ((DEVNAMES *)::GlobalLock(_hDevNames));
  3087. void *pDevMode = ::GlobalLock(_hDevMode);
  3088. if (pDevNames && pDevMode)
  3089. {
  3090. HDC hDC = NULL;
  3091. // (greglett) Non-Unicode badness. See comment at definition of _hDevMode
  3092. if (g_fUnicodePlatform)
  3093. {
  3094. hDC = ::CreateICW(((TCHAR *)pDevNames) + pDevNames->wDriverOffset,
  3095. ((TCHAR *)pDevNames) + pDevNames->wDeviceOffset,
  3096. NULL,
  3097. (DEVMODEW *)pDevMode);
  3098. }
  3099. else
  3100. {
  3101. LPSTR pchDriver = InitMultiByteFromWideChar(((TCHAR *)pDevNames) + pDevNames->wDriverOffset);
  3102. LPSTR pchDevice = InitMultiByteFromWideChar(((TCHAR *)pDevNames) + pDevNames->wDeviceOffset);
  3103. if (pchDriver && pchDevice)
  3104. {
  3105. hDC = ::CreateICA(pchDriver,
  3106. pchDevice,
  3107. NULL,
  3108. (DEVMODEA *)pDevMode);
  3109. }
  3110. if (pchDriver)
  3111. delete []pchDriver;
  3112. if (pchDevice)
  3113. delete []pchDevice;
  3114. }
  3115. if (hDC)
  3116. {
  3117. SIZE szPage;
  3118. // Obtain the resolution and unprintable areas for this device.
  3119. _szResolution.cx = ::GetDeviceCaps(hDC, LOGPIXELSX);
  3120. _szResolution.cy = ::GetDeviceCaps(hDC, LOGPIXELSY);
  3121. szPage.cx = ::GetDeviceCaps(hDC, PHYSICALWIDTH);
  3122. szPage.cy = ::GetDeviceCaps(hDC, PHYSICALHEIGHT);
  3123. _rcUnprintable.left = ::GetDeviceCaps(hDC, PHYSICALOFFSETX);
  3124. _rcUnprintable.top = ::GetDeviceCaps(hDC, PHYSICALOFFSETY);
  3125. _rcUnprintable.right = szPage.cx - ::GetDeviceCaps(hDC, HORZRES) - _rcUnprintable.left;
  3126. _rcUnprintable.bottom = szPage.cy - ::GetDeviceCaps(hDC, VERTRES) - _rcUnprintable.top;
  3127. Assert(_rcUnprintable.right >= 0);
  3128. Assert(_rcUnprintable.bottom >= 0);
  3129. _ptPaperSize.x = (_szResolution.cx)
  3130. ? MulDivQuick(szPage.cx, 1000, _szResolution.cx)
  3131. : 8500;
  3132. _ptPaperSize.y = (_szResolution.cy)
  3133. ? MulDivQuick(szPage.cy, 1000, _szResolution.cy)
  3134. : 11000;
  3135. hr = _pPeerSite->GetElement(&pElement);
  3136. if (!hr)
  3137. {
  3138. Assert(pElement);
  3139. hr = pElement->QueryInterface(IID_IHTMLElementRender, (void **)&pRender);
  3140. if (!hr)
  3141. {
  3142. Assert(pRender);
  3143. bstrPrinter = ::SysAllocString(((TCHAR *)pDevNames) + pDevNames->wDeviceOffset);
  3144. if (bstrPrinter)
  3145. pRender->SetDocumentPrinter(bstrPrinter,hDC);
  3146. else
  3147. hr = E_OUTOFMEMORY;
  3148. }
  3149. }
  3150. ::DeleteDC(hDC);
  3151. }
  3152. }
  3153. ::GlobalUnlock(_hDevNames);
  3154. ::GlobalUnlock(_hDevMode);
  3155. hr = S_OK;
  3156. }
  3157. ReleaseInterface(pElement);
  3158. ReleaseInterface(pRender);
  3159. if (bstrPrinter)
  3160. ::SysFreeString(bstrPrinter);
  3161. return hr;
  3162. }
  3163. HRESULT
  3164. CTemplatePrinter::CreateIPrintParams(DVTARGETDEVICE **ppTargetDevice, PAGESET **ppPageSet)
  3165. {
  3166. HRESULT hr = S_OK;
  3167. DWORD nStructSize;
  3168. Assert(ppTargetDevice && ppPageSet);
  3169. (*ppTargetDevice) = NULL;
  3170. (*ppPageSet) = NULL;
  3171. // Create a PAGESET.
  3172. (*ppPageSet) = (PAGESET *)::CoTaskMemAlloc(sizeof(PAGESET));
  3173. if (!(*ppPageSet))
  3174. {
  3175. hr = E_OUTOFMEMORY;
  3176. goto Cleanup;
  3177. }
  3178. ::ZeroMemory(*ppPageSet, sizeof(PAGESET));
  3179. (*ppPageSet)->cbStruct = sizeof(PAGESET) ;
  3180. (*ppPageSet)->cPageRange = 1;
  3181. if (_fPrintSelectedPages)
  3182. {
  3183. (*ppPageSet)->rgPages[0].nFromPage = _nPageFrom;
  3184. (*ppPageSet)->rgPages[0].nToPage = _nPageTo;
  3185. }
  3186. else
  3187. {
  3188. (*ppPageSet)->rgPages[0].nFromPage = 1;
  3189. (*ppPageSet)->rgPages[0].nToPage = PAGESET_TOLASTPAGE;
  3190. }
  3191. (*ppTargetDevice) = InitTargetDevice();
  3192. if (!(*ppTargetDevice))
  3193. {
  3194. // Error! Clear the PageSet structure.
  3195. ::CoTaskMemFree(*ppPageSet);
  3196. (*ppPageSet) = NULL;
  3197. hr = E_FAIL;
  3198. goto Cleanup;
  3199. }
  3200. Cleanup:
  3201. return hr;
  3202. }
  3203. // NB (greglett)
  3204. // Alas, Win9x returns a ASCII DEVMODE and a Unicode DEVNAMES from the dialog functions.
  3205. // The old code avoided converting the second structure, *except* to create a TARGETDEVICE for IPrint objects.
  3206. // Since we will need to do this, I have brought this function over.
  3207. // If this function works *really* well, then maybe we can always convert and get rid of all the explicit calls to
  3208. // ANSI functions above. (CreateICA, CreateDCA, OpenPrinterA, &c...).
  3209. DVTARGETDEVICE *
  3210. DevModeWFromDevModeA( DVTARGETDEVICE *ptd )
  3211. {
  3212. // NOTE: Only the DEVMODE structure is in the wrong (ascii) format!
  3213. DEVMODEA * lpdma = NULL;
  3214. DVTARGETDEVICE * ptdW = NULL;
  3215. if (!ptd || !ptd->tdExtDevmodeOffset)
  3216. goto Cleanup;
  3217. lpdma = (DEVMODEA *) (((BYTE *)ptd) + ptd->tdExtDevmodeOffset);
  3218. // If the reported size is too small for our conception of a DEVMODEA, don't risk a GPF
  3219. // in our code and bail out now.
  3220. if ( (DWORD)lpdma->dmSize + lpdma->dmDriverExtra < offsetof(DEVMODEA, dmLogPixels) )
  3221. goto Cleanup;
  3222. ptdW = (DVTARGETDEVICE *)::CoTaskMemAlloc( ptd->tdSize + (sizeof(BCHAR) - sizeof(char)) * (CCHDEVICENAME + CCHFORMNAME) );
  3223. if (ptdW)
  3224. {
  3225. // Copy the entire structure up to DEVMODE part.
  3226. memcpy(ptdW, ptd, ptd->tdExtDevmodeOffset);
  3227. // Account for the increase of the two DEVMODE unicode strings.
  3228. ptdW->tdSize += (sizeof(BCHAR) - sizeof(char)) * (CCHDEVICENAME + CCHFORMNAME);
  3229. // Convert the devmode structure.
  3230. {
  3231. DEVMODEW * lpdmw = (DEVMODEW *) (((BYTE *)ptdW) + ptdW->tdExtDevmodeOffset);
  3232. long nCapChar;
  3233. // Copy the first string (CCHDEVICENAME).
  3234. // Really, 0 indicates a conversion error. However, we really can't do much about it other than construct a NULL string.
  3235. if (!::MultiByteToWideChar(CP_ACP, 0, (char *)lpdma->dmDeviceName, -1, lpdmw->dmDeviceName, CCHDEVICENAME))
  3236. {
  3237. lpdmw->dmDeviceName[0] = _T('\0');
  3238. }
  3239. // Copy the gap between strings.
  3240. memcpy( &lpdmw->dmSpecVersion,
  3241. &lpdma->dmSpecVersion,
  3242. offsetof(DEVMODEA, dmFormName) -
  3243. offsetof(DEVMODEA, dmSpecVersion) );
  3244. // Copy the first string (CCHDEVICENAME).
  3245. if (!::MultiByteToWideChar(CP_ACP, 0, (char *)lpdma->dmFormName, -1, lpdmw->dmFormName, CCHFORMNAME))
  3246. {
  3247. lpdmw->dmFormName[0] = _T('\0');
  3248. }
  3249. // Copy the last part including the driver-specific DEVMODE part (dmDriverExtra).
  3250. memcpy( &lpdmw->dmLogPixels,
  3251. &lpdma->dmLogPixels,
  3252. (DWORD)lpdma->dmSize + lpdma->dmDriverExtra -
  3253. offsetof(DEVMODEA, dmLogPixels) );
  3254. // Correct the dmSize member by accounting for larger unicode strings.
  3255. lpdmw->dmSize += (sizeof(BCHAR) - sizeof(char)) * (CCHDEVICENAME + CCHFORMNAME);
  3256. }
  3257. }
  3258. Cleanup:
  3259. return ptdW;
  3260. }
  3261. //+----------------------------------------------------------------------
  3262. //
  3263. // Function: InitPrintHandles
  3264. //
  3265. // Purpose: Allocate a DVTARGETDEVICE structure, and initialize
  3266. // it according to the hDevMode and hDevNames.
  3267. // Also allocated an HIC.
  3268. //
  3269. // Note: IMPORTANT: Note that the DEVMODE structure is not wrapped
  3270. // on non-unicode platforms. (See comments below for details.)
  3271. //
  3272. // Returns: HRESULT
  3273. //
  3274. //-----------------------------------------------------------------------
  3275. DVTARGETDEVICE *
  3276. CTemplatePrinter::InitTargetDevice()
  3277. {
  3278. HRESULT hr = S_OK;
  3279. LPDEVNAMES pDN = NULL;
  3280. LPDEVMODE pDM = NULL;
  3281. LPDEVMODEA pDMA = NULL;
  3282. DVTARGETDEVICE * ptd = NULL;
  3283. WORD nMaxOffset;
  3284. DWORD dwDevNamesSize, dwDevModeSize, dwPtdSize;
  3285. int nNameLength;
  3286. if (!_hDevNames || !_hDevMode)
  3287. goto Cleanup;
  3288. pDN = (LPDEVNAMES)::GlobalLock(_hDevNames);
  3289. if (!pDN)
  3290. goto Cleanup;
  3291. if (g_fUnicodePlatform)
  3292. {
  3293. pDM = (LPDEVMODE)::GlobalLock(_hDevMode);
  3294. if (!pDM)
  3295. goto Cleanup;
  3296. }
  3297. else
  3298. {
  3299. pDMA = (LPDEVMODEA)::GlobalLock(_hDevMode);
  3300. if (!pDMA)
  3301. goto Cleanup;
  3302. }
  3303. // IMPORTANT: We have painstakingly
  3304. // converted only the hDevNames parameter and NOT hDevMode (NOT!!!) to have TCHAR
  3305. // members.
  3306. nMaxOffset = max( pDN->wDriverOffset, pDN->wDeviceOffset );
  3307. nMaxOffset = max( nMaxOffset, pDN->wOutputOffset );
  3308. nNameLength = _tcslen( (TCHAR *)pDN + nMaxOffset );
  3309. // dw* are in bytes, not TCHARS
  3310. dwDevNamesSize = sizeof(TCHAR) * ((DWORD)nMaxOffset + nNameLength + 1);
  3311. dwDevModeSize = g_fUnicodePlatform ? ((DWORD)pDM->dmSize + pDM->dmDriverExtra)
  3312. : ((DWORD)pDMA->dmSize + pDMA->dmDriverExtra);
  3313. dwPtdSize = sizeof(DWORD) + dwDevNamesSize + dwDevModeSize;
  3314. ptd = (DVTARGETDEVICE *)::CoTaskMemAlloc(dwPtdSize);
  3315. if (!ptd)
  3316. goto Cleanup;
  3317. else
  3318. {
  3319. ptd->tdSize = dwPtdSize;
  3320. // This is an ugly trick. ptd->tdDriverNameOffset and pDN happen
  3321. // to match up, so we just copy that plus the data in one big chunk.
  3322. // Remember, I didn't write this -- this code is based on the OLE2 SDK.
  3323. // Offsets are in characters, not bytes.
  3324. memcpy( &ptd->tdDriverNameOffset, pDN, dwDevNamesSize );
  3325. ptd->tdDriverNameOffset *= sizeof(TCHAR);
  3326. ptd->tdDriverNameOffset += sizeof(DWORD);
  3327. ptd->tdDeviceNameOffset *= sizeof(TCHAR);
  3328. ptd->tdDeviceNameOffset += sizeof(DWORD);
  3329. ptd->tdPortNameOffset *= sizeof(TCHAR);
  3330. ptd->tdPortNameOffset += sizeof(DWORD);
  3331. // IMPORTANT: We are not converting the DEVMODE structure back and forth
  3332. // from ASCII to Unicode on Win9x anymore because we are not touching the
  3333. // two strings or any other member. Converting the DEVMODE structure can
  3334. // be tricky because of potential and common discrepancies between the
  3335. // value of the dmSize member and sizeof(DEVMODE). (25155)
  3336. if (g_fUnicodePlatform)
  3337. memcpy((BYTE *)&ptd->tdDriverNameOffset + dwDevNamesSize, pDM, dwDevModeSize);
  3338. else
  3339. memcpy((BYTE *)&ptd->tdDriverNameOffset + dwDevNamesSize, pDMA, dwDevModeSize);
  3340. ptd->tdExtDevmodeOffset = USHORT(sizeof(DWORD) + dwDevNamesSize);
  3341. // We must return a corrent (all WCHAR) DVTARGETDEVICEW structure.
  3342. // Convert the nasty DEVMODEA if we've just copied it over.
  3343. if (!g_fUnicodePlatform)
  3344. {
  3345. DVTARGETDEVICE *ptdOld;
  3346. ptdOld = ptd;
  3347. ptd = DevModeWFromDevModeA(ptdOld);
  3348. ::CoTaskMemFree(ptdOld);
  3349. }
  3350. }
  3351. Cleanup:
  3352. if (pDM || pDMA)
  3353. ::GlobalUnlock(_hDevMode);
  3354. if (pDN)
  3355. ::GlobalUnlock(_hDevNames);
  3356. return ptd;
  3357. }
  3358. #ifdef DBG
  3359. //
  3360. // CTemplatePrinter Debug-Only functions
  3361. //
  3362. void
  3363. CTemplatePrinter::VerifyOrientation()
  3364. {
  3365. // Verify that the page size reflects the current orientation bit in the DEVMODE
  3366. // These properties should always be in sync.
  3367. if (_hDevMode)
  3368. {
  3369. void *pDevMode = ::GlobalLock(_hDevMode);
  3370. if (pDevMode)
  3371. {
  3372. BOOL fOrientationValid;
  3373. BOOL fLandscape;
  3374. // (greglett) Non-Unicode badness. See comment at definition of _hDevMode
  3375. if (g_fUnicodePlatform)
  3376. {
  3377. fOrientationValid = !!(((DEVMODEW *)pDevMode)->dmFields & DM_ORIENTATION);
  3378. fLandscape = (((DEVMODEW *)pDevMode)->dmOrientation == DMORIENT_LANDSCAPE);
  3379. }
  3380. else
  3381. {
  3382. fOrientationValid = !!(((DEVMODEA *)pDevMode)->dmFields & DM_ORIENTATION);
  3383. fLandscape = (((DEVMODEA *)pDevMode)->dmOrientation == DMORIENT_LANDSCAPE);
  3384. }
  3385. Assert( !fOrientationValid
  3386. || fLandscape == (_ptPaperSize.x > _ptPaperSize.y) );
  3387. ::GlobalUnlock(_hDevMode);
  3388. }
  3389. }
  3390. }
  3391. #endif