[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
This commit is contained in:
Colin Finck 2017-04-30 15:12:53 +00:00
parent f10b1d9976
commit 30d5e8f413
7 changed files with 748 additions and 157 deletions

View file

@ -8,23 +8,33 @@
#include "precomp.h" #include "precomp.h"
static void 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. // 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->pName = (PWSTR)((ULONG_PTR)pPrinterInfo1->pName - (ULONG_PTR)pPrinterInfo1);
pPrinterInfo1->pDescription = (PWSTR)((ULONG_PTR)pPrinterInfo1->pDescription - (ULONG_PTR)pPrinterInfo1); pPrinterInfo1->pDescription = (PWSTR)((ULONG_PTR)pPrinterInfo1->pDescription - (ULONG_PTR)pPrinterInfo1);
pPrinterInfo1->pComment = (PWSTR)((ULONG_PTR)pPrinterInfo1->pComment - (ULONG_PTR)pPrinterInfo1); pPrinterInfo1->pComment = (PWSTR)((ULONG_PTR)pPrinterInfo1->pComment - (ULONG_PTR)pPrinterInfo1);
*ppPrinterInfo += sizeof(PRINTER_INFO_1W);
} }
else if (Level == 2) 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->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPrinterName - (ULONG_PTR)pPrinterInfo2);
pPrinterInfo2->pShareName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pShareName - (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); pPrinterInfo2->pServerName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pServerName - (ULONG_PTR)pPrinterInfo2);
if (pPrinterInfo2->pSecurityDescriptor) 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; DWORD i;
PBYTE p = pPrinterEnumAligned; PBYTE p = pPrinterEnumAligned;
// Replace absolute pointer addresses in the output by relative offsets.
for (i = 0; i < *pcReturned; i++) for (i = 0; i < *pcReturned; i++)
{ _MarshallDownPrinterInfo(&p, Level);
_MarshallDownPrinterInfo(p, Level);
if (Level == 1)
p += sizeof(PRINTER_INFO_1W);
else if (Level == 2)
p += sizeof(PRINTER_INFO_2W);
}
} }
RpcRevertToSelf(); RpcRevertToSelf();
@ -183,8 +244,30 @@ _RpcFlushPrinter(WINSPOOL_PRINTER_HANDLE hPrinter, BYTE* pBuf, DWORD cbBuf, DWOR
DWORD DWORD
_RpcGetPrinter(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD Level, BYTE* pPrinter, DWORD cbBuf, DWORD* pcbNeeded) _RpcGetPrinter(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD Level, BYTE* pPrinter, DWORD cbBuf, DWORD* pcbNeeded)
{ {
UNIMPLEMENTED; DWORD dwErrorCode;
return ERROR_INVALID_FUNCTION; 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 DWORD

View file

@ -2,7 +2,7 @@
* PROJECT: ReactOS Print Spooler API * PROJECT: ReactOS Print Spooler API
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Precompiled Header for all source files * 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
@ -16,6 +16,8 @@
#include <winspool.h> #include <winspool.h>
#include <winspool_c.h> #include <winspool_c.h>
#include <spoolss.h>
#include <wine/debug.h> #include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(winspool); WINE_DEFAULT_DEBUG_CHANNEL(winspool);

View file

@ -8,23 +8,33 @@
#include "precomp.h" #include "precomp.h"
static void static void
_MarshallUpPrinterInfo(PBYTE pPrinterInfo, DWORD Level) _MarshallUpPrinterInfo(PBYTE* ppPrinterInfo, DWORD Level)
{ {
PPRINTER_INFO_1W pPrinterInfo1; // Replace relative offset addresses in the output by absolute pointers and advance to the next structure.
PPRINTER_INFO_2W pPrinterInfo2; if (Level == 0)
// Replace relative offset addresses in the output by absolute pointers.
if (Level == 1)
{ {
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->pName = (PWSTR)((ULONG_PTR)pPrinterInfo1->pName + (ULONG_PTR)pPrinterInfo1);
pPrinterInfo1->pDescription = (PWSTR)((ULONG_PTR)pPrinterInfo1->pDescription + (ULONG_PTR)pPrinterInfo1); pPrinterInfo1->pDescription = (PWSTR)((ULONG_PTR)pPrinterInfo1->pDescription + (ULONG_PTR)pPrinterInfo1);
pPrinterInfo1->pComment = (PWSTR)((ULONG_PTR)pPrinterInfo1->pComment + (ULONG_PTR)pPrinterInfo1); pPrinterInfo1->pComment = (PWSTR)((ULONG_PTR)pPrinterInfo1->pComment + (ULONG_PTR)pPrinterInfo1);
*ppPrinterInfo += sizeof(PRINTER_INFO_1W);
} }
else if (Level == 2) 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->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPrinterName + (ULONG_PTR)pPrinterInfo2);
pPrinterInfo2->pShareName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pShareName + (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); pPrinterInfo2->pServerName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pServerName + (ULONG_PTR)pPrinterInfo2);
if (pPrinterInfo2->pSecurityDescriptor) 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) EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
{ {
DWORD dwErrorCode; DWORD dwErrorCode;
DWORD i;
PBYTE p = pPrinterEnum;
// Dismiss invalid levels already at this point. // Dismiss invalid levels already at this point.
if (Level == 3 || Level > 5) if (Level == 3 || Level > 5)
@ -333,16 +400,11 @@ EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cb
if (dwErrorCode == ERROR_SUCCESS) if (dwErrorCode == ERROR_SUCCESS)
{ {
// Replace relative offset addresses in the output by absolute pointers. DWORD i;
for (i = 0; i < *pcReturned; i++) PBYTE p = pPrinterEnum;
{
_MarshallUpPrinterInfo(p, Level);
if (Level == 1) for (i = 0; i < *pcReturned; i++)
p += sizeof(PRINTER_INFO_1W); _MarshallUpPrinterInfo(&p, Level);
else if (Level == 2)
p += sizeof(PRINTER_INFO_2W);
}
} }
Cleanup: Cleanup:
@ -383,7 +445,39 @@ GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDri
BOOL WINAPI BOOL WINAPI
GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded) 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 BOOL WINAPI

View file

@ -19,6 +19,41 @@ typedef struct _MARSHALL_DOWN_INFO
} }
MARSHALL_DOWN_INFO, *PMARSHALL_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); PVOID WINAPI AlignRpcPtr(PVOID pBuffer, PDWORD pcbBuffer);
PWSTR WINAPI AllocSplStr(PCWSTR pwszInput); PWSTR WINAPI AllocSplStr(PCWSTR pwszInput);
PVOID WINAPI DllAllocSplMem(DWORD dwBytes); PVOID WINAPI DllAllocSplMem(DWORD dwBytes);

