mirror of
https://github.com/reactos/reactos.git
synced 2024-11-01 20:32:36 +00:00
3ca217621d
Fix WinSpool API regressions. Fix typos and debug prints.
261 lines
12 KiB
C
261 lines
12 KiB
C
/*
|
|
* PROJECT: ReactOS Local Spooler
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: Main functions
|
|
* COPYRIGHT: Copyright 2015-2017 Colin Finck (colin@reactos.org)
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
// Global Variables
|
|
HKEY hPrintKey = NULL;
|
|
HKEY hPrintersKey = NULL;
|
|
WCHAR wszJobDirectory[MAX_PATH];
|
|
DWORD cchJobDirectory;
|
|
WCHAR wszSpoolDirectory[MAX_PATH];
|
|
DWORD cchSpoolDirectory;
|
|
|
|
// Global Constants
|
|
#include <prtprocenv.h>
|
|
|
|
/** This is what the Spooler of Windows Server 2003 returns (for example using GetPrinterDataExW, SPLREG_MAJOR_VERSION/SPLREG_MINOR_VERSION) */
|
|
const DWORD dwSpoolerMajorVersion = 3;
|
|
const DWORD dwSpoolerMinorVersion = 0;
|
|
|
|
const WCHAR wszDefaultDocumentName[] = L"Local Downlevel Document";
|
|
|
|
PCWSTR wszPrintProviderInfo[3] = {
|
|
L"Windows NT Local Print Providor", // Name
|
|
L"Locally connected Printers", // Comment
|
|
L"Windows NT Local Printers" // Description
|
|
};
|
|
|
|
// Local Constants
|
|
static const PRINTPROVIDOR _PrintProviderFunctions = {
|
|
LocalOpenPrinter, // fpOpenPrinter
|
|
LocalSetJob, // fpSetJob
|
|
LocalGetJob, // fpGetJob
|
|
LocalEnumJobs, // fpEnumJobs
|
|
NULL, // fpAddPrinter
|
|
NULL, // fpDeletePrinter
|
|
NULL, // fpSetPrinter
|
|
LocalGetPrinter, // fpGetPrinter
|
|
LocalEnumPrinters, // fpEnumPrinters
|
|
LocalAddPrinterDriver, // fpAddPrinterDriver
|
|
LocalEnumPrinterDrivers, // fpEnumPrinterDrivers
|
|
LocalGetPrinterDriver, // fpGetPrinterDriver
|
|
LocalGetPrinterDriverDirectory, // fpGetPrinterDriverDirectory
|
|
NULL, // fpDeletePrinterDriver
|
|
NULL, // fpAddPrintProcessor
|
|
LocalEnumPrintProcessors, // fpEnumPrintProcessors
|
|
LocalGetPrintProcessorDirectory, // fpGetPrintProcessorDirectory
|
|
NULL, // fpDeletePrintProcessor
|
|
LocalEnumPrintProcessorDatatypes, // fpEnumPrintProcessorDatatypes
|
|
LocalStartDocPrinter, // fpStartDocPrinter
|
|
LocalStartPagePrinter, // fpStartPagePrinter
|
|
LocalWritePrinter, // fpWritePrinter
|
|
LocalEndPagePrinter, // fpEndPagePrinter
|
|
NULL, // fpAbortPrinter
|
|
LocalReadPrinter, // fpReadPrinter
|
|
LocalEndDocPrinter, // fpEndDocPrinter
|
|
LocalAddJob, // fpAddJob
|
|
LocalScheduleJob, // fpScheduleJob
|
|
LocalGetPrinterData, // fpGetPrinterData
|
|
LocalSetPrinterData, // fpSetPrinterData
|
|
NULL, // fpWaitForPrinterChange
|
|
LocalClosePrinter, // fpClosePrinter
|
|
LocalAddForm, // fpAddForm
|
|
LocalDeleteForm, // fpDeleteForm
|
|
LocalGetForm, // fpGetForm
|
|
LocalSetForm, // fpSetForm
|
|
LocalEnumForms, // fpEnumForms
|
|
LocalEnumMonitors, // fpEnumMonitors
|
|
LocalEnumPorts, // fpEnumPorts
|
|
LocalAddPort, // fpAddPort
|
|
LocalConfigurePort, // fpConfigurePort
|
|
LocalDeletePort, // fpDeletePort
|
|
NULL, // fpCreatePrinterIC
|
|
NULL, // fpPlayGdiScriptOnPrinterIC
|
|
NULL, // fpDeletePrinterIC
|
|
NULL, // fpAddPrinterConnection
|
|
NULL, // fpDeletePrinterConnection
|
|
LocalPrinterMessageBox, // fpPrinterMessageBox
|
|
LocalAddMonitor, // fpAddMonitor
|
|
LocalDeleteMonitor, // fpDeleteMonitor
|
|
NULL, // fpResetPrinter
|
|
LocalGetPrinterDriverEx, // fpGetPrinterDriverEx
|
|
NULL, // fpFindFirstPrinterChangeNotification
|
|
NULL, // fpFindClosePrinterChangeNotification
|
|
LocalAddPortEx, // fpAddPortEx
|
|
NULL, // fpShutDown
|
|
NULL, // fpRefreshPrinterChangeNotification
|
|
NULL, // fpOpenPrinterEx
|
|
NULL, // fpAddPrinterEx
|
|
LocalSetPort, // fpSetPort
|
|
NULL, // fpEnumPrinterData
|
|
NULL, // fpDeletePrinterData
|
|
NULL, // fpClusterSplOpen
|
|
NULL, // fpClusterSplClose
|
|
NULL, // fpClusterSplIsAlive
|
|
LocalSetPrinterDataEx, // fpSetPrinterDataEx
|
|
LocalGetPrinterDataEx, // fpGetPrinterDataEx
|
|
NULL, // fpEnumPrinterDataEx
|
|
NULL, // fpEnumPrinterKey
|
|
NULL, // fpDeletePrinterDataEx
|
|
NULL, // fpDeletePrinterKey
|
|
NULL, // fpSeekPrinter
|
|
NULL, // fpDeletePrinterDriverEx
|
|
NULL, // fpAddPerMachineConnection
|
|
NULL, // fpDeletePerMachineConnection
|
|
NULL, // fpEnumPerMachineConnections
|
|
LocalXcvData, // fpXcvData
|
|
LocalAddPrinterDriverEx, // fpAddPrinterDriverEx
|
|
NULL, // fpSplReadPrinter
|
|
NULL, // fpDriverUnloadComplete
|
|
LocalGetSpoolFileInfo, // fpGetSpoolFileInfo
|
|
LocalCommitSpoolData, // fpCommitSpoolData
|
|
LocalCloseSpoolFileHandle, // fpCloseSpoolFileHandle
|
|
NULL, // fpFlushPrinter
|
|
NULL, // fpSendRecvBidiData
|
|
NULL, // fpAddDriverCatalog
|
|
};
|
|
|
|
static BOOL
|
|
_InitializeLocalSpooler(void)
|
|
{
|
|
const WCHAR wszPrintersPath[] = L"\\PRINTERS";
|
|
const DWORD cchPrintersPath = _countof(wszPrintersPath) - 1;
|
|
const WCHAR wszSpoolPath[] = L"\\spool";
|
|
const DWORD cchSpoolPath = _countof(wszSpoolPath) - 1;
|
|
const WCHAR wszSymbolicLinkValue[] = L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers";
|
|
const DWORD cbSymbolicLinkValue = sizeof(wszSymbolicLinkValue) - sizeof(WCHAR);
|
|
|
|
BOOL bReturnValue = FALSE;
|
|
DWORD cbData;
|
|
DWORD dwErrorCode;
|
|
HKEY hKey = NULL;
|
|
|
|
// On startup, always create a volatile symbolic link in the registry if it doesn't exist yet.
|
|
// "SYSTEM\CurrentControlSet\Control\Print\Printers" -> "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers"
|
|
//
|
|
// According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51
|
|
// this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive.
|
|
dwErrorCode = (DWORD)RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Print\\Printers", 0, NULL, REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK, KEY_CREATE_LINK | KEY_SET_VALUE, NULL, &hKey, NULL);
|
|
if (dwErrorCode == ERROR_SUCCESS)
|
|
{
|
|
// Note that wszSymbolicLink has to be stored WITHOUT the terminating null character for the symbolic link to work!
|
|
// See cbSymbolicLinkValue above.
|
|
dwErrorCode = (DWORD)RegSetValueExW(hKey, L"SymbolicLinkValue", 0, REG_LINK, (PBYTE)wszSymbolicLinkValue, cbSymbolicLinkValue);
|
|
if (dwErrorCode != ERROR_SUCCESS)
|
|
{
|
|
ERR("RegSetValueExW failed for the Printers symlink with error %lu!\n", dwErrorCode);
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else if (dwErrorCode != ERROR_ALREADY_EXISTS)
|
|
{
|
|
ERR("RegCreateKeyExW failed for the Printers symlink with error %lu!\n", dwErrorCode);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Open some registry keys and leave them open. We need them multiple times throughout the Local Spooler.
|
|
dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Print", 0, KEY_ALL_ACCESS, &hPrintKey);
|
|
if (dwErrorCode != ERROR_SUCCESS)
|
|
{
|
|
ERR("RegOpenKeyExW failed for \"Print\" with error %lu!\n", dwErrorCode);
|
|
goto Cleanup;
|
|
}
|
|
|
|
dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers", 0, KEY_ALL_ACCESS, &hPrintersKey);
|
|
if (dwErrorCode != ERROR_SUCCESS)
|
|
{
|
|
ERR("RegOpenKeyExW failed for \"Printers\" with error %lu!\n", dwErrorCode);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Construct the path to "%SystemRoot%\system32\spool".
|
|
// Forget about length checks here. If this doesn't fit into MAX_PATH, our OS has more serious problems...
|
|
cchSpoolDirectory = GetSystemDirectoryW(wszSpoolDirectory, MAX_PATH);
|
|
CopyMemory(&wszSpoolDirectory[cchSpoolDirectory], wszSpoolPath, (cchSpoolPath + 1) * sizeof(WCHAR));
|
|
cchSpoolDirectory += cchSpoolPath;
|
|
|
|
// Query the job directory.
|
|
cbData = sizeof(wszJobDirectory);
|
|
dwErrorCode = (DWORD)RegQueryValueExW(hPrintersKey, SPLREG_DEFAULT_SPOOL_DIRECTORY, NULL, NULL, (PBYTE)wszJobDirectory, &cbData);
|
|
if (dwErrorCode == ERROR_SUCCESS)
|
|
{
|
|
cchJobDirectory = cbData / sizeof(WCHAR) - 1;
|
|
}
|
|
else if (dwErrorCode == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
// Use the default "%SystemRoot%\system32\spool\PRINTERS".
|
|
CopyMemory(wszJobDirectory, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR));
|
|
CopyMemory(&wszJobDirectory[cchSpoolDirectory], wszPrintersPath, (cchPrintersPath + 1) * sizeof(WCHAR));
|
|
cchJobDirectory = cchSpoolDirectory + cchPrintersPath;
|
|
|
|
// Save this for next time.
|
|
RegSetValueExW(hPrintersKey, SPLREG_DEFAULT_SPOOL_DIRECTORY, 0, REG_SZ, (PBYTE)wszJobDirectory, (cchJobDirectory + 1) * sizeof(WCHAR));
|
|
}
|
|
else
|
|
{
|
|
ERR("RegQueryValueExW failed for \"%S\" with error %lu!\n", SPLREG_DEFAULT_SPOOL_DIRECTORY, dwErrorCode);
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Initialize all lists.
|
|
if (!InitializePrintMonitorList())
|
|
goto Cleanup;
|
|
|
|
if (!InitializePortList())
|
|
goto Cleanup;
|
|
|
|
if (!InitializePrintProcessorList())
|
|
goto Cleanup;
|
|
|
|
if (!InitializePrinterList())
|
|
goto Cleanup;
|
|
|
|
if (!InitializeGlobalJobList())
|
|
goto Cleanup;
|
|
|
|
if (!InitializeFormList())
|
|
goto Cleanup;
|
|
|
|
if (!InitializePrinterDrivers())
|
|
goto Cleanup;
|
|
|
|
// Local Spooler Initialization finished successfully!
|
|
bReturnValue = TRUE;
|
|
|
|
Cleanup:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
return bReturnValue;
|
|
}
|
|
|
|
BOOL WINAPI
|
|
DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
|
{
|
|
switch (fdwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
DisableThreadLibraryCalls(hinstDLL);
|
|
return _InitializeLocalSpooler();
|
|
|
|
default:
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
BOOL WINAPI
|
|
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor, DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
|
|
{
|
|
TRACE("InitializePrintProvidor(%p, %lu, %S)\n", pPrintProvidor, cbPrintProvidor, pFullRegistryPath);
|
|
|
|
CopyMemory(pPrintProvidor, &_PrintProviderFunctions, min(cbPrintProvidor, sizeof(PRINTPROVIDOR)));
|
|
|
|
SetLastError(ERROR_SUCCESS);
|
|
return TRUE;
|
|
}
|