reactos/win32ss/printing/providers/localspl/printerdrivers.c
Joachim Henze 818e5bc752 [0.4.13][PRINTING] Fix regression CORE-16622 in comdlg32:printdlg ANSI
A very nice set of patches done by Doug Lyons!, Jim Tabor, Colin Finck
to fix:
- a crash on the testbots for comdlg32:printdlg
- erroneous behavior of PrintDlg in _A()-application "Kompozer", namely
  - prevents exceptions from being thrown when opening the print dlg
  - prevents heap allocations of 0 byte size when opening the print dlg
  - prevents a help-button that should be invisible from overlapping other controls
  - allows Kompozer to extend the print-dialog with additional controls
  - allows combobox to show the printers name, instead of memory garbage

[PRINTING] Improve Stubs for GetPrinterA and GetPrinterDeviceA (#2274)
cherry picked from commit 0.4.14-dev-849-g
acec69a1d7

[WINSPOOL] Add Implementation of EnumPrintersA (#2273)
cherry picked from commit 0.4.14-dev-878-g
e8b177825b

[FORMATTING] Fix indentation of winspool/printers.c
No code changes
cherry picked from commit 0.4.14-dev-879-g
45f39ffc25

[PRINTING] Part of GDI Support
Fix ups and added support to prevent GDI from crashing. These functions
will be required for GDI.
Part 1 of print support.
cherry picked from commit 0.4.14-dev-880-g
adffa8ea75

[WINSPOOL] printers.c: Demote 3 ERR() to TRACE(), Fix 1 copypasta (#2311)
cherry picked from commit 0.4.14-dev-889-g
06f8f80181

[WINSPOOL] Implement GetPrinterDriverA and a helper function UnicodeToAnsiInPlace (#2317)
cherry picked from commit 0.4.14-dev-957-g
d90beaeed2

[WINSPOOL] Fix build
cherry picked from commit 0.4.14-dev-958-g
8da7fbc704

[GDI32] GdiConvertToDevmodeW:
Import WINE commit 32393796bb534e9cf11dd988dce88722c67f7906
("gdi32: GdiConvertToDevmodeW should not refer to unintialized name bytes.")
This makes our GdiConvertToDevmodeW equivalent to the WINE counterpart again.
cherry picked from commit 0.4.14-dev-1031-g
5d8c39753e

[WINSPOOL] Implement DocumentPropertiesA including DEVMODE conversions (#2339)
Co-authored-by: Doug Lyons <douglyons@douglyons.com>
Co-authored-by: Colin Finck <colin@reactos.org>
cherry picked from commit 0.4.14-dev-1035-g
3077c0e43e
2020-02-27 03:02:21 +01:00

323 lines
11 KiB
C

/*
* PROJECT: ReactOS Local Spooler
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Functions for printer driver information
* COPYRIGHT: Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
*/
#include "precomp.h"
// Local Constants
static DWORD dwDriverInfo1Offsets[] = {
FIELD_OFFSET(DRIVER_INFO_1W, pName),
MAXDWORD
};
static DWORD dwDriverInfo2Offsets[] = {
FIELD_OFFSET(DRIVER_INFO_2W, pName),
FIELD_OFFSET(DRIVER_INFO_2W, pEnvironment),
FIELD_OFFSET(DRIVER_INFO_2W, pDriverPath),
FIELD_OFFSET(DRIVER_INFO_2W, pDataFile),
FIELD_OFFSET(DRIVER_INFO_2W, pConfigFile),
MAXDWORD
};
static DWORD dwDriverInfo3Offsets[] = {
FIELD_OFFSET(DRIVER_INFO_3W, pName),
FIELD_OFFSET(DRIVER_INFO_3W, pEnvironment),
FIELD_OFFSET(DRIVER_INFO_3W, pDriverPath),
FIELD_OFFSET(DRIVER_INFO_3W, pDataFile),
FIELD_OFFSET(DRIVER_INFO_3W, pConfigFile),
FIELD_OFFSET(DRIVER_INFO_3W, pHelpFile),
FIELD_OFFSET(DRIVER_INFO_3W, pDependentFiles),
FIELD_OFFSET(DRIVER_INFO_3W, pMonitorName),
FIELD_OFFSET(DRIVER_INFO_3W, pDefaultDataType),
MAXDWORD
};
static DWORD dwDriverInfo4Offsets[] = {
FIELD_OFFSET(DRIVER_INFO_4W, pName),
FIELD_OFFSET(DRIVER_INFO_4W, pEnvironment),
FIELD_OFFSET(DRIVER_INFO_4W, pDriverPath),
FIELD_OFFSET(DRIVER_INFO_4W, pDataFile),
FIELD_OFFSET(DRIVER_INFO_4W, pConfigFile),
FIELD_OFFSET(DRIVER_INFO_4W, pHelpFile),
FIELD_OFFSET(DRIVER_INFO_4W, pDependentFiles),
FIELD_OFFSET(DRIVER_INFO_4W, pMonitorName),
FIELD_OFFSET(DRIVER_INFO_4W, pDefaultDataType),
FIELD_OFFSET(DRIVER_INFO_4W, pszzPreviousNames),
MAXDWORD
};
static DWORD dwDriverInfo5Offsets[] = {
FIELD_OFFSET(DRIVER_INFO_5W, pName),
FIELD_OFFSET(DRIVER_INFO_5W, pEnvironment),
FIELD_OFFSET(DRIVER_INFO_5W, pDriverPath),
FIELD_OFFSET(DRIVER_INFO_5W, pDataFile),
FIELD_OFFSET(DRIVER_INFO_5W, pConfigFile),
MAXDWORD
};
static void
ToMultiSz(LPWSTR pString)
{
while (*pString)
{
if (*pString == '|')
*pString = '\0';
pString++;
}
}
static void
_LocalGetPrinterDriverLevel1(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_1W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
{
DWORD n;
PCWSTR pwszStrings[1];
/* This value is only here to send something, I have not verified if it is actually correct */
pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver;
// Calculate the string lengths.
if (!ppDriverInfo)
{
for (n = 0; n < _countof(pwszStrings); ++n)
{
*pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
}
*pcbNeeded += sizeof(DRIVER_INFO_1W);
return;
}
// Finally copy the structure and advance to the next one in the output buffer.
*ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo1Offsets, *ppDriverInfoEnd);
(*ppDriverInfo)++;
}
static void
_LocalGetPrinterDriverLevel2(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_2W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
{
DWORD n;
PCWSTR pwszStrings[5];
/* Clearly these things should not be hardcoded, so when it is needed, someone can add meaningfull values here */
pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver; // pName
pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
pwszStrings[2] = L"c:\\reactos\\system32\\localspl.dll"; // pDriverPath
pwszStrings[3] = L"c:\\reactos\\system32\\localspl.dll"; // pDataFile
pwszStrings[4] = L"c:\\reactos\\system32\\localspl.dll"; // pConfigFile
// Calculate the string lengths.
if (!ppDriverInfo)
{
for (n = 0; n < _countof(pwszStrings); ++n)
{
*pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
}
*pcbNeeded += sizeof(DRIVER_INFO_2W);
return;
}
(*ppDriverInfo)->cVersion = 3;
// Finally copy the structure and advance to the next one in the output buffer.
*ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo2Offsets, *ppDriverInfoEnd);
(*ppDriverInfo)++;
}
static void
_LocalGetPrinterDriverLevel3(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_3W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
{
DWORD n;
PCWSTR pwszStrings[9];
/* Clearly these things should not be hardcoded, so when it is needed, someone can add meaningfull values here */
pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver; // pName
pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
pwszStrings[2] = L"c:\\reactos\\system32\\localspl.dll"; // pDriverPath
pwszStrings[3] = L"c:\\reactos\\system32\\localspl.dll"; // pDataFile
pwszStrings[4] = L"c:\\reactos\\system32\\printui.dll"; // pConfigFile
pwszStrings[5] = L""; // pHelpFile
pwszStrings[6] = L"localspl.dll|printui.dll|"; // pDependentFiles, | is separator and terminator!
pwszStrings[7] = NULL; // pMonitorName
pwszStrings[8] = NULL; // pDefaultDataType
// Calculate the string lengths.
if (!ppDriverInfo)
{
for (n = 0; n < _countof(pwszStrings); ++n)
{
if (pwszStrings[n])
{
*pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
}
}
*pcbNeeded += sizeof(DRIVER_INFO_3W);
return;
}
(*ppDriverInfo)->cVersion = 3;
// Finally copy the structure and advance to the next one in the output buffer.
*ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo3Offsets, *ppDriverInfoEnd);
ToMultiSz((*ppDriverInfo)->pDependentFiles);
(*ppDriverInfo)++;
}
static void
_LocalGetPrinterDriverLevel4(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_4W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
{
DWORD n;
PCWSTR pwszStrings[10];
/* Clearly these things should not be hardcoded, so when it is needed, someone can add meaningfull values here */
pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver; // pName
pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
pwszStrings[2] = L"c:\\reactos\\system32\\localspl.dll"; // pDriverPath
pwszStrings[3] = L"c:\\reactos\\system32\\localspl.dll"; // pDataFile
pwszStrings[4] = L"c:\\reactos\\system32\\printui.dll"; // pConfigFile
pwszStrings[5] = L""; // pHelpFile
pwszStrings[6] = L"localspl.dll|printui.dll|"; // pDependentFiles, | is separator and terminator!
pwszStrings[7] = NULL; // pMonitorName
pwszStrings[8] = NULL; // pDefaultDataType
pwszStrings[9] = NULL; // pszzPreviousNames
// Calculate the string lengths.
if (!ppDriverInfo)
{
for (n = 0; n < _countof(pwszStrings); ++n)
{
if (pwszStrings[n])
{
*pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
}
}
*pcbNeeded += sizeof(DRIVER_INFO_4W);
return;
}
(*ppDriverInfo)->cVersion = 3;
// Finally copy the structure and advance to the next one in the output buffer.
*ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo4Offsets, *ppDriverInfoEnd);
ToMultiSz((*ppDriverInfo)->pDependentFiles);
(*ppDriverInfo)++;
}
static void
_LocalGetPrinterDriverLevel5(PLOCAL_PRINTER_HANDLE pHandle, PDRIVER_INFO_5W* ppDriverInfo, PBYTE* ppDriverInfoEnd, PDWORD pcbNeeded)
{
DWORD n;
PCWSTR pwszStrings[5];
/* Clearly these things should not be hardcoded, so when it is needed, someone can add meaningfull values here */
pwszStrings[0] = pHandle->pPrinter->pwszPrinterDriver; // pName
pwszStrings[1] = wszCurrentEnvironment; // pEnvironment
pwszStrings[2] = L"c:\\reactos\\system32\\localspl.dll"; // pDriverPath UniDrv.dll
pwszStrings[3] = L"c:\\reactos\\system32\\localspl.dll"; // pDataFile.ppd
pwszStrings[4] = L"c:\\reactos\\system32\\printui.dll"; // pConfigFile UniDrvUI.dll
// Calculate the string lengths.
if (!ppDriverInfo)
{
for (n = 0; n < _countof(pwszStrings); ++n)
{
if (pwszStrings[n])
{
*pcbNeeded += (wcslen(pwszStrings[n]) + 1) * sizeof(WCHAR);
}
}
*pcbNeeded += sizeof(DRIVER_INFO_5W);
return;
}
(*ppDriverInfo)->cVersion = 3;
// Driver attributes, like UMPD/KMPD.
(*ppDriverInfo)->dwDriverAttributes = 0; // UMPD/KMPD, So where are they?
// Number of times the configuration file for this driver has been upgraded or downgraded since the last spooler restart.
(*ppDriverInfo)->dwConfigVersion = 1;
// Number of times the driver file for this driver has been upgraded or downgraded since the last spooler restart.
(*ppDriverInfo)->dwDriverVersion = 1;
// Finally copy the structure and advance to the next one in the output buffer.
*ppDriverInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppDriverInfo), dwDriverInfo5Offsets, *ppDriverInfoEnd);
(*ppDriverInfo)++;
}
BOOL WINAPI LocalGetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
{
DWORD dwErrorCode;
PBYTE pEnd = &pDriverInfo[cbBuf];
PLOCAL_HANDLE pHandle;
PLOCAL_PRINTER_HANDLE pPrinterHandle;
TRACE("LocalGetPrinterDriver(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
// Check if this is a printer handle.
pHandle = (PLOCAL_HANDLE)hPrinter;
if (pHandle->HandleType != HandleType_Printer)
{
dwErrorCode = ERROR_INVALID_HANDLE;
goto Cleanup;
}
pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
// Only support 5 levels for now
if (Level > 5)
{
// The caller supplied an invalid level.
dwErrorCode = ERROR_INVALID_LEVEL;
goto Cleanup;
}
// Count the required buffer size.
*pcbNeeded = 0;
if (Level == 1)
_LocalGetPrinterDriverLevel1(pPrinterHandle, NULL, NULL, pcbNeeded);
else if (Level == 2)
_LocalGetPrinterDriverLevel2(pPrinterHandle, NULL, NULL, pcbNeeded);
else if (Level == 3)
_LocalGetPrinterDriverLevel3(pPrinterHandle, NULL, NULL, pcbNeeded);
else if (Level == 4)
_LocalGetPrinterDriverLevel4(pPrinterHandle, NULL, NULL, pcbNeeded);
else if (Level == 5)
_LocalGetPrinterDriverLevel5(pPrinterHandle, NULL, NULL, pcbNeeded);
// Check if the supplied buffer is large enough.
if (cbBuf < *pcbNeeded)
{
dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
goto Cleanup;
}
// Copy over the information.
pEnd = &pDriverInfo[*pcbNeeded];
if (Level == 1)
_LocalGetPrinterDriverLevel1(pPrinterHandle, (PDRIVER_INFO_1W*)&pDriverInfo, &pEnd, NULL);
else if (Level == 2)
_LocalGetPrinterDriverLevel2(pPrinterHandle, (PDRIVER_INFO_2W*)&pDriverInfo, &pEnd, NULL);
else if (Level == 3)
_LocalGetPrinterDriverLevel3(pPrinterHandle, (PDRIVER_INFO_3W*)&pDriverInfo, &pEnd, NULL);
else if (Level == 4)
_LocalGetPrinterDriverLevel4(pPrinterHandle, (PDRIVER_INFO_4W*)&pDriverInfo, &pEnd, NULL);
else if (Level == 5)
_LocalGetPrinterDriverLevel5(pPrinterHandle, (PDRIVER_INFO_5W*)&pDriverInfo, &pEnd, NULL);
dwErrorCode = ERROR_SUCCESS;
Cleanup:
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}