View file

@ -31,7 +31,7 @@ static const PRINTPROVIDOR _PrintProviderFunctions = {
NULL, // fpAddPrinter NULL, // fpAddPrinter
NULL, // fpDeletePrinter NULL, // fpDeletePrinter
NULL, // fpSetPrinter NULL, // fpSetPrinter
NULL, // fpGetPrinter LocalGetPrinter, // fpGetPrinter
LocalEnumPrinters, // fpEnumPrinters LocalEnumPrinters, // fpEnumPrinters
NULL, // fpAddPrinterDriver NULL, // fpAddPrinterDriver
NULL, // fpEnumPrinterDrivers NULL, // fpEnumPrinterDrivers

View file

@ -2,7 +2,7 @@
* PROJECT: ReactOS Local Spooler * PROJECT: ReactOS Local Spooler
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Precompiled Header for all source files * 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
@ -277,6 +277,7 @@ BOOL WINAPI LocalEnumPorts(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf,
extern SKIPLIST PrinterList; extern SKIPLIST PrinterList;
BOOL InitializePrinterList(); BOOL InitializePrinterList();
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);
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 LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDefault);
BOOL WINAPI LocalReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead); BOOL WINAPI LocalReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead);
DWORD WINAPI LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo); DWORD WINAPI LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo);

View file

