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.

4083 lines
125 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: print.c
  3. *
  4. * Created: 10-Feb-1995 07:42:16
  5. * Author: Gerrit van Wingerden [gerritv]
  6. *
  7. * Copyright (c) 1993-1999 Microsoft Corporation
  8. *
  9. \**************************************************************************/
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. #include "glsup.h"
  13. #if DBG
  14. int gerritv = 0;
  15. #endif
  16. #if DBG
  17. BOOL gbDownloadFonts = FALSE;
  18. BOOL gbForceUFIMapping = FALSE;
  19. #endif
  20. #if PRINT_TIMER
  21. BOOL bPrintTimer = TRUE;
  22. #endif
  23. #ifdef DBGSUBSET
  24. //Timing code
  25. FILETIME startPageTime, midPageTime, endPageTime;
  26. #endif
  27. int StartDocEMF(HDC hdc, CONST DOCINFOW * pDocInfo, BOOL *pbBanding); // output.c
  28. /****************************************************************************
  29. * int PutDCStateInMetafile( HDC hdcMeta, HDC hdcSrc )
  30. *
  31. * Captures state of a DC into a metafile.
  32. *
  33. *
  34. * History
  35. *
  36. * Clear the UFI in LDC so we can set the force mapping for the next metafile
  37. * Feb-07-1997 Xudong Wu [tessiew]
  38. *
  39. * This routine captures the states of a DC into a METAFILE. This is important
  40. * because we would like each page of the spooled metafile to be completely self
  41. * contained. In order to do this it must complete capture the original state
  42. * of the DC in which it was recorded.
  43. *
  44. * Gerrit van Wingerden [gerritv]
  45. *
  46. * 11-7-94 10:00:00
  47. *
  48. *****************************************************************************/
  49. BOOL PutDCStateInMetafile( HDC hdcMeta )
  50. {
  51. PLDC pldc;
  52. POINT ptlPos;
  53. ULONG ul;
  54. // DC_PLDC(hdcMeta,pldc,0);
  55. pldc = GET_PLDC(hdcMeta);
  56. if (!pldc)
  57. return FALSE;
  58. MFD1("Selecting pen into mf\n");
  59. SelectObject( hdcMeta, (HGDIOBJ) GetDCObject(hdcMeta, LO_PEN_TYPE) );
  60. MFD1("Selecting brush into mf\n");
  61. SelectObject( hdcMeta, (HGDIOBJ) GetDCObject(hdcMeta, LO_BRUSH_TYPE) );
  62. UFI_CLEAR_ID(&pldc->ufi);
  63. MFD1("Selecting logfont into mf\n");
  64. SelectObject( hdcMeta, (HGDIOBJ) GetDCObject(hdcMeta, LO_FONT_TYPE) );
  65. // DON'T TRY THIS AT HOME. We need to record the current state of the
  66. // dc in the metafile. We have optimizations however, that keep us from
  67. // setting the same attribute if it was just set.
  68. if( GetBkColor( hdcMeta ) != 0xffffff )
  69. {
  70. MFD1("Changing backround color in mf\n");
  71. SetBkColor( hdcMeta, GetBkColor( hdcMeta ) );
  72. }
  73. if( GetTextColor( hdcMeta ) != 0 )
  74. {
  75. MFD1("Changing text color in mf\n");
  76. SetTextColor( hdcMeta, GetTextColor( hdcMeta ) );
  77. }
  78. if( GetBkMode( hdcMeta ) != OPAQUE )
  79. {
  80. MFD1("Changing Background Mode in mf\n");
  81. SetBkMode( hdcMeta, GetBkMode( hdcMeta ) );
  82. }
  83. if( GetPolyFillMode( hdcMeta ) != ALTERNATE )
  84. {
  85. MFD1("Changing PolyFill mode in mf\n");
  86. SetPolyFillMode( hdcMeta, GetPolyFillMode( hdcMeta ) );
  87. }
  88. if( GetROP2( hdcMeta ) != R2_COPYPEN )
  89. {
  90. MFD1("Changing ROP2 in mf\n");
  91. SetROP2( hdcMeta, GetROP2( hdcMeta ) );
  92. }
  93. if( GetStretchBltMode( hdcMeta ) != BLACKONWHITE )
  94. {
  95. MFD1("Changing StrechBltMode in mf\n");
  96. SetStretchBltMode( hdcMeta, GetStretchBltMode( hdcMeta ) );
  97. }
  98. if( GetTextAlign( hdcMeta ) != 0 )
  99. {
  100. MFD1("Changing TextAlign in mf\n");
  101. SetTextAlign( hdcMeta, GetTextAlign( hdcMeta ) );
  102. }
  103. if( ( GetBreakExtra( hdcMeta ) != 0 )|| ( GetcBreak( hdcMeta ) != 0 ) )
  104. {
  105. MFD1("Setting Text Justification in mf\n");
  106. SetTextJustification( hdcMeta, GetBreakExtra( hdcMeta ), GetcBreak( hdcMeta ) );
  107. }
  108. if( GetMapMode( hdcMeta ) != MM_TEXT )
  109. {
  110. INT iMapMode = GetMapMode( hdcMeta );
  111. POINT ptlWindowOrg, ptlViewportOrg;
  112. SIZEL WndExt, ViewExt;
  113. // get these before we set the map mode to MM_TEXT
  114. GetViewportExtEx( hdcMeta, &ViewExt );
  115. GetWindowExtEx( hdcMeta, &WndExt );
  116. GetWindowOrgEx( hdcMeta, &ptlWindowOrg );
  117. GetViewportOrgEx( hdcMeta, &ptlViewportOrg );
  118. // set it to MM_TEXT so it doesn't get optimized out
  119. SetMapMode(hdcMeta,MM_TEXT);
  120. MFD1("Setting ANISOTROPIC or ISOTROPIC mode in mf\n");
  121. SetMapMode( hdcMeta, iMapMode );
  122. if( iMapMode == MM_ANISOTROPIC || iMapMode == MM_ISOTROPIC )
  123. {
  124. SetWindowExtEx( hdcMeta, WndExt.cx, WndExt.cy, NULL );
  125. SetViewportExtEx( hdcMeta, ViewExt.cx, ViewExt.cy, NULL );
  126. }
  127. SetWindowOrgEx( hdcMeta,
  128. ptlWindowOrg.x,
  129. ptlWindowOrg.y,
  130. NULL );
  131. SetViewportOrgEx( hdcMeta,
  132. ptlViewportOrg.x,
  133. ptlViewportOrg.y,
  134. NULL );
  135. }
  136. if( GetCurrentPositionEx( hdcMeta, &ptlPos ) )
  137. {
  138. MFD1("Set CurPos in mf\n");
  139. MoveToEx( hdcMeta, ptlPos.x, ptlPos.y, NULL );
  140. }
  141. if( GetBrushOrgEx( hdcMeta, &ptlPos ) )
  142. {
  143. MFD1("Set BrushOrg in mf\n");
  144. SetBrushOrgEx( hdcMeta, ptlPos.x, ptlPos.y, &ptlPos );
  145. }
  146. if( SetICMMode( hdcMeta, ICM_QUERY ) )
  147. {
  148. MFD1("Set ICM mode in mf\n");
  149. SetICMMode( hdcMeta, SetICMMode(hdcMeta,ICM_QUERY) );
  150. }
  151. if( GetColorSpace( hdcMeta ) != NULL )
  152. {
  153. MFD1("Set ColorSpace in mf\n");
  154. SetColorSpace( hdcMeta, GetColorSpace(hdcMeta) );
  155. }
  156. if(!NtGdiAnyLinkedFonts())
  157. {
  158. // tell the machine to turn off linking
  159. MF_SetLinkedUFIs(hdcMeta, NULL, 0);
  160. }
  161. return TRUE;
  162. }
  163. /****************************************************************************
  164. * int MFP_StartDocW( HDC hdc, CONST DOCINFOW * pDocInfo )
  165. *
  166. * Gerrit van Wingerden [gerritv]
  167. *
  168. * 11-7-94 10:00:00
  169. *
  170. ****************************************************************************/
  171. //! this needs to be moved to a spooler header file
  172. #define QSM_DOWNLOADFONTS 0x000000001
  173. BOOL MFP_StartDocW( HDC hdc, CONST DOCINFOW * pDocInfo, BOOL bBanding )
  174. {
  175. BOOL bRet = FALSE;
  176. PWSTR pstr = NULL;
  177. BOOL bEpsPrinting;
  178. PLDC pldc;
  179. UINT cjEMFSH;
  180. FLONG flSpoolMode;
  181. HANDLE hSpooler;
  182. DWORD dwSessionId = 0;
  183. EMFSPOOLHEADER *pemfsh = NULL;
  184. MFD1("Entering StartDocW\n");
  185. if (!IS_ALTDC_TYPE(hdc))
  186. return(bRet);
  187. DC_PLDC(hdc,pldc,bRet);
  188. //
  189. // Create a new EMFSpoolData object to use during EMF recording
  190. //
  191. if (!AllocEMFSpoolData(pldc, bBanding))
  192. {
  193. WARNING("MFP_StartDocW: AllocEMFSpoolData failed\n");
  194. return bRet;
  195. }
  196. if( !bBanding )
  197. {
  198. hSpooler = pldc->hSpooler;
  199. cjEMFSH = sizeof(EMFSPOOLHEADER);
  200. if( pDocInfo->lpszDocName != NULL )
  201. {
  202. cjEMFSH += ( wcslen( pDocInfo->lpszDocName ) + 1 ) * sizeof(WCHAR);
  203. }
  204. if( pDocInfo->lpszOutput != NULL )
  205. {
  206. cjEMFSH += ( wcslen( pDocInfo->lpszOutput ) + 1 ) * sizeof(WCHAR);
  207. }
  208. cjEMFSH = ROUNDUP_DWORDALIGN(cjEMFSH);
  209. pemfsh = (EMFSPOOLHEADER*) LocalAlloc( LMEM_FIXED, cjEMFSH );
  210. if( pemfsh == NULL )
  211. {
  212. WARNING("MFP_StartDOCW: out of memory.\n");
  213. goto FREEPORT;
  214. }
  215. pemfsh->cjSize = cjEMFSH;
  216. cjEMFSH = 0;
  217. if( ( pDocInfo->lpszDocName ) != NULL )
  218. {
  219. pemfsh->dpszDocName = sizeof(EMFSPOOLHEADER);
  220. wcscpy( (WCHAR*) (pemfsh+1), pDocInfo->lpszDocName );
  221. cjEMFSH += ( wcslen( pDocInfo->lpszDocName ) + 1 ) * sizeof(WCHAR);
  222. }
  223. else
  224. {
  225. pemfsh->dpszDocName = 0;
  226. }
  227. if( pDocInfo->lpszOutput != NULL )
  228. {
  229. pemfsh->dpszOutput = sizeof(EMFSPOOLHEADER) + cjEMFSH;
  230. wcscpy((WCHAR*)(((BYTE*) pemfsh ) + pemfsh->dpszOutput),
  231. pDocInfo->lpszOutput);
  232. }
  233. else
  234. {
  235. pemfsh->dpszOutput = 0;
  236. }
  237. ASSERTGDI(ghSpooler,"non null hSpooler with unloaded WINSPOOL\n");
  238. if( !(*fpQuerySpoolMode)( hSpooler, &flSpoolMode, &(pemfsh->dwVersion)))
  239. {
  240. WARNING("MFP_StartDoc: QuerySpoolMode failed\n");
  241. goto FREEPORT;
  242. }
  243. //
  244. // In the scenario of a TS session or a console session that is non zero,
  245. // (due to FastUserSwitching) the font is added using AddFontResource to the win32k.sys
  246. // of one of the clients and the printing is done with the win32k.sys of the console.
  247. // Those are separate win32k.sys that have their own data. The win32k.sys of the console
  248. // cannot access the font that is in the data of a different win32k.sys. In this case
  249. // we need to force the font to be embedded in the EMF stream.
  250. //
  251. if (!ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId) || dwSessionId != 0)
  252. {
  253. flSpoolMode |= QSM_DOWNLOADFONTS;
  254. }
  255. ASSERTGDI((pemfsh->dwVersion == 0x00010000),
  256. "QuerySpoolMode version doesn't equal 1.0\n");
  257. if( !WriteEMFSpoolData(pldc, pemfsh, pemfsh->cjSize))
  258. {
  259. WARNING("MFP_StartDOC: WriteData failed\n");
  260. goto FREEPORT;
  261. }
  262. else
  263. {
  264. MFD1("Wrote EMFSPOOLHEADER to the spooler\n");
  265. }
  266. //
  267. // Write PostScript Injection data.
  268. //
  269. // ATTENTION: THIS MUST BE RIGHT AFTER EMFSPOOLHEADER RECORD
  270. //
  271. if (pldc->dwSizeOfPSDataToRecord)
  272. {
  273. BOOL bError = FALSE;
  274. EMFITEMHEADER emfi;
  275. PLIST_ENTRY p = pldc->PSDataList.Flink;
  276. // Write the header to spooler.
  277. emfi.ulID = EMRI_PS_JOB_DATA;
  278. emfi.cjSize = pldc->dwSizeOfPSDataToRecord;
  279. if (!WriteEMFSpoolData(pldc, &emfi, sizeof(emfi)))
  280. {
  281. WARNING("MFP_StartPage: Write printer failed for PS_JOB_DATA header\n");
  282. goto FREEPORT;
  283. }
  284. else
  285. {
  286. MFD1("Wrote EMRI_PS_JOB_DATA header to the spooler\n");
  287. }
  288. // Record EMFITEMPSINJECTIONDATA
  289. while(p != &(pldc->PSDataList))
  290. {
  291. PPS_INJECTION_DATA pPSData;
  292. // get pointer to this cell.
  293. pPSData = CONTAINING_RECORD(p,PS_INJECTION_DATA,ListEntry);
  294. // record this escape to EMF.
  295. if (!bError && !WriteEMFSpoolData(pldc, &(pPSData->EmfData), pPSData->EmfData.cjSize))
  296. {
  297. WARNING("MFP_StartPage: Write printer failed for PS_JOB_DATA escape data\n");
  298. bError = TRUE;
  299. }
  300. // get pointer to next cell.
  301. p = p->Flink;
  302. // no longer needs this cell.
  303. LOCALFREE(pPSData);
  304. }
  305. // mark as data already freed.
  306. pldc->dwSizeOfPSDataToRecord = 0;
  307. InitializeListHead(&(pldc->PSDataList));
  308. if (bError)
  309. {
  310. goto FREEPORT;
  311. }
  312. }
  313. #if DBG
  314. if( gbDownloadFonts )
  315. {
  316. flSpoolMode |= QSM_DOWNLOADFONTS;
  317. }
  318. #endif
  319. if (flSpoolMode & QSM_DOWNLOADFONTS)
  320. {
  321. // Now, QMS_DOWNLOADFONTS bit are on when print on remote print server,
  322. // then I just use this bit to determine attach ICM profile to metafile
  323. // or not. - hideyukn [May-08-1997]
  324. pldc->fl |= LDC_DOWNLOAD_PROFILES;
  325. // Configure to download fonts
  326. pldc->fl |= LDC_DOWNLOAD_FONTS;
  327. pldc->ppUFIHash = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  328. sizeof( PUFIHASH ) * 3 * UFI_HASH_SIZE );
  329. if( pldc->ppUFIHash == NULL)
  330. {
  331. WARNING("MFP_StartDocW: unable to allocate UFI hash tables\n");
  332. goto FREEPORT;
  333. }
  334. // do not want to allocate memory twice
  335. pldc->ppDVUFIHash = &pldc->ppUFIHash[UFI_HASH_SIZE];
  336. pldc->ppSubUFIHash = &pldc->ppDVUFIHash[UFI_HASH_SIZE];
  337. pldc->fl |= LDC_FORCE_MAPPING;
  338. pldc->ufi.Index = 0xFFFFFFFF;
  339. }
  340. else
  341. {
  342. ULONG cEmbedFonts;
  343. pldc->ppUFIHash = pldc->ppDVUFIHash = pldc->ppSubUFIHash = NULL;
  344. if ((cEmbedFonts = NtGdiGetEmbedFonts()) && cEmbedFonts != 0xFFFFFFFF)
  345. {
  346. pldc->fl |= LDC_EMBED_FONTS;
  347. pldc->ppUFIHash = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(PUFIHASH) * UFI_HASH_SIZE);
  348. if (pldc->ppUFIHash == NULL)
  349. {
  350. WARNING("MFP_StartDocW: unable to allocate UFI has table for embed fonts\n");
  351. goto FREEPORT;
  352. }
  353. }
  354. }
  355. #if DBG
  356. // If gbDownloadFonts is set then force all fonts to be downloaded. Even
  357. // ones on the remote machine.
  358. if( (flSpoolMode & QSM_DOWNLOADFONTS) && !gbDownloadFonts )
  359. #else
  360. if( flSpoolMode & QSM_DOWNLOADFONTS )
  361. #endif
  362. {
  363. // query the spooler to get the list of fonts is has available
  364. INT nBufferSize = 0;
  365. PUNIVERSAL_FONT_ID pufi;
  366. nBufferSize = (*fpQueryRemoteFonts)( pldc->hSpooler, NULL, 0 );
  367. if( nBufferSize != -1 )
  368. {
  369. pufi = LocalAlloc( LMEM_FIXED, sizeof(UNIVERSAL_FONT_ID) * nBufferSize );
  370. if( pufi )
  371. {
  372. INT nNewBufferSize = (*fpQueryRemoteFonts)( pldc->hSpooler,
  373. pufi,
  374. nBufferSize );
  375. //
  376. // This fixes bug 420136. We have three cases according to the result
  377. // of QueryRemoteFonts. If it returns -1, nBufferSize will be set to
  378. // -1 in the if statement. If nNewBufferSize is larger than what we
  379. // allocated, then we use the buffer that we allocated (nBufferSize)
  380. // If nNewBufferSize is less than what we allocated, then we set
  381. // nBufferSize to a lower value then the one previously held. This means
  382. // we access only a part of the buffer we allocated.
  383. //
  384. if (nNewBufferSize < nBufferSize)
  385. {
  386. nBufferSize = nNewBufferSize;
  387. }
  388. MFD2("Found %d fonts\n", nBufferSize );
  389. if (nBufferSize > 0)
  390. {
  391. // next add all these fonts to UFI has table so we don't
  392. //include them in the spool file.
  393. while( nBufferSize-- )
  394. {
  395. pufihAddUFIEntry(pldc->ppUFIHash, &pufi[nBufferSize], 0, 0, 0);
  396. MFD2("%x\n", pufi[nBufferSize].CheckSum );
  397. }
  398. }
  399. LocalFree( pufi );
  400. }
  401. }
  402. else
  403. {
  404. WARNING("QueryRemoteFonts failed. We will be including all fonts in \
  405. the EMF spoolfile\n");
  406. }
  407. }
  408. #if DBG
  409. if( gbForceUFIMapping )
  410. {
  411. pldc->fl |= LDC_FORCE_MAPPING;
  412. }
  413. #endif
  414. }
  415. // we now need to create an EMF DC for this document
  416. if (!AssociateEnhMetaFile(hdc))
  417. {
  418. WARNING("Failed to create spool metafile");
  419. goto FREEPORT;
  420. }
  421. if (bBanding)
  422. {
  423. pldc->fl |= LDC_BANDING;
  424. // remove the LDC_PRINT_DIRECT which
  425. // was set in StartDocW before NtGdiStartDoc call.
  426. pldc->fl &= ~LDC_PRINT_DIRECT;
  427. }
  428. // set the data for this lhe to that of the meta file
  429. pldc->fl |= (LDC_DOC_STARTED|LDC_META_PRINT|LDC_CALL_STARTPAGE|LDC_FONT_CHANGE);
  430. // clear color page flag
  431. CLEAR_COLOR_PAGE(pldc);
  432. if (pldc->pfnAbort != NULL)
  433. {
  434. pldc->fl |= LDC_SAP_CALLBACK;
  435. pldc->ulLastCallBack = GetTickCount();
  436. }
  437. bRet = TRUE;
  438. FREEPORT:
  439. if( pemfsh != NULL )
  440. {
  441. LOCALFREE(pemfsh);
  442. }
  443. return(bRet);
  444. }
  445. /****************************************************************************
  446. * int WINAPI MFP_EndDoc(HDC hdc)
  447. *
  448. * Gerrit van Wingerden [gerritv]
  449. *
  450. * 11-7-94 10:00:00
  451. *
  452. *****************************************************************************/
  453. int WINAPI MFP_EndDoc(HDC hdc)
  454. {
  455. int iRet = 1;
  456. PLDC pldc;
  457. HENHMETAFILE hmeta;
  458. if (!IS_ALTDC_TYPE(hdc))
  459. return(iRet);
  460. DC_PLDC(hdc,pldc,0);
  461. MFD1("MFP_EndDoc\n");
  462. if ((pldc->fl & LDC_DOC_STARTED) == 0)
  463. return(1);
  464. if (pldc->fl & LDC_PAGE_STARTED)
  465. {
  466. MFP_EndPage(hdc);
  467. }
  468. ASSERTGDI(pldc->fl & LDC_META_PRINT,
  469. "DetachPrintMetafile not called on metafile D.C.\n" );
  470. // completely detach the metafile from the original printer DC
  471. hmeta = UnassociateEnhMetaFile( hdc, FALSE );
  472. DeleteEnhMetaFile( hmeta );
  473. DeleteEMFSpoolData(pldc);
  474. // Clear the LDC_SAP_CALLBACK flag.
  475. // Also clear the META_PRINT and DOC_STARTED flags
  476. pldc->fl &= ~(LDC_SAP_CALLBACK | LDC_META_PRINT);
  477. RESETUSERPOLLCOUNT();
  478. MFD1("Caling spooler to end doc\n");
  479. if( pldc->fl & LDC_BANDING )
  480. {
  481. pldc->fl &= ~LDC_BANDING;
  482. EndDoc( hdc );
  483. }
  484. else
  485. {
  486. pldc->fl &= ~LDC_DOC_STARTED;
  487. (*fpEndDocPrinter)(pldc->hSpooler);
  488. }
  489. #if PRINT_TIMER
  490. if( bPrintTimer )
  491. {
  492. DWORD tc;
  493. tc = GetTickCount();
  494. DbgPrint("Document took %d.%d seconds to spool\n",
  495. (tc - pldc->msStartDoc) / 1000,
  496. (tc - pldc->msStartDoc) % 1000 );
  497. }
  498. #endif
  499. return(iRet);
  500. }
  501. /****************************************************************************
  502. * int WINAPI MFP_StartPage(HDC hdc)
  503. *
  504. * Gerrit van Wingerden [gerritv]
  505. *
  506. * 11-7-94 10:00:00
  507. *
  508. *****************************************************************************/
  509. int MFP_StartPage( HDC hdc )
  510. {
  511. PLDC pldc;
  512. int iRet = 1;
  513. //Timing code
  514. #ifdef DBGSUBSET
  515. if (gflSubset & FL_SS_PAGETIME)
  516. {
  517. GetSystemTimeAsFileTime(&startPageTime);
  518. }
  519. #endif
  520. if (!IS_ALTDC_TYPE(hdc))
  521. return(0);
  522. DC_PLDC(hdc,pldc,0);
  523. MFD1("Entering MFP_StartPage\n");
  524. pldc->fl &= ~LDC_CALL_STARTPAGE;
  525. pldc->fl &= ~LDC_CALLED_ENDPAGE;
  526. pldc->fl &= ~LDC_META_ARCDIR_CLOCKWISE;
  527. // Do nothing if page has already been started.
  528. if (pldc->fl & LDC_PAGE_STARTED)
  529. return(1);
  530. pldc->fl |= LDC_PAGE_STARTED;
  531. RESETUSERPOLLCOUNT();
  532. if( pldc->fl & LDC_BANDING )
  533. {
  534. iRet = SP_ERROR;
  535. // ATTENTION: maybe we can delay the call here and do it right before we start
  536. // banding.
  537. MakeInfoDC( hdc, FALSE );
  538. iRet = NtGdiStartPage(hdc);
  539. MakeInfoDC( hdc, TRUE );
  540. }
  541. else
  542. {
  543. ULONG ulCopyCount;
  544. EMFITEMHEADER emfi;
  545. EMFITEMPRESTARTPAGE emfiPre;
  546. // If application calls Escape(SETCOPYCOUNT), we will over-write copy count in
  547. // devmode and save it into metafile.
  548. NtGdiGetAndSetDCDword(
  549. hdc,
  550. GASDDW_COPYCOUNT,
  551. (DWORD) -1,
  552. &ulCopyCount);
  553. if (ulCopyCount != (ULONG) -1)
  554. {
  555. if (pldc->pDevMode)
  556. {
  557. // Set copy count into devmode.
  558. // No driver call happen here, since this is EMF spooling...
  559. pldc->pDevMode->dmFields |= DM_COPIES;
  560. pldc->pDevMode->dmCopies = (short) ulCopyCount;
  561. // Fill up EMF record for devmode.
  562. emfi.ulID = EMRI_DEVMODE;
  563. emfi.cjSize = pldc->pDevMode->dmSize + pldc->pDevMode->dmDriverExtra;
  564. // Force devmode data to be DWORD aligned
  565. emfi.cjSize = ROUNDUP_DWORDALIGN(emfi.cjSize);
  566. if (!WriteEMFSpoolData(pldc, &emfi, sizeof(emfi)) ||
  567. !WriteEMFSpoolData(pldc, pldc->pDevMode, emfi.cjSize))
  568. {
  569. WARNING("MFP_StartPage: Write printer failed for DEVMODE\n");
  570. return(SP_ERROR);
  571. }
  572. }
  573. }
  574. // before the start page, we need to see if the EPS mode has
  575. // changed since the start doc.
  576. NtGdiGetAndSetDCDword(
  577. hdc,
  578. GASDDW_EPSPRINTESCCALLED,
  579. (DWORD) FALSE,
  580. &emfiPre.bEPS);
  581. if (emfiPre.bEPS)
  582. {
  583. int i;
  584. EMFITEMHEADER emfiHeader;
  585. // make sure it is true or false
  586. emfiPre.bEPS = !!emfiPre.bEPS;
  587. // This was ulCopyCount.
  588. // Just set -1 for keep compatibility. -1 means "up to devmode".
  589. emfiPre.ulUnused = -1;
  590. // is there anything we will need to do? If so record the record
  591. emfiHeader.ulID = EMRI_PRESTARTPAGE;
  592. emfiHeader.cjSize = sizeof(emfiPre);
  593. if (!WriteEMFSpoolData(pldc, &emfiHeader, sizeof(emfiHeader)) ||
  594. !WriteEMFSpoolData(pldc, &emfiPre, sizeof(emfiPre)))
  595. {
  596. WARNING("MFP_StartPage: Write printer failed for PRESTARTPAGE\n");
  597. return(SP_ERROR);
  598. }
  599. }
  600. // Metafile the start page call. Now all the play journal code has to do is
  601. // play back the metafile and the StartPage call will happen automatically
  602. // at the right place in the metafile.
  603. if( !(*fpStartPagePrinter)( pldc->hSpooler ) )
  604. {
  605. WARNING("MFP_StarPage: StartPagePrinter failed\n");
  606. return(SP_ERROR);
  607. }
  608. }
  609. return(iRet);
  610. }
  611. /****************************************************************************
  612. * BOOL StartBanding( HDC hdc, POINTL *pptl )
  613. *
  614. * Tells the printer driver to get ready for banding and asks for the origin
  615. * of the first band.
  616. *
  617. *
  618. * Gerrit van Wingerden [gerritv]
  619. *
  620. * 1-7-95 10:00:00
  621. *
  622. *****************************************************************************/
  623. BOOL StartBanding( HDC hdc, POINTL *pptl, SIZE *pSize )
  624. {
  625. return (NtGdiDoBanding(hdc, TRUE, pptl, pSize));
  626. }
  627. /****************************************************************************
  628. * BOOL NextBand( HDC hdc, POINTL *pptl )
  629. *
  630. * Tells the driver to realize the image accumlated in the DC and then
  631. * asks for the origin of the next band. If the origin is (-1,-1) the
  632. * driver is through banding.
  633. *
  634. *
  635. * Gerrit van Wingerden [gerritv]
  636. *
  637. * 1-7-95 10:00:00
  638. *
  639. *****************************************************************************/
  640. BOOL NextBand( HDC hdc, POINTL *pptl )
  641. {
  642. BOOL bRet=FALSE;
  643. SIZE szScratch;
  644. bRet = NtGdiDoBanding(hdc, FALSE, pptl, &szScratch);
  645. // reset the page started flag if this is the next band
  646. if( bRet && ( pptl->x == -1 ) )
  647. {
  648. PLDC pldc;
  649. DC_PLDC(hdc,pldc,0);
  650. pldc->fl &= ~LDC_PAGE_STARTED;
  651. }
  652. return(bRet);
  653. }
  654. /****************************************************************************\
  655. * VOID PrintBand()
  656. *
  657. * History:
  658. *
  659. * 1-05-97 Hideyuki Nagase [hideyukn]
  660. * Wrote it.
  661. * 3-23-98 Ramanathan Venkatapathy [ramanv]
  662. * Fixed Scaling bugs
  663. * 6-26-98 Ramanathan Venkatapathy [ramanv]
  664. * Added pClip to correct the clipping when Xforms are applied on the
  665. * DC. ANDing Banding region with prect incorrectly clips off regions when
  666. * prect is yet to be transformed.
  667. * 8-24-99 Steve Kiraly [steveki]
  668. * Add code to not play on the DC if there is no intersection with the
  669. * clipping rectangle and the banding rectangle. Fix n-up bug when the
  670. * imageable area of the document is larger that the physical page. The
  671. * solution consisted of setting up the clipping region to stay within
  672. * either the banding rectangle or the clipping rectangle. See bug 377434
  673. * for more information.
  674. *
  675. * An illustration of the problem.
  676. *
  677. * We are printing a document that is larger than the imageable area of the page
  678. * thus it must print on 2 pages and we are printing 2-up with banding enabled
  679. * because this is a 24 bpp document.
  680. *
  681. * The printable region rectagle is (0,0) (2114,3066)
  682. * Page one has a clipping rectangle of (216,46) (2114,1510)
  683. * Page two has a clipping rectangle of (216,1601) (2114,3066)
  684. *
  685. * GDI will print using 4 bands each 784 high.
  686. *
  687. * Band 1 pptl = 0,0 pszlBand = 2400,784
  688. * Band 2 pptl = 0,784 pszlBand = 2400,784
  689. * Band 3 pptl = 0,1568 pszlBand = 2400,784
  690. * Band 4 pptl = 0,2352 pszlBand = 2400,784
  691. *
  692. * 0,0
  693. *
  694. * 0,0 +-----------------------------------------------------------------+
  695. * | 216,46 |
  696. * | |
  697. * | |
  698. * 0,784 | |
  699. * | |
  700. * | [========================================] |
  701. * | [ ] |
  702. * | [ ] |
  703. * | [ ] 2114,1510 |
  704. * |-----------------------------------------------------------------|
  705. * | 216,1601 [ ] |
  706. * 0,1568 | [ ] |
  707. * | [ ] |
  708. * | [ ] |
  709. * 0,2352 | [ ] |
  710. * | [ ] |
  711. * | [========================================] |
  712. * | |
  713. * | 2114,3066 |
  714. * +-----------------------------------------------------------------+
  715. *
  716. * 2114,3066
  717. *
  718. * Band 1 clipping region is (216,0) (2401,785)
  719. * Band 2 clipping region is (216,784) (2114,726)
  720. * Band 3 clipping region is (216,33) (2114,785)
  721. * Band 4 clipping region is (216,0) (2114,714)
  722. *
  723. * Band 2 and 3 are the most interesting cases. Band 2 the clipping
  724. * bottom right corner is the size of the clipping rectangle rather than the
  725. * band size as the code orignally was. Band 3 on the other hand has the
  726. * top left corner of the region adjusted to the clipping rectangle.
  727. *
  728. ****************************************************************************/
  729. VOID
  730. PrintBand(
  731. HDC hdc,
  732. HENHMETAFILE hmeta,
  733. POINTL *pptl, // Offsets from top of page for this band.
  734. RECT *prect, // Rectangle for printable reagion of this page.
  735. SIZEL *pszlBand, // Size of band.
  736. RECT *pClip // Clipping rectangle, non null when n-up.
  737. )
  738. {
  739. ULONG ulRet;
  740. PERBANDINFO pbi;
  741. MFD3("gdi32:PrintBand Print offset x,y = %d,%d\n", pptl->x, pptl->y);
  742. MFD3("gdi32:PrintBand Printable region top = %d, bottom = %d\n", prect->top, prect->bottom);
  743. MFD3("gdi32:PrintBand Printable region left = %d, right = %d\n", prect->left, prect->right);
  744. MFD3("gdi32:PrintBand Band size x,y = %d,%d\n",pszlBand->cx, pszlBand->cy);
  745. do
  746. {
  747. RECT rectPage = *prect;
  748. HRGN hRgnBand = NULL;
  749. HRGN hRgnCurrent = NULL;
  750. BOOL bSaveDC = FALSE;
  751. ULONG ulXRes, ulYRes;
  752. BOOL bUsePerBandInfo = FALSE;
  753. // Updates view origin in specified coords.
  754. SetViewportOrgEx( hdc, -(pptl->x), -(pptl->y), NULL );
  755. // Initialize with current resolution.
  756. ulXRes = (ULONG) prect->right - prect->left;
  757. ulYRes = (ULONG) prect->bottom - prect->top;
  758. pbi.bRepeatThisBand = FALSE;
  759. pbi.ulHorzRes = ulXRes;
  760. pbi.ulVertRes = ulYRes;
  761. pbi.szlBand.cx = pszlBand->cx;
  762. pbi.szlBand.cy = pszlBand->cy;
  763. MFD1("GDI32:PrintBand() querying band information\n");
  764. // Query band information.
  765. ulRet = NtGdiGetPerBandInfo(hdc,&pbi);
  766. if (ulRet != GDI_ERROR)
  767. {
  768. SIZEL szlClip;
  769. POINTL pptlMove;
  770. bUsePerBandInfo = (ulRet != 0);
  771. // If return value is 0, we will draw without scaling.
  772. if (bUsePerBandInfo &&
  773. ((ulXRes != pbi.ulHorzRes) ||
  774. (ulYRes != pbi.ulVertRes)))
  775. {
  776. FLOAT sx,sy;
  777. MFD1("GDI PlayEMF band information was specified\n");
  778. // Compute scaling ratio.
  779. //
  780. // This code has rounding errors due to
  781. // float to long truncation. The correct code
  782. // should use a LONGLONG to store the numerator and do
  783. // all of the computation in integer math.
  784. //
  785. // See StretchDIBits
  786. //
  787. // The fix is coded below in comments because we can't check it
  788. // in till someone figures out how to break the original version.
  789. //
  790. sx = (FLOAT) ulXRes / (FLOAT) pbi.ulHorzRes;
  791. sy = (FLOAT) ulYRes / (FLOAT) pbi.ulVertRes;
  792. // Shrink/Stretch drawing frame.
  793. //rectPage.left = (LONG) ((LONGLONG)rectPage.left*pbi.ulHorizRes)/ulXRes;
  794. //rectPage.top = (LONG) ((LONGLONG)rectPage.top*pbi.ulVertRes)/ulYRes;
  795. //rectPage.right = (LONG) ((LONGLONG)rectPage.right*pbi.ulHorizRes)/ulXRes;
  796. //rectPage.bottom = (LONG) ((LONGLONG)rectPage.bottom*pbi.ulVertRes)/ulYRes;
  797. rectPage.left = (LONG) ((FLOAT) rectPage.left / sx);
  798. rectPage.top = (LONG) ((FLOAT) rectPage.top / sy);
  799. rectPage.right = (LONG) ((FLOAT) rectPage.right / sx);
  800. rectPage.bottom = (LONG) ((FLOAT) rectPage.bottom / sy);
  801. // Compute view origin.
  802. //pptlMove.x = (LONG) ((LONGLONG)pptl->x*pbi.ulHorizRes)/ulXRes;
  803. //pptlMove.y = (LONG) ((LONGLONG)pptl->y*pbi.ulVertRes)/ulYRes;
  804. pptlMove.x = (LONG) ((FLOAT) pptl->x / sx);
  805. pptlMove.y = (LONG) ((FLOAT) pptl->y / sy);
  806. // Updates view origin in specified coords.
  807. SetViewportOrgEx( hdc, -pptlMove.x, -pptlMove.y, NULL );
  808. // Set clip region size.
  809. //szlClip.cx = (ULONG) ((LONGLONG)pbi.szlBand.cx*pbi.ulHorizRes)/ulXRes;
  810. //szlClip.cy = (ULONG) ((LONGLONG)pbi.szlBand.cy*pbi.ulVertRes)/ulYRes;
  811. szlClip.cx = (ULONG) ((FLOAT) pbi.szlBand.cx / sx);
  812. szlClip.cy = (ULONG) ((FLOAT) pbi.szlBand.cy / sy);
  813. // Create clip region for banding.
  814. hRgnBand = CreateRectRgn(0,0,szlClip.cx,szlClip.cy);
  815. }
  816. else
  817. {
  818. SIZEL szlPage = {0,0};
  819. SIZEL szlAdjust = {0,0};
  820. if(!bUsePerBandInfo)
  821. {
  822. // Set back to default values in case driver mucked with them
  823. pbi.bRepeatThisBand = FALSE;
  824. pbi.ulHorzRes = ulXRes;
  825. pbi.ulVertRes = ulYRes;
  826. pbi.szlBand.cx = pszlBand->cx;
  827. pbi.szlBand.cy = pszlBand->cy;
  828. }
  829. pptlMove.x = pptl->x;
  830. pptlMove.y = pptl->y;
  831. MFD1("gdi32:PrintBand(): GetPerBandInfo NO SCALING is requested\n");
  832. // Page size
  833. if (pClip) {
  834. RECT rcBand;
  835. RECT rcIntersect;
  836. MFD3("gdi32:PrintBand(): Clipping Rectangle top = %d, bottom = %d\n", pClip->top, pClip->bottom);
  837. MFD3("gdi32:PrintBand(): Clipping Rectangle left = %d, right = %d\n", pClip->left, pClip->right);
  838. rcBand.left = pptlMove.x;
  839. rcBand.top = pptlMove.y;
  840. rcBand.right = pptlMove.x + pbi.szlBand.cx;
  841. rcBand.bottom = pptlMove.y + pbi.szlBand.cy;
  842. //
  843. // If the banding rect does not instersect the clip rect
  844. // not much to do, just continue.
  845. //
  846. if (!IntersectRect(&rcIntersect, pClip, &rcBand))
  847. {
  848. MFD1("gdi32:PrintBand(): No intersection with band rect and pClip\n");
  849. continue;
  850. }
  851. szlPage.cx = pClip->right;
  852. szlPage.cy = pClip->bottom;
  853. //
  854. // The adjust point it neccessary to move the clipping
  855. // region's upper or left edge. The szlClip is used to
  856. // move the clipping region's height and width.
  857. //
  858. if (pClip->left > pptlMove.x)
  859. {
  860. szlAdjust.cx = pClip->left - pptlMove.x;
  861. }
  862. if (pClip->top > pptlMove.y)
  863. {
  864. szlAdjust.cy = pClip->top - pptlMove.y;
  865. }
  866. } else {
  867. szlPage.cx = prect->right;
  868. szlPage.cy = prect->bottom;
  869. }
  870. //
  871. // Set clip region size (clip by band size)
  872. //
  873. // if band rect over page rect, adjust it.
  874. //
  875. if ((pptlMove.x + pbi.szlBand.cx) > szlPage.cx)
  876. {
  877. szlClip.cx = szlPage.cx - pptlMove.x;
  878. }
  879. else
  880. {
  881. szlClip.cx = pbi.szlBand.cx;
  882. }
  883. if ((pptlMove.y + pbi.szlBand.cy) > szlPage.cy)
  884. {
  885. szlClip.cy = szlPage.cy - pptlMove.y;
  886. }
  887. else
  888. {
  889. szlClip.cy = pbi.szlBand.cy;
  890. }
  891. MFD3("Print offset x,y = %d,%d\n",pptlMove.x,pptlMove.y);
  892. MFD3("Page size x,y = %d,%d\n",szlPage.cx,szlPage.cy);
  893. MFD3("Band size x,y = %d,%d\n",pbi.szlBand.cx,pbi.szlBand.cy);
  894. MFD3("Clip size x,y = %d,%d\n",szlClip.cx,szlClip.cy);
  895. MFD3("Adjust size x,y = %d,%d\n",szlAdjust.cx,szlAdjust.cy);
  896. // Create clip region for banding.
  897. hRgnBand = CreateRectRgn(szlAdjust.cx,szlAdjust.cy,szlClip.cx,szlClip.cy);
  898. }
  899. if (hRgnBand)
  900. {
  901. int iRet;
  902. RECT rectCurrentClip;
  903. // Get clip box currently selected in DC.
  904. iRet = GetClipBox(hdc,&rectCurrentClip);
  905. if ((iRet == NULLREGION) || (iRet == ERROR))
  906. {
  907. // Select simple band region as clip region.
  908. SelectClipRgn(hdc, hRgnBand);
  909. }
  910. else
  911. {
  912. MFD1("GDI PrintBand: Some region already exists\n");
  913. MFD3("Clip Box top = %d, bottom = %d\n",
  914. rectCurrentClip.top,rectCurrentClip.bottom);
  915. MFD3("Clip Box left = %d, right = %d\n",
  916. rectCurrentClip.left,rectCurrentClip.right);
  917. // Save currect DC to restore current clip region later.
  918. SaveDC(hdc);
  919. // Move to the clip reagion to proper place.
  920. OffsetClipRgn(hdc,-pptlMove.x,-pptlMove.y);
  921. // Some clip region already defined. we need to combine those.
  922. ExtSelectClipRgn(hdc, hRgnBand, RGN_AND);
  923. // Mark as we saved DC.
  924. bSaveDC = TRUE;
  925. }
  926. }
  927. // Play metafile.
  928. PlayEnhMetaFile( hdc, hmeta, &rectPage );
  929. if (hRgnBand)
  930. {
  931. if (bSaveDC)
  932. {
  933. RestoreDC(hdc,-1);
  934. }
  935. else
  936. {
  937. // Set back it to NULL region.
  938. SelectClipRgn(hdc,NULL);
  939. }
  940. // Reset the clip region.
  941. DeleteObject(hRgnBand);
  942. }
  943. }
  944. else
  945. {
  946. MFD1("GDI PrintBand: Got error from kernel/driver, this band will be skipped\n");
  947. // There is something error, Terminate printing for this band.
  948. return;
  949. }
  950. // Repeat this until the driver says "no".
  951. } while (pbi.bRepeatThisBand);
  952. }
  953. /****************************************************************************
  954. * int MFP_InternalEndPage(HDC hdc, DWORD dwEMFITEMID)
  955. *
  956. * Closes the EMF attached to the DC and writes it to the spooler. Then
  957. * it creates a new metafile and binds it to the DC.
  958. *
  959. * Gerrit van Wingerden [gerritv]
  960. *
  961. * 11-7-94 10:00:00
  962. *
  963. *****************************************************************************/
  964. int MFP_InternalEndPage(HDC hdc,
  965. DWORD dwEMFITEMID)
  966. {
  967. PLDC pldc;
  968. HENHMETAFILE hmeta;
  969. BOOL bOk;
  970. int iRet = SP_ERROR;
  971. MFD1("Entering MFP_EndPage\n");
  972. if (!IS_ALTDC_TYPE(hdc))
  973. return(0);
  974. DC_PLDC(hdc,pldc,0);
  975. if ((pldc->fl & LDC_DOC_CANCELLED) ||
  976. ((pldc->fl & LDC_PAGE_STARTED) == 0))
  977. {
  978. GdiSetLastError(ERROR_INVALID_PARAMETER);
  979. return(SP_ERROR);
  980. }
  981. // Need to change the dwEMFITEMID here if mono page
  982. if (!(pldc->fl & LDC_COLOR_PAGE)) {
  983. dwEMFITEMID = (dwEMFITEMID == EMRI_METAFILE) ? EMRI_BW_METAFILE
  984. : EMRI_BW_FORM_METAFILE;
  985. }
  986. DESIGNATE_COLOR_PAGE(pldc);
  987. if (pldc->fl & LDC_SAP_CALLBACK)
  988. vSAPCallback(pldc);
  989. pldc->fl &= ~LDC_PAGE_STARTED;
  990. //tessiew
  991. #ifdef DBGSUBSET
  992. if (gflSubset & FL_SS_PAGETIME)
  993. {
  994. GetSystemTimeAsFileTime(&midPageTime);
  995. DbgPrint("\t%ld", (midPageTime.dwLowDateTime-startPageTime.dwLowDateTime) / 10000);
  996. }
  997. #endif
  998. // We need to write the subset font into the spool
  999. // file first for remote printing
  1000. if ((pldc->fl & (LDC_DOWNLOAD_FONTS | LDC_FORCE_MAPPING)) && (pldc->fl & LDC_FONT_SUBSET))
  1001. {
  1002. PUFIHASH pBucket, pBucketNext;
  1003. PUCHAR puchDestBuff;
  1004. ULONG index, ulDestSize, ulBytesWritten;
  1005. for (index=0; index < UFI_HASH_SIZE; index++)
  1006. {
  1007. pBucketNext = pldc->ppSubUFIHash[index];
  1008. while(pBucketNext)
  1009. {
  1010. // We might fail on bDoFontSubset() thus pBucket would be deleted from the hash table
  1011. // in function WriteSubFontToSpoolFile(). Need to update pBucketNext first.
  1012. pBucket = pBucketNext;
  1013. pBucketNext = pBucket->pNext;
  1014. if ((pBucket->fs1 & FLUFI_DELTA) && (pBucket->u.ssi.cDeltaGlyphs == 0))
  1015. {
  1016. // No delta, skip
  1017. if (pBucket->u.ssi.pjDelta)
  1018. {
  1019. LocalFree(pBucket->u.ssi.pjDelta);
  1020. pBucket->u.ssi.pjDelta = NULL;
  1021. }
  1022. }
  1023. else // first page or page with nonzero delta
  1024. {
  1025. // pBucket->fs1 will change for the first page after bDoFontSubset() call,
  1026. // thus we can't use pBucket->fs1 & FLUFI_DELTA in WriteSubFontToSpoolFile() call.
  1027. BOOL bDelta = pBucket->fs1 & FLUFI_DELTA;
  1028. if
  1029. (
  1030. !bDoFontSubset(pBucket, &puchDestBuff, &ulDestSize, &ulBytesWritten) ||
  1031. !WriteSubFontToSpoolFile(pldc, puchDestBuff, ulBytesWritten, &pBucket->ufi, bDelta)
  1032. )
  1033. {
  1034. // if font subsetting failed, we need to write the whole font file to the spool file
  1035. // and clean up the UFI entry in the ldc
  1036. if (!bAddUFIandWriteSpool(hdc, &pBucket->ufi, TRUE, pBucket->fs2))
  1037. {
  1038. WARNING("bAddUFIandWriteSpool failed\n");
  1039. return SP_ERROR;
  1040. }
  1041. }
  1042. }
  1043. }
  1044. }
  1045. }
  1046. // Metafile the EndPage call.
  1047. MFD1("MFP_EndPage: Closing metafile\n");
  1048. hmeta = UnassociateEnhMetaFile(hdc, TRUE);
  1049. if( hmeta == NULL )
  1050. {
  1051. WARNING("MFP_InternalEndPage() Closing the Enhanced Metafile Failed\n");
  1052. return(SP_ERROR);
  1053. }
  1054. // now write the metafile to the spooler
  1055. if( pldc->fl & LDC_BANDING )
  1056. {
  1057. // play back the metafile in bands
  1058. RECT rect;
  1059. POINTL ptlOrigin;
  1060. POINT ptlKeep;
  1061. POINT ptlWindowOrg;
  1062. SIZE szWindowExt;
  1063. SIZE szViewportExt;
  1064. SIZE szSurface; // for open gl printing optimization
  1065. XFORM xf;
  1066. ULONG ulMapMode;
  1067. // get bounding rectangle
  1068. rect.left = rect.top = 0;
  1069. rect.right = GetDeviceCaps(hdc, DESKTOPHORZRES);
  1070. rect.bottom = GetDeviceCaps(hdc, DESKTOPVERTRES);
  1071. #if DBG
  1072. DbgPrint("Playing banding metafile\n");
  1073. #endif
  1074. // temporarily reset LDC_META_PRINT flag so we don't try to record
  1075. // during playback
  1076. pldc->fl &= ~LDC_META_PRINT;
  1077. bOk = StartBanding( hdc, &ptlOrigin, &szSurface );
  1078. // we need to clear the transform during this operation
  1079. GetViewportOrgEx(hdc, &ptlKeep);
  1080. GetWindowOrgEx(hdc,&ptlWindowOrg);
  1081. GetWindowExtEx(hdc,&szWindowExt);
  1082. GetViewportExtEx(hdc,&szViewportExt);
  1083. GetWorldTransform(hdc,&xf);
  1084. ulMapMode = SetMapMode(hdc,MM_TEXT);
  1085. SetWindowOrgEx(hdc,0,0,NULL);
  1086. ModifyWorldTransform(hdc,NULL,MWT_IDENTITY);
  1087. if( bOk )
  1088. {
  1089. do
  1090. {
  1091. // Print this band.
  1092. PrintBand( hdc, hmeta, &ptlOrigin, &rect, &szSurface, NULL );
  1093. // Move down to next band.
  1094. bOk = NextBand( hdc, &ptlOrigin );
  1095. } while( ptlOrigin.x != -1 && bOk );
  1096. }
  1097. if (pldc->pUMPD && bOk && (ptlOrigin.x == -1))
  1098. {
  1099. //
  1100. // if UMPD and last band
  1101. //
  1102. if( !(*fpEndPagePrinter)( pldc->hSpooler ) )
  1103. {
  1104. WARNING("MFP_StarPage: EndPagePrinter failed\n");
  1105. iRet = SP_ERROR;
  1106. }
  1107. }
  1108. SetMapMode(hdc,ulMapMode);
  1109. SetWorldTransform(hdc,&xf);
  1110. SetWindowOrgEx(hdc,ptlWindowOrg.x,ptlWindowOrg.y,NULL);
  1111. SetWindowExtEx(hdc,szWindowExt.cx,szWindowExt.cy,NULL);
  1112. SetViewportExtEx(hdc,szViewportExt.cx,szViewportExt.cy,NULL);
  1113. SetViewportOrgEx(hdc,ptlKeep.x, ptlKeep.y, NULL);
  1114. // reset the flag for the next page
  1115. pldc->fl |= LDC_META_PRINT;
  1116. if( !bOk )
  1117. {
  1118. WARNING("MFP_EndPage: Error doing banding\n");
  1119. }
  1120. else
  1121. {
  1122. // if we got here we suceeded
  1123. iRet = 1;
  1124. }
  1125. #if DBG
  1126. DbgPrint("Done playing banding metafile\n");
  1127. #endif
  1128. }
  1129. else
  1130. {
  1131. // if ResetDC was called record the devmode in the metafile stream
  1132. bOk = TRUE;
  1133. if( pldc->fl & LDC_RESETDC_CALLED )
  1134. {
  1135. EMFITEMHEADER emfi;
  1136. emfi.ulID = EMRI_DEVMODE;
  1137. emfi.cjSize = ( pldc->pDevMode ) ?
  1138. pldc->pDevMode->dmSize + pldc->pDevMode->dmDriverExtra : 0 ;
  1139. // Force devmode data to be DWORD aligned
  1140. emfi.cjSize = ROUNDUP_DWORDALIGN(emfi.cjSize);
  1141. if (!WriteEMFSpoolData(pldc, &emfi, sizeof(emfi)) ||
  1142. !WriteEMFSpoolData(pldc, pldc->pDevMode, emfi.cjSize))
  1143. {
  1144. WARNING("Writing DEVMODE to spooler failed.\n");
  1145. bOk = FALSE;
  1146. }
  1147. pldc->fl &= ~(LDC_RESETDC_CALLED);
  1148. }
  1149. if (bOk)
  1150. iRet = 1;
  1151. }
  1152. // At this point if we suceede iRet should be 1 otherwise it should be SP_ERROR
  1153. // even if we encountered an error we still want to try to associate a new
  1154. // metafile with this DC. That whether the app calls EndPage, AbortDoc, or
  1155. // EndDoc next, things will happend more smoothly.
  1156. DeleteEnhMetaFile(hmeta);
  1157. //
  1158. // flush the content of the current page to spooler
  1159. // and write out a new EndPage record
  1160. //
  1161. // next create a new metafile for the next page
  1162. if (!FlushEMFSpoolData(pldc, dwEMFITEMID) || !AssociateEnhMetaFile(hdc))
  1163. {
  1164. WARNING("StartPage: error creating metafile\n");
  1165. iRet = SP_ERROR;
  1166. }
  1167. // reset user's poll count so it counts this as output
  1168. RESETUSERPOLLCOUNT();
  1169. if( !(pldc->fl & LDC_BANDING ) )
  1170. {
  1171. if( !(*fpEndPagePrinter)( pldc->hSpooler ) )
  1172. {
  1173. WARNING("MFP_StarPage: EndPagePrinter failed\n");
  1174. iRet = SP_ERROR;
  1175. }
  1176. }
  1177. pldc->fl |= LDC_CALL_STARTPAGE;
  1178. #if PRINT_TIMER
  1179. if( bPrintTimer )
  1180. {
  1181. DWORD tc;
  1182. tc = GetTickCount();
  1183. DbgPrint("Page took %d.%d seconds to print\n",
  1184. (tc - pldc->msStartPage) / 1000,
  1185. (tc - pldc->msStartPage) % 1000 );
  1186. }
  1187. #endif
  1188. #ifdef DBGSUBSET
  1189. if (gflSubset & FL_SS_PAGETIME)
  1190. {
  1191. GetSystemTimeAsFileTime(&endPageTime);
  1192. DbgPrint("\t%ld\n", (endPageTime.dwLowDateTime-startPageTime.dwLowDateTime) / 10000);
  1193. }
  1194. #endif
  1195. return(iRet);
  1196. }
  1197. /****************************************************************************
  1198. * int WINAPI MFP_EndPage(HDC hdc)
  1199. *
  1200. * Closes the EMF attached to the DC and writes it to the spooler. Then
  1201. * it creates a new metafile and binds it to the DC.
  1202. *
  1203. * Gerrit van Wingerden [gerritv]
  1204. *
  1205. * 11-7-94 10:00:00
  1206. *
  1207. *****************************************************************************/
  1208. int WINAPI MFP_EndPage(HDC hdc) {
  1209. // Call MFP_InternalEndPage with EMRI_METAFILE
  1210. return MFP_InternalEndPage(hdc, EMRI_METAFILE);
  1211. }
  1212. /****************************************************************************
  1213. * int WINAPI MFP_EndFormPage(HDC hdc)
  1214. *
  1215. * Closes the EMF attached to the DC and writes it to the spooler. Then
  1216. * it creates a new metafile and binds it to the DC. Saves the EMF Item as a
  1217. * watermark file which is played on each physical page.
  1218. *
  1219. * Ramanathan Venkatapathy [RamanV]
  1220. *
  1221. * 7/1/97
  1222. *
  1223. *****************************************************************************/
  1224. int WINAPI MFP_EndFormPage(HDC hdc) {
  1225. // Call MFP_InternalEndPage with EMRI_FORM_METAFILE
  1226. return MFP_InternalEndPage(hdc, EMRI_FORM_METAFILE);
  1227. }
  1228. BOOL MFP_ResetDCW( HDC hdc, DEVMODEW *pdmw )
  1229. {
  1230. PLDC pldc;
  1231. HENHMETAFILE hmeta;
  1232. ULONG cjDevMode;
  1233. DC_PLDC(hdc,pldc,0);
  1234. MFD1("MFP_ResetDCW Called\n");
  1235. pldc->fl |= LDC_RESETDC_CALLED;
  1236. // finally associate a new metafile since call to ResetDC could have changed
  1237. // the dimensions of the DC
  1238. hmeta = UnassociateEnhMetaFile( hdc, FALSE );
  1239. DeleteEnhMetaFile( hmeta );
  1240. if( !AssociateEnhMetaFile( hdc ) )
  1241. {
  1242. WARNING("MFP_ResetDCW is unable to associate a new metafile\n");
  1243. return(FALSE);
  1244. }
  1245. return(TRUE);
  1246. }
  1247. BOOL MFP_ResetBanding( HDC hdc, BOOL bBanding )
  1248. {
  1249. PLDC pldc;
  1250. HENHMETAFILE hmeta;
  1251. DC_PLDC(hdc,pldc,0);
  1252. if( pldc->fl & LDC_BANDING )
  1253. {
  1254. // we were banding before so we must remove the old metafile from the DC
  1255. // since we might not be banding any more or the surface dimenstions could
  1256. // have changed requiring us to have a new metafile
  1257. hmeta = UnassociateEnhMetaFile( hdc, FALSE );
  1258. DeleteEnhMetaFile( hmeta );
  1259. pldc->fl &= ~(LDC_BANDING|LDC_META_PRINT);
  1260. MFD1("Remove old banding metafile\n");
  1261. }
  1262. if( bBanding )
  1263. {
  1264. // if we are banding after the ResetDC then we must attach a new metafile
  1265. if( !AssociateEnhMetaFile(hdc) )
  1266. {
  1267. WARNING("MFP_ResetBanding: Failed to attach banding metafile spool metafile");
  1268. return(FALSE);
  1269. }
  1270. pldc->fl |= LDC_BANDING|LDC_META_PRINT;
  1271. MFD1("Adding new banding metafile\n");
  1272. }
  1273. return(TRUE);
  1274. }
  1275. /****************************************************************************
  1276. * BOOL MyReadPrinter( HANDLE hPrinter, BYTE *pjBuf, ULONG cjBuf )
  1277. *
  1278. * Read a requested number of bytes from the spooler.
  1279. *
  1280. * History:
  1281. * 5/12/1995 by Gerrit van Wingerden [gerritv] - Author
  1282. *
  1283. * 5/1/1997 by Ramanathan N Venkatapathy [ramanv]
  1284. * Modified to synchronously wait during Print while spooling.
  1285. * SeekPrinter sets last error when spool file isn't big enough.
  1286. *****************************************************************************/
  1287. BOOL MyReadPrinter( HANDLE hPrinter, BYTE *pjBuf, ULONG cjBuf )
  1288. {
  1289. ULONG cjRead;
  1290. LARGE_INTEGER liOffset;
  1291. ASSERTGDI(ghSpooler,"non null hSpooler with unloaded WINSPOOL\n");
  1292. // Wait till enough bytes have been written.
  1293. liOffset.QuadPart = cjBuf;
  1294. if (!(*fpSeekPrinter) (hPrinter, liOffset, NULL, FILE_CURRENT, FALSE)) {
  1295. return FALSE;
  1296. }
  1297. // Seek back to the original position in the spoolfile.
  1298. liOffset.QuadPart = -liOffset.QuadPart;
  1299. if (!(*fpSeekPrinter) (hPrinter, liOffset, NULL, FILE_CURRENT, FALSE)) {
  1300. return FALSE;
  1301. }
  1302. while( cjBuf )
  1303. {
  1304. if(!(*fpReadPrinter)( hPrinter, pjBuf, cjBuf, &cjRead ) )
  1305. {
  1306. WARNING("MyReadPrinter: Read printer failed\n");
  1307. return(FALSE);
  1308. }
  1309. if( cjRead == 0 )
  1310. {
  1311. return(FALSE);
  1312. }
  1313. pjBuf += cjRead;
  1314. cjBuf -= cjRead;
  1315. }
  1316. return(TRUE);
  1317. }
  1318. BOOL MemMapReadPrinter(
  1319. HANDLE hPrinter,
  1320. LPBYTE *pBuf,
  1321. ULONG cbBuf
  1322. )
  1323. {
  1324. LARGE_INTEGER liOffset;
  1325. ASSERTGDI(ghSpooler,"non null hSpooler with unloaded WINSPOOL\n");
  1326. // Memory mapped ReadPrinter not exported.
  1327. if (!fpSplReadPrinter) {
  1328. return FALSE;
  1329. }
  1330. // Wait till enough bytes have been written.
  1331. liOffset.QuadPart = cbBuf;
  1332. if (!(*fpSeekPrinter) (hPrinter, liOffset, NULL, FILE_CURRENT, FALSE)) {
  1333. return FALSE;
  1334. }
  1335. // Seek back to the original position in the spoolfile.
  1336. liOffset.QuadPart = -liOffset.QuadPart;
  1337. if (!(*fpSeekPrinter) (hPrinter, liOffset, NULL, FILE_CURRENT, FALSE)) {
  1338. return FALSE;
  1339. }
  1340. if(!(*fpSplReadPrinter) (hPrinter, pBuf, (DWORD) cbBuf)) {
  1341. WARNING("MemMapReadPrinter: Read printer failed\n");
  1342. return FALSE;
  1343. }
  1344. return TRUE;
  1345. }
  1346. BOOL WINAPI GdiPlayEMF(
  1347. LPWSTR pwszPrinterName,
  1348. LPDEVMODEW pDevmode,
  1349. LPWSTR pwszDocName,
  1350. EMFPLAYPROC pfnEMFPlayFn,
  1351. HANDLE hPageQuery
  1352. )
  1353. /*++
  1354. Function Description:
  1355. GdiPlayEMF is the old playback function. It has been replaced by a
  1356. bunch of new GDI interfaces which give more flexibility to the print
  1357. processor on placing and reordering the pages of the print job. This
  1358. function has been rewritten to use these new interfaces (for backward
  1359. compatibility and maintainance)
  1360. Parameters:
  1361. Return Values:
  1362. If the function succeeds, the return value is TRUE;
  1363. otherwise the result is FALSE.
  1364. History:
  1365. 8/15/1997 by Ramanathan N Venkatapathy [ramanv]
  1366. --*/
  1367. {
  1368. HANDLE hSpoolHandle, hEMF;
  1369. HDC hPrinterDC;
  1370. BOOL bReturn = FALSE;
  1371. DOCINFOW DocInfo;
  1372. DWORD dwPageType, dwPageNumber = 1;
  1373. RECT rectDocument;
  1374. LPDEVMODEW pCurrDM, pLastDM;
  1375. if (!(hSpoolHandle = GdiGetSpoolFileHandle(pwszPrinterName,
  1376. pDevmode,
  1377. pwszDocName)) ||
  1378. !(hPrinterDC = GdiGetDC(hSpoolHandle))) {
  1379. goto CleanUp;
  1380. }
  1381. DocInfo.cbSize = sizeof(DOCINFOW);
  1382. DocInfo.lpszDocName = pwszDocName;
  1383. DocInfo.lpszOutput = NULL;
  1384. DocInfo.lpszDatatype = NULL;
  1385. rectDocument.left = rectDocument.top = 0;
  1386. rectDocument.right = GetDeviceCaps(hPrinterDC, DESKTOPHORZRES);
  1387. rectDocument.bottom = GetDeviceCaps(hPrinterDC, DESKTOPVERTRES);
  1388. if (!GdiStartDocEMF(hSpoolHandle, &DocInfo)) {
  1389. goto CleanUp;
  1390. }
  1391. while (1) {
  1392. hEMF = GdiGetPageHandle(hSpoolHandle,
  1393. dwPageNumber,
  1394. &dwPageType);
  1395. if (!hEMF) {
  1396. if (GetLastError() == ERROR_NO_MORE_ITEMS) {
  1397. break;
  1398. } else {
  1399. goto CleanUp;
  1400. }
  1401. }
  1402. if (!GdiGetDevmodeForPage(hSpoolHandle, dwPageNumber,
  1403. &pCurrDM, &pLastDM)) {
  1404. goto CleanUp;
  1405. }
  1406. if ((pCurrDM != pLastDM) && !GdiResetDCEMF(hSpoolHandle,
  1407. pCurrDM)) {
  1408. goto CleanUp;
  1409. }
  1410. if (!SetGraphicsMode(hPrinterDC, GM_ADVANCED)) {
  1411. goto CleanUp;
  1412. }
  1413. if (!GdiStartPageEMF(hSpoolHandle) ||
  1414. !GdiPlayPageEMF(hSpoolHandle, hEMF, &rectDocument, NULL, NULL) ||
  1415. !GdiEndPageEMF(hSpoolHandle, 0)) {
  1416. goto CleanUp;
  1417. }
  1418. ++dwPageNumber;
  1419. }
  1420. GdiEndDocEMF(hSpoolHandle);
  1421. bReturn = TRUE;
  1422. CleanUp:
  1423. if (hSpoolHandle) {
  1424. GdiDeleteSpoolFileHandle(hSpoolHandle);
  1425. }
  1426. return bReturn;
  1427. }
  1428. BOOL WINAPI GdiDeleteSpoolFileHandle(
  1429. HANDLE SpoolFileHandle)
  1430. /*
  1431. Function Description:
  1432. GdiDeleteSpoolFileHandle frees all the resources allocated by GDI for printing
  1433. the corresponding job. This function should be called by the print processor just
  1434. before it returns.
  1435. Parameters:
  1436. SpoolFileHandle - Handle returned by GdiGetSpoolFileHandle.
  1437. Return Values:
  1438. If the function succeeds, the return value is TRUE;
  1439. otherwise the result is FALSE.
  1440. History:
  1441. 5/12/1995 by Gerrit van Wingerden [gerritv] - Author
  1442. 5/15/1997 by Ramanathan N Venkatapathy [ramanv] -
  1443. Freed more resources associated with the SpoolFileHandle
  1444. */
  1445. {
  1446. SPOOL_FILE_HANDLE *pSpoolFileHandle;
  1447. LPDEVMODEW pLastDevmode;
  1448. UINT PageCount;
  1449. PRECORD_INFO_STRUCT pRecordInfo = NULL, pRecordInfoFree = NULL;
  1450. DWORD dwIndex;
  1451. PEMF_HANDLE pTemp;
  1452. pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
  1453. // first check to see if this is a valid handle by checking for the tag
  1454. try
  1455. {
  1456. if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
  1457. {
  1458. WARNING("GdiDeleteSpoolFileHandle: invalid handle\n");
  1459. return(FALSE);
  1460. }
  1461. }
  1462. except(EXCEPTION_EXECUTE_HANDLER)
  1463. {
  1464. WARNING("GdiDeleteSpoolFileHandle: exception accessing handle\n");
  1465. return(FALSE);
  1466. }
  1467. // Loop through all the page records, find the last page on which each DEVMODE is used
  1468. // and free it. The first DEVMODE is always allocated along with the memory for
  1469. // the spool file handle so never free that one. All DEVMODEs different than the original one
  1470. // must be non-NULL since they appear in the spool file.
  1471. for(PageCount = 0, pLastDevmode = pSpoolFileHandle->pOriginalDevmode;
  1472. PageCount < pSpoolFileHandle->MaxPageProcessed;
  1473. PageCount += 1 )
  1474. {
  1475. if(pSpoolFileHandle->pPageInfo[PageCount].pDevmode != pLastDevmode)
  1476. {
  1477. if(pLastDevmode != pSpoolFileHandle->pOriginalDevmode)
  1478. {
  1479. LocalFree(pLastDevmode);
  1480. }
  1481. pLastDevmode = pSpoolFileHandle->pPageInfo[PageCount].pDevmode;
  1482. }
  1483. }
  1484. // free the last DEVMODE used if it is not the original DEVMODE
  1485. if(pLastDevmode != pSpoolFileHandle->pOriginalDevmode)
  1486. {
  1487. LocalFree(pLastDevmode);
  1488. }
  1489. // free the PAGE_INFO_STRUCT array and lists held in them
  1490. if (pSpoolFileHandle->pPageInfo) {
  1491. for (dwIndex = pSpoolFileHandle->MaxPageProcessed; dwIndex; --dwIndex) {
  1492. pRecordInfo = pSpoolFileHandle->pPageInfo[dwIndex-1].pRecordInfo;
  1493. while (pRecordInfoFree = pRecordInfo) {
  1494. pRecordInfo = pRecordInfo->pNext;
  1495. LocalFree(pRecordInfoFree);
  1496. }
  1497. }
  1498. LocalFree(pSpoolFileHandle->pPageInfo);
  1499. }
  1500. // free the list of EMF_HANDLEs returned to the print processor
  1501. while (pTemp = pSpoolFileHandle->pEMFHandle) {
  1502. pSpoolFileHandle->pEMFHandle = (pSpoolFileHandle->pEMFHandle)->pNext;
  1503. if (pTemp->hemf) {
  1504. InternalDeleteEnhMetaFile(pTemp->hemf, pTemp->bAllocBuffer);
  1505. }
  1506. LocalFree(pTemp);
  1507. }
  1508. // free the DC
  1509. DeleteDC(pSpoolFileHandle->hdc);
  1510. // then the spooler's spool handle
  1511. (*fpClosePrinter)(pSpoolFileHandle->hSpooler);
  1512. // finally free the data associated with this handle
  1513. LocalFree(pSpoolFileHandle);
  1514. return(TRUE);
  1515. }
  1516. HANDLE WINAPI GdiGetSpoolFileHandle(
  1517. LPWSTR pwszPrinterName,
  1518. LPDEVMODEW pDevmode,
  1519. LPWSTR pwszDocName)
  1520. /*
  1521. Function Description:
  1522. GdiGetSpoolFileHandle is the first function that should be called by the
  1523. print processor. It returns a handle that will be needed for all the
  1524. subsequent calls. The function performs initializations of opening the
  1525. printer, creating a device context and allocating memory for the handle.
  1526. Parameters:
  1527. pwszPrinterName - Identifies the printer on which the job is to printed.
  1528. pDevmode - Pointer to a DEVMODE structure.
  1529. pwszDocName - Identifies the document name of job.
  1530. Return Values:
  1531. If the function succeeds, the return value is a valid HANDLE;
  1532. otherwise the result is NULL.
  1533. History:
  1534. 5/12/1995 by Gerrit van Wingerden [gerritv] - Author
  1535. 5/15/1997 by Ramanathan N Venkatapathy [ramanv] -
  1536. Handled NULL devmode case.
  1537. */
  1538. {
  1539. SPOOL_FILE_HANDLE *pHandle;
  1540. if( !BLOADSPOOLER )
  1541. {
  1542. WARNING("GdiGetSpoolFileHandle: Unable to load spooler\n");
  1543. return(FALSE);
  1544. }
  1545. if(pHandle = LOCALALLOC(sizeof(SPOOL_FILE_HANDLE) +
  1546. ((pDevmode != NULL) ? pDevmode->dmSize+pDevmode->dmDriverExtra
  1547. : 0 )))
  1548. {
  1549. // Zero out the SPOOL_FILE_HANDLE
  1550. RtlZeroMemory(pHandle , sizeof(SPOOL_FILE_HANDLE) +
  1551. ((pDevmode != NULL) ? pDevmode->dmSize+pDevmode->dmDriverExtra
  1552. : 0));
  1553. if((*fpOpenPrinterW)(pwszDocName, &pHandle->hSpooler,
  1554. (LPPRINTER_DEFAULTSW) NULL ) &&
  1555. pHandle->hSpooler)
  1556. {
  1557. if(pHandle->hdc = CreateDCW(L"", pwszPrinterName, L"", pDevmode))
  1558. {
  1559. pHandle->PageInfoBufferSize = 20;
  1560. if(pHandle->pPageInfo = LOCALALLOC(sizeof(PAGE_INFO_STRUCT) *
  1561. pHandle->PageInfoBufferSize))
  1562. {
  1563. pHandle->tag = SPOOL_FILE_HANDLE_TAG;
  1564. if (pDevmode) {
  1565. pHandle->pOriginalDevmode = (LPDEVMODEW) (pHandle + 1);
  1566. memcpy(pHandle->pOriginalDevmode, pDevmode,pDevmode->dmSize+pDevmode->dmDriverExtra);
  1567. } else {
  1568. pHandle->pOriginalDevmode = NULL;
  1569. }
  1570. pHandle->pLastDevmode = pHandle->pOriginalDevmode;
  1571. pHandle->MaxPageProcessed = 0;
  1572. pHandle->pEMFHandle = NULL;
  1573. RtlZeroMemory(pHandle->pPageInfo,
  1574. sizeof(PAGE_INFO_STRUCT) * pHandle->PageInfoBufferSize);
  1575. pHandle->dwPlayBackStatus = EMF_PLAY_FORCE_MONOCHROME;
  1576. if (pHandle->pLastDevmode &&
  1577. (pHandle->pLastDevmode->dmFields & DM_COLOR) &&
  1578. (pHandle->pLastDevmode->dmColor == DMCOLOR_COLOR)) {
  1579. pHandle->dwPlayBackStatus = EMF_PLAY_COLOR;
  1580. }
  1581. pHandle->bUseMemMap = TRUE;
  1582. return((HANDLE) pHandle);
  1583. }
  1584. else
  1585. {
  1586. WARNING("GdiGetSpoolFileHandle: OutOfMemory\n");
  1587. }
  1588. DeleteDC(pHandle->hdc);
  1589. }
  1590. else
  1591. {
  1592. WARNING("GdiGetSpoolHandle: CreateDCW failed\n");
  1593. }
  1594. (*fpClosePrinter)(pHandle->hSpooler);
  1595. }
  1596. LocalFree(pHandle);
  1597. }
  1598. return((HANDLE) NULL);
  1599. }
  1600. BOOL ProcessJob(
  1601. SPOOL_FILE_HANDLE *pSpoolFileHandle
  1602. )
  1603. {
  1604. LARGE_INTEGER LargeInt;
  1605. EMFSPOOLHEADER emsh;
  1606. EMFITEMHEADER emfi;
  1607. // Seek to offset 0.
  1608. LargeInt.QuadPart = 0;
  1609. if (!((*fpSeekPrinter)(pSpoolFileHandle->hSpooler, LargeInt, NULL, 0,FALSE)))
  1610. {
  1611. WARNING("GDI32 ProcessJob: seek printer to 0 failed\n");
  1612. return(FALSE);
  1613. }
  1614. // Read EMFSPOOLHEADER
  1615. if(!MyReadPrinter(pSpoolFileHandle->hSpooler, (BYTE*) &emsh, sizeof(emsh)))
  1616. {
  1617. WARNING("GDI32 ProcessJob: MyReadPrinter to read EMFSPOOLHEADER failed\n");
  1618. return(FALSE);
  1619. }
  1620. // Move Offset to next record.
  1621. LargeInt.QuadPart = emsh.cjSize;
  1622. if (!((*fpSeekPrinter)(pSpoolFileHandle->hSpooler, LargeInt, NULL, 0,FALSE)))
  1623. {
  1624. WARNING("GDI32 ProcessPages: seek printer failed\n");
  1625. return(FALSE);
  1626. }
  1627. // Read next EMFITEMHEADER
  1628. if(!MyReadPrinter(pSpoolFileHandle->hSpooler, (BYTE*) &emfi, sizeof(emfi)))
  1629. {
  1630. WARNING("GDI32 ProcessJob: MyReadPrinter to read EMFSPOOLHEADER failed\n");
  1631. return(FALSE);
  1632. }
  1633. // If this is EMRI_PS_JOB_DATA, process this record.
  1634. if (emfi.ulID == EMRI_PS_JOB_DATA)
  1635. {
  1636. PBYTE pPSBuffer = LOCALALLOC(emfi.cjSize);
  1637. if (pPSBuffer)
  1638. {
  1639. if (MyReadPrinter(pSpoolFileHandle->hSpooler, pPSBuffer, emfi.cjSize))
  1640. {
  1641. DWORD cjSizeProcessed = 0;
  1642. PEMFITEMPSINJECTIONDATA pPSData = (PEMFITEMPSINJECTIONDATA) pPSBuffer;
  1643. while (cjSizeProcessed < emfi.cjSize)
  1644. {
  1645. ExtEscape(pSpoolFileHandle->hdc,
  1646. pPSData->nEscape,
  1647. pPSData->cjInput,
  1648. (PVOID)&(pPSData->EscapeData),
  1649. 0, NULL);
  1650. cjSizeProcessed += pPSData->cjSize;
  1651. // Move to next record.
  1652. pPSData = (PEMFITEMPSINJECTIONDATA) ((PBYTE)pPSData + pPSData->cjSize);
  1653. }
  1654. }
  1655. else
  1656. {
  1657. WARNING("GDI32 ProcessJob: MyReadPrinter to read EMFSPOOLHEADER failed\n");
  1658. LOCALFREE(pPSBuffer);
  1659. return(FALSE);
  1660. }
  1661. LOCALFREE(pPSBuffer);
  1662. }
  1663. else
  1664. {
  1665. WARNING("GDI32 ProcessJob: failed on LOCALALLOC\n");
  1666. return(FALSE);
  1667. }
  1668. }
  1669. // Seek back to offset 0.
  1670. LargeInt.QuadPart = 0;
  1671. (*fpSeekPrinter)(pSpoolFileHandle->hSpooler, LargeInt, NULL, 0,FALSE);
  1672. return (TRUE);
  1673. }
  1674. BOOL ProcessPages(
  1675. SPOOL_FILE_HANDLE *pSpoolFileHandle,
  1676. UINT LastPage
  1677. )
  1678. /*
  1679. Function Description:
  1680. ProcessPages parses the spool file and processes the EMF records until the
  1681. required page.
  1682. Parameters:
  1683. SpoolFileHandle - Handle returned by GdiGetSpoolFileHandle.
  1684. LastPage - Page number to process.
  1685. Return Values:
  1686. If the function succeeds, the return value is TRUE;
  1687. otherwise the result is FALSE.
  1688. History:
  1689. 5/12/1995 by Gerrit van Wingerden [gerritv] - Author
  1690. 5/15/1997 by Ramanathan N Venkatapathy [ramanv] -
  1691. Added code to handle DELTA_FONT, SUBSET_FONT, DESIGN_VECTOR
  1692. and PRESTARTPAGE.
  1693. 1/28/1998 by Ramanathan N Venkatapathy [ramanv] -
  1694. Process EXT records
  1695. */
  1696. {
  1697. LARGE_INTEGER LargeInt;
  1698. LONGLONG CurrentOffset, EMFOffset;
  1699. ULONG CurrentPage;
  1700. LPDEVMODEW pLastDevmode = NULL;
  1701. EMFITEMHEADER emfi, emfiExt;
  1702. BYTE *pTmpBuffer = NULL;
  1703. UNIVERSAL_FONT_ID ufi;
  1704. ULONG ulBytesWritten;
  1705. PVOID pvMergeBuf;
  1706. PRECORD_INFO_STRUCT pRecordInfo;
  1707. BOOL bReadPrinter = FALSE;
  1708. INT64 iOffset;
  1709. DWORD dwSize;
  1710. BOOL bLastDevmodeAllocated = FALSE;
  1711. // early exit if we've already processed the requested number of pages
  1712. if(pSpoolFileHandle->MaxPageProcessed >= LastPage)
  1713. {
  1714. //When a document is being printed back-to-front and is restarted in
  1715. //the middle of the job, we won't detect the error in the normal way.
  1716. //So we call SeekPrinter with NOOP arguments to check for the
  1717. //ERROR_PRINT_CANCELLED return value.
  1718. BOOL fSeekResult;
  1719. LargeInt.QuadPart = 0;
  1720. fSeekResult = ((*fpSeekPrinter)(pSpoolFileHandle->hSpooler, LargeInt,
  1721. NULL, FILE_CURRENT, FALSE));
  1722. return fSeekResult || GetLastError() != ERROR_PRINT_CANCELLED;
  1723. }
  1724. // allocate memory to store info for all pages if the existing buffer isn't large
  1725. // enough
  1726. if(LastPage > pSpoolFileHandle->PageInfoBufferSize)
  1727. {
  1728. PAGE_INFO_STRUCT *pTemp;
  1729. if(pTemp = LOCALALLOC(sizeof(PAGE_INFO_STRUCT) * LastPage))
  1730. {
  1731. RtlZeroMemory(pTemp, sizeof(PAGE_INFO_STRUCT) * LastPage);
  1732. memcpy(pTemp,
  1733. pSpoolFileHandle->pPageInfo,
  1734. sizeof(PAGE_INFO_STRUCT) * pSpoolFileHandle->MaxPageProcessed);
  1735. pSpoolFileHandle->PageInfoBufferSize = LastPage;
  1736. LocalFree(pSpoolFileHandle->pPageInfo);
  1737. pSpoolFileHandle->pPageInfo = pTemp;
  1738. }
  1739. else
  1740. {
  1741. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1742. WARNING("GDI32 ProcessPages: out of memory\n");
  1743. return(FALSE);
  1744. }
  1745. }
  1746. // if we've already processed some pages then start with the last page processed
  1747. if(pSpoolFileHandle->MaxPageProcessed)
  1748. {
  1749. CurrentOffset =
  1750. pSpoolFileHandle->pPageInfo[pSpoolFileHandle->MaxPageProcessed-1].SeekOffset;
  1751. pLastDevmode =
  1752. pSpoolFileHandle->pPageInfo[pSpoolFileHandle->MaxPageProcessed-1].pDevmode;
  1753. }
  1754. else
  1755. {
  1756. EMFSPOOLHEADER emsh;
  1757. LargeInt.QuadPart = 0;
  1758. if (!((*fpSeekPrinter)(pSpoolFileHandle->hSpooler, LargeInt, NULL, 0,FALSE)))
  1759. {
  1760. WARNING("GDI32 ProcessPages: seek printer to 0 failed\n");
  1761. return(FALSE);
  1762. }
  1763. if(!MyReadPrinter(pSpoolFileHandle->hSpooler, (BYTE*) &emsh, sizeof(emsh)))
  1764. {
  1765. WARNING("GDI32 ProcessPages: MyReadPrinter failed\n");
  1766. return(FALSE);
  1767. }
  1768. CurrentOffset = emsh.cjSize;
  1769. pLastDevmode = pSpoolFileHandle->pOriginalDevmode;
  1770. }
  1771. LargeInt.QuadPart = CurrentOffset;
  1772. if (!((*fpSeekPrinter)(pSpoolFileHandle->hSpooler,
  1773. LargeInt, NULL,
  1774. 0,FALSE)))
  1775. {
  1776. WARNING("GDI32 ProcessPages: seek printer failed\n");
  1777. return(FALSE);
  1778. }
  1779. CurrentPage = pSpoolFileHandle->MaxPageProcessed;
  1780. while ((CurrentPage < LastPage) &&
  1781. MyReadPrinter(pSpoolFileHandle->hSpooler, (BYTE*) &emfi, sizeof(emfi))) {
  1782. CurrentOffset += sizeof(emfi);
  1783. if (emfi.cjSize == 0)
  1784. {
  1785. continue;
  1786. }
  1787. bReadPrinter = FALSE;
  1788. // For records to be processed now, read into a buffer
  1789. if ((emfi.ulID == EMRI_DEVMODE) ||
  1790. (emfi.ulID == EMRI_ENGINE_FONT) ||
  1791. (emfi.ulID == EMRI_TYPE1_FONT) ||
  1792. (emfi.ulID == EMRI_SUBSET_FONT) ||
  1793. (emfi.ulID == EMRI_DELTA_FONT) ||
  1794. (emfi.ulID == EMRI_DESIGNVECTOR)) {
  1795. if (pTmpBuffer = (BYTE*) LOCALALLOC(emfi.cjSize)) {
  1796. if(MyReadPrinter(pSpoolFileHandle->hSpooler,
  1797. pTmpBuffer, emfi.cjSize)) {
  1798. bReadPrinter = TRUE;
  1799. dwSize = emfi.cjSize;
  1800. } else {
  1801. WARNING("Gdi32: Process Pages error reading font or devmode\n");
  1802. goto exit;
  1803. }
  1804. } else {
  1805. WARNING("Out of memory in ProcessPages\n");
  1806. goto exit;
  1807. }
  1808. } else if ((emfi.ulID == EMRI_ENGINE_FONT_EXT) ||
  1809. (emfi.ulID == EMRI_TYPE1_FONT_EXT) ||
  1810. (emfi.ulID == EMRI_SUBSET_FONT_EXT) ||
  1811. (emfi.ulID == EMRI_DELTA_FONT_EXT) ||
  1812. (emfi.ulID == EMRI_DESIGNVECTOR_EXT) ||
  1813. (emfi.ulID == EMRI_EMBED_FONT_EXT)) {
  1814. // For EXT records get the buffer from an offset
  1815. if (emfi.cjSize < sizeof(INT64)) {
  1816. WARNING("Ext Record bad size\n");
  1817. goto exit;
  1818. }
  1819. if (MyReadPrinter(pSpoolFileHandle->hSpooler, (PBYTE) &iOffset, sizeof(INT64)) &&
  1820. (iOffset > 0)) {
  1821. LargeInt.QuadPart = -1 * (iOffset + sizeof(emfi) + sizeof(INT64));
  1822. if ((*fpSeekPrinter)(pSpoolFileHandle->hSpooler,
  1823. LargeInt, NULL, FILE_CURRENT, FALSE) &&
  1824. MyReadPrinter(pSpoolFileHandle->hSpooler, (BYTE*) &emfiExt,
  1825. sizeof(emfiExt))) {
  1826. if (pTmpBuffer = (BYTE*) LOCALALLOC(emfiExt.cjSize)) {
  1827. if (!MyReadPrinter(pSpoolFileHandle->hSpooler,
  1828. pTmpBuffer, emfiExt.cjSize)) {
  1829. WARNING("Gdi32: Process Pages error reading font or devmode\n");
  1830. goto exit;
  1831. }
  1832. dwSize = emfiExt.cjSize;
  1833. } else {
  1834. WARNING("Out of memory in ProcessPages\n");
  1835. goto exit;
  1836. }
  1837. // We will seek back to the correct position after the switch
  1838. } else {
  1839. WARNING("SeekPrinter or MyReadPrinter fail in ProcessPages\n");
  1840. goto exit;
  1841. }
  1842. } else {
  1843. WARNING("MyReadPrinter fails in ProcessPages\n");
  1844. goto exit;
  1845. }
  1846. }
  1847. switch (emfi.ulID)
  1848. {
  1849. case EMRI_METAFILE:
  1850. case EMRI_FORM_METAFILE:
  1851. case EMRI_BW_METAFILE:
  1852. case EMRI_BW_FORM_METAFILE:
  1853. // it's a metafile so setup an entry for it
  1854. pSpoolFileHandle->pPageInfo[CurrentPage].pDevmode = pLastDevmode;
  1855. pSpoolFileHandle->pPageInfo[CurrentPage].EMFOffset = CurrentOffset;
  1856. pSpoolFileHandle->pPageInfo[CurrentPage].SeekOffset = CurrentOffset + emfi.cjSize;
  1857. pSpoolFileHandle->pPageInfo[CurrentPage].EMFSize = emfi.cjSize;
  1858. pSpoolFileHandle->pPageInfo[CurrentPage].ulID = emfi.ulID;
  1859. pSpoolFileHandle->MaxPageProcessed += 1;
  1860. bLastDevmodeAllocated = FALSE;
  1861. CurrentPage += 1;
  1862. break;
  1863. case EMRI_METAFILE_EXT:
  1864. case EMRI_BW_METAFILE_EXT:
  1865. // it's a metafile at an offset
  1866. if (emfi.cjSize < sizeof(INT64)) {
  1867. WARNING("Ext Record bad size\n");
  1868. goto exit;
  1869. }
  1870. if (MyReadPrinter(pSpoolFileHandle->hSpooler, (PBYTE) &iOffset, sizeof(INT64)) &&
  1871. (iOffset > 0)) {
  1872. LargeInt.QuadPart = -1 * (iOffset + sizeof(emfi) + sizeof(INT64));
  1873. if ((*fpSeekPrinter)(pSpoolFileHandle->hSpooler,
  1874. LargeInt, NULL, FILE_CURRENT, FALSE) &&
  1875. MyReadPrinter(pSpoolFileHandle->hSpooler, (BYTE*) &emfiExt,
  1876. sizeof(emfiExt))) {
  1877. pSpoolFileHandle->pPageInfo[CurrentPage].pDevmode = pLastDevmode;
  1878. bLastDevmodeAllocated = FALSE;
  1879. EMFOffset = CurrentOffset - (LONGLONG) iOffset;
  1880. if (EMFOffset) {
  1881. pSpoolFileHandle->pPageInfo[CurrentPage].EMFOffset = EMFOffset;
  1882. } else {
  1883. WARNING("Bad Ext Record\n");
  1884. goto exit;
  1885. }
  1886. pSpoolFileHandle->pPageInfo[CurrentPage].SeekOffset =
  1887. CurrentOffset + emfi.cjSize;
  1888. pSpoolFileHandle->pPageInfo[CurrentPage].EMFSize = emfiExt.cjSize;
  1889. pSpoolFileHandle->pPageInfo[CurrentPage].ulID =
  1890. (emfi.ulID == EMRI_METAFILE_EXT) ? EMRI_METAFILE
  1891. : EMRI_BW_METAFILE;
  1892. pSpoolFileHandle->MaxPageProcessed += 1;
  1893. CurrentPage += 1;
  1894. break;
  1895. // We will seek back to the correct position after the switch
  1896. }
  1897. }
  1898. WARNING("ReadPrinter or SeekPrinter failed\n");
  1899. goto exit;
  1900. case EMRI_DEVMODE:
  1901. if (!(*fpIsValidDevmodeW)((LPDEVMODEW) pTmpBuffer, dwSize))
  1902. {
  1903. EMFVALFAIL(("ProcessPages: fpIsValidDevmodeW failed\n"));
  1904. goto exit;
  1905. }
  1906. pLastDevmode = (LPDEVMODEW) pTmpBuffer;
  1907. pTmpBuffer = NULL;
  1908. bLastDevmodeAllocated = TRUE;
  1909. break;
  1910. case EMRI_METAFILE_DATA:
  1911. // Start of EMF data. Wait till EMRI_(BW_)METAFILE_EXT so that fonts can
  1912. // be correctly processed
  1913. break;
  1914. case EMRI_ENGINE_FONT:
  1915. case EMRI_ENGINE_FONT_EXT:
  1916. case EMRI_TYPE1_FONT:
  1917. case EMRI_TYPE1_FONT_EXT:
  1918. if (!NtGdiAddRemoteFontToDC(pSpoolFileHandle->hdc,
  1919. pTmpBuffer, dwSize , NULL))
  1920. {
  1921. WARNING("Error adding remote font\n");
  1922. goto exit;
  1923. }
  1924. if ((emfi.ulID == EMRI_TYPE1_FONT) ||
  1925. (emfi.ulID == EMRI_TYPE1_FONT_EXT))
  1926. {
  1927. // force ResetDC so Type1 fonts get loaded
  1928. pSpoolFileHandle->pLastDevmode = NULL;
  1929. }
  1930. break;
  1931. case EMRI_SUBSET_FONT:
  1932. case EMRI_SUBSET_FONT_EXT:
  1933. if (bMergeSubsetFont(pSpoolFileHandle->hdc, pTmpBuffer, dwSize,
  1934. &pvMergeBuf, &ulBytesWritten, FALSE, &ufi)) {
  1935. if (!NtGdiAddRemoteFontToDC(pSpoolFileHandle->hdc, pvMergeBuf,
  1936. ulBytesWritten, &ufi)) {
  1937. WARNING("Error adding subsetted font\n");
  1938. }
  1939. } else {
  1940. WARNING("Error merging subsetted fonts\n");
  1941. }
  1942. break;
  1943. case EMRI_DELTA_FONT:
  1944. case EMRI_DELTA_FONT_EXT:
  1945. if (bMergeSubsetFont(pSpoolFileHandle->hdc, pTmpBuffer, dwSize,
  1946. &pvMergeBuf, &ulBytesWritten, TRUE, &ufi)) {
  1947. if (NtGdiRemoveMergeFont(pSpoolFileHandle->hdc, &ufi)) {
  1948. if (!NtGdiAddRemoteFontToDC(pSpoolFileHandle->hdc, pvMergeBuf,
  1949. ulBytesWritten, &ufi)) {
  1950. WARNING("Error adding subsetted font\n");
  1951. }
  1952. } else {
  1953. WARNING("Error removing merged font\n");
  1954. }
  1955. } else {
  1956. WARNING("Error merging subsetted fonts\n");
  1957. }
  1958. break;
  1959. case EMRI_DESIGNVECTOR:
  1960. case EMRI_DESIGNVECTOR_EXT:
  1961. MFD1("Unpackaging designvector \n");
  1962. if (!NtGdiAddRemoteMMInstanceToDC(pSpoolFileHandle->hdc,
  1963. (DOWNLOADDESIGNVECTOR *) pTmpBuffer,
  1964. dwSize)) {
  1965. WARNING("Error adding remote mm instance font\n");
  1966. }
  1967. break;
  1968. case EMRI_EMBED_FONT_EXT:
  1969. MFD1("Unpackaging embed fonts\n");
  1970. if (!NtGdiAddEmbFontToDC(pSpoolFileHandle->hdc,(VOID **) pTmpBuffer))
  1971. {
  1972. WARNING("Error adding embed font to DC\n");
  1973. }
  1974. break;
  1975. case EMRI_PRESTARTPAGE:
  1976. if (!(pRecordInfo =
  1977. (PRECORD_INFO_STRUCT) LOCALALLOC(sizeof(RECORD_INFO_STRUCT)))) {
  1978. WARNING("Out of memory in ProcessPages\n");
  1979. goto exit;
  1980. }
  1981. pRecordInfo->pNext = pSpoolFileHandle->pPageInfo[CurrentPage].pRecordInfo;
  1982. pSpoolFileHandle->pPageInfo[CurrentPage].pRecordInfo = pRecordInfo;
  1983. pRecordInfo->RecordID = emfi.ulID;
  1984. pRecordInfo->RecordSize = emfi.cjSize;
  1985. pRecordInfo->RecordOffset = CurrentOffset;
  1986. break;
  1987. case EMRI_PS_JOB_DATA:
  1988. // Already processed at GdiStartDocEMF().
  1989. break;
  1990. default:
  1991. WARNING("GDI32: ProcessPages: Unknown ITEM record\n");
  1992. goto exit;
  1993. break;
  1994. }
  1995. if (emfi.ulID == EMRI_METAFILE || emfi.ulID == EMRI_FORM_METAFILE)
  1996. {
  1997. ENHMETAHEADER *pemrh = ( ENHMETAHEADER *)&emfi;
  1998. CurrentOffset += pemrh->nBytes - sizeof(emfi);
  1999. }
  2000. else
  2001. {
  2002. CurrentOffset += emfi.cjSize;
  2003. }
  2004. LargeInt.QuadPart = CurrentOffset;
  2005. if(!bReadPrinter && !(*fpSeekPrinter)(pSpoolFileHandle->hSpooler,
  2006. LargeInt, NULL, 0, FALSE))
  2007. {
  2008. WARNING("GDI32 Process Pages: seekprinter failed\n");
  2009. goto exit;
  2010. }
  2011. //
  2012. // Release temp buffer each time through the loop.
  2013. //
  2014. if(pTmpBuffer)
  2015. {
  2016. LocalFree(pTmpBuffer);
  2017. pTmpBuffer = NULL;
  2018. }
  2019. }
  2020. exit:
  2021. //
  2022. // Release the temp buffer, it is a temp so it should not
  2023. // live beyond this subroutine.
  2024. //
  2025. if(pTmpBuffer)
  2026. {
  2027. LocalFree(pTmpBuffer);
  2028. }
  2029. //
  2030. // Only release the last devmode pointer if one was allocated.
  2031. //
  2032. if(pLastDevmode && bLastDevmodeAllocated)
  2033. {
  2034. LocalFree(pLastDevmode);
  2035. }
  2036. return(CurrentPage >= LastPage);
  2037. }
  2038. HDC WINAPI GdiGetDC(
  2039. HANDLE SpoolFileHandle)
  2040. /*
  2041. Function Description:
  2042. GdiGetDC returns a handle to the device context of the printer.
  2043. This handle can be used to apply transformations (translation, rotation, scaling etc)
  2044. before playing any page at the printer
  2045. Parameters:
  2046. SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
  2047. Return Values:
  2048. If the function succeeds, the return value is a valid HANDLE;
  2049. otherwise the result is NULL.
  2050. History:
  2051. 5/12/1995 by Gerrit van Wingerden [gerritv] - Author
  2052. */
  2053. {
  2054. SPOOL_FILE_HANDLE *pSpoolFileHandle;
  2055. pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
  2056. // first check to see if this is a valid handle by checking for the tag
  2057. try
  2058. {
  2059. if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
  2060. {
  2061. WARNING("GdiGetDC: invalid handle\n");
  2062. return(NULL);
  2063. }
  2064. }
  2065. except(EXCEPTION_EXECUTE_HANDLER)
  2066. {
  2067. WARNING("GdiGetDC: exception accessing handle\n");
  2068. return(NULL);
  2069. }
  2070. return(pSpoolFileHandle->hdc);
  2071. }
  2072. DWORD WINAPI GdiGetPageCount(
  2073. HANDLE SpoolFileHandle)
  2074. /*
  2075. Function Description:
  2076. GdiGetPageCount returns the number of pages in the print job. If print
  2077. while spooling option is used, GdiGetPageCount synchronously waits till
  2078. the job is completely spooled and then returns the page count.
  2079. Parameters:
  2080. SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
  2081. Return Values:
  2082. If the function succeeds, the return value is the page count
  2083. otherwise the result is 0.
  2084. History:
  2085. 5/12/1995 by Gerrit van Wingerden [gerritv] - Author
  2086. */
  2087. {
  2088. UINT Page = 10;
  2089. LARGE_INTEGER LargeInt;
  2090. SPOOL_FILE_HANDLE *pSpoolFileHandle;
  2091. pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
  2092. // first check to see if this is a valid handle by checking for the tag
  2093. try
  2094. {
  2095. if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
  2096. {
  2097. WARNING("GdiGetPageCount: invalid handle\n");
  2098. return 0;
  2099. }
  2100. }
  2101. except(EXCEPTION_EXECUTE_HANDLER)
  2102. {
  2103. WARNING("GdiGetPageCount: exception accessing handle\n");
  2104. return 0;
  2105. }
  2106. while(ProcessPages(pSpoolFileHandle, Page))
  2107. {
  2108. Page += 10;
  2109. }
  2110. LargeInt.QuadPart = 0;
  2111. if(!(*fpSeekPrinter)(pSpoolFileHandle->hSpooler, LargeInt, NULL, 0,
  2112. FALSE))
  2113. {
  2114. WARNING("GDI32 GdiGetPageCount: seek failed\n");
  2115. return 0;
  2116. }
  2117. return ((DWORD) pSpoolFileHandle->MaxPageProcessed);
  2118. }
  2119. HANDLE WINAPI GdiGetPageHandle(
  2120. HANDLE SpoolFileHandle,
  2121. DWORD Page,
  2122. LPDWORD pdwPageType)
  2123. /*
  2124. Function Description:
  2125. GdiGetPageHandle returns a handle to contents of the required page.
  2126. This handle should be used while playing the page at the printer. If the
  2127. spool file is not sufficiently large, the last error is set to ERROR_NO_MORE_ITEMS.
  2128. If print while spooling is supported, the print processor will have to examine
  2129. for this error code to determine the end of the print job. Using GdiGetPageCount
  2130. will stall the processing till the entire print job is spooled.
  2131. Parameters:
  2132. SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
  2133. Page -- number of the page required
  2134. pdwPageType -- pointer to store the type of the page (Normal/Watermark)
  2135. Return Values:
  2136. If the function succeeds, the return value is a valid HANDLE;
  2137. otherwise the result is NULL.
  2138. History:
  2139. 5/12/1995 by Gerrit van Wingerden [gerritv] - Author
  2140. 5/15/1997 by Ramanathan N Venkatapathy [ramanv] -
  2141. Changed the return value to a HANDLE that contains the page number along
  2142. with the handle to the EMF file
  2143. */
  2144. {
  2145. SPOOL_FILE_HANDLE *pSpoolFileHandle;
  2146. PEMF_HANDLE pEMF = NULL;
  2147. pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
  2148. // first check to see if this is a valid handle by checking for the tag
  2149. try
  2150. {
  2151. if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
  2152. {
  2153. WARNING("GdiGetPageHandle: invalid handle\n");
  2154. return(FALSE);
  2155. }
  2156. }
  2157. except(EXCEPTION_EXECUTE_HANDLER)
  2158. {
  2159. WARNING("GdiGetPageHandle: exception accessing handle\n");
  2160. return(NULL);
  2161. }
  2162. if(!ProcessPages(pSpoolFileHandle, (UINT) Page))
  2163. {
  2164. return(NULL);
  2165. }
  2166. if (pEMF = (PEMF_HANDLE) LOCALALLOC(sizeof(EMF_HANDLE))) {
  2167. pEMF->tag = EMF_HANDLE_TAG;
  2168. pEMF->hemf = NULL;
  2169. pEMF->bAllocBuffer = FALSE;
  2170. pEMF->dwPageNumber = Page;
  2171. if (pdwPageType) {
  2172. switch (pSpoolFileHandle->pPageInfo[Page-1].ulID) {
  2173. case EMRI_METAFILE:
  2174. case EMRI_BW_METAFILE:
  2175. *pdwPageType = EMF_PP_NORMAL;
  2176. break;
  2177. case EMRI_FORM_METAFILE:
  2178. case EMRI_BW_FORM_METAFILE:
  2179. *pdwPageType = EMF_PP_FORM;
  2180. break;
  2181. default:
  2182. // should not occur
  2183. *pdwPageType = 0;
  2184. break;
  2185. }
  2186. }
  2187. // Save the handle in spoolfilehandle to be freed later
  2188. pEMF->pNext = pSpoolFileHandle->pEMFHandle;
  2189. pSpoolFileHandle->pEMFHandle = pEMF;
  2190. } else {
  2191. WARNING("GDI32 GdiGetPageHandle: out of memory\n");
  2192. }
  2193. return ((HANDLE) pEMF);
  2194. }
  2195. BOOL WINAPI GdiStartDocEMF(
  2196. HANDLE SpoolFileHandle,
  2197. DOCINFOW *pDocInfo)
  2198. /*
  2199. Function Description:
  2200. GdiStartDocEMF performs the initializations required for before printing
  2201. a document. It calls StartDoc and allocates memory to store data about the
  2202. page layout. It also sets up the banding field in the SpoolFileHandle.
  2203. Parameters:
  2204. SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
  2205. pDocInfo -- pointer to DOCINFOW struct containing information of
  2206. the job. This struct is required for StartDoc.
  2207. Return Values:
  2208. If the function succeeds, the return value is TRUE;
  2209. otherwise the result is FALSE.
  2210. History:
  2211. 5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
  2212. */
  2213. {
  2214. SPOOL_FILE_HANDLE *pSpoolFileHandle;
  2215. pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
  2216. // first check to see if this is a valid handle by checking for the tag
  2217. try
  2218. {
  2219. if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
  2220. {
  2221. WARNING("GdiStartDocEMF: invalid handle\n");
  2222. return(FALSE);
  2223. }
  2224. }
  2225. except(EXCEPTION_EXECUTE_HANDLER)
  2226. {
  2227. WARNING("GdiStartDocEMF: exception accessing handle\n");
  2228. return(FALSE);
  2229. }
  2230. // Process Job data (before StartDoc)
  2231. if (!ProcessJob(pSpoolFileHandle))
  2232. {
  2233. WARNING("StartDocW failed at ProcessJob\n");
  2234. return(FALSE);
  2235. }
  2236. // StartDoc and get banding information
  2237. if (StartDocEMF(pSpoolFileHandle->hdc,
  2238. pDocInfo,
  2239. &(pSpoolFileHandle->bBanding)) == SP_ERROR) {
  2240. WARNING("StartDocW failed at StartDocEMF\n");
  2241. return(FALSE);
  2242. }
  2243. pSpoolFileHandle->dwNumberOfPagesInCurrSide = 0;
  2244. pSpoolFileHandle->dwNumberOfPagesAllocated = SPOOL_FILE_MAX_NUMBER_OF_PAGES_PER_SIDE;
  2245. // Allocate memory for page layout
  2246. if (!(pSpoolFileHandle->pPageLayout = LOCALALLOC(sizeof(PAGE_LAYOUT_STRUCT) *
  2247. pSpoolFileHandle->dwNumberOfPagesAllocated))) {
  2248. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2249. WARNING("GDI32 GdiStartDocEMF: out of memory\n");
  2250. return(FALSE);
  2251. }
  2252. return(TRUE);
  2253. }
  2254. BOOL WINAPI GdiStartPageEMF(
  2255. HANDLE SpoolFileHandle)
  2256. /*
  2257. Function Description:
  2258. GdiStartPageEMF performs the initializations required before printing
  2259. a page.
  2260. Parameters:
  2261. SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
  2262. Return Values:
  2263. If the function succeeds, the return value is TRUE;
  2264. otherwise the result is FALSE.
  2265. History:
  2266. 5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
  2267. */
  2268. {
  2269. SPOOL_FILE_HANDLE *pSpoolFileHandle;
  2270. pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
  2271. // first check to see if this is a valid handle by checking for the tag
  2272. try
  2273. {
  2274. if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
  2275. {
  2276. WARNING("GdiStartPageEMF: invalid handle\n");
  2277. return(FALSE);
  2278. }
  2279. }
  2280. except(EXCEPTION_EXECUTE_HANDLER)
  2281. {
  2282. WARNING("GdiStartPageEMF: exception accessing handle\n");
  2283. return(FALSE);
  2284. }
  2285. return(TRUE);
  2286. }
  2287. BOOL WINAPI GdiPlayPageEMF(
  2288. HANDLE SpoolFileHandle,
  2289. HANDLE hEMF,
  2290. RECT *prectDocument,
  2291. RECT *prectBorder,
  2292. RECT *prectClip)
  2293. /*
  2294. Function Description:
  2295. GdiPlayPageEMF allows the print processor to play any EMF page inside a
  2296. specified rectangle. It also draws a border around the page, if one is specified.
  2297. GdiPlayPageEMF saves all the information required for playing the page in the
  2298. SpoolFileHandle. When GdiEndPageEMF is called to eject the current physical page,
  2299. all the logical pages are played in the correct positions and the page is ejected.
  2300. This delayed printing operation is used to enable n-up printing with banding.
  2301. Parameters:
  2302. SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
  2303. hEMF -- handle returned by GdiGetEMFFromSpoolHandle
  2304. prectDocument -- pointer to the RECT containing coordinates where
  2305. the page is to be played
  2306. prectBorder -- pointer to the RECT containing coordinates where
  2307. the border (if any) is to be drawn
  2308. prectClip -- pointer to the RECT containing coordinates where
  2309. the page is to clipped
  2310. Return Values:
  2311. If the function succeeds, the return value is TRUE;
  2312. otherwise the result is FALSE.
  2313. History:
  2314. 5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
  2315. */
  2316. {
  2317. SPOOL_FILE_HANDLE *pSpoolFileHandle;
  2318. PAGE_LAYOUT_STRUCT *pPageLayout;
  2319. PEMF_HANDLE pEMF;
  2320. LPBYTE pBuffer = NULL;
  2321. HANDLE hFile = NULL;
  2322. BOOL bAllocBuffer = FALSE;
  2323. ULONG Size;
  2324. LARGE_INTEGER Offset;
  2325. HENHMETAFILE hEMFPage = NULL;
  2326. DWORD dwPageNumber;
  2327. pEMF = (PEMF_HANDLE) hEMF;
  2328. pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
  2329. // first check to see if this is a valid handle by checking for the tag
  2330. try
  2331. {
  2332. if ((pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG) ||
  2333. (pEMF->tag != EMF_HANDLE_TAG))
  2334. {
  2335. WARNING("GdiPlayPageEMF: invalid handle\n");
  2336. return(FALSE);
  2337. }
  2338. }
  2339. except(EXCEPTION_EXECUTE_HANDLER)
  2340. {
  2341. WARNING("GdiPlayPageEMF: exception accessing handle\n");
  2342. return(FALSE);
  2343. }
  2344. dwPageNumber = pEMF->dwPageNumber;
  2345. if (pEMF->hemf == NULL) {
  2346. // Allocate the EMF handle
  2347. Size = pSpoolFileHandle->pPageInfo[dwPageNumber-1].EMFSize;
  2348. Offset.QuadPart = pSpoolFileHandle->pPageInfo[dwPageNumber-1].EMFOffset;
  2349. // Use memory mapped read first and buffered next
  2350. if (pSpoolFileHandle->bUseMemMap) {
  2351. if ((*fpSeekPrinter) (pSpoolFileHandle->hSpooler, Offset, NULL, 0, FALSE) &&
  2352. MemMapReadPrinter(pSpoolFileHandle->hSpooler, &pBuffer, Size)) {
  2353. hEMFPage = SetEnhMetaFileBitsAlt((HLOCAL)pBuffer, NULL, NULL, 0);
  2354. }
  2355. else
  2356. {
  2357. WARNING("GdiPlayPageEMF() Failed to get memory map pointer to EMF\n");
  2358. }
  2359. }
  2360. #define kTempSpoolFileThreshold 0x100000
  2361. #define kScratchBufferSize 0x10000
  2362. if (hEMFPage == NULL && Size > kTempSpoolFileThreshold) {
  2363. // if larger then a meg, attempt create a temporary spool file
  2364. // and copy the page to the spool file
  2365. WARNING("GdiPlayPageEMF() Page size is large using temporary spool file\n");
  2366. // If memory mapped read didnt work, dont try it again
  2367. pSpoolFileHandle->bUseMemMap = FALSE;
  2368. hFile = CreateTempSpoolFile();
  2369. if(hFile != INVALID_HANDLE_VALUE)
  2370. {
  2371. if(fpSeekPrinter(pSpoolFileHandle->hSpooler, Offset, NULL, 0, FALSE))
  2372. {
  2373. PVOID pvScratch = LocalAlloc(LMEM_FIXED, kScratchBufferSize);
  2374. if(pvScratch)
  2375. {
  2376. ULONG dwOffset = 0;
  2377. while(dwOffset < Size)
  2378. {
  2379. ULONG dwSize = MIN(kScratchBufferSize, (Size - dwOffset));
  2380. ULONG dwBytesWritten;
  2381. if(!MyReadPrinter(pSpoolFileHandle->hSpooler, pvScratch, dwSize))
  2382. {
  2383. WARNING("GdiPlayPageEMF() Failed reading from spooler\n");
  2384. break;
  2385. }
  2386. if(!WriteFile(hFile, pvScratch, dwSize, &dwBytesWritten, NULL))
  2387. {
  2388. WARNING("GdiPlayPageEMF() Failed writing to temp spool file\n");
  2389. break;
  2390. }
  2391. if(dwBytesWritten != dwSize)
  2392. {
  2393. WARNING("GdiPlayPageEMF() Unexpected mismatch between attempted write size and actual\n");
  2394. break;
  2395. }
  2396. dwOffset += dwBytesWritten;
  2397. }
  2398. if(dwOffset == Size)
  2399. {
  2400. hEMFPage = SetEnhMetaFileBitsAlt(NULL, NULL, hFile, 0);
  2401. if(!hEMFPage)
  2402. {
  2403. WARNING("GdiPlayPageEMF() Failed creating EMF handle\n");
  2404. }
  2405. }
  2406. LocalFree(pvScratch);
  2407. }
  2408. else
  2409. {
  2410. WARNING("GdiPlayPageEMF() Failed creating scratch buffer\n");
  2411. }
  2412. }
  2413. else
  2414. {
  2415. WARNING("GdiPlayPageEMF() Failed seeking spooler\n");
  2416. }
  2417. pBuffer = NULL;
  2418. bAllocBuffer = TRUE;
  2419. if (hEMFPage == NULL)
  2420. {
  2421. if (!CloseHandle(hFile))
  2422. {
  2423. WARNING("GdiPlayPageEMF() Failed closing temp spool file handle\n");
  2424. }
  2425. else
  2426. {
  2427. hFile = INVALID_HANDLE_VALUE;
  2428. }
  2429. }
  2430. }
  2431. }
  2432. if (hEMFPage == NULL) {
  2433. // If memory mapped read didnt work, dont try it again
  2434. pSpoolFileHandle->bUseMemMap = FALSE;
  2435. if ((pBuffer = (BYTE*) LocalAlloc(LMEM_FIXED, Size)) &&
  2436. (*fpSeekPrinter)(pSpoolFileHandle->hSpooler, Offset, NULL, 0, FALSE) &&
  2437. MyReadPrinter(pSpoolFileHandle->hSpooler, pBuffer, Size)) {
  2438. hEMFPage = SetEnhMetaFileBitsAlt((HLOCAL)pBuffer, NULL, NULL, 0);
  2439. }
  2440. bAllocBuffer = TRUE;
  2441. }
  2442. // Check if the handle was created
  2443. if (hEMFPage == NULL) {
  2444. // Free resources and quit
  2445. if (pBuffer && bAllocBuffer) {
  2446. LocalFree(pBuffer);
  2447. }
  2448. if(hFile != INVALID_HANDLE_VALUE)
  2449. {
  2450. if(!CloseHandle(hFile))
  2451. {
  2452. WARNING("GdiPlayPageEMF() Failed closing temp spool file handle\n");
  2453. }
  2454. }
  2455. WARNING("GdiPlayPageEMF: Failed to Create EMF Handle\n");
  2456. return FALSE;
  2457. } else {
  2458. // Save hEMFPage in pEMF struct for future calls to GdiPlayPageEMF
  2459. pEMF->hemf = hEMFPage;
  2460. pEMF->bAllocBuffer = bAllocBuffer;
  2461. }
  2462. }
  2463. if (pSpoolFileHandle->dwNumberOfPagesInCurrSide >=
  2464. pSpoolFileHandle->dwNumberOfPagesAllocated) {
  2465. PAGE_LAYOUT_STRUCT *pTemp;
  2466. if (pTemp = LOCALALLOC(sizeof(PAGE_LAYOUT_STRUCT) *
  2467. (pSpoolFileHandle->dwNumberOfPagesAllocated +
  2468. SPOOL_FILE_MAX_NUMBER_OF_PAGES_PER_SIDE))) {
  2469. memcpy(pTemp,
  2470. pSpoolFileHandle->pPageLayout,
  2471. sizeof(PAGE_LAYOUT_STRUCT) * pSpoolFileHandle->dwNumberOfPagesAllocated);
  2472. LocalFree(pSpoolFileHandle->pPageLayout);
  2473. pSpoolFileHandle->pPageLayout = pTemp;
  2474. pSpoolFileHandle->dwNumberOfPagesAllocated += SPOOL_FILE_MAX_NUMBER_OF_PAGES_PER_SIDE;
  2475. } else {
  2476. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2477. WARNING("GdiPlayPageEMF: out of memory\n");
  2478. return(FALSE);
  2479. }
  2480. }
  2481. // update the fields
  2482. pPageLayout = &(pSpoolFileHandle->pPageLayout[pSpoolFileHandle->dwNumberOfPagesInCurrSide]);
  2483. pPageLayout->hemf = pEMF->hemf;
  2484. pPageLayout->bAllocBuffer = pEMF->bAllocBuffer;
  2485. pPageLayout->dwPageNumber = pEMF->dwPageNumber;
  2486. pPageLayout->rectDocument.top = prectDocument->top;
  2487. pPageLayout->rectDocument.bottom = prectDocument->bottom;
  2488. pPageLayout->rectDocument.left = prectDocument->left;
  2489. pPageLayout->rectDocument.right = prectDocument->right;
  2490. // Set the border
  2491. if (prectBorder) {
  2492. pPageLayout->rectBorder.top = prectBorder->top;
  2493. pPageLayout->rectBorder.bottom = prectBorder->bottom;
  2494. pPageLayout->rectBorder.left = prectBorder->left;
  2495. pPageLayout->rectBorder.right = prectBorder->right;
  2496. } else {
  2497. pPageLayout->rectBorder.top = -1; //invalid coordinates
  2498. pPageLayout->rectBorder.bottom = -1; //invalid coordinates
  2499. pPageLayout->rectBorder.left = -1; //invalid coordinates
  2500. pPageLayout->rectBorder.right = -1; //invalid coordinates
  2501. }
  2502. // Set the clipping rectangle
  2503. if (prectClip) {
  2504. pPageLayout->rectClip.top = prectClip->top;
  2505. pPageLayout->rectClip.bottom = prectClip->bottom;
  2506. pPageLayout->rectClip.left = prectClip->left;
  2507. pPageLayout->rectClip.right = prectClip->right;
  2508. } else {
  2509. pPageLayout->rectClip.top = -1; //invalid coordinates
  2510. pPageLayout->rectClip.bottom = -1; //invalid coordinates
  2511. pPageLayout->rectClip.left = -1; //invalid coordinates
  2512. pPageLayout->rectClip.right = -1; //invalid coordinates
  2513. }
  2514. // Save the current transformation at the DC
  2515. if (!GetWorldTransform(pSpoolFileHandle->hdc, &(pPageLayout->XFormDC))) {
  2516. WARNING("GdiPlayPageEMF: GetWorldTransform failed\n");
  2517. return(FALSE);
  2518. }
  2519. // increment the number of pages
  2520. pSpoolFileHandle->dwNumberOfPagesInCurrSide += 1;
  2521. return(TRUE);
  2522. }
  2523. BOOL WINAPI GdiPlayPrivatePageEMF(
  2524. HANDLE SpoolFileHandle,
  2525. HENHMETAFILE hEnhMetaFile,
  2526. RECT *prectDocument)
  2527. /*
  2528. Function Description:
  2529. GdiPlayPrivatePageEMF allows the print processor to play EMF pages other than the
  2530. ones present in the spool file (like watermarks) inside a specified rectangle.
  2531. Parameters:
  2532. SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
  2533. hEnhMetaFile -- handle to an EMF which is to be played on the current physical
  2534. page
  2535. prectDocument -- pointer to the RECT containing coordinates where
  2536. the page is to be played
  2537. Return Values:
  2538. If the function succeeds, the return value is TRUE;
  2539. otherwise the result is FALSE.
  2540. History:
  2541. 6/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
  2542. */
  2543. {
  2544. EMF_HANDLE hRecord;
  2545. hRecord.tag = EMF_HANDLE_TAG;
  2546. hRecord.hemf = hEnhMetaFile;
  2547. hRecord.dwPageNumber = 0; // Invalid value
  2548. hRecord.bAllocBuffer = FALSE;
  2549. return GdiPlayPageEMF(SpoolFileHandle,
  2550. (HANDLE) &hRecord,
  2551. prectDocument,
  2552. NULL,
  2553. NULL);
  2554. }
  2555. BOOL InternalProcessEMFRecord(
  2556. SPOOL_FILE_HANDLE *pSpoolFileHandle,
  2557. DWORD dwPageNumber)
  2558. /*
  2559. Function Description:
  2560. InternalProcessEMFRecord processes any EMF records that appear before the given
  2561. EMF page which should be processed immediately before playing the page.
  2562. Parameters:
  2563. pSpoolFileHandle -- pointer to the SPOOL_FILE_HANDLE struct for the job.
  2564. dwPageNumber -- number of the page being played
  2565. Return Values:
  2566. If the function succeeds, the return value is TRUE;
  2567. otherwise the result is FALSE.
  2568. History:
  2569. 5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
  2570. */
  2571. {
  2572. PRECORD_INFO_STRUCT pRecordInfo;
  2573. BYTE *pTmpBuffer = NULL;
  2574. LARGE_INTEGER liOffset;
  2575. BOOL bReturn = FALSE;
  2576. PEMFITEMPRESTARTPAGE pemfiPre;
  2577. pRecordInfo = pSpoolFileHandle->pPageInfo[dwPageNumber-1].pRecordInfo;
  2578. // loop thru all the records seen before the page
  2579. while (pRecordInfo) {
  2580. liOffset.QuadPart = pRecordInfo->RecordOffset;
  2581. if (pTmpBuffer = (BYTE*) LOCALALLOC(pRecordInfo->RecordSize)) {
  2582. if (!(*fpSeekPrinter) (pSpoolFileHandle->hSpooler,
  2583. liOffset,
  2584. NULL,
  2585. FILE_BEGIN,
  2586. FALSE) ||
  2587. !MyReadPrinter(pSpoolFileHandle->hSpooler,
  2588. pTmpBuffer,
  2589. pRecordInfo->RecordSize)) {
  2590. WARNING("Gdi32: error reading record\n");
  2591. goto exit;
  2592. }
  2593. } else {
  2594. WARNING("Out of memory in InternalProcessEMFRecord\n");
  2595. goto exit;
  2596. }
  2597. switch (pRecordInfo->RecordID) {
  2598. case EMRI_PRESTARTPAGE:
  2599. MFD1("pre start page commands\n");
  2600. pemfiPre = (PEMFITEMPRESTARTPAGE) pTmpBuffer;
  2601. if (pemfiPre->bEPS & 1) {
  2602. SHORT b = 1;
  2603. MFD1("MFP_StartDocW calling bEpsPrinting\n");
  2604. ExtEscape(pSpoolFileHandle->hdc, EPSPRINTING, sizeof(b),
  2605. (LPCSTR) &b, 0 , NULL );
  2606. }
  2607. break;
  2608. // add cases for new records that must be processed before the page is played
  2609. default:
  2610. WARNING("unknown ITEM record\n");
  2611. break;
  2612. }
  2613. LocalFree(pTmpBuffer);
  2614. pTmpBuffer = NULL;
  2615. pRecordInfo = pRecordInfo->pNext;
  2616. }
  2617. bReturn = TRUE;
  2618. exit:
  2619. if (pTmpBuffer) {
  2620. LocalFree(pTmpBuffer);
  2621. }
  2622. return bReturn;
  2623. }
  2624. BOOL InternalGdiPlayPageEMF(
  2625. SPOOL_FILE_HANDLE *pSpoolFileHandle,
  2626. PAGE_LAYOUT_STRUCT *pPageLayout,
  2627. POINTL *pptlOrigin,
  2628. SIZE *pszSurface,
  2629. BOOL bBanding)
  2630. /*
  2631. Function Description:
  2632. InternalGdiPlayPageEMF plays the EMF file on the page and draws borders, if
  2633. specified. It also performs initialization for GL records that may present in
  2634. EMF file.
  2635. Parameters:
  2636. pSpoolFileHandle -- pointer to the SPOOL_FILE_HANDLE struct for the job
  2637. pPageLayout -- pointer to PAGE_LAYOUT_STRUCT which contains information
  2638. about playing the page
  2639. pptlOrigin -- pointer to a POINTL structure used for banding
  2640. pszSurface -- pointer to a SIZE structure used for banding
  2641. bBanding -- flag to indicate if banding is being used
  2642. Return Values:
  2643. If the function succeeds, the return value is TRUE;
  2644. otherwise the result is FALSE.
  2645. History:
  2646. 5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
  2647. */
  2648. {
  2649. BOOL bPrintGl, bReturn = FALSE;
  2650. XFORM OldXForm;
  2651. POINTL ptlOrigin;
  2652. SIZE szSurface;
  2653. GLPRINTSTATE gps;
  2654. HDC hPrinterDC = pSpoolFileHandle->hdc;
  2655. RECT *rectBorder = &(pPageLayout->rectBorder);
  2656. RECT *rectClip = &(pPageLayout->rectClip);
  2657. RECT *rectBand = NULL;
  2658. HRGN hClipRgn = NULL;
  2659. INT indexDC = 0;
  2660. if (bBanding) {
  2661. // New structs created so that each page is played for the same band
  2662. ptlOrigin.x = pptlOrigin->x;
  2663. ptlOrigin.y = pptlOrigin->y;
  2664. szSurface.cx = pszSurface->cx;
  2665. szSurface.cy = pszSurface->cy;
  2666. // Print only on the correct band
  2667. SetViewportOrgEx(hPrinterDC, -ptlOrigin.x, -ptlOrigin.y, NULL);
  2668. }
  2669. // Process any PRESTARTPAGE records that appear immediately before this page
  2670. if (pPageLayout->dwPageNumber > 0) {
  2671. InternalProcessEMFRecord(pSpoolFileHandle, pPageLayout->dwPageNumber);
  2672. }
  2673. // Draw Page borders (if any)
  2674. if (!((rectBorder->top == -1) &&
  2675. (rectBorder->bottom == -1) &&
  2676. (rectBorder->right == -1) &&
  2677. (rectBorder->left == -1)) &&
  2678. ModifyWorldTransform(hPrinterDC, NULL, MWT_IDENTITY)) {
  2679. HRGN hBandRgn = NULL;
  2680. if (bBanding && !IsMetafileWithGl(pPageLayout->hemf))
  2681. {
  2682. ULONG ulRet,ulXRes,ulYRes;
  2683. PERBANDINFO pbi;
  2684. RECT *prect = &(pPageLayout->rectDocument);
  2685. ulXRes = (ULONG) prect->right - prect->left;
  2686. ulYRes = (ULONG) prect->bottom - prect->top;
  2687. pbi.bRepeatThisBand = FALSE;
  2688. pbi.ulHorzRes = ulXRes;
  2689. pbi.ulVertRes = ulYRes;
  2690. pbi.szlBand.cx = szSurface.cx;
  2691. pbi.szlBand.cy = szSurface.cy;
  2692. ulRet = NtGdiGetPerBandInfo(hPrinterDC,&pbi);
  2693. if (ulRet && ulRet != GDI_ERROR &&
  2694. pbi.ulHorzRes == ulXRes && pbi.ulVertRes == ulYRes)
  2695. {
  2696. hBandRgn = CreateRectRgn(0,0,pbi.szlBand.cx,pbi.szlBand.cy);
  2697. if (hBandRgn)
  2698. SelectClipRgn(hPrinterDC, hBandRgn);
  2699. }
  2700. }
  2701. MoveToEx(hPrinterDC, rectBorder->left, rectBorder->top, NULL);
  2702. LineTo(hPrinterDC, rectBorder->right, rectBorder->top);
  2703. MoveToEx(hPrinterDC, rectBorder->right, rectBorder->top, NULL);
  2704. LineTo(hPrinterDC, rectBorder->right, rectBorder->bottom);
  2705. MoveToEx(hPrinterDC, rectBorder->right, rectBorder->bottom, NULL);
  2706. LineTo(hPrinterDC, rectBorder->left, rectBorder->bottom);
  2707. MoveToEx(hPrinterDC, rectBorder->left, rectBorder->bottom, NULL);
  2708. LineTo(hPrinterDC, rectBorder->left, rectBorder->top);
  2709. if (hBandRgn)
  2710. {
  2711. SelectClipRgn(hPrinterDC,NULL);
  2712. DeleteObject(hBandRgn);
  2713. }
  2714. }
  2715. // Save the old transformation
  2716. if (!GetWorldTransform(hPrinterDC, &OldXForm)) {
  2717. WARNING("InternalGdiPlayEMFPage: GetWorldTransform failed\n");
  2718. return FALSE;
  2719. }
  2720. // Set the new transformation
  2721. if (!SetWorldTransform(hPrinterDC, &(pPageLayout->XFormDC))) {
  2722. WARNING("InternalGdiPlayEMFPage: SetWorldTransform failed\n");
  2723. goto CleanUp;
  2724. }
  2725. if (!((rectClip->top == -1) &&
  2726. (rectClip->bottom == -1) &&
  2727. (rectClip->right == -1) &&
  2728. (rectClip->left == -1))) {
  2729. rectBand = rectClip;
  2730. if (!bBanding) {
  2731. // Set the clipping rectangle
  2732. hClipRgn = CreateRectRgn(rectClip->left, rectClip->top,
  2733. rectClip->right, rectClip->bottom);
  2734. indexDC = SaveDC(hPrinterDC);
  2735. if (!hClipRgn || !indexDC ||
  2736. (SelectClipRgn(hPrinterDC, hClipRgn) == ERROR)) {
  2737. WARNING("InternalGdiPlayEMFPage: SelectClipRgn failed\n");
  2738. goto CleanUp;
  2739. }
  2740. }
  2741. }
  2742. // Perform GL initialization if necessary
  2743. bPrintGl = IsMetafileWithGl(pPageLayout->hemf);
  2744. if (bPrintGl) {
  2745. if (!InitGlPrinting(pPageLayout->hemf,
  2746. hPrinterDC,
  2747. &(pPageLayout->rectDocument),
  2748. pSpoolFileHandle->pLastDevmode,
  2749. &gps)) {
  2750. WARNING("InternalGdiPlayEMFPage: InitGlPrinting failed\n");
  2751. goto CleanUp;
  2752. }
  2753. }
  2754. if (bBanding) {
  2755. // call printing functions for banding case
  2756. if (bPrintGl) {
  2757. SetViewportOrgEx(hPrinterDC, -ptlOrigin.x, -ptlOrigin.y, NULL);
  2758. PrintMfWithGl(pPageLayout->hemf, &gps, &ptlOrigin, &szSurface);
  2759. EndGlPrinting(&gps);
  2760. } else {
  2761. PrintBand( hPrinterDC,
  2762. pPageLayout->hemf,
  2763. &ptlOrigin,
  2764. &(pPageLayout->rectDocument),
  2765. &szSurface,
  2766. rectBand );
  2767. }
  2768. } else {
  2769. // call priting functions for non-banding case
  2770. if (bPrintGl) {
  2771. PrintMfWithGl(pPageLayout->hemf, &gps, NULL, NULL);
  2772. EndGlPrinting(&gps);
  2773. } else {
  2774. PlayEnhMetaFile( hPrinterDC, pPageLayout->hemf, &(pPageLayout->rectDocument) );
  2775. }
  2776. }
  2777. bReturn = TRUE;
  2778. CleanUp:
  2779. // Restore the old clipping region
  2780. if (indexDC) {
  2781. RestoreDC(hPrinterDC, indexDC);
  2782. }
  2783. // Reset the world transformation
  2784. if (!SetWorldTransform(hPrinterDC, &OldXForm)) {
  2785. WARNING("InternalGdiPlayEMFPage: SetWorldTransform failed\n");
  2786. bReturn = FALSE;
  2787. }
  2788. // Delete the clipping region
  2789. if (hClipRgn) {
  2790. DeleteObject(hClipRgn);
  2791. }
  2792. return bReturn;
  2793. }
  2794. BOOL AddTempNode(
  2795. PEMF_LIST *ppHead,
  2796. HENHMETAFILE hemf,
  2797. BOOL bAllocBuffer)
  2798. /*
  2799. Function Description:
  2800. AddTempNode adds a EMF handle to a list that does not contain duplicates.
  2801. This list is used for deleting the handles later.
  2802. Parameters:
  2803. ppHead - pointer to the start of the list
  2804. hemf - handle to EMF to be added to the list
  2805. bAllocBuffer - flag indicating if buffer was allocated for hemf
  2806. Return Values:
  2807. If the function succeeds, the return value is TRUE;
  2808. otherwise the result is FALSE.
  2809. History:
  2810. 7/7/1997 by Ramanathan N Venkatapathy [ramanv] - Author
  2811. */
  2812. {
  2813. BOOL bReturn = FALSE;
  2814. PEMF_LIST pTemp;
  2815. for (pTemp = *ppHead; pTemp; ppHead = &(pTemp->pNext), pTemp = *ppHead) {
  2816. if (pTemp->hemf == hemf) {
  2817. return TRUE;
  2818. }
  2819. }
  2820. if (!(pTemp = (PEMF_LIST) LOCALALLOC(sizeof(EMF_LIST)))) {
  2821. return FALSE;
  2822. }
  2823. pTemp->hemf = hemf;
  2824. pTemp->bAllocBuffer = bAllocBuffer;
  2825. pTemp->pNext = NULL;
  2826. *ppHead = pTemp;
  2827. return TRUE;
  2828. }
  2829. VOID RemoveFromSpoolFileHandle(
  2830. SPOOL_FILE_HANDLE *pSpoolFileHandle,
  2831. HENHMETAFILE hemf)
  2832. /*
  2833. Function Description:
  2834. The EMF handles that are played get deleted at the end of the page (GdiEndPageEMF).
  2835. The rest of the handles are deleted in the cleanup routine (GdiDeleteSpoolFileHandle).
  2836. These are handles are listed in pSpoolFileHandle->pEMFHandle. RemoveFromSpoolFileHandle
  2837. removes deleted handles from this list, to avoid freeing the handles twice.
  2838. Parameters:
  2839. pSpoolFileHandle -- pointer to the SPOOL_FILE_HANDLE
  2840. hemf -- Handle to EMF that is going to be deleted
  2841. Return Values:
  2842. NONE
  2843. History:
  2844. 9/18/1997 by Ramanathan N Venkatapathy [ramanv] - Author
  2845. */
  2846. {
  2847. PEMF_HANDLE pTemp;
  2848. for (pTemp = pSpoolFileHandle->pEMFHandle; pTemp; pTemp = pTemp->pNext) {
  2849. if (pTemp->hemf == hemf) {
  2850. pTemp->hemf = NULL;
  2851. }
  2852. }
  2853. return;
  2854. }
  2855. BOOL SetColorOptimization(
  2856. SPOOL_FILE_HANDLE *pSpoolFileHandle,
  2857. DWORD dwOptimization)
  2858. /*
  2859. Function Description:
  2860. SetColorOptimization examines the page types on the next physical page and
  2861. sets the device context to take advantage of monochrome pages.
  2862. Parameters:
  2863. pSpoolFileHandle -- pointer to the SPOOL_FILE_HANDLE
  2864. dwOptimization -- flag indicating optimizations to be performed
  2865. Return Values:
  2866. TRUE if successful; FALSE otherwise
  2867. History:
  2868. 9/23/1997 by Ramanathan N Venkatapathy [ramanv] - Author
  2869. */
  2870. {
  2871. BOOL bReturn = TRUE, bFoundColor = FALSE, bReset;
  2872. short dmColor;
  2873. DWORD dmFields, dwIndex, dwPageNumber, dwRecordID;
  2874. PAGE_LAYOUT_STRUCT *pPageLayout;
  2875. // Dont process for monochrome detection if the optimization is not
  2876. // applied
  2877. if (!(dwOptimization & EMF_PP_COLOR_OPTIMIZATION)) {
  2878. return TRUE;
  2879. }
  2880. // Search for color in the pages on the current physical page
  2881. for (dwIndex = 0, pPageLayout = pSpoolFileHandle->pPageLayout;
  2882. dwIndex < pSpoolFileHandle->dwNumberOfPagesInCurrSide;
  2883. ++dwIndex, ++pPageLayout)
  2884. {
  2885. dwPageNumber = pPageLayout->dwPageNumber;
  2886. dwRecordID = pSpoolFileHandle->pPageInfo[dwPageNumber-1].ulID;
  2887. if ((dwRecordID == EMRI_METAFILE) ||
  2888. (dwRecordID == EMRI_FORM_METAFILE)) {
  2889. bFoundColor = TRUE;
  2890. break;
  2891. }
  2892. }
  2893. // Determine if the status has to changed
  2894. bReset = (bFoundColor && (pSpoolFileHandle->dwPlayBackStatus == EMF_PLAY_MONOCHROME)) ||
  2895. (!bFoundColor && (pSpoolFileHandle->dwPlayBackStatus == EMF_PLAY_COLOR));
  2896. if (bReset) {
  2897. // Save the old settings
  2898. dmFields = pSpoolFileHandle->pLastDevmode->dmFields;
  2899. dmColor = pSpoolFileHandle->pLastDevmode->dmColor;
  2900. pSpoolFileHandle->pLastDevmode->dmFields |= DM_COLOR;
  2901. pSpoolFileHandle->pLastDevmode->dmColor = bFoundColor ? DMCOLOR_COLOR
  2902. : DMCOLOR_MONOCHROME;
  2903. // Reset the DC and set graphics mode
  2904. bReturn = ResetDCWInternal(pSpoolFileHandle->hdc,
  2905. pSpoolFileHandle->pLastDevmode,
  2906. &(pSpoolFileHandle->bBanding)) &&
  2907. SetGraphicsMode(pSpoolFileHandle->hdc, GM_ADVANCED);
  2908. // Restore old settings and update status
  2909. pSpoolFileHandle->pLastDevmode->dmFields = dmFields;
  2910. pSpoolFileHandle->pLastDevmode->dmColor = dmColor;
  2911. pSpoolFileHandle->dwPlayBackStatus = bFoundColor ? EMF_PLAY_COLOR
  2912. : EMF_PLAY_MONOCHROME;
  2913. }
  2914. return bReturn;
  2915. }
  2916. BOOL WINAPI GdiEndPageEMF(
  2917. HANDLE SpoolFileHandle,
  2918. DWORD dwOptimization)
  2919. /*
  2920. Function Description:
  2921. GdiEndPageEMF completes printing on the current page and ejects it. It
  2922. loops thru the different bands while printing the page. GdiEndPageEMF also
  2923. frees up the buffers allocated for the emf handle.
  2924. Parameters:
  2925. SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
  2926. dwOptimization -- flag color optimizations. To be extended for copies
  2927. Return Values:
  2928. If the function succeeds, the return value is TRUE;
  2929. otherwise the result is FALSE.
  2930. History:
  2931. 5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
  2932. */
  2933. {
  2934. SPOOL_FILE_HANDLE *pSpoolFileHandle;
  2935. DWORD dwIndex;
  2936. PAGE_LAYOUT_STRUCT *pPageLayout;
  2937. BOOL bReturn = FALSE;
  2938. PEMF_LIST pTemp, pHead = NULL;
  2939. pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
  2940. // first check to see if this is a valid handle by checking for the tag
  2941. try
  2942. {
  2943. if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
  2944. {
  2945. WARNING("GdiEndPageEMF: invalid handle\n");
  2946. return(FALSE);
  2947. }
  2948. }
  2949. except(EXCEPTION_EXECUTE_HANDLER)
  2950. {
  2951. WARNING("GdiEndPageEMF: exception accessing handle\n");
  2952. return(FALSE);
  2953. }
  2954. if (!SetColorOptimization(pSpoolFileHandle, dwOptimization)) {
  2955. WARNING("GdiEndPageEMF: Color optimizations failed\n");
  2956. }
  2957. if (!StartPage(pSpoolFileHandle->hdc)) {
  2958. WARNING("GdiEndPageEMF: StartPage failed\n");
  2959. return(FALSE);
  2960. }
  2961. if (pSpoolFileHandle->bBanding) {
  2962. // for opengl optimization
  2963. POINTL ptlOrigin;
  2964. SIZE szSurface;
  2965. // initialize for banding
  2966. if (!StartBanding( pSpoolFileHandle->hdc, &ptlOrigin, &szSurface )) {
  2967. goto CleanUp;
  2968. }
  2969. // loop till all the bands are printed
  2970. do {
  2971. for (dwIndex = 0, pPageLayout = pSpoolFileHandle->pPageLayout;
  2972. dwIndex < pSpoolFileHandle->dwNumberOfPagesInCurrSide;
  2973. ++dwIndex, ++pPageLayout) {
  2974. if (!InternalGdiPlayPageEMF(pSpoolFileHandle,
  2975. pPageLayout,
  2976. &ptlOrigin,
  2977. &szSurface,
  2978. TRUE)) {
  2979. WARNING("GdiEndPageEMF: InternalGdiPlayEMFPage failed");
  2980. goto CleanUp;
  2981. }
  2982. }
  2983. if (!NextBand(pSpoolFileHandle->hdc, &ptlOrigin)) {
  2984. WARNING("GdiEndPageEMF: NextBand failed\n");
  2985. goto CleanUp;
  2986. }
  2987. } while (ptlOrigin.x != -1);
  2988. } else {
  2989. for (dwIndex = 0, pPageLayout = pSpoolFileHandle->pPageLayout;
  2990. dwIndex < pSpoolFileHandle->dwNumberOfPagesInCurrSide;
  2991. ++dwIndex, ++pPageLayout) {
  2992. if (!InternalGdiPlayPageEMF(pSpoolFileHandle,
  2993. pPageLayout,
  2994. NULL,
  2995. NULL,
  2996. FALSE)) {
  2997. WARNING("GdiEndPageEMF: InternalGdiPlayEMFPage failed");
  2998. goto CleanUp;
  2999. }
  3000. }
  3001. }
  3002. bReturn = TRUE;
  3003. CleanUp:
  3004. // eject the current page
  3005. if (!EndPage(pSpoolFileHandle->hdc)) {
  3006. WARNING("GdiEndPageEMF: EndPage failed\n");
  3007. bReturn = FALSE;
  3008. }
  3009. // free the emf handles
  3010. for (dwIndex = 0, pPageLayout = pSpoolFileHandle->pPageLayout;
  3011. dwIndex < pSpoolFileHandle->dwNumberOfPagesInCurrSide;
  3012. ++dwIndex, ++pPageLayout) {
  3013. AddTempNode(&pHead, pPageLayout->hemf, pPageLayout->bAllocBuffer);
  3014. }
  3015. while (pTemp = pHead) {
  3016. pHead = pHead->pNext;
  3017. RemoveFromSpoolFileHandle(pSpoolFileHandle, pTemp->hemf);
  3018. InternalDeleteEnhMetaFile(pTemp->hemf, pTemp->bAllocBuffer);
  3019. LocalFree(pTemp);
  3020. }
  3021. // reset the number of logical pages for the next physical page
  3022. pSpoolFileHandle->dwNumberOfPagesInCurrSide = 0;
  3023. return bReturn;
  3024. }
  3025. BOOL WINAPI GdiEndDocEMF(
  3026. HANDLE SpoolFileHandle)
  3027. /*
  3028. Function Description:
  3029. GdiEndDocEMF completes printing the current document. GdiEndPageEMF is called
  3030. if the last physical page was not ejected. Some of the resources associated with
  3031. printing of the document are released.
  3032. Parameters:
  3033. SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
  3034. Return Values:
  3035. If the function succeeds, the return value is TRUE;
  3036. otherwise the result is FALSE.
  3037. History:
  3038. 5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
  3039. */
  3040. {
  3041. SPOOL_FILE_HANDLE *pSpoolFileHandle;
  3042. pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
  3043. // first check to see if this is a valid handle by checking for the tag
  3044. try
  3045. {
  3046. if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
  3047. {
  3048. WARNING("GdiEndDocEMF: invalid handle\n");
  3049. return(FALSE);
  3050. }
  3051. }
  3052. except(EXCEPTION_EXECUTE_HANDLER)
  3053. {
  3054. WARNING("GdiEndDocEMF: exception accessing handle\n");
  3055. return(FALSE);
  3056. }
  3057. // call GdiEndPageEMF if the last physical page was not ejected
  3058. if (pSpoolFileHandle->dwNumberOfPagesInCurrSide) {
  3059. GdiEndPageEMF(SpoolFileHandle,0);
  3060. }
  3061. EndDoc(pSpoolFileHandle->hdc);
  3062. // free the memory used for saving the page layouts
  3063. LOCALFREE(pSpoolFileHandle->pPageLayout);
  3064. pSpoolFileHandle->pPageLayout = NULL;
  3065. return TRUE;
  3066. }
  3067. BOOL WINAPI GdiGetDevmodeForPage(
  3068. HANDLE SpoolFileHandle,
  3069. DWORD dwPageNumber,
  3070. PDEVMODEW *pCurrDM,
  3071. PDEVMODEW *pLastDM)
  3072. /*
  3073. Function Description:
  3074. GdiGetDevmodeForPage allows the print processor to retrieve the last devmode
  3075. set at the printer device context and the last devmode that appears before
  3076. any given page. If the 2 devmodes are different the print processor has to
  3077. call GdiResetDCEMF with the current devmode. However since ResetDC can be called
  3078. only at page boundaries, the print processor must end printing on the current
  3079. page before calling GdiResetDCEMF. GdiEndPageEMF allows the print processor to
  3080. complete printing on the current physical page.
  3081. Parameters:
  3082. SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
  3083. dwPageNumber -- page number for which the devmode is sought
  3084. *pCurrDM -- buffer to store the pointer to the devmode for the page
  3085. *pLastDM -- buffer to store the pointer to the last devmode used in
  3086. ResetDC
  3087. Return Values:
  3088. If the function succeeds, the return value is TRUE;
  3089. otherwise the result is FALSE.
  3090. History:
  3091. 5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
  3092. */
  3093. {
  3094. SPOOL_FILE_HANDLE *pSpoolFileHandle;
  3095. pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
  3096. // first check to see if this is a valid handle by checking for the tag
  3097. try
  3098. {
  3099. if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
  3100. {
  3101. WARNING("GdiGetDevmodeForPage: invalid handle\n");
  3102. return(FALSE);
  3103. }
  3104. }
  3105. except(EXCEPTION_EXECUTE_HANDLER)
  3106. {
  3107. WARNING("GdiGetDevmodeForPage: exception accessing handle\n");
  3108. return(FALSE);
  3109. }
  3110. // process the spool file till the required page is found
  3111. if(!ProcessPages(pSpoolFileHandle, (UINT)dwPageNumber))
  3112. {
  3113. WARNING("GdiGetDevmodeForPage: ProcessPages failed\n");
  3114. return(FALSE);
  3115. }
  3116. // return the pointers in the buffers
  3117. if (pCurrDM) {
  3118. *pCurrDM = pSpoolFileHandle->pPageInfo[dwPageNumber-1].pDevmode;
  3119. }
  3120. if (pLastDM) {
  3121. *pLastDM = pSpoolFileHandle->pLastDevmode;
  3122. }
  3123. return(TRUE);
  3124. }
  3125. BOOL WINAPI GdiResetDCEMF(
  3126. HANDLE SpoolFileHandle,
  3127. PDEVMODEW pCurrDM)
  3128. /*
  3129. Function Description:
  3130. GdiResetDCEMF should be use to reset the printer device context with a new
  3131. devmode. The memory for the devmode will be released by GDI.
  3132. Parameters:
  3133. SpoolFileHandle -- handle returned by GdiGetSpoolFileHandle
  3134. pCurrDM -- pointer to the devmode that was used in the last ResetDC
  3135. call by the print processor
  3136. Return Values:
  3137. If the function succeeds, the return value is TRUE;
  3138. otherwise the result is FALSE.
  3139. History:
  3140. 5/15/1997 by Ramanathan N Venkatapathy [ramanv] - Author
  3141. */
  3142. {
  3143. SPOOL_FILE_HANDLE *pSpoolFileHandle;
  3144. BOOL bReturn;
  3145. pSpoolFileHandle = (SPOOL_FILE_HANDLE*) SpoolFileHandle;
  3146. // first check to see if this is a valid handle by checking for the tag
  3147. try
  3148. {
  3149. if(pSpoolFileHandle->tag != SPOOL_FILE_HANDLE_TAG)
  3150. {
  3151. WARNING("GdiResetDCEMF: invalid handle\n");
  3152. return(FALSE);
  3153. }
  3154. }
  3155. except(EXCEPTION_EXECUTE_HANDLER)
  3156. {
  3157. WARNING("GdiResetDCEMF: exception accessing handle\n");
  3158. return(FALSE);
  3159. }
  3160. if (pCurrDM &&
  3161. ResetDCWInternal(pSpoolFileHandle->hdc,
  3162. pCurrDM,
  3163. &(pSpoolFileHandle->bBanding)))
  3164. {
  3165. // set the last devmode in the SpoolFileHandle
  3166. pSpoolFileHandle->pLastDevmode = pCurrDM;
  3167. bReturn = TRUE;
  3168. }
  3169. else
  3170. {
  3171. bReturn = FALSE;
  3172. }
  3173. if (pCurrDM && (pCurrDM->dmFields & DM_COLOR)) {
  3174. if (pCurrDM->dmColor == DMCOLOR_COLOR) {
  3175. pSpoolFileHandle->dwPlayBackStatus = EMF_PLAY_COLOR;
  3176. } else {
  3177. pSpoolFileHandle->dwPlayBackStatus = EMF_PLAY_FORCE_MONOCHROME;
  3178. }
  3179. }
  3180. return bReturn;
  3181. }