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.

3212 lines
70 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. nwspl.c
  5. Abstract:
  6. This module contains the Netware print provider.
  7. Author:
  8. Yi-Hsin Sung (yihsins) 15-Apr-1993
  9. Revision History:
  10. Yi-Hsin Sung (yihsins) 15-May-1993
  11. Moved most of the functionality to the server side
  12. Ram Viswanathan (ramv) 09-Aug-1995
  13. Added functionality to Add and Delete Printer.
  14. --*/
  15. #include <stdio.h>
  16. #include <nwclient.h>
  17. #include <winspool.h>
  18. #include <winsplp.h>
  19. #include <ntlsa.h>
  20. #include <nwpkstr.h>
  21. #include <splutil.h>
  22. #include <nwreg.h>
  23. #include <nwspl.h>
  24. #include <nwmisc.h>
  25. #include <winsta.h>
  26. //------------------------------------------------------------------
  27. //
  28. // Local Functions
  29. //
  30. //------------------------------------------------------------------
  31. // now all SKUs have TerminalServer flag. If App Server is enabled, SingleUserTS flag is cleared
  32. #define IsTerminalServer() (BOOLEAN)(!(USER_SHARED_DATA->SuiteMask & (1 << SingleUserTS))) //user mode
  33. DWORD
  34. InitializePortNames(
  35. VOID
  36. );
  37. VOID
  38. NwpGetUserInfo(
  39. LPWSTR *ppszUser,
  40. BOOL *pfGateway
  41. );
  42. DWORD
  43. NwpGetThreadUserInfo(
  44. LPWSTR *ppszUser,
  45. LPWSTR *ppszUserSid
  46. );
  47. DWORD
  48. NwpGetUserNameFromSid(
  49. PSID pUserSid,
  50. LPWSTR *ppszUserName
  51. );
  52. DWORD
  53. NwpGetLogonUserInfo(
  54. LPWSTR *ppszUserSid
  55. );
  56. DWORD
  57. ThreadIsInteractive(
  58. VOID
  59. );
  60. VOID
  61. pFreeAllContexts();
  62. //------------------------------------------------------------------
  63. //
  64. // Global Variables
  65. //
  66. //------------------------------------------------------------------
  67. HMODULE hmodNW = NULL;
  68. BOOL fIsWinnt = FALSE ;
  69. WCHAR *pszRegistryPath = NULL;
  70. WCHAR *pszRegistryPortNames=L"PortNames";
  71. WCHAR szMachineName[MAX_COMPUTERNAME_LENGTH + 3];
  72. PNWPORT pNwFirstPort = NULL;
  73. CRITICAL_SECTION NwSplSem;
  74. CRITICAL_SECTION NwServiceListCriticalSection; // Used to protect linked
  75. // list of registered services
  76. HANDLE NwServiceListDoneEvent = NULL;// Used to stop local advertise
  77. // threads.
  78. STATIC HANDLE handleDummy; // This is a dummy handle used to
  79. // return to the clients if we have previously
  80. // opened the given printer successfully
  81. // and the netware workstation service is not
  82. // currently available.
  83. STATIC
  84. PRINTPROVIDOR PrintProvidor = { OpenPrinter,
  85. SetJob,
  86. GetJob,
  87. EnumJobs,
  88. AddPrinter, // NOT SUPPORTED
  89. DeletePrinter, // NOT SUPPORTED
  90. SetPrinter,
  91. GetPrinter,
  92. EnumPrinters,
  93. AddPrinterDriver, // NOT SUPPORTED
  94. EnumPrinterDrivers, // NOT SUPPORTED
  95. GetPrinterDriverW, // NOT SUPPORTED
  96. GetPrinterDriverDirectory, // NOT SUPPORTED
  97. DeletePrinterDriver, // NOT SUPPORTED
  98. AddPrintProcessor, // NOT SUPPORTED
  99. EnumPrintProcessors, // NOT SUPPORTED
  100. GetPrintProcessorDirectory, // NOT SUPPORTED
  101. DeletePrintProcessor, // NOT SUPPORTED
  102. EnumPrintProcessorDatatypes,// NOT SUPPORTED
  103. StartDocPrinter,
  104. StartPagePrinter, // NOT SUPPORTED
  105. WritePrinter,
  106. EndPagePrinter, // NOT SUPPORTED
  107. AbortPrinter,
  108. ReadPrinter, // NOT SUPPORTED
  109. EndDocPrinter,
  110. AddJob,
  111. ScheduleJob,
  112. GetPrinterData, // NOT SUPPORTED
  113. SetPrinterData, // NOT SUPPORTED
  114. WaitForPrinterChange,
  115. ClosePrinter,
  116. AddForm, // NOT SUPPORTED
  117. DeleteForm, // NOT SUPPORTED
  118. GetForm, // NOT SUPPORTED
  119. SetForm, // NOT SUPPORTED
  120. EnumForms, // NOT SUPPORTED
  121. EnumMonitors, // NOT SUPPORTED
  122. EnumPorts,
  123. AddPort, // NOT SUPPORTED
  124. ConfigurePort,
  125. DeletePort,
  126. CreatePrinterIC, // NOT SUPPORTED
  127. PlayGdiScriptOnPrinterIC, // NOT SUPPORTED
  128. DeletePrinterIC, // NOT SUPPORTED
  129. AddPrinterConnection, // NOT SUPPORTED
  130. DeletePrinterConnection, // NOT SUPPORTED
  131. PrinterMessageBox, // NOT SUPPORTED
  132. AddMonitor, // NOT SUPPORTED
  133. DeleteMonitor // NOT SUPPORTED
  134. };
  135. //------------------------------------------------------------------
  136. //
  137. // Initialization Functions
  138. //
  139. //------------------------------------------------------------------
  140. BOOL InitializeDll(
  141. HINSTANCE hdll,
  142. DWORD dwReason,
  143. LPVOID lpReserved
  144. )
  145. {
  146. NT_PRODUCT_TYPE ProductType ;
  147. UNREFERENCED_PARAMETER( lpReserved );
  148. if ( dwReason == DLL_PROCESS_ATTACH )
  149. {
  150. DisableThreadLibraryCalls( hdll );
  151. hmodNW = hdll;
  152. //
  153. // are we a winnt machine?
  154. //
  155. fIsWinnt = RtlGetNtProductType(&ProductType) ?
  156. (ProductType == NtProductWinNt) :
  157. FALSE ;
  158. //
  159. // Initialize the critical section for maintaining the registered
  160. // service list
  161. //
  162. InitializeCriticalSection( &NwServiceListCriticalSection );
  163. NwServiceListDoneEvent = CreateEventA( NULL, TRUE, FALSE, NULL );
  164. }
  165. else if ( dwReason == DLL_PROCESS_DETACH )
  166. {
  167. //
  168. // Free up memories used by the port link list
  169. //
  170. DeleteAllPortEntries();
  171. //
  172. // Get rid of Service List and Shutdown SAP library
  173. //
  174. NwTerminateServiceProvider();
  175. #ifndef NT1057
  176. //
  177. // Clean up shell extensions
  178. //
  179. NwCleanupShellExtensions();
  180. #endif
  181. pFreeAllContexts(); // clean up RNR stuff
  182. DeleteCriticalSection( &NwServiceListCriticalSection );
  183. if ( NwServiceListDoneEvent )
  184. {
  185. CloseHandle( NwServiceListDoneEvent );
  186. NwServiceListDoneEvent = NULL;
  187. }
  188. }
  189. return TRUE;
  190. }
  191. DWORD
  192. InitializePortNames(
  193. VOID
  194. )
  195. /*++
  196. Routine Description:
  197. This is called by the InitializePrintProvidor to initialize the ports
  198. names used in this providor.
  199. Arguments:
  200. None.
  201. Return Value:
  202. Returns NO_ERROR or the error that occurred.
  203. --*/
  204. {
  205. DWORD err;
  206. HKEY hkeyPath;
  207. HKEY hkeyPortNames;
  208. err = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  209. pszRegistryPath,
  210. 0,
  211. KEY_READ,
  212. &hkeyPath );
  213. if ( !err )
  214. {
  215. err = RegOpenKeyEx( hkeyPath,
  216. pszRegistryPortNames,
  217. 0,
  218. KEY_READ,
  219. &hkeyPortNames );
  220. if ( !err )
  221. {
  222. DWORD i = 0;
  223. WCHAR Buffer[MAX_PATH];
  224. DWORD BufferSize;
  225. while ( !err )
  226. {
  227. BufferSize = sizeof(Buffer) / sizeof(WCHAR);
  228. err = RegEnumValue( hkeyPortNames,
  229. i,
  230. Buffer,
  231. &BufferSize,
  232. NULL,
  233. NULL,
  234. NULL,
  235. NULL );
  236. if ( !err )
  237. CreatePortEntry( Buffer );
  238. i++;
  239. }
  240. /* We expect RegEnumKeyEx to return ERROR_NO_MORE_ITEMS
  241. * when it gets to the end of the keys, so reset the status:
  242. */
  243. if( err == ERROR_NO_MORE_ITEMS )
  244. err = NO_ERROR;
  245. RegCloseKey( hkeyPortNames );
  246. }
  247. #if DBG
  248. else
  249. {
  250. IF_DEBUG(PRINT)
  251. KdPrint(("NWSPL [RegOpenKeyEx] (%ws) failed: Error = %d\n",
  252. pszRegistryPortNames, err ));
  253. }
  254. #endif
  255. RegCloseKey( hkeyPath );
  256. }
  257. #if DBG
  258. else
  259. {
  260. IF_DEBUG(PRINT)
  261. KdPrint(("NWSPL [RegOpenKeyEx] (%ws) failed: Error = %d\n",
  262. pszRegistryPath, err ));
  263. }
  264. #endif
  265. return err;
  266. }
  267. //------------------------------------------------------------------
  268. //
  269. // Print Provider Functions supported by NetWare provider
  270. //
  271. //------------------------------------------------------------------
  272. BOOL
  273. InitializePrintProvidor(
  274. LPPRINTPROVIDOR pPrintProvidor,
  275. DWORD cbPrintProvidor,
  276. LPWSTR pszFullRegistryPath
  277. )
  278. /*++
  279. Routine Description:
  280. This is called by the spooler subsystem to initialize the print
  281. providor.
  282. Arguments:
  283. pPrintProvidor - Pointer to the print providor structure to be
  284. filled in by this function
  285. cbPrintProvidor - Count of bytes of the print providor structure
  286. pszFullRegistryPath - Full path to the registry key of this print providor
  287. Return Value:
  288. Always TRUE.
  289. --*/
  290. {
  291. //
  292. // dfergus 20 Apr 2001 #323700
  293. // Prevent Multiple CS Initialization
  294. //
  295. static int iCSInit = 0;
  296. DWORD dwLen;
  297. if ( !pPrintProvidor || !pszFullRegistryPath || !*pszFullRegistryPath )
  298. {
  299. SetLastError( ERROR_INVALID_PARAMETER );
  300. return FALSE;
  301. }
  302. memcpy( pPrintProvidor,
  303. &PrintProvidor,
  304. min( sizeof(PRINTPROVIDOR), cbPrintProvidor) );
  305. //
  306. // Store the registry path for this print providor
  307. //
  308. if ( !(pszRegistryPath = AllocNwSplStr(pszFullRegistryPath)) )
  309. return FALSE;
  310. //
  311. // Store the local machine name
  312. //
  313. szMachineName[0] = szMachineName[1] = L'\\';
  314. dwLen = MAX_COMPUTERNAME_LENGTH;
  315. GetComputerName( szMachineName + 2, &dwLen );
  316. #if DBG
  317. IF_DEBUG(PRINT)
  318. {
  319. KdPrint(("NWSPL [InitializePrintProvidor] "));
  320. KdPrint(("RegistryPath = %ws, ComputerName = %ws\n",
  321. pszRegistryPath, szMachineName ));
  322. }
  323. #endif
  324. //
  325. // dfergus 20 Apr 2001 #323700
  326. // Prevent Multiple CS Initialization
  327. //
  328. if( !iCSInit )
  329. {
  330. InitializeCriticalSection( &NwSplSem );
  331. iCSInit = 1;
  332. }
  333. //
  334. // Ignore the error returned from InitializePortNames.
  335. // The provider can still function if we cannot get all the port
  336. // names.
  337. //
  338. InitializePortNames();
  339. return TRUE;
  340. }
  341. BOOL
  342. OpenPrinterW(
  343. LPWSTR pszPrinterName,
  344. LPHANDLE phPrinter,
  345. LPPRINTER_DEFAULTS pDefault
  346. )
  347. /*++
  348. Routine Description:
  349. This routine retrieves a handle identifying the specified printer.
  350. Arguments:
  351. pszPrinterName - Name of the printer
  352. phPrinter - Receives the handle that identifies the given printer
  353. pDefault - Points to a PRINTER_DEFAULTS structure. Can be NULL.
  354. Return Value:
  355. TRUE if the function succeeds, FALSE otherwise. Use GetLastError() for
  356. extended error information.
  357. --*/
  358. {
  359. DWORD err;
  360. #if DBG
  361. IF_DEBUG(PRINT)
  362. KdPrint(( "NWSPL [OpenPrinter] Name = %ws\n", pszPrinterName ));
  363. #endif
  364. UNREFERENCED_PARAMETER( pDefault );
  365. if ( !pszPrinterName )
  366. {
  367. SetLastError( ERROR_INVALID_NAME );
  368. return FALSE;
  369. }
  370. RpcTryExcept
  371. {
  372. err = NwrOpenPrinter( NULL,
  373. pszPrinterName,
  374. PortKnown( pszPrinterName ),
  375. (LPNWWKSTA_PRINTER_CONTEXT) phPrinter );
  376. //
  377. // Make sure there is a port of this name so that
  378. // EnumPorts will return it.
  379. //
  380. if ( !err )
  381. {
  382. if ( !PortExists( pszPrinterName, &err ) && !err )
  383. {
  384. //
  385. // We will ignore the errors since it is
  386. // still OK if we can't add the port.
  387. // Cannot delete once created, don't create
  388. // We should not create port entry and registry entry
  389. if ( CreatePortEntry( pszPrinterName ) )
  390. CreateRegistryEntry( pszPrinterName );
  391. }
  392. }
  393. }
  394. RpcExcept(1)
  395. {
  396. DWORD code = RpcExceptionCode();
  397. if ( code == RPC_S_SERVER_UNAVAILABLE )
  398. {
  399. if ( PortKnown( pszPrinterName ))
  400. {
  401. *phPrinter = &handleDummy;
  402. err = NO_ERROR;
  403. }
  404. else
  405. {
  406. err = ERROR_INVALID_NAME;
  407. }
  408. }
  409. else
  410. {
  411. err = NwpMapRpcError( code );
  412. }
  413. }
  414. RpcEndExcept
  415. if ( err )
  416. {
  417. SetLastError( err );
  418. #if DBG
  419. IF_DEBUG(PRINT)
  420. KdPrint(("NWSPL [OpenPrinter] err = %d\n", err));
  421. #endif
  422. }
  423. return ( err == NO_ERROR );
  424. }
  425. BOOL
  426. ClosePrinter(
  427. HANDLE hPrinter
  428. )
  429. /*++
  430. Routine Description:
  431. This routine closes the given printer object.
  432. Arguments:
  433. hPrinter - Handle of the printer object
  434. Return Value:
  435. TRUE if the function succeeds, FALSE otherwise. Use GetLastError() for
  436. extended error information.
  437. --*/
  438. {
  439. DWORD err;
  440. #if DBG
  441. IF_DEBUG(PRINT)
  442. KdPrint(( "NWSPL [ClosePrinter]\n"));
  443. #endif
  444. //
  445. // Just return success if the handle is a dummy one
  446. //
  447. if ( hPrinter == &handleDummy )
  448. return TRUE;
  449. RpcTryExcept
  450. {
  451. err = NwrClosePrinter( (LPNWWKSTA_PRINTER_CONTEXT) &hPrinter );
  452. }
  453. RpcExcept(1)
  454. {
  455. DWORD code = RpcExceptionCode();
  456. if ( code == RPC_S_SERVER_UNAVAILABLE )
  457. err = ERROR_INVALID_HANDLE;
  458. else
  459. err = NwpMapRpcError( code );
  460. }
  461. RpcEndExcept
  462. if ( err )
  463. SetLastError( err );
  464. return err == NO_ERROR;
  465. }
  466. BOOL
  467. GetPrinter(
  468. HANDLE hPrinter,
  469. DWORD dwLevel,
  470. LPBYTE pbPrinter,
  471. DWORD cbBuf,
  472. LPDWORD pcbNeeded
  473. )
  474. /*++
  475. Routine Description:
  476. The routine retrieves information about the given printer.
  477. Arguments:
  478. hPrinter - Handle of the printer
  479. dwLevel - Specifies the level of the structure to which pbPrinter points.
  480. pbPrinter - Points to a buffer that receives the PRINTER_INFO object.
  481. cbBuf - Size, in bytes of the array pbPrinter points to.
  482. pcbNeeded - Points to a value which specifies the number of bytes copied
  483. if the function succeeds or the number of bytes required if
  484. cbBuf was too small.
  485. Return Value:
  486. TRUE if the function succeeds and FALSE otherwise. GetLastError() can be
  487. used to retrieve extended error information.
  488. --*/
  489. {
  490. DWORD err;
  491. #if DBG
  492. IF_DEBUG(PRINT)
  493. KdPrint(( "NWSPL [GetPrinter] Level = %d\n", dwLevel ));
  494. #endif
  495. if ( hPrinter == &handleDummy )
  496. {
  497. SetLastError( ERROR_NO_NETWORK );
  498. return FALSE;
  499. }
  500. else if ( ( dwLevel != 1 ) && ( dwLevel != 2 ) && (dwLevel != 3 ))
  501. {
  502. SetLastError( ERROR_INVALID_LEVEL );
  503. return FALSE;
  504. }
  505. RpcTryExcept
  506. {
  507. err = NwrGetPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  508. dwLevel,
  509. pbPrinter,
  510. cbBuf,
  511. pcbNeeded );
  512. if ( !err )
  513. {
  514. if ( dwLevel == 1 )
  515. MarshallUpStructure( pbPrinter, PrinterInfo1Offsets, pbPrinter);
  516. else
  517. MarshallUpStructure( pbPrinter, PrinterInfo2Offsets, pbPrinter);
  518. }
  519. }
  520. RpcExcept(1)
  521. {
  522. DWORD code = RpcExceptionCode();
  523. if ( code == RPC_S_SERVER_UNAVAILABLE )
  524. err = ERROR_INVALID_HANDLE;
  525. else
  526. err = NwpMapRpcError( code );
  527. }
  528. RpcEndExcept
  529. if ( err )
  530. SetLastError( err );
  531. return err == NO_ERROR;
  532. }
  533. BOOL
  534. SetPrinter(
  535. HANDLE hPrinter,
  536. DWORD dwLevel,
  537. LPBYTE pbPrinter,
  538. DWORD dwCommand
  539. )
  540. /*++
  541. Routine Description:
  542. The routine sets the specified by pausing printing, resuming printing, or
  543. clearing all print jobs.
  544. Arguments:
  545. hPrinter - Handle of the printer
  546. dwLevel - Specifies the level of the structure to which pbPrinter points.
  547. pbPrinter - Points to a buffer that supplies the PRINTER_INFO object.
  548. dwCommand - Specifies the new printer state.
  549. Return Value:
  550. TRUE if the function succeeds and FALSE otherwise. GetLastError() can be
  551. used to retrieve extended error information.
  552. --*/
  553. {
  554. DWORD err = NO_ERROR;
  555. UNREFERENCED_PARAMETER( pbPrinter );
  556. #if DBG
  557. IF_DEBUG(PRINT)
  558. {
  559. KdPrint(( "NWSPL [SetPrinter] Level = %d Command = %d\n",
  560. dwLevel, dwCommand ));
  561. }
  562. #endif
  563. if ( hPrinter == &handleDummy )
  564. {
  565. SetLastError( ERROR_NO_NETWORK );
  566. return FALSE;
  567. }
  568. switch ( dwLevel )
  569. {
  570. case 0:
  571. case 1:
  572. case 2:
  573. case 3:
  574. break;
  575. default:
  576. SetLastError( ERROR_INVALID_LEVEL );
  577. return FALSE;
  578. }
  579. RpcTryExcept
  580. {
  581. err = NwrSetPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  582. dwCommand );
  583. }
  584. RpcExcept(1)
  585. {
  586. DWORD code = RpcExceptionCode();
  587. if ( code == RPC_S_SERVER_UNAVAILABLE )
  588. err = ERROR_INVALID_HANDLE;
  589. else
  590. err = NwpMapRpcError( code );
  591. }
  592. RpcEndExcept
  593. if ( err )
  594. SetLastError( err );
  595. return err == NO_ERROR;
  596. }
  597. BOOL
  598. EnumPrintersW(
  599. DWORD dwFlags,
  600. LPWSTR pszName,
  601. DWORD dwLevel,
  602. LPBYTE pbPrinter,
  603. DWORD cbBuf,
  604. LPDWORD pcbNeeded,
  605. LPDWORD pcReturned
  606. )
  607. /*++
  608. Routine Description:
  609. This routine enumerates the available providers, servers, printers
  610. depending on the given pszName.
  611. Arguments:
  612. dwFlags - Printer type requested
  613. pszName - The name of the container object
  614. dwLevel - The structure level requested
  615. pbPrinter - Points to the array to receive the PRINTER_INFO objects
  616. cbBuf - Size, in bytes of pbPrinter
  617. pcbNeeded - Count of bytes needed
  618. pcReturned - Count of PRINTER_INFO objects
  619. Return Value:
  620. TRUE if the function succeeds, FALSE otherwise.
  621. --*/
  622. {
  623. DWORD err = NO_ERROR;
  624. #if DBG
  625. IF_DEBUG(PRINT)
  626. {
  627. KdPrint(("NWSPL [EnumPrinters] Flags = %d Level = %d",dwFlags,dwLevel));
  628. if ( pszName )
  629. KdPrint((" PrinterName = %ws\n", pszName ));
  630. else
  631. KdPrint(("\n"));
  632. }
  633. #endif
  634. if ( (dwLevel != 1) && (dwLevel != 2) )
  635. {
  636. SetLastError( ERROR_INVALID_NAME ); // should be level, but winspool
  637. // is silly.
  638. return FALSE;
  639. }
  640. else if ( !pcbNeeded || !pcReturned )
  641. {
  642. SetLastError( ERROR_INVALID_PARAMETER );
  643. return FALSE;
  644. }
  645. RpcTryExcept
  646. {
  647. *pcReturned = 0;
  648. *pcbNeeded = 0;
  649. if ( ( dwFlags & PRINTER_ENUM_NAME )
  650. && ( dwLevel == 1 )
  651. )
  652. {
  653. err = NwrEnumPrinters( NULL,
  654. pszName,
  655. pbPrinter,
  656. cbBuf,
  657. pcbNeeded,
  658. pcReturned );
  659. if ( !err )
  660. {
  661. DWORD i;
  662. for ( i = 0; i < *pcReturned; i++ )
  663. MarshallUpStructure( pbPrinter + i*sizeof(PRINTER_INFO_1W),
  664. PrinterInfo1Offsets,
  665. pbPrinter );
  666. }
  667. }
  668. else
  669. {
  670. err = ERROR_INVALID_NAME;
  671. }
  672. }
  673. RpcExcept(1)
  674. {
  675. DWORD code = RpcExceptionCode();
  676. if ( code == RPC_S_SERVER_UNAVAILABLE )
  677. err = ERROR_INVALID_NAME;
  678. else
  679. err = NwpMapRpcError( code );
  680. }
  681. RpcEndExcept
  682. if ( err )
  683. SetLastError( err );
  684. return err == NO_ERROR;
  685. }
  686. //
  687. // Handle structure
  688. // This structure was copied from \nw\svcdlls\nwwks\server\spool.c
  689. // to fix NT bug # 366632.
  690. //
  691. typedef struct _NWSPOOL {
  692. DWORD nSignature; // Signature
  693. DWORD errOpenPrinter; // OpenPrinter API will always return
  694. // success on known printers. This will
  695. // contain the error that we get
  696. // if something went wrong in the API.
  697. PVOID pPrinter; // Points to the corresponding printer
  698. HANDLE hServer; // Opened handle to the server
  699. struct _NWSPOOL *pNextSpool; // Points to the next handle
  700. DWORD nStatus; // Status
  701. DWORD nJobNumber; // StartDocPrinter/AddJob: Job Number
  702. HANDLE hChangeEvent; // WaitForPrinterChange: event to wait on
  703. DWORD nWaitFlags; // WaitForPrinterChange: flags to wait on
  704. DWORD nChangeFlags; // Changes that occurred to the printer
  705. } NWSPOOL, *PNWSPOOL;
  706. DWORD
  707. StartDocPrinter(
  708. HANDLE hPrinter,
  709. DWORD dwLevel,
  710. LPBYTE lpbDocInfo
  711. )
  712. /*++
  713. Routine Description:
  714. This routine informs the print spooler that a document is to be spooled
  715. for printing.
  716. Arguments:
  717. hPrinter - Handle of the printer
  718. dwLevel - Level of the structure pointed to by lpbDocInfo. Must be 1.
  719. lpbDocInfo - Points to the DOC_INFO_1 object
  720. Return Value:
  721. TRUE if the function succeeds, FALSE otherwise. The extended error
  722. can be retrieved through GetLastError().
  723. --*/
  724. {
  725. DWORD err;
  726. DOC_INFO_1 *pDocInfo1 = (DOC_INFO_1 *) lpbDocInfo;
  727. LPWSTR pszUser = NULL;
  728. BOOL fGateway = FALSE;
  729. DWORD PrintOption = NW_GATEWAY_PRINT_OPTION_DEFAULT;
  730. LPWSTR pszPreferredSrv = NULL;
  731. #if DBG
  732. IF_DEBUG(PRINT)
  733. {
  734. KdPrint(( "NWSPL [StartDocPrinter] " ));
  735. if ( pDocInfo1 )
  736. {
  737. if ( pDocInfo1->pDocName )
  738. KdPrint(("Document %ws", pDocInfo1->pDocName ));
  739. if ( pDocInfo1->pOutputFile )
  740. KdPrint(("OutputFile %ws", pDocInfo1->pOutputFile ));
  741. if ( pDocInfo1->pDatatype )
  742. KdPrint(("Datatype %ws", pDocInfo1->pDatatype ));
  743. }
  744. KdPrint(("\n"));
  745. }
  746. #endif
  747. if ( hPrinter == &handleDummy )
  748. {
  749. SetLastError( ERROR_NO_NETWORK );
  750. return FALSE;
  751. }
  752. else if ( dwLevel != 1 )
  753. {
  754. SetLastError( ERROR_INVALID_PARAMETER );
  755. return FALSE;
  756. }
  757. // ignore the error, just use default value
  758. NwpGetUserInfo( &pszUser, &fGateway );
  759. if ( !fGateway ) {
  760. NwQueryInfo( &PrintOption, &pszPreferredSrv );
  761. if (pszPreferredSrv) {
  762. LocalFree( pszPreferredSrv );
  763. }
  764. }
  765. RpcTryExcept
  766. {
  767. err = NwrStartDocPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  768. pDocInfo1? pDocInfo1->pDocName : NULL,
  769. pszUser,
  770. PrintOption,
  771. fGateway );
  772. }
  773. RpcExcept(1)
  774. {
  775. DWORD code = RpcExceptionCode();
  776. if ( code == RPC_S_SERVER_UNAVAILABLE )
  777. err = ERROR_INVALID_HANDLE;
  778. else
  779. err = NwpMapRpcError( code );
  780. }
  781. RpcEndExcept
  782. LocalFree( pszUser );
  783. if ( err )
  784. SetLastError( err );
  785. //
  786. // Can't do this, seems to break GSWN printing on multi-homed machines
  787. // Commenting out code change that tries to return the job id.
  788. //
  789. // else
  790. // return ((PNWSPOOL) hPrinter)->nJobNumber;
  791. return err == NO_ERROR;
  792. }
  793. BOOL
  794. WritePrinter(
  795. HANDLE hPrinter,
  796. LPVOID pBuf,
  797. DWORD cbBuf,
  798. LPDWORD pcbWritten
  799. )
  800. /*++
  801. Routine Description:
  802. This routine informs the print spooler that the specified data should be
  803. written to the given printer.
  804. Arguments:
  805. hPrinter - Handle of the printer object
  806. pBuf - Address of array that contains printer data
  807. cbBuf - Size, in bytes of pBuf
  808. pcbWritten - Receives the number of bytes actually written to the printer
  809. Return Value:
  810. TRUE if it succeeds, FALSE otherwise. Use GetLastError() to get extended
  811. error.
  812. --*/
  813. {
  814. DWORD err;
  815. #if DBG
  816. IF_DEBUG(PRINT)
  817. KdPrint(( "NWSPL [WritePrinter]\n"));
  818. if ( hPrinter == &handleDummy )
  819. {
  820. SetLastError( ERROR_NO_NETWORK );
  821. return FALSE;
  822. }
  823. #endif
  824. RpcTryExcept
  825. {
  826. err = NwrWritePrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  827. pBuf,
  828. cbBuf,
  829. pcbWritten );
  830. }
  831. RpcExcept(1)
  832. {
  833. DWORD code = RpcExceptionCode();
  834. if ( code == RPC_S_SERVER_UNAVAILABLE )
  835. err = ERROR_INVALID_HANDLE;
  836. else
  837. err = NwpMapRpcError( code );
  838. }
  839. RpcEndExcept
  840. if ( err )
  841. SetLastError( err );
  842. return err == NO_ERROR;
  843. }
  844. BOOL
  845. AbortPrinter(
  846. HANDLE hPrinter
  847. )
  848. /*++
  849. Routine Description:
  850. This routine deletes a printer's spool file if the printer is configured
  851. for spooling.
  852. Arguments:
  853. hPrinter - Handle of the printer object
  854. Return Value:
  855. TRUE if the function succeeds, FALSE otherwise.
  856. --*/
  857. {
  858. DWORD err;
  859. #if DBG
  860. IF_DEBUG(PRINT)
  861. KdPrint(( "NWSPL [AbortPrinter]\n"));
  862. if ( hPrinter == &handleDummy )
  863. {
  864. SetLastError( ERROR_NO_NETWORK );
  865. return FALSE;
  866. }
  867. #endif
  868. RpcTryExcept
  869. {
  870. err = NwrAbortPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter );
  871. }
  872. RpcExcept(1)
  873. {
  874. DWORD code = RpcExceptionCode();
  875. if ( code == RPC_S_SERVER_UNAVAILABLE )
  876. err = ERROR_INVALID_HANDLE;
  877. else
  878. err = NwpMapRpcError( code );
  879. }
  880. RpcEndExcept
  881. if ( err )
  882. SetLastError( err );
  883. return err == NO_ERROR;
  884. }
  885. BOOL
  886. EndDocPrinter(
  887. HANDLE hPrinter
  888. )
  889. /*++
  890. Routine Description:
  891. This routine ends the print job for the given printer.
  892. Arguments:
  893. hPrinter - Handle of the printer object
  894. Return Value:
  895. TRUE if the function succeeds, FALSE otherwise.
  896. --*/
  897. {
  898. DWORD err;
  899. #if DBG
  900. IF_DEBUG(PRINT)
  901. KdPrint(( "NWSPL [EndDocPrinter]\n"));
  902. #endif
  903. if ( hPrinter == &handleDummy )
  904. {
  905. SetLastError( ERROR_NO_NETWORK );
  906. return FALSE;
  907. }
  908. RpcTryExcept
  909. {
  910. err = NwrEndDocPrinter( (NWWKSTA_PRINTER_CONTEXT) hPrinter );
  911. }
  912. RpcExcept(1)
  913. {
  914. DWORD code = RpcExceptionCode();
  915. if ( code == RPC_S_SERVER_UNAVAILABLE )
  916. err = ERROR_INVALID_HANDLE;
  917. else
  918. err = NwpMapRpcError( code );
  919. }
  920. RpcEndExcept
  921. if ( err )
  922. SetLastError( err );
  923. return err == NO_ERROR;
  924. }
  925. BOOL
  926. GetJob(
  927. HANDLE hPrinter,
  928. DWORD dwJobId,
  929. DWORD dwLevel,
  930. LPBYTE pbJob,
  931. DWORD cbBuf,
  932. LPDWORD pcbNeeded
  933. )
  934. /*++
  935. Routine Description:
  936. This routine retrieves print-job data for the given printer.
  937. Arguments:
  938. hPrinter - Handle of the printer
  939. dwJobId - Job identifition number
  940. dwLevel - Data structure level of pbJob
  941. pbJob - Address of data-structure array
  942. cbBuf - Count of bytes in array
  943. pcbNeeded - Count of bytes retrieved or required
  944. Return Value:
  945. TRUE if the function succeeds, FALSE otherwise.
  946. --*/
  947. {
  948. DWORD err;
  949. #if DBG
  950. IF_DEBUG(PRINT)
  951. KdPrint(("NWSPL [GetJob] JobId = %d Level = %d\n", dwJobId, dwLevel));
  952. #endif
  953. if ( hPrinter == &handleDummy )
  954. {
  955. SetLastError( ERROR_NO_NETWORK );
  956. return FALSE;
  957. }
  958. else if (( dwLevel != 1 ) && ( dwLevel != 2 ))
  959. {
  960. SetLastError( ERROR_INVALID_LEVEL );
  961. return FALSE;
  962. }
  963. RpcTryExcept
  964. {
  965. err = NwrGetJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  966. dwJobId,
  967. dwLevel,
  968. pbJob,
  969. cbBuf,
  970. pcbNeeded );
  971. if ( !err )
  972. {
  973. if ( dwLevel == 1 )
  974. MarshallUpStructure( pbJob, JobInfo1Offsets, pbJob );
  975. else
  976. MarshallUpStructure( pbJob, JobInfo2Offsets, pbJob );
  977. }
  978. }
  979. RpcExcept(1)
  980. {
  981. DWORD code = RpcExceptionCode();
  982. if ( code == RPC_S_SERVER_UNAVAILABLE )
  983. err = ERROR_INVALID_HANDLE;
  984. else
  985. err = NwpMapRpcError( code );
  986. }
  987. RpcEndExcept
  988. if ( err )
  989. SetLastError( err );
  990. return err == NO_ERROR;
  991. }
  992. BOOL
  993. EnumJobs(
  994. HANDLE hPrinter,
  995. DWORD dwFirstJob,
  996. DWORD dwNoJobs,
  997. DWORD dwLevel,
  998. LPBYTE pbJob,
  999. DWORD cbBuf,
  1000. LPDWORD pcbNeeded,
  1001. LPDWORD pcReturned
  1002. )
  1003. /*++
  1004. Routine Description:
  1005. This routine initializes the array of JOB_INFO_1 or JOB_INFO_2 structures
  1006. with data describing the specified print jobs for the given printer.
  1007. Arguments:
  1008. hPrinter - Handle of the printer
  1009. dwFirstJob - Location of first job in the printer
  1010. dwNoJobs - Number of jobs to enumerate
  1011. dwLevel - Data structure level
  1012. pbJob - Address of structure array
  1013. cbBuf - Size of pbJob, in bytes
  1014. pcbNeeded - Receives the number of bytes copied or required
  1015. pcReturned - Receives the number of jobs copied
  1016. Return Value:
  1017. TRUE if the function succeeds, FALSE otherwise.
  1018. --*/
  1019. {
  1020. DWORD err;
  1021. #if DBG
  1022. IF_DEBUG(PRINT)
  1023. KdPrint(("NWSPL [EnumJobs] Level = %d FirstJob = %d NoJobs = %d\n",
  1024. dwLevel, dwFirstJob, dwNoJobs));
  1025. #endif
  1026. if ( hPrinter == &handleDummy )
  1027. {
  1028. SetLastError( ERROR_NO_NETWORK );
  1029. return FALSE;
  1030. }
  1031. else if ( ( dwLevel != 1 ) && ( dwLevel != 2 ) )
  1032. {
  1033. SetLastError( ERROR_INVALID_LEVEL );
  1034. return FALSE;
  1035. }
  1036. RpcTryExcept
  1037. {
  1038. *pcReturned = 0;
  1039. *pcbNeeded = 0;
  1040. err = NwrEnumJobs( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  1041. dwFirstJob,
  1042. dwNoJobs,
  1043. dwLevel,
  1044. pbJob,
  1045. cbBuf,
  1046. pcbNeeded,
  1047. pcReturned );
  1048. if ( !err )
  1049. {
  1050. DWORD i;
  1051. DWORD cbStruct;
  1052. DWORD_PTR *pOffsets;
  1053. if ( dwLevel == 1 )
  1054. {
  1055. cbStruct = sizeof( JOB_INFO_1W );
  1056. pOffsets = JobInfo1Offsets;
  1057. }
  1058. else // dwLevel == 2
  1059. {
  1060. cbStruct = sizeof( JOB_INFO_2W );
  1061. pOffsets = JobInfo2Offsets;
  1062. }
  1063. for ( i = 0; i < *pcReturned; i++ )
  1064. MarshallUpStructure( pbJob + i * cbStruct, pOffsets, pbJob );
  1065. }
  1066. }
  1067. RpcExcept(1)
  1068. {
  1069. DWORD code = RpcExceptionCode();
  1070. if ( code == RPC_S_SERVER_UNAVAILABLE )
  1071. err = ERROR_INVALID_HANDLE;
  1072. else
  1073. err = NwpMapRpcError( code );
  1074. }
  1075. RpcEndExcept
  1076. if ( err )
  1077. SetLastError( err );
  1078. return err == NO_ERROR;
  1079. }
  1080. BOOL
  1081. SetJob(
  1082. HANDLE hPrinter,
  1083. DWORD dwJobId,
  1084. DWORD dwLevel,
  1085. LPBYTE pbJob,
  1086. DWORD dwCommand
  1087. )
  1088. /*++
  1089. Routine Description:
  1090. This routine pauses, cancels, resumes, restarts the specified print job
  1091. in the given printer. The function can also be used to set print job
  1092. parameters such as job position, and so on.
  1093. Arguments:
  1094. hPrinter - Handle of the printer
  1095. dwJobId - Job indentification number
  1096. dwLevel - Data structure level
  1097. pbJob - Address of data structure
  1098. dwCommand - Specify the operation to be performed
  1099. Return Value:
  1100. TRUE if the function succeeds, FALSE otherwise.
  1101. --*/
  1102. {
  1103. DWORD err;
  1104. #if DBG
  1105. IF_DEBUG(PRINT)
  1106. {
  1107. KdPrint(("NWSPL [SetJob] Level = %d JobId = %d Command = %d\n",
  1108. dwLevel, dwJobId, dwCommand));
  1109. }
  1110. #endif
  1111. if ( hPrinter == &handleDummy )
  1112. {
  1113. SetLastError( ERROR_NO_NETWORK );
  1114. return FALSE;
  1115. }
  1116. else if ( ( dwLevel != 0 ) && ( dwLevel != 1 ) && ( dwLevel != 2 ) )
  1117. {
  1118. SetLastError( ERROR_INVALID_LEVEL );
  1119. return FALSE;
  1120. }
  1121. else if ( ( dwLevel == 0 ) && ( pbJob != NULL ) )
  1122. {
  1123. SetLastError( ERROR_INVALID_PARAMETER );
  1124. return FALSE;
  1125. }
  1126. RpcTryExcept
  1127. {
  1128. NW_JOB_INFO NwJobInfo;
  1129. if ( dwLevel == 1 )
  1130. {
  1131. NwJobInfo.nPosition = ((LPJOB_INFO_1W) pbJob)->Position;
  1132. NwJobInfo.pUserName = ((LPJOB_INFO_1W) pbJob)->pUserName;
  1133. NwJobInfo.pDocument = ((LPJOB_INFO_1W) pbJob)->pDocument;
  1134. }
  1135. else if ( dwLevel == 2 )
  1136. {
  1137. NwJobInfo.nPosition = ((LPJOB_INFO_2W) pbJob)->Position;
  1138. NwJobInfo.pUserName = ((LPJOB_INFO_2W) pbJob)->pUserName;
  1139. NwJobInfo.pDocument = ((LPJOB_INFO_2W) pbJob)->pDocument;
  1140. }
  1141. err = NwrSetJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  1142. dwJobId,
  1143. dwLevel,
  1144. dwLevel == 0 ? NULL : &NwJobInfo,
  1145. dwCommand );
  1146. }
  1147. RpcExcept(1)
  1148. {
  1149. DWORD code = RpcExceptionCode();
  1150. if ( code == RPC_S_SERVER_UNAVAILABLE )
  1151. err = ERROR_INVALID_HANDLE;
  1152. else
  1153. err = NwpMapRpcError( code );
  1154. }
  1155. RpcEndExcept
  1156. if ( err )
  1157. SetLastError( err );
  1158. return err == NO_ERROR;
  1159. }
  1160. BOOL
  1161. AddJob(
  1162. HANDLE hPrinter,
  1163. DWORD dwLevel,
  1164. LPBYTE pbAddJob,
  1165. DWORD cbBuf,
  1166. LPDWORD pcbNeeded
  1167. )
  1168. /*++
  1169. Routine Description:
  1170. This routine returns a full path and filename of a file that can be used
  1171. to store a print job.
  1172. Arguments:
  1173. hPrinter - Handle of the printer
  1174. dwLevel - Data structure level
  1175. pbAddJob - Points to a ADD_INFO_1 structure
  1176. cbBuf - Size of pbAddJob, in bytes
  1177. pcbNeeded - Receives the bytes copied or required
  1178. Return Value:
  1179. TRUE if the function succeeds, FALSE otherwise.
  1180. --*/
  1181. {
  1182. DWORD err;
  1183. ADDJOB_INFO_1W TempBuffer;
  1184. PADDJOB_INFO_1W OutputBuffer;
  1185. DWORD OutputBufferSize;
  1186. #if DBG
  1187. IF_DEBUG(PRINT)
  1188. KdPrint(( "NWSPL [AddJob]\n"));
  1189. #endif
  1190. if ( hPrinter == &handleDummy )
  1191. {
  1192. SetLastError( ERROR_NO_NETWORK );
  1193. return FALSE;
  1194. }
  1195. else if ( dwLevel != 1 )
  1196. {
  1197. SetLastError( ERROR_INVALID_PARAMETER );
  1198. return FALSE;
  1199. }
  1200. //
  1201. // The output buffer size must be at least the size of the fixed
  1202. // portion of the structure marshalled by RPC or RPC will not
  1203. // call the server-side to get the pcbNeeded. Use our own temporary
  1204. // buffer to force RPC to call the server-side if output buffer
  1205. // specified by the caller is too small.
  1206. //
  1207. if (cbBuf < sizeof(ADDJOB_INFO_1W)) {
  1208. OutputBuffer = &TempBuffer;
  1209. OutputBufferSize = sizeof(ADDJOB_INFO_1W);
  1210. }
  1211. else {
  1212. OutputBuffer = (LPADDJOB_INFO_1W) pbAddJob;
  1213. OutputBufferSize = cbBuf;
  1214. }
  1215. RpcTryExcept
  1216. {
  1217. err = NwrAddJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  1218. OutputBuffer,
  1219. OutputBufferSize,
  1220. pcbNeeded );
  1221. }
  1222. RpcExcept(1)
  1223. {
  1224. DWORD code = RpcExceptionCode();
  1225. if ( code == RPC_S_SERVER_UNAVAILABLE )
  1226. err = ERROR_INVALID_HANDLE;
  1227. else
  1228. err = NwpMapRpcError( code );
  1229. }
  1230. RpcEndExcept
  1231. if ( err )
  1232. SetLastError( err );
  1233. return err == NO_ERROR;
  1234. }
  1235. BOOL
  1236. ScheduleJob(
  1237. HANDLE hPrinter,
  1238. DWORD dwJobId
  1239. )
  1240. /*++
  1241. Routine Description:
  1242. This routine informs the print spooler that the specified job can be
  1243. scheduled for spooling.
  1244. Arguments:
  1245. hPrinter - Handle of the printer
  1246. dwJobId - Job number that can be scheduled
  1247. Return Value:
  1248. TRUE if the function succeeds, FALSE otherwise.
  1249. --*/
  1250. {
  1251. DWORD err;
  1252. #if DBG
  1253. IF_DEBUG(PRINT)
  1254. KdPrint(( "NWSPL [ScheduleJob] JobId = %d\n", dwJobId ));
  1255. #endif
  1256. if ( hPrinter == &handleDummy )
  1257. {
  1258. SetLastError( ERROR_NO_NETWORK );
  1259. return FALSE;
  1260. }
  1261. RpcTryExcept
  1262. {
  1263. err = NwrScheduleJob( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  1264. dwJobId );
  1265. }
  1266. RpcExcept(1)
  1267. {
  1268. DWORD code = RpcExceptionCode();
  1269. if ( code == RPC_S_SERVER_UNAVAILABLE )
  1270. err = ERROR_INVALID_HANDLE;
  1271. else
  1272. err = NwpMapRpcError( code );
  1273. }
  1274. RpcEndExcept
  1275. if ( err )
  1276. SetLastError( err );
  1277. return err == NO_ERROR;
  1278. }
  1279. DWORD
  1280. WaitForPrinterChange(
  1281. HANDLE hPrinter,
  1282. DWORD dwFlags
  1283. )
  1284. /*++
  1285. Routine Description:
  1286. This function returns when one or more requested changes occur on a
  1287. print server or if the function times out.
  1288. Arguments:
  1289. hPrinter - Handle of the printer to wait on
  1290. dwFlags - A bitmask that specifies the changes that the application
  1291. wishes to be notified of.
  1292. Return Value:
  1293. Return a bitmask that indicates the changes that occurred.
  1294. --*/
  1295. {
  1296. DWORD err;
  1297. #if DBG
  1298. IF_DEBUG(PRINT)
  1299. KdPrint(("NWSPL [WaitForPrinterChange] Flags = %d\n", dwFlags));
  1300. #endif
  1301. if ( hPrinter == &handleDummy )
  1302. {
  1303. SetLastError( ERROR_NO_NETWORK );
  1304. return 0;
  1305. }
  1306. RpcTryExcept
  1307. {
  1308. err = NwrWaitForPrinterChange( (NWWKSTA_PRINTER_CONTEXT) hPrinter,
  1309. &dwFlags );
  1310. }
  1311. RpcExcept(1)
  1312. {
  1313. DWORD code = RpcExceptionCode();
  1314. if ( code == RPC_S_SERVER_UNAVAILABLE )
  1315. err = ERROR_INVALID_HANDLE;
  1316. else
  1317. err = NwpMapRpcError( code );
  1318. }
  1319. RpcEndExcept
  1320. if ( err )
  1321. {
  1322. SetLastError( err );
  1323. return 0;
  1324. }
  1325. return dwFlags;
  1326. }
  1327. BOOL
  1328. EnumPortsW(
  1329. LPWSTR pszName,
  1330. DWORD dwLevel,
  1331. LPBYTE pbPort,
  1332. DWORD cbBuf,
  1333. LPDWORD pcbNeeded,
  1334. LPDWORD pcReturned
  1335. )
  1336. /*++
  1337. Routine Description:
  1338. This function enumerates the ports available for printing on a
  1339. specified server.
  1340. Arguments:
  1341. pszName - Name of the server to enumerate on
  1342. dwLevel - Structure level
  1343. pbPort - Address of array to receive the port information
  1344. cbBuf - Size, in bytes, of pbPort
  1345. pcbNeeded - Address to store the number of bytes needed or copied
  1346. pcReturned - Address to store the number of entries copied
  1347. Return Value:
  1348. TRUE if the function succeeds, FALSE otherwise.
  1349. --*/
  1350. {
  1351. DWORD err = NO_ERROR;
  1352. DWORD cb = 0;
  1353. PNWPORT pNwPort;
  1354. LPPORT_INFO_1W pPortInfo1;
  1355. LPBYTE pEnd = pbPort + cbBuf;
  1356. LPBYTE pFixedDataEnd = pbPort;
  1357. BOOL FitInBuffer;
  1358. #if DBG
  1359. IF_DEBUG(PRINT)
  1360. KdPrint(("NWSPL [EnumPorts]\n"));
  1361. #endif
  1362. if ( dwLevel != 1 )
  1363. {
  1364. SetLastError( ERROR_INVALID_NAME );
  1365. return FALSE;
  1366. }
  1367. else if ( !IsLocalMachine( pszName ) )
  1368. {
  1369. SetLastError( ERROR_INVALID_NAME );
  1370. return FALSE;
  1371. }
  1372. EnterCriticalSection( &NwSplSem );
  1373. pNwPort = pNwFirstPort;
  1374. while ( pNwPort )
  1375. {
  1376. cb += sizeof(PORT_INFO_1W) + ( wcslen( pNwPort->pName)+1)*sizeof(WCHAR);
  1377. pNwPort = pNwPort->pNext;
  1378. }
  1379. *pcbNeeded = cb;
  1380. *pcReturned = 0;
  1381. if ( cb <= cbBuf )
  1382. {
  1383. pEnd = pbPort + cbBuf;
  1384. pNwPort = pNwFirstPort;
  1385. while ( pNwPort )
  1386. {
  1387. pPortInfo1 = (LPPORT_INFO_1W) pFixedDataEnd;
  1388. pFixedDataEnd += sizeof( PORT_INFO_1W );
  1389. FitInBuffer = NwlibCopyStringToBuffer( pNwPort->pName,
  1390. wcslen( pNwPort->pName),
  1391. (LPCWSTR) pFixedDataEnd,
  1392. (LPWSTR *) &pEnd,
  1393. &pPortInfo1->pName );
  1394. ASSERT( FitInBuffer );
  1395. pNwPort = pNwPort->pNext;
  1396. (*pcReturned)++;
  1397. }
  1398. }
  1399. else
  1400. {
  1401. err = ERROR_INSUFFICIENT_BUFFER;
  1402. }
  1403. LeaveCriticalSection( &NwSplSem );
  1404. if ( err )
  1405. SetLastError( err );
  1406. return err == NO_ERROR;
  1407. }
  1408. BOOL
  1409. DeletePortW(
  1410. LPWSTR pszName,
  1411. HWND hWnd,
  1412. LPWSTR pszPortName
  1413. )
  1414. /*++
  1415. Routine Description:
  1416. This routine deletes the port given on the server. A dialog can
  1417. be displayed if needed.
  1418. Arguments:
  1419. pszName - Name of the server for which the port should be deleted
  1420. hWnd - Parent window
  1421. pszPortName - The name of the port to delete
  1422. Return Value:
  1423. TRUE if the function succeeds, FALSE otherwise.
  1424. --*/
  1425. {
  1426. DWORD err;
  1427. BOOL fPortDeleted;
  1428. #if DBG
  1429. IF_DEBUG(PRINT)
  1430. KdPrint(("NWSPL [DeletePort]\n"));
  1431. #endif
  1432. if ( !IsLocalMachine( pszName ) )
  1433. {
  1434. SetLastError( ERROR_NOT_SUPPORTED );
  1435. return FALSE;
  1436. }
  1437. fPortDeleted = DeletePortEntry( pszPortName );
  1438. if ( fPortDeleted )
  1439. {
  1440. err = DeleteRegistryEntry( pszPortName );
  1441. }
  1442. else
  1443. {
  1444. err = ERROR_UNKNOWN_PORT;
  1445. }
  1446. if ( err )
  1447. SetLastError( err );
  1448. return err == NO_ERROR;
  1449. }
  1450. BOOL
  1451. ConfigurePortW(
  1452. LPWSTR pszName,
  1453. HWND hWnd,
  1454. LPWSTR pszPortName
  1455. )
  1456. /*++
  1457. Routine Description:
  1458. This routine displays the port configuration dialog box
  1459. for the given port on the given server.
  1460. Arguments:
  1461. pszName - Name of the server on which the given port exist
  1462. hWnd - Parent window
  1463. pszPortName - The name of the port to be configured
  1464. Return Value:
  1465. TRUE if the function succeeds, FALSE otherwise.
  1466. --*/
  1467. {
  1468. DWORD nCurrentThreadId;
  1469. DWORD nWindowThreadId;
  1470. WCHAR szCaption[MAX_PATH];
  1471. WCHAR szMessage[MAX_PATH];
  1472. #if DBG
  1473. IF_DEBUG(PRINT)
  1474. KdPrint(("NWSPL [ConfigurePort] PortName = %ws\n", pszPortName));
  1475. #endif
  1476. if ( !IsLocalMachine( pszName ) )
  1477. {
  1478. SetLastError( ERROR_NOT_SUPPORTED );
  1479. return FALSE;
  1480. }
  1481. else if ( !PortKnown( pszPortName ) )
  1482. {
  1483. SetLastError( ERROR_UNKNOWN_PORT );
  1484. return FALSE;
  1485. }
  1486. nCurrentThreadId = GetCurrentThreadId();
  1487. nWindowThreadId = GetWindowThreadProcessId( hWnd, NULL );
  1488. if ( !AttachThreadInput( nCurrentThreadId, nWindowThreadId, TRUE ))
  1489. KdPrint(("[NWSPL] AttachThreadInput failed with %d.\n",GetLastError()));
  1490. if ( LoadStringW( hmodNW,
  1491. IDS_NETWARE_PRINT_CAPTION,
  1492. szCaption,
  1493. sizeof( szCaption ) / sizeof( WCHAR )))
  1494. {
  1495. if ( LoadStringW( hmodNW,
  1496. IDS_NOTHING_TO_CONFIGURE,
  1497. szMessage,
  1498. sizeof( szMessage ) / sizeof( WCHAR )))
  1499. {
  1500. MessageBox( hWnd, szMessage, szCaption,
  1501. MB_OK | MB_ICONINFORMATION );
  1502. }
  1503. else
  1504. {
  1505. KdPrint(("[NWSPL] LoadString failed with %d.\n",GetLastError()));
  1506. }
  1507. }
  1508. else
  1509. {
  1510. KdPrint(("[NWSPL] LoadString failed with %d.\n",GetLastError()));
  1511. }
  1512. if ( !AttachThreadInput( nCurrentThreadId, nWindowThreadId, FALSE ))
  1513. KdPrint(("[NWSPL] DetachThreadInput failed with %d.\n",GetLastError()));
  1514. return TRUE;
  1515. }
  1516. //------------------------------------------------------------------
  1517. //
  1518. // Print Provider Functions not supported by NetWare provider
  1519. //
  1520. //------------------------------------------------------------------
  1521. BOOL
  1522. AddPrinterConnectionW(
  1523. LPWSTR pszPrinterName
  1524. )
  1525. {
  1526. #if DBG
  1527. IF_DEBUG(PRINT)
  1528. {
  1529. KdPrint(("NWSPL [AddPrinterConnection] PrinterName = %ws\n",
  1530. pszPrinterName));
  1531. }
  1532. #endif
  1533. SetLastError( ERROR_INVALID_NAME );
  1534. return FALSE;
  1535. }
  1536. BOOL
  1537. EnumMonitorsW(
  1538. LPWSTR pszName,
  1539. DWORD dwLevel,
  1540. LPBYTE pbMonitor,
  1541. DWORD cbBuf,
  1542. LPDWORD pcbNeeded,
  1543. LPDWORD pcReturned
  1544. )
  1545. {
  1546. #if DBG
  1547. IF_DEBUG(PRINT)
  1548. KdPrint(("NWSPL [EnumMonitors]\n"));
  1549. #endif
  1550. SetLastError( ERROR_INVALID_NAME );
  1551. return FALSE;
  1552. }
  1553. BOOL
  1554. AddPortW(
  1555. LPWSTR pszName,
  1556. HWND hWnd,
  1557. LPWSTR pszMonitorName
  1558. )
  1559. {
  1560. #if DBG
  1561. IF_DEBUG(PRINT)
  1562. KdPrint(("NWSPL [AddPort]\n"));
  1563. #endif
  1564. SetLastError( ERROR_NOT_SUPPORTED );
  1565. return FALSE;
  1566. }
  1567. HANDLE
  1568. AddPrinterW(
  1569. LPWSTR pszName,
  1570. DWORD dwLevel,
  1571. LPBYTE pbPrinter
  1572. )
  1573. // Creates a print queue on the netware server and returns a handle to it
  1574. {
  1575. #ifdef NOT_USED
  1576. #if DBG
  1577. IF_DEBUG(PRINT)
  1578. KdPrint(("NWSPL [AddPrinterW]\n"));
  1579. #endif
  1580. SetLastError(ERROR_NOT_SUPPORTED);
  1581. return FALSE;
  1582. #else
  1583. LPTSTR pszPrinterName = NULL;
  1584. LPTSTR pszPServer = NULL;
  1585. LPTSTR pszQueue = NULL;
  1586. HANDLE hPrinter = NULL;
  1587. DWORD err;
  1588. PPRINTER_INFO_2 pPrinterInfo;
  1589. #if DBG
  1590. IF_DEBUG(PRINT)
  1591. KdPrint(("NWSPL [AddPrinterW]\n"));
  1592. #endif
  1593. pPrinterInfo = (PPRINTER_INFO_2)pbPrinter;
  1594. if (dwLevel != 2)
  1595. {
  1596. err = ERROR_INVALID_PARAMETER;
  1597. goto ErrorExit;
  1598. }
  1599. if (!(pszPrinterName = (LPTSTR)LocalAlloc(LPTR, (wcslen(((PRINTER_INFO_2 *)pbPrinter)->pPrinterName)+1)* sizeof(WCHAR))))
  1600. {
  1601. err = ERROR_NOT_ENOUGH_MEMORY;
  1602. goto ErrorExit;
  1603. }
  1604. wcscpy(pszPrinterName,pPrinterInfo->pPrinterName);
  1605. // PrinterName is the name represented as \\server\share
  1606. //The pszPServer parameter could have multiple fields separated by semicolons
  1607. if ( ( !ValidateUNCName( pszPrinterName ) )
  1608. || ( (pszQueue = wcschr( pszPrinterName + 2, L'\\')) == NULL )
  1609. || ( pszQueue == (pszPrinterName + 2) )
  1610. || ( *(pszQueue + 1) == L'\0' )
  1611. )
  1612. {
  1613. err = ERROR_INVALID_NAME;
  1614. goto ErrorExit;
  1615. }
  1616. #if DBG
  1617. IF_DEBUG(PRINT)
  1618. KdPrint(( "NWSPL [AddPrinter] Name = %ws\n",pszPServer));
  1619. #endif
  1620. if ( pszPrinterName == NULL )
  1621. //PrinterName is a mandatory field but not the list of PServers
  1622. {
  1623. #if DBG
  1624. IF_DEBUG(PRINT)
  1625. KdPrint(( "NWSPL [AddPrinter] Printername not supplied\n" ));
  1626. #endif
  1627. SetLastError( ERROR_INVALID_NAME );
  1628. goto ErrorExit;
  1629. }
  1630. //Check to see if there is a port of the same name
  1631. // If so, abort the addprinter operation.
  1632. // This code was commented earlier
  1633. if (PortExists(pszPrinterName, &err ) && !err )
  1634. {
  1635. #if DBG
  1636. IF_DEBUG(PRINT)
  1637. KdPrint(( "NWSPL [AddPrinter], = %ws; Port exists with same name\n", pszPrinterName ));
  1638. #endif
  1639. SetLastError(ERROR_ALREADY_ASSIGNED);
  1640. goto ErrorExit;
  1641. }
  1642. // Put all the relevant information into the PRINTER_INFO_2 structure
  1643. RpcTryExcept
  1644. {
  1645. err = NwrAddPrinter ( NULL,
  1646. (LPPRINTER_INFO_2W) pPrinterInfo,
  1647. (LPNWWKSTA_PRINTER_CONTEXT) &hPrinter
  1648. );
  1649. if (!err)
  1650. {
  1651. #if DBG
  1652. IF_DEBUG(PRINT)
  1653. KdPrint(( "NWSPL [AddPrinter] Name = %ws\n", pszPrinterName ));
  1654. #endif
  1655. goto ErrorExit;
  1656. }
  1657. }
  1658. RpcExcept(1)
  1659. {
  1660. DWORD code = RpcExceptionCode();
  1661. err = NwpMapRpcError( code );
  1662. goto ErrorExit;
  1663. }
  1664. RpcEndExcept
  1665. if ( !pszPrinterName)
  1666. (void) LocalFree((HLOCAL)pszPrinterName);
  1667. return hPrinter;
  1668. ErrorExit:
  1669. if ( !pszPrinterName)
  1670. (void) LocalFree((HLOCAL)pszPrinterName);
  1671. SetLastError( err);
  1672. return (HANDLE)0x0;
  1673. #endif // #ifdef NOT_USED
  1674. }
  1675. BOOL
  1676. DeletePrinter(
  1677. HANDLE hPrinter
  1678. )
  1679. {
  1680. #ifdef NOT_USED
  1681. #if DBG
  1682. IF_DEBUG(PRINT)
  1683. KdPrint(("NWSPL [DeletePrinter]\n"));
  1684. #endif
  1685. SetLastError(ERROR_NOT_SUPPORTED);
  1686. return FALSE;
  1687. #else
  1688. LPWSTR pszPrinterName = NULL ; // Used to delete entry from registry
  1689. DWORD err = NO_ERROR;
  1690. DWORD DoesPortExist;
  1691. #if DBG
  1692. IF_DEBUG(PRINT)
  1693. KdPrint(("NWSPL [DeletePrinter]\n"));
  1694. #endif
  1695. pszPrinterName = (LPWSTR)LocalAlloc(LPTR,sizeof(WCHAR)*MAX_PATH);
  1696. if(pszPrinterName == NULL)
  1697. {
  1698. err = ERROR_NOT_ENOUGH_MEMORY;
  1699. return FALSE;
  1700. }
  1701. //
  1702. // Just return success if the handle is a dummy one
  1703. //
  1704. if ( hPrinter == &handleDummy )
  1705. {
  1706. #if DBG
  1707. IF_DEBUG(PRINT)
  1708. KdPrint(("NWSPL [DeletePrinter] Dummy handle \n"));
  1709. #endif
  1710. SetLastError(ERROR_NO_NETWORK);
  1711. return FALSE;
  1712. }
  1713. RpcTryExcept
  1714. {
  1715. err = NwrDeletePrinter( NULL,
  1716. // pszPrinterName,
  1717. (LPNWWKSTA_PRINTER_CONTEXT) &hPrinter );
  1718. }
  1719. RpcExcept(1)
  1720. {
  1721. DWORD code = RpcExceptionCode();
  1722. if ( code == RPC_S_SERVER_UNAVAILABLE )
  1723. err = ERROR_INVALID_HANDLE;
  1724. else
  1725. err = NwpMapRpcError( code );
  1726. }
  1727. RpcEndExcept
  1728. if (!err && PortExists(pszPrinterName, &DoesPortExist) && DoesPortExist)
  1729. {
  1730. if ( DeleteRegistryEntry (pszPrinterName))
  1731. (void) DeletePortEntry(pszPrinterName);
  1732. }
  1733. if ( err )
  1734. SetLastError( err );
  1735. return err == NO_ERROR;
  1736. #endif // #ifdef NOT_USED
  1737. }
  1738. BOOL
  1739. DeletePrinterConnectionW(
  1740. LPWSTR pszName
  1741. )
  1742. {
  1743. #if DBG
  1744. IF_DEBUG(PRINT)
  1745. KdPrint(("NWSPL [DeletePrinterConnection]\n"));
  1746. #endif
  1747. SetLastError( ERROR_INVALID_NAME );
  1748. return FALSE;
  1749. }
  1750. BOOL
  1751. AddPrinterDriverW(
  1752. LPWSTR pszName,
  1753. DWORD dwLevel,
  1754. LPBYTE pbPrinter
  1755. )
  1756. {
  1757. #if DBG
  1758. IF_DEBUG(PRINT)
  1759. KdPrint(("NWSPL [AddPrinterDriver]\n"));
  1760. #endif
  1761. SetLastError( ERROR_INVALID_NAME );
  1762. return FALSE;
  1763. }
  1764. BOOL
  1765. EnumPrinterDriversW(
  1766. LPWSTR pszName,
  1767. LPWSTR pszEnvironment,
  1768. DWORD dwLevel,
  1769. LPBYTE pbDriverInfo,
  1770. DWORD cbBuf,
  1771. LPDWORD pcbNeeded,
  1772. LPDWORD pcReturned
  1773. )
  1774. {
  1775. #if DBG
  1776. IF_DEBUG(PRINT)
  1777. KdPrint(("NWSPL [EnumPrinterDrivers]\n"));
  1778. #endif
  1779. SetLastError( ERROR_INVALID_NAME );
  1780. return FALSE;
  1781. }
  1782. BOOL
  1783. GetPrinterDriverW(
  1784. HANDLE hPrinter,
  1785. LPWSTR pszEnvironment,
  1786. DWORD dwLevel,
  1787. LPBYTE pbDriverInfo,
  1788. DWORD cbBuf,
  1789. LPDWORD pcbNeeded
  1790. )
  1791. {
  1792. #if DBG
  1793. IF_DEBUG(PRINT)
  1794. KdPrint(("NWSPL [GetPrinterDriver]\n"));
  1795. #endif
  1796. SetLastError( ERROR_NOT_SUPPORTED );
  1797. return FALSE;
  1798. }
  1799. BOOL
  1800. GetPrinterDriverDirectoryW(
  1801. LPWSTR pszName,
  1802. LPWSTR pszEnvironment,
  1803. DWORD dwLevel,
  1804. LPBYTE pbDriverDirectory,
  1805. DWORD cbBuf,
  1806. LPDWORD pcbNeeded
  1807. )
  1808. {
  1809. #if DBG
  1810. IF_DEBUG(PRINT)
  1811. KdPrint(("NWSPL [GetPrinterDriverDirectory]\n"));
  1812. #endif
  1813. SetLastError( ERROR_INVALID_NAME );
  1814. return FALSE;
  1815. }
  1816. BOOL
  1817. DeletePrinterDriverW(
  1818. LPWSTR pszName,
  1819. LPWSTR pszEnvironment,
  1820. LPWSTR pszDriverName
  1821. )
  1822. {
  1823. #if DBG
  1824. IF_DEBUG(PRINT)
  1825. KdPrint(("NWSPL [DeletePrinterDriver]\n"));
  1826. #endif
  1827. SetLastError( ERROR_INVALID_NAME );
  1828. return FALSE;
  1829. }
  1830. BOOL
  1831. AddPrintProcessorW(
  1832. LPWSTR pszName,
  1833. LPWSTR pszEnvironment,
  1834. LPWSTR pszPathName,
  1835. LPWSTR pszPrintProcessorName
  1836. )
  1837. {
  1838. #if DBG
  1839. IF_DEBUG(PRINT)
  1840. KdPrint(("NWSPL [AddPrintProcessor]\n"));
  1841. #endif
  1842. SetLastError( ERROR_INVALID_NAME );
  1843. return FALSE;
  1844. }
  1845. BOOL
  1846. EnumPrintProcessorsW(
  1847. LPWSTR pszName,
  1848. LPWSTR pszEnvironment,
  1849. DWORD dwLevel,
  1850. LPBYTE pbPrintProcessorInfo,
  1851. DWORD cbBuf,
  1852. LPDWORD pcbNeeded,
  1853. LPDWORD pcReturned
  1854. )
  1855. {
  1856. #if DBG
  1857. IF_DEBUG(PRINT)
  1858. KdPrint(("NWSPL [EnumPrintProcessors]\n"));
  1859. #endif
  1860. SetLastError( ERROR_INVALID_NAME );
  1861. return FALSE;
  1862. }
  1863. BOOL
  1864. EnumPrintProcessorDatatypesW(
  1865. LPWSTR pszName,
  1866. LPWSTR pszPrintProcessorName,
  1867. DWORD dwLevel,
  1868. LPBYTE pbDatatypes,
  1869. DWORD cbBuf,
  1870. LPDWORD pcbNeeded,
  1871. LPDWORD pcReturned
  1872. )
  1873. {
  1874. #if DBG
  1875. IF_DEBUG(PRINT)
  1876. KdPrint(("NWSPL [EnumPrintProcessorDatatypes]\n"));
  1877. #endif
  1878. SetLastError( ERROR_INVALID_NAME );
  1879. return FALSE;
  1880. }
  1881. BOOL
  1882. GetPrintProcessorDirectoryW(
  1883. LPWSTR pszName,
  1884. LPWSTR pszEnvironment,
  1885. DWORD dwLevel,
  1886. LPBYTE pbPrintProcessorDirectory,
  1887. DWORD cbBuf,
  1888. LPDWORD pcbNeeded
  1889. )
  1890. {
  1891. #if DBG
  1892. IF_DEBUG(PRINT)
  1893. KdPrint(("NWSPL [GetPrintProcessorDirectory]\n"));
  1894. #endif
  1895. SetLastError( ERROR_INVALID_NAME );
  1896. return FALSE;
  1897. }
  1898. BOOL
  1899. StartPagePrinter(
  1900. HANDLE hPrinter
  1901. )
  1902. {
  1903. #if DBG
  1904. IF_DEBUG(PRINT)
  1905. KdPrint(("NWSPL [StartPagePrinter]\n"));
  1906. #endif
  1907. SetLastError( ERROR_NOT_SUPPORTED );
  1908. return FALSE;
  1909. }
  1910. BOOL
  1911. EndPagePrinter(
  1912. HANDLE hPrinter
  1913. )
  1914. {
  1915. #if DBG
  1916. IF_DEBUG(PRINT)
  1917. KdPrint(("NWSPL [EndPagePrinter]\n"));
  1918. #endif
  1919. SetLastError( ERROR_NOT_SUPPORTED );
  1920. return FALSE;
  1921. }
  1922. BOOL
  1923. ReadPrinter(
  1924. HANDLE hPrinter,
  1925. LPVOID pBuf,
  1926. DWORD cbBuf,
  1927. LPDWORD pcbRead
  1928. )
  1929. {
  1930. #if DBG
  1931. IF_DEBUG(PRINT)
  1932. KdPrint(("NWSPL [ReadPrinter]\n"));
  1933. #endif
  1934. SetLastError( ERROR_NOT_SUPPORTED );
  1935. return FALSE;
  1936. }
  1937. DWORD
  1938. GetPrinterDataW(
  1939. HANDLE hPrinter,
  1940. LPWSTR pszValueName,
  1941. LPDWORD pdwType,
  1942. LPBYTE pbData,
  1943. DWORD cbBuf,
  1944. LPDWORD pcbNeeded
  1945. )
  1946. {
  1947. #if DBG
  1948. IF_DEBUG(PRINT)
  1949. KdPrint(("NWSPL [GetPrinterData]\n"));
  1950. #endif
  1951. SetLastError( ERROR_NOT_SUPPORTED );
  1952. return FALSE;
  1953. }
  1954. DWORD
  1955. SetPrinterDataW(
  1956. HANDLE hPrinter,
  1957. LPWSTR pszValueName,
  1958. DWORD dwType,
  1959. LPBYTE pbData,
  1960. DWORD cbData
  1961. )
  1962. {
  1963. #if DBG
  1964. IF_DEBUG(PRINT)
  1965. KdPrint(("NWSPL [SetPrinterData]\n"));
  1966. #endif
  1967. SetLastError( ERROR_NOT_SUPPORTED );
  1968. return FALSE;
  1969. }
  1970. BOOL
  1971. AddForm(
  1972. HANDLE hPrinter,
  1973. DWORD dwLevel,
  1974. LPBYTE pbForm
  1975. )
  1976. {
  1977. #if DBG
  1978. IF_DEBUG(PRINT)
  1979. KdPrint(("NWSPL [AddForm]\n"));
  1980. #endif
  1981. SetLastError( ERROR_NOT_SUPPORTED );
  1982. return FALSE;
  1983. }
  1984. BOOL
  1985. DeleteFormW(
  1986. HANDLE hPrinter,
  1987. LPWSTR pszFormName
  1988. )
  1989. {
  1990. #if DBG
  1991. IF_DEBUG(PRINT)
  1992. KdPrint(("NWSPL [DeleteForm]\n"));
  1993. #endif
  1994. SetLastError( ERROR_NOT_SUPPORTED );
  1995. return FALSE;
  1996. }
  1997. BOOL
  1998. GetFormW(
  1999. HANDLE hPrinter,
  2000. LPWSTR pszFormName,
  2001. DWORD dwLevel,
  2002. LPBYTE pbForm,
  2003. DWORD cbBuf,
  2004. LPDWORD pcbNeeded
  2005. )
  2006. {
  2007. #if DBG
  2008. IF_DEBUG(PRINT)
  2009. KdPrint(("NWSPL [GetForm]\n"));
  2010. #endif
  2011. SetLastError( ERROR_NOT_SUPPORTED );
  2012. return FALSE;
  2013. }
  2014. BOOL
  2015. SetFormW(
  2016. HANDLE hPrinter,
  2017. LPWSTR pszFormName,
  2018. DWORD dwLevel,
  2019. LPBYTE pbForm
  2020. )
  2021. {
  2022. #if DBG
  2023. IF_DEBUG(PRINT)
  2024. KdPrint(("NWSPL [SetForm]\n"));
  2025. #endif
  2026. SetLastError( ERROR_NOT_SUPPORTED );
  2027. return FALSE;
  2028. }
  2029. BOOL
  2030. EnumForms(
  2031. HANDLE hPrinter,
  2032. DWORD dwLevel,
  2033. LPBYTE pbForm,
  2034. DWORD cbBuf,
  2035. LPDWORD pcbNeeded,
  2036. LPDWORD pcReturned
  2037. )
  2038. {
  2039. #if DBG
  2040. IF_DEBUG(PRINT)
  2041. KdPrint(("NWSPL [EnumForms]\n"));
  2042. #endif
  2043. SetLastError( ERROR_NOT_SUPPORTED );
  2044. return FALSE;
  2045. }
  2046. HANDLE
  2047. CreatePrinterIC(
  2048. HANDLE hPrinter,
  2049. LPDEVMODE pDevMode
  2050. )
  2051. {
  2052. #if DBG
  2053. IF_DEBUG(PRINT)
  2054. KdPrint(("NWSPL [CreatePrinterIC]\n"));
  2055. #endif
  2056. SetLastError( ERROR_NOT_SUPPORTED );
  2057. return FALSE;
  2058. }
  2059. BOOL
  2060. PlayGdiScriptOnPrinterIC(
  2061. HANDLE hPrinterIC,
  2062. LPBYTE pbIn,
  2063. DWORD cbIn,
  2064. LPBYTE pbOut,
  2065. DWORD cbOut,
  2066. DWORD ul
  2067. )
  2068. {
  2069. #if DBG
  2070. IF_DEBUG(PRINT)
  2071. KdPrint(("NWSPL [PlayGdiScriptOnPrinterIC]\n"));
  2072. #endif
  2073. SetLastError( ERROR_NOT_SUPPORTED );
  2074. return FALSE;
  2075. }
  2076. BOOL
  2077. DeletePrinterIC(
  2078. HANDLE hPrinterIC
  2079. )
  2080. {
  2081. #if DBG
  2082. IF_DEBUG(PRINT)
  2083. KdPrint(("NWSPL [DeletePrinterIC]\n"));
  2084. #endif
  2085. SetLastError( ERROR_NOT_SUPPORTED );
  2086. return FALSE;
  2087. }
  2088. DWORD
  2089. PrinterMessageBoxW(
  2090. HANDLE hPrinter,
  2091. DWORD dwError,
  2092. HWND hWnd,
  2093. LPWSTR pszText,
  2094. LPWSTR pszCaption,
  2095. DWORD dwType
  2096. )
  2097. {
  2098. #if DBG
  2099. IF_DEBUG(PRINT)
  2100. KdPrint(("NWSPL [PrinterMessageBox]\n"));
  2101. #endif
  2102. SetLastError( ERROR_NOT_SUPPORTED );
  2103. return FALSE;
  2104. }
  2105. BOOL
  2106. AddMonitorW(
  2107. LPWSTR pszName,
  2108. DWORD dwLevel,
  2109. LPBYTE pbMonitorInfo
  2110. )
  2111. {
  2112. #if DBG
  2113. IF_DEBUG(PRINT)
  2114. KdPrint(("NWSPL [AddMonitor]\n"));
  2115. #endif
  2116. SetLastError( ERROR_INVALID_NAME );
  2117. return FALSE;
  2118. }
  2119. BOOL
  2120. DeleteMonitorW(
  2121. LPWSTR pszName,
  2122. LPWSTR pszEnvironment,
  2123. LPWSTR pszMonitorName
  2124. )
  2125. {
  2126. #if DBG
  2127. IF_DEBUG(PRINT)
  2128. KdPrint(("NWSPL [DeleteMonitor]\n"));
  2129. #endif
  2130. SetLastError( ERROR_INVALID_NAME );
  2131. return FALSE;
  2132. }
  2133. BOOL
  2134. DeletePrintProcessorW(
  2135. LPWSTR pszName,
  2136. LPWSTR pszEnvironment,
  2137. LPWSTR pszPrintProcessorName
  2138. )
  2139. {
  2140. #if DBG
  2141. IF_DEBUG(PRINT)
  2142. KdPrint(("NWSPL [DeletePrintProcessor]\n"));
  2143. #endif
  2144. SetLastError( ERROR_INVALID_NAME );
  2145. return FALSE;
  2146. }
  2147. //------------------------------------------------------------------
  2148. //
  2149. // Print Provider Miscellaneous Functions
  2150. //
  2151. //------------------------------------------------------------------
  2152. VOID
  2153. NwpGetUserInfo(
  2154. LPWSTR *ppszUser,
  2155. BOOL *pfGateway
  2156. )
  2157. /*++
  2158. Routine Description:
  2159. Get the user information of the impersonating client.
  2160. Arguments:
  2161. ppszUser - A pointer to buffer to store the Unicode string if
  2162. the impersonated client's user name can be looked up
  2163. successfully. If the conversion was unsuccessful, it points
  2164. to NULL.
  2165. pfGateway - A pointer to a boolean to store whether the user is
  2166. printing through a gateway or not. We assume that
  2167. if the user sid and the current logon user sid is not
  2168. the same, then the user is printing through gateway.
  2169. Else the user is printing locally.
  2170. Return Value:
  2171. None.
  2172. --*/
  2173. {
  2174. DWORD err;
  2175. LPWSTR pszUserSid = NULL;
  2176. // LPWSTR pszLogonUserSid = NULL; //Removed for Multi-user code merge
  2177. //Terminal Server doesn't user this varible
  2178. //There is no single "Logon User" in Terminal Server
  2179. //
  2180. // If any error occurs while trying to get the username, just
  2181. // assume no user name and not gateway printing.
  2182. //
  2183. *pfGateway = TRUE;
  2184. *ppszUser = NULL;
  2185. if ( ((err = NwpGetThreadUserInfo( ppszUser, &pszUserSid )) == NO_ERROR)
  2186. // && ((err = NwpGetLogonUserInfo( &pszLogonUserSid ))) == NO_ERROR) //Removed from Multi-user code merge
  2187. ) {
  2188. if ( ThreadIsInteractive() ) {
  2189. *pfGateway = FALSE;
  2190. }
  2191. else {
  2192. *pfGateway = TRUE;
  2193. }
  2194. #if DBG
  2195. IF_DEBUG(PRINT)
  2196. KdPrint(("NwpGetUserInfo: Thread User= %ws, Thread SID = %ws,\nfGateway = %d\n",
  2197. *ppszUser, pszUserSid, *pfGateway ));
  2198. #endif
  2199. // } else {
  2200. // if ( _wcsicmp( pszUserSid, pszLogonUserSid ) == 0 ) {
  2201. // *pfGateway = FALSE;
  2202. // }
  2203. //#if DBG
  2204. // IF_DEBUG(PRINT)
  2205. // KdPrint(("NwpGetUserInfo: Thread User= %ws, Thread SID = %ws,\nCurrent SID = %ws fGateway = %d\n",
  2206. // *ppszUser, pszUserSid, pszLogonUserSid, *pfGateway ));
  2207. //#endif
  2208. // }
  2209. LocalFree( pszUserSid );
  2210. }
  2211. }
  2212. #define SIZE_OF_TOKEN_INFORMATION \
  2213. sizeof( TOKEN_USER ) \
  2214. + sizeof( SID ) \
  2215. + sizeof( ULONG ) * SID_MAX_SUB_AUTHORITIES
  2216. DWORD
  2217. NwpGetThreadUserInfo(
  2218. LPWSTR *ppszUser,
  2219. LPWSTR *ppszUserSid
  2220. )
  2221. /*++
  2222. Routine Description:
  2223. Get the user name and user sid string of the impersonating client.
  2224. Arguments:
  2225. ppszUser - A pointer to buffer to store the Unicode string
  2226. if the impersonated client's can be looked up. If the
  2227. lookup was unsuccessful, it points to NULL.
  2228. ppszUserSid - A pointer to buffer to store the string if the impersonated
  2229. client's SID can be expanded successfully into unicode string.
  2230. If the conversion was unsuccessful, it points to NULL.
  2231. Return Value:
  2232. The error code.
  2233. --*/
  2234. {
  2235. DWORD err;
  2236. HANDLE TokenHandle;
  2237. UCHAR TokenInformation[ SIZE_OF_TOKEN_INFORMATION ];
  2238. ULONG ReturnLength;
  2239. *ppszUser = NULL;
  2240. *ppszUserSid = NULL;
  2241. // We can use OpenThreadToken because this server thread
  2242. // is impersonating a client
  2243. if ( !OpenThreadToken( GetCurrentThread(),
  2244. TOKEN_READ,
  2245. TRUE, /* Open as self */
  2246. &TokenHandle ))
  2247. {
  2248. #if DBG
  2249. IF_DEBUG(PRINT)
  2250. KdPrint(("NwpGetThreadUserInfo: OpenThreadToken failed: Error %d\n",
  2251. GetLastError()));
  2252. #endif
  2253. return(GetLastError());
  2254. }
  2255. // notice that we've allocated enough space for the
  2256. // TokenInformation structure. so if we fail, we
  2257. // return a NULL pointer indicating failure
  2258. if ( !GetTokenInformation( TokenHandle,
  2259. TokenUser,
  2260. TokenInformation,
  2261. sizeof( TokenInformation ),
  2262. &ReturnLength ))
  2263. {
  2264. #if DBG
  2265. IF_DEBUG(PRINT)
  2266. KdPrint(("NwpGetThreadUserInfo: GetTokenInformation failed: Error %d\n",
  2267. GetLastError()));
  2268. #endif
  2269. return(GetLastError());
  2270. }
  2271. CloseHandle( TokenHandle );
  2272. // convert the Sid (pointed to by pSid) to its
  2273. // equivalent Unicode string representation.
  2274. err = NwpGetUserNameFromSid( ((PTOKEN_USER)TokenInformation)->User.Sid,
  2275. ppszUser );
  2276. err = err? err : NwpConvertSid( ((PTOKEN_USER)TokenInformation)->User.Sid,
  2277. ppszUserSid );
  2278. if ( err )
  2279. {
  2280. if ( *ppszUser )
  2281. LocalFree( *ppszUser );
  2282. if ( *ppszUserSid )
  2283. LocalFree( *ppszUserSid );
  2284. }
  2285. return err;
  2286. }
  2287. DWORD
  2288. NwpGetUserNameFromSid(
  2289. PSID pUserSid,
  2290. LPWSTR *ppszUserName
  2291. )
  2292. /*++
  2293. Routine Description:
  2294. Lookup the user name given the user SID.
  2295. Arguments:
  2296. pUserSid - Points to the user sid to be looked up
  2297. ppszUserName - A pointer to buffer to store the string if the impersonated
  2298. client's SID can be expanded successfully into unicode string.
  2299. If the conversion was unsuccessful, it points to NULL.
  2300. Return Value:
  2301. The error code.
  2302. --*/
  2303. {
  2304. NTSTATUS ntstatus;
  2305. LSA_HANDLE hlsa;
  2306. OBJECT_ATTRIBUTES oa;
  2307. SECURITY_QUALITY_OF_SERVICE sqos;
  2308. PLSA_REFERENCED_DOMAIN_LIST plsardl = NULL;
  2309. PLSA_TRANSLATED_NAME plsatn = NULL;
  2310. sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  2311. sqos.ImpersonationLevel = SecurityImpersonation;
  2312. sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  2313. sqos.EffectiveOnly = FALSE;
  2314. InitializeObjectAttributes( &oa, NULL, 0L, NULL, NULL );
  2315. oa.SecurityQualityOfService = &sqos;
  2316. ntstatus = LsaOpenPolicy( NULL,
  2317. &oa,
  2318. POLICY_LOOKUP_NAMES,
  2319. &hlsa );
  2320. if ( NT_SUCCESS( ntstatus ))
  2321. {
  2322. ntstatus = LsaLookupSids( hlsa,
  2323. 1,
  2324. &pUserSid,
  2325. &plsardl,
  2326. &plsatn );
  2327. if ( NT_SUCCESS( ntstatus ))
  2328. {
  2329. UNICODE_STRING *pUnicodeStr = &((*plsatn).Name);
  2330. *ppszUserName = LocalAlloc( LMEM_ZEROINIT,
  2331. pUnicodeStr->Length+sizeof(WCHAR));
  2332. if ( *ppszUserName != NULL )
  2333. {
  2334. memcpy( *ppszUserName, pUnicodeStr->Buffer, pUnicodeStr->Length );
  2335. }
  2336. else
  2337. {
  2338. ntstatus = STATUS_NO_MEMORY;
  2339. }
  2340. LsaFreeMemory( plsardl );
  2341. LsaFreeMemory( plsatn );
  2342. }
  2343. #if DBG
  2344. else
  2345. {
  2346. KdPrint(("NwpGetUserNameFromSid: LsaLookupSids failed: Error = %d\n",
  2347. GetLastError()));
  2348. }
  2349. #endif
  2350. LsaClose( hlsa );
  2351. }
  2352. #if DBG
  2353. else
  2354. {
  2355. KdPrint(("NwpGetUserNameFromSid: LsaOpenPolicy failed: Error = %d\n",
  2356. GetLastError()));
  2357. }
  2358. #endif
  2359. return RtlNtStatusToDosError( ntstatus );
  2360. }
  2361. DWORD
  2362. NwpGetLogonUserInfo(
  2363. LPWSTR *ppszUserSid
  2364. )
  2365. /*++
  2366. Routine Description:
  2367. Get the logon user sid string from the registry.
  2368. Arguments:
  2369. ppszUserSid - On return, this points to the current logon user
  2370. sid string.
  2371. Return Value:
  2372. The error code.
  2373. --*/
  2374. {
  2375. DWORD err;
  2376. HKEY WkstaKey;
  2377. LPWSTR CurrentUser = NULL;
  2378. //
  2379. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  2380. // \NWCWorkstation\Parameters to get the sid of the CurrentUser
  2381. //
  2382. err = RegOpenKeyExW(
  2383. HKEY_LOCAL_MACHINE,
  2384. NW_WORKSTATION_REGKEY,
  2385. REG_OPTION_NON_VOLATILE,
  2386. KEY_READ,
  2387. &WkstaKey
  2388. );
  2389. if ( err == NO_ERROR) {
  2390. //
  2391. // Read the current user SID string so that we
  2392. // know which key is the current user key to open.
  2393. //
  2394. err = NwReadRegValue(
  2395. WkstaKey,
  2396. NW_CURRENTUSER_VALUENAME,
  2397. &CurrentUser
  2398. );
  2399. RegCloseKey( WkstaKey );
  2400. if ( err == NO_ERROR) {
  2401. *ppszUserSid = CurrentUser;
  2402. }
  2403. }
  2404. return(err);
  2405. }
  2406. #define SIZE_OF_STATISTICS_TOKEN_INFORMATION \
  2407. sizeof( TOKEN_STATISTICS )
  2408. DWORD
  2409. ThreadIsInteractive(
  2410. VOID
  2411. )
  2412. /*++
  2413. Routine Description:
  2414. Determines if this is an "Interactive" logon thread
  2415. Arguments:
  2416. none
  2417. Return Value:
  2418. TRUE - Thread is interactive
  2419. FALSE - Thread is not interactive
  2420. --*/
  2421. {
  2422. HANDLE TokenHandle;
  2423. UCHAR TokenInformation[ SIZE_OF_STATISTICS_TOKEN_INFORMATION ];
  2424. WCHAR LogonIdKeyName[NW_MAX_LOGON_ID_LEN];
  2425. ULONG ReturnLength;
  2426. LUID LogonId;
  2427. LONG RegError;
  2428. HKEY InteractiveLogonKey;
  2429. HKEY OneLogonKey;
  2430. // We can use OpenThreadToken because this server thread
  2431. // is impersonating a client
  2432. if ( !OpenThreadToken( GetCurrentThread(),
  2433. TOKEN_READ,
  2434. TRUE, /* Open as self */
  2435. &TokenHandle ))
  2436. {
  2437. #if DBG
  2438. IF_DEBUG(PRINT)
  2439. KdPrint(("ThreadIsInteractive: OpenThreadToken failed: Error %d\n",
  2440. GetLastError()));
  2441. #endif
  2442. return FALSE;
  2443. }
  2444. // notice that we've allocated enough space for the
  2445. // TokenInformation structure. so if we fail, we
  2446. // return a NULL pointer indicating failure
  2447. if ( !GetTokenInformation( TokenHandle,
  2448. TokenStatistics,
  2449. TokenInformation,
  2450. sizeof( TokenInformation ),
  2451. &ReturnLength ))
  2452. {
  2453. #if DBG
  2454. IF_DEBUG(PRINT)
  2455. KdPrint(("ThreadIsInteractive: GetTokenInformation failed: Error %d\n",
  2456. GetLastError()));
  2457. #endif
  2458. return FALSE;
  2459. }
  2460. CloseHandle( TokenHandle );
  2461. LogonId = ((PTOKEN_STATISTICS)TokenInformation)->AuthenticationId;
  2462. RegError = RegOpenKeyExW(
  2463. HKEY_LOCAL_MACHINE,
  2464. NW_INTERACTIVE_LOGON_REGKEY,
  2465. REG_OPTION_NON_VOLATILE,
  2466. KEY_READ,
  2467. &InteractiveLogonKey
  2468. );
  2469. if (RegError != ERROR_SUCCESS) {
  2470. #if DBG
  2471. IF_DEBUG(PRINT)
  2472. KdPrint(("ThreadIsInteractive: RegOpenKeyExW failed: Error %d\n",
  2473. GetLastError()));
  2474. #endif
  2475. return FALSE;
  2476. }
  2477. NwLuidToWStr(&LogonId, LogonIdKeyName);
  2478. //
  2479. // Open the <LogonIdKeyName> key under Logon
  2480. //
  2481. RegError = RegOpenKeyExW(
  2482. InteractiveLogonKey,
  2483. LogonIdKeyName,
  2484. REG_OPTION_NON_VOLATILE,
  2485. KEY_READ,
  2486. &OneLogonKey
  2487. );
  2488. if ( RegError == ERROR_SUCCESS ) {
  2489. (void) RegCloseKey(OneLogonKey);
  2490. (void) RegCloseKey(InteractiveLogonKey);
  2491. return TRUE; /* We found it */
  2492. }
  2493. else {
  2494. (void) RegCloseKey(InteractiveLogonKey);
  2495. return FALSE; /* We did not find it */
  2496. }
  2497. }
  2498. DWORD
  2499. NwpCitrixGetUserInfo(
  2500. LPWSTR *ppszUserSid
  2501. )
  2502. /*++
  2503. Routine Description:
  2504. Get the user sid string of the client.
  2505. Arguments:
  2506. ppszUserSid - A pointer to buffer to store the string.
  2507. Return Value:
  2508. The error code.
  2509. --*/
  2510. {
  2511. DWORD err;
  2512. HANDLE TokenHandle;
  2513. UCHAR TokenInformation[ SIZE_OF_TOKEN_INFORMATION ];
  2514. ULONG ReturnLength;
  2515. *ppszUserSid = NULL;
  2516. // We can use OpenThreadToken because this server thread
  2517. // is impersonating a client
  2518. if ( !OpenThreadToken( GetCurrentThread(),
  2519. TOKEN_READ,
  2520. TRUE, /* Open as self */
  2521. &TokenHandle ))
  2522. {
  2523. err = GetLastError();
  2524. if ( err == ERROR_NO_TOKEN ) {
  2525. if ( !OpenProcessToken( GetCurrentProcess(),
  2526. TOKEN_READ,
  2527. &TokenHandle )) {
  2528. #if DBG
  2529. IF_DEBUG(PRINT)
  2530. KdPrint(("NwpGetThreadUserInfo: OpenThreadToken failed: Error %d\n",
  2531. GetLastError()));
  2532. #endif
  2533. return(GetLastError());
  2534. }
  2535. }
  2536. else
  2537. return( err );
  2538. }
  2539. // notice that we've allocated enough space for the
  2540. // TokenInformation structure. so if we fail, we
  2541. // return a NULL pointer indicating failure
  2542. if ( !GetTokenInformation( TokenHandle,
  2543. TokenUser,
  2544. TokenInformation,
  2545. sizeof( TokenInformation ),
  2546. &ReturnLength ))
  2547. {
  2548. #if DBG
  2549. IF_DEBUG(PRINT)
  2550. KdPrint(("NwpGetThreadUserInfo: GetTokenInformation failed: Error %d\n",
  2551. GetLastError()));
  2552. #endif
  2553. return(GetLastError());
  2554. }
  2555. CloseHandle( TokenHandle );
  2556. // convert the Sid (pointed to by pSid) to its
  2557. // equivalent Unicode string representation.
  2558. err = NwpConvertSid( ((PTOKEN_USER)TokenInformation)->User.Sid,
  2559. ppszUserSid );
  2560. if ( err )
  2561. {
  2562. if ( *ppszUserSid )
  2563. LocalFree( *ppszUserSid );
  2564. }
  2565. return err;
  2566. }