@ -10,7 +10,39 @@
// Global Variables // Global Variables
SKIPLIST PrinterList; 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 // 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[] = { static DWORD dwPrinterInfo1Offsets[] = {
FIELD_OFFSET(PRINTER_INFO_1W, pName), FIELD_OFFSET(PRINTER_INFO_1W, pName),
FIELD_OFFSET(PRINTER_INFO_1W, pComment), FIELD_OFFSET(PRINTER_INFO_1W, pComment),
@ -18,6 +50,31 @@ static DWORD dwPrinterInfo1Offsets[] = {
MAXDWORD 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 * @name _PrinterListCompareRoutine
* *
@ -437,137 +494,378 @@ _DumpLevel1PrintProviderInformation(PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbN
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
static DWORD static void
_LocalEnumPrintersLevel0(DWORD Flags, PCWSTR Name, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned, DWORD cchComputerName, PWSTR wszComputerName) _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 static void
_LocalEnumPrintersLevel1(DWORD Flags, PCWSTR Name, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned, DWORD cchComputerName, PWSTR wszComputerName) _LocalGetPrinterLevel1(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_1W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName)
{ {
const WCHAR wszComma[] = L","; const WCHAR wszComma[] = L",";
size_t cbName; size_t cbName;
size_t cbComment; size_t cbComment;
size_t cbDescription; size_t cbDescription;
DWORD dwErrorCode;
DWORD i;
PBYTE pPrinterInfo;
PBYTE pPrinterStrings;
PSKIPLIST_NODE pNode;
PLOCAL_PRINTER pPrinter;
PWSTR p; PWSTR p;
PWSTR pwszStrings[3]; 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;
}
// Count the required buffer size and the number of printers.
i = 0;
for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0])
{
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;
// 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);
*pcbNeeded += sizeof(PRINTER_INFO_1W) + cbName + cbComment + cbDescription; *pcbNeeded += sizeof(PRINTER_INFO_1W) + cbName + cbComment + cbDescription;
i++; return;
} }
// Check if the supplied buffer is large enough. // Indicate that this is a Printer.
if (cbBuf < *pcbNeeded) (*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]);
}
static void
_LocalGetPrinterLevel2(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_2W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName)
{
WCHAR wszEmpty[] = L"";
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];
// Calculate the string lengths.
cbDevMode = pPrinter->pDefaultDevMode->dmSize + pPrinter->pDefaultDevMode->dmDriverExtra;
cbPrinterName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
if (!ppPrinterInfo)
{ {
dwErrorCode = ERROR_INSUFFICIENT_BUFFER; // Attention: pComment equals the "Description" registry value.
goto Cleanup; cbShareName = sizeof(wszEmpty);
} cbPortName = (wcslen(pPrinter->pPort->pwszName) + 1) * sizeof(WCHAR);
cbDriverName = (wcslen(pPrinter->pwszPrinterDriver) + 1) * sizeof(WCHAR);
// Initialize the variables for filling the output buffer using PackStrings.
pPrinterInfo = pPrinterEnum;
pPrinterStrings = &pPrinterEnum[*pcbNeeded];
// Copy over the Printer information.
for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0])
{
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;
// Indicate that this is a Printer.
((PPRINTER_INFO_1W)pPrinterInfo)->Flags = PRINTER_ENUM_ICON8;
// 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);
cbDescription = cbName + (wcslen(pPrinter->pwszPrinterDriver) + 1 + wcslen(pPrinter->pwszLocation) + 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);
// Copy the Printer Name. *pcbNeeded += sizeof(PRINTER_INFO_2W) + cbDevMode + cbPrinterName + cbShareName + cbPortName + cbDriverName + cbComment + cbLocation + cbSepFile + cbPrintProcessor + cbDatatype + cbParameters;
pwszStrings[0] = DllAllocSplMem(cbName); return;
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.
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; // Set the general fields.
dwErrorCode = ERROR_SUCCESS; ZeroMemory(*ppPrinterInfo, sizeof(PRINTER_INFO_2W));
(*ppPrinterInfo)->Attributes = pPrinter->dwAttributes;
(*ppPrinterInfo)->cJobs = pPrinter->JobList.NodeCount;
(*ppPrinterInfo)->Status = pPrinter->dwStatus;
Cleanup: // Set the pDevMode field (and copy the DevMode).
return dwErrorCode; *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 DWORD static void
_LocalEnumPrintersLevel2(DWORD Flags, PCWSTR Name, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned, DWORD cchComputerName, PWSTR wszComputerName) _LocalGetPrinterLevel3(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_3* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName)
{ {
return ERROR_INVALID_LEVEL; SECURITY_DESCRIPTOR SecurityDescriptor = { 0 };
if (!ppPrinterInfo)
{
*pcbNeeded += sizeof(PRINTER_INFO_3) + sizeof(SECURITY_DESCRIPTOR);
return;
}
FIXME("Return a valid security descriptor for PRINTER_INFO_3\n");
// 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 DWORD static void
_LocalEnumPrintersLevel4(DWORD Flags, PCWSTR Name, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned, DWORD cchComputerName, PWSTR wszComputerName) _LocalGetPrinterLevel4(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_4W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName)
{ {
return ERROR_INVALID_LEVEL; size_t cbPrinterName;
PWSTR p;
PWSTR pwszStrings[1];
// Calculate the string lengths.
cbPrinterName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
if (!ppPrinterInfo)
{
*pcbNeeded += sizeof(PRINTER_INFO_4W) + cbPrinterName;
return;
}
// Set the general fields.
(*ppPrinterInfo)->pServerName = NULL;
(*ppPrinterInfo)->Attributes = pPrinter->dwAttributes;
// 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);
// Finally copy the structure and advance to the next one in the output buffer.
*ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo4Offsets, *ppPrinterInfoEnd);
(*ppPrinterInfo)++;
// Free the memory for temporary strings.
DllFreeSplMem(pwszStrings[0]);
} }
static DWORD static void
_LocalEnumPrintersLevel5(DWORD Flags, PCWSTR Name, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned, DWORD cchComputerName, PWSTR wszComputerName) _LocalGetPrinterLevel5(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_5W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName)
{ {
return ERROR_INVALID_LEVEL; size_t cbPrinterName;
size_t cbPortName;
PWSTR p;
PWSTR pwszStrings[1];
// Calculate the string lengths.
cbPrinterName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
if (!ppPrinterInfo)
{
cbPortName = (wcslen(pPrinter->pPort->pwszName) + 1) * sizeof(WCHAR);
*pcbNeeded += sizeof(PRINTER_INFO_5W) + cbPrinterName + cbPortName;
return;
}
// Set the general fields.
(*ppPrinterInfo)->Attributes = pPrinter->dwAttributes;
(*ppPrinterInfo)->DeviceNotSelectedTimeout = 0;
(*ppPrinterInfo)->TransmissionRetryTimeout = 0;
// 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 void
_LocalGetPrinterLevel6(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_6* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName)
{
if (!ppPrinterInfo)
{
*pcbNeeded += sizeof(PRINTER_INFO_6);
return;
}
// Set the general fields.
(*ppPrinterInfo)->dwStatus = pPrinter->dwStatus;
// Advance to the next structure.
(*ppPrinterInfo)++;
}
static void
_LocalGetPrinterLevel7(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_7W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PWSTR wszComputerName)
{
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 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)
{
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 BOOL WINAPI
@ -575,7 +873,11 @@ LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DW
{ {
DWORD cchComputerName = 0; DWORD cchComputerName = 0;
DWORD dwErrorCode; DWORD dwErrorCode;
DWORD i;
PBYTE pPrinterInfoEnd;
PSKIPLIST_NODE pNode;
WCHAR wszComputerName[2 + MAX_COMPUTERNAME_LENGTH + 1 + 1] = { 0 }; WCHAR wszComputerName[2 + MAX_COMPUTERNAME_LENGTH + 1 + 1] = { 0 };
PLOCAL_PRINTER pPrinter;
ASSERT(pcbNeeded); ASSERT(pcbNeeded);
ASSERT(pcReturned); ASSERT(pcReturned);
@ -601,38 +903,112 @@ LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DW
goto Cleanup; 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). // Check the supplied Name parameter (if any).
// This may return a Computer Name string we later prepend to the output. // This may return a Computer Name string we later prepend to the output.
dwErrorCode = _LocalEnumPrintersCheckName(Flags, Name, wszComputerName, &cchComputerName); dwErrorCode = _LocalEnumPrintersCheckName(Flags, Name, wszComputerName, &cchComputerName);
if (dwErrorCode != ERROR_SUCCESS) if (dwErrorCode != ERROR_SUCCESS)
goto Cleanup; 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.
}
else
{
// The caller supplied an invalid level.
dwErrorCode = ERROR_INVALID_LEVEL; dwErrorCode = ERROR_INVALID_LEVEL;
goto Cleanup;
} }
// 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)
{
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: Cleanup:
SetLastError(dwErrorCode); SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS); return (dwErrorCode == ERROR_SUCCESS);