/*++ 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 \\\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