Source code of Windows XP (NT5)
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.

1783 lines
42 KiB

  1. /*++
  2. Copyright (c) 1990 - 1996 Microsoft Corporation
  3. Module Name:
  4. monitor.c
  5. Abstract:
  6. This module contains all code for Monitor-based Spooler apis
  7. LocalEnumPorts
  8. LocalAddMonitor
  9. LocalDeleteMonitor
  10. LocalEnumMonitors
  11. LocalAddPort
  12. LocalConfigurePort
  13. LocalDeletePort
  14. Support Functions in monitor.c - (Warning! Do Not Add to this list!!)
  15. CopyIniMonitorToMonitor -- KrishnaG
  16. GetMonitorSize -- KrishnaG
  17. Author:
  18. Dave Snipp (DaveSn) 15-Mar-1991
  19. Revision History:
  20. Khaled Sedky (khaleds) 15-March-2000
  21. - Added LocalSendRecvBidiData
  22. Muhunthan Sivapragasam (MuhuntS) 15-Jun-1995
  23. - Port info 2 changes
  24. Krishna Ganugapati (KrishnaG) 2-Feb-1994
  25. - reorganized the entire source file
  26. Matthew Felton (mattfe) June 1994 pIniSpooler
  27. --*/
  28. #include <precomp.h>
  29. #include <offsets.h>
  30. #include <clusspl.h>
  31. //
  32. // Private declarations
  33. //
  34. HDESK ghdeskServer = NULL;
  35. //
  36. // Function declarations
  37. //
  38. LPBYTE
  39. CopyIniMonitorToMonitor(
  40. PINIMONITOR pIniMonitor,
  41. DWORD Level,
  42. LPBYTE pMonitorInfo,
  43. LPBYTE pEnd
  44. );
  45. DWORD
  46. GetMonitorSize(
  47. PINIMONITOR pIniMonitor,
  48. DWORD Level
  49. );
  50. BOOL
  51. LocalEnumPorts(
  52. LPWSTR pName,
  53. DWORD Level,
  54. LPBYTE pPorts,
  55. DWORD cbBuf,
  56. LPDWORD pcbNeeded,
  57. LPDWORD pcReturned
  58. )
  59. {
  60. PINISPOOLER pIniSpooler;
  61. BOOL bReturn;
  62. pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
  63. if( !pIniSpooler ){
  64. return ROUTER_UNKNOWN;
  65. }
  66. bReturn = SplEnumPorts( pName,
  67. Level,
  68. pPorts,
  69. cbBuf,
  70. pcbNeeded,
  71. pcReturned,
  72. pIniSpooler );
  73. FindSpoolerByNameDecRef( pIniSpooler );
  74. return bReturn;
  75. }
  76. VOID
  77. SplReenumeratePorts(
  78. )
  79. {
  80. LPVOID pBuf;
  81. DWORD cbNeeded, dwDontCare;
  82. //
  83. // EnumPorts checks for new ports enumerated by port monitors and updates
  84. // localspl pIniPorts list
  85. //
  86. if ( !SplEnumPorts(NULL, 1, NULL, 0, &cbNeeded,
  87. &dwDontCare, pLocalIniSpooler) &&
  88. GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
  89. (pBuf = AllocSplMem(cbNeeded)) ) {
  90. SplEnumPorts(NULL, 1, pBuf, cbNeeded, &cbNeeded,
  91. &dwDontCare, pLocalIniSpooler);
  92. FreeSplMem(pBuf);
  93. }
  94. }
  95. BOOL
  96. GetPortInfo2UsingPortInfo1(
  97. PINIMONITOR pIniMonitor,
  98. LPWSTR pName,
  99. LPBYTE pPorts,
  100. DWORD cbBuf,
  101. LPDWORD pcbNeeded,
  102. LPDWORD pcReturned
  103. )
  104. {
  105. BOOL bRet;
  106. LPPORT_INFO_1 pPortInfo1;
  107. LPPORT_INFO_2 pPortInfo2;
  108. DWORD cReturned;
  109. bRet = (*pIniMonitor->Monitor2.pfnEnumPorts)(
  110. pIniMonitor->hMonitor,
  111. pName,
  112. 1,
  113. pPorts,
  114. cbBuf,
  115. pcbNeeded,
  116. pcReturned );
  117. if ( !bRet ) {
  118. //
  119. // This is the upperbound
  120. //
  121. if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  122. *pcbNeeded += (*pcbNeeded / sizeof(PORT_INFO_1)) *
  123. (sizeof(PORT_INFO_2) - sizeof(PORT_INFO_1));
  124. } else {
  125. *pcbNeeded += *pcReturned * (sizeof(PORT_INFO_2) - sizeof(PORT_INFO_1));
  126. if ( *pcbNeeded <= cbBuf ) {
  127. cReturned = *pcReturned;
  128. while ( cReturned-- ) {
  129. pPortInfo1 = (LPPORT_INFO_1) (pPorts + cReturned * sizeof(PORT_INFO_1));
  130. pPortInfo2 = (LPPORT_INFO_2) (pPorts + cReturned * sizeof(PORT_INFO_2));
  131. pPortInfo2->pPortName = pPortInfo1->pName;
  132. pPortInfo2->pMonitorName = NULL;
  133. pPortInfo2->pDescription = NULL;
  134. pPortInfo2->fPortType = 0;
  135. pPortInfo2->Reserved = 0;
  136. }
  137. } else {
  138. *pcReturned = 0;
  139. bRet = FALSE;
  140. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  141. }
  142. }
  143. return bRet;
  144. }
  145. BOOL
  146. SplEnumPorts(
  147. LPWSTR pName,
  148. DWORD Level,
  149. LPBYTE pPorts,
  150. DWORD cbBuf,
  151. LPDWORD pcbNeeded,
  152. LPDWORD pcReturned,
  153. PINISPOOLER pIniSpooler
  154. )
  155. {
  156. PINIMONITOR pIniMonitor;
  157. DWORD dwIndex, cReturned=0, cbStruct, TotalcbNeeded=0;
  158. LPBYTE pBuffer = pPorts, pTemp;
  159. DWORD Error=0, TempError = 0;
  160. DWORD BufferSize=cbBuf;
  161. LPWSTR pPortName;
  162. PINIPORT pIniPort;
  163. HANDLE hToken;
  164. BOOL bRemoteCall;
  165. if (!MyName( pName, pIniSpooler )) {
  166. return FALSE;
  167. }
  168. //
  169. // HACK: Some monitors choke if pName is non-NULL. We can make
  170. // it NULL at this point since we know that we're using the same
  171. // ports on the local machine.
  172. //
  173. pName = NULL;
  174. if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER,
  175. SERVER_ACCESS_ENUMERATE,
  176. NULL, NULL, pIniSpooler )) {
  177. return FALSE;
  178. }
  179. switch (Level) {
  180. case 1:
  181. cbStruct = sizeof(PORT_INFO_1);
  182. break;
  183. case 2:
  184. cbStruct = sizeof(PORT_INFO_2);
  185. break;
  186. default:
  187. return ERROR_INVALID_LEVEL;
  188. }
  189. bRemoteCall = !IsLocalCall();
  190. //
  191. // We revert to local system context only when the caller is remote.
  192. // The monitors may load dlls from system32 and remote users like
  193. // guest or anonymous logon do not have sufficient privileges for that.
  194. // This is safe to revert to self since we do not support delegation, so
  195. // we will never use the credentials of the remote user to go remote again.
  196. // If the caller is logged on interactively, then we do not switch the
  197. // context. Thus, a monitor may be able to go on the network for the port
  198. // enumeration.
  199. //
  200. if (bRemoteCall && !(hToken = RevertToPrinterSelf()))
  201. {
  202. return FALSE;
  203. }
  204. for ( pIniMonitor = pIniSpooler->pIniMonitor ;
  205. pIniMonitor ;
  206. pIniMonitor = pIniMonitor->pNext ) {
  207. //
  208. // Lang monitor does not have to define this
  209. //
  210. if ( !pIniMonitor->Monitor2.pfnEnumPorts )
  211. continue;
  212. *pcReturned = 0;
  213. *pcbNeeded = 0;
  214. if (!(*pIniMonitor->Monitor2.pfnEnumPorts)(
  215. pIniMonitor->hMonitor,
  216. pName,
  217. Level,
  218. pPorts,
  219. BufferSize,
  220. pcbNeeded,
  221. pcReturned)) {
  222. TempError = GetLastError();
  223. //
  224. // Level 2 is a superset of level 1. So we can make a level 1
  225. // call if the monitor does not support it
  226. //
  227. if ( Level == 2 && TempError == ERROR_INVALID_LEVEL ) {
  228. TempError = 0;
  229. if ( !GetPortInfo2UsingPortInfo1(pIniMonitor,
  230. pName,
  231. pPorts,
  232. BufferSize,
  233. pcbNeeded,
  234. pcReturned) )
  235. TempError = GetLastError();
  236. }
  237. if ( TempError ) {
  238. Error = TempError;
  239. *pcReturned = 0;
  240. if ( TempError != ERROR_INSUFFICIENT_BUFFER ) {
  241. *pcbNeeded = 0;
  242. break;
  243. }
  244. }
  245. } else {
  246. //
  247. // Now we look for new ports not in pIniPort list and add them
  248. //
  249. EnterSplSem();
  250. for ( dwIndex = 0, pTemp = pPorts ;
  251. dwIndex < *pcReturned ;
  252. ++dwIndex ) {
  253. switch ( Level ) {
  254. case 1:
  255. pPortName = ((LPPORT_INFO_1)pTemp)->pName;
  256. pTemp += sizeof(PORT_INFO_1);
  257. break;
  258. case 2:
  259. pPortName = ((LPPORT_INFO_2)pTemp)->pPortName;
  260. pTemp += sizeof(PORT_INFO_2);
  261. break;
  262. default:
  263. SPLASSERT(Level == 1 || Level == 2);
  264. }
  265. pIniPort = FindPort(pPortName, pIniSpooler);
  266. if ( !pIniPort ) {
  267. CreatePortEntry(pPortName, pIniMonitor, pIniSpooler);
  268. } else if ( !pIniPort->pIniMonitor ) {
  269. //
  270. // If a fake port gets eventually enumerated by a monitor,
  271. // update the pIniPort structure (USB monitor). It is no
  272. // longer a placeholder port at this point.
  273. //
  274. pIniPort->pIniMonitor = pIniMonitor;
  275. pIniPort->Status |= PP_MONITOR;
  276. pIniPort->Status &= ~PP_PLACEHOLDER;
  277. }
  278. }
  279. LeaveSplSem();
  280. }
  281. cReturned += *pcReturned;
  282. pPorts += *pcReturned * cbStruct;
  283. if (*pcbNeeded <= BufferSize)
  284. BufferSize -= *pcbNeeded;
  285. else
  286. BufferSize = 0;
  287. TotalcbNeeded += *pcbNeeded;
  288. }
  289. if (bRemoteCall)
  290. {
  291. ImpersonatePrinterClient(hToken);
  292. }
  293. *pcbNeeded = TotalcbNeeded;
  294. *pcReturned = cReturned;
  295. if (Error) {
  296. SetLastError(Error);
  297. return FALSE;
  298. } else if (TotalcbNeeded > cbBuf ) {
  299. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  300. return FALSE;
  301. } else {
  302. //
  303. // Stop routing if this is a cluster'd spooler. Otherwise,
  304. // we'll talk to win32spl, which RPCs to us again.
  305. //
  306. if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  307. return ROUTER_STOP_ROUTING;
  308. }
  309. return TRUE;
  310. }
  311. }
  312. BOOL
  313. LocalEnumMonitors(
  314. LPWSTR pName,
  315. DWORD Level,
  316. LPBYTE pMonitors,
  317. DWORD cbBuf,
  318. LPDWORD pcbNeeded,
  319. LPDWORD pcReturned
  320. )
  321. {
  322. PINISPOOLER pIniSpooler;
  323. BOOL bReturn;
  324. pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
  325. if( !pIniSpooler ){
  326. return ROUTER_UNKNOWN;
  327. }
  328. bReturn = SplEnumMonitors( pName, Level, pMonitors, cbBuf,
  329. pcbNeeded, pcReturned, pIniSpooler );
  330. FindSpoolerByNameDecRef( pIniSpooler );
  331. return bReturn;
  332. }
  333. BOOL
  334. SplEnumMonitors(
  335. LPWSTR pName,
  336. DWORD Level,
  337. LPBYTE pMonitors,
  338. DWORD cbBuf,
  339. LPDWORD pcbNeeded,
  340. LPDWORD pcReturned,
  341. PINISPOOLER pIniSpooler
  342. )
  343. {
  344. PINIMONITOR pIniMonitor;
  345. DWORD cReturned=0, cbStruct, cb;
  346. LPBYTE pBuffer = pMonitors;
  347. DWORD BufferSize=cbBuf, rc;
  348. LPBYTE pEnd;
  349. if (!MyName( pName, pIniSpooler )) {
  350. return ROUTER_UNKNOWN;
  351. }
  352. if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER,
  353. SERVER_ACCESS_ENUMERATE,
  354. NULL, NULL, pIniSpooler )) {
  355. return ROUTER_UNKNOWN;
  356. }
  357. switch (Level) {
  358. case 1:
  359. cbStruct = sizeof(MONITOR_INFO_1);
  360. break;
  361. case 2:
  362. cbStruct = sizeof(MONITOR_INFO_2);
  363. break;
  364. default:
  365. SetLastError(ERROR_INVALID_LEVEL);
  366. return ROUTER_UNKNOWN;
  367. }
  368. EnterSplSem();
  369. for ( cb = 0, pIniMonitor = pIniSpooler->pIniMonitor ;
  370. pIniMonitor ;
  371. pIniMonitor = pIniMonitor->pNext ) {
  372. //
  373. // We'll not enumerate monitors which do not support AddPort
  374. //
  375. if ( pIniMonitor->Monitor2.pfnAddPort ||
  376. pIniMonitor->Monitor2.pfnXcvOpenPort)
  377. cb+=GetMonitorSize(pIniMonitor, Level);
  378. }
  379. *pcbNeeded = cb;
  380. *pcReturned = 0;
  381. if (cb <= cbBuf) {
  382. pEnd=pMonitors + cbBuf;
  383. for ( pIniMonitor = pIniSpooler->pIniMonitor ;
  384. pIniMonitor ;
  385. pIniMonitor = pIniMonitor->pNext ) {
  386. //
  387. // We'll not enumerate monitors which do not support AddPort
  388. //
  389. if ( !pIniMonitor->Monitor2.pfnAddPort &&
  390. !pIniMonitor->Monitor2.pfnXcvOpenPort )
  391. continue;
  392. pEnd = CopyIniMonitorToMonitor(pIniMonitor, Level, pMonitors, pEnd);
  393. switch (Level) {
  394. case 1:
  395. pMonitors+=sizeof(MONITOR_INFO_1);
  396. break;
  397. case 2:
  398. pMonitors+=sizeof(MONITOR_INFO_2);
  399. break;
  400. }
  401. (*pcReturned)++;
  402. }
  403. if( pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  404. //
  405. // Stop routing, since we don't want any one else to report
  406. // back monitors. If we're on the local machine now and
  407. // we continue routing, win32spl will RPC back to ourself
  408. // and re-enumerate the same ports.
  409. //
  410. rc = ROUTER_STOP_ROUTING;
  411. } else {
  412. rc = ROUTER_SUCCESS;
  413. }
  414. } else {
  415. rc = ROUTER_UNKNOWN;
  416. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  417. }
  418. LeaveSplSem();
  419. return rc;
  420. }
  421. BOOL
  422. LocalAddPort(
  423. LPWSTR pName,
  424. HWND hWnd,
  425. LPWSTR pMonitorName
  426. )
  427. {
  428. PINISPOOLER pIniSpooler;
  429. BOOL bReturn;
  430. pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
  431. if( !pIniSpooler ){
  432. return ROUTER_UNKNOWN;
  433. }
  434. bReturn = SplAddPort( pName, hWnd, pMonitorName, pIniSpooler );
  435. FindSpoolerByNameDecRef( pIniSpooler );
  436. return bReturn;
  437. }
  438. BOOL
  439. SplAddPort(
  440. LPWSTR pName,
  441. HWND hWnd,
  442. LPWSTR pMonitorName,
  443. PINISPOOLER pIniSpooler
  444. )
  445. {
  446. PINIMONITOR pIniMonitor;
  447. BOOL rc=FALSE;
  448. if (!MyName( pName, pIniSpooler )) {
  449. return FALSE;
  450. }
  451. if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER,
  452. SERVER_ACCESS_ADMINISTER,
  453. NULL, NULL, pIniSpooler )) {
  454. return FALSE;
  455. }
  456. EnterSplSem();
  457. SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
  458. pIniMonitor = FindMonitor(pMonitorName, pIniSpooler);
  459. LeaveSplSem();
  460. if ( pIniMonitor ) {
  461. if ( pIniMonitor->Monitor2.pfnAddPort )
  462. rc = (*pIniMonitor->Monitor2.pfnAddPort)(
  463. pIniMonitor->hMonitor,
  464. pName,
  465. hWnd,
  466. pMonitorName );
  467. else
  468. SetLastError(ERROR_INVALID_PARAMETER);
  469. }
  470. else {
  471. SetLastError(ERROR_INVALID_NAME);
  472. }
  473. if (rc)
  474. rc = AddPortToSpooler(pName, pIniMonitor, pIniSpooler);
  475. return rc;
  476. }
  477. BOOL
  478. AddPortToSpooler(
  479. PCWSTR pName,
  480. PINIMONITOR pIniMonitor,
  481. PINISPOOLER pIniSpooler
  482. )
  483. {
  484. DWORD i, cbNeeded, cbDummy, cReturned;
  485. PPORT_INFO_1 pPorts;
  486. PINIPORT pIniPort;
  487. /* If we don't already have the port in our local cache, add it:
  488. */
  489. if (!(*pIniMonitor->Monitor2.pfnEnumPorts)(
  490. pIniMonitor->hMonitor,
  491. (PWSTR)pName,
  492. 1,
  493. NULL,
  494. 0,
  495. &cbNeeded,
  496. &cReturned)) {
  497. pPorts = AllocSplMem(cbNeeded);
  498. if (pPorts) {
  499. if ((*pIniMonitor->Monitor2.pfnEnumPorts)(
  500. pIniMonitor->hMonitor,
  501. (PWSTR)pName,
  502. 1,
  503. (LPBYTE)pPorts,
  504. cbNeeded,
  505. &cbDummy,
  506. &cReturned)) {
  507. EnterSplSem();
  508. for (i = 0 ; i < cReturned ; ++i) {
  509. pIniPort = FindPort(pPorts[i].pName, pIniSpooler);
  510. if ( !pIniPort ) {
  511. CreatePortEntry(pPorts[i].pName, pIniMonitor, pIniSpooler);
  512. //
  513. // If we have a port without a monitor and it gets added at
  514. // this time. Remove the placeholder status from it.
  515. //
  516. } else if ( !pIniPort->pIniMonitor ) {
  517. pIniPort->pIniMonitor = pIniMonitor;
  518. pIniPort->Status |= PP_MONITOR;
  519. pIniPort->Status &= ~PP_PLACEHOLDER;
  520. }
  521. }
  522. LeaveSplSem();
  523. }
  524. FreeSplMem(pPorts);
  525. }
  526. }
  527. EnterSplSem();
  528. SetPrinterChange(NULL,
  529. NULL,
  530. NULL,
  531. PRINTER_CHANGE_ADD_PORT,
  532. pIniSpooler);
  533. LeaveSplSem();
  534. return TRUE;
  535. }
  536. BOOL
  537. LocalConfigurePort(
  538. LPWSTR pName,
  539. HWND hWnd,
  540. LPWSTR pPortName
  541. )
  542. {
  543. PINISPOOLER pIniSpooler;
  544. BOOL bReturn;
  545. pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
  546. if( !pIniSpooler ){
  547. return ROUTER_UNKNOWN;
  548. }
  549. bReturn = SplConfigurePort( pName, hWnd, pPortName, pIniSpooler );
  550. FindSpoolerByNameDecRef( pIniSpooler );
  551. return bReturn;
  552. }
  553. BOOL
  554. SplConfigurePort(
  555. LPWSTR pName,
  556. HWND hWnd,
  557. LPWSTR pPortName,
  558. PINISPOOLER pIniSpooler
  559. )
  560. {
  561. PINIPORT pIniPort;
  562. BOOL rc;
  563. if (!MyName( pName, pIniSpooler )) {
  564. return FALSE;
  565. }
  566. if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER,
  567. SERVER_ACCESS_ADMINISTER,
  568. NULL, NULL, pIniSpooler )) {
  569. return FALSE;
  570. }
  571. EnterSplSem();
  572. pIniPort = FindPort(pPortName, pIniSpooler);
  573. LeaveSplSem();
  574. if ((pIniPort) && (pIniPort->Status & PP_MONITOR)) {
  575. if ( !pIniPort->pIniMonitor->Monitor2.pfnConfigurePort ) {
  576. SetLastError(ERROR_NOT_SUPPORTED);
  577. return FALSE;
  578. }
  579. if (rc = (*pIniPort->pIniMonitor->Monitor2.pfnConfigurePort)(
  580. pIniPort->pIniMonitor->hMonitor,
  581. pName,
  582. hWnd,
  583. pPortName)) {
  584. EnterSplSem();
  585. SetPrinterChange(NULL,
  586. NULL,
  587. NULL,
  588. PRINTER_CHANGE_CONFIGURE_PORT,
  589. pIniSpooler);
  590. LeaveSplSem();
  591. }
  592. return rc;
  593. }
  594. SetLastError(ERROR_UNKNOWN_PORT);
  595. return FALSE;
  596. }
  597. BOOL
  598. LocalDeletePort(
  599. LPWSTR pName,
  600. HWND hWnd,
  601. LPWSTR pPortName
  602. )
  603. {
  604. PINISPOOLER pIniSpooler;
  605. BOOL bReturn;
  606. pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
  607. if( !pIniSpooler ){
  608. return ROUTER_UNKNOWN;
  609. }
  610. bReturn = SplDeletePort( pName,
  611. hWnd,
  612. pPortName,
  613. pIniSpooler );
  614. FindSpoolerByNameDecRef( pIniSpooler );
  615. return bReturn;
  616. }
  617. BOOL
  618. SplDeletePort(
  619. LPWSTR pName,
  620. HWND hWnd,
  621. LPWSTR pPortName,
  622. PINISPOOLER pIniSpooler
  623. )
  624. {
  625. PINIPORT pIniPort;
  626. BOOL rc=FALSE;
  627. if (!MyName( pName, pIniSpooler )) {
  628. return FALSE;
  629. }
  630. if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER,
  631. SERVER_ACCESS_ADMINISTER,
  632. NULL, NULL, pIniSpooler )) {
  633. return FALSE;
  634. }
  635. EnterSplSem();
  636. pIniPort = FindPort(pPortName, pIniSpooler);
  637. if ( !pIniPort || !(pIniPort->Status & PP_MONITOR) ) {
  638. LeaveSplSem();
  639. SetLastError(ERROR_UNKNOWN_PORT);
  640. return FALSE;
  641. }
  642. if( !pIniPort->pIniMonitor->Monitor2.pfnDeletePort ){
  643. LeaveSplSem();
  644. SetLastError( ERROR_NOT_SUPPORTED );
  645. return FALSE;
  646. }
  647. rc = DeletePortFromSpoolerStart( pIniPort );
  648. LeaveSplSem();
  649. if (!rc)
  650. goto Cleanup;
  651. rc = (*pIniPort->pIniMonitor->Monitor2.pfnDeletePort)(
  652. pIniPort->pIniMonitor->hMonitor,
  653. pName,
  654. hWnd,
  655. pPortName);
  656. rc = DeletePortFromSpoolerEnd(pIniPort, pIniSpooler, rc);
  657. Cleanup:
  658. SplOutSem();
  659. return rc;
  660. }
  661. BOOL
  662. DeletePortFromSpoolerEnd(
  663. PINIPORT pIniPort,
  664. PINISPOOLER pIniSpooler,
  665. BOOL bSuccess
  666. )
  667. {
  668. EnterSplSem();
  669. if(bSuccess) {
  670. DeletePortEntry( pIniPort );
  671. //
  672. // Success, delete the port data and send a notification.
  673. //
  674. SetPrinterChange( NULL,
  675. NULL,
  676. NULL,
  677. PRINTER_CHANGE_DELETE_PORT,
  678. pIniSpooler );
  679. } else {
  680. //
  681. // Add it back. If the name is already used (e.g., just added
  682. // while we were out of the critical section), we're in trouble,
  683. // but there's not much we can do about it. (When we restart,
  684. // we'll re-enumerate the duplicate name from the monitors
  685. // anyway.)
  686. //
  687. DBGMSG( DBG_WARN, ( "SplDeletePort: port.DeletePort failed %d\n", GetLastError()));
  688. LinkPortToSpooler( pIniPort, pIniSpooler );
  689. }
  690. LeaveSplSem();
  691. SplOutSem();
  692. return bSuccess;
  693. }
  694. BOOL
  695. DeletePortFromSpoolerStart(
  696. PINIPORT pIniPort
  697. )
  698. {
  699. BOOL rc = FALSE;
  700. PINISPOOLER pIniSpooler = pIniPort->pIniSpooler;
  701. SplInSem();
  702. if ( pIniPort->cPrinters || pIniPort->cRef || pIniPort->cJobs ) {
  703. SetLastError(ERROR_BUSY);
  704. goto Cleanup;
  705. }
  706. //
  707. // Remove it from the linked list so that no one will try to grab
  708. // a reference to while we're deleting it.
  709. //
  710. DelinkPortFromSpooler( pIniPort, pIniSpooler );
  711. rc = TRUE;
  712. Cleanup:
  713. return rc;
  714. }
  715. BOOL
  716. LocalAddMonitor(
  717. LPWSTR pName,
  718. DWORD Level,
  719. LPBYTE pMonitorInfo
  720. )
  721. {
  722. PINISPOOLER pIniSpooler;
  723. BOOL bReturn;
  724. pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
  725. if( !pIniSpooler ){
  726. return ROUTER_UNKNOWN;
  727. }
  728. bReturn = SplAddMonitor( pName,
  729. Level,
  730. pMonitorInfo,
  731. pIniSpooler );
  732. FindSpoolerByNameDecRef( pIniSpooler );
  733. return bReturn;
  734. }
  735. BOOL
  736. SplAddMonitor(
  737. LPWSTR pName,
  738. DWORD Level,
  739. LPBYTE pMonitorInfo,
  740. PINISPOOLER pIniSpooler
  741. )
  742. {
  743. PINIMONITOR pIniMonitor;
  744. PMONITOR_INFO_2 pMonitor = (PMONITOR_INFO_2)pMonitorInfo;
  745. HANDLE hToken;
  746. HKEY hKey;
  747. LONG Status;
  748. BOOL rc = FALSE;
  749. DWORD dwPathLen = 0;
  750. if (!MyName( pName, pIniSpooler )) {
  751. return FALSE;
  752. }
  753. if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER,
  754. SERVER_ACCESS_ADMINISTER,
  755. NULL, NULL, pIniSpooler )) {
  756. return FALSE;
  757. }
  758. if (Level != 2) {
  759. SetLastError( ERROR_INVALID_LEVEL );
  760. return FALSE;
  761. }
  762. if (!pMonitor ||
  763. !pMonitor->pName ||
  764. !*pMonitor->pName) {
  765. SetLastError( ERROR_INVALID_PARAMETER );
  766. return FALSE;
  767. }
  768. if (!pMonitor->pEnvironment ||
  769. !*pMonitor->pEnvironment ||
  770. lstrcmpi(pMonitor->pEnvironment, szEnvironment)) {
  771. SetLastError( ERROR_INVALID_ENVIRONMENT );
  772. return FALSE;
  773. }
  774. if (!pMonitor->pDLLName ||
  775. !*pMonitor->pDLLName ){
  776. SetLastError( ERROR_INVALID_PARAMETER );
  777. return FALSE;
  778. }
  779. EnterSplSem();
  780. if (FindMonitor(pMonitor->pName, pIniSpooler)) {
  781. LeaveSplSem();
  782. SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
  783. return FALSE;
  784. }
  785. hToken = RevertToPrinterSelf();
  786. pIniMonitor = CreateMonitorEntry(pMonitor->pDLLName,
  787. pMonitor->pName,
  788. pIniSpooler);
  789. if (pIniMonitor != (PINIMONITOR)-1) {
  790. WCHAR szRegistryRoot[MAX_PATH];
  791. PINISPOOLER pIniSpoolerMonitor;
  792. HANDLE hKeyOut;
  793. LPCWSTR pszPathOut;
  794. //
  795. // Note that even though this is built once per pIniSpooler, the
  796. // list of monitors is the same for all spoolers. However, the
  797. // ports that the monitor returns from EnumPorts is different for
  798. // each pIniSpooler (for clustering).
  799. //
  800. // If it's not local, then it could be a cached win32 monitor.
  801. //
  802. if( pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL ){
  803. pIniSpoolerMonitor = pLocalIniSpooler;
  804. } else {
  805. pIniSpoolerMonitor = pIniSpooler;
  806. }
  807. //
  808. // Build the registry path. In some cases it's a relative
  809. // path from hckRoot; other times it's a hard coded path from
  810. // HKLM (e.g., win32spl).
  811. //
  812. GetRegistryLocation( pIniSpoolerMonitor->hckRoot,
  813. pIniSpoolerMonitor->pszRegistryMonitors,
  814. &hKeyOut,
  815. &pszPathOut );
  816. Status = StrNCatBuff( szRegistryRoot,
  817. COUNTOF(szRegistryRoot),
  818. pszPathOut,
  819. L"\\",
  820. pMonitor->pName,
  821. NULL );
  822. if (Status == ERROR_SUCCESS)
  823. {
  824. Status = RegCreateKeyEx( hKeyOut,
  825. szRegistryRoot,
  826. 0,
  827. NULL,
  828. 0,
  829. KEY_WRITE,
  830. NULL,
  831. &hKey,
  832. NULL );
  833. if (Status == ERROR_SUCCESS) {
  834. Status = RegSetValueEx( hKey,
  835. L"Driver",
  836. 0,
  837. REG_SZ,
  838. (LPBYTE)pMonitor->pDLLName,
  839. (wcslen(pMonitor->pDLLName) + 1)*sizeof(WCHAR));
  840. if (Status == ERROR_SUCCESS) {
  841. rc = TRUE;
  842. } else {
  843. SetLastError( Status );
  844. }
  845. RegCloseKey(hKey);
  846. } else {
  847. SetLastError( Status );
  848. }
  849. }
  850. else
  851. {
  852. SetLastError(Status);
  853. }
  854. }
  855. ImpersonatePrinterClient(hToken);
  856. //
  857. // Bug 54843 if this fails we could still have a IniMonitor on the linked list that
  858. // is BAD, it should be removed. MattFe 19th Jan 95
  859. // Note *maybe* we do this because a monitor might fail to initialize
  860. // but will correctly function next time you reboot, like hpmon ( dlc doesn't become active until
  861. // the next reboot. Please Verify.
  862. LeaveSplSem();
  863. if ( !rc ) {
  864. DBGMSG( DBG_WARNING, ("SplAddMonitor failed %d\n", GetLastError() ));
  865. }
  866. return rc;
  867. }
  868. BOOL
  869. LocalDeleteMonitor(
  870. LPWSTR pName,
  871. LPWSTR pEnvironment,
  872. LPWSTR pMonitorName
  873. )
  874. {
  875. PINISPOOLER pIniSpooler;
  876. BOOL bReturn;
  877. pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
  878. if( !pIniSpooler ){
  879. return ROUTER_UNKNOWN;
  880. }
  881. bReturn = SplDeleteMonitor( pName,
  882. pEnvironment,
  883. pMonitorName,
  884. pIniSpooler );
  885. FindSpoolerByNameDecRef( pIniSpooler );
  886. return bReturn;
  887. }
  888. BOOL
  889. SplDeleteMonitor(
  890. LPWSTR pName,
  891. LPWSTR pEnvironment,
  892. LPWSTR pMonitorName,
  893. PINISPOOLER pIniSpooler
  894. )
  895. {
  896. BOOL Remote=FALSE;
  897. PINIMONITOR pIniMonitor;
  898. PINIPORT pIniPort, pIniPortNext;
  899. HKEY hKeyMonitors, hKey;
  900. LONG Status;
  901. BOOL rc = FALSE;
  902. HANDLE hToken;
  903. HANDLE hKeyOut;
  904. LPCWSTR pszPathOut;
  905. if (pName && *pName) {
  906. if (!MyName( pName, pIniSpooler )) {
  907. return FALSE;
  908. } else {
  909. Remote=TRUE;
  910. }
  911. }
  912. if ((pMonitorName == NULL) || (*pMonitorName == L'\0')) {
  913. SetLastError(ERROR_INVALID_PARAMETER);
  914. return FALSE;
  915. }
  916. if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER,
  917. SERVER_ACCESS_ADMINISTER,
  918. NULL, NULL, pIniSpooler )) {
  919. return FALSE;
  920. }
  921. EnterSplSem();
  922. if (!(pIniMonitor=(PINIMONITOR)FindMonitor(pMonitorName,
  923. pIniSpooler))) {
  924. SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
  925. LeaveSplSem();
  926. return FALSE;
  927. }
  928. if ( pIniMonitor->cRef ) {
  929. SetLastError(ERROR_PRINT_MONITOR_IN_USE);
  930. LeaveSplSem();
  931. return FALSE;
  932. }
  933. pIniPort = pIniSpooler->pIniPort;
  934. while (pIniPort) {
  935. if ((pIniPort->pIniMonitor == pIniMonitor) &&
  936. (pIniPort->cPrinters || pIniPort->cRef)) {
  937. SetLastError(ERROR_BUSY);
  938. LeaveSplSem();
  939. return FALSE;
  940. }
  941. pIniPort = pIniPort->pNext;
  942. }
  943. hToken = RevertToPrinterSelf();
  944. GetRegistryLocation( pIniSpooler->hckRoot,
  945. pIniSpooler->pszRegistryMonitors,
  946. &hKeyOut,
  947. &pszPathOut );
  948. Status = SplRegOpenKey(hKeyOut,
  949. pszPathOut,
  950. KEY_READ | KEY_WRITE,
  951. &hKeyMonitors,
  952. pIniSpooler);
  953. if (Status == ERROR_SUCCESS)
  954. {
  955. Status = SplRegOpenKey(hKeyMonitors,
  956. pMonitorName,
  957. KEY_READ | KEY_WRITE,
  958. &hKey,
  959. pIniSpooler);
  960. if (Status == ERROR_SUCCESS)
  961. {
  962. Status = DeleteSubkeys(hKey, pIniSpooler);
  963. SplRegCloseKey(hKey, pIniSpooler);
  964. if (Status == ERROR_SUCCESS)
  965. Status = SplRegDeleteKey(hKeyMonitors, pMonitorName, pIniSpooler);
  966. }
  967. SplRegCloseKey(hKeyMonitors, pIniSpooler);
  968. }
  969. if (Status == ERROR_SUCCESS) {
  970. pIniPort = pIniSpooler->pIniPort;
  971. while (pIniPort) {
  972. pIniPortNext = pIniPort->pNext;
  973. if (pIniPort->pIniMonitor == pIniMonitor)
  974. DeletePortEntry(pIniPort);
  975. pIniPort = pIniPortNext;
  976. }
  977. RemoveFromList((PINIENTRY *)&pIniSpooler->pIniMonitor,
  978. (PINIENTRY)pIniMonitor);
  979. FreeIniMonitor( pIniMonitor );
  980. rc = TRUE;
  981. }
  982. if (Status != ERROR_SUCCESS)
  983. SetLastError(Status);
  984. ImpersonatePrinterClient(hToken);
  985. LeaveSplSem();
  986. return rc;
  987. }
  988. LPBYTE
  989. CopyIniMonitorToMonitor(
  990. PINIMONITOR pIniMonitor,
  991. DWORD Level,
  992. LPBYTE pMonitorInfo,
  993. LPBYTE pEnd
  994. )
  995. {
  996. LPWSTR *pSourceStrings, *SourceStrings;
  997. DWORD j;
  998. DWORD *pOffsets;
  999. switch (Level) {
  1000. case 1:
  1001. pOffsets = MonitorInfo1Strings;
  1002. break;
  1003. case 2:
  1004. pOffsets = MonitorInfo2Strings;
  1005. break;
  1006. default:
  1007. return pEnd;
  1008. }
  1009. for (j=0; pOffsets[j] != -1; j++) {
  1010. }
  1011. SourceStrings = pSourceStrings = AllocSplMem(j * sizeof(LPWSTR));
  1012. if (!SourceStrings) {
  1013. DBGMSG(DBG_WARNING, ("Failed to alloc Port source strings.\n"));
  1014. return pEnd;
  1015. }
  1016. switch (Level) {
  1017. case 1:
  1018. *pSourceStrings++=pIniMonitor->pName;
  1019. break;
  1020. case 2:
  1021. *pSourceStrings++=pIniMonitor->pName;
  1022. *pSourceStrings++=szEnvironment;
  1023. *pSourceStrings++=pIniMonitor->pMonitorDll;
  1024. break;
  1025. }
  1026. pEnd = PackStrings(SourceStrings, pMonitorInfo, pOffsets, pEnd);
  1027. FreeSplMem(SourceStrings);
  1028. return pEnd;
  1029. }
  1030. DWORD
  1031. GetMonitorSize(
  1032. PINIMONITOR pIniMonitor,
  1033. DWORD Level
  1034. )
  1035. {
  1036. DWORD cb=0;
  1037. switch (Level) {
  1038. case 1:
  1039. cb=sizeof(MONITOR_INFO_1) + wcslen(pIniMonitor->pName)*sizeof(WCHAR) +
  1040. sizeof(WCHAR);
  1041. break;
  1042. case 2:
  1043. cb = wcslen(pIniMonitor->pName) + 1 + wcslen(pIniMonitor->pMonitorDll) + 1
  1044. + wcslen(szEnvironment) + 1;
  1045. cb *= sizeof(WCHAR);
  1046. cb += sizeof(MONITOR_INFO_2);
  1047. break;
  1048. default:
  1049. cb = 0;
  1050. break;
  1051. }
  1052. return cb;
  1053. }
  1054. BOOL
  1055. LocalAddPortEx(
  1056. LPWSTR pName,
  1057. DWORD Level,
  1058. LPBYTE pBuffer,
  1059. LPWSTR pMonitorName
  1060. )
  1061. {
  1062. return ( SplAddPortEx( pName,
  1063. Level,
  1064. pBuffer,
  1065. pMonitorName,
  1066. pLocalIniSpooler ));
  1067. }
  1068. BOOL
  1069. SplAddPortEx(
  1070. LPWSTR pName,
  1071. DWORD Level,
  1072. LPBYTE pBuffer,
  1073. LPWSTR pMonitorName,
  1074. PINISPOOLER pIniSpooler
  1075. )
  1076. {
  1077. PINIMONITOR pIniMonitor;
  1078. BOOL rc=FALSE;
  1079. DWORD i, cbNeeded, cReturned, cbDummy;
  1080. PPORT_INFO_1 pPorts = NULL;
  1081. PINIPORT pIniPort;
  1082. if (!MyName( pName, pIniSpooler )) {
  1083. return FALSE;
  1084. }
  1085. if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER,
  1086. SERVER_ACCESS_ADMINISTER,
  1087. NULL, NULL, pIniSpooler )) {
  1088. return FALSE;
  1089. }
  1090. EnterSplSem();
  1091. pIniMonitor = FindMonitor(pMonitorName, pIniSpooler);
  1092. LeaveSplSem();
  1093. if (!pIniMonitor) {
  1094. SetLastError(ERROR_INVALID_NAME);
  1095. return(FALSE);
  1096. }
  1097. if (pIniMonitor->Monitor2.pfnAddPortEx) {
  1098. rc = (*pIniMonitor->Monitor2.pfnAddPortEx)(
  1099. pIniMonitor->hMonitor,
  1100. pName,
  1101. Level,
  1102. pBuffer,
  1103. pMonitorName);
  1104. }
  1105. if (!rc) {
  1106. return(FALSE);
  1107. }
  1108. if (!(*pIniMonitor->Monitor2.pfnEnumPorts)(
  1109. pIniMonitor->hMonitor,
  1110. pName,
  1111. 1,
  1112. NULL,
  1113. 0,
  1114. &cbNeeded,
  1115. &cReturned)) {
  1116. pPorts = AllocSplMem(cbNeeded);
  1117. }
  1118. if (pPorts) {
  1119. if ((*pIniMonitor->Monitor2.pfnEnumPorts)(
  1120. pIniMonitor->hMonitor,
  1121. pName,
  1122. 1,
  1123. (LPBYTE)pPorts,
  1124. cbNeeded,
  1125. &cbDummy,
  1126. &cReturned)) {
  1127. EnterSplSem();
  1128. for (i = 0; i < cReturned; i++) {
  1129. pIniPort = FindPort(pPorts[i].pName, pIniSpooler);
  1130. if ( !pIniPort ) {
  1131. CreatePortEntry(pPorts[i].pName, pIniMonitor, pIniSpooler);
  1132. } else if ( !pIniPort->pIniMonitor ) {
  1133. pIniPort->pIniMonitor = pIniMonitor;
  1134. pIniPort->Status |= PP_MONITOR;
  1135. }
  1136. }
  1137. LeaveSplSem();
  1138. }
  1139. FreeSplMem(pPorts);
  1140. }
  1141. EnterSplSem();
  1142. SetPrinterChange(NULL,
  1143. NULL,
  1144. NULL,
  1145. PRINTER_CHANGE_ADD_PORT,
  1146. pIniSpooler);
  1147. LeaveSplSem();
  1148. return rc;
  1149. }
  1150. VOID
  1151. LinkPortToSpooler(
  1152. PINIPORT pIniPort,
  1153. PINISPOOLER pIniSpooler
  1154. )
  1155. /*++
  1156. Routine Description:
  1157. Links a pIniPort onto the pIniSpooler.
  1158. Arguments:
  1159. pIniPort - Port to link; must not already be on a ll.
  1160. pIniSpooler - Provides ll for pIniPort.
  1161. Return Value:
  1162. --*/
  1163. {
  1164. SplInSem();
  1165. SPLASSERT( !pIniPort->pIniSpooler );
  1166. pIniPort->pNext = pIniSpooler->pIniPort;
  1167. pIniPort->pIniSpooler = pIniSpooler;
  1168. pIniSpooler->pIniPort = pIniPort;
  1169. }
  1170. VOID
  1171. DelinkPortFromSpooler(
  1172. PINIPORT pIniPort,
  1173. PINISPOOLER pIniSpooler
  1174. )
  1175. /*++
  1176. Routine Description:
  1177. Remove a pIniPort from a pIniSpooler->pIniPort linked list. The
  1178. pIniPort may or may not be on the list; if it isn't, then this
  1179. routine does nothing.
  1180. Generic delink code ripped out into a subroutine.
  1181. The refcount on pIniPort must be zero. Anyone that uses pIniPort
  1182. must hold a reference, since it may be deleted outside the
  1183. SplSem when cRef==0.
  1184. Arguments:
  1185. pIniPort - Port to delink from the list. May or may not be on
  1186. pIniSpooler->pIniPort.
  1187. pIniSpooler - Linked list from which the pIniPort will be removed.
  1188. Return Value:
  1189. --*/
  1190. {
  1191. PINIPORT *ppCurPort;
  1192. SplInSem();
  1193. SPLASSERT( !pIniPort->cRef );
  1194. //
  1195. // Keep searching for pIniPort until we hit the end of the
  1196. // list or we've found it.
  1197. //
  1198. for( ppCurPort = &pIniSpooler->pIniPort;
  1199. *ppCurPort && *ppCurPort != pIniPort;
  1200. ppCurPort = &((*ppCurPort)->pNext )){
  1201. ; // Don't do anything.
  1202. }
  1203. //
  1204. // If we found it, delink it.
  1205. //
  1206. if( *ppCurPort ){
  1207. *ppCurPort = (*ppCurPort)->pNext;
  1208. //
  1209. // Null out the back pointer since we have removed it from
  1210. // the pIniSpooler.
  1211. //
  1212. pIniPort->pIniSpooler = NULL;
  1213. }
  1214. }
  1215. /*++
  1216. Function Name:
  1217. LocalSendRecvBidiData
  1218. Description:
  1219. This function is the providor point of communicating with
  1220. Monitors supporting BIDI data. It allows the providor to
  1221. set data in the printer and query data from the printer
  1222. Parameters:
  1223. hPrinter : This could be a Printer/Port Handle
  1224. dwAccessBit : Priverledges allowed to the accessing thread
  1225. pAction :
  1226. pReqData : Request encapsulatig the queries in an array
  1227. ppResData : Response returned to client in an array of Data
  1228. Return Value:
  1229. Win32 Error Code
  1230. --*/
  1231. DWORD
  1232. LocalSendRecvBidiData(
  1233. IN HANDLE hPrinter,
  1234. IN LPCTSTR pAction,
  1235. IN PBIDI_REQUEST_CONTAINER pReqData,
  1236. OUT PBIDI_RESPONSE_CONTAINER* ppResData
  1237. )
  1238. {
  1239. DWORD dwRet = ERROR_SUCCESS;
  1240. PSPOOL pSpool = (PSPOOL)hPrinter;
  1241. PINIPORT pIniPort = NULL;
  1242. PINIMONITOR pIniMonitor = NULL;
  1243. EnterSplSem();
  1244. {
  1245. //
  1246. // Process of validating the parameters
  1247. //
  1248. if((!pAction || !*pAction) ||
  1249. (!pReqData && !ppResData))
  1250. {
  1251. dwRet = ERROR_INVALID_PARAMETER;
  1252. }
  1253. else
  1254. {
  1255. if (!ValidateSpoolHandle( pSpool, PRINTER_HANDLE_SERVER ))
  1256. {
  1257. dwRet = ERROR_INVALID_HANDLE;
  1258. }
  1259. else
  1260. {
  1261. if(pSpool->TypeofHandle & PRINTER_HANDLE_PRINTER)
  1262. {
  1263. PINIPRINTER pIniPrinter;
  1264. PINIMONITOR pIniLangMonitor = NULL;
  1265. if(pIniPrinter = pSpool->pIniPrinter)
  1266. {
  1267. pIniPort = FindIniPortFromIniPrinter( pIniPrinter );
  1268. if (pIniPort)
  1269. {
  1270. pIniLangMonitor = pIniPrinter->pIniDriver->pIniLangMonitor;
  1271. if ( pIniLangMonitor &&
  1272. !pIniLangMonitor->Monitor2.pfnSendRecvBidiDataFromPort )
  1273. pIniLangMonitor = NULL;
  1274. //
  1275. // Port needs to be opened?
  1276. //
  1277. if ( pIniPort->pIniLangMonitor != pIniLangMonitor ||
  1278. !pIniPort->hPort )
  1279. {
  1280. LPTSTR pszPrinter;
  1281. TCHAR szFullPrinter[ MAX_UNC_PRINTER_NAME ];
  1282. if( pIniPrinter->pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER )
  1283. {
  1284. pszPrinter = szFullPrinter;
  1285. wsprintf( szFullPrinter,
  1286. L"%ws\\%ws",
  1287. pIniPrinter->pIniSpooler->pMachineName,
  1288. pIniPrinter->pName );
  1289. } else {
  1290. pszPrinter = pIniPrinter->pName;
  1291. }
  1292. if ( !OpenMonitorPort(pIniPort,
  1293. & pIniLangMonitor,
  1294. pszPrinter,
  1295. FALSE) ) {
  1296. dwRet = ERROR_INVALID_HANDLE;
  1297. }
  1298. }
  1299. }
  1300. else
  1301. dwRet = ERROR_INVALID_HANDLE;
  1302. }
  1303. }
  1304. else if(pSpool->TypeofHandle & PRINTER_HANDLE_PORT)
  1305. {
  1306. pIniPort = pSpool->pIniPort;
  1307. }
  1308. if(dwRet == ERROR_SUCCESS && pIniPort && (pIniPort->Status & PP_MONITOR))
  1309. {
  1310. pIniMonitor = pIniPort->pIniLangMonitor ?
  1311. pIniPort->pIniLangMonitor :
  1312. pIniPort->pIniMonitor;
  1313. if(pIniMonitor)
  1314. {
  1315. //
  1316. // Calling into the monitor
  1317. //
  1318. if(pIniMonitor->Monitor2.pfnSendRecvBidiDataFromPort)
  1319. {
  1320. INCPORTREF(pIniPort);
  1321. INCMONITORREF(pIniMonitor);
  1322. LeaveSplSem();
  1323. SplOutSem();
  1324. dwRet = (*pIniMonitor->Monitor2.pfnSendRecvBidiDataFromPort)(pIniPort->hPort,
  1325. pSpool->GrantedAccess,
  1326. pAction,
  1327. pReqData,
  1328. ppResData);
  1329. EnterSplSem();
  1330. DECMONITORREF(pIniMonitor);
  1331. DECPORTREF(pIniPort);
  1332. }
  1333. else
  1334. {
  1335. //
  1336. // Here we could use a simulation code;
  1337. //
  1338. dwRet = ERROR_NOT_SUPPORTED;
  1339. }
  1340. }
  1341. else
  1342. {
  1343. dwRet = ERROR_INVALID_HANDLE;
  1344. }
  1345. }
  1346. else
  1347. {
  1348. dwRet = ERROR_INVALID_HANDLE;
  1349. }
  1350. }
  1351. }
  1352. }
  1353. LeaveSplSem();
  1354. return(dwRet);
  1355. }