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.

3441 lines
110 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 "prtcovpg.h"
  17. #include "jobtag.h"
  18. #include "faxreg.h"
  19. #include "faxsendw.h"
  20. #include "InfoWzrd.h"
  21. #include "tifflib.h"
  22. #include "faxutil.h"
  23. #include "covpg.h"
  24. //
  25. // Defenitions
  26. //
  27. #define SZ_CONT TEXT("...")
  28. #define SZ_CONT_SIZE (sizeof(SZ_CONT) / sizeof(TCHAR))
  29. //
  30. // Defined in FaxUI.c
  31. // Used to block the reentrancy of FxsWzrd.dll
  32. //
  33. extern BOOL g_bRunningWizard;
  34. extern CRITICAL_SECTION g_csRunningWizard;
  35. extern BOOL g_bInitRunningWizardCS;
  36. //
  37. // Data structure passed in during CREATEDCPRE document event
  38. //
  39. typedef struct
  40. {
  41. LPTSTR pDriverName; // driver name
  42. LPTSTR pPrinterName; // printer name
  43. PDEVMODE pdmInput; // input devmode
  44. ULONG fromCreateIC; // whether called from CreateIC
  45. } CREATEDCDATA, *PCREATEDCDATA;
  46. //
  47. // Data structure passed in during ESCAPE document event
  48. //
  49. typedef struct
  50. {
  51. ULONG iEscape; // nEscape parameter passed to ExtEscape
  52. ULONG cbInput; // cbInput parameter passed to ExtEscape
  53. LPCSTR pInput; // pszInData parameter passed to ExtEscape
  54. } ESCAPEDATA, *PESCAPEDATA;
  55. //
  56. // Check if a document event requires a device context
  57. //
  58. #define DocEventRequiresDC(iEsc) \
  59. ((iEsc) >= DOCUMENTEVENT_RESETDCPRE && (iEsc) <= DOCUMENTEVENT_LAST)
  60. static DWORD LaunchFaxWizard(PDOCEVENTUSERMEM pDocEventUserMem);
  61. static DWORD ShowReentrancyMessage(void);
  62. static void
  63. ComposeRecipientJobParam(
  64. LPTSTR lpParamBuf,
  65. LPDWORD lpdwParamSize,
  66. const COVERPAGEFIELDS * pCPFields
  67. );
  68. static void
  69. ComposeSenderJobParam(
  70. LPTSTR lpParamBuf,
  71. LPDWORD lpdwParamSize,
  72. PDOCEVENTUSERMEM pDocEventUserMem,
  73. const COVERPAGEFIELDS * pCPFields
  74. );
  75. static BOOL
  76. ComposeFaxJobParameter(
  77. PDOCEVENTUSERMEM pDocEventUserMem,
  78. PCOVERPAGEFIELDS pCPFields,
  79. LPTSTR * lppParamBuf
  80. );
  81. static void
  82. CloseMappingHandles(
  83. PDOCEVENTUSERMEM pDocEventUserMem
  84. );
  85. PDOCEVENTUSERMEM
  86. GetPDEVUserMem(
  87. HDC hdc
  88. )
  89. /*++
  90. Routine Description:
  91. Retrieve a pointer to the user mode memory structure associated with a PDEV
  92. Arguments:
  93. hdc - Specifies the printer device context
  94. Return Value:
  95. Pointer to user mode memory structure, NULL if there is an error
  96. --*/
  97. {
  98. PDOCEVENTUSERMEM pDocEventUserMem;
  99. //
  100. // Get a pointer to the user mode memory structure associated
  101. // with the specified device context
  102. //
  103. EnterDrvSem();
  104. pDocEventUserMem = gDocEventUserMemList;
  105. while (pDocEventUserMem && hdc != pDocEventUserMem->hdc)
  106. pDocEventUserMem = pDocEventUserMem->pNext;
  107. LeaveDrvSem();
  108. //
  109. // Make sure the user memory structure is valid
  110. //
  111. if (pDocEventUserMem)
  112. {
  113. if (! ValidPDEVUserMem(pDocEventUserMem))
  114. {
  115. Error(("Corrupted user mode memory structure\n"));
  116. pDocEventUserMem = NULL;
  117. }
  118. }
  119. else
  120. {
  121. Error(("DC has no associated user mode memory structure\n"));
  122. }
  123. return pDocEventUserMem;
  124. }
  125. static LRESULT
  126. FaxFreePersonalProfileInformation(
  127. PFAX_PERSONAL_PROFILE lpPersonalProfileInfo
  128. )
  129. {
  130. if (lpPersonalProfileInfo)
  131. {
  132. MemFree(lpPersonalProfileInfo->lptstrName);
  133. MemFree(lpPersonalProfileInfo->lptstrFaxNumber);
  134. MemFree(lpPersonalProfileInfo->lptstrCompany);
  135. MemFree(lpPersonalProfileInfo->lptstrStreetAddress);
  136. MemFree(lpPersonalProfileInfo->lptstrCity);
  137. MemFree(lpPersonalProfileInfo->lptstrState);
  138. MemFree(lpPersonalProfileInfo->lptstrZip);
  139. MemFree(lpPersonalProfileInfo->lptstrCountry);
  140. MemFree(lpPersonalProfileInfo->lptstrTitle);
  141. MemFree(lpPersonalProfileInfo->lptstrDepartment);
  142. MemFree(lpPersonalProfileInfo->lptstrOfficeLocation);
  143. MemFree(lpPersonalProfileInfo->lptstrHomePhone);
  144. MemFree(lpPersonalProfileInfo->lptstrOfficePhone);
  145. MemFree(lpPersonalProfileInfo->lptstrEmail);
  146. MemFree(lpPersonalProfileInfo->lptstrBillingCode);
  147. MemFree(lpPersonalProfileInfo->lptstrTSID);
  148. }
  149. return ERROR_SUCCESS;
  150. }
  151. static LRESULT
  152. FreeRecipientInfo(DWORD * pdwNumberOfRecipients, PFAX_PERSONAL_PROFILE lpRecipientsInfo)
  153. {
  154. LRESULT lResult;
  155. DWORD i;
  156. Assert(pdwNumberOfRecipients);
  157. if (*pdwNumberOfRecipients==0)
  158. return ERROR_SUCCESS;
  159. Assert(lpRecipientsInfo);
  160. for(i=0;i<*pdwNumberOfRecipients;i++)
  161. {
  162. if (lResult = FaxFreePersonalProfileInformation(&lpRecipientsInfo[i]) != ERROR_SUCCESS)
  163. return lResult;
  164. }
  165. MemFree(lpRecipientsInfo);
  166. *pdwNumberOfRecipients = 0;
  167. return ERROR_SUCCESS;
  168. }
  169. static DWORD
  170. CopyRecipientInfo(DWORD dwNumberOfRecipients,
  171. PFAX_PERSONAL_PROFILE pfppDestination,
  172. PFAX_PERSONAL_PROFILE pfppSource)
  173. {
  174. DWORD dwIndex;
  175. Assert(pfppDestination);
  176. Assert(pfppSource);
  177. for(dwIndex=0;dwIndex<dwNumberOfRecipients;dwIndex++)
  178. {
  179. if ((pfppDestination[dwIndex].lptstrName = DuplicateString(pfppSource[dwIndex].lptstrName)) == NULL)
  180. {
  181. Error(("Memory allocation failed\n"));
  182. return ERROR_NOT_ENOUGH_MEMORY;
  183. }
  184. if ((pfppDestination[dwIndex].lptstrFaxNumber = DuplicateString(pfppSource[dwIndex].lptstrFaxNumber)) == NULL)
  185. {
  186. Error(("Memory allocation failed\n"));
  187. return ERROR_NOT_ENOUGH_MEMORY;
  188. }
  189. Verbose(("Copied %ws from %ws\n", pfppSource[dwIndex].lptstrName,pfppSource[dwIndex].lptstrFaxNumber));
  190. }
  191. return ERROR_SUCCESS;
  192. }
  193. static DWORD
  194. CopyPersonalProfileInfo( PFAX_PERSONAL_PROFILE pfppDestination,
  195. PFAX_PERSONAL_PROFILE pfppSource)
  196. {
  197. /*++
  198. Routine Description:
  199. Duplicates FAX_PERSONAL_PROFILE structures
  200. Arguments:
  201. pfppDestination - points to destination structure
  202. pfppSource - points to source structure
  203. Comments:
  204. Set pfppDestination->dwSizeOfStruct before call to this function
  205. Return Value:
  206. ERROR_SUCCESS
  207. ERROR_INVALID_PARAMETER
  208. ERROR_NOT_ENOUGH_MEMORY
  209. --*/
  210. DWORD dwResult = ERROR_SUCCESS;
  211. Assert(pfppDestination);
  212. Assert(pfppSource);
  213. if (!pfppSource || !pfppDestination || (pfppSource->dwSizeOfStruct != sizeof(FAX_PERSONAL_PROFILE))
  214. || (pfppDestination->dwSizeOfStruct != sizeof(FAX_PERSONAL_PROFILE)))
  215. return ERROR_INVALID_PARAMETER;
  216. ZeroMemory(pfppDestination, sizeof(FAX_PERSONAL_PROFILE));
  217. pfppDestination->dwSizeOfStruct = sizeof(FAX_PERSONAL_PROFILE);
  218. if (pfppSource->lptstrName && !(pfppDestination->lptstrName = StringDup(pfppSource->lptstrName)))
  219. {
  220. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  221. goto error;
  222. }
  223. if (pfppSource->lptstrFaxNumber && !(pfppDestination->lptstrFaxNumber = StringDup(pfppSource->lptstrFaxNumber)))
  224. {
  225. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  226. goto error;
  227. }
  228. if (pfppSource->lptstrCompany && !(pfppDestination->lptstrCompany = StringDup(pfppSource->lptstrCompany)))
  229. {
  230. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  231. goto error;
  232. }
  233. if (pfppSource->lptstrStreetAddress && !(pfppDestination->lptstrStreetAddress = StringDup(pfppSource->lptstrStreetAddress)))
  234. {
  235. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  236. goto error;
  237. }
  238. if (pfppSource->lptstrCity && !(pfppDestination->lptstrCity = StringDup(pfppSource->lptstrCity)))
  239. {
  240. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  241. goto error;
  242. }
  243. if (pfppSource->lptstrState && !(pfppDestination->lptstrState = StringDup(pfppSource->lptstrState)))
  244. {
  245. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  246. goto error;
  247. }
  248. if (pfppSource->lptstrZip && !(pfppDestination->lptstrZip = StringDup(pfppSource->lptstrZip)))
  249. {
  250. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  251. goto error;
  252. }
  253. if (pfppSource->lptstrCountry && !(pfppDestination->lptstrCountry = StringDup(pfppSource->lptstrCountry)))
  254. {
  255. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  256. goto error;
  257. }
  258. if (pfppSource->lptstrTitle && !(pfppDestination->lptstrTitle = StringDup(pfppSource->lptstrTitle)))
  259. {
  260. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  261. goto error;
  262. }
  263. if (pfppSource->lptstrDepartment && !(pfppDestination->lptstrDepartment = StringDup(pfppSource->lptstrDepartment)))
  264. {
  265. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  266. goto error;
  267. }
  268. if (pfppSource->lptstrOfficeLocation && !(pfppDestination->lptstrOfficeLocation = StringDup(pfppSource->lptstrOfficeLocation)))
  269. {
  270. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  271. goto error;
  272. }
  273. if (pfppSource->lptstrHomePhone && !(pfppDestination->lptstrHomePhone = StringDup(pfppSource->lptstrHomePhone)))
  274. {
  275. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  276. goto error;
  277. }
  278. if (pfppSource->lptstrOfficePhone && !(pfppDestination->lptstrOfficePhone = StringDup(pfppSource->lptstrOfficePhone)))
  279. {
  280. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  281. goto error;
  282. }
  283. if (pfppSource->lptstrEmail && !(pfppDestination->lptstrEmail = StringDup(pfppSource->lptstrEmail)))
  284. {
  285. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  286. goto error;
  287. }
  288. if (pfppSource->lptstrBillingCode && !(pfppDestination->lptstrBillingCode = StringDup(pfppSource->lptstrBillingCode)))
  289. {
  290. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  291. goto error;
  292. }
  293. if (pfppSource->lptstrTSID && !(pfppDestination->lptstrTSID = StringDup(pfppSource->lptstrTSID)))
  294. {
  295. dwResult = ERROR_NOT_ENOUGH_MEMORY;
  296. goto error;
  297. }
  298. goto exit;
  299. error:
  300. MemFree(pfppDestination->lptstrName);
  301. MemFree(pfppDestination->lptstrFaxNumber);
  302. MemFree(pfppDestination->lptstrCompany);
  303. MemFree(pfppDestination->lptstrStreetAddress);
  304. MemFree(pfppDestination->lptstrCity);
  305. MemFree(pfppDestination->lptstrState);
  306. MemFree(pfppDestination->lptstrZip);
  307. MemFree(pfppDestination->lptstrCountry);
  308. MemFree(pfppDestination->lptstrTitle);
  309. MemFree(pfppDestination->lptstrDepartment);
  310. MemFree(pfppDestination->lptstrOfficeLocation);
  311. MemFree(pfppDestination->lptstrHomePhone);
  312. MemFree(pfppDestination->lptstrOfficePhone);
  313. MemFree(pfppDestination->lptstrEmail);
  314. MemFree(pfppDestination->lptstrBillingCode);
  315. MemFree(pfppDestination->lptstrTSID);
  316. exit:
  317. return dwResult;
  318. }
  319. VOID
  320. FreePDEVUserMem(
  321. PDOCEVENTUSERMEM pDocEventUserMem
  322. )
  323. /*++
  324. Routine Description:
  325. Free up the user mode memory associated with each PDEV and delete preview file if created.
  326. Arguments:
  327. pDocEventUserMem - Points to the user mode memory structure
  328. Return Value:
  329. NONE
  330. --*/
  331. {
  332. if (pDocEventUserMem) {
  333. FreeRecipientInfo(&pDocEventUserMem->dwNumberOfRecipients,pDocEventUserMem->lpRecipientsInfo);
  334. FaxFreePersonalProfileInformation(pDocEventUserMem->lpSenderInfo);
  335. //
  336. // Free our mapping file resources (if allocated)
  337. //
  338. CloseMappingHandles(pDocEventUserMem);
  339. //
  340. // If we created a preview file, and for some reason it wasn't deleted than delete it.
  341. //
  342. if (pDocEventUserMem->szPreviewFile[0] != TEXT('\0'))
  343. {
  344. if (!DeleteFile(pDocEventUserMem->szPreviewFile))
  345. {
  346. Error(("DeleteFile() failed. Error code: %d.\n", GetLastError()));
  347. }
  348. }
  349. MemFree(pDocEventUserMem->lpSenderInfo);
  350. MemFree(pDocEventUserMem->lptstrServerName);
  351. MemFree(pDocEventUserMem->lptstrPrinterName);
  352. MemFree(pDocEventUserMem->pSubject);
  353. MemFree(pDocEventUserMem->pNoteMessage);
  354. MemFree(pDocEventUserMem->pPrintFile);
  355. MemFree(pDocEventUserMem->pReceiptAddress);
  356. MemFree(pDocEventUserMem->pPriority);
  357. MemFree(pDocEventUserMem->pReceiptFlags);
  358. MemFree(pDocEventUserMem);
  359. }
  360. }
  361. void
  362. CloseMappingHandles(PDOCEVENTUSERMEM pDocEventUserMem)
  363. /*++
  364. Routine Description:
  365. Free any resources that were used for the preview mapping
  366. Arguments:
  367. pDocEventUserMem - Points to the user mode memory structure
  368. Return Value: --
  369. --*/
  370. {
  371. if (pDocEventUserMem->pPreviewTiffPage)
  372. {
  373. UnmapViewOfFile(pDocEventUserMem->pPreviewTiffPage);
  374. pDocEventUserMem->pPreviewTiffPage = NULL;
  375. }
  376. if (pDocEventUserMem->hMapping)
  377. {
  378. if (!CloseHandle(pDocEventUserMem->hMapping))
  379. {
  380. Error(("CloseHandle() failed: %d.\n", GetLastError()));
  381. // Try to continue...
  382. }
  383. pDocEventUserMem->hMapping = NULL;
  384. }
  385. if (INVALID_HANDLE_VALUE != pDocEventUserMem->hMappingFile)
  386. {
  387. if (!CloseHandle(pDocEventUserMem->hMappingFile))
  388. {
  389. Error(("CloseHandle() failed: %d.\n", GetLastError()));
  390. // Try to continue...
  391. }
  392. pDocEventUserMem->hMappingFile = INVALID_HANDLE_VALUE;
  393. }
  394. }
  395. DWORD
  396. CreateTiffPageMapping(PDOCEVENTUSERMEM pDocEventUserMem)
  397. /*++
  398. Routine Description:
  399. Creates a temperary file of size MAX_TIFF_PAGE_SIZE, and maps a view to it. This mapping serves
  400. as a communication channel between the UI and Graphics driver parts to transfer preview pages.
  401. The page starts with a MAP_TIFF_PAGE_HEADER structure that has the following fields:
  402. cb - The structure size
  403. dwDataSize - The number of bytes of the raw TIFF data constructing the next page
  404. iPageCount - The page number currently printed
  405. bPreview - TRUE if everything until now is OK. FALSE if print preview is disabled or
  406. aborted (by either driver parts).
  407. The cb and iPageCount fields are used to validate the mapping: cb should always be the structure
  408. size and iPageCount should be the same as our internal page count (pDocEventUserMem->pageCount)
  409. when a new page is retrieved.
  410. The bPreview field is used to abort the print preview operation by either driver parts.
  411. This function sets the hMappingFile, hMapping, pPreviewTiffPage and devmode.dmPrivate.szMappingFile
  412. fields of the user memory structure according to success / failure.
  413. Arguments:
  414. pDocEventUserMem - Points to the user mode memory structure
  415. Return Value:
  416. Win32 Error codes
  417. --*/
  418. {
  419. TCHAR szTmpPath[MAX_PATH];
  420. DWORD dwRet = ERROR_SUCCESS;
  421. LPTSTR pszMappingFile = pDocEventUserMem->devmode.dmPrivate.szMappingFile;
  422. UINT uRet;
  423. //
  424. // Invalidate all mapping handles
  425. //
  426. pDocEventUserMem->hMappingFile = INVALID_HANDLE_VALUE;
  427. pDocEventUserMem->hMapping = NULL;
  428. pDocEventUserMem->pPreviewTiffPage = NULL;
  429. //
  430. // Create the path for our mapping file. This path HAS to be under the system32
  431. // directory or the kernel driver (NT4) won't be able to map the file. My choice is:
  432. // '%WinDir%\system32\'
  433. //
  434. uRet = GetSystemDirectory(szTmpPath, MAX_PATH);
  435. if (!uRet)
  436. {
  437. dwRet = GetLastError();
  438. goto ErrExit;
  439. }
  440. //
  441. // Look for %windir%\system32\FxsTmp folder that is created by Setup.
  442. //
  443. if (wcslen(szTmpPath) +
  444. wcslen(FAX_PREVIEW_TMP_DIR) >= MAX_PATH)
  445. {
  446. dwRet = ERROR_BUFFER_OVERFLOW;
  447. goto ErrExit;
  448. }
  449. wcscat(szTmpPath, FAX_PREVIEW_TMP_DIR);
  450. //
  451. // Create a NEW file
  452. //
  453. if (!GetTempFileName(szTmpPath, FAX_PREFIX, 0, pszMappingFile))
  454. {
  455. dwRet = GetLastError();
  456. Error(("GetTempFileName() failed:%d\n", dwRet));
  457. goto ErrExit;
  458. }
  459. //
  460. // Open the new file with shared read / write / delete privileges and FILE_FLAG_DELETE_ON_CLOSE
  461. // attribute
  462. //
  463. if ( INVALID_HANDLE_VALUE == (pDocEventUserMem->hMappingFile = SafeCreateTempFile(
  464. pszMappingFile,
  465. GENERIC_READ | GENERIC_WRITE,
  466. FILE_SHARE_READ | FILE_SHARE_WRITE,
  467. NULL,
  468. OPEN_EXISTING,
  469. FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
  470. NULL)))
  471. {
  472. dwRet = GetLastError();
  473. Error(("CreateFile() failed: %d.\n", dwRet));
  474. if (!DeleteFile(pszMappingFile))
  475. {
  476. Error(("DeleteFile() failed: %d.\n", GetLastError()));
  477. }
  478. goto ErrExit;
  479. }
  480. //
  481. // Extend the file size to MAX_TIFF_PAGE_SIZE
  482. //
  483. dwRet = SetFilePointer(
  484. pDocEventUserMem->hMappingFile,
  485. MAX_TIFF_PAGE_SIZE,
  486. NULL,
  487. FILE_BEGIN);
  488. if (INVALID_SET_FILE_POINTER == dwRet)
  489. {
  490. dwRet = GetLastError();
  491. Error(("SetFilePointer() failed:%d\n", dwRet));
  492. goto ErrExit;
  493. }
  494. if (!SetEndOfFile(pDocEventUserMem->hMappingFile))
  495. {
  496. dwRet = GetLastError();
  497. Error(("SetEndOfFile() failed:%d\n", dwRet));
  498. goto ErrExit;
  499. }
  500. //
  501. // Create a file mapping of the whole file
  502. //
  503. pDocEventUserMem->hMapping = CreateFileMapping(
  504. pDocEventUserMem->hMappingFile, // handle to file
  505. NULL, // security
  506. PAGE_READWRITE, // protection
  507. 0, // high-order DWORD of size
  508. 0, // low-order DWORD of size
  509. NULL // object name
  510. );
  511. if (pDocEventUserMem->hMapping == NULL)
  512. {
  513. dwRet = GetLastError();
  514. Error(("File mapping failed:%d\n", dwRet));
  515. goto ErrExit;
  516. }
  517. //
  518. // Open a view
  519. //
  520. pDocEventUserMem->pPreviewTiffPage = (PMAP_TIFF_PAGE_HEADER) MapViewOfFile(
  521. pDocEventUserMem->hMapping, // handle to file-mapping object
  522. FILE_MAP_WRITE, // access mode
  523. 0, // high-order DWORD of offset
  524. 0, // low-order DWORD of offset
  525. 0 // number of bytes to map
  526. );
  527. if (NULL == pDocEventUserMem->pPreviewTiffPage)
  528. {
  529. dwRet = GetLastError();
  530. Error(("MapViewOfFile() failed:%d\n", dwRet));
  531. goto ErrExit;
  532. }
  533. //
  534. // Success - set initial header information
  535. //
  536. pDocEventUserMem->pPreviewTiffPage->bPreview = FALSE;
  537. pDocEventUserMem->pPreviewTiffPage->cb = sizeof(MAP_TIFF_PAGE_HEADER);
  538. pDocEventUserMem->pPreviewTiffPage->dwDataSize = 0;
  539. pDocEventUserMem->pPreviewTiffPage->iPageCount = 0;
  540. return ERROR_SUCCESS;
  541. ErrExit:
  542. //
  543. // Cleanup
  544. //
  545. // IMPORTANT: Set mapping file name to empty string. This signals the graphics dll that
  546. // there is no mapping file.
  547. //
  548. CloseMappingHandles(pDocEventUserMem);
  549. pszMappingFile[0] = TEXT('\0');
  550. return dwRet;
  551. }
  552. INT
  553. DocEventCreateDCPre(
  554. HANDLE hPrinter,
  555. HDC hdc,
  556. PCREATEDCDATA pCreateDCData,
  557. PDEVMODE *ppdmOutput
  558. )
  559. /*++
  560. Routine Description:
  561. Handle CREATEDCPRE document event
  562. Arguments:
  563. hPrinter - Handle to the printer object
  564. hdc - Specifies the printer device context
  565. pCreateDCData - Pointer to CREATEDCDATA structure passed in from GDI
  566. ppdmOutput - Buffer for returning a devmode pointer
  567. Return Value:
  568. Return value for DrvDocumentEvent
  569. --*/
  570. {
  571. PDOCEVENTUSERMEM pDocEventUserMem = NULL;
  572. PPRINTER_INFO_2 pPrinterInfo2 = NULL;
  573. DWORD dwRes;
  574. DWORD dwEnvSize;
  575. Assert(pCreateDCData);
  576. Assert(ppdmOutput);
  577. Verbose(("Document event: CREATEDCPRE%s\n", pCreateDCData->fromCreateIC ? "*" : ""));
  578. *ppdmOutput = NULL;
  579. //
  580. // Allocate space for user mode memory data structure
  581. //
  582. if (((pDocEventUserMem = MemAllocZ(sizeof(DOCEVENTUSERMEM))) == NULL))
  583. {
  584. Error(("Memory allocation failed\n"));
  585. goto Error;
  586. }
  587. ZeroMemory(pDocEventUserMem, sizeof(DOCEVENTUSERMEM));
  588. if ((pPrinterInfo2 = MyGetPrinter(hPrinter, 2)) == NULL ||
  589. (pDocEventUserMem->lptstrPrinterName = DuplicateString(pPrinterInfo2->pPrinterName)) == NULL)
  590. {
  591. Error(("Memory allocation failed\n"));
  592. goto Error;
  593. }
  594. if (pPrinterInfo2->pServerName==NULL)
  595. {
  596. pDocEventUserMem->lptstrServerName = NULL;
  597. }
  598. else
  599. {
  600. LPTSTR pServerName = pPrinterInfo2->pServerName;
  601. //
  602. // Truncate prefix backslashes
  603. //
  604. while (*pServerName == TEXT('\\'))
  605. {
  606. pServerName++;
  607. }
  608. //
  609. // Save the server name
  610. //
  611. if ((pDocEventUserMem->lptstrServerName = DuplicateString(pServerName)) == NULL)
  612. {
  613. Error(("Memory allocation failed\n"));
  614. goto Error;
  615. }
  616. }
  617. //
  618. // Merge the input devmode with the driver and system defaults
  619. //
  620. pDocEventUserMem->hPrinter = hPrinter;
  621. GetCombinedDevmode(&pDocEventUserMem->devmode,
  622. pCreateDCData->pdmInput, hPrinter, pPrinterInfo2, FALSE);
  623. Verbose(("Document event: CREATEDCPRE %x\n", pDocEventUserMem));
  624. MemFree(pPrinterInfo2);
  625. pPrinterInfo2 = NULL;
  626. //
  627. // Special code path for EFC server printing - if FAXDM_EFC_SERVER bit is
  628. // set in DMPRIVATE.flags, then we'll bypass the fax wizard and let the
  629. // job through without any intervention.
  630. //
  631. //
  632. // The above comment is not accurate. The flag that turns off the wizard is
  633. // FAXMDM_NO_WIZARD.
  634. // This flag is set in the private DEVMODE area (flags field) by FaxStartPrintJob.
  635. // FaxStartPrintJob already has all the information that the wizard usually provides and it
  636. // wishes the wizard to not show up. To do that it sets this field and passes the
  637. // job parameters in the JOB_INFO_2.pParameters string as a tagged string.
  638. // Note that this is not the same case as when StartDoc is called with a output file name specified.
  639. // In this case the wizard is not brought up as well.
  640. //
  641. if (pDocEventUserMem->devmode.dmPrivate.flags & FAXDM_NO_WIZARD)
  642. {
  643. pDocEventUserMem->directPrinting = TRUE;
  644. }
  645. //
  646. // if printing a fax attachment then enable direct printing
  647. //
  648. dwEnvSize = GetEnvironmentVariable( FAX_ENVVAR_PRINT_FILE, NULL, 0 );
  649. if (dwEnvSize)
  650. {
  651. pDocEventUserMem->pPrintFile = (LPTSTR) MemAllocZ( dwEnvSize * sizeof(TCHAR) );
  652. if (NULL == pDocEventUserMem->pPrintFile)
  653. {
  654. Error(("Memory allocation failed\n"));
  655. goto Error;
  656. }
  657. if (0 == GetEnvironmentVariable( FAX_ENVVAR_PRINT_FILE, pDocEventUserMem->pPrintFile, dwEnvSize ))
  658. {
  659. Error(("GetEnvironmentVariable failed\n"));
  660. MemFree (pDocEventUserMem->pPrintFile);
  661. pDocEventUserMem->pPrintFile = NULL;
  662. goto Error;
  663. }
  664. pDocEventUserMem->bAttachment = TRUE;
  665. pDocEventUserMem->directPrinting = TRUE;
  666. }
  667. //
  668. // Create a memory mapped file that will serve as a commincation chanel between both
  669. // driver parts. This file will provide means of transfering rendered TIFF pages for
  670. // print preview if it was required by the user
  671. //
  672. dwRes = CreateTiffPageMapping(pDocEventUserMem);
  673. if (ERROR_SUCCESS != dwRes)
  674. {
  675. Error(("CreateTiffPageMapping() failed: %d\n", dwRes));
  676. //
  677. // We can still continue, but print preview won't be available...
  678. //
  679. pDocEventUserMem->bShowPrintPreview = FALSE;
  680. pDocEventUserMem->bPreviewAborted = TRUE;
  681. }
  682. else
  683. {
  684. pDocEventUserMem->bShowPrintPreview = TRUE;
  685. pDocEventUserMem->bPreviewAborted = FALSE;
  686. }
  687. //
  688. // Initialize the TIFF preview file fields
  689. //
  690. pDocEventUserMem->szPreviewFile[0] = TEXT('\0');
  691. pDocEventUserMem->hPreviewFile = INVALID_HANDLE_VALUE;
  692. //
  693. // Mark the private fields of our devmode
  694. //
  695. //@
  696. //@ DocEventUserMem.Siganture is allways &DocEventUserMem
  697. //@ DocEventUserMem.Signature.DocEventUserMem.Signature is allways &DocEventUserMem
  698. //@ ValidPDEVUserMem checks for this.
  699. //@
  700. MarkPDEVUserMem(pDocEventUserMem);
  701. //@
  702. //@ This make the driver use the devmode we merged instaed of the
  703. //@ devmode specified by the caller to CreateDC.
  704. //@ This way we make sure the driver gets a DEVMODE with per user
  705. //@ default (W2K) or just hard-code defaults (NT4) for all the fields
  706. //@ that were not speicified or invalid in the input devmode.
  707. //@ Note that the system passes to the driver a COPY of the devmode structure
  708. //@ we return and NOT a pointer to it.
  709. //@
  710. *ppdmOutput = (PDEVMODE) &pDocEventUserMem->devmode;
  711. return DOCUMENTEVENT_SUCCESS;
  712. Error:
  713. MemFree(pPrinterInfo2);
  714. if (pDocEventUserMem)
  715. {
  716. MemFree(pDocEventUserMem->lptstrPrinterName);
  717. MemFree(pDocEventUserMem->lptstrServerName);
  718. MemFree(pDocEventUserMem);
  719. }
  720. return DOCUMENTEVENT_FAILURE;
  721. }
  722. INT
  723. DocEventResetDCPre(
  724. HDC hdc,
  725. PDOCEVENTUSERMEM pDocEventUserMem,
  726. PDEVMODE pdmInput,
  727. PDEVMODE *ppdmOutput
  728. )
  729. /*++
  730. Routine Description:
  731. Handle RESETDCPRE document event
  732. Arguments:
  733. hdc - Specifies the printer device context
  734. pDocEventUserMem - Points to the user mode memory of DocEvent structure
  735. pdmInput - Points to the input devmode passed to ResetDC
  736. ppdmOutput - Buffer for returning a devmode pointer
  737. Return Value:
  738. Return value for DrvDocumentEvent
  739. --*/
  740. {
  741. if (pdmInput == (PDEVMODE) &pDocEventUserMem->devmode)
  742. {
  743. //
  744. // ResetDC was called by ourselves - assume the devmode is already valid
  745. //
  746. }
  747. else
  748. {
  749. //
  750. // Merge the input devmode with driver and system default
  751. //
  752. GetCombinedDevmode(&pDocEventUserMem->devmode,
  753. pdmInput, pDocEventUserMem->hPrinter, NULL, TRUE);
  754. //
  755. // Mark the private fields of our devmode
  756. //
  757. MarkPDEVUserMem(pDocEventUserMem);
  758. }
  759. *ppdmOutput = (PDEVMODE) &pDocEventUserMem->devmode;
  760. return DOCUMENTEVENT_SUCCESS;
  761. }
  762. BOOL
  763. IsPrintingToFile(
  764. LPCTSTR pDestStr
  765. )
  766. /*++
  767. Routine Description:
  768. Check if the destination of a print job is a file.
  769. Arguments:
  770. pDestStr - Job destination specified in DOCINFO.lpszOutput
  771. Return Value:
  772. TRUE if the destination is a disk file, FALSE otherwise
  773. --*/
  774. {
  775. DWORD fileAttrs;
  776. HANDLE hFile;
  777. //
  778. // If the destination is NULL, then we're not printing to file
  779. //
  780. // Otherwise, attempt to use the destination string as the name of a file.
  781. // If we failed to get file attributes or the name refers to a directory,
  782. // then we're not printing to file.
  783. //
  784. if (pDestStr == NULL)
  785. {
  786. return FALSE;
  787. }
  788. //
  789. // make sure it's not a directory
  790. //
  791. fileAttrs = GetFileAttributes(pDestStr);
  792. if (fileAttrs != 0xffffffff)
  793. {
  794. if (fileAttrs & FILE_ATTRIBUTE_DIRECTORY)
  795. {
  796. return FALSE;
  797. }
  798. }
  799. //
  800. // check if file exists...if it doesn't try to create it.
  801. //
  802. hFile = SafeCreateFile(pDestStr, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
  803. if (hFile == INVALID_HANDLE_VALUE)
  804. {
  805. hFile = SafeCreateFile(pDestStr, 0, 0, NULL, CREATE_NEW, 0, NULL);
  806. if (hFile == INVALID_HANDLE_VALUE)
  807. {
  808. return FALSE;
  809. }
  810. }
  811. //
  812. // Verifiy that we did not opened a port handle
  813. //
  814. fileAttrs = GetFileAttributes(pDestStr);
  815. if (!CloseHandle(hFile))
  816. {
  817. Error(("CloseHandle() failed: %d.\n", GetLastError()));
  818. // Try to continue...
  819. }
  820. if (0xffffffff == fileAttrs)
  821. {
  822. //
  823. // pDestStr does not point to a valid file
  824. //
  825. return FALSE;
  826. }
  827. //
  828. // it must be a file
  829. //
  830. return TRUE;
  831. }
  832. DWORD LaunchFaxWizard(PDOCEVENTUSERMEM pDocEventUserMem)
  833. {
  834. DWORD hWndOwner = 0;
  835. DWORD dwFlags = 0;
  836. LPFAX_SEND_WIZARD_DATA lpInitialData = NULL;
  837. LPFAX_SEND_WIZARD_DATA lpFaxSendWizardData = NULL;
  838. INT iResult;
  839. TCHAR tszNumericData[10]={0};
  840. DWORD ec = ERROR_SUCCESS;
  841. HRESULT hRc;
  842. if ( !(lpFaxSendWizardData = MemAllocZ(sizeof(FAX_SEND_WIZARD_DATA))) ||
  843. !(lpInitialData = MemAllocZ(sizeof(FAX_SEND_WIZARD_DATA))) )
  844. {
  845. ec = GetLastError();
  846. Error(("Memory allocation failed\n"));
  847. goto Error;
  848. }
  849. ZeroMemory(lpInitialData, sizeof(FAX_SEND_WIZARD_DATA));
  850. lpInitialData->dwSizeOfStruct = sizeof(FAX_SEND_WIZARD_DATA);
  851. lpInitialData->dwPageCount = pDocEventUserMem->pageCount;
  852. ZeroMemory(lpFaxSendWizardData, sizeof(FAX_SEND_WIZARD_DATA));
  853. lpFaxSendWizardData->dwSizeOfStruct = sizeof(FAX_SEND_WIZARD_DATA);
  854. // prepare structures and parameters
  855. lpInitialData->tmSchedule.wHour = pDocEventUserMem->devmode.dmPrivate.sendAtTime.Hour;
  856. lpInitialData->tmSchedule.wMinute = pDocEventUserMem->devmode.dmPrivate.sendAtTime.Minute;
  857. lpInitialData->lptstrPreviewFile = StringDup(pDocEventUserMem->szPreviewFile);
  858. if (!lpInitialData->lptstrPreviewFile)
  859. {
  860. ec = GetLastError();
  861. Error(("StringDup() failed (ec: %ld)",ec));
  862. goto Error;
  863. }
  864. if (GetEnvironmentVariable(TEXT("NTFaxSendNote"), NULL, 0))
  865. {
  866. dwFlags |= FSW_USE_SEND_WIZARD | FSW_FORCE_COVERPAGE;
  867. }
  868. // If the file mapping succeeded enable the preview option
  869. if (pDocEventUserMem->pPreviewTiffPage &&
  870. FALSE == pDocEventUserMem->bPreviewAborted)
  871. {
  872. dwFlags |= FSW_PRINT_PREVIEW_OPTION;
  873. }
  874. iResult = DOCUMENTEVENT_SUCCESS;
  875. hRc = FaxSendWizard( hWndOwner,
  876. dwFlags,
  877. pDocEventUserMem->lptstrServerName,
  878. pDocEventUserMem->lptstrPrinterName,
  879. lpInitialData,
  880. pDocEventUserMem->tstrTifName,
  881. ARR_SIZE(pDocEventUserMem->tstrTifName),
  882. lpFaxSendWizardData );
  883. {
  884. }
  885. if (S_FALSE == hRc)
  886. {
  887. ec = ERROR_CANCELLED;
  888. goto Error; // This is not really an error
  889. }
  890. if (S_OK != hRc)
  891. {
  892. Error(("FaxSendWizard() failed (hRc: %ld)",hRc));
  893. ec = ERROR_GEN_FAILURE;
  894. goto Error;
  895. }
  896. //
  897. // Unpack result structures:
  898. //
  899. pDocEventUserMem->devmode.dmPrivate.sendAtTime.Hour = lpFaxSendWizardData->tmSchedule.wHour ;
  900. pDocEventUserMem->devmode.dmPrivate.sendAtTime.Minute = lpFaxSendWizardData->tmSchedule.wMinute ;
  901. pDocEventUserMem->devmode.dmPrivate.whenToSend = lpFaxSendWizardData->dwScheduleAction;
  902. Assert ((lpFaxSendWizardData->Priority >= FAX_PRIORITY_TYPE_LOW) &&
  903. (lpFaxSendWizardData->Priority <= FAX_PRIORITY_TYPE_HIGH));
  904. if (0 > _snwprintf (tszNumericData,
  905. sizeof (tszNumericData) / sizeof (tszNumericData[0]) - 1,
  906. TEXT("%d"),
  907. lpFaxSendWizardData->Priority))
  908. {
  909. ec = ERROR_BUFFER_OVERFLOW;
  910. goto Error;
  911. }
  912. pDocEventUserMem->pPriority = DuplicateString(tszNumericData);
  913. if (!pDocEventUserMem->pPriority)
  914. {
  915. ec = GetLastError();
  916. goto Error;
  917. }
  918. if (0 > _snwprintf (tszNumericData,
  919. sizeof (tszNumericData) / sizeof (tszNumericData[0]) - 1,
  920. TEXT("%d"),
  921. lpFaxSendWizardData->dwReceiptDeliveryType))
  922. {
  923. ec = ERROR_BUFFER_OVERFLOW;
  924. goto Error;
  925. }
  926. pDocEventUserMem->pReceiptFlags = DuplicateString(tszNumericData);
  927. if (!pDocEventUserMem->pReceiptFlags)
  928. {
  929. ec = GetLastError();
  930. goto Error;
  931. }
  932. if (lpFaxSendWizardData->szReceiptDeliveryAddress)
  933. {
  934. if (!(pDocEventUserMem->pReceiptAddress
  935. = DuplicateString(lpFaxSendWizardData->szReceiptDeliveryAddress)))
  936. {
  937. ec = GetLastError();
  938. Error(("DuplicateString() failed (ec: %ld)",ec));
  939. goto Error;
  940. }
  941. }
  942. if (lpFaxSendWizardData->lpSenderInfo->lptstrBillingCode)
  943. _tcscpy(pDocEventUserMem->devmode.dmPrivate.billingCode,
  944. lpFaxSendWizardData->lpSenderInfo->lptstrBillingCode);
  945. if (lpFaxSendWizardData->lpCoverPageInfo->lptstrCoverPageFileName)
  946. _tcscpy(pDocEventUserMem->coverPage,
  947. lpFaxSendWizardData->lpCoverPageInfo->lptstrCoverPageFileName );
  948. pDocEventUserMem->bServerCoverPage =
  949. lpFaxSendWizardData->lpCoverPageInfo->bServerBased;
  950. if (lpFaxSendWizardData->lpCoverPageInfo->lptstrSubject)
  951. {
  952. if (!(pDocEventUserMem->pSubject
  953. = DuplicateString(lpFaxSendWizardData->lpCoverPageInfo->lptstrSubject)))
  954. {
  955. ec = GetLastError();
  956. Error(("DuplicateString() failed (ec: %ld)",ec));
  957. goto Error;
  958. }
  959. }
  960. if (lpFaxSendWizardData->lpCoverPageInfo->lptstrNote)
  961. {
  962. if (!(pDocEventUserMem->pNoteMessage
  963. = DuplicateString(lpFaxSendWizardData->lpCoverPageInfo->lptstrNote)))
  964. {
  965. ec = GetLastError();
  966. Error(("DuplicateString() failed (ec: %ld)",ec));
  967. goto Error;
  968. }
  969. }
  970. Assert(lpFaxSendWizardData->dwNumberOfRecipients);
  971. pDocEventUserMem->dwNumberOfRecipients = lpFaxSendWizardData->dwNumberOfRecipients;
  972. if (!SetEnvironmentVariable( _T("ScanTifName"), pDocEventUserMem->tstrTifName ))
  973. {
  974. Error(("SetEnvironmentVariable failed. ec = 0x%X",GetLastError()));
  975. }
  976. // copy recipients
  977. if ( pDocEventUserMem->dwNumberOfRecipients && (pDocEventUserMem->lpRecipientsInfo =
  978. MemAllocZ(sizeof(FAX_PERSONAL_PROFILE)*pDocEventUserMem->dwNumberOfRecipients)) == NULL)
  979. {
  980. ec = GetLastError();
  981. Error(("Memory allocation failed (ec: %ld)",ec));
  982. goto Error;
  983. }
  984. if ((ec = CopyRecipientInfo(pDocEventUserMem->dwNumberOfRecipients,
  985. pDocEventUserMem->lpRecipientsInfo,
  986. lpFaxSendWizardData->lpRecipientsInfo)) != ERROR_SUCCESS)
  987. {
  988. Error(("CopyRecipientInfo failed (ec: %ld)",ec));
  989. goto Error;
  990. }
  991. if (lpFaxSendWizardData->lpSenderInfo)
  992. {
  993. if ((pDocEventUserMem->lpSenderInfo = MemAllocZ(sizeof(FAX_PERSONAL_PROFILE))) == NULL)
  994. {
  995. ec = GetLastError();
  996. Error(("MemAlloc() failed (ec: %ld)",ec));
  997. goto Error;
  998. }
  999. pDocEventUserMem->lpSenderInfo->dwSizeOfStruct = sizeof(FAX_PERSONAL_PROFILE);
  1000. if ((ec = CopyPersonalProfileInfo( pDocEventUserMem->lpSenderInfo,
  1001. lpFaxSendWizardData->lpSenderInfo)) != ERROR_SUCCESS)
  1002. {
  1003. Error(("CopyRecipientInfo failed (ec: %ld)", ec));
  1004. goto Error;
  1005. }
  1006. }
  1007. Assert(pDocEventUserMem->lpRecipientsInfo);
  1008. pDocEventUserMem->jobType = JOBTYPE_NORMAL;
  1009. Assert(ERROR_SUCCESS == ec);
  1010. goto Exit;
  1011. Error:
  1012. Assert(ERROR_SUCCESS != ec);
  1013. FreeRecipientInfo(&pDocEventUserMem->dwNumberOfRecipients,pDocEventUserMem->lpRecipientsInfo);
  1014. pDocEventUserMem->lpRecipientsInfo = NULL;
  1015. FaxFreePersonalProfileInformation(pDocEventUserMem->lpSenderInfo);
  1016. MemFree(pDocEventUserMem->lpSenderInfo);
  1017. pDocEventUserMem->lpSenderInfo = NULL;
  1018. MemFree(pDocEventUserMem->pSubject);
  1019. pDocEventUserMem->pSubject = NULL;
  1020. MemFree(pDocEventUserMem->pNoteMessage);
  1021. pDocEventUserMem->pNoteMessage = NULL;
  1022. MemFree(pDocEventUserMem->pPrintFile);
  1023. pDocEventUserMem->pPrintFile = NULL;
  1024. MemFree(pDocEventUserMem->pReceiptAddress);
  1025. pDocEventUserMem->pReceiptAddress = NULL;
  1026. MemFree(pDocEventUserMem->pPriority);
  1027. pDocEventUserMem->pPriority = NULL;
  1028. MemFree(pDocEventUserMem->pReceiptFlags);
  1029. pDocEventUserMem->pReceiptFlags = NULL;
  1030. Exit:
  1031. if (lpInitialData)
  1032. {
  1033. //
  1034. // Note: One should NOT call FaxFreeSendWizardData on lpInitialData.
  1035. // The reason is that FaxSendWizard used a different allocator
  1036. // then we do. Thus we just free the individual fields we
  1037. // allocated.
  1038. MemFree(lpInitialData->lptstrPreviewFile);
  1039. }
  1040. FaxFreeSendWizardData(lpFaxSendWizardData);
  1041. MemFree (lpInitialData);
  1042. MemFree (lpFaxSendWizardData);
  1043. return ec;
  1044. }
  1045. INT
  1046. DocEventStartDocPre(
  1047. HDC hdc,
  1048. PDOCEVENTUSERMEM pDocEventUserMem,
  1049. LPDOCINFO pDocInfo
  1050. )
  1051. /*++
  1052. Routine Description:
  1053. Handle STARTDOCPRE document event.
  1054. This events occurs when StartDoc is called. GDI will call this event just before calling kernel mode GDI.
  1055. If the printing is to a file:
  1056. set the job type to JOBTYPE_DIRECT (pDocEventUserMem->JobType)
  1057. and return successfully with DOCUMENTEVENT_SUCCESS.
  1058. If the printing is not to a file:
  1059. Bring up the send fax wizard.
  1060. The send fax wizard will update the relevant pUserMem members for recipient list, subject, note , etc.
  1061. Indicate that this is a normal job be setting
  1062. pDocEventUserMem->jobType = JOBTYPE_NORMAL;
  1063. Arguments:
  1064. hdc - Specifies the printer device context
  1065. pDocEventUserMem - Points to the user mode memory structure
  1066. pDocInfo - Points to DOCINFO structure that was passed in from GDI
  1067. Return Value:
  1068. Return value for DrvDocumentEvent
  1069. --*/
  1070. {
  1071. //
  1072. // Initialize user mode memory structure
  1073. //
  1074. DWORD hWndOwner = 0;
  1075. DWORD dwFlags = 0;
  1076. pDocEventUserMem->pageCount = 0;
  1077. FreeRecipientInfo(&pDocEventUserMem->dwNumberOfRecipients,pDocEventUserMem->lpRecipientsInfo);
  1078. //
  1079. // Present the fax wizard here if necessary
  1080. //
  1081. //
  1082. //If DOCINFO has a file name specified and this is indeed a file name
  1083. //(not a directory or something like LPT1:) then we need to print directly to the
  1084. //file and we do not bring up the send wizard.
  1085. //
  1086. if (pDocInfo && IsPrintingToFile(pDocInfo->lpszOutput))
  1087. {
  1088. //
  1089. // Printing to file case: don't get involved
  1090. //
  1091. Warning(("Printing direct: %ws\n", pDocInfo->lpszOutput));
  1092. pDocEventUserMem->jobType = JOBTYPE_DIRECT;
  1093. pDocEventUserMem->directPrinting = TRUE;
  1094. }
  1095. else
  1096. {
  1097. //
  1098. // Normal fax print job. Present the send fax wizard.
  1099. // If the user selected cancel, then return -2 to GDI.
  1100. //
  1101. //
  1102. // The wizard will update information in pUserMem.
  1103. // This includes the recipient list , selected cover page, subject text , note text
  1104. // and when to print the fax.
  1105. //
  1106. //
  1107. // Make sure we don't leave any open files
  1108. //
  1109. if (INVALID_HANDLE_VALUE != pDocEventUserMem->hPreviewFile)
  1110. {
  1111. //
  1112. // We should never get here with an open file handle. But if so, close the handle
  1113. // (TODO: This file will be opened with delete on close).
  1114. //
  1115. Assert(FALSE);
  1116. CloseHandle(pDocEventUserMem->hPreviewFile);
  1117. pDocEventUserMem->hPreviewFile = INVALID_HANDLE_VALUE;
  1118. }
  1119. //
  1120. // Create a temporary TIFF file for preview
  1121. //
  1122. if (FALSE == pDocEventUserMem->bPreviewAborted)
  1123. {
  1124. if (GenerateUniqueFileName(
  1125. NULL, // Create in the system temporary directory
  1126. FAX_TIF_FILE_EXT,
  1127. pDocEventUserMem->szPreviewFile,
  1128. MAX_PATH))
  1129. {
  1130. pDocEventUserMem->hPreviewFile = CreateFile(
  1131. pDocEventUserMem->szPreviewFile,
  1132. GENERIC_WRITE,
  1133. 0,
  1134. NULL,
  1135. OPEN_EXISTING,
  1136. FILE_ATTRIBUTE_TEMPORARY,
  1137. NULL);
  1138. if (INVALID_HANDLE_VALUE != pDocEventUserMem->hPreviewFile)
  1139. {
  1140. //
  1141. // Success. Signal the graphics driver we want print preview
  1142. //
  1143. // If we enabled the preview option to the user it means everything is OK
  1144. Assert(pDocEventUserMem->pPreviewTiffPage);
  1145. pDocEventUserMem->pPreviewTiffPage->bPreview = TRUE;
  1146. pDocEventUserMem->bShowPrintPreview = TRUE;
  1147. }
  1148. else
  1149. {
  1150. Error(("Failed opening file.Error: %d.\n", GetLastError()));
  1151. if (!DeleteFile(pDocEventUserMem->szPreviewFile))
  1152. {
  1153. Error(("DeleteFile() failed: %d.\n", GetLastError()));
  1154. }
  1155. }
  1156. }
  1157. else
  1158. {
  1159. Error(("Failed creating temporary preview file\n"));
  1160. }
  1161. //
  1162. // If we failed creating the file abort preview operation
  1163. //
  1164. if (INVALID_HANDLE_VALUE == pDocEventUserMem->hPreviewFile)
  1165. {
  1166. //
  1167. // Set file name to empty string so we won't try to delete the file twice when
  1168. // the DC is deleted
  1169. //
  1170. pDocEventUserMem->szPreviewFile[0] = TEXT('\0');
  1171. //
  1172. // Abort preview (note that the preview is still disabled in the mapping).
  1173. //
  1174. pDocEventUserMem->bPreviewAborted = TRUE;
  1175. }
  1176. }
  1177. pDocEventUserMem->jobType = JOBTYPE_NORMAL;
  1178. }
  1179. return DOCUMENTEVENT_SUCCESS;
  1180. }
  1181. DWORD
  1182. FaxTimeToJobTime(
  1183. DWORD faxTime
  1184. )
  1185. /*++
  1186. Routine Description:
  1187. Convert fax time to spooler job time:
  1188. Fax time is a DWORD whose low-order WORD represents hour value and
  1189. high-order WORD represents minute value. Spooler job time is a DWORD
  1190. value expressing minutes elapsed since 12:00 AM GMT.
  1191. Arguments:
  1192. faxTime - Specifies the fax time to be converted
  1193. Return Value:
  1194. Spooler job time corresponding to the input fax time
  1195. --*/
  1196. {
  1197. TIME_ZONE_INFORMATION timeZoneInfo;
  1198. LONG jobTime;
  1199. //
  1200. // Convert fax time to minutes pass midnight
  1201. //
  1202. jobTime = LOWORD(faxTime) * 60 + HIWORD(faxTime);
  1203. //
  1204. // Take time zone information in account - Add one full
  1205. // day to take care of the case where the bias is negative.
  1206. //
  1207. switch (GetTimeZoneInformation(&timeZoneInfo)) {
  1208. case TIME_ZONE_ID_DAYLIGHT:
  1209. jobTime += timeZoneInfo.DaylightBias;
  1210. case TIME_ZONE_ID_STANDARD:
  1211. case TIME_ZONE_ID_UNKNOWN:
  1212. jobTime += timeZoneInfo.Bias + MINUTES_PER_DAY;
  1213. break;
  1214. default:
  1215. Error(("GetTimeZoneInformation failed: %d\n", GetLastError()));
  1216. break;
  1217. }
  1218. //
  1219. // Make sure the time value is less than one day
  1220. //
  1221. return jobTime % MINUTES_PER_DAY;
  1222. }
  1223. PVOID
  1224. MyGetJob(
  1225. HANDLE hPrinter,
  1226. DWORD level,
  1227. DWORD jobId
  1228. )
  1229. /*++
  1230. Routine Description:
  1231. Wrapper function for spooler API GetJob
  1232. Arguments:
  1233. hPrinter - Handle to the printer object
  1234. level - Level of JOB_INFO structure interested
  1235. jobId - Specifies the job ID
  1236. Return Value:
  1237. Pointer to a JOB_INFO structure, NULL if there is an error
  1238. --*/
  1239. {
  1240. PBYTE pJobInfo = NULL;
  1241. DWORD cbNeeded;
  1242. if (!GetJob(hPrinter, jobId, level, NULL, 0, &cbNeeded) &&
  1243. GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
  1244. (pJobInfo = MemAlloc(cbNeeded)) &&
  1245. GetJob(hPrinter, jobId, level, pJobInfo, cbNeeded, &cbNeeded))
  1246. {
  1247. return pJobInfo;
  1248. }
  1249. Error(("GetJob failed: %d\n", GetLastError()));
  1250. MemFree(pJobInfo);
  1251. return NULL;
  1252. }
  1253. BOOL
  1254. SetJobInfoAndTime(
  1255. HANDLE hPrinter,
  1256. DWORD jobId,
  1257. LPTSTR pJobParam,
  1258. PDMPRIVATE pdmPrivate
  1259. )
  1260. /*++
  1261. Routine Description:
  1262. Change the devmode and start/stop times associated with a cover page job
  1263. Sets JOB_INFO_2:pParameters to the provided pJobParam string that contains the fax job parameters
  1264. to be convyed to the fax print monitor.
  1265. Arguments:
  1266. hPrinter - Specifies the printer object
  1267. jobId - Specifies the job ID
  1268. pJobParam - Specifies the fax job parameters
  1269. pdmPrivate - Specifies private devmode information
  1270. Return Value:
  1271. TRUE if successful, FALSE if there is an error
  1272. --*/
  1273. {
  1274. JOB_INFO_2 *pJobInfo2;
  1275. BOOL result = FALSE;
  1276. //
  1277. // Get the current job information
  1278. //
  1279. if (pJobInfo2 = MyGetJob(hPrinter, 2, jobId)) {
  1280. //
  1281. // set the time to send to be now, always
  1282. //
  1283. Warning(("Fax job parameters: %ws\n", pJobParam));
  1284. //
  1285. // Set the pParameters field of JOB_INFO_2 to the tagged string with the job
  1286. // information. This mechanism is used to pass the fax related job information
  1287. // to the fax monitor.
  1288. //
  1289. pJobInfo2->pParameters = pJobParam;
  1290. pJobInfo2->Position = JOB_POSITION_UNSPECIFIED;
  1291. pJobInfo2->pDevMode = NULL;
  1292. pJobInfo2->UntilTime = pJobInfo2->StartTime;
  1293. if (! (result = SetJob(hPrinter, jobId, 2, (PBYTE) pJobInfo2, 0))) {
  1294. Error(("SetJob failed: %d\n", GetLastError()));
  1295. }
  1296. MemFree(pJobInfo2);
  1297. }
  1298. return result;
  1299. }
  1300. BOOL
  1301. ChainFaxJobs(
  1302. HANDLE hPrinter,
  1303. DWORD parentJobId,
  1304. DWORD childJobId
  1305. )
  1306. /*++
  1307. Routine Description:
  1308. Tell the spooler to chain up two print jobs
  1309. Arguments:
  1310. hPrinter - Specifies the printer object
  1311. parentJobId - Specifies the job to chain from
  1312. childJobId - Specifies the job to chain to
  1313. Return Value:
  1314. TRUE if successful, FALSE if there is an error
  1315. --*/
  1316. {
  1317. JOB_INFO_3 jobInfo3 = { parentJobId, childJobId };
  1318. Warning(("Chaining cover page job to body job: %d => %d\n", parentJobId, childJobId));
  1319. return SetJob(hPrinter, parentJobId, 3, (PBYTE) &jobInfo3, 0);
  1320. }
  1321. LPTSTR
  1322. GetJobName(
  1323. HANDLE hPrinter,
  1324. DWORD jobId
  1325. )
  1326. /*++
  1327. Routine Description:
  1328. Return the name of the specified print job
  1329. Arguments:
  1330. hPrinter - Specifies the printer object
  1331. jobId - Specifies the fax body job
  1332. Return Value:
  1333. Pointer to the job name string, NULL if there is an error
  1334. --*/
  1335. {
  1336. JOB_INFO_1 *pJobInfo1;
  1337. LPTSTR pJobName = NULL;
  1338. //
  1339. // Get the information about the specified job and
  1340. // return a copy of the job name string
  1341. //
  1342. if (pJobInfo1 = MyGetJob(hPrinter, 1, jobId))
  1343. {
  1344. if ( (pJobInfo1->pDocument) &&
  1345. ((pJobName = DuplicateString(pJobInfo1->pDocument)) == NULL) )
  1346. {
  1347. Error(("DuplicateString(%s) failed.", pJobInfo1->pDocument));
  1348. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1349. }
  1350. MemFree(pJobInfo1);
  1351. }
  1352. return pJobName;
  1353. }
  1354. //*********************************************************************************
  1355. //* Name: ComposeFaxJobName()
  1356. //* Author: Ronen Barenboim
  1357. //* Date: April 22, 1999
  1358. //*********************************************************************************
  1359. //* DESCRIPTION:
  1360. //* Creates the document name for a print job by composing the document
  1361. //* body name with the recipient name (in case of a single recipient) or
  1362. //* the word "Broadcast" in case of a multiple recipient job.
  1363. //* The job name has the format <Recipient Name> - <Body Name> where
  1364. //* <Recipient Name> is "Broadcast" in the case a multiple recipient
  1365. //* tranmission.
  1366. //*
  1367. //* PARAMETERS:
  1368. //* [IN] PDOCEVENTUSERMEM pDocEventUserMem
  1369. //* A pointer to a USERMEM structure that contains information on the recipients.
  1370. //* Note that USERMEM.nRecipientCount must be valid (calculated) before calling
  1371. //* this function.
  1372. //*
  1373. //* [IN] LPTSTR pBodyDocName
  1374. //* The name of the document.
  1375. //*
  1376. //* RETURN VALUE:
  1377. //* Pointer to a newly allocated string that contains the composed name.
  1378. //* The caller must free the memory occupied by the string by calling
  1379. //* MemFree().
  1380. //* If the function fails the return value is NULL.
  1381. //*********************************************************************************
  1382. LPTSTR
  1383. ComposeFaxJobName(
  1384. PDOCEVENTUSERMEM pDocEventUserMem,
  1385. LPTSTR pBodyDocName
  1386. )
  1387. #define DOCNAME_FORMAT_STRING TEXT("%s - %s")
  1388. {
  1389. LPTSTR pCoverJobName;
  1390. LPTSTR pRecipientName;
  1391. #define MAX_BROADCAST_STRING_LEN 256
  1392. TCHAR szBroadcast[MAX_BROADCAST_STRING_LEN];
  1393. Assert(pDocEventUserMem);
  1394. if (pDocEventUserMem->dwNumberOfRecipients > 1) {
  1395. if (!LoadString(g_hResource,
  1396. IDS_BROADCAST_RECIPIENT,
  1397. szBroadcast,
  1398. sizeof(szBroadcast)/sizeof(TCHAR)))
  1399. {
  1400. Error(("Failed to load broadcast recipient string. (ec: %lc)",GetLastError()));
  1401. return NULL;
  1402. }
  1403. else {
  1404. pRecipientName = szBroadcast;
  1405. }
  1406. } else {
  1407. Assert(pDocEventUserMem->lpRecipientsInfo);
  1408. Assert(pDocEventUserMem->lpRecipientsInfo[0].lptstrName);
  1409. pRecipientName = pDocEventUserMem->lpRecipientsInfo[0].lptstrName;
  1410. }
  1411. if (pBodyDocName == NULL) {
  1412. //
  1413. // No body. job name is just the recipient name.
  1414. //
  1415. if ((pCoverJobName = DuplicateString(pRecipientName)) == NULL)
  1416. {
  1417. Error(("DuplicateString(%s) failed", pRecipientName));
  1418. }
  1419. }
  1420. else
  1421. {
  1422. DWORD dwSize;
  1423. dwSize = SizeOfString(DOCNAME_FORMAT_STRING) +
  1424. SizeOfString(pBodyDocName) +
  1425. SizeOfString(pRecipientName);
  1426. pCoverJobName = MemAlloc(dwSize);
  1427. if (pCoverJobName)
  1428. {
  1429. //
  1430. // Body name specified. The cover page job name is generated by
  1431. // concatenating the recipient's name with the body job name.
  1432. //
  1433. wsprintf(pCoverJobName, DOCNAME_FORMAT_STRING, pRecipientName, pBodyDocName);
  1434. }
  1435. else
  1436. {
  1437. Error((
  1438. "Failed to allocate %ld bytes for pCoverJobName (ec: %ld)",
  1439. dwSize,
  1440. GetLastError()));
  1441. }
  1442. }
  1443. return pCoverJobName;
  1444. }
  1445. LPTSTR
  1446. GetBaseNoteFilename(
  1447. VOID
  1448. )
  1449. /*++
  1450. Routine Description:
  1451. Get the name of base cover page file in system32 directory
  1452. Arguments:
  1453. argument-name - description of argument
  1454. Return Value:
  1455. Pointer to name of base cover page file
  1456. NULL if there is an error
  1457. --*/
  1458. #define BASENOTE_FILENAME TEXT("\\basenote.cov")
  1459. {
  1460. TCHAR systemDir[MAX_PATH];
  1461. LPTSTR pBaseNoteName = NULL;
  1462. COVDOCINFO covDocInfo;
  1463. if (GetSystemDirectory(systemDir, MAX_PATH) &&
  1464. (pBaseNoteName = MemAlloc(SizeOfString(systemDir) + SizeOfString(BASENOTE_FILENAME))))
  1465. {
  1466. _tcscpy(pBaseNoteName, systemDir);
  1467. _tcscat(pBaseNoteName, BASENOTE_FILENAME);
  1468. Verbose(("Base cover page filename: %ws\n", pBaseNoteName));
  1469. if (PrintCoverPage(NULL, NULL, pBaseNoteName, &covDocInfo) ||
  1470. ! (covDocInfo.Flags & COVFP_NOTE) ||
  1471. ! (covDocInfo.Flags & COVFP_SUBJECT))
  1472. {
  1473. Error(("Invalid base cover page file: %ws\n", pBaseNoteName));
  1474. MemFree(pBaseNoteName);
  1475. pBaseNoteName = NULL;
  1476. }
  1477. }
  1478. return pBaseNoteName;
  1479. }
  1480. //*********************************************************************************
  1481. //* Name: ComposeFaxJobParameter()
  1482. //* Author: Ronen Barenboim
  1483. //* Date: March 23, 1999
  1484. //*********************************************************************************
  1485. //* DESCRIPTION:
  1486. //* Generates the tagged parameter string that carries the job parameters
  1487. //* (sender information, cover page information ,recipient information)
  1488. //* to the fax monitor on the fax server (using JOB_INFO_2.pParameters).
  1489. //* PARAMETERS:
  1490. //* pDocEventUserMem
  1491. //* A pointer to a USERMEM structure from which some of the information
  1492. //* is collected.
  1493. //* pCPFields
  1494. //* A pointer to a COVERPAGEFIELS structure from which sender and cover
  1495. //* page information is collected.
  1496. //* lppParamBuf
  1497. //* The address of a pointer varialbe that will accept the address of the
  1498. //* buffer this function will allocated for the resulting tagged string.
  1499. //* The caller of this function must free this buffer using MemFree().
  1500. //* RETURN VALUE:
  1501. //* TRUE
  1502. //* If successful.
  1503. //* FALSE
  1504. //* If failed.
  1505. //*********************************************************************************
  1506. BOOL
  1507. ComposeFaxJobParameter(
  1508. PDOCEVENTUSERMEM pDocEventUserMem,
  1509. PCOVERPAGEFIELDS pCPFields,
  1510. LPTSTR * lppParamBuf
  1511. )
  1512. {
  1513. DWORD dwBufSize;
  1514. DWORD dwPartialBufSize;
  1515. DWORD dwLeftBufferSize;
  1516. LPTSTR lptstrBuf;
  1517. UINT i;
  1518. Assert(pDocEventUserMem);
  1519. Assert(pCPFields);
  1520. Assert(lppParamBuf);
  1521. //
  1522. // Calculate the parameter buffer we need to allocated
  1523. //
  1524. dwBufSize=0;
  1525. //
  1526. // Calcualte non recipient params string size
  1527. //
  1528. ComposeSenderJobParam(NULL, &dwPartialBufSize, pDocEventUserMem, pCPFields); // void return value
  1529. dwBufSize=dwBufSize+dwPartialBufSize;
  1530. //
  1531. // Go over each recipient and calculate the total required buffer size
  1532. //
  1533. for (i=0;i<pDocEventUserMem->dwNumberOfRecipients;i++)
  1534. {
  1535. //
  1536. // Get recipient's name and fax number
  1537. //
  1538. Assert(pDocEventUserMem->lpRecipientsInfo[i].lptstrName);
  1539. pCPFields->RecName = pDocEventUserMem->lpRecipientsInfo[i].lptstrName;
  1540. Assert(pDocEventUserMem->lpRecipientsInfo[i].lptstrFaxNumber);
  1541. pCPFields->RecFaxNumber = pDocEventUserMem->lpRecipientsInfo[i].lptstrFaxNumber;
  1542. ComposeRecipientJobParam(NULL, &dwPartialBufSize, pCPFields);
  1543. dwBufSize=dwBufSize+dwPartialBufSize; //keep space for the seperating NULL
  1544. }
  1545. //
  1546. // Don't forget the space for the terminating NULL (the ComposeX functions do not include
  1547. // it in the size they report).
  1548. //
  1549. dwBufSize=dwBufSize+sizeof(TCHAR); // dwBufSize is size in BYTES so we must calc the byte size of a TCHAR
  1550. //
  1551. // Allocate the required buffer
  1552. //
  1553. lptstrBuf=MemAlloc(dwBufSize);
  1554. if (!lptstrBuf) {
  1555. Error(("Failed to allocate buffer of size %ld for parameter buffer (ec: 0x%0X)",dwBufSize,GetLastError()));
  1556. return FALSE;
  1557. }
  1558. //
  1559. // Write the parameters into the buffer
  1560. //
  1561. dwLeftBufferSize = dwBufSize;
  1562. dwPartialBufSize = dwBufSize;
  1563. *lppParamBuf=lptstrBuf;
  1564. ComposeSenderJobParam(lptstrBuf, &dwPartialBufSize, pDocEventUserMem, pCPFields);
  1565. lptstrBuf+=(dwPartialBufSize/sizeof(TCHAR)); // The reported size is in bytes !!!
  1566. Assert (dwLeftBufferSize >= dwPartialBufSize);
  1567. dwLeftBufferSize -= dwPartialBufSize;
  1568. for (i=0;i<pDocEventUserMem->dwNumberOfRecipients;i++)
  1569. {
  1570. //
  1571. // Get recipient's name and fax number
  1572. //
  1573. pCPFields->RecName = pDocEventUserMem->lpRecipientsInfo[i].lptstrName;
  1574. pCPFields->RecFaxNumber = pDocEventUserMem->lpRecipientsInfo[i].lptstrFaxNumber;
  1575. dwPartialBufSize = dwLeftBufferSize;
  1576. ComposeRecipientJobParam(lptstrBuf, &dwPartialBufSize, pCPFields);
  1577. lptstrBuf+=(dwPartialBufSize/sizeof(TCHAR)); // The reported size is in bytes !!!
  1578. Assert (dwLeftBufferSize >= dwPartialBufSize);
  1579. dwLeftBufferSize -= dwPartialBufSize;
  1580. }
  1581. //
  1582. // No need to add a terminating NULL since ParamTagsToString allways appends a NULL terminated string
  1583. // to the existing string (it uses _tcscpy).
  1584. //
  1585. return TRUE;
  1586. }
  1587. //*********************************************************************************
  1588. //* Name: ComposeRecipientJobParam()
  1589. //* Author: Ronen Barenboim
  1590. //* Date: March 23, 1999
  1591. //*********************************************************************************
  1592. //* DESCRIPTION:
  1593. //* Creates a taged parameter string containing recipient information.
  1594. //*
  1595. //* PARAMETERS:
  1596. //* lpParamBuf
  1597. //* Pointer to the string buffer where the tagged string is written.
  1598. //* lpdwParamSize
  1599. //* Pointer to a DWORD where the function reports the size of the parameter
  1600. //* string in BYTES.
  1601. //* If this parameter is NULL then the function does not generate
  1602. //* the string but only reports its size.
  1603. //* The size does NOT include the terminating NULL char.
  1604. //* pCPFields
  1605. //* Pointer to a COVERPAGEFIELDS structure from which the recipient
  1606. //* information is collected.
  1607. //* RETURN VALUE:
  1608. //* None.
  1609. //*********************************************************************************
  1610. void
  1611. ComposeRecipientJobParam(
  1612. LPTSTR lpParamBuf,
  1613. LPDWORD lpdwParamSize,
  1614. const COVERPAGEFIELDS * pCPFields
  1615. )
  1616. {
  1617. FAX_TAG_MAP_ENTRY tagMap[] =
  1618. {
  1619. //
  1620. // Recipient info
  1621. //
  1622. { FAXTAG_NEW_RECORD, FAXTAG_NEW_RECORD_VALUE}, // Parameters record start indication
  1623. { FAXTAG_RECIPIENT_NAME, pCPFields->RecName },
  1624. { FAXTAG_RECIPIENT_NUMBER, pCPFields->RecFaxNumber },
  1625. { FAXTAG_RECIPIENT_COMPANY, pCPFields->RecCompany },
  1626. { FAXTAG_RECIPIENT_STREET, pCPFields->RecStreetAddress },
  1627. { FAXTAG_RECIPIENT_CITY, pCPFields->RecCity },
  1628. { FAXTAG_RECIPIENT_STATE, pCPFields->RecState },
  1629. { FAXTAG_RECIPIENT_ZIP, pCPFields->RecZip },
  1630. { FAXTAG_RECIPIENT_COUNTRY, pCPFields->RecCountry },
  1631. { FAXTAG_RECIPIENT_TITLE, pCPFields->RecTitle },
  1632. { FAXTAG_RECIPIENT_DEPT, pCPFields->RecDepartment },
  1633. { FAXTAG_RECIPIENT_OFFICE_LOCATION, pCPFields->RecOfficeLocation },
  1634. { FAXTAG_RECIPIENT_HOME_PHONE, pCPFields->RecHomePhone },
  1635. { FAXTAG_RECIPIENT_OFFICE_PHONE, pCPFields->RecOfficePhone },
  1636. };
  1637. DWORD dwTagCount;
  1638. Assert(pCPFields);
  1639. Assert(lpdwParamSize);
  1640. dwTagCount=sizeof(tagMap)/sizeof(FAX_TAG_MAP_ENTRY);
  1641. ParamTagsToString(tagMap, dwTagCount, lpParamBuf, lpdwParamSize );
  1642. }
  1643. //*********************************************************************************
  1644. //* Name: ComposeSenderJobParam()
  1645. //* Author: Ronen Barenboim
  1646. //* Date: March 23, 1999
  1647. //*********************************************************************************
  1648. //* DESCRIPTION:
  1649. //* Creates a taged parameter string containing cover page information, sender
  1650. //* information and the number of recipients in the tranmission.
  1651. //*
  1652. //* PARAMETERS:
  1653. //* lpParamBuf
  1654. //* Pointer to the string buffer where the tagged string is written.
  1655. //* lpdwParamSize
  1656. //* Pointer to a DWORD where the function reports the size of the parameter
  1657. //* string in BYTES.
  1658. //* If this parameter is NULL then the function does not generate
  1659. //* the string but only reports its size.
  1660. //* The size does NOT include the terminating NULL char.
  1661. //* pDocEventUserMem
  1662. //* Pointer to a USERMEM structure from which some of information
  1663. //* is collected.
  1664. //* pCPFields
  1665. //* Pointer to a COVERPAGEFIELDS structure from which the cover page
  1666. //* and sender information is collected.
  1667. //*
  1668. //* RETURN VALUE:
  1669. //* None.
  1670. //*********************************************************************************
  1671. void
  1672. ComposeSenderJobParam(
  1673. LPTSTR lpParamBuf,
  1674. LPDWORD lpdwParamSize,
  1675. PDOCEVENTUSERMEM pDocEventUserMem,
  1676. const COVERPAGEFIELDS * pCPFields)
  1677. {
  1678. #define FAXTAG_SERVER_COVERPAGE_IDX 9
  1679. #define FAXTAG_TSID_IDX 3
  1680. TCHAR lptstrRecipientCount[11];
  1681. FAX_TAG_MAP_ENTRY tagMap[] =
  1682. {
  1683. { FAXTAG_NEW_RECORD, FAXTAG_NEW_RECORD_VALUE},
  1684. { FAXTAG_WHEN_TO_SEND, NULL },
  1685. { FAXTAG_SEND_AT_TIME, NULL },
  1686. { FAXTAG_TSID, pCPFields->SdrFaxNumber },
  1687. { FAXTAG_BILLING_CODE, pDocEventUserMem->devmode.dmPrivate.billingCode },
  1688. { FAXTAG_RECEIPT_TYPE, pDocEventUserMem->pReceiptFlags },
  1689. { FAXTAG_RECEIPT_ADDR, pDocEventUserMem->pReceiptAddress },
  1690. { FAXTAG_PRIORITY, pDocEventUserMem->pPriority },
  1691. { FAXTAG_COVERPAGE_NAME, pDocEventUserMem->coverPage },
  1692. { FAXTAG_SERVER_COVERPAGE, NULL },
  1693. { FAXTAG_PAGE_COUNT, pCPFields->NumberOfPages},
  1694. { FAXTAG_SENDER_NAME, pCPFields->SdrName },
  1695. { FAXTAG_SENDER_NUMBER, pCPFields->SdrFaxNumber},
  1696. { FAXTAG_SENDER_COMPANY, pCPFields->SdrCompany },
  1697. { FAXTAG_SENDER_TITLE, pCPFields->SdrTitle },
  1698. { FAXTAG_SENDER_DEPT, pCPFields->SdrDepartment },
  1699. { FAXTAG_SENDER_OFFICE_LOCATION , pCPFields->SdrOfficeLocation },
  1700. { FAXTAG_SENDER_HOME_PHONE, pCPFields->SdrHomePhone },
  1701. { FAXTAG_SENDER_OFFICE_PHONE, pCPFields->SdrOfficePhone },
  1702. { FAXTAG_SENDER_STREET, pDocEventUserMem->lpSenderInfo->lptstrStreetAddress },
  1703. { FAXTAG_SENDER_CITY, pDocEventUserMem->lpSenderInfo->lptstrCity },
  1704. { FAXTAG_SENDER_STATE, pDocEventUserMem->lpSenderInfo->lptstrState },
  1705. { FAXTAG_SENDER_ZIP, pDocEventUserMem->lpSenderInfo->lptstrZip },
  1706. { FAXTAG_SENDER_COUNTRY, pDocEventUserMem->lpSenderInfo->lptstrCountry },
  1707. { FAXTAG_SENDER_EMAIL, pDocEventUserMem->lpSenderInfo->lptstrEmail },
  1708. { FAXTAG_NOTE, pDocEventUserMem->pNoteMessage },
  1709. { FAXTAG_SUBJECT, pDocEventUserMem->pSubject},
  1710. { FAXTAG_RECIPIENT_COUNT, lptstrRecipientCount}
  1711. };
  1712. TCHAR SendAtTime[16];
  1713. DWORD dwTagCount;
  1714. if (pDocEventUserMem->bServerCoverPage)
  1715. {
  1716. tagMap[FAXTAG_SERVER_COVERPAGE_IDX].lptstrValue=TEXT("1");
  1717. } else
  1718. {
  1719. tagMap[FAXTAG_SERVER_COVERPAGE_IDX].lptstrValue=NULL;
  1720. }
  1721. //
  1722. // create the sendattime string
  1723. //
  1724. if (pDocEventUserMem->devmode.dmPrivate.whenToSend == JSA_DISCOUNT_PERIOD) {
  1725. tagMap[1].lptstrValue=TEXT("cheap");
  1726. }
  1727. if (pDocEventUserMem->devmode.dmPrivate.whenToSend == JSA_SPECIFIC_TIME) {
  1728. wsprintf( SendAtTime, TEXT("%02d:%02d"),
  1729. pDocEventUserMem->devmode.dmPrivate.sendAtTime.Hour,
  1730. pDocEventUserMem->devmode.dmPrivate.sendAtTime.Minute
  1731. );
  1732. tagMap[1].lptstrValue= TEXT("at");
  1733. tagMap[2].lptstrValue= SendAtTime;
  1734. }
  1735. wsprintf( lptstrRecipientCount, TEXT("%10d"),pDocEventUserMem->dwNumberOfRecipients);
  1736. //
  1737. // Figure out the total length of the tagged string
  1738. //
  1739. dwTagCount=sizeof(tagMap)/sizeof(FAX_TAG_MAP_ENTRY);
  1740. ParamTagsToString(tagMap, dwTagCount, lpParamBuf, lpdwParamSize );
  1741. }
  1742. //*****************************************************************************
  1743. //* Name: WriteCoverPageToPrintJob
  1744. //* Author: Ronen Barenboim (Feb-99)
  1745. //*****************************************************************************
  1746. //* DESCRIPTION:
  1747. //* Reads the content of the specified cover page template and writes it
  1748. //* to the specified printer.
  1749. //* The user should call StartDocPrinter() and StartPagePrinter()
  1750. //* before calling this function.
  1751. //* PARAMETERS:
  1752. //* [IN] HANDLE hPrinter:
  1753. //* A handle to the printer to which the cover page template
  1754. //* should be written.
  1755. //* [IN] LPCTSTR lpctstrCoverPageFile:
  1756. //* The full path to the cover page file whose content is to be
  1757. //* written to the printer.
  1758. //* RETURN VALUE:
  1759. //* FALSE: If the function failed.
  1760. //* TRUE: Otherwise.
  1761. //*****************************************************************************
  1762. BOOL WriteCoverPageToPrintJob(HANDLE hPrinter, LPCTSTR lpctstrCoverPageFile)
  1763. {
  1764. #define BUF_SIZE 64*1024 // Buffer size for read operation
  1765. PCHAR chBuf=NULL; // Read operation buffer
  1766. BOOL bRes; // The result of the function
  1767. HANDLE hCoverFile; // Handle to the cover page file
  1768. DWORD dwBytesRead; // The number of bytes actually read at each cycle
  1769. Assert(hPrinter);
  1770. Assert(lpctstrCoverPageFile);
  1771. bRes=FALSE;
  1772. hCoverFile=INVALID_HANDLE_VALUE;
  1773. //
  1774. // Open the cover page template file for reading
  1775. //
  1776. hCoverFile=CreateFile(
  1777. lpctstrCoverPageFile,
  1778. GENERIC_READ,
  1779. 0,
  1780. NULL,
  1781. OPEN_EXISTING,
  1782. 0,
  1783. 0);
  1784. if (INVALID_HANDLE_VALUE == hCoverFile )
  1785. {
  1786. goto Exit;
  1787. }
  1788. chBuf = MemAlloc(BUF_SIZE);
  1789. if (NULL == chBuf)
  1790. {
  1791. Error(("Failed to allocate read operation buffer"));
  1792. goto Exit;
  1793. }
  1794. //
  1795. //Read the file and write it into the print job
  1796. //
  1797. do {
  1798. bRes=ReadFile(hCoverFile,chBuf,sizeof(CHAR)*BUF_SIZE,&dwBytesRead,NULL) ;
  1799. if (!bRes) {
  1800. Error(("Failed to read cover page file into print job (cover page file: %s ec: %d\n)",
  1801. lpctstrCoverPageFile,
  1802. GetLastError())
  1803. );
  1804. break;
  1805. } else {
  1806. Verbose(("Success reading cover page file %s. %d bytes read.\n",lpctstrCoverPageFile,dwBytesRead));
  1807. }
  1808. if (dwBytesRead) {
  1809. //
  1810. // If dwBytesRead != 0 we are NOT at the enf of the file.
  1811. //
  1812. DWORD dwWritten;
  1813. bRes=WritePrinter(hPrinter,(LPVOID)chBuf,dwBytesRead,&dwWritten);
  1814. if (!bRes) {
  1815. Error(("Failed to write to printer (ec = %d)", GetLastError()));
  1816. } else
  1817. {
  1818. Verbose(("Success writing to printer. %d bytes written.\n",dwWritten));
  1819. }
  1820. }
  1821. } while (dwBytesRead); // While not EOF
  1822. Exit:
  1823. //
  1824. //Close the cover page file
  1825. //
  1826. if (INVALID_HANDLE_VALUE!=hCoverFile)
  1827. {
  1828. if (!CloseHandle(hCoverFile))
  1829. {
  1830. Error(("CloseHandle() failed: %d.\n", GetLastError()));
  1831. }
  1832. }
  1833. if (NULL != chBuf)
  1834. {
  1835. MemFree(chBuf);
  1836. }
  1837. return bRes;
  1838. }
  1839. //*****************************************************************************
  1840. //* Name: DoCoverPageRendering
  1841. //* Author: Ronen Barenboim (Feb-99)
  1842. //*****************************************************************************
  1843. //* DESCRIPTION:
  1844. //* Creates the cover page print job and attaches it to the body print job.
  1845. //* The cover page job is created even when a cover page is NOT specified.
  1846. //* It contains all the job parameters for the job as a tagged string
  1847. //* placed in JOB_INFO_2.pParameters. This contains the information for the
  1848. //* sender, cover page, job parameters and ALL recipients.
  1849. //*
  1850. //* The content of the job is empty if no cover page is specified or
  1851. //* The cover page is server based.
  1852. //* For personal cover pages the content of the cover page template is written
  1853. //* into the job as "RAW" data. The print monitor on the server will extract this
  1854. //* data to reconstruct the cover page file on the server.
  1855. //*
  1856. //* PARAMETERS:
  1857. //* [IN] PDOCEVENTUSERMEM pDocEventUserMem:
  1858. //* A pointer to a USERMEM structure containing the context information
  1859. //* for the print job.
  1860. //* RETURN VALUE:
  1861. //* FALSE: If the function failed.
  1862. //* TRUE: Otherwise.
  1863. //*****************************************************************************
  1864. BOOL
  1865. DoCoverPageRendering(
  1866. PDOCEVENTUSERMEM pDocEventUserMem
  1867. )
  1868. {
  1869. PCOVERPAGEFIELDS pCPFields=NULL;
  1870. DOC_INFO_1 docinfo;
  1871. INT newJobId=0;
  1872. INT lastJobId=0;
  1873. INT cCoverPagesSent=0;
  1874. PDMPRIVATE pdmPrivate = &pDocEventUserMem->devmode.dmPrivate;
  1875. HANDLE hPrinter = pDocEventUserMem->hPrinter;
  1876. DWORD bodyJobId = pDocEventUserMem->jobId;
  1877. LPTSTR pBodyDocName=NULL;
  1878. LPTSTR pJobParam=NULL;
  1879. BOOL sendCoverPage;
  1880. DWORD pageCount;
  1881. //
  1882. // Fill out a DOCINFO structure which is passed to StartDoc
  1883. //
  1884. memset(&docinfo, 0, sizeof(docinfo));
  1885. //docinfo.cbSize = sizeof(docinfo);
  1886. //
  1887. // Determine if we need a cover page or not
  1888. //
  1889. if ( (sendCoverPage = pdmPrivate->sendCoverPage) && IsEmptyString(pDocEventUserMem->coverPage)) {
  1890. Warning(("Missing cover page file\n"));
  1891. sendCoverPage = FALSE;
  1892. }
  1893. pageCount = pDocEventUserMem->pageCount;
  1894. //
  1895. // Collect cover page information into a newly allocated pCPFields. pCPFields will be
  1896. // passed to ComposeFaxJobParameters() to provide the values for the job tags.
  1897. //
  1898. if ((pCPFields = CollectCoverPageFields(pDocEventUserMem->lpSenderInfo,pageCount)) == NULL) {
  1899. Error(("Couldn't collect cover page information\n"));
  1900. goto Exit;
  1901. }
  1902. pBodyDocName = GetJobName(hPrinter, bodyJobId);
  1903. if (!pBodyDocName) {
  1904. Error(("GetJobName failed (ec: %ld)", GetLastError()));
  1905. Assert(FALSE);
  1906. //
  1907. // We continue inspite of the error. We can handle a NULL body doc name.
  1908. //
  1909. }
  1910. //
  1911. // We assume the fax body job has already been paused
  1912. // Use a separate cover page for each recipient
  1913. //
  1914. newJobId = 0;
  1915. docinfo.pDocName = NULL;
  1916. pJobParam = NULL;
  1917. //
  1918. // Start a cover page job
  1919. //
  1920. //
  1921. // The cover page job document name is "<BODY_NAME> - COVERPAGE"
  1922. //
  1923. docinfo.pOutputFile=NULL;
  1924. docinfo.pDatatype=TEXT("RAW"); // Since we write the template into the job we want to bypass the driver.
  1925. //
  1926. // Create the tagged string of job parameters to be placed into JOB_INFO_2:pParameters.
  1927. // The parameters include the parameters found at the FAX_JOB_PARAM client API structure.
  1928. // pJobParam is ALLOCATED.
  1929. //
  1930. if (!ComposeFaxJobParameter(pDocEventUserMem, pCPFields,&pJobParam)) {
  1931. Error(("ComposeFaxJobParameter failed. (ec: 0x%X)",GetLastError()));
  1932. goto Error;
  1933. }
  1934. Assert(pJobParam); // Should be allocated now.
  1935. docinfo.pDocName = ComposeFaxJobName(pDocEventUserMem,pBodyDocName);//pBodyDocName, TEXT("COVERPAGE"));
  1936. if (!docinfo.pDocName) {
  1937. Error(("ComposeFaxJobName failed. Body: %s (ec: %ld)",pBodyDocName,GetLastError()));
  1938. //
  1939. // we can do with no document name.
  1940. //
  1941. }
  1942. if ((newJobId = StartDocPrinter(hPrinter,1, (LPBYTE)&docinfo)) !=0) {
  1943. BOOL rendered = FALSE;
  1944. //
  1945. // Pass fax job parameters using JOB_INFO_2.pParameters field.
  1946. //
  1947. //
  1948. // Pause the new cover page job.
  1949. //
  1950. if (!SetJob(hPrinter, newJobId, 0, NULL, JOB_CONTROL_PAUSE)) {
  1951. Error(("Failed to pause job id: %d (ec: %ld)",newJobId,GetLastError()));
  1952. Assert(FALSE);
  1953. goto Error;
  1954. }
  1955. if (!SetJobInfoAndTime(hPrinter,
  1956. newJobId,
  1957. pJobParam,
  1958. pdmPrivate)) {
  1959. Error(("SetJobInfoAndTime failed. Job id : %d.",newJobId));
  1960. Assert(FALSE);
  1961. goto Error;
  1962. }
  1963. if (! sendCoverPage || pDocEventUserMem->bServerCoverPage) {
  1964. //
  1965. // If the user chose not to include cover page or a server side cover page was specified
  1966. // the cover page job will be empty
  1967. // Note that even if there is no cover page to send we still create a cover page print job
  1968. // and link it to the body.
  1969. // The cover print job is used to convery sender/recipient information. The fax print monitor will
  1970. // use the job parameters string placed in JOB_INFO_2:pParameters to get this information at the server.
  1971. //
  1972. rendered = TRUE;
  1973. } else {
  1974. if (StartPagePrinter(hPrinter)) {
  1975. //
  1976. // Write the content of the cover page template into the print job.
  1977. // The print monitor on the server will extract this information to get
  1978. // the cover page template and render the cover page on the server.
  1979. //
  1980. rendered=WriteCoverPageToPrintJob(hPrinter,pDocEventUserMem->coverPage);
  1981. if (!rendered) {
  1982. Error(("WriteCoverPageToPrintJob failed: %d\n", rendered ));
  1983. //
  1984. // Must call EndPagePrinter if error was encounterd or not.
  1985. //
  1986. }
  1987. if (!EndPagePrinter(hPrinter)) {
  1988. Error(("EndPagePrinter failed. (ec: %ld)",GetLastError()));
  1989. goto Error;
  1990. }
  1991. if (!rendered) {
  1992. goto Error;
  1993. }
  1994. } else {
  1995. Error(("StartPagePrinter failed. (ec: %ld)",GetLastError()));
  1996. rendered=FALSE;
  1997. goto Error;
  1998. }
  1999. }
  2000. //
  2001. // Chain the cover page job to the fax body job if no error occured.
  2002. //
  2003. // Chain the cover page job to the BODY job.
  2004. // The cover page job is the parent job. The body is the child job.
  2005. // Note that multiple cover page
  2006. // Jobs will be chained to the same BODY job.
  2007. // also note the cover page jobs are not chained to each other. Just to the body.
  2008. //
  2009. if (rendered) {
  2010. if (ChainFaxJobs(hPrinter, newJobId, bodyJobId)) {
  2011. if (lastJobId != 0) {
  2012. if (!SetJob(hPrinter, lastJobId, 0, NULL, JOB_CONTROL_RESUME)) {
  2013. Error(("Failed to resume job with id: %d",lastJobId));
  2014. Assert(FALSE);
  2015. goto Error;
  2016. }
  2017. }
  2018. lastJobId = newJobId;
  2019. if (!EndDocPrinter(hPrinter)) {
  2020. Error(("EndPagePrinter failed. (ec: %ld)",GetLastError()));
  2021. Assert(FALSE);
  2022. goto Error;
  2023. }
  2024. cCoverPagesSent++;
  2025. } else {
  2026. Error(("ChainFaxJobs for CoverJobId=%d BodyJobId=%d has failed. Aborting job.",newJobId, bodyJobId));
  2027. goto Error;
  2028. }
  2029. } else {
  2030. Error(("Cover page template not written into job (rendered=FALSE). Aborting job."));
  2031. goto Error;
  2032. }
  2033. } else {
  2034. Error(("StartDocPrinter failed. (ec: %ld)",GetLastError()));
  2035. goto Error;
  2036. }
  2037. goto Exit;
  2038. Error:
  2039. Error(("Cover page job failed"));
  2040. if (0!=newJobId) {
  2041. //
  2042. // This means that an error was detected after we created the job.
  2043. // Note that if StartDocPrinter failed this code is not executed.
  2044. //
  2045. Error(("Aborting cover page job. JobId = %d",newJobId));
  2046. if (!AbortPrinter(hPrinter)) {
  2047. Error(("AbortPrinter failed (ec: %ld)",GetLastError()));
  2048. }
  2049. }
  2050. Exit:
  2051. if (docinfo.pDocName) {
  2052. MemFree((PVOID)docinfo.pDocName);
  2053. }
  2054. if (pJobParam) {
  2055. MemFree((PVOID)pJobParam);
  2056. }
  2057. if (pBodyDocName) {
  2058. MemFree(pBodyDocName);
  2059. }
  2060. if (pCPFields) {
  2061. FreeCoverPageFields(pCPFields);
  2062. }
  2063. //
  2064. // Resume the last cover page job if it's paused and
  2065. // delete the fax body job if no cover page jobs were sent
  2066. //
  2067. if (lastJobId != 0) {
  2068. if (!SetJob(hPrinter, lastJobId, 0, NULL, JOB_CONTROL_RESUME)) {
  2069. Error(("Failed to resume last job id : %d",lastJobId));
  2070. Assert(FALSE);
  2071. }
  2072. }
  2073. if (cCoverPagesSent > 0) {
  2074. if (!SetJob(hPrinter, bodyJobId, 0, NULL, JOB_CONTROL_RESUME)) {
  2075. Error(("Failed to resume body job with id: %d",bodyJobId));
  2076. Assert(FALSE);
  2077. }
  2078. } else {
  2079. Error(("No recipient jobs created. Fax job deleted due to an error.\n"));
  2080. if (!SetJob(hPrinter, bodyJobId, 0, NULL, JOB_CONTROL_DELETE)) {
  2081. Error(("Failed to delete body job with id: %d",bodyJobId));
  2082. Assert(FALSE);
  2083. }
  2084. }
  2085. return cCoverPagesSent > 0;
  2086. }
  2087. INT
  2088. DocEventEndDocPost(
  2089. HDC hdc,
  2090. PDOCEVENTUSERMEM pDocEventUserMem
  2091. )
  2092. /*++
  2093. Routine Description:
  2094. Handle ENDDOCPOST document event
  2095. Arguments:
  2096. hdc - Specifies the printer device context
  2097. pDocEventUserMem - Points to the user mode memory structure
  2098. Return Value:
  2099. Return value for DrvDocumentEvent
  2100. --*/
  2101. {
  2102. INT result = DOCUMENTEVENT_SUCCESS;
  2103. switch (pDocEventUserMem->jobType)
  2104. {
  2105. case JOBTYPE_NORMAL:
  2106. Warning(("Number of pages printed: %d\n", pDocEventUserMem->pageCount));
  2107. if (! pDocEventUserMem->directPrinting)
  2108. {
  2109. LRESULT ec;
  2110. BOOL bAllowed = FALSE;
  2111. //
  2112. // check if there is already running instance of Fax Wizard
  2113. //
  2114. if(!g_bInitRunningWizardCS)
  2115. {
  2116. Assert(FALSE);
  2117. result = DOCUMENTEVENT_FAILURE;
  2118. break;
  2119. }
  2120. EnterCriticalSection(&g_csRunningWizard);
  2121. if (!g_bRunningWizard)
  2122. {
  2123. //
  2124. // no running instance of Fax Wizard
  2125. //
  2126. g_bRunningWizard = TRUE;
  2127. bAllowed = TRUE;
  2128. }
  2129. LeaveCriticalSection(&g_csRunningWizard);
  2130. if (!bAllowed)
  2131. {
  2132. //
  2133. // there is running instance of Fax Wizard
  2134. // show popup to user and stop processing
  2135. //
  2136. ShowReentrancyMessage();
  2137. result = DOCUMENTEVENT_FAILURE;
  2138. break;
  2139. }
  2140. ec = LaunchFaxWizard(pDocEventUserMem);
  2141. //
  2142. // Let other threads to launch Fax Wizard
  2143. //
  2144. EnterCriticalSection(&g_csRunningWizard);
  2145. g_bRunningWizard = FALSE;
  2146. LeaveCriticalSection(&g_csRunningWizard);
  2147. if (ERROR_SUCCESS == ec)
  2148. {
  2149. //
  2150. // Generate a cover page for each recipient and associate
  2151. // the cover page job with the main body.
  2152. // The job will contain the cover page template data and the
  2153. // recipient parameters.
  2154. if (! DoCoverPageRendering(pDocEventUserMem))
  2155. {
  2156. Error(("DoCoverPageRendering failed."));
  2157. result = DOCUMENTEVENT_FAILURE;
  2158. }
  2159. }
  2160. else
  2161. {
  2162. result = DOCUMENTEVENT_FAILURE;
  2163. }
  2164. //
  2165. // Free up the list of recipients
  2166. //
  2167. FreeRecipientInfo(&pDocEventUserMem->dwNumberOfRecipients, pDocEventUserMem->lpRecipientsInfo);
  2168. }
  2169. break;
  2170. }
  2171. if (DOCUMENTEVENT_SUCCESS != result)
  2172. {
  2173. //
  2174. // Cancel the job ignoring errors
  2175. //
  2176. if (!SetJob(
  2177. pDocEventUserMem->hPrinter,
  2178. pDocEventUserMem->jobId,
  2179. 0,
  2180. NULL,
  2181. JOB_CONTROL_DELETE))
  2182. {
  2183. Error(("Failed to cancel job. JobId: %ld (ec: %ld)",
  2184. pDocEventUserMem->jobId,
  2185. GetLastError()));
  2186. }
  2187. }
  2188. return result;
  2189. }
  2190. BOOL
  2191. AppendPreviewPage(PDOCEVENTUSERMEM pDocEventUserMem)
  2192. /*++
  2193. Routine Description:
  2194. Append the next document page to the temporary preview file
  2195. Arguments:
  2196. pDocEventUserMem
  2197. Return Value:
  2198. TRUE on success
  2199. Note:
  2200. If this routine is called for page 0, it just checks that the graphics driver hasn't
  2201. cancled the print preview option and validates the mapping structures.
  2202. --*/
  2203. {
  2204. DWORD dwWritten;
  2205. // If we get here print preview should be enabled an all preview handles valid
  2206. Assert(FALSE == pDocEventUserMem->bPreviewAborted);
  2207. Assert(INVALID_HANDLE_VALUE != pDocEventUserMem->hPreviewFile);
  2208. Assert(NULL != pDocEventUserMem->pPreviewTiffPage);
  2209. //
  2210. // Validate preview mapping
  2211. //
  2212. // The size of the header should be correct
  2213. if (sizeof(MAP_TIFF_PAGE_HEADER) != pDocEventUserMem->pPreviewTiffPage->cb)
  2214. {
  2215. Error(("Preview mapping corrupted\n"));
  2216. pDocEventUserMem->bPreviewAborted = TRUE;
  2217. return FALSE;
  2218. }
  2219. // Check if the preview operation hasn't beed cancled by the graphics driver
  2220. if (FALSE == pDocEventUserMem->pPreviewTiffPage->bPreview)
  2221. {
  2222. Error(("Preview aborted by graphics driver\n"));
  2223. pDocEventUserMem->bPreviewAborted = TRUE;
  2224. return FALSE;
  2225. }
  2226. //
  2227. // If we are called prior to the first sent page just return
  2228. //
  2229. if (!pDocEventUserMem->pageCount)
  2230. {
  2231. return TRUE;
  2232. }
  2233. //
  2234. // Validate correct page number:
  2235. //
  2236. // The graphics driver increments the page count on the call to DrvStartPage(), while we
  2237. // increment the page count on the ENDPAGE event.
  2238. //
  2239. // As this function is called by the STARTPAGE event handler (before 'DrvStartPage' is called
  2240. // again in the graphics driver) or by the ENDDOCPOST event handler, the page number set by
  2241. // the graphics driver in the mapping should be equal to our page count in this stage.
  2242. //
  2243. if (pDocEventUserMem->pageCount != pDocEventUserMem->pPreviewTiffPage->iPageCount)
  2244. {
  2245. Error(("Wrong preview page: %d. Page expected: %d.\n",
  2246. pDocEventUserMem->pPreviewTiffPage->iPageCount,
  2247. pDocEventUserMem->pageCount));
  2248. pDocEventUserMem->bPreviewAborted = TRUE;
  2249. pDocEventUserMem->pPreviewTiffPage->bPreview = FALSE;
  2250. return FALSE;
  2251. }
  2252. //
  2253. // Append new page to temporary preview file
  2254. //
  2255. if (0 == pDocEventUserMem->pPreviewTiffPage->dwDataSize)
  2256. {
  2257. //
  2258. // Nothing to add (?!). It is impossible to get an empty TIFF page
  2259. //
  2260. Error(("Recieved empty preview page: %d.\n", pDocEventUserMem->pageCount));
  2261. Assert(FALSE);
  2262. return TRUE;
  2263. }
  2264. if (!WriteFile(
  2265. pDocEventUserMem->hPreviewFile,
  2266. pDocEventUserMem->pPreviewTiffPage + 1,
  2267. pDocEventUserMem->pPreviewTiffPage->dwDataSize,
  2268. &dwWritten,
  2269. NULL) || dwWritten != pDocEventUserMem->pPreviewTiffPage->dwDataSize)
  2270. {
  2271. Error(("Failed appending preview page: %d. Error: %d\n",
  2272. pDocEventUserMem->pageCount,
  2273. GetLastError()));
  2274. pDocEventUserMem->bPreviewAborted = TRUE;
  2275. pDocEventUserMem->pPreviewTiffPage->bPreview = FALSE;
  2276. return FALSE;
  2277. }
  2278. return TRUE;
  2279. }
  2280. INT
  2281. DrvDocumentEvent(
  2282. HANDLE hPrinter,
  2283. HDC hdc,
  2284. INT iEsc,
  2285. ULONG cbIn,
  2286. PULONG pjIn,
  2287. ULONG cbOut,
  2288. PULONG pjOut
  2289. )
  2290. /*++
  2291. Routine Description:
  2292. Hook into GDI at various points during the output process
  2293. Arguments:
  2294. hPrinter - Specifies the printer object
  2295. hdc - Handle to the printer DC
  2296. iEsc - Why this function is called (see notes below)
  2297. cbIn - Size of the input buffer
  2298. pjIn - Pointer to the input buffer
  2299. cbOut - Size of the output buffer
  2300. pjOut - Pointer to the output buffer
  2301. Return Value:
  2302. DOCUMENTEVENT_SUCCESS - success
  2303. DOCUMENTEVENT_UNSUPPORTED - iEsc is not supported
  2304. DOCUMENTEVENT_FAILURE - an error occured
  2305. NOTE:
  2306. DOCUMENTEVENT_CREATEDCPRE
  2307. input - pointer to a CREATEDCDATA structure
  2308. output - pointer to a devmode that's passed to DrvEnablePDEV
  2309. return value -
  2310. DOCUMENTEVENT_FAILURE causes CreateDC to fail and nothing else is called
  2311. DOCUMENTEVENT_CREATEDCPOST
  2312. hdc - NULL if if something failed since CREATEDCPRE
  2313. input - pointer to the devmode pointer returned by CREATEDCPRE
  2314. return value - ignored
  2315. DOCUMENTEVENT_RESETDCPRE
  2316. input - pointer to the input devmode passed to ResetDC
  2317. output - pointer to a devmode that's passed to the kernel driver
  2318. return value -
  2319. DOCUMENTEVENT_FAILURE causes ResetDC to fail
  2320. and CREATEDCPOST will not be called in that case
  2321. DOCUMENTEVENT_RESETDCPOST
  2322. return value - ignored
  2323. DOCUMENTEVENT_STARTDOCPRE
  2324. input - pointer to a DOCINFOW structure
  2325. return value -
  2326. DOCUMENTEVENT_FAILURE causes StartDoc to fail
  2327. and DrvStartDoc will not be called in this case
  2328. DOCUMENTEVENT_STARTDOCPOST
  2329. return value - ignored
  2330. DOCUMENTEVENT_STARTPAGE
  2331. return value -
  2332. DOCUMENTEVENT_FAILURE causes StartPage to fail
  2333. and DrvStartPage will not be called in this case
  2334. DOCUMENTEVENT_ENDPAGE
  2335. return value - ignored and DrvEndPage always called
  2336. DOCUMENTEVENT_ENDDOCPRE
  2337. return value - ignored and DrvEndDoc always called
  2338. DOCUMENTEVENT_ENDDOCPOST
  2339. return value - ignored
  2340. DOCUMENTEVENT_ABORTDOC
  2341. return value - ignored
  2342. DOCUMENTEVENT_DELETEDC
  2343. return value - ignored
  2344. DOCUMENTEVENT_ESCAPE
  2345. input - pointer to a ESCAPEDATA structure
  2346. cbOut, pjOut - cbOutput and lpszOutData parameters passed to ExtEscape
  2347. return value - ignored
  2348. DOCUMENTEVENT_SPOOLED
  2349. This flag bit is ORed with other iEsc values if the document is
  2350. spooled as metafile rather than printed directly to port.
  2351. --*/
  2352. {
  2353. PDOCEVENTUSERMEM pDocEventUserMem = NULL;
  2354. PDEVMODE pDevmode;
  2355. INT result = DOCUMENTEVENT_SUCCESS;
  2356. HANDLE hMutex;
  2357. Verbose(("Entering DrvDocumentEvent: %d...\n", iEsc));
  2358. //
  2359. // Metafile spooling on fax jobs is not currently supported
  2360. //
  2361. Assert((iEsc & DOCUMENTEVENT_SPOOLED) == 0);
  2362. //
  2363. // Check if the document event requires a device context
  2364. //
  2365. //
  2366. // Do not execute any code before this initialization
  2367. //
  2368. if(!InitializeDll())
  2369. {
  2370. return DOCUMENTEVENT_FAILURE;
  2371. }
  2372. if (DocEventRequiresDC(iEsc))
  2373. {
  2374. if (!hdc || !(pDocEventUserMem = GetPDEVUserMem(hdc)))
  2375. {
  2376. Error(("Invalid device context: hdc = %x, iEsc = %d\n", hdc, iEsc));
  2377. return DOCUMENTEVENT_FAILURE;
  2378. }
  2379. }
  2380. switch (iEsc)
  2381. {
  2382. case DOCUMENTEVENT_CREATEDCPRE:
  2383. Assert(cbIn >= sizeof(CREATEDCDATA) && pjIn && cbOut >= sizeof(PDEVMODE) && pjOut);
  2384. result = DocEventCreateDCPre(hPrinter, hdc, (PCREATEDCDATA) pjIn, (PDEVMODE *) pjOut);
  2385. break;
  2386. case DOCUMENTEVENT_CREATEDCPOST:
  2387. //
  2388. // Handle CREATEDCPOST document event:
  2389. // If CreateDC succeeded, then associate the user mode memory structure
  2390. // with the device context. Otherwise, free the user mode memory structure.
  2391. //
  2392. Assert(cbIn >= sizeof(PVOID) && pjIn);
  2393. pDevmode = *((PDEVMODE *) pjIn);
  2394. Assert(CurrentVersionDevmode(pDevmode));
  2395. pDocEventUserMem = ((PDRVDEVMODE) pDevmode)->dmPrivate.pUserMem;
  2396. Assert(ValidPDEVUserMem(pDocEventUserMem));
  2397. if (hdc)
  2398. {
  2399. pDocEventUserMem->hdc = hdc;
  2400. EnterDrvSem();
  2401. pDocEventUserMem->pNext = gDocEventUserMemList;
  2402. gDocEventUserMemList = pDocEventUserMem;
  2403. LeaveDrvSem();
  2404. }
  2405. else
  2406. {
  2407. FreePDEVUserMem(pDocEventUserMem);
  2408. }
  2409. break;
  2410. case DOCUMENTEVENT_RESETDCPRE:
  2411. Verbose(("Document event: RESETDCPRE\n"));
  2412. Assert(cbIn >= sizeof(PVOID) && pjIn && cbOut >= sizeof(PDEVMODE) && pjOut);
  2413. result = DocEventResetDCPre(hdc, pDocEventUserMem, *((PDEVMODE *) pjIn), (PDEVMODE *) pjOut);
  2414. break;
  2415. case DOCUMENTEVENT_STARTDOCPRE:
  2416. //
  2417. // normal case if we're bringing up the send wizard
  2418. //
  2419. //
  2420. // When direct printing is requested we don't even call DocEventStartDocPre().
  2421. // When direct printing is requested all the information required to print
  2422. // the job will be provided by the application. For example FaxStartPrintJob()
  2423. // uses direct printing. It provides the fax job parameters directly into
  2424. // JOB_INFO_2.pParameters on its own.
  2425. //
  2426. if (!pDocEventUserMem->directPrinting)
  2427. {
  2428. Assert(cbIn >= sizeof(PVOID) && pjIn);
  2429. //
  2430. // Check if the printing application is using DDE and did not create new process for printing
  2431. // If it so, the environment variable FAX_ENVVAR_PRINT_FILE was not found
  2432. //
  2433. hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, FAXXP_MEM_MUTEX_NAME);
  2434. if (hMutex)
  2435. {
  2436. if (WaitForSingleObject( hMutex, 1000 * 60 * 5) == WAIT_OBJECT_0)
  2437. {
  2438. HANDLE hSharedMem;
  2439. //
  2440. // we own the mutex...make sure we can open the shared memory region.
  2441. //
  2442. hSharedMem = OpenFileMapping(FILE_MAP_READ, FALSE, FAXXP_MEM_NAME);
  2443. if (NULL == hSharedMem)
  2444. {
  2445. Error(("OpenFileMapping failed error: %d\n", GetLastError()));
  2446. result = DOCUMENTEVENT_FAILURE;
  2447. }
  2448. else
  2449. {
  2450. //
  2451. // we own the mutex and we have the shared memory region open.
  2452. //
  2453. // check if we are printing to a file.
  2454. //
  2455. LPTSTR filename;
  2456. filename = (LPTSTR)MapViewOfFile(
  2457. hSharedMem,
  2458. FILE_MAP_READ,
  2459. 0,
  2460. 0,
  2461. 0
  2462. );
  2463. if (!filename || IsBadStringPtr(filename, MAX_PATH * 2))
  2464. {
  2465. //
  2466. // Never trust the shared memory region. It might get corrupted by a malicious user.
  2467. //
  2468. Error(("Failed to map a view of the file or pointer is bad: %d\n", hSharedMem));
  2469. result = DOCUMENTEVENT_FAILURE;
  2470. }
  2471. else
  2472. {
  2473. //
  2474. // check if this is really the filename we want to print to.
  2475. //
  2476. LPDOCINFO lpDocInfo = *((LPDOCINFO *)pjIn);
  2477. if (lpDocInfo->lpszDocName)
  2478. {
  2479. LPTSTR lptstrSubStr = NULL;
  2480. LPTSTR lptstrTmpInputFile = _tcschr(filename, TEXT('\0'));
  2481. Assert (lptstrTmpInputFile);
  2482. lptstrTmpInputFile = _tcsinc(lptstrTmpInputFile);
  2483. if (IsBadStringPtr(lptstrTmpInputFile, MAX_PATH * 2))
  2484. {
  2485. Error(("Corrupted shared memory buffer\n"));
  2486. result = DOCUMENTEVENT_FAILURE;
  2487. }
  2488. else
  2489. {
  2490. Assert (_tcsclen(lptstrTmpInputFile));
  2491. lptstrSubStr = _tcsstr(lpDocInfo->lpszDocName, lptstrTmpInputFile);
  2492. if (lptstrSubStr)
  2493. {
  2494. //
  2495. // We assume the shared memory was pointed to us
  2496. //
  2497. pDocEventUserMem->pPrintFile = DuplicateString(filename);
  2498. if (!pDocEventUserMem->pPrintFile)
  2499. {
  2500. Error(("Memory allocation failed\n"));
  2501. result = DOCUMENTEVENT_FAILURE;
  2502. }
  2503. else
  2504. {
  2505. //
  2506. // At last - every thing is OK, this is a direct printing from PrintRandomDocument
  2507. // to a application that is using DDE and an instance was already open.
  2508. //
  2509. pDocEventUserMem->directPrinting = TRUE;
  2510. pDocEventUserMem->bAttachment = TRUE;
  2511. }
  2512. }
  2513. }
  2514. }
  2515. else
  2516. {
  2517. //
  2518. // To handle the race conditions between two diffrent instances of the printer driver over the shared memory created by PrintRandomDocument().
  2519. // We are using now two mechanisms for detecting printing of an attachment using PrintRandomDocument().
  2520. // � First we check if an environment variable is set (Set by PrintRandomDocument()). If it is set the driver knows it is an attachment printing.
  2521. // � If it is not set, the driver looks for a mutex controlling a shred memory created by PrintRandomDocument(). If it does not exist it is a printing to the fax server.
  2522. // � If the shared memory exists, the driver compares the document name in the DOCINFO provided by StartDoc, and the input file name in the shared memory.
  2523. // � If there is a match, it is printing of an attachment, else it is a printing to the fax server
  2524. // There is still a hole in this implementation, if there is an open instance of the printing application, and the ShellExecuteEx does not create new process for printing, and the printing application does not set the lpszDocName in StartDoc to contain the input file name.
  2525. Warning (("No lpszDocName in DOCINFO - Could not verify the input file name in shared memory\n"));
  2526. }
  2527. UnmapViewOfFile( filename );
  2528. }
  2529. if (!CloseHandle( hSharedMem ))
  2530. {
  2531. Error(("CloseHandle() failed: %d.\n", GetLastError()));
  2532. // Try to continue...
  2533. }
  2534. }
  2535. ReleaseMutex( hMutex );
  2536. }
  2537. else
  2538. {
  2539. //
  2540. // Something went wrong with WaitForSingleObject
  2541. //
  2542. result = DOCUMENTEVENT_FAILURE;
  2543. }
  2544. if (!CloseHandle( hMutex ))
  2545. {
  2546. Error(("CloseHandle() failed: %d.\n", GetLastError()));
  2547. // Try to continue...
  2548. }
  2549. }
  2550. }
  2551. //
  2552. // Check again for direct printing
  2553. //
  2554. if (!pDocEventUserMem->directPrinting)
  2555. {
  2556. //
  2557. // client 'point and print' setup
  2558. //
  2559. if (FaxPointAndPrintSetup(pDocEventUserMem->lptstrPrinterName,FALSE, g_hModule))
  2560. {
  2561. Verbose(("FaxPointAndPrintSetup succeeded\n"));
  2562. }
  2563. else
  2564. {
  2565. Error(("FaxPointAndPrintSetup failed: %d\n", GetLastError()));
  2566. }
  2567. result = DocEventStartDocPre(hdc, pDocEventUserMem, *((LPDOCINFO *) pjIn));
  2568. }
  2569. else
  2570. {
  2571. //
  2572. // we're doing direct printing -- check if this is an attachment
  2573. //
  2574. pDocEventUserMem->jobType = JOBTYPE_DIRECT;
  2575. if (TRUE == pDocEventUserMem->bAttachment)
  2576. {
  2577. (*((LPDOCINFO *) pjIn))->lpszOutput = pDocEventUserMem->pPrintFile;
  2578. }
  2579. }
  2580. break;
  2581. case DOCUMENTEVENT_STARTDOCPOST:
  2582. if (!pDocEventUserMem->directPrinting && pDocEventUserMem->jobType == JOBTYPE_NORMAL)
  2583. {
  2584. //
  2585. // Job ID is passed in from GDI
  2586. //
  2587. //
  2588. // Save the job id returned from StartDoc. This is the job id of the body.
  2589. // Pause the body job so we can attach cover page jobs to it before it starts
  2590. // executing.
  2591. //
  2592. Assert(cbIn >= sizeof(DWORD) && pjIn);
  2593. pDocEventUserMem->jobId = *((LPDWORD) pjIn);
  2594. //
  2595. // Tell spooler to pause the fax body job so that
  2596. // we can associate cover pages with it later
  2597. //
  2598. if (! SetJob(pDocEventUserMem->hPrinter, pDocEventUserMem->jobId, 0, NULL, JOB_CONTROL_PAUSE))
  2599. {
  2600. Error(("Couldn't pause fax body job: %d\n", pDocEventUserMem->jobId));
  2601. return DOCUMENTEVENT_FAILURE;
  2602. }
  2603. }
  2604. break;
  2605. case DOCUMENTEVENT_STARTPAGE:
  2606. if (! pDocEventUserMem->directPrinting)
  2607. {
  2608. //
  2609. // Get PREVIOUS preview page (this event is called BEFORE the graphics dll recieved
  2610. // the DrvSendPage() call for this page, so we actually get the previous page).
  2611. //
  2612. // NOTE: This event is recieved before the graphics dll recieves its DrvStartPage()
  2613. // call where it increments the page count and resets the mapping surface. The first
  2614. // time we get this event there is no actual page but we perform validity checking.
  2615. //
  2616. if (pDocEventUserMem->bShowPrintPreview && !pDocEventUserMem->bPreviewAborted)
  2617. {
  2618. if (!AppendPreviewPage(pDocEventUserMem))
  2619. {
  2620. Error(("AppendPreviewPage() failed.\n"));
  2621. Assert(pDocEventUserMem->bPreviewAborted);
  2622. // We can continue with no print preview...
  2623. }
  2624. }
  2625. }
  2626. break;
  2627. case DOCUMENTEVENT_ENDPAGE:
  2628. if (! pDocEventUserMem->directPrinting)
  2629. {
  2630. pDocEventUserMem->pageCount++;
  2631. }
  2632. break;
  2633. case DOCUMENTEVENT_ENDDOCPOST:
  2634. if (!pDocEventUserMem->directPrinting)
  2635. {
  2636. //
  2637. // Get the last preview page
  2638. //
  2639. if (pDocEventUserMem->bShowPrintPreview && !pDocEventUserMem->bPreviewAborted)
  2640. {
  2641. if (!AppendPreviewPage(pDocEventUserMem))
  2642. {
  2643. Error(("AppendPreviewPage() failed.\n"));
  2644. Assert(pDocEventUserMem->bPreviewAborted);
  2645. // We can continue with no print preview...
  2646. }
  2647. }
  2648. //
  2649. // Close the preview file
  2650. //
  2651. if (INVALID_HANDLE_VALUE != pDocEventUserMem->hPreviewFile)
  2652. {
  2653. if (!CloseHandle(pDocEventUserMem->hPreviewFile))
  2654. {
  2655. Error(("CloseHandle() failed: %d.\n", GetLastError()));
  2656. // Try to continue...
  2657. }
  2658. pDocEventUserMem->hPreviewFile = INVALID_HANDLE_VALUE;
  2659. }
  2660. //
  2661. // Call the handler
  2662. //
  2663. result = DocEventEndDocPost(hdc, pDocEventUserMem);
  2664. //
  2665. // If we created a preview file, delete it.
  2666. //
  2667. if (pDocEventUserMem->szPreviewFile[0] != TEXT('\0'))
  2668. {
  2669. if (!DeleteFile(pDocEventUserMem->szPreviewFile))
  2670. {
  2671. Error(("DeleteFile() failed. Error code: %d.\n", GetLastError()));
  2672. }
  2673. pDocEventUserMem->szPreviewFile[0] = TEXT('\0');
  2674. }
  2675. }
  2676. if (TRUE == pDocEventUserMem->bAttachment)
  2677. {
  2678. HANDLE hEndDocEvent;
  2679. LPTSTR szEndDocEventName= NULL;
  2680. LPTSTR lptstrEventName = NULL;
  2681. Assert (pDocEventUserMem->pPrintFile);
  2682. //
  2683. // Create the EndDoc event name
  2684. //
  2685. szEndDocEventName = (LPTSTR) MemAlloc( SizeOfString(pDocEventUserMem->pPrintFile) + SizeOfString(FAXXP_ATTACH_END_DOC_EVENT) );
  2686. if (szEndDocEventName)
  2687. {
  2688. _tcscpy (szEndDocEventName, pDocEventUserMem->pPrintFile);
  2689. _tcscat (szEndDocEventName, FAXXP_ATTACH_END_DOC_EVENT);
  2690. lptstrEventName = _tcsrchr(szEndDocEventName, TEXT('\\'));
  2691. Assert (lptstrEventName);
  2692. lptstrEventName = _tcsinc(lptstrEventName);
  2693. //
  2694. // Send event to the printing application (PrintRandomDocument() that file is ready)
  2695. //
  2696. hEndDocEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, lptstrEventName);
  2697. if (NULL == hEndDocEvent)
  2698. {
  2699. Error(("OpenEvent() failed. Error code: %d.\n", GetLastError()));
  2700. result = DOCUMENTEVENT_FAILURE;
  2701. }
  2702. else
  2703. {
  2704. if (!SetEvent( hEndDocEvent ))
  2705. {
  2706. Error(("SetEvent() failed. Error code: %d.\n", GetLastError()));
  2707. result = DOCUMENTEVENT_FAILURE;
  2708. }
  2709. if (!CloseHandle(hEndDocEvent))
  2710. {
  2711. Error(("CloseHandle() failed: %d.\n", GetLastError()));
  2712. // Try to continue...
  2713. }
  2714. }
  2715. MemFree(szEndDocEventName);
  2716. }
  2717. else
  2718. {
  2719. Error(("Memory allocation for szEndDocEventName failed.\n"));
  2720. result = DOCUMENTEVENT_FAILURE;
  2721. }
  2722. }
  2723. break;
  2724. case DOCUMENTEVENT_DELETEDC:
  2725. EnterDrvSem();
  2726. if (pDocEventUserMem == gDocEventUserMemList)
  2727. {
  2728. gDocEventUserMemList = gDocEventUserMemList->pNext;
  2729. }
  2730. else
  2731. {
  2732. PDOCEVENTUSERMEM p;
  2733. if (p = gDocEventUserMemList)
  2734. {
  2735. while (p->pNext && p->pNext != pDocEventUserMem)
  2736. {
  2737. p = p->pNext;
  2738. }
  2739. if (p->pNext != NULL)
  2740. {
  2741. p->pNext = pDocEventUserMem->pNext;
  2742. }
  2743. else
  2744. {
  2745. Error(("Orphaned user mode memory structure!!!\n"));
  2746. }
  2747. }
  2748. else
  2749. {
  2750. Error(("gDocEventUserMemList shouldn't be NULL!!!\n"));
  2751. }
  2752. }
  2753. LeaveDrvSem();
  2754. FreePDEVUserMem(pDocEventUserMem);
  2755. break;
  2756. case DOCUMENTEVENT_ABORTDOC:
  2757. if (TRUE == pDocEventUserMem->bAttachment)
  2758. {
  2759. //
  2760. // Send event to the printing application (PrintRandomDocument() that printing was aborted)
  2761. //
  2762. HANDLE hAbortEvent;
  2763. TCHAR szAbortEventName[FAXXP_ATTACH_EVENT_NAME_LEN] = {0};
  2764. LPTSTR lptstrEventName = NULL;
  2765. Assert (pDocEventUserMem->pPrintFile);
  2766. //
  2767. // Create the Abort event name
  2768. //
  2769. _tcscpy (szAbortEventName, pDocEventUserMem->pPrintFile);
  2770. _tcscat (szAbortEventName, FAXXP_ATTACH_ABORT_EVENT);
  2771. lptstrEventName = _tcsrchr(szAbortEventName, TEXT('\\'));
  2772. Assert (lptstrEventName);
  2773. lptstrEventName = _tcsinc(lptstrEventName);
  2774. hAbortEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, lptstrEventName);
  2775. if (NULL == hAbortEvent)
  2776. {
  2777. Error(("OpenEvent() failed. Error code: %d.\n", GetLastError()));
  2778. result = DOCUMENTEVENT_FAILURE;
  2779. }
  2780. else
  2781. {
  2782. if (!SetEvent( hAbortEvent ))
  2783. {
  2784. Error(("SetEvent() failed. Error code: %d.\n", GetLastError()));
  2785. result = DOCUMENTEVENT_FAILURE;
  2786. }
  2787. if (!CloseHandle(hAbortEvent))
  2788. {
  2789. Error(("CloseHandle() failed: %d.\n", GetLastError()));
  2790. // Try to continue...
  2791. }
  2792. }
  2793. }
  2794. break;
  2795. case DOCUMENTEVENT_RESETDCPOST:
  2796. case DOCUMENTEVENT_ENDDOCPRE:
  2797. break;
  2798. case DOCUMENTEVENT_ESCAPE:
  2799. default:
  2800. Verbose(("Unsupported DrvDocumentEvent escape: %d\n", iEsc));
  2801. result = DOCUMENTEVENT_UNSUPPORTED;
  2802. break;
  2803. }
  2804. return result;
  2805. } // DrvDocumentEvent
  2806. /*
  2807. Function:
  2808. ShowReentrancyMessage
  2809. Purpose:
  2810. The code of FxsWzrd.dll is not re-entrant.
  2811. We prevent its running from different threads inside one process.
  2812. We want to notify user about this.
  2813. Return Value:
  2814. ERROR_SUCCESS -- success
  2815. Win32 Error Code -- failure
  2816. Author:
  2817. Iv Vakaluk (IvG) 2-Sept-2002
  2818. */
  2819. DWORD ShowReentrancyMessage(void)
  2820. {
  2821. DWORD dwRes = ERROR_SUCCESS;
  2822. TCHAR szTitle[MAX_PATH] = {0};
  2823. TCHAR szText[MAX_PATH] = {0};
  2824. Verbose(("Entering ShowReentrancyMessage()\n"));
  2825. //
  2826. // Load Title
  2827. //
  2828. if (!LoadString(g_hResource, IDS_REENTRANCY_TITLE, szTitle, sizeof(szTitle)/sizeof(TCHAR)))
  2829. {
  2830. dwRes = GetLastError();
  2831. Error(("LoadString(IDS_REENTRANCY_TITLE) failed: %d.\n", dwRes));
  2832. return dwRes;
  2833. }
  2834. //
  2835. // Load Message title
  2836. //
  2837. if (!LoadString(g_hResource, IDS_REENTRANCY_TEXT, szText, sizeof(szText)/sizeof(TCHAR)))
  2838. {
  2839. dwRes = GetLastError();
  2840. Error(("LoadString(IDS_REENTRANCY_TEXT) failed: %d.\n", dwRes));
  2841. return dwRes;
  2842. }
  2843. if (!AlignedMessageBox(NULL, szText, szTitle, MB_OK))
  2844. {
  2845. dwRes = GetLastError();
  2846. Error(("MessageBox() failed: %d.\n", dwRes));
  2847. return dwRes;
  2848. }
  2849. return dwRes;
  2850. }