Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1094 lines
29 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Abstract:
  4. This module provides functionality for publishing printers
  5. Author:
  6. Steve Wilson (NT) November 1997
  7. Revision History:
  8. --*/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. #include "pubprn.hxx"
  12. #include "varconv.hxx"
  13. #include "property.hxx"
  14. #include "dsutil.hxx"
  15. #include "client.h"
  16. #define PPM_FACTOR 48
  17. BOOL
  18. PublishPrinterW(
  19. HWND hwnd,
  20. PCWSTR pszUNCName,
  21. PCWSTR pszDN,
  22. PCWSTR pszCN,
  23. PWSTR *ppszDN,
  24. DWORD dwAction
  25. )
  26. {
  27. PRINTER_DEFAULTS Defaults;
  28. HANDLE hPrinter = NULL;
  29. HANDLE hServer = NULL;
  30. PWSTR pszServerName = NULL;
  31. PWSTR pszPrinterName = NULL;
  32. PPRINTER_INFO_2 pInfo2 = NULL;
  33. DWORD dwRet = ERROR_SUCCESS;
  34. DWORD dwType;
  35. DWORD dwMajorVersion;
  36. DWORD dwDsPresent;
  37. DWORD cbNeeded;
  38. DWORD dwLength;
  39. HRESULT hr;
  40. WCHAR szDNSMachineName[INTERNET_MAX_HOST_NAME_LENGTH + 1];
  41. WCHAR szFullUNCName[MAX_UNC_PRINTER_NAME];
  42. WCHAR szShortServerName[MAX_PATH+1];
  43. PWSTR pszFullUNCName;
  44. PWSTR pszShortServerName;
  45. PWSTR pszFullServerName;
  46. if (InCSRProcess()) {
  47. SetLastError(ERROR_NOT_SUPPORTED);
  48. return FALSE;
  49. }
  50. hr = CoInitialize(NULL);
  51. if (hr != S_OK && hr != S_FALSE) {
  52. SetLastError((DWORD)((HRESULT_FACILITY(hr) == FACILITY_WIN32) ? HRESULT_CODE(hr) : hr));
  53. return FALSE;
  54. }
  55. if (ppszDN)
  56. *ppszDN = NULL;
  57. // Get server name
  58. if (dwRet = UNC2Server(pszUNCName, &pszServerName))
  59. goto error;
  60. if(!OpenPrinter(pszServerName, &hServer, NULL)) {
  61. dwMajorVersion = 0;
  62. } else {
  63. dwRet = GetPrinterData( hServer,
  64. SPLREG_MAJOR_VERSION,
  65. &dwType,
  66. (PBYTE) &dwMajorVersion,
  67. sizeof dwMajorVersion,
  68. &cbNeeded);
  69. if (dwRet != ERROR_SUCCESS) {
  70. dwMajorVersion = 0;
  71. dwRet = ERROR_SUCCESS; // ignore errors and assume lowest version
  72. }
  73. if (dwMajorVersion >= WIN2000_SPOOLER_VERSION) {
  74. hr = MachineIsInMyForest(pszServerName);
  75. if (FAILED(hr)) {
  76. dwRet = HRESULT_CODE(hr);
  77. goto error;
  78. } else if(HRESULT_CODE(hr) == 1) {
  79. // Machine is in my forest and is NT5+
  80. dwRet = ERROR_INVALID_LEVEL;
  81. goto error;
  82. } else {
  83. // Downgrade the version for NT5+ printers published in a non-DS domain
  84. dwMajorVersion = WIN2000_SPOOLER_VERSION;
  85. }
  86. }
  87. }
  88. Defaults.pDatatype = NULL;
  89. Defaults.pDevMode = NULL;
  90. Defaults.DesiredAccess = PRINTER_ACCESS_USE;
  91. if (!OpenPrinter((PWSTR) pszUNCName, &hPrinter, &Defaults)) {
  92. dwRet = GetLastError();
  93. goto error;
  94. }
  95. hr = GetPrinterInfo2(hPrinter, &pInfo2);
  96. if (FAILED(hr)) {
  97. dwRet = HRESULT_CODE(hr);
  98. goto error;
  99. }
  100. if (dwRet = UNC2Printer(pInfo2->pPrinterName, &pszPrinterName))
  101. goto error;
  102. if( dwMajorVersion >= WIN2000_SPOOLER_VERSION){
  103. if(dwRet = GetPrinterData( hServer,
  104. SPLREG_DNS_MACHINE_NAME,
  105. &dwType,
  106. (PBYTE) szDNSMachineName,
  107. (INTERNET_MAX_HOST_NAME_LENGTH + 1) * sizeof(WCHAR),
  108. &cbNeeded) != ERROR_SUCCESS ) {
  109. goto error;
  110. }
  111. wsprintf( szFullUNCName, L"\\\\%s\\%s", szDNSMachineName, pszPrinterName );
  112. dwLength = MAX_PATH + 1;
  113. if (!DnsHostnameToComputerName(pszServerName,
  114. szShortServerName,
  115. &dwLength)) {
  116. dwRet = GetLastError();
  117. goto error;
  118. }
  119. pszFullUNCName = szFullUNCName;
  120. pszFullServerName = szDNSMachineName;
  121. pszShortServerName = szShortServerName+2;
  122. } else {
  123. pszFullUNCName = (PWSTR)pszUNCName;
  124. pszFullServerName = pszServerName+2;
  125. pszShortServerName = pszServerName+2;
  126. }
  127. // Verify PrintQueue doesn't already exist
  128. if (dwAction != PUBLISHPRINTER_IGNORE_DUPLICATES) {
  129. if(dwRet = PrintQueueExists(hwnd, hPrinter, pszFullUNCName, dwAction, (PWSTR) pszDN, (PWSTR *) ppszDN))
  130. goto error;
  131. }
  132. if (dwRet = PublishDownlevelPrinter(hPrinter,
  133. (PWSTR) pszDN,
  134. (PWSTR) pszCN,
  135. pszFullServerName,
  136. pszShortServerName,
  137. pszFullUNCName,
  138. pszPrinterName,
  139. dwMajorVersion,
  140. ppszDN))
  141. goto error;
  142. error:
  143. if (hPrinter != NULL)
  144. ClosePrinter(hPrinter);
  145. if (hServer != NULL)
  146. ClosePrinter(hServer);
  147. if (pszServerName)
  148. FreeSplMem(pszServerName);
  149. if (pszPrinterName)
  150. FreeSplMem(pszPrinterName);
  151. FreeSplMem(pInfo2);
  152. if (dwRet != ERROR_SUCCESS) {
  153. SetLastError(dwRet);
  154. return FALSE;
  155. }
  156. CoUninitialize();
  157. return TRUE;
  158. }
  159. DWORD
  160. PublishNT5Printer(
  161. HANDLE hPrinter,
  162. PWSTR pszDN,
  163. PWSTR pszCN,
  164. PWSTR *ppszObjectDN
  165. )
  166. {
  167. PRINTER_INFO_7 Info7;
  168. DWORD dwRet = ERROR_SUCCESS;
  169. BYTE Data[(100 + sizeof(PRINTER_INFO_7))*sizeof(WCHAR)]; // GUIDs don't have well-defined size
  170. PPRINTER_INFO_7 pInfo7 = NULL;
  171. DWORD cbNeeded;
  172. // Disable NT5+ publishing because it is inconsistent with SetPrinter.
  173. // Also, NT5 duplicate printer must be deleted via SetPrinter, not via DS. If it is
  174. // deleted via DS then subsequent SetPrinter to publish will take a long time since
  175. // it discovers GUID no longer exists and spins background thread to delete & republish.
  176. // This, combined with replication delays, causes PublishNT5Printer to fail because getting
  177. // the ppszObjectDN because the object may not be published yet.
  178. return ERROR_INVALID_LEVEL;
  179. Info7.dwAction = DSPRINT_PUBLISH;
  180. if (!SetPrinter(hPrinter, 7, (PBYTE) &Info7, 0)) {
  181. dwRet = GetLastError();
  182. goto error;
  183. }
  184. if (!GetPrinter(hPrinter, 7, (PBYTE) Data, sizeof(Data), &cbNeeded)) {
  185. if ((dwRet = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
  186. goto error;
  187. if (!(pInfo7 = (PPRINTER_INFO_7) AllocSplMem(cbNeeded)))
  188. goto error;
  189. if (!GetPrinter(hPrinter, 7, (PBYTE) pInfo7, cbNeeded, &cbNeeded)) {
  190. dwRet = GetLastError();
  191. goto error;
  192. }
  193. } else {
  194. pInfo7 = (PPRINTER_INFO_7) Data;
  195. }
  196. if (!(dwRet = MovePrintQueue(pInfo7->pszObjectGUID, pszDN, pszCN)))
  197. goto error;
  198. if (dwRet = GetADsPathFromGUID(pInfo7->pszObjectGUID, ppszObjectDN))
  199. goto error;
  200. error:
  201. if (pInfo7 && pInfo7 != (PPRINTER_INFO_7) Data)
  202. FreeSplMem(pInfo7);
  203. if (dwRet != ERROR_SUCCESS) {
  204. FreeGlobalStr(*ppszObjectDN);
  205. }
  206. return dwRet;
  207. }
  208. DWORD
  209. PublishDownlevelPrinter(
  210. HANDLE hPrinter,
  211. PWSTR pszDN,
  212. PWSTR pszCN,
  213. PWSTR pszServerName,
  214. PWSTR pszShortServerName,
  215. PWSTR pszUNCName,
  216. PWSTR pszPrinterName,
  217. DWORD dwVersion,
  218. PWSTR *ppszObjectDN
  219. )
  220. {
  221. HRESULT hr = S_OK;
  222. DWORD dwRet = ERROR_SUCCESS;
  223. IADs *pPrintQueue = NULL;
  224. IADsContainer *pADsContainer = NULL;
  225. IDispatch *pDispatch = NULL;
  226. PWSTR pszCommonName = pszCN;
  227. BSTR bstrADsPath = NULL;
  228. PWSTR pszDNWithDC = NULL;
  229. if (ppszObjectDN)
  230. *ppszObjectDN = NULL;
  231. // If pszCN is not supplied, generate default common name
  232. if (!pszCommonName || !*pszCommonName) {
  233. dwRet = GetCommonName(hPrinter, &pszCommonName);
  234. if (dwRet != ERROR_SUCCESS) {
  235. hr = dw2hr(dwRet);
  236. BAIL_ON_FAILURE(hr);
  237. }
  238. }
  239. // Stick DC in DN
  240. if (!(pszDNWithDC = GetDNWithServer(pszDN))) {
  241. pszDNWithDC = pszDN;
  242. }
  243. // Get container
  244. hr = ADsGetObject(pszDNWithDC, IID_IADsContainer, (void **) &pADsContainer);
  245. BAIL_ON_FAILURE(hr);
  246. // Create printqueue
  247. hr = pADsContainer->Create(SPLDS_PRINTER_CLASS, pszCommonName, &pDispatch);
  248. BAIL_ON_FAILURE(hr);
  249. hr = pDispatch->QueryInterface(IID_IADs, (void **) &pPrintQueue);
  250. BAIL_ON_FAILURE(hr);
  251. // Set properties
  252. hr = SetProperties( hPrinter,
  253. pszServerName,
  254. pszShortServerName,
  255. pszUNCName,
  256. pszPrinterName,
  257. dwVersion,
  258. pPrintQueue);
  259. BAIL_ON_FAILURE(hr);
  260. // Get ADsPath to printQueue
  261. if (ppszObjectDN) {
  262. hr = pPrintQueue->get_ADsPath(&bstrADsPath);
  263. BAIL_ON_FAILURE(hr);
  264. if (!(*ppszObjectDN = AllocGlobalStr(bstrADsPath))) {
  265. dwRet = GetLastError();
  266. hr = dw2hr(dwRet);
  267. BAIL_ON_FAILURE(hr);
  268. }
  269. }
  270. error:
  271. if (pszDNWithDC != pszDN)
  272. FreeSplMem(pszDNWithDC);
  273. if (bstrADsPath)
  274. SysFreeString(bstrADsPath);
  275. if (pszCommonName != pszCN)
  276. FreeSplMem(pszCommonName);
  277. if (pADsContainer)
  278. pADsContainer->Release();
  279. if (pDispatch)
  280. pDispatch->Release();
  281. if (pPrintQueue)
  282. pPrintQueue->Release();
  283. if (FAILED(hr) && ppszObjectDN && *ppszObjectDN)
  284. FreeGlobalStr(*ppszObjectDN);
  285. return hr2dw(hr);
  286. }
  287. HRESULT
  288. SetProperties(
  289. HANDLE hPrinter,
  290. PWSTR pszServerName,
  291. PWSTR pszShortServerName,
  292. PWSTR pszUNCName,
  293. PWSTR pszPrinterName,
  294. DWORD dwVersion,
  295. IADs *pPrintQueue
  296. )
  297. {
  298. HRESULT hr;
  299. hr = SetMandatoryProperties(pszServerName,
  300. pszShortServerName,
  301. pszUNCName,
  302. pszPrinterName,
  303. dwVersion,
  304. pPrintQueue);
  305. BAIL_ON_FAILURE(hr);
  306. SetSpoolerProperties(hPrinter, pPrintQueue, dwVersion);
  307. SetDriverProperties(hPrinter, pPrintQueue);
  308. error:
  309. return hr;
  310. }
  311. HRESULT
  312. SetMandatoryProperties(
  313. PWSTR pszServerName,
  314. PWSTR pszShortServerName,
  315. PWSTR pszUNCName,
  316. PWSTR pszPrinterName,
  317. DWORD dwVersion,
  318. IADs *pPrintQueue
  319. )
  320. {
  321. HRESULT hr;
  322. // ServerName
  323. hr = put_BSTR_Property(pPrintQueue, SPLDS_SERVER_NAME, pszServerName);
  324. BAIL_ON_FAILURE(hr);
  325. // ShortServerName
  326. hr = put_BSTR_Property(pPrintQueue, SPLDS_SHORT_SERVER_NAME, pszShortServerName);
  327. BAIL_ON_FAILURE(hr);
  328. // UNC Name
  329. hr = put_BSTR_Property(pPrintQueue, SPLDS_UNC_NAME, pszUNCName);
  330. BAIL_ON_FAILURE(hr);
  331. // PrinterName
  332. hr = put_BSTR_Property(pPrintQueue, SPLDS_PRINTER_NAME, pszPrinterName);
  333. BAIL_ON_FAILURE(hr);
  334. // versionNumber
  335. hr = put_DWORD_Property(pPrintQueue, SPLDS_VERSION_NUMBER, &dwVersion);
  336. BAIL_ON_FAILURE(hr);
  337. hr = pPrintQueue->SetInfo();
  338. if (FAILED(hr))
  339. pPrintQueue->GetInfo();
  340. error:
  341. return hr;
  342. }
  343. HRESULT
  344. SetSpoolerProperties(
  345. HANDLE hPrinter,
  346. IADs *pPrintQueue,
  347. DWORD dwVersion
  348. )
  349. {
  350. HRESULT hr = S_OK;
  351. PPRINTER_INFO_2 pInfo2 = NULL;
  352. DWORD cbNeeded;
  353. BYTE Byte;
  354. PWSTR psz;
  355. // Get PRINTER_INFO_2 properties
  356. if (!GetPrinter(hPrinter, 2, (PBYTE) pInfo2, 0, &cbNeeded)) {
  357. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  358. hr = dw2hr(GetLastError());
  359. goto error;
  360. }
  361. if (!(pInfo2 = (PPRINTER_INFO_2) AllocSplMem(cbNeeded))) {
  362. hr = dw2hr(GetLastError());
  363. goto error;
  364. }
  365. if (!GetPrinter(hPrinter, 2, (PBYTE) pInfo2, cbNeeded, &cbNeeded)) {
  366. hr = dw2hr(GetLastError());
  367. goto error;
  368. }
  369. }
  370. // Description
  371. hr = PublishDsData( pPrintQueue,
  372. SPLDS_DESCRIPTION,
  373. REG_SZ,
  374. (PBYTE) pInfo2->pComment);
  375. // Driver-Name
  376. hr = PublishDsData( pPrintQueue,
  377. SPLDS_DRIVER_NAME,
  378. REG_SZ,
  379. (PBYTE) pInfo2->pDriverName);
  380. // Location
  381. hr = PublishDsData( pPrintQueue,
  382. SPLDS_LOCATION,
  383. REG_SZ,
  384. (PBYTE) pInfo2->pLocation);
  385. // portName (Port1,Port2,Port3)
  386. if (pInfo2->pPortName) {
  387. PWSTR pszPortName;
  388. // copy comma delimited strings to Multi-sz format
  389. pszPortName = DelimString2MultiSz(pInfo2->pPortName, L',');
  390. if (pszPortName) {
  391. hr = PublishDsData( pPrintQueue,
  392. SPLDS_PORT_NAME,
  393. REG_MULTI_SZ,
  394. (PBYTE) pszPortName);
  395. FreeSplMem(pszPortName);
  396. }
  397. }
  398. // startTime
  399. hr = PublishDsData( pPrintQueue,
  400. SPLDS_PRINT_START_TIME,
  401. REG_DWORD,
  402. (PBYTE) &pInfo2->StartTime);
  403. // endTime
  404. hr = PublishDsData( pPrintQueue,
  405. SPLDS_PRINT_END_TIME,
  406. REG_DWORD,
  407. (PBYTE) &pInfo2->UntilTime);
  408. // keepPrintedJobs
  409. Byte = pInfo2->Attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS ? 1 : 0;
  410. hr = PublishDsData( pPrintQueue,
  411. SPLDS_PRINT_KEEP_PRINTED_JOBS,
  412. REG_BINARY,
  413. (PBYTE) &Byte );
  414. // printSeparatorFile
  415. hr = PublishDsData( pPrintQueue,
  416. SPLDS_PRINT_SEPARATOR_FILE,
  417. REG_SZ,
  418. (PBYTE) pInfo2->pSepFile);
  419. // printShareName
  420. hr = PublishDsData( pPrintQueue,
  421. SPLDS_PRINT_SHARE_NAME,
  422. REG_SZ,
  423. (PBYTE) pInfo2->pShareName);
  424. // printSpooling
  425. if (pInfo2->Attributes & PRINTER_ATTRIBUTE_DIRECT) {
  426. psz = L"PrintDirect";
  427. } else if (pInfo2->Attributes & PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST) {
  428. psz = L"PrintAfterSpooled";
  429. } else {
  430. psz = L"PrintWhileSpooling";
  431. }
  432. hr = PublishDsData( pPrintQueue,
  433. SPLDS_PRINT_SPOOLING,
  434. REG_SZ,
  435. (PBYTE) psz);
  436. // priority
  437. hr = PublishDsData( pPrintQueue,
  438. SPLDS_PRIORITY,
  439. REG_DWORD,
  440. (PBYTE) &pInfo2->Priority);
  441. //
  442. // Non-Info2 properties
  443. // URL - downlevel machines don't support http printers, so don't publish useless url
  444. //
  445. if (dwVersion >= WIN2000_SPOOLER_VERSION) {
  446. DWORD dwRet, dwType;
  447. PWSTR pszUrl = NULL;
  448. //
  449. // Get the url from the print server
  450. //
  451. dwRet = GetPrinterDataEx( hPrinter,
  452. SPLDS_SPOOLER_KEY,
  453. SPLDS_URL,
  454. &dwType,
  455. (PBYTE) pszUrl,
  456. 0,
  457. &cbNeeded);
  458. if (dwRet == ERROR_MORE_DATA) {
  459. if ((pszUrl = (PWSTR) AllocSplMem(cbNeeded))) {
  460. dwRet = GetPrinterDataEx( hPrinter,
  461. SPLDS_SPOOLER_KEY,
  462. SPLDS_URL,
  463. &dwType,
  464. (PBYTE) pszUrl,
  465. cbNeeded,
  466. &cbNeeded);
  467. if (dwRet == ERROR_SUCCESS && dwType == REG_SZ) {
  468. hr = PublishDsData( pPrintQueue,
  469. SPLDS_URL,
  470. REG_SZ,
  471. (PBYTE) pszUrl);
  472. }
  473. FreeSplMem(pszUrl);
  474. }
  475. }
  476. }
  477. error:
  478. FreeSplMem(pInfo2);
  479. return hr;
  480. }
  481. HRESULT
  482. SetDriverProperties(
  483. HANDLE hPrinter,
  484. IADs *pPrintQueue
  485. )
  486. {
  487. DWORD i, cbBytes, dwCount;
  488. LPWSTR pStr;
  489. DWORD dwResult;
  490. LPWSTR pOutput = NULL, pTemp = NULL, pTemp1 = NULL;
  491. DWORD cOutputBytes, cTempBytes;
  492. POINTS point;
  493. WCHAR pBuf[100];
  494. BOOL bInSplSem = TRUE;
  495. DWORD dwTemp, dwPrintRate, dwPrintRateUnit, dwPrintPPM;
  496. HRESULT hr = S_OK;
  497. PPRINTER_INFO_2 pInfo2 = NULL;
  498. PWSTR pszUNCName;
  499. // Get UNCName
  500. hr = GetPrinterInfo2(hPrinter, &pInfo2);
  501. BAIL_ON_FAILURE(hr);
  502. if (!pInfo2) {
  503. hr = dw2hr(GetLastError());
  504. goto error;
  505. }
  506. pszUNCName = pInfo2->pPrinterName;
  507. // *** DeviceCapability properties ***
  508. pOutput = (PWSTR) AllocSplMem(cOutputBytes = 200);
  509. if (!pOutput) {
  510. hr = dw2hr(GetLastError());
  511. goto error;
  512. }
  513. pTemp = (PWSTR) AllocSplMem(cTempBytes = 200);
  514. if (!pTemp) {
  515. hr = dw2hr(GetLastError());
  516. goto error;
  517. }
  518. // printBinNames
  519. DevCapMultiSz( pszUNCName,
  520. pPrintQueue,
  521. DC_BINNAMES,
  522. 24,
  523. SPLDS_PRINT_BIN_NAMES);
  524. // printCollate (awaiting DC_COLLATE)
  525. dwResult = DeviceCapabilities( pszUNCName,
  526. NULL,
  527. DC_COLLATE,
  528. NULL,
  529. NULL);
  530. if (dwResult != GDI_ERROR) {
  531. hr = PublishDsData( pPrintQueue,
  532. SPLDS_PRINT_COLLATE,
  533. REG_BINARY,
  534. (PBYTE) &dwResult);
  535. }
  536. // printColor
  537. dwResult = DeviceCapabilities( pszUNCName,
  538. NULL,
  539. DC_COLORDEVICE,
  540. NULL,
  541. NULL);
  542. if (dwResult == GDI_ERROR) {
  543. // Try alternative method
  544. dwResult = ThisIsAColorPrinter(pszUNCName);
  545. }
  546. hr = PublishDsData( pPrintQueue,
  547. SPLDS_PRINT_COLOR,
  548. REG_BINARY,
  549. (PBYTE) &dwResult);
  550. // printDuplexSupported
  551. dwResult = DeviceCapabilities( pszUNCName,
  552. NULL,
  553. DC_DUPLEX,
  554. NULL,
  555. NULL);
  556. if (dwResult != GDI_ERROR) {
  557. hr = PublishDsData( pPrintQueue,
  558. SPLDS_PRINT_DUPLEX_SUPPORTED,
  559. REG_BINARY,
  560. (PBYTE) &dwResult);
  561. }
  562. // printStaplingSupported
  563. dwResult = DeviceCapabilities( pszUNCName,
  564. NULL,
  565. DC_STAPLE,
  566. NULL,
  567. NULL);
  568. if (dwResult != GDI_ERROR) {
  569. hr = PublishDsData( pPrintQueue,
  570. SPLDS_PRINT_STAPLING_SUPPORTED,
  571. REG_BINARY,
  572. (PBYTE) &dwResult);
  573. }
  574. // printMaxXExtent & printMaxYExtent
  575. dwResult = DeviceCapabilities( pszUNCName,
  576. NULL,
  577. DC_MAXEXTENT,
  578. NULL,
  579. NULL);
  580. if (dwResult != GDI_ERROR) {
  581. *((DWORD *) &point) = dwResult;
  582. dwTemp = (DWORD) point.x;
  583. hr = PublishDsData( pPrintQueue,
  584. SPLDS_PRINT_MAX_X_EXTENT,
  585. REG_DWORD,
  586. (PBYTE) &dwTemp);
  587. dwTemp = (DWORD) point.y;
  588. hr = PublishDsData( pPrintQueue,
  589. SPLDS_PRINT_MAX_Y_EXTENT,
  590. REG_DWORD,
  591. (PBYTE) &dwTemp);
  592. }
  593. // printMinXExtent & printMinYExtent
  594. dwResult = DeviceCapabilities( pszUNCName,
  595. NULL,
  596. DC_MINEXTENT,
  597. NULL,
  598. NULL);
  599. if (dwResult != GDI_ERROR) {
  600. *((DWORD *) &point) = dwResult;
  601. dwTemp = (DWORD) point.x;
  602. hr = PublishDsData( pPrintQueue,
  603. SPLDS_PRINT_MIN_X_EXTENT,
  604. REG_DWORD,
  605. (PBYTE) &dwTemp);
  606. dwTemp = (DWORD) point.y;
  607. hr = PublishDsData( pPrintQueue,
  608. SPLDS_PRINT_MIN_Y_EXTENT,
  609. REG_DWORD,
  610. (PBYTE) &dwTemp);
  611. }
  612. // printMediaSupported
  613. DevCapMultiSz( pszUNCName,
  614. pPrintQueue,
  615. DC_PAPERNAMES,
  616. 64,
  617. SPLDS_PRINT_MEDIA_SUPPORTED);
  618. // printMediaReady
  619. DevCapMultiSz( pszUNCName,
  620. pPrintQueue,
  621. DC_MEDIAREADY,
  622. 64,
  623. SPLDS_PRINT_MEDIA_READY);
  624. // printNumberUp
  625. dwResult = DeviceCapabilities( pszUNCName,
  626. NULL,
  627. DC_NUP,
  628. NULL,
  629. NULL);
  630. if (dwResult != GDI_ERROR) {
  631. // DS NUp is boolean
  632. dwResult = !!dwResult;
  633. hr = PublishDsData( pPrintQueue,
  634. SPLDS_PRINT_DUPLEX_SUPPORTED,
  635. REG_DWORD,
  636. (PBYTE) &dwResult);
  637. }
  638. // printMemory
  639. dwResult = DeviceCapabilities( pszUNCName,
  640. NULL,
  641. DC_PRINTERMEM,
  642. NULL,
  643. NULL);
  644. if (dwResult != GDI_ERROR) {
  645. hr = PublishDsData( pPrintQueue,
  646. SPLDS_PRINT_MEMORY,
  647. REG_DWORD,
  648. (PBYTE) &dwResult);
  649. }
  650. // printOrientationsSupported
  651. dwResult = DeviceCapabilities( pszUNCName,
  652. NULL,
  653. DC_ORIENTATION,
  654. NULL,
  655. NULL);
  656. if (dwResult != GDI_ERROR) {
  657. if (dwResult == 90 || dwResult == 270) {
  658. wcscpy(pBuf, L"PORTRAIT");
  659. wcscpy(pStr = pBuf + wcslen(pBuf) + 1, L"LANDSCAPE");
  660. }
  661. else {
  662. wcscpy(pStr = pBuf, L"PORTRAIT");
  663. }
  664. pStr += wcslen(pStr) + 1;
  665. *pStr++ = L'\0';
  666. hr = PublishDsData( pPrintQueue,
  667. SPLDS_PRINT_ORIENTATIONS_SUPPORTED,
  668. REG_MULTI_SZ,
  669. (PBYTE) pBuf);
  670. }
  671. // printMaxResolutionSupported
  672. dwResult = DeviceCapabilities( pszUNCName,
  673. NULL,
  674. DC_ENUMRESOLUTIONS,
  675. NULL,
  676. NULL);
  677. if (dwResult != GDI_ERROR) {
  678. if (cOutputBytes < dwResult*2*sizeof(DWORD)) {
  679. if(!(pTemp1 = (PWSTR) ReallocSplMem(pOutput, 0, cOutputBytes = dwResult*2*sizeof(DWORD))))
  680. goto error;
  681. pOutput = pTemp1;
  682. }
  683. dwResult = DeviceCapabilities( pszUNCName,
  684. NULL,
  685. DC_ENUMRESOLUTIONS,
  686. pOutput,
  687. NULL);
  688. if (dwResult == GDI_ERROR)
  689. goto error;
  690. // Find the maximum resolution: we have dwResult*2 resolutions to check
  691. for(i = dwTemp = 0 ; i < dwResult*2 ; ++i) {
  692. if (((DWORD *) pOutput)[i] > dwTemp)
  693. dwTemp = ((DWORD *) pOutput)[i];
  694. }
  695. hr = PublishDsData( pPrintQueue,
  696. SPLDS_PRINT_MAX_RESOLUTION_SUPPORTED,
  697. REG_DWORD,
  698. (PBYTE) &dwTemp);
  699. }
  700. // printLanguage
  701. DevCapMultiSz( pszUNCName,
  702. pPrintQueue,
  703. DC_PERSONALITY,
  704. 32,
  705. SPLDS_PRINT_LANGUAGE);
  706. // printRate
  707. // NOTE: If PrintRate is 0, no value is published
  708. dwResult = DeviceCapabilities( pszUNCName,
  709. NULL,
  710. DC_PRINTRATE,
  711. NULL,
  712. NULL);
  713. dwPrintRate = dwResult ? dwResult : GDI_ERROR;
  714. if (dwPrintRate != GDI_ERROR) {
  715. hr = PublishDsData( pPrintQueue,
  716. SPLDS_PRINT_RATE,
  717. REG_DWORD,
  718. (PBYTE) &dwPrintRate);
  719. }
  720. // printRateUnit
  721. dwResult = DeviceCapabilities( pszUNCName,
  722. NULL,
  723. DC_PRINTRATEUNIT,
  724. NULL,
  725. NULL);
  726. dwPrintRateUnit = dwResult;
  727. if (dwPrintRateUnit != GDI_ERROR) {
  728. switch (dwPrintRateUnit) {
  729. case PRINTRATEUNIT_PPM:
  730. pStr = L"PagesPerMinute";
  731. break;
  732. case PRINTRATEUNIT_CPS:
  733. pStr = L"CharactersPerSecond";
  734. break;
  735. case PRINTRATEUNIT_LPM:
  736. pStr = L"LinesPerMinute";
  737. break;
  738. case PRINTRATEUNIT_IPM:
  739. pStr = L"InchesPerMinute";
  740. break;
  741. default:
  742. pStr = L"";
  743. break;
  744. }
  745. hr = PublishDsData( pPrintQueue,
  746. SPLDS_PRINT_RATE_UNIT,
  747. REG_SZ,
  748. (PBYTE) pStr);
  749. }
  750. // printPagesPerMinute
  751. // DevCap returns 0 if there is no entry in GPD
  752. dwResult = DeviceCapabilities( pszUNCName,
  753. NULL,
  754. DC_PRINTRATEPPM,
  755. NULL,
  756. NULL);
  757. if (dwResult == GDI_ERROR)
  758. dwResult = 0;
  759. dwPrintPPM = dwResult;
  760. // If dwPrintPPM == 0, then calculate PPM from PrintRate
  761. if (dwPrintPPM == 0) {
  762. if (dwPrintRate == GDI_ERROR) {
  763. dwPrintPPM = GDI_ERROR;
  764. } else {
  765. switch (dwPrintRateUnit) {
  766. case PRINTRATEUNIT_PPM:
  767. dwPrintPPM = dwPrintRate;
  768. break;
  769. case PRINTRATEUNIT_CPS:
  770. case PRINTRATEUNIT_LPM:
  771. dwPrintPPM = dwPrintRate/PPM_FACTOR;
  772. if (dwPrintPPM == 0)
  773. dwPrintPPM = 1; // min PPM is 1
  774. break;
  775. default:
  776. dwPrintPPM = GDI_ERROR;
  777. break;
  778. }
  779. }
  780. }
  781. if (dwPrintPPM != GDI_ERROR) {
  782. hr = PublishDsData( pPrintQueue,
  783. SPLDS_PRINT_PAGES_PER_MINUTE,
  784. REG_DWORD,
  785. (PBYTE) &dwPrintPPM);
  786. }
  787. // printDriverVersion
  788. dwResult = DeviceCapabilities( pszUNCName,
  789. NULL,
  790. DC_VERSION,
  791. NULL,
  792. NULL);
  793. if (dwResult != GDI_ERROR) {
  794. hr = PublishDsData( pPrintQueue,
  795. SPLDS_DRIVER_VERSION,
  796. REG_DWORD,
  797. (PBYTE) &dwResult);
  798. }
  799. error:
  800. FreeSplMem(pInfo2);
  801. if (pOutput)
  802. FreeSplMem(pOutput);
  803. if (pTemp)
  804. FreeSplMem(pTemp);
  805. return hr;
  806. }
  807. HRESULT
  808. PublishDsData(
  809. IADs *pADs,
  810. PWSTR pValue,
  811. DWORD dwType,
  812. PBYTE pData
  813. )
  814. {
  815. HRESULT hr;
  816. BOOL bCreated = FALSE;
  817. switch (dwType) {
  818. case REG_SZ:
  819. hr = put_BSTR_Property(pADs, pValue, (LPWSTR) pData);
  820. break;
  821. case REG_MULTI_SZ:
  822. hr = put_MULTISZ_Property(pADs, pValue, (LPWSTR) pData);
  823. break;
  824. case REG_DWORD:
  825. hr = put_DWORD_Property(pADs, pValue, (DWORD *) pData);
  826. break;
  827. case REG_BINARY:
  828. hr = put_BOOL_Property(pADs, pValue, (BOOL *) pData);
  829. break;
  830. default:
  831. hr = dw2hr(ERROR_INVALID_PARAMETER);
  832. }
  833. BAIL_ON_FAILURE(hr);
  834. hr = pADs->SetInfo();
  835. if (FAILED(hr))
  836. pADs->GetInfo();
  837. error:
  838. return hr;
  839. }