Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

891 lines
26 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. All Rights Reserved
  4. Module Name:
  5. splkernl.c
  6. Abstract:
  7. This module contains the Spooler's Kernel mode message router and unmarshalling functions,
  8. which then call kmxxx().
  9. Author:
  10. Steve Wilson (NT) (swilson) 1-Jun-1995
  11. [Notes:]
  12. optional-notes
  13. Revision History:
  14. --*/
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <ntddrdr.h>
  19. #include <stdio.h>
  20. #include <windows.h>
  21. #include <winspool.h>
  22. #include <winsplp.h>
  23. #include <winspl.h>
  24. #include <ntgdispl.h>
  25. #include <offsets.h>
  26. #include "server.h"
  27. #include "client.h"
  28. #include "kmspool.h"
  29. #include "yspool.h"
  30. #include "splr.h"
  31. #include "splsvr.h"
  32. #include "wingdip.h"
  33. #ifndef _SRVRMEM_H_
  34. #include "srvrmem.h"
  35. #endif
  36. #define IN_BUF_SIZE 8192 // must be at least 4096
  37. #define OUT_BUF_SIZE 1024
  38. #define DECREMENT 0
  39. #define INCREMENT 1
  40. #define MAX_GRE_STRUCT_SIZE 100 // At least the size of the largest GRExxx struct in ntgdispl.h
  41. #define WAITFOR_SYSTEM_TO_RECOVER 500
  42. DWORD cGetSpoolMessage(PSPOOLESC psesc, DWORD cjMsg, PDWORD pulOut, DWORD cjOut);
  43. BOOL SpoolerGetSpoolMessage();
  44. BOOL DoOpenPrinter(PSPOOLESC psesc, HANDLE*, DWORD*);
  45. BOOL DoGetPrinter(PSPOOLESC psesc, GREGETPRINTER *pGetPrinterReturn, DWORD *pcjOut);
  46. BOOL DoGetPrinterDriver( PSPOOLESC, GREGETPRINTERDRIVER*, DWORD* );
  47. BOOL DoStartDocPrinter( PSPOOLESC psesc );
  48. BOOL DoWritePrinter(PSPOOLESC psesc, DWORD *pWritten );
  49. BOOL DoGetForm(PSPOOLESC psesc, GREGETFORM *pGetFormReturn, DWORD *pcjOut);
  50. BOOL DoEnumForms(PSPOOLESC psesc, GREENUMFORMS *pEnumFormsReturn, DWORD *pcjOut);
  51. BOOL DoGetPrinterData(PSPOOLESC psesc, GREGETPRINTERDATA *pXReturn, DWORD *pcjOut);
  52. BOOL DoSetPrinterData(PSPOOLESC psesc, GRESETPRINTERDATA *pXReturn, DWORD *pcjOut);
  53. BOOL DoGetPathName( WCHAR *pwcSrc, WCHAR *pwcDst, DWORD *pcjWritten );
  54. BOOL DoDriverUnloadComplete( WCHAR *pDriverFile );
  55. DWORD GetSpoolMessages();
  56. DWORD AddThread();
  57. LONG nIdleThreads = 0; // Number of idle threads
  58. LONG nThreads = 0;
  59. SYSTEMTIME LastMessageTime; // Time at which last message was received
  60. // GetSpoolMessages - Manages creation & deletion of spooler message threads
  61. DWORD GetSpoolMessages()
  62. {
  63. if (!GdiInitSpool()) {
  64. DBGMSG(DBG_TRACE, ("Error calling GdiInitSpool()\n"));
  65. return GetLastError();
  66. }
  67. return AddThread();
  68. }
  69. DWORD AddThread()
  70. {
  71. HANDLE hThread;
  72. DWORD MessageThreadId;
  73. BOOL dwError;
  74. try {
  75. if(hThread = CreateThread( NULL,
  76. LARGE_INITIAL_STACK_COMMIT,
  77. (LPTHREAD_START_ROUTINE) SpoolerGetSpoolMessage,
  78. 0,
  79. 0,
  80. &MessageThreadId)) {
  81. CloseHandle(hThread);
  82. dwError = ERROR_SUCCESS;
  83. } else {
  84. dwError = GetLastError();
  85. }
  86. } except(1) {
  87. dwError = TranslateExceptionCode(GetExceptionCode());
  88. }
  89. return dwError;
  90. }
  91. BOOL SpoolerGetSpoolMessage()
  92. {
  93. DWORD dwResult;
  94. PSPOOLESC pInput; // Input buffer that receives messages from Kernel
  95. BYTE *pOutput; // Output buffer that receives data from KMxxx() spooler calls
  96. BYTE *pMem;
  97. DWORD cbOut = 0; // Size of pOutput
  98. DWORD cbIn = IN_BUF_SIZE; // Size of pInput buffer in bytes
  99. DWORD cbOutSize;
  100. DWORD dwFailureCount = 0;
  101. if(!(pInput = (PSPOOLESC) SrvrAllocSplMem(cbIn))) {
  102. DBGMSG(DBG_WARNING, ("Error allocating pInput in SpoolerGetSpoolMessage\n"));
  103. return FALSE;
  104. }
  105. if(!(pOutput = SrvrAllocSplMem(OUT_BUF_SIZE))) {
  106. SrvrFreeSplMem(pInput);
  107. DBGMSG(DBG_WARNING, ("Error allocating pInput in SpoolerGetSpoolMessage\n"));
  108. return FALSE;
  109. }
  110. cbOutSize = OUT_BUF_SIZE;
  111. EnterCriticalSection(&ThreadCriticalSection);
  112. ++nThreads;
  113. LeaveCriticalSection(&ThreadCriticalSection);
  114. while(1) {
  115. EnterCriticalSection(&ThreadCriticalSection);
  116. ++nIdleThreads;
  117. LeaveCriticalSection(&ThreadCriticalSection);
  118. dwResult = GdiGetSpoolMessage(pInput,cbIn,(PDWORD)pOutput,cbOutSize);
  119. EnterCriticalSection(&ThreadCriticalSection);
  120. --nIdleThreads;
  121. LeaveCriticalSection(&ThreadCriticalSection);
  122. if(dwResult == 0) {
  123. dwFailureCount++;
  124. //
  125. // We can get into this situation where the machine is out of memory
  126. // and GdiGetSpoolMessage fails because it cannot probe the memory for the message.
  127. // Because this thread is to aggressive, it won't give the chance to other threads in the
  128. // system to get executed. Put it to sleep for a couple of seconds when that happens.(bug 192434)
  129. //
  130. if (dwFailureCount > 1) {
  131. Sleep(WAITFOR_SYSTEM_TO_RECOVER * dwFailureCount);
  132. //
  133. // Note: 4 and WAITFOR_SYSTEM_TO_RECOVER has no significance.
  134. // They were arbitrary chosen.
  135. //
  136. dwFailureCount %= 4;
  137. }
  138. } else {
  139. dwFailureCount = 0;
  140. if( (pInput->iMsg != GDISPOOL_TERMINATETHREAD) &&
  141. (pInput->iMsg != GDISPOOL_INPUT2SMALL)) {
  142. EnterCriticalSection(&ThreadCriticalSection);
  143. if(nIdleThreads == 0) {
  144. AddThread();
  145. DBGMSG(DBG_TRACE, ("Thread Added: nIdle = %d nThreads = %d\n", nIdleThreads, nThreads));
  146. }
  147. LeaveCriticalSection(&ThreadCriticalSection);
  148. }
  149. // check if the out buffer needs to be grown or shrunk.
  150. if ((pInput->cjOut + MAX_GRE_STRUCT_SIZE) > cbOutSize) {
  151. SrvrFreeSplMem(pOutput);
  152. pOutput = SrvrAllocSplMem(cbOutSize = pInput->cjOut + MAX_GRE_STRUCT_SIZE);
  153. if (!pOutput) {
  154. DBGMSG(DBG_WARNING, ("Error allocating pInput in SpoolerGetSpoolMessage\n"));
  155. pInput->ulRet = 0;
  156. cbOut = 0;
  157. cbOutSize = 0;
  158. continue;
  159. }
  160. }
  161. else if ((pInput->cjOut < OUT_BUF_SIZE) &&
  162. (cbOutSize > OUT_BUF_SIZE)) {
  163. // we want to shrink the buffer
  164. PBYTE pbTmp = SrvrAllocSplMem(OUT_BUF_SIZE);
  165. if (pbTmp) {
  166. SrvrFreeSplMem(pOutput);
  167. pOutput = pbTmp;
  168. cbOutSize = OUT_BUF_SIZE;
  169. }
  170. }
  171. if (pInput->iMsg & GDISPOOL_API) {
  172. SPLASSERT(pInput->hSpool || pInput->iMsg == GDISPOOL_OPENPRINTER);
  173. if (pInput->iMsg != GDISPOOL_OPENPRINTER || pInput->hSpool) {
  174. if (InterlockedIncrement(&((PSPOOL)pInput->hSpool)->cThreads) > 0) {
  175. // We are already processing a message & have now gotten a ClosePrinter
  176. // We should not get here on any other API
  177. SPLASSERT(pInput->iMsg == GDISPOOL_CLOSEPRINTER);
  178. pInput->ulRet = TRUE; // Let Client terminate
  179. continue;
  180. }
  181. }
  182. }
  183. switch (pInput->iMsg) {
  184. case GDISPOOL_INPUT2SMALL:
  185. DBGMSG(DBG_TRACE,(" - buffer not big enough\n"));
  186. pMem = SrvrReallocSplMem(pInput, cbIn, pInput->cjOut);
  187. if (!pMem) {
  188. DBGMSG(DBG_WARNING, ("Error reallocating pInput in SpoolerGetSpoolMessage\n"));
  189. pInput->ulRet = 0;
  190. }
  191. else {
  192. pInput = (PSPOOLESC) pMem;
  193. cbIn = pInput->cjOut;
  194. pInput->ulRet = 1;
  195. }
  196. break;
  197. case GDISPOOL_TERMINATETHREAD:
  198. EnterCriticalSection(&ThreadCriticalSection);
  199. // There is 1 way to get here: from a 10 minute Kernel Event timeout
  200. if(nIdleThreads > 1) {
  201. --nThreads;
  202. if (nThreads == 0) {
  203. DBGMSG(DBG_WARNING, ("SpoolerGetSpoolMessage nThreads is now ZERO\n"));
  204. }
  205. DBGMSG(DBG_TRACE, ("Thread Deleted: nIdle = %d nThreads = %d\n", nIdleThreads, nThreads));
  206. LeaveCriticalSection(&ThreadCriticalSection);
  207. SrvrFreeSplMem(pInput);
  208. SrvrFreeSplMem(pOutput);
  209. return TRUE;
  210. }
  211. LeaveCriticalSection(&ThreadCriticalSection);
  212. break;
  213. case GDISPOOL_WRITE:
  214. DBGMSG(DBG_TRACE,(" - GDISPOOL_WRITE\n"));
  215. pInput->ulRet = DoWritePrinter( pInput, (DWORD*) pOutput );
  216. cbOut = sizeof(DWORD);
  217. break;
  218. case GDISPOOL_OPENPRINTER:
  219. DBGMSG(DBG_TRACE,(" - GDISPOOL_OPENPRINTER\n"));
  220. DoOpenPrinter(pInput,(HANDLE*)pOutput,&cbOut);
  221. break;
  222. case GDISPOOL_STARTDOCPRINTER:
  223. DBGMSG(DBG_TRACE,(" - GDISPOOL_STARTDOCPRINTER\n"));
  224. DoStartDocPrinter(pInput);
  225. break;
  226. case GDISPOOL_STARTPAGEPRINTER:
  227. DBGMSG(DBG_TRACE,(" - GDISPOOL_STARTPAGEPRINTER\n"));
  228. pInput->ulRet = KMStartPagePrinter( pInput->hSpool );
  229. break;
  230. case GDISPOOL_ENDPAGEPRINTER:
  231. DBGMSG(DBG_TRACE,(" - GDISPOOL_ENDPAGEPRINTER\n"));
  232. pInput->ulRet = KMEndPagePrinter( pInput->hSpool );
  233. break;
  234. case GDISPOOL_ENDDOCPRINTER:
  235. DBGMSG(DBG_TRACE,(" - GDISPOOL_ENDDOCPRINTER\n"));
  236. pInput->ulRet = KMEndDocPrinter( pInput->hSpool );
  237. break;
  238. case GDISPOOL_ENUMFORMS:
  239. DBGMSG(DBG_TRACE,(" - GDISPOOL_ENUMFORMS\n"));
  240. DoEnumForms(pInput, (GREENUMFORMS *) pOutput, &cbOut);
  241. break;
  242. case GDISPOOL_GETPRINTER:
  243. DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPRINTER\n"));
  244. DoGetPrinter(pInput, (GREGETPRINTER *) pOutput, &cbOut);
  245. break;
  246. case GDISPOOL_GETFORM:
  247. DBGMSG(DBG_TRACE,(" - GDISPOOL_GETFORM\n"));
  248. DoGetForm(pInput, (GREGETFORM *) pOutput, &cbOut);
  249. break;
  250. case GDISPOOL_GETPRINTERDRIVER:
  251. DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPRINTERDRIVER\n"));
  252. DoGetPrinterDriver(pInput,(GREGETPRINTERDRIVER*)pOutput,&cbOut);
  253. break;
  254. case GDISPOOL_GETPRINTERDATA:
  255. DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPRINTERDATA\n"));
  256. DoGetPrinterData(pInput,(GREGETPRINTERDATA *) pOutput,&cbOut);
  257. break;
  258. case GDISPOOL_SETPRINTERDATA:
  259. DBGMSG(DBG_TRACE,(" - GDISPOOL_SETPRINTERDATA\n"));
  260. DoSetPrinterData(pInput,(GRESETPRINTERDATA *) pOutput,&cbOut);
  261. break;
  262. case GDISPOOL_ABORTPRINTER:
  263. DBGMSG(DBG_TRACE,(" - GDISPOOL_ABORTPRINTER\n"));
  264. pInput->ulRet = KMAbortPrinter( pInput->hSpool );
  265. break;
  266. case GDISPOOL_CLOSEPRINTER:
  267. DBGMSG(DBG_TRACE,(" - GDISPOOL_CLOSEPRINTER\n"));
  268. pInput->ulRet = KMClosePrinter( pInput->hSpool );
  269. break;
  270. case GDISPOOL_GETPATHNAME:
  271. DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPATHNAME\n"));
  272. pInput->ulRet = DoGetPathName((WCHAR*)pInput->ajData,
  273. (WCHAR*)pOutput,
  274. &cbOut);
  275. break;
  276. case GDISPOOL_UNLOADDRIVER_COMPLETE:
  277. DBGMSG(DBG_TRACE,(" - GDISPOOL_UNLOADDRIVER_COMPLETE\n"));
  278. pInput->ulRet = DoDriverUnloadComplete((LPWSTR)pInput->ajData);
  279. break;
  280. default:
  281. DBGMSG(DBG_ERROR,(" - invalid message\n"));
  282. break;
  283. }
  284. if ((pInput->iMsg & GDISPOOL_API) &&
  285. pInput->iMsg != GDISPOOL_CLOSEPRINTER &&
  286. pInput->iMsg != GDISPOOL_OPENPRINTER &&
  287. pInput->hSpool) {
  288. if (InterlockedDecrement(&((PSPOOL)pInput->hSpool)->cThreads) == 0) {
  289. DBGMSG(DBG_TRACE,(" - GDISPOOL_CLOSEPRINTER\n"));
  290. pInput->ulRet = KMClosePrinter( pInput->hSpool );
  291. }
  292. }
  293. }
  294. }
  295. }
  296. /******************************Public*Routine******************************\
  297. * DoOpenPrinter
  298. *
  299. * History:
  300. * 11-Apr-1995 -by- Eric Kutter [erick]
  301. * Wrote it.
  302. \**************************************************************************/
  303. BOOL DoOpenPrinter(PSPOOLESC psesc, HANDLE* phPrinter, DWORD* pcjOut)
  304. {
  305. LPWSTR pPrinterName = NULL;
  306. PRINTER_DEFAULTSW pDefault;
  307. GREOPENPRINTER *pOpenPrinter;
  308. PLONG plData;
  309. ULONG cbSize;
  310. //
  311. // Make a copy of psesc->ajData if unaligned. The size of duplicated buffer
  312. // is the first LONG in psesc->ajData ( GREOPENPRINTER.cj ).
  313. //
  314. cbSize = *(PLONG)psesc->ajData;
  315. pOpenPrinter = (GREOPENPRINTER *)AlignKMPtr(psesc->ajData, cbSize);
  316. if (pOpenPrinter)
  317. {
  318. plData = pOpenPrinter->alData;
  319. pDefault = pOpenPrinter->pd;
  320. // see if there is a printer name?
  321. if (pOpenPrinter->cjName)
  322. {
  323. pPrinterName = (PWCHAR)plData;
  324. plData += pOpenPrinter->cjName/4;
  325. }
  326. // now setup the printer defaults
  327. if (pOpenPrinter->cjDatatype)
  328. {
  329. pDefault.pDatatype = (PWCHAR)plData;
  330. plData += pOpenPrinter->cjDatatype/4;
  331. }
  332. if (pOpenPrinter->cjDevMode)
  333. {
  334. pDefault.pDevMode = (PDEVMODEW)plData;
  335. }
  336. DBGMSG(DBG_TRACE,
  337. ("OpenPrinter(%ls,%ls,%lx,%d)\n",
  338. pPrinterName,
  339. pDefault.pDatatype,
  340. pDefault.pDevMode,
  341. pDefault.DesiredAccess) );
  342. psesc->ulRet = KMOpenPrinterW(pPrinterName,phPrinter,&pDefault);
  343. DBGMSG( DBG_TRACE,("OpenPrinter returned = %lx\n",psesc->ulRet));
  344. *pcjOut = sizeof(ULONG_PTR);
  345. UndoAlignKMPtr( (LPBYTE)pOpenPrinter, psesc->ajData );
  346. }
  347. else
  348. {
  349. psesc->ulRet = FALSE;
  350. }
  351. if(psesc->ulRet)
  352. return TRUE;
  353. else
  354. return FALSE;
  355. }
  356. /****************************************************************************
  357. * DoStartDocPrinter()
  358. *
  359. * History:
  360. * 4/28/1995 by Gerrit van Wingerden [gerritv]
  361. * Wrote it.
  362. *****************************************************************************/
  363. BOOL DoStartDocPrinter( PSPOOLESC psesc )
  364. {
  365. DOC_INFO_1W di;
  366. GRESTARTDOCPRINTER *pStartDocPrinter = (GRESTARTDOCPRINTER *)psesc->ajData;
  367. PLONG plData;
  368. plData = pStartDocPrinter->alData;
  369. // see if there is a printer name?
  370. if (pStartDocPrinter->cjDocName)
  371. {
  372. di.pDocName = (PWCHAR)plData;
  373. plData += pStartDocPrinter->cjDocName/4;
  374. }
  375. else
  376. {
  377. di.pDocName = NULL;
  378. }
  379. if (pStartDocPrinter->cjOutputFile)
  380. {
  381. di.pOutputFile = (PWCHAR)plData;
  382. plData += pStartDocPrinter->cjOutputFile/4;
  383. }
  384. else
  385. {
  386. di.pOutputFile = NULL;
  387. }
  388. if (pStartDocPrinter->cjDatatype)
  389. {
  390. di.pDatatype = (PWCHAR)plData;
  391. plData += pStartDocPrinter->cjDatatype/4;
  392. }
  393. else
  394. {
  395. di.pDatatype = NULL;
  396. }
  397. psesc->ulRet = KMStartDocPrinterW(psesc->hSpool, 1, (LPBYTE) &di);
  398. if(psesc->ulRet)
  399. return TRUE;
  400. else
  401. return FALSE;
  402. }
  403. /*************************************************************************************
  404. DoEnumForms()
  405. History:
  406. 25/7/95 by Steve Wilson [swilson]
  407. **************************************************************************************/
  408. BOOL DoEnumForms(
  409. PSPOOLESC psesc,
  410. GREENUMFORMS *pEnumFormsReturn,
  411. DWORD *pcjOut
  412. )
  413. {
  414. GREENUMFORMS *pEnumForms = (GREENUMFORMS *) psesc->ajData;
  415. DWORD dwNeeded = 0;
  416. DWORD dwnForms;
  417. psesc->ulRet = KMEnumFormsW ( psesc->hSpool,
  418. pEnumForms->dwLevel,
  419. (BYTE *) pEnumFormsReturn->alData,
  420. pEnumForms->cjData,
  421. &dwNeeded,
  422. &pEnumFormsReturn->nForms
  423. );
  424. if (psesc->ulRet) {
  425. // Set return data size to incoming buffer size since strings are packed at end of in buffer
  426. pEnumFormsReturn->cjData = pEnumForms->cjData;
  427. *pcjOut = pEnumForms->cjData + sizeof(GREENUMFORMS);
  428. }
  429. else {
  430. pEnumFormsReturn->cjData = dwNeeded; // This makes client alloc more than needed
  431. *pcjOut = sizeof(GREENUMFORMS);
  432. }
  433. return psesc->ulRet;
  434. }
  435. /*************************************************************************************
  436. DoGetPrinter()
  437. History:
  438. 9/30/95 by Steve Wilson [swilson]
  439. **************************************************************************************/
  440. BOOL DoGetPrinter(
  441. PSPOOLESC psesc,
  442. GREGETPRINTER *pGetPrinterReturn,
  443. DWORD *pcjOut
  444. )
  445. {
  446. GREGETPRINTER *pGetPrinter = (GREGETPRINTER *) psesc->ajData;
  447. DWORD dwNeeded = 0;
  448. psesc->ulRet = KMGetPrinterW ( psesc->hSpool,
  449. pGetPrinter->dwLevel,
  450. (BYTE *) pGetPrinterReturn->alData,
  451. pGetPrinter->cjData,
  452. &dwNeeded
  453. );
  454. if (psesc->ulRet) {
  455. // Set return data size to incoming buffer size since strings are packed at end of in buffer
  456. pGetPrinterReturn->cjData = pGetPrinter->cjData;
  457. *pcjOut = pGetPrinter->cjData + sizeof(GREGETPRINTER);
  458. }
  459. else {
  460. pGetPrinterReturn->cjData = dwNeeded; // This makes client alloc more than needed
  461. *pcjOut = sizeof(GREGETPRINTER);
  462. }
  463. return psesc->ulRet;
  464. }
  465. /*************************************************************************************
  466. DoGetForm()
  467. History:
  468. 25/7/95 by Steve Wilson [swilson]
  469. **************************************************************************************/
  470. BOOL DoGetForm(
  471. PSPOOLESC psesc,
  472. GREGETFORM *pGetFormReturn,
  473. DWORD *pcjOut
  474. )
  475. {
  476. GREGETFORM *pGetForm = (GREGETFORM *) psesc->ajData;
  477. DWORD dwNeeded = 0;
  478. psesc->ulRet = KMGetFormW ( psesc->hSpool,
  479. pGetForm->cjFormName ? (PWCHAR) pGetForm->alData : NULL,
  480. pGetForm->dwLevel,
  481. (BYTE *) pGetFormReturn->alData,
  482. pGetForm->cjData,
  483. &dwNeeded
  484. );
  485. if (psesc->ulRet) {
  486. // Set return data size to incoming buffer size since strings are packed at end of in buffer
  487. pGetFormReturn->cjData = pGetForm->cjData;
  488. *pcjOut = pGetForm->cjData + sizeof(GREGETFORM);
  489. }
  490. else {
  491. pGetFormReturn->cjData = dwNeeded; // This makes client alloc more than needed
  492. *pcjOut = sizeof(GREGETFORM);
  493. }
  494. return psesc->ulRet;
  495. }
  496. /***************************************************************************************
  497. * DoGetPrinterDriver()
  498. * History:
  499. * 4/17/1995 by Gerrit van Wingerden [gerritv]
  500. * Wrote it.
  501. **************************************************************************************/
  502. BOOL DoGetPrinterDriver(
  503. PSPOOLESC psesc,
  504. GREGETPRINTERDRIVER *pGetPrinterDriverReturn,
  505. DWORD *pcjOut
  506. )
  507. {
  508. GREGETPRINTERDRIVER *pGetPrinterDriver = (GREGETPRINTERDRIVER *)psesc->ajData;
  509. DWORD dwNeeded = 0;
  510. psesc->ulRet = KMGetPrinterDriverW(psesc->hSpool,
  511. pGetPrinterDriver->cjEnv ? (PWCHAR)pGetPrinterDriver->alData : NULL,
  512. pGetPrinterDriver->dwLevel,
  513. (BYTE*)pGetPrinterDriverReturn->alData,
  514. pGetPrinterDriver->cjData,
  515. &dwNeeded );
  516. if (psesc->ulRet)
  517. {
  518. pGetPrinterDriverReturn->cjData = pGetPrinterDriver->cjData; // fix for ValidateStrings in spool.cxx
  519. *pcjOut = pGetPrinterDriver->cjData + sizeof(GREGETPRINTERDRIVER);
  520. }
  521. else
  522. {
  523. // we failed so just return the size
  524. pGetPrinterDriverReturn->cjData = dwNeeded;
  525. *pcjOut = sizeof(GREGETPRINTERDRIVER);
  526. }
  527. if(psesc->ulRet)
  528. return TRUE;
  529. return FALSE;
  530. }
  531. /***************************************************************************************
  532. * DoGetPrinterData()
  533. * History:
  534. * Jul-25-95 by Steve Wilson [swilson]
  535. * Wrote it.
  536. **************************************************************************************/
  537. BOOL DoGetPrinterData(
  538. PSPOOLESC psesc,
  539. GREGETPRINTERDATA *pXReturn,
  540. DWORD *pcjOut
  541. )
  542. {
  543. GREGETPRINTERDATA *pX = (GREGETPRINTERDATA *) psesc->ajData;
  544. DWORD dwNeeded = 0; // return values
  545. DWORD dwType;
  546. psesc->ulRet = KMGetPrinterDataW( psesc->hSpool,
  547. pX->cjValueName ? (PWCHAR) pX->alData : NULL,
  548. &dwType,
  549. (BYTE *) pXReturn->alData,
  550. pX->cjData,
  551. &dwNeeded );
  552. pXReturn->dwNeeded = dwNeeded;
  553. pXReturn->cjData = pX->cjData;
  554. *pcjOut = pX->cjData + sizeof *pX;
  555. pXReturn->dwType = dwType;
  556. SetLastError(psesc->ulRet);
  557. return psesc->ulRet = !psesc->ulRet;
  558. }
  559. /***************************************************************************************
  560. * DoSetPrinterData()
  561. * History:
  562. * Jul-25-95 by Steve Wilson [swilson]
  563. * Wrote it.
  564. **************************************************************************************/
  565. BOOL DoSetPrinterData(
  566. PSPOOLESC psesc,
  567. GRESETPRINTERDATA *pXReturn,
  568. DWORD *pcjOut
  569. )
  570. {
  571. GRESETPRINTERDATA *pX = (GRESETPRINTERDATA *) psesc->ajData;
  572. psesc->ulRet = KMSetPrinterDataW( psesc->hSpool,
  573. pX->cjType ? (PWCHAR) pX->alData : NULL,
  574. pX->dwType,
  575. pX->cjPrinterData ? (BYTE *) pX->alData + pX->cjType : NULL,
  576. pX->cjPrinterData );
  577. *pcjOut = sizeof *pX;
  578. SetLastError(psesc->ulRet);
  579. return psesc->ulRet = !psesc->ulRet;
  580. }
  581. /****************************************************************************
  582. * DoWritePrinter()
  583. * History:
  584. * 5/1/1995 by Gerrit van Wingerden [gerritv]
  585. * Wrote it.
  586. *****************************************************************************/
  587. BOOL DoWritePrinter(PSPOOLESC psesc, DWORD *pWritten )
  588. {
  589. GREWRITEPRINTER *pWritePrinter;
  590. BOOL bReturn;
  591. ULONG cbSize;
  592. //
  593. // Make a copy of psesc->ajData if unaligned. The size of duplicated buffer
  594. // is the first LONG in psesc->ajData ( GREWRITEPRINTER.cj ).
  595. //
  596. cbSize = *(PLONG)psesc->ajData;
  597. pWritePrinter = (GREWRITEPRINTER *)AlignKMPtr(psesc->ajData, cbSize);
  598. if ( !pWritePrinter ) {
  599. return FALSE;
  600. }
  601. if (pWritePrinter->pUserModeData) {
  602. DBGMSG(DBG_TRACE,("WritePrinter UserMode data %0x\n", pWritePrinter->pUserModeData));
  603. bReturn = KMWritePrinter( psesc->hSpool,
  604. (PVOID) pWritePrinter->pUserModeData,
  605. pWritePrinter->cjUserModeData,
  606. pWritten);
  607. } else {
  608. DBGMSG(DBG_TRACE,("WritePrinter KernelMode data %0x\n", pWritePrinter->alData));
  609. bReturn = KMWritePrinter( psesc->hSpool,
  610. (PVOID) pWritePrinter->alData,
  611. pWritePrinter->cjData,
  612. pWritten);
  613. }
  614. UndoAlignKMPtr((LPBYTE)pWritePrinter, psesc->ajData );
  615. return bReturn;
  616. }
  617. BOOL DoDriverUnloadComplete( WCHAR *pDriverFile )
  618. {
  619. BOOL bRet = TRUE;
  620. LPWSTR pDriverFileCopy = NULL;
  621. WCHAR szSystemRoot[] = L"\\SystemRoot\\System32";
  622. DWORD dwLength, dwThreadId;
  623. HANDLE hThread = NULL;
  624. WCHAR szDriverFile[MAX_PATH + 1];
  625. dwLength = wcslen(szSystemRoot);
  626. // Check the validity of the driver file name
  627. if (!pDriverFile || !*pDriverFile) {
  628. return bRet;
  629. }
  630. if (wcslen(pDriverFile) < dwLength) {
  631. return bRet;
  632. }
  633. // Convert kernel mode system relative path to x:\....\system32\spool\...
  634. if (GetSystemDirectory(szDriverFile, MAX_PATH)) {
  635. if (!_wcsnicmp(pDriverFile, szSystemRoot, dwLength)) {
  636. wcscat(szDriverFile, pDriverFile + dwLength);
  637. } else {
  638. wcscpy(szDriverFile, pDriverFile);
  639. }
  640. YDriverUnloadComplete(szDriverFile);
  641. }
  642. return bRet;
  643. }
  644. BOOL DoGetPathName( WCHAR *pwcSrc, WCHAR *pwcDst, DWORD *pcjWritten )
  645. {
  646. BOOL bRet;
  647. WCHAR awcFontsDir[MAX_PATH + sizeof(L"\\DOSDEVICES\\")/sizeof(WCHAR)];
  648. wcscpy(awcFontsDir,L"\\DOSDEVICES\\");
  649. bRet = bMakePathNameW (
  650. &awcFontsDir[sizeof(L"\\DOSDEVICES\\")/sizeof(WCHAR) - 1],
  651. pwcSrc,
  652. NULL,
  653. NULL
  654. );
  655. if (bRet)
  656. {
  657. wcscpy(pwcDst,awcFontsDir);
  658. *pcjWritten = sizeof(WCHAR) * (wcslen(awcFontsDir) + 1);
  659. }
  660. // Buffer large enough and search successfull?
  661. return bRet;
  662. }