mirror of
https://github.com/reactos/reactos.git
synced 2024-11-02 04:37:32 +00:00
7bffb70353
WinSpool : Implement missing API. Sync/Port from wine. Setting it to fast track for needed testing of the later GDI code. Leaving Fix-me debug prints on. Local tree has WinSpool_winetest turned on. So no debug noise during normal ReactOS operation. SpoolSS : Reordered header types. Have more Spl function to be added while SpoolSV is being coded to forward to LocalSpl. Based on wine and old research from the GDI code.
344 lines
11 KiB
C
344 lines
11 KiB
C
/*
|
|
* PROJECT: ReactOS Spooler API
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: Functions related to Print Monitors
|
|
* COPYRIGHT: Copyright 2015-2018 Colin Finck (colin@reactos.org)
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#include <marshalling/monitors.h>
|
|
|
|
BOOL WINAPI
|
|
AddMonitorA(PSTR pName, DWORD Level, PBYTE pMonitors)
|
|
{
|
|
LPWSTR nameW = NULL;
|
|
INT len;
|
|
BOOL res;
|
|
LPMONITOR_INFO_2A mi2a;
|
|
MONITOR_INFO_2W mi2w;
|
|
|
|
mi2a = (LPMONITOR_INFO_2A) pMonitors;
|
|
TRACE("AddMonitorA(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
|
|
debugstr_a(mi2a ? mi2a->pName : NULL),
|
|
debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
|
|
debugstr_a(mi2a ? mi2a->pDLLName : NULL));
|
|
|
|
if (Level != 2)
|
|
{
|
|
ERR("Level = %d, unsupported!\n", Level);
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
return FALSE;
|
|
}
|
|
|
|
/* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
|
|
if (mi2a == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (pName)
|
|
{
|
|
len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
|
|
nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
|
|
}
|
|
|
|
memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
|
|
if (mi2a->pName)
|
|
{
|
|
len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
|
|
mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
|
|
}
|
|
if (mi2a->pEnvironment)
|
|
{
|
|
len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
|
|
mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
|
|
}
|
|
if (mi2a->pDLLName)
|
|
{
|
|
len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
|
|
mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
|
|
}
|
|
|
|
res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
|
|
|
|
HeapFree(GetProcessHeap(), 0, mi2w.pName);
|
|
HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
|
|
HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
|
|
HeapFree(GetProcessHeap(), 0, nameW);
|
|
|
|
return (res);
|
|
}
|
|
|
|
BOOL WINAPI
|
|
AddMonitorW(PWSTR pName, DWORD Level, PBYTE pMonitors)
|
|
{
|
|
DWORD dwErrorCode;
|
|
WINSPOOL_MONITOR_CONTAINER MonitorInfoContainer;
|
|
TRACE("AddMonitorW(%S, %lu, %p)\n", pName, Level, pMonitors);
|
|
|
|
if (Level != 2)
|
|
{
|
|
ERR("Level = %d, unsupported!\n", Level);
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
return FALSE;
|
|
}
|
|
|
|
MonitorInfoContainer.MonitorInfo.pMonitorInfo2 = (WINSPOOL_MONITOR_INFO_2*)pMonitors;
|
|
MonitorInfoContainer.Level = Level;
|
|
|
|
// Do the RPC call
|
|
RpcTryExcept
|
|
{
|
|
dwErrorCode = _RpcAddMonitor(pName, &MonitorInfoContainer);
|
|
}
|
|
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
dwErrorCode = RpcExceptionCode();
|
|
ERR("_RpcAddMonitor failed with exception code %lu!\n", dwErrorCode);
|
|
}
|
|
RpcEndExcept;
|
|
|
|
SetLastError(dwErrorCode);
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
|
}
|
|
|
|
BOOL WINAPI
|
|
DeleteMonitorA(PSTR pName, PSTR pEnvironment, PSTR pMonitorName)
|
|
{
|
|
LPWSTR nameW = NULL;
|
|
LPWSTR EnvironmentW = NULL;
|
|
LPWSTR MonitorNameW = NULL;
|
|
BOOL res;
|
|
INT len;
|
|
|
|
TRACE("DeleteMonitorA(%s, %s, %s)\n", pName, pEnvironment, pMonitorName);
|
|
|
|
if (pName) {
|
|
len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
|
|
nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
|
|
}
|
|
|
|
if (pEnvironment) {
|
|
len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
|
|
EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
|
|
}
|
|
if (pMonitorName) {
|
|
len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
|
|
MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
|
|
}
|
|
|
|
res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
|
|
|
|
HeapFree(GetProcessHeap(), 0, MonitorNameW);
|
|
HeapFree(GetProcessHeap(), 0, EnvironmentW);
|
|
HeapFree(GetProcessHeap(), 0, nameW);
|
|
|
|
return (res);
|
|
}
|
|
|
|
BOOL WINAPI
|
|
DeleteMonitorW(PWSTR pName, PWSTR pEnvironment, PWSTR pMonitorName)
|
|
{
|
|
DWORD dwErrorCode;
|
|
|
|
TRACE("DeleteMonitorW(%S, %S, %S)\n", pName, pEnvironment, pMonitorName);
|
|
|
|
// Do the RPC call
|
|
RpcTryExcept
|
|
{
|
|
dwErrorCode = _RpcDeleteMonitor(pName, pEnvironment, pMonitorName);
|
|
}
|
|
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
dwErrorCode = RpcExceptionCode();
|
|
ERR("_RpcDeleteMonitor failed with exception code %lu!\n", dwErrorCode);
|
|
}
|
|
RpcEndExcept;
|
|
|
|
SetLastError(dwErrorCode);
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
|
|
|
}
|
|
|
|
BOOL WINAPI
|
|
EnumMonitorsA(PSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
|
|
{
|
|
BOOL res;
|
|
LPBYTE bufferW = NULL;
|
|
LPWSTR nameW = NULL;
|
|
DWORD needed = 0;
|
|
DWORD numentries = 0;
|
|
INT len;
|
|
|
|
FIXME("EnumMonitorsA(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
|
|
|
|
if ( Level < 1 || Level > 2 )
|
|
{
|
|
ERR("Level = %d, unsupported!\n", Level);
|
|
SetLastError( ERROR_INVALID_LEVEL );
|
|
return FALSE;
|
|
}
|
|
|
|
/* convert servername to unicode */
|
|
if (pName)
|
|
{
|
|
len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
|
|
nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
|
|
}
|
|
/* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
|
|
needed = cbBuf * sizeof(WCHAR);
|
|
if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
|
|
res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
|
|
|
|
if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
|
|
{
|
|
if (pcbNeeded) needed = *pcbNeeded;
|
|
/* HeapReAlloc return NULL, when bufferW was NULL */
|
|
bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
|
|
HeapAlloc(GetProcessHeap(), 0, needed);
|
|
|
|
/* Try again with the large Buffer */
|
|
res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
|
|
}
|
|
numentries = pcReturned ? *pcReturned : 0;
|
|
needed = 0;
|
|
/*
|
|
W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
|
|
We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
|
|
*/
|
|
if (res)
|
|
{
|
|
/* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
|
|
DWORD entrysize = 0;
|
|
DWORD index;
|
|
LPSTR ptr;
|
|
LPMONITOR_INFO_2W mi2w;
|
|
LPMONITOR_INFO_2A mi2a;
|
|
|
|
/* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
|
|
entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
|
|
|
|
/* First pass: calculate the size for all Entries */
|
|
mi2w = (LPMONITOR_INFO_2W) bufferW;
|
|
mi2a = (LPMONITOR_INFO_2A) pMonitors;
|
|
index = 0;
|
|
while (index < numentries)
|
|
{
|
|
index++;
|
|
needed += entrysize; /* MONITOR_INFO_?A */
|
|
TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
|
|
|
|
needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
|
|
NULL, 0, NULL, NULL);
|
|
if (Level > 1)
|
|
{
|
|
needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
|
|
NULL, 0, NULL, NULL);
|
|
needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
|
|
NULL, 0, NULL, NULL);
|
|
}
|
|
/* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
|
|
mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
|
|
mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
|
|
}
|
|
|
|
/* check for errors and quit on failure */
|
|
if (cbBuf < needed)
|
|
{
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
res = FALSE;
|
|
goto emA_cleanup;
|
|
}
|
|
len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
|
|
ptr = (LPSTR) &pMonitors[len]; /* room for strings */
|
|
cbBuf -= len ; /* free Bytes in the user-Buffer */
|
|
mi2w = (LPMONITOR_INFO_2W) bufferW;
|
|
mi2a = (LPMONITOR_INFO_2A) pMonitors;
|
|
index = 0;
|
|
/* Second Pass: Fill the User Buffer (if we have one) */
|
|
while ((index < numentries) && pMonitors)
|
|
{
|
|
index++;
|
|
TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
|
|
mi2a->pName = ptr;
|
|
len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
|
|
ptr, cbBuf , NULL, NULL);
|
|
ptr += len;
|
|
cbBuf -= len;
|
|
if (Level > 1)
|
|
{
|
|
mi2a->pEnvironment = ptr;
|
|
len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
|
|
ptr, cbBuf, NULL, NULL);
|
|
ptr += len;
|
|
cbBuf -= len;
|
|
|
|
mi2a->pDLLName = ptr;
|
|
len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
|
|
ptr, cbBuf, NULL, NULL);
|
|
ptr += len;
|
|
cbBuf -= len;
|
|
}
|
|
/* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
|
|
mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
|
|
mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
|
|
}
|
|
}
|
|
emA_cleanup:
|
|
if (pcbNeeded) *pcbNeeded = needed;
|
|
if (pcReturned) *pcReturned = (res) ? numentries : 0;
|
|
|
|
HeapFree(GetProcessHeap(), 0, nameW);
|
|
HeapFree(GetProcessHeap(), 0, bufferW);
|
|
|
|
FIXME("returning %d with %d (%d byte for %d entries)\n", (res), GetLastError(), needed, numentries);
|
|
|
|
return (res);
|
|
|
|
}
|
|
|
|
BOOL WINAPI
|
|
EnumMonitorsW(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
|
|
{
|
|
DWORD dwErrorCode;
|
|
|
|
FIXME("EnumMonitorsW(%S, %lu, %p, %lu, %p, %p)\n", pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
|
|
|
|
if ( Level < 1 || Level > 2 )
|
|
{
|
|
ERR("Level = %d, unsupported!\n", Level);
|
|
SetLastError( ERROR_INVALID_LEVEL );
|
|
return FALSE;
|
|
}
|
|
|
|
// Do the RPC call
|
|
RpcTryExcept
|
|
{
|
|
dwErrorCode = _RpcEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
|
|
}
|
|
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
dwErrorCode = RpcExceptionCode();
|
|
ERR("_RpcEnumMonitors failed with exception code %lu!\n", dwErrorCode);
|
|
}
|
|
RpcEndExcept;
|
|
|
|
if (dwErrorCode == ERROR_SUCCESS)
|
|
{
|
|
// Replace relative offset addresses in the output by absolute pointers.
|
|
ASSERT(Level >= 1 && Level <= 2);
|
|
MarshallUpStructuresArray(cbBuf, pMonitors, *pcReturned, pMonitorInfoMarshalling[Level]->pInfo, pMonitorInfoMarshalling[Level]->cbStructureSize, TRUE);
|
|
}
|
|
|
|
SetLastError(dwErrorCode);
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
|
}
|