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.

2918 lines
79 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: spool.cxx
  3. *
  4. * Created: 21-Feb-1995 10:13:18
  5. * Author: Eric Kutter [erick]
  6. *
  7. * Copyright (c) 1993-1999 Microsoft Corporation
  8. *
  9. \**************************************************************************/
  10. #include "precomp.hxx"
  11. DWORD DriverInfo1Offsets[]={offsetof(DRIVER_INFO_1W, pName),
  12. 0xFFFFFFFF};
  13. DWORD DriverInfo2Offsets[]={offsetof(DRIVER_INFO_2W, pName),
  14. offsetof(DRIVER_INFO_2W, pEnvironment),
  15. offsetof(DRIVER_INFO_2W, pDriverPath),
  16. offsetof(DRIVER_INFO_2W, pDataFile),
  17. offsetof(DRIVER_INFO_2W, pConfigFile),
  18. 0xFFFFFFFF};
  19. DWORD DriverInfo3Offsets[]={offsetof(DRIVER_INFO_3W, pName),
  20. offsetof(DRIVER_INFO_3W, pEnvironment),
  21. offsetof(DRIVER_INFO_3W, pDriverPath),
  22. offsetof(DRIVER_INFO_3W, pDataFile),
  23. offsetof(DRIVER_INFO_3W, pConfigFile),
  24. offsetof(DRIVER_INFO_3W, pHelpFile),
  25. offsetof(DRIVER_INFO_3W, pDependentFiles),
  26. offsetof(DRIVER_INFO_3W, pMonitorName),
  27. offsetof(DRIVER_INFO_3W, pDefaultDataType),
  28. 0xFFFFFFFF};
  29. DWORD DriverInfo1Strings[]={offsetof(DRIVER_INFO_1W, pName),
  30. 0xFFFFFFFF};
  31. DWORD DriverInfo2Strings[]={offsetof(DRIVER_INFO_2W, pName),
  32. offsetof(DRIVER_INFO_2W, pEnvironment),
  33. offsetof(DRIVER_INFO_2W, pDriverPath),
  34. offsetof(DRIVER_INFO_2W, pDataFile),
  35. offsetof(DRIVER_INFO_2W, pConfigFile),
  36. 0xFFFFFFFF};
  37. DWORD DriverInfo3Strings[]={offsetof(DRIVER_INFO_3W, pName),
  38. offsetof(DRIVER_INFO_3W, pEnvironment),
  39. offsetof(DRIVER_INFO_3W, pDriverPath),
  40. offsetof(DRIVER_INFO_3W, pDataFile),
  41. offsetof(DRIVER_INFO_3W, pConfigFile),
  42. offsetof(DRIVER_INFO_3W, pHelpFile),
  43. offsetof(DRIVER_INFO_3W, pMonitorName),
  44. offsetof(DRIVER_INFO_3W, pDefaultDataType),
  45. 0xFFFFFFFF};
  46. DWORD FormInfo1Offsets[] = { offsetof(FORM_INFO_1W, pName),
  47. 0xFFFFFFFF};
  48. DWORD PrinterInfo1Offsets[]={offsetof(PRINTER_INFO_1W, pDescription),
  49. offsetof(PRINTER_INFO_1W, pName),
  50. offsetof(PRINTER_INFO_1W, pComment),
  51. 0xFFFFFFFF};
  52. DWORD PrinterInfo2Offsets[]={offsetof(PRINTER_INFO_2W, pServerName),
  53. offsetof(PRINTER_INFO_2W, pPrinterName),
  54. offsetof(PRINTER_INFO_2W, pShareName),
  55. offsetof(PRINTER_INFO_2W, pPortName),
  56. offsetof(PRINTER_INFO_2W, pDriverName),
  57. offsetof(PRINTER_INFO_2W, pComment),
  58. offsetof(PRINTER_INFO_2W, pLocation),
  59. offsetof(PRINTER_INFO_2W, pDevMode),
  60. offsetof(PRINTER_INFO_2W, pSepFile),
  61. offsetof(PRINTER_INFO_2W, pPrintProcessor),
  62. offsetof(PRINTER_INFO_2W, pDatatype),
  63. offsetof(PRINTER_INFO_2W, pParameters),
  64. offsetof(PRINTER_INFO_2W, pSecurityDescriptor),
  65. 0xFFFFFFFF};
  66. DWORD PrinterInfo3Offsets[]={offsetof(PRINTER_INFO_3, pSecurityDescriptor),
  67. 0xFFFFFFFF};
  68. DWORD PrinterInfo4Offsets[]={offsetof(PRINTER_INFO_4W, pPrinterName),
  69. offsetof(PRINTER_INFO_4W, pServerName),
  70. 0xFFFFFFFF};
  71. DWORD PrinterInfo5Offsets[]={offsetof(PRINTER_INFO_5W, pPrinterName),
  72. offsetof(PRINTER_INFO_5W, pPortName),
  73. 0xFFFFFFFF};
  74. /*********************************Class************************************\
  75. * SPOOLMSG
  76. *
  77. * structure containg a message waiting to be grabbed by a spooler thread.
  78. * This is a private structure to communicate between the applications thread
  79. * and the spoolers thread
  80. *
  81. * History:
  82. * 27-Mar-1995 -by- Eric Kutter [erick]
  83. * Wrote it.
  84. \**************************************************************************/
  85. #define SPOOLMSG_DELETE_INBUF 0x00000002
  86. #define SPOOLMSG_MAXINPUT_BUF 4
  87. #define NO_CLIENT 1
  88. #define NON_SPOOL_INSTANCE ((DWORD) -1)
  89. #define MIN_DEVMODE_SIZE 72 // Win 3.1 DevMode size. Also hard-coded in yspool
  90. typedef struct _SPOOLMSG
  91. {
  92. ULONG cj;
  93. ULONG iMsg;
  94. ULONG fl;
  95. HSPOOLOBJ hso;
  96. PETHREAD pthreadClient;
  97. SECURITY_CLIENT_CONTEXT sccSecurity;
  98. // in order to avoid extra copying into a single buffer, there are multiple
  99. // input buffers. For example, WritePrinter uses a header buffer on the
  100. // stack with a second buffer containing the output data.
  101. ULONG cjIn; // combined size of input buffers
  102. ULONG cBuf; // number of input buffers
  103. PULONG apulIn[SPOOLMSG_MAXINPUT_BUF];// input buffers
  104. ULONG acjIn[SPOOLMSG_MAXINPUT_BUF];
  105. PULONG pulOut; // location to put output data
  106. ULONG cjOut; // size of output
  107. ULONG ulRet; // return value
  108. ULONG ulErr; // transfer last error from spooler thread to client
  109. struct _SPOOLMSG *pNext;
  110. } SPOOLMSG, *PSPOOLMSG;
  111. /*********************************Class************************************\
  112. * SPOOLOBJ : public OBJECT
  113. *
  114. * a SPOOLOBJ is GDI's internal spooler object containing data need to access
  115. * the spooler for a particular print job.
  116. *
  117. * Public Interface:
  118. *
  119. * History:
  120. * 21-Jun-1995 -by- Eric Kutter [erick]
  121. * Wrote it.
  122. \**************************************************************************/
  123. class SPOOLOBJ : public OBJECT
  124. {
  125. public:
  126. KEVENT *pkevent;
  127. HANDLE hSpool;
  128. PVOID pvMsg;
  129. SPOOLMSG sm;
  130. DWORD dwFlags;
  131. DWORD dwSpoolInstance;
  132. GREWRITEPRINTER WritePrinter;
  133. DWORD dwWritePrinterReturn;
  134. };
  135. typedef SPOOLOBJ *PSPOOLOBJ;
  136. /**************************************************************************\
  137. *
  138. \**************************************************************************/
  139. BOOL gbInitSpool = FALSE; // set/cleared as the spooler comes and goes
  140. PW32PROCESS gpidSpool = 0; // process ID of the spooler
  141. PEPROCESS gpeSpool = 0; // process pointer of the spooler
  142. PKEVENT gpeventGdiSpool; // spooler lock
  143. PKEVENT gpeventSpoolerTermination; // signals spooler termination so client threads in spooler process can exit
  144. DWORD gdwSpoolInstance = 0; // Keeps track of the spooler instance
  145. LONG gpInfiniteWait = TRUE; // LONG used to ensure we have one spooler thread waiting with INFINITE timeoue
  146. // there is a queue of spool messages. Elements are removed from the head
  147. // and added to the tail
  148. PSPOOLMSG gpsmSpoolHead = NULL;
  149. PSPOOLMSG gpsmSpoolTail = NULL;
  150. int gcSpoolMsg = 0;
  151. int gcSpoolMsgCurrent = 0;
  152. int gcSpoolMsgMax = 0;
  153. #define LOCKSPOOLER GreAcquireSemaphore(ghsemGdiSpool)
  154. #define UNLOCKSPOOLER GreReleaseSemaphore(ghsemGdiSpool)
  155. #define POFFSET(pBase,pCur) ((PBYTE)(pCur) - (PBYTE)(pBase))
  156. /*********************************Class************************************\
  157. * class SPOOLREF
  158. *
  159. * Public Interface:
  160. *
  161. * History:
  162. * 22-May-1995 -by- Eric Kutter [erick]
  163. * Wrote it.
  164. \**************************************************************************/
  165. class SPOOLREF
  166. {
  167. public:
  168. PSPOOLOBJ pso;
  169. SPOOLREF() {}
  170. SPOOLREF(HANDLE hspool)
  171. {
  172. pso = (PSPOOLOBJ)HmgLock((HOBJ)hspool,SPOOL_TYPE);
  173. }
  174. ~SPOOLREF()
  175. {
  176. if (bValid())
  177. {
  178. DEC_EXCLUSIVE_REF_CNT(pso);
  179. pso = NULL;
  180. }
  181. }
  182. BOOL bDelete();
  183. BOOL GreEscapeSpool();
  184. BOOL bValid() {return(pso != NULL); }
  185. HSPOOLOBJ hGet() {return((HSPOOLOBJ)pso->hGet());}
  186. PSPOOLMSG psm() {return(&pso->sm); }
  187. // we need to know the lock count for cleanup so we don't free up a message
  188. // when it still may be accessed.
  189. ULONG cAltLock()
  190. {
  191. return(((POBJ) (pso))->ulShareCount);
  192. }
  193. };
  194. class SPOOLALTREF : public SPOOLREF
  195. {
  196. public:
  197. SPOOLALTREF(HANDLE hspool)
  198. {
  199. pso = (PSPOOLOBJ)HmgShareLock((HOBJ)hspool,SPOOL_TYPE);
  200. }
  201. ~SPOOLALTREF()
  202. {
  203. if (bValid())
  204. {
  205. DEC_SHARE_REF_CNT(pso);
  206. pso = NULL;
  207. }
  208. }
  209. };
  210. typedef SPOOLALTREF *PSPOOLALTREF;
  211. class SPOOLMEMOBJ : public SPOOLREF
  212. {
  213. public:
  214. SPOOLMEMOBJ();
  215. ~SPOOLMEMOBJ() {}
  216. };
  217. ULONG
  218. ulFinishMessage(
  219. PSPOOLMSG psm,
  220. PSPOOLESC psesc,
  221. PSPOOLALTREF sr,
  222. PBYTE pjEscData,
  223. ULONG cjEscData
  224. );
  225. BOOL AddMessage2Q(
  226. PSPOOLMSG psm,
  227. DWORD dwSpoolInstance
  228. );
  229. VOID SubtractMessageFromQ(PSPOOLMSG psmIn);
  230. /******************************Public*Routine******************************\
  231. *
  232. *
  233. * History:
  234. * 22-May-1995 -by- Eric Kutter [erick]
  235. * Wrote it.
  236. \**************************************************************************/
  237. SPOOLMEMOBJ::SPOOLMEMOBJ()
  238. {
  239. KEVENT *pkevent = (PKEVENT) GdiAllocPoolNonPagedNS(
  240. sizeof(KEVENT), 'lpsG');
  241. if (pkevent == NULL)
  242. {
  243. pso = NULL;
  244. }
  245. else
  246. {
  247. pso = (PSPOOLOBJ)HmgAlloc(sizeof(SPOOLOBJ),SPOOL_TYPE, HMGR_ALLOC_LOCK);
  248. if (bValid())
  249. {
  250. LOCKSPOOLER;
  251. pso->dwSpoolInstance = gdwSpoolInstance;
  252. UNLOCKSPOOLER;
  253. pso->pkevent = pkevent;
  254. KeInitializeEvent(
  255. pso->pkevent,
  256. SynchronizationEvent,
  257. FALSE);
  258. }
  259. else
  260. {
  261. VFREEMEM(pkevent);
  262. }
  263. }
  264. }
  265. /******************************Public*Routine******************************\
  266. *
  267. *
  268. * History:
  269. * 22-May-1995 -by- Eric Kutter [erick]
  270. * Wrote it.
  271. \**************************************************************************/
  272. BOOL SPOOLREF::bDelete()
  273. {
  274. if (bValid())
  275. {
  276. VFREEMEM(pso->pkevent);
  277. HmgFree((HOBJ)hGet());
  278. pso = NULL;
  279. }
  280. return(TRUE);
  281. }
  282. /******************************Public*Routine******************************\
  283. * bIsProcessLocalSystem()
  284. *
  285. * History:
  286. * 19-Jun-2001 -by- Barton House [bhouse]
  287. * Wrote it.
  288. \**************************************************************************/
  289. static BOOL bIsProcessLocalSystem(void)
  290. {
  291. BOOL bResult = FALSE;
  292. PEPROCESS peprocess;
  293. PACCESS_TOKEN paccessToken;
  294. NTSTATUS status;
  295. PTOKEN_USER ptu;
  296. peprocess = PsGetCurrentProcess();
  297. paccessToken = PsReferencePrimaryToken(peprocess);
  298. status = SeQueryInformationToken(paccessToken, TokenUser, (PVOID *) &ptu);
  299. PsDereferencePrimaryToken(paccessToken);
  300. if (NT_SUCCESS(status) == TRUE)
  301. {
  302. bResult = RtlEqualSid(SeExports->SeLocalSystemSid, ptu->User.Sid);
  303. ExFreePool(ptu);
  304. }
  305. return bResult;
  306. }
  307. /******************************Public*Routine******************************\
  308. * GreInitSpool()
  309. *
  310. * History:
  311. * 21-Feb-1995 -by- Eric Kutter [erick]
  312. * Wrote it.
  313. \**************************************************************************/
  314. BOOL NtGdiInitSpool()
  315. {
  316. BOOL bRet = FALSE;
  317. LOCKSPOOLER;
  318. if (gbInitSpool)
  319. {
  320. EngSetLastError(ERROR_INVALID_ACCESS);
  321. WARNING("GreInitSpool - already called\n");
  322. }
  323. else if(!bIsProcessLocalSystem())
  324. {
  325. EngSetLastError(ERROR_INVALID_ACCESS);
  326. WARNING("GreInitSpool - caller is not system\n");
  327. }
  328. else
  329. {
  330. NTSTATUS status;
  331. // intialize the spooler events
  332. gpeventGdiSpool = (PKEVENT) GdiAllocPoolNonPagedNS(
  333. sizeof(KEVENT), 'gdis');
  334. gpeventSpoolerTermination = (PKEVENT) GdiAllocPoolNonPagedNS(
  335. sizeof(KEVENT), 'gdis');
  336. if (gpeventGdiSpool && gpeventSpoolerTermination)
  337. {
  338. KeInitializeEvent(
  339. gpeventGdiSpool,
  340. SynchronizationEvent,
  341. FALSE);
  342. KeInitializeEvent(
  343. gpeventSpoolerTermination,
  344. NotificationEvent,
  345. FALSE);
  346. gbInitSpool = TRUE;
  347. bRet = TRUE;
  348. gpeSpool = PsGetCurrentProcess();
  349. }
  350. else
  351. {
  352. EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
  353. if (gpeventGdiSpool)
  354. {
  355. VFREEMEM(gpeventGdiSpool);
  356. gpeventGdiSpool = NULL;
  357. }
  358. if (gpeventSpoolerTermination)
  359. {
  360. VFREEMEM(gpeventSpoolerTermination);
  361. gpeventSpoolerTermination = NULL;
  362. }
  363. }
  364. gpidSpool = W32GetCurrentProcess();
  365. if (++gdwSpoolInstance == NON_SPOOL_INSTANCE)
  366. ++gdwSpoolInstance;
  367. }
  368. UNLOCKSPOOLER;
  369. return(bRet);
  370. }
  371. /******************************Public*Routine******************************\
  372. *
  373. *
  374. * History:
  375. * 01-Jun-1995 -by- Eric Kutter [erick]
  376. * Wrote it.
  377. \**************************************************************************/
  378. VOID vCleanupSpool()
  379. {
  380. if (gpidSpool == W32GetCurrentProcess())
  381. {
  382. //DbgPrint("vCleanupSpool() - cleaning up the spooler process\n");
  383. LOCKSPOOLER;
  384. if (gbInitSpool == TRUE)
  385. {
  386. while (gpsmSpoolHead != NULL)
  387. {
  388. //DbgPrint("vCleanupSpool() - got another\n");
  389. PSPOOLMSG psm = gpsmSpoolHead;
  390. gpsmSpoolHead = psm->pNext;
  391. // and some stats
  392. ASSERTGDI(gcSpoolMsgCurrent > 0, "GreGetSpoolMsg - invalid count\n");
  393. gcSpoolMsgCurrent--;
  394. SPOOLALTREF sr(psm->hso);
  395. if (sr.bValid())
  396. {
  397. KeSetEvent(sr.pso->pkevent,0,FALSE);
  398. }
  399. }
  400. gpsmSpoolTail = NULL;
  401. VFREEMEM(gpeventGdiSpool);
  402. VFREEMEM(gpeventSpoolerTermination);
  403. gpeventGdiSpool = NULL;
  404. gpeventSpoolerTermination = NULL;
  405. gbInitSpool = FALSE;
  406. gpeSpool = NULL;
  407. gcSpoolMsg = 0;
  408. gcSpoolMsgCurrent = 0;
  409. gcSpoolMsgMax = 0;
  410. gpidSpool = NULL;
  411. //DbgPrint("Done cleaning up spooler for this thread\n");
  412. }
  413. UNLOCKSPOOLER;
  414. }
  415. }
  416. /******************************Public*Routine******************************\
  417. * GreGetSpoolMessage()
  418. *
  419. * This is intended to be called from the spooler process (GdiGetSpoolMessage)
  420. * to get the next spooler message out of the kernel.
  421. *
  422. *
  423. * if (output buffer exists)
  424. * copy out output buffer
  425. *
  426. * wait for next message
  427. *
  428. * copy in input buffer
  429. *
  430. * input:
  431. *
  432. * psesc - buffer to place message
  433. * cjmsg - size of message buffer
  434. * pulOut - buffer containing data to be copied to output buffer
  435. * cjOut - size of output buffer
  436. *
  437. *
  438. * returns:
  439. *
  440. * size of data placed in psesc.
  441. *
  442. *
  443. * Note: the output buffer is filled by the calling routine before calling
  444. * this function again.
  445. *
  446. * History:
  447. * 21-Feb-1995 -by- Eric Kutter [erick]
  448. *
  449. * 6-Aug-1995 - Added Input buffer growing (Steve Wilson [swilson])
  450. *
  451. * Wrote it.
  452. \**************************************************************************/
  453. SECURITY_QUALITY_OF_SERVICE Sqos =
  454. {
  455. sizeof(SECURITY_QUALITY_OF_SERVICE),
  456. SecurityImpersonation,
  457. SECURITY_DYNAMIC_TRACKING,
  458. FALSE
  459. };
  460. ULONG GreGetSpoolMessage(
  461. PSPOOLESC psesc,
  462. PBYTE pjEscData, // this must only be accessed under a try/except
  463. ULONG cjEscData,
  464. PULONG pulOut,
  465. ULONG cjOut
  466. )
  467. {
  468. ULONG ulRet = 0;
  469. NTSTATUS status;
  470. LONG lState;
  471. //DbgPrint("Entered GreGetSpoolMessage\n");
  472. if (!gbInitSpool)
  473. {
  474. WARNING("GreGetSpoolMessage - not initialized\n");
  475. }
  476. else if (gpidSpool != W32GetCurrentProcess())
  477. {
  478. WARNING("GreGetSpoolMessage - called from non-spooler process\n");
  479. }
  480. else
  481. {
  482. KEVENT *pkevent = NULL;
  483. // see if we need to copy any data out
  484. if (psesc->hso)
  485. {
  486. SPOOLALTREF sr(psesc->hso);
  487. if (sr.bValid())
  488. {
  489. // we have found the spool obj. Now see if we really have
  490. // an output buffer and need to copy anything.
  491. PSPOOLMSG psm = (PSPOOLMSG)sr.pso->pvMsg;
  492. // if we asked the spooler to grow the buffer and it succeeded
  493. // finish copying the message and return. If it failed, we still
  494. // need to cleanup this message and release the thread.
  495. if (psesc->iMsg == GDISPOOL_INPUT2SMALL)
  496. {
  497. if (psesc->ulRet && psm)
  498. {
  499. return(ulFinishMessage(psm, psesc, &sr, pjEscData, cjEscData));
  500. }
  501. pulOut = NULL;
  502. psesc->ulRet = 0;
  503. }
  504. // if we actualy have a message, we need to copy out the data
  505. // if there is any and remember the event in order to let the
  506. // client continue.
  507. if (psm)
  508. {
  509. // if we are still impersonating the client, undo it
  510. if (psm->pthreadClient)
  511. {
  512. SeStopImpersonatingClient();
  513. SeDeleteClientSecurity(&psm->sccSecurity);
  514. psm->pthreadClient = NULL;
  515. }
  516. // see if we have anything to copy out
  517. if (pulOut && psm->pulOut)
  518. {
  519. if (cjOut > psm->cjOut)
  520. cjOut = psm->cjOut;
  521. __try
  522. {
  523. // this is the only place that pulOut is validated
  524. ProbeForRead(pulOut,cjOut,sizeof(ULONG));
  525. RtlCopyMemory(psm->pulOut,pulOut,cjOut);
  526. psm->cjOut = cjOut;
  527. }
  528. __except(EXCEPTION_EXECUTE_HANDLER)
  529. {
  530. psm->cjOut = 0;
  531. }
  532. }
  533. else
  534. {
  535. psm->cjOut = 0;
  536. }
  537. psm->ulRet = psesc->ulRet;
  538. psm->ulErr = EngGetLastError();
  539. // Since to have output the message must have been synchronous,
  540. // we need to let the other thread go now.
  541. pkevent = sr.pso->pkevent;
  542. }
  543. // the spool obj is now done with this message
  544. sr.pso->pvMsg = NULL;
  545. }
  546. else
  547. {
  548. WARNING("GreGetSpoolMessage - hso but no pso\n");
  549. }
  550. }
  551. // the release of the other thread needs to be done once the SPOOLOBJ has
  552. // been unlocked.
  553. if (pkevent)
  554. {
  555. lState = KeSetEvent(pkevent,0,FALSE);
  556. ASSERTGDI(lState == 0,"GreGetSpoolMessage - lState not 0, a\n");
  557. }
  558. // done with the last message. Wait for the next message.
  559. PSPOOLMSG psm = NULL;
  560. BOOL bDone;
  561. LARGE_INTEGER Timeout;
  562. // 600/(100*10(-9)) : negative value is interval, positive is absolute
  563. Timeout.QuadPart = (LONGLONG) -6000000000; // Timeout is in 100 nsec, so 6,000,000,000 == 10 min
  564. do
  565. {
  566. BOOL bGrabIt = TRUE;
  567. bDone = TRUE;
  568. if (gpsmSpoolHead == NULL)
  569. {
  570. LONG bInfiniteWait = InterlockedExchange(&gpInfiniteWait, FALSE);
  571. //DbgPrint("\nGDISPOOL(%lx): waiting for message\n",psesc);
  572. status = KeWaitForSingleObject(
  573. gpeventGdiSpool,
  574. (KWAIT_REASON)WrExecutive,
  575. UserMode,
  576. FALSE,
  577. (bInfiniteWait ? NULL : &Timeout));
  578. if(bInfiniteWait)
  579. InterlockedExchange(&gpInfiniteWait, TRUE);
  580. if (status == STATUS_TIMEOUT)
  581. {
  582. SendSimpleMessage(0, GDISPOOL_TERMINATETHREAD, NON_SPOOL_INSTANCE);
  583. }
  584. else if (status == STATUS_USER_APC) // Upon this return, User mode spooler does not execute
  585. {
  586. KeSetEvent(gpeventSpoolerTermination,0,FALSE);
  587. return (ULONG) -1;
  588. }
  589. else if (!NT_SUCCESS(status))
  590. {
  591. WARNING("GDISPOOL: wait error\n");
  592. bGrabIt = FALSE;
  593. }
  594. }
  595. else
  596. {
  597. //DbgPrint("\nGDISPOOL(%lx): message already there\n",psesc);
  598. }
  599. if (bGrabIt)
  600. {
  601. // now find the message and the spoolobj
  602. LOCKSPOOLER;
  603. if (gpsmSpoolHead == NULL)
  604. {
  605. bDone = FALSE;
  606. }
  607. else
  608. {
  609. psm = gpsmSpoolHead;
  610. gpsmSpoolHead = psm->pNext;
  611. if (gpsmSpoolHead == NULL)
  612. gpsmSpoolTail = NULL;
  613. // and some stats
  614. ASSERTGDI(gcSpoolMsgCurrent > 0, "GreGetSpoolMsg - invalid count\n");
  615. gcSpoolMsgCurrent--;
  616. //DbgPrint(" got a message(%lx), hso = %lx - count = %ld\n",psesc,psm->hso,gcSpoolMsgCurrent);
  617. }
  618. UNLOCKSPOOLER;
  619. }
  620. } while ((psm == NULL) && !bDone);
  621. // did we get a message?
  622. if (psm != NULL)
  623. {
  624. if (psm->iMsg == GDISPOOL_TERMINATETHREAD || psm->iMsg == GDISPOOL_CLOSEPRINTER)
  625. {
  626. // going to terminate the thread so just get out.
  627. ulRet = sizeof(SPOOLESC);
  628. psesc->cj = sizeof(SPOOLESC);
  629. psesc->iMsg = psm->iMsg;
  630. psesc->hso = psm->hso;
  631. if (psm->iMsg & GDISPOOL_API) // Let API messages have a spool handle
  632. {
  633. psesc->hSpool = psm->hso;
  634. if (psm->iMsg & GDISPOOL_CLOSEPRINTER)
  635. {
  636. psesc->hso = NULL;
  637. }
  638. }
  639. psesc->cjOut = 0;
  640. VFREEMEM(psm);
  641. }
  642. else // Got a non-null, non-TERMINATETHREAD message to send to spooler
  643. {
  644. SPOOLALTREF sr(psm->hso);
  645. if (sr.bValid())
  646. {
  647. if (cjEscData < psm->cjIn)
  648. {
  649. // set up the header
  650. ulRet = offsetof(SPOOLESC, ajData);
  651. psesc->cj = sizeof(SPOOLESC);
  652. psesc->iMsg = GDISPOOL_INPUT2SMALL;
  653. psesc->hSpool = sr.pso->hSpool;
  654. psesc->hso = psm->hso;
  655. sr.pso->pvMsg = (PVOID)psm;
  656. // required message buffer size
  657. psesc->cjOut = psm->cjIn + offsetof(SPOOLESC,ajData);
  658. }
  659. else
  660. {
  661. ulRet = ulFinishMessage(psm, psesc, &sr, pjEscData, cjEscData);
  662. }
  663. }
  664. }
  665. }
  666. }
  667. return(ulRet);
  668. }
  669. /******************************Public*Routine******************************\
  670. * ulFinishMessage()
  671. *
  672. * Fills in psesc structure and impersonates client
  673. *
  674. *
  675. * History:
  676. * 8-Aug-95 -by- Steve Wilson [swilson]
  677. * Wrote it.
  678. \**************************************************************************/
  679. ULONG
  680. ulFinishMessage(
  681. PSPOOLMSG psm,
  682. PSPOOLESC psesc, // this must only be accessed under a try/except
  683. PSPOOLALTREF psr,
  684. PBYTE pjEscData,
  685. ULONG cjEscDAta
  686. )
  687. {
  688. NTSTATUS status;
  689. ULONG ulRet;
  690. // impersonate the client
  691. status = SeCreateClientSecurity(
  692. psm->pthreadClient,
  693. &Sqos,
  694. FALSE,
  695. &psm->sccSecurity);
  696. if (NT_SUCCESS(status))
  697. {
  698. status = SeImpersonateClientEx(&psm->sccSecurity,NULL);
  699. }
  700. if (!NT_SUCCESS(status))
  701. {
  702. WARNING("FinishMessage - CreateClientSecurity failed\n");
  703. psm->pthreadClient = NULL;
  704. }
  705. // copy the data
  706. ulRet = 0;
  707. if (psm->cjIn)
  708. {
  709. __try
  710. {
  711. // copy all the buffers into the input buffer
  712. ulRet = 0;
  713. for (DWORD i = 0; i < psm->cBuf; ++i)
  714. {
  715. RtlCopyMemory(pjEscData+ulRet,psm->apulIn[i],psm->acjIn[i]);
  716. ulRet += psm->acjIn[i];
  717. }
  718. ASSERTGDI(ulRet == psm->cjIn,"ulFinishMessage - invalid size\n");
  719. }
  720. __except(EXCEPTION_EXECUTE_HANDLER)
  721. {
  722. ulRet = 0;
  723. }
  724. }
  725. // if the input buffer was only temporary, delete it.
  726. if (psm->fl & SPOOLMSG_DELETE_INBUF)
  727. {
  728. ASSERTGDI(psm->cBuf == 1,"ulFinishMessage - delete more than 1\n");
  729. VFREEMEM(psm->apulIn[0]);
  730. psm->apulIn[0] = NULL;
  731. }
  732. // set up the header
  733. ulRet += offsetof(SPOOLESC,ajData);
  734. psesc->iMsg = psm->iMsg;
  735. psesc->cj = ulRet;
  736. psesc->hSpool = psr->pso->hSpool;
  737. psesc->cjOut = psm->cjOut;
  738. psesc->hso = psm->hso;
  739. psr->pso->pvMsg = (PVOID)psm;
  740. return(ulRet);
  741. }
  742. /******************************Public*Routine******************************\
  743. * GreEscapeSpool()
  744. *
  745. * given a spool message, add it to the queue and notify the spooler thread
  746. *
  747. *
  748. * History:
  749. * 21-Feb-1995 -by- Eric Kutter [erick]
  750. * Wrote it.
  751. \**************************************************************************/
  752. BOOL SPOOLREF::GreEscapeSpool()
  753. {
  754. BOOL bRet = FALSE;
  755. NTSTATUS status;
  756. ASSERTGDI(psm()->iMsg != GDISPOOL_TERMINATETHREAD,"GreEscapeSpool - GDISPOOL_TERMINATETHREAD\n");
  757. ASSERTGDI(psm()->iMsg != GDISPOOL_CLOSEPRINTER,"GreEscapeSpool - GDISPOOL_CLOSEPRINTER\n");
  758. ASSERTGDI(psm() != NULL,"GreEscapeSpool - null\n");
  759. //DbgPrint("Entered GreEscapeSpool\n");
  760. if (!gbInitSpool)
  761. {
  762. EngSetLastError(ERROR_NOT_READY);
  763. WARNING("GreEscapeSpool - not initialized\n");
  764. }
  765. else if (pso->dwFlags & NO_CLIENT)
  766. {
  767. //DbgPrint(" GreEscapeSpool: NO_CLIENT, message received: %x\n",psm()->iMsg);
  768. EngSetLastError(ERROR_PROCESS_ABORTED);
  769. }
  770. else
  771. { // add the message to the queue
  772. //NOTE: we may want to reference count this in the future
  773. psm()->pthreadClient = PsGetCurrentThread();
  774. if (AddMessage2Q(psm(), pso->dwSpoolInstance))
  775. {
  776. PVOID pEvent[3];
  777. pEvent[0] = gpeSpool;
  778. pEvent[1] = pso->pkevent;
  779. pEvent[2] = gpeventSpoolerTermination;
  780. status = KeWaitForMultipleObjects( 3,
  781. pEvent,
  782. WaitAny,
  783. (KWAIT_REASON)0,
  784. UserMode,
  785. FALSE,
  786. 0,
  787. NULL);
  788. switch (status)
  789. {
  790. case 0: // Spooler terminated
  791. SubtractMessageFromQ(psm());
  792. EngSetLastError(ERROR_PROCESS_ABORTED);
  793. ASSERTGDI(cAltLock() == 0,"GreEscapeSpool - invalid lock 0\n");
  794. bRet = FALSE;
  795. break;
  796. case 1: // Spooler returned
  797. bRet = TRUE;
  798. EngSetLastError(psm()->ulErr);
  799. ASSERTGDI(cAltLock() == 0,"GreEscapeSpool - invalid lock 1\n");
  800. break;
  801. case STATUS_USER_APC: // Client terminated
  802. case 2: // Spooler terminated, this client may be the spooler
  803. // Stress Failure Note:
  804. // AddMessage2Q is called above here to add a message to the message queue.
  805. // After the message is in the queue, we leave the spooler lock and set
  806. // gpeventGdiSpool, which wakes up the spooler thread. The spooler thread
  807. // then grabs the message and removes it from the message queue inside the spooler
  808. // lock. It then returns to user mode and creates a new message thread. All this
  809. // typically works fine.
  810. //
  811. // Now suppose just after AddMessage2Q adds a new message and before gpeventGdiSpool
  812. // is set, the spooler shuts down. When the spooler shuts down, STATUS_USER_APC is
  813. // returned from the gpeventGdiSpool Wait and all spooler messaging threads will set
  814. // gpeventSpoolerTermination, which is case 2 in this switch statement. This wakes
  815. // up the client thread, which proceeds to terminate and frees the psm before exiting.
  816. // Meanwhile, the spooler is down to its very last thread and calls vCleanupSpool, which
  817. // traverses and frees the psm queue. vCleanupSpool will AV when it hits one of the freed
  818. // messages in the queue.
  819. //
  820. // The problem was rarely encountered because it would only occur if the spooler shut down
  821. // after a message was entered in the queue and before the gpeventGdiSpool event was seen.
  822. //
  823. // Removing the message from the queue when the spooler or client terminates should solve
  824. // the problem. Note that this was always done for the STATUS_USER_APC case, and has now
  825. // been added to case 0 and case 2.
  826. //
  827. // Steve Wilson (NT)
  828. //
  829. SubtractMessageFromQ(psm());
  830. WARNING("Win32K spool: Client is dying!\n");
  831. pso->dwFlags |= NO_CLIENT;
  832. EngSetLastError(ERROR_PROCESS_ABORTED);
  833. bRet = FALSE;
  834. // we need to make sure there is no alt lock
  835. pso->pvMsg = NULL;
  836. while (cAltLock())
  837. KeDelayExecutionThread(KernelMode,FALSE,gpLockShortDelay);
  838. break;
  839. default:
  840. #if 1
  841. DbgPrint("GreEscapeSpool - WaitForSingleObject failed w/ status 0x%lx\n", status);
  842. DbgBreakPoint();
  843. #else
  844. WARNING("GreEscapeSpool - WaitForSingleObject failed\n");
  845. #endif
  846. break;
  847. }
  848. }
  849. }
  850. return bRet;
  851. }
  852. /******************************Public*Routine******************************\
  853. * SendSimpleMessage()
  854. *
  855. * allow a client app to send a spool message
  856. *
  857. *
  858. * History:
  859. * 21-Feb-1995 -by- Eric Kutter [erick]
  860. * 7-Jun-1996 - Steve Wilson [SWilson] - Changed from NtGdiSpoolEsc to SendSimpleMessage
  861. *
  862. \**************************************************************************/
  863. ULONG SendSimpleMessage(
  864. HANDLE hSpool,
  865. ULONG iMsg,
  866. DWORD dwSpoolInstance)
  867. {
  868. ULONG ulRet = 0;
  869. if (!gbInitSpool)
  870. {
  871. WARNING("GreEscapeSpool - not initialized\n");
  872. }
  873. else if (iMsg == GDISPOOL_TERMINATETHREAD || iMsg == GDISPOOL_CLOSEPRINTER)
  874. {
  875. PSPOOLMSG psm = (PSPOOLMSG) PALLOCMEM(sizeof(SPOOLMSG),'lpsG');
  876. if (psm)
  877. {
  878. psm->cj = sizeof(SPOOLMSG);
  879. psm->iMsg = iMsg;
  880. psm->hso = (HSPOOLOBJ) hSpool; // This is Spooler's handle, not kernel handle
  881. ulRet = AddMessage2Q(psm, dwSpoolInstance);
  882. if (ulRet == FALSE)
  883. VFREEMEM(psm);
  884. }
  885. }
  886. return ulRet;
  887. }
  888. /*****************************
  889. SubtractMessageFromQ()
  890. *****************************/
  891. VOID SubtractMessageFromQ(PSPOOLMSG psmIn)
  892. {
  893. PSPOOLMSG psm;
  894. PSPOOLMSG psmPrev = NULL;
  895. //DbgPrint("Enter SubtractMessageFromQ\n");
  896. LOCKSPOOLER;
  897. for (psm = gpsmSpoolHead ; psm ; psmPrev = psm , psm = psm->pNext)
  898. {
  899. if (psm == psmIn)
  900. {
  901. if (psmPrev)
  902. {
  903. psmPrev->pNext = psm->pNext;
  904. if (!psmPrev->pNext)
  905. {
  906. ASSERTGDI(psm == gpsmSpoolTail,"SubtractMessageFromQ: Bad gpsmSpoolTail!\n");
  907. gpsmSpoolTail = psmPrev;
  908. }
  909. }
  910. else
  911. {
  912. gpsmSpoolHead = psm->pNext;
  913. if (!gpsmSpoolHead)
  914. {
  915. ASSERTGDI(psm == gpsmSpoolTail,"SubtractMessageFromQ: Bad gpsmSpoolTail!\n");
  916. gpsmSpoolTail = gpsmSpoolHead;
  917. }
  918. }
  919. // gcSpool stuff is for debug purposes only
  920. gcSpoolMsgCurrent--;
  921. break;
  922. }
  923. }
  924. UNLOCKSPOOLER;
  925. }
  926. /******************************Public*Routine******************************\
  927. * BOOL AddMessage2Q (PSPOOLMSG psm)
  928. *
  929. * History:
  930. * 6-Aug-1995 -by- Steve Wilson [swilson]
  931. *
  932. \**************************************************************************/
  933. BOOL AddMessage2Q(PSPOOLMSG psm, DWORD dwSpoolInstance)
  934. {
  935. BOOL bRet = FALSE;
  936. // add the message to the queue
  937. LOCKSPOOLER;
  938. if (psm == NULL)
  939. {
  940. bRet = FALSE;
  941. }
  942. else if ((dwSpoolInstance != gdwSpoolInstance) && (dwSpoolInstance != NON_SPOOL_INSTANCE))
  943. {
  944. EngSetLastError(ERROR_INVALID_HANDLE);
  945. bRet = FALSE;
  946. }
  947. else
  948. {
  949. if (gpsmSpoolTail)
  950. {
  951. // list isn't empty, so add it to the list
  952. ASSERTGDI(gpsmSpoolHead != NULL,"GreEscapeSpool - head is null\n");
  953. gpsmSpoolTail->pNext = psm;
  954. }
  955. else
  956. {
  957. ASSERTGDI(gpsmSpoolHead == NULL,"GreEscapeSpool - head not null\n");
  958. gpsmSpoolHead = psm;
  959. }
  960. // the tail now always points to the new element
  961. gpsmSpoolTail = psm;
  962. psm->pNext = NULL;
  963. // and some stats
  964. gcSpoolMsg++;
  965. gcSpoolMsgCurrent++;
  966. if (gcSpoolMsgCurrent > gcSpoolMsgMax)
  967. gcSpoolMsgMax = gcSpoolMsgCurrent;
  968. bRet = TRUE;
  969. }
  970. UNLOCKSPOOLER;
  971. // notify the spooler that there is a message ready
  972. if (bRet == TRUE)
  973. {
  974. KeSetEvent(gpeventGdiSpool,0,FALSE);
  975. }
  976. return bRet;
  977. }
  978. /******************************Public*Routine******************************\
  979. * GreOpenPrinterW()
  980. *
  981. * History:
  982. * 28-Mar-1995 -by- Eric Kutter [erick]
  983. * Wrote it.
  984. \**************************************************************************/
  985. BOOL
  986. WINAPI
  987. GreOpenPrinterW(
  988. GREOPENPRINTER *pOpenPrinter,
  989. LPHANDLE phPrinter)
  990. {
  991. ULONG bRet;
  992. ULONG ul;
  993. SPOOLMEMOBJ spmo; // Creates (PSPOOLOBJ) spmo.pso, containing pkevent, hSpool, pvMsg
  994. //DbgPrint("Enter GreOpenPrinterW\n");
  995. if (spmo.bValid())
  996. {
  997. // setup the message
  998. PSPOOLMSG psm = spmo.psm();
  999. psm->cj = sizeof(SPOOLMSG);
  1000. psm->iMsg = GDISPOOL_OPENPRINTER;
  1001. psm->fl = 0;
  1002. psm->cBuf = 1;
  1003. psm->cjIn = pOpenPrinter->cj;
  1004. psm->acjIn[0] = pOpenPrinter->cj;
  1005. psm->apulIn[0]= (PULONG)pOpenPrinter;
  1006. psm->pulOut = (PULONG)&spmo.pso->hSpool;
  1007. psm->cjOut = sizeof(*phPrinter);
  1008. psm->hso = spmo.hGet(); // returns ((HSPOOLOBJ) pso)
  1009. if (spmo.GreEscapeSpool() && psm->ulRet)
  1010. {
  1011. *phPrinter = (HANDLE)spmo.hGet();
  1012. bRet = TRUE;
  1013. }
  1014. else
  1015. {
  1016. spmo.bDelete();
  1017. bRet = FALSE;
  1018. }
  1019. }
  1020. else
  1021. {
  1022. bRet = FALSE;
  1023. }
  1024. return(bRet);
  1025. }
  1026. /*****************************************************************************
  1027. * GreEnumFormsW
  1028. *
  1029. * History:
  1030. * 25/7/95 by Steve Wilson [swilson]
  1031. * Wrote it.
  1032. *******************************************************************************/
  1033. BOOL
  1034. WINAPI
  1035. GreEnumFormsW(
  1036. HANDLE hSpool,
  1037. GREENUMFORMS *pEnumForms,
  1038. GREENUMFORMS *pEnumFormsReturn,
  1039. LONG cjOut )
  1040. {
  1041. ULONG bRet = FALSE;
  1042. SPOOLREF sr(hSpool);
  1043. if (sr.bValid())
  1044. {
  1045. PSPOOLMSG psm = sr.psm();
  1046. //DbgPrint("Enter GreEnumFormsW\n");
  1047. // setup the message
  1048. psm->cj = sizeof(SPOOLMSG);
  1049. psm->iMsg = GDISPOOL_ENUMFORMS;
  1050. psm->fl = 0;
  1051. psm->cBuf = 1;
  1052. psm->cjIn = pEnumForms->cj;
  1053. psm->acjIn[0] = pEnumForms->cj;
  1054. psm->apulIn[0]= (PULONG) pEnumForms;
  1055. psm->pulOut = (PULONG) pEnumFormsReturn;
  1056. psm->cjOut = cjOut;
  1057. psm->hso = (HSPOOLOBJ) hSpool;
  1058. bRet = sr.GreEscapeSpool() ? psm->ulRet : FALSE;
  1059. }
  1060. return bRet;
  1061. }
  1062. /*****************************************************************************
  1063. * GreGenericW
  1064. *
  1065. * History:
  1066. * 25-Jul-95 by Steve Wilson [swilson]
  1067. * Wrote it.
  1068. *******************************************************************************/
  1069. BOOL
  1070. GreGenericW(
  1071. HANDLE hSpool,
  1072. PULONG pX,
  1073. PULONG pXReturn,
  1074. LONG cjOut,
  1075. LONG MessageID,
  1076. ULONG ulFlag )
  1077. {
  1078. ULONG bRet = FALSE;
  1079. SPOOLREF sr(hSpool);
  1080. if (sr.bValid())
  1081. {
  1082. PSPOOLMSG psm = sr.psm();
  1083. //DbgPrint("Enter GreGenericW\n");
  1084. // setup the message
  1085. psm->cj = sizeof(SPOOLMSG);
  1086. psm->iMsg = MessageID;
  1087. psm->fl = ulFlag;
  1088. psm->cBuf = 1;
  1089. psm->cjIn = pX ? *(PULONG) pX : 0; // Must be sure first element of pX is LONG cj: (pX->cj)
  1090. psm->acjIn[0] = pX ? *(PULONG) pX : 0; // Must be sure first element of pX is LONG cj: (pX->cj)
  1091. psm->apulIn[0]= (PULONG) pX;
  1092. psm->pulOut = (PULONG) pXReturn;
  1093. psm->cjOut = cjOut;
  1094. psm->hso = (HSPOOLOBJ) hSpool;
  1095. bRet = sr.GreEscapeSpool() ? psm->ulRet : FALSE;
  1096. }
  1097. return bRet;
  1098. }
  1099. /*****************************************************************************\
  1100. * GrePrinterDriverUnloadW
  1101. *
  1102. * This function is used to a send a message to the spooler when a printer
  1103. * driver is unloaded (i.e the DC count on the driver goes to zero)
  1104. * On receipt of this message, the spooler attempts to upgrade the driver if
  1105. * neccesary.
  1106. *
  1107. * History:
  1108. * 11/17/97 by Ramanathan N Venkatapathy
  1109. * Wrote it.
  1110. \*****************************************************************************/
  1111. BOOL GrePrinterDriverUnloadW(
  1112. LPWSTR pDriverName
  1113. )
  1114. {
  1115. BOOL bRet = FALSE;
  1116. ULONG cbDriverName;
  1117. LPWSTR pDriverFile = NULL;
  1118. SPOOLMEMOBJ spmo;
  1119. // Check for invalid printer driver names.
  1120. if (!pDriverName || !*pDriverName)
  1121. {
  1122. return bRet;
  1123. }
  1124. // Copy the driver name into another buffer.
  1125. cbDriverName = (wcslen(pDriverName) + 1) * sizeof(WCHAR);
  1126. pDriverFile = (LPWSTR) PALLOCMEM(cbDriverName, 'lpsG');
  1127. if (spmo.bValid() && pDriverFile)
  1128. {
  1129. PSPOOLMSG psm = spmo.psm();
  1130. memcpy(pDriverFile, pDriverName, cbDriverName);
  1131. psm->cj = sizeof(SPOOLMSG);
  1132. psm->iMsg = GDISPOOL_UNLOADDRIVER_COMPLETE;
  1133. psm->fl = 0;
  1134. psm->cBuf = 1;
  1135. psm->cjIn = cbDriverName;
  1136. psm->apulIn[0] = (PULONG) pDriverFile;
  1137. psm->acjIn[0] = cbDriverName;
  1138. psm->pulOut = NULL;
  1139. psm->cjOut = 0;
  1140. psm->hso = spmo.hGet();
  1141. bRet = spmo.GreEscapeSpool() && psm->ulRet;
  1142. spmo.bDelete();
  1143. }
  1144. if (pDriverFile) {
  1145. VFREEMEM(pDriverFile);
  1146. }
  1147. return bRet;
  1148. }
  1149. /*****************************************************************************
  1150. * GreGetPrinterDriverW
  1151. *
  1152. * History:
  1153. * 4/14/1995 by Gerrit van Wingerden [gerritv]
  1154. * Wrote it.
  1155. *******************************************************************************/
  1156. BOOL WINAPI GreGetPrinterDriverW(
  1157. HANDLE hSpool,
  1158. GREGETPRINTERDRIVER *pGetPrinterDriver,
  1159. GREGETPRINTERDRIVER *pGetPrinterDriverReturn,
  1160. LONG cjOut
  1161. )
  1162. {
  1163. ULONG bRet = FALSE;
  1164. SPOOLREF sr(hSpool);
  1165. if (sr.bValid())
  1166. {
  1167. PSPOOLMSG psm = sr.psm();
  1168. //DbgPrint("Enter GreGetPrinterDriverW\n");
  1169. // setup the message
  1170. psm->cj = sizeof(SPOOLMSG);
  1171. psm->iMsg = GDISPOOL_GETPRINTERDRIVER;
  1172. psm->fl = 0;
  1173. psm->cBuf = 1;
  1174. psm->cjIn = pGetPrinterDriver->cj;
  1175. psm->acjIn[0] = pGetPrinterDriver->cj;
  1176. psm->apulIn[0]= (PULONG) pGetPrinterDriver;
  1177. psm->pulOut = (PULONG)pGetPrinterDriverReturn;
  1178. psm->cjOut = cjOut;
  1179. psm->hso = (HSPOOLOBJ)hSpool;
  1180. if( sr.GreEscapeSpool() )
  1181. {
  1182. bRet = psm->ulRet;
  1183. }
  1184. else
  1185. {
  1186. bRet = FALSE;
  1187. }
  1188. }
  1189. return(bRet);
  1190. }
  1191. /****************************************************************************
  1192. * BOOL StartPagePrinter( HANDLE hPrinter )
  1193. *
  1194. * History:
  1195. * 4/28/1995 by Gerrit van Wingerden [gerritv]
  1196. * Wrote it.
  1197. *****************************************************************************/
  1198. BOOL
  1199. WINAPI
  1200. StartPagePrinter(
  1201. HANDLE hSpool
  1202. )
  1203. {
  1204. BOOL bRet = FALSE;
  1205. SPOOLREF sr(hSpool);
  1206. if (sr.bValid())
  1207. {
  1208. PSPOOLMSG psm = sr.psm();
  1209. //DbgPrint("Enter StartPagePrinter\n");
  1210. psm->cj = sizeof(SPOOLMSG);
  1211. psm->iMsg = GDISPOOL_STARTPAGEPRINTER;
  1212. psm->fl = 0;
  1213. psm->cBuf = 0;
  1214. psm->cjIn = 0;
  1215. psm->pulOut = NULL;
  1216. psm->cjOut = 0;
  1217. psm->hso = (HSPOOLOBJ)hSpool;
  1218. if( sr.GreEscapeSpool() )
  1219. {
  1220. bRet = psm->ulRet;
  1221. }
  1222. }
  1223. return(bRet);
  1224. }
  1225. /****************************************************************************
  1226. * BOOL EndPagePrinter( HANDLE hPrinter )
  1227. *
  1228. * History:
  1229. * 4/28/1995 by Gerrit van Wingerden [gerritv]
  1230. * Wrote it.
  1231. *****************************************************************************/
  1232. BOOL
  1233. WINAPI
  1234. EndPagePrinter(
  1235. HANDLE hSpool
  1236. )
  1237. {
  1238. BOOL bRet = FALSE;
  1239. SPOOLREF sr(hSpool);
  1240. if (sr.bValid())
  1241. {
  1242. PSPOOLMSG psm = sr.psm();
  1243. //DbgPrint("Enter EndPagePrinter\n");
  1244. psm->cj = sizeof(SPOOLMSG);
  1245. psm->iMsg = GDISPOOL_ENDPAGEPRINTER;
  1246. psm->fl = 0;
  1247. psm->cBuf = 0;
  1248. psm->cjIn = 0;
  1249. psm->pulOut = NULL;
  1250. psm->cjOut = 0;
  1251. psm->hso = (HSPOOLOBJ)hSpool;
  1252. if(sr.GreEscapeSpool())
  1253. {
  1254. bRet = psm->ulRet;
  1255. }
  1256. }
  1257. return(bRet);
  1258. }
  1259. /****************************************************************************
  1260. * BOOL EndDocPrinter( HANDLE hPrinter )
  1261. *
  1262. * History:
  1263. * 4/28/1995 by Gerrit van Wingerden [gerritv]
  1264. * Wrote it.
  1265. *****************************************************************************/
  1266. BOOL
  1267. WINAPI
  1268. EndDocPrinter(
  1269. HANDLE hSpool
  1270. )
  1271. {
  1272. BOOL bRet = FALSE;
  1273. SPOOLREF sr(hSpool);
  1274. if (sr.bValid())
  1275. {
  1276. PSPOOLMSG psm = sr.psm();
  1277. //DbgPrint("Enter EndDocPrinter\n");
  1278. psm->cj = sizeof(SPOOLMSG);
  1279. psm->iMsg = GDISPOOL_ENDDOCPRINTER;
  1280. psm->fl = 0;
  1281. psm->cBuf = 0;
  1282. psm->cjIn = 0;
  1283. psm->pulOut = NULL;
  1284. psm->cjOut = 0;
  1285. psm->hso = (HSPOOLOBJ)hSpool;
  1286. if( sr.GreEscapeSpool() )
  1287. {
  1288. bRet = (DWORD) psm->ulRet;
  1289. }
  1290. }
  1291. return(bRet);
  1292. }
  1293. /****************************************************************************
  1294. * ClosePrinter( HANDLE hPrinter )
  1295. *
  1296. * History:
  1297. * 12-Feb-1996 -by- Steve Wilson (swilson)
  1298. * Wrote it.
  1299. *****************************************************************************/
  1300. BOOL
  1301. WINAPI
  1302. ClosePrinter(
  1303. HANDLE hSpool
  1304. )
  1305. {
  1306. SPOOLREF sr(hSpool);
  1307. if (sr.bValid())
  1308. {
  1309. //DbgPrint("Enter ClosePrinter: %d\n", sr.pso->hSpool);
  1310. SendSimpleMessage(sr.pso->hSpool, GDISPOOL_CLOSEPRINTER, sr.pso->dwSpoolInstance);
  1311. sr.bDelete();
  1312. }
  1313. return TRUE;
  1314. }
  1315. /******************************Public*Routine******************************\
  1316. * AbortPrinter()
  1317. *
  1318. * History:
  1319. * 18-Jul-1995 -by- Steve Wilson (swilson)
  1320. * Wrote it.
  1321. \**************************************************************************/
  1322. BOOL
  1323. WINAPI
  1324. AbortPrinter(
  1325. HANDLE hPrinter)
  1326. {
  1327. BOOL bRet = FALSE;
  1328. SPOOLREF sr(hPrinter);
  1329. if (sr.bValid())
  1330. {
  1331. PSPOOLMSG psm = sr.psm();
  1332. //DbgPrint("Enter AbortPrinter\n");
  1333. psm->cj = sizeof(SPOOLMSG);
  1334. psm->iMsg = GDISPOOL_ABORTPRINTER;
  1335. psm->fl = 0;
  1336. psm->cBuf = 0;
  1337. psm->cjIn = 0;
  1338. psm->pulOut = NULL;
  1339. psm->cjOut = 0;
  1340. psm->hso = (HSPOOLOBJ)hPrinter;
  1341. if( sr.GreEscapeSpool() )
  1342. {
  1343. bRet = (DWORD) psm->ulRet;
  1344. }
  1345. }
  1346. return(bRet);
  1347. }
  1348. /****************************************************************************
  1349. * StartDocPrinter()
  1350. *
  1351. * History:
  1352. * 4/28/1995 by Gerrit van Wingerden [gerritv]
  1353. * Wrote it.
  1354. *****************************************************************************/
  1355. DWORD
  1356. WINAPI
  1357. StartDocPrinterW(
  1358. HANDLE hPrinter,
  1359. DWORD dwLevel,
  1360. LPBYTE lpbDocInfo
  1361. )
  1362. {
  1363. LONG cj = offsetof(GRESTARTDOCPRINTER,alData);
  1364. LONG cjDocName = 0;
  1365. LONG cjOutputFile = 0;
  1366. LONG cjDatatype = 0;
  1367. DOC_INFO_1W* pDocInfo = (DOC_INFO_1W*) lpbDocInfo;
  1368. DWORD ret = 0;
  1369. //DbgPrint("Enter StartDocPrinterW\n");
  1370. ASSERTGDI( dwLevel == 1, "StartDocPrinter: dwLevel != 1\n" );
  1371. ASSERTGDI( lpbDocInfo != NULL, "StarDocPrinter lpbDocInfo is NULL\n");
  1372. // first we need to compute the sizes.
  1373. if (pDocInfo->pDocName)
  1374. {
  1375. cjDocName = (wcslen(pDocInfo->pDocName) + 1) * sizeof(WCHAR);
  1376. cj += cjDocName;
  1377. cj = (cj + 3) & ~3;
  1378. }
  1379. if (pDocInfo->pOutputFile)
  1380. {
  1381. cjOutputFile = (wcslen(pDocInfo->pOutputFile) + 1) * sizeof(WCHAR);
  1382. cj += cjOutputFile;
  1383. cj = (cj + 3) & ~3;
  1384. }
  1385. if (pDocInfo->pDatatype)
  1386. {
  1387. cjDatatype = (wcslen(pDocInfo->pDatatype) + 1) * sizeof(WCHAR);
  1388. cj += cjDatatype;
  1389. cj = (cj + 3) & ~3;
  1390. }
  1391. SPOOLREF sr(hPrinter);
  1392. if (sr.bValid())
  1393. {
  1394. PLONG plData;
  1395. GRESTARTDOCPRINTER *pStartDocPrinter;
  1396. pStartDocPrinter = (GRESTARTDOCPRINTER*)PALLOCNOZ(cj,'lpsG');
  1397. if (pStartDocPrinter)
  1398. {
  1399. PSPOOLMSG psm = sr.psm();
  1400. // we got memory, now copy the stuff in
  1401. pStartDocPrinter->cj = cj;
  1402. plData = pStartDocPrinter->alData;
  1403. pStartDocPrinter->cjDocName = (cjDocName + 3) & ~3;
  1404. pStartDocPrinter->cjOutputFile = (cjOutputFile + 3) & ~3;
  1405. pStartDocPrinter->cjDatatype = (cjDatatype + 3) & ~3;
  1406. if (pDocInfo->pDocName)
  1407. {
  1408. memcpy(plData,pDocInfo->pDocName,cjDocName);
  1409. plData += (cjDocName+3)/4;
  1410. }
  1411. if (pDocInfo->pOutputFile)
  1412. {
  1413. memcpy(plData,pDocInfo->pOutputFile,cjOutputFile);
  1414. plData += (cjOutputFile+3)/4;
  1415. }
  1416. if (pDocInfo->pDatatype)
  1417. {
  1418. memcpy(plData,pDocInfo->pDatatype,cjDatatype);
  1419. plData += (cjDatatype+3)/4;
  1420. }
  1421. ASSERTGDI(POFFSET(pStartDocPrinter,plData) == cj,
  1422. "EngStartDocPrinter - sizes are wrong\n");
  1423. // pStartDocPrinter now contains all needed data, call out
  1424. // setup the message
  1425. psm->cj = sizeof(SPOOLMSG);
  1426. psm->iMsg = GDISPOOL_STARTDOCPRINTER;
  1427. psm->fl = 0;
  1428. psm->cBuf = 1;
  1429. psm->cjIn = pStartDocPrinter->cj;
  1430. psm->acjIn[0] = pStartDocPrinter->cj;
  1431. psm->apulIn[0]= (PULONG)pStartDocPrinter;
  1432. psm->pulOut = NULL;
  1433. psm->cjOut = 0;
  1434. psm->hso = (HSPOOLOBJ)hPrinter;
  1435. if( sr.GreEscapeSpool() )
  1436. {
  1437. ret = (DWORD) psm->ulRet;
  1438. }
  1439. VFREEMEM(pStartDocPrinter);
  1440. }
  1441. }
  1442. return(ret);
  1443. }
  1444. /******************************Public*Routine******************************\
  1445. * OpenPrinterW()
  1446. *
  1447. * History:
  1448. * 05-Apr-1995 -by- Eric Kutter [erick]
  1449. * Wrote it.
  1450. \**************************************************************************/
  1451. BOOL
  1452. WINAPI
  1453. OpenPrinterW(
  1454. LPWSTR pPrinterName,
  1455. LPHANDLE phPrinter,
  1456. LPPRINTER_DEFAULTSW pDefault)
  1457. {
  1458. LONG cjName = 0;
  1459. LONG cjDatatype = 0;
  1460. LONG cjDevMode = 0;
  1461. LONG cj = offsetof(GREOPENPRINTER,alData);
  1462. BOOL bRet = FALSE;
  1463. PLONG plData;
  1464. GREOPENPRINTER *pOpenPrinter;
  1465. //DbgPrint("Enter OpenPrinterW\n");
  1466. // first we need to compute the sizes.
  1467. if (pPrinterName)
  1468. {
  1469. cjName = (wcslen(pPrinterName) + 1) * sizeof(WCHAR);
  1470. cj += cjName;
  1471. cj = (cj + 3) & ~3;
  1472. }
  1473. if (pDefault)
  1474. {
  1475. if (pDefault->pDatatype)
  1476. {
  1477. cjDatatype = (wcslen(pDefault->pDatatype) + 1) * sizeof(WCHAR);
  1478. cj += cjDatatype;
  1479. cj = (cj + 3) & ~3;
  1480. }
  1481. if (pDefault->pDevMode)
  1482. {
  1483. //DbgPrint("cjMinDevmode = %d, dmSize = %d, dmDriverExtra = %d\n", MIN_DEVMODE_SIZE, pDefault->pDevMode->dmSize, pDefault->pDevMode->dmDriverExtra);
  1484. cjDevMode = pDefault->pDevMode->dmSize + pDefault->pDevMode->dmDriverExtra;
  1485. if (cjDevMode < MIN_DEVMODE_SIZE)
  1486. {
  1487. EngSetLastError(ERROR_INVALID_PARAMETER);
  1488. return bRet;
  1489. }
  1490. cj += cjDevMode;
  1491. cj = (cj + 3) & ~3;
  1492. }
  1493. }
  1494. // allocate the memory
  1495. pOpenPrinter = (GREOPENPRINTER*)PALLOCNOZ(cj,'lpsG');
  1496. if (pOpenPrinter)
  1497. {
  1498. // we got memory, now copy the stuff in
  1499. pOpenPrinter->cj = cj;
  1500. pOpenPrinter->pd = *pDefault;
  1501. plData = pOpenPrinter->alData;
  1502. pOpenPrinter->cjName = (cjName + 3) & ~3;
  1503. pOpenPrinter->cjDatatype = (cjDatatype + 3) & ~3;
  1504. pOpenPrinter->cjDevMode = (cjDevMode + 3) & ~3;
  1505. if (pPrinterName)
  1506. {
  1507. memcpy(plData,pPrinterName,cjName);
  1508. plData += (cjName+3)/4;
  1509. }
  1510. if (pDefault)
  1511. {
  1512. if (pDefault->pDatatype)
  1513. {
  1514. pOpenPrinter->pd.pDatatype = (WCHAR*)POFFSET(pOpenPrinter,plData);
  1515. memcpy(plData,pDefault->pDatatype,cjDatatype);
  1516. plData += (cjDatatype+3)/4;
  1517. }
  1518. if (pDefault->pDevMode)
  1519. {
  1520. pOpenPrinter->pd.pDevMode = (PDEVMODEW)POFFSET(pOpenPrinter,plData);
  1521. memcpy(plData,pDefault->pDevMode,cjDevMode);
  1522. plData += (cjDevMode+3)/4;
  1523. }
  1524. }
  1525. ASSERTGDI(POFFSET(pOpenPrinter,plData) == cj,
  1526. "EngOpenPrinter - sizes are wrong\n");
  1527. // pOpenPrinter now contains all needed data, call out
  1528. bRet = GreOpenPrinterW(pOpenPrinter,phPrinter);
  1529. VFREEMEM(pOpenPrinter);
  1530. }
  1531. return(bRet);
  1532. }
  1533. /*******************************************************************************
  1534. * void MarshallUpStructure( LPBYTE lpStructure, LPDWORD lpOffsets )
  1535. *
  1536. * This routine does pointer adjustment to offsets within the buffer
  1537. *
  1538. * History:
  1539. * 6/30/1995 by Muhunthan Sivapragasam (MuhuntS)
  1540. * Got from spoolss code
  1541. *******************************************************************************/
  1542. void
  1543. MarshallUpStructure(
  1544. LPBYTE lpStructure,
  1545. LPDWORD lpOffsets
  1546. )
  1547. {
  1548. register DWORD i=0;
  1549. while (lpOffsets[i] != -1) {
  1550. if ((*(LPBYTE *)(lpStructure+lpOffsets[i]))) {
  1551. (*(LPBYTE *)(lpStructure+lpOffsets[i]))+=(ULONG_PTR)lpStructure;
  1552. }
  1553. i++;
  1554. }
  1555. }
  1556. /*******************************************************************************
  1557. * BOOL ValidateString( LPWSTR pString, PBYTE pBuffer, LONG cjLength )
  1558. *
  1559. * This routine validates a LPWSTR to make sure that it really lies inside of a buffer.
  1560. *
  1561. * History:
  1562. * 4/19/1995 by Gerrit van Wingerden [gerritv]
  1563. * Wrote it.
  1564. *******************************************************************************/
  1565. BOOL
  1566. ValidateString(
  1567. LPWSTR pString,
  1568. PBYTE pBuffer,
  1569. LONG cjLength )
  1570. {
  1571. LPWSTR pEnd = (LPWSTR) ( pBuffer + cjLength );
  1572. if( pString > pEnd || pString < (LPWSTR) pBuffer )
  1573. {
  1574. return(FALSE);
  1575. }
  1576. while( pString < pEnd && *pString)
  1577. {
  1578. pString++;
  1579. }
  1580. return( pString < pEnd );
  1581. }
  1582. /*******************************************************************************
  1583. * BOOL ValidateStrings( LPBYTE lpStructure, LPDWORD lpOffsets, LONG cjLength )
  1584. *
  1585. * This routine validates all the strings in the structure to make sure they really lie inside of a buffer.
  1586. *
  1587. * History:
  1588. * 6/30/1995 by Muhunthan Sivapragasam (MuhuntS)
  1589. * Wrote it.
  1590. *******************************************************************************/
  1591. BOOL
  1592. ValidateStrings(
  1593. LPBYTE lpStructure,
  1594. LPDWORD lpOffsets,
  1595. LONG cjLength
  1596. )
  1597. {
  1598. register DWORD i=0;
  1599. while (lpOffsets[i] != -1)
  1600. {
  1601. if ( (*(LPWSTR *) (lpStructure+lpOffsets[i])) &&
  1602. !ValidateString(*(LPWSTR *) (lpStructure+lpOffsets[i]),
  1603. lpStructure,
  1604. cjLength) )
  1605. {
  1606. return FALSE;
  1607. }
  1608. i++;
  1609. }
  1610. return TRUE;
  1611. }
  1612. /*******************************************************************************
  1613. * BOOL ValidateDependentFiles( LPWSTR pString, PBYTE pBuffer, LONG cjLength )
  1614. *
  1615. * This routine validates DependentFiles field (which is a list of strings
  1616. * up to \0\0) to make sure that it really lies inside of a buffer.
  1617. *
  1618. * History:
  1619. * 6/30/1995 by Muhunthan Sivapragasam
  1620. * Wrote it.
  1621. *******************************************************************************/
  1622. BOOL
  1623. ValidateDependentFiles(
  1624. LPWSTR pString,
  1625. PBYTE pBuffer,
  1626. LONG cjLength )
  1627. {
  1628. LPWSTR pEnd = (LPWSTR) (pBuffer + cjLength) - 1;
  1629. if (pString < (LPWSTR) pBuffer)
  1630. {
  1631. return(FALSE);
  1632. }
  1633. while (pString < pEnd)
  1634. {
  1635. if (*pString==0 && *(pString+1)==0) return TRUE;
  1636. pString++;
  1637. }
  1638. return (FALSE);
  1639. }
  1640. /*******************************************************************************
  1641. * EngEnumForms()
  1642. *
  1643. * History:
  1644. * 7/24/1995 by Steve Wilson [swilson]
  1645. * Wrote it.
  1646. *******************************************************************************/
  1647. BOOL
  1648. WINAPI
  1649. EngEnumForms(
  1650. HANDLE hPrinter,
  1651. DWORD dwLevel,
  1652. LPBYTE lpbForms,
  1653. DWORD cbBuf,
  1654. LPDWORD pcbNeeded,
  1655. LPDWORD pcbReturned
  1656. )
  1657. {
  1658. LONG cj;
  1659. DWORD cjReturn;
  1660. BOOL bRet = FALSE;
  1661. GREENUMFORMS *pEnumForms, *pEnumFormsReturn;
  1662. //DbgPrint("Enter EngEnumFormsW\n");
  1663. if(!pcbNeeded || !pcbReturned)
  1664. {
  1665. EngSetLastError(ERROR_INVALID_PARAMETER);
  1666. return FALSE;
  1667. }
  1668. cj = sizeof(GREENUMFORMS);
  1669. // Allocate TO buffer
  1670. pEnumForms = (GREENUMFORMS *) PALLOCMEM(cj, 'lpsG');
  1671. // Marshall TO buffer
  1672. if (pEnumForms) {
  1673. pEnumForms->cj = cj;
  1674. pEnumForms->cjData = cbBuf;
  1675. pEnumForms->dwLevel = dwLevel;
  1676. // Allocate RETURN buffer
  1677. pEnumFormsReturn = (GREENUMFORMS *) PALLOCNOZ(cjReturn = sizeof(GREENUMFORMS) + cbBuf, 'lpsG');
  1678. // SEND MESSAGE
  1679. if (pEnumFormsReturn) {
  1680. bRet = GreEnumFormsW(hPrinter, pEnumForms, pEnumFormsReturn, cjReturn);
  1681. // Fill in return sizes
  1682. *pcbNeeded = pEnumFormsReturn->cjData; // # return data bytes
  1683. *pcbReturned = pEnumFormsReturn->nForms; // # forms in return data
  1684. // UnMarshall Message
  1685. if (bRet) {
  1686. ASSERTGDI(*pcbNeeded <= cbBuf,"EnumFormsW - error\n");
  1687. if (lpbForms && *pcbNeeded <= cbBuf) {
  1688. // Copy returned data into supplied FORM_INFO_1 structure
  1689. memcpy(lpbForms, pEnumFormsReturn->alData, pEnumFormsReturn->cjData);
  1690. DWORD i;
  1691. for (i = 0 ; i < *pcbReturned ; ++i, lpbForms += sizeof(FORM_INFO_1W)) {
  1692. MarshallUpStructure(lpbForms, FormInfo1Offsets);
  1693. }
  1694. }
  1695. }
  1696. VFREEMEM(pEnumFormsReturn);
  1697. }
  1698. VFREEMEM(pEnumForms);
  1699. }
  1700. return bRet;
  1701. }
  1702. /*******************************************************************************
  1703. * EngGetPrinter()
  1704. *
  1705. * History:
  1706. * 9/30/1995 by Steve Wilson [swilson]
  1707. * Wrote it.
  1708. *******************************************************************************/
  1709. BOOL
  1710. WINAPI
  1711. EngGetPrinter(
  1712. HANDLE hPrinter,
  1713. DWORD dwLevel,
  1714. LPBYTE pPrinter,
  1715. DWORD cbBuf,
  1716. LPDWORD pcbNeeded
  1717. )
  1718. {
  1719. LONG cj;
  1720. DWORD cjReturn;
  1721. BOOL bRet = FALSE;
  1722. GREGETPRINTER *pGetPrinter, *pGetPrinterReturn;
  1723. DWORD *pOffsets;
  1724. //DbgPrint("Enter EngGetPrinter\n");
  1725. if (!pcbNeeded)
  1726. {
  1727. EngSetLastError(ERROR_INVALID_PARAMETER);
  1728. return FALSE;
  1729. }
  1730. switch (dwLevel)
  1731. {
  1732. case 1:
  1733. pOffsets = PrinterInfo1Offsets;
  1734. break;
  1735. case 2:
  1736. pOffsets = PrinterInfo2Offsets;
  1737. break;
  1738. case 3:
  1739. pOffsets = PrinterInfo3Offsets;
  1740. break;
  1741. case 4:
  1742. pOffsets = PrinterInfo4Offsets;
  1743. break;
  1744. case 5:
  1745. pOffsets = PrinterInfo5Offsets;
  1746. break;
  1747. default:
  1748. EngSetLastError(ERROR_INVALID_LEVEL);
  1749. return FALSE;
  1750. }
  1751. cj = sizeof(GREGETPRINTER);
  1752. // Allocate TO buffer
  1753. pGetPrinter = (GREGETPRINTER *) PALLOCMEM(cj, 'lpsG');
  1754. // Marshall TO buffer
  1755. if (pGetPrinter)
  1756. {
  1757. pGetPrinter->cj = cj;
  1758. pGetPrinter->cjData = cbBuf;
  1759. pGetPrinter->dwLevel = dwLevel;
  1760. // Allocate RETURN buffer
  1761. pGetPrinterReturn = (GREGETPRINTER *) PALLOCNOZ(cjReturn = sizeof(GREGETPRINTER) + cbBuf, 'lpsG');
  1762. // SEND MESSAGE
  1763. if (pGetPrinterReturn)
  1764. {
  1765. bRet = GreGenericW(hPrinter, (PULONG) pGetPrinter, (PULONG) pGetPrinterReturn, cjReturn, GDISPOOL_GETPRINTER, 0);
  1766. // Fill in return size
  1767. *pcbNeeded = pGetPrinterReturn->cjData;
  1768. // UnMarshall Message
  1769. if (bRet)
  1770. {
  1771. ASSERTGDI(*pcbNeeded <= cbBuf,"EngGetPrinter - error\n");
  1772. if (pPrinter && *pcbNeeded <= cbBuf)
  1773. {
  1774. memcpy(pPrinter, pGetPrinterReturn->alData, pGetPrinterReturn->cjData);
  1775. MarshallUpStructure(pPrinter, pOffsets);
  1776. }
  1777. }
  1778. VFREEMEM(pGetPrinterReturn);
  1779. }
  1780. VFREEMEM(pGetPrinter);
  1781. }
  1782. return bRet;
  1783. }
  1784. /*******************************************************************************
  1785. * EngGetForm()
  1786. *
  1787. * History:
  1788. * 7/24/1995 by Steve Wilson [swilson]
  1789. * Wrote it.
  1790. *******************************************************************************/
  1791. BOOL
  1792. WINAPI
  1793. EngGetForm(
  1794. HANDLE hPrinter,
  1795. LPWSTR pFormName,
  1796. DWORD dwLevel,
  1797. LPBYTE lpbForm,
  1798. DWORD cbBuf,
  1799. LPDWORD pcbNeeded
  1800. )
  1801. {
  1802. LONG cj, cjFormName;
  1803. DWORD cjReturn;
  1804. BOOL bRet = FALSE;
  1805. GREGETFORM *pGetForm, *pGetFormReturn;
  1806. //DbgPrint("Enter EngGetForm\n");
  1807. if (!pcbNeeded)
  1808. {
  1809. EngSetLastError(ERROR_INVALID_PARAMETER);
  1810. return FALSE;
  1811. }
  1812. // Accumulate sizes of base struct plus strings
  1813. cj = sizeof(GREGETFORM);
  1814. cj += (cjFormName = pFormName ? (wcslen(pFormName) + 1)*sizeof *pFormName : 0);
  1815. // Allocate TO buffer
  1816. pGetForm = (GREGETFORM *) PALLOCMEM(cj, 'lpsG');
  1817. // Marshall TO buffer
  1818. if (pGetForm)
  1819. {
  1820. pGetForm->cj = cj;
  1821. pGetForm->cjData = cbBuf;
  1822. pGetForm->dwLevel = dwLevel;
  1823. if (pFormName)
  1824. {
  1825. memcpy(pGetForm->alData,pFormName,cjFormName);
  1826. }
  1827. // Allocate RETURN buffer
  1828. pGetFormReturn = (GREGETFORM *) PALLOCNOZ(cjReturn = sizeof(GREGETFORM) + cbBuf, 'lpsG');
  1829. // SEND MESSAGE
  1830. if (pGetFormReturn)
  1831. {
  1832. bRet = GreGenericW(hPrinter, (PULONG) pGetForm, (PULONG) pGetFormReturn, cjReturn, GDISPOOL_GETFORM, 0);
  1833. if (bRet)
  1834. {
  1835. // Fill in return sizes
  1836. *pcbNeeded = pGetFormReturn->cjData; // # return data bytes
  1837. // UnMarshall Message
  1838. if (lpbForm && bRet)
  1839. {
  1840. if (*pcbNeeded <= cbBuf)
  1841. memcpy(lpbForm, pGetFormReturn->alData, pGetFormReturn->cjData);
  1842. else
  1843. ASSERTGDI(*pcbNeeded <= cbBuf,"GetFormW - error\n");
  1844. MarshallUpStructure(lpbForm, FormInfo1Offsets);
  1845. }
  1846. }
  1847. VFREEMEM(pGetFormReturn);
  1848. }
  1849. VFREEMEM(pGetForm);
  1850. }
  1851. return bRet;
  1852. }
  1853. /*******************************************************************************
  1854. * GetPrinterDriverW()
  1855. *
  1856. * History:
  1857. * 4/19/1995 by Gerrit van Wingerden [gerritv]
  1858. * Wrote it.
  1859. *******************************************************************************/
  1860. BOOL WINAPI GetPrinterDriverW(
  1861. HANDLE hPrinter,
  1862. LPWSTR pEnvironment,
  1863. DWORD dwLevel,
  1864. LPBYTE lpbDrvInfo,
  1865. DWORD cbBuf,
  1866. LPDWORD pcbNeeded
  1867. )
  1868. {
  1869. BOOL bRet = FALSE;
  1870. LONG cj, cjEnvironment;
  1871. DWORD *pOffsets, *pStrings;
  1872. //DbgPrint("Enter GetPrinterDriverW\n");
  1873. if (!pcbNeeded)
  1874. {
  1875. EngSetLastError(ERROR_INVALID_PARAMETER);
  1876. return FALSE;
  1877. }
  1878. cj = sizeof(GREGETPRINTERDRIVER);
  1879. cjEnvironment = 0;
  1880. *pcbNeeded = 0;
  1881. if( pEnvironment )
  1882. {
  1883. cjEnvironment += (wcslen(pEnvironment) + 1) * sizeof(WCHAR);
  1884. }
  1885. cj += cjEnvironment;
  1886. GREGETPRINTERDRIVER *pGetPrinterDriver;
  1887. pGetPrinterDriver = (GREGETPRINTERDRIVER*)PALLOCMEM(cj, 'lpsG');
  1888. if( pGetPrinterDriver )
  1889. {
  1890. pGetPrinterDriver->cj = cj;
  1891. pGetPrinterDriver->cjData = cbBuf;
  1892. pGetPrinterDriver->dwLevel = dwLevel;
  1893. if( pEnvironment )
  1894. {
  1895. memcpy(pGetPrinterDriver->alData,pEnvironment,cjEnvironment);
  1896. }
  1897. GREGETPRINTERDRIVER *pGetPrinterDriverReturn = NULL;
  1898. UINT cjSize = cbBuf + sizeof(GREGETPRINTERDRIVER);
  1899. pGetPrinterDriverReturn = (GREGETPRINTERDRIVER*) PALLOCNOZ(cjSize, 'lpsG');
  1900. if( pGetPrinterDriverReturn )
  1901. {
  1902. bRet = GreGetPrinterDriverW(hPrinter,pGetPrinterDriver, pGetPrinterDriverReturn, cjSize );
  1903. DWORD cjData = pGetPrinterDriverReturn->cjData;
  1904. if (bRet == FALSE)
  1905. {
  1906. if (cjData > cbBuf)
  1907. {
  1908. // need to return the size needed.
  1909. *pcbNeeded = pGetPrinterDriverReturn->cjData;
  1910. }
  1911. }
  1912. else
  1913. {
  1914. ASSERTGDI(cjData <= cbBuf,"GetPrinterDriverW - error\n");
  1915. // return the size needed whether everything fits or not
  1916. *pcbNeeded = cjData;
  1917. // only copy data and return success if everything fits
  1918. switch (dwLevel) {
  1919. case 1:
  1920. pOffsets = DriverInfo1Offsets;
  1921. pStrings = DriverInfo1Strings;
  1922. break;
  1923. case 2:
  1924. pOffsets = DriverInfo2Offsets;
  1925. pStrings = DriverInfo2Strings;
  1926. break;
  1927. case 3:
  1928. pOffsets = DriverInfo3Offsets;
  1929. pStrings = DriverInfo3Strings;
  1930. break;
  1931. default:
  1932. // We should not get here
  1933. ASSERTGDI(0, "GetPrinterDriverW invalid level\n");
  1934. }
  1935. if (lpbDrvInfo)
  1936. {
  1937. memcpy( lpbDrvInfo, pGetPrinterDriverReturn->alData, cjData );
  1938. MarshallUpStructure((LPBYTE)lpbDrvInfo, pOffsets);
  1939. if ( !ValidateStrings((LPBYTE)lpbDrvInfo, pStrings, cjData) ||
  1940. (dwLevel == 3 &&
  1941. ((PDRIVER_INFO_3W) lpbDrvInfo)->pDependentFiles &&
  1942. !ValidateDependentFiles(((PDRIVER_INFO_3W) lpbDrvInfo)->pDependentFiles,
  1943. (LPBYTE)lpbDrvInfo, cjData) ) ) {
  1944. WARNING("GetPrinterDriverW: String does not fit in buffer\n");
  1945. bRet = FALSE;
  1946. }
  1947. }
  1948. }
  1949. VFREEMEM(pGetPrinterDriverReturn);
  1950. }
  1951. VFREEMEM(pGetPrinterDriver);
  1952. }
  1953. return(bRet);
  1954. }
  1955. /******************************Public*Routine******************************\
  1956. *
  1957. * Routine Name:
  1958. *
  1959. * EngGetPrinterDriver
  1960. *
  1961. * Routine Description:
  1962. *
  1963. * Arguments:
  1964. *
  1965. * Called by:
  1966. *
  1967. * Return Value:
  1968. *
  1969. \**************************************************************************/
  1970. extern "C" BOOL APIENTRY EngGetPrinterDriver(
  1971. HANDLE hPrinter
  1972. , LPWSTR pEnvironment
  1973. , DWORD dwLevel
  1974. , BYTE *lpbDrvInfo
  1975. , DWORD cbBuf
  1976. , DWORD *pcbNeeded
  1977. )
  1978. {
  1979. BOOL ReturnValue;
  1980. ReturnValue = GetPrinterDriverW(
  1981. hPrinter
  1982. , pEnvironment
  1983. , dwLevel
  1984. , lpbDrvInfo
  1985. , cbBuf
  1986. , pcbNeeded
  1987. );
  1988. return( ReturnValue );
  1989. }
  1990. /*******************************************************************************
  1991. * EngGetPrinterDataW()
  1992. *
  1993. * History:
  1994. * 25-Jul-95 by Steve Wilson [swilson]
  1995. * Wrote it.
  1996. *******************************************************************************/
  1997. DWORD
  1998. WINAPI
  1999. EngGetPrinterData(
  2000. HANDLE hPrinter, // IN
  2001. LPWSTR pValueName, // IN
  2002. LPDWORD pType, // OUT -- may be NULL
  2003. LPBYTE lpbData, // OUT
  2004. DWORD cbBuf, // IN
  2005. LPDWORD pcbNeeded // OUT
  2006. )
  2007. {
  2008. LONG cj, cjValueName;
  2009. DWORD cjReturn;
  2010. DWORD dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  2011. GREGETPRINTERDATA *pX, *pXReturn;
  2012. //DbgPrint("Enter EngGetPrinterData\n");
  2013. if (!pcbNeeded)
  2014. {
  2015. EngSetLastError(ERROR_INVALID_PARAMETER);
  2016. return ERROR_INVALID_PARAMETER;
  2017. }
  2018. // Accumulate sizes of base struct plus strings
  2019. cj = sizeof *pX;
  2020. cj += (cjValueName = pValueName ? (wcslen(pValueName) + 1)*sizeof *pValueName : 0);
  2021. // Allocate TO buffer
  2022. pX = (GREGETPRINTERDATA *) PALLOCMEM(cj, 'lpsG');
  2023. // Marshall TO buffer
  2024. if (pX)
  2025. {
  2026. pX->cj = cj;
  2027. pX->cjData = cbBuf; // Client's buffer size
  2028. // Write strings at end of GRE struct
  2029. if (pValueName) {
  2030. memcpy(pX->alData,pValueName,cjValueName);
  2031. pX->cjValueName = cjValueName;
  2032. }
  2033. // Allocate RETURN buffer
  2034. pXReturn = (GREGETPRINTERDATA *) PALLOCNOZ(cjReturn = sizeof *pX + cbBuf, 'lpsG');
  2035. // SEND MESSAGE
  2036. if (pXReturn)
  2037. {
  2038. // GreGenericW return value indicates success or failure of GreEscapeSpool() and KMGetPrinterData()
  2039. GreGenericW( hPrinter,
  2040. (PULONG) pX,
  2041. (PULONG) pXReturn,
  2042. cjReturn,
  2043. (LONG) GDISPOOL_GETPRINTERDATA, 0);
  2044. dwLastError = EngGetLastError();
  2045. // return from GreGenericW may be 0, meaning any number of things, including ERROR_MORE_DATA
  2046. if (dwLastError != ERROR_PROCESS_ABORTED)
  2047. {
  2048. // Fill in return sizes
  2049. if (pcbNeeded)
  2050. {
  2051. *pcbNeeded = pXReturn->dwNeeded; // # return data bytes
  2052. //DbgPrint("EngGetPrinterData *pcbNeeded = %d\n", *pcbNeeded);
  2053. }
  2054. if (pType)
  2055. *pType = pXReturn->dwType;
  2056. if (dwLastError == ERROR_SUCCESS)
  2057. {
  2058. // Copy returned data into supplied structure
  2059. if (lpbData)
  2060. {
  2061. if ((DWORD) pXReturn->cjData <= cbBuf)
  2062. memcpy(lpbData, pXReturn->alData, pXReturn->cjData);
  2063. else
  2064. ASSERTGDI((DWORD) pXReturn->cjData <= cbBuf, "GetPrinterDataW - Bad spooler buffer size\n");
  2065. }
  2066. }
  2067. }
  2068. VFREEMEM(pXReturn);
  2069. }
  2070. VFREEMEM(pX);
  2071. }
  2072. //DbgPrint("GetPrinterData return: %d\n", dwLastError);
  2073. return dwLastError;
  2074. }
  2075. /*******************************************************************************
  2076. * EngSetPrinterData()
  2077. *
  2078. * History:
  2079. * 25-Oct-95 by Steve Wilson [swilson]
  2080. * Wrote it.
  2081. *******************************************************************************/
  2082. DWORD
  2083. WINAPI
  2084. EngSetPrinterData(
  2085. HANDLE hPrinter, // IN
  2086. LPWSTR pType, // IN
  2087. DWORD dwType, // IN
  2088. LPBYTE lpbPrinterData, // IN
  2089. DWORD cjPrinterData // IN
  2090. )
  2091. {
  2092. LONG cj, cjType;
  2093. DWORD cjReturn;
  2094. DWORD dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  2095. GRESETPRINTERDATA *pTo, *pFrom;
  2096. //DbgPrint("Enter EngSetPrinterData\n");
  2097. // Accumulate sizes of base struct plus strings
  2098. cj = sizeof *pTo;
  2099. cj += (cjType = pType ? (wcslen(pType) + 1)*sizeof *pType : 0);
  2100. cj += lpbPrinterData ? cjPrinterData : 0;
  2101. // Allocate TO buffer
  2102. pTo = (GRESETPRINTERDATA *) PALLOCMEM(cj, 'lpsG');
  2103. // Marshall TO buffer
  2104. if (pTo)
  2105. {
  2106. pTo->cj = cj;
  2107. // Write incoming data at end of GRE struct
  2108. if (pType) {
  2109. memcpy(pTo->alData,pType,cjType);
  2110. pTo->cjType = cjType;
  2111. }
  2112. if (lpbPrinterData) {
  2113. memcpy((BYTE *)pTo->alData + cjType,lpbPrinterData,cjPrinterData);
  2114. pTo->cjPrinterData = cjPrinterData;
  2115. }
  2116. // Allocate RETURN buffer
  2117. cjReturn = sizeof *pTo;
  2118. pFrom = (GRESETPRINTERDATA *) PALLOCNOZ(cjReturn, 'lpsG');
  2119. // SEND MESSAGE
  2120. if (pFrom)
  2121. {
  2122. pTo->dwType = dwType;
  2123. // GreGenericW return value indicates success or failure of GreEscapeSpool() and KMGetPrinterData()
  2124. GreGenericW( hPrinter,
  2125. (PULONG) pTo,
  2126. (PULONG) pFrom,
  2127. cjReturn,
  2128. (LONG) GDISPOOL_SETPRINTERDATA, 0);
  2129. dwLastError = EngGetLastError();
  2130. VFREEMEM(pFrom);
  2131. }
  2132. VFREEMEM(pTo);
  2133. }
  2134. //DbgPrint("GetPrinterData return: %d\n", dwLastError);
  2135. return dwLastError;
  2136. }
  2137. /******************************Public*Routine******************************\
  2138. *
  2139. *
  2140. * History:
  2141. * 27-Feb-1995 -by- Eric Kutter [erick]
  2142. * Wrote it.
  2143. \**************************************************************************/
  2144. BOOL
  2145. WINAPI
  2146. EngWritePrinter(
  2147. HANDLE hPrinter,
  2148. LPVOID pBuf,
  2149. DWORD cbBuf,
  2150. LPDWORD pcWritten
  2151. )
  2152. {
  2153. DWORD ulRet = 0;
  2154. SPOOLREF sr(hPrinter);
  2155. if (sr.bValid())
  2156. {
  2157. PSPOOLMSG psm = sr.psm();
  2158. LPVOID pKmBuf = NULL;
  2159. GREWRITEPRINTER *wp = &sr.pso->WritePrinter;
  2160. //DbgPrint("Enter EngWritePrinter\n");
  2161. wp->cj = offsetof(GREWRITEPRINTER,alData) + cbBuf;
  2162. wp->cjData = cbBuf;
  2163. if (gpeSpool == PsGetCurrentProcess() &&
  2164. pBuf <= MM_HIGHEST_USER_ADDRESS &&
  2165. pBuf >= MM_LOWEST_USER_ADDRESS)
  2166. {
  2167. wp->pUserModeData = (PULONG) pBuf;
  2168. wp->cjUserModeData = cbBuf;
  2169. psm->cBuf = 1;
  2170. psm->cjIn = offsetof(GREWRITEPRINTER, alData);
  2171. }
  2172. else
  2173. {
  2174. //
  2175. // if we recevie a user mode buffer, make a kernel copy.
  2176. // This is to patch PSCRIPT 4 driver running on NT5.
  2177. //
  2178. if (pBuf <= MM_HIGHEST_USER_ADDRESS &&
  2179. pBuf >= MM_LOWEST_USER_ADDRESS)
  2180. {
  2181. if (pKmBuf = PALLOCNOZ(cbBuf,'lpsG'))
  2182. {
  2183. __try
  2184. {
  2185. ProbeAndReadBuffer(pKmBuf,pBuf,cbBuf);
  2186. }
  2187. __except(EXCEPTION_EXECUTE_HANDLER)
  2188. {
  2189. VFREEMEM(pKmBuf);
  2190. return (FALSE);
  2191. }
  2192. pBuf = pKmBuf;
  2193. }
  2194. else
  2195. {
  2196. WARNING ("failed to allocate memory in EngWritePrinter\n");
  2197. return (FALSE);
  2198. }
  2199. }
  2200. wp->pUserModeData = NULL;
  2201. wp->cjUserModeData = 0;
  2202. psm->cBuf = 2;
  2203. psm->apulIn[1]= (PULONG)pBuf;
  2204. psm->acjIn[1] = cbBuf;
  2205. psm->cjIn = wp->cj;
  2206. }
  2207. // setup the message
  2208. psm->cj = sizeof(SPOOLMSG);
  2209. psm->iMsg = GDISPOOL_WRITE;
  2210. psm->fl = 0;
  2211. // there are two buffers, one for the GREWRITEPRINTER header and one
  2212. // for the data.
  2213. psm->apulIn[0]= (PULONG)wp;
  2214. psm->acjIn[0] = offsetof(GREWRITEPRINTER,alData);
  2215. // place the return value in ulRet
  2216. psm->pulOut = &sr.pso->dwWritePrinterReturn;
  2217. psm->cjOut = sizeof(sr.pso->dwWritePrinterReturn);
  2218. psm->hso = (HSPOOLOBJ)hPrinter;
  2219. if (!sr.GreEscapeSpool())
  2220. {
  2221. ulRet = 0;
  2222. }
  2223. else
  2224. {
  2225. ulRet = sr.pso->dwWritePrinterReturn;
  2226. }
  2227. if (pcWritten)
  2228. *pcWritten = ulRet;
  2229. if (pKmBuf)
  2230. {
  2231. VFREEMEM(pKmBuf);
  2232. }
  2233. }
  2234. // return TRUE or FALSE
  2235. return(!!ulRet);
  2236. }
  2237. /*******************************************************************************
  2238. * BOOL GetFontPathName( WCHAR *pFullPath, WCHAR *pFileName )
  2239. *
  2240. * Goes to the spooler and does a search path in the font path to find the
  2241. * full path given a font file name. We expect pFullName and pFileName to
  2242. * point to the same piece of memory although we don't require this to be the case.
  2243. *
  2244. * History
  2245. * 7-31-95 Gerrit van Wingerden [gerritv]
  2246. * Wrote it.
  2247. *
  2248. *******************************************************************************/
  2249. BOOL GetFontPathName( WCHAR *pFullPath, WCHAR *pFileName )
  2250. {
  2251. BOOL bRet = FALSE;
  2252. SPOOLMEMOBJ spmo;
  2253. if (spmo.bValid())
  2254. {
  2255. PSPOOLMSG psm = spmo.psm();
  2256. psm->cj = sizeof(SPOOLMSG);
  2257. psm->iMsg = GDISPOOL_GETPATHNAME;
  2258. psm->fl = 0;
  2259. psm->cBuf = 1;
  2260. psm->cjIn = (wcslen(pFileName) + 1) * sizeof(WCHAR);
  2261. psm->apulIn[0] = (PULONG) pFileName;
  2262. psm->acjIn[0] = psm->cjIn;
  2263. psm->pulOut = (PULONG) pFullPath;
  2264. psm->cjOut = sizeof(WCHAR) * (MAX_PATH+1);
  2265. psm->hso = spmo.hGet();
  2266. bRet = spmo.GreEscapeSpool() && psm->ulRet;
  2267. spmo.bDelete();
  2268. }
  2269. return(bRet);
  2270. }
  2271. /******************************Public*Routine******************************\
  2272. * EngEscape()
  2273. *
  2274. * History:
  2275. * 18-Sep-1995 -by- Eric Kutter [erick]
  2276. * Wrote it.
  2277. \**************************************************************************/
  2278. ULONG APIENTRY EngEscape(
  2279. HANDLE hPrinter,
  2280. ULONG iEsc,
  2281. ULONG cjIn,
  2282. PVOID pvIn,
  2283. ULONG cjOut,
  2284. PVOID pvOut)
  2285. {
  2286. BOOL ulRet = FALSE;
  2287. SPOOLREF sr(hPrinter);
  2288. if (sr.bValid())
  2289. {
  2290. PSPOOLMSG psm = sr.psm();
  2291. psm->cj = sizeof(SPOOLMSG);
  2292. psm->iMsg = GDISPOOL_ENDDOCPRINTER;
  2293. psm->fl = 0;
  2294. psm->cBuf = 2;
  2295. psm->cjIn = sizeof(ULONG)+cjIn;
  2296. psm->apulIn[0]= &iEsc;
  2297. psm->acjIn[0] = sizeof(ULONG);
  2298. psm->apulIn[1]= (PULONG)pvIn;
  2299. psm->acjIn[1] = cjIn;
  2300. psm->pulOut = (PULONG)pvOut;
  2301. psm->cjOut = cjOut;
  2302. psm->hso = (HSPOOLOBJ)hPrinter;
  2303. if( sr.GreEscapeSpool() )
  2304. {
  2305. ulRet = (DWORD) psm->ulRet;
  2306. }
  2307. }
  2308. return(ulRet);
  2309. }