/* * 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 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; FIXME("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); if (mi2w.pName) HeapFree(GetProcessHeap(), 0, mi2w.pName); if (mi2w.pEnvironment) HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment); if (mi2w.pDLLName) HeapFree(GetProcessHeap(), 0, mi2w.pDLLName); if (nameW) HeapFree(GetProcessHeap(), 0, nameW); return (res); } BOOL WINAPI AddMonitorW(PWSTR pName, DWORD Level, PBYTE pMonitors) { DWORD dwErrorCode; WINSPOOL_MONITOR_CONTAINER MonitorInfoContainer; FIXME("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; FIXME("AddMonitorW Error Code %lu\n", dwErrorCode); 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); if (MonitorNameW) HeapFree(GetProcessHeap(), 0, MonitorNameW); if (EnvironmentW) HeapFree(GetProcessHeap(), 0, EnvironmentW); if (nameW) HeapFree(GetProcessHeap(), 0, nameW); return (res); } BOOL WINAPI DeleteMonitorW(PWSTR pName, PWSTR pEnvironment, PWSTR pMonitorName) { DWORD dwErrorCode; FIXME("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; if (nameW) HeapFree(GetProcessHeap(), 0, nameW); if (bufferW) 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); }