[LOCALSPL]
authorColin Finck <colin@reactos.org>
Sun, 16 Apr 2017 14:12:01 +0000 (14:12 +0000)
committerColin Finck <colin@reactos.org>
Sun, 16 Apr 2017 14:12:01 +0000 (14:12 +0000)
- Refactor LocalEnumPrinters to make it ready for supporting additional levels.
- Correctly handle all passed flags for Level 1 queries to the Local Print Provider.
- Introduce strsafe functions to LocalEnumPrinters in a way that actually makes the code smaller. To be done in other parts too.
- Use PackStrings in LocalEnumPrinters to simplify the code.
- Return the correct 3 strings in the Description field of Level 1 queries. That also introduces the "Location" field.
- Remove debug spam in _OpenEnvironment.

[SPOOLSV]
- Make use of the newly implemented AlignRpcPtr/UndoAlignRpcPtr. Fixes a test.

[WINSPOOL]
- Dismiss invalid levels already in EnumPrintersW and zero the input buffer here (but not in localspl). Verified by a test.

EnumPrintersW for Level 1 should be fully supported now.

svn path=/trunk/; revision=74324

12 files changed:
reactos/boot/bootdata/hivesys.inf
reactos/win32ss/printing/base/spoolss/printers.c
reactos/win32ss/printing/base/spoolsv/precomp.h
reactos/win32ss/printing/base/spoolsv/printers.c
reactos/win32ss/printing/base/winspool/printers.c
reactos/win32ss/printing/include/spoolss.h
reactos/win32ss/printing/providers/localspl/main.c
reactos/win32ss/printing/providers/localspl/precomp.h
reactos/win32ss/printing/providers/localspl/printers.c
reactos/win32ss/printing/providers/localspl/printprocessors.c
rostests/apitests/localspl/dll/fpEnumPrinters.c
rostests/apitests/winspool/EnumPrinters.c

index 5fd95fb..c12dabf 100644 (file)
@@ -1277,6 +1277,7 @@ HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","De
 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
+HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Location",,"At Home"
 HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Port",,"LPT1:"
 HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Print Processor",,"winprint"
 HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Printer Driver",,"Dummy Printer Driver"
 HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Port",,"LPT1:"
 HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Print Processor",,"winprint"
 HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Printer Driver",,"Dummy Printer Driver"
index 2bbf698..51e3f87 100644 (file)
@@ -2,7 +2,7 @@
  * PROJECT:     ReactOS Spooler Router
  * LICENSE:     GNU LGPL v2.1 or any later version as published by the Free Software Foundation
  * PURPOSE:     Functions related to Printers and printing
  * PROJECT:     ReactOS Spooler Router
  * LICENSE:     GNU LGPL v2.1 or any later version as published by the Free Software Foundation
  * PURPOSE:     Functions related to Printers and printing
- * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
+ * COPYRIGHT:   Copyright 2015-2017 Colin Finck <colin@reactos.org>
  */
 
 #include "precomp.h"
  */
 
 #include "precomp.h"
@@ -68,27 +68,27 @@ EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cb
     BOOL bReturnValue;
     DWORD cbCallBuffer;
     DWORD cbNeeded;
     BOOL bReturnValue;
     DWORD cbCallBuffer;
     DWORD cbNeeded;
+    DWORD dwErrorCode = 0xFFFFFFFF;
     DWORD dwReturned;
     PBYTE pCallBuffer;
     PSPOOLSS_PRINT_PROVIDER pPrintProvider;
     PLIST_ENTRY pEntry;
 
     DWORD dwReturned;
     PBYTE pCallBuffer;
     PSPOOLSS_PRINT_PROVIDER pPrintProvider;
     PLIST_ENTRY pEntry;
 
-    // Sanity checks.
-    if ((cbBuf && !pPrinterEnum) || !pcbNeeded || !pcReturned)
-    {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-
     // Begin counting.
     *pcbNeeded = 0;
     *pcReturned = 0;
 
     // Begin counting.
     *pcbNeeded = 0;
     *pcReturned = 0;
 
+    if (cbBuf && !pPrinterEnum)
+    {
+        dwErrorCode = ERROR_INVALID_USER_BUFFER;
+        goto Cleanup;
+    }
+
     // At the beginning, we have the full buffer available.
     cbCallBuffer = cbBuf;
     pCallBuffer = pPrinterEnum;
 
     // At the beginning, we have the full buffer available.
     cbCallBuffer = cbBuf;
     pCallBuffer = pPrinterEnum;
 
-    // Loop through all Print Provider.
+    // Loop through all Print Providers.
     for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
     {
         pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
     for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
     {
         pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
@@ -109,9 +109,15 @@ EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cb
         // Advance the buffer if the caller provided it.
         if (pCallBuffer)
             pCallBuffer += cbNeeded;
         // Advance the buffer if the caller provided it.
         if (pCallBuffer)
             pCallBuffer += cbNeeded;
+
+        // dwErrorCode shall not be overwritten if a previous EnumPrinters call already succeeded.
+        if (dwErrorCode != ERROR_SUCCESS)
+            dwErrorCode = GetLastError();
     }
 
     }
 
-    return bReturnValue;
+Cleanup:
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 BOOL WINAPI
 }
 
 BOOL WINAPI
