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.

2672 lines
83 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Abstract:
  4. This module provides functionality for ADs within spooler
  5. Author:
  6. Steve Wilson (NT) December 1996
  7. Revision History:
  8. --*/
  9. #include <precomp.h>
  10. #pragma hdrstop
  11. #include "ds.hxx"
  12. #define LOG_EVENT_ERROR_BUFFER_SIZE 11
  13. #define PPM_FACTOR 48
  14. #define LOTS_OF_FORMS 300 // This is a little more than twice the number of built-in forms
  15. extern BOOL gbInDomain;
  16. extern BOOL gdwLogDsEvents;
  17. extern "C" HANDLE ghDsUpdateThread;
  18. extern "C" DWORD gdwDsUpdateThreadId;
  19. extern "C" BOOL (*pfnOpenPrinter)(LPTSTR, LPHANDLE, LPPRINTER_DEFAULTS);
  20. extern "C" BOOL (*pfnClosePrinter)(HANDLE);
  21. extern "C" DWORD
  22. SetPrinterDs(
  23. HANDLE hPrinter,
  24. DWORD dwAction,
  25. BOOL bSynchronous
  26. )
  27. {
  28. PSPOOL pSpool = (PSPOOL) hPrinter;
  29. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  30. HRESULT hr;
  31. HANDLE hToken = NULL;
  32. PWSTR pszObjectGUID, pszCN, pszDN;
  33. DWORD DsKeyUpdate, Attributes;
  34. BOOL DoChange = FALSE;
  35. NOTIFYVECTOR NotifyVector;
  36. SplInSem();
  37. if (!gbInDomain)
  38. return ERROR_DS_UNAVAILABLE;
  39. //
  40. // Don't allow masquerading printer publishing
  41. //
  42. if (pSpool->pIniPort && !(pSpool->pIniPort->Status & PP_MONITOR))
  43. return ERROR_INVALID_PARAMETER;
  44. hToken = RevertToPrinterSelf(); // All DS accesses are done by LocalSystem account
  45. //
  46. // If any of these change we'll update the registry entry
  47. //
  48. DsKeyUpdate = pIniPrinter->DsKeyUpdate;
  49. pszObjectGUID = pIniPrinter->pszObjectGUID;
  50. pszCN = pIniPrinter->pszCN;
  51. pszDN = pIniPrinter->pszDN;
  52. Attributes = pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED;
  53. //
  54. // Attribute states desired state, not current state
  55. //
  56. switch (dwAction) {
  57. case DSPRINT_UPDATE:
  58. if (!(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
  59. hr = MAKE_HRESULT( SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND);
  60. } else if (bSynchronous) {
  61. //
  62. // We are in the background thread.
  63. //
  64. if (pIniPrinter->DsKeyUpdate) {
  65. INCPRINTERREF(pIniPrinter);
  66. LeaveSplSem();
  67. hr = DsPrinterPublish(hPrinter);
  68. EnterSplSem();
  69. DECPRINTERREF(pIniPrinter);
  70. } else {
  71. hr = ERROR_SUCCESS;
  72. }
  73. } else {
  74. //
  75. // Here we are in the foreground thread.
  76. //
  77. if (pIniPrinter->DsKeyUpdateForeground) {
  78. pIniPrinter->Attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
  79. pIniPrinter->dwAction = DSPRINT_PUBLISH;
  80. hr = ERROR_IO_PENDING;
  81. } else {
  82. hr = ERROR_SUCCESS;
  83. }
  84. }
  85. break;
  86. case DSPRINT_PUBLISH:
  87. if (!(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED) &&
  88. PrinterPublishProhibited()) {
  89. //
  90. // There is a policy against publishing printers from this machine.
  91. //
  92. hr = MAKE_HRESULT( SEVERITY_ERROR, FACILITY_WIN32, ERROR_ACCESS_DENIED);
  93. } else {
  94. if (bSynchronous) {
  95. INCPRINTERREF(pIniPrinter);
  96. LeaveSplSem();
  97. hr = DsPrinterPublish(hPrinter);
  98. EnterSplSem();
  99. DECPRINTERREF(pIniPrinter);
  100. } else {
  101. //
  102. // This is a Pending Unpublish state
  103. //
  104. if (!(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED) && pIniPrinter->pszObjectGUID)
  105. pIniPrinter->dwAction = DSPRINT_REPUBLISH;
  106. else
  107. pIniPrinter->dwAction = DSPRINT_PUBLISH;
  108. pIniPrinter->Attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
  109. hr = ERROR_IO_PENDING;
  110. }
  111. }
  112. break;
  113. case DSPRINT_REPUBLISH:
  114. if (PrinterPublishProhibited()) {
  115. //
  116. // There is a policy against publishing printers from this machine.
  117. //
  118. hr = MAKE_HRESULT( SEVERITY_ERROR, FACILITY_WIN32, ERROR_ACCESS_DENIED);
  119. } else {
  120. //
  121. // Synchronous mode is from background thread and it should only call Publish/Unpublish
  122. //
  123. if (bSynchronous) {
  124. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_INVALID_PARAMETER);
  125. SPLASSERT(FALSE);
  126. } else {
  127. pIniPrinter->dwAction = DSPRINT_REPUBLISH;
  128. pIniPrinter->Attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
  129. hr = ERROR_IO_PENDING;
  130. }
  131. }
  132. break;
  133. case DSPRINT_UNPUBLISH:
  134. if (bSynchronous) {
  135. INCPRINTERREF(pIniPrinter);
  136. LeaveSplSem();
  137. hr = DsPrinterUnpublish(hPrinter);
  138. EnterSplSem();
  139. DECPRINTERREF(pIniPrinter);
  140. } else {
  141. pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_PUBLISHED;
  142. pIniPrinter->dwAction = DSPRINT_UNPUBLISH;
  143. hr = ERROR_IO_PENDING;
  144. }
  145. break;
  146. default:
  147. hr = ERROR_INVALID_PARAMETER;
  148. break;
  149. }
  150. //
  151. // Update Registry and set notifications
  152. //
  153. if (pszCN != pIniPrinter->pszCN ||
  154. pszDN != pIniPrinter->pszDN ||
  155. pszObjectGUID != pIniPrinter->pszObjectGUID ||
  156. DsKeyUpdate != pIniPrinter->DsKeyUpdate ||
  157. Attributes != (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
  158. ZERONV(NotifyVector);
  159. if (pszObjectGUID != pIniPrinter->pszObjectGUID) {
  160. NotifyVector[PRINTER_NOTIFY_TYPE] |= BIT(I_PRINTER_OBJECT_GUID);
  161. DoChange = TRUE;
  162. }
  163. if (Attributes != (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
  164. NotifyVector[PRINTER_NOTIFY_TYPE] |= BIT(I_PRINTER_ATTRIBUTES);
  165. DoChange = TRUE;
  166. }
  167. if (DoChange) {
  168. UpdatePrinterIni(pIniPrinter, UPDATE_CHANGEID);
  169. SetPrinterChange(pIniPrinter,
  170. NULL,
  171. NotifyVector,
  172. PRINTER_CHANGE_SET_PRINTER,
  173. pIniPrinter->pIniSpooler);
  174. } else if (DsKeyUpdate != pIniPrinter->DsKeyUpdate) {
  175. UpdatePrinterIni(pIniPrinter, UPDATE_DS_ONLY);
  176. }
  177. }
  178. SplInSem();
  179. if (hr == ERROR_IO_PENDING && !bSynchronous)
  180. SpawnDsUpdate(1);
  181. if (hToken)
  182. ImpersonatePrinterClient(hToken);
  183. return (DWORD) hr;
  184. }
  185. HRESULT
  186. DsPrinterPublish(
  187. HANDLE hPrinter
  188. )
  189. {
  190. HRESULT hr;
  191. PSPOOL pSpool = (PSPOOL) hPrinter;
  192. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  193. WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE];
  194. BOOL bUpdating = !!pIniPrinter->pszObjectGUID;
  195. DWORD dwDsKeyUpdate;
  196. SplOutSem();
  197. #if DBG
  198. EnterSplSem();
  199. DBGMSG( DBG_EXEC, ("DsPrinterPublish: %ws\n", pIniPrinter->pName));
  200. LeaveSplSem();
  201. #endif
  202. //
  203. // On first publish update all keys and tell the driver to write its non-devcap properties
  204. //
  205. if (!bUpdating) {
  206. //
  207. // We execute this on the background thread and hence donot need any
  208. // to be in the critical section.
  209. //
  210. pIniPrinter->DsKeyUpdate |= DS_KEY_PUBLISH | DS_KEY_SPOOLER | DS_KEY_DRIVER | DS_KEY_USER;
  211. }
  212. //
  213. // Update DS properties
  214. //
  215. dwDsKeyUpdate = pIniPrinter->DsKeyUpdate & (DS_KEY_SPOOLER | DS_KEY_DRIVER | DS_KEY_USER);
  216. hr = DsPrinterUpdate(hPrinter);
  217. BAIL_ON_FAILURE(hr);
  218. DBGMSG( DBG_EXEC, ("PublishDsUpdate: Printer Updated\n" ) );
  219. error:
  220. if (SUCCEEDED(hr)) {
  221. //
  222. // Only write a success event if something changed
  223. //
  224. if (dwDsKeyUpdate != pIniPrinter->DsKeyUpdate) {
  225. SplLogEvent( pIniPrinter->pIniSpooler,
  226. gdwLogDsEvents & LOG_INFO,
  227. bUpdating ? MSG_PRINTER_UPDATED
  228. : MSG_PRINTER_PUBLISHED,
  229. FALSE,
  230. pIniPrinter->pszCN,
  231. pIniPrinter->pszDN,
  232. NULL );
  233. }
  234. } else if (pIniPrinter->pszCN && pIniPrinter->pszDN) {
  235. StringCchPrintf(ErrorBuffer, COUNTOF(ErrorBuffer), L"%x", hr);
  236. SplLogEvent( pIniPrinter->pIniSpooler,
  237. gdwLogDsEvents & LOG_ERROR,
  238. MSG_PRINTER_NOT_PUBLISHED,
  239. FALSE,
  240. pIniPrinter->pszCN,
  241. pIniPrinter->pszDN,
  242. ErrorBuffer,
  243. NULL );
  244. }
  245. if (pIniPrinter->DsKeyUpdate)
  246. hr = ERROR_IO_PENDING;
  247. return hr;
  248. }
  249. HRESULT
  250. DsPrinterUpdate(
  251. HANDLE hPrinter
  252. )
  253. {
  254. PSPOOL pSpool = (PSPOOL) hPrinter;
  255. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  256. HRESULT hr = S_OK;
  257. DWORD dwResult;
  258. BOOL bImpersonating = FALSE;
  259. IADs *pADs = NULL;
  260. SplOutSem();
  261. if(!(pIniPrinter->DsKeyUpdate & (DS_KEY_SPOOLER | DS_KEY_DRIVER | DS_KEY_USER))) {
  262. pIniPrinter->DsKeyUpdate = 0;
  263. }
  264. //
  265. // If we aren't truly published yet, be sure to publish mandatory properties first!
  266. //
  267. if (!pIniPrinter->pszObjectGUID) {
  268. //
  269. // Fail if we're on a cluster but couldn't get the Cluster SID
  270. // The Cluster SID is required later in AddClusterAce
  271. //
  272. if ((pIniPrinter->pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG) &&
  273. !pIniPrinter->pIniSpooler->pszClusterSID) {
  274. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_CLUSTER_NO_SECURITY_CONTEXT);
  275. BAIL_ON_FAILURE(hr);
  276. }
  277. //
  278. // Get or Create printQueue object
  279. //
  280. hr = GetPrintQueue(hPrinter, &pADs);
  281. BAIL_ON_FAILURE(hr);
  282. hr = PublishMandatoryProperties(hPrinter, pADs);
  283. BAIL_ON_FAILURE(hr);
  284. } else {
  285. //
  286. // If we are a Cluster, impersonate the Cluster User
  287. //
  288. if (pIniPrinter->pIniSpooler->hClusterToken != INVALID_HANDLE_VALUE) {
  289. // Impersonate the client
  290. if (!ImpersonatePrinterClient(pIniPrinter->pIniSpooler->hClusterToken)) {
  291. dwResult = GetLastError();
  292. DBGMSG(DBG_WARNING,("DsPrinterPublish FAILED: %d\n", dwResult));
  293. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  294. BAIL_ON_FAILURE(hr);
  295. }
  296. bImpersonating = TRUE;
  297. }
  298. //
  299. // Get or Create printQueue object
  300. //
  301. hr = GetPrintQueue(hPrinter, &pADs);
  302. BAIL_ON_FAILURE(hr);
  303. }
  304. //
  305. // Update User - updates from Registry
  306. //
  307. // CopyRegistry2Ds for DS_KEY_USER values must
  308. // be called in the first place since there could be duplicate values
  309. // that might overwrite properties contained by either
  310. // DS_KEY_SPOOLER or DS_KEY_DRIVER.
  311. // Ignore the return value since publishing of DS_KEY_USER values
  312. // is not critical
  313. //
  314. if (pIniPrinter->DsKeyUpdate & DS_KEY_USER) {
  315. CopyRegistry2Ds(hPrinter, DS_KEY_USER, pADs);
  316. }
  317. // Update Spooler - updates from Registry
  318. if (pIniPrinter->DsKeyUpdate & DS_KEY_SPOOLER) {
  319. hr = CopyRegistry2Ds(hPrinter, DS_KEY_SPOOLER, pADs);
  320. BAIL_ON_FAILURE(hr);
  321. }
  322. //
  323. // Update Driver - updates from Registry
  324. //
  325. if (pIniPrinter->DsKeyUpdate & DS_KEY_DRIVER) {
  326. hr = CopyRegistry2Ds(hPrinter, DS_KEY_DRIVER, pADs);
  327. //
  328. // Ignore missing key
  329. //
  330. if (HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND)
  331. hr = S_OK;
  332. BAIL_ON_FAILURE(hr);
  333. }
  334. error:
  335. if (pADs)
  336. pADs->Release();
  337. if (bImpersonating)
  338. pIniPrinter->pIniSpooler->hClusterToken = RevertToPrinterSelf();
  339. return hr;
  340. }
  341. HRESULT
  342. DsDeletePQObject(
  343. HANDLE hPrinter
  344. )
  345. {
  346. PSPOOL pSpool = (PSPOOL) hPrinter;
  347. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  348. IADsContainer *pADsContainer = NULL;
  349. IADs *pADs = NULL;
  350. HRESULT hr = E_FAIL;
  351. WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE];
  352. BOOL bImpersonating = FALSE;
  353. DWORD dwError;
  354. //
  355. // This routine is called when AddClusterAce failed. Even if we faild deleteing the object,
  356. // we really want to clean up the pIniPrinter structure so that we prevent the case where
  357. // the object stays forever in pending un/publishing.
  358. // That's because the other cluster node fails to delete/update it
  359. // since the printQueue object doesn't have the cluster user ace added. Pruner also fails to delete it
  360. // since the PrintQueue's GUID matches the pIniPrinter's GUID.
  361. //
  362. SplOutSem();
  363. hr = GetPrintQueueContainer(hPrinter, &pADsContainer, &pADs);
  364. BAIL_ON_FAILURE(hr);
  365. //
  366. // Delete Printer Object
  367. //
  368. hr = pADsContainer->Delete(SPLDS_PRINTER_CLASS, pIniPrinter->pszCN);
  369. DBGMSG(DBG_EXEC,("DsPrinterUnpublish FAILED: %x, %ws\n", hr, pIniPrinter->pszCN));
  370. BAIL_ON_FAILURE(hr);
  371. error:
  372. if (pADs)
  373. pADs->Release();
  374. if (pADsContainer)
  375. pADsContainer->Release();
  376. pIniPrinter->DsKeyUpdate = 0;
  377. FreeSplStr(pIniPrinter->pszObjectGUID);
  378. pIniPrinter->pszObjectGUID = NULL;
  379. FreeSplStr(pIniPrinter->pszCN);
  380. pIniPrinter->pszCN = NULL;
  381. FreeSplStr(pIniPrinter->pszDN);
  382. pIniPrinter->pszDN = NULL;
  383. return hr;
  384. }
  385. HRESULT
  386. DsPrinterUnpublish(
  387. HANDLE hPrinter
  388. )
  389. {
  390. PSPOOL pSpool = (PSPOOL) hPrinter;
  391. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  392. IADsContainer *pADsContainer = NULL;
  393. IADs *pADs = NULL;
  394. HRESULT hr = E_FAIL;
  395. WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE];
  396. BOOL bImpersonating = FALSE;
  397. DWORD dwError;
  398. SplOutSem();
  399. //
  400. // If we are a Cluster, impersonate the Cluster User
  401. //
  402. if (pIniPrinter->pIniSpooler->hClusterToken != INVALID_HANDLE_VALUE) {
  403. //
  404. // Impersonate the client
  405. //
  406. if (!ImpersonatePrinterClient(pIniPrinter->pIniSpooler->hClusterToken)) {
  407. dwError = GetLastError();
  408. DBGMSG(DBG_WARNING,("DsPrinterUnpublish FAILED: %d\n", dwError));
  409. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwError);
  410. goto error;
  411. }
  412. bImpersonating = TRUE;
  413. }
  414. hr = GetPrintQueueContainer(hPrinter, &pADsContainer, &pADs);
  415. BAIL_ON_FAILURE(hr);
  416. //
  417. // Delete Printer Object
  418. //
  419. hr = pADsContainer->Delete(SPLDS_PRINTER_CLASS, pIniPrinter->pszCN);
  420. DBGMSG(DBG_EXEC,("DsPrinterUnpublish FAILED: %x, %ws\n", hr, pIniPrinter->pszCN));
  421. BAIL_ON_FAILURE(hr);
  422. error:
  423. if (bImpersonating)
  424. pIniPrinter->pIniSpooler->hClusterToken = RevertToPrinterSelf();
  425. if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT) ||
  426. HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND ||
  427. HRESULT_CODE(hr) == ERROR_PATH_NOT_FOUND) {
  428. hr = S_OK;
  429. SplLogEvent( pIniPrinter->pIniSpooler,
  430. gdwLogDsEvents & LOG_INFO,
  431. MSG_MISSING_PRINTER_UNPUBLISHED,
  432. FALSE,
  433. pIniPrinter->pName,
  434. NULL );
  435. } else if (SUCCEEDED(hr)) {
  436. SplLogEvent( pIniPrinter->pIniSpooler,
  437. gdwLogDsEvents & LOG_INFO,
  438. MSG_PRINTER_UNPUBLISHED,
  439. FALSE,
  440. pIniPrinter->pszCN,
  441. pIniPrinter->pszDN,
  442. NULL );
  443. } else if(pIniPrinter->pszCN && pIniPrinter->pszDN) {
  444. StringCchPrintf(ErrorBuffer, COUNTOF(ErrorBuffer), L"%x", hr);
  445. SplLogEvent( pIniPrinter->pIniSpooler,
  446. gdwLogDsEvents & LOG_ERROR,
  447. MSG_CANT_DELETE_PRINTQUEUE,
  448. FALSE,
  449. pIniPrinter->pszCN,
  450. pIniPrinter->pszDN,
  451. ErrorBuffer,
  452. NULL );
  453. }
  454. if (SUCCEEDED(hr)) {
  455. pIniPrinter->DsKeyUpdate = 0;
  456. FreeSplStr(pIniPrinter->pszObjectGUID);
  457. pIniPrinter->pszObjectGUID = NULL;
  458. FreeSplStr(pIniPrinter->pszCN);
  459. pIniPrinter->pszCN = NULL;
  460. FreeSplStr(pIniPrinter->pszDN);
  461. pIniPrinter->pszDN = NULL;
  462. } else {
  463. pIniPrinter->DsKeyUpdate = DS_KEY_UNPUBLISH;
  464. }
  465. if (pADs)
  466. pADs->Release();
  467. if (pADsContainer)
  468. pADsContainer->Release();
  469. if (pIniPrinter->DsKeyUpdate)
  470. hr = ERROR_IO_PENDING;
  471. return hr;
  472. }
  473. LPCWSTR
  474. MapDSFlag2DSKey(
  475. DWORD Flag
  476. )
  477. {
  478. DWORD idx;
  479. LPCWSTR pKey = NULL;
  480. struct DSEntry
  481. {
  482. DWORD Flag;
  483. LPCWSTR pKey;
  484. };
  485. static DSEntry DSKeys [] = {
  486. {DS_KEY_SPOOLER , SPLDS_SPOOLER_KEY},
  487. {DS_KEY_DRIVER , SPLDS_DRIVER_KEY},
  488. {DS_KEY_USER , SPLDS_USER_KEY},
  489. {0 , NULL},
  490. };
  491. for (idx = 0; DSKeys[idx].pKey; idx++) {
  492. if(DSKeys[idx].Flag & Flag) {
  493. pKey = DSKeys[idx].pKey;
  494. }
  495. }
  496. return pKey;
  497. }
  498. HRESULT
  499. CopyRegistry2Ds(
  500. HANDLE hPrinter,
  501. DWORD Flag,
  502. IADs *pADs
  503. )
  504. {
  505. HRESULT hr = ERROR_SUCCESS;
  506. DWORD i;
  507. DWORD dwLDAPError;
  508. DWORD cbEnumValues = 0;
  509. PPRINTER_ENUM_VALUES pEnumValues = NULL;
  510. DWORD nEnumValues;
  511. DWORD dwResult;
  512. WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE];
  513. BSTR bstrADsPath = NULL;
  514. PINIPRINTER pIniPrinter = ((PSPOOL)hPrinter)->pIniPrinter;
  515. LPCWSTR pKey = MapDSFlag2DSKey(Flag);
  516. #if DBG
  517. EnterSplSem();
  518. DBGMSG(DBG_EXEC, ("Mass Publish %ws", ((PSPOOL)hPrinter)->pIniPrinter->pName));
  519. LeaveSplSem();
  520. #endif
  521. //
  522. // Enumerate and Publish Key
  523. //
  524. dwResult = SplEnumPrinterDataEx( hPrinter,
  525. pKey,
  526. (LPBYTE) pEnumValues,
  527. cbEnumValues,
  528. &cbEnumValues,
  529. &nEnumValues
  530. );
  531. if (dwResult != ERROR_MORE_DATA) {
  532. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  533. if( HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND && Flag != DS_KEY_SPOOLER) {
  534. goto IgnoreError;
  535. }
  536. else {
  537. goto error;
  538. }
  539. }
  540. if (!(pEnumValues = (PPRINTER_ENUM_VALUES) AllocSplMem(cbEnumValues))) {
  541. DBGMSG(DBG_EXEC,("CopyRegistry2Ds EnumPrinterDataEx FAILED: %d\n", GetLastError()));
  542. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
  543. BAIL_ON_FAILURE(hr);
  544. }
  545. dwResult = SplEnumPrinterDataEx( hPrinter,
  546. pKey,
  547. (LPBYTE) pEnumValues,
  548. cbEnumValues,
  549. &cbEnumValues,
  550. &nEnumValues
  551. );
  552. if (dwResult != ERROR_SUCCESS) {
  553. DBGMSG(DBG_EXEC,("CopyRegistry2Ds 2nd EnumPrinterDataEx FAILED: %d\n", GetLastError()));
  554. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  555. if( HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND && Flag != DS_KEY_SPOOLER) {
  556. goto IgnoreError;
  557. }
  558. else {
  559. goto error;
  560. }
  561. }
  562. //
  563. // Mass publish
  564. //
  565. for (i = 0 ; i < nEnumValues ; ++i) {
  566. hr = PublishDsData( pADs,
  567. pEnumValues[i].pValueName,
  568. pEnumValues[i].dwType,
  569. (PBYTE) pEnumValues[i].pData);
  570. //
  571. // Don't bail out on failure to put a specific property
  572. //
  573. if (FAILED(hr)) {
  574. if (pEnumValues[i].pValueName) {
  575. DBGMSG(DBG_EXEC, ("Put property failed: %x, %ws\n", hr, pEnumValues[i].pValueName));
  576. } else {
  577. DBGMSG(DBG_EXEC, ("Put property failed: %x\n", hr));
  578. }
  579. } else {
  580. DBGMSG(DBG_EXEC, ("Put %ws succeeded\n", pEnumValues[i].pValueName));
  581. }
  582. }
  583. hr = pADs->SetInfo();
  584. //
  585. // Mass publishing failed, now try Setting on every Put
  586. //
  587. if (SUCCEEDED(hr)) {
  588. DBGMSG( DBG_EXEC, ("Mass Publishing Succeeded for %ws\n", pKey) );
  589. } else {
  590. if (HRESULT_CODE(hr) == ERROR_EXTENDED_ERROR)
  591. ADsGetLastError(&dwLDAPError, NULL, 0, NULL, 0);
  592. else
  593. dwLDAPError = hr;
  594. DBGMSG( DBG_EXEC, ("Mass Publishing FAILED for %ws: %x\n", pKey, dwLDAPError) );
  595. // Now we have to try SetInfo/GetInfo on every Put.
  596. // If the DS lacks a spooler property, then the spooler will never
  597. // be able to publish any properties. Also, we'll fail if duplicate
  598. // strings exist in REG_MULTISZ attributes.
  599. // Maybe it is better to publish what we can,
  600. // but this requires calling SetInfo() for every property, which defeats the cache.
  601. // Alternatively, we could try doing the single SetInfo once and if that fails, resort
  602. // to the SetInfo on every Put.
  603. // Additionally, when SetInfo fails it is necessary to call GetInfo on that property
  604. // in order to clear the cache's update flag for the property. When SetInfo fails
  605. // it does not clear the update flag: the update flag is only cleared when SetInfo
  606. // succeeds. Not calling GetInfo will result in SetInfo() errors on all subsequent
  607. // attempts to publish a property.
  608. //
  609. // Refresh the cache
  610. //
  611. hr = pADs->GetInfo();
  612. BAIL_ON_FAILURE(hr);
  613. for (i = 0 ; i < nEnumValues ; ++i) {
  614. hr = PublishDsData( pADs,
  615. pEnumValues[i].pValueName,
  616. pEnumValues[i].dwType,
  617. (PBYTE) pEnumValues[i].pData);
  618. //
  619. // Don't bail out on failure to put a specific property
  620. //
  621. if (FAILED(hr)) {
  622. if (pEnumValues[i].pValueName) {
  623. DBGMSG(DBG_EXEC, ("Put property failed: %x, %ws\n", hr, pEnumValues[i].pValueName));
  624. } else {
  625. DBGMSG(DBG_EXEC, ("Put property failed: %x\n", hr));
  626. }
  627. StringCchPrintf(ErrorBuffer, COUNTOF(ErrorBuffer), L"%x", hr);
  628. hr = pADs->get_ADsPath(&bstrADsPath);
  629. if (SUCCEEDED(hr)) {
  630. SplLogEvent( ((PSPOOL) hPrinter)->pIniSpooler,
  631. gdwLogDsEvents & LOG_WARNING,
  632. MSG_CANT_PUBLISH_PROPERTY,
  633. FALSE,
  634. pEnumValues[i].pValueName ? pEnumValues[i].pValueName : L"NULLName",
  635. bstrADsPath,
  636. ErrorBuffer,
  637. NULL );
  638. SysFreeString(bstrADsPath);
  639. }
  640. } else {
  641. DBGMSG(DBG_EXEC, ("Put2 %ws succeeded\n", pEnumValues[i].pValueName));
  642. }
  643. hr = pADs->SetInfo();
  644. if (FAILED(hr)) {
  645. if (HRESULT_CODE(hr) == ERROR_EXTENDED_ERROR)
  646. ADsGetLastError(&dwLDAPError, NULL, 0, NULL, 0);
  647. if (pEnumValues[i].dwType == REG_SZ)
  648. DBGMSG(DBG_EXEC, ("PUBLISH FAILED: %ws, \"%ws\", %x\n", pEnumValues[i].pValueName,
  649. (LPWSTR) pEnumValues[i].pData,
  650. dwLDAPError));
  651. else
  652. DBGMSG(DBG_EXEC, ("PUBLISH FAILED: %ws, %x\n", pEnumValues[i].pValueName, dwLDAPError));
  653. StringCchPrintf(ErrorBuffer, COUNTOF(ErrorBuffer), L"%x", hr);
  654. hr = pADs->get_ADsPath(&bstrADsPath);
  655. if (SUCCEEDED(hr)) {
  656. SplLogEvent( ((PSPOOL) hPrinter)->pIniSpooler,
  657. gdwLogDsEvents & LOG_WARNING,
  658. MSG_CANT_PUBLISH_PROPERTY,
  659. FALSE,
  660. pEnumValues[i].pValueName ? pEnumValues[i].pValueName : L"NULLName",
  661. bstrADsPath,
  662. ErrorBuffer,
  663. NULL );
  664. SysFreeString(bstrADsPath);
  665. }
  666. //
  667. // reset cache update flag
  668. // If this fails, there's nothing more that can be done except throw our hands up
  669. // in despair. If this fails, no spooler properties will ever be published.
  670. //
  671. hr = pADs->GetInfo();
  672. BAIL_ON_FAILURE(hr);
  673. }
  674. else {
  675. DBGMSG( DBG_EXEC, ("Published: %ws\n", pEnumValues[i].pValueName) );
  676. }
  677. }
  678. }
  679. IgnoreError:
  680. EnterSplSem();
  681. pIniPrinter->DsKeyUpdate &= ~Flag;
  682. if(!(pIniPrinter->DsKeyUpdate & (DS_KEY_SPOOLER | DS_KEY_DRIVER | DS_KEY_USER))) {
  683. pIniPrinter->DsKeyUpdate = 0;
  684. }
  685. LeaveSplSem();
  686. error:
  687. FreeSplMem(pEnumValues);
  688. return hr;
  689. }
  690. HRESULT
  691. PublishDsData(
  692. IADs *pADs,
  693. LPWSTR pValue,
  694. DWORD dwType,
  695. PBYTE pData
  696. )
  697. {
  698. HRESULT hr;
  699. BOOL bCreated = FALSE;
  700. switch (dwType) {
  701. case REG_SZ:
  702. hr = put_BSTR_Property(pADs, pValue, (LPWSTR) pData);
  703. break;
  704. case REG_MULTI_SZ:
  705. hr = put_MULTISZ_Property(pADs, pValue, (LPWSTR) pData);
  706. break;
  707. case REG_DWORD:
  708. hr = put_DWORD_Property(pADs, pValue, (DWORD *) pData);
  709. break;
  710. case REG_BINARY:
  711. hr = put_BOOL_Property(pADs, pValue, (BOOL *) pData);
  712. break;
  713. }
  714. return hr;
  715. }
  716. HRESULT
  717. PublishMandatoryProperties(
  718. HANDLE hPrinter,
  719. IADs *pADs
  720. )
  721. {
  722. PSPOOL pSpool = (PSPOOL) hPrinter;
  723. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  724. HRESULT hr, hrAce;
  725. WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE];
  726. #if DBG
  727. EnterSplSem();
  728. DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: %ws\n", pIniPrinter->pName));
  729. LeaveSplSem();
  730. #endif
  731. //
  732. // Since we are calling outside the Critical Section we set param 3 (bInSem) to false.
  733. //
  734. hr = SetMandatoryProperties(hPrinter, pADs, FALSE);
  735. DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: SMP result %d\n", hr));
  736. BAIL_ON_FAILURE(hr);
  737. hr = pADs->SetInfo();
  738. if (FAILED(hr)) {
  739. DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: SetInfo failed %d\n", hr));
  740. StringCchPrintf(ErrorBuffer, COUNTOF(ErrorBuffer), L"%x", hr);
  741. SplLogEvent( pSpool->pIniSpooler,
  742. gdwLogDsEvents & LOG_ERROR,
  743. MSG_CANT_PUBLISH_MANDATORY_PROPERTIES,
  744. FALSE,
  745. pIniPrinter->pszCN,
  746. pIniPrinter->pszDN,
  747. ErrorBuffer,
  748. NULL );
  749. //
  750. // If SetInfo returns ERROR_BUSY it means the object already exists.
  751. // We should have avoided this conflict when we created the CN because
  752. // we check for conflicts and generate a random name. Nonetheless, an
  753. // object could have appeared between the time we generated the CN and this SetInfo,
  754. // so failing here will let us try again and we'll generate a new name if we clear the
  755. // current one.
  756. //
  757. if (HRESULT_CODE(hr) == ERROR_BUSY) {
  758. FreeSplMem(pIniPrinter->pszCN);
  759. pIniPrinter->pszCN = NULL;
  760. FreeSplMem(pIniPrinter->pszDN);
  761. pIniPrinter->pszDN = NULL;
  762. }
  763. BAIL_ON_FAILURE(hr);
  764. }
  765. //
  766. // Get & Set ACE if we're a cluster. For clusters, we publish data in DS impersonating the cluster user.
  767. //
  768. //
  769. hrAce = AddClusterAce(pSpool, pADs);
  770. //
  771. // Get & store GUID
  772. //
  773. hr = GetGUID(pADs, &pIniPrinter->pszObjectGUID);
  774. //
  775. // Keep the first failure, if present
  776. //
  777. if (FAILED(hrAce)) {
  778. hr = hrAce;
  779. StringCchPrintf(ErrorBuffer, COUNTOF(ErrorBuffer), L"%x", hrAce);
  780. SplLogEvent( pSpool->pIniSpooler,
  781. gdwLogDsEvents & LOG_ERROR,
  782. MSG_CANT_ADD_CLUSTER_ACE,
  783. FALSE,
  784. pIniPrinter->pszCN,
  785. pIniPrinter->pszDN,
  786. ErrorBuffer,
  787. NULL );
  788. DsDeletePQObject(hPrinter);
  789. DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: AddClusterAce failed %d\n", hr));
  790. BAIL_ON_FAILURE(hr);
  791. }
  792. //
  793. // Unpublish if we can't add the cluster ace or get the GUID
  794. // If we can't get the GUID, unpublishing will fail, but internal flags
  795. // will be set correctly and pruner will delete the orphan
  796. //
  797. if (FAILED(hr)){
  798. DsPrinterUnpublish(hPrinter);
  799. DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: GetGuid failed %d\n", hr));
  800. BAIL_ON_FAILURE(hr);
  801. } else {
  802. DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: GetGuid success %ws\n",
  803. pIniPrinter->pszObjectGUID));
  804. }
  805. error:
  806. if (FAILED(hr)) {
  807. pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_PUBLISHED;
  808. }
  809. return hr;
  810. }
  811. HRESULT
  812. SetMandatoryProperties(
  813. HANDLE hPrinter,
  814. IADs *pADs,
  815. BOOL bInSem
  816. )
  817. {
  818. PSPOOL pSpool = (PSPOOL) hPrinter;
  819. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  820. WCHAR szBuffer[MAX_UNC_PRINTER_NAME + 1];
  821. DWORD dwResult;
  822. DWORD dwTemp;
  823. HRESULT hr;
  824. PWSTR pszServerName = NULL;
  825. //
  826. // Get FQDN of this machine
  827. // If we are calling from within the critical section we need to leave it
  828. // before making the network call.
  829. //
  830. if (bInSem) {
  831. SplInSem();
  832. LPWSTR szMachineName = AllocSplStr(pIniPrinter->pIniSpooler->pMachineName);
  833. dwResult = szMachineName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
  834. if (dwResult == ERROR_SUCCESS) {
  835. LeaveSplSem();
  836. SplOutSem();
  837. hr = GetDNSMachineName(szMachineName + 2, &pszServerName);
  838. FreeSplStr(szMachineName);
  839. EnterSplSem();
  840. }
  841. else {
  842. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  843. }
  844. }
  845. else {
  846. hr = GetDNSMachineName(pIniPrinter->pIniSpooler->pMachineName + 2, &pszServerName);
  847. }
  848. BAIL_ON_FAILURE(hr);
  849. //
  850. // UNC Printer Name
  851. // Build the UNC Printer Path
  852. //
  853. dwResult = StrNCatBuff(szBuffer, COUNTOF(szBuffer), L"\\\\", pszServerName, L"\\", pIniPrinter->pName, NULL);
  854. if (dwResult == ERROR_SUCCESS)
  855. {
  856. dwResult = SplSetPrinterDataEx(hPrinter,
  857. SPLDS_SPOOLER_KEY,
  858. SPLDS_UNC_NAME,
  859. REG_SZ,
  860. (PBYTE)szBuffer,
  861. (wcslen(szBuffer) + 1)*sizeof *szBuffer);
  862. }
  863. if (dwResult != ERROR_SUCCESS) {
  864. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  865. BAIL_ON_FAILURE(hr);
  866. }
  867. if (pADs) {
  868. hr = PublishDsData( pADs,
  869. SPLDS_UNC_NAME,
  870. REG_SZ,
  871. (PBYTE) szBuffer);
  872. BAIL_ON_FAILURE(hr);
  873. }
  874. //
  875. // versionNumber
  876. //
  877. dwTemp = DS_PRINTQUEUE_VERSION_WIN2000;
  878. dwResult = SplSetPrinterDataEx(
  879. hPrinter,
  880. SPLDS_SPOOLER_KEY,
  881. SPLDS_VERSION_NUMBER,
  882. REG_DWORD,
  883. (PBYTE) &dwTemp,
  884. sizeof dwTemp);
  885. if (dwResult != ERROR_SUCCESS) {
  886. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  887. BAIL_ON_FAILURE(hr);
  888. }
  889. if (pADs) {
  890. hr = PublishDsData( pADs,
  891. SPLDS_VERSION_NUMBER,
  892. REG_DWORD,
  893. (PBYTE) &dwTemp);
  894. BAIL_ON_FAILURE(hr);
  895. }
  896. //
  897. // ServerName (without \\)
  898. //
  899. dwResult = SplSetPrinterDataEx( hPrinter,
  900. SPLDS_SPOOLER_KEY,
  901. SPLDS_SERVER_NAME,
  902. REG_SZ,
  903. (PBYTE) pszServerName,
  904. (wcslen(pszServerName) + 1)*sizeof(WCHAR));
  905. if (dwResult != ERROR_SUCCESS) {
  906. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  907. BAIL_ON_FAILURE(hr);
  908. }
  909. if (pADs) {
  910. hr = PublishDsData( pADs,
  911. SPLDS_SERVER_NAME,
  912. REG_SZ,
  913. (PBYTE) pszServerName);
  914. BAIL_ON_FAILURE(hr);
  915. }
  916. //
  917. // ShortServerName (without \\)
  918. //
  919. dwResult = SplSetPrinterDataEx( hPrinter,
  920. SPLDS_SPOOLER_KEY,
  921. SPLDS_SHORT_SERVER_NAME,
  922. REG_SZ,
  923. (PBYTE) (pIniPrinter->pIniSpooler->pMachineName + 2),
  924. (wcslen(pIniPrinter->pIniSpooler->pMachineName + 2) + 1)*sizeof(WCHAR));
  925. if (dwResult != ERROR_SUCCESS) {
  926. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  927. BAIL_ON_FAILURE(hr);
  928. }
  929. if (pADs) {
  930. hr = PublishDsData( pADs,
  931. SPLDS_SHORT_SERVER_NAME,
  932. REG_SZ,
  933. (PBYTE) pIniPrinter->pIniSpooler->pMachineName + 2);
  934. BAIL_ON_FAILURE(hr);
  935. }
  936. //
  937. // printerName
  938. //
  939. dwResult = SplSetPrinterDataEx(
  940. hPrinter,
  941. SPLDS_SPOOLER_KEY,
  942. SPLDS_PRINTER_NAME,
  943. REG_SZ,
  944. (PBYTE) pIniPrinter->pName,
  945. pIniPrinter->pName ?
  946. (wcslen(pIniPrinter->pName) + 1)*sizeof *pIniPrinter->pName : 0);
  947. if (dwResult != ERROR_SUCCESS) {
  948. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  949. BAIL_ON_FAILURE(hr);
  950. }
  951. if (pADs) {
  952. hr = PublishDsData( pADs,
  953. SPLDS_PRINTER_NAME,
  954. REG_SZ,
  955. (PBYTE) pIniPrinter->pName);
  956. BAIL_ON_FAILURE(hr);
  957. }
  958. error:
  959. FreeSplStr(pszServerName);
  960. return hr;
  961. }
  962. VOID
  963. UpdateDsSpoolerKey(
  964. HANDLE hPrinter,
  965. DWORD dwVector
  966. )
  967. {
  968. PSPOOL pSpool = (PSPOOL) hPrinter;
  969. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  970. DWORD i, cchMultiSz, dwTemp;
  971. LPWSTR pString = NULL, pStr;
  972. DWORD dwResult = ERROR_SUCCESS;
  973. BOOL bSet = FALSE;
  974. BYTE Byte;
  975. PWSTR pszUrl = NULL;
  976. SplInSem();
  977. //
  978. // UpdateDsSpoolerKey - writes IniPrinter to registry
  979. //
  980. // Reg Value: Description
  981. //
  982. if (dwVector & BIT(I_PRINTER_COMMENT)) {
  983. dwResult = SplSetPrinterDataEx(
  984. hPrinter,
  985. SPLDS_SPOOLER_KEY,
  986. SPLDS_DESCRIPTION,
  987. REG_SZ,
  988. (PBYTE) pIniPrinter->pComment,
  989. pIniPrinter->pComment ?
  990. (wcslen(pIniPrinter->pComment) + 1)*sizeof *pIniPrinter->pComment : 0);
  991. bSet = TRUE;
  992. #if DBG
  993. if (dwResult != ERROR_SUCCESS)
  994. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: Description, %x\n", dwResult) );
  995. #endif
  996. }
  997. //
  998. // Reg Value: Driver-Name
  999. //
  1000. if (dwVector & BIT(I_PRINTER_DRIVER_NAME)) {
  1001. dwResult = SplSetPrinterDataEx(
  1002. hPrinter,
  1003. SPLDS_SPOOLER_KEY,
  1004. SPLDS_DRIVER_NAME,
  1005. REG_SZ,
  1006. (PBYTE) pIniPrinter->pIniDriver->pName,
  1007. pIniPrinter->pIniDriver->pName ?
  1008. (wcslen(pIniPrinter->pIniDriver->pName) + 1)*sizeof *pIniPrinter->pIniDriver->pName : 0);
  1009. bSet = TRUE;
  1010. #if DBG
  1011. if (dwResult != ERROR_SUCCESS)
  1012. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: DriverName, %x\n", dwResult) );
  1013. #endif
  1014. }
  1015. //
  1016. // Reg Value: Location
  1017. //
  1018. if (dwVector & BIT(I_PRINTER_LOCATION)) {
  1019. dwResult = SplSetPrinterDataEx(
  1020. hPrinter,
  1021. SPLDS_SPOOLER_KEY,
  1022. SPLDS_LOCATION,
  1023. REG_SZ,
  1024. (PBYTE) pIniPrinter->pLocation,
  1025. pIniPrinter->pLocation ?
  1026. (wcslen(pIniPrinter->pLocation) + 1)*sizeof *pIniPrinter->pLocation : 0);
  1027. bSet = TRUE;
  1028. #if DBG
  1029. if (dwResult != ERROR_SUCCESS)
  1030. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: Location, %x\n", dwResult) );
  1031. #endif
  1032. }
  1033. //
  1034. // Reg Value: portName
  1035. //
  1036. if (dwVector & BIT(I_PRINTER_PORT_NAME)) {
  1037. SIZE_T cchMultiSzCopy = 0;
  1038. for(i = cchMultiSz = 0 ; i < pIniPrinter->cPorts ; ++i)
  1039. cchMultiSz += wcslen(pIniPrinter->ppIniPorts[i]->pName) + 1;
  1040. cchMultiSz++; // final NULL of MULTI_SZ
  1041. if (!(pString = (LPWSTR) AllocSplMem(cchMultiSz * sizeof(WCHAR)))) {
  1042. dwResult = GetLastError();
  1043. goto error;
  1044. }
  1045. cchMultiSzCopy = cchMultiSz;
  1046. for(i = 0, pStr = pString ; i < pIniPrinter->cPorts ; ++i) {
  1047. StrCchCopyMultipleStr(pStr, cchMultiSzCopy, pIniPrinter->ppIniPorts[i]->pName, &pStr, &cchMultiSzCopy);
  1048. }
  1049. dwResult = SplSetPrinterDataEx(
  1050. hPrinter,
  1051. SPLDS_SPOOLER_KEY,
  1052. SPLDS_PORT_NAME,
  1053. REG_MULTI_SZ,
  1054. (PBYTE) pString,
  1055. cchMultiSz * sizeof(WCHAR));
  1056. bSet = TRUE;
  1057. #if DBG
  1058. if (dwResult != ERROR_SUCCESS)
  1059. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: PortName, %x\n", dwResult) );
  1060. #endif
  1061. }
  1062. //
  1063. // Reg Value: startTime
  1064. //
  1065. if (dwVector & BIT(I_PRINTER_START_TIME)) {
  1066. dwResult = SplSetPrinterDataEx(
  1067. hPrinter,
  1068. SPLDS_SPOOLER_KEY,
  1069. SPLDS_PRINT_START_TIME,
  1070. REG_DWORD,
  1071. (PBYTE) &pIniPrinter->StartTime,
  1072. sizeof pIniPrinter->StartTime);
  1073. bSet = TRUE;
  1074. #if DBG
  1075. if (dwResult != ERROR_SUCCESS)
  1076. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: StartTime, %x\n", dwResult) );
  1077. #endif
  1078. }
  1079. //
  1080. // Reg Value: endTime
  1081. //
  1082. if (dwVector & BIT(I_PRINTER_UNTIL_TIME)) {
  1083. dwResult = SplSetPrinterDataEx(
  1084. hPrinter,
  1085. SPLDS_SPOOLER_KEY,
  1086. SPLDS_PRINT_END_TIME,
  1087. REG_DWORD,
  1088. (PBYTE) &pIniPrinter->UntilTime,
  1089. sizeof pIniPrinter->UntilTime);
  1090. bSet = TRUE;
  1091. #if DBG
  1092. if (dwResult != ERROR_SUCCESS)
  1093. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: EndTime, %x\n", dwResult) );
  1094. #endif
  1095. }
  1096. //
  1097. // Reg Value: printerName
  1098. //
  1099. if (dwVector & BIT(I_PRINTER_PRINTER_NAME)) {
  1100. dwResult = SplSetPrinterDataEx(
  1101. hPrinter,
  1102. SPLDS_SPOOLER_KEY,
  1103. SPLDS_PRINTER_NAME,
  1104. REG_SZ,
  1105. (PBYTE) pIniPrinter->pName,
  1106. pIniPrinter->pName ?
  1107. (wcslen(pIniPrinter->pName) + 1)*sizeof *pIniPrinter->pName : 0);
  1108. bSet = TRUE;
  1109. #if DBG
  1110. if (dwResult != ERROR_SUCCESS)
  1111. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: PrinterName, %x\n", dwResult) );
  1112. #endif
  1113. }
  1114. //
  1115. // Reg Value: keepPrintedJobs
  1116. //
  1117. if (dwVector & BIT(I_PRINTER_ATTRIBUTES)) {
  1118. Byte = (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS) ? 1 : 0;
  1119. dwResult = SplSetPrinterDataEx(
  1120. hPrinter,
  1121. SPLDS_SPOOLER_KEY,
  1122. SPLDS_PRINT_KEEP_PRINTED_JOBS,
  1123. REG_BINARY,
  1124. &Byte,
  1125. sizeof Byte);
  1126. bSet = TRUE;
  1127. #if DBG
  1128. if (dwResult != ERROR_SUCCESS)
  1129. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: KeepPrintedJobs, %x\n", dwResult) );
  1130. #endif
  1131. }
  1132. //
  1133. // Reg Value: printSeparatorFile
  1134. //
  1135. if (dwVector & BIT(I_PRINTER_SEPFILE)) {
  1136. dwResult = SplSetPrinterDataEx(
  1137. hPrinter,
  1138. SPLDS_SPOOLER_KEY,
  1139. SPLDS_PRINT_SEPARATOR_FILE,
  1140. REG_SZ,
  1141. (PBYTE) pIniPrinter->pSepFile,
  1142. pIniPrinter->pSepFile ?
  1143. (wcslen(pIniPrinter->pSepFile) + 1)*sizeof *pIniPrinter->pSepFile : 0);
  1144. bSet = TRUE;
  1145. #if DBG
  1146. if (dwResult != ERROR_SUCCESS)
  1147. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: SeparatorFile, %x\n", dwResult) );
  1148. #endif
  1149. }
  1150. //
  1151. // Reg Value: printShareName
  1152. //
  1153. if (dwVector & BIT(I_PRINTER_SHARE_NAME)) {
  1154. dwResult = SplSetPrinterDataEx(
  1155. hPrinter,
  1156. SPLDS_SPOOLER_KEY,
  1157. SPLDS_PRINT_SHARE_NAME,
  1158. REG_SZ,
  1159. (PBYTE) pIniPrinter->pShareName,
  1160. pIniPrinter->pShareName ?
  1161. (wcslen(pIniPrinter->pShareName) + 1)*sizeof *pIniPrinter->pShareName : 0);
  1162. bSet = TRUE;
  1163. #if DBG
  1164. if (dwResult != ERROR_SUCCESS)
  1165. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: ShareName, %x\n", dwResult) );
  1166. #endif
  1167. }
  1168. //
  1169. // Reg Value: printSpooling
  1170. //
  1171. if (dwVector & BIT(I_PRINTER_ATTRIBUTES)) {
  1172. if (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_DIRECT) {
  1173. pStr = L"PrintDirect";
  1174. } else if (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST) {
  1175. pStr = L"PrintAfterSpooled";
  1176. } else {
  1177. pStr = L"PrintWhileSpooling";
  1178. }
  1179. dwResult = SplSetPrinterDataEx(
  1180. hPrinter,
  1181. SPLDS_SPOOLER_KEY,
  1182. SPLDS_PRINT_SPOOLING,
  1183. REG_SZ,
  1184. (PBYTE) pStr,
  1185. (wcslen(pStr) + 1)*sizeof *pStr);
  1186. bSet = TRUE;
  1187. #if DBG
  1188. if (dwResult != ERROR_SUCCESS)
  1189. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: PrintSpooling, %x\n", dwResult) );
  1190. #endif
  1191. }
  1192. //
  1193. //Reg Value: priority
  1194. //
  1195. if (dwVector & BIT(I_PRINTER_PRIORITY)) {
  1196. dwResult = SplSetPrinterDataEx(
  1197. hPrinter,
  1198. SPLDS_SPOOLER_KEY,
  1199. SPLDS_PRIORITY,
  1200. REG_DWORD,
  1201. (PBYTE) &pIniPrinter->Priority,
  1202. sizeof pIniPrinter->Priority);
  1203. bSet = TRUE;
  1204. #if DBG
  1205. if (dwResult != ERROR_SUCCESS)
  1206. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: Priority, %x\n", dwResult) );
  1207. #endif
  1208. }
  1209. //
  1210. // Non-Info2 properties
  1211. //
  1212. if (bSet) {
  1213. //
  1214. // Since we are calling from inside the Critical Section we set param 3 (bInSem) to TRUE
  1215. //
  1216. SetMandatoryProperties(hPrinter, NULL, TRUE);
  1217. //
  1218. // Reg Value: URL
  1219. //
  1220. if (pszUrl = GetPrinterUrl(pSpool)) {
  1221. dwResult = SplSetPrinterDataEx(
  1222. hPrinter,
  1223. SPLDS_SPOOLER_KEY,
  1224. SPLDS_URL,
  1225. REG_SZ,
  1226. (PBYTE) pszUrl,
  1227. (wcslen(pszUrl) + 1)*sizeof *pszUrl);
  1228. #if DBG
  1229. if (dwResult != ERROR_SUCCESS)
  1230. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: URL, %x\n", dwResult) );
  1231. #endif
  1232. }
  1233. //
  1234. // Reg Value:Immortal
  1235. //
  1236. dwResult = ImmortalPolicy();
  1237. dwResult = SplSetPrinterDataEx(
  1238. hPrinter,
  1239. SPLDS_SPOOLER_KEY,
  1240. SPLDS_FLAGS,
  1241. REG_DWORD,
  1242. (PBYTE) &dwResult,
  1243. sizeof(dwResult));
  1244. #if DBG
  1245. if (dwResult != ERROR_SUCCESS)
  1246. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: Immortal, %x\n", dwResult) );
  1247. #endif
  1248. }
  1249. error:
  1250. FreeSplMem(pszUrl);
  1251. FreeSplMem(pString);
  1252. }
  1253. VOID
  1254. UpdateDsDriverKey(
  1255. HANDLE hPrinter
  1256. )
  1257. {
  1258. PSPOOL pSpool = (PSPOOL) hPrinter;
  1259. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  1260. DWORD i, cbBytes;
  1261. WCHAR szBuffer[33];
  1262. LPWSTR pString, pStr;
  1263. BOOL bResult;
  1264. DWORD dwResult;
  1265. BYTE Byte;
  1266. LPWSTR pOutput = NULL, pTemp = NULL, pTemp1 = NULL;
  1267. DWORD cOutputBytes, cTempBytes;
  1268. POINTS point;
  1269. DWORD dwServerMajorVersion, dwServerMinorVersion;
  1270. DWORD cbNeeded;
  1271. HANDLE hModule = FALSE;
  1272. PDEVCAP pDevCap;
  1273. PSPLDEVCAP pSplDevCaps;
  1274. HANDLE hDevCapPrinter = NULL;
  1275. WCHAR pPrinterName[MAX_UNC_PRINTER_NAME];
  1276. WCHAR Buf[100];
  1277. BOOL bInSplSem = TRUE;
  1278. DWORD dwTemp, dwPrintRate, dwPrintRateUnit, dwPrintPPM;
  1279. //
  1280. // DeviceCapability properties
  1281. //
  1282. SplInSem();
  1283. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: %ws\n", pIniPrinter->pName));
  1284. pOutput = (LPWSTR) AllocSplMem(cOutputBytes = 200);
  1285. if (!pOutput)
  1286. goto error;
  1287. pTemp = (LPWSTR) AllocSplMem(cTempBytes = 200);
  1288. if (!pTemp)
  1289. goto error;
  1290. //
  1291. // Get & Load Driver
  1292. //
  1293. PINIENVIRONMENT pIniEnvironment;
  1294. pIniEnvironment = FindEnvironment(szEnvironment, pSpool->pIniSpooler);
  1295. if (pIniEnvironment) {
  1296. WCHAR szConfigFile[INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH + 1];
  1297. PINIVERSION pIniVersion;
  1298. pIniVersion = FindVersionForDriver(pIniEnvironment, pIniPrinter->pIniDriver);
  1299. if (!pIniVersion)
  1300. goto error;
  1301. if( !(i = GetDriverVersionDirectory(szConfigFile,
  1302. (DWORD)(COUNTOF(szConfigFile) - wcslen(pIniPrinter->pIniDriver->pConfigFile) - 1),
  1303. pSpool->pIniSpooler,
  1304. pIniEnvironment,
  1305. pIniVersion,
  1306. pIniPrinter->pIniDriver,
  1307. NULL)) ) {
  1308. goto error;
  1309. }
  1310. if (!BoolFromStatus(StrNCatBuff(&szConfigFile[i], COUNTOF(szConfigFile) - i, L"\\", pIniPrinter->pIniDriver->pConfigFile, NULL))) {
  1311. goto error;
  1312. }
  1313. if (!(hModule = LoadLibrary(szConfigFile))) {
  1314. goto error;
  1315. }
  1316. if (!(pDevCap = reinterpret_cast<PDEVCAP>(GetProcAddress(hModule, "DrvDeviceCapabilities")))) {
  1317. goto error;
  1318. }
  1319. pSplDevCaps = reinterpret_cast<PSPLDEVCAP>(GetProcAddress(hModule, (LPCSTR) MAKELPARAM(254, 0)));
  1320. } else {
  1321. goto error;
  1322. }
  1323. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: driver found\n"));
  1324. INCPRINTERREF(pIniPrinter);
  1325. //
  1326. // We need to use UNC format so we go to the right pIniSpooler.
  1327. // For instance, we won't find the printer if it's in the cluster pIniSpooler and we don't use
  1328. // the virtual cluster name (\\server\printer).
  1329. //
  1330. if ((dwTemp = StrNCatBuff(pPrinterName,
  1331. MAX_UNC_PRINTER_NAME,
  1332. pIniPrinter->pIniSpooler->pMachineName,
  1333. L"\\",
  1334. pIniPrinter->pName,
  1335. L",LocalsplOnly",
  1336. NULL)) != ERROR_SUCCESS)
  1337. {
  1338. SetLastError(dwTemp);
  1339. goto error;
  1340. }
  1341. LeaveSplSem();
  1342. bInSplSem = FALSE;
  1343. if (!(*pfnOpenPrinter)(pPrinterName, &hDevCapPrinter, NULL)) {
  1344. dwResult = GetLastError();
  1345. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: OpenPrinter failed %d\n",
  1346. dwResult));
  1347. goto error;
  1348. }
  1349. //
  1350. // DS property: printBinNames
  1351. //
  1352. if (!DevCapMultiSz( hPrinter,
  1353. hDevCapPrinter,
  1354. pDevCap,
  1355. NULL,
  1356. pPrinterName,
  1357. DC_BINNAMES,
  1358. 24,
  1359. SPLDS_PRINT_BIN_NAMES)) {
  1360. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_BINNAMES failed %d\n", GetLastError()));
  1361. }
  1362. //
  1363. // DS property: printCollate (awaiting DC_COLLATE)
  1364. //
  1365. _try {
  1366. dwResult = (*pDevCap)( hDevCapPrinter,
  1367. pPrinterName,
  1368. DC_COLLATE,
  1369. NULL,
  1370. NULL);
  1371. } _except(1) {
  1372. SetLastError(GetExceptionCode());
  1373. dwResult = GDI_ERROR;
  1374. }
  1375. if (dwResult != GDI_ERROR) {
  1376. dwResult = SplSetPrinterDataEx(
  1377. hPrinter,
  1378. SPLDS_DRIVER_KEY,
  1379. SPLDS_PRINT_COLLATE,
  1380. REG_BINARY,
  1381. (PBYTE) &dwResult,
  1382. sizeof(BYTE));
  1383. #if DBG
  1384. if (dwResult != ERROR_SUCCESS)
  1385. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Collate, %x\n", dwResult) );
  1386. #endif
  1387. } else {
  1388. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_COLLATE failed %d\n", GetLastError()));
  1389. }
  1390. //
  1391. // DS property: printColor
  1392. //
  1393. _try {
  1394. dwResult = (*pDevCap)( hDevCapPrinter,
  1395. pPrinterName,
  1396. DC_COLORDEVICE,
  1397. NULL,
  1398. NULL);
  1399. } _except(1) {
  1400. SetLastError(GetExceptionCode());
  1401. dwResult = GDI_ERROR;
  1402. }
  1403. if (dwResult == GDI_ERROR) {
  1404. //
  1405. // Try alternative method
  1406. //
  1407. dwResult = ThisIsAColorPrinter(pIniPrinter->pName);
  1408. } else {
  1409. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_COLORDEVICE failed %d\n", GetLastError()));
  1410. }
  1411. dwResult = SplSetPrinterDataEx(
  1412. hPrinter,
  1413. SPLDS_DRIVER_KEY,
  1414. SPLDS_PRINT_COLOR,
  1415. REG_BINARY,
  1416. (PBYTE) &dwResult,
  1417. sizeof(BYTE));
  1418. #if DBG
  1419. if (dwResult != ERROR_SUCCESS)
  1420. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Color, %x\n", dwResult) );
  1421. #endif
  1422. //
  1423. // DS property: printDuplexSupported
  1424. //
  1425. _try {
  1426. dwResult = (*pDevCap)( hDevCapPrinter,
  1427. pPrinterName,
  1428. DC_DUPLEX,
  1429. NULL,
  1430. NULL);
  1431. } _except(1) {
  1432. SetLastError(GetExceptionCode());
  1433. dwResult = GDI_ERROR;
  1434. }
  1435. if (dwResult != GDI_ERROR) {
  1436. dwResult = !!dwResult;
  1437. dwResult = SplSetPrinterDataEx(
  1438. hPrinter,
  1439. SPLDS_DRIVER_KEY,
  1440. SPLDS_PRINT_DUPLEX_SUPPORTED,
  1441. REG_BINARY,
  1442. (PBYTE) &dwResult,
  1443. sizeof(BYTE));
  1444. #if DBG
  1445. if (dwResult != ERROR_SUCCESS)
  1446. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Duplex, %x\n", dwResult) );
  1447. #endif
  1448. } else {
  1449. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_DUPLEX failed %d\n", GetLastError()));
  1450. }
  1451. //
  1452. // DS property: printStaplingSupported
  1453. //
  1454. _try {
  1455. dwResult = (*pDevCap)( hDevCapPrinter,
  1456. pPrinterName,
  1457. DC_STAPLE,
  1458. NULL,
  1459. NULL);
  1460. } _except(1) {
  1461. SetLastError(GetExceptionCode());
  1462. dwResult = GDI_ERROR;
  1463. }
  1464. if (dwResult != GDI_ERROR) {
  1465. dwResult = SplSetPrinterDataEx(
  1466. hPrinter,
  1467. SPLDS_DRIVER_KEY,
  1468. SPLDS_PRINT_STAPLING_SUPPORTED,
  1469. REG_BINARY,
  1470. (PBYTE) &dwResult,
  1471. sizeof(BYTE));
  1472. #if DBG
  1473. if (dwResult != ERROR_SUCCESS)
  1474. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Duplex, %x\n", dwResult) );
  1475. #endif
  1476. } else {
  1477. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_STAPLE failed %d\n", GetLastError()));
  1478. }
  1479. //
  1480. // DS property: printMaxXExtent & printMaxYExtent
  1481. //
  1482. _try {
  1483. dwResult = (*pDevCap)( hDevCapPrinter,
  1484. pPrinterName,
  1485. DC_MAXEXTENT,
  1486. NULL,
  1487. NULL);
  1488. } _except(1) {
  1489. SetLastError(GetExceptionCode());
  1490. dwResult = GDI_ERROR;
  1491. }
  1492. if (dwResult != GDI_ERROR) {
  1493. *((DWORD *) &point) = dwResult;
  1494. dwTemp = (DWORD) point.x;
  1495. dwResult = SplSetPrinterDataEx(
  1496. hPrinter,
  1497. SPLDS_DRIVER_KEY,
  1498. SPLDS_PRINT_MAX_X_EXTENT,
  1499. REG_DWORD,
  1500. (PBYTE) &dwTemp,
  1501. sizeof(DWORD));
  1502. #if DBG
  1503. if (dwResult != ERROR_SUCCESS)
  1504. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: MaxXExtent, %x\n", dwResult) );
  1505. #endif
  1506. dwTemp = (DWORD) point.y;
  1507. dwResult = SplSetPrinterDataEx(
  1508. hPrinter,
  1509. SPLDS_DRIVER_KEY,
  1510. SPLDS_PRINT_MAX_Y_EXTENT,
  1511. REG_DWORD,
  1512. (PBYTE) &dwTemp,
  1513. sizeof(DWORD));
  1514. #if DBG
  1515. if (dwResult != ERROR_SUCCESS)
  1516. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: MaxYExtent, %x\n", dwResult) );
  1517. #endif
  1518. } else {
  1519. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_MAXEXTENT failed %d\n", GetLastError()));
  1520. }
  1521. //
  1522. // DS property: printMinXExtent & printMinYExtent
  1523. //
  1524. _try {
  1525. dwResult = (*pDevCap)( hDevCapPrinter,
  1526. pPrinterName,
  1527. DC_MINEXTENT,
  1528. NULL,
  1529. NULL);
  1530. } _except(1) {
  1531. SetLastError(GetExceptionCode());
  1532. dwResult = GDI_ERROR;
  1533. }
  1534. if (dwResult != GDI_ERROR) {
  1535. *((DWORD *) &point) = dwResult;
  1536. dwTemp = (DWORD) point.x;
  1537. dwResult = SplSetPrinterDataEx(
  1538. hPrinter,
  1539. SPLDS_DRIVER_KEY,
  1540. SPLDS_PRINT_MIN_X_EXTENT,
  1541. REG_DWORD,
  1542. (PBYTE) &dwTemp,
  1543. sizeof(DWORD));
  1544. #if DBG
  1545. if (dwResult != ERROR_SUCCESS)
  1546. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: MinXExtent, %x\n", dwResult) );
  1547. #endif
  1548. dwTemp = (DWORD) point.y;
  1549. dwResult = SplSetPrinterDataEx(
  1550. hPrinter,
  1551. SPLDS_DRIVER_KEY,
  1552. SPLDS_PRINT_MIN_Y_EXTENT,
  1553. REG_DWORD,
  1554. (PBYTE) &dwTemp,
  1555. sizeof(DWORD));
  1556. #if DBG
  1557. if (dwResult != ERROR_SUCCESS)
  1558. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: MinYExtent, %x\n", dwResult) );
  1559. #endif
  1560. } else {
  1561. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_MINEXTENT failed %d\n", GetLastError()));
  1562. }
  1563. //
  1564. // DS property: printMediaSupported - Not part of printQueue, but is in Schema
  1565. //
  1566. if (!DevCapMultiSz( hPrinter,
  1567. hDevCapPrinter,
  1568. pDevCap,
  1569. pSplDevCaps,
  1570. pPrinterName,
  1571. DC_PAPERNAMES,
  1572. 64,
  1573. SPLDS_PRINT_MEDIA_SUPPORTED)) {
  1574. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_PAPERNAMES failed %d\n", GetLastError()));
  1575. }
  1576. //
  1577. // DS property: printMediaReady
  1578. //
  1579. if (!DevCapMultiSz( hPrinter,
  1580. hDevCapPrinter,
  1581. pDevCap,
  1582. pSplDevCaps,
  1583. pPrinterName,
  1584. DC_MEDIAREADY,
  1585. 64,
  1586. SPLDS_PRINT_MEDIA_READY)) {
  1587. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_MEDIAREADY failed %d\n", GetLastError()));
  1588. }
  1589. //
  1590. // DS property: printNumberUp
  1591. //
  1592. _try {
  1593. dwResult = (*pDevCap)( hDevCapPrinter,
  1594. pPrinterName,
  1595. DC_NUP,
  1596. NULL,
  1597. NULL);
  1598. } _except(1) {
  1599. SetLastError(GetExceptionCode());
  1600. dwResult = GDI_ERROR;
  1601. }
  1602. if (dwResult != GDI_ERROR) {
  1603. dwResult = SplSetPrinterDataEx(
  1604. hPrinter,
  1605. SPLDS_DRIVER_KEY,
  1606. SPLDS_PRINT_NUMBER_UP,
  1607. REG_DWORD,
  1608. (PBYTE) &dwResult,
  1609. sizeof(DWORD));
  1610. #if DBG
  1611. if (dwResult != ERROR_SUCCESS)
  1612. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: NumberUp, %x\n", dwResult) );
  1613. #endif
  1614. } else {
  1615. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_NUP failed %d\n", GetLastError()));
  1616. }
  1617. //
  1618. // DS property: printMemory
  1619. //
  1620. _try {
  1621. dwResult = (*pDevCap)( hDevCapPrinter,
  1622. pPrinterName,
  1623. DC_PRINTERMEM,
  1624. NULL,
  1625. NULL);
  1626. } _except(1) {
  1627. SetLastError(GetExceptionCode());
  1628. dwResult = GDI_ERROR;
  1629. }
  1630. if (dwResult != GDI_ERROR) {
  1631. dwResult = SplSetPrinterDataEx(
  1632. hPrinter,
  1633. SPLDS_DRIVER_KEY,
  1634. SPLDS_PRINT_MEMORY,
  1635. REG_DWORD,
  1636. (PBYTE) &dwResult,
  1637. sizeof(DWORD));
  1638. #if DBG
  1639. if (dwResult != ERROR_SUCCESS)
  1640. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: printMemory, %x\n", dwResult) );
  1641. #endif
  1642. } else {
  1643. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_PRINTERMEM failed %d\n", GetLastError()));
  1644. }
  1645. //
  1646. // DS property: printOrientationsSupported
  1647. //
  1648. _try {
  1649. dwResult = (*pDevCap)( hDevCapPrinter,
  1650. pPrinterName,
  1651. DC_ORIENTATION,
  1652. NULL,
  1653. NULL);
  1654. } _except(1) {
  1655. SetLastError(GetExceptionCode());
  1656. dwResult = GDI_ERROR;
  1657. }
  1658. if (dwResult != GDI_ERROR) {
  1659. SIZE_T cchRemaining = COUNTOF(Buf);
  1660. if (dwResult == 90 || dwResult == 270) {
  1661. StrCchCopyMultipleStr(Buf, COUNTOF(Buf), L"PORTRAIT", &pStr, &cchRemaining);
  1662. StrCchCopyMultipleStr(pStr, cchRemaining, L"LANDSCAPE", &pStr, &cchRemaining);
  1663. }
  1664. else {
  1665. StrCchCopyMultipleStr(Buf, COUNTOF(Buf), L"PORTRAIT", &pStr, &cchRemaining);
  1666. }
  1667. if (cchRemaining)
  1668. {
  1669. *pStr++ = L'\0';
  1670. dwResult = SplSetPrinterDataEx(
  1671. hPrinter,
  1672. SPLDS_DRIVER_KEY,
  1673. SPLDS_PRINT_ORIENTATIONS_SUPPORTED,
  1674. REG_MULTI_SZ,
  1675. (PBYTE) Buf,
  1676. (DWORD) ((ULONG_PTR) pStr - (ULONG_PTR) Buf));
  1677. }
  1678. else
  1679. {
  1680. dwResult = ERROR_INSUFFICIENT_BUFFER;
  1681. }
  1682. #if DBG
  1683. if (dwResult != ERROR_SUCCESS)
  1684. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Orientations, %x\n", dwResult) );
  1685. #endif
  1686. } else {
  1687. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_ORIENTATION failed %d\n", GetLastError()));
  1688. }
  1689. //
  1690. // DS property: printMaxResolutionSupported
  1691. //
  1692. _try {
  1693. dwResult = (*pDevCap)( hDevCapPrinter,
  1694. pPrinterName,
  1695. DC_ENUMRESOLUTIONS,
  1696. NULL,
  1697. NULL);
  1698. } _except(1) {
  1699. SetLastError(GetExceptionCode());
  1700. dwResult = GDI_ERROR;
  1701. }
  1702. if (dwResult != GDI_ERROR) {
  1703. if (cOutputBytes < dwResult*2*sizeof(DWORD)) {
  1704. if(!(pTemp1 = (LPWSTR) ReallocSplMem(pOutput, 0, cOutputBytes = dwResult*2*sizeof(DWORD))))
  1705. goto error;
  1706. pOutput = pTemp1;
  1707. }
  1708. _try {
  1709. dwResult = (*pDevCap)( hDevCapPrinter,
  1710. pPrinterName,
  1711. DC_ENUMRESOLUTIONS,
  1712. pOutput,
  1713. NULL);
  1714. } _except(1) {
  1715. SetLastError(GetExceptionCode());
  1716. dwResult = GDI_ERROR;
  1717. }
  1718. if (dwResult != GDI_ERROR && dwResult > 0) {
  1719. //
  1720. // Find the maximum resolution: we have dwResult*2 resolutions to check
  1721. //
  1722. _try {
  1723. for(i = dwTemp = 0 ; i < dwResult*2 ; ++i) {
  1724. if (((DWORD *) pOutput)[i] > dwTemp)
  1725. dwTemp = ((DWORD *) pOutput)[i];
  1726. }
  1727. dwResult = SplSetPrinterDataEx(
  1728. hPrinter,
  1729. SPLDS_DRIVER_KEY,
  1730. SPLDS_PRINT_MAX_RESOLUTION_SUPPORTED,
  1731. REG_DWORD,
  1732. (PBYTE) &dwTemp,
  1733. sizeof(DWORD));
  1734. } _except(1) {
  1735. SetLastError(dwResult = GetExceptionCode());
  1736. }
  1737. #if DBG
  1738. if (dwResult != ERROR_SUCCESS)
  1739. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Resolution, %x\n", dwResult) );
  1740. #endif
  1741. }
  1742. } else {
  1743. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_ENUMRESOLUTIONS failed %d\n", GetLastError()));
  1744. }
  1745. //
  1746. // DS property: printLanguage
  1747. //
  1748. if (!DevCapMultiSz( hPrinter,
  1749. hDevCapPrinter,
  1750. pDevCap,
  1751. NULL,
  1752. pPrinterName,
  1753. DC_PERSONALITY,
  1754. 32,
  1755. SPLDS_PRINT_LANGUAGE)) {
  1756. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_PERSONALITY failed %d\n", GetLastError()));
  1757. }
  1758. //
  1759. // DS property: printRate
  1760. // NOTE: If PrintRate is 0, no value is published
  1761. //
  1762. _try {
  1763. dwResult = (*pDevCap)( hDevCapPrinter,
  1764. pPrinterName,
  1765. DC_PRINTRATE,
  1766. NULL,
  1767. NULL);
  1768. } _except(1) {
  1769. SetLastError(GetExceptionCode());
  1770. dwResult = GDI_ERROR;
  1771. }
  1772. dwPrintRate = dwResult ? dwResult : GDI_ERROR;
  1773. if (dwPrintRate != GDI_ERROR) {
  1774. dwResult = SplSetPrinterDataEx(
  1775. hPrinter,
  1776. SPLDS_DRIVER_KEY,
  1777. SPLDS_PRINT_RATE,
  1778. REG_DWORD,
  1779. (PBYTE) &dwPrintRate,
  1780. sizeof(DWORD));
  1781. #if DBG
  1782. if (dwResult != ERROR_SUCCESS)
  1783. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: PrintRate, %x\n", dwResult) );
  1784. #endif
  1785. } else {
  1786. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_PRINTRATE failed %d\n", GetLastError()));
  1787. }
  1788. //
  1789. // DS property: printRateUnit
  1790. //
  1791. _try {
  1792. dwResult = (*pDevCap)( hDevCapPrinter,
  1793. pPrinterName,
  1794. DC_PRINTRATEUNIT,
  1795. NULL,
  1796. NULL);
  1797. } _except(1) {
  1798. SetLastError(GetExceptionCode());
  1799. dwResult = GDI_ERROR;
  1800. }
  1801. dwPrintRateUnit = dwResult;
  1802. //
  1803. // If the capability isn't supported, set printRateUnit to empty string.
  1804. //
  1805. switch (dwPrintRateUnit) {
  1806. case PRINTRATEUNIT_PPM:
  1807. pStr = L"PagesPerMinute";
  1808. break;
  1809. case PRINTRATEUNIT_CPS:
  1810. pStr = L"CharactersPerSecond";
  1811. break;
  1812. case PRINTRATEUNIT_LPM:
  1813. pStr = L"LinesPerMinute";
  1814. break;
  1815. case PRINTRATEUNIT_IPM:
  1816. pStr = L"InchesPerMinute";
  1817. break;
  1818. default:
  1819. pStr = L"";
  1820. break;
  1821. }
  1822. if (pStr) {
  1823. dwResult = SplSetPrinterDataEx(
  1824. hPrinter,
  1825. SPLDS_DRIVER_KEY,
  1826. SPLDS_PRINT_RATE_UNIT,
  1827. REG_SZ,
  1828. (PBYTE) pStr,
  1829. (wcslen(pStr) + 1)*sizeof *pStr);
  1830. #if DBG
  1831. if (dwResult != ERROR_SUCCESS)
  1832. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: PrintRateUnit, %x\n", dwResult) );
  1833. #endif
  1834. } else {
  1835. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_PRINTRATEUNIT no unit %d\n", dwPrintRateUnit ));
  1836. }
  1837. //
  1838. // printPagesPerMinute
  1839. // DevCap returns 0 if there is no entry in GPD
  1840. _try {
  1841. dwResult = (*pDevCap)( hDevCapPrinter,
  1842. pPrinterName,
  1843. DC_PRINTRATEPPM,
  1844. NULL,
  1845. NULL);
  1846. } _except(1) {
  1847. SetLastError(GetExceptionCode());
  1848. dwResult = GDI_ERROR;
  1849. }
  1850. if (dwResult == GDI_ERROR)
  1851. dwResult = 0;
  1852. dwPrintPPM = dwResult;
  1853. //
  1854. // If dwPrintPPM == 0, then calculate PPM from PrintRate
  1855. //
  1856. if (dwPrintPPM == 0) {
  1857. if (dwPrintRate == GDI_ERROR) {
  1858. dwPrintPPM = GDI_ERROR;
  1859. } else {
  1860. switch (dwPrintRateUnit) {
  1861. case PRINTRATEUNIT_PPM:
  1862. dwPrintPPM = dwPrintRate;
  1863. break;
  1864. case PRINTRATEUNIT_CPS:
  1865. case PRINTRATEUNIT_LPM:
  1866. dwPrintPPM = dwPrintRate/PPM_FACTOR;
  1867. if (dwPrintPPM == 0)
  1868. dwPrintPPM = 1; // min PPM is 1
  1869. break;
  1870. default:
  1871. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: PRINTRATEUNIT not found %d\n",
  1872. dwPrintRateUnit));
  1873. dwPrintPPM = GDI_ERROR;
  1874. break;
  1875. }
  1876. }
  1877. }
  1878. if (dwPrintPPM != GDI_ERROR) {
  1879. dwResult = SplSetPrinterDataEx(
  1880. hPrinter,
  1881. SPLDS_DRIVER_KEY,
  1882. SPLDS_PRINT_PAGES_PER_MINUTE,
  1883. REG_DWORD,
  1884. (PBYTE) &dwPrintPPM,
  1885. sizeof(DWORD));
  1886. #if DBG
  1887. if (dwResult != ERROR_SUCCESS)
  1888. DBGMSG(DBG_WARNING, ("UpdateDsDriverKey: PrintPagesPerMinute, %x\n", dwResult));
  1889. #endif
  1890. } else {
  1891. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: PPM failed %d\n", GetLastError()));
  1892. }
  1893. //
  1894. // printDriverVersion
  1895. //
  1896. _try {
  1897. dwResult = (*pDevCap)( hDevCapPrinter,
  1898. pPrinterName,
  1899. DC_VERSION,
  1900. NULL,
  1901. NULL);
  1902. } _except(1) {
  1903. SetLastError(GetExceptionCode());
  1904. dwResult = GDI_ERROR;
  1905. }
  1906. if (dwResult != GDI_ERROR) {
  1907. dwResult = SplSetPrinterDataEx(
  1908. hPrinter,
  1909. SPLDS_DRIVER_KEY,
  1910. SPLDS_DRIVER_VERSION,
  1911. REG_DWORD,
  1912. (PBYTE) &dwResult,
  1913. sizeof(DWORD));
  1914. #if DBG
  1915. if (dwResult != ERROR_SUCCESS)
  1916. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Driver Version, %x\n", dwResult) );
  1917. #endif
  1918. } else {
  1919. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_VERSION failed %d\n", GetLastError()));
  1920. }
  1921. error:
  1922. if (hDevCapPrinter)
  1923. (*pfnClosePrinter)(hDevCapPrinter);
  1924. if (!bInSplSem) {
  1925. EnterSplSem();
  1926. DECPRINTERREF(pIniPrinter);
  1927. }
  1928. if (hModule)
  1929. FreeLibrary(hModule);
  1930. FreeSplMem(pOutput);
  1931. FreeSplMem(pTemp);
  1932. }
  1933. BOOL
  1934. DevCapMultiSz(
  1935. HANDLE hPrinter,
  1936. HANDLE hDevCapPrinter,
  1937. PDEVCAP pDevCap,
  1938. PSPLDEVCAP pSplDevCap,
  1939. PWSTR pszPrinterName,
  1940. WORD fwCapability,
  1941. DWORD dwElementBytes,
  1942. PWSTR pszRegValue
  1943. )
  1944. /*++
  1945. Function Description:
  1946. This function writes a multisz devcap string to the DsDriverKey registry
  1947. Parameters:
  1948. hPrinter - printer handle
  1949. hDevCapPrinter - devcap handle
  1950. pDevCap - devcap function pointer
  1951. pszPrinterName - name of the printer
  1952. fwCapability - devcap capability entry
  1953. dwElementBytes - length of each string element in the array returned by devcaps
  1954. pszRegValue - name of the registry value to which the multisz string will be written
  1955. Return Values:
  1956. BOOL - TRUE if successful, FALSE if not. Call GetLastError to retrieve failure error.
  1957. --*/
  1958. {
  1959. DWORD dwResult, cbBytes;
  1960. PWSTR pszDevCapBuffer = NULL;
  1961. PWSTR pszRegData = NULL;
  1962. _try {
  1963. dwResult = GDI_ERROR;
  1964. if (pSplDevCap) {
  1965. dwResult = (*pSplDevCap)( hDevCapPrinter,
  1966. pszPrinterName,
  1967. fwCapability,
  1968. NULL,
  1969. 0,
  1970. NULL);
  1971. } else {
  1972. dwResult = (*pDevCap)( hDevCapPrinter,
  1973. pszPrinterName,
  1974. fwCapability,
  1975. NULL,
  1976. NULL);
  1977. }
  1978. if (dwResult != GDI_ERROR) {
  1979. //
  1980. // DeviceCapabilities doesn't take a buffer size parameter, so if you get
  1981. // printer properties on a hundred or so printers at the same time, you will
  1982. // occasionally hit the case where win32 cache is deleting & adding forms in
  1983. // RefreshFormsCache and DC_PAPERNAMES calls EnumForms and gets different
  1984. // results. The first call may return 3 forms and second returns 20. So we
  1985. // allocate a big buffer here so third party drivers don't AV. For unidrv
  1986. // we have a different interface that accepts a buffer size.
  1987. //
  1988. if (fwCapability == DC_PAPERNAMES || fwCapability == DC_MEDIAREADY) {
  1989. //
  1990. // If the driver dowsn't support the DeviceCapabilities that takes a buffer size, then
  1991. // allocate a bigger buffer.
  1992. //
  1993. dwResult += LOTS_OF_FORMS;
  1994. }
  1995. cbBytes = dwResult*dwElementBytes*sizeof(WCHAR);
  1996. pszDevCapBuffer = (PWSTR) AllocSplMem(cbBytes);
  1997. if (pszDevCapBuffer) {
  1998. dwResult = GDI_ERROR;
  1999. if (pSplDevCap) {
  2000. dwResult = (*pSplDevCap)( hDevCapPrinter,
  2001. pszPrinterName,
  2002. fwCapability,
  2003. pszDevCapBuffer,
  2004. cbBytes/sizeof(WCHAR),
  2005. NULL);
  2006. } else {
  2007. dwResult = (*pDevCap)( hDevCapPrinter,
  2008. pszPrinterName,
  2009. fwCapability,
  2010. pszDevCapBuffer,
  2011. NULL);
  2012. }
  2013. if (dwResult != GDI_ERROR) {
  2014. if (!(pszRegData = DevCapStrings2MultiSz(pszDevCapBuffer, dwResult, dwElementBytes, &cbBytes))) {
  2015. dwResult = GDI_ERROR;
  2016. }
  2017. }
  2018. } else {
  2019. dwResult = GDI_ERROR;
  2020. }
  2021. }
  2022. } _except(1) {
  2023. SetLastError(GetExceptionCode());
  2024. dwResult = GDI_ERROR;
  2025. }
  2026. if (dwResult != GDI_ERROR) {
  2027. dwResult = SplSetPrinterDataEx(
  2028. hPrinter,
  2029. SPLDS_DRIVER_KEY,
  2030. pszRegValue,
  2031. REG_MULTI_SZ,
  2032. (PBYTE) pszRegData,
  2033. cbBytes);
  2034. if (dwResult != ERROR_SUCCESS) {
  2035. SetLastError(dwResult);
  2036. dwResult = GDI_ERROR;
  2037. }
  2038. } else {
  2039. WCHAR szzNull[2];
  2040. szzNull[0] = szzNull[1] = '\0';
  2041. dwResult = SplSetPrinterDataEx(
  2042. hPrinter,
  2043. SPLDS_DRIVER_KEY,
  2044. pszRegValue,
  2045. REG_MULTI_SZ,
  2046. (PBYTE) szzNull,
  2047. 2 * sizeof(WCHAR));
  2048. }
  2049. FreeSplStr(pszDevCapBuffer);
  2050. FreeSplStr(pszRegData);
  2051. return dwResult != GDI_ERROR;
  2052. }
  2053. extern "C" DWORD
  2054. RecreateDsKey(
  2055. HANDLE hPrinter,
  2056. PWSTR pszKey
  2057. )
  2058. {
  2059. PSPOOL pSpool = (PSPOOL)hPrinter;
  2060. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  2061. if (pSpool->pIniPrinter->pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL)
  2062. {
  2063. //
  2064. // Clears existing published properties and recreates & republishes Registry key
  2065. //
  2066. SplOutSem();
  2067. //
  2068. // Clear all published Properties under Key
  2069. //
  2070. ClearDsKey(hPrinter, pszKey);
  2071. //
  2072. // Delete Key
  2073. //
  2074. EnterSplSem();
  2075. SplDeletePrinterKey(hPrinter, pszKey);
  2076. //
  2077. // Recreate Key
  2078. //
  2079. if (!wcscmp(pszKey, SPLDS_DRIVER_KEY)) {
  2080. UpdateDsDriverKey(hPrinter);
  2081. }
  2082. else if (!wcscmp(pszKey, SPLDS_SPOOLER_KEY)) {
  2083. UpdateDsSpoolerKey(hPrinter, 0xffffffff);
  2084. }
  2085. //
  2086. // Republish Key
  2087. //
  2088. SetPrinterDs(hPrinter, DSPRINT_UPDATE, FALSE);
  2089. LeaveSplSem();
  2090. SplOutSem();
  2091. }
  2092. return ERROR_SUCCESS;
  2093. }
  2094. // ClearDsKey: clears all properties in specified key
  2095. HRESULT
  2096. ClearDsKey(
  2097. HANDLE hPrinter,
  2098. PWSTR pszKey
  2099. )
  2100. {
  2101. HRESULT hr = ERROR_SUCCESS;
  2102. DWORD i;
  2103. DWORD cbEnumValues = 0;
  2104. PPRINTER_ENUM_VALUES pEnumValues = NULL;
  2105. DWORD nEnumValues;
  2106. DWORD dwResult;
  2107. PSPOOL pSpool = (PSPOOL)hPrinter;
  2108. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  2109. IADs *pADs = NULL;
  2110. HANDLE hToken = NULL;
  2111. VARIANT var;
  2112. SplOutSem();
  2113. //
  2114. // If we're not published, there's no DS key to clear, so just return success
  2115. //
  2116. if (!pIniPrinter->pszObjectGUID)
  2117. return S_OK;
  2118. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  2119. if (FAILED(hr))
  2120. return hr;
  2121. hToken = RevertToPrinterSelf(); // All DS accesses are done by LocalSystem account
  2122. //
  2123. // Enumerate and Publish Key
  2124. //
  2125. dwResult = SplEnumPrinterDataEx( hPrinter,
  2126. pszKey,
  2127. NULL,
  2128. 0,
  2129. &cbEnumValues,
  2130. &nEnumValues
  2131. );
  2132. if (dwResult != ERROR_MORE_DATA) {
  2133. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  2134. goto error;
  2135. }
  2136. if (!(pEnumValues = (PPRINTER_ENUM_VALUES) AllocSplMem(cbEnumValues))) {
  2137. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
  2138. BAIL_ON_FAILURE(hr);
  2139. }
  2140. dwResult = SplEnumPrinterDataEx( hPrinter,
  2141. pszKey,
  2142. (LPBYTE) pEnumValues,
  2143. cbEnumValues,
  2144. &cbEnumValues,
  2145. &nEnumValues
  2146. );
  2147. if (dwResult != ERROR_SUCCESS) {
  2148. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  2149. goto error;
  2150. }
  2151. //
  2152. // Get or Create printQueue object
  2153. //
  2154. hr = GetPrintQueue(hPrinter, &pADs);
  2155. BAIL_ON_FAILURE(hr);
  2156. //
  2157. // Clear Published Properties
  2158. //
  2159. VariantInit(&var);
  2160. for (i = 0 ; i < nEnumValues ; ++i) {
  2161. hr = pADs->PutEx(
  2162. ADS_PROPERTY_CLEAR,
  2163. pEnumValues[i].pValueName,
  2164. var
  2165. );
  2166. #if DBG
  2167. if (FAILED(hr))
  2168. DBGMSG(DBG_EXEC, ("Failed to clear property: %ws\n", pEnumValues[i].pValueName));
  2169. #endif
  2170. }
  2171. hr = pADs->SetInfo();
  2172. BAIL_ON_FAILURE(hr);
  2173. error:
  2174. FreeSplMem(pEnumValues);
  2175. if (hToken)
  2176. ImpersonatePrinterClient(hToken);
  2177. if (pADs) {
  2178. pADs->Release();
  2179. }
  2180. CoUninitialize();
  2181. return hr;
  2182. }
  2183. HRESULT
  2184. CreateAce(
  2185. IADsAccessControlList *pACL,
  2186. BSTR pszTrustee,
  2187. DWORD dwAccessMask
  2188. )
  2189. {
  2190. IADsAccessControlEntry *pACE = NULL;
  2191. IDispatch *pACEDispatch = NULL;
  2192. HRESULT hr;
  2193. //
  2194. // Create ACE
  2195. //
  2196. hr = CoCreateInstance( CLSID_AccessControlEntry,
  2197. NULL,
  2198. CLSCTX_INPROC_SERVER,
  2199. IID_IADsAccessControlEntry,
  2200. (void **) &pACE);
  2201. BAIL_ON_FAILURE(hr);
  2202. hr = pACE->put_AccessMask(dwAccessMask);
  2203. BAIL_ON_FAILURE(hr);
  2204. hr = pACE->put_AceType(ACCESS_ALLOWED_ACE_TYPE);
  2205. BAIL_ON_FAILURE(hr);
  2206. hr = pACE->put_AceFlags(0);
  2207. BAIL_ON_FAILURE(hr);
  2208. hr = pACE->put_Trustee(pszTrustee);
  2209. BAIL_ON_FAILURE(hr);
  2210. hr = pACE->QueryInterface(IID_IDispatch, (void **) &pACEDispatch);
  2211. BAIL_ON_FAILURE(hr);
  2212. hr = pACL->AddAce(pACEDispatch);
  2213. BAIL_ON_FAILURE(hr);
  2214. error:
  2215. if (pACEDispatch)
  2216. pACEDispatch->Release();
  2217. if (pACE)
  2218. pACE->Release();
  2219. return hr;
  2220. }
  2221. HRESULT
  2222. AddClusterAce(
  2223. PSPOOL pSpool,
  2224. IADs *pADsPrintQueue
  2225. )
  2226. {
  2227. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  2228. IDispatch *pSDPrintQueueDispatch = NULL;
  2229. IADsSecurityDescriptor *pSDPrintQueue = NULL;
  2230. IDispatch *pACLPrintQueueDispatch = NULL;
  2231. IADsAccessControlList *pACLPrintQueue = NULL;
  2232. HRESULT hr;
  2233. //
  2234. // If we don't have a GUID, then we're not a cluster and we don't need to add the ACE
  2235. //
  2236. if (!pIniPrinter->pIniSpooler->pszClusterSID)
  2237. return S_OK;
  2238. //
  2239. // Get the PrintQueue Security Descriptor
  2240. //
  2241. hr = get_Dispatch_Property(pADsPrintQueue, L"nTSecurityDescriptor", &pSDPrintQueueDispatch);
  2242. BAIL_ON_FAILURE(hr);
  2243. hr = pSDPrintQueueDispatch->QueryInterface(IID_IADsSecurityDescriptor, (void **) &pSDPrintQueue);
  2244. BAIL_ON_FAILURE(hr);
  2245. //
  2246. // Get DACL from the Security Descriptor
  2247. //
  2248. hr = pSDPrintQueue->get_DiscretionaryAcl(&pACLPrintQueueDispatch);
  2249. BAIL_ON_FAILURE(hr);
  2250. hr = pACLPrintQueueDispatch->QueryInterface(IID_IADsAccessControlList, (void **) &pACLPrintQueue);
  2251. BAIL_ON_FAILURE(hr);
  2252. hr = CreateAce(pACLPrintQueue, (BSTR) pIniPrinter->pIniSpooler->pszClusterSID, GENERIC_ALL);
  2253. BAIL_ON_FAILURE(hr);
  2254. //
  2255. // Write the ACL back to the Security Descriptor
  2256. //
  2257. hr = pSDPrintQueue->put_DiscretionaryAcl(pACLPrintQueueDispatch);
  2258. BAIL_ON_FAILURE(hr);
  2259. //
  2260. // Write the Security Descriptor back to the object
  2261. //
  2262. hr = put_Dispatch_Property(pADsPrintQueue, L"nTSecurityDescriptor", pSDPrintQueueDispatch);
  2263. BAIL_ON_FAILURE(hr);
  2264. hr = pADsPrintQueue->SetInfo();
  2265. BAIL_ON_FAILURE(hr);
  2266. error:
  2267. if (pACLPrintQueueDispatch)
  2268. pACLPrintQueueDispatch->Release();
  2269. if (pACLPrintQueue)
  2270. pACLPrintQueue->Release();
  2271. if (pSDPrintQueueDispatch)
  2272. pSDPrintQueueDispatch->Release();
  2273. if (pSDPrintQueue)
  2274. pSDPrintQueue->Release();
  2275. return hr;
  2276. }