[PRINTING] Semi-implement GetPrinterDriverW
authorMark Jansen <mark.jansen@reactos.org>
Sat, 29 Dec 2018 22:51:32 +0000 (23:51 +0100)
committerMark Jansen <mark.jansen@reactos.org>
Sun, 6 Jan 2019 20:07:27 +0000 (21:07 +0100)
CORE-15522

win32ss/printing/base/spoolsv/printerdrivers.c
win32ss/printing/base/winspool/printers.c
win32ss/printing/include/marshalling/printerdrivers.h [new file with mode: 0644]
win32ss/printing/providers/localspl/CMakeLists.txt
win32ss/printing/providers/localspl/main.c
win32ss/printing/providers/localspl/precomp.h
win32ss/printing/providers/localspl/printerdrivers.c [new file with mode: 0644]

index ac9ac58..a1f4586 100644 (file)
@@ -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
index 9c2d12b..5f130a3 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "precomp.h"
 #include <marshalling/printers.h>
+#include <marshalling/printerdrivers.h>
 
 // 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 (file)
index 0000000..49951bd
--- /dev/null
@@ -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,
+};
index fb6e988..a5608db 100644 (file)
@@ -10,6 +10,7 @@ list(APPEND SOURCE
     ports.c
     precomp.h
     printerdata.c
+    printerdrivers.c
     printers.c
     printingthread.c
     printprocessors.c
index 7666050..7c39ec2 100644 (file)
@@ -43,7 +43,7 @@ static const PRINTPROVIDOR _PrintProviderFunctions = {
     LocalEnumPrinters,                          // fpEnumPrinters
     NULL,                                       // fpAddPrinterDriver
     NULL,                                       // fpEnumPrinterDrivers
-    NULL,                                       // fpGetPrinterDriver
+    LocalGetPrinterDriver,                      // fpGetPrinterDriver
     NULL,                                       // fpGetPrinterDriverDirectory
     NULL,                                       // fpDeletePrinterDriver
     NULL,                                       // fpAddPrintProcessor
index 83061a8..1b9a2d5 100644 (file)
@@ -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 (file)
index 0000000..5bb5b3d
--- /dev/null
@@ -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);
+}