diff --git a/win32ss/printing/base/spoolsv/printerdrivers.c b/win32ss/printing/base/spoolsv/printerdrivers.c index ac9ac5801b7..a1f45865c15 100644 --- a/win32ss/printing/base/spoolsv/printerdrivers.c +++ b/win32ss/printing/base/spoolsv/printerdrivers.c @@ -6,6 +6,7 @@ */ #include "precomp.h" +#include "marshalling/printerdrivers.h" DWORD _RpcAddPrinterDriver(WINSPOOL_HANDLE pName, WINSPOOL_DRIVER_CONTAINER* pDriverContainer) @@ -45,8 +46,33 @@ _RpcEnumPrinterDrivers(WINSPOOL_HANDLE pName, WCHAR* pEnvironment, DWORD Level, DWORD _RpcGetPrinterDriver(WINSPOOL_PRINTER_HANDLE hPrinter, WCHAR* pEnvironment, DWORD Level, BYTE* pDriver, DWORD cbBuf, DWORD* pcbNeeded) { - UNIMPLEMENTED; - return ERROR_INVALID_FUNCTION; + DWORD dwErrorCode; + PBYTE pDriverAligned; + + dwErrorCode = RpcImpersonateClient(NULL); + if (dwErrorCode != ERROR_SUCCESS) + { + ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode); + return dwErrorCode; + } + + pDriverAligned = AlignRpcPtr(pDriver, &cbBuf); + + if (GetPrinterDriverW(hPrinter, pEnvironment, Level, pDriverAligned, cbBuf, pcbNeeded)) + { + // Replace relative offset addresses in the output by absolute pointers. + ASSERT(Level >= 1 && Level <= 3); + MarshallDownStructure(pDriverAligned, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE); + } + else + { + dwErrorCode = GetLastError(); + } + + RpcRevertToSelf(); + UndoAlignRpcPtr(pDriver, pDriverAligned, cbBuf, pcbNeeded); + + return dwErrorCode; } DWORD diff --git a/win32ss/printing/base/winspool/printers.c b/win32ss/printing/base/winspool/printers.c index 9c2d12b31f8..5f130a3d15b 100644 --- a/win32ss/printing/base/winspool/printers.c +++ b/win32ss/printing/base/winspool/printers.c @@ -7,6 +7,7 @@ #include "precomp.h" #include +#include // Local Constants @@ -513,8 +514,50 @@ GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriv BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded) { + DWORD dwErrorCode; + PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; + TRACE("GetPrinterDriverW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); - return FALSE; + + // Sanity checks. + if (!pHandle) + { + dwErrorCode = ERROR_INVALID_HANDLE; + goto Cleanup; + } + + // Dismiss invalid levels already at this point. + if (Level > 8 || Level < 1) + { + dwErrorCode = ERROR_INVALID_LEVEL; + goto Cleanup; + } + + if (cbBuf && pDriverInfo) + ZeroMemory(pDriverInfo, cbBuf); + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcGetPrinterDriver(pHandle->hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + if (dwErrorCode == ERROR_SUCCESS) + { + // Replace relative offset addresses in the output by absolute pointers. + ASSERT(Level <= 3); + MarshallUpStructure(cbBuf, pDriverInfo, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE); + } + +Cleanup: + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } BOOL WINAPI diff --git a/win32ss/printing/include/marshalling/printerdrivers.h b/win32ss/printing/include/marshalling/printerdrivers.h new file mode 100644 index 00000000000..49951bdca27 --- /dev/null +++ b/win32ss/printing/include/marshalling/printerdrivers.h @@ -0,0 +1,51 @@ +/* + * PROJECT: ReactOS Printing Stack Marshalling Functions + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: Marshalling definitions for DRIVER_INFO_* + * COPYRIGHT: Copyright 2018 Mark Jansen (mark.jansen@reactos.org) + */ + +static const MARSHALLING PrinterDriver1Marshalling = { + sizeof(DRIVER_INFO_1W), + { + { FIELD_OFFSET(DRIVER_INFO_1W, pName), RTL_FIELD_SIZE(DRIVER_INFO_1W, pName), RTL_FIELD_SIZE(DRIVER_INFO_1W, pName), TRUE }, + { MAXDWORD, 0, 0, FALSE } + } +}; + +static const MARSHALLING PrinterDriver2Marshalling = { + sizeof(DRIVER_INFO_2W), + { + { FIELD_OFFSET(DRIVER_INFO_2W, pName), RTL_FIELD_SIZE(DRIVER_INFO_2W, pName), RTL_FIELD_SIZE(DRIVER_INFO_2W, pName), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_2W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_2W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_2W, pEnvironment), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_2W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_2W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_2W, pDriverPath), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_2W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_2W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_2W, pDataFile), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_2W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_2W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_2W, pConfigFile), TRUE }, + { MAXDWORD, 0, 0, FALSE } + } +}; + +static const MARSHALLING PrinterDriver3Marshalling = { + sizeof(DRIVER_INFO_3W), + { + { FIELD_OFFSET(DRIVER_INFO_3W, pName), RTL_FIELD_SIZE(DRIVER_INFO_3W, pName), RTL_FIELD_SIZE(DRIVER_INFO_3W, pName), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_3W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_3W, pEnvironment), RTL_FIELD_SIZE(DRIVER_INFO_3W, pEnvironment), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_3W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_3W, pDriverPath), RTL_FIELD_SIZE(DRIVER_INFO_3W, pDriverPath), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_3W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_3W, pDataFile), RTL_FIELD_SIZE(DRIVER_INFO_3W, pDataFile), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_3W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_3W, pConfigFile), RTL_FIELD_SIZE(DRIVER_INFO_3W, pConfigFile), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_3W, pHelpFile), RTL_FIELD_SIZE(DRIVER_INFO_3W, pHelpFile), RTL_FIELD_SIZE(DRIVER_INFO_3W, pHelpFile), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_3W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_3W, pDependentFiles), RTL_FIELD_SIZE(DRIVER_INFO_3W, pDependentFiles), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_3W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_3W, pMonitorName), RTL_FIELD_SIZE(DRIVER_INFO_3W, pMonitorName), TRUE }, + { FIELD_OFFSET(DRIVER_INFO_3W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_3W, pDefaultDataType), RTL_FIELD_SIZE(DRIVER_INFO_3W, pDefaultDataType), TRUE }, + { MAXDWORD, 0, 0, FALSE } + } +}; + + + +static const MARSHALLING* pPrinterDriverMarshalling[] = { + NULL, + &PrinterDriver1Marshalling, + &PrinterDriver2Marshalling, + &PrinterDriver3Marshalling, +}; diff --git a/win32ss/printing/providers/localspl/CMakeLists.txt b/win32ss/printing/providers/localspl/CMakeLists.txt index fb6e988ab93..a5608db4063 100644 --- a/win32ss/printing/providers/localspl/CMakeLists.txt +++ b/win32ss/printing/providers/localspl/CMakeLists.txt @@ -10,6 +10,7 @@ list(APPEND SOURCE ports.c precomp.h printerdata.c + printerdrivers.c printers.c printingthread.c printprocessors.c diff --git a/win32ss/printing/providers/localspl/main.c b/win32ss/printing/providers/localspl/main.c index 76660504463..7c39ec2cf09 100644 --- a/win32ss/printing/providers/localspl/main.c +++ b/win32ss/printing/providers/localspl/main.c @@ -43,7 +43,7 @@ static const PRINTPROVIDOR _PrintProviderFunctions = { LocalEnumPrinters, // fpEnumPrinters NULL, // fpAddPrinterDriver NULL, // fpEnumPrinterDrivers - NULL, // fpGetPrinterDriver + LocalGetPrinterDriver, // fpGetPrinterDriver NULL, // fpGetPrinterDriverDirectory NULL, // fpDeletePrinterDriver NULL, // fpAddPrintProcessor diff --git a/win32ss/printing/providers/localspl/precomp.h b/win32ss/printing/providers/localspl/precomp.h index 83061a8a8b7..1b9a2d55400 100644 --- a/win32ss/printing/providers/localspl/precomp.h +++ b/win32ss/printing/providers/localspl/precomp.h @@ -287,6 +287,10 @@ DWORD WINAPI LocalGetPrinterDataEx(HANDLE hPrinter, PCWSTR pKeyName, PCWSTR pVal DWORD WINAPI LocalSetPrinterData(HANDLE hPrinter, PWSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData); DWORD WINAPI LocalSetPrinterDataEx(HANDLE hPrinter, LPCWSTR pKeyName, LPCWSTR pValueName, DWORD Type, LPBYTE pData, DWORD cbData); +// printerdriver.c +BOOL WINAPI LocalGetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded); + + // printers.c extern SKIPLIST PrinterList; BOOL InitializePrinterList(void); diff --git a/win32ss/printing/providers/localspl/printerdrivers.c b/win32ss/printing/providers/localspl/printerdrivers.c new file mode 100644 index 00000000000..5bb5b3db73a --- /dev/null +++ b/win32ss/printing/providers/localspl/printerdrivers.c @@ -0,0 +1,211 @@ +/* + * 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 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)++; +} + + +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 3 levels for now + if (Level > 3) + { + // 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); + + // 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); + + dwErrorCode = ERROR_SUCCESS; + +Cleanup: + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); +}