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.

1367 lines
34 KiB

  1. /*++
  2. Copyright (C) 1998 - 2002 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. PrntWrn
  6. Abstract:
  7. Code checks if any of the installed printers will fail during
  8. upgrade to Londhorn
  9. Author:
  10. Mikael Horal 15-March-2002
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include "string.hxx"
  15. enum EPrintUpgConstants
  16. {
  17. kReplacementDriver = 1,
  18. kWarnLevelWks = 2,
  19. kWarnLevelSrv = 3,
  20. kFileTime = 4,
  21. kUnidrv54 = 5,
  22. };
  23. enum EPrintUpgLevels
  24. {
  25. kBlocked = 1,
  26. kWarned = 2,
  27. };
  28. TCHAR cszPrintDriverMapping[] = TEXT("Printer Driver Mapping");
  29. TCHAR cszVersion[] = TEXT("Version");
  30. TCHAR cszExcludeSection[] = TEXT("Excluded Driver Files");
  31. EXTERN_C
  32. BOOL
  33. WINAPI
  34. DllMain(
  35. IN HINSTANCE hInst,
  36. IN DWORD dwReason,
  37. IN LPVOID lpRes
  38. )
  39. {
  40. UNREFERENCED_PARAMETER(lpRes);
  41. switch( dwReason ){
  42. case DLL_PROCESS_ATTACH:
  43. DisableThreadLibraryCalls(hInst);
  44. break;
  45. case DLL_PROCESS_DETACH:
  46. break;
  47. }
  48. return TRUE;
  49. }
  50. HRESULT
  51. GetLastErrorAsHResult(
  52. VOID
  53. )
  54. {
  55. return HRESULT_FROM_WIN32(GetLastError());
  56. }
  57. LPTSTR
  58. FileNamePart(
  59. IN LPCTSTR pszFullName
  60. )
  61. /*++
  62. Routine Description:
  63. Find the file name part of a fully qualified file name
  64. Arguments:
  65. pszFullName : Fully qualified path to the file
  66. Return Value:
  67. Pointer to the filename part in the fully qulaified string
  68. --*/
  69. {
  70. LPTSTR pszSlash, pszTemp;
  71. if ( !pszFullName )
  72. return NULL;
  73. //
  74. // First find the : for the drive
  75. //
  76. if ( pszTemp = wcschr(pszFullName, TEXT(':')) )
  77. pszFullName = pszFullName + 1;
  78. for ( pszTemp = (LPTSTR)pszFullName ;
  79. pszSlash = wcschr(pszTemp, TEXT('\\')) ;
  80. pszTemp = pszSlash + 1 )
  81. ;
  82. return *pszTemp ? pszTemp : NULL;
  83. }
  84. /*++
  85. Routine Name
  86. GetFileTimeByName
  87. Routine Description:
  88. Get the file time of the file given a full path.
  89. Arguments:
  90. pszPath - Full path of the driver
  91. pFileTime - Points to the file time
  92. Return Value:
  93. An HRESULT
  94. --*/
  95. HRESULT
  96. GetFileTimeByName(
  97. IN LPCTSTR pszPath,
  98. OUT FILETIME *pFileTime
  99. )
  100. {
  101. HRESULT hRetval = E_FAIL;
  102. HANDLE hFile = INVALID_HANDLE_VALUE;
  103. hRetval = pszPath && *pszPath && pFileTime ? S_OK : E_INVALIDARG;
  104. if (SUCCEEDED(hRetval))
  105. {
  106. hFile = CreateFile(pszPath,
  107. GENERIC_READ,
  108. FILE_SHARE_READ,
  109. NULL,
  110. OPEN_EXISTING,
  111. FILE_ATTRIBUTE_NORMAL,
  112. NULL);
  113. hRetval = (INVALID_HANDLE_VALUE != hFile) ? S_OK : GetLastErrorAsHResult();
  114. }
  115. if (SUCCEEDED(hRetval))
  116. {
  117. hRetval = GetFileTime(hFile, NULL, NULL, pFileTime) ? S_OK : GetLastErrorAsHResult();
  118. }
  119. if (hFile != INVALID_HANDLE_VALUE)
  120. {
  121. CloseHandle(hFile);
  122. }
  123. return hRetval;
  124. }
  125. /*++
  126. Routine Name
  127. GetSectionName
  128. Routine Description:
  129. Get the Section name in terms of environment and driver version.
  130. Arguments:
  131. pszEnvironment - The environment of the server, such as
  132. uVersion - The major version of the driver
  133. pstrSection - Points the name of section of driver mapping
  134. Return Value:
  135. An HRESULT
  136. --*/
  137. HRESULT
  138. GetSectionName(
  139. IN LPCTSTR pszEnvironment,
  140. IN UINT uVersion,
  141. OUT TString *pstrSection
  142. )
  143. {
  144. HRESULT hRetval = E_FAIL;
  145. hRetval = pszEnvironment && pstrSection ? S_OK : E_INVALIDARG;
  146. if (SUCCEEDED(hRetval))
  147. {
  148. hRetval = pstrSection->Format(_T("%s_%s_%s %d"), cszPrintDriverMapping, pszEnvironment, cszVersion, uVersion);
  149. }
  150. return hRetval;
  151. }
  152. /*++
  153. Routine Name
  154. InfGetString
  155. Routine Description:
  156. This routine is a wrapper to SetupGetStringField using TString.
  157. Arguments:
  158. pInfContext - The context of the inf
  159. uFieldIndex - The field index of the string to retrieve
  160. pstrField - Points to the string field as TString
  161. Return Value:
  162. An HRESULT
  163. --*/
  164. HRESULT
  165. InfGetString(
  166. IN INFCONTEXT *pInfContext,
  167. IN UINT uFieldIndex,
  168. OUT TString *pstrField
  169. )
  170. {
  171. HRESULT hRetval = E_FAIL;
  172. TCHAR szField[MAX_PATH] = {0};
  173. DWORD dwNeeded = 0;
  174. TCHAR *pszField = NULL;
  175. hRetval = pInfContext && pstrField ? S_OK : E_INVALIDARG;
  176. if (SUCCEEDED(hRetval))
  177. {
  178. hRetval = SetupGetStringField(pInfContext,
  179. uFieldIndex,
  180. szField,
  181. COUNTOF(szField),
  182. &dwNeeded) ? S_OK : GetLastErrorAsHResult();
  183. if (SUCCEEDED(hRetval))
  184. {
  185. hRetval = pstrField->Update(szField);
  186. }
  187. else if (FAILED(hRetval) && (ERROR_INSUFFICIENT_BUFFER == HRESULT_CODE(hRetval)))
  188. {
  189. pszField = new TCHAR[dwNeeded];
  190. hRetval = pszField ? S_OK : E_OUTOFMEMORY;
  191. if (SUCCEEDED(hRetval))
  192. {
  193. hRetval = SetupGetStringField(pInfContext,
  194. uFieldIndex,
  195. pszField,
  196. dwNeeded,
  197. &dwNeeded) ? S_OK : GetLastErrorAsHResult();
  198. }
  199. if (SUCCEEDED(hRetval))
  200. {
  201. hRetval = pstrField->Update(pszField);
  202. }
  203. }
  204. }
  205. delete [] pszField;
  206. return hRetval;
  207. }
  208. LPTSTR
  209. ReadDigit(
  210. LPTSTR ptr,
  211. LPWORD pW
  212. )
  213. {
  214. TCHAR c;
  215. //
  216. // Skip spaces
  217. //
  218. while ( !iswdigit(c = *ptr) && c != TEXT('\0') )
  219. ++ptr;
  220. if ( c == TEXT('\0') )
  221. return NULL;
  222. //
  223. // Read field
  224. //
  225. for ( *pW = 0 ; iswdigit(c = *ptr) ; ++ptr )
  226. *pW = *pW * 10 + c - TEXT('0');
  227. return ptr;
  228. }
  229. HRESULT
  230. StringToDate(
  231. LPTSTR pszDate,
  232. SYSTEMTIME *pInfTime
  233. )
  234. {
  235. BOOL bRet = FALSE;
  236. ZeroMemory(pInfTime, sizeof(*pInfTime));
  237. bRet = (pszDate = ReadDigit(pszDate, &(pInfTime->wMonth))) &&
  238. (pszDate = ReadDigit(pszDate, &(pInfTime->wDay))) &&
  239. (pszDate = ReadDigit(pszDate, &(pInfTime->wYear)));
  240. //
  241. // Y2K compatible check
  242. //
  243. if ( bRet && pInfTime->wYear < 100 ) {
  244. ASSERT(pInfTime->wYear >= 100);
  245. if ( pInfTime->wYear < 10 )
  246. pInfTime->wYear += 2000;
  247. else
  248. pInfTime->wYear += 1900;
  249. }
  250. if(!bRet)
  251. {
  252. SetLastError(ERROR_INVALID_DATA);
  253. }
  254. return bRet? S_OK : GetLastErrorAsHResult();
  255. }
  256. /*++
  257. Routine Name
  258. StringTimeToFileTime
  259. Routine Description:
  260. Converts a string of time in the form of "11/27/1999" to FILETIME.
  261. Arguments:
  262. pszFileTime - The file time as string such as "11/27/1999"
  263. pFileTime - Points to the converted FILETIME
  264. Return Value:
  265. An HRESULT
  266. --*/
  267. HRESULT
  268. StringTimeToFileTime(
  269. IN LPCTSTR pszFileTime,
  270. OUT FILETIME *pFileTime
  271. )
  272. {
  273. HRESULT hRetval = E_FAIL;
  274. SYSTEMTIME SystemTime;
  275. hRetval = pszFileTime && pFileTime ? S_OK : E_INVALIDARG;
  276. if (SUCCEEDED(hRetval))
  277. {
  278. //
  279. // StringToDate should take pszFileTime as const.
  280. //
  281. hRetval = StringToDate(const_cast<LPTSTR>(pszFileTime), &SystemTime) ? S_OK : GetLastErrorAsHResult();
  282. }
  283. if (SUCCEEDED(hRetval))
  284. {
  285. hRetval = SystemTimeToFileTime(&SystemTime, pFileTime) ? S_OK : GetLastErrorAsHResult();
  286. }
  287. return hRetval;
  288. }
  289. /*++
  290. Routine Name
  291. InfGetStringAsFileTime
  292. Routine Description:
  293. This routine get the time of driver in printupg and converts it to FILETIME.
  294. Arguments:
  295. pInfContext - The context of the inf
  296. uFieldIndex - The field index of the string to retrieve
  297. pFielTime - Points to the FILETIME structure
  298. Return Value:
  299. An HRESULT
  300. --*/
  301. HRESULT
  302. InfGetStringAsFileTime(
  303. IN INFCONTEXT *pInfContext,
  304. IN UINT uFieldIndex,
  305. OUT FILETIME *pFileTime
  306. )
  307. {
  308. HRESULT hRetval = E_FAIL;
  309. TString strDate;
  310. hRetval = pInfContext && pFileTime ? S_OK : E_INVALIDARG;
  311. if (SUCCEEDED(hRetval))
  312. {
  313. hRetval = InfGetString(pInfContext, uFieldIndex, &strDate);
  314. }
  315. if (SUCCEEDED(hRetval))
  316. {
  317. hRetval = StringTimeToFileTime(strDate, pFileTime);
  318. }
  319. return hRetval;
  320. }
  321. /*++
  322. Routine Name
  323. IsDateInLineNoOlderThanDriverDate
  324. Routine Description:
  325. This routines process the current line of inf and determinate whether the
  326. date in the line is not older than that of driver.
  327. Arguments:
  328. pInfContext - Points to the current context of an INF
  329. pDriverFileTime - File time of the actual driver
  330. pdwWarnLevelSrv - Points to the warning level for server SKU
  331. pdwWarnLevelWks - Points to the warning level for wks SKU
  332. pstrReplacementDriver - The replacement driver.
  333. pbHasUnidrv54 - Points to BOOL variable indicating if the driver has
  334. a Unidrv5.4 if function returns S_OK.
  335. Return Value:
  336. An HRESULT - S_OK means the date in the current line is no older
  337. than that of the driver
  338. --*/
  339. HRESULT
  340. IsDateInLineNoOlderThanDriverDate(
  341. IN INFCONTEXT *pInfContext,
  342. IN FILETIME *pDriverFileTime,
  343. OUT UINT *puWarnLevelSrv,
  344. OUT UINT *puWarnLevelWks,
  345. OUT TString *pstrReplacementDriver,
  346. OUT BOOL *pbHasUnidrv54
  347. )
  348. {
  349. HRESULT hRetval = E_FAIL;
  350. INT iWarnLevel = 0;
  351. FILETIME FileTimeInInf = {0};
  352. DWORD dwFieldCount;
  353. hRetval = pInfContext && pDriverFileTime && puWarnLevelSrv && puWarnLevelWks && pstrReplacementDriver && pbHasUnidrv54 ? S_OK : E_INVALIDARG;
  354. if (SUCCEEDED(hRetval))
  355. {
  356. dwFieldCount = SetupGetFieldCount(pInfContext);
  357. hRetval = SetupGetIntField(pInfContext, kWarnLevelSrv, &iWarnLevel) ? S_OK: GetLastErrorAsHResult();
  358. if (SUCCEEDED(hRetval))
  359. {
  360. *puWarnLevelSrv = iWarnLevel;
  361. hRetval = SetupGetIntField(pInfContext, kWarnLevelWks, &iWarnLevel) ? S_OK: GetLastErrorAsHResult();
  362. }
  363. if (SUCCEEDED(hRetval))
  364. {
  365. *puWarnLevelWks = iWarnLevel;
  366. hRetval = InfGetString(pInfContext, kReplacementDriver, pstrReplacementDriver);
  367. }
  368. if (SUCCEEDED(hRetval) && (dwFieldCount >= kUnidrv54))
  369. {
  370. INT iUniDrv54 = 0;
  371. //
  372. // Unidrv5.4 field is optional
  373. //
  374. if(FAILED(SetupGetIntField(pInfContext, kUnidrv54, &iUniDrv54) ? S_OK: GetLastErrorAsHResult()))
  375. {
  376. *pbHasUnidrv54 = FALSE;
  377. }
  378. else
  379. {
  380. *pbHasUnidrv54 = iUniDrv54 ? TRUE : FALSE;
  381. }
  382. }
  383. if (SUCCEEDED(hRetval))
  384. {
  385. hRetval = InfGetStringAsFileTime(pInfContext, kFileTime, &FileTimeInInf);
  386. //
  387. // Date field is optional.
  388. //
  389. if (FAILED(hRetval) && (ERROR_INVALID_PARAMETER == HRESULT_CODE(hRetval)))
  390. {
  391. hRetval = S_OK;
  392. }
  393. else if (SUCCEEDED(hRetval))
  394. {
  395. hRetval = CompareFileTime(pDriverFileTime, &FileTimeInInf) <= 0 ? S_OK : S_FALSE ;
  396. }
  397. }
  398. }
  399. return hRetval;
  400. }
  401. /*++
  402. Routine Name
  403. GetBlockingStatusByWksType
  404. Routine Description:
  405. Fill out the status of blocking according to the type of SKU that runs the
  406. service.
  407. Arguments:
  408. uWarnLevelSrv - The warn level for server SKU
  409. uWarnLevelSrv - The warn level for wks SKU
  410. bIsServer - Whether the SKU running printing service is server
  411. puBlockingStatus - Points to the result as status of blocking
  412. Return Value:
  413. An HRESULT
  414. --*/
  415. HRESULT
  416. GetBlockingStatusByWksType(
  417. IN UINT uWarnLevelSrv,
  418. IN UINT uWarnLevelWks,
  419. IN BOOL bIsServer,
  420. OUT UINT *puBlockingStatus
  421. )
  422. {
  423. HRESULT hRetval = E_FAIL;
  424. UINT uWarnLevel = 0;
  425. hRetval = puBlockingStatus ? S_OK : E_INVALIDARG;
  426. if (SUCCEEDED(hRetval))
  427. {
  428. *puBlockingStatus &= ~BSP_BLOCKING_LEVEL_MASK;
  429. *puBlockingStatus |= BSP_PRINTER_DRIVER_OK;
  430. uWarnLevel = bIsServer ? uWarnLevelSrv : uWarnLevelWks;
  431. switch (uWarnLevel)
  432. {
  433. case kBlocked:
  434. *puBlockingStatus |= BSP_PRINTER_DRIVER_BLOCKED;
  435. break;
  436. case kWarned:
  437. *puBlockingStatus |= BSP_PRINTER_DRIVER_WARNED;
  438. break;
  439. default:
  440. hRetval = E_FAIL;
  441. break;
  442. }
  443. }
  444. return hRetval;
  445. }
  446. /*++
  447. Routine Name
  448. IsDriverDllInExcludedSection
  449. Routine Description:
  450. Determine Whether the driver dll name is in the excluded section of printupg.
  451. Arguments:
  452. pszDriverPath - The path of the driver and this can be a full path or
  453. the file name
  454. hPrintUpgInf - The handle to printupg INF file
  455. Return Value:
  456. An HRESULT - S_OK means the driver dll is in the excluded section,
  457. S_FALSE means it is not.
  458. --*/
  459. HRESULT
  460. IsDriverDllInExcludedSection(
  461. IN LPCTSTR pszDriverPath,
  462. IN HINF hPrintUpgInf
  463. )
  464. {
  465. HRESULT hRetval = E_FAIL;
  466. TString strDriverFileName;
  467. INFCONTEXT InfContext;
  468. hRetval = pszDriverPath && (INVALID_HANDLE_VALUE != hPrintUpgInf) ? S_OK : E_INVALIDARG;
  469. if (SUCCEEDED(hRetval))
  470. {
  471. hRetval = strDriverFileName.Update(FileNamePart(pszDriverPath));
  472. }
  473. if (SUCCEEDED(hRetval) && !strDriverFileName.bEmpty())
  474. {
  475. hRetval = SetupFindFirstLine(hPrintUpgInf,
  476. cszExcludeSection,
  477. strDriverFileName,
  478. &InfContext) ? S_OK : GetLastErrorAsHResult();
  479. //
  480. // ERROR_LINE_NOT_FOUND is an HRESULT!
  481. //
  482. if (FAILED(hRetval) && (HRESULT_CODE(ERROR_LINE_NOT_FOUND) == HRESULT_CODE(hRetval)))
  483. {
  484. hRetval = S_FALSE;
  485. }
  486. }
  487. return hRetval;
  488. }
  489. /*++
  490. Routine Name
  491. IsDriverInMappingSection
  492. Routine Description:
  493. Check whether the driver is mapped, aka a bad driver.
  494. Arguments:
  495. pszDriverModel - The name of the driver to check
  496. pszEnvironment - The environment of the server, such as
  497. uVersion - The major version of the driver
  498. hPrintUpgInf - The handle to the PrintUpg Inf file
  499. pFileTimeDriver - Points to the file time of the driver
  500. pdwWarnLevelSrv - Points to the warning level for server SKU
  501. pdwWarnLevelWks - Points to the warning level for wks SKU
  502. pstrReplacementDriver - The replacement driver
  503. pbHasUnidrv54 - Points to BOOL variable indicating if the driver has
  504. a Unidrv5.4 if function returns S_OK.
  505. Return Value:
  506. An HRESULT - S_OK means the driver is a bad driver and is mapped to
  507. some inbox driver, S_FALSE means the driver is not.
  508. --*/
  509. HRESULT
  510. IsDriverInMappingSection(
  511. IN LPCTSTR pszModelName,
  512. IN LPCTSTR pszEnvironment,
  513. IN UINT uVersion,
  514. IN HINF hPrintUpgInf,
  515. IN FILETIME *pFileTimeDriver,
  516. OUT UINT *puWarnLevelSrv,
  517. OUT UINT *puWarnLevelWks,
  518. OUT TString *pstrReplacementDriver,
  519. OUT BOOL *pbHasUnidrv54
  520. )
  521. {
  522. HRESULT hRetval = E_FAIL;
  523. UINT uWarnLevelSrv = 0;
  524. UINT uWarnLevelWks = 0;
  525. INFCONTEXT InfContext;
  526. TString strMappingSection;
  527. TString strReplacementDriver;
  528. hRetval = pszModelName && pszEnvironment && (INVALID_HANDLE_VALUE != hPrintUpgInf) && pFileTimeDriver && puWarnLevelSrv && puWarnLevelWks && pstrReplacementDriver && pbHasUnidrv54 ? S_OK : E_INVALIDARG;
  529. if (SUCCEEDED(hRetval))
  530. {
  531. *puWarnLevelSrv = 0;
  532. *puWarnLevelWks = 0;
  533. hRetval = GetSectionName(pszEnvironment, uVersion, &strMappingSection);
  534. }
  535. if (SUCCEEDED(hRetval))
  536. {
  537. hRetval = SetupFindFirstLine(hPrintUpgInf, strMappingSection, pszModelName, &InfContext) ? S_FALSE : GetLastErrorAsHResult();
  538. }
  539. //
  540. // This code assumes that:
  541. //
  542. // There can be multiple lines for the same printer driver, but they
  543. // are sorted in non-descreasing order by date, the last field of the
  544. // line. The fist line that has the date no older than the driver's
  545. // date is used.
  546. //
  547. // An interesting case would be like (since date is optional)
  548. //
  549. // "HP LaserJet 4" = "HP LaserJet 4", 1, 2, "11/28/1999"
  550. // "HP LaserJet 4" = "HP LaserJet 4", 2, 1
  551. //
  552. // If a date is empty then the driver of all dates are blocked, hence
  553. // an empty date means close to a very late date in the future.
  554. //
  555. for (;S_FALSE == hRetval;)
  556. {
  557. hRetval = IsDateInLineNoOlderThanDriverDate(&InfContext, pFileTimeDriver, &uWarnLevelSrv, &uWarnLevelWks, &strReplacementDriver, pbHasUnidrv54);
  558. if (S_FALSE == hRetval)
  559. {
  560. hRetval = SetupFindNextMatchLine(&InfContext, pszModelName, &InfContext) ? S_FALSE : GetLastErrorAsHResult();
  561. }
  562. }
  563. //
  564. // ERROR_LINE_NOT_FOUND is an HRESULT!
  565. //
  566. if (FAILED(hRetval) && (HRESULT_CODE(ERROR_LINE_NOT_FOUND) == HRESULT_CODE(hRetval)))
  567. {
  568. hRetval = S_FALSE;
  569. }
  570. if (S_OK == hRetval)
  571. {
  572. *puWarnLevelSrv = uWarnLevelSrv;
  573. *puWarnLevelWks = uWarnLevelWks;
  574. hRetval = pstrReplacementDriver->Update(strReplacementDriver);
  575. }
  576. return hRetval;
  577. }
  578. /*++
  579. Routine Name
  580. bFoundSwitch
  581. Routine Description:
  582. Checks if the switch pszFlag is given at the command prompt. If it is
  583. it tries to find (the compressed) printupg at this location and
  584. decompress it into pszTempFileName.
  585. Arguments:
  586. pszFlag - Flag
  587. pszTempFileName - The name of the temporary file to which the compressed
  588. printupg.inf is decompressed.
  589. Return Value:
  590. A BOOL - TRUE if path was found and file successfully decompressed
  591. FALSE otherwise
  592. --*/
  593. BOOL bFoundSwitch(IN TCHAR *pszFlag, IN TCHAR *pszTempFileName)
  594. {
  595. BOOL bRet = FALSE;
  596. TCHAR szInstallPath[MAX_PATH];
  597. HRESULT hRet;
  598. int nr_args;
  599. LPTSTR *ppszCommandLine = CommandLineToArgvW(GetCommandLine(), &nr_args);
  600. if (ppszCommandLine == NULL)
  601. {
  602. //
  603. // Note GlobalFree does NOT take NULL argument!
  604. // (generates an access violation!)
  605. //
  606. return FALSE;
  607. }
  608. for (int i = 0; i < nr_args; i++)
  609. {
  610. if (!_tcsncicmp(ppszCommandLine[i], pszFlag, _tcslen(pszFlag)))
  611. {
  612. TCHAR *pszPath = ppszCommandLine[i] + _tcslen(pszFlag);
  613. //
  614. // Only check if a non-zero length path was specified
  615. //
  616. if (_tcslen(pszPath))
  617. {
  618. //
  619. // Add "\" if it is not already the last charachter in the path.
  620. // Append printupg.inf to path
  621. //
  622. hRet = StringCchCopy(szInstallPath, COUNTOF(szInstallPath), pszPath);
  623. if (SUCCEEDED(hRet) && (szInstallPath[_tcslen(szInstallPath)-1] != _T('\\')))
  624. {
  625. hRet = StringCchCat(szInstallPath, COUNTOF(szInstallPath), _T("\\"));
  626. }
  627. if(SUCCEEDED(hRet))
  628. {
  629. hRet = StringCchCat(szInstallPath, COUNTOF(szInstallPath), _T("printupg.inf"));
  630. }
  631. if (SUCCEEDED(hRet))
  632. {
  633. hRet = HRESULT_FROM_WIN32(SetupDecompressOrCopyFile(szInstallPath, pszTempFileName, NULL));
  634. }
  635. if(SUCCEEDED(hRet))
  636. {
  637. bRet = TRUE;
  638. }
  639. else
  640. {
  641. SetLastError(HRESULT_CODE(hRet));
  642. }
  643. }
  644. break;
  645. }
  646. }
  647. GlobalFree(ppszCommandLine);
  648. return bRet;
  649. }
  650. /*++
  651. Routine Name
  652. CreateInfHandle
  653. Routine Description:
  654. Creates a handle to printupg.inf. The function first tries to find the
  655. directory where printupg.inf resides. First it checks is the flag /m:
  656. was found at the command prompt. If it is it looks in the specified
  657. directory. If it does not find it there - or if no /s: flag was given -
  658. it checks the directory specified after /m: and if it is not found there
  659. it checks the directory in which winnt32.exe was started up from.
  660. Arguments:
  661. pszTempFileName - The name of the temporary file to which the compressed
  662. printupg.inf is decompressed.
  663. hInfFile - Pointer to a the printupg.inf file's handle
  664. Return Value:
  665. A BOOL - TRUE if success; FALSE otherwise
  666. --*/
  667. BOOL CreateInfHandle(IN TCHAR *pszTempFileName, OUT HINF *hInfFile){
  668. BOOL bRet = FALSE;
  669. BOOL bFoundInf = bFoundSwitch(_T("/m:"), pszTempFileName);
  670. if (!bFoundInf)
  671. {
  672. bFoundInf = bFoundSwitch(_T("/s:"), pszTempFileName);
  673. }
  674. if (!bFoundInf)
  675. {
  676. TCHAR szInstallPath[MAX_PATH];
  677. //
  678. // szInstallPath will contain the full path for winnt32.exe
  679. //
  680. if (!GetModuleFileName(NULL, szInstallPath, COUNTOF(szInstallPath)))
  681. {
  682. goto Cleanup;
  683. }
  684. szInstallPath[COUNTOF(szInstallPath) - 1] = TEXT('\0');
  685. //
  686. // Keep the directory, but exchange winnt32.exe for printupg.inf
  687. //
  688. TCHAR *pszTemp = (TCHAR *) _tcsrchr(szInstallPath, _T('\\'));
  689. HRESULT hRet;
  690. if(!pszTemp)
  691. {
  692. goto Cleanup;
  693. }
  694. pszTemp++;
  695. *pszTemp = _T('\0');
  696. if(FAILED(hRet = StringCchCat(szInstallPath, COUNTOF(szInstallPath), _T("printupg.inf"))))
  697. {
  698. SetLastError(HRESULT_CODE(hRet));
  699. goto Cleanup;
  700. }
  701. //
  702. // Did we find printupg.inf in the local directory?
  703. //
  704. if (SetupDecompressOrCopyFile(szInstallPath, pszTempFileName, NULL) != ERROR_SUCCESS)
  705. {
  706. goto Cleanup;
  707. }
  708. }
  709. *hInfFile = SetupOpenInfFile(pszTempFileName,
  710. _T("PrinterUpgrade"),
  711. INF_STYLE_WIN4,
  712. NULL);
  713. if ((*hInfFile) != INVALID_HANDLE_VALUE)
  714. {
  715. bRet = TRUE;
  716. }
  717. Cleanup:
  718. return bRet;
  719. }
  720. /*++
  721. Routine Name
  722. GetTempInfFile
  723. Routine Description:
  724. Creates a temporary file and returns its name (and full path) in pszTempFileName
  725. Arguments:
  726. pszTempFileName - The full path and name of the temporary file
  727. Must have length MAX_PATH
  728. Return Value:
  729. A BOOL - TRUE if success; FALSE otherwise
  730. --*/
  731. BOOL GetTempInfFile(OUT TCHAR *pszTempFileName){
  732. TCHAR szTempPath[MAX_PATH];
  733. BOOL bRet = FALSE;
  734. if (!GetTempPath(COUNTOF(szTempPath), szTempPath))
  735. {
  736. goto Cleanup;
  737. }
  738. if (!GetTempFileName(szTempPath, _T("upg"), 0, pszTempFileName))
  739. {
  740. pszTempFileName[0] = _T('\0');
  741. goto Cleanup;
  742. }
  743. bRet = TRUE;
  744. Cleanup:
  745. return bRet;}
  746. /*++
  747. Routine Name
  748. GetProductType
  749. Routine Description:
  750. Check whether the product type of the running version is Workstation.
  751. Arguments:
  752. bIsWrk - Boolean indicating if the product type of
  753. the running version is Workstation (i.e. not Server)
  754. Return Value:
  755. A BOOL - TRUE if success; FALSE otherwise
  756. --*/
  757. BOOL GetProductType(OUT BOOL *bIsWrk)
  758. {
  759. OSVERSIONINFOEX osvi;
  760. //
  761. // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
  762. // If that fails, check registry instead
  763. //
  764. ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
  765. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  766. if ( GetVersionEx ((OSVERSIONINFO *) &osvi) )
  767. {
  768. if ( osvi.wProductType == VER_NT_WORKSTATION )
  769. {
  770. *bIsWrk = TRUE;
  771. }
  772. else
  773. {
  774. *bIsWrk = FALSE;
  775. }
  776. }
  777. else
  778. {
  779. HKEY hKey;
  780. TCHAR szProductType[MAX_PATH];
  781. DWORD dwBufLen;
  782. if (RegOpenKeyEx(
  783. HKEY_LOCAL_MACHINE,
  784. _T("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"),
  785. 0,
  786. KEY_QUERY_VALUE,
  787. &hKey) != ERROR_SUCCESS)
  788. {
  789. return FALSE;
  790. }
  791. dwBufLen = sizeof(szProductType);
  792. if (RegQueryValueEx(hKey,
  793. _T("ProductType"),
  794. NULL,
  795. NULL,
  796. (LPBYTE) szProductType,
  797. &dwBufLen) != ERROR_SUCCESS)
  798. {
  799. RegCloseKey(hKey);
  800. return FALSE;
  801. }
  802. RegCloseKey( hKey );
  803. szProductType[COUNTOF(szProductType)-1] = _T('\0');
  804. if ( lstrcmpi( _T("WINNT"), szProductType) == 0 )
  805. {
  806. *bIsWrk = TRUE;
  807. }
  808. else
  809. {
  810. *bIsWrk = FALSE;
  811. }
  812. }
  813. return TRUE;
  814. }
  815. /*++
  816. Routine Name
  817. SetupCallback
  818. Routine Description:
  819. Calls the callback function after setting up the parameters.
  820. Arguments:
  821. BlockingStatus - The blocking status of the driver
  822. bHasInBox - Boolean indicating if there exists a replacement driver
  823. for the driver
  824. bHasUnidrv54 - Boolean indicating if there exists a Unidrv5.4 for the driver
  825. pszDriverName - The name of the driver
  826. CompatibilityCallback - The Callback funtcion
  827. Context - Argument for the callback function
  828. Return Value:
  829. A BOOL - TRUE if callback called successfull or if the driver is not blocked
  830. FALSE otherwise
  831. --*/
  832. BOOL SetupCallback(IN INT BlockingStatus,
  833. IN BOOL bHasInBox,
  834. IN BOOL bHasUnidrv54,
  835. IN PCTSTR pszDriverName,
  836. IN PCOMPAIBILITYCALLBACK CompatibilityCallback,
  837. IN LPVOID Context){
  838. COMPATIBILITY_ENTRY CompEntry = {0};
  839. CompEntry.Description = (TCHAR *) pszDriverName;
  840. CompEntry.RegKeyName = NULL;
  841. CompEntry.RegValName = NULL;
  842. CompEntry.RegValDataSize= 0;
  843. CompEntry.RegValData = NULL;
  844. CompEntry.SaveValue = NULL;
  845. CompEntry.Flags = 0;
  846. /*++
  847. case 0: Driver not blocked - will not happen here!
  848. case 1: Driver Blocked
  849. case 2: Driver Warned
  850. case n: Illegal blocking status - ignore
  851. --*/
  852. switch (BlockingStatus)
  853. {
  854. case kBlocked:
  855. if (bHasInBox && bHasUnidrv54)
  856. {
  857. CompEntry.HtmlName = _T("CompData\\upgbyy.htm");
  858. CompEntry.TextName = _T("CompData\\upgbyy.txt");
  859. }
  860. else if (bHasInBox)
  861. {
  862. CompEntry.HtmlName = _T("CompData\\upgbyn.htm");
  863. CompEntry.TextName = _T("CompData\\upgbyn.txt");
  864. }
  865. else
  866. {
  867. CompEntry.HtmlName = _T("CompData\\upgbnn.htm");
  868. CompEntry.TextName = _T("CompData\\upgbnn.txt");
  869. }
  870. break;
  871. case kWarned:
  872. if (bHasInBox)
  873. {
  874. CompEntry.HtmlName = _T("CompData\\upgwy.htm");
  875. CompEntry.TextName = _T("CompData\\upgwy.txt");
  876. }
  877. else
  878. {
  879. CompEntry.HtmlName = _T("CompData\\upgwn.htm");
  880. CompEntry.TextName = _T("CompData\\upgwn.txt");
  881. }
  882. break;
  883. default:
  884. return TRUE;
  885. }
  886. return CompatibilityCallback(&CompEntry,Context);
  887. }
  888. /*++
  889. Entry point for prntwrn.dll
  890. Return Value:
  891. A BOOL - FALSE if something failed
  892. TRUE in all other cases
  893. --*/
  894. BOOL
  895. PrntWrn(
  896. PCOMPAIBILITYCALLBACK CompatibilityCallback,
  897. LPVOID Context
  898. )
  899. {
  900. BOOL bRet = FALSE;
  901. HRESULT hRetval = S_OK;
  902. PDRIVER_INFO_3 pInstalledDrivers = NULL;
  903. DWORD dwMemoryNeeded = 0, cInstalledDrivers = 0;
  904. HINF hInfFile = INVALID_HANDLE_VALUE;
  905. TCHAR szTempFileName[MAX_PATH+1] = _T("\0");
  906. BOOL bIsWrk;
  907. if (!GetProductType(&bIsWrk))
  908. {
  909. goto Cleanup;
  910. }
  911. if (!GetTempInfFile(szTempFileName))
  912. {
  913. goto Cleanup;
  914. }
  915. if (!CreateInfHandle(szTempFileName, &hInfFile))
  916. {
  917. goto Cleanup;
  918. }
  919. //
  920. // ISSUE-2002/03/14-mikaelho
  921. // We will only warn for printer drivers of the same platform.
  922. //
  923. //
  924. // Note - EnumPrinterDrivers succeedes if there are no drivers!!
  925. //
  926. if (!EnumPrinterDrivers(NULL, LOCAL_ENVIRONMENT, 3, NULL, 0, &dwMemoryNeeded, &cInstalledDrivers))
  927. {
  928. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  929. {
  930. pInstalledDrivers = (PDRIVER_INFO_3) LocalAlloc(LPTR, dwMemoryNeeded);
  931. if (pInstalledDrivers == NULL)
  932. {
  933. goto Cleanup;
  934. }
  935. }
  936. else
  937. {
  938. goto Cleanup;
  939. }
  940. }
  941. //
  942. // No drivers installed!
  943. //
  944. if (!pInstalledDrivers)
  945. {
  946. bRet = TRUE;
  947. goto Cleanup;
  948. }
  949. //
  950. // Copy all the installed drivers into pInstalledDrivers array
  951. //
  952. if (!EnumPrinterDrivers(NULL, LOCAL_ENVIRONMENT, 3, (LPBYTE) pInstalledDrivers, dwMemoryNeeded, &dwMemoryNeeded, &cInstalledDrivers))
  953. {
  954. goto Cleanup;
  955. }
  956. //
  957. // Check all installed drivers
  958. //
  959. for (DWORD cDrivers = 0; SUCCEEDED(hRetval) && (cDrivers < cInstalledDrivers); cDrivers++)
  960. {
  961. FILETIME DriverFileTime;
  962. BOOL bHasUnidrv54 = FALSE;
  963. TString strReplacementDriver;
  964. UINT uBlockingStatus = 0;
  965. UINT uWarnLevelSrv = 0;
  966. UINT uWarnLevelWks = 0;
  967. if (SUCCEEDED(GetFileTimeByName(pInstalledDrivers[cDrivers].pDriverPath, &DriverFileTime)))
  968. {
  969. hRetval = IsDriverDllInExcludedSection(pInstalledDrivers[cDrivers].pDriverPath, hInfFile);
  970. //
  971. // S_FALSE means that the driver is not in excluded driverfiles secion.
  972. //
  973. if (S_FALSE == hRetval)
  974. {
  975. hRetval = IsDriverInMappingSection(pInstalledDrivers[cDrivers].pName,
  976. LOCAL_ENVIRONMENT,
  977. pInstalledDrivers[cDrivers].cVersion,
  978. hInfFile,
  979. &DriverFileTime,
  980. &uWarnLevelSrv,
  981. &uWarnLevelWks,
  982. &strReplacementDriver,
  983. &bHasUnidrv54);
  984. //
  985. // S_OK means that driver is blocked or warned
  986. //
  987. if (S_OK == hRetval)
  988. {
  989. if (SUCCEEDED(GetBlockingStatusByWksType(uWarnLevelSrv, uWarnLevelWks, !bIsWrk, &uBlockingStatus)))
  990. {
  991. if (!SetupCallback(uBlockingStatus,
  992. !strReplacementDriver.bEmpty(),
  993. bHasUnidrv54,
  994. pInstalledDrivers[cDrivers].pName,
  995. CompatibilityCallback,
  996. Context))
  997. {
  998. goto Cleanup;
  999. }
  1000. }
  1001. }
  1002. }
  1003. }
  1004. }
  1005. if(SUCCEEDED(hRetval))
  1006. {
  1007. bRet = TRUE;
  1008. }
  1009. Cleanup:
  1010. LocalFree(pInstalledDrivers);
  1011. if (hInfFile != INVALID_HANDLE_VALUE)
  1012. {
  1013. SetupCloseInfFile(hInfFile);
  1014. }
  1015. if (_tcslen(szTempFileName))
  1016. {
  1017. DeleteFile(szTempFileName);
  1018. }
  1019. return bRet;
  1020. }