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.
635 lines
16 KiB
635 lines
16 KiB
/*++
|
|
*
|
|
* WOW v1.0
|
|
*
|
|
* Copyright (c) 1991, Microsoft Corporation
|
|
*
|
|
* WSPOOL.C
|
|
* WOW32 printer spooler support routines
|
|
*
|
|
* These routines help a Win 3.0 task to use the print spooler apis. These
|
|
* apis were exposed by DDK in Win 3.1.
|
|
*
|
|
* History:
|
|
* Created 1-July-1993 by Chandan Chauhan (ChandanC)
|
|
*
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include <winspool.h>
|
|
|
|
extern WORD gUser16hInstance;
|
|
|
|
VOID WOWSpoolerThread(WOWSPOOL *lpwowSpool);
|
|
|
|
WORD gprn16 = 0x100; // Global spooler job # (can be anything > 0)
|
|
|
|
MODNAME(wspool.c);
|
|
|
|
LPDEVMODE GetDefaultDevMode32(LPSTR szDriver)
|
|
{
|
|
LONG cbDevMode;
|
|
LPDEVMODE lpDevMode = NULL;
|
|
|
|
if (szDriver != NULL) {
|
|
|
|
if (!(spoolerapis[WOW_EXTDEVICEMODE].lpfn)) {
|
|
if (!LoadLibraryAndGetProcAddresses(L"WINSPOOL.DRV", spoolerapis, WOW_SPOOLERAPI_COUNT)) {
|
|
goto LeaveGetDefaultDevMode32;
|
|
}
|
|
}
|
|
|
|
if ((cbDevMode = (*spoolerapis[WOW_EXTDEVICEMODE].lpfn)(NULL, NULL, NULL, szDriver, NULL, NULL, NULL, 0)) > 0) {
|
|
if ((lpDevMode = (LPDEVMODE) malloc_w(cbDevMode)) != NULL) {
|
|
if ((*spoolerapis[WOW_EXTDEVICEMODE].lpfn)(NULL, NULL, lpDevMode, szDriver, NULL, NULL, NULL, DM_COPY) != IDOK) {
|
|
free_w(lpDevMode);
|
|
lpDevMode = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
LeaveGetDefaultDevMode32:
|
|
|
|
if (!lpDevMode) {
|
|
LOGDEBUG(0,("WOW::GetDefaultDevMode32: Unable to get default DevMode\n"));
|
|
}
|
|
}
|
|
|
|
return(lpDevMode);
|
|
}
|
|
|
|
ULONG FASTCALL WG32OpenJob (PVDMFRAME pFrame)
|
|
{
|
|
INT len;
|
|
PSZ psz1 = NULL;
|
|
PSZ psz2 = NULL;
|
|
PSZ pszDriver = NULL;
|
|
ULONG ul=0;
|
|
DOC_INFO_1 DocInfo1;
|
|
HANDLE hnd;
|
|
register POPENJOB16 parg16;
|
|
PRINTER_DEFAULTS PrinterDefault;
|
|
PPRINTER_DEFAULTS pPrinterDefault = NULL;
|
|
|
|
GETARGPTR(pFrame, sizeof(OPENJOB16), parg16);
|
|
|
|
// save off the 16-bit params now since this could callback into a 16-bit
|
|
// fax driver & cause 16-bit memory to move.
|
|
if(parg16->f1) {
|
|
if(psz1 = malloc_w_strcpy_vp16to32(parg16->f1, FALSE, 0)) {
|
|
len = strlen(psz1)+1;
|
|
len = max(len, 40);
|
|
pszDriver = malloc_w(len);
|
|
}
|
|
}
|
|
|
|
if(parg16->f2) {
|
|
psz2 = malloc_w_strcpy_vp16to32(parg16->f2, FALSE, 0);
|
|
}
|
|
|
|
FREEARGPTR(parg16);
|
|
// all 16-bit pointers are now invalid!!
|
|
|
|
// this implies that psz1 may also be bad
|
|
if(!pszDriver) {
|
|
goto exitpath;
|
|
}
|
|
|
|
|
|
if (!(spoolerapis[WOW_OpenPrinterA].lpfn)) {
|
|
if (!LoadLibraryAndGetProcAddresses(L"WINSPOOL.DRV", spoolerapis, WOW_SPOOLERAPI_COUNT)) {
|
|
goto exitpath;
|
|
}
|
|
}
|
|
|
|
if (GetDriverName(psz1, pszDriver, len)) {
|
|
if((PrinterDefault.pDevMode = GetDefaultDevMode32(pszDriver)) != NULL) {
|
|
PrinterDefault.pDatatype = NULL;
|
|
PrinterDefault.DesiredAccess = 0;
|
|
pPrinterDefault = &PrinterDefault;
|
|
|
|
if ((*spoolerapis[WOW_OpenPrinterA].lpfn) (pszDriver,
|
|
&hnd,
|
|
pPrinterDefault)) {
|
|
|
|
DocInfo1.pDocName = psz2;
|
|
DocInfo1.pOutputFile = psz1;
|
|
DocInfo1.pDatatype = NULL;
|
|
|
|
if (ul = (*spoolerapis[WOW_StartDocPrinterA].lpfn) (hnd, 1, (LPBYTE)&DocInfo1)) {
|
|
ul = GetPrn16(hnd);
|
|
}
|
|
else {
|
|
ul = GetLastError();
|
|
}
|
|
|
|
}
|
|
else {
|
|
ul = GetLastError();
|
|
}
|
|
}
|
|
}
|
|
|
|
LOGDEBUG(0,("WOW::WG32OpenJob: ul = %x\n", ul));
|
|
|
|
if (pPrinterDefault) {
|
|
free_w(PrinterDefault.pDevMode);
|
|
}
|
|
|
|
exitpath:
|
|
|
|
if(psz1) {
|
|
free_w(psz1);
|
|
}
|
|
if(psz2) {
|
|
free_w(psz2);
|
|
}
|
|
if(pszDriver) {
|
|
free_w(pszDriver);
|
|
}
|
|
|
|
RETURN(ul);
|
|
}
|
|
|
|
|
|
ULONG FASTCALL WG32StartSpoolPage (PVDMFRAME pFrame)
|
|
{
|
|
ULONG ul=0;
|
|
register PSTARTSPOOLPAGE16 parg16;
|
|
|
|
GETARGPTR(pFrame, sizeof(STARTSPOOLPAGE16), parg16);
|
|
|
|
if (!(ul = (*spoolerapis[WOW_StartPagePrinter].lpfn) (Prn32(parg16->f1)))) {
|
|
ul = GetLastError();
|
|
}
|
|
|
|
LOGDEBUG(0,("WOW::WG32StartSpoolPage: ul = %x\n", ul));
|
|
|
|
FREEARGPTR(parg16);
|
|
RETURN(ul);
|
|
}
|
|
|
|
|
|
ULONG FASTCALL WG32EndSpoolPage (PVDMFRAME pFrame)
|
|
{
|
|
ULONG ul=0;
|
|
register PENDSPOOLPAGE16 parg16;
|
|
|
|
GETARGPTR(pFrame, sizeof(ENDSPOOLPAGE16), parg16);
|
|
|
|
if (!(ul = (*spoolerapis[WOW_EndPagePrinter].lpfn) (Prn32(parg16->f1)))) {
|
|
ul = GetLastError();
|
|
}
|
|
|
|
LOGDEBUG(0,("WOW::WG32EndSpoolPage: ul = %x\n", ul));
|
|
|
|
FREEARGPTR(parg16);
|
|
RETURN(ul);
|
|
}
|
|
|
|
|
|
ULONG FASTCALL WG32CloseJob (PVDMFRAME pFrame)
|
|
{
|
|
ULONG ul=0;
|
|
register PCLOSEJOB16 parg16;
|
|
|
|
GETARGPTR(pFrame, sizeof(CLOSEJOB16), parg16);
|
|
|
|
if (!(ul = (*spoolerapis[WOW_EndDocPrinter].lpfn) (Prn32(parg16->f1)))) {
|
|
|
|
ul = GetLastError();
|
|
}
|
|
|
|
if (!(ul = (*spoolerapis[WOW_ClosePrinter].lpfn) (Prn32(parg16->f1)))) {
|
|
ul = GetLastError();
|
|
}
|
|
|
|
if (ul) {
|
|
FreePrn(parg16->f1);
|
|
}
|
|
|
|
LOGDEBUG(0,("WOW::WG32CloseJob: ul = %x\n", ul));
|
|
|
|
FREEARGPTR(parg16);
|
|
RETURN(ul);
|
|
}
|
|
|
|
|
|
ULONG FASTCALL WG32WriteSpool (PVDMFRAME pFrame)
|
|
{
|
|
DWORD dwWritten;
|
|
ULONG ul=0;
|
|
register PWRITESPOOL16 parg16;
|
|
LPVOID pBuf;
|
|
|
|
GETARGPTR(pFrame, sizeof(WRITESPOOL16), parg16);
|
|
GETMISCPTR (parg16->f2, pBuf);
|
|
|
|
if (ul = (*spoolerapis[WOW_WritePrinter].lpfn) (Prn32(parg16->f1), pBuf,
|
|
FETCHWORD(parg16->f3), &dwWritten)) {
|
|
ul = FETCHWORD(parg16->f3);
|
|
}
|
|
else {
|
|
ul = GetLastError();
|
|
}
|
|
|
|
LOGDEBUG(0,("WOW::WG32WriteSpool: ul = %x\n", ul));
|
|
|
|
FREEMISCPTR(pBuf);
|
|
FREEARGPTR(parg16);
|
|
RETURN(ul);
|
|
}
|
|
|
|
|
|
ULONG FASTCALL WG32DeleteJob (PVDMFRAME pFrame)
|
|
{
|
|
ULONG ul = 0;
|
|
register PDELETEJOB16 parg16;
|
|
|
|
GETARGPTR(pFrame, sizeof(DELETEJOB16), parg16);
|
|
|
|
if (!(ul = (*spoolerapis[WOW_DeletePrinter].lpfn) (Prn32(parg16->f1)))) {
|
|
ul = GetLastError();
|
|
}
|
|
|
|
LOGDEBUG(0,("WOW::WG32DeleteJob: ul = %x\n", ul));
|
|
|
|
FREEARGPTR(parg16);
|
|
RETURN(ul);
|
|
}
|
|
|
|
|
|
ULONG FASTCALL WG32SpoolFile (PVDMFRAME pFrame)
|
|
{
|
|
INT len;
|
|
PSZ psz2 = NULL;
|
|
PSZ psz3 = NULL;
|
|
PSZ psz4 = NULL;
|
|
PSZ pszDriver = NULL;
|
|
LONG ul = -1; // SP_ERROR
|
|
HANDLE hFile = NULL;
|
|
HANDLE hPrinter = NULL;
|
|
HANDLE hThread = NULL;
|
|
WOWSPOOL *lpwowSpool = NULL;
|
|
DOC_INFO_1 DocInfo1;
|
|
DWORD dwUnused;
|
|
register PSPOOLFILE16 parg16;
|
|
|
|
|
|
GETARGPTR(pFrame, sizeof(SPOOLFILE16), parg16);
|
|
|
|
// save off the 16-bit params now since this could callback into a 16-bit
|
|
// fax driver & cause 16-bit memory to move.
|
|
|
|
// ignore psz1 (printer name)
|
|
|
|
// get the port name and the associated driver name
|
|
if(parg16->f2) {
|
|
if(!(psz2 = malloc_w_strcpy_vp16to32(parg16->f2, FALSE, 0))) {
|
|
goto exitpath;
|
|
}
|
|
len = strlen(psz2)+1;
|
|
len = max(len, 40);
|
|
if(!(pszDriver = malloc_w(len))) {
|
|
goto exitpath;
|
|
}
|
|
if(!GetDriverName(psz2, pszDriver, len)) {
|
|
goto exitpath;
|
|
}
|
|
}
|
|
|
|
// get the Job Title
|
|
if(parg16->f3) {
|
|
if(!(psz3 = malloc_w_strcpy_vp16to32(parg16->f3, FALSE, 0))) {
|
|
goto exitpath;
|
|
}
|
|
}
|
|
|
|
// get the file name
|
|
if(parg16->f4) {
|
|
if(!(psz4 = malloc_w_strcpy_vp16to32(parg16->f4, FALSE, 0))) {
|
|
goto exitpath;
|
|
}
|
|
}
|
|
|
|
FREEARGPTR(parg16);
|
|
// all 16-bit pointers are now invalid!!
|
|
|
|
// all fields of this struct are initially zero
|
|
if(!(lpwowSpool = (WOWSPOOL *)malloc_w_zero(sizeof(WOWSPOOL)))) {
|
|
goto exitpath;
|
|
}
|
|
|
|
if(!(spoolerapis[WOW_OpenPrinterA].lpfn)) {
|
|
if(!LoadLibraryAndGetProcAddresses(L"WINSPOOL.DRV", spoolerapis, WOW_SPOOLERAPI_COUNT)) {
|
|
goto exitpath;
|
|
}
|
|
}
|
|
|
|
// open the specified file
|
|
if((hFile = DPM_CreateFile(psz4,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL)) == INVALID_HANDLE_VALUE) {
|
|
|
|
goto exitpath;
|
|
}
|
|
|
|
// create the WOWSpoolerThread to handle the "spooling"
|
|
if(!(hThread = CreateThread(NULL,
|
|
16384,
|
|
(LPTHREAD_START_ROUTINE)WOWSpoolerThread,
|
|
lpwowSpool,
|
|
CREATE_SUSPENDED,
|
|
(LPDWORD)&dwUnused))) {
|
|
goto exitpath;
|
|
}
|
|
|
|
// open the printer
|
|
if((*spoolerapis[WOW_OpenPrinterA].lpfn)(pszDriver, &hPrinter, NULL)) {
|
|
|
|
DocInfo1.pDocName = psz3;
|
|
DocInfo1.pOutputFile = NULL;
|
|
DocInfo1.pDatatype = "RAW";
|
|
|
|
// start a doc
|
|
if(!(*spoolerapis[WOW_StartDocPrinterA].lpfn)(hPrinter,
|
|
1,
|
|
(LPBYTE)&DocInfo1)) {
|
|
goto ClosePrinter;
|
|
}
|
|
|
|
// start a page
|
|
if((*spoolerapis[WOW_StartPagePrinter].lpfn)(hPrinter)) {
|
|
|
|
// tell the WOWSpoolerThread that it's OK to do its thing
|
|
lpwowSpool->fOK = TRUE;
|
|
lpwowSpool->hFile = hFile;
|
|
lpwowSpool->hPrinter = hPrinter;
|
|
lpwowSpool->prn16 = gprn16;
|
|
|
|
// tell the app that everything is hunky dory
|
|
ul = (LONG)gprn16++;
|
|
|
|
// make sure this doesn't go negative (-> an error ret to the app)
|
|
if(gprn16 & 0x8000) {
|
|
gprn16 = 0x100;
|
|
}
|
|
}
|
|
|
|
// error path
|
|
else {
|
|
|
|
(*spoolerapis[WOW_EndDocPrinter].lpfn) (hPrinter);
|
|
ClosePrinter:
|
|
// note: hPrinter is freed by WOW_ClosePrinter
|
|
(*spoolerapis[WOW_ClosePrinter].lpfn) (hPrinter);
|
|
}
|
|
}
|
|
|
|
exitpath:
|
|
|
|
LOGDEBUG(2,("WOW::WG32SpoolFile: ul = %x\n", ul));
|
|
|
|
if(psz2) {
|
|
free_w(psz2);
|
|
}
|
|
if(psz3) {
|
|
free_w(psz3);
|
|
}
|
|
if(psz4) {
|
|
free_w(psz4);
|
|
}
|
|
if(pszDriver) {
|
|
free_w(pszDriver);
|
|
}
|
|
|
|
// give the spooler thread a kick start then close the thread handle
|
|
// (note: the thread will still be active)
|
|
if(hThread) {
|
|
ResumeThread(hThread);
|
|
CloseHandle(hThread);
|
|
}
|
|
|
|
// clean up if there was an error -- otherwise the thread will clean up
|
|
if(ul == -1) {
|
|
if(hFile) {
|
|
DPM_CloseHandle(hFile);
|
|
}
|
|
if(lpwowSpool) {
|
|
free_w(lpwowSpool);
|
|
}
|
|
// note: hPrinter is freed by WOW_ClosePrinter
|
|
}
|
|
|
|
return((ULONG)ul);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define SPOOL_BUFF_SIZE 4096
|
|
|
|
VOID WOWSpoolerThread(WOWSPOOL *lpwowSpool)
|
|
{
|
|
DWORD dwBytes;
|
|
DWORD dwWritten;
|
|
BYTE buf[SPOOL_BUFF_SIZE];
|
|
|
|
|
|
// this thread will only do something if fOK is TRUE
|
|
if(lpwowSpool && lpwowSpool->fOK) {
|
|
do {
|
|
|
|
// this is a sequential read
|
|
if(DPM_ReadFile(lpwowSpool->hFile, buf, SPOOL_BUFF_SIZE, &dwBytes, NULL)) {
|
|
|
|
// if dwBytes==0 --> EOF
|
|
if(dwBytes) {
|
|
|
|
//
|
|
if(!(*spoolerapis[WOW_WritePrinter].lpfn)(lpwowSpool->hPrinter,
|
|
buf,
|
|
dwBytes,
|
|
&dwWritten)) {
|
|
LOGDEBUG(0,("WOW::WOWSpoolerThread:WritePrinter ERROR!\n"));
|
|
break;
|
|
}
|
|
else if(dwBytes != dwWritten) {
|
|
LOGDEBUG(0,("WOW::WOWSpoolerThread:WritePrinter error!\n"));
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
} while (dwBytes == SPOOL_BUFF_SIZE);
|
|
|
|
// shut down the print job
|
|
(*spoolerapis[WOW_EndPagePrinter].lpfn) (lpwowSpool->hPrinter);
|
|
(*spoolerapis[WOW_EndDocPrinter].lpfn) (lpwowSpool->hPrinter);
|
|
// note: hPrinter is freed by WOW_ClosePrinter
|
|
(*spoolerapis[WOW_ClosePrinter].lpfn) (lpwowSpool->hPrinter);
|
|
|
|
// clean up
|
|
if(lpwowSpool->hFile) {
|
|
DPM_CloseHandle(lpwowSpool->hFile);
|
|
}
|
|
if(lpwowSpool) {
|
|
free_w(lpwowSpool);
|
|
}
|
|
|
|
} // end if
|
|
|
|
ExitThread(0);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
WORD GetPrn16(HANDLE h32)
|
|
{
|
|
HANDLE hnd;
|
|
VPVOID vp;
|
|
LPBYTE lpMem16;
|
|
|
|
hnd = LocalAlloc16(LMEM_MOVEABLE, sizeof(HANDLE), (HANDLE) gUser16hInstance);
|
|
|
|
vp = LocalLock16(hnd);
|
|
|
|
if (vp) {
|
|
GETMISCPTR (vp, lpMem16);
|
|
if (lpMem16) {
|
|
*((PDWORD16)lpMem16) = (DWORD) h32;
|
|
FREEMISCPTR(lpMem16);
|
|
LocalUnlock16(hnd);
|
|
}
|
|
}
|
|
else {
|
|
LOGDEBUG (0, ("WOW::GETPRN16: Can't allocate a 16 bit handle\n"));
|
|
}
|
|
|
|
return (LOWORD(hnd));
|
|
}
|
|
|
|
|
|
HANDLE Prn32(WORD h16)
|
|
{
|
|
VPVOID vp;
|
|
HANDLE h32 = NULL;
|
|
LPBYTE lpMem16;
|
|
|
|
vp = LocalLock16 ((HANDLE) MAKELONG(h16, gUser16hInstance));
|
|
if (vp) {
|
|
GETMISCPTR (vp, lpMem16);
|
|
|
|
if (lpMem16) {
|
|
h32 = (HANDLE) *((PDWORD16)lpMem16);
|
|
FREEMISCPTR(lpMem16);
|
|
}
|
|
LocalUnlock16 ((HANDLE) MAKELONG(h16, gUser16hInstance));
|
|
}
|
|
|
|
return (h32);
|
|
}
|
|
|
|
|
|
VOID FreePrn (WORD h16)
|
|
{
|
|
LocalFree16 ((HANDLE) MAKELONG(h16, gUser16hInstance));
|
|
}
|
|
|
|
|
|
BOOL GetDriverName (char *psz, char *pszDriver, int cbDriver)
|
|
{
|
|
CHAR szAllDevices[1024];
|
|
CHAR *szNextDevice;
|
|
CHAR szPrinter[64];
|
|
CHAR *szOutput;
|
|
UINT len;
|
|
|
|
if(!psz || (*psz == '\0')) {
|
|
return FALSE;
|
|
}
|
|
|
|
len = strlen(psz);
|
|
|
|
szAllDevices[0]='\0';
|
|
GetProfileString ("devices", NULL, "", szAllDevices, sizeof(szAllDevices));
|
|
|
|
szNextDevice = szAllDevices;
|
|
|
|
LOGDEBUG(6,("WOW::GetDriverName: szAllDevices = %s\n", szAllDevices));
|
|
|
|
// strings from win.ini will be of the form "PS Printer=PSCRIPT,LPT1:"
|
|
while (*szNextDevice) {
|
|
|
|
szPrinter[0]='\0';
|
|
GetProfileString ("devices", szNextDevice, "", szPrinter, sizeof(szPrinter));
|
|
if (*szPrinter) {
|
|
if (szOutput = WOW32_strchr (szPrinter, ',')) {
|
|
szOutput++;
|
|
while (*szOutput == ' ') {
|
|
szOutput++;
|
|
}
|
|
|
|
if (!WOW32_stricmp(psz, szOutput)) {
|
|
break; // found it!
|
|
}
|
|
|
|
// some apps pass "LPT1" without the ':' -- account for that
|
|
// if the app passed "LPT1" and ...
|
|
if (psz[len-1] != ':') {
|
|
|
|
// ...strlen(szOutput) == 5 && szOutput[4] == ':' ...
|
|
if((strlen(szOutput) == len+1) && (szOutput[len] == ':')) {
|
|
|
|
// ...clobber the ':' char ...
|
|
szOutput[len] = '\0';
|
|
|
|
// ...and see if the strings match now
|
|
if (!WOW32_stricmp(psz, szOutput)) {
|
|
break; // found it!
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (szNextDevice = WOW32_strchr (szNextDevice, '\0')) {
|
|
szNextDevice++;
|
|
}
|
|
else {
|
|
szNextDevice = "";
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (*szNextDevice) {
|
|
LOGDEBUG(0,("WOW::GetDriverName: szNextDevice = %s\n", szNextDevice));
|
|
|
|
if (lstrcpyn (pszDriver, szNextDevice, cbDriver)) {
|
|
pszDriver[cbDriver-1] = '\0';
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// else they may have specified a network printer eg. "\\msprint44\corpk"
|
|
// in which case we'll assume it's all right (since it will fail once the
|
|
// WOW functions that call into this will fail when they call into the
|
|
// driver with a bogus driver name)
|
|
if(psz[0] == '\\' && psz[1] == '\\') {
|
|
strncpy(pszDriver, psz, cbDriver);
|
|
pszDriver[cbDriver-1] = '\0';
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|