You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1117 lines
27 KiB
1117 lines
27 KiB
/*++
|
|
|
|
Copyright (c) 1990-2003 Microsoft Corporation
|
|
All rights reserved
|
|
|
|
Module Name:
|
|
|
|
localmon.c
|
|
|
|
// @@BEGIN_DDKSPLIT
|
|
Abstract:
|
|
|
|
Environment:
|
|
|
|
User Mode -Win32
|
|
|
|
Revision History:
|
|
|
|
|
|
Adina Trufinescu (adinatru) 07-December 1998-2003
|
|
Commented LocalMonInitializePrintMonitor2 that used to be called by InitializePrintMonitor2;
|
|
Changed back to the old interface - InitializePrintMonitor which initialize LcmhMonitor to a MONITOREX structure.
|
|
MONITOREX structure are filled with old style functions(LcmxNAME) that (don't takes hMonitor as parameter).This functions calls
|
|
LcmNAME functions passing LcmhMonitor as hMonitor parameter.
|
|
|
|
// @@END_DDKSPLIT
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "lmon.h"
|
|
#include "irda.h"
|
|
|
|
// @@BEGIN_DDKSPLIT
|
|
#ifdef INTERNAL
|
|
//MODULE_DEBUG_INIT(DBG_ERROR | DBG_WARN, DBG_ERROR);
|
|
#endif
|
|
// @@END_DDKSPLIT
|
|
|
|
HANDLE LcmhMonitor;
|
|
HANDLE LcmhInst;
|
|
CRITICAL_SECTION LcmSpoolerSection;
|
|
DWORD LocalmonDebug;
|
|
|
|
DWORD LcmPortInfo1Strings[]={FIELD_OFFSET(PORT_INFO_1, pName),
|
|
(DWORD)-1};
|
|
|
|
DWORD LcmPortInfo2Strings[]={FIELD_OFFSET(PORT_INFO_2, pPortName),
|
|
FIELD_OFFSET(PORT_INFO_2, pMonitorName),
|
|
FIELD_OFFSET(PORT_INFO_2, pDescription),
|
|
(DWORD)-1};
|
|
|
|
WCHAR szPorts[] = L"ports";
|
|
WCHAR gszPorts[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports";
|
|
WCHAR szPortsEx[] = L"portsex"; /* Extra ports values */
|
|
WCHAR szFILE[] = L"FILE:";
|
|
WCHAR szLcmCOM[] = L"COM";
|
|
WCHAR szLcmLPT[] = L"LPT";
|
|
WCHAR szIRDA[] = L"IR";
|
|
|
|
extern WCHAR szWindows[];
|
|
extern WCHAR szINIKey_TransmissionRetryTimeout[];
|
|
|
|
BOOL
|
|
LocalMonInit(HANDLE hModule)
|
|
{
|
|
LcmhInst = hModule;
|
|
|
|
InitializeCriticalSection(&LcmSpoolerSection);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
LcmEnumPorts(
|
|
HANDLE hMonitor,
|
|
LPWSTR pName,
|
|
DWORD Level,
|
|
LPBYTE pPorts,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded,
|
|
LPDWORD pcReturned
|
|
)
|
|
{
|
|
PINILOCALMON pIniLocalMon = (PINILOCALMON)hMonitor;
|
|
PINIPORT pIniPort;
|
|
DWORD cb;
|
|
LPBYTE pEnd;
|
|
DWORD LastError=0;
|
|
|
|
LcmEnterSplSem();
|
|
|
|
cb=0;
|
|
|
|
pIniPort = pIniLocalMon->pIniPort;
|
|
|
|
CheckAndAddIrdaPort(pIniLocalMon);
|
|
|
|
while (pIniPort) {
|
|
|
|
if ( !(pIniPort->Status & PP_FILEPORT) ) {
|
|
|
|
cb+=GetPortSize(pIniPort, Level);
|
|
}
|
|
pIniPort=pIniPort->pNext;
|
|
}
|
|
|
|
*pcbNeeded=cb;
|
|
|
|
if (cb <= cbBuf) {
|
|
|
|
pEnd=pPorts+cbBuf;
|
|
*pcReturned=0;
|
|
|
|
pIniPort = pIniLocalMon->pIniPort;
|
|
while (pIniPort) {
|
|
|
|
if (!(pIniPort->Status & PP_FILEPORT)) {
|
|
|
|
pEnd = CopyIniPortToPort(pIniPort, Level, pPorts, pEnd);
|
|
|
|
if( !pEnd ){
|
|
LastError = GetLastError();
|
|
break;
|
|
}
|
|
|
|
switch (Level) {
|
|
case 1:
|
|
pPorts+=sizeof(PORT_INFO_1);
|
|
break;
|
|
case 2:
|
|
pPorts+=sizeof(PORT_INFO_2);
|
|
break;
|
|
default:
|
|
DBGMSG(DBG_ERROR,
|
|
("EnumPorts: invalid level %d", Level));
|
|
LastError = ERROR_INVALID_LEVEL;
|
|
goto Cleanup;
|
|
}
|
|
(*pcReturned)++;
|
|
}
|
|
pIniPort=pIniPort->pNext;
|
|
}
|
|
|
|
} else
|
|
|
|
LastError = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
Cleanup:
|
|
LcmLeaveSplSem();
|
|
|
|
if (LastError) {
|
|
|
|
SetLastError(LastError);
|
|
return FALSE;
|
|
|
|
} else
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
LcmxEnumPorts(
|
|
LPWSTR pName,
|
|
DWORD Level,
|
|
LPBYTE pPorts,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbNeeded,
|
|
LPDWORD pcReturned
|
|
)
|
|
{
|
|
return LcmEnumPorts(LcmhMonitor, pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
|
|
}
|
|
|
|
BOOL
|
|
LcmOpenPort(
|
|
HANDLE hMonitor,
|
|
LPWSTR pName,
|
|
PHANDLE pHandle
|
|
)
|
|
{
|
|
PINILOCALMON pIniLocalMon = (PINILOCALMON)hMonitor;
|
|
PINIPORT pIniPort;
|
|
BOOL bRet = FALSE;
|
|
|
|
LcmEnterSplSem();
|
|
|
|
if ( IS_FILE_PORT(pName) ) {
|
|
|
|
//
|
|
// We will always create multiple file port
|
|
// entries, so that the spooler can print
|
|
// to multiple files.
|
|
//
|
|
DBGMSG(DBG_TRACE, ("Creating a new pIniPort for %ws\n", pName));
|
|
pIniPort = LcmCreatePortEntry( pIniLocalMon, pName );
|
|
if ( !pIniPort )
|
|
goto Done;
|
|
|
|
pIniPort->Status |= PP_FILEPORT;
|
|
*pHandle = pIniPort;
|
|
bRet = TRUE;
|
|
goto Done;
|
|
}
|
|
|
|
pIniPort = FindPort(pIniLocalMon, pName);
|
|
|
|
if ( !pIniPort )
|
|
goto Done;
|
|
|
|
//
|
|
// For LPT ports language monitors could do reads outside Start/End doc
|
|
// port to do bidi even when there are no jobs printing. So we do a
|
|
// CreateFile and keep the handle open all the time.
|
|
//
|
|
// But for COM ports you could have multiple devices attached to a COM
|
|
// port (ex. a printer and some other device with a switch)
|
|
// To be able to use the other device they write a utility which will
|
|
// do a net stop serial and then use the other device. To be able to
|
|
// stop the serial service spooler should not have a handle to the port.
|
|
// So we need to keep handle to COM port open only when there is a job
|
|
// printing
|
|
//
|
|
//
|
|
if ( IS_COM_PORT(pName) ) {
|
|
|
|
bRet = TRUE;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// If it is not a port redirected we are done (succeed the call)
|
|
//
|
|
if ( ValidateDosDevicePort(pIniPort) ) {
|
|
|
|
bRet = TRUE;
|
|
|
|
//
|
|
// If it isn't a true dosdevice port (ex. net use lpt1 \\<server>\printer)
|
|
// then we need to do CreateFile and CloseHandle per job so that
|
|
// StartDoc/EndDoc is issued properly for the remote printer
|
|
//
|
|
if ( (pIniPort->Status & PP_DOSDEVPORT) &&
|
|
!(pIniPort->Status & PP_COMM_PORT) ) {
|
|
|
|
CloseHandle(pIniPort->hFile);
|
|
pIniPort->hFile = INVALID_HANDLE_VALUE;
|
|
|
|
(VOID)RemoveDosDeviceDefinition(pIniPort);
|
|
}
|
|
}
|
|
|
|
Done:
|
|
if ( !bRet && pIniPort && (pIniPort->Status & PP_FILEPORT) )
|
|
DeletePortNode(pIniLocalMon, pIniPort);
|
|
|
|
if ( bRet )
|
|
*pHandle = pIniPort;
|
|
|
|
LcmLeaveSplSem();
|
|
return bRet;
|
|
}
|
|
|
|
BOOL
|
|
LcmxOpenPort(
|
|
LPWSTR pName,
|
|
PHANDLE pHandle
|
|
)
|
|
{
|
|
return LcmOpenPort(LcmhMonitor, pName, pHandle);
|
|
}
|
|
|
|
BOOL
|
|
LcmStartDocPort(
|
|
HANDLE hPort,
|
|
LPWSTR pPrinterName,
|
|
DWORD JobId,
|
|
DWORD Level,
|
|
LPBYTE pDocInfo)
|
|
{
|
|
PINIPORT pIniPort = (PINIPORT)hPort;
|
|
PDOC_INFO_1 pDocInfo1 = (PDOC_INFO_1)pDocInfo;
|
|
DWORD Error = 0;
|
|
|
|
DBGMSG(DBG_TRACE, ("StartDocPort(%08x, %ws, %d, %d, %08x)\n",
|
|
hPort, pPrinterName, JobId, Level, pDocInfo));
|
|
|
|
if (pIniPort->Status & PP_STARTDOC) {
|
|
return TRUE;
|
|
}
|
|
|
|
LcmEnterSplSem();
|
|
pIniPort->Status |= PP_STARTDOC;
|
|
LcmLeaveSplSem();
|
|
|
|
pIniPort->hPrinter = NULL;
|
|
pIniPort->pPrinterName = AllocSplStr(pPrinterName);
|
|
|
|
if (pIniPort->pPrinterName) {
|
|
|
|
if (OpenPrinter(pPrinterName, &pIniPort->hPrinter, NULL)) {
|
|
|
|
pIniPort->JobId = JobId;
|
|
|
|
//
|
|
// For COMx port we need to validates dos device now since
|
|
// we do not do it during OpenPort
|
|
//
|
|
if ( IS_COM_PORT(pIniPort->pName) &&
|
|
!ValidateDosDevicePort(pIniPort) ) {
|
|
|
|
goto Fail;
|
|
}
|
|
|
|
if ( IS_FILE_PORT(pIniPort->pName) ) {
|
|
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
|
|
if (pDocInfo1 &&
|
|
pDocInfo1->pOutputFile &&
|
|
pDocInfo1->pOutputFile[0]){
|
|
|
|
hFile = CreateFile( pDocInfo1->pOutputFile,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL );
|
|
|
|
DBGMSG(DBG_TRACE,
|
|
("Print to file and the handle is %x\n", hFile));
|
|
|
|
}
|
|
else
|
|
{
|
|
Error = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
SetEndOfFile(hFile);
|
|
|
|
pIniPort->hFile = hFile;
|
|
} else if ( IS_IRDA_PORT(pIniPort->pName) ) {
|
|
|
|
if ( !IrdaStartDocPort(pIniPort) )
|
|
goto Fail;
|
|
} else if ( !(pIniPort->Status & PP_DOSDEVPORT) ) {
|
|
|
|
//
|
|
// For non dosdevices CreateFile on the name of the port
|
|
//
|
|
pIniPort->hFile = CreateFile(pIniPort->pName,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL |
|
|
FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL);
|
|
|
|
if ( pIniPort->hFile != INVALID_HANDLE_VALUE )
|
|
SetEndOfFile(pIniPort->hFile);
|
|
|
|
} else if ( !IS_COM_PORT(pIniPort->pName) ) {
|
|
|
|
if ( !FixupDosDeviceDefinition(pIniPort) )
|
|
goto Fail;
|
|
}
|
|
}
|
|
} // end of if (pIniPort->pPrinterName)
|
|
|
|
if (pIniPort->hFile == INVALID_HANDLE_VALUE)
|
|
goto Fail;
|
|
|
|
return TRUE;
|
|
|
|
|
|
Fail:
|
|
SPLASSERT(pIniPort->hFile == INVALID_HANDLE_VALUE);
|
|
|
|
LcmEnterSplSem();
|
|
pIniPort->Status &= ~PP_STARTDOC;
|
|
LcmLeaveSplSem();
|
|
|
|
if (pIniPort->hPrinter) {
|
|
ClosePrinter(pIniPort->hPrinter);
|
|
}
|
|
|
|
if (pIniPort->pPrinterName) {
|
|
FreeSplStr(pIniPort->pPrinterName);
|
|
}
|
|
|
|
if (Error)
|
|
SetLastError(Error);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
LcmWritePort(
|
|
HANDLE hPort,
|
|
LPBYTE pBuffer,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbWritten)
|
|
{
|
|
PINIPORT pIniPort = (PINIPORT)hPort;
|
|
BOOL rc;
|
|
|
|
DBGMSG(DBG_TRACE, ("WritePort(%08x, %08x, %d)\n", hPort, pBuffer, cbBuf));
|
|
|
|
if ( IS_IRDA_PORT(pIniPort->pName) )
|
|
rc = IrdaWritePort(pIniPort, pBuffer, cbBuf, pcbWritten);
|
|
else if ( !pIniPort->hFile || pIniPort->hFile == INVALID_HANDLE_VALUE ) {
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
} else {
|
|
|
|
rc = WriteFile(pIniPort->hFile, pBuffer, cbBuf, pcbWritten, NULL);
|
|
if ( rc && *pcbWritten == 0 ) {
|
|
|
|
SetLastError(ERROR_TIMEOUT);
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
|
|
DBGMSG(DBG_TRACE, ("WritePort returns %d; %d bytes written\n", rc, *pcbWritten));
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
BOOL
|
|
LcmReadPort(
|
|
HANDLE hPort,
|
|
LPBYTE pBuffer,
|
|
DWORD cbBuf,
|
|
LPDWORD pcbRead)
|
|
{
|
|
PINIPORT pIniPort = (PINIPORT)hPort;
|
|
BOOL rc;
|
|
|
|
DBGMSG(DBG_TRACE, ("ReadPort(%08x, %08x, %d)\n", hPort, pBuffer, cbBuf));
|
|
|
|
if ( !pIniPort->hFile ||
|
|
pIniPort->hFile == INVALID_HANDLE_VALUE ||
|
|
!(pIniPort->Status & PP_COMM_PORT) ) {
|
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
rc = ReadFile(pIniPort->hFile, pBuffer, cbBuf, pcbRead, NULL);
|
|
|
|
DBGMSG(DBG_TRACE, ("ReadPort returns %d; %d bytes read\n", rc, *pcbRead));
|
|
|
|
return rc;
|
|
}
|
|
|
|
BOOL
|
|
LcmEndDocPort(
|
|
HANDLE hPort
|
|
)
|
|
{
|
|
PINIPORT pIniPort = (PINIPORT)hPort;
|
|
|
|
DBGMSG(DBG_TRACE, ("EndDocPort(%08x)\n", hPort));
|
|
|
|
if (!(pIniPort->Status & PP_STARTDOC)) {
|
|
return TRUE;
|
|
}
|
|
|
|
// The flush here is done to make sure any cached IO's get written
|
|
// before the handle is closed. This is particularly a problem
|
|
// for Intelligent buffered serial devices
|
|
|
|
FlushFileBuffers(pIniPort->hFile);
|
|
|
|
//
|
|
// For any ports other than real LPT ports we open during StartDocPort
|
|
// and close it during EndDocPort
|
|
//
|
|
if ( !(pIniPort->Status & PP_COMM_PORT) || IS_COM_PORT(pIniPort->pName) ) {
|
|
|
|
if ( IS_IRDA_PORT(pIniPort->pName) ) {
|
|
|
|
IrdaEndDocPort(pIniPort);
|
|
} else {
|
|
|
|
CloseHandle(pIniPort->hFile);
|
|
pIniPort->hFile = INVALID_HANDLE_VALUE;
|
|
|
|
if ( pIniPort->Status & PP_DOSDEVPORT ) {
|
|
|
|
(VOID)RemoveDosDeviceDefinition(pIniPort);
|
|
}
|
|
|
|
if ( IS_COM_PORT(pIniPort->pName) ) {
|
|
|
|
pIniPort->Status &= ~(PP_COMM_PORT | PP_DOSDEVPORT);
|
|
FreeSplStr(pIniPort->pDeviceName);
|
|
pIniPort->pDeviceName = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
SetJob(pIniPort->hPrinter, pIniPort->JobId, 0, NULL, JOB_CONTROL_SENT_TO_PRINTER);
|
|
|
|
ClosePrinter(pIniPort->hPrinter);
|
|
|
|
FreeSplStr(pIniPort->pPrinterName);
|
|
|
|
//
|
|
// Startdoc no longer active.
|
|
//
|
|
pIniPort->Status &= ~PP_STARTDOC;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
LcmClosePort(
|
|
HANDLE hPort
|
|
)
|
|
{
|
|
PINIPORT pIniPort = (PINIPORT)hPort;
|
|
|
|
FreeSplStr(pIniPort->pDeviceName);
|
|
pIniPort->pDeviceName = NULL;
|
|
|
|
if (pIniPort->Status & PP_FILEPORT) {
|
|
|
|
LcmEnterSplSem();
|
|
DeletePortNode(pIniPort->pIniLocalMon, pIniPort);
|
|
LcmLeaveSplSem();
|
|
} else if ( pIniPort->Status & PP_COMM_PORT ) {
|
|
|
|
(VOID) RemoveDosDeviceDefinition(pIniPort);
|
|
if ( pIniPort->hFile != INVALID_HANDLE_VALUE ) {
|
|
|
|
// @@BEGIN_DDKSPLIT
|
|
if ( pIniPort->hNotify ) {
|
|
|
|
SplUnregisterForDeviceEvents(pIniPort->hNotify);
|
|
pIniPort->hNotify = NULL;
|
|
}
|
|
// @@END_DDKSPLIT
|
|
|
|
CloseHandle(pIniPort->hFile);
|
|
pIniPort->hFile = INVALID_HANDLE_VALUE;
|
|
}
|
|
pIniPort->Status &= ~(PP_COMM_PORT | PP_DOSDEVPORT);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
LcmAddPortEx(
|
|
HANDLE hMonitor,
|
|
LPWSTR pName,
|
|
DWORD Level,
|
|
LPBYTE pBuffer,
|
|
LPWSTR pMonitorName
|
|
)
|
|
{
|
|
PINILOCALMON pIniLocalMon = (PINILOCALMON)hMonitor;
|
|
LPWSTR pPortName;
|
|
DWORD Error;
|
|
LPPORT_INFO_1 pPortInfo1;
|
|
LPPORT_INFO_FF pPortInfoFF;
|
|
|
|
switch (Level) {
|
|
case (DWORD)-1:
|
|
pPortInfoFF = (LPPORT_INFO_FF)pBuffer;
|
|
pPortName = pPortInfoFF->pName;
|
|
break;
|
|
|
|
case 1:
|
|
pPortInfo1 = (LPPORT_INFO_1)pBuffer;
|
|
pPortName = pPortInfo1->pName;
|
|
break;
|
|
|
|
default:
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
return(FALSE);
|
|
}
|
|
if (!pPortName) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
if (PortExists(pName, pPortName, &Error)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
if (Error != NO_ERROR) {
|
|
SetLastError(Error);
|
|
return(FALSE);
|
|
}
|
|
if (!LcmCreatePortEntry(pIniLocalMon, pPortName)) {
|
|
return(FALSE);
|
|
}
|
|
if (!WriteProfileString(szPorts, pPortName, L"")) {
|
|
LcmDeletePortEntry( pIniLocalMon, pPortName );
|
|
return(FALSE);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
LcmxAddPortEx(
|
|
LPWSTR pName,
|
|
DWORD Level,
|
|
LPBYTE pBuffer,
|
|
LPWSTR pMonitorName
|
|
)
|
|
{
|
|
return LcmAddPortEx(LcmhMonitor, pName, Level, pBuffer, pMonitorName);
|
|
}
|
|
|
|
BOOL
|
|
LcmGetPrinterDataFromPort(
|
|
HANDLE hPort,
|
|
DWORD ControlID,
|
|
LPWSTR pValueName,
|
|
LPWSTR lpInBuffer,
|
|
DWORD cbInBuffer,
|
|
LPWSTR lpOutBuffer,
|
|
DWORD cbOutBuffer,
|
|
LPDWORD lpcbReturned)
|
|
{
|
|
PINIPORT pIniPort = (PINIPORT)hPort;
|
|
BOOL rc;
|
|
|
|
DBGMSG(DBG_TRACE,
|
|
("GetPrinterDataFromPort(%08x, %d, %ws, %ws, %d, ",
|
|
hPort, ControlID, pValueName, lpInBuffer, cbInBuffer));
|
|
|
|
if ( !ControlID ||
|
|
!pIniPort->hFile ||
|
|
pIniPort->hFile == INVALID_HANDLE_VALUE ||
|
|
!(pIniPort->Status & PP_DOSDEVPORT) ) {
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
rc = DeviceIoControl(pIniPort->hFile,
|
|
ControlID,
|
|
lpInBuffer,
|
|
cbInBuffer,
|
|
lpOutBuffer,
|
|
cbOutBuffer,
|
|
lpcbReturned,
|
|
NULL);
|
|
|
|
DBGMSG(DBG_TRACE,
|
|
("%ws, %d, %d)\n", lpOutBuffer, cbOutBuffer, lpcbReturned));
|
|
|
|
return rc;
|
|
}
|
|
|
|
BOOL
|
|
LcmSetPortTimeOuts(
|
|
HANDLE hPort,
|
|
LPCOMMTIMEOUTS lpCTO,
|
|
DWORD reserved) // must be set to 0
|
|
{
|
|
PINIPORT pIniPort = (PINIPORT)hPort;
|
|
COMMTIMEOUTS cto;
|
|
|
|
if (reserved != 0)
|
|
return FALSE;
|
|
|
|
if ( !(pIniPort->Status & PP_DOSDEVPORT) ) {
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if ( GetCommTimeouts(pIniPort->hFile, &cto) )
|
|
{
|
|
cto.ReadTotalTimeoutConstant = lpCTO->ReadTotalTimeoutConstant;
|
|
cto.ReadIntervalTimeout = lpCTO->ReadIntervalTimeout;
|
|
return SetCommTimeouts(pIniPort->hFile, &cto);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID
|
|
LcmShutdown(
|
|
HANDLE hMonitor
|
|
)
|
|
{
|
|
PINIPORT pIniPort;
|
|
PINIPORT pIniPortNext;
|
|
PINILOCALMON pIniLocalMon = (PINILOCALMON)hMonitor;
|
|
|
|
//
|
|
// Delete the ports, then delete the LOCALMONITOR.
|
|
//
|
|
for( pIniPort = pIniLocalMon->pIniPort; pIniPort; pIniPort = pIniPortNext ){
|
|
pIniPortNext = pIniPort->pNext;
|
|
FreeSplMem( pIniPort );
|
|
}
|
|
|
|
FreeSplMem( pIniLocalMon );
|
|
}
|
|
|
|
|
|
BOOL
|
|
LcmxXcvOpenPort(
|
|
LPCWSTR pszObject,
|
|
ACCESS_MASK GrantedAccess,
|
|
PHANDLE phXcv
|
|
)
|
|
{
|
|
return LcmXcvOpenPort(LcmhMonitor, pszObject, GrantedAccess, phXcv);
|
|
}
|
|
|
|
// @@BEGIN_DDKSPLIT
|
|
#ifdef _SPL_CLUST
|
|
// @@END_DDKSPLIT
|
|
|
|
MONITOR2 Monitor2 = {
|
|
sizeof(MONITOR2),
|
|
LcmEnumPorts,
|
|
LcmOpenPort,
|
|
NULL, // OpenPortEx is not supported
|
|
LcmStartDocPort,
|
|
LcmWritePort,
|
|
LcmReadPort,
|
|
LcmEndDocPort,
|
|
LcmClosePort,
|
|
NULL, // AddPort is not supported
|
|
LcmAddPortEx,
|
|
NULL, // ConfigurePort is not supported
|
|
NULL, // DeletePort is not supported
|
|
LcmGetPrinterDataFromPort,
|
|
LcmSetPortTimeOuts,
|
|
LcmXcvOpenPort,
|
|
LcmXcvDataPort,
|
|
LcmXcvClosePort,
|
|
LcmShutdown
|
|
};
|
|
|
|
|
|
LPMONITOR2
|
|
LocalMonInitializePrintMonitor2(
|
|
PMONITORINIT pMonitorInit,
|
|
PHANDLE phMonitor
|
|
)
|
|
{
|
|
LPWSTR pPortTmp;
|
|
DWORD dwCharCount=1024, rc, i, j;
|
|
PINILOCALMON pIniLocalMon = NULL;
|
|
LPWSTR pPorts = NULL;
|
|
|
|
// @@BEGIN_DDKSPLIT
|
|
//
|
|
// If we are clustered (e.g., bLocal is FALSE), then we don't want to
|
|
// initialize, since local ports can't be used with clustering.
|
|
//
|
|
// @@END_DDKSPLIT
|
|
if( !pMonitorInit->bLocal ){
|
|
return NULL;
|
|
}
|
|
|
|
do {
|
|
FreeSplMem((LPVOID)pPorts);
|
|
|
|
dwCharCount *= 2;
|
|
pPorts = (LPWSTR) AllocSplMem(dwCharCount*sizeof(WCHAR));
|
|
if ( !pPorts ) {
|
|
|
|
DBGMSG(DBG_ERROR,
|
|
("Failed to alloc %d characters for ports\n", dwCharCount));
|
|
goto Fail;
|
|
}
|
|
|
|
rc = GetProfileString(szPorts, NULL, szNULL, pPorts, dwCharCount);
|
|
//
|
|
// GetProfileString will does not return the proper character count for long port names.
|
|
// fail the call if the port list length exceeds 1mb
|
|
//
|
|
if ( !rc || dwCharCount >= 1024*1024 ) {
|
|
|
|
DBGMSG(DBG_ERROR,
|
|
("GetProfilesString failed with %d\n", GetLastError()));
|
|
goto Fail;
|
|
}
|
|
|
|
} while ( rc >= dwCharCount - 2 );
|
|
|
|
pIniLocalMon = (PINILOCALMON)AllocSplMem( sizeof( INILOCALMON ));
|
|
|
|
if( !pIniLocalMon ){
|
|
goto Fail;
|
|
}
|
|
|
|
pIniLocalMon->signature = ILM_SIGNATURE;
|
|
pIniLocalMon->pMonitorInit = pMonitorInit;
|
|
|
|
//
|
|
// dwCharCount is now the count of return buffer, not including
|
|
// the NULL terminator. When we are past pPorts[rc], then
|
|
// we have parsed the entire string.
|
|
//
|
|
dwCharCount = rc;
|
|
|
|
LcmEnterSplSem();
|
|
|
|
//
|
|
// We now have all the ports
|
|
//
|
|
for( j = 0; j <= dwCharCount; j += rc + 1 ){
|
|
|
|
pPortTmp = pPorts + j;
|
|
|
|
rc = wcslen(pPortTmp);
|
|
|
|
if( !rc ){
|
|
continue;
|
|
}
|
|
|
|
if (!_wcsnicmp(pPortTmp, L"Ne", 2)) {
|
|
|
|
i = 2;
|
|
//
|
|
// For Ne-ports
|
|
//
|
|
if ( rc > 2 && pPortTmp[2] == L'-' )
|
|
++i;
|
|
for ( ; i < rc - 1 && iswdigit(pPortTmp[i]) ; ++i )
|
|
;
|
|
|
|
if ( i == rc - 1 && pPortTmp[rc-1] == L':' ) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
LcmCreatePortEntry(pIniLocalMon, pPortTmp);
|
|
}
|
|
|
|
FreeSplMem(pPorts);
|
|
|
|
LcmLeaveSplSem();
|
|
|
|
CheckAndAddIrdaPort(pIniLocalMon);
|
|
|
|
*phMonitor = (HANDLE)pIniLocalMon;
|
|
|
|
return &Monitor2;
|
|
|
|
Fail:
|
|
|
|
FreeSplMem( pPorts );
|
|
FreeSplMem( pIniLocalMon );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// @@BEGIN_DDKSPLIT
|
|
#endif
|
|
|
|
MONITOREX MonitorEx = {
|
|
sizeof(MONITOR),
|
|
{
|
|
LcmxEnumPorts,
|
|
LcmxOpenPort,
|
|
NULL,
|
|
LcmStartDocPort,
|
|
LcmWritePort,
|
|
LcmReadPort,
|
|
LcmEndDocPort,
|
|
LcmClosePort,
|
|
NULL, // AddPort not supported
|
|
LcmxAddPortEx,
|
|
NULL, // ConfigurePort not supported
|
|
NULL, // DeletePort not supported
|
|
LcmGetPrinterDataFromPort,
|
|
LcmSetPortTimeOuts, // SetPortTimeOuts not supported
|
|
LcmxXcvOpenPort,
|
|
LcmXcvDataPort,
|
|
LcmXcvClosePort
|
|
}
|
|
};
|
|
|
|
DWORD
|
|
GetPortStrings(
|
|
PWSTR *ppPorts,
|
|
PDWORD pdwUsed
|
|
)
|
|
{
|
|
DWORD sRetval = ERROR_INVALID_PARAMETER;
|
|
HKEY hPortKey = NULL;
|
|
|
|
if (ppPorts && pdwUsed)
|
|
{
|
|
sRetval = RegOpenKeyEx(HKEY_LOCAL_MACHINE, gszPorts, 0, KEY_READ, &hPortKey);
|
|
|
|
if (sRetval == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwcValues = 0;
|
|
DWORD dwMaxValueName = 0;
|
|
|
|
sRetval = RegQueryInfoKey(hPortKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwcValues, &dwMaxValueName, NULL, NULL, NULL);
|
|
|
|
if (sRetval == ERROR_SUCCESS)
|
|
{
|
|
PWSTR pPorts = NULL;
|
|
DWORD cbMaxMemNeeded = ((dwcValues * (dwMaxValueName + 1) + 1) * sizeof(WCHAR));
|
|
|
|
pPorts = (LPWSTR)AllocSplMem(cbMaxMemNeeded);
|
|
|
|
if (pPorts)
|
|
{
|
|
DWORD sTempRetval = ERROR_SUCCESS;
|
|
INT CharsAvail = cbMaxMemNeeded/sizeof(WCHAR);
|
|
INT cIndex = 0;
|
|
PWSTR pPort = NULL;
|
|
DWORD dwCurLen = 0;
|
|
|
|
|
|
for (pPort = pPorts; (sTempRetval == ERROR_SUCCESS) && (CharsAvail > 0); cIndex++)
|
|
{
|
|
if (dwCurLen)
|
|
{
|
|
dwCurLen++;
|
|
CharsAvail -= dwCurLen;
|
|
pPort += dwCurLen;
|
|
}
|
|
|
|
dwCurLen = dwMaxValueName + 1;
|
|
sTempRetval = RegEnumValue(hPortKey, cIndex, pPort, &dwCurLen, NULL, NULL, NULL, NULL);
|
|
}
|
|
|
|
if ((sTempRetval == ERROR_NO_MORE_ITEMS) && (CharsAvail > 0))
|
|
{
|
|
*pPort = L'\0';
|
|
*ppPorts = pPorts;
|
|
CharsAvail--;
|
|
*pdwUsed = (cbMaxMemNeeded / sizeof(WCHAR)) - CharsAvail;
|
|
}
|
|
else
|
|
{
|
|
sRetval = sTempRetval;
|
|
|
|
if (sRetval == ERROR_SUCCESS)
|
|
{
|
|
sRetval = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sRetval = GetLastError();
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hPortKey);
|
|
}
|
|
}
|
|
|
|
return sRetval;
|
|
}
|
|
|
|
|
|
LPMONITOREX
|
|
WINAPI
|
|
InitializePrintMonitor(
|
|
IN LPTSTR pszRegistryRoot
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Fill the monitor function table. Spooler makes call to this routine
|
|
to get the monitor functions.
|
|
|
|
Arguments:
|
|
pszRegistryRoot : Registry root to be used by this dll
|
|
|
|
Return Value:
|
|
Pointer to monitor function table
|
|
|
|
--*/
|
|
{
|
|
LPWSTR pPortTmp;
|
|
DWORD dwCharCount=0, rc, i;
|
|
DWORD sRetval = ERROR_SUCCESS;
|
|
PINILOCALMON pIniLocalMon = NULL;
|
|
LPWSTR pPorts = NULL;
|
|
|
|
if ( !pszRegistryRoot || !*pszRegistryRoot ) {
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return NULL;
|
|
}
|
|
|
|
if (sRetval = GetPortStrings(&pPorts, &dwCharCount) != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(sRetval);
|
|
goto Fail;
|
|
}
|
|
|
|
pIniLocalMon = (PINILOCALMON)AllocSplMem( sizeof( INILOCALMON ));
|
|
|
|
if( !pIniLocalMon ){
|
|
goto Fail;
|
|
}
|
|
|
|
pIniLocalMon->signature = ILM_SIGNATURE;
|
|
|
|
|
|
LcmEnterSplSem();
|
|
|
|
//
|
|
// We now have all the ports
|
|
//
|
|
for(pPortTmp = pPorts; pPortTmp && *pPortTmp; pPortTmp += rc + 1){
|
|
|
|
rc = wcslen(pPortTmp);
|
|
|
|
if (!_wcsnicmp(pPortTmp, L"Ne", 2)) {
|
|
|
|
i = 2;
|
|
|
|
//
|
|
// For Ne- ports
|
|
//
|
|
if ( rc > 2 && pPortTmp[2] == L'-' )
|
|
++i;
|
|
for ( ; i < rc - 1 && iswdigit(pPortTmp[i]) ; ++i )
|
|
;
|
|
|
|
if ( i == rc - 1 && pPortTmp[rc-1] == L':' ) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
LcmCreatePortEntry(pIniLocalMon, pPortTmp);
|
|
}
|
|
|
|
FreeSplMem(pPorts);
|
|
|
|
LcmLeaveSplSem();
|
|
|
|
CheckAndAddIrdaPort(pIniLocalMon);
|
|
|
|
LcmhMonitor = (HANDLE)pIniLocalMon;
|
|
|
|
return &MonitorEx;
|
|
|
|
Fail:
|
|
|
|
FreeSplMem( pPorts );
|
|
FreeSplMem( pIniLocalMon );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
//
|
|
// Since the DDK is a standalone DLL, we need a DLL init routine.
|
|
// However, the NT version is a library and we call LocamonInit
|
|
// directly, so this isn't needed.
|
|
//
|
|
|
|
// @@END_DDKSPLIT
|
|
|
|
VOID
|
|
LocalMonCleanUp(
|
|
VOID
|
|
)
|
|
{
|
|
DeleteCriticalSection(&LcmSpoolerSection);
|
|
}
|
|
|
|
BOOL
|
|
DllMain(
|
|
HANDLE hModule,
|
|
DWORD dwReason,
|
|
LPVOID lpRes)
|
|
{
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
|
|
LocalMonInit(hModule);
|
|
DisableThreadLibraryCalls(hModule);
|
|
return TRUE;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
|
|
LocalMonCleanUp();
|
|
return TRUE;
|
|
}
|
|
|
|
UNREFERENCED_PARAMETER(lpRes);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// @@BEGIN_DDKSPLIT
|
|
#endif
|
|
// @@END_DDKSPLIT
|