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.

3292 lines
88 KiB

  1. /*++
  2. Copyright (c) 1990-1994 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. printer.c
  6. Abstract:
  7. Author:
  8. Environment:
  9. User Mode -Win32
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include "local.h"
  15. #include "clusrout.h"
  16. #include <offsets.h>
  17. WCHAR szNoCache[] = L",NoCache";
  18. WCHAR szProvidorValue[] = L"Provider";
  19. WCHAR szRegistryConnections[] = L"Printers\\Connections";
  20. WCHAR szServerValue[] = L"Server";
  21. WCHAR szWin32spl[] = L"win32spl.dll";
  22. //
  23. // Router Cache Table
  24. //
  25. DWORD RouterCacheSize;
  26. PROUTERCACHE RouterCacheTable;
  27. CRITICAL_SECTION RouterCriticalSection;
  28. //
  29. // Forward prototypes
  30. //
  31. BOOL
  32. EnumerateConnectedPrinters(
  33. LPBYTE pPrinter,
  34. DWORD cbBuf,
  35. LPDWORD pcbNeeded,
  36. LPDWORD pcReturned,
  37. HKEY hKeyUser);
  38. PPRINTER_INFO_2
  39. pGetPrinterInfo2(
  40. HANDLE hPrinter
  41. );
  42. BOOL
  43. SavePrinterConnectionInRegistry(
  44. PPRINTER_INFO_2 pPrinterInfo2,
  45. LPPROVIDOR pProvidor
  46. );
  47. BOOL
  48. RemovePrinterConnectionInRegistry(
  49. LPWSTR pName);
  50. DWORD
  51. FindClosePrinterChangeNotificationWorker(
  52. HANDLE hPrinter);
  53. VOID
  54. RundownPrinterNotify(
  55. HANDLE hNotify);
  56. BOOL
  57. EnumPrintersW(
  58. DWORD Flags,
  59. LPWSTR Name,
  60. DWORD Level,
  61. LPBYTE pPrinterEnum,
  62. DWORD cbBuf,
  63. LPDWORD pcbNeeded,
  64. LPDWORD pcReturned)
  65. {
  66. DWORD cReturned, cbStruct, cbNeeded;
  67. DWORD TotalcbNeeded = 0;
  68. DWORD cTotalReturned = 0;
  69. DWORD Error = ERROR_SUCCESS;
  70. PROVIDOR *pProvidor;
  71. DWORD BufferSize=cbBuf;
  72. HKEY hKeyUser;
  73. BOOL bPartialSuccess = FALSE;
  74. if (pPrinterEnum==NULL && cbBuf!=0)
  75. {
  76. SetLastError(ERROR_INVALID_USER_BUFFER);
  77. return FALSE;
  78. }
  79. WaitForSpoolerInitialization();
  80. switch (Level)
  81. {
  82. case STRESSINFOLEVEL:
  83. cbStruct = sizeof(PRINTER_INFO_STRESS);
  84. break;
  85. case 1:
  86. cbStruct = sizeof(PRINTER_INFO_1);
  87. break;
  88. case 2:
  89. cbStruct = sizeof(PRINTER_INFO_2);
  90. break;
  91. case 4:
  92. cbStruct = sizeof(PRINTER_INFO_4);
  93. break;
  94. case 5:
  95. cbStruct = sizeof(PRINTER_INFO_5);
  96. break;
  97. default:
  98. SetLastError(ERROR_INVALID_LEVEL);
  99. return FALSE;
  100. }
  101. if (Level==4 && (Flags & PRINTER_ENUM_CONNECTIONS))
  102. {
  103. //
  104. // The router will handle info level_4 for connected printers.
  105. //
  106. Flags &= ~PRINTER_ENUM_CONNECTIONS;
  107. if (hKeyUser = GetClientUserHandle(KEY_READ))
  108. {
  109. if (!EnumerateConnectedPrinters(pPrinterEnum,
  110. BufferSize,
  111. &TotalcbNeeded,
  112. &cTotalReturned,
  113. hKeyUser))
  114. {
  115. Error = GetLastError();
  116. }
  117. else
  118. {
  119. bPartialSuccess = TRUE;
  120. }
  121. RegCloseKey(hKeyUser);
  122. }
  123. else
  124. {
  125. Error = GetLastError();
  126. }
  127. pPrinterEnum += cTotalReturned * cbStruct;
  128. if (TotalcbNeeded <= BufferSize)
  129. BufferSize -= TotalcbNeeded;
  130. else
  131. BufferSize = 0;
  132. }
  133. for (pProvidor = pLocalProvidor; pProvidor; )
  134. {
  135. cReturned = 0;
  136. cbNeeded = 0;
  137. if (!(*pProvidor->PrintProvidor.fpEnumPrinters) (Flags, Name, Level,
  138. pPrinterEnum,
  139. BufferSize,
  140. &cbNeeded,
  141. &cReturned))
  142. {
  143. Error = GetLastError();
  144. if (Error==ERROR_INSUFFICIENT_BUFFER)
  145. {
  146. TotalcbNeeded += cbNeeded;
  147. BufferSize = 0;
  148. }
  149. }
  150. else
  151. {
  152. bPartialSuccess = TRUE;
  153. TotalcbNeeded += cbNeeded;
  154. cTotalReturned += cReturned;
  155. pPrinterEnum += cReturned * cbStruct;
  156. BufferSize -= cbNeeded;
  157. }
  158. if ((Flags & PRINTER_ENUM_NAME) && Name && (Error!=ERROR_INVALID_NAME))
  159. pProvidor = NULL;
  160. else
  161. pProvidor = pProvidor->pNext;
  162. }
  163. *pcbNeeded = TotalcbNeeded;
  164. *pcReturned = cTotalReturned;
  165. //
  166. // Allow partial returns
  167. //
  168. if (bPartialSuccess)
  169. Error = ERROR_SUCCESS;
  170. if (TotalcbNeeded > cbBuf)
  171. Error = ERROR_INSUFFICIENT_BUFFER;
  172. SetLastError(Error);
  173. return Error==ERROR_SUCCESS;
  174. }
  175. BOOL
  176. EnumerateConnectedPrinters(
  177. LPBYTE pPrinter,
  178. DWORD cbBuf,
  179. LPDWORD pcbNeeded,
  180. LPDWORD pcReturned,
  181. HKEY hClientKey
  182. )
  183. /*++
  184. Routine Description:
  185. Handles info level four enumeration.
  186. Arguments:
  187. Return Value:
  188. --*/
  189. {
  190. HKEY hKey1=NULL;
  191. HKEY hKeyPrinter;
  192. DWORD cPrinters, cchData;
  193. WCHAR PrinterName[MAX_UNC_PRINTER_NAME];
  194. WCHAR ServerName[MAX_UNC_PRINTER_NAME];
  195. DWORD cReturned, cbRequired, cbNeeded, cTotalReturned;
  196. DWORD Error=0;
  197. PWCHAR p;
  198. LPBYTE pEnd;
  199. DWORD cbSize;
  200. BOOL bInsufficientBuffer = FALSE;
  201. if((Error = RegOpenKeyEx(hClientKey, szRegistryConnections, 0,
  202. KEY_READ, &hKey1))!=ERROR_SUCCESS)
  203. {
  204. SetLastError(Error);
  205. return(FALSE);
  206. }
  207. cPrinters=0;
  208. cchData = COUNTOF(PrinterName);
  209. cTotalReturned = 0;
  210. cReturned = cbNeeded = 0;
  211. cbRequired = 0;
  212. pEnd = pPrinter + cbBuf;
  213. while (RegEnumKeyEx(hKey1, cPrinters, PrinterName, &cchData,
  214. NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
  215. //
  216. // Fetch server name. Open the key and read it
  217. // from the "Server" field.
  218. //
  219. Error = RegOpenKeyEx(hKey1,
  220. PrinterName,
  221. 0,
  222. KEY_READ,
  223. &hKeyPrinter);
  224. if( Error == ERROR_SUCCESS ){
  225. cbSize = sizeof(ServerName);
  226. Error = RegQueryValueEx(hKeyPrinter,
  227. szServerValue,
  228. NULL,
  229. NULL,
  230. (LPBYTE)ServerName,
  231. &cbSize);
  232. RegCloseKey(hKeyPrinter);
  233. }
  234. if( Error == ERROR_SUCCESS ){
  235. //
  236. // Force NULL termination of ServerName.
  237. //
  238. ServerName[COUNTOF(ServerName)-1] = 0;
  239. } else {
  240. //
  241. // On error condition, try and extract the server name
  242. // based on the printer name. Pretty ugly...
  243. //
  244. wcscpy(ServerName, PrinterName);
  245. p = wcschr(ServerName+2, ',');
  246. if (p)
  247. *p = 0;
  248. }
  249. FormatRegistryKeyForPrinter(PrinterName, PrinterName);
  250. if (MyUNCName(PrinterName)) // don't enumerate local printers!
  251. {
  252. cPrinters++;
  253. cchData = COUNTOF(PrinterName);
  254. continue;
  255. }
  256. //
  257. // At this stage we don't care about opening the printers
  258. // We just want to enumerate the names; in effect we're
  259. // just reading HKEY_CURRENT_USER and returning the
  260. // contents; we will copy the name of the printer and we will
  261. // set its attributes to NETWORK and !LOCAL
  262. //
  263. cbRequired = sizeof(PRINTER_INFO_4) +
  264. wcslen(PrinterName)*sizeof(WCHAR) + sizeof(WCHAR) +
  265. wcslen(ServerName)*sizeof(WCHAR) + sizeof(WCHAR);
  266. if (cbBuf >= cbRequired) {
  267. //
  268. // copy it in
  269. //
  270. DBGMSG(DBG_TRACE,
  271. ("cbBuf %d cbRequired %d PrinterName %ws\n", cbBuf, cbRequired, PrinterName));
  272. pEnd = CopyPrinterNameToPrinterInfo4(ServerName,
  273. PrinterName,
  274. pPrinter,
  275. pEnd);
  276. //
  277. // Fill in any in structure contents
  278. //
  279. pPrinter += sizeof(PRINTER_INFO_4);
  280. //
  281. // Increment the count of structures copied
  282. //
  283. cTotalReturned++;
  284. //
  285. // Reduce the size of the buffer by amount required
  286. //
  287. cbBuf -= cbRequired;
  288. //
  289. // Keep track of the total ammount required.
  290. //
  291. } else {
  292. cbBuf = 0;
  293. bInsufficientBuffer = TRUE;
  294. }
  295. cbNeeded += cbRequired;
  296. cPrinters++;
  297. cchData = COUNTOF(PrinterName);
  298. }
  299. RegCloseKey(hKey1);
  300. *pcbNeeded = cbNeeded;
  301. *pcReturned = cTotalReturned;
  302. if (bInsufficientBuffer) {
  303. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  304. return FALSE;
  305. }
  306. return TRUE;
  307. }
  308. LPBYTE
  309. CopyPrinterNameToPrinterInfo4(
  310. LPWSTR pServerName,
  311. LPWSTR pPrinterName,
  312. LPBYTE pPrinter,
  313. LPBYTE pEnd)
  314. {
  315. LPWSTR SourceStrings[sizeof(PRINTER_INFO_4)/sizeof(LPWSTR)];
  316. LPWSTR *pSourceStrings=SourceStrings;
  317. LPPRINTER_INFO_4 pPrinterInfo=(LPPRINTER_INFO_4)pPrinter;
  318. DWORD *pOffsets;
  319. pOffsets = PrinterInfo4Strings;
  320. *pSourceStrings++=pPrinterName;
  321. *pSourceStrings++=pServerName;
  322. pEnd = PackStrings(SourceStrings,
  323. (LPBYTE) pPrinterInfo,
  324. pOffsets,
  325. pEnd);
  326. pPrinterInfo->Attributes = PRINTER_ATTRIBUTE_NETWORK;
  327. return pEnd;
  328. }
  329. LPPROVIDOR
  330. FindProvidorFromConnection(
  331. LPWSTR pszPrinter
  332. )
  333. /*++
  334. Routine Description:
  335. Looks in the current user's Printer\Connections to see if a printer
  336. is there, and returns which provider that owns it.
  337. Note: this will always fail if the pszPrinter is a share name.
  338. Arguments:
  339. pszPrinter - Printer to search.
  340. Return Value:
  341. pProvidor - Provider that own's it.
  342. NULL - none found.
  343. --*/
  344. {
  345. PWCHAR pszKey = NULL;
  346. DWORD cchSize = MAX_UNC_PRINTER_NAME + COUNTOF( szRegistryConnections );
  347. WCHAR szProvidor[MAX_PATH];
  348. DWORD cbProvidor;
  349. LPWSTR pszKeyPrinter;
  350. LONG Status;
  351. LPPROVIDOR pProvidor = NULL;
  352. HKEY hKeyClient = NULL;
  353. HKEY hKeyPrinter = NULL;
  354. SPLASSERT(pszPrinter);
  355. if ( pszPrinter && wcslen(pszPrinter) + 1 < MAX_UNC_PRINTER_NAME ) {
  356. if(pszKey = AllocSplMem(cchSize * sizeof(WCHAR))) {
  357. //
  358. // Prepare to read in
  359. // HKEY_CURRENT_USER:\Printer\Connections\,,server,printer
  360. //
  361. wcscpy( pszKey, szRegistryConnections );
  362. //
  363. // Find the end of this key so we can append the registry-formatted
  364. // printer name to it.
  365. //
  366. pszKeyPrinter = &pszKey[ COUNTOF( szRegistryConnections ) - 1 ];
  367. *pszKeyPrinter++ = L'\\';
  368. FormatPrinterForRegistryKey( pszPrinter, pszKeyPrinter );
  369. if( hKeyClient = GetClientUserHandle(KEY_READ)){
  370. Status = RegOpenKeyEx( hKeyClient,
  371. pszKey,
  372. 0,
  373. KEY_READ,
  374. &hKeyPrinter );
  375. if( Status == ERROR_SUCCESS ){
  376. cbProvidor = sizeof( szProvidor );
  377. Status = RegQueryValueEx( hKeyPrinter,
  378. szProvidorValue,
  379. NULL,
  380. NULL,
  381. (LPBYTE)szProvidor,
  382. &cbProvidor );
  383. if( Status == ERROR_SUCCESS ){
  384. //
  385. // Scan through all providers, trying to match dll string.
  386. //
  387. for( pProvidor = pLocalProvidor; pProvidor; pProvidor = pProvidor->pNext ){
  388. if( !_wcsicmp( pProvidor->lpName, szProvidor )){
  389. break;
  390. }
  391. }
  392. }
  393. RegCloseKey( hKeyPrinter );
  394. }
  395. RegCloseKey( hKeyClient );
  396. }
  397. FreeSplMem(pszKey);
  398. }
  399. }
  400. return pProvidor;
  401. }
  402. VOID
  403. UpdateSignificantError(
  404. DWORD dwNewError,
  405. PDWORD pdwOldError
  406. )
  407. /*++
  408. Routine Description:
  409. Determines whether the new error code is more "important"
  410. than the previous one in cases where we continue routing.
  411. Arguments:
  412. dwNewError - New error code that occurred.
  413. pdwOldError - Pointer to previous significant error.
  414. This is updated if a significant error occurs
  415. Return Value:
  416. --*/
  417. {
  418. //
  419. // Error code must be non-zero or else it will look
  420. // like success.
  421. //
  422. SPLASSERT(dwNewError);
  423. //
  424. // If we have no significant error yet and we have one now,
  425. // keep it.
  426. //
  427. if (*pdwOldError == ERROR_INVALID_NAME &&
  428. dwNewError &&
  429. dwNewError != WN_BAD_NETNAME &&
  430. dwNewError != ERROR_BAD_NETPATH &&
  431. dwNewError != ERROR_NOT_SUPPORTED &&
  432. dwNewError != ERROR_REM_NOT_LIST &&
  433. dwNewError != ERROR_INVALID_LEVEL &&
  434. dwNewError != ERROR_INVALID_PARAMETER &&
  435. dwNewError != ERROR_INVALID_NAME &&
  436. dwNewError != WN_BAD_LOCALNAME) {
  437. *pdwOldError = dwNewError;
  438. }
  439. return;
  440. }
  441. BOOL
  442. OpenPrinterPortW(
  443. LPWSTR pPrinterName,
  444. HANDLE *pHandle,
  445. LPPRINTER_DEFAULTS pDefault
  446. )
  447. /*++
  448. Routine Description:
  449. This routine is exactly the same as OpenPrinterW,
  450. except that it doesn't call the local provider.
  451. This is so that the local provider can open a network printer
  452. with the same name as the local printer without getting
  453. into a loop.
  454. Arguments:
  455. Return Value:
  456. --*/
  457. {
  458. //
  459. // We will set bLocalPrintProvidor = FALSE here
  460. //
  461. return(RouterOpenPrinterW(pPrinterName,
  462. pHandle,
  463. pDefault,
  464. NULL,
  465. 0,
  466. FALSE));
  467. }
  468. BOOL
  469. OpenPrinterW(
  470. LPWSTR pPrinterName,
  471. HANDLE *pHandle,
  472. LPPRINTER_DEFAULTS pDefault
  473. )
  474. {
  475. //
  476. // We will set bLocalPrintProvidor = TRUE here
  477. //
  478. return(RouterOpenPrinterW(pPrinterName,
  479. pHandle,
  480. pDefault,
  481. NULL,
  482. 0,
  483. TRUE));
  484. }
  485. BOOL
  486. OpenPrinterExW(
  487. LPWSTR pPrinterName,
  488. HANDLE *pHandle,
  489. LPPRINTER_DEFAULTS pDefault,
  490. PSPLCLIENT_CONTAINER pSplClientContainer
  491. )
  492. {
  493. BOOL bReturn = FALSE;
  494. DWORD dwLevel = 0;
  495. if (pSplClientContainer) {
  496. dwLevel = pSplClientContainer->Level;
  497. }
  498. //
  499. // We will set bLocalPrintProvidor = TRUE here
  500. //
  501. switch (dwLevel) {
  502. case 1:
  503. bReturn = RouterOpenPrinterW(pPrinterName,
  504. pHandle,
  505. pDefault,
  506. (LPBYTE) (pSplClientContainer->ClientInfo.pClientInfo1),
  507. 1,
  508. TRUE);
  509. break;
  510. case 2:
  511. bReturn = RouterOpenPrinterW(pPrinterName,
  512. pHandle,
  513. pDefault,
  514. NULL,
  515. 0,
  516. TRUE);
  517. if (pSplClientContainer) {
  518. if (bReturn) {
  519. pSplClientContainer->ClientInfo.pClientInfo2->hSplPrinter = (ULONG_PTR) *pHandle;
  520. } else {
  521. pSplClientContainer->ClientInfo.pClientInfo2->hSplPrinter = 0;
  522. }
  523. }
  524. break;
  525. default:
  526. break;
  527. }
  528. return bReturn;
  529. }
  530. DWORD
  531. TryOpenPrinterAndCache(
  532. LPPROVIDOR pProvidor,
  533. LPWSTR pszPrinterName,
  534. PHANDLE phPrinter,
  535. LPPRINTER_DEFAULTS pDefault,
  536. PDWORD pdwFirstSignificantError,
  537. LPBYTE pSplClientInfo,
  538. DWORD dwLevel
  539. )
  540. /*++
  541. Routine Description:
  542. Attempt to open the printer using the providor. If there is
  543. an error, update the dwFirstSignificantError variable. If the
  544. providor "knows" the printer (either a success, or ROUTER_STOP_ROUTING),
  545. then update the cache.
  546. Arguments:
  547. pProvidor - Providor to try
  548. pszPrinterName - Name of printer that will be sent to the providor
  549. phPrinter - Receives printer handle on ROUTER_SUCCESS
  550. pDefault - Defaults used to open printer
  551. pdwFirstSignificantError - Pointer to DWORD to get updated error.
  552. This gets updated on ROUTER_STOP_ROUTING or ROUTER_UNKNOWN.
  553. Return Value:
  554. ROUTER_* status code:
  555. ROUTER_SUCCESS, phPrinter holds return handle, name cached
  556. ROUTER_UNKNOWN, printer not recognized, error updated
  557. ROUTER_STOP_ROUTING, printer recognized, but failure, error updated
  558. --*/
  559. {
  560. DWORD OpenError;
  561. OpenError = (*pProvidor->PrintProvidor.fpOpenPrinterEx)
  562. (pszPrinterName,
  563. phPrinter,
  564. pDefault,
  565. pSplClientInfo,
  566. dwLevel);
  567. if (( OpenError == ROUTER_UNKNOWN && GetLastError() == ERROR_NOT_SUPPORTED ) ||
  568. OpenError == ERROR_NOT_SUPPORTED )
  569. OpenError = (*pProvidor->PrintProvidor.fpOpenPrinter)
  570. (pszPrinterName,
  571. phPrinter,
  572. pDefault);
  573. if( OpenError == ROUTER_SUCCESS ||
  574. OpenError == ROUTER_STOP_ROUTING ){
  575. //
  576. // Now add this entry into the cache. We never cache
  577. // the local providor.
  578. //
  579. EnterRouterSem();
  580. if (!FindEntryinRouterCache(pszPrinterName)) {
  581. AddEntrytoRouterCache(pszPrinterName, pProvidor);
  582. }
  583. LeaveRouterSem();
  584. }
  585. if( OpenError != ROUTER_SUCCESS ){
  586. UpdateSignificantError(GetLastError(), pdwFirstSignificantError);
  587. }
  588. return OpenError;
  589. }
  590. BOOL
  591. RouterOpenPrinterW(
  592. LPWSTR pszPrinterNameIn,
  593. HANDLE *pHandle,
  594. LPPRINTER_DEFAULTS pDefault,
  595. LPBYTE pSplClientInfo,
  596. DWORD dwLevel,
  597. BOOL bLocalProvidor
  598. )
  599. /*++
  600. Routine Description:
  601. Routes the OpenPrinter{Port} call. This checks the local providor
  602. first (if bLocalProvidor TRUE), the the cache, and finally all the
  603. non-local providors.
  604. To open a printer, the following steps are taken:
  605. 1. Check localspl
  606. This must be done to ensure that masq printers are handled
  607. correctly (see comment below in code).
  608. 2. Check cache
  609. This will speed up most of the connections, since OpenPrinters
  610. tend to be clumped together.
  611. 3. Check registry under connections
  612. If this is a connected printer, first try the providor
  613. that granted the connection.
  614. 4. Check provider order
  615. This is the last resort, since it is the slowest.
  616. Arguments:
  617. pPrinterName - Name of printer to open
  618. pHandle - Handle to receive open printer. If the open was not
  619. successful, this value may be modified!
  620. pDefault - Default attributes of the open.
  621. pSplClientInfo - Pointer ClientInfox structure
  622. dwLevel - Level of the ClientInfo structure
  623. bLocalProvidor TRUE = OpenPrinterW called, check localspl first.
  624. FALSE = OpenPrinterPortW called, don't check localspl.
  625. Return Value:
  626. TRUE = success
  627. FALSE = fail, GetLastError indicates error (must be non-zero!)
  628. --*/
  629. {
  630. BOOL bReturn = TRUE;
  631. DWORD dwFirstSignificantError = ERROR_INVALID_NAME;
  632. LPPROVIDOR pProvidor;
  633. LPPROVIDOR pProvidorAlreadyTried = NULL;
  634. PPRINTHANDLE pPrintHandle;
  635. HANDLE hPrinter;
  636. DWORD OpenError;
  637. BOOL bRemoveFromCache = FALSE;
  638. PRINTER_DEFAULTS Default;
  639. PDEVMODE pDevModeFree = NULL;
  640. PWSTR pszPrinterName = pszPrinterNameIn;
  641. PWSTR pszNoCache;
  642. //
  643. // Max name we allow for printers is MAX_UNC_PRINTER_NAME.
  644. // Providers can use suffixes only for OpenPrinter (not for Add/Set)
  645. //
  646. if ( pszPrinterName &&
  647. wcslen(pszPrinterName) + 1 > MAX_UNC_PRINTER_NAME + PRINTER_NAME_SUFFIX_MAX ) {
  648. SetLastError(ERROR_INVALID_PRINTER_NAME);
  649. return FALSE;
  650. }
  651. WaitForSpoolerInitialization();
  652. // There may be a ",NoCache" appended to the printer name.
  653. // We only want to send this NoCache name to win32spl, so make
  654. // a regular name here.
  655. if (pszPrinterName) {
  656. pszNoCache = wcsstr(pszPrinterNameIn, szNoCache);
  657. if (pszNoCache) {
  658. pszPrinterName = AllocSplStr(pszPrinterNameIn);
  659. if (!pszPrinterName) {
  660. DBGMSG(DBG_WARNING, ("RouterOpenPrinter - Failed to alloc pszPrinterName.\n"));
  661. return FALSE;
  662. }
  663. pszPrinterName[pszNoCache - pszPrinterNameIn] = L'\0';
  664. }
  665. }
  666. pPrintHandle = AllocSplMem(sizeof(PRINTHANDLE));
  667. if (!pPrintHandle) {
  668. DBGMSG(DBG_WARNING, ("RouterOpenPrinter - Failed to alloc print handle.\n"));
  669. if (pszPrinterName != pszPrinterNameIn) {
  670. FreeSplStr(pszPrinterName);
  671. pszPrinterName = pszPrinterNameIn;
  672. }
  673. return FALSE;
  674. }
  675. if( pszPrinterName ){
  676. pPrintHandle->pszPrinter = AllocSplStr( pszPrinterName );
  677. if (!pPrintHandle->pszPrinter) {
  678. DBGMSG(DBG_WARNING, ("RouterOpenPrinter - Failed to alloc print name.\n"));
  679. if (pszPrinterName != pszPrinterNameIn) {
  680. FreeSplStr(pszPrinterName);
  681. pszPrinterName = pszPrinterNameIn;
  682. }
  683. FreePrinterHandle( pPrintHandle );
  684. return FALSE;
  685. }
  686. }
  687. //
  688. // Retrieve the per-user DevMode. This must be done at the router
  689. // instead of the provider, since the per-user DevMode is only available
  690. // on the client. It also must be here instead of client side, since
  691. // spooler components will make this call also.
  692. //
  693. if( !pDefault || !pDefault->pDevMode ){
  694. //
  695. // No default specified--get the per-user one.
  696. //
  697. if( bGetDevModePerUser( NULL, pszPrinterName, &pDevModeFree ) &&
  698. pDevModeFree ){
  699. if( pDefault ){
  700. Default.pDatatype = pDefault->pDatatype;
  701. Default.DesiredAccess = pDefault->DesiredAccess;
  702. } else {
  703. Default.pDatatype = NULL;
  704. Default.DesiredAccess = 0;
  705. }
  706. Default.pDevMode = pDevModeFree;
  707. //
  708. // Now switch to use the temp structure.
  709. //
  710. pDefault = &Default;
  711. }
  712. }
  713. //
  714. // We must check the local print providor first in
  715. // the masquerading case.
  716. //
  717. // For example, when a Netware printer is opened:
  718. //
  719. // 1. First OpenPrinter to the Netware printer will succeed
  720. // if it has been cached.
  721. //
  722. // 2. We create a local printer masquerading as a network printer.
  723. //
  724. // 3. Second OpenPrinter must open local masquerading printer.
  725. // If we hit the cache, we will go to the Netware providor,
  726. // and we will never use the masquerading printer.
  727. //
  728. // For this reason, we will not cache local printers in the
  729. // RouterCache. The RouterCache will only containing Network
  730. // Print Providers, i.e., Win32spl NwProvAu and other such providers.
  731. //
  732. // Also, we must always check the local printprovidor since
  733. // DeletePrinter will be called on a false connect and
  734. // we need to delete the local network printer rather
  735. // than the remote printer. When we get rid of the false
  736. // connect case, we go directly to the cache.
  737. //
  738. if (bLocalProvidor) {
  739. pProvidor = pLocalProvidor;
  740. OpenError = (*pProvidor->PrintProvidor.fpOpenPrinterEx)
  741. (pszPrinterName, &hPrinter, pDefault,
  742. pSplClientInfo, dwLevel);
  743. if (OpenError == ROUTER_SUCCESS) {
  744. goto Success;
  745. }
  746. UpdateSignificantError(GetLastError(), &dwFirstSignificantError);
  747. if (OpenError == ROUTER_STOP_ROUTING) {
  748. goto StopRouting;
  749. }
  750. }
  751. //
  752. // Now check the cache.
  753. //
  754. EnterRouterSem();
  755. pProvidor = FindEntryinRouterCache(pszPrinterName);
  756. LeaveRouterSem();
  757. if (pProvidor) {
  758. OpenError = (*pProvidor->PrintProvidor.fpOpenPrinterEx)
  759. (pszPrinterName,
  760. &hPrinter,
  761. pDefault,
  762. pSplClientInfo,
  763. dwLevel);
  764. if (( OpenError == ROUTER_UNKNOWN && GetLastError() == ERROR_NOT_SUPPORTED ) ||
  765. OpenError == ERROR_NOT_SUPPORTED ){
  766. OpenError = (*pProvidor->PrintProvidor.fpOpenPrinter)
  767. (pszPrinterName,
  768. &hPrinter,
  769. pDefault);
  770. }
  771. if (OpenError == ROUTER_SUCCESS) {
  772. goto Success;
  773. }
  774. UpdateSignificantError(GetLastError(), &dwFirstSignificantError);
  775. if (OpenError == ROUTER_STOP_ROUTING) {
  776. goto StopRouting;
  777. }
  778. //
  779. // Wasn't claimed by above providor, so remove from cache.
  780. // If a providor returns ROUTER_STOP_ROUTING, then it states
  781. // that it is the sole owner of the printer name (i.e.,
  782. // it has been recognized but can't be opened, and can't
  783. // be accessed by other providors). Therefore we keep
  784. // it in the cache.
  785. //
  786. bRemoveFromCache = TRUE;
  787. //
  788. // Don't try this providor again below.
  789. //
  790. pProvidorAlreadyTried = pProvidor;
  791. }
  792. //
  793. // Not in the cache. Check if it is in the registry under
  794. // connections.
  795. //
  796. pProvidor = FindProvidorFromConnection( pszPrinterName );
  797. //
  798. // If we want to remove it from the cache, do so here. Note
  799. // we only remove it if we failed above, AND the connection wasn't
  800. // originally established using the provider.
  801. //
  802. // If the connection fails, but that provider "owns" the printer
  803. // connection, leave it in the cache since we won't try other providers.
  804. //
  805. if( bRemoveFromCache && pProvidor != pProvidorAlreadyTried ){
  806. EnterRouterSem();
  807. DeleteEntryfromRouterCache(pszPrinterName);
  808. LeaveRouterSem();
  809. }
  810. if( pProvidor ){
  811. //
  812. // If we already tried this providor, don't try it again.
  813. //
  814. if( pProvidor != pProvidorAlreadyTried ){
  815. OpenError = TryOpenPrinterAndCache( pProvidor,
  816. pszPrinterName,
  817. &hPrinter,
  818. pDefault,
  819. &dwFirstSignificantError,
  820. pSplClientInfo,
  821. dwLevel);
  822. if( OpenError == ROUTER_SUCCESS ){
  823. goto Success;
  824. }
  825. }
  826. //
  827. // We stop routing at this point! If a user wants to go with
  828. // another providor, they need to remove the connection then
  829. // re-establish it.
  830. //
  831. goto StopRouting;
  832. }
  833. //
  834. // Check all non-localspl providors.
  835. //
  836. for (pProvidor = pLocalProvidor->pNext;
  837. pProvidor;
  838. pProvidor = pProvidor->pNext) {
  839. if( pProvidor == pProvidorAlreadyTried ){
  840. //
  841. // We already tried this providor, and it failed.
  842. //
  843. continue;
  844. }
  845. // Use ",NoCache" only if Provider is win32spl
  846. OpenError = TryOpenPrinterAndCache( pProvidor,
  847. _wcsicmp(pProvidor->lpName, szWin32spl) ?
  848. pszPrinterName : pszPrinterNameIn,
  849. &hPrinter,
  850. pDefault,
  851. &dwFirstSignificantError,
  852. pSplClientInfo,
  853. dwLevel);
  854. switch( OpenError ) {
  855. case ROUTER_SUCCESS:
  856. goto Success;
  857. case ROUTER_STOP_ROUTING:
  858. goto StopRouting;
  859. }
  860. }
  861. StopRouting:
  862. //
  863. // Did not find a providor, return the error.
  864. //
  865. FreePrinterHandle( pPrintHandle );
  866. //
  867. // Set using first significant error. If there was no signifcant
  868. // error, we use ERROR_INVALID_PRINTER_NAME.
  869. //
  870. SPLASSERT(dwFirstSignificantError);
  871. if (dwFirstSignificantError == ERROR_INVALID_NAME)
  872. dwFirstSignificantError = ERROR_INVALID_PRINTER_NAME;
  873. SetLastError(dwFirstSignificantError);
  874. bReturn = FALSE;
  875. Success:
  876. if( bReturn ){
  877. pPrintHandle->signature = PRINTHANDLE_SIGNATURE;
  878. pPrintHandle->pProvidor = pProvidor;
  879. pPrintHandle->hPrinter = hPrinter;
  880. pPrintHandle->hFileSpooler = INVALID_HANDLE_VALUE;
  881. pPrintHandle->szTempSpoolFile = NULL;
  882. pPrintHandle->dwUniqueSessionID = 0;
  883. *pHandle = (HANDLE)pPrintHandle;
  884. }
  885. FreeSplMem( pDevModeFree );
  886. if (pszPrinterName != pszPrinterNameIn)
  887. FreeSplStr(pszPrinterName);
  888. return bReturn;
  889. }
  890. BOOL
  891. ResetPrinterW(
  892. HANDLE hPrinter,
  893. LPPRINTER_DEFAULTS pDefault)
  894. {
  895. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  896. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  897. SetLastError(ERROR_INVALID_HANDLE);
  898. return FALSE;
  899. }
  900. if (pDefault) {
  901. if (pDefault->pDatatype == (LPWSTR)-1 ||
  902. pDefault->pDevMode == (LPDEVMODE)-1) {
  903. if (!wcscmp(pPrintHandle->pProvidor->lpName, szLocalSplDll)) {
  904. return (*pPrintHandle->pProvidor->PrintProvidor.fpResetPrinter)
  905. (pPrintHandle->hPrinter,
  906. pDefault);
  907. } else {
  908. SetLastError(ERROR_INVALID_PARAMETER);
  909. return(FALSE);
  910. }
  911. } else {
  912. return (*pPrintHandle->pProvidor->PrintProvidor.fpResetPrinter)
  913. (pPrintHandle->hPrinter,
  914. pDefault);
  915. }
  916. } else {
  917. return (*pPrintHandle->pProvidor->PrintProvidor.fpResetPrinter)
  918. (pPrintHandle->hPrinter,
  919. pDefault);
  920. }
  921. }
  922. HANDLE
  923. AddPrinterExW(
  924. LPWSTR pName,
  925. DWORD Level,
  926. LPBYTE pPrinter,
  927. LPBYTE pClientInfo,
  928. DWORD dwLevel
  929. )
  930. {
  931. LPPROVIDOR pProvidor;
  932. DWORD dwFirstSignificantError = ERROR_INVALID_NAME;
  933. HANDLE hPrinter;
  934. PPRINTHANDLE pPrintHandle;
  935. LPWSTR pPrinterName = NULL;
  936. LPWSTR pszServer = NULL;
  937. WaitForSpoolerInitialization();
  938. if ( pPrinter ) {
  939. switch ( Level ) {
  940. case 1:
  941. pPrinterName = ((PPRINTER_INFO_1)pPrinter)->pName;
  942. break;
  943. case 2:
  944. pPrinterName = ((PPRINTER_INFO_2)pPrinter)->pPrinterName;
  945. pszServer = ((PPRINTER_INFO_2)pPrinter)->pServerName;
  946. break;
  947. default:
  948. break;
  949. }
  950. //
  951. // Name length (plus null terminator) and server
  952. // name (plus backslash) length check.
  953. //
  954. if (( pPrinterName && wcslen(pPrinterName) + 1 > MAX_PRINTER_NAME ) ||
  955. ( pszServer && wcslen(pszServer) > (MAX_UNC_PRINTER_NAME - MAX_PRINTER_NAME - 1))) {
  956. SetLastError(ERROR_INVALID_PRINTER_NAME);
  957. return FALSE;
  958. }
  959. }
  960. pPrintHandle = AllocSplMem(sizeof(PRINTHANDLE));
  961. if (!pPrintHandle) {
  962. DBGMSG( DBG_WARNING, ("Failed to alloc print handle."));
  963. goto Fail;
  964. }
  965. if( pPrinterName ){
  966. WCHAR szFullPrinterName[MAX_UNC_PRINTER_NAME];
  967. szFullPrinterName[0] = 0;
  968. if( pszServer ){
  969. wcscpy( szFullPrinterName, pszServer );
  970. wcscat( szFullPrinterName, L"\\" );
  971. }
  972. wcscat( szFullPrinterName, pPrinterName );
  973. pPrintHandle->pszPrinter = AllocSplStr( szFullPrinterName );
  974. if( !pPrintHandle->pszPrinter ){
  975. goto Fail;
  976. }
  977. }
  978. pProvidor = pLocalProvidor;
  979. while (pProvidor) {
  980. hPrinter = (HANDLE)(*pProvidor->PrintProvidor.fpAddPrinterEx)
  981. (pName,
  982. Level,
  983. pPrinter,
  984. pClientInfo,
  985. dwLevel);
  986. if ( !hPrinter && GetLastError() == ERROR_NOT_SUPPORTED ) {
  987. hPrinter = (HANDLE)(*pProvidor->PrintProvidor.fpAddPrinter)
  988. (pName,
  989. Level,
  990. pPrinter);
  991. }
  992. if ( hPrinter ) {
  993. //
  994. // CLS
  995. //
  996. // !! HACK !!
  997. //
  998. // Make (HANDLE)-1 ROUTER_STOP_ROUTING.
  999. //
  1000. if( hPrinter == (HANDLE)-1 ){
  1001. UpdateSignificantError(GetLastError(), &dwFirstSignificantError);
  1002. break;
  1003. }
  1004. pPrintHandle->signature = PRINTHANDLE_SIGNATURE;
  1005. pPrintHandle->pProvidor = pProvidor;
  1006. pPrintHandle->hPrinter = hPrinter;
  1007. pPrintHandle->hFileSpooler = INVALID_HANDLE_VALUE;
  1008. pPrintHandle->szTempSpoolFile = NULL;
  1009. pPrintHandle->dwUniqueSessionID = 0;
  1010. return (HANDLE)pPrintHandle;
  1011. }
  1012. UpdateSignificantError(GetLastError(), &dwFirstSignificantError);
  1013. pProvidor = pProvidor->pNext;
  1014. }
  1015. UpdateSignificantError(ERROR_INVALID_PRINTER_NAME, &dwFirstSignificantError);
  1016. SetLastError(dwFirstSignificantError);
  1017. Fail:
  1018. if( pPrintHandle ){
  1019. FreeSplStr( pPrintHandle->pszPrinter );
  1020. FreeSplMem(pPrintHandle);
  1021. }
  1022. return FALSE;
  1023. }
  1024. HANDLE
  1025. AddPrinterW(
  1026. LPWSTR pName,
  1027. DWORD Level,
  1028. LPBYTE pPrinter
  1029. )
  1030. {
  1031. return AddPrinterExW(pName, Level, pPrinter, NULL, 0);
  1032. }
  1033. BOOL
  1034. DeletePrinter(
  1035. HANDLE hPrinter
  1036. )
  1037. {
  1038. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  1039. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  1040. SetLastError(ERROR_INVALID_HANDLE);
  1041. return FALSE;
  1042. }
  1043. return (*pPrintHandle->pProvidor->PrintProvidor.fpDeletePrinter)(pPrintHandle->hPrinter);
  1044. }
  1045. BOOL
  1046. AddPrinterConnectionW(
  1047. LPWSTR pName
  1048. )
  1049. {
  1050. DWORD dwLastError;
  1051. HANDLE hPrinter;
  1052. HKEY hClientKey = NULL;
  1053. BOOL rc = FALSE;
  1054. LPPRINTER_INFO_2 pPrinterInfo2;
  1055. LPPRINTHANDLE pPrintHandle;
  1056. WaitForSpoolerInitialization();
  1057. //
  1058. // If the printer connection being made is \\server\sharename,
  1059. // this may be different from the \\server\printername.
  1060. // Make sure we have the real name, so that we can be consistent
  1061. // in the registry.
  1062. //
  1063. if (!OpenPrinter(pName,
  1064. &hPrinter,
  1065. NULL)) {
  1066. return FALSE;
  1067. }
  1068. pPrinterInfo2 = pGetPrinterInfo2( hPrinter );
  1069. pPrintHandle = (LPPRINTHANDLE)hPrinter;
  1070. if( pPrinterInfo2 ){
  1071. if ((*pPrintHandle->pProvidor->PrintProvidor.
  1072. fpAddPrinterConnection)(pPrinterInfo2->pPrinterName)) {
  1073. if( SavePrinterConnectionInRegistry(
  1074. pPrinterInfo2,
  1075. pPrintHandle->pProvidor )){
  1076. rc = TRUE;
  1077. } else {
  1078. dwLastError = GetLastError();
  1079. (*pPrintHandle->pProvidor->PrintProvidor.
  1080. fpDeletePrinterConnection)(pPrinterInfo2->pPrinterName);
  1081. SetLastError(dwLastError);
  1082. }
  1083. }
  1084. FreeSplMem(pPrinterInfo2);
  1085. }
  1086. dwLastError = GetLastError();
  1087. ClosePrinter(hPrinter);
  1088. SetLastError(dwLastError);
  1089. return rc;
  1090. }
  1091. BOOL
  1092. DeletePrinterConnectionW(
  1093. LPWSTR pName
  1094. )
  1095. {
  1096. BOOL bRet = FALSE;
  1097. BOOL bDone = FALSE;
  1098. HANDLE hPrinter;
  1099. //
  1100. // If pName is empty string, all providers will fail with ERROR_INVALID_NAME
  1101. // and we will delete the registry key. For empty string, it will
  1102. // delete all subkeys under Printers\\Connections. Fix it by checking
  1103. // pName against empty string.
  1104. //
  1105. if (pName && *pName)
  1106. {
  1107. WaitForSpoolerInitialization();
  1108. //
  1109. // Adding the code required to succeed DeletePrinterConnection
  1110. // with a Share name
  1111. //
  1112. if(OpenPrinter(pName,&hPrinter,NULL))
  1113. {
  1114. DWORD PrntrInfoSize=0,PrntrInfoSizeReq=0;
  1115. PPRINTER_INFO_2 pPrinterInfo2 = NULL;
  1116. if(!GetPrinter(hPrinter,
  1117. 2,
  1118. (LPBYTE)pPrinterInfo2,
  1119. PrntrInfoSize,
  1120. &PrntrInfoSizeReq) &&
  1121. (GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
  1122. (pPrinterInfo2 = (PPRINTER_INFO_2)AllocSplMem((PrntrInfoSize = PrntrInfoSizeReq))) &&
  1123. GetPrinter(hPrinter,
  1124. 2,
  1125. (LPBYTE)pPrinterInfo2,
  1126. PrntrInfoSize,
  1127. &PrntrInfoSizeReq))
  1128. {
  1129. PPRINTHANDLE pPrintHandle;
  1130. pPrintHandle = (PPRINTHANDLE)hPrinter;
  1131. if((bRet = (*pPrintHandle->
  1132. pProvidor->
  1133. PrintProvidor.
  1134. fpDeletePrinterConnection)(pPrinterInfo2->pPrinterName)))
  1135. {
  1136. bRet = RemovePrinterConnectionInRegistry(pPrinterInfo2->pPrinterName);
  1137. bDone = TRUE;
  1138. }
  1139. }
  1140. if(hPrinter)
  1141. ClosePrinter(hPrinter);
  1142. if(pPrinterInfo2)
  1143. FreeSplMem(pPrinterInfo2);
  1144. }
  1145. else
  1146. {
  1147. LPPROVIDOR pProvidor;
  1148. pProvidor = pLocalProvidor;
  1149. if (pName && (wcslen(pName) < MAX_PRINTER_NAME))
  1150. {
  1151. for(pProvidor=pLocalProvidor;
  1152. pProvidor && (GetLastError()!=ERROR_INVALID_NAME) &&!bDone;
  1153. pProvidor = pProvidor->pNext)
  1154. {
  1155. if(bRet = (*pProvidor->PrintProvidor.fpDeletePrinterConnection)(pName))
  1156. {
  1157. bRet = RemovePrinterConnectionInRegistry(pName);
  1158. bDone = TRUE;
  1159. }
  1160. }
  1161. }
  1162. else
  1163. {
  1164. SetLastError(ERROR_INVALID_PRINTER_NAME);
  1165. bDone = TRUE;
  1166. }
  1167. }
  1168. //
  1169. // If all providors failed with ERROR_INVALID_NAME then try to delete
  1170. // from registry
  1171. //
  1172. if(!bDone && (GetLastError()==ERROR_INVALID_NAME))
  1173. {
  1174. if(!(bRet = RemovePrinterConnectionInRegistry(pName)))
  1175. {
  1176. SetLastError(ERROR_INVALID_PRINTER_NAME);
  1177. }
  1178. }
  1179. }
  1180. else
  1181. {
  1182. SetLastError(ERROR_INVALID_PRINTER_NAME);
  1183. }
  1184. return bRet;
  1185. }
  1186. BOOL
  1187. SetPrinterW(
  1188. HANDLE hPrinter,
  1189. DWORD Level,
  1190. LPBYTE pPrinter,
  1191. DWORD Command
  1192. )
  1193. {
  1194. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  1195. LPWSTR pPrinterName = NULL;
  1196. PDEVMODE pDevModeRestore = NULL;
  1197. BOOL bReturn;
  1198. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  1199. SetLastError(ERROR_INVALID_HANDLE);
  1200. return FALSE;
  1201. }
  1202. if ( pPrinter ) {
  1203. switch (Level) {
  1204. case 2:
  1205. pPrinterName = ((PPRINTER_INFO_2)pPrinter)->pPrinterName;
  1206. break;
  1207. case 4:
  1208. pPrinterName = ((PPRINTER_INFO_4)pPrinter)->pPrinterName;
  1209. break;
  1210. case 5:
  1211. pPrinterName = ((PPRINTER_INFO_5)pPrinter)->pPrinterName;
  1212. break;
  1213. }
  1214. if ( pPrinterName &&
  1215. wcslen(pPrinterName) + 1 > MAX_PRINTER_NAME ) {
  1216. SetLastError(ERROR_INVALID_PRINTER_NAME);
  1217. return FALSE;
  1218. }
  1219. }
  1220. switch( Level ){
  1221. case 8:
  1222. {
  1223. //
  1224. // Setting the global DevMode.
  1225. //
  1226. PPRINTER_INFO_8 pPrinterInfo8 = (PPRINTER_INFO_8)pPrinter;
  1227. PPRINTER_INFO_2 pPrinterInfo2;
  1228. DWORD rc = FALSE;;
  1229. if( Command != 0 ){
  1230. SetLastError( ERROR_INVALID_PRINTER_COMMAND );
  1231. return FALSE;
  1232. }
  1233. //
  1234. // Call GetPrinter then SetPrinter.
  1235. //
  1236. pPrinterInfo2 = pGetPrinterInfo2( hPrinter );
  1237. if( pPrinterInfo2 ){
  1238. //
  1239. // Set the DevMode, and also clear the security descriptor
  1240. // so that the set will succeed.
  1241. //
  1242. pPrinterInfo2->pDevMode = pPrinterInfo8->pDevMode;
  1243. pPrinterInfo2->pSecurityDescriptor = NULL;
  1244. rc = (*pPrintHandle->pProvidor->PrintProvidor.fpSetPrinter) (
  1245. pPrintHandle->hPrinter,
  1246. 2,
  1247. (PBYTE)pPrinterInfo2,
  1248. Command );
  1249. FreeSplMem( pPrinterInfo2 );
  1250. }
  1251. return rc;
  1252. }
  1253. case 9:
  1254. {
  1255. PPRINTER_INFO_9 pPrinterInfo9 = (PPRINTER_INFO_9)pPrinter;
  1256. //
  1257. // Setting the per-user DevMode.
  1258. //
  1259. if( !pPrinter ){
  1260. SetLastError( ERROR_INVALID_PARAMETER );
  1261. return FALSE;
  1262. }
  1263. if( Command != 0 ){
  1264. SetLastError( ERROR_INVALID_PRINTER_COMMAND );
  1265. return FALSE;
  1266. }
  1267. if( !IsLocalCall( )){
  1268. SetLastError( ERROR_NOT_SUPPORTED );
  1269. return FALSE;
  1270. }
  1271. return bSetDevModePerUser( NULL,
  1272. pPrintHandle->pszPrinter,
  1273. pPrinterInfo9->pDevMode );
  1274. }
  1275. case 2:
  1276. {
  1277. PPRINTER_INFO_2 pPrinterInfo2 = (PPRINTER_INFO_2)pPrinter;
  1278. if( IsLocalCall( )){
  1279. if( pPrinterInfo2 && pPrinterInfo2->pDevMode ){
  1280. bSetDevModePerUser( NULL,
  1281. pPrintHandle->pszPrinter,
  1282. pPrinterInfo2->pDevMode );
  1283. //
  1284. // Don't set the global DevMode.
  1285. //
  1286. pDevModeRestore = pPrinterInfo2->pDevMode;
  1287. pPrinterInfo2->pDevMode = NULL;
  1288. }
  1289. }
  1290. }
  1291. default:
  1292. break;
  1293. }
  1294. bReturn = (*pPrintHandle->pProvidor->PrintProvidor.fpSetPrinter)
  1295. (pPrintHandle->hPrinter, Level, pPrinter, Command);
  1296. if( pDevModeRestore ){
  1297. ((PPRINTER_INFO_2)pPrinter)->pDevMode = pDevModeRestore;
  1298. }
  1299. return bReturn;
  1300. }
  1301. BOOL
  1302. GetPrinterW(
  1303. HANDLE hPrinter,
  1304. DWORD Level,
  1305. LPBYTE pPrinter,
  1306. DWORD cbBuf,
  1307. LPDWORD pcbNeeded
  1308. )
  1309. {
  1310. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  1311. PDEVMODE pDevModeSrc = NULL;
  1312. PDEVMODE pDevModeDest = NULL;
  1313. PDEVMODE pDevModeFree = NULL;
  1314. BOOL bCallServer = TRUE;
  1315. BOOL bReturnValue = FALSE;
  1316. PPRINTER_INFO_2 pPrinterInfo2 = NULL;
  1317. DWORD cbDevModeSrc;
  1318. DWORD Error;
  1319. DWORD cbExtraSpace2 = 0;
  1320. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  1321. SetLastError(ERROR_INVALID_HANDLE);
  1322. return FALSE;
  1323. }
  1324. if ((pPrinter == NULL) && (cbBuf != 0)) {
  1325. SetLastError(ERROR_INVALID_USER_BUFFER);
  1326. return FALSE;
  1327. }
  1328. switch( Level ){
  1329. case 2:
  1330. if( pPrintHandle->pszPrinter && IsLocalCall( )){
  1331. bGetDevModePerUser( NULL,
  1332. pPrintHandle->pszPrinter,
  1333. &pDevModeFree );
  1334. if( pDevModeFree ){
  1335. pDevModeSrc = pDevModeFree;
  1336. cbDevModeSrc = pDevModeSrc->dmSize +
  1337. pDevModeSrc->dmDriverExtra;
  1338. cbExtraSpace2 = DWORD_ALIGN_UP( cbDevModeSrc );
  1339. cbBuf = DWORD_ALIGN_DOWN( cbBuf );
  1340. }
  1341. }
  1342. break;
  1343. case 8:
  1344. {
  1345. PPRINTER_INFO_8 pPrinterInfo8 = (PPRINTER_INFO_8)pPrinter;
  1346. //
  1347. // Handle info level 8 calls for global DevModes.
  1348. //
  1349. if( !pPrintHandle->pszPrinter ){
  1350. SetLastError( ERROR_FILE_NOT_FOUND );
  1351. return FALSE;
  1352. }
  1353. bCallServer = FALSE;
  1354. *pcbNeeded = sizeof( PRINTER_INFO_8 );
  1355. //
  1356. // Call GetPrinter to get the real DevMode.
  1357. //
  1358. pPrinterInfo2 = pGetPrinterInfo2( hPrinter );
  1359. if( pPrinterInfo2 ){
  1360. //
  1361. // Pickup the DevMode from pPrinterInfo2;
  1362. // destination is after the pDevModeStructure.
  1363. // Don't need to free pDevModeSrc since it will be
  1364. // freed when pPrinterInfo2 is released.
  1365. //
  1366. pDevModeSrc = pPrinterInfo2->pDevMode;
  1367. if( pDevModeSrc ){
  1368. cbDevModeSrc = pDevModeSrc->dmSize +
  1369. pDevModeSrc->dmDriverExtra;
  1370. *pcbNeeded += cbDevModeSrc;
  1371. }
  1372. if( cbBuf < *pcbNeeded ){
  1373. //
  1374. // Not enough space. SetLastError and fall through
  1375. // to the end.
  1376. //
  1377. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  1378. } else {
  1379. bReturnValue = TRUE;
  1380. if( pDevModeSrc ){
  1381. //
  1382. // Update the pointer and indicate via pDevModeDest
  1383. // that we need to copy the DevMode in.
  1384. //
  1385. pDevModeDest = (PDEVMODE)&pPrinterInfo8[1];
  1386. pPrinterInfo8->pDevMode = pDevModeDest;
  1387. } else {
  1388. //
  1389. // No DevMode, return pointer to NULL.
  1390. //
  1391. pPrinterInfo8->pDevMode = NULL;
  1392. }
  1393. }
  1394. }
  1395. break;
  1396. }
  1397. case 9:
  1398. {
  1399. //
  1400. // Per-user DevMode. Use the client side one.
  1401. //
  1402. PPRINTER_INFO_9 pPrinterInfo9 = (PPRINTER_INFO_9)pPrinter;
  1403. if( !pPrintHandle->pszPrinter ){
  1404. SetLastError( ERROR_INVALID_HANDLE );
  1405. return FALSE;
  1406. }
  1407. if( !IsLocalCall( )){
  1408. SetLastError( ERROR_NOT_SUPPORTED );
  1409. return FALSE;
  1410. }
  1411. bCallServer = FALSE;
  1412. *pcbNeeded = sizeof( PRINTER_INFO_9 );
  1413. if( bGetDevModePerUserEvenForShares( NULL,
  1414. pPrintHandle->pszPrinter,
  1415. &pDevModeFree )){
  1416. pDevModeSrc = pDevModeFree;
  1417. if( pDevModeSrc ){
  1418. cbDevModeSrc = pDevModeSrc->dmSize +
  1419. pDevModeSrc->dmDriverExtra;
  1420. *pcbNeeded += cbDevModeSrc;
  1421. }
  1422. }
  1423. if( cbBuf < *pcbNeeded ){
  1424. //
  1425. // Not enough space. We'll fall through below
  1426. // and fail.
  1427. //
  1428. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  1429. } else {
  1430. bReturnValue = TRUE;
  1431. if( pDevModeSrc ){
  1432. pDevModeDest = (PDEVMODE)&pPrinterInfo9[1];
  1433. pPrinterInfo9->pDevMode = pDevModeDest;
  1434. } else {
  1435. //
  1436. // No per-user DevMode. Return SUCCESS, but indicate
  1437. // no DevMode available.
  1438. //
  1439. pPrinterInfo9->pDevMode = NULL;
  1440. }
  1441. }
  1442. break;
  1443. }
  1444. default:
  1445. break;
  1446. }
  1447. if( bCallServer ){
  1448. DWORD cbAvailable;
  1449. //
  1450. // Allocate extra space at the end for the per-user DevMode,
  1451. // in case there isn't a global devmode in the printer info 2
  1452. // structure.
  1453. //
  1454. cbAvailable = ( cbBuf >= cbExtraSpace2 ) ?
  1455. cbBuf - cbExtraSpace2 :
  1456. 0;
  1457. bReturnValue = (*pPrintHandle->pProvidor->PrintProvidor.fpGetPrinter)
  1458. (pPrintHandle->hPrinter, Level, pPrinter,
  1459. cbAvailable, pcbNeeded);
  1460. *pcbNeeded += cbExtraSpace2;
  1461. }
  1462. Error = GetLastError();
  1463. if( Level == 9 && pDevModeSrc == NULL){
  1464. PPRINTER_INFO_2 pInfo2 = (PPRINTER_INFO_2)pPrinter;
  1465. if( pInfo2 && pInfo2->pDevMode ){
  1466. pDevModeSrc = pInfo2->pDevMode;
  1467. }
  1468. }
  1469. //
  1470. // Special case INFO level 2, since we want to get the provider's
  1471. // information, but then we also want the per-user DevMode.
  1472. //
  1473. // Only do this for local calls.
  1474. //
  1475. if( cbExtraSpace2 ){
  1476. PPRINTER_INFO_2 pInfo2 = (PPRINTER_INFO_2)pPrinter;
  1477. //
  1478. // If we succeeded and we have a buffer, then we need to check if we
  1479. // need to put the per-user DevMode at the end of the buffer.
  1480. //
  1481. if( pInfo2 && bReturnValue ){
  1482. //
  1483. // If we have no DevMode, or it's compatible, then we want to
  1484. // use the per-user DevMode.
  1485. //
  1486. if( !pInfo2->pDevMode ||
  1487. bCompatibleDevMode( pPrintHandle,
  1488. pInfo2->pDevMode,
  1489. pDevModeSrc )){
  1490. pDevModeDest = (PDEVMODE)(pPrinter + cbBuf - cbExtraSpace2 );
  1491. pInfo2->pDevMode = pDevModeDest;
  1492. } else {
  1493. //
  1494. // !! POLICY !!
  1495. //
  1496. // Not compatible with per-user DevMode. Delete the
  1497. // per-user one.
  1498. //
  1499. bSetDevModePerUser( NULL, pPrintHandle->pszPrinter, NULL );
  1500. }
  1501. }
  1502. }
  1503. //
  1504. // Check if we need to copy over a DevMode.
  1505. //
  1506. if( pDevModeDest ){
  1507. //
  1508. // Update the DevMode.
  1509. //
  1510. CopyMemory( (PVOID)pDevModeDest,
  1511. (PVOID)pDevModeSrc,
  1512. cbDevModeSrc );
  1513. bReturnValue = TRUE;
  1514. }
  1515. FreeSplMem( pDevModeFree );
  1516. FreeSplMem( pPrinterInfo2 );
  1517. SetLastError( Error );
  1518. return bReturnValue;
  1519. }
  1520. DWORD
  1521. GetPrinterDataW(
  1522. HANDLE hPrinter,
  1523. LPWSTR pValueName,
  1524. LPDWORD pType,
  1525. LPBYTE pData,
  1526. DWORD nSize,
  1527. LPDWORD pcbNeeded
  1528. )
  1529. {
  1530. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  1531. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  1532. SetLastError(ERROR_INVALID_HANDLE);
  1533. return FALSE;
  1534. }
  1535. return (*pPrintHandle->pProvidor->PrintProvidor.fpGetPrinterData)(pPrintHandle->hPrinter,
  1536. pValueName,
  1537. pType,
  1538. pData,
  1539. nSize,
  1540. pcbNeeded);
  1541. }
  1542. DWORD
  1543. GetPrinterDataExW(
  1544. HANDLE hPrinter,
  1545. LPCWSTR pKeyName,
  1546. LPCWSTR pValueName,
  1547. LPDWORD pType,
  1548. LPBYTE pData,
  1549. DWORD nSize,
  1550. LPDWORD pcbNeeded
  1551. )
  1552. {
  1553. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  1554. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  1555. SetLastError(ERROR_INVALID_HANDLE);
  1556. return FALSE;
  1557. }
  1558. return (*pPrintHandle->pProvidor->PrintProvidor.fpGetPrinterDataEx)(pPrintHandle->hPrinter,
  1559. pKeyName,
  1560. pValueName,
  1561. pType,
  1562. pData,
  1563. nSize,
  1564. pcbNeeded);
  1565. }
  1566. DWORD
  1567. EnumPrinterDataW(
  1568. HANDLE hPrinter,
  1569. DWORD dwIndex, // index of value to query
  1570. LPWSTR pValueName, // address of buffer for value string
  1571. DWORD cbValueName, // size of buffer for value string
  1572. LPDWORD pcbValueName, // address for size of value buffer
  1573. LPDWORD pType, // address of buffer for type code
  1574. LPBYTE pData, // address of buffer for value data
  1575. DWORD cbData, // size of buffer for value data
  1576. LPDWORD pcbData // address for size of data buffer
  1577. )
  1578. {
  1579. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  1580. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  1581. SetLastError(ERROR_INVALID_HANDLE);
  1582. return FALSE;
  1583. }
  1584. return (*pPrintHandle->pProvidor->PrintProvidor.fpEnumPrinterData)(pPrintHandle->hPrinter,
  1585. dwIndex,
  1586. pValueName,
  1587. cbValueName,
  1588. pcbValueName,
  1589. pType,
  1590. pData,
  1591. cbData,
  1592. pcbData);
  1593. }
  1594. DWORD
  1595. EnumPrinterDataExW(
  1596. HANDLE hPrinter,
  1597. LPCWSTR pKeyName, // address of key name
  1598. LPBYTE pEnumValues,
  1599. DWORD cbEnumValues,
  1600. LPDWORD pcbEnumValues,
  1601. LPDWORD pnEnumValues
  1602. )
  1603. {
  1604. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  1605. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  1606. SetLastError(ERROR_INVALID_HANDLE);
  1607. return FALSE;
  1608. }
  1609. return (*pPrintHandle->pProvidor->PrintProvidor.fpEnumPrinterDataEx)(pPrintHandle->hPrinter,
  1610. pKeyName,
  1611. pEnumValues,
  1612. cbEnumValues,
  1613. pcbEnumValues,
  1614. pnEnumValues);
  1615. }
  1616. DWORD
  1617. EnumPrinterKeyW(
  1618. HANDLE hPrinter,
  1619. LPCWSTR pKeyName, // address of key name
  1620. LPWSTR pSubkey, // address of buffer for value string
  1621. DWORD cbSubkey, // size of buffer for value string
  1622. LPDWORD pcbSubkey // address for size of value buffer
  1623. )
  1624. {
  1625. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  1626. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  1627. SetLastError(ERROR_INVALID_HANDLE);
  1628. return FALSE;
  1629. }
  1630. return (*pPrintHandle->pProvidor->PrintProvidor.fpEnumPrinterKey)(pPrintHandle->hPrinter,
  1631. pKeyName,
  1632. pSubkey,
  1633. cbSubkey,
  1634. pcbSubkey);
  1635. }
  1636. DWORD
  1637. DeletePrinterDataW(
  1638. HANDLE hPrinter,
  1639. LPWSTR pValueName
  1640. )
  1641. {
  1642. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  1643. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  1644. SetLastError(ERROR_INVALID_HANDLE);
  1645. return FALSE;
  1646. }
  1647. return (*pPrintHandle->pProvidor->PrintProvidor.fpDeletePrinterData)(pPrintHandle->hPrinter,
  1648. pValueName);
  1649. }
  1650. DWORD
  1651. DeletePrinterDataExW(
  1652. HANDLE hPrinter,
  1653. LPCWSTR pKeyName,
  1654. LPCWSTR pValueName
  1655. )
  1656. {
  1657. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  1658. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  1659. SetLastError(ERROR_INVALID_HANDLE);
  1660. return FALSE;
  1661. }
  1662. return (*pPrintHandle->pProvidor->PrintProvidor.fpDeletePrinterDataEx)(pPrintHandle->hPrinter,
  1663. pKeyName,
  1664. pValueName);
  1665. }
  1666. DWORD
  1667. DeletePrinterKeyW(
  1668. HANDLE hPrinter,
  1669. LPCWSTR pKeyName
  1670. )
  1671. {
  1672. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  1673. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  1674. SetLastError(ERROR_INVALID_HANDLE);
  1675. return FALSE;
  1676. }
  1677. return (*pPrintHandle->pProvidor->PrintProvidor.fpDeletePrinterKey)(pPrintHandle->hPrinter,
  1678. pKeyName);
  1679. }
  1680. DWORD
  1681. SetPrinterDataW(
  1682. HANDLE hPrinter,
  1683. LPWSTR pValueName,
  1684. DWORD Type,
  1685. LPBYTE pData,
  1686. DWORD cbData
  1687. )
  1688. {
  1689. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  1690. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  1691. SetLastError(ERROR_INVALID_HANDLE);
  1692. return FALSE;
  1693. }
  1694. return (*pPrintHandle->pProvidor->PrintProvidor.fpSetPrinterData)(pPrintHandle->hPrinter,
  1695. pValueName,
  1696. Type,
  1697. pData,
  1698. cbData);
  1699. }
  1700. DWORD
  1701. SetPrinterDataExW(
  1702. HANDLE hPrinter,
  1703. LPCWSTR pKeyName,
  1704. LPCWSTR pValueName,
  1705. DWORD Type,
  1706. LPBYTE pData,
  1707. DWORD cbData
  1708. )
  1709. {
  1710. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  1711. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  1712. SetLastError(ERROR_INVALID_HANDLE);
  1713. return FALSE;
  1714. }
  1715. return (*pPrintHandle->pProvidor->PrintProvidor.fpSetPrinterDataEx)(pPrintHandle->hPrinter,
  1716. pKeyName,
  1717. pValueName,
  1718. Type,
  1719. pData,
  1720. cbData);
  1721. }
  1722. DWORD
  1723. WaitForPrinterChange(
  1724. HANDLE hPrinter,
  1725. DWORD Flags
  1726. )
  1727. {
  1728. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  1729. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  1730. SetLastError(ERROR_INVALID_HANDLE);
  1731. return FALSE;
  1732. }
  1733. return (*pPrintHandle->pProvidor->PrintProvidor.fpWaitForPrinterChange)
  1734. (pPrintHandle->hPrinter, Flags);
  1735. }
  1736. BOOL
  1737. ClosePrinter(
  1738. HANDLE hPrinter
  1739. )
  1740. {
  1741. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  1742. EnterRouterSem();
  1743. if (!pPrintHandle || pPrintHandle->signature != PRINTHANDLE_SIGNATURE) {
  1744. LeaveRouterSem();
  1745. SetLastError(ERROR_INVALID_HANDLE);
  1746. return FALSE;
  1747. }
  1748. //
  1749. // Close any notifications on this handle.
  1750. //
  1751. // The local case cleans up the event, while the remote
  1752. // case potentially cleans up the Reply Notification context
  1753. // handle.
  1754. //
  1755. // We must close this first, since the Providor->ClosePrinter
  1756. // call removes data structures that FindClose... relies on.
  1757. //
  1758. // Client side should be shutdown by winspool.drv.
  1759. //
  1760. if (pPrintHandle->pChange &&
  1761. (pPrintHandle->pChange->eStatus & STATUS_CHANGE_VALID)) {
  1762. FindClosePrinterChangeNotificationWorker(hPrinter);
  1763. }
  1764. LeaveRouterSem();
  1765. if ((*pPrintHandle->pProvidor->PrintProvidor.fpClosePrinter) (pPrintHandle->hPrinter)) {
  1766. //
  1767. // We can't just free it, since there may be a reply waiting
  1768. // on it.
  1769. //
  1770. FreePrinterHandle(pPrintHandle);
  1771. return TRUE;
  1772. } else
  1773. return FALSE;
  1774. }
  1775. /* FormatPrinterForRegistryKey
  1776. *
  1777. * Returns a pointer to a copy of the source string with backslashes removed.
  1778. * This is to store the printer name as the key name in the registry,
  1779. * which interprets backslashes as branches in the registry structure.
  1780. * Convert them to commas, since we don't allow printer names with commas,
  1781. * so there shouldn't be any clashes.
  1782. * If there are no backslashes, the string is unchanged.
  1783. */
  1784. LPWSTR
  1785. FormatPrinterForRegistryKey(
  1786. LPCWSTR pSource, /* The string from which backslashes are to be removed. */
  1787. LPWSTR pScratch /* Scratch buffer for the function to write in; */
  1788. ) /* must be at least as long as pSource. */
  1789. {
  1790. LPWSTR p;
  1791. if (pScratch != pSource) {
  1792. //
  1793. // Copy the string into the scratch buffer:
  1794. //
  1795. wcscpy(pScratch, pSource);
  1796. }
  1797. //
  1798. // Check each character, and, if it's a backslash,
  1799. // convert it to a comma:
  1800. //
  1801. for (p = pScratch; *p; ++p) {
  1802. if (*p == L'\\')
  1803. *p = L',';
  1804. }
  1805. return pScratch;
  1806. }
  1807. /* FormatRegistryKeyForPrinter
  1808. *
  1809. * Returns a pointer to a copy of the source string with backslashes added.
  1810. * This must be the opposite of FormatPrinterForRegistryKey, so the mapping
  1811. * _must_ be 1-1.
  1812. *
  1813. * If there are no commas, the string is unchanged.
  1814. */
  1815. LPWSTR
  1816. FormatRegistryKeyForPrinter(
  1817. LPWSTR pSource, /* The string from which backslashes are to be added. */
  1818. LPWSTR pScratch /* Scratch buffer for the function to write in; */
  1819. ) /* must be at least as long as pSource. */
  1820. {
  1821. /* Copy the string into the scratch buffer:
  1822. */
  1823. wcscpy(pScratch, pSource);
  1824. /* Check each character, and, if it's a backslash,
  1825. * convert it to a comma:
  1826. */
  1827. for (pSource = pScratch; *pSource; pSource++) {
  1828. if (*pSource == L',')
  1829. *pSource = L'\\';
  1830. }
  1831. return pScratch;
  1832. }
  1833. /* SavePrinterConnectionInRegistry
  1834. *
  1835. * Saves data in the registry for a printer connection.
  1836. * Creates a key under the current impersonation client's key
  1837. * in the registry under \Printers\Connections.
  1838. * The printer name is stripped of backslashes, since the registry
  1839. * API does not permit the creation of keys with backslashes.
  1840. * They are replaced by commas, which are invalid characters
  1841. * in printer names, so we should never get one passed in.
  1842. *
  1843. *
  1844. * *** WARNING ***
  1845. *
  1846. * IF YOU MAKE CHANGES TO THE LOCATION IN THE REGISTRY
  1847. * WHERE PRINTER CONNECTIONS ARE STORED, YOU MUST MAKE
  1848. * CORRESPONDING CHANGES IN USER\USERINIT\USERINIT.C.
  1849. *
  1850. */
  1851. BOOL
  1852. SavePrinterConnectionInRegistry(
  1853. PPRINTER_INFO_2 pPrinterInfo2,
  1854. LPPROVIDOR pProvidor
  1855. )
  1856. {
  1857. HKEY hClientKey = NULL;
  1858. HKEY hConnectionsKey;
  1859. HKEY hPrinterKey;
  1860. DWORD Status;
  1861. BOOL rc = FALSE;
  1862. LPCTSTR pszProvidor = pProvidor->lpName;
  1863. PWSTR pKeyName = NULL;
  1864. DWORD cchSize = MAX_PATH;
  1865. DWORD dwError;
  1866. //
  1867. // CLS
  1868. //
  1869. // If the provider is localspl, change it to win32spl.dll.
  1870. // This is required for clustering since localspl handles printer
  1871. // connections, but they should be "owned" by win32spl.dll. When
  1872. // Someone opens a printer that they are connected to, we will
  1873. // always hit localspl.dll first before we look at this entry.
  1874. //
  1875. // When the cluster is remote, then they need to go through win32spl.dll.
  1876. //
  1877. if( pProvidor == pLocalProvidor ){
  1878. pszProvidor = szWin32spl;
  1879. }
  1880. hClientKey = GetClientUserHandle(KEY_READ);
  1881. if (hClientKey) {
  1882. if (wcslen(pPrinterInfo2->pPrinterName) < cchSize &&
  1883. (pKeyName = AllocSplMem(cchSize * sizeof(WCHAR)))) {
  1884. Status = RegCreateKeyEx(hClientKey, szRegistryConnections,
  1885. REG_OPTION_RESERVED, NULL, REG_OPTION_NON_VOLATILE,
  1886. KEY_WRITE, NULL, &hConnectionsKey, NULL);
  1887. if (Status == NO_ERROR) {
  1888. /* Make a key name without backslashes, so that the
  1889. * registry doesn't interpret them as branches in the registry tree:
  1890. */
  1891. FormatPrinterForRegistryKey(pPrinterInfo2->pPrinterName,
  1892. pKeyName);
  1893. Status = RegCreateKeyEx(hConnectionsKey, pKeyName, REG_OPTION_RESERVED,
  1894. NULL, 0, KEY_WRITE, NULL, &hPrinterKey, NULL);
  1895. if (Status == NO_ERROR) {
  1896. RegSetValueEx(hPrinterKey,
  1897. szServerValue,
  1898. 0,
  1899. REG_SZ,
  1900. (LPBYTE)pPrinterInfo2->pServerName,
  1901. (lstrlen(pPrinterInfo2->pServerName)+1) *
  1902. sizeof(pPrinterInfo2->pServerName[0]));
  1903. Status = RegSetValueEx(hPrinterKey,
  1904. szProvidorValue,
  1905. 0,
  1906. REG_SZ,
  1907. (LPBYTE)pszProvidor,
  1908. (lstrlen(pszProvidor)+1) *
  1909. sizeof(pszProvidor[0]));
  1910. if (Status == ERROR_SUCCESS) {
  1911. dwError = UpdatePrinterRegUser(hClientKey,
  1912. NULL,
  1913. pPrinterInfo2->pPrinterName,
  1914. NULL,
  1915. UPDATE_REG_CHANGE);
  1916. if (dwError == ERROR_SUCCESS) {
  1917. BroadcastMessage(BROADCAST_TYPE_MESSAGE,
  1918. WM_WININICHANGE,
  1919. 0,
  1920. (LPARAM)szDevices);
  1921. rc = TRUE;
  1922. } else {
  1923. DBGMSG(DBG_TRACE, ("UpdatePrinterRegUser failed: Error %d\n",
  1924. dwError));
  1925. }
  1926. } else {
  1927. DBGMSG(DBG_WARNING, ("RegSetValueEx(%ws) failed: Error %d\n",
  1928. pszProvidor, Status));
  1929. rc = FALSE;
  1930. }
  1931. RegCloseKey(hPrinterKey);
  1932. } else {
  1933. DBGMSG(DBG_WARNING, ("RegCreateKeyEx(%ws) failed: Error %d\n",
  1934. pKeyName, Status ));
  1935. rc = FALSE;
  1936. }
  1937. RegCloseKey(hConnectionsKey);
  1938. } else {
  1939. DBGMSG(DBG_WARNING, ("RegCreateKeyEx(%ws) failed: Error %d\n",
  1940. szRegistryConnections, Status ));
  1941. rc = FALSE;
  1942. }
  1943. if (!rc) {
  1944. DBGMSG(DBG_WARNING, ("Error updating registry: %d\n",
  1945. GetLastError())); /* This may not be the error */
  1946. /* that caused the failure. */
  1947. if (pKeyName)
  1948. RegDeleteKey(hClientKey, pKeyName);
  1949. }
  1950. FreeSplMem(pKeyName);
  1951. }
  1952. RegCloseKey(hClientKey);
  1953. }
  1954. return rc;
  1955. }
  1956. BOOL
  1957. RemovePrinterConnectionInRegistry(
  1958. LPWSTR pName)
  1959. {
  1960. HKEY hClientKey;
  1961. HKEY hPrinterConnectionsKey;
  1962. DWORD Status = NO_ERROR;
  1963. DWORD i = 0;
  1964. PWSTR pKeyName = NULL;
  1965. DWORD cchSize = MAX_PATH;
  1966. BOOL Found = FALSE;
  1967. BOOL bRet = FALSE;
  1968. if (pName &&
  1969. wcslen(pName) < cchSize) {
  1970. if (pKeyName = AllocSplMem(cchSize * sizeof(WCHAR))) {
  1971. hClientKey = GetClientUserHandle(KEY_READ);
  1972. if (hClientKey) {
  1973. Status = RegOpenKeyEx(hClientKey, szRegistryConnections,
  1974. REG_OPTION_RESERVED,
  1975. KEY_READ | KEY_WRITE, &hPrinterConnectionsKey);
  1976. if (Status == NO_ERROR) {
  1977. FormatPrinterForRegistryKey(pName, pKeyName);
  1978. bRet = DeleteSubKeyTree(hPrinterConnectionsKey, pKeyName);
  1979. RegCloseKey(hPrinterConnectionsKey);
  1980. }
  1981. if ( bRet ) {
  1982. UpdatePrinterRegUser(hClientKey,
  1983. NULL,
  1984. pName,
  1985. NULL,
  1986. UPDATE_REG_DELETE);
  1987. }
  1988. RegCloseKey(hClientKey);
  1989. if ( bRet ) {
  1990. BroadcastMessage(BROADCAST_TYPE_MESSAGE,
  1991. WM_WININICHANGE,
  1992. 0,
  1993. (LPARAM)szDevices);
  1994. }
  1995. }
  1996. FreeSplMem(pKeyName);
  1997. }
  1998. }
  1999. return bRet;
  2000. }
  2001. VOID
  2002. PrinterHandleRundown(
  2003. HANDLE hPrinter)
  2004. {
  2005. LPPRINTHANDLE pPrintHandle;
  2006. if (hPrinter) {
  2007. pPrintHandle = (LPPRINTHANDLE)hPrinter;
  2008. switch (pPrintHandle->signature) {
  2009. case PRINTHANDLE_SIGNATURE:
  2010. // Log warning to detect handle free
  2011. DBGMSG(DBG_WARNING, ("PrinterHandleRundown: 0x%x 0x%x", pPrintHandle, pPrintHandle->hPrinter));
  2012. DBGMSG(DBG_TRACE, ("Rundown PrintHandle 0x%x\n", hPrinter));
  2013. ClosePrinter(hPrinter);
  2014. break;
  2015. case NOTIFYHANDLE_SIGNATURE:
  2016. DBGMSG(DBG_TRACE, ("Rundown NotifyHandle 0x%x\n", hPrinter));
  2017. RundownPrinterNotify(hPrinter);
  2018. break;
  2019. case CLUSTERHANDLE_SIGNATURE:
  2020. DBGMSG(DBG_TRACE, ("Rundown ClusterHandle 0x%x\n", hPrinter ));
  2021. ClusterSplClose(hPrinter);
  2022. break;
  2023. default:
  2024. //
  2025. // Unknown type.
  2026. //
  2027. DBGMSG( DBG_ERROR, ("Rundown: Unknown type 0x%x\n", hPrinter ) );
  2028. break;
  2029. }
  2030. }
  2031. return;
  2032. }
  2033. BOOL
  2034. ValidatePrinterName(
  2035. LPWSTR pPrinterName)
  2036. /*++
  2037. Function Description: Validates the fully qualified printer name. Performs the following checks
  2038. 1) Length < MAX_UNC_PRINTER_NAME
  2039. 2) No invalid chars in the names \,!
  2040. 3) No empty names after removing trailing blanks
  2041. Parameters: pPrinterName - printer name
  2042. Return Values: TRUE if valid name; FALSE otherwise
  2043. --*/
  2044. {
  2045. DWORD dwLength;
  2046. LPWSTR pWack, pTemp, pLastSpace;
  2047. WCHAR szServer[MAX_UNC_PRINTER_NAME], szPrinter[MAX_UNC_PRINTER_NAME];
  2048. // Make length checks
  2049. dwLength = wcslen( pPrinterName );
  2050. if ( dwLength < 5 || dwLength > MAX_UNC_PRINTER_NAME )
  2051. {
  2052. return FALSE;
  2053. }
  2054. // Search for invalid characters , and !
  2055. if ( wcschr( pPrinterName, L',' ) ||
  2056. wcschr( pPrinterName, L'!' ) )
  2057. {
  2058. return FALSE;
  2059. }
  2060. // Search for exactly 3 wacks
  2061. if ( (pPrinterName[0] != L'\\') ||
  2062. (pPrinterName[1] != L'\\') ||
  2063. !(pWack = wcschr( pPrinterName+2, L'\\' )) ||
  2064. wcschr( pWack+1, L'\\' ) )
  2065. {
  2066. return FALSE;
  2067. }
  2068. // Check for empty server or printer names
  2069. wcsncpy( szServer, pPrinterName+2, (size_t) (pWack - (pPrinterName+2)) );
  2070. szServer[pWack - (pPrinterName+2)] = L'\0';
  2071. wcsncpy( szPrinter, pWack+1, dwLength - (size_t) ((pWack+1 - pPrinterName)) );
  2072. szPrinter[dwLength - (pWack+1 - pPrinterName)] = L'\0';
  2073. // Remove trailing spaces in the server name
  2074. for (pLastSpace = NULL, pTemp = szServer; pTemp && *pTemp; ++pTemp)
  2075. {
  2076. if (*pTemp == L' ') {
  2077. if (!pLastSpace) {
  2078. pLastSpace = pTemp;
  2079. }
  2080. } else {
  2081. pLastSpace = NULL;
  2082. }
  2083. }
  2084. if (pLastSpace) {
  2085. *pLastSpace = L'\0';
  2086. }
  2087. // Remove trailing spaces in the printer name
  2088. for (pLastSpace = NULL, pTemp = szPrinter; pTemp && *pTemp; ++pTemp)
  2089. {
  2090. if (*pTemp == L' ') {
  2091. if (!pLastSpace) {
  2092. pLastSpace = pTemp;
  2093. }
  2094. } else {
  2095. pLastSpace = NULL;
  2096. }
  2097. }
  2098. if (pLastSpace) {
  2099. *pLastSpace = L'\0';
  2100. }
  2101. if (!*szServer || !*szPrinter) {
  2102. return FALSE;
  2103. }
  2104. return TRUE;
  2105. }
  2106. BOOL
  2107. RouterAddPerMachineConnection(
  2108. LPCWSTR pPrinterNameP,
  2109. LPCWSTR pPrintServerP,
  2110. LPCWSTR pProviderP)
  2111. /*++
  2112. Function Description: RouterAddPerMachineConnection adds a subkey to HKEY_LOCAL_MACHINE\
  2113. SYSTEM\CurrentControlSet\Control\Print\Connections with the PrinterName.
  2114. The PrintServer name and the name of the dll used as a provider for
  2115. this connection are stored as values in the key.
  2116. Parameters:
  2117. pPrinterNameP - pointer to the fully qualified printer name. (\\printserver\name)
  2118. pPrintServerP - pointer to the print server name.
  2119. pProviderP - pointer to the provider name. Currently only LanMan Print Services
  2120. is supported. This corresponds to win32spl.dll. NULL or szNULL value
  2121. defaults to this provider. Currently there is no check to enforce that
  2122. only LanMan Print Services is passed.
  2123. Return Value: TRUE for success
  2124. FALSE otherwise.
  2125. --*/
  2126. {
  2127. BOOL bReturn = TRUE;
  2128. DWORD dwLocalConnection = 1, dwLastError, dwType, cbBuf;
  2129. HKEY hMcConnectionKey = NULL, hPrinterKey = NULL;
  2130. HKEY hProviderKey = NULL, hAllProviderKey = NULL;
  2131. HANDLE hImpersonationToken = NULL;
  2132. LPWSTR pPrintServer=NULL, pProvider=NULL, pPrinterName=NULL, pEnd;
  2133. WCHAR szConnData[MAX_PATH];
  2134. WCHAR szRegistryConnections[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Connections";
  2135. WCHAR szRegistryProviders[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Providers";
  2136. EnterRouterSem();
  2137. // Getting the name of the library for the provider.
  2138. if (!pProviderP || !*pProviderP) {
  2139. pProvider = AllocSplStr(L"win32spl.dll");
  2140. } else {
  2141. cbBuf = sizeof(szConnData);
  2142. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegistryProviders, 0,
  2143. KEY_READ, &hAllProviderKey) ||
  2144. RegOpenKeyEx(hAllProviderKey, pProviderP, 0, KEY_READ,
  2145. &hProviderKey) ||
  2146. RegQueryValueEx(hProviderKey, L"Name", 0, &dwType,
  2147. (LPBYTE)szConnData,&cbBuf)) {
  2148. SetLastError(ERROR_INVALID_PARAMETER);
  2149. bReturn = FALSE;
  2150. goto CleanUp;
  2151. } else {
  2152. pProvider = AllocSplStr(szConnData);
  2153. }
  2154. }
  2155. pPrintServer = AllocSplStr(pPrintServerP);
  2156. pPrinterName = AllocSplStr(pPrinterNameP);
  2157. if (!pProvider || !pPrintServer || !pPrinterName) {
  2158. bReturn = FALSE;
  2159. goto CleanUp;
  2160. }
  2161. // Check for a fully qualified printer name without commas
  2162. if (!ValidatePrinterName(pPrinterName)) {
  2163. SetLastError(ERROR_INVALID_PRINTER_NAME);
  2164. bReturn = FALSE;
  2165. goto CleanUp;
  2166. }
  2167. // Replacing the \'s from the Printer name with ,'s
  2168. FormatPrinterForRegistryKey(pPrinterName, pPrinterName);
  2169. hImpersonationToken = RevertToPrinterSelf();
  2170. // Creating the subkey for the holding all printer connections.
  2171. if ((dwLastError = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szRegistryConnections, 0,
  2172. NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  2173. NULL, &hMcConnectionKey, NULL)) ||
  2174. (dwLastError = RegCreateKeyEx(hMcConnectionKey, pPrinterName, 0, NULL,
  2175. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
  2176. &hPrinterKey, NULL))) {
  2177. SetLastError(dwLastError);
  2178. bReturn = FALSE;
  2179. goto CleanUp;
  2180. }
  2181. // Setting the connection data.
  2182. if ((dwLastError = RegSetValueEx(hPrinterKey, L"Server", 0, REG_SZ, (LPBYTE) pPrintServer,
  2183. (wcslen(pPrintServer)+1)*sizeof(pPrintServer[0]))) ||
  2184. (dwLastError = RegSetValueEx(hPrinterKey, L"Provider", 0, REG_SZ, (LPBYTE) pProvider,
  2185. (wcslen(pProvider)+1)*sizeof(pProvider[0]))) ||
  2186. (dwLastError = RegSetValueEx(hPrinterKey, L"LocalConnection", 0, REG_DWORD,
  2187. (LPBYTE) &dwLocalConnection, sizeof(dwLocalConnection)))) {
  2188. SetLastError(dwLastError);
  2189. bReturn = FALSE;
  2190. }
  2191. CleanUp:
  2192. if (pPrintServer) {
  2193. FreeSplStr(pPrintServer);
  2194. }
  2195. if (pProvider) {
  2196. FreeSplStr(pProvider);
  2197. }
  2198. if (hAllProviderKey) {
  2199. RegCloseKey(hAllProviderKey);
  2200. }
  2201. if (hProviderKey) {
  2202. RegCloseKey(hProviderKey);
  2203. }
  2204. if (hPrinterKey) {
  2205. RegCloseKey(hPrinterKey);
  2206. }
  2207. if (!bReturn) {
  2208. if (hMcConnectionKey) RegDeleteKey(hMcConnectionKey,pPrinterName);
  2209. }
  2210. if (pPrinterName) {
  2211. FreeSplStr(pPrinterName);
  2212. }
  2213. if (hMcConnectionKey) {
  2214. RegCloseKey(hMcConnectionKey);
  2215. }
  2216. if (hImpersonationToken) {
  2217. ImpersonatePrinterClient(hImpersonationToken);
  2218. }
  2219. LeaveRouterSem();
  2220. return bReturn;
  2221. }
  2222. BOOL
  2223. AddPerMachineConnectionW(
  2224. LPCWSTR pServer,
  2225. LPCWSTR pPrinterName,
  2226. LPCWSTR pPrintServer,
  2227. LPCWSTR pProvider
  2228. )
  2229. {
  2230. LPPROVIDOR pProvidor;
  2231. WaitForSpoolerInitialization();
  2232. pProvidor = pLocalProvidor;
  2233. if ((*pProvidor->PrintProvidor.fpAddPerMachineConnection)
  2234. (pServer, pPrinterName, pPrintServer, pProvider)) {
  2235. return RouterAddPerMachineConnection(pPrinterName,pPrintServer,pProvider);
  2236. } else if (GetLastError() != ERROR_INVALID_NAME) {
  2237. return FALSE;
  2238. }
  2239. pProvidor = pProvidor->pNext;
  2240. while (pProvidor) {
  2241. if ((*pProvidor->PrintProvidor.fpAddPerMachineConnection)
  2242. (pServer, pPrinterName, pPrintServer, pProvider)) {
  2243. return TRUE;
  2244. }
  2245. if (GetLastError() != ERROR_INVALID_NAME) {
  2246. return FALSE;
  2247. }
  2248. pProvidor = pProvidor->pNext;
  2249. }
  2250. return FALSE;
  2251. }
  2252. BOOL
  2253. RouterDeletePerMachineConnection(
  2254. LPCWSTR pPrinterNameP
  2255. )
  2256. /*++
  2257. Function Description: This function deletes the registry entry in HKEY_LOCAL_MACHINE\
  2258. SYSTEM\CurrentControlSet\Control\Print\Connections corresponding to
  2259. pPrinterNameP. All users will lose the connection when they logon.
  2260. Parameters: pPrinterNameP - pointer to the fully qualified name of the printer.
  2261. Return Values: TRUE for Success
  2262. FALSE otherwise.
  2263. --*/
  2264. {
  2265. BOOL bReturn = TRUE, bEnteredRouterSem = FALSE;
  2266. HANDLE hImpersonationToken = NULL;
  2267. HKEY hMcConnectionKey = NULL;
  2268. LPWSTR pPrinterName = NULL;
  2269. DWORD dwLastError;
  2270. WCHAR szRegistryConnections[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Connections";
  2271. if (!(pPrinterName = AllocSplStr(pPrinterNameP))) {
  2272. bReturn = FALSE;
  2273. goto CleanUp;
  2274. }
  2275. // Convert \'s to ,'s in the printer name.
  2276. FormatPrinterForRegistryKey(pPrinterName, pPrinterName);
  2277. EnterRouterSem();
  2278. bEnteredRouterSem = TRUE;
  2279. hImpersonationToken = RevertToPrinterSelf();
  2280. if (dwLastError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegistryConnections, 0,
  2281. KEY_ALL_ACCESS, &hMcConnectionKey)) {
  2282. SetLastError(dwLastError);
  2283. bReturn = FALSE;
  2284. goto CleanUp;
  2285. }
  2286. if (dwLastError = RegDeleteKey(hMcConnectionKey, pPrinterName)) {
  2287. SetLastError(dwLastError);
  2288. bReturn = FALSE;
  2289. }
  2290. CleanUp:
  2291. if (hMcConnectionKey) {
  2292. RegCloseKey(hMcConnectionKey);
  2293. }
  2294. if (pPrinterName) {
  2295. FreeSplStr(pPrinterName);
  2296. }
  2297. if (hImpersonationToken) {
  2298. ImpersonatePrinterClient(hImpersonationToken);
  2299. }
  2300. if (bEnteredRouterSem) {
  2301. LeaveRouterSem();
  2302. }
  2303. return bReturn;
  2304. }
  2305. BOOL
  2306. DeletePerMachineConnectionW(
  2307. LPCWSTR pServer,
  2308. LPCWSTR pPrinterName
  2309. )
  2310. {
  2311. LPPROVIDOR pProvidor;
  2312. WaitForSpoolerInitialization();
  2313. pProvidor = pLocalProvidor;
  2314. if ((*pProvidor->PrintProvidor.fpDeletePerMachineConnection)
  2315. (pServer, pPrinterName)) {
  2316. return RouterDeletePerMachineConnection(pPrinterName);
  2317. } else if (GetLastError() != ERROR_INVALID_NAME) {
  2318. return FALSE;
  2319. }
  2320. pProvidor = pProvidor->pNext;
  2321. while (pProvidor) {
  2322. if ((*pProvidor->PrintProvidor.fpDeletePerMachineConnection)
  2323. (pServer, pPrinterName)) {
  2324. return TRUE;
  2325. }
  2326. if (GetLastError() != ERROR_INVALID_NAME) {
  2327. return FALSE;
  2328. }
  2329. pProvidor = pProvidor->pNext;
  2330. }
  2331. return FALSE;
  2332. }
  2333. BOOL
  2334. RouterEnumPerMachineConnections(
  2335. LPCWSTR pServer,
  2336. LPBYTE pPrinterEnum,
  2337. DWORD cbBuf,
  2338. LPDWORD pcbNeeded,
  2339. LPDWORD pcReturned
  2340. )
  2341. /*++
  2342. Function Description: This function copies the PRINTER_INFO_4 structs for all the per
  2343. machine connections into the buffer (pPrinterEnum).
  2344. Parameters: pServer - pointer to the server name (NULL for local)
  2345. pPrinterEnum - pointer to the buffer
  2346. cbBuf - size of the buffer in bytes
  2347. pcbNeeded - pointer to a variable which contains the number of bytes written
  2348. into the buffer/ number of bytes required (if the given buffer
  2349. is insufficient)
  2350. pcReturned - pointer to the variable which contains the number of PRINTER_INFO_4
  2351. structs returned in the buffer.
  2352. Return Values: TRUE for success
  2353. FALSE otherwise.
  2354. --*/
  2355. {
  2356. DWORD dwRegIndex, dwType, cbdata, dwNameSize, dwLastError;
  2357. BOOL bReturn = TRUE, bEnteredRouterSem = FALSE;
  2358. HANDLE hImpersonationToken = NULL;
  2359. HKEY hMcConnectionKey = NULL, hPrinterKey = NULL;
  2360. LPBYTE pStart = NULL, pEnd = NULL;
  2361. WCHAR szMachineConnections[]=L"SYSTEM\\CurrentControlSet\\Control\\Print\\Connections";
  2362. WCHAR szPrinterName[MAX_UNC_PRINTER_NAME],szConnData[MAX_UNC_PRINTER_NAME];
  2363. // Check for local machine
  2364. if (pServer && *pServer) {
  2365. if (!MyUNCName((LPWSTR)pServer)) {
  2366. SetLastError(ERROR_INVALID_NAME);
  2367. bReturn = FALSE;
  2368. goto CleanUp;
  2369. }
  2370. }
  2371. EnterRouterSem();
  2372. bEnteredRouterSem = TRUE;
  2373. hImpersonationToken = RevertToPrinterSelf();
  2374. *pcbNeeded = *pcReturned = 0;
  2375. // Open the key containing all per-machine connections.
  2376. if (dwLastError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szMachineConnections, 0,
  2377. KEY_READ , &hMcConnectionKey)) {
  2378. bReturn = (dwLastError == ERROR_FILE_NOT_FOUND) ? TRUE
  2379. : FALSE;
  2380. if (!bReturn) {
  2381. SetLastError(dwLastError);
  2382. }
  2383. goto CleanUp;
  2384. }
  2385. // pStart and pEnd point to the start and end of the buffer respt.
  2386. pStart = pPrinterEnum;
  2387. pEnd = pPrinterEnum + cbBuf;
  2388. for (dwRegIndex = 0;
  2389. dwNameSize = COUNTOF(szPrinterName),
  2390. ((dwLastError = RegEnumKeyEx(hMcConnectionKey, dwRegIndex, szPrinterName,
  2391. &dwNameSize, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS);
  2392. ++dwRegIndex) {
  2393. // Enumerate each of the connections and copy data into the buffer
  2394. cbdata = sizeof(szConnData);
  2395. if ((dwLastError = RegOpenKeyEx(hMcConnectionKey, szPrinterName, 0,
  2396. KEY_READ, &hPrinterKey)) ||
  2397. (dwLastError = RegQueryValueEx(hPrinterKey, L"Server", NULL, &dwType,
  2398. (LPBYTE)szConnData, &cbdata))) {
  2399. SetLastError(dwLastError);
  2400. bReturn = FALSE;
  2401. goto CleanUp;
  2402. }
  2403. RegCloseKey(hPrinterKey);
  2404. hPrinterKey=NULL;
  2405. // Update the size of the required buffer
  2406. *pcbNeeded = *pcbNeeded + sizeof(PRINTER_INFO_4) + sizeof(DWORD) +
  2407. (wcslen(szConnData) + 1)*sizeof(szConnData[0]) +
  2408. (wcslen(szPrinterName) + 1)*sizeof(szPrinterName[0]);
  2409. // Copy data into the buffer if there is space.
  2410. if (*pcbNeeded <= cbBuf) {
  2411. pEnd = CopyPrinterNameToPrinterInfo4(szConnData,szPrinterName,pStart,pEnd);
  2412. FormatRegistryKeyForPrinter(((PPRINTER_INFO_4) pStart)->pPrinterName,
  2413. ((PPRINTER_INFO_4) pStart)->pPrinterName);
  2414. pStart += sizeof(PRINTER_INFO_4);
  2415. (*pcReturned)++;
  2416. }
  2417. }
  2418. if (dwLastError != ERROR_NO_MORE_ITEMS) {
  2419. SetLastError(dwLastError);
  2420. bReturn = FALSE;
  2421. goto CleanUp;
  2422. }
  2423. if (cbBuf < *pcbNeeded) {
  2424. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  2425. bReturn = FALSE;
  2426. }
  2427. CleanUp:
  2428. if (hMcConnectionKey) {
  2429. RegCloseKey(hMcConnectionKey);
  2430. }
  2431. if (hPrinterKey) {
  2432. RegCloseKey(hPrinterKey);
  2433. }
  2434. if (hImpersonationToken) {
  2435. ImpersonatePrinterClient(hImpersonationToken);
  2436. }
  2437. if (bEnteredRouterSem) {
  2438. LeaveRouterSem();
  2439. }
  2440. if (!bReturn) {
  2441. *pcReturned = 0;
  2442. }
  2443. return bReturn;
  2444. }
  2445. BOOL
  2446. EnumPerMachineConnectionsW(
  2447. LPCWSTR pServer,
  2448. LPBYTE pPrinterEnum,
  2449. DWORD cbBuf,
  2450. LPDWORD pcbNeeded,
  2451. LPDWORD pcReturned
  2452. )
  2453. {
  2454. LPPROVIDOR pProvidor;
  2455. if ((pPrinterEnum == NULL) && (cbBuf != 0)) {
  2456. SetLastError(ERROR_INVALID_USER_BUFFER);
  2457. return FALSE;
  2458. }
  2459. WaitForSpoolerInitialization();
  2460. if (RouterEnumPerMachineConnections(pServer, pPrinterEnum, cbBuf,
  2461. pcbNeeded, pcReturned)) {
  2462. return TRUE;
  2463. } else if (GetLastError() != ERROR_INVALID_NAME) {
  2464. return FALSE;
  2465. }
  2466. pProvidor = pLocalProvidor;
  2467. while (pProvidor) {
  2468. if ((*pProvidor->PrintProvidor.fpEnumPerMachineConnections)
  2469. (pServer, pPrinterEnum, cbBuf, pcbNeeded, pcReturned)) {
  2470. return TRUE;
  2471. }
  2472. if (GetLastError() != ERROR_INVALID_NAME) {
  2473. return FALSE;
  2474. }
  2475. pProvidor = pProvidor->pNext;
  2476. }
  2477. return FALSE;
  2478. }
  2479. PPRINTER_INFO_2
  2480. pGetPrinterInfo2(
  2481. HANDLE hPrinter
  2482. )
  2483. /*++
  2484. Routine Description:
  2485. Retrieve a printer info 2 structure from an hPrinter. Data must
  2486. be FreeSplMem'd by caller.
  2487. Arguments:
  2488. hPrinter - Printer to query.
  2489. Return Value:
  2490. PRINTER_INFO_2 - On success, a valid structure.
  2491. NULL - On failure.
  2492. --*/
  2493. {
  2494. LPPRINTHANDLE pPrintHandle=(LPPRINTHANDLE)hPrinter;
  2495. DWORD cbPrinter = 0x1000;
  2496. DWORD cbNeeded;
  2497. PPRINTER_INFO_2 pPrinterInfo2;
  2498. BOOL bSuccess = FALSE;
  2499. if( pPrinterInfo2 = AllocSplMem( cbPrinter )){
  2500. bSuccess = (*pPrintHandle->pProvidor->PrintProvidor.fpGetPrinter)
  2501. ( pPrintHandle->hPrinter,
  2502. 2,
  2503. (PBYTE)pPrinterInfo2,
  2504. cbPrinter,
  2505. &cbNeeded );
  2506. if( !bSuccess ){
  2507. if( GetLastError() == ERROR_INSUFFICIENT_BUFFER ){
  2508. FreeSplMem( pPrinterInfo2 );
  2509. if (pPrinterInfo2 = (PPRINTER_INFO_2)AllocSplMem( cbNeeded )){
  2510. cbPrinter = cbNeeded;
  2511. bSuccess = (*pPrintHandle->pProvidor->PrintProvidor.fpGetPrinter)
  2512. ( pPrintHandle->hPrinter,
  2513. 2,
  2514. (PBYTE)pPrinterInfo2,
  2515. cbPrinter,
  2516. &cbNeeded );
  2517. }
  2518. }
  2519. }
  2520. }
  2521. if( !bSuccess ){
  2522. FreeSplMem( pPrinterInfo2 );
  2523. return NULL;
  2524. }
  2525. return pPrinterInfo2;
  2526. }
  2527. VOID
  2528. SplDriverUnloadComplete(
  2529. LPWSTR pDriverFile
  2530. )
  2531. /*++
  2532. Function Description: Notify the print provider that the driver is being unloaded
  2533. so that it may continue with any pending driver upgrades.
  2534. Parameters: pDriverFile -- name of the library that has been unloaded
  2535. Return Values: NONE
  2536. --*/
  2537. {
  2538. LPPROVIDOR pProvidor;
  2539. for (pProvidor = pLocalProvidor; pProvidor; pProvidor = pProvidor->pNext) {
  2540. if ((*pProvidor->PrintProvidor.fpDriverUnloadComplete)(pDriverFile)) {
  2541. break;
  2542. }
  2543. }
  2544. return;
  2545. }