reactos/win32ss/printing/base/winspool/printerdata.c
Colin Finck 46b9165909 [WINSPOOL] Provide stubs with tracing and reasonable failure codes for even more popular Spooler APIs.
This may get more applications to work which previously called into the WINE-generated stubs (that throw an exception).
It also improves debug logs when the "winspool" debug channel is enabled. With such detailed debug logs, we may get an idea which winspool APIs need to be implemented sooner than others.
2017-12-09 14:14:05 +01:00

459 lines
15 KiB
C

/*
* PROJECT: ReactOS Spooler API
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Functions related to Printer Configuration Data
* COPYRIGHT: Copyright 2015-2017 Colin Finck (colin@reactos.org)
*/
#include "precomp.h"
LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, PSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
{
TRACE("AdvancedDocumentPropertiesA(%p, %p, %s, %p, %p)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput);
UNIMPLEMENTED;
return 0;
}
LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, PWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
{
TRACE("AdvancedDocumentPropertiesW(%p, %p, %S, %p, %p)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput);
UNIMPLEMENTED;
return 0;
}
DWORD WINAPI
DeletePrinterDataA(HANDLE hPrinter, PSTR pValueName)
{
TRACE("DeletePrinterDataA(%p, %s)\n", hPrinter, pValueName);
UNIMPLEMENTED;
return ERROR_NOT_SUPPORTED;
}
DWORD WINAPI
DeletePrinterDataExA(HANDLE hPrinter, PCSTR pKeyName, PCSTR pValueName)
{
TRACE("DeletePrinterDataExA(%p, %s, %s)\n", hPrinter, pKeyName, pValueName);
UNIMPLEMENTED;
return ERROR_NOT_SUPPORTED;
}
DWORD WINAPI
DeletePrinterDataExW(HANDLE hPrinter, PCWSTR pKeyName, PCWSTR pValueName)
{
TRACE("DeletePrinterDataExW(%p, %S, %S)\n", hPrinter, pKeyName, pValueName);
UNIMPLEMENTED;
return ERROR_NOT_SUPPORTED;
}
DWORD WINAPI
DeletePrinterDataW(HANDLE hPrinter, PWSTR pValueName)
{
TRACE("DeletePrinterDataW(%p, %S)\n", hPrinter, pValueName);
UNIMPLEMENTED;
return ERROR_NOT_SUPPORTED;
}
DWORD WINAPI
DeletePrinterKeyA(HANDLE hPrinter, PCSTR pKeyName)
{
TRACE("DeletePrinterKeyA(%p, %s)\n", hPrinter, pKeyName);
UNIMPLEMENTED;
return ERROR_NOT_SUPPORTED;
}
DWORD WINAPI
DeletePrinterKeyW(HANDLE hPrinter, PCWSTR pKeyName)
{
TRACE("DeletePrinterKeyW(%p, %S)\n", hPrinter, pKeyName);
UNIMPLEMENTED;
return ERROR_NOT_SUPPORTED;
}
DWORD WINAPI
EnumPrinterDataA(HANDLE hPrinter, DWORD dwIndex, PSTR pValueName, DWORD cbValueName, PDWORD pcbValueName, PDWORD pType, PBYTE pData, DWORD cbData, PDWORD pcbData)
{
TRACE("EnumPrinterDataA(%p, %lu, %s, %lu, %p, %p, %p, %lu, %p)\n", hPrinter, dwIndex, pValueName, cbValueName, pcbValueName, pType, pData, cbData, pcbData);
UNIMPLEMENTED;
return ERROR_NOT_SUPPORTED;
}
DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter, PCSTR pKeyName, PBYTE pEnumValues, DWORD cbEnumValues, PDWORD pcbEnumValues, PDWORD pnEnumValues)
{
TRACE("EnumPrinterDataExA(%p, %s, %p, %lu, %p, %p)\n", hPrinter, pKeyName, pEnumValues, cbEnumValues, pcbEnumValues, pnEnumValues);
UNIMPLEMENTED;
return ERROR_NOT_SUPPORTED;
}
DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter, PCWSTR pKeyName, PBYTE pEnumValues, DWORD cbEnumValues, PDWORD pcbEnumValues, PDWORD pnEnumValues)
{
TRACE("EnumPrinterDataExW(%p, %S, %p, %lu, %p, %p)\n", hPrinter, pKeyName, pEnumValues, cbEnumValues, pcbEnumValues, pnEnumValues);
UNIMPLEMENTED;
return ERROR_NOT_SUPPORTED;
}
DWORD WINAPI
EnumPrinterDataW(HANDLE hPrinter, DWORD dwIndex, PWSTR pValueName, DWORD cbValueName, PDWORD pcbValueName, PDWORD pType, PBYTE pData, DWORD cbData, PDWORD pcbData)
{
TRACE("EnumPrinterDataW(%p, %lu, %S, %lu, %p, %p, %p, %lu, %p)\n", hPrinter, dwIndex, pValueName, cbValueName, pcbValueName, pType, pData, cbData, pcbData);
UNIMPLEMENTED;
return ERROR_NOT_SUPPORTED;
}
DWORD WINAPI
EnumPrinterKeyA(HANDLE hPrinter, PCSTR pKeyName, PSTR pSubkey, DWORD cbSubkey, PDWORD pcbSubkey)
{
TRACE("EnumPrinterKeyA(%p, %s, %s, %lu, %p)\n", hPrinter, pKeyName, pSubkey, cbSubkey, pcbSubkey);
UNIMPLEMENTED;
return ERROR_NOT_SUPPORTED;
}
DWORD WINAPI
EnumPrinterKeyW(HANDLE hPrinter, PCWSTR pKeyName, PWSTR pSubkey, DWORD cbSubkey, PDWORD pcbSubkey)
{
TRACE("EnumPrinterKeyW(%p, %S, %S, %lu, %p)\n", hPrinter, pKeyName, pSubkey, cbSubkey, pcbSubkey);
UNIMPLEMENTED;
return ERROR_NOT_SUPPORTED;
}
DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType, LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
{
TRACE("GetPrinterDataA(%p, %s, %p, %p, %lu, %p)\n", hPrinter, pValueName, pType, pData, nSize, pcbNeeded);
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;
TRACE("GetPrinterDataExA(%p, %s, %s, %p, %p, %lu, %p)\n", hPrinter, pKeyName, pValueName, pType, pData, nSize, pcbNeeded);
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;
TRACE("GetPrinterDataExW(%p, %S, %S, %p, %p, %lu, %p)\n", hPrinter, pKeyName, pValueName, pType, pData, nSize, pcbNeeded);
// 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)
{
TRACE("GetPrinterDataW(%p, %S, %p, %p, %lu, %p)\n", hPrinter, pValueName, pType, pData, nSize, pcbNeeded);
return GetPrinterDataExW(hPrinter, L"PrinterDriverData", pValueName, pType, pData, nSize, pcbNeeded);
}
DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter, PSTR pValueName, DWORD Type, PBYTE pData, DWORD cbData)
{
TRACE("SetPrinterDataA(%p, %s, %lu, %p, %lu)\n", hPrinter, pValueName, Type, pData, 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;
TRACE("SetPrinterDataExA(%p, %s, %s, %lu, %p, %lu)\n", hPrinter, pKeyName, pValueName, Type, pData, cbData);
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;
TRACE("SetPrinterDataExW(%p, %S, %S, %lu, %p, %lu)\n", hPrinter, pKeyName, pValueName, Type, pData, cbData);
// 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)
{
TRACE("SetPrinterDataW(%p, %S, %lu, %p, %lu)\n", hPrinter, pValueName, Type, pData, cbData);
return SetPrinterDataExW(hPrinter, L"PrinterDriverData", pValueName, Type, pData, cbData);
}