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.
850 lines
29 KiB
850 lines
29 KiB
/*************************************************************************
|
|
*
|
|
* splkernl.c
|
|
*
|
|
* This is a modified Microsoft NT 4.0 file from
|
|
* \nt\private\windows\spooler\spoolss\server\splkernl.c
|
|
*
|
|
* This provides for reading spooler requests from printer device drivers
|
|
* running in kernel mode under WIN32K.SYS.
|
|
*
|
|
* WinFrame isolates each WIN32K.SYS and printer device driver into its
|
|
* own independent WINSTATION SPACE. Because of this, the threads that
|
|
* run inside of the spool subsystem can only read the requests from
|
|
* printer drivers running on the console.
|
|
*
|
|
* This module has been moved to CSRSS to read the requests out for this
|
|
* WINSTATION, and then convert them to RPC calls onto the spooler.
|
|
*
|
|
* NOTE: The kernel mode spooler requests take a different path than
|
|
* pure RPC requests. The console will continue to run this way. On
|
|
* WINSTATIONS, all print spooler interaction will be through RPC
|
|
* like NT 3.51.
|
|
*
|
|
* Also there is a new printer UI type that processing when a page
|
|
* or job is printed. These are OEM supplied for things like FAX
|
|
* servers. If they attempt to do any Windows dialogs or pop-ups
|
|
* they will only show up on the console. By having them be inside
|
|
* of the WINSTATIONS CSRSS they will pop up on the proper WINSTATION.
|
|
*
|
|
* copyright notice: Copyright 1997, Microsoft
|
|
*
|
|
* Author:
|
|
*
|
|
*************************************************************************/
|
|
|
|
/*++
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
splkernl.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the Spooler's Kernel mode message router and unmarshalling functions,
|
|
which then call kmxxx().
|
|
|
|
Author:
|
|
|
|
Steve Wilson (NT) (swilson) 1-Jun-1995
|
|
|
|
[Notes:]
|
|
|
|
optional-notes
|
|
|
|
Revision History:
|
|
Nicolas Biju-Duval Dec-97 : adaptation for Hydra
|
|
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include <ntddrdr.h>
|
|
#include <stdio.h>
|
|
#include <windows.h>
|
|
#include <winspool.h>
|
|
#include <ntgdispl.h>
|
|
#include "winspl.h"
|
|
#include "wingdip.h"
|
|
#include "musspl.h"
|
|
#include "kmsplapi.h"
|
|
#include "winuserk.h"
|
|
|
|
extern CRITICAL_SECTION ThreadCriticalSection;
|
|
|
|
#define IN_BUF_SIZE 4500 // must be at least 4096
|
|
#define OUT_BUF_SIZE 1024
|
|
|
|
#define DECREMENT 0
|
|
#define INCREMENT 1
|
|
|
|
#define MAX_GRE_STRUCT_SIZE 100 // At least the size of the largest GRExxx struct in ntgdispl.h
|
|
|
|
BOOL LoadWinspoolDrv();
|
|
|
|
DWORD cGetSpoolMessage(PSPOOLESC psesc, DWORD cjMsg, PDWORD pulOut, DWORD cjOut);
|
|
BOOL SpoolerGetSpoolMessage();
|
|
|
|
BOOL DoOpenPrinter(PSPOOLESC psesc, HANDLE*, DWORD*);
|
|
BOOL DoGetPrinter(PSPOOLESC psesc, GREGETPRINTER *pGetPrinterReturn, DWORD *pcjOut);
|
|
BOOL DoGetPrinterDriver( PSPOOLESC, GREGETPRINTERDRIVER*, DWORD* );
|
|
BOOL DoStartDocPrinter( PSPOOLESC psesc );
|
|
BOOL DoWritePrinter(PSPOOLESC psesc, DWORD *pWritten );
|
|
BOOL DoGetForm(PSPOOLESC psesc, GREGETFORM *pGetFormReturn, DWORD *pcjOut);
|
|
BOOL DoEnumForms(PSPOOLESC psesc, GREENUMFORMS *pEnumFormsReturn, DWORD *pcjOut);
|
|
BOOL DoGetPrinterData(PSPOOLESC psesc, GREGETPRINTERDATA *pXReturn, DWORD *pcjOut);
|
|
BOOL DoSetPrinterData(PSPOOLESC psesc, GRESETPRINTERDATA *pXReturn, DWORD *pcjOut);
|
|
BOOL DoGetPathName(WCHAR *pwcSrc, WCHAR *pwcDst, DWORD cbDst, DWORD *pcjWritten);
|
|
|
|
DWORD GetSpoolMessages();
|
|
DWORD AddThread();
|
|
|
|
LONG nIdleThreads = 0; // Number of idle threads
|
|
LONG nThreads = 0;
|
|
SYSTEMTIME LastMessageTime; // Time at which last message was received
|
|
|
|
//*************************************************************
|
|
//
|
|
// LoadWinspoolDrv
|
|
//
|
|
// This function is called at initialization, just to make sure
|
|
// that there is enough memory available. This is a little weird:
|
|
// we just want to load winspool.drv, but the obtained pointers
|
|
// will never be used. By doing that we are protected against
|
|
// the risk of not being able to load winspool.drv later.
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL LoadWinspoolDrv()
|
|
{
|
|
BOOL bRet = FALSE;
|
|
HANDLE hWinspoolDll = NULL;
|
|
hWinspoolDll = LoadLibraryW(L"winspool.drv");
|
|
|
|
if (hWinspoolDll != NULL) // winspool.drv OK, now get the addresses
|
|
{
|
|
fpOpenPrinterW = (FPOPENPRINTERW) GetProcAddress( hWinspoolDll, "OpenPrinterW");
|
|
fpGetPrinterW = (FPGETPRINTERW) GetProcAddress( hWinspoolDll, "GetPrinterW");
|
|
fpGetPrinterDriverW = (FPGETPRINTERDRIVERW)GetProcAddress( hWinspoolDll, "GetPrinterDriverW");
|
|
fpGetPrinterDataW = (FPGETPRINTERDATAW) GetProcAddress( hWinspoolDll, "GetPrinterDataW");
|
|
fpSetPrinterDataW = (FPSETPRINTERDATAW) GetProcAddress( hWinspoolDll, "SetPrinterDataW");
|
|
fpGetFormW = (FPGETFORMW) GetProcAddress( hWinspoolDll, "GetFormW");
|
|
fpEnumFormsW = (FPENUMFORMSW) GetProcAddress( hWinspoolDll, "EnumFormsW");
|
|
fpClosePrinter = (FPCLOSEPRINTER) GetProcAddress( hWinspoolDll, "ClosePrinter");
|
|
fpStartDocPrinterW = (FPSTARTDOCPRINTERW)GetProcAddress( hWinspoolDll, "StartDocPrinterW");
|
|
fpStartPagePrinter = (FPSTARTPAGEPRINTER)GetProcAddress( hWinspoolDll, "StartPagePrinter");
|
|
fpWritePrinter = (FPWRITEPRINTER) GetProcAddress( hWinspoolDll, "WritePrinter");
|
|
fpAbortPrinter = (FPABORTPRINTER) GetProcAddress( hWinspoolDll, "AbortPrinter");
|
|
fpEndPagePrinter = (FPENDPAGEPRINTER) GetProcAddress( hWinspoolDll, "EndPagePrinter");
|
|
fpEndDocPrinter = (FPENDDOCPRINTER) GetProcAddress( hWinspoolDll, "EndDocPrinter");
|
|
|
|
if ((fpOpenPrinterW != NULL) &&
|
|
(fpGetPrinterW != NULL) &&
|
|
(fpGetPrinterDriverW != NULL) &&
|
|
(fpGetPrinterDataW != NULL) &&
|
|
(fpSetPrinterDataW != NULL) &&
|
|
(fpGetFormW != NULL) &&
|
|
(fpEnumFormsW != NULL) &&
|
|
(fpClosePrinter != NULL) &&
|
|
(fpStartDocPrinterW != NULL) &&
|
|
(fpStartPagePrinter != NULL) &&
|
|
(fpWritePrinter != NULL) &&
|
|
(fpAbortPrinter != NULL) &&
|
|
(fpEndPagePrinter != NULL) &&
|
|
(fpEndDocPrinter != NULL) )
|
|
{
|
|
bRet = TRUE; // everything is OK. We are ready to call winspool.drv
|
|
}
|
|
else
|
|
{
|
|
bRet = FALSE;
|
|
FreeLibrary(hWinspoolDll);
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//
|
|
// GetSpoolMessages - Manages creation & deletion of spooler message threads
|
|
//
|
|
DWORD GetSpoolMessages()
|
|
{
|
|
if (!GdiInitSpool()) {
|
|
DBGMSG(DBG_TRACE, ("Error calling GdiInitSpool()\n"));
|
|
return GetLastError();
|
|
}
|
|
|
|
if (!LoadWinspoolDrv())
|
|
{
|
|
DBGMSG(DBG_TRACE, ("Unable to load Winspool.drv\n"));
|
|
return GetLastError();
|
|
}
|
|
|
|
return AddThread();
|
|
}
|
|
|
|
DWORD AddThread()
|
|
{
|
|
HANDLE hThread;
|
|
DWORD MessageThreadId;
|
|
DWORD dwError;
|
|
|
|
try {
|
|
if(hThread = CreateThread( NULL,
|
|
64*1024,
|
|
(LPTHREAD_START_ROUTINE) SpoolerGetSpoolMessage,
|
|
0,
|
|
0,
|
|
&MessageThreadId)) {
|
|
CloseHandle(hThread);
|
|
dwError = ERROR_SUCCESS;
|
|
} else {
|
|
dwError = GetLastError();
|
|
}
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
dwError = TranslateExceptionCode(GetExceptionCode());
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
BOOL SpoolerGetSpoolMessage()
|
|
{
|
|
DWORD dwResult;
|
|
PSPOOLESC pInput; // Input buffer that receives messages from Kernel
|
|
BYTE *pOutput; // Output buffer that receives data from KMxxx() spooler calls
|
|
BYTE *pMem;
|
|
DWORD cbOut = 0; // Size of pOutput
|
|
DWORD cbIn = IN_BUF_SIZE; // Size of pInput buffer in bytes
|
|
DWORD cbOutSize;
|
|
USERTHREAD_USEDESKTOPINFO utudi = { 0 };
|
|
BOOL bHaveDesktop = FALSE;
|
|
|
|
(VOID) CsrConnectToUser();
|
|
|
|
if(!(pInput = (PSPOOLESC) AllocSplMem(cbIn))) {
|
|
DBGMSG(DBG_WARNING, ("Error allocating pInput in SpoolerGetSpoolMessage\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
if(!(pOutput = AllocSplMem(OUT_BUF_SIZE))) {
|
|
FreeSplMem(pInput);
|
|
DBGMSG(DBG_WARNING, ("Error allocating pInput in SpoolerGetSpoolMessage\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
cbOutSize = OUT_BUF_SIZE;
|
|
|
|
EnterCriticalSection(&ThreadCriticalSection);
|
|
|
|
++nThreads;
|
|
|
|
LeaveCriticalSection(&ThreadCriticalSection);
|
|
|
|
while(1) {
|
|
|
|
EnterCriticalSection(&ThreadCriticalSection);
|
|
++nIdleThreads;
|
|
LeaveCriticalSection(&ThreadCriticalSection);
|
|
|
|
dwResult = GdiGetSpoolMessage(pInput,cbIn,(PDWORD)pOutput,cbOut);
|
|
|
|
EnterCriticalSection(&ThreadCriticalSection);
|
|
--nIdleThreads;
|
|
LeaveCriticalSection(&ThreadCriticalSection);
|
|
|
|
if(dwResult) {
|
|
if( (pInput->iMsg != GDISPOOL_TERMINATETHREAD) &&
|
|
(pInput->iMsg != GDISPOOL_INPUT2SMALL)) {
|
|
|
|
EnterCriticalSection(&ThreadCriticalSection);
|
|
|
|
if(nIdleThreads == 0) {
|
|
AddThread();
|
|
DBGMSG(DBG_TRACE, ("Thread Added: nIdle = %d nThreads = %d\n", nIdleThreads, nThreads));
|
|
}
|
|
|
|
LeaveCriticalSection(&ThreadCriticalSection);
|
|
}
|
|
|
|
// check if the out buffer needs to be grown or shrunk.
|
|
|
|
if ((pInput->cjOut + MAX_GRE_STRUCT_SIZE) > cbOutSize) {
|
|
|
|
FreeSplMem(pOutput);
|
|
|
|
pOutput = AllocSplMem(cbOutSize = pInput->cjOut + MAX_GRE_STRUCT_SIZE);
|
|
|
|
if (!pOutput) {
|
|
|
|
DBGMSG(DBG_WARNING, ("Error allocating pInput in SpoolerGetSpoolMessage\n"));
|
|
pInput->ulRet = 0;
|
|
cbOut = 0;
|
|
cbOutSize = 0;
|
|
continue;
|
|
}
|
|
}
|
|
else if ((pInput->cjOut < OUT_BUF_SIZE) &&
|
|
(cbOutSize > OUT_BUF_SIZE)) {
|
|
|
|
// we want to shrink the buffer
|
|
|
|
PBYTE pbTmp = AllocSplMem(OUT_BUF_SIZE);
|
|
|
|
if (pbTmp) {
|
|
|
|
FreeSplMem(pOutput);
|
|
|
|
pOutput = pbTmp;
|
|
cbOutSize = OUT_BUF_SIZE;
|
|
}
|
|
}
|
|
|
|
|
|
if (pInput->iMsg & GDISPOOL_API) {
|
|
|
|
SPLASSERT(pInput->hSpool || pInput->iMsg == GDISPOOL_OPENPRINTER);
|
|
|
|
if (pInput->iMsg != GDISPOOL_OPENPRINTER || pInput->hSpool) {
|
|
if (InterlockedIncrement(&((PSPOOL)pInput->hSpool)->cThreads) > 0) {
|
|
|
|
// We are already processing a message & have now gotten a ClosePrinter
|
|
// We should not get here on any other API
|
|
SPLASSERT(pInput->iMsg == GDISPOOL_CLOSEPRINTER);
|
|
|
|
pInput->ulRet = TRUE; // Let Client terminate
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// This is a Csrss thread with no desktop. It needs to grab a temporary one
|
|
// before calling into win32k so set a desktop in case there is a user mode
|
|
// print driver that wants to write to a desktop (ie dialog box messages).
|
|
//
|
|
utudi.hThread = NULL;
|
|
utudi.drdRestore.pdeskRestore = NULL;
|
|
|
|
bHaveDesktop = ((NtUserSetInformationThread(
|
|
NtCurrentThread(),
|
|
UserThreadUseActiveDesktop,
|
|
&utudi,
|
|
sizeof(utudi)) == STATUS_SUCCESS) ? TRUE : FALSE );
|
|
|
|
switch (pInput->iMsg) {
|
|
case GDISPOOL_INPUT2SMALL:
|
|
DBGMSG(DBG_TRACE,(" - buffer not big enough\n"));
|
|
|
|
pMem = ReallocSplMem(pInput, cbIn, pInput->cjOut);
|
|
|
|
if (!pMem) {
|
|
|
|
DBGMSG(DBG_WARNING, ("Error reallocating pInput in SpoolerGetSpoolMessage\n"));
|
|
pInput->ulRet = 0;
|
|
}
|
|
else {
|
|
pInput = (PSPOOLESC) pMem;
|
|
cbIn = pInput->cjOut;
|
|
pInput->ulRet = 1;
|
|
}
|
|
|
|
break;
|
|
|
|
case GDISPOOL_TERMINATETHREAD:
|
|
EnterCriticalSection(&ThreadCriticalSection);
|
|
|
|
// There is 1 way to get here: from a 10 minute Kernel Event timeout
|
|
|
|
if(nIdleThreads > 1) {
|
|
--nThreads;
|
|
if (nThreads == 0) {
|
|
DBGMSG(DBG_WARNING, ("SpoolerGetSpoolMessage nThreads is now ZERO\n"));
|
|
}
|
|
|
|
DBGMSG(DBG_TRACE, ("Thread Deleted: nIdle = %d nThreads = %d\n", nIdleThreads, nThreads));
|
|
|
|
LeaveCriticalSection(&ThreadCriticalSection);
|
|
|
|
FreeSplMem(pInput);
|
|
FreeSplMem(pOutput);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LeaveCriticalSection(&ThreadCriticalSection);
|
|
break;
|
|
#ifdef _IA64_
|
|
case GDISPOOL_WRITE:
|
|
case GDISPOOL_OPENPRINTER:
|
|
case GDISPOOL_STARTDOCPRINTER:
|
|
case GDISPOOL_STARTPAGEPRINTER:
|
|
case GDISPOOL_ENDPAGEPRINTER:
|
|
case GDISPOOL_ENDDOCPRINTER:
|
|
case GDISPOOL_ENUMFORMS:
|
|
case GDISPOOL_GETPRINTER:
|
|
case GDISPOOL_GETFORM:
|
|
case GDISPOOL_GETPRINTERDRIVER:
|
|
case GDISPOOL_GETPRINTERDATA:
|
|
case GDISPOOL_SETPRINTERDATA:
|
|
case GDISPOOL_ABORTPRINTER:
|
|
case GDISPOOL_CLOSEPRINTER:
|
|
case GDISPOOL_GETPATHNAME:
|
|
|
|
//
|
|
// We should normally never get here. We do not support KMPD on IA64.
|
|
// However, GDI may try to take the route of KM messaging, if OpenPrinter
|
|
// for a queue using a UMPD fails. This can happen under stress conditons.
|
|
// For this reason we handle the KM request on IA64.
|
|
//
|
|
pInput->ulRet = FALSE;
|
|
SetLastError(ERROR_NOT_SUPPORTED);
|
|
break;
|
|
#else
|
|
case GDISPOOL_WRITE:
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_WRITE\n"));
|
|
pInput->ulRet = DoWritePrinter( pInput, (DWORD*) pOutput );
|
|
cbOut = sizeof(DWORD);
|
|
break;
|
|
|
|
case GDISPOOL_OPENPRINTER:
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_OPENPRINTER\n"));
|
|
DoOpenPrinter(pInput,(HANDLE*)pOutput,&cbOut);
|
|
break;
|
|
|
|
case GDISPOOL_STARTDOCPRINTER:
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_STARTDOCPRINTER\n"));
|
|
DoStartDocPrinter(pInput);
|
|
break;
|
|
|
|
case GDISPOOL_STARTPAGEPRINTER:
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_STARTPAGEPRINTER\n"));
|
|
pInput->ulRet = KMStartPagePrinter( pInput->hSpool );
|
|
break;
|
|
|
|
case GDISPOOL_ENDPAGEPRINTER:
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_ENDPAGEPRINTER\n"));
|
|
pInput->ulRet = KMEndPagePrinter( pInput->hSpool );
|
|
break;
|
|
|
|
case GDISPOOL_ENDDOCPRINTER:
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_ENDDOCPRINTER\n"));
|
|
pInput->ulRet = KMEndDocPrinter( pInput->hSpool );
|
|
break;
|
|
|
|
case GDISPOOL_ENUMFORMS:
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_ENUMFORMS\n"));
|
|
DoEnumForms(pInput, (GREENUMFORMS *) pOutput, &cbOut);
|
|
break;
|
|
|
|
case GDISPOOL_GETPRINTER:
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPRINTER\n"));
|
|
DoGetPrinter(pInput, (GREGETPRINTER *) pOutput, &cbOut);
|
|
break;
|
|
|
|
case GDISPOOL_GETFORM:
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_GETFORM\n"));
|
|
DoGetForm(pInput, (GREGETFORM *) pOutput, &cbOut);
|
|
break;
|
|
|
|
case GDISPOOL_GETPRINTERDRIVER:
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPRINTERDRIVER\n"));
|
|
DoGetPrinterDriver(pInput,(GREGETPRINTERDRIVER*)pOutput,&cbOut);
|
|
break;
|
|
|
|
case GDISPOOL_GETPRINTERDATA:
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPRINTERDATA\n"));
|
|
DoGetPrinterData(pInput,(GREGETPRINTERDATA *) pOutput,&cbOut);
|
|
break;
|
|
|
|
case GDISPOOL_SETPRINTERDATA:
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_SETPRINTERDATA\n"));
|
|
DoSetPrinterData(pInput,(GRESETPRINTERDATA *) pOutput,&cbOut);
|
|
break;
|
|
|
|
case GDISPOOL_ABORTPRINTER:
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_ABORTPRINTER\n"));
|
|
pInput->ulRet = KMAbortPrinter( pInput->hSpool );
|
|
break;
|
|
|
|
case GDISPOOL_CLOSEPRINTER:
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_CLOSEPRINTER\n"));
|
|
pInput->ulRet = KMClosePrinter( pInput->hSpool );
|
|
break;
|
|
|
|
case GDISPOOL_GETPATHNAME:
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_GETPATHNAME\n"));
|
|
pInput->ulRet = DoGetPathName((WCHAR*)pInput->ajData,
|
|
(WCHAR*)pOutput,
|
|
cbOutSize,
|
|
&cbOut);
|
|
break;
|
|
#endif
|
|
default:
|
|
DBGMSG(DBG_ERROR,(" - invalid message\n"));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Release the temporary desktop
|
|
//
|
|
if (bHaveDesktop) {
|
|
|
|
(VOID)NtUserSetInformationThread(NtCurrentThread(),
|
|
UserThreadUseDesktop,
|
|
&utudi,
|
|
sizeof(utudi));
|
|
}
|
|
|
|
if ((pInput->iMsg & GDISPOOL_API) &&
|
|
pInput->iMsg != GDISPOOL_CLOSEPRINTER &&
|
|
pInput->iMsg != GDISPOOL_OPENPRINTER &&
|
|
pInput->hSpool) {
|
|
|
|
if (InterlockedDecrement(&((PSPOOL)pInput->hSpool)->cThreads) == 0) {
|
|
|
|
DBGMSG(DBG_TRACE,(" - GDISPOOL_CLOSEPRINTER\n"));
|
|
#ifdef _IA64_
|
|
pInput->ulRet = FALSE;
|
|
SetLastError(ERROR_NOT_SUPPORTED);
|
|
#else
|
|
pInput->ulRet = KMClosePrinter( pInput->hSpool );
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
BOOL DoOpenPrinter(PSPOOLESC psesc, HANDLE* phPrinter, DWORD* pcjOut)
|
|
{
|
|
LPWSTR pPrinterName = NULL;
|
|
PRINTER_DEFAULTSW pDefault;
|
|
GREOPENPRINTER *pOpenPrinter = (GREOPENPRINTER *)psesc->ajData;
|
|
PLONG plData;
|
|
|
|
plData = pOpenPrinter->alData;
|
|
pDefault = pOpenPrinter->pd;
|
|
|
|
// see if there is a printer name?
|
|
|
|
if (pOpenPrinter->cjName)
|
|
{
|
|
pPrinterName = (PWCHAR)plData;
|
|
plData += pOpenPrinter->cjName/4;
|
|
}
|
|
|
|
// now setup the printer defaults
|
|
|
|
if (pOpenPrinter->cjDatatype)
|
|
{
|
|
pDefault.pDatatype = (PWCHAR)plData;
|
|
plData += pOpenPrinter->cjDatatype/4;
|
|
}
|
|
|
|
if (pOpenPrinter->cjDevMode)
|
|
{
|
|
pDefault.pDevMode = (PDEVMODEW)plData;
|
|
}
|
|
|
|
DBGMSG(DBG_TRACE,
|
|
("OpenPrinter(%ls,%ls,%lx,%d)\n",
|
|
pPrinterName,
|
|
pDefault.pDatatype,
|
|
pDefault.pDevMode,
|
|
pDefault.DesiredAccess) );
|
|
|
|
psesc->ulRet = KMOpenPrinterW(pPrinterName,phPrinter,&pDefault);
|
|
|
|
DBGMSG( DBG_TRACE,("OpenPrinter returned = %lx\n",psesc->ulRet));
|
|
|
|
*pcjOut = sizeof(DWORD);
|
|
|
|
if(psesc->ulRet)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL DoStartDocPrinter( PSPOOLESC psesc )
|
|
{
|
|
DOC_INFO_1W di;
|
|
GRESTARTDOCPRINTER *pStartDocPrinter = (GRESTARTDOCPRINTER *)psesc->ajData;
|
|
PLONG plData;
|
|
|
|
plData = pStartDocPrinter->alData;
|
|
|
|
// see if there is a printer name?
|
|
|
|
if (pStartDocPrinter->cjDocName)
|
|
{
|
|
di.pDocName = (PWCHAR)plData;
|
|
plData += pStartDocPrinter->cjDocName/4;
|
|
}
|
|
else
|
|
{
|
|
di.pDocName = NULL;
|
|
}
|
|
|
|
if (pStartDocPrinter->cjOutputFile)
|
|
{
|
|
di.pOutputFile = (PWCHAR)plData;
|
|
plData += pStartDocPrinter->cjOutputFile/4;
|
|
}
|
|
else
|
|
{
|
|
di.pOutputFile = NULL;
|
|
}
|
|
|
|
if (pStartDocPrinter->cjDatatype)
|
|
{
|
|
di.pDatatype = (PWCHAR)plData;
|
|
plData += pStartDocPrinter->cjDatatype/4;
|
|
}
|
|
else
|
|
{
|
|
di.pDatatype = NULL;
|
|
}
|
|
|
|
psesc->ulRet = KMStartDocPrinterW(psesc->hSpool, 1, (LPBYTE) &di);
|
|
|
|
if(psesc->ulRet)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL DoEnumForms(
|
|
PSPOOLESC psesc,
|
|
GREENUMFORMS *pEnumFormsReturn,
|
|
DWORD *pcjOut
|
|
)
|
|
{
|
|
GREENUMFORMS *pEnumForms = (GREENUMFORMS *) psesc->ajData;
|
|
DWORD dwNeeded = 0;
|
|
|
|
psesc->ulRet = KMEnumFormsW ( psesc->hSpool,
|
|
pEnumForms->dwLevel,
|
|
(BYTE *) pEnumFormsReturn->alData,
|
|
pEnumForms->cjData,
|
|
&dwNeeded,
|
|
&pEnumFormsReturn->nForms
|
|
);
|
|
|
|
if (psesc->ulRet) {
|
|
|
|
// Set return data size to incoming buffer size since strings are packed at end of in buffer
|
|
pEnumFormsReturn->cjData = pEnumForms->cjData;
|
|
*pcjOut = pEnumForms->cjData + sizeof(GREENUMFORMS);
|
|
}
|
|
else {
|
|
pEnumFormsReturn->cjData = dwNeeded; // This makes client alloc more than needed
|
|
*pcjOut = sizeof(GREENUMFORMS);
|
|
}
|
|
|
|
return psesc->ulRet;
|
|
}
|
|
|
|
BOOL DoGetPrinter(
|
|
PSPOOLESC psesc,
|
|
GREGETPRINTER *pGetPrinterReturn,
|
|
DWORD *pcjOut
|
|
)
|
|
{
|
|
GREGETPRINTER *pGetPrinter = (GREGETPRINTER *) psesc->ajData;
|
|
DWORD dwNeeded = 0;
|
|
|
|
psesc->ulRet = KMGetPrinterW ( psesc->hSpool,
|
|
pGetPrinter->dwLevel,
|
|
(BYTE *) pGetPrinterReturn->alData,
|
|
pGetPrinter->cjData,
|
|
&dwNeeded
|
|
);
|
|
|
|
if (psesc->ulRet) {
|
|
|
|
// Set return data size to incoming buffer size since strings are packed at end of in buffer
|
|
pGetPrinterReturn->cjData = pGetPrinter->cjData;
|
|
*pcjOut = pGetPrinter->cjData + sizeof(GREGETPRINTER);
|
|
}
|
|
else {
|
|
pGetPrinterReturn->cjData = dwNeeded; // This makes client alloc more than needed
|
|
*pcjOut = sizeof(GREGETPRINTER);
|
|
}
|
|
|
|
return psesc->ulRet;
|
|
}
|
|
|
|
BOOL DoGetForm(
|
|
PSPOOLESC psesc,
|
|
GREGETFORM *pGetFormReturn,
|
|
DWORD *pcjOut
|
|
)
|
|
{
|
|
GREGETFORM *pGetForm = (GREGETFORM *) psesc->ajData;
|
|
DWORD dwNeeded = 0;
|
|
|
|
psesc->ulRet = KMGetFormW ( psesc->hSpool,
|
|
pGetForm->cjFormName ? (PWCHAR) pGetForm->alData : NULL,
|
|
pGetForm->dwLevel,
|
|
(BYTE *) pGetFormReturn->alData,
|
|
pGetForm->cjData,
|
|
&dwNeeded
|
|
);
|
|
|
|
if (psesc->ulRet) {
|
|
|
|
// Set return data size to incoming buffer size since strings are packed at end of in buffer
|
|
pGetFormReturn->cjData = pGetForm->cjData;
|
|
*pcjOut = pGetForm->cjData + sizeof(GREGETFORM);
|
|
}
|
|
else {
|
|
pGetFormReturn->cjData = dwNeeded; // This makes client alloc more than needed
|
|
*pcjOut = sizeof(GREGETFORM);
|
|
}
|
|
|
|
return psesc->ulRet;
|
|
}
|
|
|
|
|
|
BOOL DoGetPrinterDriver(
|
|
PSPOOLESC psesc,
|
|
GREGETPRINTERDRIVER *pGetPrinterDriverReturn,
|
|
DWORD *pcjOut
|
|
)
|
|
{
|
|
GREGETPRINTERDRIVER *pGetPrinterDriver = (GREGETPRINTERDRIVER *)psesc->ajData;
|
|
DWORD dwNeeded = 0;
|
|
|
|
psesc->ulRet = KMGetPrinterDriverW(psesc->hSpool,
|
|
pGetPrinterDriver->cjEnv ? (PWCHAR)pGetPrinterDriver->alData : NULL,
|
|
pGetPrinterDriver->dwLevel,
|
|
(BYTE*)pGetPrinterDriverReturn->alData,
|
|
pGetPrinterDriver->cjData,
|
|
&dwNeeded );
|
|
|
|
if (psesc->ulRet)
|
|
{
|
|
pGetPrinterDriverReturn->cjData = pGetPrinterDriver->cjData; // fix for ValidateStrings in spool.cxx
|
|
*pcjOut = pGetPrinterDriver->cjData + sizeof(GREGETPRINTERDRIVER);
|
|
}
|
|
else
|
|
{
|
|
// we failed so just return the size
|
|
|
|
pGetPrinterDriverReturn->cjData = dwNeeded;
|
|
*pcjOut = sizeof(GREGETPRINTERDRIVER);
|
|
}
|
|
|
|
|
|
if(psesc->ulRet)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL DoGetPrinterData(
|
|
PSPOOLESC psesc,
|
|
GREGETPRINTERDATA *pXReturn,
|
|
DWORD *pcjOut
|
|
)
|
|
{
|
|
GREGETPRINTERDATA *pX = (GREGETPRINTERDATA *) psesc->ajData;
|
|
|
|
DWORD dwNeeded = 0;
|
|
DWORD dwType;
|
|
|
|
|
|
psesc->ulRet = KMGetPrinterDataW( psesc->hSpool,
|
|
pX->cjValueName ? (PWCHAR) pX->alData : NULL,
|
|
&dwType,
|
|
(BYTE *) pXReturn->alData,
|
|
pX->cjData,
|
|
&dwNeeded );
|
|
|
|
pXReturn->dwNeeded = dwNeeded;
|
|
pXReturn->cjData = pX->cjData;
|
|
*pcjOut = pX->cjData + sizeof *pX;
|
|
pXReturn->dwType = dwType;
|
|
|
|
SetLastError(psesc->ulRet);
|
|
|
|
return psesc->ulRet = !psesc->ulRet;
|
|
}
|
|
|
|
BOOL DoSetPrinterData(
|
|
PSPOOLESC psesc,
|
|
GRESETPRINTERDATA *pXReturn,
|
|
DWORD *pcjOut
|
|
)
|
|
{
|
|
GRESETPRINTERDATA *pX = (GRESETPRINTERDATA *) psesc->ajData;
|
|
|
|
|
|
psesc->ulRet = KMSetPrinterDataW( psesc->hSpool,
|
|
pX->cjType ? (PWCHAR) pX->alData : NULL,
|
|
pX->dwType,
|
|
pX->cjPrinterData ? (BYTE *) pX->alData + pX->cjType : NULL,
|
|
pX->cjPrinterData );
|
|
|
|
*pcjOut = sizeof *pX;
|
|
|
|
SetLastError(psesc->ulRet);
|
|
|
|
return psesc->ulRet = !psesc->ulRet;
|
|
UNREFERENCED_PARAMETER(pXReturn);
|
|
}
|
|
|
|
BOOL DoWritePrinter(PSPOOLESC psesc, DWORD *pWritten )
|
|
{
|
|
GREWRITEPRINTER *pWritePrinter;
|
|
|
|
pWritePrinter = (GREWRITEPRINTER*) psesc->ajData;
|
|
|
|
if( KMWritePrinter( psesc->hSpool,
|
|
(PVOID) pWritePrinter->alData,
|
|
pWritePrinter->cjData,
|
|
pWritten) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
BOOL DoGetPathName( WCHAR *pwcSrc, WCHAR *pwcDst, DWORD cbDst, DWORD *pcjWritten )
|
|
{
|
|
BOOL bRet;
|
|
WCHAR awcFontsDir[MAX_PATH + sizeof(L"\\DOSDEVICES\\")/sizeof(WCHAR)] = {L"\\DOSDEVICES\\"};
|
|
|
|
bRet = bMakePathNameW (
|
|
&awcFontsDir[sizeof(L"\\DOSDEVICES\\")/sizeof(WCHAR) - 1],
|
|
pwcSrc,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
|
|
if (bRet)
|
|
{
|
|
bRet = SUCCEEDED(StringCbCopyW(pwcDst, cbDst, awcFontsDir));
|
|
*pcjWritten = sizeof(WCHAR) * (wcslen(awcFontsDir) + 1);
|
|
}
|
|
|
|
//
|
|
// Buffer large enough and search successfull?
|
|
//
|
|
return bRet;
|
|
}
|