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.

2196 lines
65 KiB

  1. /*++
  2. Copyright (c) 1991-1993 Microsoft Corporation
  3. Module Name:
  4. DosPrtW.c
  5. Abstract:
  6. This module provides the UNICODE mapping layer from the old DosPrint APIs
  7. to the new all singing all dancing beautiful Print APIs. (The ANSI
  8. mapping layer is in DosPrint.c)
  9. Author:
  10. Dave Snipp (DaveSn) 26-Apr-1991
  11. Revision History:
  12. 09-Jul-1992 JohnRo
  13. Created this file (from DaveSn's DosPrint.c) for RAID 10324: net print
  14. vs. UNICODE.
  15. 05-Oct-1992 JohnRo
  16. RAID 3556: DosPrintQGetInfo(from downlevel) level 3, rc=124. (4&5 too.)
  17. RAID 3580: lmsvcs.exe: access violation from OS/2 DosPrintJobGetInfo.
  18. RAID 8333: view printer queues hangs DOS LM enh client.
  19. Make sure data type in job level 1 is null terminated.
  20. Fixed job submitted times.
  21. Fixed error code if GlobalAlloc fails.
  22. Fixed memory leak in DosPrintQGetInfoW.
  23. Fixed DosPrintQEnumW level 5 array bug.
  24. Fixed DosPrintJobEnumW levels 2 and 3.
  25. 25-Nov-1992 JohnRo
  26. RAID 1661: downlevel to NT DosPrintDestEnum not supported.
  27. Added code to track down empty queue name.
  28. Quiet normal debug output.
  29. Avoid const vs. volatile compiler warnings.
  30. Avoid other new compiler warnings.
  31. 08-Feb-1993 JohnRo
  32. RAID 10164: Data misalignment error during XsDosPrintQGetInfo().
  33. 22-Mar-1993 JohnRo
  34. RAID 2974: NET PRINT says NT printer is held when it isn't.
  35. 11-May-1993 JohnRo
  36. RAID 9942: fix queue name in job info level 3.
  37. 14-May-1993 JohnRo
  38. RAID 9961: DosPrintDestEnum returns NO_ERROR to downlevel but
  39. pcReturned=0; should return NERR_DestNotFound.
  40. Fixed data type returned from PrjInfoFixedSizeW().
  41. 18-May-1993 JohnRo
  42. DosPrintQGetInfoW underestimates number of bytes needed.
  43. Use NetpKdPrint() where possible.
  44. Made changes suggested by PC-LINT.
  45. 04-Jun-1993 JohnRo
  46. RAID 10222: DosPrintQEnumW returns ERROR_INVALID_USER_BUFFER
  47. when queue is empty.
  48. Made changes suggested by PC-LINT 5.0
  49. 08-Jul-1993 JohnRo
  50. RAID 15509: GetJob() API sometimes returned TRUE, even on error case.
  51. Also added some >64KB checks.
  52. Added some assert checks...
  53. 13-Jul-1993 JohnRo
  54. Intermittent empty print queue (was buggy after some MyEnumJobs calls).
  55. 29-Mar-1995 AlbertT
  56. Support for pause/resume/purge printer queue added.
  57. SetJobInfo 1 comment field (translated into document name) support
  58. added so that chicago clients can set the doc name.
  59. --*/
  60. #ifndef UNICODE
  61. #error "RxPrint APIs assume RxRemoteApi uses wide characters."
  62. #endif
  63. #define NOMINMAX
  64. #define NOSERVICE // Avoid <winsvc.h> vs. <lmsvc.h> conflicts.
  65. #include <windows.h>
  66. //#include <lm.h>
  67. #include <netdebug.h>
  68. #include <string.h>
  69. #include <align.h>
  70. #ifdef _WINSPOOL_
  71. #error "Include of winspool.h moved, make sure it doesn't get UNICODE."
  72. #endif
  73. #undef UNICODE
  74. #undef TEXT
  75. #define TEXT(quote) quote
  76. #include <winspool.h>
  77. #undef TEXT
  78. #define TEXT(quote) __TEXT(quote)
  79. #define UNICODE
  80. #ifndef _WINSPOOL_
  81. #error "Oops, winspool.h changed, make sure this code is still OK."
  82. #endif
  83. #include <dosprint.h>
  84. #include <dosprtp.h> // CommandALocalJob(), etc.
  85. #include <lmapibuf.h> // NetApiBufferFree(), etc.
  86. #include <lmerr.h> // NO_ERROR, NERR_, and ERROR_ equates.
  87. #include <lmshare.h> // LPSHARE_INFO_1, STYPE_ equates, etc.
  88. #include <prefix.h> // PREFIX_ equates.
  89. #include <stddef.h> // offsetof().
  90. #include <timelib.h> // NetpSystemTimeToGmtTime().
  91. #include <tstring.h> // WCSSIZE(), NetpNCopy{type}To{type}.
  92. #include <wchar.h> // wsclen(), wcscpy(), etc.
  93. #include "myspool.h"
  94. #define STR_CONV_SIZE(psz) ( (strlen(psz)+1) * sizeof(WCHAR) )
  95. // NULL_STR_CONV_SIZE: Compute size needed for converted string, which
  96. // is possibly a null pointer but downlevel really wants ptr to null char.
  97. #define NULL_STR_CONV_SIZE(psz) ( (psz) ? STR_CONV_SIZE(psz) : sizeof(WCHAR) )
  98. #define ARRAY_END ((DWORD) -1)
  99. #define MAX_WORD ( (WORD) (~0) )
  100. #define MY_PROTOCOL_LIMIT_ERROR ERROR_NOT_ENOUGH_MEMORY
  101. #define WIN95_DRIVER_SHARE "\\print$\\WIN40\\0"
  102. VOID
  103. NetpSetJobCountForQueue(
  104. IN DWORD QueueLevel,
  105. IN OUT LPVOID Queue,
  106. IN BOOL HasUnicodeStrings,
  107. IN DWORD JobCount
  108. );
  109. DBGSTATIC LPWSTR
  110. PackAnsiStringsToW(
  111. LPSTR *pSource,
  112. LPBYTE pDest,
  113. CONST DWORD *DestOffsets,
  114. LPWSTR pEnd
  115. )
  116. {
  117. // Make sure our end pointer is WCHAR aligned or we'll fault later
  118. pEnd = ROUND_DOWN_POINTER( pEnd, ALIGN_WCHAR );
  119. while (*DestOffsets != ARRAY_END) {
  120. if (*pSource) {
  121. pEnd-=(strlen(*pSource) + 1);
  122. // Copy the string and convert chars while we're at it.
  123. NetpCopyStrToWStr(pEnd, *pSource);
  124. *(LPWSTR *)(pDest+*DestOffsets) = pEnd;
  125. } else {
  126. --pEnd; // need 1 char for this.
  127. *pEnd = L'\0';
  128. *(LPWSTR *)(pDest+*DestOffsets) = pEnd;
  129. }
  130. pSource++;
  131. DestOffsets++;
  132. }
  133. return pEnd;
  134. }
  135. DBGSTATIC DWORD
  136. PrjInfoFixedSizeW(
  137. IN DWORD Level // assumed valid
  138. )
  139. {
  140. switch (Level) {
  141. case 0:
  142. return sizeof(WORD); // job number.
  143. case 1:
  144. return (sizeof(PRJINFOW));
  145. case 2:
  146. return (sizeof(PRJINFO2W));
  147. case 3:
  148. return (sizeof(PRJINFO3W));
  149. default:
  150. NetpAssert( FALSE );
  151. return (0);
  152. }
  153. /*NOTREACHED*/
  154. }
  155. DBGSTATIC DWORD
  156. GetPrjInfoSizeW(
  157. IN DWORD Level,
  158. IN LPJOB_INFO_2 pJob,
  159. IN LPCWSTR QueueNameW
  160. )
  161. {
  162. NetpAssert( pJob != NULL );
  163. switch (Level) {
  164. case 0:
  165. return sizeof(WORD); // job number.
  166. case 1:
  167. return sizeof(PRJINFOW) +
  168. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pParameters) ) +
  169. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pStatus) ) +
  170. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDocument) ); // fake pszComment
  171. case 2:
  172. return sizeof(PRJINFO2W) +
  173. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pUserName) ) +
  174. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDocument) ) + // fake pszComment
  175. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDocument) );
  176. case 3:
  177. NetpAssert( QueueNameW != NULL );
  178. return sizeof(PRJINFO3W) +
  179. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pUserName) ) +
  180. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDocument) ) + // fake pszComment
  181. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDocument) ) +
  182. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pNotifyName) ) +
  183. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDatatype) ) +
  184. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pParameters) ) +
  185. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pStatus) ) +
  186. WCSSIZE( QueueNameW ) + // pszQueue
  187. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pPrintProcessor) ) +
  188. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pParameters) ) +
  189. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pDriverName) ) +
  190. NULL_STR_CONV_SIZE( (LPSTR) (pJob->pPrinterName) );
  191. default:
  192. NetpKdPrint(( PREFIX_DOSPRINT
  193. "GetPrjInfoSizeW: invalid level!\n" ));
  194. return 0;
  195. }
  196. /*NOTREACHED*/
  197. }
  198. // Print job info string table (for level 1).
  199. DBGSTATIC CONST DWORD PrjInfo1StringsW[]={
  200. offsetof(PRJINFOW, pszParms),
  201. offsetof(PRJINFOW, pszStatus),
  202. offsetof(PRJINFOW, pszComment),
  203. ARRAY_END};
  204. // Print job info string table (for level 2).
  205. DBGSTATIC CONST DWORD PrjInfo2StringsW[]={
  206. offsetof(PRJINFO2W, pszUserName),
  207. offsetof(PRJINFO2W, pszComment),
  208. offsetof(PRJINFO2W, pszDocument),
  209. (DWORD) -1};
  210. // Print job info string table (for items which level 3 has on top of level 2).
  211. DBGSTATIC CONST DWORD PrjInfo3StringsW[]={
  212. offsetof(PRJINFO3W, pszNotifyName),
  213. offsetof(PRJINFO3W, pszDataType),
  214. offsetof(PRJINFO3W, pszParms),
  215. offsetof(PRJINFO3W, pszStatus),
  216. offsetof(PRJINFO3W, pszQProcName),
  217. offsetof(PRJINFO3W, pszQProcParms),
  218. offsetof(PRJINFO3W, pszDriverName),
  219. offsetof(PRJINFO3W, pszPrinterName),
  220. (DWORD) -1};
  221. DBGSTATIC LPWSTR
  222. CopyJobToPrjInfoW(
  223. IN DWORD Level,
  224. IN LPJOB_INFO_2 pJob,
  225. IN LPCWSTR QueueNameW,
  226. OUT PBYTE pBuffer,
  227. IN OUT LPWSTR pEnd
  228. )
  229. {
  230. LPSTR *pSourceStrings;
  231. NET_API_STATUS rc;
  232. NetpAssert( pBuffer != NULL );
  233. NetpAssert( pEnd != NULL );
  234. NetpAssert( pJob != NULL );
  235. switch (Level) {
  236. case 0:
  237. {
  238. PWORD pJobIds = (PWORD) pBuffer;
  239. *pJobIds = (WORD)pJob->JobId;
  240. }
  241. break;
  242. case 1:
  243. {
  244. LPSTR SourceStrings[sizeof(PrjInfo1StringsW)/sizeof(DWORD)];
  245. PPRJINFOW pPrjInfo = (LPVOID) pBuffer;
  246. pSourceStrings=SourceStrings;
  247. *pSourceStrings++ = (LPSTR) (pJob->pParameters);
  248. *pSourceStrings++ = (LPSTR) (pJob->pStatus);
  249. *pSourceStrings++ = (LPSTR) (pJob->pDocument); // fake pszComment
  250. pEnd = PackAnsiStringsToW(
  251. SourceStrings,
  252. (LPBYTE) (LPVOID) pPrjInfo,
  253. PrjInfo1StringsW,
  254. pEnd);
  255. pPrjInfo->uJobId = (WORD)pJob->JobId;
  256. if (pJob->pUserName)
  257. (VOID) NetpNCopyStrToWStr(
  258. (LPWSTR) (pPrjInfo->szUserName),
  259. (LPSTR) (pJob->pUserName),
  260. LM20_UNLEN+1);
  261. else
  262. pPrjInfo->szUserName[0] = L'\0';
  263. if (pJob->pNotifyName)
  264. (VOID) NetpNCopyStrToWStr(
  265. (LPWSTR) (pPrjInfo->szNotifyName),
  266. (LPSTR) (pJob->pNotifyName),
  267. LM20_CNLEN+1);
  268. else
  269. pPrjInfo->szNotifyName[0] = L'\0';
  270. if (pJob->pDatatype) {
  271. (VOID) NetpNCopyStrToWStr(
  272. (LPWSTR) (pPrjInfo->szDataType),
  273. (LPSTR) (pJob->pDatatype),
  274. DTLEN+1);
  275. pPrjInfo->szDataType[DTLEN] = L'\0';
  276. } else {
  277. pPrjInfo->szDataType[0] = L'\0';
  278. }
  279. pPrjInfo->uPosition = (WORD)pJob->Position;
  280. pPrjInfo->fsStatus = PrjStatusFromJobStatus( pJob->Status );
  281. rc = NetpSystemTimeToGmtTime(
  282. &pJob->Submitted,
  283. &pPrjInfo->ulSubmitted );
  284. NetpAssert( rc == NO_ERROR );
  285. pPrjInfo->ulSize = pJob->Size;
  286. }
  287. break;
  288. case 2: /*FALLTHROUGH*/
  289. case 3:
  290. {
  291. PPRJINFO2W pPrjInfo = (LPVOID) pBuffer;
  292. LPSTR SourceStrings[sizeof(PrjInfo2StringsW)/sizeof(DWORD)];
  293. pSourceStrings=SourceStrings;
  294. *pSourceStrings++ = (LPSTR) (pJob->pUserName);
  295. *pSourceStrings++ = (LPSTR) (pJob->pDocument); // fake pszComment
  296. *pSourceStrings++ = (LPSTR) (pJob->pDocument);
  297. pEnd = PackAnsiStringsToW(
  298. SourceStrings,
  299. (LPBYTE) (LPVOID) pPrjInfo,
  300. PrjInfo2StringsW,
  301. pEnd);
  302. pPrjInfo->uJobId = (WORD)pJob->JobId;
  303. pPrjInfo->uPriority = (WORD)pJob->Priority;
  304. pPrjInfo->uPosition = (WORD)pJob->Position;
  305. pPrjInfo->fsStatus = PrjStatusFromJobStatus( pJob->Status );
  306. rc = NetpSystemTimeToGmtTime(
  307. &pJob->Submitted,
  308. &pPrjInfo->ulSubmitted );
  309. NetpAssert( rc == NO_ERROR );
  310. pPrjInfo->ulSize = pJob->Size;
  311. }
  312. if (Level == 3) {
  313. PPRJINFO3W pPrjInfo = (LPVOID) pBuffer;
  314. LPSTR SourceStrings[sizeof(PrjInfo3StringsW)/sizeof(DWORD)];
  315. //
  316. // Copy queue name first, as it is already right char set.
  317. //
  318. NetpAssert( QueueNameW != NULL );
  319. pEnd-=(wcslen(QueueNameW) + 1);
  320. (VOID) wcscpy(pEnd, QueueNameW);
  321. pPrjInfo->pszQueue = pEnd;
  322. //
  323. // Copy and convert other strings.
  324. //
  325. pSourceStrings=SourceStrings;
  326. *pSourceStrings++ = (LPSTR) (pJob->pNotifyName);
  327. *pSourceStrings++ = (LPSTR) (pJob->pDatatype);
  328. *pSourceStrings++ = (LPSTR) (pJob->pParameters);
  329. *pSourceStrings++ = (LPSTR) (pJob->pStatus);
  330. *pSourceStrings++ = (LPSTR) (pJob->pPrintProcessor);
  331. *pSourceStrings++ = (LPSTR) (pJob->pParameters);
  332. *pSourceStrings++ = (LPSTR) (pJob->pDriverName);
  333. *pSourceStrings++ = (LPSTR) (pJob->pPrinterName);
  334. pEnd = PackAnsiStringsToW(
  335. SourceStrings,
  336. (LPBYTE) (LPVOID) pPrjInfo,
  337. PrjInfo3StringsW,
  338. pEnd);
  339. pPrjInfo->pDriverData = NULL;
  340. }
  341. break;
  342. default:
  343. NetpKdPrint(( PREFIX_DOSPRINT
  344. "CopyJobToPrjInfoW: invalid level!\n" ));
  345. }
  346. return pEnd;
  347. }
  348. DBGSTATIC DWORD
  349. GetPrqInfoSizeW(
  350. IN DWORD Level,
  351. IN LPCWSTR QueueNameW,
  352. IN LPPRINTER_INFO_2 pPrinter
  353. )
  354. {
  355. NetpAssert( QueueNameW != NULL );
  356. NetpAssert( (*QueueNameW) != L'\0' );
  357. switch (Level) {
  358. case 0:
  359. return ( (LM20_QNLEN+1) * sizeof(WCHAR) );
  360. case 1: /*FALLTHROUGH*/
  361. case 2:
  362. return sizeof(PRQINFOW) +
  363. NULL_STR_CONV_SIZE( pPrinter->pSepFile ) +
  364. NULL_STR_CONV_SIZE( pPrinter->pPrintProcessor ) +
  365. NULL_STR_CONV_SIZE( pPrinter->pPortName ) +
  366. NULL_STR_CONV_SIZE( pPrinter->pParameters ) +
  367. NULL_STR_CONV_SIZE( pPrinter->pComment );
  368. case 3: /*FALLTHROUGH*/
  369. case 4:
  370. NetpAssert( QueueNameW != NULL );
  371. return sizeof(PRQINFO3W) +
  372. WCSSIZE( QueueNameW ) + // pszName
  373. NULL_STR_CONV_SIZE( pPrinter->pSepFile ) +
  374. NULL_STR_CONV_SIZE( pPrinter->pPrintProcessor ) +
  375. NULL_STR_CONV_SIZE( pPrinter->pParameters ) +
  376. NULL_STR_CONV_SIZE( pPrinter->pComment ) +
  377. NULL_STR_CONV_SIZE( pPrinter->pPortName ) +
  378. NULL_STR_CONV_SIZE( pPrinter->pDriverName );
  379. case 5:
  380. NetpAssert( QueueNameW != NULL );
  381. return sizeof(LPWSTR) +
  382. WCSSIZE( QueueNameW ); // pszName
  383. default:
  384. NetpKdPrint(( PREFIX_DOSPRINT
  385. "GetPrqInfoSizeW: invalid level!\n" ));
  386. }
  387. return 0;
  388. }
  389. DBGSTATIC DWORD
  390. GetDrvInfoSizeW(
  391. IN DWORD Level,
  392. IN LPDRIVER_INFO_3A pDriverInfo3,
  393. IN LPCSTR pUNCSharePath,
  394. OUT LPDWORD pdwDependentFileCount
  395. )
  396. {
  397. LPSTR psz;
  398. DWORD dwSize;
  399. switch (Level) {
  400. case 52:
  401. dwSize = sizeof(PRQINFO52W) +
  402. NULL_STR_CONV_SIZE(pDriverInfo3->pName) +
  403. NULL_STR_CONV_SIZE(GetFileNameA(pDriverInfo3->pDriverPath)) +
  404. NULL_STR_CONV_SIZE(GetFileNameA(pDriverInfo3->pDataFile)) +
  405. NULL_STR_CONV_SIZE(GetFileNameA(pDriverInfo3->pConfigFile)) +
  406. NULL_STR_CONV_SIZE(GetFileNameA(pDriverInfo3->pHelpFile)) +
  407. NULL_STR_CONV_SIZE(pDriverInfo3->pDefaultDataType) +
  408. NULL_STR_CONV_SIZE(pDriverInfo3->pMonitorName) +
  409. NULL_STR_CONV_SIZE(pUNCSharePath);
  410. *pdwDependentFileCount = 0;
  411. for ( psz = pDriverInfo3->pDependentFiles;
  412. psz && *psz ; psz += strlen(psz) + 1 ) {
  413. dwSize += NULL_STR_CONV_SIZE(GetDependentFileNameA(psz));
  414. (*pdwDependentFileCount)++;
  415. }
  416. //
  417. // For the '\0's
  418. //
  419. dwSize += (MAX_DEPENDENT_FILES-*pdwDependentFileCount)*sizeof(WCHAR);
  420. return dwSize;
  421. default:
  422. NetpKdPrint(( PREFIX_DOSPRINT "GetDrvInfoSizeW: invalid level!\n" ));
  423. }
  424. return 0;
  425. }
  426. DBGSTATIC DWORD
  427. PrqInfoFixedSizeW(
  428. IN DWORD Level // assumed valid
  429. )
  430. {
  431. switch (Level) {
  432. case 0:
  433. return ( (LM20_QNLEN+1) * sizeof(WCHAR) );
  434. case 1: /*FALLTHROUGH*/
  435. case 2:
  436. return (sizeof(PRQINFOW));
  437. case 3: /*FALLTHROUGH*/
  438. case 4:
  439. return (sizeof(PRQINFO3W));
  440. case 5:
  441. return (sizeof(LPWSTR));
  442. default:
  443. NetpAssert( FALSE ); // Level should be valid!
  444. return (0);
  445. }
  446. /*NOTREACHED*/
  447. }
  448. // String table for Q levels 1,2
  449. DBGSTATIC CONST DWORD PrqInfo1StringsW[]={
  450. offsetof(PRQINFOW, pszSepFile),
  451. offsetof(PRQINFOW, pszPrProc),
  452. offsetof(PRQINFOW, pszDestinations),
  453. offsetof(PRQINFOW, pszParms),
  454. offsetof(PRQINFOW, pszComment),
  455. ARRAY_END};
  456. // String table for Q levels 3,4.
  457. DBGSTATIC CONST DWORD PrqInfo3StringsW[]={
  458. offsetof(PRQINFO3W, pszSepFile),
  459. offsetof(PRQINFO3W, pszPrProc),
  460. offsetof(PRQINFO3W, pszParms),
  461. offsetof(PRQINFO3W, pszComment),
  462. offsetof(PRQINFO3W, pszPrinters),
  463. offsetof(PRQINFO3W, pszDriverName),
  464. (DWORD) -1};
  465. // Print driver info3 string table (for level 52)
  466. DBGSTATIC CONST DWORD PrqInfo52StringsW[]={
  467. offsetof(PRQINFO52W, pszModelName),
  468. offsetof(PRQINFO52W, pszDriverName),
  469. offsetof(PRQINFO52W, pszDataFileName),
  470. offsetof(PRQINFO52W, pszMonitorName),
  471. offsetof(PRQINFO52W, pszDriverPath),
  472. offsetof(PRQINFO52W, pszDefaultDataType),
  473. offsetof(PRQINFO52W, pszHelpFile),
  474. offsetof(PRQINFO52W, pszConfigFile),
  475. offsetof(PRQINFO52W, pszDependentNames[0]),
  476. offsetof(PRQINFO52W, pszDependentNames[1]),
  477. offsetof(PRQINFO52W, pszDependentNames[2]),
  478. offsetof(PRQINFO52W, pszDependentNames[3]),
  479. offsetof(PRQINFO52W, pszDependentNames[4]),
  480. offsetof(PRQINFO52W, pszDependentNames[5]),
  481. offsetof(PRQINFO52W, pszDependentNames[6]),
  482. offsetof(PRQINFO52W, pszDependentNames[7]),
  483. offsetof(PRQINFO52W, pszDependentNames[8]),
  484. offsetof(PRQINFO52W, pszDependentNames[9]),
  485. offsetof(PRQINFO52W, pszDependentNames[10]),
  486. offsetof(PRQINFO52W, pszDependentNames[11]),
  487. offsetof(PRQINFO52W, pszDependentNames[12]),
  488. offsetof(PRQINFO52W, pszDependentNames[13]),
  489. offsetof(PRQINFO52W, pszDependentNames[14]),
  490. offsetof(PRQINFO52W, pszDependentNames[15]),
  491. offsetof(PRQINFO52W, pszDependentNames[16]),
  492. offsetof(PRQINFO52W, pszDependentNames[17]),
  493. offsetof(PRQINFO52W, pszDependentNames[18]),
  494. offsetof(PRQINFO52W, pszDependentNames[19]),
  495. offsetof(PRQINFO52W, pszDependentNames[20]),
  496. offsetof(PRQINFO52W, pszDependentNames[21]),
  497. offsetof(PRQINFO52W, pszDependentNames[22]),
  498. offsetof(PRQINFO52W, pszDependentNames[23]),
  499. offsetof(PRQINFO52W, pszDependentNames[24]),
  500. offsetof(PRQINFO52W, pszDependentNames[25]),
  501. offsetof(PRQINFO52W, pszDependentNames[26]),
  502. offsetof(PRQINFO52W, pszDependentNames[27]),
  503. offsetof(PRQINFO52W, pszDependentNames[28]),
  504. offsetof(PRQINFO52W, pszDependentNames[29]),
  505. offsetof(PRQINFO52W, pszDependentNames[30]),
  506. offsetof(PRQINFO52W, pszDependentNames[31]),
  507. offsetof(PRQINFO52W, pszDependentNames[32]),
  508. offsetof(PRQINFO52W, pszDependentNames[33]),
  509. offsetof(PRQINFO52W, pszDependentNames[34]),
  510. offsetof(PRQINFO52W, pszDependentNames[35]),
  511. offsetof(PRQINFO52W, pszDependentNames[36]),
  512. offsetof(PRQINFO52W, pszDependentNames[37]),
  513. offsetof(PRQINFO52W, pszDependentNames[38]),
  514. offsetof(PRQINFO52W, pszDependentNames[39]),
  515. offsetof(PRQINFO52W, pszDependentNames[40]),
  516. offsetof(PRQINFO52W, pszDependentNames[41]),
  517. offsetof(PRQINFO52W, pszDependentNames[42]),
  518. offsetof(PRQINFO52W, pszDependentNames[43]),
  519. offsetof(PRQINFO52W, pszDependentNames[44]),
  520. offsetof(PRQINFO52W, pszDependentNames[45]),
  521. offsetof(PRQINFO52W, pszDependentNames[46]),
  522. offsetof(PRQINFO52W, pszDependentNames[47]),
  523. offsetof(PRQINFO52W, pszDependentNames[48]),
  524. offsetof(PRQINFO52W, pszDependentNames[49]),
  525. offsetof(PRQINFO52W, pszDependentNames[50]),
  526. offsetof(PRQINFO52W, pszDependentNames[51]),
  527. offsetof(PRQINFO52W, pszDependentNames[52]),
  528. offsetof(PRQINFO52W, pszDependentNames[53]),
  529. offsetof(PRQINFO52W, pszDependentNames[54]),
  530. offsetof(PRQINFO52W, pszDependentNames[55]),
  531. offsetof(PRQINFO52W, pszDependentNames[56]),
  532. offsetof(PRQINFO52W, pszDependentNames[57]),
  533. offsetof(PRQINFO52W, pszDependentNames[58]),
  534. offsetof(PRQINFO52W, pszDependentNames[59]),
  535. offsetof(PRQINFO52W, pszDependentNames[60]),
  536. offsetof(PRQINFO52W, pszDependentNames[61]),
  537. offsetof(PRQINFO52W, pszDependentNames[62]),
  538. offsetof(PRQINFO52W, pszDependentNames[63]),
  539. (DWORD) -1};
  540. DBGSTATIC LPWSTR
  541. CopyPrinterToPrqInfoW(
  542. IN LPPRINTER_INFO_2 pPrinter,
  543. IN DWORD Level,
  544. OUT LPBYTE pBuffer,
  545. IN LPCWSTR QueueNameW,
  546. OUT LPWSTR pEnd
  547. )
  548. {
  549. LPSTR *pSourceStrings;
  550. NetpAssert( pEnd != NULL );
  551. NetpAssert( QueueNameW != NULL );
  552. NetpAssert( (*QueueNameW) != L'\0' );
  553. switch (Level) {
  554. case 0:
  555. (VOID) wcsncpy(
  556. (LPWSTR) (LPVOID) pBuffer,
  557. QueueNameW,
  558. LM20_QNLEN);
  559. break;
  560. case 1: /*FALLTHROUGH*/
  561. case 2:
  562. {
  563. LPSTR SourceStrings[sizeof(PrqInfo1StringsW)/sizeof(DWORD)];
  564. PPRQINFOW pPrqInfo = (LPVOID) pBuffer;
  565. pSourceStrings=SourceStrings;
  566. *pSourceStrings++ = pPrinter->pSepFile;
  567. *pSourceStrings++ = pPrinter->pPrintProcessor;
  568. *pSourceStrings++ = pPrinter->pPortName;
  569. *pSourceStrings++ = pPrinter->pParameters;
  570. *pSourceStrings++ = pPrinter->pComment;
  571. pEnd = PackAnsiStringsToW(
  572. SourceStrings,
  573. (LPBYTE) (LPVOID) pPrqInfo,
  574. PrqInfo1StringsW,
  575. pEnd);
  576. NetpAssert( QueueNameW != NULL );
  577. (VOID) wcsncpy(
  578. pPrqInfo->szName, // dest
  579. QueueNameW, // src
  580. LM20_QNLEN); // char count
  581. pPrqInfo->szName[LM20_QNLEN] = (USHORT)0;
  582. pPrqInfo->uPriority = (WORD)pPrinter->Priority;
  583. pPrqInfo->uStartTime = (WORD)pPrinter->StartTime;
  584. pPrqInfo->uUntilTime = (WORD)pPrinter->UntilTime;
  585. pPrqInfo->fsStatus = PrqStatusFromPrinterStatus( pPrinter->Status );
  586. pPrqInfo->cJobs = (WORD)pPrinter->cJobs;
  587. }
  588. break;
  589. case 3: /*FALLTHROUGH*/
  590. case 4:
  591. {
  592. LPSTR SourceStrings[sizeof(PrqInfo3StringsW)/sizeof(DWORD)];
  593. PPRQINFO3W pPrqInfo = (LPVOID) pBuffer;
  594. //
  595. // Copy queue name first, as it is already right char set.
  596. //
  597. NetpAssert( QueueNameW != NULL );
  598. pEnd-=(wcslen(QueueNameW) + 1);
  599. (VOID) wcscpy(pEnd, QueueNameW);
  600. pPrqInfo->pszName = pEnd;
  601. //
  602. // Copy and convert other strings.
  603. //
  604. pSourceStrings=SourceStrings;
  605. *pSourceStrings++ = pPrinter->pSepFile;
  606. *pSourceStrings++ = pPrinter->pPrintProcessor;
  607. *pSourceStrings++ = pPrinter->pParameters;
  608. *pSourceStrings++ = pPrinter->pComment;
  609. *pSourceStrings++ = pPrinter->pPortName; // pszPrinters
  610. *pSourceStrings++ = pPrinter->pDriverName;
  611. pEnd = PackAnsiStringsToW(
  612. SourceStrings,
  613. (LPBYTE) (LPVOID) pPrqInfo,
  614. PrqInfo3StringsW,
  615. pEnd);
  616. pPrqInfo->uPriority = (WORD)pPrinter->Priority;
  617. pPrqInfo->uStartTime = (WORD)pPrinter->StartTime;
  618. pPrqInfo->uUntilTime = (WORD)pPrinter->UntilTime;
  619. pPrqInfo->fsStatus = PrqStatusFromPrinterStatus( pPrinter->Status );
  620. pPrqInfo->cJobs = (WORD)pPrinter->cJobs;
  621. pPrqInfo->pDriverData = NULL;
  622. // Note: if level is 4, caller will add array of jobs after this.
  623. break;
  624. }
  625. case 5:
  626. NetpAssert( QueueNameW != NULL );
  627. pEnd -= (wcslen( QueueNameW ) + 1);
  628. * (LPWSTR *) pBuffer = pEnd;
  629. (VOID) wcscpy(
  630. pEnd, // dest
  631. QueueNameW ); // src
  632. break;
  633. default:
  634. NetpKdPrint(( PREFIX_DOSPRINT
  635. "CopyPrinterToPrqInfoW: invalid level!\n" ));
  636. }
  637. return pEnd;
  638. }
  639. DBGSTATIC LPWSTR
  640. CopyDriverToPrqInfoW(
  641. IN LPDRIVER_INFO_3A pDriver3,
  642. IN DWORD dwDependentFileCount,
  643. IN LPSTR pUNCSharePath,
  644. IN DWORD Level,
  645. OUT LPBYTE pBuffer,
  646. OUT LPWSTR pEnd
  647. )
  648. {
  649. LPSTR *pSourceStrings;
  650. LPSTR psz;
  651. NetpAssert( pEnd != NULL );
  652. NetpAssert(MAX_DEPENDENT_FILES == 64);
  653. switch (Level) {
  654. case 52:
  655. {
  656. PPRQINFO52W pPrqInfo = (LPVOID) pBuffer;
  657. LPSTR SourceStrings[sizeof(PrqInfo52StringsW)/sizeof(DWORD)];
  658. ZeroMemory((LPBYTE)SourceStrings, sizeof(SourceStrings));
  659. pSourceStrings=SourceStrings;
  660. *pSourceStrings++ = pDriver3->pName;
  661. *pSourceStrings++ = GetFileNameA(pDriver3->pDriverPath);
  662. *pSourceStrings++ = GetFileNameA(pDriver3->pDataFile);
  663. *pSourceStrings++ = GetFileNameA(pDriver3->pMonitorName);
  664. *pSourceStrings++ = pUNCSharePath;
  665. *pSourceStrings++ = GetFileNameA(pDriver3->pDefaultDataType);
  666. *pSourceStrings++ = GetFileNameA(pDriver3->pHelpFile);
  667. *pSourceStrings++ = GetFileNameA(pDriver3->pConfigFile);
  668. for ( psz = pDriver3->pDependentFiles ;
  669. psz && *psz ; psz += strlen(psz) + 1 ) {
  670. *pSourceStrings++ = GetDependentFileNameA(psz);
  671. }
  672. pEnd = PackAnsiStringsToW(
  673. SourceStrings,
  674. (LPBYTE) (LPVOID)pPrqInfo,
  675. PrqInfo52StringsW,
  676. pEnd);
  677. pPrqInfo->uVersion = (WORD)pDriver3->cVersion;
  678. pPrqInfo->cDependentNames = (WORD)dwDependentFileCount;
  679. }
  680. break;
  681. default:
  682. NetpKdPrint(( PREFIX_DOSPRINT
  683. "CopyPrinterToPrqInfoW: invalid level!\n" ));
  684. }
  685. return pEnd;
  686. }
  687. DBGSTATIC NET_API_STATUS
  688. ComputeSpaceNeededForJobs(
  689. IN LPCWSTR QueueNameW,
  690. IN DWORD QLevel,
  691. IN HANDLE PrinterHandle,
  692. OUT LPDWORD pcbNeeded
  693. )
  694. {
  695. NET_API_STATUS ApiStatus;
  696. DWORD cJobs;
  697. DWORD cbJobs;
  698. DWORD cbNeeded = 0;
  699. DWORD JobLevel;
  700. LPJOB_INFO_2 pJob = NULL;
  701. LPJOB_INFO_2 pJobs = NULL;
  702. NetpAssert( (QLevel==2) || (QLevel==4) );
  703. NetpAssert( QueueNameW != NULL );
  704. if (QLevel==2) {
  705. JobLevel = 1;
  706. } else {
  707. JobLevel = 2;
  708. }
  709. if (!MyEnumJobs(PrinterHandle, 0, (DWORD) -1, 2, NULL, 0, &cbJobs, &cJobs)) {
  710. ApiStatus = (NET_API_STATUS) GetLastError();
  711. if (ApiStatus == ERROR_INSUFFICIENT_BUFFER) {
  712. pJobs = (LPVOID) GlobalAlloc(GMEM_FIXED, cbJobs);
  713. if (pJobs == NULL) {
  714. ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
  715. goto Cleanup;
  716. }
  717. } else {
  718. NetpKdPrint(( PREFIX_DOSPRINT
  719. "ComputeSpaceNeededForJobs: got error " FORMAT_API_STATUS
  720. " from MyEnumJobs(first).\n", ApiStatus ));
  721. goto Cleanup;
  722. }
  723. }
  724. if (!MyEnumJobs(PrinterHandle, 0, (DWORD) -1, 2, (LPBYTE)pJobs, cbJobs,
  725. &cbJobs, &cJobs)) {
  726. ApiStatus = (NET_API_STATUS) GetLastError();
  727. NetpAssert( ApiStatus != ERROR_INSUFFICIENT_BUFFER );
  728. NetpKdPrint(( PREFIX_DOSPRINT
  729. "ComputeSpaceNeededForJobs: got error " FORMAT_API_STATUS
  730. " from MyEnumJobs(second)\n", ApiStatus ));
  731. goto Cleanup;
  732. }
  733. if (cJobs == 0) {
  734. cbNeeded = 0;
  735. ApiStatus = NO_ERROR;
  736. goto Cleanup;
  737. }
  738. if (pJobs == NULL) {
  739. NetpKdPrint(( PREFIX_DOSPRINT
  740. "ComputeSpaceNeededForJobs: never allocated array!\n" ));
  741. ApiStatus = NERR_InternalError;
  742. goto Cleanup;
  743. }
  744. pJob=pJobs;
  745. while (cJobs--) {
  746. cbNeeded+=GetPrjInfoSizeW(JobLevel, pJob++, QueueNameW);
  747. }
  748. *pcbNeeded=(WORD)cbNeeded; // final byte count for this queue's jobs.
  749. ApiStatus = NO_ERROR;
  750. Cleanup:
  751. if (pJobs != NULL) {
  752. (VOID) GlobalFree(pJobs);
  753. }
  754. *pcbNeeded = cbNeeded; // final byte count for this queue's jobs.
  755. return (ApiStatus);
  756. } // ComputeSpaceNeededForJobs
  757. DBGSTATIC NET_API_STATUS
  758. AppendJobsToPrqW(
  759. IN LPCWSTR QueueNameW,
  760. IN DWORD QLevel,
  761. IN HANDLE PrinterHandle,
  762. OUT LPBYTE pbBuf,
  763. IN DWORD cbBuf,
  764. IN LPVOID pEnd,
  765. OUT LPVOID * pNewEnd,
  766. OUT LPDWORD pcbNeeded,
  767. OUT LPDWORD pcReturned,
  768. IN BOOL AllowPartialData
  769. )
  770. {
  771. DWORD cJobs;
  772. DWORD cbJobs;
  773. DWORD cbNeeded = 0;
  774. DWORD cbPrj;
  775. DWORD JobLevel;
  776. DWORD rc;
  777. DWORD JobSize;
  778. DWORD BytesLeft;
  779. DWORD JobsStored;
  780. LPJOB_INFO_2 pJob = NULL;
  781. LPJOB_INFO_2 pJobs = NULL;
  782. NetpAssert( (QLevel==2) || (QLevel==4) );
  783. NetpAssert( QueueNameW != NULL );
  784. if (QLevel==2) {
  785. cbPrj = sizeof(PRJINFOW);
  786. JobLevel = 1;
  787. } else {
  788. cbPrj = sizeof(PRJINFO2W);
  789. JobLevel = 2;
  790. }
  791. if (!MyEnumJobs(PrinterHandle, 0, (DWORD) -1, 2, NULL, 0, &cbJobs, pcReturned)) {
  792. rc = GetLastError();
  793. if (rc == ERROR_INSUFFICIENT_BUFFER) {
  794. pJobs = (LPVOID) GlobalAlloc(GMEM_FIXED, cbJobs);
  795. if (pJobs == NULL) {
  796. rc = ERROR_NOT_ENOUGH_MEMORY;
  797. goto Cleanup;
  798. }
  799. } else {
  800. NetpKdPrint(( PREFIX_DOSPRINT
  801. "AppendJobsToPrqW: got error " FORMAT_API_STATUS
  802. " from MyEnumJobs(first)\n", rc ));
  803. goto Cleanup;
  804. }
  805. }
  806. if (!MyEnumJobs(PrinterHandle, 0, (DWORD) -1, 2, (LPBYTE)pJobs, cbJobs,
  807. &cbJobs, pcReturned)) {
  808. rc = GetLastError();
  809. NetpAssert( rc != ERROR_INSUFFICIENT_BUFFER );
  810. NetpKdPrint(( PREFIX_DOSPRINT
  811. "AppendJobsToPrqW: got error " FORMAT_API_STATUS
  812. " from MyEnumJobs(second)\n", rc ));
  813. goto Cleanup;
  814. }
  815. if (*pcReturned == 0) {
  816. cbNeeded = 0;
  817. rc = NO_ERROR;
  818. goto Cleanup;
  819. }
  820. if (pJobs == NULL) {
  821. NetpKdPrint(( PREFIX_DOSPRINT
  822. "AppendJobsToPrqW: never allocated array!\n" ));
  823. rc = NERR_InternalError;
  824. goto Cleanup;
  825. }
  826. cJobs = *pcReturned;
  827. pJob=pJobs;
  828. while (cJobs--)
  829. cbNeeded+=GetPrjInfoSizeW(JobLevel, pJob++, QueueNameW);
  830. *pcbNeeded = cbNeeded; // final byte count for this queue's jobs.
  831. if (cbNeeded <= cbBuf) {
  832. cJobs = *pcReturned;
  833. pJob=pJobs;
  834. while (cJobs--) {
  835. pEnd = CopyJobToPrjInfoW(JobLevel, pJob++, QueueNameW,
  836. pbBuf,
  837. pEnd);
  838. pbBuf += cbPrj; // Note: Wasn't DWORD aligned
  839. }
  840. rc = NO_ERROR;
  841. } else {
  842. //
  843. // See if the user wants to receive as much data as we can fit.
  844. //
  845. if( AllowPartialData == TRUE ) {
  846. cJobs = *pcReturned;
  847. pJob = pJobs;
  848. JobsStored = 0;
  849. BytesLeft = cbBuf;
  850. while( cJobs-- ) {
  851. JobSize = GetPrjInfoSizeW( JobLevel,
  852. pJob,
  853. QueueNameW );
  854. if( JobSize <= BytesLeft ) {
  855. //
  856. // This job will fit. Add it in.
  857. //
  858. pEnd = CopyJobToPrjInfoW( JobLevel,
  859. pJob++,
  860. QueueNameW,
  861. pbBuf,
  862. pEnd );
  863. pbBuf += cbPrj; // Note: Wasn't DWORD aligned
  864. BytesLeft -= JobSize;
  865. JobsStored++;
  866. } else {
  867. //
  868. // The buffer is full.
  869. //
  870. break;
  871. }
  872. }
  873. if( JobsStored != 0 ) {
  874. //
  875. // Return what we were able to store.
  876. //
  877. *pcReturned = JobsStored;
  878. rc = NO_ERROR;
  879. } else {
  880. rc = NERR_BufTooSmall;
  881. }
  882. } else {
  883. rc = NERR_BufTooSmall;
  884. }
  885. }
  886. Cleanup:
  887. if (pJobs != NULL) {
  888. (VOID) GlobalFree(pJobs);
  889. }
  890. *pcbNeeded = cbNeeded; // final byte count for this queue's jobs.
  891. if (pNewEnd != NULL) {
  892. *pNewEnd = pEnd;
  893. }
  894. return (rc);
  895. }
  896. SPLERR SPLENTRY DosPrintQGetInfoW(
  897. LPWSTR pszServer,
  898. LPWSTR pszQueueName,
  899. WORD uLevel,
  900. PBYTE pbBuf,
  901. WORD cbBuf,
  902. PUSHORT pcbNeeded
  903. )
  904. {
  905. DWORD cJobsReturned;
  906. LPWSTR pEnd;
  907. DWORD rc;
  908. HANDLE hPrinter = INVALID_HANDLE_VALUE;
  909. LPPRINTER_INFO_2 pPrinter = NULL;
  910. LPDRIVER_INFO_3A pDriver = NULL;
  911. CHAR szDriverDir[MAX_PATH];
  912. DWORD cbNeeded = 0, dwDependentFileCount;
  913. DWORD cbNeededForJobs;
  914. if (pszServer && *pszServer) {
  915. rc = RxPrintQGetInfo(pszServer, pszQueueName, uLevel, pbBuf,
  916. cbBuf, &cbNeeded);
  917. if (cbNeeded > MAX_WORD) {
  918. rc = MY_PROTOCOL_LIMIT_ERROR;
  919. goto Cleanup;
  920. }
  921. *pcbNeeded = (USHORT)cbNeeded;
  922. goto Cleanup;
  923. }
  924. *pcbNeeded = 0; // in case an error occurs.
  925. if ( !NetpIsPrintQLevelValid( uLevel, FALSE ) ) {
  926. rc = ERROR_INVALID_LEVEL;
  927. goto Cleanup;
  928. }
  929. if ( (pszQueueName==NULL) || ((*pszQueueName)==L'\0') ) {
  930. rc = ERROR_INVALID_PARAMETER;
  931. goto Cleanup;
  932. }
  933. if ( !MyOpenPrinterW( pszQueueName, &hPrinter, NULL) ) {
  934. rc = GetLastError();
  935. if ( rc == ERROR_INVALID_PRINTER_NAME )
  936. rc = NERR_QNotFound;
  937. goto Cleanup;
  938. }
  939. //
  940. // Level 52 is meant for point and print from a Windows 95 clients
  941. // can't use with other clients since no environment info is passed
  942. //
  943. if ( uLevel == 52 ) {
  944. cbNeeded = sizeof(szDriverDir)-2;
  945. szDriverDir[0] = szDriverDir[1] = '\\';
  946. if ( !GetComputerNameA(szDriverDir+2, &cbNeeded) ) {
  947. rc = GetLastError();
  948. goto Cleanup;
  949. }
  950. if ( strlen(szDriverDir) + strlen(WIN95_DRIVER_SHARE) + 1
  951. > sizeof(szDriverDir) ) {
  952. rc = ERROR_NOT_ENOUGH_MEMORY;
  953. NetpAssert( rc != NO_ERROR ); // Always break
  954. goto Cleanup;
  955. }
  956. strcat(szDriverDir, WIN95_DRIVER_SHARE);
  957. (VOID)MyGetPrinterDriver(hPrinter, WIN95_ENVIRONMENT, 3,
  958. NULL, 0, &cbNeeded);
  959. rc = GetLastError();
  960. if ( rc != ERROR_INSUFFICIENT_BUFFER )
  961. goto Cleanup;
  962. pDriver = (LPVOID) GlobalAlloc(GMEM_FIXED, cbNeeded);
  963. if ( !pDriver ) {
  964. rc = ERROR_NOT_ENOUGH_MEMORY;
  965. goto Cleanup;
  966. }
  967. if ( !MyGetPrinterDriver(hPrinter, WIN95_ENVIRONMENT, 3,
  968. (LPVOID)pDriver, cbNeeded, &cbNeeded) ) {
  969. rc = GetLastError();
  970. goto Cleanup;
  971. }
  972. cbNeeded=GetDrvInfoSizeW(uLevel, pDriver,
  973. szDriverDir, &dwDependentFileCount);
  974. if ( dwDependentFileCount > MAX_DEPENDENT_FILES ) {
  975. rc = ERROR_NOT_ENOUGH_MEMORY;
  976. goto Cleanup;
  977. }
  978. } else {
  979. if (!MyGetPrinter(hPrinter, 2, NULL, 0, &cbNeeded)) {
  980. rc = GetLastError();
  981. if (rc == ERROR_INSUFFICIENT_BUFFER) {
  982. pPrinter = (LPVOID) GlobalAlloc(GMEM_FIXED, cbNeeded);
  983. if (pPrinter == NULL) {
  984. rc = ERROR_NOT_ENOUGH_MEMORY;
  985. goto Cleanup;
  986. }
  987. } else {
  988. goto Cleanup;
  989. }
  990. }
  991. if (!MyGetPrinter(hPrinter, 2, (LPBYTE)pPrinter, cbNeeded, &cbNeeded)) {
  992. rc = GetLastError();
  993. goto Cleanup;
  994. }
  995. // How much for just the queue structure and its strings?
  996. cbNeeded=GetPrqInfoSizeW(uLevel, pszQueueName, pPrinter);
  997. }
  998. if (cbNeeded > MAX_WORD) {
  999. rc = MY_PROTOCOL_LIMIT_ERROR;
  1000. goto Cleanup;
  1001. }
  1002. *pcbNeeded = (WORD)cbNeeded; // Tell caller the size (so far).
  1003. //
  1004. // Build the queue structure itself.
  1005. //
  1006. if (cbNeeded <= (DWORD) cbBuf) {
  1007. if ( uLevel == 52 ) {
  1008. ZeroMemory(pbBuf, cbNeeded);
  1009. pEnd = CopyDriverToPrqInfoW(pDriver, dwDependentFileCount,
  1010. szDriverDir, uLevel, pbBuf,
  1011. (LPWSTR) (pbBuf+cbBuf) );
  1012. } else {
  1013. pEnd = CopyPrinterToPrqInfoW(pPrinter, uLevel, pbBuf, pszQueueName,
  1014. (LPWSTR) (pbBuf+cbBuf) );
  1015. }
  1016. } else {
  1017. //
  1018. // Too small. Well, need to find total size before we can tell caller.
  1019. //
  1020. if ( (uLevel==2) || (uLevel==4) ) {
  1021. rc = ComputeSpaceNeededForJobs(
  1022. pszQueueName,
  1023. uLevel, // Q info level
  1024. hPrinter,
  1025. & cbNeededForJobs );
  1026. if (rc != NO_ERROR) {
  1027. goto Cleanup;
  1028. }
  1029. cbNeeded += cbNeededForJobs;
  1030. }
  1031. if (cbNeeded > MAX_WORD) {
  1032. rc = MY_PROTOCOL_LIMIT_ERROR;
  1033. goto Cleanup;
  1034. }
  1035. rc = NERR_BufTooSmall;
  1036. goto Cleanup;
  1037. }
  1038. //
  1039. // Append jobs if necessary.
  1040. //
  1041. if ( (uLevel==2) || (uLevel==4) ) {
  1042. DWORD cbPrq = PrqInfoFixedSizeW( uLevel );
  1043. rc = AppendJobsToPrqW(
  1044. pszQueueName,
  1045. uLevel, // Q info level
  1046. hPrinter,
  1047. pbBuf + cbPrq, // put first job here
  1048. cbBuf - cbNeeded, // bytes avail for jobs
  1049. pEnd, // str area
  1050. NULL, // don't need new pEnd
  1051. & cbNeededForJobs,
  1052. & cJobsReturned,
  1053. cbBuf == MAX_WORD ? TRUE : FALSE ); // If the buffer is at its max, get what we can.
  1054. if( cbNeeded + cbNeededForJobs > MAX_WORD ) {
  1055. *pcbNeeded = MAX_WORD;
  1056. } else {
  1057. *pcbNeeded = (USHORT) (cbNeeded + cbNeededForJobs);
  1058. }
  1059. //
  1060. // Update job count in queue structure, as it may be out of date.
  1061. //
  1062. NetpSetJobCountForQueue(
  1063. uLevel, // queue info level
  1064. pbBuf, // queue structure to update
  1065. TRUE, // yes, UNICODE strings
  1066. cJobsReturned ); // actual job count
  1067. if (rc != NO_ERROR) {
  1068. goto Cleanup;
  1069. }
  1070. }
  1071. rc = NO_ERROR;
  1072. Cleanup:
  1073. if (hPrinter != INVALID_HANDLE_VALUE) {
  1074. (VOID) MyClosePrinter( hPrinter );
  1075. }
  1076. if (pPrinter) {
  1077. (VOID) GlobalFree( pPrinter );
  1078. }
  1079. if (pDriver) {
  1080. (VOID) GlobalFree( pDriver );
  1081. }
  1082. return rc;
  1083. }
  1084. SPLERR SPLENTRY DosPrintJobGetInfoW(
  1085. LPWSTR pszServer,
  1086. BOOL bRemote,
  1087. WORD uJobId,
  1088. WORD uLevel,
  1089. PBYTE pbBuf,
  1090. WORD cbBuf,
  1091. PUSHORT pcbNeeded
  1092. )
  1093. {
  1094. DWORD cb;
  1095. HANDLE hPrinter = INVALID_HANDLE_VALUE;
  1096. LPSTR QueueNameA = NULL;
  1097. LPWSTR QueueNameW = NULL;
  1098. LPJOB_INFO_2 pJob = NULL;
  1099. LPWSTR pEnd;
  1100. DWORD rc;
  1101. DWORD cbNeeded = 0;
  1102. if (bRemote) {
  1103. rc = RxPrintJobGetInfo(pszServer, uJobId, uLevel, pbBuf,
  1104. cbBuf, &cbNeeded);
  1105. *pcbNeeded = (USHORT)cbNeeded;
  1106. return rc;
  1107. }
  1108. *pcbNeeded = 0; // in case an error occurs.
  1109. if ( !NetpIsPrintJobLevelValid( uLevel, FALSE ) ) {
  1110. rc = ERROR_INVALID_LEVEL;
  1111. goto Cleanup;
  1112. }
  1113. //
  1114. // The 3.51 spooler has been changed to accept Get/SetJobs on the
  1115. // local server handle. We will still do security checks against
  1116. // the Job's security descriptor. This also avoids the costly
  1117. // FindLocalJob() call.
  1118. //
  1119. if (!MyOpenPrinterW( pszServer, &hPrinter, NULL)) {
  1120. rc = GetLastError();
  1121. NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobSetInfoW: "
  1122. "MyOpenPrinter( NULL, &hPrinter, NULL ) failed"
  1123. FORMAT_API_STATUS "\n", rc ));
  1124. hPrinter = INVALID_HANDLE_VALUE;
  1125. goto Cleanup;
  1126. }
  1127. NetpAssert( hPrinter != INVALID_HANDLE_VALUE );
  1128. //
  1129. // Note: this should really call MyGetJobW, since it looks
  1130. // like the code later thunks from ansi back to unicode.
  1131. //
  1132. if (!MyGetJobA(hPrinter, uJobId, 2, NULL, 0, &cb)) {
  1133. rc=GetLastError();
  1134. NetpAssert( rc != NO_ERROR );
  1135. if (rc == ERROR_INSUFFICIENT_BUFFER) {
  1136. pJob = (LPVOID) GlobalAlloc(GMEM_FIXED, cb);
  1137. if (pJob == NULL) {
  1138. rc = ERROR_NOT_ENOUGH_MEMORY;
  1139. goto Cleanup;
  1140. }
  1141. if ( !MyGetJobA(hPrinter, uJobId, 2, (LPBYTE)pJob, cb, &cb) ) {
  1142. rc=GetLastError();
  1143. NetpAssert( rc != NO_ERROR );
  1144. goto Cleanup;
  1145. }
  1146. } else {
  1147. if (rc == ERROR_INVALID_PARAMETER) {
  1148. rc = NERR_JobNotFound;
  1149. }
  1150. goto Cleanup; // Job deleted? Not enough mem?
  1151. }
  1152. }
  1153. if (pJob == NULL) {
  1154. NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobGetInfoW: "
  1155. "*** STILL INVALID RESULT FROM MyGetJob, pJob IS NULL!\n" ));
  1156. rc = NERR_InternalError;
  1157. goto Cleanup;
  1158. }
  1159. NetpAssert( pJob != NULL );
  1160. NetpAssert( pJob->pPrinterName != NULL );
  1161. QueueNameA = FindQueueNameInPrinterNameA(
  1162. (pJob->pPrinterName) );
  1163. NetpAssert( QueueNameA != NULL );
  1164. QueueNameW = NetpAllocWStrFromStr( QueueNameA );
  1165. if (QueueNameW == NULL) {
  1166. rc = ERROR_NOT_ENOUGH_MEMORY;
  1167. goto Cleanup;
  1168. }
  1169. NetpAssert( QueueNameW != NULL );
  1170. cb=GetPrjInfoSizeW(uLevel, pJob, QueueNameW);
  1171. *pcbNeeded=(WORD)cb;
  1172. if (cb > (DWORD) cbBuf) {
  1173. rc = NERR_BufTooSmall;
  1174. goto Cleanup;
  1175. }
  1176. pEnd = (LPVOID) (pbBuf+cbBuf);
  1177. (VOID) CopyJobToPrjInfoW(uLevel, pJob, QueueNameW, pbBuf, pEnd);
  1178. rc = NO_ERROR;
  1179. Cleanup:
  1180. if (hPrinter != INVALID_HANDLE_VALUE) {
  1181. (VOID) MyClosePrinter( hPrinter );
  1182. }
  1183. if (pJob != NULL) {
  1184. (VOID) GlobalFree( pJob );
  1185. }
  1186. if (QueueNameW != NULL) {
  1187. (VOID) NetApiBufferFree( QueueNameW );
  1188. }
  1189. return (rc);
  1190. }
  1191. SPLERR SPLENTRY DosPrintJobDelW(
  1192. LPWSTR pszServer,
  1193. BOOL bRemote,
  1194. WORD uJobId
  1195. )
  1196. {
  1197. if (bRemote)
  1198. return RxPrintJobDel(pszServer, uJobId);
  1199. return (CommandALocalJobA(NULL, pszServer, NULL, uJobId, 0, NULL, JOB_CONTROL_CANCEL ) );
  1200. }
  1201. SPLERR SPLENTRY DosPrintJobContinueW(
  1202. LPWSTR pszServer,
  1203. BOOL bRemote,
  1204. WORD uJobId
  1205. )
  1206. {
  1207. if (bRemote)
  1208. return RxPrintJobContinue(pszServer, uJobId);
  1209. return (CommandALocalJobA(NULL, pszServer, NULL, uJobId, 0, NULL, JOB_CONTROL_RESUME ) );
  1210. }
  1211. SPLERR SPLENTRY DosPrintJobPauseW(
  1212. LPWSTR pszServer,
  1213. BOOL bRemote,
  1214. WORD uJobId
  1215. )
  1216. {
  1217. if (bRemote)
  1218. return RxPrintJobPause(pszServer, uJobId);
  1219. return (CommandALocalJobA(NULL, pszServer, NULL, uJobId, 0, NULL, JOB_CONTROL_PAUSE ) );
  1220. }
  1221. SPLERR SPLENTRY DosPrintJobEnumW(
  1222. LPWSTR pszServer,
  1223. LPWSTR pszQueueName,
  1224. WORD uLevel,
  1225. PBYTE pbBuf,
  1226. WORD cbBuf,
  1227. PWORD pcReturned,
  1228. PWORD pcTotal
  1229. )
  1230. {
  1231. DWORD cbPrinter;
  1232. LPJOB_INFO_2 pJob = NULL;
  1233. LPJOB_INFO_2 pJobs;
  1234. DWORD cb, cbJobs, cReturned, cJobs;
  1235. HANDLE hPrinter = INVALID_HANDLE_VALUE;
  1236. LPWSTR pEnd;
  1237. DWORD rc;
  1238. DWORD cTotal;
  1239. if (pszServer && *pszServer) {
  1240. rc = RxPrintJobEnum(pszServer, pszQueueName, uLevel, pbBuf,
  1241. cbBuf, &cReturned, &cTotal);
  1242. *pcReturned = (WORD)cReturned;
  1243. *pcTotal = (WORD)cTotal;
  1244. goto Cleanup;
  1245. }
  1246. *pcReturned=0;
  1247. *pcTotal = 0;
  1248. if ( !NetpIsPrintJobLevelValid( uLevel, FALSE ) ) {
  1249. rc = ERROR_INVALID_LEVEL;
  1250. goto Cleanup;
  1251. }
  1252. if (!MyOpenPrinterW( pszQueueName, &hPrinter, NULL)) {
  1253. rc = GetLastError();
  1254. goto Cleanup;
  1255. }
  1256. NetpAssert( hPrinter != INVALID_HANDLE_VALUE );
  1257. if (!MyEnumJobs(hPrinter, 0, (DWORD) -1, 2, NULL, 0, &cbJobs, &cReturned)) {
  1258. rc = GetLastError();
  1259. NetpAssert( rc != NO_ERROR );
  1260. if (rc == ERROR_INSUFFICIENT_BUFFER) {
  1261. if (pJob = (LPVOID) GlobalAlloc(GMEM_FIXED, cbJobs)) {
  1262. if (!MyEnumJobs(hPrinter, 0, (DWORD) -1, 2, (LPBYTE)pJob, cbJobs,
  1263. &cbJobs, &cReturned)) {
  1264. rc = GetLastError();
  1265. NetpAssert( rc != NO_ERROR );
  1266. NetpAssert( rc != ERROR_INSUFFICIENT_BUFFER );
  1267. NetpKdPrint(( PREFIX_DOSPRINT
  1268. "DosPrintJobEnumW: got error " FORMAT_API_STATUS
  1269. " from MyEnumJobs(first)\n", rc ));
  1270. goto Cleanup;
  1271. }
  1272. } else {
  1273. rc = ERROR_NOT_ENOUGH_MEMORY;
  1274. goto Cleanup;
  1275. }
  1276. } else {
  1277. NetpKdPrint(( PREFIX_DOSPRINT
  1278. "DosPrintJobEnumW: got error " FORMAT_API_STATUS
  1279. " from MyEnumJobs(first)\n", rc ));
  1280. goto Cleanup;
  1281. }
  1282. }
  1283. if (cReturned == 0) {
  1284. *pcReturned = 0;
  1285. *pcTotal = 0;
  1286. rc = NO_ERROR;
  1287. goto Cleanup;
  1288. }
  1289. if (pJob == NULL) {
  1290. NetpKdPrint(( PREFIX_DOSPRINT
  1291. "DosPrintJobEnumW: never allocated array!\n" ));
  1292. rc = NERR_InternalError;
  1293. goto Cleanup;
  1294. }
  1295. *pcTotal = (WORD)cReturned;
  1296. cb=0;
  1297. cJobs=cReturned;
  1298. pJobs=pJob;
  1299. while (cJobs--)
  1300. cb+=GetPrjInfoSizeW(uLevel, pJobs++, pszQueueName);
  1301. if (cb <= (DWORD) cbBuf) {
  1302. DWORD cbFixedPortion = PrjInfoFixedSizeW( uLevel );
  1303. NetpAssert( cbFixedPortion != 0 ); // level already checked!
  1304. pEnd = (LPWSTR)(pbBuf+cbBuf);
  1305. cJobs=cReturned;
  1306. pJobs=pJob;
  1307. while (cJobs--) {
  1308. pEnd = CopyJobToPrjInfoW(uLevel, pJobs++,
  1309. pszQueueName,
  1310. pbBuf, pEnd);
  1311. pbBuf += cbFixedPortion;
  1312. }
  1313. *pcReturned = (WORD)cReturned;
  1314. rc = NO_ERROR;
  1315. } else {
  1316. rc = NERR_BufTooSmall;
  1317. goto Cleanup;
  1318. }
  1319. Cleanup:
  1320. if (hPrinter != INVALID_HANDLE_VALUE) {
  1321. (VOID) MyClosePrinter( hPrinter );
  1322. }
  1323. if (pJob != NULL) {
  1324. (VOID) GlobalFree( pJob );
  1325. }
  1326. return rc;
  1327. }
  1328. SPLERR SPLENTRY
  1329. DosPrintDestEnumW(
  1330. IN LPWSTR pszServer OPTIONAL,
  1331. IN WORD uLevel,
  1332. OUT PBYTE pbBuf,
  1333. IN WORD cbBuf,
  1334. OUT PUSHORT pcReturned,
  1335. OUT PUSHORT pcTotal
  1336. )
  1337. {
  1338. DWORD cReturned=0, cTotal=0, rc;
  1339. if (pszServer && *pszServer) {
  1340. rc = RxPrintDestEnum(pszServer, uLevel, pbBuf, cbBuf,
  1341. &cReturned, &cTotal);
  1342. *pcReturned = (USHORT)cReturned;
  1343. *pcTotal = (USHORT)cTotal;
  1344. return rc;
  1345. }
  1346. // Stub for local dest enum - no entries, dest not found.
  1347. *pcReturned = 0;
  1348. *pcTotal = 0;
  1349. return ERROR_NOT_SUPPORTED;
  1350. }
  1351. SPLERR SPLENTRY DosPrintDestControlW(
  1352. LPWSTR pszServer,
  1353. LPWSTR pszDevName,
  1354. WORD uControl
  1355. )
  1356. {
  1357. if (pszServer && *pszServer)
  1358. return RxPrintDestControl(pszServer, pszDevName, uControl);
  1359. return ERROR_NOT_SUPPORTED;
  1360. }
  1361. SPLERR SPLENTRY DosPrintDestGetInfoW(
  1362. LPWSTR pszServer,
  1363. LPWSTR pszName,
  1364. WORD uLevel,
  1365. PBYTE pbBuf,
  1366. WORD cbBuf,
  1367. PUSHORT pcbNeeded
  1368. )
  1369. {
  1370. DWORD cbNeeded = 0, rc;
  1371. if (pszServer && *pszServer) {
  1372. rc = RxPrintDestGetInfo(pszServer, pszName, uLevel, pbBuf,
  1373. cbBuf, &cbNeeded);
  1374. *pcbNeeded = (USHORT)cbNeeded;
  1375. return rc;
  1376. }
  1377. return ERROR_NOT_SUPPORTED;
  1378. }
  1379. SPLERR SPLENTRY DosPrintDestAddW(
  1380. LPWSTR pszServer,
  1381. WORD uLevel,
  1382. PBYTE pbBuf,
  1383. WORD cbBuf
  1384. )
  1385. {
  1386. if (pszServer && *pszServer)
  1387. return RxPrintDestAdd(pszServer, uLevel, pbBuf, cbBuf);
  1388. return ERROR_NOT_SUPPORTED;
  1389. }
  1390. SPLERR SPLENTRY DosPrintDestSetInfoW(
  1391. LPWSTR pszServer,
  1392. LPWSTR pszName,
  1393. WORD uLevel,
  1394. PBYTE pbBuf,
  1395. WORD cbBuf,
  1396. WORD uParmNum
  1397. )
  1398. {
  1399. if (pszServer && *pszServer)
  1400. return RxPrintDestSetInfo(pszServer, pszName, uLevel, pbBuf,
  1401. cbBuf, uParmNum);
  1402. return ERROR_NOT_SUPPORTED;
  1403. }
  1404. SPLERR SPLENTRY DosPrintDestDelW(
  1405. LPWSTR pszServer,
  1406. LPWSTR pszPrinterName
  1407. )
  1408. {
  1409. if (pszServer && *pszServer)
  1410. return RxPrintDestDel(pszServer, pszPrinterName);
  1411. return ERROR_NOT_SUPPORTED;
  1412. }
  1413. SPLERR SPLENTRY DosPrintQEnumW(
  1414. LPWSTR pszServer,
  1415. WORD uLevel,
  1416. PBYTE pbBuf,
  1417. WORD cbBuf,
  1418. PUSHORT pcReturned,
  1419. PUSHORT pcTotal
  1420. )
  1421. {
  1422. DWORD cJobsReturned;
  1423. DWORD Total, cbNeeded, rc;
  1424. HANDLE hPrinter = INVALID_HANDLE_VALUE;
  1425. DWORD i;
  1426. DWORD JobFixedEntrySize = 0;
  1427. DWORD JobLevel;
  1428. LPSHARE_INFO_1 pShareInfo = NULL;
  1429. DWORD cbPrinter;
  1430. LPPRINTER_INFO_2 pPrinter = NULL;
  1431. BOOL BufferTooSmall=FALSE;
  1432. DWORD cReturned = 0;
  1433. DWORD cTotal = 0;
  1434. #if DBG
  1435. LPVOID OutputBufferStart = pbBuf;
  1436. #endif
  1437. LPVOID pEnd;
  1438. DWORD SharesRead;
  1439. if ( !NetpIsPrintQLevelValid( uLevel, FALSE ) ) {
  1440. rc = ERROR_INVALID_LEVEL;
  1441. goto Cleanup;
  1442. }
  1443. if (pszServer && *pszServer) {
  1444. rc = RxPrintQEnum(pszServer, uLevel, pbBuf, cbBuf, &cReturned, &cTotal);
  1445. *pcReturned = (USHORT)cReturned;
  1446. *pcTotal = (USHORT)cTotal;
  1447. goto Cleanup;
  1448. }
  1449. *pcReturned = 0;
  1450. *pcTotal = 0;
  1451. rc=NetShareEnum(
  1452. NULL,
  1453. 1,
  1454. (LPBYTE *)(LPVOID)&pShareInfo,
  1455. MAX_PREFERRED_LENGTH,
  1456. &SharesRead,
  1457. &Total,
  1458. NULL);
  1459. if (rc != NO_ERROR) {
  1460. NetpKdPrint((PREFIX_DOSPRINT "DosPrintQEnumW: NetShareEnum returned "
  1461. FORMAT_API_STATUS "\n", rc));
  1462. goto Cleanup;
  1463. }
  1464. pEnd = (pbBuf + cbBuf);
  1465. if (uLevel==2) {
  1466. JobLevel = 1;
  1467. JobFixedEntrySize = PrjInfoFixedSizeW( JobLevel );
  1468. } else if (uLevel == 4) {
  1469. JobLevel = 2;
  1470. JobFixedEntrySize = PrjInfoFixedSizeW( JobLevel );
  1471. }
  1472. for (i=0; i<SharesRead; i++) {
  1473. if (pShareInfo[i].shi1_type != STYPE_PRINTQ) {
  1474. continue;
  1475. }
  1476. NetpAssert( pShareInfo[i].shi1_netname != NULL );
  1477. NetpAssert( (*pShareInfo[i].shi1_netname) != L'\0' );
  1478. if (STRLEN( pShareInfo[i].shi1_netname ) > LM20_QNLEN) {
  1479. continue;
  1480. }
  1481. if ( !MyOpenPrinterW(pShareInfo[i].shi1_netname, &hPrinter, NULL)) {
  1482. rc = (NET_API_STATUS) GetLastError();
  1483. NetpKdPrint(( PREFIX_DOSPRINT
  1484. "DosPrintQEnumW: MyOpenPrinter failed, status "
  1485. FORMAT_API_STATUS ".\n", rc ));
  1486. NetpAssert( rc != NO_ERROR );
  1487. goto Cleanup;
  1488. }
  1489. NetpAssert( hPrinter != INVALID_HANDLE_VALUE );
  1490. if (!MyGetPrinter(hPrinter, 2, NULL, 0, &cbPrinter)) {
  1491. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  1492. rc = (NET_API_STATUS) GetLastError();
  1493. NetpKdPrint(( PREFIX_DOSPRINT
  1494. "DosPrintQEnumW: MyGetPrinter(first) failed, status "
  1495. FORMAT_API_STATUS ".\n", rc ));
  1496. NetpAssert( rc != NO_ERROR );
  1497. goto Cleanup;
  1498. }
  1499. }
  1500. NetpAssert( cbPrinter != 0 );
  1501. pPrinter = (LPVOID) GlobalAlloc(GMEM_FIXED, cbPrinter);
  1502. if (pPrinter == NULL) {
  1503. rc = ERROR_NOT_ENOUGH_MEMORY;
  1504. goto Cleanup;
  1505. }
  1506. if ( !MyGetPrinter(hPrinter, 2, (LPBYTE)pPrinter,
  1507. cbPrinter, &cbPrinter)) {
  1508. rc = (NET_API_STATUS) GetLastError();
  1509. NetpKdPrint(( PREFIX_DOSPRINT
  1510. "DosPrintQEnumW: MyGetPrinter(second) failed, status "
  1511. FORMAT_API_STATUS ".\n", rc ));
  1512. NetpAssert( rc != NO_ERROR );
  1513. goto Cleanup;
  1514. }
  1515. cbNeeded=GetPrqInfoSizeW(uLevel,
  1516. pShareInfo[i].shi1_netname, // Q nam
  1517. pPrinter);
  1518. NetpAssert( cbNeeded > 0 );
  1519. NetpAssert( cbNeeded <= (DWORD) MAX_WORD );
  1520. if ( (!BufferTooSmall) && ((DWORD)cbBuf >= cbNeeded) ) {
  1521. LPVOID pbQueue = pbBuf;
  1522. //
  1523. // Handle queue structure itself.
  1524. //
  1525. pEnd = CopyPrinterToPrqInfoW(pPrinter,
  1526. uLevel,
  1527. pbBuf,
  1528. pShareInfo[i].shi1_netname,
  1529. pEnd);
  1530. pbBuf += PrqInfoFixedSizeW( uLevel );
  1531. cbBuf -= (WORD) cbNeeded;
  1532. //
  1533. // Append job structures if needed.
  1534. //
  1535. if ( (uLevel==2) || (uLevel==4) ) { // info level includes jobs
  1536. NetpAssert( pbBuf < (LPBYTE) pEnd );
  1537. rc = AppendJobsToPrqW(
  1538. pShareInfo[i].shi1_netname,
  1539. uLevel, // Q info level
  1540. hPrinter,
  1541. pbBuf, // first job here
  1542. cbBuf, // bytes avail
  1543. pEnd, // str area
  1544. & pEnd, // set new end ptr
  1545. & cbNeeded,
  1546. & cJobsReturned,
  1547. FALSE ); // Only accept all the data.
  1548. if (rc == NERR_BufTooSmall) {
  1549. BufferTooSmall = TRUE; // continue, as we need pcTotal...
  1550. } else if (rc != NO_ERROR) {
  1551. goto Cleanup;
  1552. } else { // Must be NO_ERROR.
  1553. NetpAssert( cbNeeded <= (DWORD) MAX_WORD );
  1554. NetpAssert( pbBuf < (LPBYTE) pEnd );
  1555. NetpAssert( JobFixedEntrySize !=0 );
  1556. pbBuf += (JobFixedEntrySize * cJobsReturned);
  1557. cbBuf -= (WORD) cbNeeded;
  1558. (*pcReturned)++;
  1559. // Correct possible out of date
  1560. // job count in queue structure.
  1561. NetpSetJobCountForQueue(
  1562. uLevel,
  1563. pbQueue,
  1564. TRUE, // yes, UNICODE strs
  1565. cJobsReturned );
  1566. }
  1567. } else { // info level does not include jobs
  1568. (*pcReturned)++;
  1569. }
  1570. } else { // not enough mem for Q struct
  1571. BufferTooSmall = TRUE;
  1572. // Continue, as we want to compute pcTotal for subsequent queues.
  1573. }
  1574. (*pcTotal)++;
  1575. NetpAssert( pPrinter != NULL );
  1576. (VOID) GlobalFree(pPrinter);
  1577. pPrinter = NULL;
  1578. NetpAssert( hPrinter != INVALID_HANDLE_VALUE );
  1579. (VOID) MyClosePrinter(hPrinter);
  1580. hPrinter = INVALID_HANDLE_VALUE;
  1581. } // for each share
  1582. Cleanup:
  1583. if (hPrinter != INVALID_HANDLE_VALUE) {
  1584. (VOID) MyClosePrinter( hPrinter );
  1585. }
  1586. if (pPrinter != NULL) {
  1587. (VOID) GlobalFree( pPrinter );
  1588. }
  1589. if (pShareInfo != NULL) {
  1590. (VOID) NetApiBufferFree(pShareInfo);
  1591. }
  1592. if (BufferTooSmall) {
  1593. rc = NERR_BufTooSmall;
  1594. }
  1595. return (rc);
  1596. }
  1597. SPLERR SPLENTRY DosPrintQSetInfoW(
  1598. LPWSTR pszServer,
  1599. LPWSTR pszQueueName,
  1600. WORD uLevel,
  1601. PBYTE pbBuf,
  1602. WORD cbBuf,
  1603. WORD uParmNum
  1604. )
  1605. {
  1606. if (pszServer && *pszServer)
  1607. return RxPrintQSetInfo(pszServer, pszQueueName, uLevel, pbBuf,
  1608. cbBuf, uParmNum);
  1609. return ERROR_NOT_SUPPORTED;
  1610. }
  1611. SPLERR SPLENTRY DosPrintQPauseW(
  1612. LPWSTR pszServer,
  1613. LPWSTR pszQueueName
  1614. )
  1615. {
  1616. if (pszServer && *pszServer)
  1617. return RxPrintQPause(pszServer, pszQueueName);
  1618. return (CommandALocalPrinterW( pszQueueName, PRINTER_CONTROL_PAUSE ) );
  1619. }
  1620. SPLERR SPLENTRY DosPrintQContinueW(
  1621. LPWSTR pszServer,
  1622. LPWSTR pszQueueName
  1623. )
  1624. {
  1625. if (pszServer && *pszServer)
  1626. return RxPrintQContinue(pszServer, pszQueueName);
  1627. return (CommandALocalPrinterW( pszQueueName, PRINTER_CONTROL_RESUME ) );
  1628. }
  1629. SPLERR SPLENTRY DosPrintQPurgeW(
  1630. LPWSTR pszServer,
  1631. LPWSTR pszQueueName
  1632. )
  1633. {
  1634. if (pszServer && *pszServer)
  1635. return RxPrintQPurge(pszServer, pszQueueName);
  1636. return (CommandALocalPrinterW( pszQueueName, PRINTER_CONTROL_PURGE ) );
  1637. }
  1638. SPLERR SPLENTRY DosPrintQAddW(
  1639. LPWSTR pszServer,
  1640. WORD uLevel,
  1641. PBYTE pbBuf,
  1642. WORD cbBuf
  1643. )
  1644. {
  1645. if (pszServer && *pszServer)
  1646. return RxPrintQAdd(pszServer, uLevel, pbBuf, cbBuf);
  1647. return ERROR_NOT_SUPPORTED;
  1648. }
  1649. SPLERR SPLENTRY DosPrintQDelW(
  1650. LPWSTR pszServer,
  1651. LPWSTR pszQueueName
  1652. )
  1653. {
  1654. if (pszServer && *pszServer)
  1655. return RxPrintQDel(pszServer, pszQueueName);
  1656. return ERROR_NOT_SUPPORTED;
  1657. }
  1658. SPLERR SPLENTRY DosPrintJobSetInfoW(
  1659. LPWSTR pszServer,
  1660. BOOL bRemote,
  1661. WORD uJobId,
  1662. WORD uLevel,
  1663. PBYTE pbBuf,
  1664. WORD cbBuf,
  1665. WORD uParmNum
  1666. )
  1667. {
  1668. if (bRemote)
  1669. return RxPrintJobSetInfo(pszServer, uJobId, uLevel, pbBuf,
  1670. cbBuf, uParmNum);
  1671. //
  1672. // Hack for Chicago: support Level 1, ParmNum 0xb so that jobs
  1673. // are set with the comment field.
  1674. //
  1675. if (uLevel == 1 && uParmNum == PRJ_COMMENT_PARMNUM) {
  1676. HANDLE hPrinter = INVALID_HANDLE_VALUE;
  1677. CHAR szDocument[MAX_PATH];
  1678. PJOB_INFO_1 pJob = NULL;
  1679. DWORD cbJob;
  1680. SPLERR rc;
  1681. //
  1682. // Allocate maximum size of JOB_INFO_1A. Later, this
  1683. // should be moved into the spooler's header file.
  1684. //
  1685. cbJob = sizeof(JOB_INFO_1) + 6 * MAX_PATH;
  1686. pJob = (PJOB_INFO_1) GlobalAlloc(GMEM_FIXED, cbJob);
  1687. if (pJob == NULL) {
  1688. rc = GetLastError();
  1689. goto Cleanup;
  1690. }
  1691. //
  1692. // The 3.51 spooler has been changed to accept Get/SetJobs on the
  1693. // local server handle. We will still do security checks against
  1694. // the Job's security descriptor. This also avoids the costly
  1695. // FindLocalJob() call.
  1696. //
  1697. if (!MyOpenPrinterW( pszServer, &hPrinter, NULL)) {
  1698. rc = GetLastError();
  1699. NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobSetInfoW: "
  1700. "MyOpenPrinter( NULL, &hPrinter, NULL ) failed"
  1701. FORMAT_API_STATUS "\n", rc ));
  1702. hPrinter = INVALID_HANDLE_VALUE;
  1703. goto Cleanup;
  1704. }
  1705. NetpAssert( hPrinter != INVALID_HANDLE_VALUE );
  1706. //
  1707. // We need to get a copy of the old job info. Later, the
  1708. // spooler should be changed to allow "don't change" values.
  1709. //
  1710. if (!MyGetJobA( hPrinter, uJobId, 1, (PBYTE)pJob, cbJob, &cbJob )) {
  1711. rc = GetLastError();
  1712. NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobSetInfoW: "
  1713. "MyGetJob failed" FORMAT_API_STATUS "\n", rc ));
  1714. goto Cleanup;
  1715. }
  1716. //
  1717. // Put in new document name.
  1718. //
  1719. NetpNCopyWStrToStr( szDocument,
  1720. (LPWSTR)pbBuf,
  1721. sizeof( szDocument ) / sizeof( szDocument[0] ));
  1722. pJob->pDocument = szDocument;
  1723. //
  1724. // Don't try and change the position, since this requires
  1725. // admin access (and isn't necessary).
  1726. //
  1727. pJob->Position = JOB_POSITION_UNSPECIFIED;
  1728. rc = CommandALocalJobA( hPrinter, NULL, NULL, uJobId, 1, (PBYTE)pJob, 0 );
  1729. if (rc) {
  1730. NetpKdPrint((PREFIX_DOSPRINT "DosPrintJobSetInfoW: "
  1731. "CommandALocalJobA failed " FORMAT_API_STATUS "\n", rc ));
  1732. }
  1733. Cleanup:
  1734. if (pJob) {
  1735. GlobalFree( pJob );
  1736. }
  1737. if (hPrinter != INVALID_HANDLE_VALUE) {
  1738. MyClosePrinter( hPrinter );
  1739. }
  1740. return rc;
  1741. }
  1742. return ERROR_NOT_SUPPORTED;
  1743. }
  1744. VOID
  1745. NetpSetJobCountForQueue(
  1746. IN DWORD QueueLevel,
  1747. IN OUT LPVOID Queue,
  1748. IN BOOL HasUnicodeStrings,
  1749. IN DWORD JobCount
  1750. )
  1751. {
  1752. NetpAssert( NetpIsPrintQLevelValid( QueueLevel, FALSE ) );
  1753. NetpAssert( Queue != NULL );
  1754. if (QueueLevel == 2) {
  1755. if (HasUnicodeStrings) {
  1756. PPRQINFOW pq = Queue;
  1757. pq->cJobs = (WORD) JobCount;
  1758. } else {
  1759. PPRQINFOA pq = Queue;
  1760. pq->cJobs = (WORD) JobCount;
  1761. }
  1762. } else if (QueueLevel == 4) {
  1763. if (HasUnicodeStrings) {
  1764. PPRQINFO3W pq = Queue;
  1765. pq->cJobs = (WORD) JobCount;
  1766. } else {
  1767. PPRQINFO3A pq = Queue;
  1768. pq->cJobs = (WORD) JobCount;
  1769. }
  1770. } else {
  1771. NetpAssert( FALSE ); // Should never get here!
  1772. }
  1773. } // NetpSetJobCountForQueue