[PRINTING]

- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
  They support all features for Print Server and Printer Handles (minus security checks!)
  I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
  According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51, this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.

One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..

svn path=/trunk/; revision=75125
This commit is contained in:
Colin Finck 2017-06-19 14:18:19 +00:00
parent 483bdaa405
commit a82d7577b3
29 changed files with 1740 additions and 452 deletions

View file

@ -432,6 +432,23 @@ HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Ports","LPT1:",2,""
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Ports","LPT2:",2,""
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Ports","LPT3:",2,""
; Printing
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers",,0x00000012
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\Dummy Printer On LPT1","Attributes",0x00010001,0
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\Dummy Printer On LPT1","Datatype",,"RAW"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\Dummy Printer On LPT1","Description",,""
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\Dummy Printer On LPT1","Default DevMode",1,\
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,dc,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,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,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\Dummy Printer On LPT1","Location",,"At Home"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\Dummy Printer On LPT1","Port",,"LPT1:"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\Dummy Printer On LPT1","Print Processor",,"winprint"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\Dummy Printer On LPT1","Printer Driver",,"Dummy Printer Driver"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\Dummy Printer On LPT1","Status",0x00010001,0
; Image File Execution Options (NtGlobalFlag with FLG_SHOW_LDR_SNAPS set for loadlib.exe)
HKLM,"Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\loadlib.exe","GlobalFlag",0x00000000,"0x02000000"
;HKLM,"Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\loaddll.exe","GlobalFlag",0x00010001,0x00000002

View file

@ -1277,9 +1277,12 @@ HKLM,"SYSTEM\CurrentControlSet\Control\PnP\Pci\CardList","Ali",0x00030003,\
; Printing
HKLM,"SYSTEM\CurrentControlSet\Control\Print","BeepEnabled",0x00010001,0
HKLM,"SYSTEM\CurrentControlSet\Control\Print","MajorVersion",0x00010001,2
HKLM,"SYSTEM\CurrentControlSet\Control\Print","MinorVersion",0x00010001,0
HKLM,"SYSTEM\CurrentControlSet\Control\Print","PortThreadPriority",0x00010001,0
HKLM,"SYSTEM\CurrentControlSet\Control\Print","PriorityClass",0x00010001,0
HKLM,"SYSTEM\CurrentControlSet\Control\Print","SchedulerThreadPriority",0x00010001,0
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Environments",,0x00000010
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Environments\Windows NT x86","Directory",,"W32X86"
@ -1289,22 +1292,6 @@ HKLM,"SYSTEM\CurrentControlSet\Control\Print\Environments\Windows NT x86\Print P
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Monitors",,0x00000010
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Monitors\Local Port","Driver",,"localmon.dll"
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers",,0x00000012
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Attributes",0x00010001,0
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Datatype",,"RAW"
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Description",,""
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Default DevMode",1,\
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,dc,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Location",,"At Home"
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Port",,"LPT1:"
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Print Processor",,"winprint"
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Printer Driver",,"Dummy Printer Driver"
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Printers\Dummy Printer On LPT1","Status",0x00010001,0
HKLM,"SYSTEM\CurrentControlSet\Control\Print\Providers",,0x00000010
@ -2131,7 +2118,7 @@ HKLM,"SYSTEM\Setup","SystemPartition",0x00000000,"\Device\Harddisk0\Partition1"
HKLM,"SYSTEM\Setup","SystemSetupInProgress",0x00010001,0x00000001
; Debug channels
;HKLM,"SYSTEM\CurrentControlSet\Control\Session Manager\Environment","DEBUGCHANNEL",0x00020000,"+ole,+rpc"
HKLM,"SYSTEM\CurrentControlSet\Control\Session Manager\Environment","DEBUGCHANNEL",0x00020000,"+localspl"
; Winsrv configuration
HKLM,"SYSTEM\CurrentControlSet\Control\PriorityControl",,0x00000012

View file

@ -9,6 +9,7 @@ list(APPEND SOURCE
monitors.c
ports.c
precomp.h
printerdata.c
printers.c
printprocessors.c
tools.c)

View file

@ -43,7 +43,7 @@ _AddPrintProviderToList(PCWSTR pwszFileName)
if (!pPrintProvider)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
@ -117,7 +117,7 @@ _InitializePrintProviderList()
if (!pwszPrintProviderName)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}

View file

@ -69,7 +69,7 @@ AllocSplStr(PCWSTR pwszInput)
pwszOutput = HeapAlloc(hProcessHeap, 0, cbInput);
if (!pwszOutput)
{
ERR("HeapAlloc failed with error %lu!\n", GetLastError());
ERR("HeapAlloc failed!\n");
return NULL;
}
@ -159,7 +159,7 @@ ReallocSplMem(PVOID pOldMem, DWORD cbOld, DWORD cbNew)
pNewMem = DllAllocSplMem(cbNew);
if (!pNewMem)
{
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
return NULL;
}

View file

