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.

1085 lines
27 KiB

  1. #include "procs.hxx"
  2. #pragma hdrstop
  3. /*++
  4. Copyright (c) 1996 Microsoft Corporation
  5. All rights reserved
  6. Module Name:
  7. PrintWrp.c
  8. Abstract:
  9. Wide end to Win95 Ansi printing APIs
  10. Author:
  11. Felix Wong (t-felixw)
  12. Environment:
  13. Revision History:
  14. --*/
  15. #include "dswarn.h"
  16. #include <stddef.h>
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <data.h>
  20. typedef struct _SPOOL *PSPOOL;
  21. typedef struct _NOTIFY *PNOTIFY;
  22. typedef struct _NOTIFY {
  23. PNOTIFY pNext;
  24. HANDLE hEvent; // event to trigger on notification
  25. DWORD fdwFlags; // flags to watch for
  26. DWORD fdwOptions; // PRINTER_NOTIFY_*
  27. DWORD dwReturn; // used by WPC when simulating FFPCN
  28. PSPOOL pSpool;
  29. } NOTIFY;
  30. typedef struct _SPOOL {
  31. DWORD signature;
  32. HANDLE hPrinter;
  33. HANDLE hFile;
  34. DWORD JobId;
  35. LPBYTE pBuffer;
  36. DWORD cbBuffer;
  37. DWORD Status;
  38. DWORD fdwFlags;
  39. DWORD cCacheWrite;
  40. DWORD cWritePrinters;
  41. DWORD cFlushBuffers;
  42. DWORD dwTickCount;
  43. DWORD dwCheckJobInterval;
  44. PNOTIFY pNotify;
  45. } SPOOL;
  46. #define SPOOL_STATUS_ANSI 0x00000004
  47. #define MIN_DEVMODE_SIZEW 72
  48. #define MIN_DEVMODE_SIZEA 40
  49. #define NULL_TERMINATED 0
  50. BOOL
  51. ConvertAnsiToUnicodeBuf(
  52. LPBYTE pAnsiBlob,
  53. LPBYTE pUnicodeBlob,
  54. DWORD dwAnsiSize,
  55. DWORD dwUnicodeSize,
  56. PDWORD pOffsets
  57. );
  58. BOOL
  59. bValidDevModeW(
  60. const DEVMODEW *pDevModeW
  61. )
  62. /*++
  63. Routine Description:
  64. Check whether a devmode is valid to be RPC'd across to the spooler.
  65. Arguments:
  66. pDevMode - DevMode to check.
  67. Return Value:
  68. TRUE - Devmode can be RPC'd to spooler.
  69. FALSE - Invalid Devmode.
  70. --*/
  71. {
  72. if( !pDevModeW ){
  73. return FALSE;
  74. }
  75. if( pDevModeW->dmSize < MIN_DEVMODE_SIZEW ){
  76. //
  77. // The only valid case is if pDevModeW is NULL. If it's
  78. // not NULL, then a bad devmode was passed in and the
  79. // app should fix it's code.
  80. //
  81. ASSERT( pDevModeW->dmSize >= MIN_DEVMODE_SIZEW );
  82. return FALSE;
  83. }
  84. return TRUE;
  85. }
  86. LPSTR
  87. AllocateAnsiString(
  88. LPWSTR pPrinterName
  89. )
  90. {
  91. LPSTR pAnsiString;
  92. if (!pPrinterName)
  93. return NULL;
  94. pAnsiString = (LPSTR)LocalAlloc(LPTR, wcslen(pPrinterName)*sizeof(CHAR) +
  95. sizeof(CHAR));
  96. if (pAnsiString)
  97. UnicodeToAnsiString(pPrinterName, pAnsiString, NULL_TERMINATED);
  98. return pAnsiString;
  99. }
  100. LPSTR
  101. FreeAnsiString(
  102. LPSTR pAnsiString
  103. )
  104. {
  105. if (!pAnsiString)
  106. return NULL;
  107. return (LPSTR)LocalFree(pAnsiString);
  108. }
  109. /***************************** Function Header ******************************
  110. * AllocateAnsiDevMode
  111. * Allocate an ANSI version of the DEVMODE structure, and optionally
  112. * copy the contents of the ANSI version passed in.
  113. *
  114. * RETURNS:
  115. * Address of newly allocated structure, 0 if storage not available.
  116. *
  117. * HISTORY:
  118. * 09:23 on 10-Aug-92 -by- Lindsay Harris [lindsayh]
  119. * Made it usable.
  120. *
  121. * Originally "written" by DaveSn.
  122. *
  123. ***************************************************************************/
  124. LPDEVMODEA
  125. AllocateAnsiDevMode(
  126. LPDEVMODEW pUNICODEDevMode
  127. )
  128. {
  129. LPDEVMODEA pAnsiDevMode;
  130. LPBYTE p1, p2;
  131. DWORD dwSize;
  132. //
  133. // If the devmode is NULL, then return NULL -- KrishnaG
  134. //
  135. if ( !pUNICODEDevMode || !pUNICODEDevMode->dmSize ) {
  136. return NULL;
  137. }
  138. ASSERT( bValidDevModeW( pUNICODEDevMode ));
  139. //
  140. // Determine output structure size. This has two components: the
  141. // DEVMODEW structure size, plus any private data area. The latter
  142. // is only meaningful when a structure is passed in.
  143. //
  144. dwSize = pUNICODEDevMode->dmSize + pUNICODEDevMode->dmDriverExtra
  145. + sizeof(DEVMODEA) - sizeof(DEVMODEW);
  146. pAnsiDevMode = (LPDEVMODEA) LocalAlloc(LPTR, dwSize);
  147. if( !pAnsiDevMode ) {
  148. return NULL; /* This is bad news */
  149. }
  150. //
  151. // Copy dmDeviceName which is a string
  152. //
  153. UnicodeToAnsiString(pUNICODEDevMode->dmDeviceName,
  154. (LPSTR)(pAnsiDevMode->dmDeviceName),
  155. ComputeMaxStrlenW(pUNICODEDevMode->dmDeviceName,
  156. sizeof pUNICODEDevMode->dmDeviceName));
  157. //
  158. // Does the devmode we got have a dmFormName? (Windows 3.1 had
  159. // DevMode of size 40 and did not have dmFormName)
  160. //
  161. if ( (LPBYTE)pUNICODEDevMode + pUNICODEDevMode->dmSize >
  162. (LPBYTE) pUNICODEDevMode->dmFormName ) {
  163. //
  164. // Copy everything between dmDeviceName and dmFormName
  165. //
  166. p1 = (LPBYTE) pUNICODEDevMode->dmDeviceName +
  167. sizeof(pUNICODEDevMode->dmDeviceName);
  168. p2 = (LPBYTE) pUNICODEDevMode->dmFormName;
  169. CopyMemory((LPBYTE) pAnsiDevMode->dmDeviceName +
  170. sizeof(pAnsiDevMode->dmDeviceName),
  171. p1,
  172. p2 - p1);
  173. //
  174. // Copy dmFormName which is a string
  175. //
  176. UnicodeToAnsiString(pUNICODEDevMode->dmFormName,
  177. (LPSTR)(pAnsiDevMode->dmFormName),
  178. ComputeMaxStrlenW(pUNICODEDevMode->dmFormName,
  179. sizeof pUNICODEDevMode->dmFormName));
  180. //
  181. // Copy everything after dmFormName
  182. //
  183. p1 = (LPBYTE) pUNICODEDevMode->dmFormName +
  184. sizeof(pUNICODEDevMode->dmFormName);
  185. p2 = (LPBYTE) pUNICODEDevMode + pUNICODEDevMode->dmSize
  186. + pUNICODEDevMode->dmDriverExtra;
  187. CopyMemory((LPBYTE) pAnsiDevMode->dmFormName +
  188. sizeof(pAnsiDevMode->dmFormName),
  189. p1,
  190. p2 - p1);
  191. pAnsiDevMode->dmSize = pUNICODEDevMode->dmSize + sizeof(DEVMODEA)
  192. - sizeof(DEVMODEW);
  193. } else {
  194. //
  195. // Copy everything after dmDeviceName
  196. //
  197. p1 = (LPBYTE) pUNICODEDevMode->dmDeviceName +
  198. sizeof(pUNICODEDevMode->dmDeviceName);
  199. p2 = (LPBYTE) pUNICODEDevMode + pUNICODEDevMode->dmSize + pUNICODEDevMode->dmDriverExtra;
  200. CopyMemory((LPBYTE) pAnsiDevMode->dmDeviceName +
  201. sizeof(pAnsiDevMode->dmDeviceName),
  202. p1,
  203. p2-p1);
  204. pAnsiDevMode->dmSize = pUNICODEDevMode->dmSize
  205. + sizeof(pAnsiDevMode->dmDeviceName)
  206. - sizeof(pUNICODEDevMode->dmDeviceName);
  207. }
  208. ASSERT(pAnsiDevMode->dmDriverExtra == pUNICODEDevMode->dmDriverExtra);
  209. return pAnsiDevMode;
  210. }
  211. /************************** Function Header ******************************
  212. * CopyUnicodeDevModeFromAnsiDevMode
  213. * Converts the ANSI version of the DEVMODE to the UNICODE version.
  214. *
  215. * RETURNS:
  216. * Nothing.
  217. *
  218. * HISTORY:
  219. * 09:57 on 10-Aug-92 -by- Lindsay Harris [lindsayh]
  220. * This one actually works!
  221. *
  222. * Originally dreamed up by DaveSn.
  223. *
  224. **************************************************************************/
  225. void
  226. CopyUnicodeDevModeFromAnsiDevMode(
  227. LPDEVMODEW pUNICODEDevMode, /* Filled in by us */
  228. LPDEVMODEA pAnsiDevMode /* Source of data to fill above */
  229. )
  230. {
  231. LPBYTE p1, p2, pExtra;
  232. WORD dmSize, dmDriverExtra;
  233. //
  234. // NOTE: THE TWO INPUT STRUCTURES MAY BE THE SAME.
  235. //
  236. dmSize = pAnsiDevMode->dmSize;
  237. dmDriverExtra = pAnsiDevMode->dmDriverExtra;
  238. pExtra = (LPBYTE) pAnsiDevMode + pAnsiDevMode->dmSize;
  239. //
  240. // Copy dmDeviceName which is a string
  241. //
  242. AnsiToUnicodeString((LPSTR)(pAnsiDevMode->dmDeviceName),
  243. (pUNICODEDevMode->dmDeviceName),
  244. ComputeMaxStrlenA((LPSTR)(pAnsiDevMode->dmDeviceName),
  245. sizeof pUNICODEDevMode->dmDeviceName));
  246. //
  247. // Does the devmode we got have a dmFormName? (Windows 3.1 had
  248. // DevMode of size 40 and did not have dmFormName)
  249. //
  250. if ( (LPBYTE)pAnsiDevMode + dmSize >
  251. (LPBYTE) pAnsiDevMode->dmFormName ) {
  252. //
  253. // Copy everything between dmDeviceName and dmFormName
  254. //
  255. p1 = (LPBYTE) pAnsiDevMode->dmDeviceName +
  256. sizeof(pAnsiDevMode->dmDeviceName);
  257. p2 = (LPBYTE) pAnsiDevMode->dmFormName;
  258. MoveMemory((LPBYTE) pUNICODEDevMode->dmDeviceName +
  259. sizeof(pUNICODEDevMode->dmDeviceName),
  260. p1,
  261. p2 - p1);
  262. //
  263. // Copy dmFormName which is a string
  264. //
  265. AnsiToUnicodeString((LPSTR)(pAnsiDevMode->dmFormName),
  266. pUNICODEDevMode->dmFormName,
  267. ComputeMaxStrlenA((LPSTR)pAnsiDevMode->dmFormName,
  268. sizeof pUNICODEDevMode->dmFormName));
  269. //
  270. // Copy everything after dmFormName
  271. //
  272. p1 = (LPBYTE) pAnsiDevMode->dmFormName +
  273. sizeof(pAnsiDevMode->dmFormName);
  274. p2 = (LPBYTE) pAnsiDevMode + dmSize + dmDriverExtra;
  275. MoveMemory((LPBYTE) pUNICODEDevMode->dmFormName +
  276. sizeof(pUNICODEDevMode->dmFormName),
  277. p1,
  278. p2 - p1);
  279. pUNICODEDevMode->dmSize = dmSize + sizeof(DEVMODEW) - sizeof(DEVMODEA);
  280. } else {
  281. //
  282. // Copy everything after dmDeviceName
  283. //
  284. p1 = (LPBYTE) pAnsiDevMode->dmDeviceName +
  285. sizeof(pAnsiDevMode->dmDeviceName);
  286. p2 = (LPBYTE) pAnsiDevMode + dmSize + dmDriverExtra;
  287. MoveMemory((LPBYTE) pUNICODEDevMode->dmDeviceName +
  288. sizeof(pUNICODEDevMode->dmDeviceName),
  289. p1,
  290. p2 - p1);
  291. pUNICODEDevMode->dmSize = dmSize + sizeof(pUNICODEDevMode->dmDeviceName)
  292. - sizeof(pAnsiDevMode->dmDeviceName);
  293. }
  294. ASSERT(pUNICODEDevMode->dmDriverExtra == dmDriverExtra);
  295. return;
  296. }
  297. void
  298. ConvertAnsiToUnicodeStrings(
  299. LPBYTE pStructure,
  300. LPDWORD pOffsets
  301. )
  302. {
  303. register DWORD i=0;
  304. LPSTR pAnsi;
  305. LPWSTR pUnicode;
  306. while (pOffsets[i] != -1) {
  307. pAnsi = *(LPSTR *)(pStructure+pOffsets[i]);
  308. if (pAnsi) {
  309. pUnicode = (LPWSTR)LocalAlloc( LPTR,
  310. strlen(pAnsi)*sizeof(WCHAR)+
  311. sizeof(WCHAR));
  312. if (pUnicode) {
  313. AnsiToUnicodeString(pAnsi,
  314. pUnicode,
  315. NULL_TERMINATED);
  316. *(LPWSTR *)(pStructure+pOffsets[i]) = pUnicode;
  317. LocalFree(pAnsi);
  318. }
  319. }
  320. i++;
  321. }
  322. }
  323. LPBYTE
  324. AllocateAnsiStructure(
  325. LPBYTE pUnicodeStructure,
  326. DWORD cbStruct,
  327. LPDWORD pOffsets
  328. )
  329. {
  330. DWORD i, j;
  331. LPSTR *ppAnsiString;
  332. LPWSTR *ppUnicodeString;
  333. LPBYTE pAnsiStructure;
  334. if (!pUnicodeStructure) {
  335. return NULL;
  336. }
  337. pAnsiStructure = (LPBYTE)LocalAlloc(LPTR, cbStruct);
  338. if (pAnsiStructure) {
  339. memcpy(pAnsiStructure, pUnicodeStructure, cbStruct);
  340. for (i = 0 ; pOffsets[i] != -1 ; ++i) {
  341. ppUnicodeString = (LPWSTR *)(pUnicodeStructure+pOffsets[i]);
  342. ppAnsiString = (LPSTR *)(pAnsiStructure+pOffsets[i]);
  343. *ppAnsiString = AllocateAnsiString(*ppUnicodeString);
  344. if (*ppUnicodeString && !*ppAnsiString) {
  345. for( j = 0 ; j < i ; ++j) {
  346. ppAnsiString = (LPSTR *)(pAnsiStructure+pOffsets[j]);
  347. FreeAnsiString(*ppAnsiString);
  348. }
  349. LocalFree(pAnsiStructure);
  350. pAnsiStructure = NULL;
  351. break;
  352. }
  353. }
  354. }
  355. return pAnsiStructure;
  356. }
  357. void
  358. FreeAnsiStructure(
  359. LPBYTE pAnsiStructure,
  360. LPDWORD pOffsets
  361. )
  362. {
  363. DWORD i=0;
  364. if ( pAnsiStructure == NULL ) {
  365. return;
  366. }
  367. while (pOffsets[i] != -1) {
  368. FreeAnsiString(*(LPSTR *)(pAnsiStructure+pOffsets[i]));
  369. i++;
  370. }
  371. LocalFree( pAnsiStructure );
  372. }
  373. BOOL
  374. EnumJobsW(
  375. HANDLE hPrinter,
  376. DWORD FirstJob,
  377. DWORD NoJobs,
  378. DWORD Level,
  379. LPBYTE pJob,
  380. DWORD cbBuf,
  381. LPDWORD pcbNeeded,
  382. LPDWORD pcReturned
  383. )
  384. {
  385. DWORD i, cbStruct, *pOffsets;
  386. switch (Level) {
  387. case 1:
  388. pOffsets = JobInfo1StringsA;
  389. cbStruct = sizeof(JOB_INFO_1W);
  390. break;
  391. case 2:
  392. pOffsets = JobInfo2StringsA;
  393. cbStruct = sizeof(JOB_INFO_2W);
  394. break;
  395. case 3:
  396. return EnumJobsA( hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned );
  397. default:
  398. SetLastError(ERROR_INVALID_LEVEL);
  399. return FALSE;
  400. }
  401. if (EnumJobsA(hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded,
  402. pcReturned)) {
  403. i=*pcReturned;
  404. while (i--) {
  405. ConvertAnsiToUnicodeStrings(pJob, pOffsets);
  406. //
  407. // Convert the devmode in place for INFO_2.
  408. //
  409. if( Level == 2 ){
  410. PJOB_INFO_2W pJobInfo2 = (PJOB_INFO_2W)pJob;
  411. if( pJobInfo2->pDevMode ){
  412. CopyUnicodeDevModeFromAnsiDevMode(
  413. (LPDEVMODEW)pJobInfo2->pDevMode,
  414. (LPDEVMODEA)pJobInfo2->pDevMode);
  415. }
  416. }
  417. pJob += cbStruct;
  418. }
  419. return TRUE;
  420. } else
  421. return FALSE;
  422. }
  423. BOOL
  424. GetPrinterW(
  425. HANDLE hPrinter,
  426. DWORD Level,
  427. LPBYTE pPrinter,
  428. DWORD cbBuf,
  429. LPDWORD pcbNeeded
  430. )
  431. {
  432. DWORD *pOffsets;
  433. switch (Level) {
  434. //case STRESSINFOLEVEL:
  435. // pOffsets = PrinterInfoStressOffsetsA;
  436. // break;
  437. case 1:
  438. pOffsets = PrinterInfo1StringsA;
  439. break;
  440. case 2:
  441. pOffsets = PrinterInfo2StringsA;
  442. break;
  443. case 3:
  444. pOffsets = PrinterInfo3StringsA;
  445. break;
  446. case 4:
  447. pOffsets = PrinterInfo4StringsA;
  448. break;
  449. case 5:
  450. pOffsets = PrinterInfo5StringsA;
  451. break;
  452. default:
  453. SetLastError(ERROR_INVALID_LEVEL);
  454. return FALSE;
  455. }
  456. if (GetPrinterA(hPrinter, Level, pPrinter, cbBuf, pcbNeeded)) {
  457. if (pPrinter) {
  458. ConvertAnsiToUnicodeStrings(pPrinter, pOffsets);
  459. if ((Level == 2) && pPrinter) {
  460. PRINTER_INFO_2W *pPrinterInfo2 = (PRINTER_INFO_2W *)pPrinter;
  461. if (pPrinterInfo2->pDevMode)
  462. CopyUnicodeDevModeFromAnsiDevMode(
  463. (LPDEVMODEW)pPrinterInfo2->pDevMode,
  464. (LPDEVMODEA)pPrinterInfo2->pDevMode);
  465. }
  466. }
  467. return TRUE;
  468. }
  469. return FALSE;
  470. }
  471. BOOL
  472. SetPrinterW(
  473. HANDLE hPrinter,
  474. DWORD Level,
  475. LPBYTE pPrinter,
  476. DWORD Command
  477. )
  478. {
  479. LPBYTE pAnsiStructure; /* Ansi version of input data */
  480. DWORD cbStruct; /* Size of the output structure */
  481. DWORD *pOffsets; /* -1 terminated list of addresses */
  482. DWORD ReturnValue=FALSE;
  483. switch (Level) {
  484. case 0:
  485. //
  486. // This could be 2 cases. STRESSINFOLEVEL, or the real 0 level.
  487. // If Command is 0 then it is STRESSINFOLEVEL, else real 0 level
  488. //
  489. /*
  490. if ( !Command ) {
  491. pOffsets = PrinterInfoStressStringsA;
  492. cbStruct = sizeof( PRINTER_INFO_STRESSA );
  493. }
  494. */
  495. break;
  496. case 1:
  497. pOffsets = PrinterInfo1StringsA;
  498. cbStruct = sizeof( PRINTER_INFO_1W );
  499. break;
  500. case 2:
  501. pOffsets = PrinterInfo2StringsA;
  502. cbStruct = sizeof( PRINTER_INFO_2W );
  503. break;
  504. case 3:
  505. pOffsets = PrinterInfo3StringsA;
  506. cbStruct = sizeof( PRINTER_INFO_3);
  507. break;
  508. case 4:
  509. pOffsets = PrinterInfo4StringsA;
  510. cbStruct = sizeof( PRINTER_INFO_4W );
  511. break;
  512. case 5:
  513. pOffsets = PrinterInfo5StringsA;
  514. cbStruct = sizeof( PRINTER_INFO_5W );
  515. break;
  516. case 6:
  517. break;
  518. default:
  519. SetLastError( ERROR_INVALID_LEVEL );
  520. return FALSE;
  521. }
  522. //
  523. // The structure needs to have its CONTENTS converted from
  524. // ANSI to Unicode. The above switch() statement filled in
  525. // the two important pieces of information needed to accomplish
  526. // this goal. First is the size of the structure, second is
  527. // a list of the offset within the structure to UNICODE
  528. // string pointers. The AllocateUnicodeStructure() call will
  529. // allocate a wide version of the structure, copy its contents
  530. // and convert the strings to Unicode as it goes. That leaves
  531. // us to deal with any other pieces needing conversion.
  532. //
  533. //
  534. // If Level == 0 and Command != 0 then pPrintert is a DWORD
  535. //
  536. if ( Level == 6 || (!Level && Command) ) {
  537. if ( Level == 6 || Command == PRINTER_CONTROL_SET_STATUS )
  538. pAnsiStructure = pPrinter;
  539. else
  540. pAnsiStructure = NULL;
  541. } else {
  542. pAnsiStructure = AllocateAnsiStructure(pPrinter, cbStruct, pOffsets);
  543. if (pPrinter && !pAnsiStructure)
  544. return FALSE;
  545. }
  546. #define pPrinterInfo2A ((LPPRINTER_INFO_2A)pAnsiStructure)
  547. #define pPrinterInfo2W ((LPPRINTER_INFO_2W)pPrinter)
  548. // The Level 2 structure has a DEVMODE struct in it: convert now
  549. if ( Level == 2 &&
  550. pAnsiStructure &&
  551. pPrinterInfo2W->pDevMode ) {
  552. if( bValidDevModeW( pPrinterInfo2W->pDevMode )){
  553. pPrinterInfo2A->pDevMode = AllocateAnsiDevMode(
  554. pPrinterInfo2W->pDevMode );
  555. if( !pPrinterInfo2A->pDevMode) {
  556. FreeAnsiStructure(pAnsiStructure, pOffsets);
  557. return FALSE;
  558. }
  559. }
  560. }
  561. ReturnValue = SetPrinterA( hPrinter, Level, pAnsiStructure, Command );
  562. // Free the DEVMODE we allocated (if we did!), then the
  563. // the Unicode structure and its contents.
  564. if (Level == 2 &&
  565. pAnsiStructure &&
  566. pPrinterInfo2A->pDevMode ) {
  567. LocalFree( pPrinterInfo2A->pDevMode );
  568. }
  569. //
  570. // STRESS_INFO and Levels 1-5
  571. //
  572. if ( Level != 6 && (Level || !Command) )
  573. FreeAnsiStructure( pAnsiStructure, pOffsets );
  574. #undef pPrinterInfo2A
  575. #undef pPrinterInfo2W
  576. return ReturnValue;
  577. }
  578. BOOL
  579. SetJobW(
  580. HANDLE hPrinter,
  581. DWORD JobId,
  582. DWORD Level,
  583. LPBYTE pJob,
  584. DWORD Command
  585. )
  586. {
  587. BOOL ReturnValue=FALSE;
  588. LPBYTE pAnsiStructure=NULL;
  589. LPDEVMODEA pDevModeA = NULL;
  590. DWORD cbStruct;
  591. DWORD *pOffsets;
  592. switch (Level) {
  593. case 0:
  594. break;
  595. case 1:
  596. pOffsets = JobInfo1StringsA;
  597. cbStruct = sizeof(JOB_INFO_1W);
  598. break;
  599. case 2:
  600. pOffsets = JobInfo2StringsA;
  601. cbStruct = sizeof(JOB_INFO_2W);
  602. break;
  603. case 3:
  604. return SetJobA( hPrinter, JobId, Level, pJob, Command );
  605. default:
  606. SetLastError(ERROR_INVALID_LEVEL);
  607. return FALSE;
  608. }
  609. if (Level) {
  610. pAnsiStructure = AllocateAnsiStructure(pJob, cbStruct, pOffsets);
  611. if (pJob && !pAnsiStructure)
  612. return FALSE;
  613. }
  614. if ( Level == 2 && pAnsiStructure && pJob ) {
  615. if( bValidDevModeW( ((LPJOB_INFO_2W)pJob)->pDevMode )){
  616. pDevModeA = AllocateAnsiDevMode(((LPJOB_INFO_2W)pJob)->pDevMode);
  617. if( !pDevModeA ){
  618. ReturnValue = FALSE;
  619. goto Cleanup;
  620. }
  621. ((LPJOB_INFO_2A) pAnsiStructure)->pDevMode = pDevModeA;
  622. }
  623. }
  624. ReturnValue = SetJobA(hPrinter, JobId, Level, pAnsiStructure, Command);
  625. if ( pDevModeA ) {
  626. LocalFree(pDevModeA);
  627. }
  628. Cleanup:
  629. FreeAnsiStructure(pAnsiStructure, pOffsets);
  630. return ReturnValue;
  631. }
  632. BOOL
  633. GetJobW(
  634. HANDLE hPrinter,
  635. DWORD JobId,
  636. DWORD Level,
  637. LPBYTE pJob,
  638. DWORD cbBuf,
  639. LPDWORD pcbNeeded
  640. )
  641. {
  642. DWORD *pOffsets;
  643. LPBYTE pJobA = NULL;
  644. DWORD cbNeededA = 0;
  645. DWORD cbBufA = 0;
  646. DWORD dwJobStructSizeW = 0;
  647. DWORD dwJobStructSizeA = 0;
  648. BOOL fRetval;
  649. switch (Level) {
  650. case 1:
  651. pOffsets = JobInfo1StringsA;
  652. dwJobStructSizeW = sizeof(JOB_INFO_1W);
  653. dwJobStructSizeA = sizeof(JOB_INFO_1A);
  654. break;
  655. case 2:
  656. pOffsets = JobInfo2StringsA;
  657. dwJobStructSizeW = sizeof(JOB_INFO_2W);
  658. dwJobStructSizeA = sizeof(JOB_INFO_2A);
  659. break;
  660. case 3:
  661. return GetJobA( hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded );
  662. default:
  663. SetLastError(ERROR_INVALID_LEVEL);
  664. return FALSE;
  665. }
  666. //
  667. // GetJobA is broken. THis is a workaround here which will work
  668. // sometimes. The AV problem however goes away.
  669. //
  670. // Ramv bug fix: The user has passed in a certain amount of
  671. // unicode memory. This has to be appropriately translated into
  672. // equivalent ANSI memory.
  673. //
  674. //
  675. // The translation is to take the entire blob of memory and
  676. // subtract sizeof(JOB_INFO_2W) and then divide the remaining memory
  677. // into 2.
  678. //
  679. // we also have to contend with GetJobA's erroneous return values
  680. // when we pass in a buffer of sixe 0, it gives back wrong results
  681. //
  682. //
  683. //
  684. cbBufA = cbBuf > dwJobStructSizeW ?
  685. (cbBuf-dwJobStructSizeW)/sizeof(WCHAR) + dwJobStructSizeA : 64;
  686. pJobA = (LPBYTE)AllocADsMem( cbBufA);
  687. if (!pJobA){
  688. goto error;
  689. }
  690. fRetval = GetJobA (hPrinter, JobId, Level, pJobA, cbBufA, &cbNeededA);
  691. if ( fRetval) {
  692. //
  693. // RamV bug fix.
  694. // The size that we get back is actually the size of
  695. // the ANSI array needed. We need our array to be larger for
  696. // unicode by an amount = (total lengths of all strings +1)
  697. // times the sizeof(WCHAR)
  698. //
  699. //
  700. // Looks like we have sufficient memory here for our operations
  701. // we need to copy the memory blob from Ansi to Unicode
  702. //
  703. //
  704. // Thanks to win95 returning erroneous values, we are forced
  705. // to fail this call even though it succeeded and send back
  706. // the cbNeededA value converted into the Unicode value
  707. //
  708. if (cbBuf == 0){
  709. *pcbNeeded = 2*cbNeededA; // just being conservative here by
  710. // allocating a little more space than needed
  711. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  712. goto error;
  713. }
  714. if (!ConvertAnsiToUnicodeBuf(
  715. pJobA,
  716. pJob,
  717. dwJobStructSizeA,
  718. dwJobStructSizeW,
  719. pOffsets)){
  720. goto error;
  721. }
  722. //
  723. // Convert the devmode in place for INFO_2.
  724. //
  725. if( Level == 2 ){
  726. PJOB_INFO_2W pJobInfo2 = (PJOB_INFO_2W)pJob;
  727. if( pJobInfo2->pDevMode ){
  728. CopyUnicodeDevModeFromAnsiDevMode(
  729. (LPDEVMODEW)pJobInfo2->pDevMode,
  730. (LPDEVMODEA)pJobInfo2->pDevMode);
  731. }
  732. }
  733. return TRUE;
  734. } else {
  735. //
  736. // RamV bug fix.
  737. // The size that we get back is actually the size of
  738. // the ANSI array needed. We need our array to be larger for
  739. // unicode by an amount = (total lengths of all strings +1)
  740. // times the sizeof(WCHAR)
  741. //
  742. if(cbNeededA) {
  743. //
  744. // we need to translate this into unicode terms
  745. //
  746. *pcbNeeded = dwJobStructSizeW +
  747. (cbBufA + cbNeededA - dwJobStructSizeA)*sizeof(WCHAR);
  748. }
  749. return FALSE;
  750. }
  751. error:
  752. if(pJobA) {
  753. FreeADsMem(pJobA);
  754. }
  755. return FALSE;
  756. }
  757. BOOL
  758. ConvertAnsiToUnicodeBuf(
  759. LPBYTE pAnsiBlob,
  760. LPBYTE pUnicodeBlob,
  761. DWORD dwAnsiSize,
  762. DWORD dwUnicodeSize,
  763. PDWORD pOffsets
  764. )
  765. {
  766. DWORD i = 0;
  767. LPSTR pAnsi;
  768. LPBYTE pUnicode;
  769. LPBYTE pszString = pUnicodeBlob + dwUnicodeSize;
  770. LPBYTE pStringPos = NULL;
  771. memcpy(pUnicodeBlob, pAnsiBlob, dwAnsiSize);
  772. pUnicode = pszString;
  773. while (pOffsets[i] != -1) {
  774. pAnsi = *(LPSTR *)(pAnsiBlob + pOffsets[i]);
  775. if (!AnsiToUnicodeString((LPSTR)pAnsi,
  776. (LPWSTR)pUnicode,
  777. NULL_TERMINATED )){
  778. return(FALSE);
  779. }
  780. pStringPos = pUnicodeBlob +pOffsets[i];
  781. *((LPBYTE *)pStringPos) = pUnicode;
  782. pUnicode = pUnicode + (wcslen((LPWSTR)(pUnicode))+1)* sizeof(WCHAR);
  783. i++;
  784. }
  785. return(TRUE);
  786. }
  787. BOOL
  788. OpenPrinterW(
  789. LPWSTR pPrinterName,
  790. LPHANDLE phPrinter,
  791. LPPRINTER_DEFAULTSW pDefault
  792. )
  793. {
  794. BOOL ReturnValue = FALSE;
  795. LPSTR pAnsiPrinterName = NULL;
  796. PRINTER_DEFAULTSA AnsiDefaults={NULL, NULL, 0};
  797. pAnsiPrinterName = AllocateAnsiString(pPrinterName);
  798. if (pPrinterName && !pAnsiPrinterName)
  799. goto Cleanup;
  800. if (pDefault) {
  801. AnsiDefaults.pDatatype = AllocateAnsiString(pDefault->pDatatype);
  802. if (pDefault->pDatatype && !AnsiDefaults.pDatatype)
  803. goto Cleanup;
  804. //
  805. // Milestones etc. 4.5 passes in a bogus devmode in pDefaults.
  806. // Be sure to validate here.
  807. //
  808. if( bValidDevModeW( pDefault->pDevMode )){
  809. AnsiDefaults.pDevMode = AllocateAnsiDevMode(
  810. pDefault->pDevMode );
  811. if( !AnsiDefaults.pDevMode ){
  812. goto Cleanup;
  813. }
  814. }
  815. AnsiDefaults.DesiredAccess = pDefault->DesiredAccess;
  816. }
  817. ReturnValue = OpenPrinterA(pAnsiPrinterName, phPrinter, &AnsiDefaults);
  818. /* Ramv This code below causes AV. I have disabled it
  819. MattRim 1-10-00: Leaving this disabled. phPrinter is an opaque handle
  820. to an undocumented structure. Trying to manipulate it is a surefire way
  821. to cause AVs if a service pack/O.S. upgrade ever changes the implementation
  822. of this Win9x-internal structure.
  823. if (ReturnValue) {
  824. ((PSPOOL)*phPrinter)->Status |= SPOOL_STATUS_ANSI;
  825. }
  826. */
  827. Cleanup:
  828. if (AnsiDefaults.pDevMode)
  829. LocalFree(AnsiDefaults.pDevMode);
  830. FreeAnsiString(AnsiDefaults.pDatatype);
  831. FreeAnsiString(pAnsiPrinterName);
  832. return ReturnValue;
  833. }