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.

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