From: Colin Finck Date: Sun, 16 Apr 2017 14:12:01 +0000 (+0000) Subject: [LOCALSPL] X-Git-Tag: ReactOS-0.4.5~110 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=cb609f0b17a4b73e7bcaa1881b420a4e1becdf1b;hp=c860e2b80d195ace6a3ddc2f4203148974a82d1d [LOCALSPL] - 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 --- diff --git a/reactos/boot/bootdata/hivesys.inf b/reactos/boot/bootdata/hivesys.inf index 5fd95fbd6df..c12dabfea21 100644 --- a/reactos/boot/bootdata/hivesys.inf +++ b/reactos/boot/bootdata/hivesys.inf @@ -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 +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" diff --git a/reactos/win32ss/printing/base/spoolss/printers.c b/reactos/win32ss/printing/base/spoolss/printers.c index 2bbf698e3ae..51e3f871878 100644 --- a/reactos/win32ss/printing/base/spoolss/printers.c +++ b/reactos/win32ss/printing/base/spoolss/printers.c @@ -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 - * COPYRIGHT: Copyright 2015 Colin Finck + * COPYRIGHT: Copyright 2015-2017 Colin Finck */ #include "precomp.h" @@ -68,27 +68,27 @@ EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cb BOOL bReturnValue; DWORD cbCallBuffer; DWORD cbNeeded; + DWORD dwErrorCode = 0xFFFFFFFF; 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; + if (cbBuf && !pPrinterEnum) + { + dwErrorCode = ERROR_INVALID_USER_BUFFER; + goto Cleanup; + } + // 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); @@ -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; + + // 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 @@ -148,6 +154,7 @@ BOOL WINAPI 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; @@ -156,8 +163,8 @@ OpenPrinterW(PWSTR pPrinterName, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault) // 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. @@ -173,27 +180,33 @@ OpenPrinterW(PWSTR pPrinterName, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault) pHandle = DllAllocSplMem(sizeof(SPOOLSS_PRINTER_HANDLE)); if (!pHandle) { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); 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; - 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); - 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 diff --git a/reactos/win32ss/printing/base/spoolsv/precomp.h b/reactos/win32ss/printing/base/spoolsv/precomp.h index b882f9888fc..8efb51c0035 100644 --- a/reactos/win32ss/printing/base/spoolsv/precomp.h +++ b/reactos/win32ss/printing/base/spoolsv/precomp.h @@ -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 - * COPYRIGHT: Copyright 2015 Colin Finck + * COPYRIGHT: Copyright 2015-2017 Colin Finck */ #ifndef _PRECOMP_H @@ -18,14 +18,12 @@ #include #include +#include + #include WINE_DEFAULT_DEBUG_CHANNEL(spoolsv); // rpcserver.c DWORD WINAPI LrpcThreadProc(LPVOID lpParameter); -// Undocumented spoolss -BOOL WINAPI InitializeRouter(HANDLE SpoolerStatusHandle); -DWORD WINAPI SpoolerInit(); - #endif diff --git a/reactos/win32ss/printing/base/spoolsv/printers.c b/reactos/win32ss/printing/base/spoolsv/printers.c index fb20f04f411..1468faa1aa8 100644 --- a/reactos/win32ss/printing/base/spoolsv/printers.c +++ b/reactos/win32ss/printing/base/spoolsv/printers.c @@ -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 - * COPYRIGHT: Copyright 2015 Colin Finck + * COPYRIGHT: Copyright 2015-2017 Colin Finck */ #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; - DWORD i; - PBYTE p = pPrinterEnum; + PBYTE pPrinterEnumAligned; dwErrorCode = RpcImpersonateClient(NULL); if (dwErrorCode != ERROR_SUCCESS) @@ -147,11 +146,15 @@ _RpcEnumPrinters(DWORD Flags, WINSPOOL_HANDLE Name, DWORD Level, BYTE* pPrinterE 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) { + DWORD i; + PBYTE p = pPrinterEnumAligned; + // 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(); + UndoAlignRpcPtr(pPrinterEnum, pPrinterEnumAligned, cbBuf, pcbNeeded); + return dwErrorCode; } diff --git a/reactos/win32ss/printing/base/winspool/printers.c b/reactos/win32ss/printing/base/winspool/printers.c index c82132c1bf8..ffa965f7067 100644 --- a/reactos/win32ss/printing/base/winspool/printers.c +++ b/reactos/win32ss/printing/base/winspool/printers.c @@ -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 - * COPYRIGHT: Copyright 2015 Colin Finck + * COPYRIGHT: Copyright 2015-2017 Colin Finck */ #include "precomp.h" @@ -309,6 +309,16 @@ EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cb 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 { @@ -335,6 +345,7 @@ EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cb } } +Cleanup: SetLastError(dwErrorCode); return (dwErrorCode == ERROR_SUCCESS); } diff --git a/reactos/win32ss/printing/include/spoolss.h b/reactos/win32ss/printing/include/spoolss.h index e43c3460937..af7436d73f1 100644 --- a/reactos/win32ss/printing/include/spoolss.h +++ b/reactos/win32ss/printing/include/spoolss.h @@ -24,11 +24,13 @@ PWSTR WINAPI AllocSplStr(PCWSTR pwszInput); 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); +DWORD WINAPI SpoolerInit(); PDWORD WINAPI UndoAlignRpcPtr(PVOID pDestinationBuffer, PVOID pSourceBuffer, DWORD cbBuffer, PDWORD pcbNeeded); #endif diff --git a/reactos/win32ss/printing/providers/localspl/main.c b/reactos/win32ss/printing/providers/localspl/main.c index aada4a9abc9..458edba2318 100644 --- a/reactos/win32ss/printing/providers/localspl/main.c +++ b/reactos/win32ss/printing/providers/localspl/main.c @@ -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 - * COPYRIGHT: Copyright 2015-2016 Colin Finck + * COPYRIGHT: Copyright 2015-2017 Colin Finck */ #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 - L"Windows NT Local Printers", // Description - L"Locally connected Printers" // Comment + L"Locally connected Printers", // Comment + L"Windows NT Local Printers" // Description }; // Local Constants diff --git a/reactos/win32ss/printing/providers/localspl/precomp.h b/reactos/win32ss/printing/providers/localspl/precomp.h index c8728535b7e..98e219b24a2 100644 --- a/reactos/win32ss/printing/providers/localspl/precomp.h +++ b/reactos/win32ss/printing/providers/localspl/precomp.h @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -114,6 +115,7 @@ struct _LOCAL_PRINTER DWORD dwAttributes; DWORD dwStatus; + PWSTR pwszLocation; PWSTR pwszPrinterDriver; PWSTR pwszDescription; PWSTR pwszDefaultDatatype; diff --git a/reactos/win32ss/printing/providers/localspl/printers.c b/reactos/win32ss/printing/providers/localspl/printers.c index f7f941072bd..8a8056cc3a1 100644 --- a/reactos/win32ss/printing/providers/localspl/printers.c +++ b/reactos/win32ss/printing/providers/localspl/printers.c @@ -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 - * COPYRIGHT: Copyright 2015 Colin Finck + * COPYRIGHT: Copyright 2015-2017 Colin Finck */ #include "precomp.h" @@ -10,6 +10,13 @@ // 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 @@ -170,6 +177,11 @@ InitializePrinterList() 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) @@ -284,9 +296,93 @@ Cleanup: 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","; @@ -297,57 +393,28 @@ _LocalEnumPrintersLevel1(DWORD Flags, LPWSTR Name, LPBYTE pPrinterEnum, DWORD cb DWORD dwErrorCode; DWORD i; PBYTE pPrinterInfo; - PBYTE pPrinterString; + PBYTE pPrinterStrings; 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. - // 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'\\') { - // 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; - } - - // 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) { - // 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; } @@ -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. - *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; } } @@ -384,14 +435,17 @@ _LocalEnumPrintersLevel1(DWORD Flags, LPWSTR Name, LPBYTE pPrinterEnum, DWORD cb { 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. - cbName = (wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR); + cbName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 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++; } @@ -402,49 +456,53 @@ _LocalEnumPrintersLevel1(DWORD Flags, LPWSTR Name, LPBYTE pPrinterEnum, DWORD cb 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; - 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; - // 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); - 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. - CopyMemory(pPrinterInfo, &PrinterInfo1, sizeof(PRINTER_INFO_1W)); + pPrinterStrings = PackStrings(pwszStrings, pPrinterInfo, dwPrinterInfo1Offsets, pPrinterStrings); pPrinterInfo += sizeof(PRINTER_INFO_1W); + + // Free the memory for temporary strings. + DllFreeSplMem(pwszStrings[0]); + DllFreeSplMem(pwszStrings[2]); } *pcReturned = i; @@ -454,6 +512,24 @@ Cleanup: 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) { @@ -465,24 +541,47 @@ LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DW *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: diff --git a/reactos/win32ss/printing/providers/localspl/printprocessors.c b/reactos/win32ss/printing/providers/localspl/printprocessors.c index 66214d22ceb..1b994c65b09 100644 --- a/reactos/win32ss/printing/providers/localspl/printprocessors.c +++ b/reactos/win32ss/printing/providers/localspl/printprocessors.c @@ -160,10 +160,7 @@ InitializePrintProcessorList() // Open the environment registry key. dwErrorCode = _OpenEnvironment(wszCurrentEnvironment, &hKey); if (dwErrorCode != ERROR_SUCCESS) - { - ERR("_OpenEnvironment failed with error %lu!\n", dwErrorCode); goto Cleanup; - } // 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) - { - ERR("_OpenEnvironment failed with error %lu!\n", dwErrorCode); goto Cleanup; - } // Open the "Print Processors" subkey. dwErrorCode = (DWORD)RegOpenKeyExW(hKey, L"Print Processors", 0, KEY_READ, &hSubKey); diff --git a/rostests/apitests/localspl/dll/fpEnumPrinters.c b/rostests/apitests/localspl/dll/fpEnumPrinters.c index 82cb5e7a8a6..7b1bf584af9 100644 --- a/rostests/apitests/localspl/dll/fpEnumPrinters.c +++ b/rostests/apitests/localspl/dll/fpEnumPrinters.c @@ -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 - * COPYRIGHT: Copyright 2015 Colin Finck + * COPYRIGHT: Copyright 2015-2017 Colin Finck */ #include @@ -22,6 +22,8 @@ extern BOOL GetLocalsplFuncs(LPPRINTPROVIDOR pp); START_TEST(fpEnumPrinters) { + BYTE TempBuffer[50]; + BYTE ZeroBuffer[50]; DWORD cbNeeded; DWORD cbTemp; DWORD dwReturned; @@ -33,18 +35,30 @@ START_TEST(fpEnumPrinters) 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); - 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(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); diff --git a/rostests/apitests/winspool/EnumPrinters.c b/rostests/apitests/winspool/EnumPrinters.c index f199f60abad..7223fc46d12 100644 --- a/rostests/apitests/winspool/EnumPrinters.c +++ b/rostests/apitests/winspool/EnumPrinters.c @@ -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 - * COPYRIGHT: Copyright 2015 Colin Finck + * COPYRIGHT: Copyright 2015-2017 Colin Finck */ #include @@ -15,6 +15,8 @@ START_TEST(EnumPrinters) { + BYTE TempBuffer[50]; + BYTE ZeroBuffer[50] = { 0 }; DWORD cbNeeded; DWORD cbTemp; DWORD dwReturned; @@ -22,6 +24,17 @@ START_TEST(EnumPrinters) 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; @@ -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]); - // 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]);