reactos/win32ss/printing/base/winspool/ports.c

1040 lines
30 KiB
C

/*
* PROJECT: ReactOS Spooler API
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Functions related to Ports
* COPYRIGHT: Copyright 2015-2018 Colin Finck (colin@reactos.org)
*/
#include "precomp.h"
#include <marshalling/ports.h>
typedef struct _MONITORUIDATA
{
HMODULE hLibrary;
HANDLE hActCtx;
ULONG_PTR ulpCookie;
PWSTR pModuleName;
BOOL Activeated;
} MONITORUIDATA, *PMONITORUIDATA;
typedef DWORD (*PPfpFunction)(LPWSTR, ULONG_PTR, LPWSTR);
typedef struct _PORTTHREADINFO
{
LPWSTR pName;
ULONG_PTR hWnd;
LPWSTR pPortName;
PPfpFunction fpFunction;
DWORD dwErrorCode;
HANDLE hEvent;
} PORTTHREADINFO, *PPORTTHREADINFO;
VOID WINAPI
IntPortThread( PPORTTHREADINFO pPortThreadInfo )
{
FIXME("IPT : %s\n",debugstr_w( pPortThreadInfo->pPortName ));
// Do the RPC call
RpcTryExcept
{
pPortThreadInfo->dwErrorCode = pPortThreadInfo->fpFunction( pPortThreadInfo->pName, pPortThreadInfo->hWnd, pPortThreadInfo->pPortName );
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
pPortThreadInfo->dwErrorCode = RpcExceptionCode();
ERR("IPT : _RpcXyzPort failed with exception code %lu!\n", pPortThreadInfo->dwErrorCode);
}
RpcEndExcept;
SetEvent( pPortThreadInfo->hEvent );
}
//
// Start a thread to wait on a printer port.
//
BOOL WINAPI
StartPortThread( LPWSTR pName, HWND hWnd, LPWSTR pPortName, PPfpFunction fpFunction )
{
PORTTHREADINFO PortThreadInfo;
HANDLE htHandle;
MSG Msg;
DWORD tid;
if ( hWnd ) EnableWindow( hWnd, FALSE );
PortThreadInfo.pName = pName;
PortThreadInfo.hWnd = (ULONG_PTR)hWnd;
PortThreadInfo.pPortName = pPortName;
PortThreadInfo.fpFunction = fpFunction;
PortThreadInfo.dwErrorCode = ERROR_SUCCESS;
PortThreadInfo.hEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
htHandle = CreateThread( NULL,
32*1024,
(LPTHREAD_START_ROUTINE)IntPortThread,
&PortThreadInfo,
0,
&tid );
CloseHandle( htHandle );
while ( MsgWaitForMultipleObjects( 1, &PortThreadInfo.hEvent, FALSE, INFINITE, QS_ALLINPUT ) == 1 )
{
while ( PeekMessageW( &Msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &Msg );
DispatchMessageW( &Msg );
}
}
CloseHandle( PortThreadInfo.hEvent );
if ( hWnd )
{
EnableWindow(hWnd, TRUE);
SetForegroundWindow(hWnd);
SetFocus(hWnd);
}
SetLastError(PortThreadInfo.dwErrorCode);
return (PortThreadInfo.dwErrorCode == ERROR_SUCCESS);
}
BOOL WINAPI
GetMonitorUIFullName( PWSTR pDeviceName, PWSTR *pModuleName )
{
STRSAFE_LPWSTR SysDir;
UINT length;
HRESULT hr;
*pModuleName = NULL;
SysDir = HeapAlloc(hProcessHeap, 0, MAX_PATH*sizeof(WCHAR));
if ( SysDir )
{
memset( SysDir, 0, MAX_PATH*sizeof(WCHAR) );
length = GetSystemDirectoryW( SysDir, MAX_PATH*sizeof(WCHAR) );
if ( length > 0 )
{
StringCbCatW(SysDir, MAX_PATH*sizeof(WCHAR), L"\\");
hr = StringCchCatW( SysDir, MAX_PATH*sizeof(WCHAR), pDeviceName );
if ( !FAILED(hr) )
{
*pModuleName = SysDir;
return TRUE;
}
SetLastError(HRESULT_CODE(hr));
}
HeapFree(hProcessHeap, 0, SysDir);
}
return FALSE;
}
BOOL WINAPI
GetMonitorUIActivationContext( PWSTR pDeviceName, PMONITORUIDATA pmuid )
{
// ACTCTXW actctx;
// HANDLE handle;
BOOL Ret = FALSE;
FIXME("GMUIAC : Module pDeviceName %S\n",pDeviceName);
if ( !GetMonitorUIFullName( pDeviceName, &pmuid->pModuleName ) )
{
ERR("GetMonitorUIFullName Failed\n");
return Ret;
}
/* OMG! SxS again?
memset(&actctx, 0, sizeof(ACTCTXW));
actctx.cbSize = sizeof(ACTCTXW);
actctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
actctx.lpResourceName = MAKEINTRESOURCEW(123); This might be the reason....
actctx.lpSource = pmuid->pModuleName;
handle = CreateActCtxW(&actctx);
if ( handle != INVALID_HANDLE_VALUE )
{
pmuid->hActCtx = handle;
if ( ActivateActCtx( handle, &pmuid->ulpCookie ) )
{
pmuid->Activeated = TRUE;
Ret = TRUE;
}
else
{
pmuid->Activeated = FALSE;
}
}
else
{
ERR("GetMonitorUIActivationContext Failed %S\n",pmuid->pModuleName);
}*/
pmuid->hActCtx = INVALID_HANDLE_VALUE;
Ret = TRUE;
return Ret;
}
VOID FASTCALL
FreeMonitorUI( PMONITORUIDATA pmuid )
{
if ( pmuid )
{
if ( pmuid->hLibrary )
{
FreeLibrary( pmuid->hLibrary );
}
if ( pmuid->Activeated )
{
DeactivateActCtx( 0, pmuid->ulpCookie );
}
if ( pmuid->hActCtx != INVALID_HANDLE_VALUE )
{
ReleaseActCtx( pmuid->hActCtx );
}
if ( pmuid->pModuleName )
{
DllFreeSplMem( pmuid->pModuleName );
}
DllFreeSplMem( pmuid );
}
}
BOOL FASTCALL
StrNCatBuff( PWSTR ptr, size_t Size, PWSTR args, ...)
{
va_list Args;
PWSTR pwstr;
HRESULT hr;
BOOL Ret = TRUE;
va_start(Args, args );
for ( pwstr = args ; pwstr ; pwstr = va_arg( Args, PWSTR ) )
{
hr = StringCchCatNW( ptr, Size, pwstr, wcslen(pwstr) );
if ( FAILED(hr) )
{
SetLastError(HRESULT_CODE(hr));
Ret = FALSE;
break;
}
}
va_end(Args);
return Ret;
}
PWSTR WINAPI
ConstructXcvName( PWSTR pName, PWSTR pMonitorPortName, PWSTR pXcvName )
{
BOOL Ret = FALSE;
PWSTR pwstr = NULL;
size_t sXcv, smpn = 0, Size = 0;
if ( pName )
{
Size = wcslen( pName ) + 1;
}
sXcv = wcslen( pXcvName ) + Size;
if ( pMonitorPortName )
{
smpn = wcslen( pMonitorPortName );
}
Size = sXcv + smpn + 3;
pwstr = DllAllocSplMem( Size * sizeof(WCHAR) );
memset( pwstr, 0, Size );
if ( pwstr )
{
// The caller wants an Xcv handle and provided a string like:
// ", XcvMonitor Local Port"
// "\\COMPUTERNAME\, XcvMonitor Local Port"
// ", XcvPort LPT1:"
// "\\COMPUTERNAME\, XcvPort LPT1:"
//
// This produces; !pName ",XcvMonitor " or pName "\\COMPUTERNAME\XcvMonitor "
//
Ret = StrNCatBuff( pwstr,
Size,
pName ? pName : L"",
pName ? L"\\" : L",",
pXcvName,
L" ",
pMonitorPortName ? pMonitorPortName : L"",
NULL );
}
if ( !Ret )
{
DllFreeSplMem( pwstr );
pwstr = NULL;
}
return pwstr;
}
DWORD WINAPI
GetMonitorUI( PWSTR pName, PWSTR pMonitorPortName, PWSTR pXcvName, PMONITORUI *pmui, PMONITORUIDATA *ppmuid )
{
DWORD dwErrorCode = ERROR_SUCCESS, cbOutputNeeded, dwStatus;
HANDLE hPrinter = NULL;
HMODULE hModule;
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
PWSTR pDevice = NULL, pOutputString = NULL;
PMONITORUIDATA pmuid = NULL;
PRINTER_DEFAULTSW wDefault = { 0, 0, PRINTER_ATTRIBUTE_QUEUED };
BYTE OutputData[1024], InputData[4];
*pmui = NULL;
*ppmuid = NULL;
pDevice = ConstructXcvName( pName, pMonitorPortName, pXcvName );
if ( !pDevice )
{
return GetLastError();
}
FIXME("GMUI : XcvName : %S\n",pDevice);
if ( OpenPrinterW( (LPWSTR)pDevice, &hPrinter, &wDefault ) )
{
pHandle = (PSPOOLER_HANDLE)hPrinter;
// Do the RPC call
RpcTryExcept
{
dwErrorCode = _RpcXcvData( pHandle->hPrinter,
L"MonitorUI",
(PBYTE)&InputData,
0,
(PBYTE)&OutputData,
1024,
&cbOutputNeeded,
&dwStatus );
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwErrorCode = RpcExceptionCode();
ERR("GMUI : _RpcXcvData failed with exception code %lu!\n", dwErrorCode);
}
RpcEndExcept;
if ( dwErrorCode == ERROR_INSUFFICIENT_BUFFER )
{
pOutputString = DllAllocSplMem( cbOutputNeeded );
// Do the RPC call
RpcTryExcept
{
dwErrorCode = _RpcXcvData( pHandle->hPrinter,
L"MonitorUI",
(PBYTE)&InputData,
0,
(PBYTE)pOutputString,
cbOutputNeeded,
&cbOutputNeeded,
&dwStatus );
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwErrorCode = RpcExceptionCode();
ERR("GMUI : _RpcXcvData failed with exception code %lu!\n", dwErrorCode);
}
RpcEndExcept;
}
if ( dwErrorCode != ERROR_SUCCESS || dwStatus != ERROR_SUCCESS )
{
goto Cleanup;
}
pmuid = DllAllocSplMem( sizeof(MONITORUIDATA) );
if ( pmuid )
{
memset( pmuid, 0, sizeof(MONITORUIDATA) );
pmuid->hActCtx = INVALID_HANDLE_VALUE;
}
else
{
ERR("GMUI : Memory error\n");
dwErrorCode = GetLastError();
goto Cleanup;
}
if ( GetMonitorUIActivationContext( pOutputString ? pOutputString : (PWSTR)&OutputData, pmuid ) )
{
FIXME("GMUI : MonitorUI Path : %S\n",pmuid->pModuleName);
hModule = LoadLibraryW( pmuid->pModuleName );
if ( hModule )
{
FARPROC fpInitializePrintMonitorUI = (PVOID) GetProcAddress( hModule, "InitializePrintMonitorUI" );
if ( fpInitializePrintMonitorUI )
{
pmuid->hLibrary = hModule;
*pmui = (PMONITORUI)(*fpInitializePrintMonitorUI)();
*ppmuid = pmuid;
}
else
{
ERR("GMUI : Failed to get MUI %S\n",pmuid->pModuleName);
FreeMonitorUI( pmuid );
}
}
else
{
ERR("GMUI : Failed to load library %S\n",pmuid->pModuleName);
}
}
}
else
{
ERR("GMUI : Failed to open printer handle\n");
}
dwErrorCode = GetLastError();
Cleanup:
if ( hPrinter ) ClosePrinter( hPrinter );
if ( pOutputString ) DllFreeSplMem( pOutputString );
if ( pDevice ) DllFreeSplMem( pDevice );
FIXME("GMUI : Error Code Exit %d\n",dwErrorCode);
return dwErrorCode;
}
BOOL WINAPI
AddPortA(PSTR pName, HWND hWnd, PSTR pMonitorName)
{
LPWSTR nameW = NULL;
LPWSTR monitorW = NULL;
DWORD len;
BOOL res;
TRACE("AddPortA(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(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 (pMonitorName)
{
len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
}
res = AddPortW(nameW, hWnd, monitorW);
if (nameW) HeapFree(GetProcessHeap(), 0, nameW);
if (monitorW) HeapFree(GetProcessHeap(), 0, monitorW);
return res;
}
BOOL WINAPI
AddPortExW(PWSTR pName, DWORD Level, PBYTE lpBuffer, PWSTR lpMonitorName)
{
DWORD dwErrorCode;
WINSPOOL_PORT_CONTAINER PortInfoContainer;
WINSPOOL_PORT_VAR_CONTAINER PortVarContainer;
WINSPOOL_PORT_INFO_FF *pPortInfoFF;
FIXME("AddPortExW(%S, %lu, %p, %S)\n", pName, Level, lpBuffer, lpMonitorName);
switch (Level)
{
case 1:
// FIXME!!!! Only Level 1 is supported? See note in wine winspool test info.c : line 575. It's just not supported here.
PortInfoContainer.PortInfo.pPortInfo1 = (WINSPOOL_PORT_INFO_1*)lpBuffer;
PortInfoContainer.Level = Level;
PortVarContainer.cbMonitorData = 0;
PortVarContainer.pMonitorData = NULL;
break;
case 0xFFFFFFFF:
pPortInfoFF = (WINSPOOL_PORT_INFO_FF*)lpBuffer;
PortInfoContainer.PortInfo.pPortInfoFF = pPortInfoFF;
PortInfoContainer.Level = Level;
PortVarContainer.cbMonitorData = pPortInfoFF->cbMonitorData;
PortVarContainer.pMonitorData = pPortInfoFF->pMonitorData;
break;
default:
ERR("Level = %d, unsupported!\n", Level);
SetLastError(ERROR_INVALID_LEVEL);
return FALSE;
}
// Do the RPC call
RpcTryExcept
{
dwErrorCode = _RpcAddPortEx(pName, &PortInfoContainer, &PortVarContainer, lpMonitorName);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwErrorCode = RpcExceptionCode();
}
RpcEndExcept;
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}
BOOL WINAPI
AddPortExA(PSTR pName, DWORD Level, PBYTE lpBuffer, PSTR lpMonitorName)
{
PORT_INFO_1W pi1W;
PORT_INFO_1A * pi1A;
LPWSTR nameW = NULL;
LPWSTR monitorW = NULL;
DWORD len;
BOOL res = FALSE;
WINSPOOL_PORT_INFO_FF *pPortInfoFF, PortInfoFF;
pi1A = (PORT_INFO_1A *)lpBuffer;
pPortInfoFF = (WINSPOOL_PORT_INFO_FF*)lpBuffer;
FIXME("AddPortExA(%s, %d, %p, %s): %s\n", debugstr_a(pName), Level, lpBuffer, debugstr_a(lpMonitorName), debugstr_a(pi1A ? pi1A->pName : NULL));
if ( !lpBuffer || !lpMonitorName )
{
SetLastError(ERROR_INVALID_PARAMETER);
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);
}
if (lpMonitorName)
{
len = MultiByteToWideChar(CP_ACP, 0, lpMonitorName, -1, NULL, 0);
monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, lpMonitorName, -1, monitorW, len);
}
pi1W.pName = NULL;
ZeroMemory( &PortInfoFF, sizeof(WINSPOOL_PORT_INFO_FF));
switch ( Level )
{
case 1:
if ( pi1A->pName )
{
len = MultiByteToWideChar(CP_ACP, 0, pi1A->pName, -1, NULL, 0);
pi1W.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, pi1A->pName, -1, pi1W.pName, len);
}
break;
case 0xFFFFFFFF:
//
// Remember the calling parameter is Ansi.
//
if ( !pPortInfoFF->pPortName || !(PCHAR)pPortInfoFF->pPortName )
{
SetLastError(ERROR_INVALID_PARAMETER);
goto Cleanup;
}
len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pPortInfoFF->pPortName, -1, NULL, 0);
PortInfoFF.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pPortInfoFF->pPortName, -1, (LPWSTR)PortInfoFF.pPortName, len);
PortInfoFF.cbMonitorData = pPortInfoFF->cbMonitorData;
PortInfoFF.pMonitorData = pPortInfoFF->pMonitorData;
break;
default:
ERR("Level = %d, unsupported!\n", Level);
SetLastError(ERROR_INVALID_LEVEL);
goto Cleanup;
}
res = AddPortExW( nameW, Level, Level == 1 ? (PBYTE)&pi1W : (PBYTE)&PortInfoFF, monitorW );
Cleanup:
if (nameW) HeapFree(GetProcessHeap(), 0, nameW);
if (monitorW) HeapFree(GetProcessHeap(), 0, monitorW);
if (pi1W.pName) HeapFree(GetProcessHeap(), 0, pi1W.pName);
if (PortInfoFF.pPortName) HeapFree(GetProcessHeap(), 0, PortInfoFF.pPortName);
return res;
}
BOOL WINAPI
AddPortW(PWSTR pName, HWND hWnd, PWSTR pMonitorName)
{
DWORD SessionId, dwErrorCode = 0;
PMONITORUIDATA pmuid;
PMONITORUI pmui = NULL;
BOOL Ret = FALSE;
FIXME("AddPortW(%S, %p, %S)\n", pName, hWnd, pMonitorName);
dwErrorCode = GetMonitorUI( pName, pMonitorName, L"XcvMonitor", &pmui, &pmuid );
FIXME("AddPortW Error %d\n",dwErrorCode);
if (dwErrorCode != ERROR_SUCCESS )
{
if ( dwErrorCode == ERROR_NOT_SUPPORTED ||
dwErrorCode == ERROR_MOD_NOT_FOUND ||
dwErrorCode == ERROR_INVALID_PRINT_MONITOR ||
dwErrorCode == ERROR_UNKNOWN_PORT ||
dwErrorCode == ERROR_INVALID_PRINTER_NAME )
{
if ( ProcessIdToSessionId( GetCurrentProcessId(), &SessionId ) && SessionId ) // Looking if this is remote.
{
dwErrorCode = ERROR_NOT_SUPPORTED;
}
else
{
Ret = StartPortThread( pName, hWnd, pMonitorName, (PPfpFunction)_RpcAddPort );
FIXME("AddPortW return StartPortThread\n");
dwErrorCode = GetLastError();
}
}
}
else
{
Ret = (*pmui->pfnAddPortUI)( pName, hWnd, pMonitorName, NULL );
}
SetLastError(dwErrorCode);
FreeMonitorUI( pmuid );
return Ret;
}
BOOL WINAPI
ConfigurePortA(PSTR pName, HWND hWnd, PSTR pPortName)
{
LPWSTR nameW = NULL;
LPWSTR portW = NULL;
INT len;
DWORD res;
TRACE("ConfigurePortA(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
/* 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);
}
/* convert portname to unicode */
if (pPortName)
{
len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
}
res = ConfigurePortW(nameW, hWnd, portW);
if (nameW) HeapFree(GetProcessHeap(), 0, nameW);
if (portW) HeapFree(GetProcessHeap(), 0, portW);
return res;
}
BOOL WINAPI
ConfigurePortW(PWSTR pName, HWND hWnd, PWSTR pPortName)
{
DWORD SessionId, dwErrorCode = 0;
PMONITORUIDATA pmuid;
PMONITORUI pmui = NULL;
BOOL Ret = FALSE;
FIXME("ConfigurePortW(%S, %p, %S)\n", pName, hWnd, pPortName);
dwErrorCode = GetMonitorUI( pName, pPortName, L"XcvPort", &pmui, &pmuid );
if (dwErrorCode != ERROR_SUCCESS )
{
if ( dwErrorCode == ERROR_NOT_SUPPORTED ||
dwErrorCode == ERROR_MOD_NOT_FOUND ||
dwErrorCode == ERROR_INVALID_PRINT_MONITOR ||
dwErrorCode == ERROR_UNKNOWN_PORT ||
dwErrorCode == ERROR_INVALID_PRINTER_NAME )
{
if ( ProcessIdToSessionId( GetCurrentProcessId(), &SessionId ) && SessionId ) // Looking if this is remote.
{
dwErrorCode = ERROR_NOT_SUPPORTED;
}
else
{
Ret = StartPortThread(pName, hWnd, pPortName, (PPfpFunction)_RpcConfigurePort );
dwErrorCode = GetLastError();
}
}
}
else
{
Ret = (*pmui->pfnConfigurePortUI)( pName, hWnd, pPortName );
}
SetLastError(dwErrorCode);
FreeMonitorUI( pmuid );
return Ret;
}
BOOL WINAPI
DeletePortA(PSTR pName, HWND hWnd, PSTR pPortName)
{
LPWSTR nameW = NULL;
LPWSTR portW = NULL;
INT len;
DWORD res;
FIXME("DeletePortA(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
/* 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);
}
/* convert portname to unicode */
if (pPortName)
{
len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
}
res = DeletePortW(nameW, hWnd, portW);
if (nameW) HeapFree(GetProcessHeap(), 0, nameW);
if (portW) HeapFree(GetProcessHeap(), 0, portW);
return res;
}
BOOL WINAPI
DeletePortW(PWSTR pName, HWND hWnd, PWSTR pPortName)
{
DWORD dwErrorCode = 0;
PMONITORUIDATA pmuid;
PMONITORUI pmui = NULL;
BOOL Ret = FALSE;
FIXME("DeletePortW(%S, %p, %S)\n", pName, hWnd, pPortName);
dwErrorCode = GetMonitorUI( pName, pPortName, L"XcvPort", &pmui, &pmuid );
FIXME("DeletePortW Error %d\n",dwErrorCode);
if (dwErrorCode != ERROR_SUCCESS )
{
if ( dwErrorCode == ERROR_NOT_SUPPORTED ||
dwErrorCode == ERROR_MOD_NOT_FOUND ||
dwErrorCode == ERROR_INVALID_PRINT_MONITOR ||
dwErrorCode == ERROR_UNKNOWN_PORT ||
dwErrorCode == ERROR_INVALID_PRINTER_NAME )
{
Ret = StartPortThread(pName, hWnd, pPortName, (PPfpFunction)_RpcDeletePort );
dwErrorCode = GetLastError();
}
}
else
{
Ret = (*pmui->pfnDeletePortUI)( pName, hWnd, pPortName );
}
SetLastError(dwErrorCode);
FreeMonitorUI( pmuid );
return Ret;
}
BOOL WINAPI
EnumPortsA(PSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
{
BOOL res;
LPBYTE bufferW = NULL;
LPWSTR nameW = NULL;
DWORD needed = 0;
DWORD numentries = 0;
INT len;
TRACE("EnumPortsA(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts, 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 Ports */
needed = cbBuf * sizeof(WCHAR);
if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
res = EnumPortsW(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 = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
}
needed = pcbNeeded ? *pcbNeeded : 0;
numentries = pcReturned ? *pcReturned : 0;
/*
W2k require the buffersize from EnumPortsW also for EnumPortsA.
We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
*/
if (res)
{
/* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
DWORD entrysize = 0;
DWORD index;
LPSTR ptr;
LPPORT_INFO_2W pi2w;
LPPORT_INFO_2A pi2a;
needed = 0;
entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
/* First pass: calculate the size for all Entries */
pi2w = (LPPORT_INFO_2W) bufferW;
pi2a = (LPPORT_INFO_2A) pPorts;
index = 0;
while (index < numentries)
{
index++;
needed += entrysize; /* PORT_INFO_?A */
TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
NULL, 0, NULL, NULL);
if (Level > 1)
{
needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
NULL, 0, NULL, NULL);
needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
NULL, 0, NULL, NULL);
}
/* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
}
/* check for errors and quit on failure */
if (cbBuf < needed)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
res = FALSE;
goto cleanup;
}
len = entrysize * numentries; /* room for all PORT_INFO_?A */
ptr = (LPSTR) &pPorts[len]; /* room for strings */
cbBuf -= len ; /* free Bytes in the user-Buffer */
pi2w = (LPPORT_INFO_2W) bufferW;
pi2a = (LPPORT_INFO_2A) pPorts;
index = 0;
/* Second Pass: Fill the User Buffer (if we have one) */
while ((index < numentries) && pPorts)
{
index++;
TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
pi2a->pPortName = ptr;
len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
ptr, cbBuf , NULL, NULL);
ptr += len;
cbBuf -= len;
if (Level > 1)
{
pi2a->pMonitorName = ptr;
len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
ptr, cbBuf, NULL, NULL);
ptr += len;
cbBuf -= len;
pi2a->pDescription = ptr;
len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
ptr, cbBuf, NULL, NULL);
ptr += len;
cbBuf -= len;
pi2a->fPortType = pi2w->fPortType;
pi2a->Reserved = 0; /* documented: "must be zero" */
}
/* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
}
}
cleanup:
if (pcbNeeded) *pcbNeeded = needed;
if (pcReturned) *pcReturned = (res) ? numentries : 0;
if (nameW) HeapFree(GetProcessHeap(), 0, nameW);
if (bufferW) HeapFree(GetProcessHeap(), 0, bufferW);
TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
(res), GetLastError(), needed, (res)? numentries : 0, numentries);
return (res);
}
BOOL WINAPI
EnumPortsW(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
{
DWORD dwErrorCode;
TRACE("EnumPortsW(%S, %lu, %p, %lu, %p, %p)\n", pName, Level, pPorts, 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 = _RpcEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwErrorCode = RpcExceptionCode();
ERR("_RpcEnumPorts 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, pPorts, *pcReturned, pPortInfoMarshalling[Level]->pInfo, pPortInfoMarshalling[Level]->cbStructureSize, TRUE);
}
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}
BOOL WINAPI
SetPortA(PSTR pName, PSTR pPortName, DWORD dwLevel, PBYTE pPortInfo)
{
LPWSTR NameW = NULL;
LPWSTR PortNameW = NULL;
PORT_INFO_3W pi3W;
PORT_INFO_3A *pi3A;
DWORD len;
BOOL res;
pi3A = (PORT_INFO_3A*)pPortInfo;
TRACE("SetPortA(%s, %s, %lu, %p)\n", pName, pPortName, dwLevel, pPortInfo);
if ( dwLevel != 3 )
{
ERR("Level = %d, unsupported!\n", dwLevel);
SetLastError(ERROR_INVALID_LEVEL);
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);
}
if (pPortName)
{
len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
PortNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, pPortName, -1, PortNameW, len);
}
if (pi3A->pszStatus)
{
len = MultiByteToWideChar(CP_ACP, 0, pi3A->pszStatus, -1, NULL, 0);
pi3W.pszStatus = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, pi3A->pszStatus, -1, pi3W.pszStatus, len);
}
pi3W.dwStatus = pi3A->dwStatus;
pi3W.dwSeverity = pi3A->dwSeverity;
res = SetPortW( NameW, PortNameW, dwLevel, (PBYTE)&pi3W );
if (NameW) HeapFree(GetProcessHeap(), 0, NameW);
if (PortNameW) HeapFree(GetProcessHeap(), 0, PortNameW);
if (pi3W.pszStatus) HeapFree(GetProcessHeap(), 0, pi3W.pszStatus);
return res;
}
BOOL WINAPI
SetPortW(PWSTR pName, PWSTR pPortName, DWORD dwLevel, PBYTE pPortInfo)
{
DWORD dwErrorCode;
WINSPOOL_PORT_CONTAINER PortInfoContainer;
TRACE("SetPortW(%S, %S, %lu, %p)\n", pName, pPortName, dwLevel, pPortInfo);
if ( dwLevel != 3 )
{
ERR("Level = %d, unsupported!\n", dwLevel);
SetLastError(ERROR_INVALID_LEVEL);
return FALSE;
}
PortInfoContainer.PortInfo.pPortInfo3 = (WINSPOOL_PORT_INFO_3*)pPortInfo;
PortInfoContainer.Level = dwLevel;
// Do the RPC call
RpcTryExcept
{
dwErrorCode = _RpcSetPort(pName, pPortName, &PortInfoContainer);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwErrorCode = RpcExceptionCode();
}
RpcEndExcept;
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}