Source code of Windows XP (NT5)
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.

1873 lines
42 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. docevent.c
  5. Abstract:
  6. Implementation of DrvDocumentEvent
  7. Environment:
  8. Fax driver user interface
  9. Revision History:
  10. 01/13/96 -davidx-
  11. Created it.
  12. mm/dd/yy -author-
  13. description
  14. --*/
  15. #include "faxui.h"
  16. #include "tapiutil.h"
  17. #include <gdispool.h>
  18. #include "prtcovpg.h"
  19. #include "jobtag.h"
  20. #include "faxreg.h"
  21. //
  22. // Data structure passed in during CREATEDCPRE document event
  23. //
  24. typedef struct {
  25. LPTSTR pDriverName; // driver name
  26. LPTSTR pPrinterName; // printer name
  27. PDEVMODE pdmInput; // input devmode
  28. ULONG fromCreateIC; // whether called from CreateIC
  29. } CREATEDCDATA, *PCREATEDCDATA;
  30. //
  31. // Data structure passed in during ESCAPE document event
  32. //
  33. typedef struct {
  34. ULONG iEscape; // nEscape parameter passed to ExtEscape
  35. ULONG cbInput; // cbInput parameter passed to ExtEscape
  36. LPCSTR pInput; // pszInData parameter passed to ExtEscape
  37. } ESCAPEDATA, *PESCAPEDATA;
  38. //
  39. // Check if a document event requires a device context
  40. //
  41. #define DocEventRequiresDC(iEsc) \
  42. ((iEsc) >= DOCUMENTEVENT_RESETDCPRE && (iEsc) <= DOCUMENTEVENT_LAST)
  43. //
  44. // Present the Send Fax Wizard to the user
  45. //
  46. BOOL
  47. SendFaxWizard(
  48. PUSERMEM pUserMem
  49. );
  50. BOOL
  51. DoFirstTimeInitStuff(
  52. HWND hwnd,
  53. BOOL WarnOnPrint
  54. );
  55. PUSERMEM
  56. GetPDEVUserMem(
  57. HDC hdc
  58. )
  59. /*++
  60. Routine Description:
  61. Retrieve a pointer to the user mode memory structure associated with a PDEV
  62. Arguments:
  63. hdc - Specifies the printer device context
  64. Return Value:
  65. Pointer to user mode memory structure, NULL if there is an error
  66. --*/
  67. {
  68. PUSERMEM pUserMem;
  69. //
  70. // Get a pointer to the user mode memory structure associated
  71. // with the specified device context
  72. //
  73. EnterDrvSem();
  74. pUserMem = gUserMemList;
  75. while (pUserMem && hdc != pUserMem->hdc)
  76. pUserMem = pUserMem->pNext;
  77. LeaveDrvSem();
  78. //
  79. // Make sure the user memory structure is valid
  80. //
  81. if (pUserMem) {
  82. if (! ValidPDEVUserMem(pUserMem)) {
  83. Error(("Corrupted user mode memory structure\n"));
  84. pUserMem = NULL;
  85. }
  86. } else
  87. Error(("DC has no associated user mode memory structure\n"));
  88. return pUserMem;
  89. }
  90. VOID
  91. FreeRecipientList(
  92. PUSERMEM pUserMem
  93. )
  94. /*++
  95. Routine Description:
  96. Free up the list of recipients associated with each fax job
  97. Arguments:
  98. pUserMem - Points to the user mode memory structure
  99. Return Value:
  100. NONE
  101. --*/
  102. {
  103. PRECIPIENT pNextRecipient, pFreeRecipient;
  104. //
  105. // Free the list of recipients
  106. //
  107. pNextRecipient = pUserMem->pRecipients;
  108. while (pNextRecipient) {
  109. pFreeRecipient = pNextRecipient;
  110. pNextRecipient = pNextRecipient->pNext;
  111. FreeRecipient(pFreeRecipient);
  112. }
  113. pUserMem->pRecipients = NULL;
  114. }
  115. VOID
  116. FreePDEVUserMem(
  117. PUSERMEM pUserMem
  118. )
  119. /*++
  120. Routine Description:
  121. Free up the user mode memory associated with each PDEV
  122. Arguments:
  123. pUserMem - Points to the user mode memory structure
  124. Return Value:
  125. NONE
  126. --*/
  127. {
  128. if (pUserMem) {
  129. FreeRecipientList(pUserMem);
  130. MemFree(pUserMem->pPrinterName);
  131. MemFree(pUserMem->pSubject);
  132. MemFree(pUserMem->pNoteMessage);
  133. MemFree(pUserMem->pEnvVar);
  134. MemFree(pUserMem->pPrintFile);
  135. MemFree(pUserMem);
  136. }
  137. }
  138. INT
  139. DocEventCreateDCPre(
  140. HANDLE hPrinter,
  141. HDC hdc,
  142. PCREATEDCDATA pCreateDCData,
  143. PDEVMODE *ppdmOutput
  144. )
  145. /*++
  146. Routine Description:
  147. Handle CREATEDCPRE document event
  148. Arguments:
  149. hPrinter - Handle to the printer object
  150. hdc - Specifies the printer device context
  151. pCreateDCData - Pointer to CREATEDCDATA structure passed in from GDI
  152. ppdmOutput - Buffer for returning a devmode pointer
  153. Return Value:
  154. Return value for DrvDocumentEvent
  155. --*/
  156. {
  157. PUSERMEM pUserMem;
  158. PPRINTER_INFO_2 pPrinterInfo2 = NULL;
  159. Verbose(("Document event: CREATEDCPRE%s\n", pCreateDCData->fromCreateIC ? "*" : ""));
  160. *ppdmOutput = NULL;
  161. //
  162. // Allocate space for user mode memory data structure
  163. //
  164. if ((pUserMem = MemAllocZ(sizeof(USERMEM))) == NULL ||
  165. (pPrinterInfo2 = MyGetPrinter(hPrinter, 2)) == NULL ||
  166. (pUserMem->pPrinterName = DuplicateString(pPrinterInfo2->pPrinterName)) == NULL)
  167. {
  168. Error(("Memory allocation failed\n"));
  169. MemFree(pUserMem);
  170. MemFree(pPrinterInfo2);
  171. return DOCUMENTEVENT_FAILURE;
  172. }
  173. //
  174. // Merge the input devmode with the driver and system defaults
  175. //
  176. pUserMem->hPrinter = hPrinter;
  177. pUserMem->isLocalPrinter = (pPrinterInfo2->pServerName == NULL);
  178. GetCombinedDevmode(&pUserMem->devmode, pCreateDCData->pdmInput, hPrinter, pPrinterInfo2, FALSE);
  179. MemFree(pPrinterInfo2);
  180. //
  181. // Special code path for EFC server printing - if FAXDM_EFC_SERVER bit is
  182. // set in DMPRIVATE.flags, then we'll bypass the fax wizard and let the
  183. // job through without any intervention.
  184. //
  185. if (pUserMem->devmode.dmPrivate.flags & FAXDM_NO_WIZARD) {
  186. pUserMem->directPrinting = TRUE;
  187. }
  188. //
  189. // Mark the private fields of our devmode
  190. //
  191. MarkPDEVUserMem(pUserMem);
  192. *ppdmOutput = (PDEVMODE) &pUserMem->devmode;
  193. return DOCUMENTEVENT_SUCCESS;
  194. }
  195. INT
  196. DocEventResetDCPre(
  197. HDC hdc,
  198. PUSERMEM pUserMem,
  199. PDEVMODE pdmInput,
  200. PDEVMODE *ppdmOutput
  201. )
  202. /*++
  203. Routine Description:
  204. Handle RESETDCPRE document event
  205. Arguments:
  206. hdc - Specifies the printer device context
  207. pUserMem - Points to the user mode memory structure
  208. pdmInput - Points to the input devmode passed to ResetDC
  209. ppdmOutput - Buffer for returning a devmode pointer
  210. Return Value:
  211. Return value for DrvDocumentEvent
  212. --*/
  213. {
  214. if (pdmInput == (PDEVMODE) &pUserMem->devmode) {
  215. //
  216. // ResetDC was called by ourselves - assume the devmode is already valid
  217. //
  218. } else {
  219. //
  220. // Merge the input devmode with driver and system default
  221. //
  222. GetCombinedDevmode(&pUserMem->devmode, pdmInput, pUserMem->hPrinter, NULL, TRUE);
  223. //
  224. // Mark the private fields of our devmode
  225. //
  226. MarkPDEVUserMem(pUserMem);
  227. }
  228. *ppdmOutput = (PDEVMODE) &pUserMem->devmode;
  229. return DOCUMENTEVENT_SUCCESS;
  230. }
  231. BOOL
  232. IsPrintingToFile(
  233. LPCTSTR pDestStr
  234. )
  235. /*++
  236. Routine Description:
  237. Check if the destination of a print job is a file.
  238. Arguments:
  239. pDestStr - Job destination specified in DOCINFO.lpszOutput
  240. Return Value:
  241. TRUE if the destination is a disk file, FALSE otherwse
  242. --*/
  243. {
  244. DWORD fileAttrs, fileType;
  245. HANDLE hFile;
  246. //
  247. // If the destination is NULL, then we're not printing to file
  248. //
  249. // Otherwise, attempt to use the destination string as the name of a file.
  250. // If we failed to get file attributes or the name refers to a directory,
  251. // then we're not printing to file.
  252. //
  253. if (pDestStr == NULL) {
  254. return FALSE;
  255. }
  256. //
  257. // make sure it's not a directory
  258. //
  259. fileAttrs = GetFileAttributes(pDestStr);
  260. if (fileAttrs != 0xffffffff) {
  261. if (fileAttrs & FILE_ATTRIBUTE_DIRECTORY) {
  262. return FALSE;
  263. }
  264. }
  265. //
  266. // check if file exists...if it doesn't try to create it.
  267. //
  268. hFile = CreateFile(pDestStr, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
  269. if (hFile == INVALID_HANDLE_VALUE) {
  270. hFile = CreateFile(pDestStr, 0, 0, NULL, CREATE_NEW, 0, NULL);
  271. if (hFile == INVALID_HANDLE_VALUE) {
  272. return FALSE;
  273. }
  274. }
  275. //
  276. // verify that this file is really a disk file, not a link to LPT1 or something evil like that
  277. //
  278. fileType = GetFileType(hFile);
  279. CloseHandle(hFile);
  280. if ((fileType & FILE_TYPE_DISK)==0) {
  281. return FALSE;
  282. }
  283. //
  284. // it must be a file
  285. //
  286. return TRUE;
  287. }
  288. INT
  289. DocEventStartDocPre(
  290. HDC hdc,
  291. PUSERMEM pUserMem,
  292. LPDOCINFO pDocInfo
  293. )
  294. /*++
  295. Routine Description:
  296. Handle STARTDOCPRE document event
  297. Arguments:
  298. hdc - Specifies the printer device context
  299. pUserMem - Points to the user mode memory structure
  300. pDocInfo - Points to DOCINFO structure that was passed in from GDI
  301. Return Value:
  302. Return value for DrvDocumentEvent
  303. --*/
  304. {
  305. //
  306. // Initialize user mode memory structure
  307. //
  308. pUserMem->pageCount = 0;
  309. FreeRecipientList(pUserMem);
  310. //
  311. // Present the fax wizard here if necessary
  312. //
  313. if (pDocInfo && IsPrintingToFile(pDocInfo->lpszOutput)) {
  314. //
  315. // Printing to file case: don't get involved
  316. //
  317. Warning(("Printing direct: %ws\n", pDocInfo->lpszOutput));
  318. pUserMem->jobType = JOBTYPE_DIRECT;
  319. } else {
  320. //
  321. // check to see if we should print to file
  322. //
  323. LPTSTR pEnvVar;
  324. DWORD EnvSize;
  325. EnvSize = GetEnvironmentVariable( FAX_ENVVAR_PRINT_FILE, NULL, 0 );
  326. if (EnvSize) {
  327. pEnvVar = (LPTSTR) MemAllocZ( EnvSize * sizeof(TCHAR) );
  328. if (pEnvVar) {
  329. if (GetEnvironmentVariable( FAX_ENVVAR_PRINT_FILE, pEnvVar, EnvSize )) {
  330. pUserMem->directPrinting = TRUE;
  331. pUserMem->pPrintFile = pEnvVar;
  332. pUserMem->jobType = JOBTYPE_DIRECT;
  333. pDocInfo->lpszOutput = pEnvVar;
  334. return DOCUMENTEVENT_SUCCESS;
  335. }
  336. }
  337. }
  338. //
  339. // Normal fax print job. Present the send fax wizard.
  340. // If the user selected cancel, then return -2 to GDI.
  341. //
  342. if (!DoFirstTimeInitStuff(NULL, TRUE) ||
  343. ! SendFaxWizard(pUserMem)) {
  344. SetLastError(ERROR_CANCELLED);
  345. return -2;
  346. }
  347. Assert(pUserMem->pRecipients);
  348. pUserMem->jobType = JOBTYPE_NORMAL;
  349. }
  350. return DOCUMENTEVENT_SUCCESS;
  351. }
  352. VOID
  353. FreeCoverPageFields(
  354. PCOVERPAGEFIELDS pCPFields
  355. )
  356. /*++
  357. Routine Description:
  358. Free up memory used to hold the cover page information
  359. Arguments:
  360. pCPFields - Points to a COVERPAGEFIELDS structure
  361. Return Value:
  362. NONE
  363. --*/
  364. {
  365. if (pCPFields == NULL)
  366. return;
  367. //
  368. // NOTE: We don't need to free the following fields here because they're
  369. // allocated and freed elsewhere and we're only using a copy of the pointer:
  370. // RecName
  371. // RecFaxNumber
  372. // Note
  373. // Subject
  374. //
  375. MemFree(pCPFields->SdrName);
  376. MemFree(pCPFields->SdrFaxNumber);
  377. MemFree(pCPFields->SdrCompany);
  378. MemFree(pCPFields->SdrAddress);
  379. MemFree(pCPFields->SdrTitle);
  380. MemFree(pCPFields->SdrDepartment);
  381. MemFree(pCPFields->SdrOfficeLocation);
  382. MemFree(pCPFields->SdrHomePhone);
  383. MemFree(pCPFields->SdrOfficePhone);
  384. MemFree(pCPFields->NumberOfPages);
  385. MemFree(pCPFields->TimeSent);
  386. MemFree(pCPFields);
  387. }
  388. PCOVERPAGEFIELDS
  389. CollectCoverPageFields(
  390. PUSERMEM pUserMem,
  391. DWORD pageCount
  392. )
  393. /*++
  394. Routine Description:
  395. Collect cover page information into a COVERPAGEFIELDS structure
  396. Arguments:
  397. pUserMem - Pointer to user mode data structure
  398. pageCount - Total number of pages (including cover pages)
  399. Return Value:
  400. Pointer to a COVERPAGEFIELDS structure, NULL if there is an error
  401. --*/
  402. #define FillCoverPageField(field, pValueName) { \
  403. buffer = GetRegistryString(hRegKey, pValueName, TEXT("")); \
  404. if (! IsEmptyString(buffer)) { \
  405. pCPFields->field = DuplicateString(buffer); \
  406. MemFree(buffer); \
  407. } \
  408. }
  409. {
  410. PCOVERPAGEFIELDS pCPFields;
  411. LPTSTR buffer;
  412. HKEY hRegKey;
  413. INT dateTimeLen;
  414. //
  415. // Allocate memory to hold the top level structure
  416. // and open the user info registry key for reading
  417. //
  418. if (! (pCPFields = MemAllocZ(sizeof(COVERPAGEFIELDS))) ||
  419. ! (hRegKey = GetUserInfoRegKey(REGKEY_FAX_USERINFO, REG_READWRITE)))
  420. {
  421. FreeCoverPageFields(pCPFields);
  422. return NULL;
  423. }
  424. //
  425. // Read sender information from the registry
  426. //
  427. pCPFields->ThisStructSize = sizeof(COVERPAGEFIELDS);
  428. FillCoverPageField(SdrName, REGVAL_FULLNAME);
  429. FillCoverPageField(SdrCompany, REGVAL_COMPANY);
  430. FillCoverPageField(SdrAddress, REGVAL_ADDRESS);
  431. FillCoverPageField(SdrTitle, REGVAL_TITLE);
  432. FillCoverPageField(SdrDepartment, REGVAL_DEPT);
  433. FillCoverPageField(SdrOfficeLocation, REGVAL_OFFICE);
  434. FillCoverPageField(SdrHomePhone, REGVAL_HOME_PHONE);
  435. FillCoverPageField(SdrOfficePhone, REGVAL_OFFICE_PHONE);
  436. FillCoverPageField(SdrFaxNumber, REGVAL_FAX_NUMBER);
  437. RegCloseKey(hRegKey);
  438. //
  439. // Number of pages and current local system time
  440. //
  441. if (pCPFields->NumberOfPages = MemAllocZ(sizeof(TCHAR) * 16))
  442. wsprintf(pCPFields->NumberOfPages, TEXT("%d"), pageCount);
  443. //
  444. // When the fax was sent
  445. //
  446. dateTimeLen = 128;
  447. if (pCPFields->TimeSent = MemAllocZ(sizeof(TCHAR) * dateTimeLen)) {
  448. LPTSTR p = pCPFields->TimeSent;
  449. INT cch;
  450. GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, p, dateTimeLen);
  451. cch = _tcslen(p);
  452. p += cch;
  453. if (++cch < dateTimeLen) {
  454. *p++ = ' ';
  455. dateTimeLen -= cch;
  456. GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, p, dateTimeLen);
  457. }
  458. }
  459. return pCPFields;
  460. }
  461. DWORD
  462. FaxTimeToJobTime(
  463. DWORD faxTime
  464. )
  465. /*++
  466. Routine Description:
  467. Convert fax time to spooler job time:
  468. Fax time is a DWORD whose low-order WORD represents hour value and
  469. high-order WORD represents minute value. Spooler job time is a DWORD
  470. value expressing minutes ellapsed since 12:00 AM GMT.
  471. Arguments:
  472. faxTime - Specifies the fax time to be converted
  473. Return Value:
  474. Spooler job time corresponding to the input fax time
  475. --*/
  476. {
  477. TIME_ZONE_INFORMATION timeZoneInfo;
  478. LONG jobTime;
  479. //
  480. // Convert fax time to minutes pass midnight
  481. //
  482. jobTime = LOWORD(faxTime) * 60 + HIWORD(faxTime);
  483. //
  484. // Take time zone information in account - Add one full
  485. // day to take care of the case where the bias is negative.
  486. //
  487. switch (GetTimeZoneInformation(&timeZoneInfo)) {
  488. case TIME_ZONE_ID_DAYLIGHT:
  489. jobTime += timeZoneInfo.DaylightBias;
  490. case TIME_ZONE_ID_STANDARD:
  491. case TIME_ZONE_ID_UNKNOWN:
  492. jobTime += timeZoneInfo.Bias + MINUTES_PER_DAY;
  493. break;
  494. default:
  495. Error(("GetTimeZoneInformation failed: %d\n", GetLastError()));
  496. break;
  497. }
  498. //
  499. // Make sure the time value is less than one day
  500. //
  501. return jobTime % MINUTES_PER_DAY;
  502. }
  503. PVOID
  504. MyGetJob(
  505. HANDLE hPrinter,
  506. DWORD level,
  507. DWORD jobId
  508. )
  509. /*++
  510. Routine Description:
  511. Wrapper function for spooler API GetJob
  512. Arguments:
  513. hPrinter - Handle to the printer object
  514. level - Level of JOB_INFO structure interested
  515. jobId - Specifies the job ID
  516. Return Value:
  517. Pointer to a JOB_INFO structure, NULL if there is an error
  518. --*/
  519. {
  520. PBYTE pJobInfo = NULL;
  521. DWORD cbNeeded;
  522. if (!GetJob(hPrinter, jobId, level, NULL, 0, &cbNeeded) &&
  523. GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
  524. (pJobInfo = MemAlloc(cbNeeded)) &&
  525. GetJob(hPrinter, jobId, level, pJobInfo, cbNeeded, &cbNeeded))
  526. {
  527. return pJobInfo;
  528. }
  529. Error(("GetJob failed: %d\n", GetLastError()));
  530. MemFree(pJobInfo);
  531. return NULL;
  532. }
  533. BOOL
  534. SetJobInfoAndTime(
  535. HANDLE hPrinter,
  536. DWORD jobId,
  537. LPTSTR pJobParam,
  538. PDMPRIVATE pdmPrivate
  539. )
  540. /*++
  541. Routine Description:
  542. Change the devmode and start/stop times associated with a cover page job
  543. Arguments:
  544. hPrinter - Specifies the printer object
  545. jobId - Specifies the job ID
  546. pJobParam - Specifies the fax job parameters
  547. pdmPrivate - Specifies private devmode information
  548. Return Value:
  549. TRUE if successful, FALSE if there is an error
  550. --*/
  551. {
  552. JOB_INFO_2 *pJobInfo2;
  553. BOOL result = FALSE;
  554. //
  555. // Get the current job information
  556. //
  557. if (pJobInfo2 = MyGetJob(hPrinter, 2, jobId)) {
  558. //
  559. // set the time to send to be now, always
  560. //
  561. Warning(("Fax job parameters: %ws\n", pJobParam));
  562. pJobInfo2->pParameters = pJobParam;
  563. pJobInfo2->Position = JOB_POSITION_UNSPECIFIED;
  564. pJobInfo2->pDevMode = NULL;
  565. pJobInfo2->UntilTime = pJobInfo2->StartTime;
  566. if (! (result = SetJob(hPrinter, jobId, 2, (PBYTE) pJobInfo2, 0))) {
  567. Error(("SetJob failed: %d\n", GetLastError()));
  568. }
  569. MemFree(pJobInfo2);
  570. }
  571. return result;
  572. }
  573. BOOL
  574. ChainFaxJobs(
  575. HANDLE hPrinter,
  576. DWORD parentJobId,
  577. DWORD childJobId
  578. )
  579. /*++
  580. Routine Description:
  581. Tell the spooler to chain up two print jobs
  582. Arguments:
  583. hPrinter - Specifies the printer object
  584. parentJobId - Specifies the job to chain from
  585. childJobId - Specifies the job to chain to
  586. Return Value:
  587. TRUE if successful, FALSE if there is an error
  588. --*/
  589. {
  590. JOB_INFO_3 jobInfo3 = { parentJobId, childJobId };
  591. Warning(("Chaining cover page job to body job: %d => %d\n", parentJobId, childJobId));
  592. return SetJob(hPrinter, parentJobId, 3, (PBYTE) &jobInfo3, 0);
  593. }
  594. LPTSTR
  595. GetJobName(
  596. HANDLE hPrinter,
  597. DWORD jobId
  598. )
  599. /*++
  600. Routine Description:
  601. Return the name of the specified print job
  602. Arguments:
  603. hPrinter - Specifies the printer object
  604. jobId - Specifies the fax body job
  605. Return Value:
  606. Pointer to the job name string, NULL if there is an error
  607. --*/
  608. {
  609. JOB_INFO_1 *pJobInfo1;
  610. LPTSTR pJobName;
  611. //
  612. // Get the information about the specified job and
  613. // return a copy of the job name string
  614. //
  615. if (pJobInfo1 = MyGetJob(hPrinter, 1, jobId)) {
  616. pJobName = DuplicateString(pJobInfo1->pDocument);
  617. MemFree(pJobInfo1);
  618. } else
  619. pJobName = NULL;
  620. return pJobName;
  621. }
  622. LPTSTR
  623. ComposeFaxJobName(
  624. LPTSTR pBodyDocName,
  625. LPTSTR pRecipientName
  626. )
  627. /*++
  628. Routine Description:
  629. Compose the document name string for a cover page job
  630. Arguments:
  631. pBodyDocName - Specifies the name of the body job
  632. pRecipient - Specifies the recipient's name
  633. Return Value:
  634. Pointer to cover page job name string, NULL if there is an error
  635. --*/
  636. #define DOCNAME_FORMAT_STRING TEXT("%s - %s")
  637. {
  638. LPTSTR pCoverJobName;
  639. if (pBodyDocName == NULL) {
  640. //
  641. // If the body job name is NULL somehow, then simply
  642. // use the recipient's name as the cover page job name.
  643. //
  644. pCoverJobName = DuplicateString(pRecipientName);
  645. } else if (pCoverJobName = MemAlloc(SizeOfString(DOCNAME_FORMAT_STRING) +
  646. SizeOfString(pBodyDocName) +
  647. SizeOfString(pRecipientName)))
  648. {
  649. //
  650. // Otherwise, the cover page job name is generated by
  651. // concatenating the recipient's name with the body job name.
  652. //
  653. wsprintf(pCoverJobName, DOCNAME_FORMAT_STRING, pRecipientName, pBodyDocName);
  654. }
  655. return pCoverJobName;
  656. }
  657. LPTSTR
  658. GetBaseNoteFilename(
  659. VOID
  660. )
  661. /*++
  662. Routine Description:
  663. Get the name of base cover page file in system32 directory
  664. Arguments:
  665. argument-name - description of argument
  666. Return Value:
  667. Pointer to name of base cover page file
  668. NULL if there is an error
  669. --*/
  670. #define BASENOTE_FILENAME TEXT("\\basenote.cov")
  671. {
  672. TCHAR systemDir[MAX_PATH];
  673. LPTSTR pBaseNoteName = NULL;
  674. COVDOCINFO covDocInfo;
  675. if (GetSystemDirectory(systemDir, MAX_PATH) &&
  676. (pBaseNoteName = MemAlloc(SizeOfString(systemDir) + SizeOfString(BASENOTE_FILENAME))))
  677. {
  678. _tcscpy(pBaseNoteName, systemDir);
  679. _tcscat(pBaseNoteName, BASENOTE_FILENAME);
  680. Verbose(("Base cover page filename: %ws\n", pBaseNoteName));
  681. if (PrintCoverPage(NULL, NULL, pBaseNoteName, &covDocInfo) ||
  682. ! (covDocInfo.Flags & COVFP_NOTE) ||
  683. ! (covDocInfo.Flags & COVFP_SUBJECT))
  684. {
  685. Error(("Invalid base cover page file: %ws\n", pBaseNoteName));
  686. MemFree(pBaseNoteName);
  687. pBaseNoteName = NULL;
  688. }
  689. }
  690. return pBaseNoteName;
  691. }
  692. LPTSTR
  693. ComposeFaxJobParameter(
  694. PUSERMEM pUserMem,
  695. PCOVERPAGEFIELDS pCPFields
  696. )
  697. /*++
  698. Routine Description:
  699. Assemble fax job parameters into a single tagged string
  700. Arguments:
  701. pUserMem - Points to user mode memory structure
  702. pCPFields - Points to cover page field information
  703. Return Value:
  704. Pointer to fax job parameter string, NULL if there is an error
  705. --*/
  706. #define NUM_JOBPARAM_TAGS 10
  707. {
  708. //
  709. // Tags used to pass information about fax jobs
  710. //
  711. static LPTSTR faxtagNames[NUM_JOBPARAM_TAGS] = {
  712. FAXTAG_RECIPIENT_NUMBER,
  713. FAXTAG_RECIPIENT_NAME,
  714. FAXTAG_TSID,
  715. FAXTAG_SENDER_NAME,
  716. FAXTAG_SENDER_COMPANY,
  717. FAXTAG_SENDER_DEPT,
  718. FAXTAG_BILLING_CODE,
  719. FAXTAG_EMAIL_NAME,
  720. FAXTAG_WHEN_TO_SEND,
  721. FAXTAG_SEND_AT_TIME
  722. };
  723. LPTSTR faxtagValues[NUM_JOBPARAM_TAGS] = {
  724. pCPFields->RecFaxNumber,
  725. pCPFields->RecName,
  726. pCPFields->SdrFaxNumber,
  727. pCPFields->SdrName,
  728. pCPFields->SdrCompany,
  729. pCPFields->SdrDepartment,
  730. pUserMem->devmode.dmPrivate.billingCode,
  731. pUserMem->devmode.dmPrivate.emailAddress,
  732. NULL,
  733. NULL
  734. };
  735. LPTSTR pJobParam, p;
  736. INT index, size;
  737. TCHAR SendAtTime[16];
  738. //
  739. // create the sendattime string
  740. //
  741. if (pUserMem->devmode.dmPrivate.whenToSend == SENDFAX_AT_CHEAP) {
  742. faxtagValues[8] = TEXT("cheap");
  743. }
  744. if (pUserMem->devmode.dmPrivate.whenToSend == SENDFAX_AT_TIME) {
  745. wsprintf( SendAtTime, TEXT("%02d:%02d"),
  746. pUserMem->devmode.dmPrivate.sendAtTime.Hour,
  747. pUserMem->devmode.dmPrivate.sendAtTime.Minute
  748. );
  749. faxtagValues[8] = TEXT("at");
  750. faxtagValues[9] = SendAtTime;
  751. }
  752. //
  753. // Figure out the total length of the tagged string
  754. //
  755. for (index=size=0; index < NUM_JOBPARAM_TAGS; index++) {
  756. if (faxtagValues[index] && !IsEmptyString(faxtagValues[index]))
  757. size += SizeOfString(faxtagNames[index]) + SizeOfString(faxtagValues[index]);
  758. }
  759. if (size == 0 || (pJobParam = p = MemAlloc(size)) == NULL)
  760. return NULL;
  761. //
  762. // Assemble fax job parameters into a single tagged string
  763. //
  764. for (index=0; index < NUM_JOBPARAM_TAGS; index++) {
  765. if (faxtagValues[index] && !IsEmptyString(faxtagValues[index])) {
  766. _tcscpy(p, faxtagNames[index]);
  767. p += _tcslen(p);
  768. _tcscpy(p, faxtagValues[index]);
  769. p += _tcslen(p);
  770. }
  771. }
  772. return pJobParam;
  773. }
  774. BOOL
  775. DoCoverPageRendering(
  776. HDC hdc,
  777. PUSERMEM pUserMem
  778. )
  779. /*++
  780. Routine Description:
  781. Render a cover page for each recipient
  782. Arguments:
  783. hdc - Handle to the current printer device context
  784. pUserMem - Points to user mode memory structure
  785. Return Value:
  786. TRUE if successful, FALSE otherwise
  787. --*/
  788. {
  789. PCOVERPAGEFIELDS pCPFields;
  790. PRECIPIENT pRecipient;
  791. DOCINFO docinfo;
  792. INT newJobId, lastJobId, cCoverPagesSent;
  793. LPTSTR pBaseNoteName = NULL;
  794. PDMPRIVATE pdmPrivate = &pUserMem->devmode.dmPrivate;
  795. HANDLE hPrinter = pUserMem->hPrinter;
  796. DWORD bodyJobId = pUserMem->jobId;
  797. LPTSTR pBodyDocName, pJobParam;
  798. BOOL sendCoverPage;
  799. DWORD pageCount;
  800. //
  801. // Determine if we need a cover page or not
  802. //
  803. if ((sendCoverPage = pdmPrivate->sendCoverPage) && IsEmptyString(pUserMem->coverPage)) {
  804. Warning(("Missing cover page file\n"));
  805. sendCoverPage = FALSE;
  806. }
  807. //
  808. // Check if we need an extra cover page for rendering note/subject fields
  809. //
  810. pageCount = pUserMem->pageCount;
  811. if (sendCoverPage)
  812. pageCount++;
  813. if (((pUserMem->pSubject && !(pUserMem->noteSubjectFlag & COVFP_SUBJECT)) ||
  814. (pUserMem->pNoteMessage && !(pUserMem->noteSubjectFlag & COVFP_NOTE))) &&
  815. (pBaseNoteName = GetBaseNoteFilename()))
  816. {
  817. pageCount++;
  818. }
  819. //
  820. // Collect cover page information
  821. //
  822. if ((pCPFields = CollectCoverPageFields(pUserMem, pageCount)) == NULL) {
  823. Error(("Couldn't collect cover page information\n"));
  824. return FALSE;
  825. }
  826. //
  827. // Fill out a DOCINFO structure which is passed to StartDoc
  828. //
  829. memset(&docinfo, 0, sizeof(docinfo));
  830. docinfo.cbSize = sizeof(docinfo);
  831. pBodyDocName = GetJobName(hPrinter, bodyJobId);
  832. //
  833. // We assume the fax body job has already been paused
  834. // Use a separate cover page for each recipient
  835. //
  836. lastJobId = cCoverPagesSent = 0;
  837. for (pRecipient=pUserMem->pRecipients; pRecipient; pRecipient=pRecipient->pNext) {
  838. //
  839. // Fill out other fields of cover page information
  840. //
  841. pCPFields->Subject = pUserMem->pSubject;
  842. pCPFields->Note = pUserMem->pNoteMessage;
  843. //
  844. // Get recipient's name and fax number
  845. //
  846. pCPFields->RecName = pRecipient->pName;
  847. pCPFields->RecFaxNumber = pRecipient->pAddress;
  848. //
  849. // Start a cover page job
  850. //
  851. docinfo.lpszDocName = ComposeFaxJobName(pBodyDocName, pRecipient->pName);
  852. pJobParam = ComposeFaxJobParameter(pUserMem, pCPFields);
  853. if ((newJobId = StartDoc(hdc, &docinfo)) > 0) {
  854. BOOL rendered = FALSE;
  855. COVDOCINFO covDocInfo;
  856. //
  857. // Pass fax job parameters using JOB_INFO_2.pParameters field.
  858. //
  859. if (! SetJob(hPrinter, newJobId, 0, NULL, JOB_CONTROL_PAUSE) ||
  860. ! SetJobInfoAndTime(hPrinter,
  861. newJobId,
  862. pJobParam ? pJobParam : pCPFields->RecFaxNumber,
  863. pdmPrivate))
  864. {
  865. Error(("Couldn't modify the fax job\n"));
  866. } else if (! sendCoverPage) {
  867. //
  868. // If the user chose not to include cover page,
  869. // the cover page job will be empty
  870. //
  871. rendered = TRUE;
  872. } else if (StartPage(hdc) > 0) {
  873. //
  874. // Call the library function to render the cover page.
  875. //
  876. rendered = PrintCoverPage( hdc, pCPFields, pUserMem->coverPage, &covDocInfo );
  877. if (rendered) {
  878. Error(("PrintCoverPage failed: %d\n", rendered ));
  879. rendered = FALSE;
  880. } else {
  881. rendered = TRUE;
  882. }
  883. EndPage(hdc);
  884. }
  885. //
  886. // Chain the cover page job to the fax body job if no error occured
  887. //
  888. if (rendered && ChainFaxJobs(hPrinter, newJobId, bodyJobId)) {
  889. //
  890. // Check if we need an extra page for note/subject fields
  891. //
  892. if (pBaseNoteName) {
  893. if (StartPage(hdc) > 0) {
  894. DWORD ec;
  895. if (pUserMem->noteSubjectFlag & COVFP_SUBJECT)
  896. pCPFields->Subject = NULL;
  897. if (pUserMem->noteSubjectFlag & COVFP_NOTE)
  898. pCPFields->Note = NULL;
  899. ec = PrintCoverPage(hdc, pCPFields, pBaseNoteName, &covDocInfo);
  900. if (ec) {
  901. Error(("PrintCoverPage failed: %d\n", ec));
  902. }
  903. EndPage(hdc);
  904. } else
  905. Error(("StartPage failed: %d\n", GetLastError()));
  906. }
  907. if (lastJobId != 0)
  908. SetJob(hPrinter, lastJobId, 0, NULL, JOB_CONTROL_RESUME);
  909. lastJobId = newJobId;
  910. EndDoc(hdc);
  911. cCoverPagesSent++;
  912. } else {
  913. AbortDoc(hdc);
  914. newJobId = 0;
  915. }
  916. }
  917. MemFree((PVOID)docinfo.lpszDocName);
  918. MemFree((PVOID)pJobParam);
  919. //
  920. // Indicate to the user about the fact that we failed to render the
  921. // for the current recipient
  922. //
  923. if (newJobId <= 0)
  924. DisplayMessageDialog(NULL, 0, 0, IDS_CPRENDER_FAILED, pRecipient->pName);
  925. }
  926. MemFree(pBaseNoteName);
  927. MemFree(pBodyDocName);
  928. FreeCoverPageFields(pCPFields);
  929. //
  930. // Resume the last cover page job if it's paused and
  931. // delete the fax body job if no cover page jobs were sent
  932. //
  933. if (lastJobId != 0)
  934. SetJob(hPrinter, lastJobId, 0, NULL, JOB_CONTROL_RESUME);
  935. if (cCoverPagesSent > 0)
  936. SetJob(hPrinter, bodyJobId, 0, NULL, JOB_CONTROL_RESUME);
  937. else {
  938. Error(("Fax job deleted due to an error\n"));
  939. SetJob(hPrinter, bodyJobId, 0, NULL, JOB_CONTROL_DELETE);
  940. }
  941. return cCoverPagesSent > 0;
  942. }
  943. INT
  944. DocEventEndDocPost(
  945. HDC hdc,
  946. PUSERMEM pUserMem
  947. )
  948. /*++
  949. Routine Description:
  950. Handle ENDDOCPOST document event
  951. Arguments:
  952. hdc - Specifies the printer device context
  953. pUserMem - Points to the user mode memory structure
  954. Return Value:
  955. Return value for DrvDocumentEvent
  956. --*/
  957. {
  958. INT result = DOCUMENTEVENT_SUCCESS;
  959. switch (pUserMem->jobType) {
  960. case JOBTYPE_NORMAL:
  961. Warning(("Number of pages printed: %d\n", pUserMem->pageCount));
  962. if (! pUserMem->directPrinting) {
  963. HDC hdcCP = NULL;
  964. DWORD dmFlags, dmFields;
  965. SHORT dmPaperSize, dmOrientation;
  966. PDEVMODE pdmPublic;
  967. PDMPRIVATE pdmPrivate;
  968. //
  969. // Generate a cover page for each recipient and associate
  970. // the cover page job with the main body. Create a new DC
  971. // to rendering the cover page instead of using the existing DC.
  972. //
  973. pdmPublic = &pUserMem->devmode.dmPublic;
  974. pdmPrivate = &pUserMem->devmode.dmPrivate;
  975. dmFlags = pdmPrivate->flags;
  976. pdmPrivate->flags |= FAXDM_NO_WIZARD;
  977. if (pUserMem->cpPaperSize) {
  978. dmFields = pdmPublic->dmFields;
  979. pdmPublic->dmFields &= ~(DM_PAPERWIDTH|DM_PAPERLENGTH|DM_FORMNAME);
  980. pdmPublic->dmFields |= DM_PAPERSIZE;
  981. dmPaperSize = pdmPublic->dmPaperSize;
  982. pdmPublic->dmPaperSize = pUserMem->cpPaperSize;
  983. dmOrientation = pdmPublic->dmOrientation;
  984. pdmPublic->dmOrientation = pUserMem->cpOrientation;
  985. }
  986. if (! (hdcCP = CreateDC(NULL,
  987. pUserMem->pPrinterName,
  988. NULL,
  989. (PDEVMODE) &pUserMem->devmode)) ||
  990. ! DoCoverPageRendering(hdcCP, pUserMem))
  991. {
  992. result = DOCUMENTEVENT_FAILURE;
  993. }
  994. if (hdcCP != NULL)
  995. DeleteDC(hdcCP);
  996. if (pUserMem->cpPaperSize) {
  997. pdmPublic->dmFields = dmFields;
  998. pdmPublic->dmPaperSize = dmPaperSize;
  999. pdmPublic->dmOrientation = dmOrientation;
  1000. }
  1001. pdmPrivate->flags = dmFlags;
  1002. //
  1003. // Free up the list of recipients
  1004. //
  1005. FreeRecipientList(pUserMem);
  1006. }
  1007. break;
  1008. }
  1009. return result;
  1010. }
  1011. INT
  1012. DrvDocumentEvent(
  1013. HANDLE hPrinter,
  1014. HDC hdc,
  1015. INT iEsc,
  1016. ULONG cbIn,
  1017. PULONG pjIn,
  1018. ULONG cbOut,
  1019. PULONG pjOut
  1020. )
  1021. /*++
  1022. Routine Description:
  1023. Hook into GDI at various points during the output process
  1024. Arguments:
  1025. hPrinter - Specifies the printer object
  1026. hdc - Handle to the printer DC
  1027. iEsc - Why this function is called (see notes below)
  1028. cbIn - Size of the input buffer
  1029. pjIn - Pointer to the input buffer
  1030. cbOut - Size of the output buffer
  1031. pjOut - Pointer to the output buffer
  1032. Return Value:
  1033. DOCUMENTEVENT_SUCCESS - success
  1034. DOCUMENTEVENT_UNSUPPORTED - iEsc is not supported
  1035. DOCUMENTEVENT_FAILURE - an error occured
  1036. NOTE:
  1037. DOCUMENTEVENT_CREATEDCPRE
  1038. input - pointer to a CREATEDCDATA structure
  1039. output - pointer to a devmode that's passed to DrvEnablePDEV
  1040. return value -
  1041. DOCUMENTEVENT_FAILURE causes CreateDC to fail and nothing else is called
  1042. DOCUMENTEVENT_CREATEDCPOST
  1043. hdc - NULL if if something failed since CREATEDCPRE
  1044. input - pointer to the devmode pointer returned by CREATEDCPRE
  1045. return value - ignored
  1046. DOCUMENTEVENT_RESETDCPRE
  1047. input - pointer to the input devmode passed to ResetDC
  1048. output - pointer to a devmode that's passed to the kernel driver
  1049. return value -
  1050. DOCUMENTEVENT_FAILURE causes ResetDC to fail
  1051. and CREATEDCPOST will not be called in that case
  1052. DOCUMENTEVENT_RESETDCPOST
  1053. return value - ignored
  1054. DOCUMENTEVENT_STARTDOCPRE
  1055. input - pointer to a DOCINFOW structure
  1056. return value -
  1057. DOCUMENTEVENT_FAILURE causes StartDoc to fail
  1058. and DrvStartDoc will not be called in this case
  1059. DOCUMENTEVENT_STARTDOCPOST
  1060. return value - ignored
  1061. DOCUMENTEVENT_STARTPAGE
  1062. return value -
  1063. DOCUMENTEVENT_FAILURE causes StartPage to fail
  1064. and DrvStartPage will not be called in this case
  1065. DOCUMENTEVENT_ENDPAGE
  1066. return value - ignored and DrvEndPage always called
  1067. DOCUMENTEVENT_ENDDOCPRE
  1068. return value - ignored and DrvEndDoc always called
  1069. DOCUMENTEVENT_ENDDOCPOST
  1070. return value - ignored
  1071. DOCUMENTEVENT_ABORTDOC
  1072. return value - ignored
  1073. DOCUMENTEVENT_DELETEDC
  1074. return value - ignored
  1075. DOCUMENTEVENT_ESCAPE
  1076. input - pointer to a ESCAPEDATA structure
  1077. cbOut, pjOut - cbOutput and lpszOutData parameters passed to ExtEscape
  1078. return value - ignored
  1079. DOCUMENTEVENT_SPOOLED
  1080. This flag bit is ORed with other iEsc values if the document is
  1081. spooled as metafile rather than printed directly to port.
  1082. --*/
  1083. {
  1084. PUSERMEM pUserMem = NULL;
  1085. PDEVMODE pDevmode;
  1086. INT result = DOCUMENTEVENT_SUCCESS;
  1087. Verbose(("Entering DrvDocumentEvent: %d...\n", iEsc));
  1088. //
  1089. // Metafile spooling on fax jobs is not currently supported
  1090. //
  1091. Assert((iEsc & DOCUMENTEVENT_SPOOLED) == 0);
  1092. //
  1093. // Check if the document event requires a device context
  1094. //
  1095. if (DocEventRequiresDC(iEsc)) {
  1096. if (!hdc || !(pUserMem = GetPDEVUserMem(hdc))) {
  1097. Error(("Invalid device context: hdc = %x, iEsc = %d\n", hdc, iEsc));
  1098. return DOCUMENTEVENT_FAILURE;
  1099. }
  1100. }
  1101. switch (iEsc) {
  1102. case DOCUMENTEVENT_CREATEDCPRE:
  1103. Assert(cbIn >= sizeof(CREATEDCDATA) && pjIn && cbOut >= sizeof(PDEVMODE) && pjOut);
  1104. result = DocEventCreateDCPre(hPrinter, hdc, (PCREATEDCDATA) pjIn, (PDEVMODE *) pjOut);
  1105. break;
  1106. case DOCUMENTEVENT_CREATEDCPOST:
  1107. //
  1108. // Handle CREATEDCPOST document event:
  1109. // If CreateDC succeeded, then associate the user mode memory structure
  1110. // with the device context. Otherwise, free the user mode memory structure.
  1111. //
  1112. Assert(cbIn >= sizeof(PVOID) && pjIn);
  1113. pDevmode = *((PDEVMODE *) pjIn);
  1114. Assert(CurrentVersionDevmode(pDevmode));
  1115. pUserMem = ((PDRVDEVMODE) pDevmode)->dmPrivate.pUserMem;
  1116. Assert(ValidPDEVUserMem(pUserMem));
  1117. if (hdc) {
  1118. pUserMem->hdc = hdc;
  1119. EnterDrvSem();
  1120. pUserMem->pNext = gUserMemList;
  1121. gUserMemList = pUserMem;
  1122. LeaveDrvSem();
  1123. } else
  1124. FreePDEVUserMem(pUserMem);
  1125. break;
  1126. case DOCUMENTEVENT_RESETDCPRE:
  1127. Verbose(("Document event: RESETDCPRE\n"));
  1128. Assert(cbIn >= sizeof(PVOID) && pjIn && cbOut >= sizeof(PDEVMODE) && pjOut);
  1129. result = DocEventResetDCPre(hdc, pUserMem, *((PDEVMODE *) pjIn), (PDEVMODE *) pjOut);
  1130. break;
  1131. case DOCUMENTEVENT_STARTDOCPRE:
  1132. //
  1133. // if printing a fax attachment then enable direct printing
  1134. //
  1135. if (pUserMem->hMutex == NULL) {
  1136. pUserMem->hMutex = OpenMutex(MUTEX_ALL_ACCESS,FALSE,FAXXP_MUTEX_NAME);
  1137. if (pUserMem->hMutex) {
  1138. if (WaitForSingleObject( pUserMem->hMutex, 0) == WAIT_OBJECT_0) {
  1139. pUserMem->directPrinting = TRUE;
  1140. }
  1141. else {
  1142. CloseHandle( pUserMem->hMutex ) ;
  1143. pUserMem->hMutex = NULL;
  1144. }
  1145. }
  1146. }
  1147. //
  1148. // normal case if we're bringing up the send wizard
  1149. //
  1150. if (! pUserMem->directPrinting) {
  1151. Assert(cbIn >= sizeof(PVOID) && pjIn);
  1152. result = DocEventStartDocPre(hdc, pUserMem, *((LPDOCINFO *) pjIn));
  1153. }
  1154. //
  1155. // we're doing direct printing -- check if this is invoked via mapi-spooler
  1156. //
  1157. else if (pUserMem->hMutex) {
  1158. //
  1159. // we own the mutex...make sure we can open the shared memory region.
  1160. //
  1161. pUserMem->pEnvVar = OpenFileMapping(FILE_MAP_ALL_ACCESS,FALSE,FAXXP_MEM_NAME);
  1162. if (!pUserMem->pEnvVar) {
  1163. ReleaseMutex( pUserMem->hMutex );
  1164. CloseHandle( pUserMem->hMutex );
  1165. pUserMem->hMutex = NULL;
  1166. } else {
  1167. //
  1168. // we own the mutex and we have the shared memory region open.
  1169. //
  1170. // check if we are printing to a file or are doing direct printing for
  1171. // the mapi spooler.
  1172. //
  1173. LPTSTR filename;
  1174. filename = (LPTSTR)MapViewOfFile(
  1175. pUserMem->pEnvVar,
  1176. FILE_MAP_WRITE,
  1177. 0,
  1178. 0,
  1179. 0
  1180. );
  1181. if (!filename) {
  1182. Error(("Failed to map a view of the file: %d\n", pUserMem->pEnvVar));
  1183. return DOCUMENTEVENT_FAILURE;
  1184. }
  1185. if (filename && *filename) {
  1186. //
  1187. // this is really the filename we want to print to.
  1188. //
  1189. pUserMem->directPrinting = TRUE;
  1190. pUserMem->pPrintFile = DuplicateString(filename);
  1191. pUserMem->jobType = JOBTYPE_DIRECT;
  1192. (*((LPDOCINFO *) pjIn))->lpszOutput = pUserMem->pPrintFile;
  1193. }
  1194. UnmapViewOfFile( filename );
  1195. }
  1196. }
  1197. break;
  1198. case DOCUMENTEVENT_STARTDOCPOST:
  1199. if (!pUserMem->directPrinting && pUserMem->jobType == JOBTYPE_NORMAL) {
  1200. //
  1201. // Job ID is passed in from GDI
  1202. //
  1203. Assert(cbIn >= sizeof(DWORD) && pjIn);
  1204. pUserMem->jobId = *((LPDWORD) pjIn);
  1205. //
  1206. // Tell spooler to pause the fax body job so that
  1207. // we can associate cover pages with it later
  1208. //
  1209. if (! SetJob(pUserMem->hPrinter, pUserMem->jobId, 0, NULL, JOB_CONTROL_PAUSE)) {
  1210. Error(("Couldn't pause fax body job: %d\n", pUserMem->jobId));
  1211. return DOCUMENTEVENT_FAILURE;
  1212. }
  1213. } else if (pUserMem->pEnvVar) {
  1214. LPDWORD pJobId;
  1215. //
  1216. // Job ID is passed in from GDI
  1217. //
  1218. Assert(cbIn >= sizeof(DWORD) && pjIn);
  1219. pUserMem->jobId = *((LPDWORD) pjIn);
  1220. if (!pUserMem->pPrintFile) {
  1221. //
  1222. // Tell spooler to pause the fax job
  1223. // so that the mapi fax transport provider
  1224. // can chain this job
  1225. //
  1226. if (! SetJob(pUserMem->hPrinter, pUserMem->jobId, 0, NULL, JOB_CONTROL_PAUSE)) {
  1227. Error(("Couldn't pause fax body job: %d\n", pUserMem->jobId));
  1228. return DOCUMENTEVENT_FAILURE;
  1229. }
  1230. }
  1231. pJobId = (LPDWORD)MapViewOfFile(
  1232. pUserMem->pEnvVar,
  1233. FILE_MAP_WRITE,
  1234. 0,
  1235. 0,
  1236. 0
  1237. );
  1238. if (!pJobId) {
  1239. Error(("Failed to map a view of the file: %d\n", pUserMem->jobId));
  1240. return DOCUMENTEVENT_FAILURE;
  1241. }
  1242. *pJobId = (DWORD) pUserMem->jobId;
  1243. UnmapViewOfFile( pJobId );
  1244. CloseHandle( pUserMem->pEnvVar );
  1245. pUserMem->pEnvVar = NULL;
  1246. }
  1247. break;
  1248. case DOCUMENTEVENT_ENDPAGE:
  1249. if (! pUserMem->directPrinting)
  1250. pUserMem->pageCount++;
  1251. break;
  1252. case DOCUMENTEVENT_ENDDOCPOST:
  1253. if (! pUserMem->directPrinting)
  1254. result = DocEventEndDocPost(hdc, pUserMem);
  1255. else if (pUserMem->hMutex) {
  1256. HANDLE hEvent = NULL;
  1257. hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, FAXXP_EVENT_NAME);
  1258. if (hEvent) {
  1259. SetEvent(hEvent);
  1260. CloseHandle(hEvent) ;
  1261. }
  1262. ReleaseMutex(pUserMem->hMutex);
  1263. CloseHandle(pUserMem->hMutex);
  1264. pUserMem->hMutex = NULL;
  1265. }
  1266. break;
  1267. case DOCUMENTEVENT_DELETEDC:
  1268. EnterDrvSem();
  1269. if (pUserMem == gUserMemList)
  1270. gUserMemList = gUserMemList->pNext;
  1271. else {
  1272. PUSERMEM p;
  1273. if (p = gUserMemList) {
  1274. while (p->pNext && p->pNext != pUserMem)
  1275. p = p->pNext;
  1276. if (p->pNext != NULL)
  1277. p->pNext = pUserMem->pNext;
  1278. else
  1279. Error(("Orphaned user mode memory structure!!!\n"));
  1280. } else
  1281. Error(("gUserMemList shouldn't be NULL!!!\n"));
  1282. }
  1283. LeaveDrvSem();
  1284. FreePDEVUserMem(pUserMem);
  1285. break;
  1286. case DOCUMENTEVENT_ABORTDOC:
  1287. case DOCUMENTEVENT_RESETDCPOST:
  1288. case DOCUMENTEVENT_STARTPAGE:
  1289. case DOCUMENTEVENT_ENDDOCPRE:
  1290. break;
  1291. case DOCUMENTEVENT_ESCAPE:
  1292. default:
  1293. Verbose(("Unsupported DrvDocumentEvent escape: %d\n", iEsc));
  1294. result = DOCUMENTEVENT_UNSUPPORTED;
  1295. break;
  1296. }
  1297. return result;
  1298. }