@@ -148,6 +154,7 @@ BOOL WINAPI
 OpenPrinterW(PWSTR pPrinterName, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault)
 {
     BOOL bReturnValue;
 OpenPrinterW(PWSTR pPrinterName, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault)
 {
     BOOL bReturnValue;
+    DWORD dwErrorCode = ERROR_INVALID_PRINTER_NAME;
     HANDLE hPrinter;
     PLIST_ENTRY pEntry;
     PSPOOLSS_PRINTER_HANDLE pHandle;
     HANDLE hPrinter;
     PLIST_ENTRY pEntry;
     PSPOOLSS_PRINTER_HANDLE pHandle;
@@ -156,8 +163,8 @@ OpenPrinterW(PWSTR pPrinterName, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault)
     // Sanity checks.
     if (!pPrinterName || !phPrinter)
     {
     // Sanity checks.
     if (!pPrinterName || !phPrinter)
     {
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
+        dwErrorCode = ERROR_INVALID_PARAMETER;
+        goto Cleanup;
     }
 
     // Loop through all Print Providers to find one able to open this Printer.
     }
 
     // Loop through all Print Providers to find one able to open this Printer.
@@ -173,27 +180,33 @@ OpenPrinterW(PWSTR pPrinterName, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault)
             pHandle = DllAllocSplMem(sizeof(SPOOLSS_PRINTER_HANDLE));
             if (!pHandle)
             {
             pHandle = DllAllocSplMem(sizeof(SPOOLSS_PRINTER_HANDLE));
             if (!pHandle)
             {
-                SetLastError(ERROR_NOT_ENOUGH_MEMORY);
                 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
                 ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
-                return FALSE;
+                dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+                goto Cleanup;
             }
 
             pHandle->pPrintProvider = pPrintProvider;
             pHandle->hPrinter = hPrinter;
             *phPrinter = (HANDLE)pHandle;
 
             }
 
             pHandle->pPrintProvider = pPrintProvider;
             pHandle->hPrinter = hPrinter;
             *phPrinter = (HANDLE)pHandle;
 
-            SetLastError(ERROR_SUCCESS);
-            return TRUE;
+            dwErrorCode = ERROR_SUCCESS;
+            goto Cleanup;
         }
         else if (bReturnValue == ROUTER_STOP_ROUTING)
         {
             ERR("A Print Provider returned ROUTER_STOP_ROUTING for Printer \"%S\"!\n", pPrinterName);
         }
         else if (bReturnValue == ROUTER_STOP_ROUTING)
         {
             ERR("A Print Provider returned ROUTER_STOP_ROUTING for Printer \"%S\"!\n", pPrinterName);
-            return FALSE;
+            dwErrorCode = GetLastError();
+            goto Cleanup;
         }
     }
 
         }
     }
 
-    // We found no Print Provider able to open this Printer.
-    return FALSE;
+    // ERROR_INVALID_NAME by the Print Provider is translated to ERROR_INVALID_PRINTER_NAME here, but not in other APIs as far as I know.
+    if (dwErrorCode == ERROR_INVALID_NAME)
+        dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+
+Cleanup:
+    SetLastError(dwErrorCode);
+    return (dwErrorCode == ERROR_SUCCESS);
 }
 
 BOOL WINAPI
 }
 
 BOOL WINAPI
index b882f98..8efb51c 100644 (file)
@@ -2,7 +2,7 @@
  * PROJECT:     ReactOS Print Spooler Service
  * LICENSE:     GNU GPLv2 or any later version as published by the Free Software Foundation
  * PURPOSE:     Precompiled Header for all source files
  * PROJECT:     ReactOS Print Spooler Service
  * LICENSE:     GNU GPLv2 or any later version as published by the Free Software Foundation
  * PURPOSE:     Precompiled Header for all source files
- * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
+ * COPYRIGHT:   Copyright 2015-2017 Colin Finck <colin@reactos.org>
  */
 
 #ifndef _PRECOMP_H
  */
 
 #ifndef _PRECOMP_H
 #include <winsplp.h>
 #include <winspool_s.h>
 
 #include <winsplp.h>
 #include <winspool_s.h>
 
+#include <spoolss.h>
+
 #include <wine/debug.h>
 WINE_DEFAULT_DEBUG_CHANNEL(spoolsv);
 
 // rpcserver.c
 DWORD WINAPI LrpcThreadProc(LPVOID lpParameter);
 
 #include <wine/debug.h>
 WINE_DEFAULT_DEBUG_CHANNEL(spoolsv);
 
 // rpcserver.c
 DWORD WINAPI LrpcThreadProc(LPVOID lpParameter);
 
-// Undocumented spoolss
-BOOL WINAPI InitializeRouter(HANDLE SpoolerStatusHandle);
-DWORD WINAPI SpoolerInit();
-
 #endif
 #endif
index fb20f04..1468faa 100644 (file)
@@ -2,7 +2,7 @@
  * PROJECT:     ReactOS Print Spooler Service
  * LICENSE:     GNU GPLv2 or any later version as published by the Free Software Foundation
  * PURPOSE:     Functions related to Printers and printing
  * PROJECT:     ReactOS Print Spooler Service
  * LICENSE:     GNU GPLv2 or any later version as published by the Free Software Foundation
  * PURPOSE:     Functions related to Printers and printing
- * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
+ * COPYRIGHT:   Copyright 2015-2017 Colin Finck <colin@reactos.org>
  */
 
 #include "precomp.h"
  */
 
 #include "precomp.h"
@@ -137,8 +137,7 @@ DWORD
 _RpcEnumPrinters(DWORD Flags, WINSPOOL_HANDLE Name, DWORD Level, BYTE* pPrinterEnum, DWORD cbBuf, DWORD* pcbNeeded, DWORD* pcReturned)
 {
     DWORD dwErrorCode;
 _RpcEnumPrinters(DWORD Flags, WINSPOOL_HANDLE Name, DWORD Level, BYTE* pPrinterEnum, DWORD cbBuf, DWORD* pcbNeeded, DWORD* pcReturned)
 {
     DWORD dwErrorCode;
-    DWORD i;
-    PBYTE p = pPrinterEnum;
+    PBYTE pPrinterEnumAligned;
 
     dwErrorCode = RpcImpersonateClient(NULL);
     if (dwErrorCode != ERROR_SUCCESS)
 
     dwErrorCode = RpcImpersonateClient(NULL);
     if (dwErrorCode != ERROR_SUCCESS)
@@ -147,11 +146,15 @@ _RpcEnumPrinters(DWORD Flags, WINSPOOL_HANDLE Name, DWORD Level, BYTE* pPrinterE
         return dwErrorCode;
     }
 
         return dwErrorCode;
     }
 
-    EnumPrintersW(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
+    pPrinterEnumAligned = AlignRpcPtr(pPrinterEnum, &cbBuf);
+    EnumPrintersW(Flags, Name, Level, pPrinterEnumAligned, cbBuf, pcbNeeded, pcReturned);
     dwErrorCode = GetLastError();
 
     if (dwErrorCode == ERROR_SUCCESS)
     {
     dwErrorCode = GetLastError();
 
     if (dwErrorCode == ERROR_SUCCESS)
     {
+        DWORD i;
+        PBYTE p = pPrinterEnumAligned;
+
         // Replace absolute pointer addresses in the output by relative offsets.
         for (i = 0; i < *pcReturned; i++)
         {
         // Replace absolute pointer addresses in the output by relative offsets.
         for (i = 0; i < *pcReturned; i++)
         {
@@ -165,6 +168,8 @@ _RpcEnumPrinters(DWORD Flags, WINSPOOL_HANDLE Name, DWORD Level, BYTE* pPrinterE
     }
 
     RpcRevertToSelf();
     }
 
     RpcRevertToSelf();
+    UndoAlignRpcPtr(pPrinterEnum, pPrinterEnumAligned, cbBuf, pcbNeeded);
+
     return dwErrorCode;
 }
 
     return dwErrorCode;
 }
 
index c82132c..ffa965f 100644 (file)
@@ -2,7 +2,7 @@
  * PROJECT:     ReactOS Spooler API
  * LICENSE:     GNU LGPL v2.1 or any later version as published by the Free Software Foundation
  * PURPOSE:     Functions related to Printers and printing
  * PROJECT:     ReactOS Spooler API
  * LICENSE:     GNU LGPL v2.1 or any later version as published by the Free Software Foundation
  * PURPOSE:     Functions related to Printers and printing
- * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
+ * COPYRIGHT:   Copyright 2015-2017 Colin Finck <colin@reactos.org>
  */
 
 #include "precomp.h"
  */
 
 #include "precomp.h"
@@ -309,6 +309,16 @@ EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cb
     DWORD i;
     PBYTE p = pPrinterEnum;
 
     DWORD i;
     PBYTE p = pPrinterEnum;
 
+    // Dismiss invalid levels already at this point.
+    if (Level == 3 || Level > 5)
+    {
+        dwErrorCode = ERROR_INVALID_LEVEL;
+        goto Cleanup;
+    }
+
+    if (cbBuf && pPrinterEnum)
+        ZeroMemory(pPrinterEnum, cbBuf);
+
     // Do the RPC call
     RpcTryExcept
     {
     // Do the RPC call
     RpcTryExcept
     {
@@ -335,6 +345,7 @@ EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cb
         }
     }
 
         }
     }
 
+Cleanup:
     SetLastError(dwErrorCode);
     return (dwErrorCode == ERROR_SUCCESS);
 }
     SetLastError(dwErrorCode);
     return (dwErrorCode == ERROR_SUCCESS);
 }
