Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

3056 lines
76 KiB

/*++
Copyright (c) 1994 - 1996 Microsoft Corporation
Module Name:
cache.c
Abstract:
This module contains all the Cache Printer Connection for
true Connected Printers.
Author:
Matthew A Felton ( MattFe ) June 1994
Revision History:
June 1994 - Created.
May 1996 - Modified RefreshDriverDataCache to use EnumPrinterData (SWilson)
--*/
#include <windows.h>
#include <winspool.h>
#include <winsplp.h>
#include <lm.h>
#include <stdio.h>
#include <string.h>
#include <rpc.h>
#include <drivinit.h>
#include <offsets.h>
#include <w32types.h>
#include <splcom.h>
#include <local.h>
#include <search.h>
#include <splapip.h>
#include <winerror.h>
#include <gdispool.h>
PWCHAR pszRaw = L"RAW";
PWCHAR szWin32SplDirectory = L"\\spool";
PWCHAR pszRegistryWin32Root = L"System\\CurrentControlSet\\Control\\Print\\Providers\\LanMan Print Services\\Servers";
PWCHAR pszPrinters = L"\\Printers";
PWCHAR pszRegistryMonitors = L"System\\CurrentControlSet\\Control\\Print\\Providers\\LanMan Print Services\\Monitors";
PWCHAR pszRegistryEnvironments = L"System\\CurrentControlSet\\Control\\Print\\Providers\\LanMan Print Services\\Environments";
PWCHAR pszRegistryEventLog = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\System\\Print";
PWCHAR pszRegistryProviders = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Providers\\LanMan Print Services\\Providers";
PWCHAR pszEventLogMsgFile = L"%SystemRoot%\\System32\\Win32Spl.dll";
PWCHAR pszDriversShareName = L"wn32prt$";
PWCHAR pszForms = L"\\Forms";
PWCHAR pszMyDllName = L"win32spl.dll";
PWCHAR pszMonitorName = L"LanMan Print Services Port";
PWSPOOL pFirstWSpool = NULL;
WCHAR *szCachePrinterInfo2 = L"CachePrinterInfo2";
WCHAR *szCacheTimeLastChange = L"CacheChangeID";
WCHAR *szServerVersion = L"ServerVersion";
WCHAR *szcRef = L"CacheReferenceCount";
//
// If we have an rpc handle created recently don't hit the net
//
#define REFRESH_TIMEOUT 15000 // 15 seconds
VOID
RefreshDriverEvent(
PWSPOOL pSpool
)
/*++
Routine Description:
Call out to the Printer Driver UI DLL to allow it to do any caching it might want to do.
For example there might be a large FONT metric file on the print server which is too large
to be written to the registry using SetPrinterData(). This callout will allow the printer
driver to copy this font file to the workstation when the cache is established and will
allow it to periodically check that the file is still valid.
Arguments:
pSpool - Handle to remote printer.
Return Value:
None
--*/
{
SplOutSem();
SplDriverEvent( pSpool->pName, PRINTER_EVENT_CACHE_REFRESH, (LPARAM)NULL );
}
HANDLE
CacheCreateSpooler(
LPWSTR pMachineName
)
{
PWCHAR pScratch = NULL;
PWCHAR pRegistryRoot = NULL;
PWCHAR pRegistryPrinters = NULL;
SPOOLER_INFO_1 SpoolInfo1;
HANDLE hIniSpooler = INVALID_HANDLE_VALUE;
PWCHAR pMachineOneSlash;
MONITOR_INFO_2 MonitorInfo;
DWORD dwNeeded;
DWORD Returned;
try {
pScratch = AllocSplMem( MAX_PATH );
if ( pScratch == NULL ) {
leave;
}
pMachineOneSlash = pMachineName;
pMachineOneSlash++;
//
// Create a "Machine" for this Printer
//
SpoolInfo1.pDir = gpWin32SplDir; // %systemroot%\system32\win32spl
SpoolInfo1.pDefaultSpoolDir = NULL; // Default %systemroot%\system32\win32spl\PRINTERS
wcscpy( pScratch, pszRegistryWin32Root);
wcscat( pScratch, pMachineOneSlash );
pRegistryRoot = AllocSplStr( pScratch );
SpoolInfo1.pszRegistryRoot = pRegistryRoot;
wcscat( pScratch, pszPrinters );
pRegistryPrinters = AllocSplStr( pScratch );
SpoolInfo1.pszRegistryPrinters = pRegistryPrinters;
SpoolInfo1.pszRegistryMonitors = pszRegistryMonitors;
SpoolInfo1.pszRegistryEnvironments = pszRegistryEnvironments;
SpoolInfo1.pszRegistryEventLog = pszRegistryEventLog;
SpoolInfo1.pszRegistryProviders = pszRegistryProviders;
SpoolInfo1.pszEventLogMsgFile = pszEventLogMsgFile;
SpoolInfo1.pszDriversShare = pszDriversShareName;
wcscpy( pScratch, pszRegistryWin32Root);
wcscat( pScratch, pMachineOneSlash );
wcscat( pScratch, pszForms );
SpoolInfo1.pszRegistryForms = pScratch;
// The router graciously does the WIN.INI devices update so let have
// Spl not also create a printer for us.
// Select Features we do NOT want.
SpoolInfo1.SpoolerFlags = (DWORD) ~( SPL_UPDATE_WININI_DEVICES |
SPL_PRINTER_CHANGES |
SPL_LOG_EVENTS |
SPL_SECURITY_CHECK |
SPL_OPEN_CREATE_PORTS |
SPL_FORMS_CHANGE |
SPL_REMOTE_HANDLE_CHECK |
SPL_PRINTER_DRIVER_EVENT |
SPL_PRINT |
SPL_FAIL_OPEN_PRINTERS_PENDING_DELETION );
SpoolInfo1.pfnReadRegistryExtra = (FARPROC) &CacheReadRegistryExtra;
SpoolInfo1.pfnWriteRegistryExtra = (FARPROC) &CacheWriteRegistryExtra;
SpoolInfo1.pfnFreePrinterExtra = (FARPROC) &CacheFreeExtraData;
SplOutSem();
hIniSpooler = SplCreateSpooler( pMachineName,
1,
&SpoolInfo1,
NULL );
if ( hIniSpooler != INVALID_HANDLE_VALUE ) {
// Add WIN32SPL.DLL as the Monitor
MonitorInfo.pName = pszMonitorName;
MonitorInfo.pEnvironment = szEnvironment;
MonitorInfo.pDLLName = pszMyDllName;
if ( (!SplAddMonitor( NULL, 2, (LPBYTE)&MonitorInfo, hIniSpooler)) &&
( GetLastError() != ERROR_PRINT_MONITOR_ALREADY_INSTALLED ) ) {
DBGMSG( DBG_WARNING, ("CacheCreateSpooler failed SplAddMonitor %d\n", GetLastError()));
SplCloseSpooler( hIniSpooler );
hIniSpooler = INVALID_HANDLE_VALUE;
}
}
} finally {
FreeSplStr ( pScratch );
FreeSplStr ( pRegistryRoot );
FreeSplStr ( pRegistryPrinters );
}
return hIniSpooler;
}
VOID
RefreshCompletePrinterCache(
PWSPOOL pSpool
)
{
DBGMSG( DBG_TRACE, ("RefreshCompletePrinterCache %x\n", pSpool));
// Note the order is important.
// Refreshing the printer might require that the new driver has
// been installed on the system.
RefreshPrinterDriver( pSpool );
RefreshFormsCache( pSpool );
RefreshDriverDataCache( pSpool );
RefreshPrinter( pSpool );
RefreshDriverEvent( pSpool );
SplBroadcastChange(pSpool->hSplPrinter, WM_DEVMODECHANGE, 0, (LPARAM) pSpool->pName);
}
PPRINTER_INFO_2
GetRemotePrinterInfo(
PWSPOOL pSpool,
LPDWORD pReturnCount
)
{
PPRINTER_INFO_2 pRemoteInfo = NULL;
HANDLE hPrinter = (HANDLE) pSpool;
DWORD cbRemoteInfo = 0;
DWORD dwBytesNeeded = 0;
DWORD dwLastError = 0;
BOOL bReturnValue = FALSE;
*pReturnCount = 0;
do {
if ( pRemoteInfo != NULL ) {
FreeSplMem( pRemoteInfo );
pRemoteInfo = NULL;
cbRemoteInfo = 0;
}
if ( dwBytesNeeded != 0 ) {
pRemoteInfo = AllocSplMem( dwBytesNeeded );
if ( pRemoteInfo == NULL )
break;
}
cbRemoteInfo = dwBytesNeeded;
bReturnValue = RemoteGetPrinter( hPrinter,
2,
(LPBYTE)pRemoteInfo,
cbRemoteInfo,
&dwBytesNeeded );
dwLastError = GetLastError();
} while ( !bReturnValue && dwLastError == ERROR_INSUFFICIENT_BUFFER );
if ( !bReturnValue && pRemoteInfo != NULL ) {
FreeSplMem( pRemoteInfo );
pRemoteInfo = NULL;
cbRemoteInfo = 0;
} else if ( pRemoteInfo != NULL ) {
//
// So that apps can tell if they get the Cached Info
//
pRemoteInfo->Status |= PRINTER_STATUS_SERVER_UNKNOWN;
}
*pReturnCount = cbRemoteInfo;
return pRemoteInfo;
}
//
// This routine Clones the Printer_Info_2 structure from the Remote machine
//
//
PWCACHEINIPRINTEREXTRA
AllocExtraData(
PPRINTER_INFO_2W pPrinterInfo2,
DWORD cbPrinterInfo2
)
{
PWCACHEINIPRINTEREXTRA pExtraData = NULL;
DWORD cbSize;
SPLASSERT( cbPrinterInfo2 != 0);
SPLASSERT( pPrinterInfo2 != NULL );
cbSize = sizeof( WCACHEINIPRINTEREXTRA );
pExtraData = AllocSplMem( cbSize );
if ( pExtraData != NULL ) {
pExtraData->signature = WCIP_SIGNATURE;
pExtraData->cb = cbSize;
pExtraData->cRef = 0;
pExtraData->cbPI2 = cbPrinterInfo2;
pExtraData->dwTickCount = GetTickCount();
pExtraData->pPI2 = AllocSplMem( cbPrinterInfo2 );
if ( pExtraData->pPI2 != NULL ) {
CacheCopyPrinterInfo( pExtraData->pPI2, pPrinterInfo2, cbPrinterInfo2 );
} else {
FreeSplMem( pExtraData );
pExtraData = NULL;
}
}
return pExtraData;
}
VOID
CacheFreeExtraData(
PWCACHEINIPRINTEREXTRA pExtraData
)
{
PWCACHEINIPRINTEREXTRA pPrev = NULL;
PWCACHEINIPRINTEREXTRA pCur = NULL;
if ( pExtraData != NULL ) {
SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
if ( pExtraData->cRef != 0 ) {
DBGMSG( DBG_TRACE, ("CacheFreeExtraData pExtraData %x cRef %d != 0 freeing anyway\n",
pExtraData,
pExtraData->cRef ));
}
if ( pExtraData->pPI2 != NULL ) {
FreeSplMem( pExtraData->pPI2 );
}
FreeSplMem( pExtraData );
}
}
// Use This routine to move around structures
// so the offsets pointers are valid after the move
VOID
MarshallDownStructure(
LPBYTE lpStructure,
LPDWORD lpOffsets
)
{
register DWORD i=0;
while (lpOffsets[i] != -1) {
if ((*(LPBYTE *)(lpStructure+lpOffsets[i]))) {
(*(LPBYTE *)(lpStructure+lpOffsets[i]))-=(DWORD)lpStructure;
}
i++;
}
}
VOID
DownAndMarshallUpStructure(
LPBYTE lpStructure,
LPBYTE lpSource,
LPDWORD lpOffsets
)
{
register DWORD i=0;
while (lpOffsets[i] != -1) {
if ((*(LPBYTE *)(lpStructure+lpOffsets[i]))) {
(*(LPBYTE *)(lpStructure+lpOffsets[i]))-=(DWORD)lpSource;
(*(LPBYTE *)(lpStructure+lpOffsets[i]))+=(DWORD)lpStructure;
}
i++;
}
}
VOID
CacheCopyPrinterInfo(
PPRINTER_INFO_2W pDestination,
PPRINTER_INFO_2W pPrinterInfo2,
DWORD cbPrinterInfo2
)
{
LPWSTR SourceStrings[sizeof(PRINTER_INFO_2)/sizeof(LPWSTR)];
LPWSTR *pSourceStrings = SourceStrings;
//
// Copy the lot then fix up the pointers
//
CopyMemory( pDestination, pPrinterInfo2, cbPrinterInfo2 );
DownAndMarshallUpStructure( (LPBYTE)pDestination, (LPBYTE)pPrinterInfo2, PrinterInfo2Offsets );
}
VOID
ConvertRemoteInfoToLocalInfo(
PPRINTER_INFO_2 pPrinterInfo2
)
{
SPLASSERT( pPrinterInfo2 != NULL );
DBGMSG(DBG_TRACE,("%ws %ws ShareName %x %ws pSecurityDesc %x Attributes %x StartTime %d UntilTime %d Status %x\n",
pPrinterInfo2->pServerName,
pPrinterInfo2->pPrinterName,
pPrinterInfo2->pShareName,
pPrinterInfo2->pPortName,
pPrinterInfo2->pSecurityDescriptor,
pPrinterInfo2->Attributes,
pPrinterInfo2->StartTime,
pPrinterInfo2->UntilTime,
pPrinterInfo2->Status));
//
// GetPrinter returns the name \\server\printername we only want the printer name
//
SPLASSERT ( 0 == _wcsnicmp( pPrinterInfo2->pPrinterName, L"\\\\", 2 ) ) ;
pPrinterInfo2->pPrinterName = wcschr( pPrinterInfo2->pPrinterName + 2, L'\\' );
pPrinterInfo2->pPrinterName++;
//
// LATER this should be a Win32Spl Port
//
pPrinterInfo2->pPortName = L"NExx:";
pPrinterInfo2->pSepFile = NULL;
pPrinterInfo2->pSecurityDescriptor = NULL;
pPrinterInfo2->pPrintProcessor = L"winprint";
pPrinterInfo2->pDatatype = pszRaw;
pPrinterInfo2->pParameters = NULL;
pPrinterInfo2->Attributes &= ~( PRINTER_ATTRIBUTE_NETWORK | PRINTER_ATTRIBUTE_DIRECT | PRINTER_ATTRIBUTE_SHARED );
pPrinterInfo2->StartTime = 0;
pPrinterInfo2->UntilTime = 0;
pPrinterInfo2->Status = PRINTER_STATUS_PAUSED | PRINTER_STATUS_SERVER_UNKNOWN;
pPrinterInfo2->cJobs = 0;
pPrinterInfo2->AveragePPM = 0;
}
VOID
RefreshPrinter(
PWSPOOL pSpool
)
{
PPRINTER_INFO_2 pRemoteInfo = NULL;
DWORD cbRemoteInfo = 0;
BOOL ReturnValue;
PWCACHEINIPRINTEREXTRA pExtraData = NULL;
PWCACHEINIPRINTEREXTRA pNewExtraData = NULL;
PPRINTER_INFO_2 pTempPI2, pCopyExtraPI2ToFree;
//
// Get the Remote Printer Info
//
pRemoteInfo = GetRemotePrinterInfo( pSpool, &cbRemoteInfo );
if ( pRemoteInfo != NULL ) {
// LATER
// Optimization could be to only update the cache if something
// actually changed.
// IE Compare every field.
EnterSplSem();
ReturnValue = SplGetPrinterExtra( pSpool->hSplPrinter, &(DWORD)pExtraData );
if ( ReturnValue == FALSE ) {
DBGMSG( DBG_WARNING, ("RefreshPrinter SplGetPrinterExtra pSpool %x error %d\n", pSpool, GetLastError() ));
SPLASSERT( ReturnValue );
}
if ( pExtraData == NULL ) {
pExtraData = AllocExtraData( pRemoteInfo, cbRemoteInfo );
if ( pExtraData != NULL ) {
pExtraData->cRef++;
}
} else {
SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
pTempPI2 = AllocSplMem( cbRemoteInfo );
if ( pTempPI2 != NULL ) {
SplInSem();
CacheCopyPrinterInfo( pTempPI2, pRemoteInfo, cbRemoteInfo );
pCopyExtraPI2ToFree = pExtraData->pPI2;
pExtraData->pPI2 = pTempPI2;
pExtraData->cbPI2 = cbRemoteInfo;
FreeSplMem( pCopyExtraPI2ToFree );
}
}
LeaveSplSem();
if ( pExtraData != NULL ) {
SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
}
ConvertRemoteInfoToLocalInfo( pRemoteInfo );
ReturnValue = SplSetPrinter( pSpool->hSplPrinter, 2, (LPBYTE)pRemoteInfo, 0 );
if ( !ReturnValue ) {
DBGMSG( DBG_WARNING, ("RefreshPrinter Failed SplSetPrinter %d\n", GetLastError() ));
}
ReturnValue = SplSetPrinterExtra( pSpool->hSplPrinter, (LPBYTE)pExtraData );
if (!ReturnValue) {
DBGMSG(DBG_ERROR, ("RefreshPrinter SplSetPrinterExtra failed %x\n", GetLastError()));
}
} else {
DBGMSG( DBG_WARNING, ("RefreshPrinter failed GetRemotePrinterInfo %x\n", GetLastError() ));
}
if ( pRemoteInfo != NULL )
FreeSplMem( pRemoteInfo );
}
//
// TESTING
//
DWORD dwAddPrinterConnection = 0;
BOOL
AddPrinterConnection(
LPWSTR pName
)
{
PWSPOOL pSpool = NULL;
BOOL bReturnValue = FALSE;
HANDLE hIniSpooler = INVALID_HANDLE_VALUE;
PPRINTER_INFO_2 pPrinterInfo2 = NULL;
DWORD cbPrinterInfo2 = 0;
HANDLE hSplPrinter = INVALID_HANDLE_VALUE;
PWCACHEINIPRINTEREXTRA pExtraData = NULL;
BOOL bSuccess = FALSE;
LPPRINTER_INFO_STRESSW pPrinter0 = NULL;
DWORD dwNeeded;
DWORD LastError = ERROR_SUCCESS;
BOOL bLoopDetected = FALSE;
//
// TESTING
//
++dwAddPrinterConnection;
try {
if (!VALIDATE_NAME(pName)) {
SetLastError(ERROR_INVALID_NAME);
leave;
}
if (!RemoteOpenPrinter(pName, &pSpool, NULL, DO_NOT_CALL_LM_OPEN)) {
leave;
}
pPrinter0 = AllocSplMem( MAX_PRINTER_INFO0 );
if ( pPrinter0 == NULL )
leave;
SPLASSERT( pSpool != NULL );
SPLASSERT( pSpool->Type == SJ_WIN32HANDLE );
DBGMSG( DBG_TRACE, ("AddPrinterConnection pName %ws pSpool %x\n",pName, pSpool ));
//
// Get Remote ChangeID to be certain nothing changes on the Server
// whilst we are establishing our Cache.
//
bReturnValue = RemoteGetPrinter( pSpool, STRESSINFOLEVEL, (LPBYTE)pPrinter0, MAX_PRINTER_INFO0, &dwNeeded );
if ( !bReturnValue ) {
SPLASSERT( GetLastError() != ERROR_INSUFFICIENT_BUFFER );
DBGMSG(DBG_TRACE, ("AddPrinterConnection failed RemoteGetPrinter %d\n", GetLastError()));
pPrinter0->cChangeID = 0;
}
DBGMSG( DBG_TRACE, ("AddPrinterConnection << Server cCacheID %x >>\n", pPrinter0->cChangeID ));
//
// See If the Printer is already in the Cache
//
APC_OpenCache:
bReturnValue = OpenCachePrinterOnly( pName, &hSplPrinter, &hIniSpooler, NULL );
if ( hIniSpooler == INVALID_HANDLE_VALUE ) {
DBGMSG( DBG_WARNING, ("AddPrinterConnection - CacheCreateSpooler Failed %x\n",GetLastError()));
leave;
}
pSpool->hIniSpooler = hIniSpooler;
if ( bReturnValue ) {
//
// Printer Exists in Cache
//
SPLASSERT( ( hSplPrinter != INVALID_HANDLE_VALUE) ||
( hSplPrinter != NULL ) );
DBGMSG( DBG_TRACE,("AddPrinterConnection hIniSpooler %x hSplPrinter%x\n", hIniSpooler, hSplPrinter) );
pSpool->hSplPrinter = hSplPrinter;
pSpool->Status |= WSPOOL_STATUS_USE_CACHE;
//
// Update Connection Reference Count
//
EnterSplSem();
bReturnValue = SplGetPrinterExtra( pSpool->hSplPrinter, &(DWORD)pExtraData );
if ( bReturnValue == FALSE ) {
DBGMSG( DBG_WARNING, ("AddPrinterConnection SplGetPrinterExtra pSpool %x error %d\n", pSpool, GetLastError() ));
SPLASSERT( bReturnValue );
}
if ( pExtraData != NULL ) {
SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
pExtraData->cRef++;
}
LeaveSplSem();
// Make Sure Reference Count Gets Updated in Registry
if ( !SplSetPrinterExtra( hSplPrinter, (LPBYTE)pExtraData ) ) {
DBGMSG( DBG_ERROR, ("AddPrinterConnection SplSetPrinterExtra failed %x\n", GetLastError() ));
}
// Refresh Cache
// It could be that the remote machine is old NT Daytona 3.5 or before
// which doesn't support the ChangeID, that would mean the only
// way for a user to force an update is to do a connection.
if ( pPrinter0->cChangeID == 0 ) {
// Old NT
RefreshCompletePrinterCache( pSpool );
} else {
ConsistencyCheckCache( pSpool );
}
bSuccess = TRUE;
leave;
} else if ( GetLastError() != ERROR_INVALID_PRINTER_NAME ) {
DBGMSG( DBG_WARNING, ("AddPrinterConnection failed OpenCachePrinterOnly %d\n", GetLastError() ));
leave;
}
//
// There is NO Cache Entry for This Printer
//
DBGMSG( DBG_TRACE, ("AddPrinterConnection failed SplOpenPrinter %ws %d\n", pName, GetLastError() ));
RefreshPrinterDriver( pSpool );
//
// Get PRINTER Info from Remote Machine
//
pPrinterInfo2 = GetRemotePrinterInfo( pSpool, &cbPrinterInfo2 );
if ( pPrinterInfo2 == NULL ) {
DBGMSG( DBG_WARNING, ("AddPrinterConnection failed GetRemotePrinterInfo %x\n", GetLastError() ));
leave;
}
//
// Allocate My Extra Data for this Printer
// ( from RemoteGetPrinter )
//
pExtraData = AllocExtraData( pPrinterInfo2, cbPrinterInfo2 );
if ( pExtraData == NULL )
leave;
pExtraData->cRef++;
pExtraData->cCacheID = pPrinter0->cChangeID;
pExtraData->dwServerVersion = pPrinter0->dwGetVersion;
//
// Convert Remote Printer_Info_2 to Local Version for Cache
//
ConvertRemoteInfoToLocalInfo( pPrinterInfo2 );
//
// Add Printer to Cache
//
hSplPrinter = SplAddPrinter(NULL, 2, (LPBYTE)pPrinterInfo2,
hIniSpooler, (LPBYTE)pExtraData,
NULL, 0);
pExtraData = NULL;
if ( hSplPrinter == NULL ) {
LastError = GetLastError();
if ( LastError == ERROR_PRINTER_ALREADY_EXISTS ) {
SplCloseSpooler( pSpool->hIniSpooler );
hIniSpooler = INVALID_HANDLE_VALUE;
if ( bLoopDetected == FALSE ) {
bLoopDetected = TRUE;
goto APC_OpenCache;
} else {
DBGMSG( DBG_WARNING, ("AddPrinterConnection APC_OpenCache Loop Detected << Should Never Happen >>\n"));
leave;
}
}
// If we failed to Create the printer above, we should NOT be able to Open it now.
DBGMSG( DBG_WARNING, ("AddPrinterConnection Failed SplAddPrinter error %d\n", LastError ));
hSplPrinter = INVALID_HANDLE_VALUE;
bSuccess = FALSE;
leave;
}
DBGMSG( DBG_TRACE, ("AddPrinterConnection SplAddPrinter SUCCESS hSplPrinter %x\n", hSplPrinter));
pSpool->hSplPrinter = hSplPrinter;
pSpool->Status |= WSPOOL_STATUS_USE_CACHE;
RefreshPrinter(pSpool);
RefreshFormsCache( pSpool );
RefreshDriverDataCache( pSpool );
RefreshDriverEvent( pSpool );
// Just In Case something change whilst we were initializing the cache
// go check it again now.
ConsistencyCheckCache( pSpool );
bSuccess = TRUE;
} finally {
if ( !bSuccess ) {
if ( LastError == ERROR_SUCCESS )
LastError = GetLastError();
DeletePrinterConnection( pName );
}
if ( pSpool != NULL )
CacheClosePrinter( pSpool );
if ( pPrinterInfo2 != NULL )
FreeSplMem( pPrinterInfo2 );
if ( pPrinter0 != NULL )
FreeSplMem( pPrinter0 );
}
if ( !bSuccess ) {
SetLastError( LastError );
DBGMSG( DBG_TRACE, ("AddPrinterConnection %ws Failed %d\n", pName, GetLastError() ));
}
return( bSuccess );
}
//
// TESTING
//
DWORD dwRefreshFormsCache = 0;
DWORD dwNoMatch = 0;
DWORD dwDeleteForm = 0;
DWORD dwAddForm = 0;
VOID
RefreshFormsCache(
PWSPOOL pSpool
)
/*++
Routine Description:
This routine will check to see if any forms have changed. If anything changed it adds
or deletes forms from the cache so that it matches the server.
Note it is very important that the order of the forms on the workstation matches those
on the Server.
Implementation:
EnumRemoteForms
EnumLocalForms
If there is any difference
Delete All LocalForms
Add All the Remote Forms
The code is optimized for the typical case
Forms are added at the end only.
Forms are hardly ever deleted.
Arguments:
pSpool - Handle to remote printer.
Return Value:
None
--*/
{
PFORM_INFO_1 pRemoteForms = NULL , pSaveRemoteForms = NULL;
PFORM_INFO_1 pLocalCacheForms = NULL, pSaveLocalCacheForms = NULL;
PFORM_INFO_1 pRemote = NULL, pLocal = NULL;
DWORD dwBuf = 0;
DWORD dwSplBuf = 0;
DWORD dwNeeded = 0;
DWORD dwSplNeeded = 0;
DWORD dwRemoteFormsReturned = 0;
DWORD dwSplReturned = 0;
BOOL bReturnValue = FALSE;
DWORD LastError = ERROR_INSUFFICIENT_BUFFER;
INT iCompRes = 0;
DWORD LoopCount;
BOOL bCacheMatchesRemoteMachine = FALSE;
SPLASSERT( pSpool != NULL );
SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
//
// Get Remote Machine Forms Data
//
//
// TESTING
//
++dwRefreshFormsCache;
do {
bReturnValue = RemoteEnumForms( (HANDLE)pSpool, 1, (LPBYTE)pRemoteForms, dwBuf, &dwNeeded, &dwRemoteFormsReturned);
if ( bReturnValue )
break;
LastError = GetLastError();
if ( LastError != ERROR_INSUFFICIENT_BUFFER ) {
DBGMSG( DBG_WARNING, ("RefreshFormsCache Failed RemoteEnumForms error %d\n", GetLastError()));
goto RefreshFormsCacheErrorReturn;
}
if ( pRemoteForms != NULL )
FreeSplMem( pRemoteForms );
pRemoteForms = AllocSplMem( dwNeeded );
pSaveRemoteForms = pRemoteForms;
dwBuf = dwNeeded;
if ( pRemoteForms == NULL ) {
DBGMSG( DBG_WARNING, ("RefreshFormsCache Failed AllocSplMem Error %d dwNeeded %d\n", GetLastError(), dwNeeded));
goto RefreshFormsCacheErrorReturn;
}
} while ( !bReturnValue && LastError == ERROR_INSUFFICIENT_BUFFER );
if( pRemoteForms == NULL ) {
DBGMSG( DBG_WARNING, ("RefreshFormsCache Failed pRemoteForms == NULL\n"));
goto RefreshFormsCacheErrorReturn;
}
//
// Get LocalCachedForms Data
//
do {
bReturnValue = SplEnumForms( pSpool->hSplPrinter, 1, (LPBYTE)pLocalCacheForms, dwSplBuf, &dwSplNeeded, &dwSplReturned);
if ( bReturnValue )
break;
LastError = GetLastError();
if ( LastError != ERROR_INSUFFICIENT_BUFFER ) {
DBGMSG( DBG_WARNING, ("RefreshFormsCache Failed SplEnumForms hSplPrinter %x error %d\n", pSpool->hSplPrinter, GetLastError()));
goto RefreshFormsCacheErrorReturn;
}
if ( pLocalCacheForms != NULL )
FreeSplMem( pLocalCacheForms );
pLocalCacheForms = AllocSplMem( dwSplNeeded );
pSaveLocalCacheForms = pLocalCacheForms;
dwSplBuf = dwSplNeeded;
if ( pLocalCacheForms == NULL ) {
DBGMSG( DBG_WARNING, ("RefreshFormsCache Failed AllocSplMem ( %d )\n",dwSplNeeded));
goto RefreshFormsCacheErrorReturn;
}
} while ( !bReturnValue && LastError == ERROR_INSUFFICIENT_BUFFER );
//
// Optimization Check Local vs Remote
// If nothing has changed no need to do anything
//
if ( dwRemoteFormsReturned >= dwSplReturned ) {
SPLASSERT( pRemoteForms != NULL );
SPLASSERT( pLocalCacheForms != NULL );
for ( LoopCount = 0, pRemote = pRemoteForms, pLocal = pLocalCacheForms, bCacheMatchesRemoteMachine = TRUE;
LoopCount < dwSplReturned && bCacheMatchesRemoteMachine;
LoopCount++, pRemote++, pLocal++ ) {
if (( wcscmp( pRemote->pName, pLocal->pName ) != STRINGS_ARE_EQUAL ) ||
( pRemote->Size.cx != pLocal->Size.cx ) ||
( pRemote->Size.cy != pLocal->Size.cy ) ||
( pRemote->ImageableArea.left != pLocal->ImageableArea.left ) ||
( pRemote->ImageableArea.top != pLocal->ImageableArea.top ) ||
( pRemote->ImageableArea.right != pLocal->ImageableArea.right ) ||
( pRemote->ImageableArea.bottom != pLocal->ImageableArea.bottom ) ) {
DBGMSG( DBG_TRACE, ("RefreshFormsCache Remote cx %d cy %d left %d right %d top %d bottom %d %ws\n",
pRemote->Size.cx, pRemote->Size.cy,
pRemote->ImageableArea.left,
pRemote->ImageableArea.right,
pRemote->ImageableArea.top,
pRemote->ImageableArea.bottom,
pRemote->pName));
DBGMSG( DBG_TRACE, ("RefreshFormsCache Local cx %d cy %d left %d right %d top %d bottom %d %ws - Does Not Match\n",
pLocal->Size.cx, pLocal->Size.cy,
pLocal->ImageableArea.left,
pLocal->ImageableArea.right,
pLocal->ImageableArea.top,
pLocal->ImageableArea.bottom,
pLocal->pName));
bCacheMatchesRemoteMachine = FALSE;
}
}
//
// If Everything matches we're done.
//
if ( bCacheMatchesRemoteMachine ) {
if ( dwRemoteFormsReturned == dwSplReturned ) {
DBGMSG( DBG_TRACE, ("RefreshFormsCache << Cache Forms Match Remote Forms - Nothing to do >>\n"));
goto RefreshFormsCacheReturn;
} else {
//
// All the forms we have in the cache match
// Now add the Extra Remote Forms.
dwRemoteFormsReturned -= dwSplReturned;
pRemoteForms = pRemote;
// dwSplReturned == 0 will skip the delete loop
dwSplReturned = 0;
}
}
}
//
// TESTING
//
++dwNoMatch;
DBGMSG( DBG_TRACE, ("RefreshFormsCache - Something Doesn't Match, Delete all the Cache and Refresh it\n"));
//
// Delete all the forms in the Cache
//
for ( LoopCount = dwSplReturned, pLocal = pLocalCacheForms;
LoopCount != 0;
pLocal++, LoopCount-- ) {
//
// TESTING
//
++dwDeleteForm;
bReturnValue = SplDeleteForm( pSpool->hSplPrinter, pLocal->pName );
DBGMSG( DBG_TRACE, ("RefreshFormsCache %x SplDeleteForm( %x, %ws)\n",bReturnValue, pSpool->hSplPrinter, pLocal->pName));
}
//
// Add all the Remote Forms to the Cache
//
for ( LoopCount = dwRemoteFormsReturned, pRemote = pRemoteForms;
LoopCount != 0;
LoopCount--, pRemote++ ) {
//
// TESTING
//
++dwAddForm;
SPLASSERT( pRemote != NULL );
bReturnValue = SplAddForm( pSpool->hSplPrinter, 1, (LPBYTE)pRemote );
DBGMSG( DBG_TRACE, ("RefreshFormsCache %x SplAddForm( %x, 1, %ws)\n",bReturnValue, pSpool->hSplPrinter, pRemote->pName));
}
RefreshFormsCacheReturn:
RefreshFormsCacheErrorReturn:
if ( pSaveRemoteForms != NULL )
FreeSplMem( pSaveRemoteForms );
if ( pSaveLocalCacheForms != NULL )
FreeSplMem( pSaveLocalCacheForms );
}
VOID
RefreshDriverDataCache(
PWSPOOL pSpool
)
{
DWORD iCount = 0;
DWORD dwType = 0;
DWORD ReturnValue = 0;
LPBYTE lpbData = NULL;
DWORD dwSizeData;
DWORD dwMaxSizeData;
LPWSTR pValueString = NULL;
DWORD dwSizeValueString;
DWORD dwMaxSizeValueString;
SPLASSERT( pSpool != NULL );
SPLASSERT( pSpool->signature == WSJ_SIGNATURE );
SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
SPLASSERT( pSpool->pName != NULL );
// Get the required sizes
ReturnValue = RemoteEnumPrinterData(pSpool,
iCount,
pValueString,
0,
&dwMaxSizeValueString,
&dwType,
lpbData,
0,
&dwMaxSizeData);
if (ReturnValue != ERROR_SUCCESS) {
DBGMSG( DBG_TRACE, ("RefreshDriverDataCache Failed first RemoteEnumPrinterData %d\n", GetLastError()));
goto RefreshDriverDataCacheError;
}
// Allocate
if ((pValueString = AllocSplMem(dwMaxSizeValueString)) == NULL) {
DBGMSG( DBG_WARNING, ("RefreshDriverDataCache Failed to allocate enough memory\n"));
goto RefreshDriverDataCacheError;
}
if ((lpbData = AllocSplMem(dwMaxSizeData)) == NULL) {
DBGMSG( DBG_WARNING, ("RefreshDriverDataCache Failed to allocate enough memory\n"));
goto RefreshDriverDataCacheError;
}
// Enumerate
for (iCount = 0 ;
RemoteEnumPrinterData( pSpool,
iCount,
pValueString,
dwMaxSizeValueString,
&dwSizeValueString,
&dwType,
lpbData,
dwMaxSizeData,
&dwSizeData) == ERROR_SUCCESS ;
++iCount) {
//
// Optimization - Do NOT write the data if it is the same
//
if ((ReturnValue = SplSetPrinterData(pSpool->hSplPrinter,
(LPWSTR)pValueString,
dwType,
lpbData,
dwSizeData )) != ERROR_SUCCESS) {
DBGMSG( DBG_WARNING, ("RefreshDriverDataCache Failed SplSetPrinterData %d\n",ReturnValue ));
goto RefreshDriverDataCacheError;
}
}
RefreshDriverDataCacheError:
FreeSplMem( lpbData );
FreeSplStr( pValueString );
}
BOOL
CacheEnumForms(
HANDLE hPrinter,
DWORD Level,
LPBYTE pForm,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
)
{
PWSPOOL pSpool = (PWSPOOL) hPrinter;
BOOL ReturnValue;
VALIDATEW32HANDLE( pSpool );
if (( pSpool->Status & WSPOOL_STATUS_USE_CACHE ) &&
!( pSpool->PrinterDefaults.DesiredAccess & PRINTER_ACCESS_ADMINISTER )) {
SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
ReturnValue = SplEnumForms( pSpool->hSplPrinter,
Level,
pForm,
cbBuf,
pcbNeeded,
pcReturned );
} else {
ReturnValue = RemoteEnumForms( hPrinter,
Level,
pForm,
cbBuf,
pcbNeeded,
pcReturned );
}
return ReturnValue;
}
BOOL
CacheGetForm(
HANDLE hPrinter,
LPWSTR pFormName,
DWORD Level,
LPBYTE pForm,
DWORD cbBuf,
LPDWORD pcbNeeded
)
{
PWSPOOL pSpool = (PWSPOOL) hPrinter;
BOOL ReturnValue;
VALIDATEW32HANDLE( pSpool );
if (( pSpool->Status & WSPOOL_STATUS_USE_CACHE ) &&
!( pSpool->PrinterDefaults.DesiredAccess & PRINTER_ACCESS_ADMINISTER )) {
SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
ReturnValue = SplGetForm( pSpool->hSplPrinter,
pFormName,
Level,
pForm,
cbBuf,
pcbNeeded );
} else {
ReturnValue = RemoteGetForm( hPrinter,
pFormName,
Level,
pForm,
cbBuf,
pcbNeeded );
}
return ReturnValue;
}
DWORD
CacheGetPrinterData(
HANDLE hPrinter,
LPWSTR pValueName,
LPDWORD pType,
LPBYTE pData,
DWORD nSize,
LPDWORD pcbNeeded
)
{
PWSPOOL pSpool = (PWSPOOL) hPrinter;
DWORD ReturnValue;
VALIDATEW32HANDLE( pSpool );
if (( pSpool->Status & WSPOOL_STATUS_USE_CACHE ) &&
!( pSpool->PrinterDefaults.DesiredAccess & PRINTER_ACCESS_ADMINISTER )) {
SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
ReturnValue = SplGetPrinterData( pSpool->hSplPrinter,
pValueName,
pType,
pData,
nSize,
pcbNeeded );
} else {
ReturnValue = RemoteGetPrinterData( hPrinter,
pValueName,
pType,
pData,
nSize,
pcbNeeded );
}
return ReturnValue;
}
BOOL
CacheOpenPrinter(
LPWSTR pName,
LPHANDLE phPrinter,
LPPRINTER_DEFAULTS pDefault
)
{
PWSPOOL pSpool = NULL;
PWSPOOL pRemoteSpool = NULL;
HANDLE hSplPrinter = INVALID_HANDLE_VALUE;
BOOL ReturnValue = FALSE;
HANDLE hIniSpooler = INVALID_HANDLE_VALUE;
BOOL DoOpenOnError = TRUE;
DWORD LastError;
BOOL bSync = FALSE;
if (!VALIDATE_NAME(pName)) {
SetLastError(ERROR_INVALID_NAME);
return FALSE;
}
ReturnValue = OpenCachePrinterOnly( pName, &hSplPrinter, &hIniSpooler, pDefault );
if ( hIniSpooler == INVALID_HANDLE_VALUE ) {
EnterSplSem();
hSplPrinter = INVALID_HANDLE_VALUE;
goto OpenPrinterError;
}
if ( ReturnValue == FALSE ) {
// Printer Not Found in Cache
DBGMSG(DBG_TRACE, ("CacheOpenPrinter SplOpenPrinter %ws error %d\n",
pName,
GetLastError() ));
// FLOATING PROFILE
// If this is a Floating Profile then the following condition applies
// there is an entry in HKEY_CURRENT_USER but not entry in
// HKEY_LOCAL_MACHINE for the cache.
// If this is the case then we need to establish the Cache now
if ( !PrinterConnectionExists( pName )) {
EnterSplSem();
goto OpenPrinterError;
}
if ( !AddPrinterConnection( pName ) ||
SplOpenPrinter( pName ,
&hSplPrinter,
pDefault,
hIniSpooler,
NULL,
0) != ROUTER_SUCCESS ) {
DBGMSG( DBG_TRACE, ("CacheOpenPrinter Failed to establish Floating Profile into Cache %d\n",
GetLastError() ));
DoOpenOnError = FALSE;
EnterSplSem();
goto OpenPrinterError;
}
DBGMSG( DBG_TRACE, ("CacheOpenPrinter Floating Profile Added to Cache\n"));
}
EnterSplSem();
SplInSem();
//
// Create a pSpool Object for this Cached Printer
//
pSpool = AllocWSpool();
if ( pSpool == NULL ) {
DBGMSG(DBG_WARNING, ("CacheOpenPrinter AllocWSpool error %d\n", GetLastError() ));
ReturnValue = FALSE;
goto OpenPrinterError;
}
pSpool->pName = AllocSplStr( pName );
if ( pSpool->pName == NULL ) {
DBGMSG(DBG_WARNING, ("CacheOpenPrinter AllocSplStr error %d\n", GetLastError() ));
ReturnValue = FALSE;
goto OpenPrinterError;
}
pSpool->Status = WSPOOL_STATUS_USE_CACHE | WSPOOL_STATUS_NO_RPC_HANDLE;
pSpool->hIniSpooler = hIniSpooler;
pSpool->hSplPrinter = hSplPrinter;
SPLASSERT( hIniSpooler != INVALID_HANDLE_VALUE );
SPLASSERT( hSplPrinter != INVALID_HANDLE_VALUE );
//
// We want to hit the network if:
// 1. The dwSyncOpenPrinter is non-zero, OR
// 2. A default is specified AND:
// a. A datatype is specified, and it's not RAW OR
// b. Administrative access is requested.
//
// For admin, we want to get the true status of the printer, since
// they will be administering it.
//
// If a non-default and non-RAW datatype is specified, we need to
// be synchronous, since the remote machine may refuse the datatype
// (e.g., connecting to 1057 with EMF).
//
if( pDefault ){
if( ( pDefault->pDatatype && ( _wcsicmp( pDefault->pDatatype, pszRaw ) != STRINGS_ARE_EQUAL )) ||
( pDefault->DesiredAccess & PRINTER_ACCESS_ADMINISTER )){
bSync = TRUE;
}
}
if( dwSyncOpenPrinter != 0 || bSync ){
LeaveSplSem();
ReturnValue = RemoteOpenPrinter( pName, &pRemoteSpool, pDefault, DO_NOT_CALL_LM_OPEN );
EnterSplSem();
if ( ReturnValue ) {
DBGMSG( DBG_TRACE, ( "CacheOpenPrinter Synchronous Open OK pRemoteSpool %x pSpool %x\n", pRemoteSpool, pSpool ));
SPLASSERT( pRemoteSpool->Type == SJ_WIN32HANDLE );
pSpool->RpcHandle = pRemoteSpool->RpcHandle;
pSpool->Status |= pRemoteSpool->Status;
pSpool->RpcError = pRemoteSpool->RpcError;
pSpool->bNt3xServer = pRemoteSpool->bNt3xServer;
pRemoteSpool->RpcHandle = INVALID_HANDLE_VALUE;
FreepSpool( pRemoteSpool );
pRemoteSpool = NULL;
CopypDefaultTopSpool( pSpool, pDefault );
pSpool->Status &= ~WSPOOL_STATUS_NO_RPC_HANDLE;
LeaveSplSem();
ConsistencyCheckCache( pSpool );
EnterSplSem();
} else {
DBGMSG( DBG_TRACE, ( "CacheOpenPrinter Synchronous Open Failed pSpool %x LastError %d\n", pSpool, GetLastError() ));
DoOpenOnError = FALSE;
}
} else {
ReturnValue = DoAsyncRemoteOpenPrinter( pSpool, pDefault );
}
OpenPrinterError:
SplInSem();
if ( !ReturnValue ) {
// Failure
LeaveSplSem();
LastError = GetLastError();
if (( hSplPrinter != INVALID_HANDLE_VALUE ) &&
( hSplPrinter != NULL ) ) {
SplClosePrinter( hSplPrinter );
}
if ( hIniSpooler != INVALID_HANDLE_VALUE ) {
SplCloseSpooler( hIniSpooler );
}
EnterSplSem();
if ( pSpool != NULL ) {
pSpool->hSplPrinter = INVALID_HANDLE_VALUE;
pSpool->hIniSpooler = INVALID_HANDLE_VALUE;
SPLASSERT( pSpool->cRef == 0 );
FreepSpool( pSpool );
pSpool = NULL;
}
LeaveSplSem();
SetLastError( LastError );
if ( DoOpenOnError ) {
ReturnValue = RemoteOpenPrinter( pName, phPrinter, pDefault, CALL_LM_OPEN );
}
} else {
// Success, pass back Handle
*phPrinter = (HANDLE)pSpool;
LeaveSplSem();
}
SplOutSem();
if ( ReturnValue == FALSE ) {
DBGMSG(DBG_TRACE,("CacheOpenPrinter %ws failed %d *phPrinter %x\n", pName, GetLastError(), *phPrinter ));
}
return ( ReturnValue );
}
BOOL
CopypDefaultTopSpool(
PWSPOOL pSpool,
LPPRINTER_DEFAULTSW pDefault
)
{
DWORD cbDevMode = 0;
BOOL ReturnValue = FALSE;
//
// Copy the pDefaults so we can use them later
//
try {
if ( ( pDefault != NULL ) &&
( pDefault != &pSpool->PrinterDefaults ) ) {
if (!ReallocSplStr( &pSpool->PrinterDefaults.pDatatype , pDefault->pDatatype )) {
leave;
}
if ( pSpool->PrinterDefaults.pDevMode != NULL ) {
cbDevMode = pSpool->PrinterDefaults.pDevMode->dmSize +
pSpool->PrinterDefaults.pDevMode->dmDriverExtra;
FreeSplMem( pSpool->PrinterDefaults.pDevMode );
pSpool->PrinterDefaults.pDevMode = NULL;
}
if ( pDefault->pDevMode != NULL ) {
cbDevMode = pDefault->pDevMode->dmSize + pDefault->pDevMode->dmDriverExtra;
pSpool->PrinterDefaults.pDevMode = AllocSplMem( cbDevMode );
if ( pSpool->PrinterDefaults.pDevMode != NULL ) {
CopyMemory( pSpool->PrinterDefaults.pDevMode, pDefault->pDevMode, cbDevMode );
} else {
leave;
}
} else pSpool->PrinterDefaults.pDevMode = NULL;
pSpool->PrinterDefaults.DesiredAccess = pDefault->DesiredAccess;
}
ReturnValue = TRUE;
} finally {
}
return ReturnValue;
}
BOOL
DoAsyncRemoteOpenPrinter(
PWSPOOL pSpool,
LPPRINTER_DEFAULTS pDefault
)
{
BOOL ReturnValue = FALSE;
HANDLE hThread = NULL;
DWORD IDThread;
SplInSem();
SPLASSERT( pSpool->Status & WSPOOL_STATUS_USE_CACHE );
CopypDefaultTopSpool( pSpool, pDefault );
pSpool->hWaitValidHandle = CreateEvent( NULL,
EVENT_RESET_MANUAL,
EVENT_INITIAL_STATE_NOT_SIGNALED,
NULL );
if ( pSpool->hWaitValidHandle != NULL ) {
ReturnValue = GetSid( &pSpool->hToken );
if ( ReturnValue ) {
pSpool->cRef++;
hThread = CreateThread( NULL, 16*1024, RemoteOpenPrinterThread, pSpool, 0, &IDThread );
if ( hThread != NULL ) {
CloseHandle( hThread );
ReturnValue = TRUE;
} else {
pSpool->cRef--;
SPLASSERT( pSpool->cRef == 0 );
ReturnValue = FALSE;
}
}
}
return ReturnValue;
}
BOOL
DoRemoteOpenPrinter(
LPWSTR pPrinterName,
LPPRINTER_DEFAULTS pDefault,
PWSPOOL pSpool
)
{
PWSPOOL pRemoteSpool = NULL;
BOOL bReturnValue;
DWORD dwLastError;
SplOutSem();
bReturnValue = RemoteOpenPrinter( pPrinterName, &pRemoteSpool, pDefault, DO_NOT_CALL_LM_OPEN );
dwLastError = GetLastError();
//
// Copy useful values to our CacheHandle and discard the new handle
//
EnterSplSem();
if ( bReturnValue ) {
DBGMSG(DBG_TRACE, ("DoRemoteOpenPrinter RemoteOpenPrinter OK hRpcHandle %x\n", pRemoteSpool->RpcHandle ));
SPLASSERT( WSJ_SIGNATURE == pSpool->signature );
SPLASSERT( WSJ_SIGNATURE == pRemoteSpool->signature );
SPLASSERT( pRemoteSpool->Type == SJ_WIN32HANDLE );
SPLASSERT( pSpool->Type == pRemoteSpool->Type );
SPLASSERT( pRemoteSpool->pServer == NULL );
SPLASSERT( pRemoteSpool->pShare == NULL );
SPLASSERT( pRemoteSpool->cRef == 0 );
pSpool->RpcHandle = pRemoteSpool->RpcHandle;
pSpool->Status |= pRemoteSpool->Status;
pSpool->RpcError = pRemoteSpool->RpcError;
pSpool->bNt3xServer = pRemoteSpool->bNt3xServer;
pRemoteSpool->RpcHandle = INVALID_HANDLE_VALUE;
FreepSpool( pRemoteSpool );
pRemoteSpool = NULL;
if ( pSpool->RpcHandle != INVALID_HANDLE_VALUE ) {
pSpool->Status &= ~WSPOOL_STATUS_OPEN_ERROR;
}
} else {
DBGMSG(DBG_WARNING, ("DoRemoteOpenPrinter RemoteOpenPrinter %ws failed %d\n", pPrinterName, dwLastError ));
pSpool->RpcHandle = INVALID_HANDLE_VALUE;
pSpool->Status |= WSPOOL_STATUS_OPEN_ERROR;
pSpool->RpcError = dwLastError;
}
pSpool->Status &= ~WSPOOL_STATUS_NO_RPC_HANDLE;
if ( !SetEvent( pSpool->hWaitValidHandle )) {
DBGMSG(DBG_ERROR, ("DoRemoteOpenPrinter failed SetEvent pSpool %x pSpool->hWaitValidHandle %x\n",
pSpool, pSpool->hWaitValidHandle ));
}
LeaveSplSem();
// Check Cache Consistency
// The Workstation and the Server have a version ID
// If the version number has changed on the server then update the
// workstation Cache.
ConsistencyCheckCache( pSpool );
SplOutSem();
return ( bReturnValue );
}
DWORD
RemoteOpenPrinterThread(
PWSPOOL pSpool
)
{
DWORD Status;
SplOutSem();
SPLASSERT( pSpool->signature == WSJ_SIGNATURE );
SetCurrentSid( pSpool->hToken );
DoRemoteOpenPrinter( pSpool->pName, &pSpool->PrinterDefaults, pSpool );
SplOutSem();
EnterSplSem();
SPLASSERT( pSpool->cRef != 0 );
pSpool->cRef--;
Status = pSpool->Status;
LeaveSplSem();
if ( Status & WSPOOL_STATUS_PENDING_DELETE ) {
DBGMSG(DBG_TRACE,
("RemoteOpenPrinterThread - WSPOOL_STATUS_PENDING_DELETE closing handle %x\n",
pSpool ));
SPLASSERT( pSpool->cRef == 0 );
CacheClosePrinter( pSpool );
pSpool = NULL;
}
SetCurrentSid( NULL );
SplOutSem();
ExitThread( 0 );
return ( 0 );
}
PWSPOOL
AllocWSpool(
VOID
)
{
PWSPOOL pSpool = NULL;
SplInSem();
if (pSpool = AllocSplMem(sizeof(WSPOOL))) {
pSpool->signature = WSJ_SIGNATURE;
pSpool->Type = SJ_WIN32HANDLE;
pSpool->RpcHandle = INVALID_HANDLE_VALUE;
pSpool->hFile = INVALID_HANDLE_VALUE;
pSpool->hIniSpooler = INVALID_HANDLE_VALUE;
pSpool->hSplPrinter = INVALID_HANDLE_VALUE;
pSpool->hToken = INVALID_HANDLE_VALUE;
pSpool->hWaitValidHandle = INVALID_HANDLE_VALUE;
// Add to List
pSpool->pNext = pFirstWSpool;
pSpool->pPrev = NULL;
if ( pFirstWSpool != NULL ) {
pFirstWSpool->pPrev = pSpool;
}
pFirstWSpool = pSpool;
} else {
DBGMSG( DBG_WARNING, ("AllocWSpool failed %d\n", GetLastError() ));
}
return ( pSpool );
}
VOID
FreepSpool(
PWSPOOL pSpool
)
{
SplInSem();
if ( pSpool->cRef == 0 ) {
SPLASSERT( pSpool->hSplPrinter == INVALID_HANDLE_VALUE );
SPLASSERT( pSpool->hIniSpooler == INVALID_HANDLE_VALUE );
SPLASSERT( pSpool->RpcHandle == INVALID_HANDLE_VALUE );
SPLASSERT( pSpool->hFile == INVALID_HANDLE_VALUE );
if( pSpool->hWaitValidHandle != INVALID_HANDLE_VALUE ) {
SetEvent( pSpool->hWaitValidHandle );
CloseHandle( pSpool->hWaitValidHandle );
pSpool->hWaitValidHandle = INVALID_HANDLE_VALUE;
}
if( pSpool->hToken != INVALID_HANDLE_VALUE ) {
CloseHandle( pSpool->hToken );
pSpool->hToken = INVALID_HANDLE_VALUE;
}
// Remove form linked List
if ( pSpool->pNext != NULL ) {
SPLASSERT( pSpool->pNext->pPrev == pSpool);
pSpool->pNext->pPrev = pSpool->pPrev;
}
if ( pSpool->pPrev == NULL ) {
SPLASSERT( pFirstWSpool == pSpool );
pFirstWSpool = pSpool->pNext;
} else {
SPLASSERT( pSpool->pPrev->pNext == pSpool );
pSpool->pPrev->pNext = pSpool->pNext;
}
FreeSplStr( pSpool->pName );
FreeSplStr( pSpool->PrinterDefaults.pDatatype );
if ( pSpool->PrinterDefaults.pDevMode != NULL ) {
FreeSplMem( pSpool->PrinterDefaults.pDevMode );
}
FreeSplMem(pSpool);
// DbgDelHandle( pSpool );
} else {
pSpool->Status |= WSPOOL_STATUS_PENDING_DELETE;
}
}
BOOL
CacheClosePrinter(
HANDLE hPrinter
)
{
BOOL ReturnValue = TRUE;
PWSPOOL pSpool = (PWSPOOL)hPrinter;
VALIDATEW32HANDLE( pSpool );
if (pSpool->Status & WSPOOL_STATUS_PRINT_FILE) {
RemoteEndDocPrinter( pSpool );
}
SplOutSem();
EnterSplSem();
if ( pSpool->Status & WSPOOL_STATUS_TEMP_CONNECTION ) {
pSpool->Status &= ~WSPOOL_STATUS_TEMP_CONNECTION;
LeaveSplSem();
if (!DeletePrinterConnection( pSpool->pName )) {
DBGMSG( DBG_TRACE, ("CacheClosePrinter failed DeletePrinterConnection %ws %d\n",
pSpool->pName, GetLastError() ));
}
EnterSplSem();
SPLASSERT( pSpool->signature == WSJ_SIGNATURE );
}
SplInSem();
if ( pSpool->Status & WSPOOL_STATUS_USE_CACHE ) {
if ( pSpool->cRef == 0 ) {
pSpool->cRef++;
if ( pSpool->RpcHandle != INVALID_HANDLE_VALUE ) {
DBGMSG(DBG_TRACE, ("CacheClosePrinter pSpool %x RpcHandle %x Status %x cRef %d\n",
pSpool, pSpool->RpcHandle, pSpool->Status, pSpool->cRef));
LeaveSplSem();
SplOutSem();
ReturnValue = RemoteClosePrinter( hPrinter );
EnterSplSem();
}
SplInSem();
SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
SPLASSERT( pSpool->hSplPrinter != INVALID_HANDLE_VALUE );
LeaveSplSem();
SplOutSem();
SplClosePrinter( pSpool->hSplPrinter );
SplCloseSpooler( pSpool->hIniSpooler );
EnterSplSem();
pSpool->hSplPrinter = INVALID_HANDLE_VALUE;
pSpool->hIniSpooler = INVALID_HANDLE_VALUE;
pSpool->Status &= ~WSPOOL_STATUS_USE_CACHE;
pSpool->cRef--;
SPLASSERT( pSpool->cRef == 0 );
}
FreepSpool( pSpool );
LeaveSplSem();
} else {
LeaveSplSem();
SplOutSem();
if ( pSpool->hIniSpooler != INVALID_HANDLE_VALUE ) {
SplCloseSpooler( pSpool->hIniSpooler );
pSpool->hIniSpooler = INVALID_HANDLE_VALUE;
}
ReturnValue = RemoteClosePrinter( hPrinter );
}
SplOutSem();
return ( ReturnValue );
}
BOOL
CacheSyncRpcHandle(
PWSPOOL pSpool
)
{
DWORD dwLastError;
EnterSplSem();
if ( pSpool->Status & WSPOOL_STATUS_NO_RPC_HANDLE ) {
LeaveSplSem();
DBGMSG(DBG_TRACE,("CacheSyncRpcHandle Status WSPOOL_STATUS_NO_RPC_HANDLE waiting for RpcHandle....\n"));
SplOutSem();
WaitForSingleObject( pSpool->hWaitValidHandle, INFINITE );
EnterSplSem();
}
if ( pSpool->Status & WSPOOL_STATUS_OPEN_ERROR ) {
DBGMSG(DBG_WARNING, ("CacheSyncRpcHandle pSpool %x Status %x; setting last error = %d\n",
pSpool,
pSpool->Status,
pSpool->RpcError));
dwLastError = pSpool->RpcError;
// If we failed to open the Server because it was unavailable
// then try and open it again ( provded the asynchronous thread is not active ).
if (!( pSpool->Status & WSPOOL_STATUS_PENDING_DELETE ) &&
( pSpool->RpcHandle == INVALID_HANDLE_VALUE ) &&
( pSpool->RpcError != ERROR_ACCESS_DENIED ) &&
( pSpool->cRef == 0 ) ) {
CloseHandle( pSpool->hWaitValidHandle );
pSpool->hWaitValidHandle = INVALID_HANDLE_VALUE;
pSpool->Status |= WSPOOL_STATUS_NO_RPC_HANDLE;
DBGMSG( DBG_WARNING, ("CacheSyncRpcHandle retrying Async OpenPrinter\n"));
if ( !DoAsyncRemoteOpenPrinter( pSpool, &pSpool->PrinterDefaults ) ) {
pSpool->Status &= ~WSPOOL_STATUS_NO_RPC_HANDLE;
SetEvent( pSpool->hWaitValidHandle );
}
}
LeaveSplSem();
SPLASSERT( dwLastError );
SetLastError( dwLastError );
return FALSE;
}
LeaveSplSem();
if ( pSpool->RpcHandle != INVALID_HANDLE_VALUE &&
pSpool->Status & WSPOOL_STATUS_RESETPRINTER_PENDING ) {
DBGMSG(DBG_TRACE, ("CacheSyncRpcHandle calling RemoteResetPrinter\n"));
pSpool->Status &= ~ WSPOOL_STATUS_RESETPRINTER_PENDING;
if ( ! RemoteResetPrinter( pSpool, &pSpool->PrinterDefaults ) ) {
pSpool->Status |= WSPOOL_STATUS_RESETPRINTER_PENDING;
}
}
return TRUE;
}
BOOL
CacheGetPrinterDriver(
HANDLE hPrinter,
LPWSTR pEnvironment,
DWORD Level,
LPBYTE pDriverInfo,
DWORD cbBuf,
LPDWORD pcbNeeded
)
{
BOOL ReturnValue = FALSE;
PWSPOOL pSpool = (PWSPOOL) hPrinter;
DWORD dwServerMajorVersion = 0;
DWORD dwServerMinorVersion = 0;
VALIDATEW32HANDLE( pSpool );
try {
if (pSpool->Type != SJ_WIN32HANDLE) {
SetLastError(ERROR_INVALID_FUNCTION);
leave;
}
if ( !(pSpool->Status & WSPOOL_STATUS_USE_CACHE) ) {
// Someone is calling GetPrinterDriver without a connection
// we must NEVER EVER pass the caller a UNC name since they
// will LoadLibrary accross the network, which might lead
// to InPageIOErrors ( if the net goes down).
// The solution is to establish a Temporary Connection for the life
// of the pSpool handle, the connection will be removed
// in CacheClosePrinter. The connection will ensure that the
// drivers are copied locally and a local cache is established
// for this printer.
pSpool->Status |= WSPOOL_STATUS_TEMP_CONNECTION;
ReturnValue = AddPrinterConnection( pSpool->pName );
if ( !ReturnValue ) {
pSpool->Status &= ~WSPOOL_STATUS_TEMP_CONNECTION;
DBGMSG( DBG_TRACE, ("CacheGetPrinterDriver failed AddPrinterConnection %d\n",
GetLastError() ));
leave;
}
ReturnValue = OpenCachePrinterOnly( pSpool->pName, &pSpool->hSplPrinter, &pSpool->hIniSpooler, NULL );
if ( !ReturnValue ) {
SplCloseSpooler( pSpool->hIniSpooler );
DBGMSG( DBG_WARNING, ("CacheGetPrinterDriver Connection OK Failed CacheOpenPrinter %d\n",
GetLastError() ));
leave;
}
pSpool->Status |= WSPOOL_STATUS_USE_CACHE;
}
SPLASSERT( pSpool->Status & WSPOOL_STATUS_USE_CACHE );
ReturnValue = SplGetPrinterDriverEx( pSpool->hSplPrinter,
pEnvironment,
Level,
pDriverInfo,
cbBuf,
pcbNeeded,
cThisMajorVersion,
cThisMinorVersion,
&dwServerMajorVersion,
&dwServerMinorVersion);
} finally {
}
return ReturnValue;
}
BOOL
CacheResetPrinter(
HANDLE hPrinter,
LPPRINTER_DEFAULTS pDefault
)
{
PWSPOOL pSpool = (PWSPOOL) hPrinter;
BOOL ReturnValue = FALSE;
VALIDATEW32HANDLE( pSpool );
if ( pSpool->Status & WSPOOL_STATUS_USE_CACHE ) {
EnterSplSem();
ReturnValue = SplResetPrinter( pSpool->hSplPrinter,
pDefault );
if ( ReturnValue ) {
CopypDefaultTopSpool( pSpool, pDefault );
if ( pSpool->RpcHandle != INVALID_HANDLE_VALUE ) {
//
// Have RPC Handle
//
LeaveSplSem();
ReturnValue = RemoteResetPrinter( hPrinter, pDefault );
} else {
//
// No RpcHandle
//
DBGMSG( DBG_TRACE, ("CacheResetPrinter %x NO_RPC_HANDLE Status Pending\n",
pSpool ));
pSpool->Status |= WSPOOL_STATUS_RESETPRINTER_PENDING;
LeaveSplSem();
}
}
} else {
ReturnValue = RemoteResetPrinter( hPrinter, pDefault );
}
return ReturnValue;
}
BOOL
CacheGetPrinter(
HANDLE hPrinter,
DWORD Level,
LPBYTE pPrinter,
DWORD cbBuf,
LPDWORD pcbNeeded
)
{
PWSPOOL pSpool = (PWSPOOL) hPrinter;
BOOL ReturnValue = FALSE;
PWCACHEINIPRINTEREXTRA pExtraData = NULL;
DWORD LastError = ERROR_SUCCESS;
DWORD cbSize = 0;
DWORD cbDevMode;
DWORD cbSecDesc;
LPWSTR SourceStrings[sizeof(PRINTER_INFO_2)/sizeof(LPWSTR)];
LPWSTR *pSourceStrings=SourceStrings;
LPBYTE pEnd;
DWORD *pOffsets;
PPRINTER_INFO_2W pPrinter2 = (PPRINTER_INFO_2)pPrinter;
BOOL bCallRemote = TRUE;
VALIDATEW32HANDLE( pSpool );
try {
if ( Level == 2 &&
(pSpool->Status & WSPOOL_STATUS_USE_CACHE) ) {
ReturnValue = SplGetPrinterExtra( pSpool->hSplPrinter, &(DWORD)pExtraData );
if ( ReturnValue ) {
if ( (GetTickCount() - pExtraData->dwTickCount) < REFRESH_TIMEOUT )
bCallRemote = FALSE;
}
pExtraData = NULL;
}
if ( ((pSpool->RpcHandle != INVALID_HANDLE_VALUE ) && bCallRemote ) ||
( pSpool->PrinterDefaults.DesiredAccess & PRINTER_ACCESS_ADMINISTER ) ||
!( pSpool->Status & WSPOOL_STATUS_USE_CACHE ) ||
( Level == GET_SECURITY_DESCRIPTOR ) ||
( Level == STRESSINFOLEVEL )) {
ReturnValue = RemoteGetPrinter( hPrinter,
Level,
pPrinter,
cbBuf,
pcbNeeded );
if ( ReturnValue ) {
leave;
}
LastError = GetLastError();
if (( pSpool->PrinterDefaults.DesiredAccess & PRINTER_ACCESS_ADMINISTER ) ||
!( pSpool->Status & WSPOOL_STATUS_USE_CACHE ) ||
( Level == GET_SECURITY_DESCRIPTOR ) ||
( Level == STRESSINFOLEVEL )) {
leave;
}
SPLASSERT( pSpool->Status & WSPOOL_STATUS_USE_CACHE );
if (( LastError != RPC_S_SERVER_UNAVAILABLE ) &&
( LastError != RPC_S_CALL_FAILED ) &&
( LastError != RPC_S_CALL_FAILED_DNE ) &&
( LastError != ERROR_INVALID_HANDLE ) &&
( LastError != RPC_S_SERVER_TOO_BUSY )) {
// Valid Error like ERROR_INSUFFICIENT_BUFFER
leave;
}
if ( LastError == ERROR_INVALID_HANDLE ) {
//
// The Server Must have gone down and come
// back up now our RpcHandle is bad
// so reopen it
//
pSpool->RpcError = LastError;
pSpool->Status |= WSPOOL_STATUS_OPEN_ERROR;
pSpool->RpcHandle = INVALID_HANDLE_VALUE;
SPLASSERT( !( pSpool->Status & WSPOOL_STATUS_NO_RPC_HANDLE) );
CacheSyncRpcHandle( pSpool );
}
}
SPLASSERT( pSpool->Status & WSPOOL_STATUS_USE_CACHE );
switch ( Level ) {
case 1:
ReturnValue = SplGetPrinter( pSpool->hSplPrinter,
Level,
pPrinter,
cbBuf,
pcbNeeded );
if ( ReturnValue == FALSE ) {
LastError = GetLastError();
}
break;
case 2:
EnterSplSem();
ReturnValue = SplGetPrinterExtra( pSpool->hSplPrinter, &(DWORD)pExtraData );
if ( ReturnValue == FALSE ) {
DBGMSG( DBG_WARNING, ("CacheGetPrinter SplGetPrinterExtra pSpool %x error %d\n", pSpool, GetLastError() ));
SPLASSERT( ReturnValue );
}
if ( pExtraData == NULL ) {
LeaveSplSem();
break;
}
SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
cbSize = pExtraData->cbPI2;
*pcbNeeded = cbSize;
if ( cbSize > cbBuf ) {
LastError = ERROR_INSUFFICIENT_BUFFER;
ReturnValue = FALSE;
LeaveSplSem();
break;
}
// NOTE
// In the case of EnumerateFavoritePrinters it expects us to pack our
// strings at the end of the structure not just following it.
// You might wrongly assume that you could just copy the complete structure
// inluding strings but you would be wrong.
*pSourceStrings++ = pExtraData->pPI2->pServerName;
*pSourceStrings++ = pExtraData->pPI2->pPrinterName;
*pSourceStrings++ = pExtraData->pPI2->pShareName;
*pSourceStrings++ = pExtraData->pPI2->pPortName;
*pSourceStrings++ = pExtraData->pPI2->pDriverName;
*pSourceStrings++ = pExtraData->pPI2->pComment;
*pSourceStrings++ = pExtraData->pPI2->pLocation;
*pSourceStrings++ = pExtraData->pPI2->pSepFile;
*pSourceStrings++ = pExtraData->pPI2->pPrintProcessor;
*pSourceStrings++ = pExtraData->pPI2->pDatatype;
*pSourceStrings++ = pExtraData->pPI2->pParameters;
pOffsets = PrinterInfo2Strings;
pEnd = pPrinter + cbBuf;
pEnd = PackStrings(SourceStrings, pPrinter, pOffsets, pEnd);
if ( pExtraData->pPI2->pDevMode != NULL ) {
cbDevMode = ( pExtraData->pPI2->pDevMode->dmSize + pExtraData->pPI2->pDevMode->dmDriverExtra );
pEnd -= cbDevMode;
pEnd = (LPBYTE)((DWORD)pEnd & ~3);
pPrinter2->pDevMode = (LPDEVMODE)pEnd;
CopyMemory(pPrinter2->pDevMode, pExtraData->pPI2->pDevMode, cbDevMode );
} else {
pPrinter2->pDevMode = NULL;
}
if ( pExtraData->pPI2->pSecurityDescriptor != NULL ) {
cbSecDesc = GetSecurityDescriptorLength( pExtraData->pPI2->pSecurityDescriptor );
pEnd -= cbSecDesc;
pEnd = (LPBYTE)((DWORD)pEnd & ~3);
pPrinter2->pSecurityDescriptor = pEnd;
CopyMemory( pPrinter2->pSecurityDescriptor, pExtraData->pPI2->pSecurityDescriptor, cbSecDesc );
} else {
pPrinter2->pSecurityDescriptor = NULL;
}
pPrinter2->Attributes = pExtraData->pPI2->Attributes;
pPrinter2->Priority = pExtraData->pPI2->Priority;
pPrinter2->DefaultPriority = pExtraData->pPI2->DefaultPriority;
pPrinter2->StartTime = pExtraData->pPI2->StartTime;
pPrinter2->UntilTime = pExtraData->pPI2->UntilTime;
pPrinter2->Status = pExtraData->pPI2->Status;
pPrinter2->cJobs = pExtraData->pPI2->cJobs;
pPrinter2->AveragePPM = pExtraData->pPI2->AveragePPM;
ReturnValue = TRUE;
LeaveSplSem();
break;
case 3:
DBGMSG( DBG_ERROR, ("CacheGetPrinter Level 3 impossible\n"));
default:
LastError = ERROR_INVALID_LEVEL;
ReturnValue = FALSE;
break;
}
} finally {
if ( !ReturnValue ) {
SetLastError( LastError );
}
}
return ReturnValue;
}
//
// Called When the Printer is read back from the registry
//
PWCACHEINIPRINTEREXTRA
CacheReadRegistryExtra(
HKEY hPrinterKey
)
{
PWCACHEINIPRINTEREXTRA pExtraData = NULL;
LONG ReturnValue;
PPRINTER_INFO_2W pPrinterInfo2 = NULL;
DWORD cbSizeRequested = 0;
DWORD cbSizeInfo2 = 0;
ReturnValue = RegQueryValueEx( hPrinterKey, szCachePrinterInfo2, NULL, NULL, NULL, &cbSizeRequested );
if ((ReturnValue == ERROR_MORE_DATA) || (ReturnValue == ERROR_SUCCESS)) {
cbSizeInfo2 = cbSizeRequested;
pPrinterInfo2 = AllocSplMem( cbSizeInfo2 );
if ( pPrinterInfo2 != NULL ) {
ReturnValue = RegQueryValueEx( hPrinterKey,
szCachePrinterInfo2,
NULL, NULL, (LPBYTE)pPrinterInfo2,
&cbSizeRequested );
if ( ReturnValue == ERROR_SUCCESS ) {
//
// Cached Structures on Disk have offsets for pointers
//
MarshallUpStructure( (LPBYTE)pPrinterInfo2, PrinterInfo2Offsets );
pExtraData = AllocExtraData( pPrinterInfo2, cbSizeInfo2 );
}
FreeSplMem( pPrinterInfo2 );
}
}
//
// Read the timestamp for the Cached Printer Data
//
if ( pExtraData != NULL ) {
cbSizeRequested = sizeof( pExtraData->cCacheID );
ReturnValue = RegQueryValueEx(hPrinterKey,
szCacheTimeLastChange,
NULL, NULL,
(LPBYTE)&pExtraData->cCacheID, &cbSizeRequested );
// Read the Connection Reference Count
cbSizeRequested = sizeof( pExtraData->cRef );
ReturnValue = RegQueryValueEx(hPrinterKey,
szcRef,
NULL, NULL,
(LPBYTE)&pExtraData->cRef, &cbSizeRequested );
cbSizeRequested = sizeof(pExtraData->dwServerVersion);
ReturnValue = RegQueryValueEx(hPrinterKey,
szServerVersion,
NULL, NULL,
(LPBYTE)&pExtraData->dwServerVersion,
&cbSizeRequested);
}
return pExtraData;
}
BOOL
CacheWriteRegistryExtra(
LPWSTR pName,
HKEY hPrinterKey,
PWCACHEINIPRINTEREXTRA pExtraData
)
{
PPRINTER_INFO_2 pPrinterInfo2 = NULL;
DWORD cbSize = 0;
DWORD dwLastError = ERROR_SUCCESS;
DWORD Status;
if ( pExtraData == NULL ) return FALSE;
SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
cbSize = pExtraData->cbPI2;
if ( cbSize != 0 ) {
pPrinterInfo2 = AllocSplMem( cbSize );
if ( pPrinterInfo2 != NULL ) {
CacheCopyPrinterInfo( pPrinterInfo2, pExtraData->pPI2, cbSize );
//
// Before writing it to the regsitry make all pointers offsets
//
MarshallDownStructure( (LPBYTE)pPrinterInfo2, PrinterInfo2Offsets );
dwLastError = RegSetValueEx( hPrinterKey, szCachePrinterInfo2, 0, REG_BINARY, (LPBYTE)pPrinterInfo2, cbSize );
FreeSplMem( pPrinterInfo2 );
} else {
dwLastError = GetLastError();
}
}
//
// Write Cache TimeStamp to Registry
//
cbSize = sizeof ( pExtraData->cCacheID );
Status = RegSetValueEx( hPrinterKey, szCacheTimeLastChange, 0, REG_DWORD, (LPBYTE)&pExtraData->cCacheID, cbSize );
if ( Status != ERROR_SUCCESS ) dwLastError = Status;
cbSize = sizeof(pExtraData->dwServerVersion);
Status = RegSetValueEx( hPrinterKey, szServerVersion, 0, REG_DWORD, (LPBYTE)&pExtraData->dwServerVersion, cbSize );
if ( Status != ERROR_SUCCESS ) dwLastError = Status;
cbSize = sizeof ( pExtraData->cRef );
Status = RegSetValueEx( hPrinterKey, szcRef, 0, REG_DWORD, (LPBYTE)&pExtraData->cRef, cbSize );
if ( Status != ERROR_SUCCESS ) dwLastError = Status;
if ( dwLastError == ERROR_SUCCESS ) {
return TRUE;
} else {
SetLastError( dwLastError );
return FALSE;
}
}
VOID
ConsistencyCheckCache(
PWSPOOL pSpool
)
{
BOOL ReturnValue;
DWORD cbBuf = MAX_PRINTER_INFO0;
BYTE PrinterInfoW0[ MAX_PRINTER_INFO0 ];
LPPRINTER_INFO_STRESSW pPrinter0 = (LPPRINTER_INFO_STRESSW)&PrinterInfoW0;
DWORD dwNeeded;
PWCACHEINIPRINTEREXTRA pExtraData;
BOOL bGetPrinterExtra = TRUE;
if ( ( pSpool->RpcHandle == INVALID_HANDLE_VALUE ) ||
!( pSpool->Status & WSPOOL_STATUS_USE_CACHE )) {
return;
}
SPLASSERT( pSpool->Status & WSPOOL_STATUS_USE_CACHE );
//
// Keep Updating our Cache until we match the Server
//
while ( TRUE ) {
ReturnValue = RemoteGetPrinter( pSpool, STRESSINFOLEVEL, (LPBYTE)&PrinterInfoW0, cbBuf, &dwNeeded );
if ( !ReturnValue ) {
SPLASSERT( GetLastError() != ERROR_INSUFFICIENT_BUFFER );
DBGMSG( DBG_TRACE, ("ConsistencyCheckCache failed RemoteGetPrinter %d\n", GetLastError() ));
break;
}
bGetPrinterExtra = SplGetPrinterExtra( pSpool->hSplPrinter, &(DWORD)pExtraData );
if ( !bGetPrinterExtra ) {
DBGMSG( DBG_WARNING, ("ConsistencyCheckCache SplGetPrinterExtra pSpool %x error %d\n", pSpool, GetLastError() ));
SPLASSERT( bGetPrinterExtra );
break;
}
if ( pExtraData != NULL ) {
SPLASSERT( pExtraData->signature == WCIP_SIGNATURE );
SPLASSERT( pExtraData->pPI2 != NULL );
//
// Try to keep the cJobs in the Cache as up to date as possible
// Some apps do OpenPrinter GetPrinter ClosePrinter and pole
// will at least get something as accurate as the last successful open
//
pExtraData->pPI2->cJobs = pPrinter0->cJobs;
pExtraData->pPI2->Status = pPrinter0->Status;
pExtraData->dwTickCount = GetTickCount();
if ( pExtraData->cCacheID == pPrinter0->cChangeID ) {
// Nothing to do the CacheID has NOT changed.
break;
}
DBGMSG( DBG_TRACE, ("ConsistencyCheckCache << Server cCacheID %x Workstation cChangeID %x >>\n",
pPrinter0->cChangeID,
pExtraData->cCacheID ));
//
// Don't have tons of threads doing a refresh at the same time
// In stress when there are lots of folks changing printer settings
// so the cChangeId changes a lot, but we don't want multiple threads
// all doing a refresh since you get a LOT, it doesn't buy anything
//
EnterSplSem();
if ( pExtraData->Status & EXTRA_STATUS_DOING_REFRESH ) {
LeaveSplSem();
break;
}
pExtraData->Status |= EXTRA_STATUS_DOING_REFRESH;
pExtraData->cCacheID = pPrinter0->cChangeID;
pExtraData->dwServerVersion = pPrinter0->dwGetVersion;
LeaveSplSem();
RefreshCompletePrinterCache( pSpool );
EnterSplSem();
SPLASSERT( pExtraData->Status & EXTRA_STATUS_DOING_REFRESH );
pExtraData->Status &= ~EXTRA_STATUS_DOING_REFRESH;
LeaveSplSem();
} else {
DBGMSG( DBG_WARNING, ("ConsistencyCheckCache Should NEVER get here, pExtraData == NULL contact MattFe pSpool %x\n", pSpool ));
break;
}
}
}
BOOL
RefreshPrinterDriver(
PWSPOOL pSpool
)
{
LPBYTE pDriverInfo = NULL;
DWORD cbDriverInfo = MAX_DRIVER_INFO_3;
DWORD cbNeeded, Level, dwLastError = ERROR_SUCCESS;
BOOL bReturnValue = FALSE;
SPLASSERT( pSpool->hIniSpooler != INVALID_HANDLE_VALUE );
try {
pDriverInfo = AllocSplMem( cbDriverInfo );
if ( pDriverInfo == NULL ) {
leave;
}
Level = 3;
bReturnValue = CopyDriversLocally(pSpool, szEnvironment, pDriverInfo, Level, cbDriverInfo, &cbNeeded);
if ( !bReturnValue && (dwLastError = GetLastError()) == ERROR_INVALID_LEVEL ) {
Level = 2;
bReturnValue = CopyDriversLocally(pSpool, szEnvironment, pDriverInfo, Level, cbDriverInfo, &cbNeeded);
if ( !bReturnValue ) {
dwLastError = GetLastError();
}
}
if ( !bReturnValue ) {
if ( dwLastError == ERROR_INSUFFICIENT_BUFFER ) {
if ( pDriverInfo ) {
FreeSplMem( pDriverInfo );
}
if ( !(pDriverInfo=AllocSplMem(cbNeeded)) ) {
leave;
}
cbDriverInfo = cbNeeded;
bReturnValue = CopyDriversLocally(pSpool, szEnvironment, pDriverInfo, Level, cbDriverInfo, &cbNeeded);
}
}
if ( bReturnValue ) {
// Do Not add to KHKEY_CURRENT_USER for Temp connections
if ( !pSpool->Status & WSPOOL_STATUS_TEMP_CONNECTION ) {
bReturnValue = SavePrinterConnectionInRegistry( pSpool->pName, pDriverInfo, Level );
}
}
} finally {
if ( pDriverInfo != NULL ) {
FreeSplMem( pDriverInfo );
}
}
if ( !bReturnValue ) {
DBGMSG( DBG_WARNING, ("RefreshPrinterDriver Failed SplAddPrinterDriver %d\n", GetLastError() ));
}
return bReturnValue;
}
BOOL
OpenCachePrinterOnly(
LPWSTR pName,
LPHANDLE phSplPrinter,
LPHANDLE phIniSpooler,
LPPRINTER_DEFAULTS pDefault
)
{
PWCHAR pMachineName = NULL;
PWCHAR pPrinterName;
BOOL ReturnValue = FALSE;
if (!VALIDATE_NAME(pName)) {
SetLastError(ERROR_INVALID_NAME);
return FALSE;
}
try {
//
// See if we already known about this server in the cache
//
DBGMSG(DBG_TRACE, ("OpenCachePrinterOnly pName %ws \n",pName));
//
// Find the Machine Name
//
SPLASSERT ( 0 == _wcsnicmp( pName, L"\\\\", 2 ) ) ;
pMachineName = AllocSplStr( pName );
if ( pMachineName == NULL )
leave;
// Get Past leading \\ or \\server\printer
pPrinterName = pMachineName + 2;
pPrinterName = wcschr( pPrinterName, L'\\' );
//
// If this is a \\ServerName only Open then don't bother with Cache
//
if ( pPrinterName == NULL ) {
leave;
}
*pPrinterName = L'\0';
DBGMSG(DBG_TRACE,("MachineName %ws pName %ws\n", pMachineName, pName));
//
// Does this Machine Exist in the Cache ?
//
*phIniSpooler = CacheCreateSpooler( pMachineName );
if ( *phIniSpooler == INVALID_HANDLE_VALUE ) {
leave;
}
//
// Try to Open the Cached Printer
//
ReturnValue = SplOpenPrinter( pName ,
phSplPrinter,
pDefault,
*phIniSpooler,
NULL,
0) == ROUTER_SUCCESS;
} finally {
FreeSplStr( pMachineName );
}
return ReturnValue;
}