Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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