index e43c346..af7436d 100644 (file)
@@ -24,11 +24,13 @@ PWSTR WINAPI AllocSplStr(PCWSTR pwszInput);
 PVOID WINAPI DllAllocSplMem(DWORD dwBytes);
 BOOL WINAPI DllFreeSplMem(PVOID pMem);
 BOOL WINAPI DllFreeSplStr(PWSTR pwszString);
 PVOID WINAPI DllAllocSplMem(DWORD dwBytes);
 BOOL WINAPI DllFreeSplMem(PVOID pMem);
 BOOL WINAPI DllFreeSplStr(PWSTR pwszString);
+BOOL WINAPI InitializeRouter(HANDLE SpoolerStatusHandle);
 BOOL WINAPI MarshallDownStructure(PVOID pStructure, PMARSHALL_DOWN_INFO pParameters, DWORD cbStructureSize, BOOL bSomeBoolean);
 PBYTE WINAPI PackStrings(PCWSTR* pSource, PBYTE pDest, const DWORD* DestOffsets, PBYTE pEnd);
 PVOID WINAPI ReallocSplMem(PVOID pOldMem, DWORD cbOld, DWORD cbNew);
 BOOL WINAPI ReallocSplStr(PWSTR* ppwszString, PCWSTR pwszInput);
 BOOL WINAPI SplInitializeWinSpoolDrv(PVOID* pTable);
 BOOL WINAPI MarshallDownStructure(PVOID pStructure, PMARSHALL_DOWN_INFO pParameters, DWORD cbStructureSize, BOOL bSomeBoolean);
 PBYTE WINAPI PackStrings(PCWSTR* pSource, PBYTE pDest, const DWORD* DestOffsets, PBYTE pEnd);
 PVOID WINAPI ReallocSplMem(PVOID pOldMem, DWORD cbOld, DWORD cbNew);
 BOOL WINAPI ReallocSplStr(PWSTR* ppwszString, PCWSTR pwszInput);
 BOOL WINAPI SplInitializeWinSpoolDrv(PVOID* pTable);
+DWORD WINAPI SpoolerInit();
 PDWORD WINAPI UndoAlignRpcPtr(PVOID pDestinationBuffer, PVOID pSourceBuffer, DWORD cbBuffer, PDWORD pcbNeeded);
 
 #endif
 PDWORD WINAPI UndoAlignRpcPtr(PVOID pDestinationBuffer, PVOID pSourceBuffer, DWORD cbBuffer, PDWORD pcbNeeded);
 
 #endif
index aada4a9..458edba 100644 (file)
@@ -2,7 +2,7 @@
  * PROJECT:     ReactOS Local Spooler
  * LICENSE:     GNU LGPL v2.1 or any later version as published by the Free Software Foundation
  * PURPOSE:     Main functions
  * PROJECT:     ReactOS Local Spooler
  * LICENSE:     GNU LGPL v2.1 or any later version as published by the Free Software Foundation
  * PURPOSE:     Main functions
- * COPYRIGHT:   Copyright 2015-2016 Colin Finck <colin@reactos.org>
+ * COPYRIGHT:   Copyright 2015-2017 Colin Finck <colin@reactos.org>
  */
 
 #include "precomp.h"
  */
 
 #include "precomp.h"
@@ -18,8 +18,8 @@ const WCHAR wszDefaultDocumentName[] = L"Local Downlevel Document";
 
 const WCHAR* wszPrintProviderInfo[3] = {
     L"Windows NT Local Print Providor",     // Name
 
 const WCHAR* wszPrintProviderInfo[3] = {
     L"Windows NT Local Print Providor",     // Name
-    L"Windows NT Local Printers",           // Description
-    L"Locally connected Printers"           // Comment
+    L"Locally connected Printers",          // Comment
+    L"Windows NT Local Printers"            // Description
 };
 
 // Local Constants
 };
 
 // Local Constants
index c872853..98e219b 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <lmcons.h>
 #include <rpc.h>
 
 #include <lmcons.h>
 #include <rpc.h>
+#include <strsafe.h>
 #include <windef.h>
 #include <winbase.h>
 #include <wingdi.h>
 #include <windef.h>
 #include <winbase.h>
 #include <wingdi.h>
@@ -114,6 +115,7 @@ struct _LOCAL_PRINTER
 
     DWORD dwAttributes;
     DWORD dwStatus;
 
     DWORD dwAttributes;
     DWORD dwStatus;
+    PWSTR pwszLocation;
     PWSTR pwszPrinterDriver;
     PWSTR pwszDescription;
     PWSTR pwszDefaultDatatype;
     PWSTR pwszPrinterDriver;
     PWSTR pwszDescription;
     PWSTR pwszDefaultDatatype;
