Leaked source code of windows server 2003
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

  1. /*++
  2. Copyright (c) 1990-2003 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. localmon.c
  6. // @@BEGIN_DDKSPLIT
  7. Abstract:
  8. Environment:
  9. User Mode -Win32
  10. Revision History:
  11. Adina Trufinescu (adinatru) 07-December 1998-2003
  12. Commented LocalMonInitializePrintMonitor2 that used to be called by InitializePrintMonitor2;
  13. Changed back to the old interface - InitializePrintMonitor which initialize LcmhMonitor to a MONITOREX structure.
  14. MONITOREX structure are filled with old style functions(LcmxNAME) that (don't takes hMonitor as parameter).This functions calls
  15. LcmNAME functions passing LcmhMonitor as hMonitor parameter.
  16. // @@END_DDKSPLIT
  17. --*/
  18. #include "precomp.h"
  19. #pragma hdrstop
  20. #include "lmon.h"
  21. #include "irda.h"
  22. // @@BEGIN_DDKSPLIT
  23. #ifdef INTERNAL
  24. //MODULE_DEBUG_INIT(DBG_ERROR | DBG_WARN, DBG_ERROR);
  25. #endif
  26. // @@END_DDKSPLIT
  27. HANDLE LcmhMonitor;
  28. HANDLE LcmhInst;
  29. CRITICAL_SECTION LcmSpoolerSection;
  30. DWORD LocalmonDebug;
  31. DWORD LcmPortInfo1Strings[]={FIELD_OFFSET(PORT_INFO_1, pName),
  32. (DWORD)-1};
  33. DWORD LcmPortInfo2Strings[]={FIELD_OFFSET(PORT_INFO_2, pPortName),
  34. FIELD_OFFSET(PORT_INFO_2, pMonitorName),
  35. FIELD_OFFSET(PORT_INFO_2, pDescription),
  36. (DWORD)-1};
  37. WCHAR szPorts[] = L"ports";
  38. WCHAR gszPorts[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports";
  39. WCHAR szPortsEx[] = L"portsex"; /* Extra ports values */
  40. WCHAR szFILE[] = L"FILE:";
  41. WCHAR szLcmCOM[] = L"COM";
  42. WCHAR szLcmLPT[] = L"LPT";
  43. WCHAR szIRDA[] = L"IR";
  44. extern WCHAR szWindows[];
  45. extern WCHAR szINIKey_TransmissionRetryTimeout[];
  46. BOOL
  47. LocalMonInit(HANDLE hModule)
  48. {
  49. LcmhInst = hModule;
  50. InitializeCriticalSection(&LcmSpoolerSection);
  51. return TRUE;
  52. }
  53. BOOL
  54. LcmEnumPorts(
  55. HANDLE hMonitor,
  56. LPWSTR pName,
  57. DWORD Level,
  58. LPBYTE pPorts,
  59. DWORD cbBuf,
  60. LPDWORD pcbNeeded,
  61. LPDWORD pcReturned
  62. )
  63. {
  64. PINILOCALMON pIniLocalMon = (PINILOCALMON)hMonitor;
  65. PINIPORT pIniPort;
  66. DWORD cb;
  67. LPBYTE pEnd;
  68. DWORD LastError=0;
  69. LcmEnterSplSem();
  70. cb=0;
  71. pIniPort = pIniLocalMon->pIniPort;
  72. CheckAndAddIrdaPort(pIniLocalMon);
  73. while (pIniPort) {
  74. if ( !(pIniPort->Status & PP_FILEPORT) ) {
  75. cb+=GetPortSize(pIniPort, Level);
  76. }
  77. pIniPort=pIniPort->pNext;
  78. }
  79. *pcbNeeded=cb;
  80. if (cb <= cbBuf) {
  81. pEnd=pPorts+cbBuf;
  82. *pcReturned=0;
  83. pIniPort = pIniLocalMon->pIniPort;
  84. while (pIniPort) {
  85. if (!(pIniPort->Status & PP_FILEPORT)) {
  86. pEnd = CopyIniPortToPort(pIniPort, Level, pPorts, pEnd);
  87. if( !pEnd ){
  88. LastError = GetLastError();
  89. break;
  90. }
  91. switch (Level) {
  92. case 1:
  93. pPorts+=sizeof(PORT_INFO_1);
  94. break;
  95. case 2:
  96. pPorts+=sizeof(PORT_INFO_2);
  97. break;
  98. default:
  99. DBGMSG(DBG_ERROR,
  100. ("EnumPorts: invalid level %d", Level));
  101. LastError = ERROR_INVALID_LEVEL;
  102. goto Cleanup;
  103. }
  104. (*pcReturned)++;
  105. }
  106. pIniPort=pIniPort->pNext;
  107. }
  108. } else
  109. LastError = ERROR_INSUFFICIENT_BUFFER;
  110. Cleanup:
  111. LcmLeaveSplSem();
  112. if (LastError) {
  113. SetLastError(LastError);
  114. return FALSE;
  115. } else
  116. return TRUE;
  117. }
  118. BOOL
  119. LcmxEnumPorts(
  120. LPWSTR pName,
  121. DWORD Level,
  122. LPBYTE pPorts,
  123. DWORD cbBuf,
  124. LPDWORD pcbNeeded,
  125. LPDWORD pcReturned
  126. )
  127. {
  128. return LcmEnumPorts(LcmhMonitor, pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
  129. }
  130. BOOL
  131. LcmOpenPort(
  132. HANDLE hMonitor,
  133. LPWSTR pName,
  134. PHANDLE pHandle
  135. )
  136. {
  137. PINILOCALMON pIniLocalMon = (PINILOCALMON)hMonitor;
  138. PINIPORT pIniPort;
  139. BOOL bRet = FALSE;
  140. LcmEnterSplSem();
  141. if ( IS_FILE_PORT(pName) ) {
  142. //
  143. // We will always create multiple file port
  144. // entries, so that the spooler can print
  145. // to multiple files.
  146. //
  147. DBGMSG(DBG_TRACE, ("Creating a new pIniPort for %ws\n", pName));
  148. pIniPort = LcmCreatePortEntry( pIniLocalMon, pName );
  149. if ( !pIniPort )
  150. goto Done;
  151. pIniPort->Status |= PP_FILEPORT;
  152. *pHandle = pIniPort;
  153. bRet = TRUE;
  154. goto Done;
  155. }
  156. pIniPort = FindPort(pIniLocalMon, pName);
  157. if ( !pIniPort )
  158. goto Done;
  159. //
  160. // For LPT ports language monitors could do reads outside Start/End doc
  161. // port to do bidi even when there are no jobs printing. So we do a
  162. // CreateFile and keep the handle open all the time.
  163. //
  164. // But for COM ports you could have multiple devices attached to a COM
  165. // port (ex. a printer and some other device with a switch)
  166. // To be able to use the other device they write a utility which will
  167. // do a net stop serial and then use the other device. To be able to
  168. // stop the serial service spooler should not have a handle to the port.
  169. // So we need to keep handle to COM port open only when there is a job
  170. // printing
  171. //
  172. //
  173. if ( IS_COM_PORT(pName) ) {
  174. bRet = TRUE;
  175. goto Done;
  176. }
  177. //
  178. // If it is not a port redirected we are done (succeed the call)
  179. //
  180. if ( ValidateDosDevicePort(pIniPort) ) {
  181. bRet = TRUE;
  182. //
  183. // If it isn't a true dosdevice port (ex. net use lpt1 \\<server>\printer)
  184. // then we need to do CreateFile and CloseHandle per job so that
  185. // StartDoc/EndDoc is issued properly for the remote printer
  186. //
  187. if ( (pIniPort->Status & PP_DOSDEVPORT) &&
  188. !(pIniPort->Status & PP_COMM_PORT) ) {
  189. CloseHandle(pIniPort->hFile);
  190. pIniPort->hFile = INVALID_HANDLE_VALUE;
  191. (VOID)RemoveDosDeviceDefinition(pIniPort);
  192. }
  193. }
  194. Done:
  195. if ( !bRet && pIniPort && (pIniPort->Status & PP_FILEPORT) )
  196. DeletePortNode(pIniLocalMon, pIniPort);
  197. if ( bRet )
  198. *pHandle = pIniPort;
  199. LcmLeaveSplSem();
  200. return bRet;
  201. }
  202. BOOL
  203. LcmxOpenPort(
  204. LPWSTR pName,
  205. PHANDLE pHandle
  206. )
  207. {
  208. return LcmOpenPort(LcmhMonitor, pName, pHandle);
  209. }
  210. BOOL
  211. LcmStartDocPort(
  212. HANDLE hPort,
  213. LPWSTR pPrinterName,
  214. DWORD JobId,
  215. DWORD Level,
  216. LPBYTE pDocInfo)
  217. {
  218. PINIPORT pIniPort = (PINIPORT)hPort;
  219. PDOC_INFO_1 pDocInfo1 = (PDOC_INFO_1)pDocInfo;
  220. DWORD Error = 0;
  221. DBGMSG(DBG_TRACE, ("StartDocPort(%08x, %ws, %d, %d, %08x)\n",
  222. hPort, pPrinterName, JobId, Level, pDocInfo));
  223. if (pIniPort->Status & PP_STARTDOC) {
  224. return TRUE;
  225. }
  226. LcmEnterSplSem();
  227. pIniPort->Status |= PP_STARTDOC;
  228. LcmLeaveSplSem();
  229. pIniPort->hPrinter = NULL;
  230. pIniPort->pPrinterName = AllocSplStr(pPrinterName);
  231. if (pIniPort->pPrinterName) {
  232. if (OpenPrinter(pPrinterName, &pIniPort->hPrinter, NULL)) {
  233. pIniPort->JobId = JobId;
  234. //
  235. // For COMx port we need to validates dos device now since
  236. // we do not do it during OpenPort
  237. //
  238. if ( IS_COM_PORT(pIniPort->pName) &&
  239. !ValidateDosDevicePort(pIniPort) ) {
  240. goto Fail;
  241. }
  242. if ( IS_FILE_PORT(pIniPort->pName) ) {
  243. HANDLE hFile = INVALID_HANDLE_VALUE;
  244. if (pDocInfo1 &&
  245. pDocInfo1->pOutputFile &&
  246. pDocInfo1->pOutputFile[0]){
  247. hFile = CreateFile( pDocInfo1->pOutputFile,
  248. GENERIC_WRITE,
  249. FILE_SHARE_READ | FILE_SHARE_WRITE,
  250. NULL,
  251. OPEN_ALWAYS,
  252. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  253. NULL );
  254. DBGMSG(DBG_TRACE,
  255. ("Print to file and the handle is %x\n", hFile));
  256. }
  257. else
  258. {
  259. Error = ERROR_INVALID_PARAMETER;
  260. }
  261. if (hFile != INVALID_HANDLE_VALUE)
  262. SetEndOfFile(hFile);
  263. pIniPort->hFile = hFile;
  264. } else if ( IS_IRDA_PORT(pIniPort->pName) ) {
  265. if ( !IrdaStartDocPort(pIniPort) )
  266. goto Fail;
  267. } else if ( !(pIniPort->Status & PP_DOSDEVPORT) ) {
  268. //
  269. // For non dosdevices CreateFile on the name of the port
  270. //
  271. pIniPort->hFile = CreateFile(pIniPort->pName,
  272. GENERIC_WRITE,
  273. FILE_SHARE_READ,
  274. NULL,
  275. OPEN_ALWAYS,
  276. FILE_ATTRIBUTE_NORMAL |
  277. FILE_FLAG_SEQUENTIAL_SCAN,
  278. NULL);
  279. if ( pIniPort->hFile != INVALID_HANDLE_VALUE )
  280. SetEndOfFile(pIniPort->hFile);
  281. } else if ( !IS_COM_PORT(pIniPort->pName) ) {
  282. if ( !FixupDosDeviceDefinition(pIniPort) )
  283. goto Fail;
  284. }
  285. }
  286. } // end of if (pIniPort->pPrinterName)
  287. if (pIniPort->hFile == INVALID_HANDLE_VALUE)
  288. goto Fail;
  289. return TRUE;
  290. Fail:
  291. SPLASSERT(pIniPort->hFile == INVALID_HANDLE_VALUE);
  292. LcmEnterSplSem();
  293. pIniPort->Status &= ~PP_STARTDOC;
  294. LcmLeaveSplSem();
  295. if (pIniPort->hPrinter) {
  296. ClosePrinter(pIniPort->hPrinter);
  297. }
  298. if (pIniPort->pPrinterName) {
  299. FreeSplStr(pIniPort->pPrinterName);
  300. }
  301. if (Error)
  302. SetLastError(Error);
  303. return FALSE;
  304. }
  305. BOOL
  306. LcmWritePort(
  307. HANDLE hPort,
  308. LPBYTE pBuffer,
  309. DWORD cbBuf,
  310. LPDWORD pcbWritten)
  311. {
  312. PINIPORT pIniPort = (PINIPORT)hPort;
  313. BOOL rc;
  314. DBGMSG(DBG_TRACE, ("WritePort(%08x, %08x, %d)\n", hPort, pBuffer, cbBuf));
  315. if ( IS_IRDA_PORT(pIniPort->pName) )
  316. rc = IrdaWritePort(pIniPort, pBuffer, cbBuf, pcbWritten);
  317. else if ( !pIniPort->hFile || pIniPort->hFile == INVALID_HANDLE_VALUE ) {
  318. SetLastError(ERROR_INVALID_HANDLE);
  319. return FALSE;
  320. } else {
  321. rc = WriteFile(pIniPort->hFile, pBuffer, cbBuf, pcbWritten, NULL);
  322. if ( rc && *pcbWritten == 0 ) {
  323. SetLastError(ERROR_TIMEOUT);
  324. rc = FALSE;
  325. }
  326. }
  327. DBGMSG(DBG_TRACE, ("WritePort returns %d; %d bytes written\n", rc, *pcbWritten));
  328. return rc;
  329. }
  330. BOOL
  331. LcmReadPort(
  332. HANDLE hPort,
  333. LPBYTE pBuffer,
  334. DWORD cbBuf,
  335. LPDWORD pcbRead)
  336. {
  337. PINIPORT pIniPort = (PINIPORT)hPort;
  338. BOOL rc;
  339. DBGMSG(DBG_TRACE, ("ReadPort(%08x, %08x, %d)\n", hPort, pBuffer, cbBuf));
  340. if ( !pIniPort->hFile ||
  341. pIniPort->hFile == INVALID_HANDLE_VALUE ||
  342. !(pIniPort->Status & PP_COMM_PORT) ) {
  343. SetLastError(ERROR_INVALID_HANDLE);
  344. return FALSE;
  345. }
  346. rc = ReadFile(pIniPort->hFile, pBuffer, cbBuf, pcbRead, NULL);
  347. DBGMSG(DBG_TRACE, ("ReadPort returns %d; %d bytes read\n", rc, *pcbRead));
  348. return rc;
  349. }
  350. BOOL
  351. LcmEndDocPort(
  352. HANDLE hPort
  353. )
  354. {
  355. PINIPORT pIniPort = (PINIPORT)hPort;
  356. DBGMSG(DBG_TRACE, ("EndDocPort(%08x)\n", hPort));
  357. if (!(pIniPort->Status & PP_STARTDOC)) {
  358. return TRUE;
  359. }
  360. // The flush here is done to make sure any cached IO's get written
  361. // before the handle is closed. This is particularly a problem
  362. // for Intelligent buffered serial devices
  363. FlushFileBuffers(pIniPort->hFile);
  364. //
  365. // For any ports other than real LPT ports we open during StartDocPort
  366. // and close it during EndDocPort
  367. //
  368. if ( !(pIniPort->Status & PP_COMM_PORT) || IS_COM_PORT(pIniPort->pName) ) {
  369. if ( IS_IRDA_PORT(pIniPort->pName) ) {
  370. IrdaEndDocPort(pIniPort);
  371. } else {
  372. CloseHandle(pIniPort->hFile);
  373. pIniPort->hFile = INVALID_HANDLE_VALUE;
  374. if ( pIniPort->Status & PP_DOSDEVPORT ) {
  375. (VOID)RemoveDosDeviceDefinition(pIniPort);
  376. }
  377. if ( IS_COM_PORT(pIniPort->pName) ) {
  378. pIniPort->Status &= ~(PP_COMM_PORT | PP_DOSDEVPORT);
  379. FreeSplStr(pIniPort->pDeviceName);
  380. pIniPort->pDeviceName = NULL;
  381. }
  382. }
  383. }
  384. SetJob(pIniPort->hPrinter, pIniPort->JobId, 0, NULL, JOB_CONTROL_SENT_TO_PRINTER);
  385. ClosePrinter(pIniPort->hPrinter);
  386. FreeSplStr(pIniPort->pPrinterName);
  387. //
  388. // Startdoc no longer active.
  389. //
  390. pIniPort->Status &= ~PP_STARTDOC;
  391. return TRUE;
  392. }
  393. BOOL
  394. LcmClosePort(
  395. HANDLE hPort
  396. )
  397. {
  398. PINIPORT pIniPort = (PINIPORT)hPort;
  399. FreeSplStr(pIniPort->pDeviceName);
  400. pIniPort->pDeviceName = NULL;
  401. if (pIniPort->Status & PP_FILEPORT) {
  402. LcmEnterSplSem();
  403. DeletePortNode(pIniPort->pIniLocalMon, pIniPort);
  404. LcmLeaveSplSem();
  405. } else if ( pIniPort->Status & PP_COMM_PORT ) {
  406. (VOID) RemoveDosDeviceDefinition(pIniPort);
  407. if ( pIniPort->hFile != INVALID_HANDLE_VALUE ) {
  408. // @@BEGIN_DDKSPLIT
  409. if ( pIniPort->hNotify ) {
  410. SplUnregisterForDeviceEvents(pIniPort->hNotify);
  411. pIniPort->hNotify = NULL;
  412. }
  413. // @@END_DDKSPLIT
  414. CloseHandle(pIniPort->hFile);
  415. pIniPort->hFile = INVALID_HANDLE_VALUE;
  416. }
  417. pIniPort->Status &= ~(PP_COMM_PORT | PP_DOSDEVPORT);
  418. }
  419. return TRUE;
  420. }
  421. BOOL
  422. LcmAddPortEx(
  423. HANDLE hMonitor,
  424. LPWSTR pName,
  425. DWORD Level,
  426. LPBYTE pBuffer,
  427. LPWSTR pMonitorName
  428. )
  429. {
  430. PINILOCALMON pIniLocalMon = (PINILOCALMON)hMonitor;
  431. LPWSTR pPortName;
  432. DWORD Error;
  433. LPPORT_INFO_1 pPortInfo1;
  434. LPPORT_INFO_FF pPortInfoFF;
  435. switch (Level) {
  436. case (DWORD)-1:
  437. pPortInfoFF = (LPPORT_INFO_FF)pBuffer;
  438. pPortName = pPortInfoFF->pName;
  439. break;
  440. case 1:
  441. pPortInfo1 = (LPPORT_INFO_1)pBuffer;
  442. pPortName = pPortInfo1->pName;
  443. break;
  444. default:
  445. SetLastError(ERROR_INVALID_LEVEL);
  446. return(FALSE);
  447. }
  448. if (!pPortName) {
  449. SetLastError(ERROR_INVALID_PARAMETER);
  450. return(FALSE);
  451. }
  452. if (PortExists(pName, pPortName, &Error)) {
  453. SetLastError(ERROR_INVALID_PARAMETER);
  454. return(FALSE);
  455. }
  456. if (Error != NO_ERROR) {
  457. SetLastError(Error);
  458. return(FALSE);
  459. }
  460. if (!LcmCreatePortEntry(pIniLocalMon, pPortName)) {
  461. return(FALSE);
  462. }
  463. if (!WriteProfileString(szPorts, pPortName, L"")) {
  464. LcmDeletePortEntry( pIniLocalMon, pPortName );
  465. return(FALSE);
  466. }
  467. return TRUE;
  468. }
  469. BOOL
  470. LcmxAddPortEx(
  471. LPWSTR pName,
  472. DWORD Level,
  473. LPBYTE pBuffer,
  474. LPWSTR pMonitorName
  475. )
  476. {
  477. return LcmAddPortEx(LcmhMonitor, pName, Level, pBuffer, pMonitorName);
  478. }
  479. BOOL
  480. LcmGetPrinterDataFromPort(
  481. HANDLE hPort,
  482. DWORD ControlID,
  483. LPWSTR pValueName,
  484. LPWSTR lpInBuffer,
  485. DWORD cbInBuffer,
  486. LPWSTR lpOutBuffer,
  487. DWORD cbOutBuffer,
  488. LPDWORD lpcbReturned)
  489. {
  490. PINIPORT pIniPort = (PINIPORT)hPort;
  491. BOOL rc;
  492. DBGMSG(DBG_TRACE,
  493. ("GetPrinterDataFromPort(%08x, %d, %ws, %ws, %d, ",
  494. hPort, ControlID, pValueName, lpInBuffer, cbInBuffer));
  495. if ( !ControlID ||
  496. !pIniPort->hFile ||
  497. pIniPort->hFile == INVALID_HANDLE_VALUE ||
  498. !(pIniPort->Status & PP_DOSDEVPORT) ) {
  499. SetLastError(ERROR_INVALID_PARAMETER);
  500. return FALSE;
  501. }
  502. rc = DeviceIoControl(pIniPort->hFile,
  503. ControlID,
  504. lpInBuffer,
  505. cbInBuffer,
  506. lpOutBuffer,
  507. cbOutBuffer,
  508. lpcbReturned,
  509. NULL);
  510. DBGMSG(DBG_TRACE,
  511. ("%ws, %d, %d)\n", lpOutBuffer, cbOutBuffer, lpcbReturned));
  512. return rc;
  513. }
  514. BOOL
  515. LcmSetPortTimeOuts(
  516. HANDLE hPort,
  517. LPCOMMTIMEOUTS lpCTO,
  518. DWORD reserved) // must be set to 0
  519. {
  520. PINIPORT pIniPort = (PINIPORT)hPort;
  521. COMMTIMEOUTS cto;
  522. if (reserved != 0)
  523. return FALSE;
  524. if ( !(pIniPort->Status & PP_DOSDEVPORT) ) {
  525. SetLastError(ERROR_INVALID_PARAMETER);
  526. return FALSE;
  527. }
  528. if ( GetCommTimeouts(pIniPort->hFile, &cto) )
  529. {
  530. cto.ReadTotalTimeoutConstant = lpCTO->ReadTotalTimeoutConstant;
  531. cto.ReadIntervalTimeout = lpCTO->ReadIntervalTimeout;
  532. return SetCommTimeouts(pIniPort->hFile, &cto);
  533. }
  534. return FALSE;
  535. }
  536. VOID
  537. LcmShutdown(
  538. HANDLE hMonitor
  539. )
  540. {
  541. PINIPORT pIniPort;
  542. PINIPORT pIniPortNext;
  543. PINILOCALMON pIniLocalMon = (PINILOCALMON)hMonitor;
  544. //
  545. // Delete the ports, then delete the LOCALMONITOR.
  546. //
  547. for( pIniPort = pIniLocalMon->pIniPort; pIniPort; pIniPort = pIniPortNext ){
  548. pIniPortNext = pIniPort->pNext;
  549. FreeSplMem( pIniPort );
  550. }
  551. FreeSplMem( pIniLocalMon );
  552. }
  553. BOOL
  554. LcmxXcvOpenPort(
  555. LPCWSTR pszObject,
  556. ACCESS_MASK GrantedAccess,
  557. PHANDLE phXcv
  558. )
  559. {
  560. return LcmXcvOpenPort(LcmhMonitor, pszObject, GrantedAccess, phXcv);
  561. }
  562. // @@BEGIN_DDKSPLIT
  563. #ifdef _SPL_CLUST
  564. // @@END_DDKSPLIT
  565. MONITOR2 Monitor2 = {
  566. sizeof(MONITOR2),
  567. LcmEnumPorts,
  568. LcmOpenPort,
  569. NULL, // OpenPortEx is not supported
  570. LcmStartDocPort,
  571. LcmWritePort,
  572. LcmReadPort,
  573. LcmEndDocPort,
  574. LcmClosePort,
  575. NULL, // AddPort is not supported
  576. LcmAddPortEx,
  577. NULL, // ConfigurePort is not supported
  578. NULL, // DeletePort is not supported
  579. LcmGetPrinterDataFromPort,
  580. LcmSetPortTimeOuts,
  581. LcmXcvOpenPort,
  582. LcmXcvDataPort,
  583. LcmXcvClosePort,
  584. LcmShutdown
  585. };
  586. LPMONITOR2
  587. LocalMonInitializePrintMonitor2(
  588. PMONITORINIT pMonitorInit,
  589. PHANDLE phMonitor
  590. )
  591. {
  592. LPWSTR pPortTmp;
  593. DWORD dwCharCount=1024, rc, i, j;
  594. PINILOCALMON pIniLocalMon = NULL;
  595. LPWSTR pPorts = NULL;
  596. // @@BEGIN_DDKSPLIT
  597. //
  598. // If we are clustered (e.g., bLocal is FALSE), then we don't want to
  599. // initialize, since local ports can't be used with clustering.
  600. //
  601. // @@END_DDKSPLIT
  602. if( !pMonitorInit->bLocal ){
  603. return NULL;
  604. }
  605. do {
  606. FreeSplMem((LPVOID)pPorts);
  607. dwCharCount *= 2;
  608. pPorts = (LPWSTR) AllocSplMem(dwCharCount*sizeof(WCHAR));
  609. if ( !pPorts ) {
  610. DBGMSG(DBG_ERROR,
  611. ("Failed to alloc %d characters for ports\n", dwCharCount));
  612. goto Fail;
  613. }
  614. rc = GetProfileString(szPorts, NULL, szNULL, pPorts, dwCharCount);
  615. //
  616. // GetProfileString will does not return the proper character count for long port names.
  617. // fail the call if the port list length exceeds 1mb
  618. //
  619. if ( !rc || dwCharCount >= 1024*1024 ) {
  620. DBGMSG(DBG_ERROR,
  621. ("GetProfilesString failed with %d\n", GetLastError()));
  622. goto Fail;
  623. }
  624. } while ( rc >= dwCharCount - 2 );
  625. pIniLocalMon = (PINILOCALMON)AllocSplMem( sizeof( INILOCALMON ));
  626. if( !pIniLocalMon ){
  627. goto Fail;
  628. }
  629. pIniLocalMon->signature = ILM_SIGNATURE;
  630. pIniLocalMon->pMonitorInit = pMonitorInit;
  631. //
  632. // dwCharCount is now the count of return buffer, not including
  633. // the NULL terminator. When we are past pPorts[rc], then
  634. // we have parsed the entire string.
  635. //
  636. dwCharCount = rc;
  637. LcmEnterSplSem();
  638. //
  639. // We now have all the ports
  640. //
  641. for( j = 0; j <= dwCharCount; j += rc + 1 ){
  642. pPortTmp = pPorts + j;
  643. rc = wcslen(pPortTmp);
  644. if( !rc ){
  645. continue;
  646. }
  647. if (!_wcsnicmp(pPortTmp, L"Ne", 2)) {
  648. i = 2;
  649. //
  650. // For Ne-ports
  651. //
  652. if ( rc > 2 && pPortTmp[2] == L'-' )
  653. ++i;
  654. for ( ; i < rc - 1 && iswdigit(pPortTmp[i]) ; ++i )
  655. ;
  656. if ( i == rc - 1 && pPortTmp[rc-1] == L':' ) {
  657. continue;
  658. }
  659. }
  660. LcmCreatePortEntry(pIniLocalMon, pPortTmp);
  661. }
  662. FreeSplMem(pPorts);
  663. LcmLeaveSplSem();
  664. CheckAndAddIrdaPort(pIniLocalMon);
  665. *phMonitor = (HANDLE)pIniLocalMon;
  666. return &Monitor2;
  667. Fail:
  668. FreeSplMem( pPorts );
  669. FreeSplMem( pIniLocalMon );
  670. return NULL;
  671. }
  672. // @@BEGIN_DDKSPLIT
  673. #endif
  674. MONITOREX MonitorEx = {
  675. sizeof(MONITOR),
  676. {
  677. LcmxEnumPorts,
  678. LcmxOpenPort,
  679. NULL,
  680. LcmStartDocPort,
  681. LcmWritePort,
  682. LcmReadPort,
  683. LcmEndDocPort,
  684. LcmClosePort,
  685. NULL, // AddPort not supported
  686. LcmxAddPortEx,
  687. NULL, // ConfigurePort not supported
  688. NULL, // DeletePort not supported
  689. LcmGetPrinterDataFromPort,
  690. LcmSetPortTimeOuts, // SetPortTimeOuts not supported
  691. LcmxXcvOpenPort,
  692. LcmXcvDataPort,
  693. LcmXcvClosePort
  694. }
  695. };
  696. DWORD
  697. GetPortStrings(
  698. PWSTR *ppPorts,
  699. PDWORD pdwUsed
  700. )
  701. {
  702. DWORD sRetval = ERROR_INVALID_PARAMETER;
  703. HKEY hPortKey = NULL;
  704. if (ppPorts && pdwUsed)
  705. {
  706. sRetval = RegOpenKeyEx(HKEY_LOCAL_MACHINE, gszPorts, 0, KEY_READ, &hPortKey);
  707. if (sRetval == ERROR_SUCCESS)
  708. {
  709. DWORD dwcValues = 0;
  710. DWORD dwMaxValueName = 0;
  711. sRetval = RegQueryInfoKey(hPortKey, NULL, NULL, NULL, NULL, NULL, NULL, &dwcValues, &dwMaxValueName, NULL, NULL, NULL);
  712. if (sRetval == ERROR_SUCCESS)
  713. {
  714. PWSTR pPorts = NULL;
  715. DWORD cbMaxMemNeeded = ((dwcValues * (dwMaxValueName + 1) + 1) * sizeof(WCHAR));
  716. pPorts = (LPWSTR)AllocSplMem(cbMaxMemNeeded);
  717. if (pPorts)
  718. {
  719. DWORD sTempRetval = ERROR_SUCCESS;
  720. INT CharsAvail = cbMaxMemNeeded/sizeof(WCHAR);
  721. INT cIndex = 0;
  722. PWSTR pPort = NULL;
  723. DWORD dwCurLen = 0;
  724. for (pPort = pPorts; (sTempRetval == ERROR_SUCCESS) && (CharsAvail > 0); cIndex++)
  725. {
  726. if (dwCurLen)
  727. {
  728. dwCurLen++;
  729. CharsAvail -= dwCurLen;
  730. pPort += dwCurLen;
  731. }
  732. dwCurLen = dwMaxValueName + 1;
  733. sTempRetval = RegEnumValue(hPortKey, cIndex, pPort, &dwCurLen, NULL, NULL, NULL, NULL);
  734. }
  735. if ((sTempRetval == ERROR_NO_MORE_ITEMS) && (CharsAvail > 0))
  736. {
  737. *pPort = L'\0';
  738. *ppPorts = pPorts;
  739. CharsAvail--;
  740. *pdwUsed = (cbMaxMemNeeded / sizeof(WCHAR)) - CharsAvail;
  741. }
  742. else
  743. {
  744. sRetval = sTempRetval;
  745. if (sRetval == ERROR_SUCCESS)
  746. {
  747. sRetval = ERROR_NOT_ENOUGH_MEMORY;
  748. }
  749. }
  750. }
  751. else
  752. {
  753. sRetval = GetLastError();
  754. }
  755. }
  756. RegCloseKey(hPortKey);
  757. }
  758. }
  759. return sRetval;
  760. }
  761. LPMONITOREX
  762. WINAPI
  763. InitializePrintMonitor(
  764. IN LPTSTR pszRegistryRoot
  765. )
  766. /*++
  767. Routine Description:
  768. Fill the monitor function table. Spooler makes call to this routine
  769. to get the monitor functions.
  770. Arguments:
  771. pszRegistryRoot : Registry root to be used by this dll
  772. Return Value:
  773. Pointer to monitor function table
  774. --*/
  775. {
  776. LPWSTR pPortTmp;
  777. DWORD dwCharCount=0, rc, i;
  778. DWORD sRetval = ERROR_SUCCESS;
  779. PINILOCALMON pIniLocalMon = NULL;
  780. LPWSTR pPorts = NULL;
  781. if ( !pszRegistryRoot || !*pszRegistryRoot ) {
  782. SetLastError(ERROR_INVALID_PARAMETER);
  783. return NULL;
  784. }
  785. if (sRetval = GetPortStrings(&pPorts, &dwCharCount) != ERROR_SUCCESS)
  786. {
  787. SetLastError(sRetval);
  788. goto Fail;
  789. }
  790. pIniLocalMon = (PINILOCALMON)AllocSplMem( sizeof( INILOCALMON ));
  791. if( !pIniLocalMon ){
  792. goto Fail;
  793. }
  794. pIniLocalMon->signature = ILM_SIGNATURE;
  795. LcmEnterSplSem();
  796. //
  797. // We now have all the ports
  798. //
  799. for(pPortTmp = pPorts; pPortTmp && *pPortTmp; pPortTmp += rc + 1){
  800. rc = wcslen(pPortTmp);
  801. if (!_wcsnicmp(pPortTmp, L"Ne", 2)) {
  802. i = 2;
  803. //
  804. // For Ne- ports
  805. //
  806. if ( rc > 2 && pPortTmp[2] == L'-' )
  807. ++i;
  808. for ( ; i < rc - 1 && iswdigit(pPortTmp[i]) ; ++i )
  809. ;
  810. if ( i == rc - 1 && pPortTmp[rc-1] == L':' ) {
  811. continue;
  812. }
  813. }
  814. LcmCreatePortEntry(pIniLocalMon, pPortTmp);
  815. }
  816. FreeSplMem(pPorts);
  817. LcmLeaveSplSem();
  818. CheckAndAddIrdaPort(pIniLocalMon);
  819. LcmhMonitor = (HANDLE)pIniLocalMon;
  820. return &MonitorEx;
  821. Fail:
  822. FreeSplMem( pPorts );
  823. FreeSplMem( pIniLocalMon );
  824. return NULL;
  825. }
  826. #if 0
  827. //
  828. // Since the DDK is a standalone DLL, we need a DLL init routine.
  829. // However, the NT version is a library and we call LocamonInit
  830. // directly, so this isn't needed.
  831. //
  832. // @@END_DDKSPLIT
  833. VOID
  834. LocalMonCleanUp(
  835. VOID
  836. )
  837. {
  838. DeleteCriticalSection(&LcmSpoolerSection);
  839. }
  840. BOOL
  841. DllMain(
  842. HANDLE hModule,
  843. DWORD dwReason,
  844. LPVOID lpRes)
  845. {
  846. switch (dwReason)
  847. {
  848. case DLL_PROCESS_ATTACH:
  849. LocalMonInit(hModule);
  850. DisableThreadLibraryCalls(hModule);
  851. return TRUE;
  852. case DLL_PROCESS_DETACH:
  853. LocalMonCleanUp();
  854. return TRUE;
  855. }
  856. UNREFERENCED_PARAMETER(lpRes);
  857. return TRUE;
  858. }
  859. // @@BEGIN_DDKSPLIT
  860. #endif
  861. // @@END_DDKSPLIT