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.

631 lines
16 KiB

  1. /*++
  2. *
  3. * WOW v1.0
  4. *
  5. * Copyright (c) 1991, Microsoft Corporation
  6. *
  7. * WSPOOL.C
  8. * WOW32 printer spooler support routines
  9. *
  10. * These routines help a Win 3.0 task to use the print spooler apis. These
  11. * apis were exposed by DDK in Win 3.1.
  12. *
  13. * History:
  14. * Created 1-July-1993 by Chandan Chauhan (ChandanC)
  15. *
  16. --*/
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. #include <winspool.h>
  20. extern WORD gUser16hInstance;
  21. VOID WOWSpoolerThread(WOWSPOOL *lpwowSpool);
  22. WORD gprn16 = 0x100; // Global spooler job # (can be anything > 0)
  23. MODNAME(wspool.c);
  24. LPDEVMODE GetDefaultDevMode32(LPSTR szDriver)
  25. {
  26. LONG cbDevMode;
  27. LPDEVMODE lpDevMode = NULL;
  28. if (szDriver != NULL) {
  29. if (!(spoolerapis[WOW_EXTDEVICEMODE].lpfn)) {
  30. if (!LoadLibraryAndGetProcAddresses("WINSPOOL.DRV", spoolerapis, WOW_SPOOLERAPI_COUNT)) {
  31. goto LeaveGetDefaultDevMode32;
  32. }
  33. }
  34. if ((cbDevMode = (*spoolerapis[WOW_EXTDEVICEMODE].lpfn)(NULL, NULL, NULL, szDriver, NULL, NULL, NULL, 0)) > 0) {
  35. if ((lpDevMode = (LPDEVMODE) malloc_w(cbDevMode)) != NULL) {
  36. if ((*spoolerapis[WOW_EXTDEVICEMODE].lpfn)(NULL, NULL, lpDevMode, szDriver, NULL, NULL, NULL, DM_COPY) != IDOK) {
  37. free_w(lpDevMode);
  38. lpDevMode = NULL;
  39. }
  40. }
  41. }
  42. LeaveGetDefaultDevMode32:
  43. if (!lpDevMode) {
  44. LOGDEBUG(0,("WOW::GetDefaultDevMode32: Unable to get default DevMode\n"));
  45. }
  46. }
  47. return(lpDevMode);
  48. }
  49. ULONG FASTCALL WG32OpenJob (PVDMFRAME pFrame)
  50. {
  51. INT len;
  52. PSZ psz1 = NULL;
  53. PSZ psz2 = NULL;
  54. PSZ pszDriver = NULL;
  55. ULONG ul=0;
  56. DOC_INFO_1 DocInfo1;
  57. HANDLE hnd;
  58. register POPENJOB16 parg16;
  59. PRINTER_DEFAULTS PrinterDefault;
  60. PPRINTER_DEFAULTS pPrinterDefault = NULL;
  61. GETARGPTR(pFrame, sizeof(OPENJOB16), parg16);
  62. // save off the 16-bit params now since this could callback into a 16-bit
  63. // fax driver & cause 16-bit memory to move.
  64. if(parg16->f1) {
  65. if(psz1 = malloc_w_strcpy_vp16to32(parg16->f1, FALSE, 0)) {
  66. len = strlen(psz1);
  67. pszDriver = malloc_w(max(len, 40));
  68. }
  69. }
  70. if(parg16->f2) {
  71. psz2 = malloc_w_strcpy_vp16to32(parg16->f2, FALSE, 0);
  72. }
  73. FREEARGPTR(parg16);
  74. // all 16-bit pointers are now invalid!!
  75. // this implies that psz1 may also be bad
  76. if(!pszDriver) {
  77. goto exitpath;
  78. }
  79. if (!(spoolerapis[WOW_OpenPrinterA].lpfn)) {
  80. if (!LoadLibraryAndGetProcAddresses("WINSPOOL.DRV", spoolerapis, WOW_SPOOLERAPI_COUNT)) {
  81. goto exitpath;
  82. }
  83. }
  84. if (GetDriverName(psz1, pszDriver)) {
  85. if((PrinterDefault.pDevMode = GetDefaultDevMode32(pszDriver)) != NULL) {
  86. PrinterDefault.pDatatype = NULL;
  87. PrinterDefault.DesiredAccess = 0;
  88. pPrinterDefault = &PrinterDefault;
  89. if ((*spoolerapis[WOW_OpenPrinterA].lpfn) (pszDriver,
  90. &hnd,
  91. pPrinterDefault)) {
  92. DocInfo1.pDocName = psz2;
  93. DocInfo1.pOutputFile = psz1;
  94. DocInfo1.pDatatype = NULL;
  95. if (ul = (*spoolerapis[WOW_StartDocPrinterA].lpfn) (hnd, 1, (LPBYTE)&DocInfo1)) {
  96. ul = GetPrn16(hnd);
  97. }
  98. else {
  99. ul = GetLastError();
  100. }
  101. }
  102. else {
  103. ul = GetLastError();
  104. }
  105. }
  106. }
  107. LOGDEBUG(0,("WOW::WG32OpenJob: ul = %x\n", ul));
  108. if (pPrinterDefault) {
  109. free_w(PrinterDefault.pDevMode);
  110. }
  111. exitpath:
  112. if(psz1) {
  113. free_w(psz1);
  114. }
  115. if(psz2) {
  116. free_w(psz2);
  117. }
  118. if(pszDriver) {
  119. free_w(pszDriver);
  120. }
  121. RETURN(ul);
  122. }
  123. ULONG FASTCALL WG32StartSpoolPage (PVDMFRAME pFrame)
  124. {
  125. ULONG ul=0;
  126. register PSTARTSPOOLPAGE16 parg16;
  127. GETARGPTR(pFrame, sizeof(STARTSPOOLPAGE16), parg16);
  128. if (!(ul = (*spoolerapis[WOW_StartPagePrinter].lpfn) (Prn32(parg16->f1)))) {
  129. ul = GetLastError();
  130. }
  131. LOGDEBUG(0,("WOW::WG32StartSpoolPage: ul = %x\n", ul));
  132. FREEARGPTR(parg16);
  133. RETURN(ul);
  134. }
  135. ULONG FASTCALL WG32EndSpoolPage (PVDMFRAME pFrame)
  136. {
  137. ULONG ul=0;
  138. register PENDSPOOLPAGE16 parg16;
  139. GETARGPTR(pFrame, sizeof(ENDSPOOLPAGE16), parg16);
  140. if (!(ul = (*spoolerapis[WOW_EndPagePrinter].lpfn) (Prn32(parg16->f1)))) {
  141. ul = GetLastError();
  142. }
  143. LOGDEBUG(0,("WOW::WG32EndSpoolPage: ul = %x\n", ul));
  144. FREEARGPTR(parg16);
  145. RETURN(ul);
  146. }
  147. ULONG FASTCALL WG32CloseJob (PVDMFRAME pFrame)
  148. {
  149. ULONG ul=0;
  150. register PCLOSEJOB16 parg16;
  151. GETARGPTR(pFrame, sizeof(CLOSEJOB16), parg16);
  152. if (!(ul = (*spoolerapis[WOW_EndDocPrinter].lpfn) (Prn32(parg16->f1)))) {
  153. ul = GetLastError();
  154. }
  155. if (!(ul = (*spoolerapis[WOW_ClosePrinter].lpfn) (Prn32(parg16->f1)))) {
  156. ul = GetLastError();
  157. }
  158. if (ul) {
  159. FreePrn(parg16->f1);
  160. }
  161. LOGDEBUG(0,("WOW::WG32CloseJob: ul = %x\n", ul));
  162. FREEARGPTR(parg16);
  163. RETURN(ul);
  164. }
  165. ULONG FASTCALL WG32WriteSpool (PVDMFRAME pFrame)
  166. {
  167. DWORD dwWritten;
  168. ULONG ul=0;
  169. register PWRITESPOOL16 parg16;
  170. LPVOID pBuf;
  171. GETARGPTR(pFrame, sizeof(WRITESPOOL16), parg16);
  172. GETMISCPTR (parg16->f2, pBuf);
  173. if (ul = (*spoolerapis[WOW_WritePrinter].lpfn) (Prn32(parg16->f1), pBuf,
  174. FETCHWORD(parg16->f3), &dwWritten)) {
  175. ul = FETCHWORD(parg16->f3);
  176. }
  177. else {
  178. ul = GetLastError();
  179. }
  180. LOGDEBUG(0,("WOW::WG32WriteSpool: ul = %x\n", ul));
  181. FREEMISCPTR(pBuf);
  182. FREEARGPTR(parg16);
  183. RETURN(ul);
  184. }
  185. ULONG FASTCALL WG32DeleteJob (PVDMFRAME pFrame)
  186. {
  187. ULONG ul = 0;
  188. register PDELETEJOB16 parg16;
  189. GETARGPTR(pFrame, sizeof(DELETEJOB16), parg16);
  190. if (!(ul = (*spoolerapis[WOW_DeletePrinter].lpfn) (Prn32(parg16->f1)))) {
  191. ul = GetLastError();
  192. }
  193. LOGDEBUG(0,("WOW::WG32DeleteJob: ul = %x\n", ul));
  194. FREEARGPTR(parg16);
  195. RETURN(ul);
  196. }
  197. ULONG FASTCALL WG32SpoolFile (PVDMFRAME pFrame)
  198. {
  199. INT len;
  200. PSZ psz2 = NULL;
  201. PSZ psz3 = NULL;
  202. PSZ psz4 = NULL;
  203. PSZ pszDriver = NULL;
  204. LONG ul = -1; // SP_ERROR
  205. HANDLE hFile = NULL;
  206. HANDLE hPrinter = NULL;
  207. HANDLE hThread = NULL;
  208. WOWSPOOL *lpwowSpool = NULL;
  209. DOC_INFO_1 DocInfo1;
  210. DWORD dwUnused;
  211. register PSPOOLFILE16 parg16;
  212. GETARGPTR(pFrame, sizeof(SPOOLFILE16), parg16);
  213. // save off the 16-bit params now since this could callback into a 16-bit
  214. // fax driver & cause 16-bit memory to move.
  215. // ignore psz1 (printer name)
  216. // get the port name and the associated driver name
  217. if(parg16->f2) {
  218. if(!(psz2 = malloc_w_strcpy_vp16to32(parg16->f2, FALSE, 0))) {
  219. goto exitpath;
  220. }
  221. len = strlen(psz2);
  222. if(!(pszDriver = malloc_w(max(len, 40)))) {
  223. goto exitpath;
  224. }
  225. if(!GetDriverName(psz2, pszDriver)) {
  226. goto exitpath;
  227. }
  228. }
  229. // get the Job Title
  230. if(parg16->f3) {
  231. if(!(psz3 = malloc_w_strcpy_vp16to32(parg16->f3, FALSE, 0))) {
  232. goto exitpath;
  233. }
  234. }
  235. // get the file name
  236. if(parg16->f4) {
  237. if(!(psz4 = malloc_w_strcpy_vp16to32(parg16->f4, FALSE, 0))) {
  238. goto exitpath;
  239. }
  240. }
  241. FREEARGPTR(parg16);
  242. // all 16-bit pointers are now invalid!!
  243. // all fields of this struct are initially zero
  244. if(!(lpwowSpool = (WOWSPOOL *)malloc_w_zero(sizeof(WOWSPOOL)))) {
  245. goto exitpath;
  246. }
  247. if(!(spoolerapis[WOW_OpenPrinterA].lpfn)) {
  248. if(!LoadLibraryAndGetProcAddresses("WINSPOOL.DRV", spoolerapis, WOW_SPOOLERAPI_COUNT)) {
  249. goto exitpath;
  250. }
  251. }
  252. // open the specified file
  253. if((hFile = CreateFile(psz4,
  254. GENERIC_READ,
  255. 0,
  256. NULL,
  257. OPEN_EXISTING,
  258. FILE_FLAG_SEQUENTIAL_SCAN,
  259. NULL)) == INVALID_HANDLE_VALUE) {
  260. goto exitpath;
  261. }
  262. // create the WOWSpoolerThread to handle the "spooling"
  263. if(!(hThread = CreateThread(NULL,
  264. 16384,
  265. (LPTHREAD_START_ROUTINE)WOWSpoolerThread,
  266. lpwowSpool,
  267. CREATE_SUSPENDED,
  268. (LPDWORD)&dwUnused))) {
  269. goto exitpath;
  270. }
  271. // open the printer
  272. if((*spoolerapis[WOW_OpenPrinterA].lpfn)(pszDriver, &hPrinter, NULL)) {
  273. DocInfo1.pDocName = psz3;
  274. DocInfo1.pOutputFile = NULL;
  275. DocInfo1.pDatatype = "RAW";
  276. // start a doc
  277. if(!(*spoolerapis[WOW_StartDocPrinterA].lpfn)(hPrinter,
  278. 1,
  279. (LPBYTE)&DocInfo1)) {
  280. goto ClosePrinter;
  281. }
  282. // start a page
  283. if((*spoolerapis[WOW_StartPagePrinter].lpfn)(hPrinter)) {
  284. // tell the WOWSpoolerThread that it's OK to do its thing
  285. lpwowSpool->fOK = TRUE;
  286. lpwowSpool->hFile = hFile;
  287. lpwowSpool->hPrinter = hPrinter;
  288. lpwowSpool->prn16 = gprn16;
  289. // tell the app that everything is hunky dory
  290. ul = (LONG)gprn16++;
  291. // make sure this doesn't go negative (-> an error ret to the app)
  292. if(gprn16 & 0x8000) {
  293. gprn16 = 0x100;
  294. }
  295. }
  296. // error path
  297. else {
  298. (*spoolerapis[WOW_EndDocPrinter].lpfn) (hPrinter);
  299. ClosePrinter:
  300. // note: hPrinter is freed by WOW_ClosePrinter
  301. (*spoolerapis[WOW_ClosePrinter].lpfn) (hPrinter);
  302. }
  303. }
  304. exitpath:
  305. LOGDEBUG(2,("WOW::WG32SpoolFile: ul = %x\n", ul));
  306. if(psz2) {
  307. free_w(psz2);
  308. }
  309. if(psz3) {
  310. free_w(psz3);
  311. }
  312. if(psz4) {
  313. free_w(psz4);
  314. }
  315. if(pszDriver) {
  316. free_w(pszDriver);
  317. }
  318. // give the spooler thread a kick start then close the thread handle
  319. // (note: the thread will still be active)
  320. if(hThread) {
  321. ResumeThread(hThread);
  322. CloseHandle(hThread);
  323. }
  324. // clean up if there was an error -- otherwise the thread will clean up
  325. if(ul == -1) {
  326. if(hFile) {
  327. CloseHandle(hFile);
  328. }
  329. if(lpwowSpool) {
  330. free_w(lpwowSpool);
  331. }
  332. // note: hPrinter is freed by WOW_ClosePrinter
  333. }
  334. return((ULONG)ul);
  335. }
  336. #define SPOOL_BUFF_SIZE 4096
  337. VOID WOWSpoolerThread(WOWSPOOL *lpwowSpool)
  338. {
  339. DWORD dwBytes;
  340. DWORD dwWritten;
  341. LPBYTE buf[SPOOL_BUFF_SIZE];
  342. // this thread will only do something if fOK is TRUE
  343. if(lpwowSpool->fOK) {
  344. do {
  345. // this is a sequential read
  346. if(ReadFile(lpwowSpool->hFile, buf, SPOOL_BUFF_SIZE, &dwBytes, NULL)) {
  347. // if dwBytes==0 --> EOF
  348. if(dwBytes) {
  349. //
  350. if(!(*spoolerapis[WOW_WritePrinter].lpfn)(lpwowSpool->hPrinter,
  351. buf,
  352. dwBytes,
  353. &dwWritten)) {
  354. LOGDEBUG(0,("WOW::WOWSpoolerThread:WritePrinter ERROR!\n"));
  355. break;
  356. }
  357. else if(dwBytes != dwWritten) {
  358. LOGDEBUG(0,("WOW::WOWSpoolerThread:WritePrinter error!\n"));
  359. break;
  360. }
  361. }
  362. }
  363. } while (dwBytes == SPOOL_BUFF_SIZE);
  364. // shut down the print job
  365. (*spoolerapis[WOW_EndPagePrinter].lpfn) (lpwowSpool->hPrinter);
  366. (*spoolerapis[WOW_EndDocPrinter].lpfn) (lpwowSpool->hPrinter);
  367. // note: hPrinter is freed by WOW_ClosePrinter
  368. (*spoolerapis[WOW_ClosePrinter].lpfn) (lpwowSpool->hPrinter);
  369. // clean up
  370. if(lpwowSpool->hFile) {
  371. CloseHandle(lpwowSpool->hFile);
  372. }
  373. if(lpwowSpool) {
  374. free_w(lpwowSpool);
  375. }
  376. } // end if
  377. ExitThread(0);
  378. }
  379. WORD GetPrn16(HANDLE h32)
  380. {
  381. HANDLE hnd;
  382. VPVOID vp;
  383. LPBYTE lpMem16;
  384. hnd = LocalAlloc16(LMEM_MOVEABLE, sizeof(HANDLE), (HANDLE) gUser16hInstance);
  385. vp = LocalLock16(hnd);
  386. if (vp) {
  387. GETMISCPTR (vp, lpMem16);
  388. if (lpMem16) {
  389. *((PDWORD16)lpMem16) = (DWORD) h32;
  390. FREEMISCPTR(lpMem16);
  391. LocalUnlock16(hnd);
  392. }
  393. }
  394. else {
  395. LOGDEBUG (0, ("WOW::GETPRN16: Can't allocate a 16 bit handle\n"));
  396. }
  397. return (LOWORD(hnd));
  398. }
  399. HANDLE Prn32(WORD h16)
  400. {
  401. VPVOID vp;
  402. HANDLE h32 = NULL;
  403. LPBYTE lpMem16;
  404. vp = LocalLock16 ((HANDLE) MAKELONG(h16, gUser16hInstance));
  405. if (vp) {
  406. GETMISCPTR (vp, lpMem16);
  407. if (lpMem16) {
  408. h32 = (HANDLE) *((PDWORD16)lpMem16);
  409. FREEMISCPTR(lpMem16);
  410. }
  411. LocalUnlock16 ((HANDLE) MAKELONG(h16, gUser16hInstance));
  412. }
  413. return (h32);
  414. }
  415. VOID FreePrn (WORD h16)
  416. {
  417. LocalFree16 ((HANDLE) MAKELONG(h16, gUser16hInstance));
  418. }
  419. BOOL GetDriverName (char *psz, char *pszDriver)
  420. {
  421. CHAR szAllDevices[1024];
  422. CHAR *szNextDevice;
  423. CHAR szPrinter[64];
  424. CHAR *szOutput;
  425. UINT len;
  426. if(!psz || (*psz == '\0')) {
  427. return FALSE;
  428. }
  429. len = strlen(psz);
  430. szAllDevices[0]='\0';
  431. GetProfileString ("devices", NULL, "", szAllDevices, sizeof(szAllDevices));
  432. szNextDevice = szAllDevices;
  433. LOGDEBUG(6,("WOW::GetDriverName: szAllDevices = %s\n", szAllDevices));
  434. // strings from win.ini will be of the form "PS Printer=PSCRIPT,LPT1:"
  435. while (*szNextDevice) {
  436. szPrinter[0]='\0';
  437. GetProfileString ("devices", szNextDevice, "", szPrinter, sizeof(szPrinter));
  438. if (*szPrinter) {
  439. if (szOutput = WOW32_strchr (szPrinter, ',')) {
  440. szOutput++;
  441. while (*szOutput == ' ') {
  442. szOutput++;
  443. }
  444. if (!WOW32_stricmp(psz, szOutput)) {
  445. break; // found it!
  446. }
  447. // some apps pass "LPT1" without the ':' -- account for that
  448. // if the app passed "LPT1" and ...
  449. if (psz[len-1] != ':') {
  450. // ...strlen(szOutput) == 5 && szOutput[4] == ':' ...
  451. if((strlen(szOutput) == len+1) && (szOutput[len] == ':')) {
  452. // ...clobber the ':' char ...
  453. szOutput[len] = '\0';
  454. // ...and see if the strings match now
  455. if (!WOW32_stricmp(psz, szOutput)) {
  456. break; // found it!
  457. }
  458. }
  459. }
  460. }
  461. }
  462. if (szNextDevice = WOW32_strchr (szNextDevice, '\0')) {
  463. szNextDevice++;
  464. }
  465. else {
  466. szNextDevice = "";
  467. break;
  468. }
  469. }
  470. if (*szNextDevice) {
  471. LOGDEBUG(0,("WOW::GetDriverName: szNextDevice = %s\n", szNextDevice));
  472. if (lstrcpy (pszDriver, szNextDevice)) {
  473. return TRUE;
  474. }
  475. }
  476. // else they may have specified a network printer eg. "\\msprint44\corpk"
  477. // in which case we'll assume it's all right (since it will fail once the
  478. // WOW functions that call into this will fail when they call into the
  479. // driver with a bogus driver name)
  480. if(psz[0] == '\\' && psz[1] == '\\') {
  481. strcpy(pszDriver, psz);
  482. return TRUE;
  483. }
  484. return FALSE;
  485. }