windows-nt/Source/XPSP1/NT/printscan/print/spooler/localspl/clusport.c
2020-09-26 16:20:57 +08:00

766 lines
18 KiB
C

/*++
Copyright (c) 1997 Microsoft Corporation
All rights reserved
Module Name:
Downlevel cluster port support.
Abstract:
Supports mixing and matching downlevel and uplevel language
and monitor ports.
Author:
Environment:
User Mode -Win32
Revision History:
--*/
#include <precomp.h>
#pragma hdrstop
/********************************************************************
Downlevel Port Monitor (Dp)
Dp support is used when we have an uplevel language monitor
and downlevel port monitor. We pass a stub function vector
to the LM and set the hMonitor to the downlevel pIniMonitor.
When we get called, we can dereference the hMonitor to call the
real downlevel monitor.
********************************************************************/
BOOL
DpEnumPorts(
HANDLE hMonitor,
LPWSTR pName,
DWORD Level,
LPBYTE pPorts,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
)
{
PINIMONITOR pIniMonitor = (PINIMONITOR)hMonitor;
return pIniMonitor->Monitor.pfnEnumPorts( pName,
Level,
pPorts,
cbBuf,
pcbNeeded,
pcReturned );
}
BOOL
DpOpenPort(
HANDLE hMonitor,
LPWSTR pName,
PHANDLE pHandle
)
{
PINIMONITOR pIniMonitor = (PINIMONITOR)hMonitor;
return pIniMonitor->Monitor.pfnOpenPort( pName, pHandle );
}
BOOL
DpOpenPortEx(
HANDLE hMonitor,
LPWSTR pPortName,
LPWSTR pPrinterName,
PHANDLE pHandle,
struct _MONITOR FAR *pMonitor
)
{
PINIMONITOR pIniMonitor = (PINIMONITOR)hMonitor;
return pIniMonitor->Monitor.pfnOpenPortEx( pPortName,
pPrinterName,
pHandle,
pMonitor );
}
BOOL
DpAddPort(
HANDLE hMonitor,
LPWSTR pName,
HWND hWnd,
LPWSTR pMonitorName
)
{
PINIMONITOR pIniMonitor = (PINIMONITOR)hMonitor;
return pIniMonitor->Monitor.pfnAddPort( pName,
hWnd,
pMonitorName );
}
BOOL
DpAddPortEx(
HANDLE hMonitor,
LPWSTR pName,
DWORD Level,
LPBYTE pBuffer,
LPWSTR pMonitorName
)
{
PINIMONITOR pIniMonitor = (PINIMONITOR)hMonitor;
return pIniMonitor->Monitor.pfnAddPortEx( pName,
Level,
pBuffer,
pMonitorName );
}
BOOL
DpConfigurePort(
HANDLE hMonitor,
LPWSTR pName,
HWND hWnd,
LPWSTR pPortName
)
{
PINIMONITOR pIniMonitor = (PINIMONITOR)hMonitor;
return pIniMonitor->Monitor.pfnConfigurePort( pName,
hWnd,
pPortName );
}
BOOL
DpDeletePort(
HANDLE hMonitor,
LPWSTR pName,
HWND hWnd,
LPWSTR pPortName
)
{
PINIMONITOR pIniMonitor = (PINIMONITOR)hMonitor;
return pIniMonitor->Monitor.pfnDeletePort( pName,
hWnd,
pPortName );
}
BOOL
DpXcvOpenPort(
HANDLE hMonitor,
LPCWSTR pszObject,
ACCESS_MASK GrantedAccess,
PHANDLE phXcv
)
{
PINIMONITOR pIniMonitor = (PINIMONITOR)hMonitor;
return pIniMonitor->Monitor.pfnXcvOpenPort( pszObject,
GrantedAccess,
phXcv );
}
/********************************************************************
Downlevel Language Monitor (Dl)
Dl support is used when we have a downlevel language monitor
and uplevel port monitor.
This is very messy, since the language monitor is given the
ports function vector directly, and we don't have any extra
handles to pass around state information.
Instead, we overload the name string yet again. The port name
is converted to:
{NormalPortName},{pIniMonitorHex}
LPT1:,a53588
We then strip off the two trailing hex numbers and pass LPT1:
back.
********************************************************************/
BOOL
GetDlPointers(
IN LPCWSTR pszName,
OUT LPWSTR pszNameNew,
OUT PINIMONITOR *ppIniMonitor,
IN DWORD cchBufferSize
)
/*++
Routine Description:
Hack function to take a pszName and convert it to a new name
string with two additional parameters: hMonitor and pMonitor2
Arguments:
pszName - Hacked up name overloaded with pIniMonitor.
pszNameNew - Receives "real" shorter name of the port.
ppIniMonitor - Receives cracked pIniMonitor.
Return Value:
--*/
{
BOOL bReturn = FALSE;
LPCWSTR p;
LPCWSTR p1 = NULL;
for( p = pszName; p = wcschr( p, TEXT( ',' )); ){
p1 = p;
++p;
}
if( p1 ){
lstrcpyn( pszNameNew, pszName, cchBufferSize );
pszNameNew[p1-pszName] = 0;
++p1;
*ppIniMonitor = (PINIMONITOR)atox( p1 );
__try {
bReturn = ( (*ppIniMonitor)->signature == IMO_SIGNATURE );
} except( EXCEPTION_EXECUTE_HANDLER ){
}
if( bReturn ){
return TRUE;
}
}
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
BOOL
CreateDlName(
IN LPCWSTR pszName,
IN PINIMONITOR pIniMonitor,
OUT LPWSTR pszNameNew
)
/*++
Routine Description:
Create a downlevel name that can be parsed by GetDlPointers.
Arguments:
pszName - Name of port. The newly created name must be < MAX_PATH,
and since we need to append one hex values (4 characters) plus
one comma, we need to verify that the string length has at least
5 characters left.
pIniMonitor - Monitor structure of the uplevel port monitor.
Return Value:
TRUE - Success
FALSE - Failure, due to too long port name length.
--*/
{
if( lstrlen( pszName ) >= MAX_PATH - sizeof(ULONG_PTR) -1 ){
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
wsprintf( pszNameNew,
TEXT( "%s,%p" ),
pszName,
pIniMonitor );
return TRUE;
}
FARPROC gafpMonitor2Stub[] = {
(FARPROC) &DpEnumPorts,
(FARPROC) &DpOpenPort,
NULL, // OpenPortEx
NULL, // StartDocPort
NULL, // WritePort
NULL, // ReadPort
NULL, // EndDocPort
NULL, // ClosePort
(FARPROC) &DpAddPort,
(FARPROC) &DpAddPortEx,
(FARPROC) &DpConfigurePort,
(FARPROC) &DpDeletePort,
NULL,
NULL,
(FARPROC) &DpXcvOpenPort,
NULL, // XcvDataPortW
NULL, // XcvClosePortW
NULL // Shutdown
};
BOOL
DlEnumPorts(
LPWSTR pName,
DWORD Level,
LPBYTE pPorts,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
)
{
WCHAR szName[MAX_PATH];
PINIMONITOR pIniMonitor;
if( GetDlPointers( pName, szName, &pIniMonitor, COUNTOF(szName) )){
return pIniMonitor->Monitor2.pfnEnumPorts( pIniMonitor->hMonitor,
szName,
Level,
pPorts,
cbBuf,
pcbNeeded,
pcReturned );
}
return FALSE;
}
BOOL
DlOpenPort(
LPWSTR pName,
PHANDLE pHandle
)
{
WCHAR szName[MAX_PATH];
PINIMONITOR pIniMonitor;
if( GetDlPointers( pName, szName, &pIniMonitor, COUNTOF(szName) )){
return pIniMonitor->Monitor2.pfnOpenPort( pIniMonitor->hMonitor,
szName,
pHandle );
}
return FALSE;
}
BOOL
DlOpenPortEx(
LPWSTR pPortName,
LPWSTR pPrinterName,
PHANDLE pHandle,
struct _MONITOR FAR *pMonitor
)
{
SetLastError( ERROR_NOT_SUPPORTED );
return FALSE;
}
BOOL
DlAddPort(
LPWSTR pName,
HWND hWnd,
LPWSTR pMonitorName
)
{
WCHAR szName[MAX_PATH];
PINIMONITOR pIniMonitor;
if( GetDlPointers( pName, szName, &pIniMonitor, COUNTOF(szName) )){
return pIniMonitor->Monitor2.pfnAddPort( pIniMonitor->hMonitor,
szName,
hWnd,
pMonitorName );
}
return FALSE;
}
BOOL
DlAddPortEx(
LPWSTR pName,
DWORD Level,
LPBYTE pBuffer,
LPWSTR pMonitorName
)
{
WCHAR szName[MAX_PATH];
PINIMONITOR pIniMonitor;
if( GetDlPointers( pName, szName, &pIniMonitor, COUNTOF(szName) )){
return pIniMonitor->Monitor2.pfnAddPortEx( pIniMonitor->hMonitor,
pName,
Level,
pBuffer,
pMonitorName );
}
return FALSE;
}
BOOL
DlConfigurePort(
LPWSTR pName,
HWND hWnd,
LPWSTR pPortName
)
{
WCHAR szName[MAX_PATH];
PINIMONITOR pIniMonitor;
if( GetDlPointers( pName, szName, &pIniMonitor, COUNTOF(szName) )){
return pIniMonitor->Monitor2.pfnConfigurePort( pIniMonitor->hMonitor,
szName,
hWnd,
pPortName );
}
return FALSE;
}
BOOL
DlDeletePort(
LPWSTR pName,
HWND hWnd,
LPWSTR pPortName
)
{
WCHAR szName[MAX_PATH];
PINIMONITOR pIniMonitor;
if( GetDlPointers( pName, szName, &pIniMonitor, COUNTOF(szName) )){
return pIniMonitor->Monitor2.pfnDeletePort( pIniMonitor->hMonitor,
szName,
hWnd,
pPortName );
}
return FALSE;
}
FARPROC gafpDlStub[] = {
(FARPROC) &DlEnumPorts,
(FARPROC) &DlOpenPort,
(FARPROC) &DlOpenPortEx,
NULL, // StartDocPort
NULL, // WritePort
NULL, // ReadPort
NULL, // EndDocPort
NULL, // ClosePort
(FARPROC) &DlAddPort,
(FARPROC) &DlAddPortEx,
(FARPROC) &DlConfigurePort,
(FARPROC) &DlDeletePort,
NULL,
NULL,
};
VOID
InitializeUMonitor(
PINIMONITOR pIniMonitor
)
/*++
Routine Description:
Initialize an uplevel port monitor for downlevel support. When a
downlevel language monitor is used with an uplevel port monitor,
we need to setup stubs since the language monitor calls the port
monitor interfaces directly.
We create a downlevel function vector with patched entries and pass
it to the language monitor. The LM is passed in a formatted name
that has both the port name and also the pIniMonitor encoded in the
string.
Arguments:
pIniMonitor - Monitor to initialize.
Return Value:
--*/
{
FARPROC *pfpSrc;
FARPROC *pfpDest;
FARPROC *pfpStub;
INT i;
//
// Create the downlevel port monitor interface. This is
// used when we have a downlevel language monitor with an
// uplevel port monitor.
//
CopyMemory( (LPBYTE)&pIniMonitor->Monitor,
(LPBYTE)&pIniMonitor->Monitor2.pfnEnumPorts,
sizeof( pIniMonitor->Monitor ));
for( i=0,
pfpSrc = (FARPROC*)&pIniMonitor->Monitor2.pfnEnumPorts,
pfpDest = (FARPROC*)&pIniMonitor->Monitor,
pfpStub = gafpDlStub;
i < sizeof( pIniMonitor->Monitor )/sizeof( *pfpDest );
++i, ++pfpDest, ++pfpStub, ++pfpSrc ){
*pfpDest = *pfpStub ?
*pfpStub :
*pfpSrc;
}
}
/********************************************************************
Initialize a Downlevel language or port monitor.
********************************************************************/
//
// List of monitor functions for downlevel (3.51) monitors. Instead
// of receiving a function vector, the spooler has to call GetProcAddress
// on each of these functions. The order of these ports must be in the
// same format as the pMonitor2 structure.
//
LPCSTR aszMonitorFunction[] = {
"EnumPortsW",
"OpenPort",
NULL,
"StartDocPort",
"WritePort",
"ReadPort",
"EndDocPort",
"ClosePort",
"AddPortW",
"AddPortExW",
"ConfigurePortW",
"DeletePortW",
NULL,
NULL,
"XcvOpenPortW",
"XcvDataPortW",
"XcvClosePortW"
};
PINIMONITOR
InitializeDMonitor(
PINIMONITOR pIniMonitor,
LPWSTR pszRegistryRoot
)
/*++
Routine Description:
Initialize downlevel monitor.
Arguments:
pIniMonitor - Partially created pIniMonitor that needs to be initialized
with functions.
Return Value:
NULL - Initialization failed, but possibly because monitor could not
initialize. Still add monitor to spooler datastructures.
(PINIMONITOR)-1 - Failed.
--*/
{
BOOL (*pfnInitialize)(LPWSTR) = NULL;
BOOL (*pfnInitializeMonitorEx)(LPWSTR, LPMONITOR) = NULL;
LPMONITOREX (*pfnInitializePrintMonitor)(LPWSTR) = NULL;
LPMONITOREX pMonEx;
DWORD cbDpMonitor;
PINIMONITOR pReturnValue = (PINIMONITOR)-1;
//
// Try calling the entry points in the following order:
// InitializePrintMonitor,
// InitializeMonitorEx,
// InitializeMonitor
//
(FARPROC)pfnInitializePrintMonitor = GetProcAddress(
pIniMonitor->hModule,
"InitializePrintMonitor" );
if( !pfnInitializePrintMonitor ){
(FARPROC)pfnInitializeMonitorEx = GetProcAddress(
pIniMonitor->hModule,
"InitializeMonitorEx" );
if( !pfnInitializeMonitorEx ){
(FARPROC)pfnInitialize = GetProcAddress(
pIniMonitor->hModule,
"InitializeMonitor" );
}
}
if ( !pfnInitializePrintMonitor &&
!pfnInitializeMonitorEx &&
!pfnInitialize ) {
DBGMSG( DBG_WARNING,
( "InitializeDLPrintMonitor %ws GetProcAddress failed %d\n",
pszRegistryRoot,
GetLastError()));
} else {
BOOL bSuccess = FALSE;
LeaveSplSem();
if( pfnInitializePrintMonitor ) {
pMonEx = (*pfnInitializePrintMonitor)(pszRegistryRoot);
if( pMonEx ){
bSuccess = TRUE;
cbDpMonitor = pMonEx->dwMonitorSize;
CopyMemory((LPBYTE)&pIniMonitor->Monitor,
(LPBYTE)&pMonEx->Monitor,
min(pMonEx->dwMonitorSize, sizeof(MONITOR)));
}
} else if ( pfnInitializeMonitorEx ) {
bSuccess = (*pfnInitializeMonitorEx)( pszRegistryRoot,
&pIniMonitor->Monitor );
cbDpMonitor = sizeof(MONITOR);
} else {
INT i;
FARPROC* pfp;
bSuccess = (BOOL)((*pfnInitialize)(pszRegistryRoot));
cbDpMonitor = sizeof(MONITOR);
for( i=0, pfp=(FARPROC*)&pIniMonitor->Monitor;
i< COUNTOF( aszMonitorFunction );
++i, ++pfp ){
if( aszMonitorFunction[i] ){
*pfp = GetProcAddress( pIniMonitor->hModule,
aszMonitorFunction[i] );
}
}
}
EnterSplSem();
if( bSuccess ){
INT i;
INT iMax;
FARPROC* pfpSrc;
FARPROC* pfpDest;
FARPROC* pfpStub;
//
// Store away the pIniMonitor as the handle returned from the monitor.
// When we call the stub, it will cast it back to a pIniMonitor then
// use it to get to pIniMonitor->Monitor.fn.
//
pIniMonitor->hMonitor = (HANDLE)pIniMonitor;
//
// New size of the stub Monitor2 structure is the size of the
// downlevel monitor, plus the extra DWORD for Monitor2.cbSize.
//
pIniMonitor->Monitor2.cbSize = min( cbDpMonitor + sizeof( DWORD ),
sizeof( MONITOR2 ));
//
// The number of stub pointers we want to copy is the size of
// the struct, minus the extra DWORD that we added above.
//
iMax = (pIniMonitor->Monitor2.cbSize - sizeof( DWORD )) / sizeof( pfpSrc );
//
// We have copied the monitor entrypoints into the downlevel Monitor
// structure. Now we must run through the uplevel vector and fill
// it in with the stubs.
//
for( i=0,
pfpSrc = (FARPROC*)&pIniMonitor->Monitor,
pfpDest = (FARPROC*)&pIniMonitor->Monitor2.pfnEnumPorts,
pfpStub = (FARPROC*)gafpMonitor2Stub;
i< iMax;
++i, ++pfpSrc, ++pfpDest, ++pfpStub ){
if( *pfpSrc ){
//
// Stubs aren't needed for all routines. Only use them
// when they are needed; in other cases, just use the
// regular one.
//
*pfpDest = *pfpStub ?
*pfpStub :
*pfpSrc;
}
}
//
// Success, return the original pIniMonitor.
//
pReturnValue = pIniMonitor;
} else {
DBGMSG( DBG_WARNING,
( "InitializeDLPrintMonitor %ws Init failed %d\n",
pszRegistryRoot,
GetLastError()));
//
// Some old (before NT 4.0) monitors may not initialize until
// reboot.
//
if( pfnInitialize ){
pReturnValue = NULL;
}
}
}
return pReturnValue;
}