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.

850 lines
29 KiB

  1. /*************************************************************************
  2. *
  3. * splkernl.c
  4. *
  5. * This is a modified Microsoft NT 4.0 file from
  6. * \nt\private\windows\spooler\spoolss\server\splkernl.c
  7. *
  8. * This provides for reading spooler requests from printer device drivers
  9. * running in kernel mode under WIN32K.SYS.
  10. *
  11. * WinFrame isolates each WIN32K.SYS and printer device driver into its
  12. * own independent WINSTATION SPACE. Because of this, the threads that
  13. * run inside of the spool subsystem can only read the requests from
  14. * printer drivers running on the console.
  15. *
  16. * This module has been moved to CSRSS to read the requests out for this
  17. * WINSTATION, and then convert them to RPC calls onto the spooler.
  18. *
  19. * NOTE: The kernel mode spooler requests take a different path than
  20. * pure RPC requests. The console will continue to run this way. On
  21. * WINSTATIONS, all print spooler interaction will be through RPC
  22. * like NT 3.51.
  23. *
  24. * Also there is a new printer UI type that processing when a page
  25. * or job is printed. These are OEM supplied for things like FAX
  26. * servers. If they attempt to do any Windows dialogs or pop-ups
  27. * they will only show up on the console. By having them be inside
  28. * of the WINSTATIONS CSRSS they will pop up on the proper WINSTATION.
  29. *
  30. * copyright notice: Copyright 1997, Microsoft
  31. *
  32. * Author:
  33. *
  34. *************************************************************************/
  35. /*++
  36. Copyright (c) 1990 Microsoft Corporation
  37. Module Name:
  38. splkernl.c
  39. Abstract:
  40. This module contains the Spooler's Kernel mode message router and unmarshalling functions,
  41. which then call kmxxx().
  42. Author:
  43. Steve Wilson (NT) (swilson) 1-Jun-1995
  44. [Notes:]
  45. optional-notes
  46. Revision History:
  47. Nicolas Biju-Duval Dec-97 : adaptation for Hydra
  48. --*/
  49. #include "precomp.h"
  50. #pragma hdrstop
  51. #include <ntddrdr.h>
  52. #include <stdio.h>
  53. #include <windows.h>
  54. #include <winspool.h>
  55. #include <ntgdispl.h>
  56. #include "winspl.h"
  57. #include "wingdip.h"
  58. #include "musspl.h"
  59. #include "kmsplapi.h"
  60. #include "winuserk.h"
  61. extern CRITICAL_SECTION ThreadCriticalSection;
  62. #define IN_BUF_SIZE 4500 // must be at least 4096
  63. #define OUT_BUF_SIZE 1024
  64. #define DECREMENT 0
  65. #define INCREMENT 1
  66. #define MAX_GRE_STRUCT_SIZE 100 // At least the size of the largest GRExxx struct in ntgdispl.h
  67. BOOL LoadWinspoolDrv();
  68. DWORD cGetSpoolMessage(PSPOOLESC psesc, DWORD cjMsg, PDWORD pulOut, DWORD cjOut);
  69. BOOL SpoolerGetSpoolMessage();
  70. BOOL DoOpenPrinter(PSPOOLESC psesc, HANDLE*, DWORD*);
  71. BOOL DoGetPrinter(PSPOOLESC psesc, GREGETPRINTER *pGetPrinterReturn, DWORD *pcjOut);
  72. BOOL DoGetPrinterDriver( PSPOOLESC, GREGETPRINTERDRIVER*, DWORD* );
  73. BOOL DoStartDocPrinter( PSPOOLESC psesc );
  74. BOOL DoWritePrinter(PSPOOLESC psesc, DWORD *pWritten );
  75. BOOL DoGetForm(PSPOOLESC psesc, GREGETFORM *pGetFormReturn, DWORD *pcjOut);
  76. BOOL DoEnumForms(PSPOOLESC psesc, GREENUMFORMS *pEnumFormsReturn, DWORD *pcjOut);
  77. BOOL DoGetPrinterData(PSPOOLESC psesc, GREGETPRINTERDATA *pXReturn, DWORD *pcjOut);
  78. BOOL DoSetPrinterData(PSPOOLESC psesc, GRESETPRINTERDATA *pXReturn, DWORD *pcjOut);
  79. BOOL DoGetPathName(WCHAR *pwcSrc, WCHAR *pwcDst, DWORD cbDst, DWORD *pcjWritten);
  80. DWORD GetSpoolMessages();
  81. DWORD AddThread();
  82. LONG nIdleThreads = 0; // Number of idle threads
  83. LONG nThreads = 0;
  84. SYSTEMTIME LastMessageTime; // Time at which last message was received
  85. //*************************************************************
  86. //
  87. // LoadWinspoolDrv
  88. //
  89. // This function is called at initialization, just to make sure
  90. // that there is enough memory available. This is a little weird:
  91. // we just want to load winspool.drv, but the obtained pointers
  92. // will never be used. By doing that we are protected against
  93. // the risk of not being able to load winspool.drv later.
  94. //
  95. //*************************************************************
  96. BOOL LoadWinspoolDrv()
  97. {
  98. BOOL bRet = FALSE;
  99. HANDLE hWinspoolDll = NULL;
  100. hWinspoolDll = LoadLibraryW(L"winspool.drv");
  101. if (hWinspoolDll != NULL) // winspool.drv OK, now get the addresses
  102. {
  103. fpOpenPrinterW = (FPOPENPRINTERW) GetProcAddress( hWinspoolDll, "OpenPrinterW");
  104. fpGetPrinterW = (FPGETPRINTERW) GetProcAddress( hWinspoolDll, "GetPrinterW");
  105. fpGetPrinterDriverW = (FPGETPRINTERDRIVERW)GetProcAddress( hWinspoolDll, "GetPrinterDriverW");
  106. fpGetPrinterDataW = (FPGETPRINTERDATAW) GetProcAddress( hWinspoolDll, "GetPrinterDataW");
  107. fpSetPrinterDataW = (FPSETPRINTERDATAW) GetProcAddress( hWinspoolDll, "SetPrinterDataW");
  108. fpGetFormW = (FPGETFORMW) GetProcAddress( hWinspoolDll, "GetFormW");
  109. fpEnumFormsW = (FPENUMFORMSW) GetProcAddress( hWinspoolDll, "EnumFormsW");
  110. fpClosePrinter = (FPCLOSEPRINTER) GetProcAddress( hWinspoolDll, "ClosePrinter");
  111. fpStartDocPrinterW = (FPSTARTDOCPRINTERW)GetProcAddress( hWinspoolDll, "StartDocPrinterW");
  112. fpStartPagePrinter = (FPSTARTPAGEPRINTER)GetProcAddress( hWinspoolDll, "StartPagePrinter");
  113. fpWritePrinter = (FPWRITEPRINTER) GetProcAddress( hWinspoolDll, "WritePrinter");
  114. fpAbortPrinter = (FPABORTPRINTER) GetProcAddress( hWinspoolDll, "AbortPrinter");
  115. fpEndPagePrinter = (FPENDPAGEPRINTER) GetProcAddress( hWinspoolDll, "EndPagePrinter");
  116. fpEndDocPrinter = (FPENDDOCPRINTER) GetProcAddress( hWinspoolDll, "EndDocPrinter");
  117. if ((fpOpenPrinterW != NULL) &&
  118. (fpGetPrinterW != NULL) &&
  119. (fpGetPrinterDriverW != NULL) &&
  120. (fpGetPrinterDataW != NULL) &&
  121. (fpSetPrinterDataW != NULL) &&
  122. (fpGetFormW != NULL) &&
  123. (fpEnumFormsW != NULL) &&
  124. (fpClosePrinter != NULL) &&
  125. (fpStartDocPrinterW != NULL) &&
  126. (fpStartPagePrinter != NULL) &&
  127. (fpWritePrinter != NULL) &&
  128. (fpAbortPrinter != NULL) &&
  129. (fpEndPagePrinter != NULL) &&
  130. (fpEndDocPrinter != NULL) )
  131. {
  132. bRet = TRUE; // everything is OK. We are ready to call winspool.drv
  133. }
  134. else
  135. {
  136. bRet = FALSE;
  137. FreeLibrary(hWinspoolDll);
  138. }
  139. }
  140. return bRet;
  141. }
  142. //
  143. // GetSpoolMessages - Manages creation & deletion of spooler message threads
  144. //
  145. DWORD GetSpoolMessages()
  146. {
  147. if (!GdiInitSpool()) {
  148. DBGMSG(DBG_TRACE, ("Error calling GdiInitSpool()\n"));
  149. return GetLastError();
  150. }
  151. if (!LoadWinspoolDrv())
  152. {
  153. DBGMSG(DBG_TRACE, ("Unable to load Winspool.drv\n"));
  154. return GetLastError();
  155. }
  156. return AddThread();
  157. }
  158. DWORD AddThread()
  159. {
  160. HANDLE hThread;
  161. DWORD MessageThreadId;
  162. DWORD dwError;
  163. try {
  164. if(hThread = CreateThread( NULL,
  165. 64*1024,
  166. (LPTHREAD_START_ROUTINE) SpoolerGetSpoolMessage,
  167. 0,
  168. 0,
  169. &MessageThreadId)) {
  170. CloseHandle(hThread);
  171. dwError = ERROR_SUCCESS;
  172. } else {
  173. dwError = GetLastError();
  174. }
  175. } except(EXCEPTION_EXECUTE_HANDLER) {
  176. dwError = TranslateExceptionCode(GetExceptionCode());
  177. }
  178. return dwError;
  179. }
  180. BOOL SpoolerGetSpoolMessage()
  181. {
  182. DWORD dwResult;
  183. PSPOOLESC pInput; // Input buffer that receives messages from Kernel
  184. BYTE *pOutput; // Output buffer that receives data from KMxxx() spooler calls
  185. BYTE *pMem;
  186. DWORD cbOut = 0; // Size of pOutput
  187. DWORD cbIn = IN_BUF_SIZE; // Size of pInput buffer in bytes
  188. DWORD cbOutSize;
  189. USERTHREAD_USEDESKTOPINFO utudi = { 0 };
  190. BOOL bHaveDesktop = FALSE;
  191. (VOID) CsrConnectToUser();
  192. if(!(pInput = (PSPOOLESC) AllocSplMem(cbIn))) {
  193. DBGMSG(DBG_WARNING, ("Error allocating pInput in SpoolerGetSpoolMessage\n"));
  194. return FALSE;
  195. }
  196. if(!(pOutput = AllocSplMem(OUT_BUF_SIZE))) {
  197. FreeSplMem(pInput);
  198. DBGMSG(DBG_WARNING, ("Error allocating pInput in SpoolerGetSpoolMessage\n"));
  199. return FALSE;
  200. }
  201. cbOutSize = OUT_BUF_SIZE;
  202. EnterCriticalSection(&ThreadCriticalSection);
  203. ++nThreads;
  204. LeaveCriticalSection(&ThreadCriticalSection);
  205. while(1) {
  206. EnterCriticalSection(&ThreadCriticalSection);
  207. ++nIdleThreads;
  208. LeaveCriticalSection(&ThreadCriticalSection);
  209. dwResult = GdiGetSpoolMessage(pInput,cbIn,(PDWORD)pOutput,cbOut);
  210. EnterCriticalSection(&ThreadCriticalSection);
  211. --nIdleThreads;
  212. LeaveCriticalSection(&ThreadCriticalSection);
  213. if(dwResult) {
  214. if( (pInput->iMsg != GDISPOOL_TERMINATETHREAD) &&
  215. (pInput->iMsg != GDISPOOL_INPUT2SMALL)) {
  216. EnterCriticalSection(&ThreadCriticalSection);
  217. if(nIdleThreads == 0) {
  218. AddThread();
  219. DBGMSG(DBG_TRACE, ("Thread Added: nIdle = %d nThreads = %d\n", nIdleThreads, nThreads));
  220. }
  221. LeaveCriticalSection(&ThreadCriticalSection);
  222. }
  223. // check if the out buffer needs to be grown or shrunk.
  224. if ((pInput->cjOut + MAX_GRE_STRUCT_SIZE) > cbOutSize) {
  225. FreeSplMem(pOutput);
  226. pOutput = AllocSplMem(cbOutSize = pInput->cjOut + MAX_GRE_STRUCT_SIZE);
  227. if (!pOutput) {
  228. DBGMSG(DBG_WARNING, ("Error allocating pInput in SpoolerGetSpoolMessage\n"));
  229. pInput->ulRet = 0;
  230. cbOut = 0;
  231. cbOutSize = 0;
  232. continue;
  233. }
  234. }
  235. else if ((pInput->cjOut < OUT_BUF_SIZE) &&
  236. (cbOutSize > OUT_BUF_SIZE)) {
  237. // we want to shrink the buffer
  238. PBYTE pbTmp = AllocSplMem(OUT_BUF_SIZE);
  239. if (pbTmp) {
  240. FreeSplMem(pOutput);
  241. pOutput = pbTmp;
  242. cbOutSize = OUT_BUF_SIZE;
  243. }
  244. }
  245. if (pInput->iMsg & GDISPOOL_API) {
  246. SPLASSERT(pInput->hSpool || pInput->iMsg == GDISPOOL_OPENPRINTER);
  247. if (pInput->iMsg != GDISPOOL_OPENPRINTER || pInput->hSpool) {
  248. if (InterlockedIncrement(&((PSPOOL)pInput->hSpool)->cThreads) > 0) {
  249. // We are already processing a message & have now gotten a ClosePrinter
  250. // We should not get here on any other API
  251. SPLASSERT(pInput->iMsg == GDISPOOL_CLOSEPRINTER);
  252. pInput->ulRet = TRUE; // Let Client terminate
  253. continue;
  254. }
  255. }
  256. }
  257. //
  258. // This is a Csrss thread with no desktop. It needs to grab a temporary one
  259. // before calling into win32k so set a desktop in case there is a user mode
  260. // print driver that wants to write to a desktop (ie dialog box messages).
  261. //
  262. utudi.hThread = NULL;
  263. utudi.drdRestore.pdeskRestore = NULL;
  264. bHaveDesktop = ((NtUserSetInformationThread(
  265. NtCurrentThread(),
  266. UserThreadUseActiveDesktop,
  267. &utudi,
  268. sizeof(utudi)) == STATUS_SUCCESS) ? TRUE : FALSE );
  269. switch (pInput->iMsg) {
  270. case GDISPOOL_INPUT2SMALL:
  271. DBGMSG(DBG_TRACE,(" - buffer not big enough\n"));
  272. pMem = ReallocSplMem(pInput, cbIn, pInput->cjOut);
  273. if (!pMem) {
  274. DBGMSG(DBG_WARNING, ("Error reallocating pInput in SpoolerGetSpoolMessage\n"));
  275. pInput->ulRet = 0;
  276. }
  277. else {
  278. pInput = (PSPOOLESC) pMem;
  279. cbIn = pInput->cjOut;
  280. pInput->ulRet = 1;
  281. }
  282. break;
  283. case GDISPOOL_TERMINATETHREAD:
  284. EnterCriticalSection(&ThreadCriticalSection);
  285. // There is 1 way to get here: from a 10 minute Kernel Event timeout
  286. if(nIdleThreads > 1) {
  287. --nThreads;
  288. if (nThreads == 0) {
  289. DBGMSG(DBG_WARNING, ("SpoolerGetSpoolMessage nThreads is now ZERO\n"));
  290. }
  291. DBGMSG(DBG_TRACE, ("Thread Deleted: nIdle = %d nThreads = %d\n", nIdleThreads, nThreads));
  292. LeaveCriticalSection(&ThreadCriticalSection);
  293. FreeSplMem(pInput);
  294. FreeSplMem(pOutput);
  295. return TRUE;
  296. }
  297. LeaveCriticalSection(&ThreadCriticalSection);
  298. break;
  299. #ifdef _IA64_
  300. case GDISPOOL_WRITE:
  301. case GDISPOOL_OPENPRINTER:
  302. case GDISPOOL_STARTDOCPRINTER:
  303. case GDISPOOL_STARTPAGEPRINTER:
  304. case GDISPOOL_ENDPAGEPRINTER:
  305. case GDISPOOL_ENDDOCPRINTER:
  306. case GDISPOOL_ENUMFORMS:
  307. case GDISPOOL_GETPRINTER:
  308. case GDISPOOL_GETFORM:
  309. case GDISPOOL_GETPRINTERDRIVER:
  310. case GDISPOOL_GETPRINTERDATA:
  311. case GDISPOOL_SETPRINTERDATA:
  312. case GDISPOOL_ABORTPRINTER:
  313. case GDISPOOL_CLOSEPRINTER:
  314. case GDISPOOL_GETPATHNAME:
  315. //
  316. // We should normally never get here. We do not support KMPD on IA64.
  317. // However, GDI may try to take the route of KM messaging, if OpenPrinter
  318. // for a queue using a UMPD fails. This can happen under stress conditons.
  319. // For this reason we handle the KM request on IA64.
  320. //
  321. pInput->ulRet = FALSE;
  322. SetLastError(ERROR_NOT_SUPPORTED);
  323. break;
  324. #else
  325. case GDISPOOL_WRITE:
  326. DBGMSG(DBG_TRACE,(" - GDISPOOL_WRITE\n"));
  327. pInput->ulRet = DoWritePrinter( pInput, (DWORD*) pOutput );
  328. cbOut = sizeof(DWORD);
  329. break;
  330. case GDISPOOL_OPENPRINTER:
  331. DBGMSG(DBG_TRACE,(" - GDISPOOL_OPENPRINTER\n"));
  332. DoOpenPrinter(pInput,(HANDLE*)pOutput,&cbOut);
  333. break;
  334. case GDISPOOL_STARTDOCPRINTER:
  335. DBGMSG(DBG_TRACE,(" - GDISPOOL_STARTDOCPRINTER\n"));
  336. DoStartDocPrinter(pInput);
  337. break;
  338. case GDISPOOL_STARTPAGEPRINTER:
  339. DBGMSG(DBG_TRACE,(" - GDISPOOL_STARTPAGEPRINTER\n"));
  340. pInput->ulRet = KMStartPagePrinter( pInput->hSpool );
  341. break;
  342. case GDISPOOL_ENDPAGEPRINTER:
  343. DBGMSG(DBG_TRACE,(" - GDISPOOL_ENDPAGEPRINTER\n"));
  344. pInput->ulRet = KMEndPagePrinter( pInput->hSpool );
  345. break;
  346. case GDISPOOL_ENDDOCPRINTER:
  347. DBGMSG(DBG_TRACE,(" - GDISPOOL_ENDDOCPRINTER\n"));
  348. pInput->ulRet = KMEndDocPrinter( pInput->hSpool );
  349. break;
  350. case GDISPOOL_ENUMFORMS:
  351. DBGMSG(DBG_TRACE,(" - GDISPOOL_ENUMFORMS\n"));
  352. DoEnumForms(pInput, (GREENUMFORMS *) pOutput, &cbOut);
  353. break;
  354. case GDISPOOL_GETPRINTER:
  355. DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPRINTER\n"));
  356. DoGetPrinter(pInput, (GREGETPRINTER *) pOutput, &cbOut);
  357. break;
  358. case GDISPOOL_GETFORM:
  359. DBGMSG(DBG_TRACE,(" - GDISPOOL_GETFORM\n"));
  360. DoGetForm(pInput, (GREGETFORM *) pOutput, &cbOut);
  361. break;
  362. case GDISPOOL_GETPRINTERDRIVER:
  363. DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPRINTERDRIVER\n"));
  364. DoGetPrinterDriver(pInput,(GREGETPRINTERDRIVER*)pOutput,&cbOut);
  365. break;
  366. case GDISPOOL_GETPRINTERDATA:
  367. DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPRINTERDATA\n"));
  368. DoGetPrinterData(pInput,(GREGETPRINTERDATA *) pOutput,&cbOut);
  369. break;
  370. case GDISPOOL_SETPRINTERDATA:
  371. DBGMSG(DBG_TRACE,(" - GDISPOOL_SETPRINTERDATA\n"));
  372. DoSetPrinterData(pInput,(GRESETPRINTERDATA *) pOutput,&cbOut);
  373. break;
  374. case GDISPOOL_ABORTPRINTER:
  375. DBGMSG(DBG_TRACE,(" - GDISPOOL_ABORTPRINTER\n"));
  376. pInput->ulRet = KMAbortPrinter( pInput->hSpool );
  377. break;
  378. case GDISPOOL_CLOSEPRINTER:
  379. DBGMSG(DBG_TRACE,(" - GDISPOOL_CLOSEPRINTER\n"));
  380. pInput->ulRet = KMClosePrinter( pInput->hSpool );
  381. break;
  382. case GDISPOOL_GETPATHNAME:
  383. DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPATHNAME\n"));
  384. pInput->ulRet = DoGetPathName((WCHAR*)pInput->ajData,
  385. (WCHAR*)pOutput,
  386. cbOutSize,
  387. &cbOut);
  388. break;
  389. #endif
  390. default:
  391. DBGMSG(DBG_ERROR,(" - invalid message\n"));
  392. break;
  393. }
  394. //
  395. // Release the temporary desktop
  396. //
  397. if (bHaveDesktop) {
  398. (VOID)NtUserSetInformationThread(NtCurrentThread(),
  399. UserThreadUseDesktop,
  400. &utudi,
  401. sizeof(utudi));
  402. }
  403. if ((pInput->iMsg & GDISPOOL_API) &&
  404. pInput->iMsg != GDISPOOL_CLOSEPRINTER &&
  405. pInput->iMsg != GDISPOOL_OPENPRINTER &&
  406. pInput->hSpool) {
  407. if (InterlockedDecrement(&((PSPOOL)pInput->hSpool)->cThreads) == 0) {
  408. DBGMSG(DBG_TRACE,(" - GDISPOOL_CLOSEPRINTER\n"));
  409. #ifdef _IA64_
  410. pInput->ulRet = FALSE;
  411. SetLastError(ERROR_NOT_SUPPORTED);
  412. #else
  413. pInput->ulRet = KMClosePrinter( pInput->hSpool );
  414. #endif
  415. }
  416. }
  417. }
  418. }
  419. }
  420. BOOL DoOpenPrinter(PSPOOLESC psesc, HANDLE* phPrinter, DWORD* pcjOut)
  421. {
  422. LPWSTR pPrinterName = NULL;
  423. PRINTER_DEFAULTSW pDefault;
  424. GREOPENPRINTER *pOpenPrinter = (GREOPENPRINTER *)psesc->ajData;
  425. PLONG plData;
  426. plData = pOpenPrinter->alData;
  427. pDefault = pOpenPrinter->pd;
  428. // see if there is a printer name?
  429. if (pOpenPrinter->cjName)
  430. {
  431. pPrinterName = (PWCHAR)plData;
  432. plData += pOpenPrinter->cjName/4;
  433. }
  434. // now setup the printer defaults
  435. if (pOpenPrinter->cjDatatype)
  436. {
  437. pDefault.pDatatype = (PWCHAR)plData;
  438. plData += pOpenPrinter->cjDatatype/4;
  439. }
  440. if (pOpenPrinter->cjDevMode)
  441. {
  442. pDefault.pDevMode = (PDEVMODEW)plData;
  443. }
  444. DBGMSG(DBG_TRACE,
  445. ("OpenPrinter(%ls,%ls,%lx,%d)\n",
  446. pPrinterName,
  447. pDefault.pDatatype,
  448. pDefault.pDevMode,
  449. pDefault.DesiredAccess) );
  450. psesc->ulRet = KMOpenPrinterW(pPrinterName,phPrinter,&pDefault);
  451. DBGMSG( DBG_TRACE,("OpenPrinter returned = %lx\n",psesc->ulRet));
  452. *pcjOut = sizeof(DWORD);
  453. if(psesc->ulRet)
  454. return TRUE;
  455. else
  456. return FALSE;
  457. }
  458. BOOL DoStartDocPrinter( PSPOOLESC psesc )
  459. {
  460. DOC_INFO_1W di;
  461. GRESTARTDOCPRINTER *pStartDocPrinter = (GRESTARTDOCPRINTER *)psesc->ajData;
  462. PLONG plData;
  463. plData = pStartDocPrinter->alData;
  464. // see if there is a printer name?
  465. if (pStartDocPrinter->cjDocName)
  466. {
  467. di.pDocName = (PWCHAR)plData;
  468. plData += pStartDocPrinter->cjDocName/4;
  469. }
  470. else
  471. {
  472. di.pDocName = NULL;
  473. }
  474. if (pStartDocPrinter->cjOutputFile)
  475. {
  476. di.pOutputFile = (PWCHAR)plData;
  477. plData += pStartDocPrinter->cjOutputFile/4;
  478. }
  479. else
  480. {
  481. di.pOutputFile = NULL;
  482. }
  483. if (pStartDocPrinter->cjDatatype)
  484. {
  485. di.pDatatype = (PWCHAR)plData;
  486. plData += pStartDocPrinter->cjDatatype/4;
  487. }
  488. else
  489. {
  490. di.pDatatype = NULL;
  491. }
  492. psesc->ulRet = KMStartDocPrinterW(psesc->hSpool, 1, (LPBYTE) &di);
  493. if(psesc->ulRet)
  494. return TRUE;
  495. else
  496. return FALSE;
  497. }
  498. BOOL DoEnumForms(
  499. PSPOOLESC psesc,
  500. GREENUMFORMS *pEnumFormsReturn,
  501. DWORD *pcjOut
  502. )
  503. {
  504. GREENUMFORMS *pEnumForms = (GREENUMFORMS *) psesc->ajData;
  505. DWORD dwNeeded = 0;
  506. psesc->ulRet = KMEnumFormsW ( psesc->hSpool,
  507. pEnumForms->dwLevel,
  508. (BYTE *) pEnumFormsReturn->alData,
  509. pEnumForms->cjData,
  510. &dwNeeded,
  511. &pEnumFormsReturn->nForms
  512. );
  513. if (psesc->ulRet) {
  514. // Set return data size to incoming buffer size since strings are packed at end of in buffer
  515. pEnumFormsReturn->cjData = pEnumForms->cjData;
  516. *pcjOut = pEnumForms->cjData + sizeof(GREENUMFORMS);
  517. }
  518. else {
  519. pEnumFormsReturn->cjData = dwNeeded; // This makes client alloc more than needed
  520. *pcjOut = sizeof(GREENUMFORMS);
  521. }
  522. return psesc->ulRet;
  523. }
  524. BOOL DoGetPrinter(
  525. PSPOOLESC psesc,
  526. GREGETPRINTER *pGetPrinterReturn,
  527. DWORD *pcjOut
  528. )
  529. {
  530. GREGETPRINTER *pGetPrinter = (GREGETPRINTER *) psesc->ajData;
  531. DWORD dwNeeded = 0;
  532. psesc->ulRet = KMGetPrinterW ( psesc->hSpool,
  533. pGetPrinter->dwLevel,
  534. (BYTE *) pGetPrinterReturn->alData,
  535. pGetPrinter->cjData,
  536. &dwNeeded
  537. );
  538. if (psesc->ulRet) {
  539. // Set return data size to incoming buffer size since strings are packed at end of in buffer
  540. pGetPrinterReturn->cjData = pGetPrinter->cjData;
  541. *pcjOut = pGetPrinter->cjData + sizeof(GREGETPRINTER);
  542. }
  543. else {
  544. pGetPrinterReturn->cjData = dwNeeded; // This makes client alloc more than needed
  545. *pcjOut = sizeof(GREGETPRINTER);
  546. }
  547. return psesc->ulRet;
  548. }
  549. BOOL DoGetForm(
  550. PSPOOLESC psesc,
  551. GREGETFORM *pGetFormReturn,
  552. DWORD *pcjOut
  553. )
  554. {
  555. GREGETFORM *pGetForm = (GREGETFORM *) psesc->ajData;
  556. DWORD dwNeeded = 0;
  557. psesc->ulRet = KMGetFormW ( psesc->hSpool,
  558. pGetForm->cjFormName ? (PWCHAR) pGetForm->alData : NULL,
  559. pGetForm->dwLevel,
  560. (BYTE *) pGetFormReturn->alData,
  561. pGetForm->cjData,
  562. &dwNeeded
  563. );
  564. if (psesc->ulRet) {
  565. // Set return data size to incoming buffer size since strings are packed at end of in buffer
  566. pGetFormReturn->cjData = pGetForm->cjData;
  567. *pcjOut = pGetForm->cjData + sizeof(GREGETFORM);
  568. }
  569. else {
  570. pGetFormReturn->cjData = dwNeeded; // This makes client alloc more than needed
  571. *pcjOut = sizeof(GREGETFORM);
  572. }
  573. return psesc->ulRet;
  574. }
  575. BOOL DoGetPrinterDriver(
  576. PSPOOLESC psesc,
  577. GREGETPRINTERDRIVER *pGetPrinterDriverReturn,
  578. DWORD *pcjOut
  579. )
  580. {
  581. GREGETPRINTERDRIVER *pGetPrinterDriver = (GREGETPRINTERDRIVER *)psesc->ajData;
  582. DWORD dwNeeded = 0;
  583. psesc->ulRet = KMGetPrinterDriverW(psesc->hSpool,
  584. pGetPrinterDriver->cjEnv ? (PWCHAR)pGetPrinterDriver->alData : NULL,
  585. pGetPrinterDriver->dwLevel,
  586. (BYTE*)pGetPrinterDriverReturn->alData,
  587. pGetPrinterDriver->cjData,
  588. &dwNeeded );
  589. if (psesc->ulRet)
  590. {
  591. pGetPrinterDriverReturn->cjData = pGetPrinterDriver->cjData; // fix for ValidateStrings in spool.cxx
  592. *pcjOut = pGetPrinterDriver->cjData + sizeof(GREGETPRINTERDRIVER);
  593. }
  594. else
  595. {
  596. // we failed so just return the size
  597. pGetPrinterDriverReturn->cjData = dwNeeded;
  598. *pcjOut = sizeof(GREGETPRINTERDRIVER);
  599. }
  600. if(psesc->ulRet)
  601. return TRUE;
  602. return FALSE;
  603. }
  604. BOOL DoGetPrinterData(
  605. PSPOOLESC psesc,
  606. GREGETPRINTERDATA *pXReturn,
  607. DWORD *pcjOut
  608. )
  609. {
  610. GREGETPRINTERDATA *pX = (GREGETPRINTERDATA *) psesc->ajData;
  611. DWORD dwNeeded = 0;
  612. DWORD dwType;
  613. psesc->ulRet = KMGetPrinterDataW( psesc->hSpool,
  614. pX->cjValueName ? (PWCHAR) pX->alData : NULL,
  615. &dwType,
  616. (BYTE *) pXReturn->alData,
  617. pX->cjData,
  618. &dwNeeded );
  619. pXReturn->dwNeeded = dwNeeded;
  620. pXReturn->cjData = pX->cjData;
  621. *pcjOut = pX->cjData + sizeof *pX;
  622. pXReturn->dwType = dwType;
  623. SetLastError(psesc->ulRet);
  624. return psesc->ulRet = !psesc->ulRet;
  625. }
  626. BOOL DoSetPrinterData(
  627. PSPOOLESC psesc,
  628. GRESETPRINTERDATA *pXReturn,
  629. DWORD *pcjOut
  630. )
  631. {
  632. GRESETPRINTERDATA *pX = (GRESETPRINTERDATA *) psesc->ajData;
  633. psesc->ulRet = KMSetPrinterDataW( psesc->hSpool,
  634. pX->cjType ? (PWCHAR) pX->alData : NULL,
  635. pX->dwType,
  636. pX->cjPrinterData ? (BYTE *) pX->alData + pX->cjType : NULL,
  637. pX->cjPrinterData );
  638. *pcjOut = sizeof *pX;
  639. SetLastError(psesc->ulRet);
  640. return psesc->ulRet = !psesc->ulRet;
  641. UNREFERENCED_PARAMETER(pXReturn);
  642. }
  643. BOOL DoWritePrinter(PSPOOLESC psesc, DWORD *pWritten )
  644. {
  645. GREWRITEPRINTER *pWritePrinter;
  646. pWritePrinter = (GREWRITEPRINTER*) psesc->ajData;
  647. if( KMWritePrinter( psesc->hSpool,
  648. (PVOID) pWritePrinter->alData,
  649. pWritePrinter->cjData,
  650. pWritten) )
  651. {
  652. return TRUE;
  653. }
  654. else
  655. {
  656. return FALSE;
  657. }
  658. }
  659. BOOL DoGetPathName( WCHAR *pwcSrc, WCHAR *pwcDst, DWORD cbDst, DWORD *pcjWritten )
  660. {
  661. BOOL bRet;
  662. WCHAR awcFontsDir[MAX_PATH + sizeof(L"\\DOSDEVICES\\")/sizeof(WCHAR)] = {L"\\DOSDEVICES\\"};
  663. bRet = bMakePathNameW (
  664. &awcFontsDir[sizeof(L"\\DOSDEVICES\\")/sizeof(WCHAR) - 1],
  665. pwcSrc,
  666. NULL,
  667. NULL
  668. );
  669. if (bRet)
  670. {
  671. bRet = SUCCEEDED(StringCbCopyW(pwcDst, cbDst, awcFontsDir));
  672. *pcjWritten = sizeof(WCHAR) * (wcslen(awcFontsDir) + 1);
  673. }
  674. //
  675. // Buffer large enough and search successfull?
  676. //
  677. return bRet;
  678. }