[LOCALSPL, WINSPOOL]
Partially implement the whole StartDocPrinter, StartPagePrinter, ReadPrinter, WritePrinter, EndPagePrinter, EndDocPrinter, ClosePrinter group of functions.
They behave very differently based on whether spooled printing is enabled, whether it's a local or remote call, etc. Most information was gained by observing callchains under Windows.
So far, only the spooled path is implemented, the others need more investigation first.
Many other TODOs remain as well, see the comments.
Also make some more comments Doxygen-aware :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS Local Spooler
|
2017-09-29 17:18:19 +00:00
|
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
[LOCALSPL, WINSPOOL]
Partially implement the whole StartDocPrinter, StartPagePrinter, ReadPrinter, WritePrinter, EndPagePrinter, EndDocPrinter, ClosePrinter group of functions.
They behave very differently based on whether spooled printing is enabled, whether it's a local or remote call, etc. Most information was gained by observing callchains under Windows.
So far, only the spooled path is implemented, the others need more investigation first.
Many other TODOs remain as well, see the comments.
Also make some more comments Doxygen-aware :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
* PURPOSE: Implementation of the Thread that actually performs the printing process
|
2017-09-29 17:18:19 +00:00
|
|
|
* COPYRIGHT: Copyright 2015-2017 Colin Finck (colin@reactos.org)
|
[LOCALSPL, WINSPOOL]
Partially implement the whole StartDocPrinter, StartPagePrinter, ReadPrinter, WritePrinter, EndPagePrinter, EndDocPrinter, ClosePrinter group of functions.
They behave very differently based on whether spooled printing is enabled, whether it's a local or remote call, etc. Most information was gained by observing callchains under Windows.
So far, only the spooled path is implemented, the others need more investigation first.
Many other TODOs remain as well, see the comments.
Also make some more comments Doxygen-aware :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
|
|
DWORD WINAPI
|
|
|
|
PrintingThreadProc(PLOCAL_JOB pJob)
|
|
|
|
{
|
|
|
|
const DWORD cchMaxJobIdDigits = 5; // Job ID is limited to 5 decimal digits, see IS_VALID_JOB_ID
|
|
|
|
const WCHAR wszJobAppendix[] = L", Job ";
|
|
|
|
const DWORD cchJobAppendix = _countof(wszJobAppendix) - 1;
|
|
|
|
const WCHAR wszPortAppendix[] = L", Port";
|
|
|
|
|
|
|
|
DWORD cchPortName;
|
|
|
|
DWORD cchPrinterName;
|
|
|
|
DWORD dwErrorCode;
|
|
|
|
HANDLE hPrintProcessor = NULL;
|
|
|
|
PLOCAL_PRINT_PROCESSOR pPrintProcessor = pJob->pPrintProcessor;
|
|
|
|
PRINTPROCESSOROPENDATA OpenData;
|
|
|
|
PWSTR pwszPrinterAndJob = NULL;
|
|
|
|
PWSTR pwszPrinterPort = NULL;
|
|
|
|
PWSTR pwszSPLFile = NULL;
|
|
|
|
|
2017-07-05 15:29:13 +00:00
|
|
|
TRACE("PrintingThreadProc(%p)\n", pJob);
|
|
|
|
|
[LOCALSPL, WINSPOOL]
Partially implement the whole StartDocPrinter, StartPagePrinter, ReadPrinter, WritePrinter, EndPagePrinter, EndDocPrinter, ClosePrinter group of functions.
They behave very differently based on whether spooled printing is enabled, whether it's a local or remote call, etc. Most information was gained by observing callchains under Windows.
So far, only the spooled path is implemented, the others need more investigation first.
Many other TODOs remain as well, see the comments.
Also make some more comments Doxygen-aware :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
// Prepare the pPrinterName parameter.
|
|
|
|
// This is the string for LocalOpenPrinter to open a port (e.g. "LPT1:, Port").
|
|
|
|
cchPortName = wcslen(pJob->pPrinter->pPort->pwszName);
|
|
|
|
pwszPrinterPort = DllAllocSplMem(cchPortName * sizeof(WCHAR) + sizeof(wszPortAppendix));
|
|
|
|
if (!pwszPrinterPort)
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
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. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
ERR("DllAllocSplMem failed!\n");
|
[LOCALSPL, WINSPOOL]
Partially implement the whole StartDocPrinter, StartPagePrinter, ReadPrinter, WritePrinter, EndPagePrinter, EndDocPrinter, ClosePrinter group of functions.
They behave very differently based on whether spooled printing is enabled, whether it's a local or remote call, etc. Most information was gained by observing callchains under Windows.
So far, only the spooled path is implemented, the others need more investigation first.
Many other TODOs remain as well, see the comments.
Also make some more comments Doxygen-aware :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
CopyMemory(pwszPrinterPort, pJob->pPrinter->pPort->pwszName, cchPortName * sizeof(WCHAR));
|
|
|
|
CopyMemory(&pwszPrinterPort[cchPortName], wszPortAppendix, sizeof(wszPortAppendix));
|
|
|
|
|
|
|
|
// Prepare the pPrintProcessorOpenData parameter.
|
|
|
|
OpenData.JobId = pJob->dwJobID;
|
|
|
|
OpenData.pDatatype = pJob->pwszDatatype;
|
|
|
|
OpenData.pDevMode = pJob->pDevMode;
|
|
|
|
OpenData.pDocumentName = pJob->pwszDocumentName;
|
|
|
|
OpenData.pOutputFile = NULL;
|
|
|
|
OpenData.pParameters = pJob->pwszPrintProcessorParameters;
|
|
|
|
OpenData.pPrinterName = pJob->pPrinter->pwszPrinterName;
|
|
|
|
|
[LOCALSPL]
This is where things get dirty. StartDocPort of the Print Monitor needs the Printer Name and Job ID of the job to print on this port.
But StartDocPort is called by LocalStartDocPrinter, whose parameters are fixed and don't include this information.
Therefore, I have no way to pass these parameters to a port handle directly. Instead, I need to store a pointer to the job in the port structure itself and let the next port handle pick up this information in LocalStartDocPrinter.
Surprisingly, Windows doesn't seem to do any better here. For testing, I stalled execution inside my own Print Processor and called StartDocPrinter from another thread.
It then picked up and "stole" the stored job information. When the Print Processor resumed execution, the job information wasn't present anymore and its StartDocPrinter call crashed. So even Windows definitely stores this information only for a single StartDocPrinter call.
Having solved this, I could finally implement OpenPrinter, StartDocPrinter, ReadPrinter, WritePrinter and ClosePrinter for Port handles as well as OpenPrinter and ClosePrinter for Xcv handles.
svn path=/branches/colins-printing-for-freedom/; revision=68550
2015-07-22 12:44:22 +00:00
|
|
|
// Associate our job to the port. The next port handle created through LocalOpenPrinter will pick this up.
|
|
|
|
// LocalStartDocPrinter needs this information to call StartDocPort of the Print Monitor, but as the parameters
|
|
|
|
// for LocalOpenPrinter and LocalStartDocPrinter are fixed, we can only pass over the information this way.
|
|
|
|
pJob->pPrinter->pPort->pNextJobToProcess = pJob;
|
|
|
|
|
[LOCALSPL, WINSPOOL]
Partially implement the whole StartDocPrinter, StartPagePrinter, ReadPrinter, WritePrinter, EndPagePrinter, EndDocPrinter, ClosePrinter group of functions.
They behave very differently based on whether spooled printing is enabled, whether it's a local or remote call, etc. Most information was gained by observing callchains under Windows.
So far, only the spooled path is implemented, the others need more investigation first.
Many other TODOs remain as well, see the comments.
Also make some more comments Doxygen-aware :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
// Open a handle to the Print Processor.
|
|
|
|
hPrintProcessor = pPrintProcessor->pfnOpenPrintProcessor(pwszPrinterPort, &OpenData);
|
|
|
|
if (!hPrintProcessor)
|
|
|
|
{
|
|
|
|
dwErrorCode = GetLastError();
|
|
|
|
ERR("OpenPrintProcessor failed with error %lu!\n", dwErrorCode);
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Let other functions use the Print Processor as well while it's opened.
|
|
|
|
pJob->hPrintProcessor = hPrintProcessor;
|
|
|
|
|
|
|
|
// Prepare the pDocumentName parameter.
|
|
|
|
cchPrinterName = wcslen(OpenData.pPrinterName);
|
|
|
|
pwszPrinterAndJob = DllAllocSplMem((cchPrinterName + cchJobAppendix + cchMaxJobIdDigits + 1) * sizeof(WCHAR));
|
|
|
|
if (!pwszPrinterAndJob)
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
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. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
ERR("DllAllocSplMem failed!\n");
|
[LOCALSPL, WINSPOOL]
Partially implement the whole StartDocPrinter, StartPagePrinter, ReadPrinter, WritePrinter, EndPagePrinter, EndDocPrinter, ClosePrinter group of functions.
They behave very differently based on whether spooled printing is enabled, whether it's a local or remote call, etc. Most information was gained by observing callchains under Windows.
So far, only the spooled path is implemented, the others need more investigation first.
Many other TODOs remain as well, see the comments.
Also make some more comments Doxygen-aware :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
CopyMemory(pwszPrinterAndJob, OpenData.pPrinterName, cchPrinterName * sizeof(WCHAR));
|
|
|
|
CopyMemory(&pwszPrinterAndJob[cchPrinterName], wszJobAppendix, cchJobAppendix * sizeof(WCHAR));
|
|
|
|
_ultow(OpenData.JobId, &pwszPrinterAndJob[cchPrinterName + cchJobAppendix], 10);
|
|
|
|
|
2015-07-22 09:21:20 +00:00
|
|
|
// Printing starts here.
|
|
|
|
pJob->dwStatus |= JOB_STATUS_PRINTING;
|
|
|
|
|
[LOCALSPL, WINSPOOL]
Partially implement the whole StartDocPrinter, StartPagePrinter, ReadPrinter, WritePrinter, EndPagePrinter, EndDocPrinter, ClosePrinter group of functions.
They behave very differently based on whether spooled printing is enabled, whether it's a local or remote call, etc. Most information was gained by observing callchains under Windows.
So far, only the spooled path is implemented, the others need more investigation first.
Many other TODOs remain as well, see the comments.
Also make some more comments Doxygen-aware :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
// Print the document.
|
|
|
|
// Note that pJob is freed after this function, so we may not access it anymore.
|
|
|
|
if (!pPrintProcessor->pfnPrintDocumentOnPrintProcessor(hPrintProcessor, pwszPrinterAndJob))
|
|
|
|
{
|
|
|
|
dwErrorCode = GetLastError();
|
|
|
|
ERR("PrintDocumentOnPrintProcessor failed with error %lu!\n", dwErrorCode);
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close the Print Processor.
|
|
|
|
pPrintProcessor->pfnClosePrintProcessor(hPrintProcessor);
|
|
|
|
hPrintProcessor = NULL;
|
|
|
|
|
|
|
|
// Delete the spool file.
|
|
|
|
pwszSPLFile = DllAllocSplMem(GetJobFilePath(L"SPL", 0, NULL));
|
|
|
|
if (!pwszSPLFile)
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
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. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
ERR("DllAllocSplMem failed!\n");
|
[LOCALSPL, WINSPOOL]
Partially implement the whole StartDocPrinter, StartPagePrinter, ReadPrinter, WritePrinter, EndPagePrinter, EndDocPrinter, ClosePrinter group of functions.
They behave very differently based on whether spooled printing is enabled, whether it's a local or remote call, etc. Most information was gained by observing callchains under Windows.
So far, only the spooled path is implemented, the others need more investigation first.
Many other TODOs remain as well, see the comments.
Also make some more comments Doxygen-aware :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
GetJobFilePath(L"SPL", OpenData.JobId, pwszSPLFile);
|
|
|
|
DeleteFileW(pwszSPLFile);
|
|
|
|
|
|
|
|
// We were successful!
|
|
|
|
dwErrorCode = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (hPrintProcessor)
|
|
|
|
pPrintProcessor->pfnClosePrintProcessor(hPrintProcessor);
|
|
|
|
|
|
|
|
if (pwszPrinterPort)
|
|
|
|
DllFreeSplMem(pwszPrinterPort);
|
|
|
|
|
|
|
|
if (pwszPrinterAndJob)
|
|
|
|
DllFreeSplMem(pwszPrinterAndJob);
|
|
|
|
|
|
|
|
if (pwszSPLFile)
|
|
|
|
DllFreeSplMem(pwszSPLFile);
|
|
|
|
|
|
|
|
return dwErrorCode;
|
|
|
|
}
|