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.

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