@ -2,7 +2,7 @@
* PROJECT: ReactOS Spooler Router
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Functions related to Print Monitors
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
* COPYRIGHT: Copyright 2015-2017 Colin Finck <colin@reactos.org>
*/
#include "precomp.h"
@ -43,6 +43,8 @@ EnumMonitorsW(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcb
continue;
// Call the EnumMonitors function of this Print Provider.
cbNeeded = 0;
dwReturned = 0;
bReturnValue = pPrintProvider->PrintProvider.fpEnumMonitors(pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
// Add the returned counts to the total values.

View file

@ -2,7 +2,7 @@
* PROJECT: ReactOS Spooler Router
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Functions related to Ports of the Print Monitors
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
* COPYRIGHT: Copyright 2015-2017 Colin Finck <colin@reactos.org>
*/
#include "precomp.h"
@ -39,6 +39,8 @@ EnumPortsW(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded
pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
// Call the EnumPorts function of this Print Provider.
cbNeeded = 0;
dwReturned = 0;
bReturnValue = pPrintProvider->PrintProvider.fpEnumPorts(pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
// Add the returned counts to the total values.

View file

@ -0,0 +1,62 @@
/*
* PROJECT: ReactOS Spooler Router
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Functions related to Printer Configuration Data
* COPYRIGHT: Copyright 2017 Colin Finck <colin@reactos.org>
*/
#include "precomp.h"
DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName, LPCWSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
{
PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
// Sanity check.
if (!pHandle)
{
// Yes, Windows checks for the handle here and sets the last error to ERROR_INVALID_HANDLE,
// but returns FALSE and not the error code.
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
// Call GetPrinterDataEx of the Print Provider.
return pHandle->pPrintProvider->PrintProvider.fpGetPrinterDataEx(pHandle->hPrinter, pKeyName, pValueName, pType, pData, nSize, pcbNeeded);
}
DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
{
// The ReactOS Printing Stack forwards all GetPrinterData calls to GetPrinterDataEx as soon as possible.
// This function may only be called if spoolss.dll is used together with Windows Printing Stack components.
WARN("This function should never be called!\n");
return GetPrinterDataExW(hPrinter, L"PrinterDriverData", pValueName, pType, pData, nSize, pcbNeeded);
}
DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName, LPCWSTR pValueName, DWORD Type, LPBYTE pData, DWORD cbData)
{
PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter;
// Sanity check.
if (!pHandle)
{
// Yes, Windows checks for the handle here and sets the last error to ERROR_INVALID_HANDLE,
// but returns FALSE and not the error code.
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
// Call SetPrinterDataEx of the Print Provider.
return pHandle->pPrintProvider->PrintProvider.fpSetPrinterDataEx(pHandle->hPrinter, pKeyName, pValueName, Type, pData, cbData);
}
DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter, PWSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData)
{
// The ReactOS Printing Stack forwards all SetPrinterData calls to SetPrinterDataEx as soon as possible.
// This function may only be called if spoolss.dll is used together with Windows Printing Stack components.
WARN("This function should never be called!\n");
return SetPrinterDataExW(hPrinter, L"PrinterDriverData", pValueName, Type, pData, cbData);
}

View file

@ -93,6 +93,8 @@ EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cb
pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry);
// Call the EnumPrinters function of this Print Provider.
cbNeeded = 0;
dwReturned = 0;
pPrintProvider->PrintProvider.fpEnumPrinters(Flags, Name, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
// Add the returned counts to the total values.
@ -159,13 +161,6 @@ OpenPrinterW(PWSTR pPrinterName, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault)
PSPOOLSS_PRINTER_HANDLE pHandle;
PSPOOLSS_PRINT_PROVIDER pPrintProvider;
// Sanity checks.
if (!pPrinterName || !phPrinter)
{
dwErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
// Loop through all Print Providers to find one able to open this Printer.
for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink)
{
@ -179,8 +174,8 @@ OpenPrinterW(PWSTR pPrinterName, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault)
pHandle = DllAllocSplMem(sizeof(SPOOLSS_PRINTER_HANDLE));
if (!pHandle)
{
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
@ -199,11 +194,11 @@ OpenPrinterW(PWSTR pPrinterName, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault)
}
}
Cleanup:
// 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);
}

View file

@ -80,8 +80,8 @@
@ stub GetJobAttributes
@ stdcall GetJobW(long long long ptr long ptr)
@ stub GetNetworkId
@ stub GetPrinterDataExW
@ stub GetPrinterDataW
@ stdcall GetPrinterDataExW(long wstr wstr ptr ptr long ptr)
@ stdcall GetPrinterDataW(long wstr ptr ptr long ptr)
@ stub GetPrinterDriverDirectoryW
@ stub GetPrinterDriverExW
@ stdcall GetPrinterDriverW(long wstr long ptr long ptr)
@ -139,8 +139,8 @@
@ stub SetFormW
@ stdcall SetJobW(long long long ptr long)
@ stub SetPortW
@ stub SetPrinterDataExW
@ stub SetPrinterDataW
@ stdcall SetPrinterDataExW(long wstr wstr long ptr long)
@ stdcall SetPrinterDataW(long wstr long ptr long)
@ stub SetPrinterW
@ stub SplCloseSpoolFileHandle
@ stub SplCommitSpoolData

View file

@ -2,7 +2,7 @@
* PROJECT: ReactOS Print Spooler Service
* LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
* PURPOSE: Functions related to Printer Configuration Data
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
* COPYRIGHT: Copyright 2015-2017 Colin Finck <colin@reactos.org>
*/
#include "precomp.h"
@ -52,27 +52,49 @@ _RpcEnumPrinterDataEx(WINSPOOL_PRINTER_HANDLE hPrinter, const WCHAR* pKeyName, B
DWORD
_RpcGetPrinterData(WINSPOOL_PRINTER_HANDLE hPrinter, WCHAR* pValueName, DWORD* pType, BYTE* pData, DWORD nSize, DWORD* pcbNeeded)
{
UNIMPLEMENTED;
return ERROR_INVALID_FUNCTION;
return _RpcGetPrinterDataEx(hPrinter, L"PrinterDriverData", pValueName, pType, pData, nSize, pcbNeeded);
}
DWORD
_RpcGetPrinterDataEx(WINSPOOL_PRINTER_HANDLE hPrinter, const WCHAR* pKeyName, const WCHAR* pValueName, DWORD* pType, BYTE* pData, DWORD nSize, DWORD* pcbNeeded)
{
UNIMPLEMENTED;
return ERROR_INVALID_FUNCTION;
DWORD dwErrorCode;
dwErrorCode = RpcImpersonateClient(NULL);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
return dwErrorCode;
}
dwErrorCode = GetPrinterDataExW(hPrinter, pKeyName, pValueName, pType, pData, nSize, pcbNeeded);
RpcRevertToSelf();
return dwErrorCode;
}
DWORD
_RpcSetPrinterData(WINSPOOL_PRINTER_HANDLE hPrinter, WCHAR* pValueName, DWORD Type, BYTE* pData, DWORD cbData)
{
UNIMPLEMENTED;
return ERROR_INVALID_FUNCTION;
return _RpcSetPrinterDataEx(hPrinter, L"PrinterDriverData", pValueName, Type, pData, cbData);
}
DWORD
_RpcSetPrinterDataEx(WINSPOOL_PRINTER_HANDLE hPrinter, const WCHAR* pKeyName, const WCHAR* pValueName, DWORD Type, BYTE* pData, DWORD cbData)
{
UNIMPLEMENTED;
return ERROR_INVALID_FUNCTION;
DWORD dwErrorCode;
dwErrorCode = RpcImpersonateClient(NULL);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RpcImpersonateClient failed with error %lu!\n", dwErrorCode);
return dwErrorCode;
}
dwErrorCode = SetPrinterDataExW(hPrinter, pKeyName, pValueName, Type, pData, cbData);
RpcRevertToSelf();
return dwErrorCode;
}

View file

@ -2,7 +2,7 @@
* PROJECT: ReactOS Spooler API
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Functions related to Printer Configuration Data
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
* COPYRIGHT: Copyright 2015-2017 Colin Finck <colin@reactos.org>
*/
#include "precomp.h"
@ -15,15 +15,327 @@ AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, PWSTR pDeviceName, PDEVM
}
DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter, PWSTR pValueName, PDWORD pType, PBYTE pData, DWORD nSize, PDWORD pcbNeeded)
GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
{
UNIMPLEMENTED;
return FALSE;
return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType, pData, nSize, pcbNeeded);
}
DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName, LPCSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
{
DWORD cbUnicodeData;
DWORD cch;
DWORD dwReturnValue;
DWORD dwType;
POSVERSIONINFOEXA pInfoA;
POSVERSIONINFOEXW pInfoW;
PVOID pUnicodeData = NULL;
PWSTR pwszKeyName = NULL;
PWSTR pwszValueName = NULL;
if (pKeyName)
{
// Convert pKeyName to a Unicode string pwszKeyName
cch = strlen(pKeyName);
pwszKeyName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
if (!pwszKeyName)
{
dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, pwszKeyName, cch + 1);
}
if (pValueName)
{
// Convert pValueName to a Unicode string pwszValueName
cch = strlen(pValueName);
pwszValueName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
if (!pwszValueName)
{
dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
MultiByteToWideChar(CP_ACP, 0, pValueName, -1, pwszValueName, cch + 1);
}
// We need the data type information, even if no pData was passed.
if (!pType)
pType = &dwType;
// Call GetPrinterDataExW for the first time.
// If we're lucky, the supplied buffer is already large enough and we don't need to do the expensive RPC call a second time.
dwReturnValue = GetPrinterDataExW(hPrinter, pwszKeyName, pwszValueName, pType, pData, nSize, pcbNeeded);
// If a critical error occurred, just return it. We cannot do anything else in this case.
if (dwReturnValue != ERROR_SUCCESS && dwReturnValue != ERROR_MORE_DATA)
goto Cleanup;
// Save the needed buffer size for the Unicode data. We may alter *pcbNeeded for an ANSI buffer size.
cbUnicodeData = *pcbNeeded;
if (*pType == REG_SZ || *pType == REG_MULTI_SZ || *pType == REG_EXPAND_SZ)
{
// This is a string that needs to be converted from Unicode to ANSI.
// Output the required buffer size for the ANSI string.
*pcbNeeded /= sizeof(WCHAR);
}
else if (*pType == REG_NONE)
{
if (cbUnicodeData == sizeof(OSVERSIONINFOW) && wcsicmp(pwszValueName, SPLREG_OS_VERSION) == 0)
{
// This is a Unicode OSVERSIONINFOW structure that needs to be converted to an ANSI OSVERSIONINFOA.
*pcbNeeded = sizeof(OSVERSIONINFOA);
}
else if (cbUnicodeData == sizeof(OSVERSIONINFOEXW) && wcsicmp(pwszValueName, SPLREG_OS_VERSIONEX) == 0)
{
// This is a Unicode OSVERSIONINFOEXW structure that needs to be converted to an ANSI OSVERSIONINFOEXA.
*pcbNeeded = sizeof(OSVERSIONINFOEXA);
}
else
{
// Other REG_NONE value, nothing to do.
goto Cleanup;
}
}
// Check if the supplied buffer is large enough for the ANSI data.
if (nSize < *pcbNeeded)
{
dwReturnValue = ERROR_MORE_DATA;
goto Cleanup;
}
// Allocate a temporary buffer for the Unicode data.
pUnicodeData = HeapAlloc(hProcessHeap, 0, cbUnicodeData);
if (!pUnicodeData)
{
dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
if (dwReturnValue == ERROR_SUCCESS)
{
// ERROR_SUCCESS: The buffer is large enough for the ANSI and the Unicode string,
// so the Unicode string has been copied into pData. Copy it to pUnicodeData.
CopyMemory(pUnicodeData, pData, cbUnicodeData);
}
else
{
// ERROR_MORE_DATA: The buffer is large enough for the ANSI string, but not for the Unicode string.
// We have to call GetPrinterDataExW again with the temporary buffer.
dwReturnValue = GetPrinterDataExW(hPrinter, pwszKeyName, pwszValueName, NULL, (PBYTE)pUnicodeData, cbUnicodeData, &cbUnicodeData);
if (dwReturnValue != ERROR_SUCCESS)
goto Cleanup;
}
if (*pType == REG_SZ || *pType == REG_MULTI_SZ || *pType == REG_EXPAND_SZ)
{
// Convert the Unicode string to ANSI.
WideCharToMultiByte(CP_ACP, 0, (PWSTR)pUnicodeData, -1, (PSTR)pData, *pcbNeeded, NULL, NULL);
}
else
{
// This is a REG_NONE with either OSVERSIONINFOW or OSVERSIONINFOEXW.
// Copy the fields and convert the Unicode CSD Version string to ANSI.
pInfoW = (POSVERSIONINFOEXW)pUnicodeData;
pInfoA = (POSVERSIONINFOEXA)pData;
pInfoA->dwMajorVersion = pInfoW->dwMajorVersion;
pInfoA->dwMinorVersion = pInfoW->dwMinorVersion;
pInfoA->dwBuildNumber = pInfoW->dwBuildNumber;
pInfoA->dwPlatformId = pInfoW->dwPlatformId;
WideCharToMultiByte(CP_ACP, 0, pInfoW->szCSDVersion, -1, pInfoA->szCSDVersion, sizeof(pInfoA->szCSDVersion), NULL, NULL);
if (cbUnicodeData == sizeof(OSVERSIONINFOW))
{
pInfoA->dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
}
else
{
pInfoA->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXA);
pInfoA->wServicePackMajor = pInfoW->wServicePackMajor;
pInfoA->wServicePackMinor = pInfoW->wServicePackMinor;
pInfoA->wSuiteMask = pInfoW->wSuiteMask;
pInfoA->wProductType = pInfoW->wProductType;
pInfoA->wReserved = pInfoW->wReserved;
}
}
Cleanup:
if (pwszKeyName)
HeapFree(hProcessHeap, 0, pwszKeyName);
if (pwszValueName)
HeapFree(hProcessHeap, 0, pwszValueName);
if (pUnicodeData)
HeapFree(hProcessHeap, 0, pUnicodeData);
return dwReturnValue;
}
DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName, LPCWSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
{
const WCHAR wszEmptyString[] = L"";
BYTE DummyData;
DWORD dwErrorCode;
DWORD dwType = REG_NONE;
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
// Sanity checks
if (!pHandle)
return ERROR_INVALID_HANDLE;
// Yes, instead of declaring these pointers unique in the IDL file (and perfectly accepting NULL pointers this way),
// Windows does it differently for GetPrinterDataExW and points them to empty variables.
if (!pKeyName)
pKeyName = wszEmptyString;
if (!pType)
pType = &dwType;
if (!pData && !nSize)
pData = &DummyData;
// Do the RPC call
RpcTryExcept
{
dwErrorCode = _RpcGetPrinterDataEx(pHandle->hPrinter, pKeyName, pValueName, pType, pData, nSize, pcbNeeded);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwErrorCode = RpcExceptionCode();
}
RpcEndExcept;
return dwErrorCode;
}
DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
{
return GetPrinterDataExW(hPrinter, L"PrinterDriverData", pValueName, pType, pData, nSize, pcbNeeded);
}
DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter, PSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData)
{
return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type, pData, cbData);
}
DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName, LPCSTR pValueName, DWORD Type, LPBYTE pData, DWORD cbData)
{
DWORD cch;
DWORD dwReturnValue;
PWSTR pwszKeyName = NULL;
PWSTR pwszValueName = NULL;
PWSTR pUnicodeData = NULL;
if (pKeyName)
{
// Convert pKeyName to a Unicode string pwszKeyName
cch = strlen(pKeyName);
pwszKeyName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
if (!pwszKeyName)
{
dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
MultiByteToWideChar(CP_ACP, 0, pKeyName, -1, pwszKeyName, cch + 1);
}
if (pValueName)
{
// Convert pValueName to a Unicode string pwszValueName
cch = strlen(pValueName);
pwszValueName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
if (!pwszValueName)
{
dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
MultiByteToWideChar(CP_ACP, 0, pValueName, -1, pwszValueName, cch + 1);
}
if (Type == REG_SZ || Type == REG_MULTI_SZ || Type == REG_EXPAND_SZ)
{
// Convert pData to a Unicode string pUnicodeData.
pUnicodeData = HeapAlloc(hProcessHeap, 0, cbData * sizeof(WCHAR));
if (!pUnicodeData)
{
dwReturnValue = ERROR_NOT_ENOUGH_MEMORY;
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
MultiByteToWideChar(CP_ACP, 0, (PCSTR)pData, -1, pUnicodeData, cbData);
pData = (PBYTE)pUnicodeData;
cbData *= sizeof(WCHAR);
}
dwReturnValue = SetPrinterDataExW(hPrinter, pwszKeyName, pwszValueName, Type, pData, cbData);
Cleanup:
if (pwszKeyName)
HeapFree(hProcessHeap, 0, pwszKeyName);
if (pwszValueName)
HeapFree(hProcessHeap, 0, pwszValueName);
if (pUnicodeData)
HeapFree(hProcessHeap, 0, pUnicodeData);
return dwReturnValue;
}
DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName, LPCWSTR pValueName, DWORD Type, LPBYTE pData, DWORD cbData)
{
const WCHAR wszEmptyString[] = L"";
DWORD dwErrorCode;
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
// Sanity checks
if (!pHandle)
return ERROR_INVALID_HANDLE;
if (!pKeyName)
pKeyName = wszEmptyString;
// Do the RPC call
RpcTryExcept
{
dwErrorCode = _RpcSetPrinterDataEx(pHandle->hPrinter, pKeyName, pValueName, Type, pData, cbData);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwErrorCode = RpcExceptionCode();
}
RpcEndExcept;
return dwErrorCode;
}
DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter, PWSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData)
{
UNIMPLEMENTED;
return FALSE;
return SetPrinterDataExW(hPrinter, L"PrinterDriverData", pValueName, Type, pData, cbData);
}

View file

@ -152,7 +152,7 @@ _StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1, PADDJOB
if (!pJobInfo1)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("HeapAlloc failed with error %lu!\n", GetLastError());
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
@ -254,7 +254,6 @@ ClosePrinter(HANDLE hPrinter)
Cleanup:
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}
DWORD WINAPI
@ -438,8 +437,8 @@ GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer)
pwszBuffer = HeapAlloc(hProcessHeap, 0, *pcchBuffer * sizeof(WCHAR));
if (!pwszBuffer)
{
dwErrorCode = GetLastError();
ERR("HeapAlloc failed with error %lu!\n", dwErrorCode);
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
}
@ -499,8 +498,8 @@ GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
pwszDevice = HeapAlloc(hProcessHeap, 0, cbNeeded);
if (!pwszDevice)
{
dwErrorCode = GetLastError();
ERR("HeapAlloc failed with error %lu!\n", dwErrorCode);
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
@ -621,7 +620,8 @@ OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefaul
pwszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
if (!pwszPrinterName)
{
ERR("HeapAlloc failed for pwszPrinterName with last error %lu!\n", GetLastError());
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
@ -640,7 +640,8 @@ OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefaul
wDefault.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
if (!wDefault.pDatatype)
{
ERR("HeapAlloc failed for wDefault.pDatatype with last error %lu!\n", GetLastError());
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
@ -676,6 +677,13 @@ OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefau
WINSPOOL_DEVMODE_CONTAINER DevModeContainer = { 0 };
ACCESS_MASK AccessRequired = 0;
// Sanity check
if (!phPrinter)
{
dwErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
// Prepare the additional parameters in the format required by _RpcOpenPrinter
if (pDefault)
{
@ -704,7 +712,7 @@ OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefau
if (!pHandle)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("HeapAlloc failed with error %lu!\n", GetLastError());
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
@ -772,7 +780,8 @@ SetDefaultPrinterA(LPCSTR pszPrinter)
pwszPrinter = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
if (!pwszPrinter)
{
ERR("HeapAlloc failed for pwszPrinter with last error %lu!\n", GetLastError());
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
@ -854,8 +863,8 @@ SetDefaultPrinterW(LPCWSTR pszPrinter)
pwszDeviceValueData = HeapAlloc(hProcessHeap, 0, cbDeviceValueData);
if (!pwszDeviceValueData)
{
dwErrorCode = GetLastError();
ERR("HeapAlloc failed with error %lu\n", dwErrorCode);
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
@ -936,7 +945,8 @@ StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
wDocInfo1.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
if (!wDocInfo1.pDatatype)
{
ERR("HeapAlloc failed for wDocInfo1.pDatatype with last error %lu!\n", GetLastError());
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
@ -951,7 +961,8 @@ StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
wDocInfo1.pDocName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
if (!wDocInfo1.pDocName)
{
ERR("HeapAlloc failed for wDocInfo1.pDocName with last error %lu!\n", GetLastError());
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
@ -966,7 +977,8 @@ StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
wDocInfo1.pOutputFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
if (!wDocInfo1.pOutputFile)
{
ERR("HeapAlloc failed for wDocInfo1.pOutputFile with last error %lu!\n", GetLastError());
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
@ -1040,7 +1052,7 @@ StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
if (!pAddJobInfo1)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("HeapAlloc failed with error %lu!\n", GetLastError());
ERR("HeapAlloc failed!\n");
goto Cleanup;
}

View file

@ -2,7 +2,7 @@
* PROJECT: ReactOS Spooler API
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Functions related to Print Processors
* COPYRIGHT: Copyright 2015-2016 Colin Finck <colin@reactos.org>
* COPYRIGHT: Copyright 2015-2017 Colin Finck <colin@reactos.org>
*/
#include "precomp.h"
@ -129,7 +129,8 @@ GetPrintProcessorDirectoryA(PSTR pName, PSTR pEnvironment, DWORD Level, PBYTE pP
pwszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
if (!pwszName)
{
ERR("HeapAlloc failed for pwszName with last error %lu!\n", GetLastError());
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
@ -144,7 +145,8 @@ GetPrintProcessorDirectoryA(PSTR pName, PSTR pEnvironment, DWORD Level, PBYTE pP
pwszEnvironment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
if (!pwszEnvironment)
{
ERR("HeapAlloc failed for pwszEnvironment with last error %lu!\n", GetLastError());
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
@ -159,7 +161,8 @@ GetPrintProcessorDirectoryA(PSTR pName, PSTR pEnvironment, DWORD Level, PBYTE pP
pwszPrintProcessorInfo = HeapAlloc(hProcessHeap, 0, cbBuf);
if (!pwszPrintProcessorInfo)
{
ERR("HeapAlloc failed for pwszPrintProcessorInfo with last error %lu!\n", GetLastError());
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
ERR("HeapAlloc failed!\n");
goto Cleanup;
}
}

View file

@ -147,9 +147,9 @@
246 stdcall GetPrintProcessorDirectoryA(str str long ptr long ptr)
247 stdcall GetPrintProcessorDirectoryW(wstr wstr long ptr long ptr)
248 stdcall GetPrinterA(long long ptr long ptr)
249 stub GetPrinterDataA
250 stub GetPrinterDataExA
251 stub GetPrinterDataExW
249 stdcall GetPrinterDataA(long str ptr ptr long ptr)
250 stdcall GetPrinterDataExA(long str str ptr ptr long ptr)
251 stdcall GetPrinterDataExW(long wstr wstr ptr ptr long ptr)
252 stdcall GetPrinterDataW(long wstr ptr ptr long ptr)
253 stdcall GetPrinterDriverA(long str long ptr long ptr)
254 stdcall -stub GetPrinterDriverDirectoryA(str str long ptr long ptr)
@ -181,9 +181,9 @@
280 stub SetPortA
281 stub SetPortW
282 stub SetPrinterA
283 stub SetPrinterDataA
284 stub SetPrinterDataExA
285 stub SetPrinterDataExW
283 stdcall SetPrinterDataA(long str long ptr long)
284 stdcall SetPrinterDataExA(long str str long ptr long)
285 stdcall SetPrinterDataExW(long wstr wstr long ptr long)
286 stdcall SetPrinterDataW(long wstr long ptr long)
287 stdcall SetPrinterW(long long ptr long)
288 stub SplDriverUnloadComplete

View file

@ -9,6 +9,7 @@ list(APPEND SOURCE
monitors.c
ports.c
precomp.h
printerdata.c
printers.c
printingthread.c
printprocessors.c
@ -22,6 +23,6 @@ add_library(localspl SHARED
set_module_type(localspl win32dll UNICODE)
target_link_libraries(localspl skiplist16 wine)
add_importlibs(localspl advapi32 rpcrt4 spoolss msvcrt kernel32 ntdll)
add_importlibs(localspl advapi32 netapi32 rpcrt4 secur32 spoolss msvcrt kernel32 ntdll)
add_pch(localspl precomp.h SOURCE)
add_cd_file(TARGET localspl DESTINATION reactos/system32 FOR all)

View file

@ -2,7 +2,7 @@
* PROJECT: ReactOS Local Spooler
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Functions for managing print jobs
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
* COPYRIGHT: Copyright 2015-2017 Colin Finck <colin@reactos.org>
*/
#include "precomp.h"
@ -135,26 +135,20 @@ _PrinterJobListCompareRoutine(PVOID FirstStruct, PVOID SecondStruct)
DWORD
GetJobFilePath(PCWSTR pwszExtension, DWORD dwJobID, PWSTR pwszOutput)
{
const WCHAR wszPrintersPath[] = L"\\PRINTERS\\";
const DWORD cchPrintersPath = _countof(wszPrintersPath) - 1;
const DWORD cchSpoolerFile = sizeof("?????.") - 1;
const DWORD cchExtension = sizeof("SPL") - 1; // pwszExtension may be L"SPL" or L"SHD", same length for both!
if (pwszOutput)
{
CopyMemory(pwszOutput, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR));
CopyMemory(&pwszOutput[cchSpoolDirectory], wszPrintersPath, cchPrintersPath * sizeof(WCHAR));
swprintf(&pwszOutput[cchSpoolDirectory + cchPrintersPath], L"%05lu.", dwJobID);
CopyMemory(&pwszOutput[cchSpoolDirectory + cchPrintersPath + cchSpoolerFile], pwszExtension, (cchExtension + 1) * sizeof(WCHAR));
CopyMemory(pwszOutput, wszJobDirectory, cchJobDirectory * sizeof(WCHAR));
swprintf(&pwszOutput[cchJobDirectory], L"\\%05lu.%s", dwJobID, pwszExtension);
}
return (cchSpoolDirectory + cchPrintersPath + cchSpoolerFile + cchExtension + 1) * sizeof(WCHAR);
// pwszExtension may be L"SPL" or L"SHD", same length for both!
return (cchJobDirectory + sizeof("\\?????.SPL")) * sizeof(WCHAR);
}
BOOL
InitializeGlobalJobList()
{
const WCHAR wszPath[] = L"\\PRINTERS\\?????.SHD";
const WCHAR wszPath[] = L"\\?????.SHD";
const DWORD cchPath = _countof(wszPath) - 1;
DWORD dwErrorCode;
@ -173,8 +167,8 @@ InitializeGlobalJobList()
InitializeSkiplist(&GlobalJobList, DllAllocSplMem, _GlobalJobListCompareRoutine, (PSKIPLIST_FREE_ROUTINE)DllFreeSplMem);
// Construct the full path search pattern.
CopyMemory(wszFullPath, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR));
CopyMemory(&wszFullPath[cchSpoolDirectory], wszPath, (cchPath + 1) * sizeof(WCHAR));
CopyMemory(wszFullPath, wszJobDirectory, cchJobDirectory * sizeof(WCHAR));
CopyMemory(&wszFullPath[cchJobDirectory], wszPath, (cchPath + 1) * sizeof(WCHAR));
// Use the search pattern to look for unfinished jobs serialized in shadow files (.SHD)
hFind = FindFirstFileW(wszFullPath, &FindData);
@ -262,7 +256,7 @@ CreateJob(PLOCAL_PRINTER_HANDLE pPrinterHandle)
if (!pJob)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
@ -1209,7 +1203,7 @@ ReadJobShadowFile(PCWSTR pwszFilePath)
pShadowFile = DllAllocSplMem(cbFileSize);
if (!pShadowFile)
{
ERR("DllAllocSplMem failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
ERR("DllAllocSplMem failed for file \"%S\"!\n", pwszFilePath);
goto Cleanup;
}
@ -1249,7 +1243,7 @@ ReadJobShadowFile(PCWSTR pwszFilePath)
pJob = DllAllocSplMem(sizeof(LOCAL_JOB));
if (!pJob)
{
ERR("DllAllocSplMem failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
ERR("DllAllocSplMem failed for file \"%S\"!\n", pwszFilePath);
goto Cleanup;
}
@ -1341,7 +1335,7 @@ WriteJobShadowFile(PWSTR pwszFilePath, const PLOCAL_JOB pJob)
pShadowFile = DllAllocSplMem(cbFileSize);
if (!pShadowFile)
{
ERR("DllAllocSplMem failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
ERR("DllAllocSplMem failed for file \"%S\"!\n", pwszFilePath);
goto Cleanup;
}

View file

@ -8,12 +8,20 @@
#include "precomp.h"
// Global Variables
HKEY hPrintKey = NULL;
HKEY hPrintersKey = NULL;
WCHAR wszJobDirectory[MAX_PATH];
DWORD cchJobDirectory;
WCHAR wszSpoolDirectory[MAX_PATH];
DWORD cchSpoolDirectory;
// Global Constants
#include <prtprocenv.h>
/** This is what the Spooler of Windows Server 2003 returns (for example using GetPrinterDataExW, SPLREG_MAJOR_VERSION/SPLREG_MINOR_VERSION) */
const DWORD dwSpoolerMajorVersion = 3;
const DWORD dwSpoolerMinorVersion = 0;
const WCHAR wszDefaultDocumentName[] = L"Local Downlevel Document";
PWSTR wszPrintProviderInfo[3] = {
@ -52,8 +60,8 @@ static const PRINTPROVIDOR _PrintProviderFunctions = {
LocalEndDocPrinter, // fpEndDocPrinter
LocalAddJob, // fpAddJob
LocalScheduleJob, // fpScheduleJob
NULL, // fpGetPrinterData
NULL, // fpSetPrinterData
LocalGetPrinterData, // fpGetPrinterData
LocalSetPrinterData, // fpSetPrinterData
NULL, // fpWaitForPrinterChange
LocalClosePrinter, // fpClosePrinter
NULL, // fpAddForm
@ -89,8 +97,8 @@ static const PRINTPROVIDOR _PrintProviderFunctions = {
NULL, // fpClusterSplOpen
NULL, // fpClusterSplClose
NULL, // fpClusterSplIsAlive
NULL, // fpSetPrinterDataEx
NULL, // fpGetPrinterDataEx
LocalSetPrinterDataEx, // fpSetPrinterDataEx
LocalGetPrinterDataEx, // fpGetPrinterDataEx
NULL, // fpEnumPrinterDataEx
NULL, // fpEnumPrinterKey
NULL, // fpDeletePrinterDataEx
@ -112,17 +120,112 @@ static const PRINTPROVIDOR _PrintProviderFunctions = {
NULL, // fpAddDriverCatalog
};
static void
_GetSpoolDirectory()
static BOOL
_InitializeLocalSpooler(void)
{
const WCHAR wszPrintersPath[] = L"\\PRINTERS";
const DWORD cchPrintersPath = _countof(wszPrintersPath) - 1;
const WCHAR wszSpoolPath[] = L"\\spool";
const DWORD cchSpoolPath = _countof(wszSpoolPath) - 1;
const WCHAR wszSymbolicLinkValue[] = L"REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers";
const DWORD cbSymbolicLinkValue = sizeof(wszSymbolicLinkValue) - sizeof(WCHAR);
// Get the system directory and append the "spool" subdirectory.
BOOL bReturnValue = FALSE;
DWORD cbData;
DWORD dwErrorCode;
HKEY hKey;
// On startup, always create a volatile symbolic link in the registry if it doesn't exist yet.
// "SYSTEM\CurrentControlSet\Control\Print\Printers" -> "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers"
//
// According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51
// this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive.
dwErrorCode = (DWORD)RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Print\\Printers", 0, NULL, REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK, KEY_CREATE_LINK | KEY_SET_VALUE, NULL, &hKey, NULL);
if (dwErrorCode == ERROR_SUCCESS)
{
// Note that wszSymbolicLink has to be stored WITHOUT the terminating null character for the symbolic link to work!
// See cbSymbolicLinkValue above.
dwErrorCode = (DWORD)RegSetValueExW(hKey, L"SymbolicLinkValue", 0, REG_LINK, (PBYTE)wszSymbolicLinkValue, cbSymbolicLinkValue);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegSetValueExW failed for the Printers symlink with error %lu!\n", dwErrorCode);
goto Cleanup;
}
}
else if (dwErrorCode != ERROR_ALREADY_EXISTS)
{
ERR("RegCreateKeyExW failed for the Printers symlink with error %lu!\n", dwErrorCode);
goto Cleanup;
}
// Open some registry keys and leave them open. We need them multiple times throughout the Local Spooler.
dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Print", 0, KEY_ALL_ACCESS, &hPrintKey);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW failed for \"Print\" with error %lu!\n", dwErrorCode);
goto Cleanup;
}
dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers", 0, KEY_ALL_ACCESS, &hPrintersKey);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW failed for \"Printers\" with error %lu!\n", dwErrorCode);
goto Cleanup;
}
// Construct the path to "%SystemRoot%\system32\spool".
// Forget about length checks here. If this doesn't fit into MAX_PATH, our OS has more serious problems...
cchSpoolDirectory = GetSystemDirectoryW(wszSpoolDirectory, MAX_PATH);
CopyMemory(&wszSpoolDirectory[cchSpoolDirectory], wszSpoolPath, (cchSpoolPath + 1) * sizeof(WCHAR));
cchSpoolDirectory += cchSpoolPath;
// Query the job directory.
cbData = sizeof(wszJobDirectory);
dwErrorCode = (DWORD)RegQueryValueExW(hPrintersKey, SPLREG_DEFAULT_SPOOL_DIRECTORY, NULL, NULL, (PBYTE)wszJobDirectory, &cbData);
if (dwErrorCode == ERROR_SUCCESS)
{
cchJobDirectory = cbData / sizeof(WCHAR) - 1;
}
else if (dwErrorCode == ERROR_FILE_NOT_FOUND)
{
// Use the default "%SystemRoot%\system32\spool\PRINTERS".
CopyMemory(wszJobDirectory, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR));
CopyMemory(&wszJobDirectory[cchSpoolDirectory], wszPrintersPath, (cchPrintersPath + 1) * sizeof(WCHAR));
cchJobDirectory = cchSpoolDirectory + cchPrintersPath;
// Save this for next time.
RegSetValueExW(hPrintersKey, SPLREG_DEFAULT_SPOOL_DIRECTORY, 0, REG_SZ, (PBYTE)wszJobDirectory, (cchJobDirectory + 1) * sizeof(WCHAR));
}
else
{
ERR("RegQueryValueExW failed for \"%S\" with error %lu!\n", SPLREG_DEFAULT_SPOOL_DIRECTORY, dwErrorCode);
goto Cleanup;
}
// Initialize all lists.
if (!InitializePrintMonitorList())
goto Cleanup;
if (!InitializePortList())
goto Cleanup;
if (!InitializePrintProcessorList())
goto Cleanup;
if (!InitializePrinterList())
goto Cleanup;
if (!InitializeGlobalJobList())
goto Cleanup;
// Local Spooler Initialization finished successfully!
bReturnValue = TRUE;
Cleanup:
if (hKey)
RegCloseKey(hKey);
return bReturnValue;
}
BOOL WINAPI
@ -132,13 +235,7 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
_GetSpoolDirectory();
return InitializePrintMonitorList() &&
InitializePortList() &&
InitializePrintProcessorList() &&
InitializePrinterList() &&
InitializeGlobalJobList();
return _InitializeLocalSpooler();
default:
return TRUE;

View file

@ -2,7 +2,7 @@
* PROJECT: ReactOS Local Spooler
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Functions related to Print Monitors
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
* COPYRIGHT: Copyright 2015-2017 Colin Finck <colin@reactos.org>
*/
#include "precomp.h"
@ -103,7 +103,7 @@ InitializePrintMonitorList()
if (!pPrintMonitor)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
@ -112,7 +112,7 @@ InitializePrintMonitorList()
if (!pPrintMonitor->pwszName)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
@ -177,7 +177,7 @@ InitializePrintMonitorList()
if (!pwszRegistryPath)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}

View file

@ -2,7 +2,7 @@
* PROJECT: ReactOS Local Spooler
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Functions related to Ports of the Print Monitors
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
* COPYRIGHT: Copyright 2015-2017 Colin Finck <colin@reactos.org>
*/
#include "precomp.h"
@ -79,7 +79,7 @@ InitializePortList()
if (!pPortInfo1)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
@ -108,7 +108,7 @@ InitializePortList()
if (!pPort)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
@ -165,6 +165,9 @@ LocalEnumPorts(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNe
pPrintMonitor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_MONITOR, Entry);
// Call the EnumPorts function of this Print Monitor.
cbNeeded = 0;
dwReturned = 0;
if (pPrintMonitor->bIsLevel2)
bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnEnumPorts(pPrintMonitor->hMonitor, pName, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned);
else

View file

@ -22,6 +22,8 @@
#include <winreg.h>
#include <winspool.h>
#include <winsplp.h>
#include <dsrole.h>
#include <secext.h>
#include <ndk/rtlfuncs.h>
#define SKIPLIST_LEVELS 16
@ -195,6 +197,7 @@ struct _LOCAL_HANDLE
enum {
HandleType_Port, /** pSpecificHandle is a PLOCAL_PORT_HANDLE. */
HandleType_Printer, /** pSpecificHandle is a PLOCAL_PRINTER_HANDLE. */
HandleType_PrintServer, /** pSpecificHandle is NULL (no additional information needed for a handle to the Print Server) */
HandleType_Xcv /** pSpecificHandle is a PLOCAL_XCV_HANDLE. */
}
HandleType;
@ -256,8 +259,14 @@ BOOL WriteJobShadowFile(PWSTR pwszFilePath, const PLOCAL_JOB pJob);
// main.c
extern const WCHAR wszCurrentEnvironment[];
extern const DWORD cbCurrentEnvironment;
extern const DWORD dwSpoolerMajorVersion;
extern const DWORD dwSpoolerMinorVersion;
extern const WCHAR wszDefaultDocumentName[];
extern HKEY hPrintKey;
extern HKEY hPrintersKey;
extern PWSTR wszPrintProviderInfo[3];
extern WCHAR wszJobDirectory[MAX_PATH];
extern DWORD cchJobDirectory;
extern WCHAR wszSpoolDirectory[MAX_PATH];
extern DWORD cchSpoolDirectory;
@ -272,6 +281,12 @@ PLOCAL_PORT FindPort(PCWSTR pwszName);
BOOL InitializePortList();
BOOL WINAPI LocalEnumPorts(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned);
// printerdata.c
DWORD WINAPI LocalGetPrinterData(HANDLE hPrinter, PWSTR pValueName, PDWORD pType, PBYTE pData, DWORD nSize, PDWORD pcbNeeded);
DWORD WINAPI LocalGetPrinterDataEx(HANDLE hPrinter, PCWSTR pKeyName, PCWSTR pValueName, PDWORD pType, PBYTE pData, DWORD nSize, PDWORD pcbNeeded);
DWORD WINAPI LocalSetPrinterData(HANDLE hPrinter, PWSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData);
DWORD WINAPI LocalSetPrinterDataEx(HANDLE hPrinter, LPCWSTR pKeyName, LPCWSTR pValueName, DWORD Type, LPBYTE pData, DWORD cbData);
// printers.c
extern SKIPLIST PrinterList;
BOOL InitializePrinterList();

View file

@ -0,0 +1,478 @@
/*
* PROJECT: ReactOS Local Spooler
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Functions related to Printer Configuration Data
* COPYRIGHT: Copyright 2017 Colin Finck <colin@reactos.org>
*/
#include "precomp.h"
DWORD WINAPI
LocalGetPrinterData(HANDLE hPrinter, PWSTR pValueName, PDWORD pType, PBYTE pData, DWORD nSize, PDWORD pcbNeeded)
{
// The ReactOS Printing Stack forwards all GetPrinterData calls to GetPrinterDataEx as soon as possible.
// This function may only be called if localspl.dll is used together with Windows Printing Stack components.
WARN("This function should never be called!\n");
return LocalGetPrinterDataEx(hPrinter, L"PrinterDriverData", pValueName, pType, pData, nSize, pcbNeeded);
}
static DWORD
_MakePrinterSubKey(PLOCAL_PRINTER_HANDLE pPrinterHandle, PCWSTR pKeyName, PWSTR* ppwszSubKey)
{
const WCHAR wszBackslash[] = L"\\";
size_t cbSubKey;
PWSTR p;
// Sanity check
if (!pKeyName)
return ERROR_INVALID_PARAMETER;
// Allocate a buffer for the subkey "PrinterName\KeyName".
cbSubKey = (wcslen(pPrinterHandle->pPrinter->pwszPrinterName) + 1 + wcslen(pKeyName) + 1) * sizeof(WCHAR);
*ppwszSubKey = DllAllocSplMem(cbSubKey);
if (!*ppwszSubKey)
return ERROR_NOT_ENOUGH_MEMORY;
// Concatenate the subkey.
p = *ppwszSubKey;
StringCbCopyExW(p, cbSubKey, pPrinterHandle->pPrinter->pwszPrinterName, &p, &cbSubKey, 0);
StringCbCopyExW(p, cbSubKey, wszBackslash, &p, &cbSubKey, 0);
StringCbCopyExW(p, cbSubKey, pKeyName, &p, &cbSubKey, 0);
return ERROR_SUCCESS;
}
static DWORD
_LocalGetPrinterHandleData(PLOCAL_PRINTER_HANDLE pPrinterHandle, PCWSTR pKeyName, PCWSTR pValueName, PDWORD pType, PBYTE pData, DWORD nSize, PDWORD pcbNeeded)
{
DWORD dwErrorCode;
HKEY hKey = NULL;
PWSTR pwszSubKey = NULL;
dwErrorCode = _MakePrinterSubKey(pPrinterHandle, pKeyName, &pwszSubKey);
if (dwErrorCode != ERROR_SUCCESS)
goto Cleanup;
// Open the subkey.
dwErrorCode = (DWORD)RegOpenKeyExW(hPrintersKey, pwszSubKey, 0, KEY_READ, &hKey);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW failed for \"%S\" with error %lu!\n", pwszSubKey, dwErrorCode);
goto Cleanup;
}
// Query the desired value.
*pcbNeeded = nSize;
dwErrorCode = (DWORD)RegQueryValueExW(hKey, pValueName, NULL, pType, pData, pcbNeeded);
Cleanup:
if (hKey)
RegCloseKey(hKey);
if (pwszSubKey)
DllFreeSplMem(pwszSubKey);
return dwErrorCode;
}
static DWORD
_LocalGetPrintServerHandleData(PCWSTR pValueName, PDWORD pType, PBYTE pData, DWORD nSize, PDWORD pcbNeeded)
{
DWORD dwErrorCode;
if (wcsicmp(pValueName, SPLREG_DEFAULT_SPOOL_DIRECTORY) == 0 ||
wcsicmp(pValueName, SPLREG_PORT_THREAD_PRIORITY) == 0 ||
wcsicmp(pValueName, SPLREG_SCHEDULER_THREAD_PRIORITY) == 0 ||
wcsicmp(pValueName, SPLREG_BEEP_ENABLED) == 0 ||
wcsicmp(pValueName, SPLREG_ALLOW_USER_MANAGEFORMS) == 0)
{
*pcbNeeded = nSize;
return (DWORD)RegQueryValueExW(hPrintersKey, pValueName, NULL, pType, pData, pcbNeeded);
}
else if (wcsicmp(pValueName, SPLREG_PORT_THREAD_PRIORITY_DEFAULT) == 0 ||
wcsicmp(pValueName, SPLREG_SCHEDULER_THREAD_PRIORITY_DEFAULT) == 0)
{
// Store a DWORD value as REG_NONE.
*pType = REG_NONE;
*pcbNeeded = sizeof(DWORD);
if (nSize < *pcbNeeded)
return ERROR_MORE_DATA;
// Apparently, these values don't serve a purpose anymore.
*((PDWORD)pData) = 0;
return ERROR_SUCCESS;
}
else if (wcsicmp(pValueName, SPLREG_NET_POPUP) == 0 ||
wcsicmp(pValueName, SPLREG_RETRY_POPUP) == 0 ||
wcsicmp(pValueName, SPLREG_NET_POPUP_TO_COMPUTER) == 0 ||
wcsicmp(pValueName, SPLREG_EVENT_LOG) == 0 ||
wcsicmp(pValueName, SPLREG_RESTART_JOB_ON_POOL_ERROR) == 0 ||
wcsicmp(pValueName, SPLREG_RESTART_JOB_ON_POOL_ENABLED) == 0)
{
HKEY hKey;
dwErrorCode = (DWORD)RegOpenKeyExW(hPrintKey, L"Providers", 0, KEY_READ, &hKey);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW failed for \"Providers\" with error %lu!\n", dwErrorCode);
return dwErrorCode;
}
*pcbNeeded = nSize;
dwErrorCode = (DWORD)RegQueryValueExW(hKey, pValueName, NULL, pType, pData, pcbNeeded);
RegCloseKey(hKey);
return dwErrorCode;
}
else if (wcsicmp(pValueName, SPLREG_MAJOR_VERSION) == 0)
{
// Store a DWORD value as REG_NONE.
*pType = REG_NONE;
*pcbNeeded = sizeof(DWORD);
if (nSize < *pcbNeeded)
return ERROR_MORE_DATA;
// Apparently, these values don't serve a purpose anymore.
*((PDWORD)pData) = dwSpoolerMajorVersion;
return ERROR_SUCCESS;
}
else if (wcsicmp(pValueName, SPLREG_MINOR_VERSION) == 0)
{
// Store a DWORD value as REG_NONE.
*pType = REG_NONE;
*pcbNeeded = sizeof(DWORD);
if (nSize < *pcbNeeded)
return ERROR_MORE_DATA;
// Apparently, these values don't serve a purpose anymore.
*((PDWORD)pData) = dwSpoolerMinorVersion;
return ERROR_SUCCESS;
}
else if (wcsicmp(pValueName, SPLREG_ARCHITECTURE) == 0)
{
// Store a string as REG_NONE with the length of the environment name string.
*pType = REG_NONE;
*pcbNeeded = cbCurrentEnvironment;
if (nSize < *pcbNeeded)
return ERROR_MORE_DATA;
// Copy the environment name as the output value for SPLREG_ARCHITECTURE.
CopyMemory(pData, wszCurrentEnvironment, cbCurrentEnvironment);
return ERROR_SUCCESS;
}
else if (wcsicmp(pValueName, SPLREG_OS_VERSION) == 0)
{
POSVERSIONINFOW pInfo = (POSVERSIONINFOW)pData;
// Store the OSVERSIONINFOW structure as REG_NONE.
*pType = REG_NONE;
*pcbNeeded = sizeof(OSVERSIONINFOW);
if (nSize < *pcbNeeded)
return ERROR_MORE_DATA;
// Return OS version information.
pInfo->dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
GetVersionExW(pInfo);
return ERROR_SUCCESS;
}
else if (wcsicmp(pValueName, SPLREG_OS_VERSIONEX) == 0)
{
POSVERSIONINFOEXW pInfo = (POSVERSIONINFOEXW)pData;
// Store the OSVERSIONINFOEXW structure as REG_NONE.
*pType = REG_NONE;
*pcbNeeded = sizeof(OSVERSIONINFOEXW);
if (nSize < *pcbNeeded)
return ERROR_MORE_DATA;
// Return extended OS version information.
pInfo->dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
GetVersionExW((POSVERSIONINFOW)pInfo);
return ERROR_SUCCESS;
}
else if (wcsicmp(pValueName, SPLREG_DS_PRESENT) == 0)
{
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pInfo;
// We want to store a REG_DWORD value.
*pType = REG_DWORD;
*pcbNeeded = sizeof(DWORD);
if (nSize < *pcbNeeded)
return ERROR_MORE_DATA;
// Get information about the domain membership of this computer.
dwErrorCode = DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE*)&pInfo);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("DsRoleGetPrimaryDomainInformation failed with error %lu!\n", GetLastError());
return dwErrorCode;
}
// Return whether this computer is a workstation or server inside a domain.
*((PDWORD)pData) = (pInfo->MachineRole == DsRole_RoleMemberWorkstation || pInfo->MachineRole == DsRole_RoleMemberServer);
DsRoleFreeMemory(pInfo);
return ERROR_SUCCESS;
}
else if (wcsicmp(pValueName, SPLREG_DS_PRESENT_FOR_USER) == 0)
{
DWORD cch;
PWSTR pwszUserSam;
PWSTR p;
WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH + 1];
// We want to store a REG_DWORD value.
*pType = REG_DWORD;
*pcbNeeded = sizeof(DWORD);
if (nSize < *pcbNeeded)
return ERROR_MORE_DATA;
// Get the local Computer Name.
cch = MAX_COMPUTERNAME_LENGTH + 1;
if (!GetComputerNameW(wszComputerName, &cch))
{
ERR("GetComputerNameW failed with error %lu!\n", GetLastError());
return GetLastError();
}
// Get the User Name in the SAM format.
// This could either be:
// COMPUTERNAME\User
// DOMAINNAME\User
cch = 0;
GetUserNameExW(NameSamCompatible, NULL, &cch);
dwErrorCode = GetLastError();
if (dwErrorCode != ERROR_MORE_DATA)
{
ERR("GetUserNameExW failed with error %lu!\n", dwErrorCode);
return dwErrorCode;
}
pwszUserSam = DllAllocSplMem(cch * sizeof(WCHAR));
if (!pwszUserSam)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed!\n");
return dwErrorCode;
}
if (!GetUserNameExW(NameSamCompatible, pwszUserSam, &cch))
{
dwErrorCode = GetLastError();
ERR("GetUserNameExW failed with error %lu!\n", dwErrorCode);
DllFreeSplMem(pwszUserSam);
return dwErrorCode;
}
// Terminate the SAM-formatted User Name at the backslash.
p = wcschr(pwszUserSam, L'\\');
*p = 0;
// Compare it with the Computer Name.
// If they differ, this User is part of a domain.
*((PDWORD)pData) = (wcscmp(pwszUserSam, wszComputerName) != 0);
DllFreeSplMem(pwszUserSam);
return ERROR_SUCCESS;
}
else if (wcsicmp(pValueName, SPLREG_REMOTE_FAX) == 0)
{
// Store a DWORD value as REG_NONE.
*pType = REG_NONE;
*pcbNeeded = sizeof(DWORD);
if (nSize < *pcbNeeded)
return ERROR_MORE_DATA;
// TODO: We don't support any fax service yet, but let's return the same value as Windows Server 2003 here.
*((PDWORD)pData) = 1;
return ERROR_SUCCESS;
}
else if (wcsicmp(pValueName, SPLREG_DNS_MACHINE_NAME) == 0)
{
DWORD cchDnsName = 0;
// Get the length of the fully-qualified computer DNS name.
GetComputerNameExW(ComputerNameDnsFullyQualified, NULL, &cchDnsName);
dwErrorCode = GetLastError();
if (dwErrorCode != ERROR_MORE_DATA)
{
ERR("GetComputerNameExW failed with error %lu!\n", dwErrorCode);
return dwErrorCode;
}
// Check if our supplied buffer is large enough.
*pType = REG_SZ;
*pcbNeeded = cchDnsName * sizeof(WCHAR);
if (nSize < *pcbNeeded)
return ERROR_MORE_DATA;
// Get the actual DNS name.
if (!GetComputerNameExW(ComputerNameDnsFullyQualified, (PWSTR)pData, &cchDnsName))
{
dwErrorCode = GetLastError();
ERR("GetComputerNameExW failed with error %lu!\n", dwErrorCode);
return dwErrorCode;
}
// Lowercase the output just like Windows does.
_wcslwr((PWSTR)pData);
return ERROR_SUCCESS;
}
else
{
// For all other, unknown settings, we just return ERROR_INVALID_PARAMETER.
// That also includes SPLREG_WEBSHAREMGMT, which is supported in Windows Server 2003 according to the documentation,
// but is actually not!
return ERROR_INVALID_PARAMETER;
}
}
DWORD WINAPI
LocalGetPrinterDataEx(HANDLE hPrinter, PCWSTR pKeyName, PCWSTR pValueName, PDWORD pType, PBYTE pData, DWORD nSize, PDWORD pcbNeeded)
{
DWORD dwErrorCode;
DWORD dwTemp;
PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
// Even if GetPrinterDataExW in winspool ensures that the RPC function is never called without a valid pointer for pType,
// it's officially optional. Windows' fpGetPrinterDataEx also works with NULL for pType!
// Ensure here that it is always set to simplify the code later.
if (!pType)
pType = &dwTemp;
if (!pHandle)
{
dwErrorCode = ERROR_INVALID_HANDLE;
}
else if (!pcbNeeded)
{
dwErrorCode = ERROR_INVALID_PARAMETER;
}
else if (pHandle->HandleType == HandleType_Printer)
{
dwErrorCode = _LocalGetPrinterHandleData(pHandle->pSpecificHandle, pKeyName, pValueName, pType, pData, nSize, pcbNeeded);
}
else if (pHandle->HandleType == HandleType_PrintServer)
{
dwErrorCode = _LocalGetPrintServerHandleData(pValueName, pType, pData, nSize, pcbNeeded);
}
else
{
dwErrorCode = ERROR_INVALID_HANDLE;
}
SetLastError(dwErrorCode);
return dwErrorCode;
}
DWORD WINAPI
LocalSetPrinterData(HANDLE hPrinter, PWSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData)
{
// The ReactOS Printing Stack forwards all SetPrinterData calls to SetPrinterDataEx as soon as possible.
// This function may only be called if localspl.dll is used together with Windows Printing Stack components.
WARN("This function should never be called!\n");
return LocalSetPrinterDataEx(hPrinter, L"PrinterDriverData", pValueName, Type, pData, cbData);
}
static DWORD
_LocalSetPrinterHandleData(PLOCAL_PRINTER_HANDLE pPrinterHandle, PCWSTR pKeyName, PCWSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData)
{
DWORD dwErrorCode;
HKEY hKey = NULL;
PWSTR pwszSubKey = NULL;
dwErrorCode = _MakePrinterSubKey(pPrinterHandle, pKeyName, &pwszSubKey);
if (dwErrorCode != ERROR_SUCCESS)
goto Cleanup;
// Open the subkey.
dwErrorCode = (DWORD)RegOpenKeyExW(hPrintersKey, pwszSubKey, 0, KEY_SET_VALUE, &hKey);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW failed for \"%S\" with error %lu!\n", pwszSubKey, dwErrorCode);
goto Cleanup;
}
// Set the value.
dwErrorCode = (DWORD)RegSetValueExW(hKey, pValueName, 0, Type, pData, cbData);
Cleanup:
if (hKey)
RegCloseKey(hKey);
if (pwszSubKey)
DllFreeSplMem(pwszSubKey);
return dwErrorCode;
}
static DWORD
_LocalSetPrintServerHandleData(PCWSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData)
{
DWORD dwErrorCode;
if (wcsicmp(pValueName, SPLREG_DEFAULT_SPOOL_DIRECTORY) == 0 ||
wcsicmp(pValueName, SPLREG_PORT_THREAD_PRIORITY) == 0 ||
wcsicmp(pValueName, SPLREG_SCHEDULER_THREAD_PRIORITY) == 0 ||
wcsicmp(pValueName, SPLREG_BEEP_ENABLED) == 0 ||
wcsicmp(pValueName, SPLREG_ALLOW_USER_MANAGEFORMS) == 0)
{
return (DWORD)RegSetValueExW(hPrintersKey, pValueName, 0, Type, pData, cbData);
}
else if (wcsicmp(pValueName, SPLREG_NET_POPUP) == 0 ||
wcsicmp(pValueName, SPLREG_RETRY_POPUP) == 0 ||
wcsicmp(pValueName, SPLREG_NET_POPUP_TO_COMPUTER) == 0 ||
wcsicmp(pValueName, SPLREG_EVENT_LOG) == 0 ||
wcsicmp(pValueName, SPLREG_RESTART_JOB_ON_POOL_ERROR) == 0 ||
wcsicmp(pValueName, SPLREG_RESTART_JOB_ON_POOL_ENABLED) == 0 ||
wcsicmp(pValueName, L"NoRemotePrinterDrivers") == 0)
{
HKEY hKey;
dwErrorCode = (DWORD)RegOpenKeyExW(hPrintKey, L"Providers", 0, KEY_SET_VALUE, &hKey);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW failed for \"Providers\" with error %lu!\n", dwErrorCode);
return dwErrorCode;
}
dwErrorCode = (DWORD)RegSetValueExW(hKey, pValueName, 0, Type, pData, cbData);
RegCloseKey(hKey);
return dwErrorCode;
}
else if (wcsicmp(pValueName, SPLREG_WEBSHAREMGMT) == 0)
{
WARN("Attempting to set WebShareMgmt, which is based on IIS and therefore not supported. Returning fake success!\n");
return ERROR_SUCCESS;
}
else
{
// For all other, unknown settings, we just return ERROR_INVALID_PARAMETER.
return ERROR_INVALID_PARAMETER;
}
}
DWORD WINAPI
LocalSetPrinterDataEx(HANDLE hPrinter, PCWSTR pKeyName, PCWSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData)
{
DWORD dwErrorCode;
PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
if (!pHandle)
{
dwErrorCode = ERROR_INVALID_HANDLE;
}
else if (pHandle->HandleType == HandleType_Printer)
{
dwErrorCode = _LocalSetPrinterHandleData(pHandle->pSpecificHandle, pKeyName, pValueName, Type, pData, cbData);
}
else if (pHandle->HandleType == HandleType_PrintServer)
{
dwErrorCode = _LocalSetPrintServerHandleData(pValueName, Type, pData, cbData);
}
else
{
dwErrorCode = ERROR_INVALID_HANDLE;
}
SetLastError(dwErrorCode);
return dwErrorCode;
}