index f7f9410..8a8056c 100644 (file)
@@ -2,7 +2,7 @@
  * PROJECT:     ReactOS Local Spooler
  * LICENSE:     GNU LGPL v2.1 or any later version as published by the Free Software Foundation
  * PURPOSE:     Functions related to Printers and printing
  * PROJECT:     ReactOS Local Spooler
  * LICENSE:     GNU LGPL v2.1 or any later version as published by the Free Software Foundation
  * PURPOSE:     Functions related to Printers and printing
- * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
+ * COPYRIGHT:   Copyright 2015-2017 Colin Finck <colin@reactos.org>
  */
 
 #include "precomp.h"
  */
 
 #include "precomp.h"
 // Global Variables
 SKIPLIST PrinterList;
 
 // Global Variables
 SKIPLIST PrinterList;
 
+// Local Constants
+static DWORD dwPrinterInfo1Offsets[] = {
+    FIELD_OFFSET(PRINTER_INFO_1W, pName),
+    FIELD_OFFSET(PRINTER_INFO_1W, pComment),
+    FIELD_OFFSET(PRINTER_INFO_1W, pDescription),
+    MAXDWORD
+};
 
 /**
  * @name _PrinterListCompareRoutine
 
 /**
  * @name _PrinterListCompareRoutine
@@ -170,6 +177,11 @@ InitializePrinterList()
         pPrinter->pPort = pPort;
         InitializePrinterJobList(pPrinter);
 
         pPrinter->pPort = pPort;
         InitializePrinterJobList(pPrinter);
 
+        // Get the location.
+        pPrinter->pwszLocation = AllocAndRegQueryWSZ(hSubKey, L"Location");
+        if (!pPrinter->pwszLocation)
+            continue;
+
         // Get the printer driver.
         pPrinter->pwszPrinterDriver = AllocAndRegQueryWSZ(hSubKey, L"Printer Driver");
         if (!pPrinter->pwszPrinterDriver)
         // Get the printer driver.
         pPrinter->pwszPrinterDriver = AllocAndRegQueryWSZ(hSubKey, L"Printer Driver");
         if (!pPrinter->pwszPrinterDriver)
@@ -284,9 +296,93 @@ Cleanup:
     return (dwErrorCode == ERROR_SUCCESS);
 }
 
     return (dwErrorCode == ERROR_SUCCESS);
 }
 
+/**
+ * @name _IsLocalComputerName
+ *
+ * Checks if the given Computer Name matches the local Computer Name.
+ *
+ * @param Name
+ * Computer Name prepended with two backslashes to check.
+ *
+ * @param pwszComputerName
+ * Pointer to a string able to hold 2 + MAX_COMPUTERNAME_LENGTH + 1 + 1 characters.
+ * Will contain a string "\\COMPUTERNAME\" on success that can be prepended in EnumPrinters.
+ *
+ * @param pcchComputerName
+ * On success, this pointer receives the length in characters of pwszComputerName.
+ *
+ * @return
+ * ERROR_SUCCESS on success or an error code on failure.
+ */
+static DWORD
+_IsLocalComputerName(PCWSTR Name, PWSTR pwszComputerName, PDWORD pcchComputerName)
+{
+    DWORD dwErrorCode;
+
+    // Prepend slashes to the computer name.
+    pwszComputerName[0] = L'\\';
+    pwszComputerName[1] = L'\\';
 
 
-DWORD
-_LocalEnumPrintersLevel1(DWORD Flags, LPWSTR Name, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
+    // Get the local computer name for comparison.
+    *pcchComputerName = MAX_COMPUTERNAME_LENGTH + 1;
+    if (!GetComputerNameW(&pwszComputerName[2], pcchComputerName))
+    {
+        dwErrorCode = GetLastError();
+        ERR("GetComputerNameW failed with error %lu!\n", dwErrorCode);
+        goto Cleanup;
+    }
+
+    // Add the leading slashes to the total length.
+    *pcchComputerName += 2;
+
+    // Now compare this with the local computer name and reject it with ERROR_INVALID_NAME if it doesn't match.
+    if (wcsicmp(&Name[2], &pwszComputerName[2]) != 0)
+    {
+        dwErrorCode = ERROR_INVALID_NAME;
+        goto Cleanup;
+    }
+
+    // Add a trailing backslash to pwszComputerName, which will later be prepended in front of the printer names.
+    pwszComputerName[(*pcchComputerName)++] = L'\\';
+    pwszComputerName[*pcchComputerName] = 0;
+
+    dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+    return dwErrorCode;
+}
+
+static DWORD
+_DumpLevel1PrintProviderInformation(PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+    int i;
+
+    // Count the needed bytes for Print Provider information.
+    *pcbNeeded = sizeof(PRINTER_INFO_1W);
+
+    for (i = 0; i < 3; i++)
+        *pcbNeeded += (wcslen(wszPrintProviderInfo[i]) + 1) * sizeof(WCHAR);
+
+    // Check if the supplied buffer is large enough.
+    if (cbBuf < *pcbNeeded)
+        return ERROR_INSUFFICIENT_BUFFER;
+
+    // Copy over the Print Provider information.
+    ((PPRINTER_INFO_1W)pPrinterEnum)->Flags = 0;
+    PackStrings(wszPrintProviderInfo, pPrinterEnum, dwPrinterInfo1Offsets, &pPrinterEnum[*pcbNeeded]);
+    *pcReturned = 1;
+
+    return ERROR_SUCCESS;
+}
+
+static DWORD
+_LocalEnumPrintersLevel0(DWORD Flags, PCWSTR Name, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+    return ERROR_INVALID_LEVEL;
+}
+
+static DWORD
+_LocalEnumPrintersLevel1(DWORD Flags, PCWSTR Name, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
 {
     const WCHAR wszComma[] = L",";
 
 {
     const WCHAR wszComma[] = L",";
 
@@ -297,57 +393,28 @@ _LocalEnumPrintersLevel1(DWORD Flags, LPWSTR Name, LPBYTE pPrinterEnum, DWORD cb
     DWORD dwErrorCode;
     DWORD i;
     PBYTE pPrinterInfo;
     DWORD dwErrorCode;
     DWORD i;
     PBYTE pPrinterInfo;
-    PBYTE pPrinterString;
+    PBYTE pPrinterStrings;
     PSKIPLIST_NODE pNode;
     PLOCAL_PRINTER pPrinter;
     PSKIPLIST_NODE pNode;
     PLOCAL_PRINTER pPrinter;
-    PRINTER_INFO_1W PrinterInfo1;
-    WCHAR wszComputerName[2 + MAX_COMPUTERNAME_LENGTH + 1 + 1];
-
-    DWORD dwOffsets[] = {
-        FIELD_OFFSET(PRINTER_INFO_1W, pName),
-        FIELD_OFFSET(PRINTER_INFO_1W, pDescription),
-        FIELD_OFFSET(PRINTER_INFO_1W, pComment),
-        MAXDWORD
-    };
+    PWSTR p;
+    PWSTR pwszStrings[3];
+    WCHAR wszComputerName[2 + MAX_COMPUTERNAME_LENGTH + 1 + 1] = { 0 };
 
     if (Flags & PRINTER_ENUM_NAME)
     {
         if (Name)
         {
             // The user supplied a Computer Name (with leading double backslashes) or Print Provider Name.
 
     if (Flags & PRINTER_ENUM_NAME)
     {
         if (Name)
         {
             // The user supplied a Computer Name (with leading double backslashes) or Print Provider Name.
-            // Only process what's directed at us and dismiss every other request with ERROR_INVALID_NAME.
+            // Only process what's directed at us.
             if (Name[0] == L'\\' && Name[1] == L'\\')
             {
             if (Name[0] == L'\\' && Name[1] == L'\\')
             {
-                // Prepend slashes to the computer name.
-                wszComputerName[0] = L'\\';
-                wszComputerName[1] = L'\\';
-
-                // Get the local computer name for comparison.
-                cchComputerName = MAX_COMPUTERNAME_LENGTH + 1;
-                if (!GetComputerNameW(&wszComputerName[2], &cchComputerName))
-                {
-                    dwErrorCode = GetLastError();
-                    ERR("GetComputerNameW failed with error %lu!\n", dwErrorCode);
+                dwErrorCode = _IsLocalComputerName(Name, wszComputerName, &cchComputerName);
+                if (dwErrorCode != ERROR_SUCCESS)
                     goto Cleanup;
                     goto Cleanup;
-                }
-
-                // Add the leading slashes to the total length.
-                cchComputerName += 2;
-
-                // Now compare this with the local computer name and reject if it doesn't match.
-                if (wcsicmp(&Name[2], &wszComputerName[2]) != 0)
-                {
-                    dwErrorCode = ERROR_INVALID_NAME;
-                    goto Cleanup;
-                }
-
-                // Add a trailing backslash to wszComputerName, which will later be prepended in front of the printer names.
-                wszComputerName[cchComputerName++] = L'\\';
-                wszComputerName[cchComputerName] = 0;
             }
             else if (wcsicmp(Name, wszPrintProviderInfo[0]) != 0)
             {
             }
             else if (wcsicmp(Name, wszPrintProviderInfo[0]) != 0)
             {
-                // The user supplied a name that cannot be processed by the local print provider.
+                // The user supplied a name that cannot be processed by the Local Print Provider.
                 dwErrorCode = ERROR_INVALID_NAME;
                 goto Cleanup;
             }
                 dwErrorCode = ERROR_INVALID_NAME;
                 goto Cleanup;
             }
@@ -356,23 +423,7 @@ _LocalEnumPrintersLevel1(DWORD Flags, LPWSTR Name, LPBYTE pPrinterEnum, DWORD cb
         {
             // The caller wants information about this Print Provider.
             // spoolss packs this into an array of information about all Print Providers.
         {
             // The caller wants information about this Print Provider.
             // spoolss packs this into an array of information about all Print Providers.
-            *pcbNeeded = sizeof(PRINTER_INFO_1W);
-
-            for (i = 0; i < 3; i++)
-                *pcbNeeded += (wcslen(wszPrintProviderInfo[i]) + 1) * sizeof(WCHAR);
-
-            // Check if the supplied buffer is large enough.
-            if (cbBuf < *pcbNeeded)
-            {
-                dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
-                goto Cleanup;
-            }
-
-            // Copy over the print processor information.
-            ((PPRINTER_INFO_1W)pPrinterEnum)->Flags = 0;
-            PackStrings(wszPrintProviderInfo, pPrinterEnum, dwOffsets, &pPrinterEnum[*pcbNeeded]);
-            *pcReturned = 1;
-            dwErrorCode = ERROR_SUCCESS;
+            dwErrorCode = _DumpLevel1PrintProviderInformation(pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
             goto Cleanup;
         }
     }
             goto Cleanup;
         }
     }
@@ -384,14 +435,17 @@ _LocalEnumPrintersLevel1(DWORD Flags, LPWSTR Name, LPBYTE pPrinterEnum, DWORD cb
     {
         pPrinter = (PLOCAL_PRINTER)pNode->Element;
 
     {
         pPrinter = (PLOCAL_PRINTER)pNode->Element;
 
-        // This looks wrong, but is totally right. PRINTER_INFO_1W has three members pName, pComment and pDescription.
-        // But pComment equals the "Description" registry value while pDescription is concatenated out of pName and pComment.
+        // TODO: If PRINTER_ENUM_SHARED is given, add this Printer if it's shared instead of just ignoring it.
+        if (Flags & PRINTER_ENUM_SHARED)
+            continue;
+
+        // Attention: pComment equals the "Description" registry value while pDescription is concatenated out of several strings.
         // On top of this, the computer name is prepended to the printer name if the user supplied the local computer name during the query.
         // On top of this, the computer name is prepended to the printer name if the user supplied the local computer name during the query.
-        cbName = (wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
+        cbName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
         cbComment = (wcslen(pPrinter->pwszDescription) + 1) * sizeof(WCHAR);
         cbComment = (wcslen(pPrinter->pwszDescription) + 1) * sizeof(WCHAR);
-        cbDescription = cchComputerName * sizeof(WCHAR) + cbName + cbComment + sizeof(WCHAR);
+        cbDescription = cbName + (wcslen(pPrinter->pwszPrinterDriver) + 1 + wcslen(pPrinter->pwszLocation) + 1) * sizeof(WCHAR);
 
 
-        *pcbNeeded += sizeof(PRINTER_INFO_1W) + cchComputerName * sizeof(WCHAR) + cbName + cbComment + cbDescription;
+        *pcbNeeded += sizeof(PRINTER_INFO_1W) + cbName + cbComment + cbDescription;
         i++;
     }
 
         i++;
     }
 
@@ -402,49 +456,53 @@ _LocalEnumPrintersLevel1(DWORD Flags, LPWSTR Name, LPBYTE pPrinterEnum, DWORD cb
         goto Cleanup;
     }
 
         goto Cleanup;
     }
 
-    // Put the strings right after the last PRINTER_INFO_1W structure.
-    // Due to all the required string processing, we can't just use PackStrings here :(
+    // Initialize the variables for filling the output buffer using PackStrings.
     pPrinterInfo = pPrinterEnum;
     pPrinterInfo = pPrinterEnum;
-    pPrinterString = pPrinterEnum + i * sizeof(PRINTER_INFO_1W);
+    pPrinterStrings = &pPrinterEnum[*pcbNeeded];
 
 
-    // Copy over the printer information.
+    // Copy over the Printer information.
     for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0])
     {
         pPrinter = (PLOCAL_PRINTER)pNode->Element;
 
     for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0])
     {
         pPrinter = (PLOCAL_PRINTER)pNode->Element;
 
-        // FIXME: As for now, the Flags member returns no information.
-        PrinterInfo1.Flags = 0;
+        // TODO: If PRINTER_ENUM_SHARED is given, add this Printer if it's shared instead of just ignoring it.
+        if (Flags & PRINTER_ENUM_SHARED)
+            continue;
 
 
-        // Copy the printer name.
-        PrinterInfo1.pName = (PWSTR)pPrinterString;
-        CopyMemory(pPrinterString, wszComputerName, cchComputerName * sizeof(WCHAR));
-        pPrinterString += cchComputerName * sizeof(WCHAR);
-        cbName = (wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
-        CopyMemory(pPrinterString, pPrinter->pwszPrinterName, cbName);
-        pPrinterString += cbName;
+        // Indicate that this is a Printer.
+        ((PPRINTER_INFO_1W)pPrinterInfo)->Flags = PRINTER_ENUM_ICON8;
 
 
-        // Copy the printer comment (equals the "Description" registry value).
-        PrinterInfo1.pComment = (PWSTR)pPrinterString;
+        // Calculate the string lengths.
+        cbName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
         cbComment = (wcslen(pPrinter->pwszDescription) + 1) * sizeof(WCHAR);
         cbComment = (wcslen(pPrinter->pwszDescription) + 1) * sizeof(WCHAR);
-        CopyMemory(pPrinterString, pPrinter->pwszDescription, cbComment);
-        pPrinterString += cbComment;
-
-        // Copy the description, which for PRINTER_INFO_1W has the form "Name,Comment,"
-        PrinterInfo1.pDescription = (PWSTR)pPrinterString;
-        CopyMemory(pPrinterString, wszComputerName, cchComputerName * sizeof(WCHAR));
-        pPrinterString += cchComputerName * sizeof(WCHAR);
-        CopyMemory(pPrinterString, pPrinter->pwszPrinterName, cbName - sizeof(WCHAR));
-        pPrinterString += cbName - sizeof(WCHAR);
-        CopyMemory(pPrinterString, wszComma, sizeof(WCHAR));
-        pPrinterString += sizeof(WCHAR);
-        CopyMemory(pPrinterString, pPrinter->pwszDescription, cbComment - sizeof(WCHAR));
-        pPrinterString += cbComment - sizeof(WCHAR);
-        CopyMemory(pPrinterString, wszComma, sizeof(wszComma));
-        pPrinterString += sizeof(wszComma);
-                
+        cbDescription = cbName + (wcslen(pPrinter->pwszPrinterDriver) + 1 + wcslen(pPrinter->pwszLocation) + 1) * sizeof(WCHAR);
+
+        // Copy the Printer Name.
+        pwszStrings[0] = DllAllocSplMem(cbName);
+        p = pwszStrings[0];
+        StringCbCopyExW(p, cbName, wszComputerName, &p, &cbName, 0);
+        StringCbCopyExW(p, cbName, pPrinter->pwszPrinterName, &p, &cbName, 0);
+
+        // Copy the Printer comment (equals the "Description" registry value).
+        pwszStrings[1] = pPrinter->pwszDescription;
+
+        // Copy the description, which for PRINTER_INFO_1W has the form "Name,Printer Driver,Location"
+        pwszStrings[2] = DllAllocSplMem(cbDescription);
+        p = pwszStrings[2];
+        StringCbCopyExW(p, cbDescription, wszComputerName, &p, &cbDescription, 0);
+        StringCbCopyExW(p, cbDescription, pPrinter->pwszPrinterName, &p, &cbDescription, 0);
+        StringCbCopyExW(p, cbDescription, wszComma, &p, &cbDescription, 0);
+        StringCbCopyExW(p, cbDescription, pPrinter->pwszPrinterDriver, &p, &cbDescription, 0);
+        StringCbCopyExW(p, cbDescription, wszComma, &p, &cbDescription, 0);
+        StringCbCopyExW(p, cbDescription, pPrinter->pwszLocation, &p, &cbDescription, 0);
+
         // Finally copy the structure and advance to the next one in the output buffer.
         // Finally copy the structure and advance to the next one in the output buffer.
-        CopyMemory(pPrinterInfo, &PrinterInfo1, sizeof(PRINTER_INFO_1W));
+        pPrinterStrings = PackStrings(pwszStrings, pPrinterInfo, dwPrinterInfo1Offsets, pPrinterStrings);
         pPrinterInfo += sizeof(PRINTER_INFO_1W);
         pPrinterInfo += sizeof(PRINTER_INFO_1W);
+
+        // Free the memory for temporary strings.
+        DllFreeSplMem(pwszStrings[0]);
+        DllFreeSplMem(pwszStrings[2]);
     }
 
     *pcReturned = i;
     }
 
     *pcReturned = i;
@@ -454,6 +512,24 @@ Cleanup:
     return dwErrorCode;
 }
 
     return dwErrorCode;
 }
 
+static DWORD
+_LocalEnumPrintersLevel2(DWORD Flags, PCWSTR Name, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+    return ERROR_INVALID_LEVEL;
+}
+
+static DWORD
+_LocalEnumPrintersLevel4(DWORD Flags, PCWSTR Name, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+    return ERROR_INVALID_LEVEL;
+}
+
+static DWORD
+_LocalEnumPrintersLevel5(DWORD Flags, PCWSTR Name, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
+{
+    return ERROR_INVALID_LEVEL;
+}
+
 BOOL WINAPI
 LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
 {
 BOOL WINAPI
 LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
 {
@@ -465,24 +541,47 @@ LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DW
     *pcbNeeded = 0;
     *pcReturned = 0;
 
     *pcbNeeded = 0;
     *pcReturned = 0;
 
-    // Think positive :)
-    // Treat it as success if the caller queried no information and we don't need to return any.
-    dwErrorCode = ERROR_SUCCESS;
+    if (Flags & PRINTER_ENUM_CONNECTIONS || Flags & PRINTER_ENUM_REMOTE || Flags & PRINTER_ENUM_NETWORK)
+    {
+        // If the flags for the Network Print Provider are given, bail out with ERROR_INVALID_NAME.
+        // This is the internal way for a Print Provider to signal that it doesn't handle this request.
+        dwErrorCode = ERROR_INVALID_NAME;
+        goto Cleanup;
+    }
 
 
-    if (Flags & PRINTER_ENUM_LOCAL)
+    if (!(Flags & PRINTER_ENUM_LOCAL || Flags & PRINTER_ENUM_NAME))
     {
     {
-        // The function behaves quite differently for each level.
-        if (Level == 1)
-        {
-            dwErrorCode = _LocalEnumPrintersLevel1(Flags, Name, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
-        }
-        else
-        {
-            // TODO: Handle other levels.
-            // The caller supplied an invalid level.
-            dwErrorCode = ERROR_INVALID_LEVEL;
-            goto Cleanup;
-        }
+        // The Local Print Provider is the right destination for the request, but without any of these flags,
+        // there is no information that can be returned.
+        // So just signal a successful request.
+        dwErrorCode = ERROR_SUCCESS;
+        goto Cleanup;
+    }
+
+    if (Level == 0)
+    {
+        dwErrorCode = _LocalEnumPrintersLevel0(Flags, Name, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
+    }
+    else if (Level == 1)
+    {
+        dwErrorCode = _LocalEnumPrintersLevel1(Flags, Name, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
+    }
+    else if (Level == 2)
+    {
+        dwErrorCode = _LocalEnumPrintersLevel2(Flags, Name, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
+    }
+    else if (Level == 4)
+    {
+        dwErrorCode = _LocalEnumPrintersLevel4(Flags, Name, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
+    }
+    else if (Level == 5)
+    {
+        dwErrorCode = _LocalEnumPrintersLevel5(Flags, Name, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
+    }
+    else
+    {
+        // The caller supplied an invalid level.
+        dwErrorCode = ERROR_INVALID_LEVEL;
     }
 
 Cleanup:
     }
 
 Cleanup:
index 66214d2..1b994c6 100644 (file)
@@ -160,10 +160,7 @@ InitializePrintProcessorList()
     // Open the environment registry key.
     dwErrorCode = _OpenEnvironment(wszCurrentEnvironment, &hKey);
     if (dwErrorCode != ERROR_SUCCESS)
     // Open the environment registry key.
     dwErrorCode = _OpenEnvironment(wszCurrentEnvironment, &hKey);
     if (dwErrorCode != ERROR_SUCCESS)
-    {
-        ERR("_OpenEnvironment failed with error %lu!\n", dwErrorCode);
         goto Cleanup;
         goto Cleanup;
-    }
 
     // Open the "Print Processors" subkey.
     dwErrorCode = (DWORD)RegOpenKeyExW(hKey, L"Print Processors", 0, KEY_READ, &hSubKey);
 
     // Open the "Print Processors" subkey.
     dwErrorCode = (DWORD)RegOpenKeyExW(hKey, L"Print Processors", 0, KEY_READ, &hSubKey);
@@ -494,10 +491,7 @@ LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE
     // We use the registry and not the PrintProcessorList here, because the caller may request information about a different environment.
     dwErrorCode = _OpenEnvironment(pEnvironment, &hKey);
     if (dwErrorCode != ERROR_SUCCESS)
     // We use the registry and not the PrintProcessorList here, because the caller may request information about a different environment.
     dwErrorCode = _OpenEnvironment(pEnvironment, &hKey);
     if (dwErrorCode != ERROR_SUCCESS)
-    {
-        ERR("_OpenEnvironment failed with error %lu!\n", dwErrorCode);
         goto Cleanup;
         goto Cleanup;
-    }
 
     // Open the "Print Processors" subkey.
     dwErrorCode = (DWORD)RegOpenKeyExW(hKey, L"Print Processors", 0, KEY_READ, &hSubKey);
 
     // Open the "Print Processors" subkey.
     dwErrorCode = (DWORD)RegOpenKeyExW(hKey, L"Print Processors", 0, KEY_READ, &hSubKey);
index 82cb5e7..7b1bf58 100644 (file)
@@ -2,7 +2,7 @@
  * PROJECT:     ReactOS Local Spooler API Tests Injected DLL
  * LICENSE:     GNU GPLv2 or any later version as published by the Free Software Foundation
  * PURPOSE:     Tests for fpEnumPrinters
  * PROJECT:     ReactOS Local Spooler API Tests Injected DLL
  * LICENSE:     GNU GPLv2 or any later version as published by the Free Software Foundation
  * PURPOSE:     Tests for fpEnumPrinters
- * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
+ * COPYRIGHT:   Copyright 2015-2017 Colin Finck <colin@reactos.org>
  */
 
 #include <apitest.h>
  */
 
 #include <apitest.h>
@@ -22,6 +22,8 @@ extern BOOL GetLocalsplFuncs(LPPRINTPROVIDOR pp);
 
 START_TEST(fpEnumPrinters)
 {
 
 START_TEST(fpEnumPrinters)
 {
+    BYTE TempBuffer[50];
+    BYTE ZeroBuffer[50];
     DWORD cbNeeded;
     DWORD cbTemp;
     DWORD dwReturned;
     DWORD cbNeeded;
     DWORD cbTemp;
     DWORD dwReturned;
@@ -33,18 +35,30 @@ START_TEST(fpEnumPrinters)
     if (!GetLocalsplFuncs(&pp))
         return;
 
     if (!GetLocalsplFuncs(&pp))
         return;
 
+    // Verify that fpEnumPrinters returns success and zeros cbNeeded and dwReturned (but not TempBuffer!) if no flag has been specified.
+    memset(TempBuffer, 0xDE, sizeof(TempBuffer));
+    memset(ZeroBuffer, 0, sizeof(ZeroBuffer));
+    cbNeeded = 0xDEADBEEF;
+    dwReturned = 0xDEADBEEF;
+    SetLastError(0xDEADBEEF);
+    ok(pp.fpEnumPrinters(0, NULL, 1, TempBuffer, sizeof(TempBuffer), &cbNeeded, &dwReturned), "fpEnumPrinters returns FALSE\n");
+    ok(GetLastError() == ERROR_SUCCESS, "fpEnumPrinters returns error %lu!\n", GetLastError());
+    ok(memcmp(TempBuffer, ZeroBuffer, sizeof(TempBuffer)) != 0, "TempBuffer has been zeroed!\n");
+    ok(cbNeeded == 0, "cbNeeded is %lu!\n", cbNeeded);
+    ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
     // Verify that localspl only returns information about a single print provider (namely itself).
     cbNeeded = 0xDEADBEEF;
     dwReturned = 0xDEADBEEF;
     SetLastError(0xDEADBEEF);
     // Verify that localspl only returns information about a single print provider (namely itself).
     cbNeeded = 0xDEADBEEF;
     dwReturned = 0xDEADBEEF;
     SetLastError(0xDEADBEEF);
-    ok(!pp.fpEnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, NULL, 1, NULL, 0, &cbNeeded, &dwReturned), "fpEnumPrinters returns TRUE\n");
+    ok(!pp.fpEnumPrinters(PRINTER_ENUM_NAME, NULL, 1, NULL, 0, &cbNeeded, &dwReturned), "fpEnumPrinters returns TRUE\n");
     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "fpEnumPrinters returns error %lu!\n", GetLastError());
     ok(cbNeeded > 0, "cbNeeded is 0!\n");
     ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
 
     SetLastError(0xDEADBEEF);
     pPrinterInfo1 = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "fpEnumPrinters returns error %lu!\n", GetLastError());
     ok(cbNeeded > 0, "cbNeeded is 0!\n");
     ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
 
     SetLastError(0xDEADBEEF);
     pPrinterInfo1 = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
-    ok(pp.fpEnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME, NULL, 1, (PBYTE)pPrinterInfo1, cbNeeded, &cbNeeded, &dwReturned), "fpEnumPrinters returns FALSE\n");
+    ok(pp.fpEnumPrinters(PRINTER_ENUM_NAME, NULL, 1, (PBYTE)pPrinterInfo1, cbNeeded, &cbNeeded, &dwReturned), "fpEnumPrinters returns FALSE\n");
     ok(GetLastError() == ERROR_SUCCESS, "fpEnumPrinters returns error %lu!\n", GetLastError());
     ok(cbNeeded > 0, "cbNeeded is 0!\n");
     ok(dwReturned == 1, "dwReturned is %lu!\n", dwReturned);
     ok(GetLastError() == ERROR_SUCCESS, "fpEnumPrinters returns error %lu!\n", GetLastError());
     ok(cbNeeded > 0, "cbNeeded is 0!\n");
     ok(dwReturned == 1, "dwReturned is %lu!\n", dwReturned);
index f199f60..7223fc4 100644 (file)
@@ -2,7 +2,7 @@
  * PROJECT:     ReactOS Print Spooler DLL API Tests
  * LICENSE:     GNU GPLv2 or any later version as published by the Free Software Foundation
  * PURPOSE:     Tests for EnumPrintersA/EnumPrintersW
  * PROJECT:     ReactOS Print Spooler DLL API Tests
  * LICENSE:     GNU GPLv2 or any later version as published by the Free Software Foundation
  * PURPOSE:     Tests for EnumPrintersA/EnumPrintersW
- * COPYRIGHT:   Copyright 2015 Colin Finck <colin@reactos.org>
+ * COPYRIGHT:   Copyright 2015-2017 Colin Finck <colin@reactos.org>
  */
 
 #include <apitest.h>
  */
 
 #include <apitest.h>
@@ -15,6 +15,8 @@
 
 START_TEST(EnumPrinters)
 {
 
 START_TEST(EnumPrinters)
 {
+    BYTE TempBuffer[50];
+    BYTE ZeroBuffer[50] = { 0 };
     DWORD cbNeeded;
     DWORD cbTemp;
     DWORD dwReturned;
     DWORD cbNeeded;
     DWORD cbTemp;
     DWORD dwReturned;
@@ -22,6 +24,17 @@ START_TEST(EnumPrinters)
     DWORD i;
     DWORD dwValidLevels[] = { 0, 1, 2, 4, 5 };
 
     DWORD i;
     DWORD dwValidLevels[] = { 0, 1, 2, 4, 5 };
 
+    // Verify that EnumPrintersW returns success and zeroes all input variables even though no flag has been specified.
+    memset(TempBuffer, 0xDE, sizeof(TempBuffer));
+    cbNeeded = 0xDEADBEEF;
+    dwReturned = 0xDEADBEEF;
+    SetLastError(0xDEADBEEF);
+    ok(EnumPrintersW(0, NULL, 1, TempBuffer, sizeof(TempBuffer), &cbNeeded, &dwReturned), "EnumPrintersW returns FALSE\n");
+    ok(GetLastError() == ERROR_SUCCESS, "EnumPrintersW returns error %lu!\n", GetLastError());
+    ok(memcmp(TempBuffer, ZeroBuffer, sizeof(TempBuffer)) == 0, "TempBuffer has not been zeroed!\n");
+    ok(cbNeeded == 0, "cbNeeded is %lu!\n", cbNeeded);
+    ok(dwReturned == 0, "dwReturned is %lu!\n", dwReturned);
+
     // Level 5 is the highest supported under Windows Server 2003. Higher levels need to fail and leave the variables untouched!
     cbNeeded = 0xDEADBEEF;
     dwReturned = 0xDEADBEEF;
     // Level 5 is the highest supported under Windows Server 2003. Higher levels need to fail and leave the variables untouched!
     cbNeeded = 0xDEADBEEF;
     dwReturned = 0xDEADBEEF;
@@ -69,7 +82,7 @@ START_TEST(EnumPrinters)
         ok(cbNeeded > 0, "cbNeeded is 0 for Level %lu!\n", dwValidLevels[i]);
         ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, dwValidLevels[i]);
 
         ok(cbNeeded > 0, "cbNeeded is 0 for Level %lu!\n", dwValidLevels[i]);
         ok(dwReturned == 0, "dwReturned is %lu for Level %lu!\n", dwReturned, dwValidLevels[i]);
 
-        // Same error has to occur with a size to small.
+        // Same error has to occur with no buffer, but a size < 4 (AlignRpcPtr comes into play here).
         SetLastError(0xDEADBEEF);
         ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, dwValidLevels[i], NULL, 1, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", dwValidLevels[i]);
         ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), dwValidLevels[i]);
         SetLastError(0xDEADBEEF);
         ok(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, dwValidLevels[i], NULL, 1, &cbNeeded, &dwReturned), "EnumPrintersW returns TRUE for Level %lu!\n", dwValidLevels[i]);
         ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "EnumPrintersW returns error %lu for Level %lu!\n", GetLastError(), dwValidLevels[i]);