From 30d5e8f413f4da2a7d37fe6b66fe2f94104b3d8f Mon Sep 17 00:00:00 2001 From: Colin Finck Date: Sun, 30 Apr 2017 15:12:53 +0000 Subject: [PATCH] [LOCALSPL] [SPOOLSV] [WINSPOOL] - Refactor the code returning PRINTER_INFO_* yet another time to support both EnumPrinters and GetPrinter calls. - Implement support for PRINTER_INFO_1 through PRINTER_INFO_9 as well as the mostly unknown PRINTER_INFO_STRESS (level 0) structure and return as much information as we can. - Implement GetPrinterW / LocalGetPrinter. The Printers Shell folder in Explorer now shows our "Dummy Printer on LPT1" and we pass all 291 winspool:EnumPrinters API tests :) svn path=/trunk/; revision=74433 --- .../win32ss/printing/base/spoolsv/printers.c | 121 +++- .../win32ss/printing/base/winspool/precomp.h | 4 +- .../win32ss/printing/base/winspool/printers.c | 134 +++- reactos/win32ss/printing/include/spoolss.h | 35 ++ .../printing/providers/localspl/main.c | 2 +- .../printing/providers/localspl/precomp.h | 3 +- .../printing/providers/localspl/printers.c | 572 +++++++++++++++--- 7 files changed, 731 insertions(+), 140 deletions(-) diff --git a/reactos/win32ss/printing/base/spoolsv/printers.c b/reactos/win32ss/printing/base/spoolsv/printers.c index 1468faa1aa8..75872d2b404 100644 --- a/reactos/win32ss/printing/base/spoolsv/printers.c +++ b/reactos/win32ss/printing/base/spoolsv/printers.c @@ -8,23 +8,33 @@ #include "precomp.h" static void -_MarshallDownPrinterInfo(PBYTE pPrinterInfo, DWORD Level) +_MarshallDownPrinterInfo(PBYTE* ppPrinterInfo, DWORD Level) { - PPRINTER_INFO_1W pPrinterInfo1; - PPRINTER_INFO_2W pPrinterInfo2; - // Replace absolute pointer addresses in the output by relative offsets. - if (Level == 1) + if (Level == 0) { - pPrinterInfo1 = (PPRINTER_INFO_1W)pPrinterInfo; + PPRINTER_INFO_STRESS pPrinterInfo0 = (PPRINTER_INFO_STRESS)(*ppPrinterInfo); + + pPrinterInfo0->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo0->pPrinterName - (ULONG_PTR)pPrinterInfo0); + + if (pPrinterInfo0->pServerName) + pPrinterInfo0->pServerName = (PWSTR)((ULONG_PTR)pPrinterInfo0->pServerName - (ULONG_PTR)pPrinterInfo0); + + *ppPrinterInfo += sizeof(PRINTER_INFO_STRESS); + } + else if (Level == 1) + { + PPRINTER_INFO_1W pPrinterInfo1 = (PPRINTER_INFO_1W)(*ppPrinterInfo); pPrinterInfo1->pName = (PWSTR)((ULONG_PTR)pPrinterInfo1->pName - (ULONG_PTR)pPrinterInfo1); pPrinterInfo1->pDescription = (PWSTR)((ULONG_PTR)pPrinterInfo1->pDescription - (ULONG_PTR)pPrinterInfo1); pPrinterInfo1->pComment = (PWSTR)((ULONG_PTR)pPrinterInfo1->pComment - (ULONG_PTR)pPrinterInfo1); + + *ppPrinterInfo += sizeof(PRINTER_INFO_1W); } else if (Level == 2) { - pPrinterInfo2 = (PPRINTER_INFO_2W)pPrinterInfo; + PPRINTER_INFO_2W pPrinterInfo2 = (PPRINTER_INFO_2W)(*ppPrinterInfo); pPrinterInfo2->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPrinterName - (ULONG_PTR)pPrinterInfo2); pPrinterInfo2->pShareName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pShareName - (ULONG_PTR)pPrinterInfo2); @@ -42,7 +52,66 @@ _MarshallDownPrinterInfo(PBYTE pPrinterInfo, DWORD Level) pPrinterInfo2->pServerName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pServerName - (ULONG_PTR)pPrinterInfo2); if (pPrinterInfo2->pSecurityDescriptor) - pPrinterInfo2->pSecurityDescriptor = (PWSTR)((ULONG_PTR)pPrinterInfo2->pSecurityDescriptor - (ULONG_PTR)pPrinterInfo2); + pPrinterInfo2->pSecurityDescriptor = (PSECURITY_DESCRIPTOR)((ULONG_PTR)pPrinterInfo2->pSecurityDescriptor - (ULONG_PTR)pPrinterInfo2); + + *ppPrinterInfo += sizeof(PRINTER_INFO_2W); + } + else if (Level == 3) + { + PPRINTER_INFO_3 pPrinterInfo3 = (PPRINTER_INFO_3)(*ppPrinterInfo); + + pPrinterInfo3->pSecurityDescriptor = (PSECURITY_DESCRIPTOR)((ULONG_PTR)pPrinterInfo3->pSecurityDescriptor - (ULONG_PTR)pPrinterInfo3); + + *ppPrinterInfo += sizeof(PRINTER_INFO_3); + } + else if (Level == 4) + { + PPRINTER_INFO_4W pPrinterInfo4 = (PPRINTER_INFO_4W)(*ppPrinterInfo); + + pPrinterInfo4->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo4->pPrinterName - (ULONG_PTR)pPrinterInfo4); + + if (pPrinterInfo4->pServerName) + pPrinterInfo4->pServerName = (PWSTR)((ULONG_PTR)pPrinterInfo4->pServerName - (ULONG_PTR)pPrinterInfo4); + + *ppPrinterInfo += sizeof(PRINTER_INFO_4W); + } + else if (Level == 5) + { + PPRINTER_INFO_5W pPrinterInfo5 = (PPRINTER_INFO_5W)(*ppPrinterInfo); + + pPrinterInfo5->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo5->pPrinterName - (ULONG_PTR)pPrinterInfo5); + pPrinterInfo5->pPortName = (PWSTR)((ULONG_PTR)pPrinterInfo5->pPortName - (ULONG_PTR)pPrinterInfo5); + + *ppPrinterInfo += sizeof(PRINTER_INFO_5W); + } + else if (Level == 6) + { + *ppPrinterInfo += sizeof(PRINTER_INFO_6); + } + else if (Level == 7) + { + PPRINTER_INFO_7W pPrinterInfo7 = (PPRINTER_INFO_7W)(*ppPrinterInfo); + + if (pPrinterInfo7->pszObjectGUID) + pPrinterInfo7->pszObjectGUID = (PWSTR)((ULONG_PTR)pPrinterInfo7->pszObjectGUID - (ULONG_PTR)pPrinterInfo7); + + *ppPrinterInfo += sizeof(PRINTER_INFO_7W); + } + else if (Level == 8) + { + PPRINTER_INFO_8W pPrinterInfo8 = (PPRINTER_INFO_8W)(*ppPrinterInfo); + + pPrinterInfo8->pDevMode = (PDEVMODEW)((ULONG_PTR)pPrinterInfo8->pDevMode - (ULONG_PTR)pPrinterInfo8); + + *ppPrinterInfo += sizeof(PRINTER_INFO_8W); + } + else if (Level == 9) + { + PPRINTER_INFO_9W pPrinterInfo9 = (PPRINTER_INFO_9W)(*ppPrinterInfo); + + pPrinterInfo9->pDevMode = (PDEVMODEW)((ULONG_PTR)pPrinterInfo9->pDevMode - (ULONG_PTR)pPrinterInfo9); + + *ppPrinterInfo += sizeof(PRINTER_INFO_9W); } } @@ -155,16 +224,8 @@ _RpcEnumPrinters(DWORD Flags, WINSPOOL_HANDLE Name, DWORD Level, BYTE* pPrinterE DWORD i; PBYTE p = pPrinterEnumAligned; - // Replace absolute pointer addresses in the output by relative offsets. for (i = 0; i < *pcReturned; i++) - { - _MarshallDownPrinterInfo(p, Level); - - if (Level == 1) - p += sizeof(PRINTER_INFO_1W); - else if (Level == 2) - p += sizeof(PRINTER_INFO_2W); - } + _MarshallDownPrinterInfo(&p, Level); } RpcRevertToSelf(); @@ -183,8 +244,30 @@ _RpcFlushPrinter(WINSPOOL_PRINTER_HANDLE hPrinter, BYTE* pBuf, DWORD cbBuf, DWOR DWORD _RpcGetPrinter(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD Level, BYTE* pPrinter, DWORD cbBuf, DWORD* pcbNeeded) { - UNIMPLEMENTED; - return ERROR_INVALID_FUNCTION; + DWORD dwErrorCode; + PBYTE pPrinterAligned; + + dwErrorCode = RpcImpersonateClient(NULL); + if (dwErrorCode != ERROR_SUCCESS) + { + ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode); + return dwErrorCode; + } + + pPrinterAligned = AlignRpcPtr(pPrinter, &cbBuf); + GetPrinterW(hPrinter, Level, pPrinterAligned, cbBuf, pcbNeeded); + dwErrorCode = GetLastError(); + + if (dwErrorCode == ERROR_SUCCESS) + { + PBYTE p = pPrinterAligned; + _MarshallDownPrinterInfo(&p, Level); + } + + RpcRevertToSelf(); + UndoAlignRpcPtr(pPrinter, pPrinterAligned, cbBuf, pcbNeeded); + + return dwErrorCode; } DWORD diff --git a/reactos/win32ss/printing/base/winspool/precomp.h b/reactos/win32ss/printing/base/winspool/precomp.h index df5588a6770..f5fc05ee168 100644 --- a/reactos/win32ss/printing/base/winspool/precomp.h +++ b/reactos/win32ss/printing/base/winspool/precomp.h @@ -2,7 +2,7 @@ * PROJECT: ReactOS Print Spooler API * LICENSE: GNU LGPL v2.1 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 @@ -16,6 +16,8 @@ #include #include +#include + #include WINE_DEFAULT_DEBUG_CHANNEL(winspool); diff --git a/reactos/win32ss/printing/base/winspool/printers.c b/reactos/win32ss/printing/base/winspool/printers.c index ffa965f7067..a34a43fa60e 100644 --- a/reactos/win32ss/printing/base/winspool/printers.c +++ b/reactos/win32ss/printing/base/winspool/printers.c @@ -8,23 +8,33 @@ #include "precomp.h" static void -_MarshallUpPrinterInfo(PBYTE pPrinterInfo, DWORD Level) +_MarshallUpPrinterInfo(PBYTE* ppPrinterInfo, DWORD Level) { - PPRINTER_INFO_1W pPrinterInfo1; - PPRINTER_INFO_2W pPrinterInfo2; + // Replace relative offset addresses in the output by absolute pointers and advance to the next structure. + if (Level == 0) + { + PPRINTER_INFO_STRESS pPrinterInfo0 = (PPRINTER_INFO_STRESS)(*ppPrinterInfo); + + pPrinterInfo0->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo0->pPrinterName + (ULONG_PTR)pPrinterInfo0); - // Replace relative offset addresses in the output by absolute pointers. - if (Level == 1) + if (pPrinterInfo0->pServerName) + pPrinterInfo0->pServerName = (PWSTR)((ULONG_PTR)pPrinterInfo0->pServerName + (ULONG_PTR)pPrinterInfo0); + + *ppPrinterInfo += sizeof(PRINTER_INFO_STRESS); + } + else if (Level == 1) { - pPrinterInfo1 = (PPRINTER_INFO_1W)pPrinterInfo; + PPRINTER_INFO_1W pPrinterInfo1 = (PPRINTER_INFO_1W)(*ppPrinterInfo); pPrinterInfo1->pName = (PWSTR)((ULONG_PTR)pPrinterInfo1->pName + (ULONG_PTR)pPrinterInfo1); pPrinterInfo1->pDescription = (PWSTR)((ULONG_PTR)pPrinterInfo1->pDescription + (ULONG_PTR)pPrinterInfo1); pPrinterInfo1->pComment = (PWSTR)((ULONG_PTR)pPrinterInfo1->pComment + (ULONG_PTR)pPrinterInfo1); + + *ppPrinterInfo += sizeof(PRINTER_INFO_1W); } else if (Level == 2) { - pPrinterInfo2 = (PPRINTER_INFO_2W)pPrinterInfo; + PPRINTER_INFO_2W pPrinterInfo2 = (PPRINTER_INFO_2W)(*ppPrinterInfo); pPrinterInfo2->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPrinterName + (ULONG_PTR)pPrinterInfo2); pPrinterInfo2->pShareName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pShareName + (ULONG_PTR)pPrinterInfo2); @@ -42,7 +52,66 @@ _MarshallUpPrinterInfo(PBYTE pPrinterInfo, DWORD Level) pPrinterInfo2->pServerName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pServerName + (ULONG_PTR)pPrinterInfo2); if (pPrinterInfo2->pSecurityDescriptor) - pPrinterInfo2->pSecurityDescriptor = (PWSTR)((ULONG_PTR)pPrinterInfo2->pSecurityDescriptor + (ULONG_PTR)pPrinterInfo2); + pPrinterInfo2->pSecurityDescriptor = (PSECURITY_DESCRIPTOR)((ULONG_PTR)pPrinterInfo2->pSecurityDescriptor + (ULONG_PTR)pPrinterInfo2); + + *ppPrinterInfo += sizeof(PRINTER_INFO_2W); + } + else if (Level == 3) + { + PPRINTER_INFO_3 pPrinterInfo3 = (PPRINTER_INFO_3)(*ppPrinterInfo); + + pPrinterInfo3->pSecurityDescriptor = (PSECURITY_DESCRIPTOR)((ULONG_PTR)pPrinterInfo3->pSecurityDescriptor + (ULONG_PTR)pPrinterInfo3); + + *ppPrinterInfo += sizeof(PRINTER_INFO_3); + } + else if (Level == 4) + { + PPRINTER_INFO_4W pPrinterInfo4 = (PPRINTER_INFO_4W)(*ppPrinterInfo); + + pPrinterInfo4->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo4->pPrinterName + (ULONG_PTR)pPrinterInfo4); + + if (pPrinterInfo4->pServerName) + pPrinterInfo4->pServerName = (PWSTR)((ULONG_PTR)pPrinterInfo4->pServerName + (ULONG_PTR)pPrinterInfo4); + + *ppPrinterInfo += sizeof(PRINTER_INFO_4W); + } + else if (Level == 5) + { + PPRINTER_INFO_5W pPrinterInfo5 = (PPRINTER_INFO_5W)(*ppPrinterInfo); + + pPrinterInfo5->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo5->pPrinterName + (ULONG_PTR)pPrinterInfo5); + pPrinterInfo5->pPortName = (PWSTR)((ULONG_PTR)pPrinterInfo5->pPortName + (ULONG_PTR)pPrinterInfo5); + + *ppPrinterInfo += sizeof(PRINTER_INFO_5W); + } + else if (Level == 6) + { + *ppPrinterInfo += sizeof(PRINTER_INFO_6); + } + else if (Level == 7) + { + PPRINTER_INFO_7W pPrinterInfo7 = (PPRINTER_INFO_7W)(*ppPrinterInfo); + + if (pPrinterInfo7->pszObjectGUID) + pPrinterInfo7->pszObjectGUID = (PWSTR)((ULONG_PTR)pPrinterInfo7->pszObjectGUID + (ULONG_PTR)pPrinterInfo7); + + *ppPrinterInfo += sizeof(PRINTER_INFO_7W); + } + else if (Level == 8) + { + PPRINTER_INFO_8W pPrinterInfo8 = (PPRINTER_INFO_8W)(*ppPrinterInfo); + + pPrinterInfo8->pDevMode = (PDEVMODEW)((ULONG_PTR)pPrinterInfo8->pDevMode + (ULONG_PTR)pPrinterInfo8); + + *ppPrinterInfo += sizeof(PRINTER_INFO_8W); + } + else if (Level == 9) + { + PPRINTER_INFO_9W pPrinterInfo9 = (PPRINTER_INFO_9W)(*ppPrinterInfo); + + pPrinterInfo9->pDevMode = (PDEVMODEW)((ULONG_PTR)pPrinterInfo9->pDevMode + (ULONG_PTR)pPrinterInfo9); + + *ppPrinterInfo += sizeof(PRINTER_INFO_9W); } } @@ -306,8 +375,6 @@ BOOL WINAPI EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) { DWORD dwErrorCode; - DWORD i; - PBYTE p = pPrinterEnum; // Dismiss invalid levels already at this point. if (Level == 3 || Level > 5) @@ -333,16 +400,11 @@ EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cb if (dwErrorCode == ERROR_SUCCESS) { - // Replace relative offset addresses in the output by absolute pointers. - for (i = 0; i < *pcReturned; i++) - { - _MarshallUpPrinterInfo(p, Level); + DWORD i; + PBYTE p = pPrinterEnum; - if (Level == 1) - p += sizeof(PRINTER_INFO_1W); - else if (Level == 2) - p += sizeof(PRINTER_INFO_2W); - } + for (i = 0; i < *pcReturned; i++) + _MarshallUpPrinterInfo(&p, Level); } Cleanup: @@ -383,7 +445,39 @@ GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDri BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded) { - return FALSE; + DWORD dwErrorCode; + + // Dismiss invalid levels already at this point. + if (Level > 9) + { + dwErrorCode = ERROR_INVALID_LEVEL; + goto Cleanup; + } + + if (cbBuf && pPrinter) + ZeroMemory(pPrinter, cbBuf); + + // Do the RPC call + RpcTryExcept + { + dwErrorCode = _RpcGetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded); + } + RpcExcept(EXCEPTION_EXECUTE_HANDLER) + { + dwErrorCode = RpcExceptionCode(); + ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode); + } + RpcEndExcept; + + if (dwErrorCode == ERROR_SUCCESS) + { + PBYTE p = pPrinter; + _MarshallUpPrinterInfo(&p, Level); + } + +Cleanup: + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } BOOL WINAPI diff --git a/reactos/win32ss/printing/include/spoolss.h b/reactos/win32ss/printing/include/spoolss.h index bbbbee9432c..d877baa7f3c 100644 --- a/reactos/win32ss/printing/include/spoolss.h +++ b/reactos/win32ss/printing/include/spoolss.h @@ -19,6 +19,41 @@ typedef struct _MARSHALL_DOWN_INFO } MARSHALL_DOWN_INFO, *PMARSHALL_DOWN_INFO; +/** From MS-RPRN, 2.2.1.10.1 */ +typedef struct _PRINTER_INFO_STRESS +{ + PWSTR pPrinterName; + PWSTR pServerName; + DWORD cJobs; + DWORD cTotalJobs; + DWORD cTotalBytes; + SYSTEMTIME stUpTime; + DWORD MaxcRef; + DWORD cTotalPagesPrinted; + DWORD dwGetVersion; + DWORD fFreeBuild; + DWORD cSpooling; + DWORD cMaxSpooling; + DWORD cRef; + DWORD cErrorOutOfPaper; + DWORD cErrorNotReady; + DWORD cJobError; + DWORD dwNumberOfProcessors; + DWORD dwProcessorType; + DWORD dwHighPartTotalBytes; + DWORD cChangeID; + DWORD dwLastError; + DWORD Status; + DWORD cEnumerateNetworkPrinters; + DWORD cAddNetPrinters; + USHORT wProcessorArchitecture; + USHORT wProcessorLevel; + DWORD cRefIC; + DWORD dwReserved2; + DWORD dwReserved3; +} +PRINTER_INFO_STRESS, *PPRINTER_INFO_STRESS; + PVOID WINAPI AlignRpcPtr(PVOID pBuffer, PDWORD pcbBuffer); PWSTR WINAPI AllocSplStr(PCWSTR pwszInput); PVOID WINAPI DllAllocSplMem(DWORD dwBytes); diff --git a/reactos/win32ss/printing/providers/localspl/main.c b/reactos/win32ss/printing/providers/localspl/main.c index c9c424a0ff5..4b2e75a6deb 100644 --- a/reactos/win32ss/printing/providers/localspl/main.c +++ b/reactos/win32ss/printing/providers/localspl/main.c @@ -31,7 +31,7 @@ static const PRINTPROVIDOR _PrintProviderFunctions = { NULL, // fpAddPrinter NULL, // fpDeletePrinter NULL, // fpSetPrinter - NULL, // fpGetPrinter + LocalGetPrinter, // fpGetPrinter LocalEnumPrinters, // fpEnumPrinters NULL, // fpAddPrinterDriver NULL, // fpEnumPrinterDrivers diff --git a/reactos/win32ss/printing/providers/localspl/precomp.h b/reactos/win32ss/printing/providers/localspl/precomp.h index 699ba023122..b57fd6560b8 100644 --- a/reactos/win32ss/printing/providers/localspl/precomp.h +++ b/reactos/win32ss/printing/providers/localspl/precomp.h @@ -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: Precompiled Header for all source files - * COPYRIGHT: Copyright 2015 Colin Finck + * COPYRIGHT: Copyright 2015-2017 Colin Finck */ #ifndef _PRECOMP_H @@ -277,6 +277,7 @@ BOOL WINAPI LocalEnumPorts(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, extern SKIPLIST PrinterList; BOOL InitializePrinterList(); BOOL WINAPI LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned); +BOOL WINAPI LocalGetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded); BOOL WINAPI LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDefault); BOOL WINAPI LocalReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead); DWORD WINAPI LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo); diff --git a/reactos/win32ss/printing/providers/localspl/printers.c b/reactos/win32ss/printing/providers/localspl/printers.c index 339c138208f..435c61249cb 100644 --- a/reactos/win32ss/printing/providers/localspl/printers.c +++ b/reactos/win32ss/printing/providers/localspl/printers.c @@ -10,7 +10,39 @@ // Global Variables SKIPLIST PrinterList; +// Forward Declarations +static void _LocalGetPrinterLevel0(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_STRESS* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName); +static void _LocalGetPrinterLevel1(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_1W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName); +static void _LocalGetPrinterLevel2(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_2W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName); +static void _LocalGetPrinterLevel3(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_3* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName); +static void _LocalGetPrinterLevel4(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_4W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName); +static void _LocalGetPrinterLevel5(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_5W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName); +static void _LocalGetPrinterLevel6(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_6* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName); +static void _LocalGetPrinterLevel7(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_7W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName); +static void _LocalGetPrinterLevel8(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_8W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName); +static void _LocalGetPrinterLevel9(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_9W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName); + // Local Constants +typedef void (*PLocalGetPrinterLevelFunc)(PLOCAL_PRINTER, PVOID, PBYTE*, PDWORD, DWORD, PWSTR); + +static const PLocalGetPrinterLevelFunc pfnGetPrinterLevels[] = { + (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel0, + (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel1, + (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel2, + (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel3, + (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel4, + (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel5, + (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel6, + (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel7, + (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel8, + (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel9 +}; + +static DWORD dwPrinterInfo0Offsets[] = { + FIELD_OFFSET(PRINTER_INFO_STRESS, pPrinterName), + MAXDWORD +}; + static DWORD dwPrinterInfo1Offsets[] = { FIELD_OFFSET(PRINTER_INFO_1W, pName), FIELD_OFFSET(PRINTER_INFO_1W, pComment), @@ -18,6 +50,31 @@ static DWORD dwPrinterInfo1Offsets[] = { MAXDWORD }; +static DWORD dwPrinterInfo2Offsets[] = { + FIELD_OFFSET(PRINTER_INFO_2W, pPrinterName), + FIELD_OFFSET(PRINTER_INFO_2W, pShareName), + FIELD_OFFSET(PRINTER_INFO_2W, pPortName), + FIELD_OFFSET(PRINTER_INFO_2W, pDriverName), + FIELD_OFFSET(PRINTER_INFO_2W, pComment), + FIELD_OFFSET(PRINTER_INFO_2W, pLocation), + FIELD_OFFSET(PRINTER_INFO_2W, pSepFile), + FIELD_OFFSET(PRINTER_INFO_2W, pPrintProcessor), + FIELD_OFFSET(PRINTER_INFO_2W, pDatatype), + FIELD_OFFSET(PRINTER_INFO_2W, pParameters), + MAXDWORD +}; + +static DWORD dwPrinterInfo4Offsets[] = { + FIELD_OFFSET(PRINTER_INFO_4W, pPrinterName), + MAXDWORD +}; + +static DWORD dwPrinterInfo5Offsets[] = { + FIELD_OFFSET(PRINTER_INFO_5W, pPrinterName), + FIELD_OFFSET(PRINTER_INFO_5W, pPortName), + MAXDWORD +}; + /** * @name _PrinterListCompareRoutine * @@ -437,137 +494,378 @@ _DumpLevel1PrintProviderInformation(PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbN return ERROR_SUCCESS; } -static DWORD -_LocalEnumPrintersLevel0(DWORD Flags, PCWSTR Name, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned, DWORD cchComputerName, PWSTR wszComputerName) +static void +_LocalGetPrinterLevel0(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_STRESS* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName) { - return ERROR_INVALID_LEVEL; + size_t cbName; + PWSTR p; + PWSTR pwszStrings[1]; + SYSTEM_INFO SystemInfo; + + // Calculate the string lengths. + cbName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR); + + if (!ppPrinterInfo) + { + *pcbNeeded += sizeof(PRINTER_INFO_STRESS) + cbName; + return; + } + + // Set the general fields. + ZeroMemory(*ppPrinterInfo, sizeof(PRINTER_INFO_STRESS)); + (*ppPrinterInfo)->cJobs = pPrinter->JobList.NodeCount; + (*ppPrinterInfo)->dwGetVersion = GetVersion(); + (*ppPrinterInfo)->Status = pPrinter->dwStatus; + +#if !defined(DBG) + (*ppPrinterInfo)->fFreeBuild = 1; +#endif + + GetSystemInfo(&SystemInfo); + (*ppPrinterInfo)->dwNumberOfProcessors = SystemInfo.dwNumberOfProcessors; + (*ppPrinterInfo)->dwProcessorType = SystemInfo.dwProcessorType; + (*ppPrinterInfo)->wProcessorArchitecture = SystemInfo.wProcessorArchitecture; + (*ppPrinterInfo)->wProcessorLevel = SystemInfo.wProcessorLevel; + + // 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); + + // Finally copy the structure and advance to the next one in the output buffer. + *ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo0Offsets, *ppPrinterInfoEnd); + (*ppPrinterInfo)++; + + // Free the memory for temporary strings. + DllFreeSplMem(pwszStrings[0]); } -static DWORD -_LocalEnumPrintersLevel1(DWORD Flags, PCWSTR Name, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned, DWORD cchComputerName, PWSTR wszComputerName) +static void +_LocalGetPrinterLevel1(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_1W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName) { const WCHAR wszComma[] = L","; size_t cbName; size_t cbComment; size_t cbDescription; - DWORD dwErrorCode; - DWORD i; - PBYTE pPrinterInfo; - PBYTE pPrinterStrings; - PSKIPLIST_NODE pNode; - PLOCAL_PRINTER pPrinter; PWSTR p; PWSTR pwszStrings[3]; - if (Flags & PRINTER_ENUM_NAME && !Name) + // Calculate the string lengths. + // 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 = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR); + cbComment = (wcslen(pPrinter->pwszDescription) + 1) * sizeof(WCHAR); + cbDescription = cbName + (wcslen(pPrinter->pwszPrinterDriver) + 1 + wcslen(pPrinter->pwszLocation) + 1) * sizeof(WCHAR); + + if (!ppPrinterInfo) { - // The caller wants information about this Print Provider. - // spoolss packs this into an array of information about all Print Providers. - dwErrorCode = _DumpLevel1PrintProviderInformation(pPrinterEnum, cbBuf, pcbNeeded, pcReturned); - goto Cleanup; + *pcbNeeded += sizeof(PRINTER_INFO_1W) + cbName + cbComment + cbDescription; + return; } - // Count the required buffer size and the number of printers. - i = 0; + // Indicate that this is a Printer. + (*ppPrinterInfo)->Flags = PRINTER_ENUM_ICON8; + + // 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. + *ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo1Offsets, *ppPrinterInfoEnd); + (*ppPrinterInfo)++; + + // Free the memory for temporary strings. + DllFreeSplMem(pwszStrings[0]); + DllFreeSplMem(pwszStrings[2]); +} - for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0]) - { - pPrinter = (PLOCAL_PRINTER)pNode->Element; +static void +_LocalGetPrinterLevel2(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_2W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName) +{ + WCHAR wszEmpty[] = L""; - // 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; + size_t cbDevMode; + size_t cbPrinterName; + size_t cbShareName; + size_t cbPortName; + size_t cbDriverName; + size_t cbComment; + size_t cbLocation; + size_t cbSepFile; + size_t cbPrintProcessor; + size_t cbDatatype; + size_t cbParameters; + PWSTR p; + PWSTR pwszStrings[10]; - // 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 = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR); - cbComment = (wcslen(pPrinter->pwszDescription) + 1) * sizeof(WCHAR); - cbDescription = cbName + (wcslen(pPrinter->pwszPrinterDriver) + 1 + wcslen(pPrinter->pwszLocation) + 1) * sizeof(WCHAR); + // Calculate the string lengths. + cbDevMode = pPrinter->pDefaultDevMode->dmSize + pPrinter->pDefaultDevMode->dmDriverExtra; + cbPrinterName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR); - *pcbNeeded += sizeof(PRINTER_INFO_1W) + cbName + cbComment + cbDescription; - i++; + if (!ppPrinterInfo) + { + // Attention: pComment equals the "Description" registry value. + cbShareName = sizeof(wszEmpty); + cbPortName = (wcslen(pPrinter->pPort->pwszName) + 1) * sizeof(WCHAR); + cbDriverName = (wcslen(pPrinter->pwszPrinterDriver) + 1) * sizeof(WCHAR); + cbComment = (wcslen(pPrinter->pwszDescription) + 1) * sizeof(WCHAR); + cbLocation = (wcslen(pPrinter->pwszLocation) + 1) * sizeof(WCHAR); + cbSepFile = sizeof(wszEmpty); + cbPrintProcessor = (wcslen(pPrinter->pPrintProcessor->pwszName) + 1) * sizeof(WCHAR); + cbDatatype = (wcslen(pPrinter->pwszDefaultDatatype) + 1) * sizeof(WCHAR); + cbParameters = sizeof(wszEmpty); + + *pcbNeeded += sizeof(PRINTER_INFO_2W) + cbDevMode + cbPrinterName + cbShareName + cbPortName + cbDriverName + cbComment + cbLocation + cbSepFile + cbPrintProcessor + cbDatatype + cbParameters; + return; } - // Check if the supplied buffer is large enough. - if (cbBuf < *pcbNeeded) + // Set the general fields. + ZeroMemory(*ppPrinterInfo, sizeof(PRINTER_INFO_2W)); + (*ppPrinterInfo)->Attributes = pPrinter->dwAttributes; + (*ppPrinterInfo)->cJobs = pPrinter->JobList.NodeCount; + (*ppPrinterInfo)->Status = pPrinter->dwStatus; + + // Set the pDevMode field (and copy the DevMode). + *ppPrinterInfoEnd -= cbDevMode; + CopyMemory(*ppPrinterInfoEnd, pPrinter->pDefaultDevMode, cbDevMode); + (*ppPrinterInfo)->pDevMode = (PDEVMODEW)(*ppPrinterInfoEnd); + + // Set the pPrinterName field. + pwszStrings[0] = DllAllocSplMem(cbPrinterName); + p = pwszStrings[0]; + StringCbCopyExW(p, cbPrinterName, wszComputerName, &p, &cbPrinterName, 0); + StringCbCopyExW(p, cbPrinterName, pPrinter->pwszPrinterName, &p, &cbPrinterName, 0); + + // Set the pShareName field. + pwszStrings[1] = wszEmpty; + + // Set the pPortName field. + pwszStrings[2] = pPrinter->pPort->pwszName; + + // Set the pDriverName field. + pwszStrings[3] = pPrinter->pwszPrinterDriver; + + // Set the pComment field ((equals the "Description" registry value). + pwszStrings[4] = pPrinter->pwszDescription; + + // Set the pLocation field. + pwszStrings[5] = pPrinter->pwszLocation; + + // Set the pSepFile field. + pwszStrings[6] = wszEmpty; + + // Set the pPrintProcessor field. + pwszStrings[7] = pPrinter->pPrintProcessor->pwszName; + + // Set the pDatatype field. + pwszStrings[8] = pPrinter->pwszDefaultDatatype; + + // Set the pParameters field. + pwszStrings[9] = wszEmpty; + + // Finally copy the structure and advance to the next one in the output buffer. + *ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo2Offsets, *ppPrinterInfoEnd); + (*ppPrinterInfo)++; + + // Free the memory for temporary strings. + DllFreeSplMem(pwszStrings[0]); +} + +static void +_LocalGetPrinterLevel3(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_3* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName) +{ + SECURITY_DESCRIPTOR SecurityDescriptor = { 0 }; + + if (!ppPrinterInfo) { - dwErrorCode = ERROR_INSUFFICIENT_BUFFER; - goto Cleanup; + *pcbNeeded += sizeof(PRINTER_INFO_3) + sizeof(SECURITY_DESCRIPTOR); + return; } - // Initialize the variables for filling the output buffer using PackStrings. - pPrinterInfo = pPrinterEnum; - pPrinterStrings = &pPrinterEnum[*pcbNeeded]; + FIXME("Return a valid security descriptor for PRINTER_INFO_3\n"); - // Copy over the Printer information. - for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0]) + // Set the pSecurityDescriptor field (and copy the Security Descriptor). + *ppPrinterInfoEnd -= sizeof(SECURITY_DESCRIPTOR); + CopyMemory(*ppPrinterInfoEnd, &SecurityDescriptor, sizeof(SECURITY_DESCRIPTOR)); + (*ppPrinterInfo)->pSecurityDescriptor = (PSECURITY_DESCRIPTOR)(*ppPrinterInfoEnd); + + // Advance to the next structure. + (*ppPrinterInfo)++; +} + +static void +_LocalGetPrinterLevel4(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_4W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName) +{ + size_t cbPrinterName; + PWSTR p; + PWSTR pwszStrings[1]; + + // Calculate the string lengths. + cbPrinterName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR); + + if (!ppPrinterInfo) { - pPrinter = (PLOCAL_PRINTER)pNode->Element; + *pcbNeeded += sizeof(PRINTER_INFO_4W) + cbPrinterName; + return; + } - // 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; + // Set the general fields. + (*ppPrinterInfo)->pServerName = NULL; + (*ppPrinterInfo)->Attributes = pPrinter->dwAttributes; - // Indicate that this is a Printer. - ((PPRINTER_INFO_1W)pPrinterInfo)->Flags = PRINTER_ENUM_ICON8; + // Set the pPrinterName field. + pwszStrings[0] = DllAllocSplMem(cbPrinterName); + p = pwszStrings[0]; + StringCbCopyExW(p, cbPrinterName, wszComputerName, &p, &cbPrinterName, 0); + StringCbCopyExW(p, cbPrinterName, pPrinter->pwszPrinterName, &p, &cbPrinterName, 0); - // Calculate the string lengths. - cbName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR); - cbComment = (wcslen(pPrinter->pwszDescription) + 1) * sizeof(WCHAR); - cbDescription = cbName + (wcslen(pPrinter->pwszPrinterDriver) + 1 + wcslen(pPrinter->pwszLocation) + 1) * sizeof(WCHAR); + // Finally copy the structure and advance to the next one in the output buffer. + *ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo4Offsets, *ppPrinterInfoEnd); + (*ppPrinterInfo)++; - // 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); + // Free the memory for temporary strings. + DllFreeSplMem(pwszStrings[0]); +} - // Copy the Printer comment (equals the "Description" registry value). - pwszStrings[1] = pPrinter->pwszDescription; +static void +_LocalGetPrinterLevel5(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_5W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName) +{ + size_t cbPrinterName; + size_t cbPortName; + PWSTR p; + PWSTR pwszStrings[1]; - // 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); + // Calculate the string lengths. + cbPrinterName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR); - // Finally copy the structure and advance to the next one in the output buffer. - pPrinterStrings = PackStrings(pwszStrings, pPrinterInfo, dwPrinterInfo1Offsets, pPrinterStrings); - pPrinterInfo += sizeof(PRINTER_INFO_1W); + if (!ppPrinterInfo) + { + cbPortName = (wcslen(pPrinter->pPort->pwszName) + 1) * sizeof(WCHAR); - // Free the memory for temporary strings. - DllFreeSplMem(pwszStrings[0]); - DllFreeSplMem(pwszStrings[2]); + *pcbNeeded += sizeof(PRINTER_INFO_5W) + cbPrinterName + cbPortName; + return; } - *pcReturned = i; - dwErrorCode = ERROR_SUCCESS; + // Set the general fields. + (*ppPrinterInfo)->Attributes = pPrinter->dwAttributes; + (*ppPrinterInfo)->DeviceNotSelectedTimeout = 0; + (*ppPrinterInfo)->TransmissionRetryTimeout = 0; -Cleanup: - return dwErrorCode; + // Set the pPrinterName field. + pwszStrings[0] = DllAllocSplMem(cbPrinterName); + p = pwszStrings[0]; + StringCbCopyExW(p, cbPrinterName, wszComputerName, &p, &cbPrinterName, 0); + StringCbCopyExW(p, cbPrinterName, pPrinter->pwszPrinterName, &p, &cbPrinterName, 0); + + // Set the pPortName field. + pwszStrings[1] = pPrinter->pPort->pwszName; + + // Finally copy the structure and advance to the next one in the output buffer. + *ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo5Offsets, *ppPrinterInfoEnd); + (*ppPrinterInfo)++; + + // Free the memory for temporary strings. + DllFreeSplMem(pwszStrings[0]); } -static DWORD -_LocalEnumPrintersLevel2(DWORD Flags, PCWSTR Name, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned, DWORD cchComputerName, PWSTR wszComputerName) +static void +_LocalGetPrinterLevel6(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_6* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName) { - return ERROR_INVALID_LEVEL; + if (!ppPrinterInfo) + { + *pcbNeeded += sizeof(PRINTER_INFO_6); + return; + } + + // Set the general fields. + (*ppPrinterInfo)->dwStatus = pPrinter->dwStatus; + + // Advance to the next structure. + (*ppPrinterInfo)++; } -static DWORD -_LocalEnumPrintersLevel4(DWORD Flags, PCWSTR Name, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned, DWORD cchComputerName, PWSTR wszComputerName) +static void +_LocalGetPrinterLevel7(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_7W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName) { - return ERROR_INVALID_LEVEL; + if (!ppPrinterInfo) + { + *pcbNeeded += sizeof(PRINTER_INFO_7W); + return; + } + + FIXME("No Directory Support, returning DSPRINT_UNPUBLISH for PRINTER_INFO_7 all the time!\n"); + + // Set the general fields. + (*ppPrinterInfo)->dwAction = DSPRINT_UNPUBLISH; + (*ppPrinterInfo)->pszObjectGUID = NULL; + + // Advance to the next structure. + (*ppPrinterInfo)++; } -static DWORD -_LocalEnumPrintersLevel5(DWORD Flags, PCWSTR Name, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned, DWORD cchComputerName, PWSTR wszComputerName) +static void +_LocalGetPrinterLevel8(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_8W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName) +{ + DWORD cbDevMode; + + // Calculate the string lengths. + cbDevMode = pPrinter->pDefaultDevMode->dmSize + pPrinter->pDefaultDevMode->dmDriverExtra; + + if (!ppPrinterInfo) + { + *pcbNeeded += sizeof(PRINTER_INFO_8W) + cbDevMode; + return; + } + + // Set the pDevMode field (and copy the DevMode). + *ppPrinterInfoEnd -= cbDevMode; + CopyMemory(*ppPrinterInfoEnd, pPrinter->pDefaultDevMode, cbDevMode); + (*ppPrinterInfo)->pDevMode = (PDEVMODEW)(*ppPrinterInfoEnd); + + // Advance to the next structure. + (*ppPrinterInfo)++; +} + +static void +_LocalGetPrinterLevel9(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_9W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName) { - return ERROR_INVALID_LEVEL; + DWORD cbDevMode; + + // Calculate the string lengths. + cbDevMode = pPrinter->pDefaultDevMode->dmSize + pPrinter->pDefaultDevMode->dmDriverExtra; + + if (!ppPrinterInfo) + { + *pcbNeeded += sizeof(PRINTER_INFO_9W) + cbDevMode; + return; + } + + FIXME("Per-user settings are not yet implemented, returning the global DevMode for PRINTER_INFO_9!\n"); + + // Set the pDevMode field (and copy the DevMode). + *ppPrinterInfoEnd -= cbDevMode; + CopyMemory(*ppPrinterInfoEnd, pPrinter->pDefaultDevMode, cbDevMode); + (*ppPrinterInfo)->pDevMode = (PDEVMODEW)(*ppPrinterInfoEnd); + + // Advance to the next structure. + (*ppPrinterInfo)++; } BOOL WINAPI @@ -575,7 +873,11 @@ LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DW { DWORD cchComputerName = 0; DWORD dwErrorCode; + DWORD i; + PBYTE pPrinterInfoEnd; + PSKIPLIST_NODE pNode; WCHAR wszComputerName[2 + MAX_COMPUTERNAME_LENGTH + 1 + 1] = { 0 }; + PLOCAL_PRINTER pPrinter; ASSERT(pcbNeeded); ASSERT(pcReturned); @@ -601,38 +903,112 @@ LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DW goto Cleanup; } + if (Level == 3 || Level > 5) + { + // The caller supplied an invalid level for EnumPrinters. + dwErrorCode = ERROR_INVALID_LEVEL; + goto Cleanup; + } + + if (Level == 1 && Flags & PRINTER_ENUM_NAME && !Name) + { + // The caller wants information about this Print Provider. + // spoolss packs this into an array of information about all Print Providers. + dwErrorCode = _DumpLevel1PrintProviderInformation(pPrinterEnum, cbBuf, pcbNeeded, pcReturned); + goto Cleanup; + } + // Check the supplied Name parameter (if any). // This may return a Computer Name string we later prepend to the output. dwErrorCode = _LocalEnumPrintersCheckName(Flags, Name, wszComputerName, &cchComputerName); if (dwErrorCode != ERROR_SUCCESS) goto Cleanup; - if (Level == 0) + // Count the required buffer size and the number of printers. + i = 0; + for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0]) { - dwErrorCode = _LocalEnumPrintersLevel0(Flags, Name, pPrinterEnum, cbBuf, pcbNeeded, pcReturned, cchComputerName, wszComputerName); + pPrinter = (PLOCAL_PRINTER)pNode->Element; + + // TODO: If PRINTER_ENUM_SHARED is given, add this Printer if it's shared instead of just ignoring it. + if (Flags & PRINTER_ENUM_SHARED) + { + FIXME("Printer Sharing is not supported yet, returning no printers!\n"); + continue; + } + + pfnGetPrinterLevels[Level](pPrinter, NULL, NULL, pcbNeeded, cchComputerName, wszComputerName); + i++; } - else if (Level == 1) + + // Check if the supplied buffer is large enough. + if (cbBuf < *pcbNeeded) { - dwErrorCode = _LocalEnumPrintersLevel1(Flags, Name, pPrinterEnum, cbBuf, pcbNeeded, pcReturned, cchComputerName, wszComputerName); + dwErrorCode = ERROR_INSUFFICIENT_BUFFER; + goto Cleanup; } - else if (Level == 2) + + // Copy over the Printer information. + pPrinterInfoEnd = &pPrinterEnum[*pcbNeeded]; + + for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0]) { - dwErrorCode = _LocalEnumPrintersLevel2(Flags, Name, pPrinterEnum, cbBuf, pcbNeeded, pcReturned, cchComputerName, wszComputerName); + pPrinter = (PLOCAL_PRINTER)pNode->Element; + + // 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; + + pfnGetPrinterLevels[Level](pPrinter, &pPrinterEnum, &pPrinterInfoEnd, NULL, cchComputerName, wszComputerName); } - else if (Level == 4) + + *pcReturned = i; + dwErrorCode = ERROR_SUCCESS; + +Cleanup: + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); +} + +BOOL WINAPI +LocalGetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded) +{ + DWORD dwErrorCode; + PBYTE pPrinterEnd; + PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter; + PLOCAL_PRINTER_HANDLE pPrinterHandle; + + // Check if this is a printer handle. + if (pHandle->HandleType != HandleType_Printer) { - dwErrorCode = _LocalEnumPrintersLevel4(Flags, Name, pPrinterEnum, cbBuf, pcbNeeded, pcReturned, cchComputerName, wszComputerName); + dwErrorCode = ERROR_INVALID_HANDLE; + goto Cleanup; } - else if (Level == 5) + + pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle; + + if (Level > 9) { - dwErrorCode = _LocalEnumPrintersLevel5(Flags, Name, pPrinterEnum, cbBuf, pcbNeeded, pcReturned, cchComputerName, wszComputerName); + // The caller supplied an invalid level for GetPrinter. + dwErrorCode = ERROR_INVALID_LEVEL; + goto Cleanup; } - else + + // Count the required buffer size. + pfnGetPrinterLevels[Level](pPrinterHandle->pPrinter, NULL, NULL, pcbNeeded, 0, NULL); + + // Check if the supplied buffer is large enough. + if (cbBuf < *pcbNeeded) { - // The caller supplied an invalid level. - dwErrorCode = ERROR_INVALID_LEVEL; + dwErrorCode = ERROR_INSUFFICIENT_BUFFER; + goto Cleanup; } + // Copy over the Printer information. + pPrinterEnd = &pPrinter[*pcbNeeded]; + pfnGetPrinterLevels[Level](pPrinterHandle->pPrinter, &pPrinter, &pPrinterEnd, NULL, 0, NULL); + dwErrorCode = ERROR_SUCCESS; + Cleanup: SetLastError(dwErrorCode); return (dwErrorCode == ERROR_SUCCESS); -- 2.17.1