View file

@ -106,14 +106,11 @@ _PrinterListCompareRoutine(PVOID FirstStruct, PVOID SecondStruct)
BOOL
InitializePrinterList()
{
const WCHAR wszPrintersKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Printers";
DWORD cbData;
DWORD cchPrinterName;
DWORD dwErrorCode;
DWORD dwSubKeys;
DWORD i;
HKEY hKey = NULL;
HKEY hSubKey = NULL;
PLOCAL_PORT pPort;
PLOCAL_PRINTER pPrinter = NULL;
@ -125,16 +122,8 @@ InitializePrinterList()
// Initialize an empty list for our printers.
InitializeSkiplist(&PrinterList, DllAllocSplMem, _PrinterListCompareRoutine, (PSKIPLIST_FREE_ROUTINE)DllFreeSplMem);
// Open our printers registry key. Each subkey is a local printer there.
dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszPrintersKey, 0, KEY_READ, &hKey);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
goto Cleanup;
}
// Get the number of subkeys.
dwErrorCode = (DWORD)RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &dwSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
// Get the number of subkeys of the printers registry key. Each subkey is a local printer there.
dwErrorCode = (DWORD)RegQueryInfoKeyW(hPrintersKey, NULL, NULL, NULL, &dwSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode);
@ -180,7 +169,7 @@ InitializePrinterList()
// Get the name of this printer.
cchPrinterName = _countof(wszPrinterName);
dwErrorCode = (DWORD)RegEnumKeyExW(hKey, i, wszPrinterName, &cchPrinterName, NULL, NULL, NULL, NULL);
dwErrorCode = (DWORD)RegEnumKeyExW(hPrintersKey, i, wszPrinterName, &cchPrinterName, NULL, NULL, NULL, NULL);
if (dwErrorCode == ERROR_MORE_DATA)
{
// This printer name exceeds the maximum length and is invalid.
@ -193,7 +182,7 @@ InitializePrinterList()
}
// Open this Printer's registry key.
dwErrorCode = (DWORD)RegOpenKeyExW(hKey, wszPrinterName, 0, KEY_READ, &hSubKey);
dwErrorCode = (DWORD)RegOpenKeyExW(hPrintersKey, wszPrinterName, 0, KEY_READ, &hSubKey);
if (dwErrorCode != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW failed for Printer \"%S\" with status %lu!\n", wszPrinterName, dwErrorCode);
@ -231,7 +220,7 @@ InitializePrinterList()
if (!pPrinter)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
@ -280,7 +269,7 @@ InitializePrinterList()
if (!pPrinter->pDefaultDevMode)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
@ -351,10 +340,6 @@ Cleanup:
if (pwszPrintProcessor)
DllFreeSplStr(pwszPrintProcessor);
// Outside the loop
if (hKey)
RegCloseKey(hKey);
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}
@ -885,8 +870,8 @@ LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DW
WCHAR wszComputerName[2 + MAX_COMPUTERNAME_LENGTH + 1 + 1] = { 0 };
PLOCAL_PRINTER pPrinter;
ASSERT(pcbNeeded);
ASSERT(pcReturned);
// Do no sanity checks or assertions for pcbNeeded and pcReturned here.
// This is verified and required by localspl_apitest!
// Begin counting.
*pcbNeeded = 0;
@ -984,6 +969,13 @@ LocalGetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDW
PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
PLOCAL_PRINTER_HANDLE pPrinterHandle;
// Sanity checks.
if (!pHandle)
{
dwErrorCode = ERROR_INVALID_HANDLE;
goto Cleanup;
}
// Check if this is a printer handle.
if (pHandle->HandleType != HandleType_Printer)
{
@ -1020,41 +1012,358 @@ Cleanup:
return (dwErrorCode == ERROR_SUCCESS);
}
BOOL WINAPI
LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDefault)
static DWORD
_LocalOpenPortHandle(PWSTR pwszPortName, PHANDLE phPrinter)
{
BOOL bReturnValue;
DWORD cchComputerName;
DWORD cchFirstParameter;
DWORD dwErrorCode;
DWORD dwJobID;
HANDLE hExternalHandle;
PWSTR p = lpPrinterName;
PWSTR pwszFirstParameter = NULL;
PWSTR pwszSecondParameter = NULL;
PLOCAL_JOB pJob;
HANDLE hPort;
PLOCAL_HANDLE pHandle = NULL;
PLOCAL_PORT pPort;
PLOCAL_PORT_HANDLE pPortHandle = NULL;
PLOCAL_PRINT_MONITOR pPrintMonitor;
PLOCAL_PRINTER pPrinter;
PLOCAL_PRINTER_HANDLE pPrinterHandle = NULL;
PLOCAL_XCV_HANDLE pXcvHandle = NULL;
WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH + 1];
WCHAR wszFullPath[MAX_PATH];
// TODO: lpPrinterName == NULL is supported and means access to the local printer server.
// Not sure yet if that is passed down to localspl.dll or processed in advance.
// Sanity checks
if (!lpPrinterName || !phPrinter)
// Look for this port in our Print Monitor Port list.
pPort = FindPort(pwszPortName);
if (!pPort)
{
dwErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
// The supplied port is unknown to all our Print Monitors.
dwErrorCode = ERROR_INVALID_NAME;
goto Failure;
}
pPrintMonitor = pPort->pPrintMonitor;
// Call the monitor's OpenPort function.
if (pPrintMonitor->bIsLevel2)
bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnOpenPort(pPrintMonitor->hMonitor, pwszPortName, &hPort);
else
bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnOpenPort(pwszPortName, &hPort);
if (!bReturnValue)
{
// The OpenPort function failed. Return its last error.
dwErrorCode = GetLastError();
goto Failure;
}
// Create a new generic handle.
pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
if (!pHandle)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed!\n");
goto Failure;
}
// Create a new LOCAL_PORT_HANDLE.
pPortHandle = DllAllocSplMem(sizeof(LOCAL_PORT_HANDLE));
if (!pPortHandle)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed!\n");
goto Failure;
}
pPortHandle->hPort = hPort;
pPortHandle->pPort = pPort;
// Make the generic handle a Port handle.
pHandle->HandleType = HandleType_Port;
pHandle->pSpecificHandle = pPortHandle;
// Return it.
*phPrinter = (HANDLE)pHandle;
return ERROR_SUCCESS;
Failure:
if (pHandle)
DllFreeSplMem(pHandle);
if (pPortHandle)
DllFreeSplMem(pPortHandle);
return dwErrorCode;
}
static DWORD
_LocalOpenPrinterHandle(PWSTR pwszPrinterName, PWSTR pwszJobParameter, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault)
{
DWORD dwErrorCode;
DWORD dwJobID;
PLOCAL_HANDLE pHandle = NULL;
PLOCAL_JOB pJob;
PLOCAL_PRINTER pPrinter;
PLOCAL_PRINTER_HANDLE pPrinterHandle = NULL;
WCHAR wszFullPath[MAX_PATH];
// Retrieve the printer from the list.
pPrinter = LookupElementSkiplist(&PrinterList, &pwszPrinterName, NULL);
if (!pPrinter)
{
// The printer does not exist.
dwErrorCode = ERROR_INVALID_NAME;
goto Failure;
}
// Create a new LOCAL_PRINTER_HANDLE.
pPrinterHandle = DllAllocSplMem(sizeof(LOCAL_PRINTER_HANDLE));
if (!pPrinterHandle)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed!\n");
goto Failure;
}
pPrinterHandle->hSPLFile = INVALID_HANDLE_VALUE;
pPrinterHandle->pPrinter = pPrinter;
// Check if a datatype was given.
if (pDefault && pDefault->pDatatype)
{
// Use the datatype if it's valid.
if (!FindDatatype(pPrinter->pPrintProcessor, pDefault->pDatatype))
{
dwErrorCode = ERROR_INVALID_DATATYPE;
goto Failure;
}
pPrinterHandle->pwszDatatype = AllocSplStr(pDefault->pDatatype);
}
else
{
// Use the default datatype.
pPrinterHandle->pwszDatatype = AllocSplStr(pPrinter->pwszDefaultDatatype);
}
// Check if a DevMode was given, otherwise use the default.
if (pDefault && pDefault->pDevMode)
pPrinterHandle->pDevMode = DuplicateDevMode(pDefault->pDevMode);
else
pPrinterHandle->pDevMode = DuplicateDevMode(pPrinter->pDefaultDevMode);
// Check if the caller wants a handle to an existing Print Job.
if (pwszJobParameter)
{
// The "Job " string has to follow now.
if (wcsncmp(pwszJobParameter, L"Job ", 4) != 0)
{
dwErrorCode = ERROR_INVALID_NAME;
goto Failure;
}
// Skip the "Job " string.
pwszJobParameter += 4;
// Skip even more whitespace.
while (*pwszJobParameter == ' ')
++pwszJobParameter;
// Finally extract the desired Job ID.
dwJobID = wcstoul(pwszJobParameter, NULL, 10);
if (!IS_VALID_JOB_ID(dwJobID))
{
// The user supplied an invalid Job ID.
dwErrorCode = ERROR_INVALID_NAME;
goto Failure;
}
// Look for this job in the Global Job List.
pJob = LookupElementSkiplist(&GlobalJobList, &dwJobID, NULL);
if (!pJob || pJob->pPrinter != pPrinter)
{
// The user supplied a non-existing Job ID or the Job ID does not belong to the supplied printer name.
dwErrorCode = ERROR_INVALID_PRINTER_NAME;
goto Failure;
}
// Try to open its SPL file.
GetJobFilePath(L"SPL", dwJobID, wszFullPath);
pPrinterHandle->hSPLFile = CreateFileW(wszFullPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (pPrinterHandle->hSPLFile == INVALID_HANDLE_VALUE)
{
dwErrorCode = GetLastError();
ERR("CreateFileW failed with error %lu for \"%S\"!", dwErrorCode, wszFullPath);
goto Failure;
}
// Associate the job to our Printer Handle, but don't set bStartedDoc.
// This prevents the caller from doing further StartDocPrinter, WritePrinter, etc. calls on it.
pPrinterHandle->pJob = pJob;
}
// Make the generic handle a Port handle.
pHandle->HandleType = HandleType_Printer;
pHandle->pSpecificHandle = pPrinterHandle;
// Return it.
*phPrinter = (HANDLE)pHandle;
return ERROR_SUCCESS;
Failure:
if (pHandle)
DllFreeSplMem(pHandle);
if (pPrinterHandle)
{
if (pPrinterHandle->pwszDatatype)
DllFreeSplStr(pPrinterHandle->pwszDatatype);
if (pPrinterHandle->pDevMode)
DllFreeSplMem(pPrinterHandle->pDevMode);
DllFreeSplMem(pPrinterHandle);
}
return dwErrorCode;
}
static DWORD
_LocalOpenPrintServerHandle(PHANDLE phPrinter)
{
PLOCAL_HANDLE pHandle;
// Create a new generic handle.
pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
if (!pHandle)
{
ERR("DllAllocSplMem failed!\n");
return ERROR_NOT_ENOUGH_MEMORY;
}
// Make the generic handle a Print Server handle.
pHandle->HandleType = HandleType_PrintServer;
pHandle->pSpecificHandle = NULL;
// Return it.
*phPrinter = (HANDLE)pHandle;
return ERROR_SUCCESS;
}
static DWORD
_LocalOpenXcvHandle(PWSTR pwszParameter, PHANDLE phPrinter)
{
BOOL bReturnValue;
DWORD dwErrorCode;
HANDLE hXcv;
PLOCAL_HANDLE pHandle = NULL;
PLOCAL_PORT pPort;
PLOCAL_PRINT_MONITOR pPrintMonitor;
PLOCAL_XCV_HANDLE pXcvHandle = NULL;
// Skip the "Xcv" string.
pwszParameter += 3;
// Is XcvMonitor or XcvPort requested?
if (wcsncmp(pwszParameter, L"Monitor ", 8) == 0)
{
// Skip the "Monitor " string.
pwszParameter += 8;
// Look for this monitor in our Print Monitor list.
pPrintMonitor = FindPrintMonitor(pwszParameter);
if (!pPrintMonitor)
{
// The caller supplied a non-existing Monitor name.
dwErrorCode = ERROR_INVALID_NAME;
goto Failure;
}
}
else if (wcsncmp(pwszParameter, L"Port ", 5) == 0)
{
// Skip the "Port " string.
pwszParameter += 5;
// Look for this port in our Print Monitor Port list.
pPort = FindPort(pwszParameter);
if (!pPort)
{
// The supplied port is unknown to all our Print Monitors.
dwErrorCode = ERROR_INVALID_NAME;
goto Failure;
}
pPrintMonitor = pPort->pPrintMonitor;
}
else
{
dwErrorCode = ERROR_INVALID_NAME;
goto Failure;
}
// Call the monitor's XcvOpenPort function.
if (pPrintMonitor->bIsLevel2)
bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnXcvOpenPort(pPrintMonitor->hMonitor, pwszParameter, SERVER_EXECUTE, &hXcv);
else
bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnXcvOpenPort(pwszParameter, SERVER_EXECUTE, &hXcv);
if (!bReturnValue)
{
// The XcvOpenPort function failed. Return its last error.
dwErrorCode = GetLastError();
goto Failure;
}
// Create a new generic handle.
pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
if (!pHandle)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed!\n");
goto Failure;
}
// Create a new LOCAL_XCV_HANDLE.
pXcvHandle = DllAllocSplMem(sizeof(LOCAL_XCV_HANDLE));
if (!pXcvHandle)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed!\n");
goto Failure;
}
pXcvHandle->hXcv = hXcv;
pXcvHandle->pPrintMonitor = pPrintMonitor;
// Make the generic handle a Xcv handle.
pHandle->HandleType = HandleType_Xcv;
pHandle->pSpecificHandle = pXcvHandle;
// Return it.
*phPrinter = (HANDLE)pHandle;
return ERROR_SUCCESS;
Failure:
if (pHandle)
DllFreeSplMem(pHandle);
if (pXcvHandle)
DllFreeSplMem(pXcvHandle);
return dwErrorCode;
}
BOOL WINAPI
LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDefault)
{
DWORD cchComputerName;
DWORD cchFirstParameter;
DWORD dwErrorCode;
PWSTR p = lpPrinterName;
PWSTR pwszFirstParameter = NULL;
PWSTR pwszSecondParameter;
WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH + 1];
ASSERT(phPrinter);
*phPrinter = NULL;
if (!lpPrinterName)
{
// The caller wants a Print Server handle and provided a NULL string.
dwErrorCode = _LocalOpenPrintServerHandle(phPrinter);
goto Cleanup;
}
// Skip any server name in the first parameter.
// Does lpPrinterName begin with two backslashes to indicate a server name?
if (lpPrinterName[0] == L'\\' && lpPrinterName[1] == L'\\')
@ -1062,14 +1371,10 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
// Skip these two backslashes.
lpPrinterName += 2;
// Look for the closing backslash.
p = wcschr(lpPrinterName, L'\\');
if (!p)
{
// We didn't get a proper server name.
dwErrorCode = ERROR_INVALID_PRINTER_NAME;
goto Cleanup;
}
// Look for the terminating null character or closing backslash.
p = lpPrinterName;
while (*p != L'\0' && *p != L'\\')
p++;
// Get the local computer name for comparison.
cchComputerName = _countof(wszComputerName);
@ -1085,7 +1390,16 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
// This print provider only supports local printers, so both strings have to match.
if (p - lpPrinterName != cchComputerName || _wcsnicmp(lpPrinterName, wszComputerName, cchComputerName) != 0)
{
dwErrorCode = ERROR_INVALID_PRINTER_NAME;
dwErrorCode = ERROR_INVALID_NAME;
goto Cleanup;
}
// If lpPrinterName is only "\\COMPUTERNAME" with nothing more, the caller wants a handle to the local Print Server.
if (!*p)
{
// The caller wants a Print Server handle and provided a string like:
// "\\COMPUTERNAME"
dwErrorCode = _LocalOpenPrintServerHandle(phPrinter);
goto Cleanup;
}
@ -1103,7 +1417,7 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
// We must have at least one parameter.
if (!cchFirstParameter && !pwszSecondParameter)
{
dwErrorCode = ERROR_INVALID_PRINTER_NAME;
dwErrorCode = ERROR_INVALID_NAME;
goto Cleanup;
}
@ -1127,61 +1441,13 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
++pwszSecondParameter;
}
// Create a new handle.
pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
if (!pHandle)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
// Now we can finally check the type of handle actually requested.
if (pwszFirstParameter && pwszSecondParameter && wcsncmp(pwszSecondParameter, L"Port", 4) == 0)
{
// The caller wants a port handle and provided a string like:
// "LPT1:, Port"
// "\\COMPUTERNAME\LPT1:, Port"
// Look for this port in our Print Monitor Port list.
pPort = FindPort(pwszFirstParameter);
if (!pPort)
{
// The supplied port is unknown to all our Print Monitors.
dwErrorCode = ERROR_INVALID_PRINTER_NAME;
goto Cleanup;
}
pPrintMonitor = pPort->pPrintMonitor;
// Call the monitor's OpenPort function.
if (pPrintMonitor->bIsLevel2)
bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnOpenPort(pPrintMonitor->hMonitor, pwszFirstParameter, &hExternalHandle);
else
bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnOpenPort(pwszFirstParameter, &hExternalHandle);
if (!bReturnValue)
{
// The OpenPort function failed. Return its last error.
dwErrorCode = GetLastError();
goto Cleanup;
}
// Create a new LOCAL_PORT_HANDLE.
pPortHandle = DllAllocSplMem(sizeof(LOCAL_PORT_HANDLE));
if (!pPortHandle)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
pPortHandle->hPort = hExternalHandle;
pPortHandle->pPort = pPort;
// Return the Port handle through our general handle.
pHandle->HandleType = HandleType_Port;
pHandle->pSpecificHandle = pPortHandle;
dwErrorCode = _LocalOpenPortHandle(pwszFirstParameter, phPrinter);
}
else if (!pwszFirstParameter && pwszSecondParameter && wcsncmp(pwszSecondParameter, L"Xcv", 3) == 0)
{
@ -1190,75 +1456,7 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
// "\\COMPUTERNAME\, XcvMonitor Local Port"
// ", XcvPort LPT1:"
// "\\COMPUTERNAME\, XcvPort LPT1:"
// Skip the "Xcv" string.
pwszSecondParameter += 3;
// Is XcvMonitor or XcvPort requested?
if (wcsncmp(pwszSecondParameter, L"Monitor ", 8) == 0)
{
// Skip the "Monitor " string.
pwszSecondParameter += 8;
// Look for this monitor in our Print Monitor list.
pPrintMonitor = FindPrintMonitor(pwszSecondParameter);
if (!pPrintMonitor)
{
// The caller supplied a non-existing Monitor name.
dwErrorCode = ERROR_INVALID_PRINTER_NAME;
goto Cleanup;
}
}
else if (wcsncmp(pwszSecondParameter, L"Port ", 5) == 0)
{
// Skip the "Port " string.
pwszSecondParameter += 5;
// Look for this port in our Print Monitor Port list.
pPort = FindPort(pwszFirstParameter);
if (!pPort)
{
// The supplied port is unknown to all our Print Monitors.
dwErrorCode = ERROR_INVALID_PRINTER_NAME;
goto Cleanup;
}
pPrintMonitor = pPort->pPrintMonitor;
}
else
{
dwErrorCode = ERROR_INVALID_PRINTER_NAME;
goto Cleanup;
}
// Call the monitor's XcvOpenPort function.
if (pPrintMonitor->bIsLevel2)
bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnXcvOpenPort(pPrintMonitor->hMonitor, pwszSecondParameter, SERVER_EXECUTE, &hExternalHandle);
else
bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnXcvOpenPort(pwszSecondParameter, SERVER_EXECUTE, &hExternalHandle);
if (!bReturnValue)
{
// The XcvOpenPort function failed. Return its last error.
dwErrorCode = GetLastError();
goto Cleanup;
}
// Create a new LOCAL_XCV_HANDLE.
pXcvHandle = DllAllocSplMem(sizeof(LOCAL_XCV_HANDLE));
if (!pXcvHandle)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
pXcvHandle->hXcv = hExternalHandle;
pXcvHandle->pPrintMonitor = pPrintMonitor;
// Return the Xcv handle through our general handle.
pHandle->HandleType = HandleType_Xcv;
pHandle->pSpecificHandle = pXcvHandle;
dwErrorCode = _LocalOpenXcvHandle(pwszSecondParameter, phPrinter);
}
else
{
@ -1267,130 +1465,10 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
// "\\COMPUTERNAME\HP DeskJet"
// "HP DeskJet, Job 5"
// "\\COMPUTERNAME\HP DeskJet, Job 5"
// Retrieve the printer from the list.
pPrinter = LookupElementSkiplist(&PrinterList, &pwszFirstParameter, NULL);
if (!pPrinter)
{
// The printer does not exist.
dwErrorCode = ERROR_INVALID_PRINTER_NAME;
goto Cleanup;
}
// Create a new LOCAL_PRINTER_HANDLE.
pPrinterHandle = DllAllocSplMem(sizeof(LOCAL_PRINTER_HANDLE));
if (!pPrinterHandle)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
pPrinterHandle->hSPLFile = INVALID_HANDLE_VALUE;
pPrinterHandle->pPrinter = pPrinter;
// Check if a datatype was given.
if (pDefault && pDefault->pDatatype)
{
// Use the datatype if it's valid.
if (!FindDatatype(pPrinter->pPrintProcessor, pDefault->pDatatype))
{
dwErrorCode = ERROR_INVALID_DATATYPE;
goto Cleanup;
}
pPrinterHandle->pwszDatatype = AllocSplStr(pDefault->pDatatype);
}
else
{
// Use the default datatype.
pPrinterHandle->pwszDatatype = AllocSplStr(pPrinter->pwszDefaultDatatype);
}
// Check if a DevMode was given, otherwise use the default.
if (pDefault && pDefault->pDevMode)
pPrinterHandle->pDevMode = DuplicateDevMode(pDefault->pDevMode);
else
pPrinterHandle->pDevMode = DuplicateDevMode(pPrinter->pDefaultDevMode);
// Check if the caller wants a handle to an existing Print Job.
if (pwszSecondParameter)
{
// The "Job " string has to follow now.
if (wcsncmp(pwszSecondParameter, L"Job ", 4) != 0)
{
dwErrorCode = ERROR_INVALID_PRINTER_NAME;
goto Cleanup;
}
// Skip the "Job " string.
pwszSecondParameter += 4;
// Skip even more whitespace.
while (*pwszSecondParameter == ' ')
++pwszSecondParameter;
// Finally extract the desired Job ID.
dwJobID = wcstoul(pwszSecondParameter, NULL, 10);
if (!IS_VALID_JOB_ID(dwJobID))
{
// The user supplied an invalid Job ID.
dwErrorCode = ERROR_INVALID_PRINTER_NAME;
goto Cleanup;
}
// Look for this job in the Global Job List.
pJob = LookupElementSkiplist(&GlobalJobList, &dwJobID, NULL);
if (!pJob || pJob->pPrinter != pPrinter)
{
// The user supplied a non-existing Job ID or the Job ID does not belong to the supplied printer name.
dwErrorCode = ERROR_INVALID_PRINTER_NAME;
goto Cleanup;
}
// Try to open its SPL file.
GetJobFilePath(L"SPL", dwJobID, wszFullPath);
pPrinterHandle->hSPLFile = CreateFileW(wszFullPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (pPrinterHandle->hSPLFile == INVALID_HANDLE_VALUE)
{
dwErrorCode = GetLastError();
ERR("CreateFileW failed with error %lu for \"%S\"!", dwErrorCode, wszFullPath);
goto Cleanup;
}
// Associate the job to our Printer Handle, but don't set bStartedDoc.
// This prevents the caller from doing further StartDocPrinter, WritePrinter, etc. calls on it.
pPrinterHandle->pJob = pJob;
}
// Return the Printer handle through our general handle.
pHandle->HandleType = HandleType_Printer;
pHandle->pSpecificHandle = pPrinterHandle;
dwErrorCode = _LocalOpenPrinterHandle(pwszFirstParameter, pwszSecondParameter, phPrinter, pDefault);
}
// We were successful! Return the handle.
*phPrinter = (HANDLE)pHandle;
dwErrorCode = ERROR_SUCCESS;
// Don't let the cleanup routines free this.
pHandle = NULL;
pPrinterHandle = NULL;
Cleanup:
if (pHandle)
DllFreeSplMem(pHandle);
if (pPrinterHandle)
{
if (pPrinterHandle->pwszDatatype)
DllFreeSplStr(pPrinterHandle->pwszDatatype);
if (pPrinterHandle->pDevMode)
DllFreeSplMem(pPrinterHandle->pDevMode);
DllFreeSplMem(pPrinterHandle);
}
if (pwszFirstParameter)
DllFreeSplMem(pwszFirstParameter);
@ -1778,13 +1856,42 @@ Cleanup:
return (dwErrorCode == ERROR_SUCCESS);
}
static void
_LocalClosePortHandle(PLOCAL_PORT_HANDLE pPortHandle)
{
// Call the monitor's ClosePort function.
if (pPortHandle->pPort->pPrintMonitor->bIsLevel2)
((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnClosePort(pPortHandle->hPort);
else
((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnClosePort(pPortHandle->hPort);
}
static void
_LocalClosePrinterHandle(PLOCAL_PRINTER_HANDLE pPrinterHandle)
{
// Terminate any started job.
if (pPrinterHandle->pJob)
FreeJob(pPrinterHandle->pJob);
// Free memory for the fields.
DllFreeSplMem(pPrinterHandle->pDevMode);
DllFreeSplStr(pPrinterHandle->pwszDatatype);
}
static void
_LocalCloseXcvHandle(PLOCAL_XCV_HANDLE pXcvHandle)
{
// Call the monitor's XcvClosePort function.
if (pXcvHandle->pPrintMonitor->bIsLevel2)
((PMONITOR2)pXcvHandle->pPrintMonitor->pMonitor)->pfnXcvClosePort(pXcvHandle->hXcv);
else
((LPMONITOREX)pXcvHandle->pPrintMonitor->pMonitor)->Monitor.pfnXcvClosePort(pXcvHandle->hXcv);
}
BOOL WINAPI
LocalClosePrinter(HANDLE hPrinter)
{
PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
PLOCAL_PORT_HANDLE pPortHandle;
PLOCAL_PRINTER_HANDLE pPrinterHandle;
PLOCAL_XCV_HANDLE pXcvHandle;
if (!pHandle)
{
@ -1794,39 +1901,25 @@ LocalClosePrinter(HANDLE hPrinter)
if (pHandle->HandleType == HandleType_Port)
{
pPortHandle = (PLOCAL_PORT_HANDLE)pHandle->pSpecificHandle;
// Call the monitor's ClosePort function.
if (pPortHandle->pPort->pPrintMonitor->bIsLevel2)
((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnClosePort(pPortHandle->hPort);
else
((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnClosePort(pPortHandle->hPort);
_LocalClosePortHandle(pHandle->pSpecificHandle);
}
else if (pHandle->HandleType == HandleType_Printer)
{
pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
// Terminate any started job.
if (pPrinterHandle->pJob)
FreeJob(pPrinterHandle->pJob);
// Free memory for the fields.
DllFreeSplMem(pPrinterHandle->pDevMode);
DllFreeSplStr(pPrinterHandle->pwszDatatype);
_LocalClosePrinterHandle(pHandle->pSpecificHandle);
}
else if (pHandle->HandleType == HandleType_PrintServer)
{
// Nothing to do.
}
else if (pHandle->HandleType == HandleType_Xcv)
{
pXcvHandle = (PLOCAL_XCV_HANDLE)pHandle->pSpecificHandle;
// Call the monitor's XcvClosePort function.
if (pXcvHandle->pPrintMonitor->bIsLevel2)
((PMONITOR2)pXcvHandle->pPrintMonitor->pMonitor)->pfnXcvClosePort(pXcvHandle->hXcv);
else
((LPMONITOREX)pXcvHandle->pPrintMonitor->pMonitor)->Monitor.pfnXcvClosePort(pXcvHandle->hXcv);
_LocalCloseXcvHandle(pHandle->pSpecificHandle);
}
// Free memory for the handle and the specific handle.
DllFreeSplMem(pHandle->pSpecificHandle);
// Free memory for the handle and the specific handle (if any).
if (pHandle->pSpecificHandle)
DllFreeSplMem(pHandle->pSpecificHandle);
DllFreeSplMem(pHandle);
return TRUE;

View file

@ -2,7 +2,7 @@
* PROJECT: ReactOS Local Spooler
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Implementation of the Thread that actually performs the printing process
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
* COPYRIGHT: Copyright 2015-2017 Colin Finck <colin@reactos.org>
*/
#include "precomp.h"
@ -32,7 +32,7 @@ PrintingThreadProc(PLOCAL_JOB pJob)
if (!pwszPrinterPort)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
@ -71,7 +71,7 @@ PrintingThreadProc(PLOCAL_JOB pJob)
if (!pwszPrinterAndJob)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
@ -100,7 +100,7 @@ PrintingThreadProc(PLOCAL_JOB pJob)
if (!pwszSPLFile)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}

View file

@ -2,7 +2,7 @@
* PROJECT: ReactOS Local Spooler
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Functions related to Print Processors
* COPYRIGHT: Copyright 2015-2016 Colin Finck <colin@reactos.org>
* COPYRIGHT: Copyright 2015-2017 Colin Finck <colin@reactos.org>
*/
#include "precomp.h"
@ -48,7 +48,8 @@ _OpenEnvironment(PCWSTR pEnvironment, PHKEY hKey)
pwszEnvironmentKey = DllAllocSplMem((cchEnvironmentsKey + cchEnvironment + 1) * sizeof(WCHAR));
if (!pwszEnvironmentKey)
{
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
@ -205,7 +206,7 @@ InitializePrintProcessorList()
if (!pPrintProcessor)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
@ -214,7 +215,7 @@ InitializePrintProcessorList()
if (!pPrintProcessor->pwszName)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
@ -311,7 +312,7 @@ InitializePrintProcessorList()
if (!pPrintProcessor->pDatatypesInfo1)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
@ -514,7 +515,7 @@ LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE
if (!pwszTemp)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}

View file

@ -2,7 +2,7 @@
* PROJECT: ReactOS Local Spooler
* LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
* PURPOSE: Various tools
* COPYRIGHT: Copyright 2015 Colin Finck <colin@reactos.org>
* COPYRIGHT: Copyright 2015-2017 Colin Finck <colin@reactos.org>
*/
#include "precomp.h"
@ -41,7 +41,7 @@ AllocAndRegQueryWSZ(HKEY hKey, PCWSTR pwszValueName)
pwszValue = DllAllocSplMem(cbNeeded);
if (!pwszValue)
{
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
return NULL;
}
@ -66,7 +66,7 @@ DuplicateDevMode(PDEVMODEW pInput)
pOutput = DllAllocSplMem(pInput->dmSize + pInput->dmDriverExtra);
if (!pOutput)
{
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
ERR("DllAllocSplMem failed!\n");
return NULL;
}

View file

@ -4,6 +4,7 @@ list(APPEND SOURCE
EnumPrinters.c
EnumPrintProcessorDatatypes.c
GetDefaultPrinter.c
GetPrinterData.c
GetPrintProcessorDirectory.c
IsValidDevmode.c
OpenPrinter.c

View file

@ -0,0 +1,188 @@
/*
* PROJECT: ReactOS Print Spooler DLL API Tests
* LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
* PURPOSE: Tests for GetPrinterData(Ex)A/GetPrinterData(Ex)W/SetPrinterData(Ex)A/SetPrinterData(Ex)W
* COPYRIGHT: Copyright 2017 Colin Finck <colin@reactos.org>
*/
#include <apitest.h>
#define WIN32_NO_STATUS
#include <windef.h>
#include <winbase.h>
#include <wingdi.h>
#include <winspool.h>
#include <winreg.h>
/* From printing/include/spoolss.h */
#define MAX_PRINTER_NAME 220
typedef struct _SPLREG_VALUE
{
PSTR pszName;
PWSTR pwszName;
DWORD dwType;
DWORD cbNeededA;
BOOL bSettable;
}
SPLREG_VALUE, *PSPLREG_VALUE;
SPLREG_VALUE SplRegValues[] = {
#if 0
{ "DefaultSpoolDirectory", L"DefaultSpoolDirectory", REG_SZ, 0xFFFFFFFF, TRUE },
{ "PortThreadPriorityDefault", L"PortThreadPriorityDefault", REG_NONE, 4, FALSE },
{ "PortThreadPriority", L"PortThreadPriority", REG_DWORD, 4, TRUE },
{ "SchedulerThreadPriorityDefault", L"SchedulerThreadPriorityDefault", REG_NONE, 4, FALSE },
{ "SchedulerThreadPriority", L"SchedulerThreadPriority", REG_DWORD, 4, TRUE },
{ "BeepEnabled", L"BeepEnabled", REG_DWORD, 4, TRUE },
/* These fail in Win8, probably removed since NT6:
{ "NetPopup", L"NetPopup", REG_DWORD, 4, TRUE },
{ "RetryPopup", L"RetryPopup", REG_DWORD, 4, TRUE },
{ "NetPopupToComputer", L"NetPopupToComputer", REG_DWORD, 4, TRUE },
*/
{ "EventLog", L"EventLog", REG_DWORD, 4, TRUE },
{ "MajorVersion", L"MajorVersion", REG_NONE, 4, FALSE },
{ "MinorVersion", L"MinorVersion", REG_NONE, 4, FALSE },
{ "Architecture", L"Architecture", REG_NONE, 0xFFFFFFFF, FALSE },
{ "OSVersion", L"OSVersion", REG_NONE, sizeof(OSVERSIONINFOA), FALSE },
{ "OSVersionEx", L"OSVersionEx", REG_NONE, sizeof(OSVERSIONINFOEXA), FALSE },
{ "DsPresent", L"DsPresent", REG_DWORD, 4, FALSE },
{ "DsPresentForUser", L"DsPresentForUser", REG_DWORD, 4, FALSE },
#endif
{ "RemoteFax", L"RemoteFax", REG_NONE, 4, FALSE },
{ "RestartJobOnPoolError", L"RestartJobOnPoolError", REG_DWORD, 4, TRUE },
{ "RestartJobOnPoolEnabled", L"RestartJobOnPoolEnabled", REG_DWORD, 4, TRUE },
{ "DNSMachineName", L"DNSMachineName", REG_SZ, 0xFFFFFFFF, FALSE },
{ "AllowUserManageForms", L"AllowUserManageForms", REG_DWORD, 4, TRUE },
{ NULL, NULL, 0, 0, FALSE }
};
START_TEST(GetPrinterData)
{
DWORD cbNeeded;
DWORD cchDefaultPrinter;
DWORD dwReturnCode;
DWORD dwType;
HANDLE hPrinter;
PBYTE pDataA;
PBYTE pDataW;
PSPLREG_VALUE p;
WCHAR wszDefaultPrinter[MAX_PRINTER_NAME + 1];
// Don't supply any parameters, this has to fail with ERROR_INVALID_HANDLE!
dwReturnCode = GetPrinterDataExW(NULL, NULL, NULL, NULL, NULL, 0, NULL);
ok(dwReturnCode == ERROR_INVALID_HANDLE, "GetPrinterDataExW returns error %lu!\n", dwReturnCode);
// Open a handle to the local print server.
if (!OpenPrinterW(NULL, &hPrinter, NULL))
{
skip("Could not retrieve a handle to the local print server!\n");
return;
}
// Now try with valid handle, but leave remaining parameters NULL.
dwReturnCode = GetPrinterDataExW(hPrinter, NULL, NULL, NULL, NULL, 0, NULL);
ok(dwReturnCode == RPC_X_NULL_REF_POINTER, "GetPrinterDataExW returns error %lu!\n", dwReturnCode);
// Try all valid Print Server data values.
for (p = SplRegValues; p->pszName; p++)
{
// Try the ANSI version of the function.
dwType = 0xDEADBEEF;
dwReturnCode = GetPrinterDataExA(hPrinter, NULL, p->pszName, &dwType, NULL, 0, &cbNeeded);
ok(dwReturnCode == ERROR_MORE_DATA || dwReturnCode == ERROR_FILE_NOT_FOUND, "GetPrinterDataExA returns %lu for \"%s\"!\n", dwReturnCode, p->pszName);
if (dwReturnCode != ERROR_MORE_DATA)
continue;
ok(dwType == p->dwType, "dwType is %lu for \"%s\"!\n", dwType, p->pszName);
if (p->cbNeededA < 0xFFFFFFFF)
ok(cbNeeded == p->cbNeededA, "cbNeeded is %lu for \"%s\", but expected %lu!\n", cbNeeded, p->pszName, p->cbNeededA);
else
ok(cbNeeded > 0, "cbNeeded is 0 for \"%s\"!\n", p->pszName);
pDataA = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
dwReturnCode = GetPrinterDataExA(hPrinter, NULL, p->pszName, NULL, pDataA, cbNeeded, &cbNeeded);
ok(dwReturnCode == ERROR_SUCCESS, "GetPrinterDataExA returns %lu for \"%s\"!\n", dwReturnCode, p->pszName);
// Try the Unicode version of the function too.
dwType = 0xDEADBEEF;
dwReturnCode = GetPrinterDataExW(hPrinter, NULL, p->pwszName, &dwType, NULL, 0, &cbNeeded);
ok(dwReturnCode == ERROR_MORE_DATA, "GetPrinterDataExW returns %lu for \"%s\"!\n", dwReturnCode, p->pszName);
ok(dwType == p->dwType, "dwType is %lu for \"%s\"!\n", dwType, p->pszName);
pDataW = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
dwReturnCode = GetPrinterDataExW(hPrinter, NULL, p->pwszName, NULL, pDataW, cbNeeded, &cbNeeded);
ok(dwReturnCode == ERROR_SUCCESS, "GetPrinterDataExW returns %lu for \"%s\"!\n", dwReturnCode, p->pszName);
// Verify that OSVERSIONINFO structures are correctly returned.
if (strcmp(p->pszName, "OSVersion") == 0)
{
POSVERSIONINFOA pOSVersionInfoA = (POSVERSIONINFOA)pDataA;
POSVERSIONINFOW pOSVersionInfoW = (POSVERSIONINFOW)pDataW;
ok(pOSVersionInfoA->dwOSVersionInfoSize == sizeof(OSVERSIONINFOA), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoA->dwOSVersionInfoSize);
ok(pOSVersionInfoW->dwOSVersionInfoSize == sizeof(OSVERSIONINFOW), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoW->dwOSVersionInfoSize);
}
else if (strcmp(p->pszName, "OSVersionEx") == 0)
{
POSVERSIONINFOEXA pOSVersionInfoA = (POSVERSIONINFOEXA)pDataA;
POSVERSIONINFOEXW pOSVersionInfoW = (POSVERSIONINFOEXW)pDataW;
ok(pOSVersionInfoA->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoA->dwOSVersionInfoSize);
ok(pOSVersionInfoW->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXW), "dwOSVersionInfoSize is %lu!\n", pOSVersionInfoW->dwOSVersionInfoSize);
}
// Shortly test SetPrinterDataExW by setting the same data we just retrieved.
if (p->bSettable)
{
dwReturnCode = SetPrinterDataExW(hPrinter, NULL, p->pwszName, dwType, pDataW, cbNeeded);
ok(dwReturnCode == ERROR_SUCCESS, "SetPrinterDataExW returns %lu for \"%s\"!\n", dwReturnCode, p->pszName);
}
HeapFree(GetProcessHeap(), 0, pDataA);
HeapFree(GetProcessHeap(), 0, pDataW);
}
// Try an invalid one.
dwReturnCode = GetPrinterDataExW(hPrinter, NULL, L"Invalid", NULL, NULL, 0, &cbNeeded);
ok(dwReturnCode == ERROR_INVALID_PARAMETER, "GetPrinterDataExW returns %lu!\n", dwReturnCode);
ClosePrinter(hPrinter);
// Open a handle to the default printer.
cchDefaultPrinter = _countof(wszDefaultPrinter);
ok(GetDefaultPrinterW(wszDefaultPrinter, &cchDefaultPrinter), "GetDefaultPrinterW returns FALSE and requires %lu characters!\n", cchDefaultPrinter);
if (!OpenPrinterW(wszDefaultPrinter, &hPrinter, NULL))
{
skip("Could not retrieve a handle to the default printer!\n");
return;
}
// Using NULL or L"" for pKeyName on a Printer handle yields ERROR_INVALID_PARAMETER.
dwReturnCode = GetPrinterDataExW(hPrinter, NULL, L"Name", NULL, NULL, 0, &cbNeeded);
ok(dwReturnCode == ERROR_INVALID_PARAMETER, "GetPrinterDataExW returns %lu!\n", dwReturnCode);
dwReturnCode = GetPrinterDataExW(hPrinter, L"", L"Name", NULL, NULL, 0, &cbNeeded);
ok(dwReturnCode == ERROR_INVALID_PARAMETER, "GetPrinterDataExW returns %lu!\n", dwReturnCode);
// Using L"\\" allows us to examine the contents of the main printer key anyway.
dwReturnCode = GetPrinterDataExW(hPrinter, L"\\", L"Name", &dwType, NULL, 0, &cbNeeded);
ok(dwReturnCode == ERROR_MORE_DATA, "GetPrinterDataExW returns %lu!\n", dwReturnCode);
ok(dwType == REG_SZ, "dwType is %lu!\n", dwType);
ok(cbNeeded > 0, "cbNeeded is 0!\n");
pDataW = HeapAlloc(GetProcessHeap(), 0, cbNeeded);
dwReturnCode = GetPrinterDataExW(hPrinter, L"\\", L"Name", NULL, pDataW, cbNeeded, &cbNeeded);
ok(dwReturnCode == ERROR_SUCCESS, "GetPrinterDataExW returns %lu!\n", dwReturnCode);
// The following test fails if the default printer is a remote printer.
ok(wcscmp((PWSTR)pDataW, wszDefaultPrinter) == 0, "pDataW is \"%S\", default printer is \"%S\"!\n", (PWSTR)pDataW, wszDefaultPrinter);
// SetPrinterDataExW should return ERROR_ACCESS_DENIED when attempting to set the Name.
dwReturnCode = SetPrinterDataExW(hPrinter, L"\\", L"Name", REG_SZ, pDataW, cbNeeded);
ok(dwReturnCode == ERROR_ACCESS_DENIED, "SetPrinterDataExW returns %lu!\n", dwReturnCode);
HeapFree(GetProcessHeap(), 0, pDataW);
}

View file

@ -14,6 +14,7 @@ extern void func_ClosePrinter(void);
extern void func_EnumPrinters(void);
extern void func_EnumPrintProcessorDatatypes(void);
extern void func_GetDefaultPrinter(void);
extern void func_GetPrinterData(void);
extern void func_GetPrintProcessorDirectoryA(void);
extern void func_GetPrintProcessorDirectoryW(void);
extern void func_IsValidDevmodeA(void);
@ -27,6 +28,7 @@ const struct test winetest_testlist[] =
{ "EnumPrinters", func_EnumPrinters },
{ "EnumPrintProcessorDatatypes", func_EnumPrintProcessorDatatypes },
{ "GetDefaultPrinter", func_GetDefaultPrinter },
{ "GetPrinterData", func_GetPrinterData },
{ "GetPrintProcessorDirectoryA", func_GetPrintProcessorDirectoryA },
{ "GetPrintProcessorDirectoryW", func_GetPrintProcessorDirectoryW },
{ "IsValidDevmodeA", func_IsValidDevmodeA },