|
|
/*++
Copyright (c) 1990 - 1996 Microsoft Corporation
Module Name:
monitor.c
Abstract:
This module contains all code for Monitor-based Spooler apis
LocalEnumPorts LocalAddMonitor LocalDeleteMonitor LocalEnumMonitors LocalAddPort LocalConfigurePort LocalDeletePort
Support Functions in monitor.c - (Warning! Do Not Add to this list!!)
CopyIniMonitorToMonitor -- KrishnaG GetMonitorSize -- KrishnaG
Author:
Dave Snipp (DaveSn) 15-Mar-1991
Revision History: Khaled Sedky (khaleds) 15-March-2000 - Added LocalSendRecvBidiData
Muhunthan Sivapragasam (MuhuntS) 15-Jun-1995 - Port info 2 changes
Krishna Ganugapati (KrishnaG) 2-Feb-1994 - reorganized the entire source file
Matthew Felton (mattfe) June 1994 pIniSpooler
--*/
#include <precomp.h>
#include <offsets.h>
#include <clusspl.h>
//
// Private declarations
//
HDESK ghdeskServer = NULL;
//
// Function declarations
//
LPBYTE CopyIniMonitorToMonitor( PINIMONITOR pIniMonitor, DWORD Level, LPBYTE pMonitorInfo, LPBYTE pEnd );
DWORD GetMonitorSize( PINIMONITOR pIniMonitor, DWORD Level );
BOOL LocalEnumPorts( LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned ) { PINISPOOLER pIniSpooler; BOOL bReturn;
pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
if( !pIniSpooler ){ return ROUTER_UNKNOWN; }
bReturn = SplEnumPorts( pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned, pIniSpooler );
FindSpoolerByNameDecRef( pIniSpooler ); return bReturn; }
VOID SplReenumeratePorts( ) { LPVOID pBuf; DWORD cbNeeded, dwDontCare;
//
// EnumPorts checks for new ports enumerated by port monitors and updates
// localspl pIniPorts list
//
if ( !SplEnumPorts(NULL, 1, NULL, 0, &cbNeeded, &dwDontCare, pLocalIniSpooler) && GetLastError() == ERROR_INSUFFICIENT_BUFFER && (pBuf = AllocSplMem(cbNeeded)) ) {
SplEnumPorts(NULL, 1, pBuf, cbNeeded, &cbNeeded, &dwDontCare, pLocalIniSpooler); FreeSplMem(pBuf); } }
BOOL GetPortInfo2UsingPortInfo1( PINIMONITOR pIniMonitor, LPWSTR pName, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned ) {
BOOL bRet; LPPORT_INFO_1 pPortInfo1; LPPORT_INFO_2 pPortInfo2; DWORD cReturned;
bRet = (*pIniMonitor->Monitor2.pfnEnumPorts)( pIniMonitor->hMonitor, pName, 1, pPorts, cbBuf, pcbNeeded, pcReturned );
if ( !bRet ) {
//
// This is the upperbound
//
if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) *pcbNeeded += (*pcbNeeded / sizeof(PORT_INFO_1)) * (sizeof(PORT_INFO_2) - sizeof(PORT_INFO_1)); } else {
*pcbNeeded += *pcReturned * (sizeof(PORT_INFO_2) - sizeof(PORT_INFO_1));
if ( *pcbNeeded <= cbBuf ) {
cReturned = *pcReturned; while ( cReturned-- ) {
pPortInfo1 = (LPPORT_INFO_1) (pPorts + cReturned * sizeof(PORT_INFO_1)); pPortInfo2 = (LPPORT_INFO_2) (pPorts + cReturned * sizeof(PORT_INFO_2));
pPortInfo2->pPortName = pPortInfo1->pName; pPortInfo2->pMonitorName = NULL; pPortInfo2->pDescription = NULL; pPortInfo2->fPortType = 0; pPortInfo2->Reserved = 0; } } else {
*pcReturned = 0; bRet = FALSE; SetLastError(ERROR_INSUFFICIENT_BUFFER); } }
return bRet; }
BOOL SplEnumPorts( LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned, PINISPOOLER pIniSpooler ) { PINIMONITOR pIniMonitor; DWORD dwIndex, cReturned=0, cbStruct, TotalcbNeeded=0; LPBYTE pBuffer = pPorts, pTemp; DWORD Error=0, TempError = 0; DWORD BufferSize=cbBuf; LPWSTR pPortName; PINIPORT pIniPort; HANDLE hToken; BOOL bRemoteCall = FALSE;
if (!MyName( pName, pIniSpooler )) {
return FALSE; }
//
// HACK: Some monitors choke if pName is non-NULL. We can make
// it NULL at this point since we know that we're using the same
// ports on the local machine.
//
pName = NULL;
if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER, SERVER_ACCESS_ENUMERATE, NULL, NULL, pIniSpooler )) {
return FALSE; }
switch (Level) {
case 1: cbStruct = sizeof(PORT_INFO_1); break;
case 2: cbStruct = sizeof(PORT_INFO_2); break;
default: return ERROR_INVALID_LEVEL; }
{ HRESULT hRes = CheckLocalCall();
if (hRes == S_FALSE) { bRemoteCall = TRUE; } else if (hRes != S_OK) { SetLastError(SCODE_CODE(hRes)); return FALSE; } }
//
// We revert to local system context only when the caller is remote.
// The monitors may load dlls from system32 and remote users like
// guest or anonymous logon do not have sufficient privileges for that.
// This is safe to revert to self since we do not support delegation, so
// we will never use the credentials of the remote user to go remote again.
// If the caller is logged on interactively, then we do not switch the
// context. Thus, a monitor may be able to go on the network for the port
// enumeration.
//
if (bRemoteCall && !(hToken = RevertToPrinterSelf())) { return FALSE; }
for ( pIniMonitor = pIniSpooler->pIniMonitor ; pIniMonitor ; pIniMonitor = pIniMonitor->pNext ) {
//
// Lang monitor does not have to define this
//
if ( !pIniMonitor->Monitor2.pfnEnumPorts ) continue;
*pcReturned = 0;
*pcbNeeded = 0;
if (!(*pIniMonitor->Monitor2.pfnEnumPorts)( pIniMonitor->hMonitor, pName, Level, pPorts, BufferSize, pcbNeeded, pcReturned)) {
TempError = GetLastError(); //
// Level 2 is a superset of level 1. So we can make a level 1
// call if the monitor does not support it
//
if ( Level == 2 && TempError == ERROR_INVALID_LEVEL ) {
TempError = 0; if ( !GetPortInfo2UsingPortInfo1(pIniMonitor, pName, pPorts, BufferSize, pcbNeeded, pcReturned) ) TempError = GetLastError(); }
if ( TempError ) {
Error = TempError;
*pcReturned = 0;
if ( TempError != ERROR_INSUFFICIENT_BUFFER ) {
*pcbNeeded = 0; break; } } } else {
//
// Now we look for new ports not in pIniPort list and add them
//
EnterSplSem();
for ( dwIndex = 0, pTemp = pPorts ; dwIndex < *pcReturned ; ++dwIndex ) {
switch ( Level ) {
case 1: pPortName = ((LPPORT_INFO_1)pTemp)->pName; pTemp += sizeof(PORT_INFO_1); break;
case 2: pPortName = ((LPPORT_INFO_2)pTemp)->pPortName; pTemp += sizeof(PORT_INFO_2); break;
default: SPLASSERT(Level == 1 || Level == 2); }
pIniPort = FindPort(pPortName, pIniSpooler); if ( !pIniPort ) { CreatePortEntry(pPortName, pIniMonitor, pIniSpooler);
} else if ( !pIniPort->pIniMonitor ) { //
// If a fake port gets eventually enumerated by a monitor,
// update the pIniPort structure (USB monitor). It is no
// longer a placeholder port at this point.
//
pIniPort->pIniMonitor = pIniMonitor; pIniPort->Status |= PP_MONITOR; pIniPort->Status &= ~PP_PLACEHOLDER; } }
LeaveSplSem(); }
cReturned += *pcReturned;
pPorts += *pcReturned * cbStruct;
if (*pcbNeeded <= BufferSize) BufferSize -= *pcbNeeded; else BufferSize = 0;
TotalcbNeeded += *pcbNeeded; }
if (bRemoteCall) { ImpersonatePrinterClient(hToken); }
*pcbNeeded = TotalcbNeeded;
*pcReturned = cReturned;
if (Error) {
SetLastError(Error); return FALSE; } else if (TotalcbNeeded > cbBuf ) {
SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } else {
//
// Stop routing if this is a cluster'd spooler. Otherwise,
// we'll talk to win32spl, which RPCs to us again.
//
if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){ return ROUTER_STOP_ROUTING; } return TRUE; } }
BOOL LocalEnumMonitors( LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned ) { PINISPOOLER pIniSpooler; BOOL bReturn;
pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
if( !pIniSpooler ){ return ROUTER_UNKNOWN; }
bReturn = SplEnumMonitors( pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned, pIniSpooler );
FindSpoolerByNameDecRef( pIniSpooler ); return bReturn; }
BOOL SplEnumMonitors( LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned, PINISPOOLER pIniSpooler ) { PINIMONITOR pIniMonitor; DWORD cReturned=0, cbStruct, cb; LPBYTE pBuffer = pMonitors; DWORD BufferSize=cbBuf, rc; LPBYTE pEnd;
if (!MyName( pName, pIniSpooler )) {
return ROUTER_UNKNOWN; }
if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER, SERVER_ACCESS_ENUMERATE, NULL, NULL, pIniSpooler )) {
return ROUTER_UNKNOWN; }
switch (Level) {
case 1: cbStruct = sizeof(MONITOR_INFO_1); break;
case 2: cbStruct = sizeof(MONITOR_INFO_2); break;
default: SetLastError(ERROR_INVALID_LEVEL); return ROUTER_UNKNOWN; }
EnterSplSem();
for ( cb = 0, pIniMonitor = pIniSpooler->pIniMonitor ; pIniMonitor ; pIniMonitor = pIniMonitor->pNext ) {
//
// We'll not enumerate monitors which do not support AddPort
//
if ( pIniMonitor->Monitor2.pfnAddPort || pIniMonitor->Monitor2.pfnXcvOpenPort) cb+=GetMonitorSize(pIniMonitor, Level); }
*pcbNeeded = cb; *pcReturned = 0;
if (cb <= cbBuf) {
pEnd=pMonitors + cbBuf;
for ( pIniMonitor = pIniSpooler->pIniMonitor ; pIniMonitor ; pIniMonitor = pIniMonitor->pNext ) {
//
// We'll not enumerate monitors which do not support AddPort
//
if ( !pIniMonitor->Monitor2.pfnAddPort && !pIniMonitor->Monitor2.pfnXcvOpenPort ) continue;
pEnd = CopyIniMonitorToMonitor(pIniMonitor, Level, pMonitors, pEnd);
switch (Level) {
case 1: pMonitors+=sizeof(MONITOR_INFO_1); break;
case 2: pMonitors+=sizeof(MONITOR_INFO_2); break; }
(*pcReturned)++; }
if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
//
// Stop routing, since we don't want any one else to report
// back monitors. If we're on the local machine now and
// we continue routing, win32spl will RPC back to ourself
// and re-enumerate the same ports.
//
rc = ROUTER_STOP_ROUTING;
} else {
rc = ROUTER_SUCCESS; }
} else {
rc = ROUTER_UNKNOWN; SetLastError(ERROR_INSUFFICIENT_BUFFER); }
LeaveSplSem();
return rc; }
BOOL LocalAddPort( LPWSTR pName, HWND hWnd, LPWSTR pMonitorName ) { PINISPOOLER pIniSpooler; BOOL bReturn;
pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
if( !pIniSpooler ){ return ROUTER_UNKNOWN; }
bReturn = SplAddPort( pName, hWnd, pMonitorName, pIniSpooler );
FindSpoolerByNameDecRef( pIniSpooler ); return bReturn; }
BOOL SplAddPort( LPWSTR pName, HWND hWnd, LPWSTR pMonitorName, PINISPOOLER pIniSpooler ) { PINIMONITOR pIniMonitor; BOOL rc=FALSE;
if (!MyName( pName, pIniSpooler )) {
return FALSE; }
if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL, pIniSpooler )) {
return FALSE; }
EnterSplSem(); SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE ); pIniMonitor = FindMonitor(pMonitorName, pIniSpooler);
//
// The monitor could be deleted while we are adding a port.
//
if (pIniMonitor) { INCMONITORREF(pIniMonitor); }
LeaveSplSem();
if ( pIniMonitor ) {
if ( pIniMonitor->Monitor2.pfnAddPort ) rc = (*pIniMonitor->Monitor2.pfnAddPort)( pIniMonitor->hMonitor, pName, hWnd, pMonitorName ); else SetLastError(ERROR_INVALID_PARAMETER); } else {
SetLastError(ERROR_INVALID_NAME); }
if (rc) rc = AddPortToSpooler(pName, pIniMonitor, pIniSpooler);
EnterSplSem();
if (pIniMonitor) { DECMONITORREF(pIniMonitor); }
LeaveSplSem();
return rc; }
BOOL AddPortToSpooler( PCWSTR pName, PINIMONITOR pIniMonitor, PINISPOOLER pIniSpooler ) { DWORD i, cbNeeded, cbDummy, cReturned; PPORT_INFO_1 pPorts; PINIPORT pIniPort;
/* If we don't already have the port in our local cache, add it:
*/ if (!(*pIniMonitor->Monitor2.pfnEnumPorts)( pIniMonitor->hMonitor, (PWSTR)pName, 1, NULL, 0, &cbNeeded, &cReturned)) {
pPorts = AllocSplMem(cbNeeded);
if (pPorts) {
if ((*pIniMonitor->Monitor2.pfnEnumPorts)( pIniMonitor->hMonitor, (PWSTR)pName, 1, (LPBYTE)pPorts, cbNeeded, &cbDummy, &cReturned)) {
EnterSplSem();
for (i = 0 ; i < cReturned ; ++i) {
pIniPort = FindPort(pPorts[i].pName, pIniSpooler); if ( !pIniPort ) { CreatePortEntry(pPorts[i].pName, pIniMonitor, pIniSpooler);
//
// If we have a port without a monitor and it gets added at
// this time. Remove the placeholder status from it.
//
} else if ( !pIniPort->pIniMonitor ) { pIniPort->pIniMonitor = pIniMonitor; pIniPort->Status |= PP_MONITOR; pIniPort->Status &= ~PP_PLACEHOLDER; } }
LeaveSplSem(); }
FreeSplMem(pPorts); } }
EnterSplSem(); SetPrinterChange(NULL, NULL, NULL, PRINTER_CHANGE_ADD_PORT, pIniSpooler); LeaveSplSem();
return TRUE; }
BOOL LocalConfigurePort( LPWSTR pName, HWND hWnd, LPWSTR pPortName ) { PINISPOOLER pIniSpooler; BOOL bReturn;
pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
if( !pIniSpooler ){ return ROUTER_UNKNOWN; }
bReturn = SplConfigurePort( pName, hWnd, pPortName, pIniSpooler );
FindSpoolerByNameDecRef( pIniSpooler ); return bReturn; }
BOOL SplConfigurePort( LPWSTR pName, HWND hWnd, LPWSTR pPortName, PINISPOOLER pIniSpooler ) { PINIPORT pIniPort; BOOL rc = FALSE;
if (!MyName( pName, pIniSpooler )) {
return FALSE; }
if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL, pIniSpooler )) {
return FALSE; }
EnterSplSem();
pIniPort = FindPort(pPortName, pIniSpooler);
//
// Port could be deleted while we are configuring it.
//
if (pIniPort) { INCPORTREF(pIniPort); }
LeaveSplSem();
if ((pIniPort) && (pIniPort->Status & PP_MONITOR)) {
if ( !pIniPort->pIniMonitor->Monitor2.pfnConfigurePort ) {
SetLastError(ERROR_NOT_SUPPORTED); } else if (rc = (*pIniPort->pIniMonitor->Monitor2.pfnConfigurePort)( pIniPort->pIniMonitor->hMonitor, pName, hWnd, pPortName)) {
EnterSplSem();
SetPrinterChange(NULL, NULL, NULL, PRINTER_CHANGE_CONFIGURE_PORT, pIniSpooler); LeaveSplSem(); } } else {
SetLastError(ERROR_UNKNOWN_PORT); }
EnterSplSem();
if (pIniPort) {
DECPORTREF(pIniPort); }
LeaveSplSem();
return rc; }
BOOL LocalDeletePort( LPWSTR pName, HWND hWnd, LPWSTR pPortName ) { PINISPOOLER pIniSpooler; BOOL bReturn;
pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
if( !pIniSpooler ){ return ROUTER_UNKNOWN; }
bReturn = SplDeletePort( pName, hWnd, pPortName, pIniSpooler );
FindSpoolerByNameDecRef( pIniSpooler ); return bReturn; }
BOOL SplDeletePort( LPWSTR pName, HWND hWnd, LPWSTR pPortName, PINISPOOLER pIniSpooler ) { PINIPORT pIniPort; BOOL rc=FALSE;
if (!MyName( pName, pIniSpooler )) {
return FALSE; }
if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL, pIniSpooler )) {
return FALSE; }
EnterSplSem();
pIniPort = FindPort(pPortName, pIniSpooler);
if ( !pIniPort || !(pIniPort->Status & PP_MONITOR) ) { LeaveSplSem(); SetLastError(ERROR_UNKNOWN_PORT); return FALSE; }
if( !pIniPort->pIniMonitor->Monitor2.pfnDeletePort ){ LeaveSplSem(); SetLastError( ERROR_NOT_SUPPORTED ); return FALSE; }
rc = DeletePortFromSpoolerStart( pIniPort );
LeaveSplSem();
if (!rc) goto Cleanup;
rc = (*pIniPort->pIniMonitor->Monitor2.pfnDeletePort)( pIniPort->pIniMonitor->hMonitor, pName, hWnd, pPortName);
rc = DeletePortFromSpoolerEnd(pIniPort, pIniSpooler, rc);
Cleanup: SplOutSem(); return rc; }
BOOL DeletePortFromSpoolerEnd( PINIPORT pIniPort, PINISPOOLER pIniSpooler, BOOL bSuccess ) {
EnterSplSem();
if(bSuccess) {
DeletePortEntry( pIniPort );
//
// Success, delete the port data and send a notification.
//
SetPrinterChange( NULL, NULL, NULL, PRINTER_CHANGE_DELETE_PORT, pIniSpooler ); } else {
//
// Add it back. If the name is already used (e.g., just added
// while we were out of the critical section), we're in trouble,
// but there's not much we can do about it. (When we restart,
// we'll re-enumerate the duplicate name from the monitors
// anyway.)
//
DBGMSG( DBG_WARN, ( "SplDeletePort: port.DeletePort failed %d\n", GetLastError())); LinkPortToSpooler( pIniPort, pIniSpooler ); }
LeaveSplSem(); SplOutSem();
return bSuccess; }
BOOL DeletePortFromSpoolerStart( PINIPORT pIniPort ) { BOOL rc = FALSE; PINISPOOLER pIniSpooler = pIniPort->pIniSpooler;
SplInSem();
if ( pIniPort->cPrinters || pIniPort->cRef || pIniPort->cJobs ) {
SetLastError(ERROR_BUSY); goto Cleanup; }
//
// Remove it from the linked list so that no one will try to grab
// a reference to while we're deleting it.
//
DelinkPortFromSpooler( pIniPort, pIniSpooler ); rc = TRUE;
Cleanup:
return rc; }
BOOL LocalAddMonitor( LPWSTR pName, DWORD Level, LPBYTE pMonitorInfo ) { PINISPOOLER pIniSpooler; BOOL bReturn;
pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
if( !pIniSpooler ){ return ROUTER_UNKNOWN; }
bReturn = SplAddMonitor( pName, Level, pMonitorInfo, pIniSpooler );
FindSpoolerByNameDecRef( pIniSpooler ); return bReturn; }
BOOL SplAddMonitor( LPWSTR pName, DWORD Level, LPBYTE pMonitorInfo, PINISPOOLER pIniSpooler ) { PINIMONITOR pIniMonitor; PMONITOR_INFO_2 pMonitor = (PMONITOR_INFO_2)pMonitorInfo; HANDLE hToken; HKEY hKey; LONG Status; BOOL rc = FALSE; DWORD dwPathLen = 0;
if (!MyName( pName, pIniSpooler )) {
return FALSE; }
if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL, pIniSpooler )) {
return FALSE; }
if (Level != 2) {
SetLastError( ERROR_INVALID_LEVEL ); return FALSE; }
if (!pMonitor || !pMonitor->pName || !*pMonitor->pName) {
SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; }
if (!pMonitor->pEnvironment || !*pMonitor->pEnvironment || lstrcmpi(pMonitor->pEnvironment, szEnvironment)) {
SetLastError( ERROR_INVALID_ENVIRONMENT ); return FALSE; }
if (!pMonitor->pDLLName || !*pMonitor->pDLLName ){
SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; }
EnterSplSem();
if (FindMonitor(pMonitor->pName, pIniSpooler)) {
LeaveSplSem(); SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED); return FALSE; }
hToken = RevertToPrinterSelf();
pIniMonitor = CreateMonitorEntry(pMonitor->pDLLName, pMonitor->pName, pIniSpooler);
if (pIniMonitor != (PINIMONITOR)-1) {
WCHAR szRegistryRoot[MAX_PATH]; PINISPOOLER pIniSpoolerMonitor; HANDLE hKeyOut; LPCWSTR pszPathOut;
//
// Note that even though this is built once per pIniSpooler, the
// list of monitors is the same for all spoolers. However, the
// ports that the monitor returns from EnumPorts is different for
// each pIniSpooler (for clustering).
//
// If it's not local, then it could be a cached win32 monitor.
//
if( pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL ){ pIniSpoolerMonitor = pLocalIniSpooler; } else { pIniSpoolerMonitor = pIniSpooler; }
//
// Build the registry path. In some cases it's a relative
// path from hckRoot; other times it's a hard coded path from
// HKLM (e.g., win32spl).
//
GetRegistryLocation( pIniSpoolerMonitor->hckRoot, pIniSpoolerMonitor->pszRegistryMonitors, &hKeyOut, &pszPathOut );
Status = StrNCatBuff( szRegistryRoot, COUNTOF(szRegistryRoot), pszPathOut, L"\\", pMonitor->pName, NULL );
if (Status == ERROR_SUCCESS) {
Status = RegCreateKeyEx( hKeyOut, szRegistryRoot, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL );
if (Status == ERROR_SUCCESS) {
Status = RegSetValueEx( hKey, L"Driver", 0, REG_SZ, (LPBYTE)pMonitor->pDLLName, (wcslen(pMonitor->pDLLName) + 1)*sizeof(WCHAR));
if (Status == ERROR_SUCCESS) { rc = TRUE; } else { SetLastError( Status ); }
RegCloseKey(hKey);
} else { SetLastError( Status ); } } else { SetLastError(Status); }
}
if(!ImpersonatePrinterClient(hToken)) { rc = FALSE; }
//
// Bug 54843 if this fails we could still have a IniMonitor on the linked list that
// is BAD, it should be removed.
// Note *maybe* we do this because a monitor might fail to initialize
// but will correctly function next time you reboot, like hpmon ( dlc doesn't become active until
// the next reboot. Please Verify.
LeaveSplSem();
if ( !rc ) { DBGMSG( DBG_WARNING, ("SplAddMonitor failed %d\n", GetLastError() )); }
return rc; }
BOOL LocalDeleteMonitor( LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName ) { PINISPOOLER pIniSpooler; BOOL bReturn;
pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
if( !pIniSpooler ){ return ROUTER_UNKNOWN; }
bReturn = SplDeleteMonitor( pName, pEnvironment, pMonitorName, pIniSpooler );
FindSpoolerByNameDecRef( pIniSpooler ); return bReturn; }
BOOL SplDeleteMonitor( LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName, PINISPOOLER pIniSpooler ) { BOOL Remote=FALSE; PINIMONITOR pIniMonitor; PINIPORT pIniPort, pIniPortNext; HKEY hKeyMonitors, hKey; LONG Status; BOOL rc = FALSE; HANDLE hToken; HANDLE hKeyOut; LPCWSTR pszPathOut;
if (pName && *pName) {
if (!MyName( pName, pIniSpooler )) {
return FALSE;
} else {
Remote=TRUE; } }
if ((pMonitorName == NULL) || (*pMonitorName == L'\0')) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }
if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL, pIniSpooler )) {
return FALSE; }
EnterSplSem();
if (!(pIniMonitor=(PINIMONITOR)FindMonitor(pMonitorName, pIniSpooler))) {
SetLastError(ERROR_UNKNOWN_PRINT_MONITOR); LeaveSplSem(); return FALSE; }
if ( pIniMonitor->cRef ) {
SetLastError(ERROR_PRINT_MONITOR_IN_USE); LeaveSplSem(); return FALSE; }
pIniPort = pIniSpooler->pIniPort;
while (pIniPort) {
if ((pIniPort->pIniMonitor == pIniMonitor) && (pIniPort->cPrinters || pIniPort->cRef)) {
SetLastError(ERROR_BUSY); LeaveSplSem(); return FALSE; }
pIniPort = pIniPort->pNext; }
hToken = RevertToPrinterSelf();
GetRegistryLocation( pIniSpooler->hckRoot, pIniSpooler->pszRegistryMonitors, &hKeyOut, &pszPathOut );
Status = SplRegOpenKey(hKeyOut, pszPathOut, KEY_READ | KEY_WRITE | DELETE, &hKeyMonitors, pIniSpooler);
if (Status == ERROR_SUCCESS) { Status = SplRegOpenKey(hKeyMonitors, pMonitorName, KEY_READ | KEY_WRITE, &hKey, pIniSpooler);
if (Status == ERROR_SUCCESS) { Status = DeleteSubkeys(hKey, pIniSpooler);
SplRegCloseKey(hKey, pIniSpooler);
if (Status == ERROR_SUCCESS) Status = SplRegDeleteKey(hKeyMonitors, pMonitorName, pIniSpooler); }
SplRegCloseKey(hKeyMonitors, pIniSpooler); }
if (Status == ERROR_SUCCESS) {
pIniPort = pIniSpooler->pIniPort;
while (pIniPort) {
pIniPortNext = pIniPort->pNext;
if (pIniPort->pIniMonitor == pIniMonitor) DeletePortEntry(pIniPort);
pIniPort = pIniPortNext; }
RemoveFromList((PINIENTRY *)&pIniSpooler->pIniMonitor, (PINIENTRY)pIniMonitor);
FreeIniMonitor( pIniMonitor );
rc = TRUE;
}
if (Status != ERROR_SUCCESS) SetLastError(Status);
if(!ImpersonatePrinterClient(hToken)) { rc = FALSE; }
LeaveSplSem();
return rc; }
LPBYTE CopyIniMonitorToMonitor( PINIMONITOR pIniMonitor, DWORD Level, LPBYTE pMonitorInfo, LPBYTE pEnd ) { LPWSTR *pSourceStrings, *SourceStrings; DWORD j; DWORD *pOffsets;
switch (Level) {
case 1: pOffsets = MonitorInfo1Strings; break;
case 2: pOffsets = MonitorInfo2Strings; break;
default: return pEnd; }
for (j=0; pOffsets[j] != -1; j++) { }
SourceStrings = pSourceStrings = AllocSplMem(j * sizeof(LPWSTR));
if (!SourceStrings) { DBGMSG(DBG_WARNING, ("Failed to alloc Port source strings.\n")); return pEnd; }
switch (Level) {
case 1: *pSourceStrings++=pIniMonitor->pName; break;
case 2: *pSourceStrings++=pIniMonitor->pName; *pSourceStrings++=szEnvironment; *pSourceStrings++=pIniMonitor->pMonitorDll; break; }
pEnd = PackStrings(SourceStrings, pMonitorInfo, pOffsets, pEnd); FreeSplMem(SourceStrings);
return pEnd; }
DWORD GetMonitorSize( PINIMONITOR pIniMonitor, DWORD Level ) { DWORD cb=0;
switch (Level) {
case 1: cb=sizeof(MONITOR_INFO_1) + wcslen(pIniMonitor->pName)*sizeof(WCHAR) + sizeof(WCHAR); break;
case 2: cb = wcslen(pIniMonitor->pName) + 1 + wcslen(pIniMonitor->pMonitorDll) + 1 + wcslen(szEnvironment) + 1; cb *= sizeof(WCHAR); cb += sizeof(MONITOR_INFO_2); break;
default:
cb = 0; break; }
return cb; }
BOOL LocalAddPortEx( LPWSTR pName, DWORD Level, LPBYTE pBuffer, LPWSTR pMonitorName ) { return ( SplAddPortEx( pName, Level, pBuffer, pMonitorName,
pLocalIniSpooler )); }
BOOL SplAddPortEx( LPWSTR pName, DWORD Level, LPBYTE pBuffer, LPWSTR pMonitorName, PINISPOOLER pIniSpooler ) { PINIMONITOR pIniMonitor; BOOL rc=FALSE; DWORD i, cbNeeded, cReturned, cbDummy; PPORT_INFO_1 pPorts = NULL; PINIPORT pIniPort;
SplOutSem();
//
// At this time we do not know if the server name in pName refers to our local
// machine. We are trying to add the server name to the name cache. The name
// cache functions decide if the name refers to the local machine and if positive,
// add an entry for it in the cache.
//
CacheAddName(pName);
if (!MyName( pName, pIniSpooler )) {
return FALSE; }
if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER, SERVER_ACCESS_ADMINISTER, NULL, NULL, pIniSpooler )) {
return FALSE; }
EnterSplSem(); pIniMonitor = FindMonitor(pMonitorName, pIniSpooler); LeaveSplSem();
if (!pIniMonitor) { SetLastError(ERROR_INVALID_NAME); return(FALSE); }
if (pIniMonitor->Monitor2.pfnAddPortEx) { rc = (*pIniMonitor->Monitor2.pfnAddPortEx)( pIniMonitor->hMonitor, pName, Level, pBuffer, pMonitorName); } if (!rc) { return(FALSE); }
if (!(*pIniMonitor->Monitor2.pfnEnumPorts)( pIniMonitor->hMonitor, pName, 1, NULL, 0, &cbNeeded, &cReturned)) {
pPorts = AllocSplMem(cbNeeded); }
if (pPorts) { if ((*pIniMonitor->Monitor2.pfnEnumPorts)( pIniMonitor->hMonitor, pName, 1, (LPBYTE)pPorts, cbNeeded, &cbDummy, &cReturned)) {
EnterSplSem();
for (i = 0; i < cReturned; i++) {
pIniPort = FindPort(pPorts[i].pName, pIniSpooler); if ( !pIniPort ) { CreatePortEntry(pPorts[i].pName, pIniMonitor, pIniSpooler);
} else if ( !pIniPort->pIniMonitor ) { pIniPort->pIniMonitor = pIniMonitor; pIniPort->Status |= PP_MONITOR; } } LeaveSplSem(); }
FreeSplMem(pPorts); }
EnterSplSem(); SetPrinterChange(NULL, NULL, NULL, PRINTER_CHANGE_ADD_PORT, pIniSpooler); LeaveSplSem();
return rc; }
VOID LinkPortToSpooler( PINIPORT pIniPort, PINISPOOLER pIniSpooler )
/*++
Routine Description:
Links a pIniPort onto the pIniSpooler.
Arguments:
pIniPort - Port to link; must not already be on a ll.
pIniSpooler - Provides ll for pIniPort.
Return Value:
--*/
{ SplInSem(); SPLASSERT( !pIniPort->pIniSpooler );
pIniPort->pNext = pIniSpooler->pIniPort; pIniPort->pIniSpooler = pIniSpooler; pIniSpooler->pIniPort = pIniPort; }
VOID DelinkPortFromSpooler( PINIPORT pIniPort, PINISPOOLER pIniSpooler )
/*++
Routine Description:
Remove a pIniPort from a pIniSpooler->pIniPort linked list. The pIniPort may or may not be on the list; if it isn't, then this routine does nothing.
Generic delink code ripped out into a subroutine.
The refcount on pIniPort must be zero. Anyone that uses pIniPort must hold a reference, since it may be deleted outside the SplSem when cRef==0.
Arguments:
pIniPort - Port to delink from the list. May or may not be on pIniSpooler->pIniPort.
pIniSpooler - Linked list from which the pIniPort will be removed.
Return Value:
--*/
{ PINIPORT *ppCurPort;
SplInSem(); SPLASSERT( !pIniPort->cRef );
//
// Keep searching for pIniPort until we hit the end of the
// list or we've found it.
//
for( ppCurPort = &pIniSpooler->pIniPort; *ppCurPort && *ppCurPort != pIniPort; ppCurPort = &((*ppCurPort)->pNext )){
; // Don't do anything.
}
//
// If we found it, delink it.
//
if( *ppCurPort ){ *ppCurPort = (*ppCurPort)->pNext;
//
// Null out the back pointer since we have removed it from
// the pIniSpooler.
//
pIniPort->pIniSpooler = NULL; } }
/*++
Function Name: LocalSendRecvBidiData
Description: This function is the providor point of communicating with Monitors supporting BIDI data. It allows the providor to set data in the printer and query data from the printer
Parameters: hPrinter : This could be a Printer/Port Handle dwAccessBit : Priverledges allowed to the accessing thread pAction : pReqData : Request encapsulatig the queries in an array ppResData : Response returned to client in an array of Data
Return Value: Win32 Error Code --*/
DWORD LocalSendRecvBidiData( IN HANDLE hPrinter, IN LPCTSTR pAction, IN PBIDI_REQUEST_CONTAINER pReqData, OUT PBIDI_RESPONSE_CONTAINER* ppResData ) { DWORD dwRet = ERROR_SUCCESS; PSPOOL pSpool = (PSPOOL)hPrinter; PINIPORT pIniPort = NULL; PINIMONITOR pIniMonitor = NULL; PINIMONITOR pIniLangMonitor = NULL; PINIPRINTER pIniPrinter = NULL; LPTSTR pszPrinter = NULL; TCHAR szFullPrinter[ MAX_UNC_PRINTER_NAME ];
EnterSplSem(); //
// Process of validating the parameters
//
if((!pAction || !*pAction) || (!pReqData && !ppResData)) { dwRet = ERROR_INVALID_PARAMETER; } else { if (!ValidateSpoolHandle( pSpool, PRINTER_HANDLE_SERVER )) { dwRet = ERROR_INVALID_HANDLE; } else { if(pSpool->TypeofHandle & PRINTER_HANDLE_PRINTER) { if ((pIniPrinter = pSpool->pIniPrinter) && (pIniPort = FindIniPortFromIniPrinter(pIniPrinter)) && (pIniPort->Status & PP_MONITOR)) { pIniLangMonitor = pIniPrinter->pIniDriver->pIniLangMonitor;
if (pIniLangMonitor && !pIniLangMonitor->Monitor2.pfnSendRecvBidiDataFromPort) { pIniLangMonitor = NULL; } if (pIniPrinter->pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER) { pszPrinter = szFullPrinter;
dwRet = StatusFromHResult(StringCchPrintf(szFullPrinter, COUNTOF(szFullPrinter), L"%ws\\%ws", pIniPrinter->pIniSpooler->pMachineName, pIniPrinter->pName)); } else { pszPrinter = pIniPrinter->pName; } } else { dwRet = ERROR_INVALID_HANDLE; } } else if(pSpool->TypeofHandle & PRINTER_HANDLE_PORT && (pSpool->pIniPort->Status & PP_MONITOR)) { pIniPort = pSpool->pIniPort; } else { dwRet = ERROR_INVALID_HANDLE; }
if (dwRet == ERROR_SUCCESS) { //
// Port always must be opened
//
dwRet = StatusFromHResult(OpenMonitorPort(pIniPort, pIniLangMonitor, pszPrinter));
if (dwRet == ERROR_SUCCESS) { pIniMonitor = GetOpenedMonitor(pIniPort);
//
// Calling into the monitor
//
if(pIniMonitor->Monitor2.pfnSendRecvBidiDataFromPort) { LeaveSplSem(); SplOutSem();
dwRet = (*pIniMonitor->Monitor2.pfnSendRecvBidiDataFromPort)(GetMonitorHandle(pIniPort), pSpool->GrantedAccess, pAction, pReqData, ppResData); EnterSplSem(); } else { //
// Here we could use a simulation code;
//
dwRet = ERROR_NOT_SUPPORTED; } ReleaseMonitorPort(pIniPort); } } } }
LeaveSplSem();
return(dwRet); }
|