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.

883 lines
23 KiB

  1. // Printer.cpp: implementation of the CPrinter class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "Printer.h"
  6. #include "wininet.h"
  7. static const DWORD BIT_IGNORED_JOB = (JOB_STATUS_PAUSED |
  8. JOB_STATUS_PRINTED |
  9. JOB_STATUS_DELETING |
  10. JOB_STATUS_OFFLINE |
  11. JOB_STATUS_SPOOLING);
  12. static const DWORD BIT_ERROR_JOB = (JOB_STATUS_ERROR | JOB_STATUS_PAPEROUT);
  13. static const DWORD CHAR_PER_PAGE = 4800;
  14. static const DWORD PAGEPERJOB = 1;
  15. static const DWORD BYTEPERJOB = 2;
  16. #ifdef WIN9X
  17. #error This code requires DRIVER_INFO_6 which is not availabe under Win9X
  18. #endif
  19. //////////////////////////////////////////////////////////////////////
  20. // Construction/Destruction
  21. //////////////////////////////////////////////////////////////////////
  22. CPrinter::CPrinter():
  23. m_hPrinter(NULL),
  24. m_pInfo2(NULL),
  25. m_pInfo4(NULL),
  26. m_pDriverInfo6(NULL),
  27. m_bCalcJobETA(NULL),
  28. m_pszUrlBuffer(NULL),
  29. m_pszOemUrl (NULL),
  30. m_pszManufacturer (NULL)
  31. {
  32. }
  33. CPrinter::~CPrinter()
  34. {
  35. if (m_pInfo2) {
  36. LocalFree (m_pInfo2);
  37. }
  38. if (m_pInfo4) {
  39. LocalFree (m_pInfo4);
  40. }
  41. if (m_pDriverInfo6) {
  42. LocalFree (m_pDriverInfo6);
  43. }
  44. if (m_hPrinter) {
  45. ClosePrinter (m_hPrinter);
  46. }
  47. if (m_pszUrlBuffer) {
  48. LocalFree (m_pszUrlBuffer);
  49. }
  50. if (m_pszOemUrl) {
  51. LocalFree (m_pszOemUrl);
  52. }
  53. if (m_pszManufacturer) {
  54. LocalFree (m_pszManufacturer);
  55. }
  56. }
  57. BOOL CPrinter::Open(LPTSTR pPrinterName, LPHANDLE phPrinter)
  58. {
  59. PRINTER_DEFAULTS pd = {NULL, NULL, PRINTER_ACCESS_USE};
  60. if (m_hPrinter != NULL)
  61. return FALSE;
  62. if (! (OpenPrinter(pPrinterName, &m_hPrinter, &pd)))
  63. return FALSE;
  64. if (phPrinter) {
  65. *phPrinter = m_hPrinter;
  66. }
  67. return TRUE;
  68. }
  69. // This is a compiler safe way of checking that an unsigned integer is
  70. // negative and returning zero if it is or the integer if it is not
  71. // Note: Tval can be any size but must be unsigned
  72. template<class T> inline T ZeroIfNegative(T Tval) {
  73. if (Tval & (T(1) << (sizeof(Tval) * 8 - 1))) return 0;
  74. else return Tval;
  75. }
  76. BOOL CPrinter::CalJobEta()
  77. {
  78. DWORD dwPrintRate = DWERROR;
  79. PJOB_INFO_2 pJobInfo = NULL;
  80. PJOB_INFO_2 pJob;
  81. DWORD dwNumJobs;
  82. DWORD dwNeeded = 0;
  83. DWORD i;
  84. float fFactor = 1;
  85. float fTotal = 0;
  86. DWORD dwNumJobsReqested;
  87. BOOL bRet = FALSE;
  88. const DWORD cdwLimit = 256;
  89. if (! AllocGetPrinterInfo2())
  90. return NULL;
  91. if (m_pInfo2->cJobs > 0) {
  92. if (m_pInfo2->cJobs > cdwLimit) {
  93. fFactor = (float) m_pInfo2->cJobs / cdwLimit;
  94. dwNumJobsReqested = cdwLimit;
  95. }
  96. else
  97. dwNumJobsReqested = m_pInfo2->cJobs;
  98. EnumJobs (m_hPrinter, 0, dwNumJobsReqested, 2,
  99. NULL, 0, &dwNeeded, &dwNumJobs);
  100. if ((GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
  101. (NULL == (pJobInfo = (PJOB_INFO_2)LocalAlloc(LPTR, dwNeeded))) ||
  102. (!EnumJobs (m_hPrinter, 0, dwNumJobsReqested, 2, (LPBYTE) pJobInfo, dwNeeded,
  103. &dwNeeded, &dwNumJobs))) {
  104. goto Cleanup;
  105. }
  106. // Get the average Job size
  107. // Find out if we can use page as the unit
  108. for (pJob = pJobInfo, i = 0; i < dwNumJobs; i++, pJob++) {
  109. if (pJob->Status & BIT_IGNORED_JOB)
  110. continue;
  111. if (pJob->Size > 0 && pJob->TotalPages == 0)
  112. break;
  113. }
  114. m_dwPendingJobCount = 0;
  115. if (i == dwNumJobs) {
  116. // All the jobs have the page information. Use page as the unit
  117. m_dwAvgJobSizeUnit = PAGEPERJOB;
  118. for (pJob = pJobInfo, i = 0; i < dwNumJobs; i++, pJob++) {
  119. if (pJob->Status & BIT_IGNORED_JOB)
  120. continue;
  121. m_dwPendingJobCount++;
  122. fTotal += pJob->TotalPages;
  123. }
  124. }
  125. else {
  126. // Use byte as the unit
  127. m_dwAvgJobSizeUnit = BYTEPERJOB;
  128. for (pJob = pJobInfo, i = 0; i < dwNumJobs; i++, pJob++) {
  129. if (pJob->Status & BIT_IGNORED_JOB)
  130. continue;
  131. m_dwPendingJobCount++;
  132. fTotal += ZeroIfNegative(pJob->Size);
  133. }
  134. }
  135. // Calculate the averate job size
  136. if (m_dwPendingJobCount) {
  137. m_dwAvgJobSize = DWORD ((fTotal) / (float) m_dwPendingJobCount);
  138. dwPrintRate = GetPPM();
  139. if (dwPrintRate != DWERROR)
  140. m_dwJobCompletionMinute = (DWORD) (fFactor * GetWaitingMinutes (dwPrintRate, pJobInfo, dwNumJobs));
  141. }
  142. else {
  143. m_dwAvgJobSize = 0;
  144. m_dwJobCompletionMinute = 0;
  145. }
  146. m_dwPendingJobCount = (DWORD) (m_dwPendingJobCount * fFactor);
  147. }
  148. else {
  149. m_dwPendingJobCount = 0;
  150. m_dwAvgJobSize = 0;
  151. m_dwJobCompletionMinute = 0;
  152. m_dwAvgJobSizeUnit = PAGEPERJOB;
  153. }
  154. m_bCalcJobETA = TRUE;
  155. // Set the last error to ERROR_INVALID_DATA if the printer rate is not available for the current printer
  156. // or if the printer status is not suitable to display the summary information
  157. //
  158. if (dwPrintRate == DWERROR ||
  159. m_pInfo2->Status & ( PRINTER_STATUS_PAUSED |
  160. PRINTER_STATUS_ERROR |
  161. PRINTER_STATUS_PENDING_DELETION |
  162. PRINTER_STATUS_PAPER_JAM |
  163. PRINTER_STATUS_PAPER_OUT |
  164. PRINTER_STATUS_OFFLINE )) {
  165. SetLastError (ERROR_INVALID_DATA);
  166. m_dwJobCompletionMinute = DWERROR;
  167. bRet = FALSE;
  168. }
  169. else
  170. bRet = TRUE;
  171. Cleanup:
  172. if (pJobInfo)
  173. LocalFree(pJobInfo);
  174. return bRet;
  175. }
  176. DWORD CPrinter::GetWaitingMinutes(DWORD dwPPM, PJOB_INFO_2 pJobInfo, DWORD dwNumJob)
  177. {
  178. DWORD dwWaitingTime = 0;
  179. DWORD dwTotalPages = 0;
  180. if (dwNumJob == 0)
  181. return 0;
  182. if (dwPPM == 0)
  183. return DWERROR;
  184. for (DWORD i = 0; i < dwNumJob; i++, pJobInfo++) {
  185. if (pJobInfo->Status & BIT_IGNORED_JOB)
  186. continue;
  187. if (pJobInfo->Status & BIT_ERROR_JOB)
  188. return DWERROR;
  189. if (pJobInfo->TotalPages > 0) {
  190. dwTotalPages += pJobInfo->TotalPages;
  191. }
  192. else {
  193. if (pJobInfo->Size) {
  194. dwTotalPages += 1 + ZeroIfNegative(pJobInfo->Size) / CHAR_PER_PAGE;
  195. }
  196. }
  197. }
  198. if (dwTotalPages)
  199. dwWaitingTime = 1 + dwTotalPages / dwPPM;
  200. return dwWaitingTime;
  201. }
  202. DWORD CPrinter::GetPPM()
  203. {
  204. DWORD dwPrintRate;
  205. DWORD dwPrintRateUnit;
  206. // Get PrintRate
  207. dwPrintRate = MyDeviceCapabilities(m_pInfo2->pPrinterName,
  208. NULL,
  209. DC_PRINTRATE,
  210. NULL,
  211. NULL);
  212. if (dwPrintRate == DWERROR ) {
  213. return dwPrintRate;
  214. }
  215. dwPrintRateUnit = MyDeviceCapabilities(m_pInfo2->pPrinterName,
  216. NULL,
  217. DC_PRINTRATEUNIT,
  218. NULL,
  219. NULL);
  220. switch (dwPrintRateUnit) {
  221. case PRINTRATEUNIT_PPM: // PagesPerMinute
  222. break;
  223. case PRINTRATEUNIT_CPS: // CharactersPerSecond
  224. dwPrintRate = CPS2PPM (dwPrintRate);
  225. break;
  226. case PRINTRATEUNIT_LPM: // LinesPerMinute
  227. dwPrintRate = LPM2PPM (dwPrintRate);
  228. break;
  229. case PRINTRATEUNIT_IPM: // InchesPerMinute
  230. dwPrintRate = DWERROR;
  231. break;
  232. default: // Unknown
  233. dwPrintRate = DWERROR;
  234. break;
  235. }
  236. return dwPrintRate ;
  237. }
  238. BOOL CPrinter::AllocGetPrinterInfo2()
  239. {
  240. DWORD dwNeeded = 0;
  241. PPRINTER_INFO_2 pPrinterInfo = NULL;
  242. LPTSTR pszTmp;
  243. if (m_hPrinter == NULL) {
  244. SetLastError (ERROR_INVALID_HANDLE);
  245. return FALSE;
  246. }
  247. // Get a PRINTER_INFO_2 structure filled up
  248. if (GetPrinter(m_hPrinter, 2, NULL, 0, &dwNeeded) ||
  249. (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
  250. (NULL == (pPrinterInfo = (PPRINTER_INFO_2)LocalAlloc(LPTR, dwNeeded))) ||
  251. (!GetPrinter(m_hPrinter, 2, (byte *)pPrinterInfo, dwNeeded, &dwNeeded))) {
  252. if (pPrinterInfo)
  253. LocalFree(pPrinterInfo);
  254. if (! GetLastError())
  255. SetLastError (ERROR_INVALID_DATA);
  256. return FALSE;
  257. }
  258. // Mark the offline status if the attribute says offline
  259. if (pPrinterInfo->Attributes & PRINTER_ATTRIBUTE_WORK_OFFLINE) {
  260. pPrinterInfo->Status |= PRINTER_STATUS_OFFLINE;
  261. }
  262. // Extract the first port for the case of pooled printing. i.e. we don't support pooled printing.
  263. if ( pPrinterInfo->pPortName) {
  264. if( pszTmp = _tcschr( pPrinterInfo->pPortName, TEXT(',')))
  265. *pszTmp = TEXT('\0');
  266. }
  267. if (m_pInfo2) {
  268. LocalFree (m_pInfo2);
  269. }
  270. m_pInfo2 = pPrinterInfo;
  271. return TRUE;
  272. }
  273. BOOL CPrinter::AllocGetPrinterInfo4()
  274. {
  275. DWORD dwNeeded = 0;
  276. PPRINTER_INFO_4 pPrinterInfo = NULL;
  277. if (m_hPrinter == NULL) {
  278. SetLastError (ERROR_INVALID_HANDLE);
  279. return FALSE;
  280. }
  281. // Get a PRINTER_INFO_4 structure filled up
  282. if (GetPrinter(m_hPrinter, 4, NULL, 0, &dwNeeded) ||
  283. (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
  284. (NULL == (pPrinterInfo = (PPRINTER_INFO_4)LocalAlloc(LPTR, dwNeeded))) ||
  285. (!GetPrinter(m_hPrinter, 4, (byte *)pPrinterInfo, dwNeeded, &dwNeeded))) {
  286. if (pPrinterInfo)
  287. LocalFree(pPrinterInfo);
  288. if (! (GetLastError()))
  289. SetLastError (ERROR_INVALID_DATA);
  290. return FALSE;
  291. }
  292. if (m_pInfo4) {
  293. LocalFree (m_pInfo4);
  294. }
  295. m_pInfo4 = pPrinterInfo;
  296. return TRUE;
  297. }
  298. BOOL CPrinter::AllocGetDriverInfo6()
  299. {
  300. DWORD dwNeeded = 0;
  301. PDRIVER_INFO_6 pDriverInfo = NULL;
  302. if (m_hPrinter == NULL) {
  303. SetLastError (ERROR_INVALID_HANDLE);
  304. return FALSE;
  305. }
  306. // Get a DRIVER_INFO_6 structure filled up
  307. if (GetPrinterDriver(m_hPrinter, NULL, 6, NULL, 0, &dwNeeded) ||
  308. (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ||
  309. (NULL == (pDriverInfo = (PDRIVER_INFO_6)LocalAlloc(LPTR, dwNeeded))) ||
  310. (!GetPrinterDriver(m_hPrinter, NULL, 6, (LPBYTE)pDriverInfo, dwNeeded, &dwNeeded))) {
  311. if (pDriverInfo)
  312. LocalFree(pDriverInfo);
  313. if (! (GetLastError()))
  314. SetLastError (ERROR_INVALID_DATA);
  315. return FALSE;
  316. }
  317. if (m_pDriverInfo6) {
  318. LocalFree (m_pDriverInfo6);
  319. }
  320. m_pDriverInfo6 = pDriverInfo;
  321. return TRUE;
  322. }
  323. PPRINTER_INFO_2 CPrinter::GetPrinterInfo2()
  324. {
  325. if (m_pInfo2 == NULL) {
  326. if (! AllocGetPrinterInfo2())
  327. return NULL;
  328. }
  329. return m_pInfo2;
  330. }
  331. PDRIVER_INFO_6 CPrinter::GetDriverInfo6()
  332. {
  333. if (m_pDriverInfo6 == NULL) {
  334. if (! AllocGetDriverInfo6()) {
  335. return NULL;
  336. }
  337. }
  338. return m_pDriverInfo6;
  339. }
  340. DWORD CPrinter::GetWaitingTime()
  341. {
  342. if (!m_bCalcJobETA) {
  343. SetLastError (ERROR_INVALID_DATA);
  344. return FALSE;
  345. }
  346. return m_dwJobCompletionMinute;
  347. }
  348. BOOL CPrinter::GetJobEtaData (DWORD & dwWaitingTime, DWORD &dwJobCount, DWORD &dwJobSize, DWORD &dwJob)
  349. {
  350. if (!m_bCalcJobETA) {
  351. SetLastError (ERROR_INVALID_DATA);
  352. return FALSE;
  353. }
  354. dwJobCount = m_dwPendingJobCount;
  355. dwJobSize = m_dwAvgJobSize;
  356. dwWaitingTime = m_dwJobCompletionMinute;
  357. dwJob = m_dwAvgJobSizeUnit;
  358. return TRUE;
  359. }
  360. LPTSTR CPrinter::GetPrinterWebUrl(void)
  361. {
  362. static const TCHAR c_szHttp[] = TEXT("http://");
  363. static const TCHAR c_szHttps[] = TEXT("https://");
  364. BOOL bReturn = FALSE;
  365. DWORD dwLastError = ERROR_SUCCESS;
  366. DWORD dwLen = 0;
  367. TCHAR szBuffer[MAX_COMPUTERNAME_LENGTH+1];
  368. DWORD dwBufferSize;
  369. DWORD dwAttributes;
  370. LPCTSTR pszServerName;
  371. LPTSTR pszShareName;
  372. LPTSTR pszSplServerName;
  373. LPTSTR pszSplPrinterName;
  374. LPTSTR pszSplShareName;
  375. //
  376. // Get printer info 4 to fetch the attribute.
  377. //
  378. bReturn = AllocGetPrinterInfo4();
  379. if (!bReturn) {
  380. if (GetLastError () == ERROR_INVALID_LEVEL ) {
  381. //
  382. // Most likely it is a remote printers folder, no support for level4, so
  383. // we have to use level 2 instead.
  384. //
  385. if (! AllocGetPrinterInfo2())
  386. goto Cleanup;
  387. }
  388. else {
  389. //
  390. // The call fails with other reasons
  391. //
  392. goto Cleanup;
  393. }
  394. }
  395. else{
  396. if (m_pInfo4->Attributes & PRINTER_ATTRIBUTE_LOCAL) {
  397. // Check if the local flag is on. If so, try to get printer info2 for more information
  398. if (! AllocGetPrinterInfo2())
  399. goto Cleanup;
  400. }
  401. }
  402. //
  403. // Assume failure
  404. //
  405. bReturn = FALSE;
  406. if (m_pInfo2) {
  407. dwAttributes = m_pInfo2->Attributes;
  408. pszSplServerName = m_pInfo2->pServerName;
  409. pszSplPrinterName = m_pInfo2->pPrinterName;
  410. pszSplShareName = m_pInfo2->pShareName;
  411. }
  412. else
  413. {
  414. dwAttributes = m_pInfo4->Attributes;
  415. pszSplServerName = m_pInfo4->pServerName;
  416. pszSplPrinterName = m_pInfo4->pPrinterName;
  417. pszSplShareName = NULL;
  418. }
  419. //
  420. // Check if it is a printer connected to an http port
  421. // then the port name is the url.
  422. //
  423. if( m_pInfo2 )
  424. {
  425. if( m_pInfo2->pPortName )
  426. {
  427. //
  428. // Compare the port name prefex to see if it is an HTTP port.
  429. //
  430. if( !_tcsnicmp( m_pInfo2->pPortName, c_szHttp, _tcslen( c_szHttp ) ) ||
  431. !_tcsnicmp( m_pInfo2->pPortName, c_szHttps, _tcslen( c_szHttps ) ) )
  432. {
  433. //
  434. // We always use portname as the URL
  435. //
  436. dwLen = 1 + lstrlen( m_pInfo2->pPortName );
  437. if (! (m_pszUrlBuffer = (LPTSTR) LocalAlloc (LPTR, dwLen * sizeof (TCHAR))))
  438. {
  439. goto Cleanup;
  440. }
  441. lstrcpy( m_pszUrlBuffer, m_pInfo2->pPortName );
  442. bReturn = TRUE;
  443. goto Cleanup;
  444. }
  445. }
  446. }
  447. //
  448. // If it is an unshared printer, return false
  449. //
  450. if ( !(dwAttributes & PRINTER_ATTRIBUTE_SHARED) )
  451. {
  452. goto Cleanup;
  453. }
  454. //
  455. // Check if it is a connection or a local printer or a masq printer
  456. // which is not connected over http, then build the url
  457. // from the \\server name\share name.
  458. //
  459. if( !pszSplServerName )
  460. {
  461. dwBufferSize = COUNTOF( szBuffer );
  462. if( !GetComputerName( szBuffer, &dwBufferSize ) )
  463. {
  464. goto Cleanup;
  465. }
  466. pszServerName = szBuffer;
  467. }
  468. //
  469. // Server name was provided then set our pointer to just
  470. // after the two leading wacks.
  471. //
  472. else
  473. {
  474. if( pszSplServerName[0] == TEXT('\\') &&
  475. pszSplServerName[1] == TEXT('\\') )
  476. {
  477. pszServerName = pszSplServerName + 2;
  478. }
  479. else
  480. {
  481. goto Cleanup;
  482. }
  483. }
  484. if ( !IsWebServerInstalled(pszSplServerName) ) {
  485. dwLastError = ERROR_NO_BROWSER_SERVERS_FOUND;
  486. goto Cleanup;
  487. }
  488. //
  489. // Build the URL - http://server/printers/ipp_0004.asp?printer=ShareName
  490. //
  491. if (pszSplShareName)
  492. {
  493. pszShareName = pszSplShareName;
  494. }
  495. else {
  496. //
  497. // Parse the sharename/printername from the printer name
  498. //
  499. if(pszSplPrinterName) {
  500. if (pszSplPrinterName[0] == TEXT ('\\') && pszSplPrinterName[1] == TEXT ('\\') )
  501. {
  502. pszShareName = _tcschr (pszSplPrinterName + 2, TEXT ('\\'));
  503. pszShareName++;
  504. }
  505. else
  506. pszShareName = pszSplPrinterName;
  507. }
  508. else
  509. {
  510. goto Cleanup;
  511. }
  512. }
  513. GetWebUIUrl (pszServerName, pszShareName, NULL, &dwLen);
  514. if (GetLastError () != ERROR_INSUFFICIENT_BUFFER )
  515. {
  516. goto Cleanup;
  517. }
  518. if (! (m_pszUrlBuffer = (LPTSTR) LocalAlloc (LPTR, dwLen * sizeof (TCHAR))))
  519. {
  520. goto Cleanup;
  521. }
  522. if (!GetWebUIUrl (pszServerName, pszShareName, m_pszUrlBuffer, &dwLen))
  523. {
  524. goto Cleanup;
  525. }
  526. //
  527. // Indicate success.
  528. //
  529. bReturn = TRUE;
  530. //
  531. // Clean any opened or allocated resources.
  532. //
  533. Cleanup:
  534. //
  535. // If this routine failed then set the last error.
  536. //
  537. if( !bReturn )
  538. {
  539. //
  540. // If the last error was not set then a called routine may
  541. // have set the last error. We don't want to clear the
  542. // last error.
  543. //
  544. if( dwLastError != ERROR_SUCCESS )
  545. {
  546. SetLastError( dwLastError );
  547. }
  548. }
  549. return m_pszUrlBuffer;
  550. }
  551. BOOL CPrinter::GetDriverData(
  552. DriverData dwDriverData,
  553. LPTSTR &pszData)
  554. {
  555. static const ULONG_PTR ulpOffset[LastDriverData] = {
  556. // This has the offsets into the DRIVER_INFO_6 structure.....
  557. ULOFFSET( PDRIVER_INFO_6, pszOEMUrl ) ,
  558. ULOFFSET( PDRIVER_INFO_6, pszHardwareID ) ,
  559. ULOFFSET( PDRIVER_INFO_6, pszMfgName)
  560. };
  561. LPTSTR pszDataString = NULL;
  562. BOOL bRet = FALSE;
  563. DWORD dwSize;
  564. ASSERT( (int)dwDriverData >= 0 && (int)dwDriverData < LastDriverData );
  565. if (! GetDriverInfo6() )
  566. goto Cleanup;
  567. pszDataString = *(LPTSTR *)(((ULONG_PTR) m_pDriverInfo6) + ulpOffset[dwDriverData] );
  568. if (pszDataString == NULL || *pszDataString == NULL)
  569. goto Cleanup;
  570. dwSize = sizeof(TCHAR) * (lstrlen( pszDataString ) + 1);
  571. if (! (pszData = (LPTSTR)LocalAlloc(LPTR, dwSize)))
  572. goto Cleanup;
  573. lstrcpy( pszData, pszDataString);
  574. bRet = TRUE;
  575. Cleanup:
  576. return bRet;
  577. }
  578. BOOL CPrinter::ParseUrlPattern(
  579. LPTSTR pSrc,
  580. LPTSTR pDest,
  581. DWORD &dwDestLen)
  582. {
  583. const dwMaxMacroLen = 255;
  584. enum {
  585. NORMALTEXT, STARTMACRO
  586. } URL_PATTERN_STATE;
  587. BOOL bRet = FALSE;
  588. DWORD dwLen = 0;
  589. DWORD dwMacroLen = 0;
  590. DWORD dwAvailbleSize;
  591. DWORD dwState = NORMALTEXT;
  592. int i;
  593. TCHAR ch;
  594. TCHAR szMacroName [dwMaxMacroLen + 1];
  595. LPTSTR pMacroValue = NULL;
  596. LPTSTR pszMacroList[] = {
  597. TEXT ("MODEL"),
  598. TEXT ("HARDWAREID"),
  599. };
  600. while (ch = *pSrc++) {
  601. switch (dwState) {
  602. case NORMALTEXT:
  603. if (ch == TEXT ('%')) {
  604. // Start a macro
  605. dwState = STARTMACRO;
  606. dwMacroLen = 0;
  607. szMacroName[0] = 0;
  608. }
  609. else {
  610. if (dwLen >= dwDestLen) {
  611. dwLen ++;
  612. }
  613. else {
  614. pDest[dwLen++] = ch;
  615. }
  616. }
  617. break;
  618. case STARTMACRO:
  619. if (ch == TEXT ('%')) {
  620. szMacroName[dwMacroLen] = 0;
  621. // Replace Macro
  622. for (int i = 0; i < sizeof (pszMacroList) / sizeof (pszMacroList[0]); i++) {
  623. if (!lstrcmpi (szMacroName, pszMacroList[i])) {
  624. pMacroValue = 0;
  625. switch (i) {
  626. case 0:
  627. AssignString (pMacroValue, m_pInfo2->pDriverName);
  628. break;
  629. case 1:
  630. GetDriverData (HardwareID , pMacroValue);
  631. break;
  632. default:
  633. break;
  634. }
  635. if (pMacroValue) {
  636. if (dwDestLen > dwLen)
  637. dwAvailbleSize = dwDestLen - dwLen;
  638. else
  639. dwAvailbleSize = 0;
  640. TCHAR szPlaceHolder[1];
  641. DWORD dwBufSize = sizeof (szPlaceHolder) / sizeof (TCHAR);
  642. if (!InternetCanonicalizeUrl (pMacroValue, szPlaceHolder, &dwBufSize, 0)) {
  643. if (dwBufSize < dwAvailbleSize ) {
  644. if (!InternetCanonicalizeUrl (pMacroValue, pDest + dwLen, &dwBufSize, 0)) {
  645. LocalFree (pMacroValue);
  646. return bRet;
  647. }
  648. else {
  649. dwLen = lstrlen (pDest);
  650. }
  651. }
  652. else {
  653. dwLen += dwBufSize;
  654. }
  655. }
  656. LocalFree (pMacroValue);
  657. }
  658. break;
  659. }
  660. }
  661. dwState = NORMALTEXT;
  662. }
  663. else {
  664. if (dwMacroLen < dwMaxMacroLen) {
  665. szMacroName[dwMacroLen ++] = ch;
  666. }
  667. }
  668. break;
  669. }
  670. }
  671. if (dwState == STARTMACRO) {
  672. SetLastError ( ERROR_INVALID_DATA );
  673. }
  674. else {
  675. if (dwLen >= dwDestLen) {
  676. SetLastError (ERROR_INSUFFICIENT_BUFFER);
  677. dwDestLen = dwLen + 1;
  678. }
  679. else {
  680. pDest[dwLen] = 0;
  681. bRet = TRUE;
  682. }
  683. }
  684. return bRet;
  685. }
  686. LPTSTR CPrinter::GetOemUrl(
  687. LPTSTR & pszManufacturer)
  688. {
  689. LPTSTR pszOemUrlPattern = NULL;
  690. DWORD dwLen = 0;
  691. LPTSTR pszUrl = NULL;
  692. if (!GetPrinterInfo2 () )
  693. goto Cleanup;
  694. if (GetDriverData (OEMUrlPattern, pszOemUrlPattern)) {
  695. if (! ParseUrlPattern (pszOemUrlPattern, NULL, dwLen)
  696. && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  697. m_pszOemUrl = (LPTSTR) LocalAlloc (LPTR, sizeof (TCHAR) * dwLen);
  698. if (m_pszOemUrl) {
  699. if (!ParseUrlPattern (pszOemUrlPattern, m_pszOemUrl, dwLen))
  700. goto Cleanup;
  701. }
  702. else
  703. goto Cleanup;
  704. }
  705. }
  706. if (GetDriverData (Manufacturer, m_pszManufacturer)) {
  707. pszManufacturer = m_pszManufacturer;
  708. pszUrl = m_pszOemUrl;
  709. }
  710. Cleanup:
  711. if (pszOemUrlPattern) {
  712. LocalFree ( pszOemUrlPattern);
  713. }
  714. return pszUrl;
  715. }