mirror of https://github.com/lianthony/NT4.0
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.
3918 lines
121 KiB
3918 lines
121 KiB
/*++
|
|
|
|
Copyright (c) 1990 - 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
init.c
|
|
|
|
Abstract:
|
|
|
|
This module has all the initialization functions for the Local Print Provider
|
|
|
|
Author:
|
|
|
|
Dave Snipp (DaveSn) 15-Mar-1991
|
|
|
|
Revision History:
|
|
|
|
Muhunthan Sivapragasam (MuhuntS) 1-June-1995
|
|
Driver info 3 changes; Changes to use RegGetString, RegGetDword etc
|
|
|
|
Matthew A Felton (MattFe) 27-June-1994
|
|
pIniSpooler - allow other providers to call the spooler functions in LocalSpl
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
#include <lm.h>
|
|
#include <winbasep.h>
|
|
|
|
MODULE_DEBUG_INIT( DBG_ERROR | DBG_WARN, DBG_ERROR );
|
|
|
|
VOID
|
|
BuildOtherNamesFromMachineName(
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
BOOL
|
|
NotIniSpooler(
|
|
BYTE *pMem
|
|
);
|
|
|
|
|
|
PINIDRIVER
|
|
GetDriverList(
|
|
HKEY hVersionKey,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
PINIVERSION
|
|
GetVersionDrivers(
|
|
HKEY hDriversKey,
|
|
LPWSTR VersionName,
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
VOID
|
|
GetPrintSystemVersion(
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
|
|
|
|
VOID
|
|
WaitForSpoolerInitialization(
|
|
VOID
|
|
);
|
|
|
|
|
|
BOOL
|
|
LocalRefreshPrinterChangeNotification(
|
|
HANDLE hPrinter,
|
|
DWORD dwColor,
|
|
PVOID pPrinterNotifyRefresh,
|
|
LPVOID* ppPrinterNotifyInfo
|
|
);
|
|
|
|
|
|
LPWSTR
|
|
FormatRegistryKeyForPrinter(
|
|
LPWSTR pSource, /* The string from which backslashes are to be added. */
|
|
LPWSTR pScratch /* Scratch buffer for the function to write in; */
|
|
); /* must be at least as long as pSource. */
|
|
|
|
#define MAX_LENGTH_DRIVERS_SHARE_REMARK 256
|
|
|
|
WCHAR *szSpoolDirectory = L"\\spool";
|
|
WCHAR *szPrintShareName = L""; /* No share for printers in product1 */
|
|
WCHAR *szPrintDirectory = L"\\printers";
|
|
WCHAR *szDriversDirectory = L"\\drivers";
|
|
|
|
|
|
SHARE_INFO_2 DriversShareInfo={NULL, /* Netname - initialized below */
|
|
STYPE_DISKTREE, /* Type of share */
|
|
NULL, /* Remark */
|
|
0, /* Default permissions */
|
|
SHI_USES_UNLIMITED, /* No users limit */
|
|
SHI_USES_UNLIMITED, /* Current uses (??) */
|
|
NULL, /* Path - initialized below */
|
|
NULL}; /* No password */
|
|
|
|
|
|
// WARNING
|
|
// Do not access these directly always go via pIniSpooler->pszRegistr...
|
|
// This will then work for multiple pIniSpoolers
|
|
|
|
PWCHAR ipszRegistryRoot = L"System\\CurrentControlSet\\Control\\Print";
|
|
PWCHAR ipszRegistryPrinters = L"System\\CurrentControlSet\\Control\\Print\\Printers";
|
|
PWCHAR ipszRegistryMonitors = L"System\\CurrentControlSet\\Control\\Print\\Monitors";
|
|
PWCHAR ipszRegistryEnvironments = L"System\\CurrentControlSet\\Control\\Print\\Environments";
|
|
PWCHAR ipszRegistryEventLog = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\System\\Print";
|
|
PWCHAR ipszRegistryProviders = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Providers";
|
|
PWCHAR ipszEventLogMsgFile = L"%SystemRoot%\\System32\\LocalSpl.dll";
|
|
PWCHAR ipszDriversShareName = L"print$";
|
|
PWCHAR ipszRegistryForms = L"System\\CurrentControlSet\\Control\\Print\\Forms";
|
|
|
|
PWCHAR ipszRegistryWin32Root = L"System\\CurrentControlSet\\Control\\Print\\Providers\\LanMan Print Services\\Servers";
|
|
//
|
|
//
|
|
|
|
WCHAR *szPrinterData = L"PrinterDriverData";
|
|
WCHAR *szConfigurationKey = L"Configuration File";
|
|
WCHAR *szDataFileKey = L"Data File";
|
|
WCHAR *szDriverVersion = L"Version";
|
|
WCHAR *szDriversKey = L"Drivers";
|
|
WCHAR *szPrintProcKey = L"Print Processors";
|
|
WCHAR *szPrintersKey = L"Printers";
|
|
WCHAR *szEnvironmentsKey = L"Environments";
|
|
WCHAR *szDirectory = L"Directory";
|
|
WCHAR *szDriverIni = L"Drivers.ini";
|
|
WCHAR *szDriverFile = L"Driver";
|
|
WCHAR *szDriverDataFile = L"DataFile";
|
|
WCHAR *szDriverConfigFile = L"ConfigFile";
|
|
WCHAR *szDriverDir = L"DRIVERS";
|
|
WCHAR *szPrintProcDir = L"PRTPROCS";
|
|
WCHAR *szPrinterDir = L"PRINTERS";
|
|
WCHAR *szPrinterIni = L"\\printer.ini";
|
|
WCHAR *szAllShadows = L"\\*.SHD";
|
|
WCHAR *szNullPort = L"NULL";
|
|
WCHAR *szComma = L",";
|
|
WCHAR *szName = L"Name";
|
|
WCHAR *szShare = L"Share Name";
|
|
WCHAR *szPort = L"Port";
|
|
WCHAR *szPrintProcessor = L"Print Processor";
|
|
WCHAR *szDatatype = L"Datatype";
|
|
WCHAR *szDriver = L"Printer Driver";
|
|
WCHAR *szLocation = L"Location";
|
|
WCHAR *szDescription = L"Description";
|
|
WCHAR *szAttributes = L"Attributes";
|
|
WCHAR *szStatus = L"Status";
|
|
WCHAR *szPriority = L"Priority";
|
|
WCHAR *szDefaultPriority = L"Default Priority";
|
|
WCHAR *szUntilTime = L"UntilTime";
|
|
WCHAR *szStartTime = L"StartTime";
|
|
WCHAR *szParameters = L"Parameters";
|
|
WCHAR *szSepFile = L"Separator File";
|
|
WCHAR *szDevMode = L"Default DevMode";
|
|
WCHAR *szSecurity = L"Security";
|
|
WCHAR *szSpoolDir = L"SpoolDirectory";
|
|
WCHAR *szNetMsgDll = L"NETMSG.DLL";
|
|
WCHAR *szMajorVersion = L"MajorVersion";
|
|
WCHAR *szMinorVersion = L"MinorVersion";
|
|
WCHAR *szTimeLastChange = L"ChangeID";
|
|
WCHAR *szTotalJobs = L"TotalJobs";
|
|
WCHAR *szTotalBytes = L"TotalBytes";
|
|
WCHAR *szTotalPages = L"TotalPages";
|
|
WCHAR *szHelpFile = L"Help File";
|
|
WCHAR *szMonitor = L"Monitor";
|
|
WCHAR *szDependentFiles = L"Dependent Files";
|
|
WCHAR *szDNSTimeout = L"dnsTimeout";
|
|
WCHAR *szTXTimeout = L"txTimeout";
|
|
WCHAR *szNTFaxDriver = L"Windows NT Fax Driver";
|
|
|
|
#if DBG
|
|
WCHAR *szDebugFlags = L"DebugFlags";
|
|
#endif
|
|
|
|
WCHAR *szEnvironment = LOCAL_ENVIRONMENT;
|
|
WCHAR *szWin95Environment = L"Windows 4.0";
|
|
|
|
HANDLE hInst;
|
|
|
|
// Time before a job is assumed abandond and deleted during FastPrint
|
|
// operation
|
|
DWORD dwFastPrintWaitTimeout = FASTPRINT_WAIT_TIMEOUT;
|
|
DWORD dwSpoolerPriority = THREAD_PRIORITY_NORMAL;
|
|
DWORD dwPortThreadPriority = DEFAULT_PORT_THREAD_PRIORITY;
|
|
DWORD dwSchedulerThreadPriority = DEFAULT_SCHEDULER_THREAD_PRIORITY;
|
|
DWORD dwFastPrintThrottleTimeout = FASTPRINT_THROTTLE_TIMEOUT;
|
|
DWORD dwFastPrintSlowDownThreshold = FASTPRINT_SLOWDOWN_THRESHOLD;
|
|
DWORD dwServerThreadPriority = DEFAULT_SERVER_THREAD_PRIORITY;
|
|
|
|
// Time to sleep if the LocalWritePrinter WritePort doesn't write any bytes
|
|
// but still returns success.
|
|
DWORD dwWritePrinterSleepTime = WRITE_PRINTER_SLEEP_TIME;
|
|
|
|
BOOL Initialized = FALSE;
|
|
|
|
LPWSTR szDriversShare;
|
|
PINISPOOLER pLocalIniSpooler = NULL;
|
|
LPDWORD pJobIdMap;
|
|
DWORD MaxJobId=256;
|
|
DWORD CurrentJobId;
|
|
HANDLE InitSemaphore;
|
|
PINIENVIRONMENT pThisEnvironment;
|
|
|
|
// NT 3.1 No Version ( Version 0 ) User Mode
|
|
// NT 3.5 and 3.51 Version 1 User Mode
|
|
// NT 4.0 Version 2 Kernel Mode
|
|
|
|
DWORD cThisMajorVersion = 2;
|
|
DWORD cThisMinorVersion = 0;
|
|
|
|
//
|
|
// 0 - Not upgrading, 1 - performing upgrade
|
|
//
|
|
|
|
DWORD dwUpgradeFlag = 0;
|
|
|
|
LPWSTR szRemoteDoc;
|
|
LPWSTR szLocalDoc;
|
|
LPWSTR szFastPrintTimeout;
|
|
LPWSTR szRaw = L"RAW";
|
|
|
|
|
|
PRINTPROVIDOR PrintProvidor = {LocalOpenPrinter,
|
|
LocalSetJob,
|
|
LocalGetJob,
|
|
LocalEnumJobs,
|
|
LocalAddPrinter,
|
|
SplDeletePrinter,
|
|
SplSetPrinter,
|
|
SplGetPrinter,
|
|
LocalEnumPrinters,
|
|
LocalAddPrinterDriver,
|
|
LocalEnumPrinterDrivers,
|
|
SplGetPrinterDriver,
|
|
LocalGetPrinterDriverDirectory,
|
|
LocalDeletePrinterDriver,
|
|
LocalAddPrintProcessor,
|
|
LocalEnumPrintProcessors,
|
|
LocalGetPrintProcessorDirectory,
|
|
LocalDeletePrintProcessor,
|
|
LocalEnumPrintProcessorDatatypes,
|
|
LocalStartDocPrinter,
|
|
LocalStartPagePrinter,
|
|
LocalWritePrinter,
|
|
LocalEndPagePrinter,
|
|
LocalAbortPrinter,
|
|
LocalReadPrinter,
|
|
LocalEndDocPrinter,
|
|
LocalAddJob,
|
|
LocalScheduleJob,
|
|
SplGetPrinterData,
|
|
SplSetPrinterData,
|
|
LocalWaitForPrinterChange,
|
|
SplClosePrinter,
|
|
SplAddForm,
|
|
SplDeleteForm,
|
|
SplGetForm,
|
|
SplSetForm,
|
|
SplEnumForms,
|
|
LocalEnumMonitors,
|
|
LocalEnumPorts,
|
|
LocalAddPort,
|
|
LocalConfigurePort,
|
|
LocalDeletePort,
|
|
LocalCreatePrinterIC,
|
|
LocalPlayGdiScriptOnPrinterIC,
|
|
LocalDeletePrinterIC,
|
|
LocalAddPrinterConnection,
|
|
LocalDeletePrinterConnection,
|
|
LocalPrinterMessageBox,
|
|
LocalAddMonitor,
|
|
LocalDeleteMonitor,
|
|
SplResetPrinter,
|
|
SplGetPrinterDriverEx,
|
|
LocalFindFirstPrinterChangeNotification,
|
|
LocalFindClosePrinterChangeNotification,
|
|
LocalAddPortEx,
|
|
NULL,
|
|
LocalRefreshPrinterChangeNotification,
|
|
LocalOpenPrinterEx,
|
|
LocalAddPrinterEx,
|
|
LocalSetPort,
|
|
SplEnumPrinterData,
|
|
SplDeletePrinterData
|
|
};
|
|
|
|
DWORD
|
|
FinalInitAfterRouterInitCompleteThread( DWORD dwUpgrade );
|
|
|
|
#if DBG
|
|
VOID
|
|
InitializeDebug(
|
|
PINISPOOLER pIniSpooler
|
|
);
|
|
#endif
|
|
|
|
BOOL
|
|
LibMain(
|
|
HANDLE hModule,
|
|
DWORD dwReason,
|
|
LPVOID lpRes
|
|
)
|
|
{
|
|
switch(dwReason) {
|
|
case DLL_PROCESS_ATTACH:
|
|
|
|
InitializeLocalspl();
|
|
|
|
DisableThreadLibraryCalls(hModule);
|
|
|
|
hInst = hModule;
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH :
|
|
ShutdownPorts( pLocalIniSpooler );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return TRUE;
|
|
|
|
UNREFERENCED_PARAMETER( lpRes );
|
|
}
|
|
|
|
|
|
VOID
|
|
InitializeLocalspl(
|
|
VOID
|
|
)
|
|
{
|
|
#if DBG
|
|
gpDbgPointers = DbgGetPointers();
|
|
|
|
if( gpDbgPointers ){
|
|
|
|
hcsSpoolerSection = gpDbgPointers->pfnAllocCritSec();
|
|
SPLASSERT( hcsSpoolerSection );
|
|
}
|
|
|
|
if( !hcsSpoolerSection ){
|
|
|
|
//
|
|
// Must be using the free version of spoolss.dll.
|
|
//
|
|
InitializeCriticalSection( &SpoolerSection );
|
|
}
|
|
#else
|
|
InitializeCriticalSection( &SpoolerSection );
|
|
#endif
|
|
}
|
|
|
|
BOOL
|
|
SplDeleteSpooler(
|
|
HANDLE hSpooler
|
|
)
|
|
{
|
|
PINISPOOLER pIniSpooler = (PINISPOOLER) hSpooler;
|
|
BOOL bReturn = FALSE;
|
|
PINISPOOLER pCurrentIniSpooler = pLocalIniSpooler;
|
|
|
|
// Can't Delete the MasterSpooler
|
|
|
|
EnterSplSem();
|
|
|
|
// Whoever calls this must have deleted all the object associated with
|
|
// this spooler, ie all printers etc, just make certain
|
|
//
|
|
|
|
if ( ( SplCloseSpooler( hSpooler )) &&
|
|
( pIniSpooler != pLocalIniSpooler ) &&
|
|
( pIniSpooler->cRef == 0 ) &&
|
|
( pIniSpooler->pIniPrinter == NULL ) ) {
|
|
|
|
if ( pIniSpooler->pIniEnvironment != pLocalIniSpooler->pIniEnvironment ) {
|
|
|
|
DBGMSG( DBG_WARNING, ("SplDeleteSpooler we should process pIniEnvironment now \n"));
|
|
|
|
}
|
|
|
|
if ( pIniSpooler->pIniPort != pLocalIniSpooler->pIniPort ) {
|
|
|
|
DBGMSG( DBG_TRACE, ("SplDeleteSpooler processing pIniPort %x\n", pIniSpooler->pIniPort));
|
|
|
|
}
|
|
|
|
|
|
//( pIniSpooler->pIniPort == NULL ) &&
|
|
//( pIniSpooler->pIniForm == NULL ) &&
|
|
//( pIniSpooler->pIniMonitor == NULL ) &&
|
|
//( pIniSpooler->pIniNetPrint == NULL ) &&
|
|
//( pIniSpooler->pSpool == NULL )) {
|
|
|
|
|
|
// Take this Spooler Off the Linked List
|
|
//
|
|
//
|
|
|
|
while (( pCurrentIniSpooler->pIniNextSpooler != NULL ) &&
|
|
( pCurrentIniSpooler->pIniNextSpooler != pIniSpooler )) {
|
|
|
|
pCurrentIniSpooler = pCurrentIniSpooler->pIniNextSpooler;
|
|
|
|
}
|
|
|
|
SPLASSERT( pCurrentIniSpooler->pIniNextSpooler == pIniSpooler );
|
|
|
|
pCurrentIniSpooler->pIniNextSpooler = pIniSpooler->pIniNextSpooler;
|
|
|
|
//
|
|
// Delete All the Strings
|
|
//
|
|
|
|
CloseHandle( pIniSpooler->hSizeDetectionThread );
|
|
FreeIniSpoolerOtherNames(pIniSpooler);
|
|
FreeStructurePointers((LPBYTE)pIniSpooler, NULL, IniSpoolerOffsets);
|
|
|
|
// Free this IniSpooler
|
|
|
|
FreeSplMem( pIniSpooler );
|
|
|
|
bReturn = TRUE;
|
|
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SplCloseSpooler(
|
|
HANDLE hSpooler
|
|
)
|
|
{
|
|
PINISPOOLER pIniSpooler = (PINISPOOLER) hSpooler;
|
|
|
|
EnterSplSem();
|
|
|
|
if ((pIniSpooler == NULL) ||
|
|
(pIniSpooler == INVALID_HANDLE_VALUE) ||
|
|
(pIniSpooler == pLocalIniSpooler) ||
|
|
(pIniSpooler->signature != ISP_SIGNATURE) ||
|
|
(pIniSpooler->cRef == 0)) {
|
|
|
|
|
|
SetLastError( ERROR_INVALID_HANDLE );
|
|
|
|
DBGMSG(DBG_WARNING, ("SplCloseSpooler InvalidHandle %x\n", pIniSpooler ));
|
|
LeaveSplSem();
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
DECSPOOLERREF( pIniSpooler );
|
|
|
|
DBGMSG(DBG_TRACE, ("SplCloseSpooler %x %ws cRef %d\n",pIniSpooler,
|
|
pIniSpooler->pMachineName,
|
|
pIniSpooler->cRef));
|
|
|
|
LeaveSplSem();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HANDLE
|
|
SplCreateSpooler(
|
|
LPWSTR pMachineName,
|
|
DWORD Level,
|
|
PSPOOLER_INFO_1 pSpooler,
|
|
LPBYTE pReserved
|
|
)
|
|
{
|
|
HANDLE hReturn = INVALID_HANDLE_VALUE;
|
|
PINISPOOLER pIniSpooler = NULL;
|
|
PSPOOLER_INFO_1 pSpoolInfo1 = (PSPOOLER_INFO_1) pSpooler;
|
|
DWORD i;
|
|
WCHAR Buffer[MAX_PATH];
|
|
PSHARE_INFO_2 pShareInfo = NULL;
|
|
|
|
|
|
// !!! DEBUG CODE
|
|
VOID Blah(BOOL (*pFcn)());
|
|
|
|
Blah(NotIniSpooler);
|
|
// !!! END DEBUG CODE
|
|
|
|
EnterSplSem();
|
|
|
|
// Validate Parameters
|
|
|
|
if ( pMachineName == NULL ) {
|
|
SetLastError( ERROR_INVALID_NAME );
|
|
goto SplCreateDone;
|
|
}
|
|
|
|
DBGMSG( DBG_TRACE, ("SplCreateSpooler %ws %x %d %x\n", pMachineName,
|
|
Level, pSpooler, pReserved ));
|
|
|
|
|
|
if (pLocalIniSpooler != NULL) {
|
|
|
|
pIniSpooler = FindSpooler( pMachineName );
|
|
}
|
|
|
|
|
|
if ( pIniSpooler == NULL ) {
|
|
|
|
pIniSpooler = AllocSplMem( sizeof(INISPOOLER) );
|
|
|
|
if (pIniSpooler == NULL ) {
|
|
DBGMSG( DBG_WARNING, ("Unable to allocate IniSpooler\n"));
|
|
goto SplCreateDone;
|
|
}
|
|
|
|
pIniSpooler->signature = ISP_SIGNATURE;
|
|
INCSPOOLERREF( pIniSpooler );
|
|
|
|
pIniSpooler->pMachineName = AllocSplStr( pMachineName );
|
|
|
|
if ( pIniSpooler->pMachineName == NULL ) {
|
|
|
|
DBGMSG( DBG_WARNING, ("Unable to allocate pMachineName\n"));
|
|
goto SplCreateDone;
|
|
}
|
|
|
|
|
|
|
|
if ( pSpoolInfo1->pDir != NULL ) {
|
|
|
|
pIniSpooler->pDir = AllocSplStr( pSpoolInfo1->pDir );
|
|
|
|
if ( pIniSpooler->pMachineName == NULL ) {
|
|
DBGMSG( DBG_WARNING, ("Unable to allocate pSpoolInfo1-pDir\n"));
|
|
goto SplCreateDone;
|
|
}
|
|
wcscpy(&Buffer[0], pIniSpooler->pDir);
|
|
|
|
} else {
|
|
|
|
i = GetSystemDirectory(Buffer, sizeof(Buffer));
|
|
wcscpy(&Buffer[i], szSpoolDirectory);
|
|
pIniSpooler->pDir = AllocSplStr(Buffer);
|
|
|
|
if ( pIniSpooler->pDir == NULL ) {
|
|
DBGMSG( DBG_WARNING, ("Unable to Allocate pIniSpooler->pDir\n"));
|
|
goto SplCreateDone;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// DriverShareInfo
|
|
//
|
|
//
|
|
|
|
pIniSpooler->pDriversShareInfo = AllocSplMem( sizeof( SHARE_INFO_2));
|
|
|
|
if ( pIniSpooler->pDriversShareInfo == NULL ) {
|
|
DBGMSG(DBG_WARNING, ("Unable to Alloc pIniSpooler->pDriversShareInfo\n"));
|
|
goto SplCreateDone;
|
|
}
|
|
|
|
pShareInfo = (PSHARE_INFO_2)pIniSpooler->pDriversShareInfo;
|
|
|
|
if ( pIniSpooler->pDriversShareInfo == NULL )
|
|
goto SplCreateDone;
|
|
|
|
pShareInfo->shi2_netname = NULL;
|
|
pShareInfo->shi2_type = STYPE_DISKTREE;
|
|
pShareInfo->shi2_remark = NULL;
|
|
pShareInfo->shi2_permissions = 0;
|
|
pShareInfo->shi2_max_uses = SHI_USES_UNLIMITED;
|
|
pShareInfo->shi2_current_uses = SHI_USES_UNLIMITED;
|
|
pShareInfo->shi2_path = NULL;
|
|
pShareInfo->shi2_passwd = NULL;
|
|
|
|
i = wcslen(Buffer); /* Find end of "<winnt>\system32\spool" */
|
|
|
|
wcscpy(&Buffer[i], szDriversDirectory); /* <winnt>\system32\spool\drivers */
|
|
|
|
pShareInfo->shi2_path = AllocSplStr(Buffer);
|
|
|
|
if ( pShareInfo->shi2_path == NULL ) {
|
|
DBGMSG( DBG_WARNING, ("Unable to alloc pShareInfo->shi2_path\n"));
|
|
goto SplCreateDone;
|
|
}
|
|
|
|
pShareInfo->shi2_netname = ipszDriversShareName;
|
|
*Buffer = L'\0';
|
|
LoadString(hInst, IDS_PRINTER_DRIVERS, Buffer, (sizeof Buffer / sizeof *Buffer));
|
|
|
|
pShareInfo->shi2_remark = AllocSplStr(Buffer);
|
|
|
|
if ( pShareInfo->shi2_remark == NULL ) {
|
|
DBGMSG(DBG_WARNING, ("SplCreateSpooler Unable to allocate\n"));
|
|
goto SplCreateDone;
|
|
}
|
|
|
|
pIniSpooler->pIniPrinter = NULL;
|
|
pIniSpooler->pIniEnvironment = NULL;
|
|
pIniSpooler->pIniPort = NULL;
|
|
pIniSpooler->pIniForm = NULL;
|
|
pIniSpooler->pIniMonitor = NULL;
|
|
pIniSpooler->pIniNetPrint = NULL;
|
|
pIniSpooler->pSpool = NULL;
|
|
pIniSpooler->pDefaultSpoolDir = NULL;
|
|
pIniSpooler->hSizeDetectionThread = INVALID_HANDLE_VALUE;
|
|
|
|
if (( pSpoolInfo1->pszRegistryRoot == NULL ) &&
|
|
( pSpoolInfo1->pszRegistryPrinters == NULL ) &&
|
|
( pSpoolInfo1->pszRegistryMonitors == NULL ) &&
|
|
( pSpoolInfo1->pszRegistryEnvironments == NULL ) &&
|
|
( pSpoolInfo1->pszRegistryEventLog == NULL ) &&
|
|
( pSpoolInfo1->pszRegistryProviders == NULL ) &&
|
|
( pSpoolInfo1->pszEventLogMsgFile == NULL ) &&
|
|
( pSpoolInfo1->pszRegistryForms == NULL ) &&
|
|
( pSpoolInfo1->pszDriversShare == NULL )) {
|
|
|
|
DBGMSG( DBG_WARNING, ("SplCreateSpooler Invalid Parameters\n"));
|
|
goto SplCreateDone;
|
|
}
|
|
|
|
if ( pSpoolInfo1->pDefaultSpoolDir != NULL ) {
|
|
pIniSpooler->pDefaultSpoolDir = AllocSplStr( pSpoolInfo1->pDefaultSpoolDir );
|
|
|
|
if ( pIniSpooler->pDefaultSpoolDir == NULL ) {
|
|
DBGMSG(DBG_WARNING, ("SplCreateSpooler Unable to allocate\n"));
|
|
goto SplCreateDone;
|
|
|
|
}
|
|
}
|
|
|
|
pIniSpooler->pszRegistryRoot = AllocSplStr( pSpoolInfo1->pszRegistryRoot );
|
|
pIniSpooler->pszRegistryPrinters = AllocSplStr( pSpoolInfo1->pszRegistryPrinters );
|
|
pIniSpooler->pszRegistryMonitors = AllocSplStr( pSpoolInfo1->pszRegistryMonitors );
|
|
pIniSpooler->pszRegistryEnvironments = AllocSplStr( pSpoolInfo1->pszRegistryEnvironments );
|
|
pIniSpooler->pszRegistryEventLog = AllocSplStr( pSpoolInfo1->pszRegistryEventLog );
|
|
pIniSpooler->pszRegistryProviders = AllocSplStr( pSpoolInfo1->pszRegistryProviders );
|
|
pIniSpooler->pszEventLogMsgFile = AllocSplStr( pSpoolInfo1->pszEventLogMsgFile );
|
|
pIniSpooler->pszDriversShare = AllocSplStr( pSpoolInfo1->pszDriversShare );
|
|
pIniSpooler->pszRegistryForms = AllocSplStr( pSpoolInfo1->pszRegistryForms ) ;
|
|
|
|
if ( pIniSpooler->pszRegistryRoot == NULL ||
|
|
pIniSpooler->pszRegistryPrinters == NULL ||
|
|
pIniSpooler->pszRegistryMonitors == NULL ||
|
|
pIniSpooler->pszRegistryEnvironments == NULL ||
|
|
pIniSpooler->pszRegistryEventLog == NULL ||
|
|
pIniSpooler->pszRegistryProviders == NULL ||
|
|
pIniSpooler->pszEventLogMsgFile == NULL ||
|
|
pIniSpooler->pszDriversShare == NULL ||
|
|
pIniSpooler->pszRegistryForms == NULL ) {
|
|
|
|
DBGMSG(DBG_WARNING, ("SplCreateSpooler Unable to allocate\n"));
|
|
goto SplCreateDone;
|
|
|
|
}
|
|
|
|
|
|
pIniSpooler->SpoolerFlags = pSpoolInfo1->SpoolerFlags;
|
|
|
|
pIniSpooler->pfnReadRegistryExtra = pSpoolInfo1->pfnReadRegistryExtra;
|
|
pIniSpooler->pfnWriteRegistryExtra = pSpoolInfo1->pfnWriteRegistryExtra;
|
|
pIniSpooler->pfnFreePrinterExtra = pSpoolInfo1->pfnFreePrinterExtra;
|
|
|
|
// Success add to Linked List
|
|
|
|
if ( pLocalIniSpooler != NULL ) {
|
|
|
|
pIniSpooler->pIniNextSpooler = pLocalIniSpooler->pIniNextSpooler;
|
|
pLocalIniSpooler->pIniNextSpooler = pIniSpooler;
|
|
|
|
|
|
} else {
|
|
|
|
// First One is Always LocalSpl
|
|
|
|
pLocalIniSpooler = pIniSpooler;
|
|
pIniSpooler->pIniNextSpooler = NULL;
|
|
|
|
|
|
}
|
|
|
|
InitializeEventLogging( pIniSpooler );
|
|
|
|
QueryUpgradeFlag( pIniSpooler );
|
|
|
|
//
|
|
// Create the Initial Forms DataBase with all the built in forms
|
|
//
|
|
|
|
InitializeForms( pIniSpooler );
|
|
|
|
// Currently Spoolers all share the same Evironments
|
|
// and drivers so special case when LocalSpl is being created
|
|
//
|
|
|
|
|
|
if ( pIniSpooler == pLocalIniSpooler ) {
|
|
|
|
GetPrintSystemVersion( pIniSpooler );
|
|
|
|
BuildAllPorts( pIniSpooler );
|
|
|
|
BuildEnvironmentInfo( pIniSpooler );
|
|
|
|
BuildOtherNamesFromMachineName(pIniSpooler);
|
|
|
|
if ( dwUpgradeFlag ) {
|
|
|
|
//
|
|
// If we are upgrading from NT 3.1 the drivers need to be
|
|
// moved to the correct target directory and the registry needs to
|
|
// be fixed. Because NT 3.1 didn't have different driver
|
|
//
|
|
|
|
Upgrade31DriversRegistryForAllEnvironments( pIniSpooler );
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
pIniSpooler->pIniEnvironment = pLocalIniSpooler->pIniEnvironment;
|
|
pIniSpooler->pszRegistryEnvironments = pLocalIniSpooler->pszRegistryEnvironments;
|
|
|
|
BuildAllPorts( pIniSpooler );
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Read Printer Info from Registry
|
|
//
|
|
|
|
BuildPrinterInfo( pIniSpooler, (BOOL) dwUpgradeFlag );
|
|
|
|
|
|
} else {
|
|
|
|
INCSPOOLERREF( pIniSpooler );
|
|
|
|
}
|
|
|
|
hReturn = (HANDLE) pIniSpooler;
|
|
|
|
SplCreateDone:
|
|
LeaveSplSem();
|
|
return hReturn;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
InitializePrintProvidor(
|
|
LPPRINTPROVIDOR pPrintProvidor,
|
|
DWORD cbPrintProvidor,
|
|
LPWSTR pFullRegistryPath
|
|
)
|
|
{
|
|
HANDLE hSchedulerThread;
|
|
HANDLE hFinalInitAfterRouterInitCompleteThread;
|
|
DWORD ThreadId;
|
|
BOOL bSucceeded = TRUE;
|
|
WCHAR Buffer[MAX_PATH];
|
|
DWORD i;
|
|
PINISPOOLER pIniSpooler = NULL;
|
|
LPWSTR pMachineName = NULL;
|
|
SPOOLER_INFO_1 SpoolerInfo1;
|
|
BOOL bInSem = FALSE;
|
|
|
|
#if DBG
|
|
// Sleep(30*1000);
|
|
#endif
|
|
|
|
try {
|
|
|
|
if (!InitializeWinSpoolDrv())
|
|
leave;
|
|
|
|
//
|
|
// Make sure sizes of structres are good
|
|
//
|
|
|
|
SPLASSERT( sizeof( PRINTER_INFO_STRESSW ) == ( sizeof( SYSTEMTIME ) + 27*sizeof( DWORD )) );
|
|
SPLASSERT( sizeof( PRINTER_INFO_STRESSW ) == sizeof ( PRINTER_INFO_STRESSA ) );
|
|
|
|
|
|
// !! LATER !!
|
|
// We could change this to succeed even on failure
|
|
// if we point all the routines to a function which returns failure
|
|
//
|
|
|
|
if (!InitializeNet())
|
|
leave;
|
|
|
|
//
|
|
// Initialize the JobIdMap
|
|
// MUST happen before we read any shadow jobs
|
|
|
|
pJobIdMap = AllocSplMem(MaxJobId/8);
|
|
|
|
if ( pJobIdMap == NULL ) {
|
|
|
|
DBGMSG( DBG_WARNING,
|
|
("InitializePrintProvidor failed to alloc JobIdMap error %d\n",
|
|
GetLastError() ));
|
|
|
|
leave;
|
|
}
|
|
|
|
|
|
MARKUSE(pJobIdMap, 0);
|
|
CurrentJobId = 0;
|
|
|
|
//
|
|
// Allocate LocalSpl Global IniSpooler
|
|
//
|
|
|
|
Buffer[0] = Buffer[1] = L'\\';
|
|
i = MAX_PATH-2;
|
|
if (!GetComputerName(Buffer+2, &i)) {
|
|
|
|
DBGMSG(DBG_WARNING, ("GetComputerName failed.\n"));
|
|
leave;
|
|
}
|
|
|
|
pMachineName = AllocSplStr(Buffer);
|
|
if ( pMachineName == NULL )
|
|
leave;
|
|
|
|
// i is the length of the computer name
|
|
Buffer[i+2] = L'\\';
|
|
|
|
wcscpy(&Buffer[i+3], ipszDriversShareName);
|
|
SpoolerInfo1.pszDriversShare = AllocSplStr(Buffer); /* \computer\print$ */
|
|
if ( SpoolerInfo1.pszDriversShare == NULL )
|
|
leave;
|
|
|
|
// Use Defaults
|
|
|
|
SpoolerInfo1.pDir = NULL;
|
|
SpoolerInfo1.pDefaultSpoolDir = NULL;
|
|
|
|
SpoolerInfo1.pszRegistryRoot = ipszRegistryRoot;
|
|
SpoolerInfo1.pszRegistryPrinters = ipszRegistryPrinters;
|
|
SpoolerInfo1.pszRegistryMonitors = ipszRegistryMonitors;
|
|
SpoolerInfo1.pszRegistryEnvironments = ipszRegistryEnvironments;
|
|
SpoolerInfo1.pszRegistryEventLog = ipszRegistryEventLog;
|
|
SpoolerInfo1.pszRegistryProviders = ipszRegistryProviders;
|
|
SpoolerInfo1.pszEventLogMsgFile = ipszEventLogMsgFile;
|
|
SpoolerInfo1.pszRegistryForms = ipszRegistryForms;
|
|
|
|
// For LocalSpooler we want ALL features on
|
|
|
|
SpoolerInfo1.SpoolerFlags = 0xffffffff;
|
|
|
|
SpoolerInfo1.pfnReadRegistryExtra = NULL;
|
|
SpoolerInfo1.pfnWriteRegistryExtra = NULL;
|
|
|
|
pLocalIniSpooler = SplCreateSpooler( pMachineName,
|
|
1,
|
|
&SpoolerInfo1,
|
|
NULL );
|
|
|
|
|
|
if ( pLocalIniSpooler == NULL ) {
|
|
DBGMSG( DBG_WARNING, ("InitializePrintProvidor Unable to allocate pLocalIniSpooler\n"));
|
|
leave;
|
|
}
|
|
|
|
pIniSpooler = pLocalIniSpooler;
|
|
|
|
#if DBG
|
|
InitializeDebug( pIniSpooler );
|
|
#endif
|
|
|
|
// !! LATER !!
|
|
// Why is this done inside critical section ?
|
|
|
|
|
|
EnterSplSem();
|
|
bInSem = TRUE;
|
|
|
|
if (!LoadString(hInst, IDS_REMOTE_DOC, Buffer, MAX_PATH))
|
|
leave;
|
|
|
|
szRemoteDoc = AllocSplStr( Buffer );
|
|
if ( szRemoteDoc == NULL )
|
|
leave;
|
|
|
|
if (!LoadString(hInst, IDS_LOCAL_DOC, Buffer, MAX_PATH))
|
|
leave;
|
|
|
|
szLocalDoc = AllocSplStr( Buffer );
|
|
if ( szLocalDoc == NULL )
|
|
leave;
|
|
|
|
if (!LoadString(hInst, IDS_FASTPRINT_TIMEOUT, Buffer, MAX_PATH))
|
|
leave;
|
|
|
|
szFastPrintTimeout = AllocSplStr( Buffer );
|
|
if ( szFastPrintTimeout == NULL )
|
|
leave;
|
|
|
|
if ( NULL == CreateServerSecurityDescriptor() )
|
|
leave;
|
|
|
|
for ( CurrentJobId = 0;
|
|
CurrentJobId < MaxJobId && !ISBITON( pJobIdMap, CurrentJobId );
|
|
CurrentJobId++ )
|
|
;
|
|
|
|
SchedulerSignal = CreateEvent( NULL,
|
|
EVENT_RESET_AUTOMATIC,
|
|
EVENT_INITIAL_STATE_NOT_SIGNALED,
|
|
NULL );
|
|
|
|
hSchedulerThread = CreateThread( NULL, 16*1024,
|
|
(LPTHREAD_START_ROUTINE)SchedulerThread,
|
|
pIniSpooler, 0, &ThreadId );
|
|
|
|
hFinalInitAfterRouterInitCompleteThread = CreateThread( NULL, 16*1024,
|
|
(LPTHREAD_START_ROUTINE)FinalInitAfterRouterInitCompleteThread,
|
|
(LPVOID)dwUpgradeFlag, 0, &ThreadId );
|
|
|
|
|
|
if (!SchedulerSignal || !hSchedulerThread || !hFinalInitAfterRouterInitCompleteThread) {
|
|
|
|
DBGMSG( DBG_WARNING, ("Scheduler/FinalInitAfterRouterInitCompleteThread not initialised properly: Error %d\n", GetLastError()));
|
|
leave;
|
|
}
|
|
|
|
if ( !SetThreadPriority( hSchedulerThread, dwSchedulerThreadPriority ) ) {
|
|
|
|
DBGMSG( DBG_WARNING, ("Setting Scheduler thread priority failed %d\n", GetLastError()));
|
|
}
|
|
|
|
|
|
CloseHandle( hSchedulerThread );
|
|
CloseHandle( hFinalInitAfterRouterInitCompleteThread );
|
|
|
|
CHECK_SCHEDULER();
|
|
|
|
CopyMemory( pPrintProvidor, &PrintProvidor, min(sizeof(PRINTPROVIDOR), cbPrintProvidor));
|
|
|
|
LeaveSplSem();
|
|
bInSem = FALSE;
|
|
|
|
CloseProfileUserMapping(); // !!! We should be able to get rid of this
|
|
|
|
Initialized = TRUE;
|
|
|
|
|
|
} finally {
|
|
|
|
if ( bInSem ) {
|
|
LeaveSplSem();
|
|
}
|
|
|
|
}
|
|
|
|
SplOutSem();
|
|
|
|
// BUGBUG should LogEvent here if Initialized == FALSE
|
|
// so we have some idea what failed.
|
|
|
|
return Initialized;
|
|
}
|
|
|
|
|
|
PINIPORT
|
|
CreatePortEntry(
|
|
LPWSTR pPortName,
|
|
PINIMONITOR pIniMonitor,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
DWORD cb;
|
|
PINIPORT pIniPort = NULL;
|
|
HANDLE hPort=NULL, hWaitToOpenOrClose=NULL;
|
|
|
|
SplInSem();
|
|
|
|
SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
|
|
|
|
if (!pPortName) {
|
|
|
|
SetLastError(ERROR_UNKNOWN_PORT);
|
|
return NULL;
|
|
}
|
|
|
|
if (!pIniMonitor) {
|
|
|
|
/* Don't bother validating the port if we aren't initialised.
|
|
* It must be valid, since we wrote it in the registry.
|
|
* This fixes the problem of attempting to open a network
|
|
* printer before the redirector has initialised,
|
|
* and the problem of access denied because we're currently
|
|
* in the system's context.
|
|
*/
|
|
if (Initialized) {
|
|
|
|
//
|
|
// !! Warning !!
|
|
//
|
|
// Watch for deadlock:
|
|
//
|
|
// spoolss!OpenPrinterPortW -> RPC to self printer port
|
|
// localspl!CreatePortEntry
|
|
// localspl!ValidatePortTokenList
|
|
// localspl!SetPrinterPorts
|
|
// localspl!LocalSetPrinter
|
|
// spoolss!SetPrinterW
|
|
// spoolss!RpcSetPrinter
|
|
// spoolss!winspool_RpcSetPrinter
|
|
//
|
|
|
|
if (!OpenPrinterPortW(pPortName, &hPort, NULL)) {
|
|
|
|
if (GetLastError() == ERROR_INVALID_NAME) {
|
|
SetLastError(ERROR_UNKNOWN_PORT);
|
|
return FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
ClosePrinter(hPort);
|
|
}
|
|
}
|
|
}
|
|
|
|
cb = sizeof(INIPORT) + wcslen(pPortName)*sizeof(WCHAR) + sizeof(WCHAR);
|
|
|
|
hWaitToOpenOrClose = CreateEvent(NULL, FALSE, TRUE, NULL);
|
|
if ( !hWaitToOpenOrClose )
|
|
goto Cleanup;
|
|
|
|
if (pIniPort=AllocSplMem(cb)) {
|
|
|
|
pIniPort->pName = wcscpy((LPWSTR)(pIniPort+1), pPortName);
|
|
pIniPort->signature = IPO_SIGNATURE;
|
|
pIniPort->pIniMonitor = pIniMonitor;
|
|
|
|
if (pIniMonitor) {
|
|
pIniPort->Status |= PP_MONITOR;
|
|
}
|
|
|
|
pIniPort->hWaitToOpenOrClose = hWaitToOpenOrClose;
|
|
|
|
LinkPortToSpooler( pIniPort, pIniSpooler );
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if ( !pIniPort && hWaitToOpenOrClose )
|
|
CloseHandle(hWaitToOpenOrClose);
|
|
|
|
return pIniPort;
|
|
}
|
|
|
|
BOOL
|
|
DeletePortEntry(
|
|
PINIPORT pIniPort
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free pIniPort resources then delete it. If the pIniPort is on
|
|
a pIniSpooler's linked list, remove it too.
|
|
|
|
Arguments:
|
|
|
|
pIniPort - Port to delete. May or may not be on a pIniSpooler.
|
|
|
|
Return Value:
|
|
|
|
TRUE - deleted
|
|
FALSE - not deleted (may be in use).
|
|
|
|
--*/
|
|
|
|
{
|
|
PINISPOOLER pIniSpooler;
|
|
|
|
SplInSem();
|
|
|
|
SPLASSERT ( ( pIniPort != NULL) || ( pIniPort->signature == IPO_SIGNATURE) );
|
|
|
|
//
|
|
// We had better already closed the port monitor.
|
|
//
|
|
SPLASSERT( !pIniPort->hPort &&
|
|
!(pIniPort->Status & PP_THREADRUNNING) &&
|
|
!pIniPort->cJobs);
|
|
|
|
if (pIniPort->cRef) {
|
|
pIniPort->Status |= PP_DELETING;
|
|
return FALSE;
|
|
}
|
|
|
|
pIniSpooler = pIniPort->pIniSpooler;
|
|
|
|
//
|
|
// If currently linked to a pIniSpooler, delink it.
|
|
//
|
|
if( pIniSpooler ){
|
|
|
|
SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
|
|
|
|
DelinkPortFromSpooler( pIniPort, pIniSpooler );
|
|
}
|
|
|
|
if (pIniPort->ppIniPrinter)
|
|
FreeSplMem(pIniPort->ppIniPrinter);
|
|
|
|
CloseHandle(pIniPort->hWaitToOpenOrClose);
|
|
|
|
FreeSplMem(pIniPort);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
PINIMONITOR
|
|
CreateMonitorEntry(
|
|
LPWSTR pMonitorDll,
|
|
LPWSTR pMonitorName,
|
|
LPWSTR pRegistryRoot,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Valid pIniMonitor - This means everything worked out fine.
|
|
|
|
NULL - This means the monitor DLL was found, but the initialisation routine
|
|
returned FALSE. This is non-fatal, as the monitor may need the
|
|
system to reboot before it can run properly.
|
|
|
|
-1 - This means the monitor DLL or the initialisation routine was not found.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD cb, cbNeeded, cReturned;
|
|
HANDLE hModule;
|
|
PPORT_INFO_1 pPorts, pPort;
|
|
PINIMONITOR pIniMonitor;
|
|
UINT dwOldErrMode;
|
|
BOOL bInitMonitor = FALSE;
|
|
BOOL (*pfnInitialize)(LPWSTR) = NULL;
|
|
BOOL (*pfnInitializeMonitorEx)(LPWSTR, LPMONITOR) = NULL;
|
|
LPMONITOREX (*pfnInitializePrintMonitor)(LPWSTR) = NULL;
|
|
LPMONITOREX pMonEx;
|
|
|
|
SPLASSERT( (pIniSpooler != NULL) || (pIniSpooler->signature == ISP_SIGNATURE));
|
|
|
|
SplInSem();
|
|
|
|
dwOldErrMode = SetErrorMode( SEM_FAILCRITICALERRORS );
|
|
|
|
hModule = LoadLibrary(pMonitorDll);
|
|
|
|
//
|
|
// Restore error mode
|
|
//
|
|
SetErrorMode( dwOldErrMode );
|
|
|
|
if (!hModule) {
|
|
|
|
DBGMSG(DBG_WARNING, ("CreateMonitorEntry( %ws, %ws, %ws ) LoadLibrary failed %d\n",
|
|
pMonitorDll ? pMonitorDll : L"(NULL)",
|
|
pMonitorName ? pMonitorName : L"(NULL)",
|
|
pRegistryRoot, GetLastError()));
|
|
return (PINIMONITOR)-1;
|
|
}
|
|
|
|
//
|
|
// Try calling the entry points in the following order:
|
|
// InitializePrintMonitor, InitializeMonitorEx, InitializeMonitor
|
|
//
|
|
(FARPROC)pfnInitializePrintMonitor = GetProcAddress(hModule,
|
|
"InitializePrintMonitor");
|
|
|
|
if ( !pfnInitializePrintMonitor ) {
|
|
|
|
(FARPROC)pfnInitializeMonitorEx = GetProcAddress(hModule,
|
|
"InitializeMonitorEx");
|
|
|
|
if ( !pfnInitializeMonitorEx ) {
|
|
|
|
(FARPROC)pfnInitialize = GetProcAddress(hModule,
|
|
"InitializeMonitor");
|
|
}
|
|
}
|
|
|
|
if ( !pfnInitializePrintMonitor &&
|
|
!pfnInitializeMonitorEx &&
|
|
!pfnInitialize ) {
|
|
|
|
DBGMSG(DBG_WARNING, ("CreateMonitorEntry( %ws, %ws, %ws ) GetProcAddress failed %d\n",
|
|
pMonitorDll ? pMonitorDll : L"(NULL)",
|
|
pMonitorName ? pMonitorName : L"(NULL)",
|
|
pRegistryRoot, GetLastError()));
|
|
return (PINIMONITOR)-1;
|
|
}
|
|
|
|
cb = sizeof(INIMONITOR) + wcslen(pMonitorName)*sizeof(WCHAR) + sizeof(WCHAR);
|
|
|
|
if ( pIniMonitor = AllocSplMem(cb) ) {
|
|
|
|
LeaveSplSem();
|
|
if ( pfnInitializePrintMonitor ) {
|
|
|
|
pMonEx = (*pfnInitializePrintMonitor)(pRegistryRoot);
|
|
|
|
if ( pMonEx ) {
|
|
|
|
bInitMonitor = TRUE;
|
|
pIniMonitor->dwMonitorSize = pMonEx->dwMonitorSize;
|
|
CopyMemory((LPBYTE)&pIniMonitor->fn,
|
|
(LPBYTE)&pMonEx->Monitor,
|
|
min(pMonEx->dwMonitorSize, sizeof(MONITOR)));
|
|
}
|
|
} else if ( pfnInitializeMonitorEx ) {
|
|
|
|
bInitMonitor = (*pfnInitializeMonitorEx)(pRegistryRoot,
|
|
&pIniMonitor->fn);
|
|
pIniMonitor->dwMonitorSize = sizeof(MONITOR);
|
|
} else {
|
|
|
|
bInitMonitor = (BOOL)((*pfnInitialize)(pRegistryRoot));
|
|
pIniMonitor->dwMonitorSize = sizeof(MONITOR);
|
|
}
|
|
|
|
EnterSplSem();
|
|
|
|
if ( !bInitMonitor) {
|
|
|
|
DBGMSG(DBG_WARNING, ("CreateMonitorEntry( %ws, %ws, %ws ) Init failed %d\n",
|
|
pMonitorDll ? pMonitorDll : L"(NULL)",
|
|
pMonitorName ? pMonitorName : L"(NULL)",
|
|
pRegistryRoot, GetLastError()));
|
|
|
|
FreeSplMem(pIniMonitor);
|
|
|
|
//
|
|
// Some old (before NT 4.0) monitors may not initialize till
|
|
// reboot.
|
|
//
|
|
return pfnInitialize ? NULL : (PINIMONITOR)-1;
|
|
}
|
|
|
|
if ( pfnInitialize ) {
|
|
|
|
(FARPROC) pIniMonitor->fn.pfnEnumPorts = GetProcAddress(hModule, "EnumPortsW");
|
|
(FARPROC) pIniMonitor->fn.pfnOpenPort = GetProcAddress(hModule, "OpenPort");
|
|
|
|
(FARPROC) pIniMonitor->fn.pfnStartDocPort = GetProcAddress(hModule, "StartDocPort");
|
|
|
|
(FARPROC) pIniMonitor->fn.pfnWritePort = GetProcAddress(hModule, "WritePort");
|
|
|
|
(FARPROC) pIniMonitor->fn.pfnReadPort = GetProcAddress(hModule, "ReadPort");
|
|
|
|
(FARPROC) pIniMonitor->fn.pfnEndDocPort = GetProcAddress(hModule, "EndDocPort");
|
|
|
|
(FARPROC) pIniMonitor->fn.pfnClosePort = GetProcAddress(hModule, "ClosePort");
|
|
|
|
(FARPROC) pIniMonitor->fn.pfnAddPort = GetProcAddress(hModule, "AddPortW");
|
|
|
|
(FARPROC) pIniMonitor->fn.pfnConfigurePort = GetProcAddress(hModule, "ConfigurePortW");
|
|
|
|
(FARPROC) pIniMonitor->fn.pfnDeletePort = GetProcAddress(hModule, "DeletePortW");
|
|
|
|
(FARPROC) pIniMonitor->fn.pfnAddPortEx = GetProcAddress(hModule, "AddPortExW");
|
|
|
|
}
|
|
|
|
//
|
|
// Check if the monitor supports essential functions
|
|
//
|
|
if ( (!pIniMonitor->fn.pfnOpenPort &&
|
|
!pIniMonitor->fn.pfnOpenPortEx) ||
|
|
!pIniMonitor->fn.pfnClosePort ||
|
|
!pIniMonitor->fn.pfnStartDocPort ||
|
|
!pIniMonitor->fn.pfnWritePort ||
|
|
!pIniMonitor->fn.pfnReadPort ||
|
|
!pIniMonitor->fn.pfnEndDocPort ) {
|
|
|
|
DBGMSG(DBG_ERROR, ("Invalid print monitor %ws\n", pMonitorName));
|
|
SetLastError(ERROR_INVALID_PRINT_MONITOR);
|
|
FreeSplMem(pIniMonitor);
|
|
return (PINIMONITOR)-1;
|
|
}
|
|
|
|
pIniMonitor->pName = wcscpy((LPWSTR)(pIniMonitor+1), pMonitorName);
|
|
pIniMonitor->signature = IMO_SIGNATURE;
|
|
pIniMonitor->hMonitorModule = hModule;
|
|
pIniMonitor->pMonitorDll = AllocSplStr(pMonitorDll);
|
|
pIniMonitor->pNext = pIniSpooler->pIniMonitor;
|
|
pIniMonitor->pIniSpooler = pIniSpooler;
|
|
pIniSpooler->pIniMonitor = pIniMonitor;
|
|
|
|
if ((pIniMonitor->fn.pfnEnumPorts) &&
|
|
!(*pIniMonitor->fn.pfnEnumPorts)(NULL, 1, NULL, 0,
|
|
&cbNeeded, &cReturned)) {
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
|
if (pPorts = AllocSplMem(cbNeeded)) {
|
|
pPort = pPorts;
|
|
if ((*pIniMonitor->fn.pfnEnumPorts)(NULL, 1,
|
|
(LPBYTE)pPorts,
|
|
cbNeeded,
|
|
&cbNeeded,
|
|
&cReturned)) {
|
|
while (cReturned--) {
|
|
CreatePortEntry(pPort->pName,
|
|
pIniMonitor,
|
|
pIniSpooler);
|
|
pPort++;
|
|
}
|
|
}
|
|
FreeSplMem(pPorts);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DBGMSG(DBG_TRACE, ("CreateMonitorEntry( %ws, %ws, %ws ) returning %x\n",
|
|
pMonitorDll ? pMonitorDll : L"(NULL)",
|
|
pMonitorName ? pMonitorName : L"(NULL)",
|
|
pRegistryRoot, pIniMonitor));
|
|
|
|
SplInSem();
|
|
|
|
return pIniMonitor;
|
|
}
|
|
|
|
BOOL
|
|
BuildAllPorts(
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
DWORD cbData, cbDll, cMonitors;
|
|
WCHAR Dll[MAX_PATH];
|
|
WCHAR MonitorName[MAX_PATH];
|
|
WCHAR RegistryPath[MAX_PATH];
|
|
HKEY hKey, hKey1;
|
|
LONG Status;
|
|
|
|
Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pIniSpooler->pszRegistryMonitors, 0,
|
|
KEY_READ, &hKey);
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
return FALSE;
|
|
|
|
cMonitors=0;
|
|
cbData = sizeof(MonitorName);
|
|
|
|
while (RegEnumKeyEx(hKey, cMonitors, MonitorName, &cbData, NULL, NULL,
|
|
NULL, NULL) == ERROR_SUCCESS) {
|
|
|
|
DBGMSG(DBG_TRACE, ("Found monitor %ws\n", MonitorName));
|
|
|
|
if (RegOpenKeyEx(hKey, MonitorName, 0, KEY_READ, &hKey1)
|
|
== ERROR_SUCCESS) {
|
|
|
|
cbDll = sizeof(Dll);
|
|
|
|
if (RegQueryValueEx(hKey1, L"Driver", NULL, NULL,
|
|
(LPBYTE)Dll, &cbDll)
|
|
== ERROR_SUCCESS) {
|
|
|
|
wsprintf(RegistryPath, L"%ws\\%ws", pIniSpooler->pszRegistryMonitors,
|
|
MonitorName);
|
|
|
|
CreateMonitorEntry(Dll, MonitorName, RegistryPath, pIniSpooler);
|
|
}
|
|
|
|
RegCloseKey(hKey1);
|
|
}
|
|
|
|
cMonitors++;
|
|
cbData = sizeof(MonitorName);
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
GoodDirectory(
|
|
PWIN32_FIND_DATA pFindFileData
|
|
)
|
|
{
|
|
if ((pFindFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
|
!(!wcscmp(pFindFileData->cFileName, L".") ||
|
|
!wcscmp(pFindFileData->cFileName, L"..")))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
Current Directory == <NT directory>\system32\spool\printers
|
|
pFindFileData->cFileName == 0
|
|
*/
|
|
|
|
BOOL
|
|
BuildPrinterInfo(
|
|
PINISPOOLER pIniSpooler,
|
|
BOOL UpdateChangeID
|
|
)
|
|
{
|
|
WCHAR PrinterName[MAX_PRINTER_NAME];
|
|
WCHAR szData[MAX_PATH];
|
|
WCHAR szDefaultPrinterDirectory[MAX_PATH];
|
|
DWORD cbData, i;
|
|
DWORD cbSecurity;
|
|
DWORD cPrinters, Type;
|
|
HKEY hPrinterRootKey, hPrinterKey;
|
|
PINIPRINTER pIniPrinter;
|
|
PINIPORT pIniPort;
|
|
PINIMONITOR pIniLangMonitor;
|
|
LONG Status;
|
|
SECURITY_ATTRIBUTES SecurityAttributes;
|
|
PKEYDATA pKeyData = NULL;
|
|
BOOL bUpdateRegistryForThisPrinter = UpdateChangeID;
|
|
BOOL bWriteDirectory = FALSE;
|
|
|
|
Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pIniSpooler->pszRegistryPrinters, 0,
|
|
KEY_ALL_ACCESS, &hPrinterRootKey);
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
return FALSE;
|
|
|
|
//
|
|
// Has user specified Default Spool Directory ?
|
|
//
|
|
|
|
cbData = sizeof( szData );
|
|
*szData = (WCHAR)0;
|
|
|
|
Status = RegQueryValueEx( hPrinterRootKey,
|
|
SPLREG_DEFAULT_SPOOL_DIRECTORY,
|
|
NULL,
|
|
&Type,
|
|
(LPBYTE)szData, //szData gets spool directory name
|
|
&cbData);
|
|
|
|
if (Status == ERROR_SUCCESS) { // found a value, so verify the directory
|
|
if (!(pIniSpooler->pDefaultSpoolDir = AllocSplStr( szData ))) // Copies szData to pDefaultSpoolDir
|
|
return FALSE;
|
|
} else {
|
|
bWriteDirectory = TRUE; // No registry directory, so create one
|
|
}
|
|
|
|
// Copy pDefaultSpoolDir to szDefaultPrinterDirectory
|
|
GetPrinterDirectory(NULL, FALSE, szDefaultPrinterDirectory, pIniSpooler);
|
|
|
|
if (!pIniSpooler->pDefaultSpoolDir)
|
|
return FALSE;
|
|
|
|
|
|
// Create the directory with the proper security, or fail trying
|
|
|
|
SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
SecurityAttributes.lpSecurityDescriptor = CreateEverybodySecurityDescriptor();
|
|
SecurityAttributes.bInheritHandle = FALSE;
|
|
|
|
if (!CreateDirectory(szDefaultPrinterDirectory, &SecurityAttributes)) {
|
|
|
|
// Failed to create the directory? Back to factory default
|
|
|
|
bWriteDirectory = TRUE;
|
|
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS) {
|
|
DBGMSG(DBG_WARNING, ("Failed to create DefaultSpoolDirectory %ws\n", szDefaultPrinterDirectory));
|
|
FreeSplStr(pIniSpooler->pDefaultSpoolDir);
|
|
|
|
pIniSpooler->pDefaultSpoolDir = NULL; // This tells GetPrinterDirectory to alloc pDefaultSpoolDir
|
|
GetPrinterDirectory(NULL, FALSE, szDefaultPrinterDirectory, pIniSpooler);
|
|
|
|
if (!pIniSpooler->pDefaultSpoolDir)
|
|
return FALSE;
|
|
|
|
Status = CreateDirectory(szDefaultPrinterDirectory, &SecurityAttributes);
|
|
|
|
if (Status != ERROR_SUCCESS && Status != ERROR_ALREADY_EXISTS) {
|
|
DBGMSG(DBG_WARNING, ("Failed to create DefaultSpoolDirectory %ws\n", szDefaultPrinterDirectory));
|
|
FreeSplStr(pIniSpooler->pDefaultSpoolDir);
|
|
pIniSpooler->pDefaultSpoolDir = NULL;
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
LocalFree(SecurityAttributes.lpSecurityDescriptor);
|
|
|
|
if (bWriteDirectory) {
|
|
Status = SetPrinterDataServer( pIniSpooler,
|
|
SPLREG_DEFAULT_SPOOL_DIRECTORY,
|
|
REG_SZ,
|
|
(LPBYTE) pIniSpooler->pDefaultSpoolDir,
|
|
wcslen(pIniSpooler->pDefaultSpoolDir)*sizeof(WCHAR) + sizeof(WCHAR));
|
|
}
|
|
|
|
cPrinters=0;
|
|
cbData = sizeof(PrinterName);
|
|
|
|
while (RegEnumKeyEx(hPrinterRootKey, cPrinters, PrinterName, &cbData,
|
|
NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
|
|
|
|
DBGMSG(DBG_TRACE, ("Found printer %ws\n", PrinterName));
|
|
|
|
if (RegOpenKeyEx(hPrinterRootKey, PrinterName, 0, KEY_READ,
|
|
&hPrinterKey) == ERROR_SUCCESS) {
|
|
|
|
if ( pIniPrinter = AllocSplMem(sizeof(INIPRINTER) )) {
|
|
|
|
DWORD rcDataKey;
|
|
|
|
pIniPrinter->signature = IP_SIGNATURE;
|
|
GetSystemTime( &pIniPrinter->stUpTime );
|
|
|
|
//
|
|
// Get a handle to the Printer Data for this printer.
|
|
//
|
|
rcDataKey = RegCreateKeyEx( hPrinterKey, szPrinterData, 0,
|
|
szPrinterData, 0, ( KEY_READ | KEY_WRITE ),
|
|
NULL, &pIniPrinter->hPrinterDataKey, NULL );
|
|
|
|
cbData = sizeof(szData);
|
|
*szData = (WCHAR)0;
|
|
|
|
if (RegQueryValueEx(hPrinterKey, szName,
|
|
NULL, &Type, (LPBYTE)szData,
|
|
&cbData) == ERROR_SUCCESS)
|
|
|
|
pIniPrinter->pName = AllocSplStr(szData);
|
|
|
|
//
|
|
// Get Spool Directory for this printer
|
|
//
|
|
|
|
cbData = sizeof(szData);
|
|
*szData = (WCHAR)0;
|
|
|
|
if (RegQueryValueEx(hPrinterKey, szSpoolDir,
|
|
NULL, &Type, (LPBYTE)szData,
|
|
&cbData) == ERROR_SUCCESS) {
|
|
|
|
if ( *szData != (WCHAR)0 ) {
|
|
|
|
pIniPrinter->pSpoolDir = AllocSplStr(szData);
|
|
}
|
|
|
|
}
|
|
|
|
// Make Certain this Printers Printer directory exists
|
|
// with correct security
|
|
|
|
if ((pIniPrinter->pSpoolDir) &&
|
|
(wcscmp(pIniPrinter->pSpoolDir, szDefaultPrinterDirectory) != 0)) {
|
|
|
|
SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
SecurityAttributes.lpSecurityDescriptor = CreateEverybodySecurityDescriptor();
|
|
|
|
SecurityAttributes.bInheritHandle = FALSE;
|
|
|
|
|
|
if (!CreateDirectory(pIniPrinter->pSpoolDir, &SecurityAttributes)) {
|
|
|
|
// Failed to Create the Directory, revert back
|
|
// to the default
|
|
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS) {
|
|
DBGMSG(DBG_WARNING, ("Could not create printer spool directory %ws %d\n",
|
|
pIniPrinter->pSpoolDir, GetLastError() ));
|
|
pIniPrinter->pSpoolDir = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
LocalFree(SecurityAttributes.lpSecurityDescriptor);
|
|
}
|
|
|
|
|
|
cbData = sizeof(szData);
|
|
*szData = (WCHAR)0;
|
|
|
|
if (RegQueryValueEx(hPrinterKey, szShare,
|
|
NULL, &Type, (LPBYTE)szData,
|
|
&cbData) == ERROR_SUCCESS)
|
|
|
|
pIniPrinter->pShareName = AllocSplStr(szData);
|
|
|
|
cbData = sizeof(szData);
|
|
*szData = (WCHAR)0;
|
|
|
|
if (RegQueryValueEx(hPrinterKey, szPort, NULL,
|
|
&Type, (LPBYTE)szData, &cbData)
|
|
== ERROR_SUCCESS) {
|
|
|
|
if (pKeyData = CreateTokenList(szData)) {
|
|
|
|
if (!ValidatePortTokenList( pKeyData, pIniSpooler )) {
|
|
|
|
FreePortTokenList(pKeyData);
|
|
pKeyData = NULL;
|
|
} else {
|
|
|
|
pIniPrinter->ppIniPorts = AllocSplMem(pKeyData->cTokens * sizeof(PINIPORT));
|
|
}
|
|
}
|
|
}
|
|
|
|
cbData = sizeof(szData);
|
|
*szData = (WCHAR)0;
|
|
|
|
if (RegQueryValueEx(hPrinterKey, szPrintProcessor, NULL,
|
|
&Type, (LPBYTE)szData, &cbData)
|
|
== ERROR_SUCCESS)
|
|
|
|
pIniPrinter->pIniPrintProc = FindLocalPrintProc(szData);
|
|
|
|
cbData = sizeof(szData);
|
|
*szData = (WCHAR)0;
|
|
|
|
if (RegQueryValueEx(hPrinterKey, szDatatype,
|
|
NULL, &Type, (LPBYTE)szData,
|
|
&cbData) == ERROR_SUCCESS)
|
|
|
|
pIniPrinter->pDatatype = AllocSplStr(szData);
|
|
|
|
cbData = sizeof(szData);
|
|
*szData = (WCHAR)0;
|
|
|
|
if (RegQueryValueEx( hPrinterKey,
|
|
szDriver,
|
|
NULL,
|
|
&Type,
|
|
(LPBYTE)szData,
|
|
&cbData)
|
|
== ERROR_SUCCESS) {
|
|
|
|
pIniPrinter->pIniDriver = (PINIDRIVER)FindLocalDriver( szData );
|
|
if ( !pIniPrinter->pIniDriver ) {
|
|
|
|
LogEvent(pLocalIniSpooler,
|
|
LOG_ERROR,
|
|
MSG_NO_DRIVER_FOUND_FOR_PRINTER,
|
|
pIniPrinter->pName,
|
|
szData,
|
|
NULL);
|
|
}
|
|
|
|
}
|
|
|
|
cbData = sizeof(szData);
|
|
*szData = (WCHAR)0;
|
|
|
|
if (RegQueryValueEx(hPrinterKey, szLocation, NULL,
|
|
&Type, (LPBYTE)szData, &cbData)
|
|
== ERROR_SUCCESS)
|
|
|
|
pIniPrinter->pLocation = AllocSplStr(szData);
|
|
|
|
cbData = sizeof(szData);
|
|
*szData = (WCHAR)0;
|
|
|
|
if (RegQueryValueEx(hPrinterKey, szDescription, NULL,
|
|
&Type, (LPBYTE)szData, &cbData)
|
|
== ERROR_SUCCESS)
|
|
|
|
pIniPrinter->pComment = AllocSplStr(szData);
|
|
|
|
cbData = sizeof(szData);
|
|
*szData = (WCHAR)0;
|
|
|
|
if (RegQueryValueEx(hPrinterKey, szParameters, NULL,
|
|
&Type, (LPBYTE)szData, &cbData)
|
|
== ERROR_SUCCESS)
|
|
|
|
pIniPrinter->pParameters = AllocSplStr(szData);
|
|
|
|
cbData = sizeof(szData);
|
|
*szData = (WCHAR)0;
|
|
|
|
if (RegQueryValueEx(hPrinterKey, szSepFile, NULL,
|
|
&Type, (LPBYTE)szData, &cbData)
|
|
== ERROR_SUCCESS)
|
|
|
|
pIniPrinter->pSepFile = AllocSplStr(szData);
|
|
|
|
cbData = sizeof(pIniPrinter->Attributes);
|
|
|
|
RegQueryValueEx(hPrinterKey, szAttributes, NULL, &Type,
|
|
(LPBYTE)&pIniPrinter->Attributes, &cbData);
|
|
|
|
|
|
cbData = sizeof(pIniPrinter->cTotalJobs);
|
|
|
|
RegQueryValueEx(hPrinterKey, szTotalJobs, NULL, &Type,
|
|
(LPBYTE)&pIniPrinter->cTotalJobs, &cbData);
|
|
|
|
|
|
cbData = sizeof(pIniPrinter->cTotalBytes);
|
|
|
|
RegQueryValueEx(hPrinterKey, szTotalBytes, NULL, &Type,
|
|
(LPBYTE)&pIniPrinter->cTotalBytes, &cbData);
|
|
|
|
|
|
cbData = sizeof(pIniPrinter->cTotalPagesPrinted );
|
|
|
|
RegQueryValueEx(hPrinterKey, szTotalPages, NULL, &Type,
|
|
(LPBYTE)&pIniPrinter->cTotalPagesPrinted, &cbData);
|
|
|
|
|
|
cbData = sizeof(pIniPrinter->Status);
|
|
|
|
Status = RegQueryValueEx(hPrinterKey, szStatus, NULL, &Type,
|
|
(LPBYTE)&pIniPrinter->Status, &cbData);
|
|
|
|
pIniPrinter->Status |= PRINTER_FROM_REG;
|
|
|
|
if ( Status == ERROR_SUCCESS ) {
|
|
|
|
pIniPrinter->Status &= ( PRINTER_PAUSED |
|
|
PRINTER_PENDING_DELETION |
|
|
PRINTER_ZOMBIE_OBJECT |
|
|
PRINTER_FROM_REG |
|
|
PRINTER_OK |
|
|
PRINTER_PENDING_CREATION );
|
|
|
|
} else {
|
|
|
|
pIniPrinter->Status |= PRINTER_PENDING_CREATION ;
|
|
|
|
}
|
|
|
|
// Half formed printers should be deleted
|
|
// before they cause us trouble
|
|
|
|
if ( pIniPrinter->Status & PRINTER_PENDING_CREATION ) {
|
|
|
|
pIniPrinter->Status |= PRINTER_PENDING_DELETION ;
|
|
|
|
}
|
|
|
|
|
|
|
|
cbData = sizeof(pIniPrinter->Priority);
|
|
|
|
RegQueryValueEx(hPrinterKey, szPriority, NULL, &Type,
|
|
(LPBYTE)&pIniPrinter->Priority, &cbData);
|
|
|
|
cbData = sizeof(pIniPrinter->DefaultPriority);
|
|
|
|
RegQueryValueEx(hPrinterKey, szDefaultPriority, NULL, &Type,
|
|
(LPBYTE)&pIniPrinter->DefaultPriority, &cbData);
|
|
|
|
cbData = sizeof(pIniPrinter->UntilTime);
|
|
|
|
RegQueryValueEx(hPrinterKey, szUntilTime, NULL, &Type,
|
|
(LPBYTE)&pIniPrinter->UntilTime, &cbData);
|
|
|
|
cbData = sizeof(pIniPrinter->StartTime);
|
|
|
|
RegQueryValueEx(hPrinterKey, szStartTime, NULL, &Type,
|
|
(LPBYTE)&pIniPrinter->StartTime, &cbData);
|
|
|
|
cbData = sizeof(pIniPrinter->dnsTimeout);
|
|
|
|
if ( RegQueryValueEx(hPrinterKey, szDNSTimeout,
|
|
NULL, &Type,
|
|
(LPBYTE)&pIniPrinter->dnsTimeout,
|
|
&cbData) != ERROR_SUCCESS ) {
|
|
pIniPrinter->dnsTimeout = DEFAULT_DNS_TIMEOUT;
|
|
}
|
|
|
|
cbData = sizeof(pIniPrinter->txTimeout);
|
|
|
|
if ( RegQueryValueEx(hPrinterKey, szTXTimeout,
|
|
NULL, &Type,
|
|
(LPBYTE)&pIniPrinter->txTimeout,
|
|
&cbData) != ERROR_SUCCESS ) {
|
|
pIniPrinter->txTimeout = DEFAULT_TX_TIMEOUT;
|
|
}
|
|
|
|
cbData = sizeof( pIniPrinter->cChangeID ) ;
|
|
|
|
if ( ERROR_SUCCESS != RegQueryValueEx(hPrinterKey,
|
|
szTimeLastChange,
|
|
NULL,
|
|
&Type,
|
|
(LPBYTE)&pIniPrinter->cChangeID,
|
|
&cbData) ) {
|
|
|
|
// Current Registry Doesn't have a UniqueID
|
|
// Make sure one gets written
|
|
|
|
bUpdateRegistryForThisPrinter = TRUE;
|
|
|
|
}
|
|
|
|
pIniPrinter->cbDevMode = 0;
|
|
pIniPrinter->pDevMode = NULL;
|
|
|
|
if (RegQueryValueEx(hPrinterKey, szDevMode, NULL, &Type,
|
|
NULL, &pIniPrinter->cbDevMode)
|
|
== ERROR_SUCCESS) {
|
|
|
|
if (pIniPrinter->cbDevMode) {
|
|
|
|
pIniPrinter->pDevMode = AllocSplMem(pIniPrinter->cbDevMode);
|
|
|
|
RegQueryValueEx(hPrinterKey, szDevMode, NULL, &Type,
|
|
(LPBYTE)pIniPrinter->pDevMode,
|
|
&pIniPrinter->cbDevMode);
|
|
}
|
|
}
|
|
|
|
//
|
|
// A Provider might want to Read Extra Data from Registry
|
|
//
|
|
|
|
|
|
if ( pIniSpooler->pfnReadRegistryExtra != NULL ) {
|
|
|
|
pIniPrinter->pExtraData = (LPBYTE)(*pIniSpooler->pfnReadRegistryExtra)(hPrinterKey);
|
|
|
|
}
|
|
|
|
/* SECURITY */
|
|
|
|
Status = RegQueryValueEx(hPrinterKey, szSecurity, NULL, NULL,
|
|
NULL, &cbSecurity);
|
|
|
|
if ((Status == ERROR_MORE_DATA) || (Status == ERROR_SUCCESS)) {
|
|
|
|
/* Use the process' heap to allocate security descriptors,
|
|
* so that they can be passed to the security API, which
|
|
* may need to reallocate them.
|
|
*/
|
|
if (pIniPrinter->pSecurityDescriptor =
|
|
LocalAlloc(0, cbSecurity)) {
|
|
|
|
if (Status = RegQueryValueEx(hPrinterKey, szSecurity,
|
|
NULL, NULL,
|
|
pIniPrinter->pSecurityDescriptor,
|
|
&cbSecurity)
|
|
!= ERROR_SUCCESS) {
|
|
|
|
LocalFree(pIniPrinter->pSecurityDescriptor);
|
|
|
|
pIniPrinter->pSecurityDescriptor = NULL;
|
|
|
|
DBGMSG( DBG_WARNING,
|
|
( "RegQueryValue returned %d on Permissions for %ws (%ws)\n",
|
|
Status,
|
|
pIniPrinter->pName ?
|
|
pIniPrinter->pName :
|
|
szNull,
|
|
PrinterName) );
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
pIniPrinter->pSecurityDescriptor = NULL;
|
|
|
|
DBGMSG( DBG_WARNING,
|
|
( "RegQueryValue (2) returned %d on Permissions for %ws (%ws)\n",
|
|
Status,
|
|
pIniPrinter->pName ?
|
|
pIniPrinter->pName :
|
|
szNull,
|
|
PrinterName) );
|
|
}
|
|
|
|
/* END SECURITY */
|
|
|
|
if ( rcDataKey == ERROR_SUCCESS &&
|
|
pIniPrinter->pName &&
|
|
pIniPrinter->pShareName &&
|
|
pKeyData &&
|
|
pIniPrinter->ppIniPorts &&
|
|
pIniPrinter->pIniPrintProc &&
|
|
pIniPrinter->pIniDriver &&
|
|
pIniPrinter->pLocation &&
|
|
pIniPrinter->pComment &&
|
|
pIniPrinter->pSecurityDescriptor
|
|
#if DBG
|
|
&& ( IsValidSecurityDescriptor (pIniPrinter->pSecurityDescriptor)
|
|
? TRUE
|
|
: (DBGMSG( DBG_SECURITY,
|
|
( "The security descriptor for %ws (%ws) is invalid\n",
|
|
pIniPrinter->pName ?
|
|
pIniPrinter->pName :
|
|
szNull,
|
|
PrinterName)), /* (sequential evaluation) */
|
|
FALSE) )
|
|
#endif /* DBG */
|
|
) {
|
|
|
|
pIniPrinter->pIniFirstJob = pIniPrinter->pIniLastJob = NULL;
|
|
|
|
pIniPrinter->pIniPrintProc->cRef++;
|
|
|
|
INCDRIVERREF( pIniPrinter->pIniDriver );
|
|
|
|
if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_ENABLE_BIDI ) {
|
|
|
|
pIniLangMonitor = pIniPrinter->pIniDriver->pIniLangMonitor;
|
|
} else {
|
|
|
|
pIniLangMonitor = NULL;
|
|
}
|
|
|
|
for (i=0; i<pKeyData->cTokens; i++) {
|
|
|
|
pIniPort = (PINIPORT)pKeyData->pTokens[i];
|
|
pIniPrinter->ppIniPorts[i] = pIniPort;
|
|
|
|
pIniPort->ppIniPrinter =
|
|
|
|
ReallocSplMem(pIniPort->ppIniPrinter,
|
|
pIniPort->cPrinters *
|
|
sizeof(pIniPort->ppIniPrinter),
|
|
(pIniPort->cPrinters+1) *
|
|
sizeof(pIniPort->ppIniPrinter));
|
|
|
|
if (!pIniPort->ppIniPrinter) {
|
|
DBGMSG(DBG_WARNING, ("Failed to allocate memory for printer info\n." ));
|
|
}
|
|
|
|
pIniPort->ppIniPrinter[pIniPort->cPrinters] =
|
|
pIniPrinter;
|
|
|
|
//
|
|
// With the new monitors localspl does the
|
|
// redirection for LPT, COM ports
|
|
//
|
|
if ( !pIniPort->cPrinters++ )
|
|
CreateRedirectionThread(pIniPort);
|
|
|
|
//
|
|
// bidi monitor can inform spooler of errors. First
|
|
// printer will keep the port at the beginning
|
|
//
|
|
if ( !pIniPort->hPort ) {
|
|
|
|
OpenMonitorPort(pIniPort,
|
|
pIniLangMonitor,
|
|
pIniPrinter->pName,
|
|
TRUE);
|
|
}
|
|
}
|
|
|
|
pIniPrinter->cPorts = pKeyData->cTokens;
|
|
pIniPrinter->Priority =
|
|
pIniPrinter->Priority ? pIniPrinter->Priority
|
|
: DEF_PRIORITY;
|
|
|
|
if ((pIniPrinter->Attributes &
|
|
(PRINTER_ATTRIBUTE_QUEUED | PRINTER_ATTRIBUTE_DIRECT)) ==
|
|
(PRINTER_ATTRIBUTE_QUEUED | PRINTER_ATTRIBUTE_DIRECT))
|
|
|
|
pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_DIRECT;
|
|
|
|
pIniPrinter->pNext = pIniSpooler->pIniPrinter;
|
|
|
|
pIniPrinter->pIniSpooler = pIniSpooler;
|
|
|
|
pIniSpooler->pIniPrinter = pIniPrinter;
|
|
|
|
if ( bUpdateRegistryForThisPrinter ) {
|
|
|
|
UpdatePrinterIni( pIniPrinter , UPDATE_CHANGEID );
|
|
bUpdateRegistryForThisPrinter = UpdateChangeID;
|
|
}
|
|
|
|
} else {
|
|
|
|
DBGMSG( DBG_WARNING,
|
|
( "Initialization of printer failed:\
|
|
\n\tpPrinterName:\t%ws\
|
|
\n\tKeyName:\t%ws\
|
|
\n\tpShareName:\t%ws\
|
|
\n\tpKeyData:\t%08x\
|
|
\n\tpIniPrintProc:\t%08x",
|
|
pIniPrinter->pName ? pIniPrinter->pName : szNull,
|
|
PrinterName,
|
|
pIniPrinter->pShareName ? pIniPrinter->pShareName : szNull ,
|
|
pKeyData,
|
|
pIniPrinter->pIniPrintProc ) );
|
|
|
|
/* Do this in two lumps, because otherwise NTSD might crash.
|
|
* (Raid bug #10650)
|
|
*/
|
|
DBGMSG( DBG_WARNING,
|
|
( " \n\tpIniDriver:\t%08x\
|
|
\n\tpLocation:\t%ws\
|
|
\n\tpComment:\t%ws\
|
|
\n\tpSecurity:\t%08x\
|
|
\n\tStatus:\t\t%08x %s\n\n",
|
|
pIniPrinter->pIniDriver,
|
|
pIniPrinter->pLocation ? pIniPrinter->pLocation : szNull,
|
|
pIniPrinter->pComment ? pIniPrinter->pComment : szNull,
|
|
pIniPrinter->pSecurityDescriptor,
|
|
pIniPrinter->Status,
|
|
( pIniPrinter->Status & PRINTER_PENDING_DELETION
|
|
? "Pending deletion" : "" ) ) );
|
|
|
|
FreeStructurePointers((LPBYTE)pIniPrinter,
|
|
NULL,
|
|
IniPrinterOffsets);
|
|
|
|
if (pIniPrinter->pSecurityDescriptor)
|
|
LocalFree(pIniPrinter->pSecurityDescriptor);
|
|
|
|
if (( pIniSpooler->pfnFreePrinterExtra != NULL ) &&
|
|
( pIniPrinter->pExtraData != NULL )) {
|
|
|
|
(*pIniSpooler->pfnFreePrinterExtra)( pIniPrinter->pExtraData );
|
|
|
|
}
|
|
|
|
if ( pIniPrinter->hPrinterDataKey != NULL ) {
|
|
|
|
RegCloseKey( pIniPrinter->hPrinterDataKey );
|
|
}
|
|
|
|
|
|
FreeSplMem(pIniPrinter);
|
|
}
|
|
|
|
FreePortTokenList(pKeyData);
|
|
pKeyData = NULL;
|
|
}
|
|
RegCloseKey(hPrinterKey);
|
|
}
|
|
|
|
cPrinters++;
|
|
|
|
cbData = sizeof(PrinterName);
|
|
}
|
|
|
|
|
|
RegCloseKey(hPrinterRootKey);
|
|
|
|
// Read .SHD files from common printer directory
|
|
|
|
ProcessShadowJobs( NULL, pIniSpooler );
|
|
|
|
// If any printer has a separate Printer directory process them
|
|
// also
|
|
|
|
GetPrinterDirectory(NULL, FALSE, szData, pIniSpooler);
|
|
|
|
for ( pIniPrinter = pIniSpooler->pIniPrinter;
|
|
pIniPrinter;
|
|
pIniPrinter = pIniPrinter->pNext ) {
|
|
|
|
if ((pIniPrinter->pSpoolDir != NULL) &&
|
|
(_wcsicmp(szData, pIniPrinter->pSpoolDir) != 0)) {
|
|
|
|
ProcessShadowJobs(pIniPrinter, pIniSpooler);
|
|
|
|
}
|
|
}
|
|
|
|
UpdateReferencesToChainedJobs( pIniSpooler );
|
|
|
|
// Finally, go through all Printers looking for PENDING_DELETION
|
|
// if there are no jobs for that Printer, then we can delete it now
|
|
|
|
pIniPrinter = pIniSpooler->pIniPrinter;
|
|
|
|
while (pIniPrinter) {
|
|
|
|
if (pIniPrinter->Status & PRINTER_PENDING_DELETION &&
|
|
!pIniPrinter->cJobs) {
|
|
|
|
DeletePrinterForReal(pIniPrinter);
|
|
|
|
// The link list will have changed underneath us
|
|
// This could be the last printer and we will be
|
|
// pointing to oblivion
|
|
// Lets just loop through again from the beginning
|
|
|
|
pIniPrinter = pIniSpooler->pIniPrinter;
|
|
|
|
} else
|
|
|
|
pIniPrinter = pIniPrinter->pNext;
|
|
}
|
|
|
|
DBGMSG( DBG_TRACE, ("BuildPrinterInfo returned\n"));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* InitializePrintProcessor
|
|
*
|
|
* Allocates and initialises an INIPRINTPROC structure for the specified
|
|
* print processor and environment.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pIniEnvironment - Data structure for the requested environment
|
|
* The pIniPrintProc field is initialised with the chain of print
|
|
* processor structures
|
|
*
|
|
* pPathName - Full path to the print processors directory,
|
|
* e.g. C:\NT\SYSTEM32\SPOOL\PRTPROCS
|
|
*
|
|
* pEnvironment - The environment directory, e.g. W32X86
|
|
*
|
|
* pDLLName - The DLL name, e.g. WINPRINT
|
|
*
|
|
* Returns:
|
|
*
|
|
* TRUE if no error was detected, otherwise FALSE.
|
|
*
|
|
*
|
|
*/
|
|
PINIPRINTPROC
|
|
InitializePrintProcessor(
|
|
PINIENVIRONMENT pIniEnvironment,
|
|
LPWSTR pPrintProcessorName,
|
|
LPWSTR pDLLName,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
DWORD cb, cbNeeded, cReturned;
|
|
PINIPRINTPROC pIniPrintProc;
|
|
WCHAR string[MAX_PATH];
|
|
BOOL rc;
|
|
DWORD Error;
|
|
DWORD dwOldErrMode = 0;
|
|
|
|
DBGMSG(DBG_TRACE, ("InitializePrintProcessor( %08x, %ws, %ws )\n",
|
|
pIniEnvironment, pPrintProcessorName, pDLLName));
|
|
|
|
cb = sizeof(INIPRINTPROC) +
|
|
wcslen(pPrintProcessorName)*sizeof(WCHAR) +
|
|
sizeof(WCHAR) +
|
|
wcslen(pDLLName)*sizeof(WCHAR) +
|
|
sizeof(WCHAR);
|
|
|
|
if (!(pIniPrintProc = (PINIPRINTPROC)AllocSplMem(cb))) {
|
|
|
|
DBGMSG(DBG_WARNING, ("Failed to allocate %d bytes for print processor\n.", cb));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/* Typical strings used to build the full path of the DLL:
|
|
*
|
|
* pPathName = C:\NT\SYSTEM32\SPOOL\PRTPROCS
|
|
* pEnvironment = W32X86
|
|
* pDLLName = WINPRINT
|
|
*/
|
|
wsprintf(string, L"%ws\\PRTPROCS\\%ws\\%ws", pIniSpooler->pDir,
|
|
pIniEnvironment->pDirectory,
|
|
pDLLName);
|
|
|
|
dwOldErrMode = SetErrorMode( SEM_FAILCRITICALERRORS );
|
|
|
|
pIniPrintProc->hLibrary = LoadLibrary(string);
|
|
|
|
SetErrorMode( dwOldErrMode ); /* Restore error mode */
|
|
|
|
if (!pIniPrintProc->hLibrary) {
|
|
|
|
FreeSplMem(pIniPrintProc);
|
|
DBGMSG(DBG_WARNING, ("Failed to LoadLibrary(%ws)\n", string));
|
|
return FALSE;
|
|
}
|
|
|
|
pIniPrintProc->EnumDatatypes = GetProcAddress(pIniPrintProc->hLibrary,
|
|
"EnumPrintProcessorDatatypesW");
|
|
|
|
if (!pIniPrintProc->EnumDatatypes) {
|
|
|
|
DBGMSG(DBG_WARNING, ("Failed to GetProcAddress(EnumDatatypes)\n"));
|
|
FreeLibrary(pIniPrintProc->hLibrary);
|
|
FreeSplMem(pIniPrintProc);
|
|
return FALSE;
|
|
}
|
|
|
|
rc = (*pIniPrintProc->EnumDatatypes)(NULL, pPrintProcessorName, 1, NULL, 0,
|
|
&cbNeeded, &cReturned);
|
|
|
|
if (!rc && ((Error = GetLastError()) == ERROR_INSUFFICIENT_BUFFER)) {
|
|
|
|
pIniPrintProc->cbDatatypes = cbNeeded;
|
|
|
|
if (!(pIniPrintProc->pDatatypes = AllocSplMem(cbNeeded))) {
|
|
|
|
DBGMSG(DBG_WARNING, ("Failed to allocate %d bytes for print proc datatypes\n.", cbNeeded));
|
|
FreeLibrary(pIniPrintProc->hLibrary);
|
|
FreeSplMem(pIniPrintProc);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (!(*pIniPrintProc->EnumDatatypes)(NULL, pPrintProcessorName, 1,
|
|
pIniPrintProc->pDatatypes,
|
|
cbNeeded, &cbNeeded,
|
|
&pIniPrintProc->cDatatypes)) {
|
|
|
|
Error = GetLastError();
|
|
DBGMSG(DBG_WARNING, ("EnumPrintProcessorDatatypes(%ws) failed: Error %d\n",
|
|
pPrintProcessorName, Error));
|
|
}
|
|
|
|
} else if(rc) {
|
|
|
|
DBGMSG(DBG_WARNING, ("EnumPrintProcessorDatatypes(%ws) returned no data\n",
|
|
pPrintProcessorName));
|
|
|
|
} else {
|
|
|
|
DBGMSG(DBG_WARNING, ("EnumPrintProcessorDatatypes(%ws) failed: Error %d\n",
|
|
pPrintProcessorName, Error));
|
|
}
|
|
|
|
pIniPrintProc->Install = GetProcAddress(pIniPrintProc->hLibrary,
|
|
"InstallPrintProcessor");
|
|
|
|
pIniPrintProc->Open = GetProcAddress(pIniPrintProc->hLibrary,
|
|
"OpenPrintProcessor");
|
|
|
|
pIniPrintProc->Print = GetProcAddress(pIniPrintProc->hLibrary,
|
|
"PrintDocumentOnPrintProcessor");
|
|
|
|
pIniPrintProc->Close = GetProcAddress(pIniPrintProc->hLibrary,
|
|
"ClosePrintProcessor");
|
|
|
|
pIniPrintProc->Control = GetProcAddress(pIniPrintProc->hLibrary,
|
|
"ControlPrintProcessor");
|
|
|
|
|
|
/* pName and pDLLName are contiguous with the INIPRINTPROC structure:
|
|
*/
|
|
pIniPrintProc->pName = (LPWSTR)(pIniPrintProc+1);
|
|
wcscpy(pIniPrintProc->pName, pPrintProcessorName);
|
|
|
|
pIniPrintProc->pDLLName = (LPWSTR)(pIniPrintProc->pName +
|
|
wcslen(pIniPrintProc->pName) + 1);
|
|
wcscpy(pIniPrintProc->pDLLName, pDLLName);
|
|
|
|
|
|
pIniPrintProc->signature = IPP_SIGNATURE;
|
|
|
|
pIniPrintProc->pNext = pIniEnvironment->pIniPrintProc;
|
|
|
|
pIniEnvironment->pIniPrintProc = pIniPrintProc;
|
|
|
|
InitializeCriticalSection(&pIniPrintProc->CriticalSection);
|
|
|
|
return pIniPrintProc;
|
|
}
|
|
|
|
/*
|
|
Current Directory == c:\winspool\drivers
|
|
pFindFileData->cFileName == win32.x86
|
|
*/
|
|
|
|
|
|
/* BuildEnvironmentInfo
|
|
*
|
|
*
|
|
* The registry tree for Environments is as follows:
|
|
*
|
|
* Print
|
|
* ³
|
|
* ÃÄ Environments
|
|
* ³ ³
|
|
* ³ ÃÄ Windows NT x86
|
|
* ³ ³ ³
|
|
* ³ ³ ÃÄ Drivers
|
|
* ³ ³ ³ ³
|
|
* ³ ³ ³ ÀÄ Agfa Compugraphic Genics (e.g.)
|
|
* ³ ³ ³
|
|
* ³ ³ ³ :
|
|
* ³ ³ ³ :
|
|
* ³ ³ ³
|
|
* ³ ³ ÀÄ Print Processors
|
|
* ³ ³ ³
|
|
* ³ ³ ÀÄ WINPRINT : WINPRINT.DLL (e.g.)
|
|
* ³ ³
|
|
* ³ ³ :
|
|
* ³ ³ :
|
|
* ³ ³
|
|
* ³ ÀÄ Windows NT R4000
|
|
* ³
|
|
* ÀÄ Printers
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
BOOL
|
|
BuildEnvironmentInfo(
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
WCHAR Environment[MAX_PATH];
|
|
WCHAR szData[MAX_PATH];
|
|
DWORD cbData, cb;
|
|
DWORD cbBuffer = sizeof(Environment);
|
|
DWORD cEnvironments=0, Type;
|
|
HKEY hEnvironmentsKey, hEnvironmentKey;
|
|
LPWSTR pDirectory;
|
|
PINIENVIRONMENT pIniEnvironment;
|
|
LONG Status;
|
|
|
|
/* Open the "Environments" key:
|
|
*/
|
|
Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pIniSpooler->pszRegistryEnvironments, 0,
|
|
KEY_READ, &hEnvironmentsKey);
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
DBGMSG(DBG_WARNING, ("RegOpenKey of %ws Failed: Error = %d\n",
|
|
szEnvironmentsKey, Status));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* Enumerate the subkeys of "Environment".
|
|
* This will give us "Windows NT x86", "Windows NT R4000",
|
|
* and maybe others:
|
|
*/
|
|
while (RegEnumKeyEx(hEnvironmentsKey, cEnvironments, Environment, &cbBuffer,
|
|
NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
|
|
|
|
DBGMSG(DBG_TRACE, ("Found environment %ws\n", Environment));
|
|
|
|
/* For each one found, create or open the key:
|
|
*/
|
|
if (RegCreateKeyEx(hEnvironmentsKey, Environment, 0, NULL, 0,
|
|
KEY_READ, NULL, &hEnvironmentKey, NULL)
|
|
== ERROR_SUCCESS) {
|
|
|
|
cbData = sizeof(szData);
|
|
|
|
pDirectory = NULL;
|
|
|
|
//
|
|
// Find the name of the directory associated with this environment,
|
|
// e.g. "Windows NT x86" -> "W32X86"
|
|
// "Windows NT R4000" -> "W32MIPS"
|
|
//
|
|
if (RegQueryValueEx(hEnvironmentKey, szDirectory,
|
|
NULL, &Type, (LPBYTE)szData,
|
|
&cbData) == ERROR_SUCCESS) {
|
|
|
|
pDirectory = AllocSplStr(szData);
|
|
}
|
|
|
|
cb = sizeof(INIENVIRONMENT) +
|
|
wcslen(Environment)*sizeof(WCHAR) +
|
|
sizeof(WCHAR);
|
|
|
|
if (pDirectory && (pIniEnvironment=AllocSplMem(cb))) {
|
|
|
|
pIniEnvironment->pName = wcscpy((LPWSTR)(pIniEnvironment+1),
|
|
Environment);
|
|
|
|
pIniEnvironment->signature = IE_SIGNATURE;
|
|
pIniEnvironment->pDirectory = pDirectory;
|
|
pIniEnvironment->pNext = pIniSpooler->pIniEnvironment;
|
|
pIniSpooler->pIniEnvironment = pIniEnvironment;
|
|
pIniEnvironment->pIniVersion = NULL;
|
|
pIniEnvironment->pIniPrintProc = NULL;
|
|
pIniEnvironment->pIniSpooler = pIniSpooler;
|
|
BuildDriverInfo(hEnvironmentKey, pIniEnvironment, pIniSpooler);
|
|
BuildPrintProcInfo (hEnvironmentKey, pIniEnvironment, pIniSpooler);
|
|
|
|
DBGMSG(DBG_TRACE, ("Data for environment %ws created:\
|
|
\n\tpDirectory: %ws\n",
|
|
Environment,
|
|
pDirectory));
|
|
}
|
|
|
|
RegCloseKey(hEnvironmentKey);
|
|
}
|
|
|
|
cEnvironments++;
|
|
|
|
cbBuffer = sizeof(Environment);
|
|
}
|
|
|
|
RegCloseKey(hEnvironmentsKey);
|
|
|
|
pThisEnvironment = FindEnvironment( szEnvironment );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
BuildDriverInfo(
|
|
HKEY hKeyEnvironment,
|
|
PINIENVIRONMENT pIniEnvironment,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates driver and version ini structures based on environment.
|
|
|
|
Arguments:
|
|
|
|
hKeyEnvironment - Registry key specifying environment.
|
|
|
|
pIniEnvironment - Structure for environemnt. Will be initialized
|
|
to hold pIniVersions and pIniDrivers.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Success,
|
|
False - Failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
WCHAR szVersionName[MAX_PATH];
|
|
DWORD cchBuffer;
|
|
DWORD cVersion;
|
|
HKEY hDriversKey;
|
|
DWORD Status;
|
|
PINIVERSION pIniVersionList, pIniVersion;
|
|
|
|
Status = RegCreateKeyEx( hKeyEnvironment,
|
|
szDriversKey, 0, NULL, 0,
|
|
KEY_READ, NULL, &hDriversKey, NULL);
|
|
|
|
if (Status != ERROR_SUCCESS) {
|
|
DBGMSG( DBG_ERROR, ("RegOpenKeyEx of %ws failed: Error = %d\n",
|
|
szDriversKey, Status));
|
|
return FALSE;
|
|
}
|
|
|
|
DBGMSG(DBG_TRACE,("RegCreateKeyEx succeeded in BuildDriverInfo\n"));
|
|
|
|
for( pIniVersionList = NULL, cVersion = 0;
|
|
|
|
cchBuffer = COUNTOF( szVersionName ),
|
|
RegEnumKeyEx( hDriversKey,
|
|
cVersion,
|
|
szVersionName,
|
|
&cchBuffer,
|
|
NULL, NULL, NULL, NULL ) == ERROR_SUCCESS;
|
|
|
|
cVersion++ ){
|
|
|
|
DBGMSG(DBG_TRACE,("Version found %ws\n", szVersionName));
|
|
|
|
//
|
|
// If it isn't a version -- remember we look for current
|
|
// drivers before we upgrade, just move on.
|
|
//
|
|
if (_wcsnicmp(szVersionName, L"Version-", 8)) {
|
|
continue;
|
|
}
|
|
|
|
pIniVersion = GetVersionDrivers( hDriversKey, szVersionName, pIniSpooler );
|
|
|
|
if( pIniVersion ){
|
|
InsertVersionList( &pIniVersionList, pIniVersion );
|
|
}
|
|
}
|
|
RegCloseKey(hDriversKey);
|
|
pIniEnvironment->pIniVersion = pIniVersionList;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* BuildPrintProcInfo
|
|
*
|
|
* Opens the printproc subkey for the specified environment and enumerates
|
|
* the print processors listed.
|
|
*
|
|
* For each print processor found, calls InitializePrintProcessor to allocate
|
|
* and inintialize a data structure.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* hKeyEnvironment - The key for the specified environment,
|
|
* used for Registry API calls.
|
|
*
|
|
* pIniEnvironment - Data structure for the environment.
|
|
* The pIniPrintProc field will be initialised to contain a chain
|
|
* of one or more print processors enumerated from the registry.
|
|
*
|
|
* Return:
|
|
*
|
|
* TRUE if operation was successful, otherwise FALSE
|
|
*
|
|
*
|
|
* 8 Sept 1992 by andrewbe, based on an original idea by davesn
|
|
*/
|
|
BOOL
|
|
BuildPrintProcInfo(
|
|
HKEY hKeyEnvironment,
|
|
PINIENVIRONMENT pIniEnvironment,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
WCHAR PrintProcName[MAX_PATH];
|
|
WCHAR DLLName[MAX_PATH];
|
|
DWORD cbBuffer, cbDLLName;
|
|
DWORD cPrintProcs;
|
|
HKEY hPrintProcKey, hPrintProc;
|
|
DWORD Status;
|
|
PINIPRINTPROC pIniPrintProc;
|
|
|
|
cPrintProcs=0;
|
|
|
|
|
|
if ((Status = RegOpenKeyEx(hKeyEnvironment, szPrintProcKey, 0,
|
|
KEY_READ, &hPrintProcKey))
|
|
== ERROR_SUCCESS) {
|
|
|
|
cbBuffer = sizeof(PrintProcName);
|
|
|
|
while (RegEnumKeyEx(hPrintProcKey, cPrintProcs, (LPTSTR)PrintProcName,
|
|
&cbBuffer, NULL, NULL, NULL, NULL)
|
|
== ERROR_SUCCESS) {
|
|
|
|
DBGMSG(DBG_TRACE, ("Print processor found: %ws\n", PrintProcName));
|
|
|
|
if (RegOpenKeyEx(hPrintProcKey, PrintProcName, 0, KEY_READ,
|
|
&hPrintProc) == ERROR_SUCCESS) {
|
|
|
|
cbDLLName = sizeof(DLLName);
|
|
|
|
if (RegQueryValueEx(hPrintProc, szDriverFile, NULL, NULL,
|
|
(LPBYTE)DLLName, &cbDLLName)
|
|
== ERROR_SUCCESS) {
|
|
|
|
pIniPrintProc = InitializePrintProcessor(pIniEnvironment,
|
|
PrintProcName,
|
|
DLLName,
|
|
pIniSpooler);
|
|
}
|
|
|
|
RegCloseKey(hPrintProc);
|
|
}
|
|
|
|
//
|
|
// Don't delete the key !! If winprint.dll was corrupt,
|
|
// then we nuke it and we are hosed since there is no UI
|
|
// to add print procs.
|
|
// We can afford to be a little slow on init, since we only
|
|
// do it once.
|
|
//
|
|
cbBuffer = sizeof(PrintProcName);
|
|
cPrintProcs++;
|
|
}
|
|
|
|
RegCloseKey(hPrintProcKey);
|
|
|
|
DBGMSG(DBG_TRACE, ("End of print processor initialization.\n"));
|
|
|
|
} else {
|
|
|
|
DBGMSG (DBG_WARNING, ("RegOpenKeyEx failed: Error = %d\n", Status));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#define SetOffset(Dest, Source, End) \
|
|
if (Source) { \
|
|
Dest=End; \
|
|
End+=wcslen(Source)+1; \
|
|
}
|
|
|
|
#define SetPointer(struc, off) \
|
|
if (struc->off) { \
|
|
struc->off += (DWORD)struc/sizeof(*struc->off); \
|
|
}
|
|
|
|
#define WriteString(hFile, pStr) \
|
|
if (pStr) {\
|
|
rc = WriteFile(hFile, pStr, wcslen(pStr)*sizeof(WCHAR) + \
|
|
sizeof(WCHAR), &BytesWritten, NULL); \
|
|
if (!rc) { \
|
|
DBGMSG(DBG_WARNING, ("WriteShadowJob: WriteFile failed %d\n", \
|
|
GetLastError())); \
|
|
} \
|
|
}
|
|
|
|
|
|
BOOL
|
|
WriteShadowJob(
|
|
PINIJOB pIniJob
|
|
)
|
|
{
|
|
HANDLE hFile;
|
|
DWORD BytesWritten, cb;
|
|
SHADOWFILE_2 ShadowFile;
|
|
LPWSTR pEnd;
|
|
WCHAR szFileName[MAX_PATH];
|
|
HANDLE hImpersonationToken;
|
|
BOOL rc;
|
|
|
|
GetFullNameFromId(pIniJob->pIniPrinter, pIniJob->JobId, FALSE, szFileName, FALSE);
|
|
|
|
hImpersonationToken = RevertToPrinterSelf();
|
|
|
|
hFile=CreateFile(szFileName, GENERIC_WRITE, FILE_SHARE_READ,
|
|
NULL, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL);
|
|
|
|
ImpersonatePrinterClient(hImpersonationToken);
|
|
|
|
if ( hFile == INVALID_HANDLE_VALUE ) {
|
|
|
|
DBGMSG( DBG_WARNING, ("WriteShadowJob failed to open shadow file %s\n Error %d\n",szFileName, GetLastError() ));
|
|
return FALSE;
|
|
}
|
|
|
|
memset(&ShadowFile, 0, sizeof(ShadowFile));
|
|
ShadowFile.signature = SF_SIGNATURE_2;
|
|
ShadowFile.Version = SF_VERSION_2;
|
|
ShadowFile.Status = pIniJob->Status;
|
|
ShadowFile.JobId = pIniJob->JobId;
|
|
ShadowFile.Priority = pIniJob->Priority;
|
|
ShadowFile.Submitted = pIniJob->Submitted;
|
|
ShadowFile.StartTime = pIniJob->StartTime;
|
|
ShadowFile.UntilTime = pIniJob->UntilTime;
|
|
ShadowFile.Size = pIniJob->Size;
|
|
ShadowFile.cPages = pIniJob->cPages;
|
|
ShadowFile.dwReboots = pIniJob->dwReboots;
|
|
if(pIniJob->pSecurityDescriptor)
|
|
ShadowFile.cbSecurityDescriptor=GetSecurityDescriptorLength(
|
|
pIniJob->pSecurityDescriptor);
|
|
|
|
pEnd=(LPWSTR)sizeof(ShadowFile);
|
|
|
|
if (pIniJob->pDevMode) {
|
|
ShadowFile.pDevMode=(LPDEVMODE)pEnd;
|
|
cb = pIniJob->pDevMode->dmSize + pIniJob->pDevMode->dmDriverExtra;
|
|
cb /= sizeof(WCHAR);
|
|
pEnd += cb;
|
|
}
|
|
|
|
if (pIniJob->pSecurityDescriptor) {
|
|
ShadowFile.pSecurityDescriptor=(PSECURITY_DESCRIPTOR)pEnd;
|
|
cb = ShadowFile.cbSecurityDescriptor;
|
|
cb /= sizeof(WCHAR);
|
|
pEnd += cb;
|
|
}
|
|
|
|
ShadowFile.NextJobId = pIniJob->NextJobId;
|
|
|
|
SetOffset( ShadowFile.pNotify, pIniJob->pNotify, pEnd );
|
|
SetOffset( ShadowFile.pUser, pIniJob->pUser, pEnd );
|
|
SetOffset( ShadowFile.pDocument, pIniJob->pDocument, pEnd );
|
|
SetOffset( ShadowFile.pOutputFile, pIniJob->pOutputFile, pEnd );
|
|
SetOffset( ShadowFile.pPrinterName, pIniJob->pIniPrinter->pName, pEnd );
|
|
SetOffset( ShadowFile.pDriverName, pIniJob->pIniDriver->pName, pEnd );
|
|
SetOffset( ShadowFile.pPrintProcName, pIniJob->pIniPrintProc->pName, pEnd );
|
|
SetOffset( ShadowFile.pDatatype, pIniJob->pDatatype, pEnd );
|
|
SetOffset( ShadowFile.pParameters, pIniJob->pParameters, pEnd );
|
|
|
|
|
|
rc = WriteFile( hFile, &ShadowFile, sizeof(SHADOWFILE_2), &BytesWritten, NULL );
|
|
|
|
if (!rc) {
|
|
|
|
DBGMSG( DBG_WARNING, ("WriteShadowJob: WriteFile failed %d\n", GetLastError()));
|
|
}
|
|
|
|
if ( pIniJob->pDevMode ) {
|
|
|
|
rc = WriteFile( hFile, pIniJob->pDevMode, pIniJob->pDevMode->dmSize +
|
|
pIniJob->pDevMode->dmDriverExtra,
|
|
&BytesWritten, NULL );
|
|
if ( !rc ) {
|
|
|
|
DBGMSG( DBG_WARNING, ("WriteShadowJob: WriteFile failed %d\n", GetLastError() ));
|
|
}
|
|
}
|
|
|
|
if ( pIniJob->pSecurityDescriptor ) {
|
|
|
|
rc = WriteFile( hFile, pIniJob->pSecurityDescriptor,
|
|
ShadowFile.cbSecurityDescriptor,
|
|
&BytesWritten, NULL );
|
|
|
|
if ( !rc ) {
|
|
|
|
DBGMSG( DBG_WARNING, ("WriteShadowJob: WriteFile failed %d\n", GetLastError() ));
|
|
}
|
|
}
|
|
|
|
WriteString( hFile, pIniJob->pNotify );
|
|
WriteString( hFile, pIniJob->pUser );
|
|
WriteString( hFile, pIniJob->pDocument );
|
|
WriteString( hFile, pIniJob->pOutputFile );
|
|
WriteString( hFile, pIniJob->pIniPrinter->pName );
|
|
WriteString( hFile, pIniJob->pIniDriver->pName );
|
|
WriteString( hFile, pIniJob->pIniPrintProc->pName );
|
|
WriteString( hFile, pIniJob->pDatatype );
|
|
WriteString( hFile, pIniJob->pParameters );
|
|
|
|
//#if 0
|
|
// Thought to be a performance Hit
|
|
// So removed in PPC build
|
|
rc = FlushFileBuffers( hFile );
|
|
|
|
if (!rc) {
|
|
DBGMSG(DBG_WARNING, ("WriteShadowJob: FlushFileBuffers failed %d\n",
|
|
GetLastError()));
|
|
}
|
|
//#endif
|
|
|
|
if (!CloseHandle(hFile)) {
|
|
DBGMSG(DBG_WARNING, ("WriteShadowJob CloseHandle failed %d %d\n",
|
|
hFile, GetLastError()));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
ProcessShadowJobs(
|
|
PINIPRINTER pIniPrinter,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
WCHAR wczPrintDirAllShadows[MAX_PATH];
|
|
WCHAR wczPrinterDirectory[MAX_PATH];
|
|
HANDLE fFile;
|
|
BOOL b;
|
|
PWIN32_FIND_DATA pFindFileData;
|
|
PINIJOB pIniJob;
|
|
|
|
SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
|
|
|
|
//
|
|
// Don't Process Shadow Jobs during Upgrade
|
|
//
|
|
|
|
if ( dwUpgradeFlag != 0) {
|
|
|
|
return;
|
|
}
|
|
|
|
GetPrinterDirectory(pIniPrinter, FALSE, wczPrintDirAllShadows, pIniSpooler);
|
|
|
|
GetPrinterDirectory(pIniPrinter, FALSE, wczPrinterDirectory, pIniSpooler);
|
|
|
|
wcscat(wczPrintDirAllShadows, szAllShadows);
|
|
|
|
if ( pFindFileData = AllocSplMem(sizeof(WIN32_FIND_DATA) )) {
|
|
|
|
fFile = FindFirstFile( wczPrintDirAllShadows, pFindFileData );
|
|
|
|
if ( fFile != (HANDLE)-1 ) {
|
|
|
|
b=TRUE;
|
|
|
|
while( b ) {
|
|
|
|
if ( !(pFindFileData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
ReadShadowJob(wczPrinterDirectory, pFindFileData, pIniSpooler);
|
|
}
|
|
|
|
b = FindNextFile(fFile, pFindFileData);
|
|
}
|
|
|
|
FindClose( fFile );
|
|
|
|
}
|
|
|
|
FreeSplMem( pFindFileData );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#define CheckPointer( strptr ) \
|
|
if( strptr ) { \
|
|
if( (DWORD)(strptr + wcslen(strptr) + 1) > (DWORD)pEnd ) { \
|
|
bRet = FALSE; \
|
|
goto BailOut; \
|
|
} \
|
|
}
|
|
|
|
//
|
|
// make sure all pointers contain embedded data bounded within the pShadowFile (not passed the end).
|
|
//
|
|
BOOL
|
|
CheckAllPointers(
|
|
PSHADOWFILE_2 pShadowFile,
|
|
DWORD dwSize
|
|
)
|
|
{
|
|
LPBYTE pEnd = (LPBYTE)pShadowFile + dwSize;
|
|
DWORD cb;
|
|
BOOL bRet = TRUE;
|
|
|
|
try {
|
|
|
|
CheckPointer(pShadowFile->pDatatype);
|
|
CheckPointer(pShadowFile->pNotify);
|
|
CheckPointer(pShadowFile->pUser);
|
|
CheckPointer(pShadowFile->pDocument);
|
|
CheckPointer(pShadowFile->pOutputFile);
|
|
CheckPointer(pShadowFile->pPrinterName);
|
|
CheckPointer(pShadowFile->pDriverName);
|
|
CheckPointer(pShadowFile->pPrintProcName);
|
|
CheckPointer(pShadowFile->pParameters);
|
|
|
|
// Now check the rest of the two data structures
|
|
if( (DWORD)pShadowFile->pSecurityDescriptor + pShadowFile->cbSecurityDescriptor > (DWORD)pEnd ) {
|
|
bRet = FALSE;
|
|
goto BailOut;
|
|
}
|
|
|
|
if( pShadowFile->pDevMode ) {
|
|
cb = pShadowFile->pDevMode->dmSize + pShadowFile->pDevMode->dmDriverExtra;
|
|
if( (DWORD)pShadowFile->pDevMode + cb > (DWORD)pEnd )
|
|
bRet = FALSE;
|
|
}
|
|
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
bRet = FALSE;
|
|
}
|
|
|
|
BailOut:
|
|
return bRet;
|
|
}
|
|
|
|
#undef CheckPointer
|
|
|
|
|
|
PINIJOB
|
|
ReadShadowJob(
|
|
LPWSTR szDir,
|
|
PWIN32_FIND_DATA pFindFileData,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads a *.shd file and partially validates the file.
|
|
|
|
Arguments:
|
|
|
|
szDir -- pointer to spool directory string
|
|
|
|
pFindFileData -- found file data
|
|
|
|
pIniSpooler -- spooler the *.shd belongs to
|
|
|
|
Return Value:
|
|
|
|
Allocated pIniJob.
|
|
|
|
Warning: Changing the format of SHADOWFILE requires modifying the data integrity checks performed here!
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
HANDLE hFileSpl = INVALID_HANDLE_VALUE;
|
|
DWORD BytesRead;
|
|
PSHADOWFILE_2 pShadowFile2 = NULL;
|
|
PSHADOWFILE_2 pShadowFile = NULL;
|
|
PINIJOB pIniJob;
|
|
DWORD cb,i;
|
|
WCHAR szFileName[MAX_PATH];
|
|
LPWSTR pExt;
|
|
BOOL rc;
|
|
LPWSTR pFileSpec;
|
|
|
|
SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
|
|
|
|
wcscpy(&szFileName[0], szDir);
|
|
pFileSpec = szFileName + wcslen(szFileName);
|
|
|
|
*pFileSpec++ = L'\\';
|
|
wcscpy(pFileSpec, pFindFileData->cFileName);
|
|
|
|
hFile=CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ,
|
|
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|
DBGMSG(DBG_WARNING, ("ReadShadowJob CreateFile( %ws ) failed: LastError = %d\n",
|
|
szFileName, GetLastError()));
|
|
|
|
goto Fail;
|
|
}
|
|
|
|
CharUpper(szFileName);
|
|
pExt = wcsstr(szFileName, L".SHD");
|
|
|
|
if (!pExt)
|
|
goto Fail;
|
|
|
|
pExt[2] = L'P';
|
|
pExt[3] = L'L';
|
|
|
|
if (pFindFileData->nFileSizeLow < sizeof(*pShadowFile)) {
|
|
|
|
DBGMSG(DBG_WARNING, ( "Bad ShadowJob: %ws Size: %d, expecting %d\n",
|
|
pFindFileData->cFileName,
|
|
pFindFileData->nFileSizeLow,
|
|
sizeof(*pShadowFile)));
|
|
goto Fail;
|
|
}
|
|
|
|
hFileSpl=CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ,
|
|
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
|
|
|
if (hFileSpl == INVALID_HANDLE_VALUE) {
|
|
DBGMSG(DBG_WARNING, ("ReadShadowJob CreateFile( %ws ) failed: LastError = %d\n",
|
|
szFileName, GetLastError()));
|
|
|
|
goto Fail;
|
|
}
|
|
|
|
|
|
if (!(pShadowFile=AllocSplMem(pFindFileData->nFileSizeLow))) {
|
|
goto Fail;
|
|
}
|
|
|
|
rc = ReadFile(hFile, pShadowFile, pFindFileData->nFileSizeLow, &BytesRead, NULL);
|
|
|
|
// If Shadow file is old style, then convert it to new
|
|
if (rc && (BytesRead == pFindFileData->nFileSizeLow) && pShadowFile->signature == SF_SIGNATURE) {
|
|
|
|
if ((BytesRead < sizeof(SHADOWFILE)) ||
|
|
!(pShadowFile2 = AllocSplMem(pFindFileData->nFileSizeLow +
|
|
sizeof(SHADOWFILE_2) - sizeof(SHADOWFILE))) ) {
|
|
|
|
goto Fail;
|
|
}
|
|
|
|
Old2NewShadow((PSHADOWFILE) pShadowFile, pShadowFile2, &BytesRead);
|
|
pFindFileData->nFileSizeLow = BytesRead; // This is used in CheckAllPointers, below
|
|
FreeSplMem(pShadowFile);
|
|
pShadowFile = pShadowFile2;
|
|
}
|
|
|
|
if (!rc ||
|
|
(pShadowFile->signature != SF_SIGNATURE && pShadowFile->signature != SF_SIGNATURE_2) ||
|
|
(BytesRead != pFindFileData->nFileSizeLow) || (BytesRead < sizeof(SHADOWFILE_2)) ||
|
|
(pShadowFile->Status & (JOB_SPOOLING | JOB_PENDING_DELETION))) {
|
|
|
|
DBGMSG(DBG_WARNING, ( "Error reading shadow job:\
|
|
\n\tReadFile returned %d: Error %d\
|
|
\n\tsignature = %08x\
|
|
\n\tBytes read = %d; expected %d\
|
|
\n\tFile size = %d; expected %d\
|
|
\n\tStatus = %08x %s\n",
|
|
rc, ( rc ? 0 : GetLastError() ),
|
|
pShadowFile->signature,
|
|
BytesRead, pFindFileData->nFileSizeLow,
|
|
sizeof(*pShadowFile), pShadowFile->Size,
|
|
pShadowFile->Status,
|
|
( (pShadowFile->Status & JOB_SPOOLING) ?
|
|
"Job is spooling!" : "" ) ) );
|
|
|
|
goto Fail;
|
|
}
|
|
|
|
if (!CloseHandle(hFile)) {
|
|
DBGMSG(DBG_WARNING, ("CloseHandle failed %d %d\n", hFileSpl, GetLastError()));
|
|
}
|
|
hFile = INVALID_HANDLE_VALUE;
|
|
|
|
if (!CloseHandle(hFileSpl)) {
|
|
DBGMSG(DBG_WARNING, ("CloseHandle failed %d %d\n", hFileSpl, GetLastError()));
|
|
}
|
|
hFileSpl = INVALID_HANDLE_VALUE;
|
|
|
|
// Check number of reboots on this file & delete if too many
|
|
if (pShadowFile->dwReboots > 1) {
|
|
DBGMSG(DBG_WARNING, ("Corrupt shadow file %ws\n", szFileName));
|
|
goto Fail;
|
|
}
|
|
|
|
if (pIniJob = AllocSplMem(sizeof(INIJOB))) {
|
|
|
|
INITJOBREFZERO(pIniJob);
|
|
|
|
pIniJob->signature=IJ_SIGNATURE;
|
|
pIniJob->Status = pShadowFile->Status & (JOB_PAUSED | JOB_REMOTE | JOB_PRINTED );
|
|
pIniJob->JobId = pShadowFile->JobId;
|
|
pIniJob->Priority = pShadowFile->Priority;
|
|
pIniJob->Submitted = pShadowFile->Submitted;
|
|
pIniJob->StartTime = pShadowFile->StartTime;
|
|
pIniJob->UntilTime = pShadowFile->UntilTime;
|
|
pIniJob->Size = pShadowFile->Size;
|
|
pIniJob->cPages = pShadowFile->cPages;
|
|
pIniJob->cbPrinted = 0;
|
|
pIniJob->NextJobId = pShadowFile->NextJobId;
|
|
pIniJob->dwReboots = pShadowFile->dwReboots;
|
|
|
|
pIniJob->WaitForWrite = INVALID_HANDLE_VALUE;
|
|
pIniJob->WaitForRead = INVALID_HANDLE_VALUE;
|
|
pIniJob->hWriteFile = INVALID_HANDLE_VALUE;
|
|
|
|
SetPointer(pShadowFile, pDatatype);
|
|
SetPointer(pShadowFile, pNotify);
|
|
SetPointer(pShadowFile, pUser);
|
|
SetPointer(pShadowFile, pDocument);
|
|
SetPointer(pShadowFile, pOutputFile);
|
|
SetPointer(pShadowFile, pPrinterName);
|
|
SetPointer(pShadowFile, pDriverName);
|
|
SetPointer(pShadowFile, pPrintProcName);
|
|
SetPointer(pShadowFile, pParameters);
|
|
|
|
if( (pShadowFile->cbSecurityDescriptor > 0) && pShadowFile->pSecurityDescriptor )
|
|
pShadowFile->pSecurityDescriptor = (PSECURITY_DESCRIPTOR)((LPBYTE)pShadowFile +
|
|
(DWORD)pShadowFile->pSecurityDescriptor);
|
|
|
|
if (pShadowFile->pDevMode)
|
|
pShadowFile->pDevMode = (LPDEVMODEW)((LPBYTE)pShadowFile +
|
|
(DWORD)pShadowFile->pDevMode);
|
|
|
|
|
|
// check the length of the embedded strings as well as DevMode and Security structs.
|
|
if( !CheckAllPointers( pShadowFile, pFindFileData->nFileSizeLow )) {
|
|
DBGMSG( DBG_WARNING, ("CheckAllPointers() failed; bad shadow file %ws\n", pFindFileData->cFileName ));
|
|
|
|
DELETEJOBREF(pIniJob);
|
|
FreeSplMem(pIniJob);
|
|
|
|
goto Fail;
|
|
}
|
|
|
|
//
|
|
// Discard any jobs which were NT JNL 1.000 since the fonts might not
|
|
// be correct
|
|
|
|
if ( pShadowFile->pDatatype != NULL ) {
|
|
if (!lstrcmpi( pShadowFile->pDatatype, L"NT JNL 1.000" )) {
|
|
|
|
DBGMSG(DBG_WARNING, ("Deleteing job Datatype %ws %ws %ws\n",
|
|
pShadowFile->pDatatype,
|
|
pFindFileData->cFileName, szFileName));
|
|
DELETEJOBREF(pIniJob);
|
|
FreeSplMem(pIniJob);
|
|
goto Fail;
|
|
}
|
|
}
|
|
|
|
pIniJob->pIniDriver = (PINIDRIVER)FindLocalDriver(
|
|
pShadowFile->pDriverName);
|
|
|
|
if ((pIniJob->pIniPrinter = FindPrinter(pShadowFile->pPrinterName)) &&
|
|
pIniJob->pIniDriver &&
|
|
(pIniJob->pIniPrintProc = FindLocalPrintProc(pShadowFile->pPrintProcName))) {
|
|
|
|
|
|
// Notice that MaxJobId is really the number of job slots in the pJobIdMap, so
|
|
// the maximum job id we can allow is (MaxJobId - 1).
|
|
if (pIniJob->JobId >= MaxJobId) {
|
|
// If the job id is too huge (i.e. from a corrupt file) then we might allocate
|
|
// too much unnecessary memory for the JobIdMap!
|
|
// Notice we need to ask for (JobId+1) number of slots in the map!.
|
|
if( !ReallocJobIdMap( pIniJob->JobId + 1 )) {
|
|
|
|
// probably a bad job id, dump the job!
|
|
DBGMSG( DBG_WARNING, ("Failed to alloc JobIdMap in ShadowFile %ws for JobId %d\n", pFindFileData->cFileName, pIniJob->JobId ));
|
|
|
|
DELETEJOBREF(pIniJob);
|
|
FreeSplMem(pIniJob);
|
|
|
|
goto Fail;
|
|
}
|
|
}
|
|
else {
|
|
if( ISBITON( pJobIdMap, pIniJob->JobId )) {
|
|
|
|
// A bad job id from a corrupt shadowfile; dump the job!
|
|
DBGMSG( DBG_WARNING, ("Duplicate Job Id in ShadowFile %ws for JobId %d\n", pFindFileData->cFileName, pIniJob->JobId ));
|
|
|
|
DELETEJOBREF(pIniJob);
|
|
FreeSplMem(pIniJob);
|
|
|
|
goto Fail;
|
|
}
|
|
}
|
|
|
|
SPLASSERT( pJobIdMap != NULL );
|
|
MARKUSE(pJobIdMap, pIniJob->JobId);
|
|
|
|
|
|
INCPRINTERREF( pIniJob->pIniPrinter );
|
|
pIniJob->pIniPrinter->cJobs++;
|
|
pIniJob->pIniPrinter->cTotalJobs++;
|
|
|
|
INCDRIVERREF( pIniJob->pIniDriver );
|
|
|
|
pIniJob->pIniPrintProc->cRef++;
|
|
pIniJob->pIniPort = NULL;
|
|
|
|
|
|
if (pShadowFile->pSecurityDescriptor) {
|
|
|
|
if (pIniJob->pSecurityDescriptor=LocalAlloc(LPTR,
|
|
pShadowFile->cbSecurityDescriptor))
|
|
memcpy(pIniJob->pSecurityDescriptor,
|
|
pShadowFile->pSecurityDescriptor,
|
|
pShadowFile->cbSecurityDescriptor);
|
|
else
|
|
DBGMSG(DBG_WARNING, ("Failed to alloc ini job security descriptor.\n"));
|
|
}
|
|
|
|
if (pShadowFile->pDevMode) {
|
|
|
|
cb=pShadowFile->pDevMode->dmSize +
|
|
pShadowFile->pDevMode->dmDriverExtra;
|
|
if (pIniJob->pDevMode=AllocSplMem(cb))
|
|
memcpy(pIniJob->pDevMode, pShadowFile->pDevMode, cb);
|
|
else
|
|
DBGMSG(DBG_WARNING, ("Failed to alloc ini job devmode.\n"));
|
|
}
|
|
|
|
pIniJob->pNotify = AllocSplStr( pShadowFile->pNotify);
|
|
pIniJob->pUser = AllocSplStr( pShadowFile->pUser);
|
|
pIniJob->pDocument = AllocSplStr( pShadowFile->pDocument);
|
|
pIniJob->pOutputFile = AllocSplStr( pShadowFile->pOutputFile);
|
|
pIniJob->pDatatype = AllocSplStr( pShadowFile->pDatatype);
|
|
pIniJob->pParameters = AllocSplStr( pShadowFile->pParameters);
|
|
pIniJob->pMachineName = AllocSplStr( pIniSpooler->pMachineName);
|
|
|
|
pIniJob->pIniNextJob = NULL;
|
|
pIniJob->pStatus = NULL;
|
|
|
|
if (pIniJob->pIniPrevJob = pIniJob->pIniPrinter->pIniLastJob)
|
|
pIniJob->pIniPrevJob->pIniNextJob=pIniJob;
|
|
|
|
if (!pIniJob->pIniPrinter->pIniFirstJob)
|
|
pIniJob->pIniPrinter->pIniFirstJob = pIniJob;
|
|
|
|
pIniJob->pIniPrinter->pIniLastJob=pIniJob;
|
|
|
|
} else {
|
|
|
|
DBGMSG( DBG_WARNING, ("Failed to find printer %ws\n",pShadowFile->pPrinterName));
|
|
|
|
DELETEJOBREF(pIniJob);
|
|
FreeSplMem(pIniJob);
|
|
|
|
goto Fail;
|
|
}
|
|
|
|
} else {
|
|
|
|
DBGMSG(DBG_WARNING, ("Failed to allocate ini job.\n"));
|
|
}
|
|
|
|
FreeSplMem( pShadowFile );
|
|
|
|
return pIniJob;
|
|
|
|
Fail:
|
|
|
|
if (pShadowFile) {
|
|
FreeSplMem(pShadowFile);
|
|
}
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE && !CloseHandle(hFile)) {
|
|
DBGMSG(DBG_WARNING, ("CloseHandle failed %d %d\n", hFile, GetLastError()));
|
|
}
|
|
if (hFileSpl != INVALID_HANDLE_VALUE && !CloseHandle(hFileSpl)) {
|
|
DBGMSG(DBG_WARNING, ("CloseHandle failed %d %d\n", hFileSpl, GetLastError()));
|
|
}
|
|
|
|
DeleteFile(szFileName);
|
|
|
|
wcscpy(pFileSpec, pFindFileData->cFileName);
|
|
DeleteFile(szFileName);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
#define NEW2OLDDIFF (sizeof(SHADOWFILE_2) - sizeof(SHADOWFILE))
|
|
|
|
VOID
|
|
Old2NewShadow(
|
|
PSHADOWFILE pShadowFile1,
|
|
PSHADOWFILE_2 pShadowFile2,
|
|
DWORD *nBytes
|
|
)
|
|
{
|
|
|
|
MoveMemory((PVOID) pShadowFile2, (PVOID) pShadowFile1, sizeof(SHADOWFILE));
|
|
|
|
// Move strings
|
|
MoveMemory((PVOID) (pShadowFile2 + 1),
|
|
(PVOID) (pShadowFile1 + 1),
|
|
*nBytes - sizeof(SHADOWFILE));
|
|
|
|
pShadowFile2->signature = SF_SIGNATURE_2;
|
|
|
|
pShadowFile2->pNotify += pShadowFile1->pNotify ? NEW2OLDDIFF/sizeof *pShadowFile1->pNotify : 0;
|
|
pShadowFile2->pUser += pShadowFile1->pUser ? NEW2OLDDIFF/sizeof *pShadowFile1->pUser : 0;
|
|
pShadowFile2->pDocument += pShadowFile1->pDocument ? NEW2OLDDIFF/sizeof *pShadowFile2->pDocument : 0;
|
|
pShadowFile2->pOutputFile += pShadowFile1->pOutputFile ? NEW2OLDDIFF/sizeof *pShadowFile2->pOutputFile : 0;
|
|
pShadowFile2->pPrinterName += pShadowFile1->pPrinterName ? NEW2OLDDIFF/sizeof *pShadowFile2->pPrinterName : 0;
|
|
pShadowFile2->pDriverName += pShadowFile1->pDriverName ? NEW2OLDDIFF/sizeof *pShadowFile2->pDriverName : 0;
|
|
pShadowFile2->pPrintProcName += pShadowFile1->pPrintProcName ? NEW2OLDDIFF/sizeof *pShadowFile2->pPrintProcName : 0;
|
|
pShadowFile2->pDatatype += pShadowFile1->pDatatype ? NEW2OLDDIFF/sizeof *pShadowFile2->pDatatype : 0;
|
|
pShadowFile2->pParameters += pShadowFile1->pParameters ? NEW2OLDDIFF/sizeof *pShadowFile2->pParameters : 0;
|
|
|
|
pShadowFile2->pDevMode = (PDEVMODE) (pShadowFile1->pDevMode ?
|
|
(DWORD) pShadowFile1->pDevMode + NEW2OLDDIFF : 0);
|
|
|
|
pShadowFile2->pSecurityDescriptor = (PSECURITY_DESCRIPTOR) (pShadowFile1->pSecurityDescriptor ?
|
|
(DWORD) pShadowFile1->pSecurityDescriptor + NEW2OLDDIFF : 0);
|
|
|
|
pShadowFile2->Version = SF_VERSION_2;
|
|
pShadowFile2->dwReboots = 0;
|
|
|
|
*nBytes += NEW2OLDDIFF;
|
|
}
|
|
|
|
|
|
PINIVERSION
|
|
GetVersionDrivers(
|
|
HKEY hDriversKey,
|
|
LPWSTR szVersionName,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
HKEY hVersionKey;
|
|
WCHAR szDirectoryValue[MAX_PATH];
|
|
PINIDRIVER pIniDriver;
|
|
DWORD cMajorVersion, cMinorVersion;
|
|
DWORD cbData;
|
|
DWORD Type;
|
|
PINIVERSION pIniVersion = NULL;
|
|
|
|
if( RegOpenKeyEx( hDriversKey,
|
|
szVersionName,
|
|
0,
|
|
KEY_READ,
|
|
&hVersionKey ) != ERROR_SUCCESS ){
|
|
return NULL;
|
|
}
|
|
|
|
cbData = sizeof(szDirectoryValue);
|
|
|
|
if( RegQueryValueEx( hVersionKey,
|
|
szDirectory,
|
|
NULL,
|
|
&Type,
|
|
(LPBYTE)szDirectoryValue,
|
|
&cbData ) != ERROR_SUCCESS ){
|
|
|
|
DBGMSG(DBG_TRACE, ("Couldn't query for directory in version structure\n"));
|
|
goto Done;
|
|
}
|
|
|
|
cbData = sizeof(DWORD);
|
|
|
|
if( RegQueryValueEx( hVersionKey,
|
|
szMajorVersion,
|
|
NULL,
|
|
&Type,
|
|
(LPBYTE)&cMajorVersion,
|
|
&cbData ) != ERROR_SUCCESS ){
|
|
|
|
DBGMSG(DBG_TRACE, ("Couldn't query for major version in version structure\n"));
|
|
goto Done;
|
|
}
|
|
|
|
cbData = sizeof(DWORD);
|
|
|
|
if( RegQueryValueEx( hVersionKey,
|
|
szMinorVersion,
|
|
NULL,
|
|
&Type,
|
|
(LPBYTE)&cMinorVersion,
|
|
&cbData ) != ERROR_SUCCESS ){
|
|
|
|
DBGMSG(DBG_TRACE, ("Couldn't query for minor version in version structure\n"));
|
|
goto Done;
|
|
}
|
|
|
|
DBGMSG(DBG_TRACE,("Got all information to build the version entry\n"));
|
|
|
|
pIniDriver = GetDriverList(hVersionKey, pIniSpooler);
|
|
|
|
//
|
|
// Now build the version node structure.
|
|
//
|
|
|
|
pIniVersion = AllocSplMem(sizeof(INIVERSION));
|
|
|
|
if( pIniVersion ){
|
|
|
|
pIniVersion->signature = IV_SIGNATURE;
|
|
pIniVersion->pName = AllocSplStr(szVersionName);
|
|
pIniVersion->szDirectory = AllocSplStr(szDirectoryValue);
|
|
pIniVersion->cMajorVersion = cMajorVersion;
|
|
pIniVersion->cMinorVersion = cMinorVersion;
|
|
pIniVersion->pIniDriver = pIniDriver;
|
|
|
|
if( !pIniVersion->pName ||
|
|
!pIniVersion->szDirectory ){
|
|
|
|
FreeSplStr( pIniVersion->pName );
|
|
FreeSplStr( pIniVersion->szDirectory );
|
|
|
|
FreeSplMem( pIniVersion );
|
|
pIniVersion = NULL;
|
|
}
|
|
}
|
|
|
|
Done:
|
|
RegCloseKey(hVersionKey);
|
|
return pIniVersion;
|
|
}
|
|
|
|
|
|
|
|
|
|
PINIDRIVER
|
|
GetDriverList(
|
|
HKEY hVersionKey,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
PINIDRIVER pIniDriverList = NULL;
|
|
DWORD cDrivers = 0;
|
|
PINIDRIVER pIniDriver;
|
|
WCHAR DriverName[MAX_PATH];
|
|
DWORD cbBuffer =0;
|
|
|
|
|
|
pIniDriverList = NULL;
|
|
|
|
cbBuffer = sizeof( DriverName );
|
|
|
|
while ( RegEnumKeyEx( hVersionKey, cDrivers++, DriverName,
|
|
&cbBuffer, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
|
|
|
|
cbBuffer = sizeof(DriverName);
|
|
|
|
DBGMSG( DBG_TRACE,("Found a driver - %ws\n", DriverName ));
|
|
|
|
pIniDriver = GetDriver( hVersionKey, DriverName, pIniSpooler );
|
|
|
|
if ( pIniDriver != NULL ) {
|
|
|
|
pIniDriver->pNext = pIniDriverList;
|
|
pIniDriverList = pIniDriver;
|
|
}
|
|
}
|
|
|
|
return pIniDriverList;
|
|
}
|
|
|
|
|
|
|
|
|
|
PINIDRIVER
|
|
GetDriver(
|
|
HKEY hVersionKey,
|
|
LPWSTR DriverName,
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
HKEY hDriverKey;
|
|
DWORD Type;
|
|
WCHAR szData[MAX_PATH];
|
|
DWORD cbData;
|
|
DWORD Version;
|
|
LPWSTR pConfigFile, pDataFile, pDriver;
|
|
LPWSTR pHelpFile, pMonitorName, pDefaultDataType, pDependentFiles;
|
|
LPWSTR pDriverName;
|
|
PINIDRIVER pIniDriver = NULL;
|
|
DWORD cb, cLen, cchDependentFiles = 0, dwLastError = ERROR_SUCCESS;
|
|
|
|
pDriverName = pConfigFile = pDataFile = pDriver = NULL;
|
|
pHelpFile = pMonitorName = pDefaultDataType = pDependentFiles = NULL;
|
|
|
|
if ( RegOpenKeyEx( hVersionKey, DriverName, 0,KEY_READ, &hDriverKey) == ERROR_SUCCESS) {
|
|
|
|
if ( !(pDriverName=AllocSplStr(DriverName)) ) {
|
|
dwLastError = GetLastError();
|
|
}
|
|
|
|
RegGetString( hDriverKey, szConfigurationKey, &pConfigFile, &cLen, &dwLastError, TRUE );
|
|
|
|
RegGetString( hDriverKey, szDataFileKey, &pDataFile, &cLen, &dwLastError, TRUE );
|
|
|
|
RegGetString( hDriverKey, szDriverFile, &pDriver, &cLen, &dwLastError, TRUE );
|
|
|
|
RegGetString( hDriverKey, szHelpFile, &pHelpFile, &cLen, &dwLastError, FALSE );
|
|
|
|
RegGetString( hDriverKey, szMonitor, &pMonitorName, &cLen, &dwLastError, FALSE );
|
|
|
|
RegGetString( hDriverKey, szDatatype, &pDefaultDataType, &cLen, &dwLastError, FALSE );
|
|
|
|
RegGetString( hDriverKey, szDependentFiles, &pDependentFiles, &cchDependentFiles, &dwLastError, FALSE );
|
|
|
|
//
|
|
// Retrieve the version number
|
|
//
|
|
|
|
cbData = sizeof(Version);
|
|
|
|
if ( RegQueryValueEx( hDriverKey, szDriverVersion, NULL,
|
|
&Type, (LPBYTE)&Version, &cbData) != ERROR_SUCCESS) {
|
|
|
|
Version = 0;
|
|
}
|
|
|
|
RegCloseKey( hDriverKey );
|
|
}
|
|
|
|
if ( dwLastError == ERROR_SUCCESS ) {
|
|
|
|
cb = sizeof( INIDRIVER );
|
|
|
|
if ( pIniDriver = AllocSplMem( cb )) {
|
|
|
|
pIniDriver->signature = ID_SIGNATURE;
|
|
pIniDriver->pName = pDriverName;
|
|
pIniDriver->pDriverFile = pDriver;
|
|
pIniDriver->pDataFile = pDataFile;
|
|
pIniDriver->pConfigFile = pConfigFile;
|
|
pIniDriver->cVersion = Version;
|
|
pIniDriver->pHelpFile = pHelpFile;
|
|
pIniDriver->pMonitorName = pMonitorName;
|
|
pIniDriver->pDefaultDataType = pDefaultDataType;
|
|
pIniDriver->pDependentFiles = pDependentFiles;
|
|
pIniDriver->cchDependentFiles = cchDependentFiles;
|
|
|
|
DBGMSG( DBG_TRACE, ("Data for driver %ws created:\
|
|
\n\tpDriverFile:\t%ws\
|
|
\n\tpDataFile:\t%ws\
|
|
\n\tpConfigFile:\t%ws\n\n",
|
|
pDriverName, pDriver, pDataFile, pConfigFile));
|
|
|
|
if ( pIniDriver->pMonitorName && *pIniDriver->pMonitorName ) {
|
|
|
|
pIniDriver->pIniLangMonitor = FindMonitor(pIniDriver->pMonitorName);
|
|
|
|
if ( !pIniDriver->pIniLangMonitor ) {
|
|
|
|
DBGMSG(DBG_WARNING,
|
|
("Can't find print monitor %ws\n",
|
|
pIniDriver->pMonitorName));
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
//
|
|
// Failed, cleanup
|
|
//
|
|
|
|
FreeSplStr( pDriverName );
|
|
FreeSplStr( pConfigFile );
|
|
FreeSplStr( pDataFile );
|
|
FreeSplStr( pHelpFile );
|
|
FreeSplStr( pMonitorName );
|
|
FreeSplStr( pDefaultDataType );
|
|
FreeSplStr( pDependentFiles );
|
|
FreeSplStr( pDriver );
|
|
|
|
SetLastError( dwLastError );
|
|
}
|
|
return pIniDriver;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PINIDRIVER
|
|
FindLocalDriver(
|
|
LPWSTR pz
|
|
)
|
|
{
|
|
PINIVERSION pIniVersion;
|
|
|
|
if ( !pz || !*pz ) {
|
|
return NULL;
|
|
}
|
|
|
|
// During Upgrade we load any driver so we have a valid printer, which might not be able to boot.
|
|
|
|
return FindCompatibleDriver( pThisEnvironment, &pIniVersion, pz, cThisMajorVersion, dwUpgradeFlag );
|
|
}
|
|
|
|
#if DBG
|
|
VOID
|
|
InitializeDebug(
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
DWORD Status;
|
|
HKEY hKey;
|
|
DWORD cbData;
|
|
INT TimeOut = 60;
|
|
|
|
Status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, pIniSpooler->pszRegistryRoot, 0, KEY_READ, &hKey );
|
|
|
|
if (Status != ERROR_SUCCESS) {
|
|
|
|
DBGMSG(DBG_ERROR, ("Failed To OpenKey %ws\n",pIniSpooler->pszRegistryRoot));
|
|
return;
|
|
}
|
|
|
|
cbData = sizeof(DWORD);
|
|
|
|
Status = RegQueryValueEx( hKey, szDebugFlags, NULL, NULL, (LPBYTE)&MODULE_DEBUG, &cbData);
|
|
|
|
// Wait until someone turns off the Pause Flag
|
|
|
|
if ( Status != NO_ERROR )
|
|
return;
|
|
|
|
while ( MODULE_DEBUG & DBG_PAUSE ) {
|
|
Sleep(1*1000);
|
|
if ( TimeOut-- == 0)
|
|
break;
|
|
}
|
|
|
|
DBGMSG(DBG_TRACE, ("DebugFlags %x\n", MODULE_DEBUG));
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
VOID
|
|
GetPrintSystemVersion(
|
|
PINISPOOLER pIniSpooler
|
|
)
|
|
{
|
|
DWORD Status;
|
|
HKEY hKey;
|
|
DWORD cbData;
|
|
WCHAR DriverNames[MAX_PATH];
|
|
DWORD dwLastError;
|
|
|
|
Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, pIniSpooler->pszRegistryRoot, 0,
|
|
KEY_READ, &hKey);
|
|
if (Status != ERROR_SUCCESS) {
|
|
DBGMSG(DBG_ERROR, ("Cannot determine Print System Version Number\n"));
|
|
}
|
|
|
|
|
|
cbData = sizeof(DWORD);
|
|
RegQueryValueEx(hKey, szMinorVersion, NULL, NULL,
|
|
(LPBYTE)&cThisMinorVersion, &cbData);
|
|
DBGMSG(DBG_TRACE, ("This Minor Version - %d\n", cThisMinorVersion));
|
|
|
|
|
|
|
|
cbData = sizeof(DWORD);
|
|
RegQueryValueEx(hKey, L"FastPrintWaitTimeout", NULL, NULL,
|
|
(LPBYTE)&dwFastPrintWaitTimeout, &cbData);
|
|
DBGMSG(DBG_TRACE, ("dwFastPrintWaitTimeout - %d\n", dwFastPrintWaitTimeout));
|
|
|
|
|
|
|
|
cbData = sizeof(DWORD);
|
|
RegQueryValueEx(hKey, L"FastPrintThrottleTimeout", NULL, NULL,
|
|
(LPBYTE)&dwFastPrintThrottleTimeout, &cbData);
|
|
DBGMSG(DBG_TRACE, ("dwFastPrintThrottleTimeout - %d\n", dwFastPrintThrottleTimeout));
|
|
|
|
|
|
|
|
// If the values look invalid use Defaults
|
|
|
|
if (( dwFastPrintThrottleTimeout == 0) ||
|
|
( dwFastPrintWaitTimeout < dwFastPrintThrottleTimeout)) {
|
|
|
|
DBGMSG( DBG_WARNING, ("Bad timeout values FastPrintThrottleTimeout %d FastPrintWaitTimeout %d using defaults\n",
|
|
dwFastPrintThrottleTimeout, dwFastPrintWaitTimeout));
|
|
|
|
dwFastPrintThrottleTimeout = FASTPRINT_THROTTLE_TIMEOUT;
|
|
dwFastPrintWaitTimeout = FASTPRINT_WAIT_TIMEOUT;
|
|
|
|
}
|
|
|
|
// Calculate a reasonable Threshold based on the two timeouts
|
|
|
|
dwFastPrintSlowDownThreshold = dwFastPrintWaitTimeout / dwFastPrintThrottleTimeout;
|
|
|
|
|
|
// FastPrintSlowDownThreshold
|
|
cbData = sizeof(DWORD);
|
|
RegQueryValueEx(hKey, L"FastPrintSlowDownThreshold", NULL, NULL,
|
|
(LPBYTE)&dwFastPrintSlowDownThreshold, &cbData);
|
|
DBGMSG(DBG_TRACE, ("dwFastPrintSlowDownThreshold - %d\n", dwFastPrintSlowDownThreshold));
|
|
|
|
|
|
// PortThreadPriority
|
|
cbData = sizeof dwPortThreadPriority;
|
|
Status = RegQueryValueEx(hKey, SPLREG_PORT_THREAD_PRIORITY, NULL, NULL,
|
|
(LPBYTE)&dwPortThreadPriority, &cbData);
|
|
|
|
if (Status != ERROR_SUCCESS ||
|
|
(dwPortThreadPriority != THREAD_PRIORITY_LOWEST &&
|
|
dwPortThreadPriority != THREAD_PRIORITY_BELOW_NORMAL &&
|
|
dwPortThreadPriority != THREAD_PRIORITY_NORMAL &&
|
|
dwPortThreadPriority != THREAD_PRIORITY_ABOVE_NORMAL &&
|
|
dwPortThreadPriority != THREAD_PRIORITY_HIGHEST)) {
|
|
|
|
dwPortThreadPriority = DEFAULT_PORT_THREAD_PRIORITY;
|
|
|
|
SetPrinterDataServer( pIniSpooler,
|
|
SPLREG_PORT_THREAD_PRIORITY,
|
|
REG_DWORD,
|
|
(LPBYTE) &dwPortThreadPriority,
|
|
sizeof dwPortThreadPriority
|
|
);
|
|
}
|
|
DBGMSG(DBG_TRACE, ("dwPortThreadPriority - %d\n", dwPortThreadPriority));
|
|
|
|
|
|
// SchedulerThreadPriority
|
|
cbData = sizeof dwSchedulerThreadPriority;
|
|
Status = RegQueryValueEx(hKey, SPLREG_SCHEDULER_THREAD_PRIORITY, NULL, NULL,
|
|
(LPBYTE)&dwSchedulerThreadPriority, &cbData);
|
|
|
|
if (Status != ERROR_SUCCESS ||
|
|
(dwSchedulerThreadPriority != THREAD_PRIORITY_LOWEST &&
|
|
dwSchedulerThreadPriority != THREAD_PRIORITY_BELOW_NORMAL &&
|
|
dwSchedulerThreadPriority != THREAD_PRIORITY_NORMAL &&
|
|
dwSchedulerThreadPriority != THREAD_PRIORITY_ABOVE_NORMAL &&
|
|
dwSchedulerThreadPriority != THREAD_PRIORITY_HIGHEST)) {
|
|
|
|
dwSchedulerThreadPriority = DEFAULT_SCHEDULER_THREAD_PRIORITY;
|
|
|
|
SetPrinterDataServer( pIniSpooler,
|
|
SPLREG_SCHEDULER_THREAD_PRIORITY,
|
|
REG_DWORD,
|
|
(LPBYTE) &dwSchedulerThreadPriority,
|
|
sizeof dwSchedulerThreadPriority
|
|
);
|
|
}
|
|
DBGMSG(DBG_TRACE, ("dwSchedulerThreadPriority - %d\n", dwSchedulerThreadPriority));
|
|
|
|
|
|
// WritePrinterSleepTime
|
|
cbData = sizeof(DWORD);
|
|
RegQueryValueEx(hKey, L"WritePrinterSleepTime", NULL, NULL,
|
|
(LPBYTE)&dwWritePrinterSleepTime, &cbData);
|
|
DBGMSG(DBG_TRACE, ("dwWritePrinterSleepTime - %d\n", dwWritePrinterSleepTime));
|
|
|
|
// ServerThreadPriority
|
|
cbData = sizeof(DWORD);
|
|
RegQueryValueEx(hKey, L"ServerThreadPriority", NULL, NULL,
|
|
(LPBYTE)&dwServerThreadPriority, &cbData);
|
|
DBGMSG(DBG_TRACE, ("dwServerThreadPriority - %d\n", dwServerThreadPriority));
|
|
|
|
// ServerThreadTimeout
|
|
cbData = sizeof(DWORD);
|
|
RegQueryValueEx(hKey, L"ServerThreadTimeout", NULL, NULL,
|
|
(LPBYTE)&ServerThreadTimeout, &cbData);
|
|
DBGMSG(DBG_TRACE, ("ServerThreadTimeout - %d\n", ServerThreadTimeout));
|
|
|
|
|
|
// DisableServerThread
|
|
cbData = sizeof(DWORD);
|
|
RegQueryValueEx(hKey, L"DisableServerThread", NULL, NULL,
|
|
(LPBYTE)&ServerThreadRunning, &cbData);
|
|
DBGMSG(DBG_TRACE, ("ServerThreadRunning - %d\n", ServerThreadRunning));
|
|
|
|
|
|
// NetPrinterDecayPeriod
|
|
cbData = sizeof(DWORD);
|
|
RegQueryValueEx(hKey, L"NetPrinterDecayPeriod", NULL, NULL,
|
|
(LPBYTE)&NetPrinterDecayPeriod, &cbData);
|
|
DBGMSG(DBG_TRACE, ("NetPrinterDecayPeriod - %d\n", NetPrinterDecayPeriod));
|
|
|
|
|
|
// RefreshTimesPerDecayPeriod
|
|
cbData = sizeof(DWORD);
|
|
RegQueryValueEx(hKey, L"RefreshTimesPerDecayPeriod", NULL, NULL,
|
|
(LPBYTE)&RefreshTimesPerDecayPeriod, &cbData);
|
|
DBGMSG(DBG_TRACE, ("RefreshTimesPerDecayPeriod - %d\n", RefreshTimesPerDecayPeriod));
|
|
|
|
if ( RefreshTimesPerDecayPeriod == 0 ) {
|
|
|
|
RefreshTimesPerDecayPeriod = DEFAULT_REFRESH_TIMES_PER_DECAY_PERIOD;
|
|
}
|
|
|
|
// BrowsePrintWorkstations
|
|
cbData = sizeof( BrowsePrintWorkstations );
|
|
RegQueryValueEx( hKey, L"BrowsePrintWorkstations", NULL, NULL, (LPBYTE)&BrowsePrintWorkstations, &cbData );
|
|
|
|
DBGMSG( DBG_TRACE, ("BrowsePrintWorkstations - %d\n", BrowsePrintWorkstations ));
|
|
|
|
|
|
// BeepEnabled
|
|
cbData = sizeof dwBeepEnabled;
|
|
RegQueryValueEx(hKey, SPLREG_BEEP_ENABLED, NULL, NULL,
|
|
(LPBYTE)&dwBeepEnabled, &cbData);
|
|
DBGMSG(DBG_TRACE, ("BeepEnabled - %d\n", dwBeepEnabled));
|
|
|
|
dwBeepEnabled = !!dwBeepEnabled;
|
|
|
|
SetPrinterDataServer( pIniSpooler,
|
|
SPLREG_BEEP_ENABLED,
|
|
REG_DWORD,
|
|
(LPBYTE) &dwBeepEnabled,
|
|
sizeof dwBeepEnabled
|
|
);
|
|
|
|
//
|
|
// Some Folks like the NT FAX Service Don't want people to be able
|
|
// to remotely print with specific printer drivers.
|
|
//
|
|
|
|
if (!RegGetString( hKey,
|
|
SPLREG_NO_REMOTE_PRINTER_DRIVERS,
|
|
&pIniSpooler->pNoRemotePrintDrivers,
|
|
&pIniSpooler->cchNoRemotePrintDrivers,
|
|
&dwLastError,
|
|
FALSE )) {
|
|
|
|
//
|
|
// If nothing is specified then write it back to the registry
|
|
//
|
|
|
|
DBGMSG( DBG_WARNING, ("Adding SPLREG_NO_REMOTE_PRINTER_DRIVERS value\n"));
|
|
|
|
pIniSpooler->pNoRemotePrintDrivers = szNTFaxDriver;
|
|
pIniSpooler->cchNoRemotePrintDrivers = wcslen( szNTFaxDriver );
|
|
|
|
SetPrinterDataServer( pIniSpooler,
|
|
SPLREG_NO_REMOTE_PRINTER_DRIVERS,
|
|
REG_SZ,
|
|
(LPBYTE) pIniSpooler->pNoRemotePrintDrivers,
|
|
sizeof(WCHAR) * pIniSpooler->cchNoRemotePrintDrivers );
|
|
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
FinalInitAfterRouterInitCompleteThread(
|
|
DWORD dwUpgrade
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This thread does LocalSpl initialization that has to happen after
|
|
the router has completely initialized.
|
|
|
|
There are 2 jobs:-
|
|
Upgrading Printer Driver Data
|
|
Sharing Printers
|
|
|
|
Ensures that printers are shared. This case occurs when the spooler
|
|
service not running on startup (and the server is), and then the
|
|
user starts the spooler.
|
|
|
|
We also get the benefit of closing down any invalid printer handles
|
|
(in the server).
|
|
|
|
Arguments:
|
|
|
|
dwUpgrade != 0 upgrade printer driver data.
|
|
|
|
Return Value:
|
|
|
|
DWORD - ignored
|
|
|
|
--*/
|
|
|
|
{
|
|
PINIPRINTER pIniPrinter;
|
|
PINIPRINTER pIniPrinterNext;
|
|
|
|
// Do Not share all the printers during an Upgrade.
|
|
|
|
if ( dwUpgrade ) {
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
WaitForSpoolerInitialization();
|
|
|
|
|
|
EnterSplSem();
|
|
|
|
|
|
//
|
|
// Re-share all shared printers.
|
|
//
|
|
|
|
for( pIniPrinter = pLocalIniSpooler->pIniPrinter;
|
|
pIniPrinter;
|
|
pIniPrinter = pIniPrinterNext ) {
|
|
|
|
if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED ) {
|
|
|
|
//
|
|
// Up the ref count to prevent deletion
|
|
//
|
|
INCPRINTERREF( pIniPrinter );
|
|
|
|
//
|
|
// Unshare it first to close all handles in the
|
|
// server.
|
|
//
|
|
ShareThisPrinter( pIniPrinter,
|
|
pIniPrinter->pShareName,
|
|
FALSE );
|
|
|
|
//
|
|
// ShareThisPrinter leave SplSem, so check again to
|
|
// decrease window.
|
|
//
|
|
if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED ) {
|
|
|
|
//
|
|
// Now share it again.
|
|
//
|
|
ShareThisPrinter( pIniPrinter,
|
|
pIniPrinter->pShareName,
|
|
TRUE );
|
|
}
|
|
|
|
DECPRINTERREF( pIniPrinter );
|
|
pIniPrinterNext = pIniPrinter->pNext;
|
|
|
|
if ( pIniPrinter->Status & PRINTER_PENDING_DELETION &&
|
|
pIniPrinter->cRef == 0 &&
|
|
pIniPrinter->cJobs == 0 ) {
|
|
|
|
DeletePrinterForReal(pIniPrinter);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// The unshared case.
|
|
//
|
|
pIniPrinterNext = pIniPrinter->pNext;
|
|
}
|
|
}
|
|
LeaveSplSem();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// DEBUG PURPOSE ONLY - - returns TRUE if pMem is an IniSpooler, FALSE otherwise
|
|
BOOL
|
|
NotIniSpooler(
|
|
BYTE *pMem
|
|
)
|
|
{
|
|
PINISPOOLER pIniSpooler;
|
|
|
|
for (pIniSpooler = pLocalIniSpooler ; pIniSpooler ; pIniSpooler = pIniSpooler->pIniNextSpooler)
|
|
if (pIniSpooler == (PINISPOOLER) pMem)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
|
|
}
|