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
; 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"
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
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
monitors.c
ports.c
precomp.h
+ printerdata.c
printers.c
printprocessors.c
tools.c)
if (!pPrintProvider)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
if (!pwszPrintProviderName)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
pwszOutput = HeapAlloc(hProcessHeap, 0, cbInput);
if (!pwszOutput)
{
- ERR("HeapAlloc failed with error %lu!\n", GetLastError());
+ ERR("HeapAlloc failed!\n");
return NULL;
}
pNewMem = DllAllocSplMem(cbNew);
if (!pNewMem)
{
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
return NULL;
}
* 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"
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.
* 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"
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.
--- /dev/null
+/*
+ * 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);
+}
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.
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)
{
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;
}
}
}
+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);
}
@ 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)
@ 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
* 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"
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;
}
* 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"
}
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);
}
if (!pJobInfo1)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("HeapAlloc failed with error %lu!\n", GetLastError());
+ ERR("HeapAlloc failed!\n");
goto Cleanup;
}
Cleanup:
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
-
}
DWORD WINAPI
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;
}
}
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;
}
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;
}
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;
}
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)
{
if (!pHandle)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("HeapAlloc failed with error %lu!\n", GetLastError());
+ ERR("HeapAlloc failed!\n");
goto Cleanup;
}
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;
}
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;
}
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;
}
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;
}
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;
}
if (!pAddJobInfo1)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("HeapAlloc failed with error %lu!\n", GetLastError());
+ ERR("HeapAlloc failed!\n");
goto Cleanup;
}
* 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"
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;
}
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;
}
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;
}
}
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)
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
monitors.c
ports.c
precomp.h
+ printerdata.c
printers.c
printingthread.c
printprocessors.c
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)
* 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"
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;
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);
if (!pJob)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
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;
}
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;
}
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;
}
#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] = {
LocalEndDocPrinter, // fpEndDocPrinter
LocalAddJob, // fpAddJob
LocalScheduleJob, // fpScheduleJob
- NULL, // fpGetPrinterData
- NULL, // fpSetPrinterData
+ LocalGetPrinterData, // fpGetPrinterData
+ LocalSetPrinterData, // fpSetPrinterData
NULL, // fpWaitForPrinterChange
LocalClosePrinter, // fpClosePrinter
NULL, // fpAddForm
NULL, // fpClusterSplOpen
NULL, // fpClusterSplClose
NULL, // fpClusterSplIsAlive
- NULL, // fpSetPrinterDataEx
- NULL, // fpGetPrinterDataEx
+ LocalSetPrinterDataEx, // fpSetPrinterDataEx
+ LocalGetPrinterDataEx, // fpGetPrinterDataEx
NULL, // fpEnumPrinterDataEx
NULL, // fpEnumPrinterKey
NULL, // fpDeletePrinterDataEx
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);
+
+ 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;
+ }
- // Get the system directory and append the "spool" subdirectory.
+ // 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
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
- _GetSpoolDirectory();
-
- return InitializePrintMonitorList() &&
- InitializePortList() &&
- InitializePrintProcessorList() &&
- InitializePrinterList() &&
- InitializeGlobalJobList();
+ return _InitializeLocalSpooler();
default:
return TRUE;
* 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"
if (!pPrintMonitor)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
if (!pPrintMonitor->pwszName)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
if (!pwszRegistryPath)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
* 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"
if (!pPortInfo1)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
if (!pPort)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
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
#include <winreg.h>
#include <winspool.h>
#include <winsplp.h>
+#include <dsrole.h>
+#include <secext.h>
#include <ndk/rtlfuncs.h>
#define SKIPLIST_LEVELS 16
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;
// 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;
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();
--- /dev/null
+/*
+ * 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;
+}
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;
// 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);
// 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.
}
// 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);
if (!pPrinter)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
if (!pPrinter->pDefaultDevMode)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
if (pwszPrintProcessor)
DllFreeSplStr(pwszPrintProcessor);
- // Outside the loop
- if (hKey)
- RegCloseKey(hKey);
-
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}
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;
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)
{
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;
+
+ // Look for this port in our Print Monitor Port list.
+ pPort = FindPort(pwszPortName);
+ if (!pPort)
+ {
+ // 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;
- 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.
+ // Retrieve the printer from the list.
+ pPrinter = LookupElementSkiplist(&PrinterList, &pwszPrinterName, NULL);
+ if (!pPrinter)
+ {
+ // The printer does not exist.
+ dwErrorCode = ERROR_INVALID_NAME;
+ goto Failure;
+ }
- // Sanity checks
- if (!lpPrinterName || !phPrinter)
+ // Create a new LOCAL_PRINTER_HANDLE.
+ pPrinterHandle = DllAllocSplMem(sizeof(LOCAL_PRINTER_HANDLE));
+ if (!pPrinterHandle)
{
- dwErrorCode = ERROR_INVALID_PARAMETER;
- goto Cleanup;
+ 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'\\')
// 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);
// 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;
}
// We must have at least one parameter.
if (!cchFirstParameter && !pwszSecondParameter)
{
- dwErrorCode = ERROR_INVALID_PRINTER_NAME;
+ dwErrorCode = ERROR_INVALID_NAME;
goto Cleanup;
}
++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)
{
// "\\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
{
// "\\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);
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)
{
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;
* 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"
if (!pwszPrinterPort)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
if (!pwszPrinterAndJob)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
if (!pwszSPLFile)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
* 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"
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;
}
if (!pPrintProcessor)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
if (!pPrintProcessor->pwszName)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
if (!pPrintProcessor->pDatatypesInfo1)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
if (!pwszTemp)
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
goto Cleanup;
}
* 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"
pwszValue = DllAllocSplMem(cbNeeded);
if (!pwszValue)
{
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
return NULL;
}
pOutput = DllAllocSplMem(pInput->dmSize + pInput->dmDriverExtra);
if (!pOutput)
{
- ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ ERR("DllAllocSplMem failed!\n");
return NULL;
}
EnumPrinters.c
EnumPrintProcessorDatatypes.c
GetDefaultPrinter.c
+ GetPrinterData.c
GetPrintProcessorDirectory.c
IsValidDevmode.c
OpenPrinter.c
--- /dev/null
+/*
+ * 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);
+}
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);
{ "EnumPrinters", func_EnumPrinters },
{ "EnumPrintProcessorDatatypes", func_EnumPrintProcessorDatatypes },
{ "GetDefaultPrinter", func_GetDefaultPrinter },
+ { "GetPrinterData", func_GetPrinterData },
{ "GetPrintProcessorDirectoryA", func_GetPrintProcessorDirectoryA },
{ "GetPrintProcessorDirectoryW", func_GetPrintProcessorDirectoryW },
{ "IsValidDevmodeA", func_IsValidDevmodeA },