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.

1667 lines
46 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. Utildi.c
  6. Abstract:
  7. Driver Setup DeviceInstaller Utility functions
  8. Author:
  9. Muhunthan Sivapragasam (MuhuntS) 06-Sep-1995
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. static const GUID GUID_DEVCLASS_PRINTER =
  14. { 0x4d36e979L, 0xe325, 0x11ce,
  15. { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } };
  16. #if 0
  17. TCHAR cszOEMInfGen[] = TEXT("%s\\inf\\OEM%d.INF");
  18. TCHAR cszInfGen[] = TEXT("%s\\inf\\%s");
  19. TCHAR cszClass[] = TEXT("Class");
  20. TCHAR cszProvider[] = TEXT("Provider");
  21. TCHAR cszPNF[] = TEXT ("PNF");
  22. TCHAR cszINF[] = TEXT ("\\INF\\");
  23. TCHAR cszInfWildCard[] = TEXT ("*.inf");
  24. #endif
  25. extern TCHAR cszPrinter[];
  26. LPTSTR
  27. GetInfQueryString(
  28. IN PSP_INF_INFORMATION pSpInfInfo,
  29. IN LPCTSTR pszKey
  30. )
  31. /*++
  32. Routine Description:
  33. Gets a specified string in a INF info list and put it into allocated memory
  34. Arguments:
  35. pSpInfInfo : Pointer to Handle to the information of an INF file
  36. pszKey : Key of the string to be queried
  37. Return Value:
  38. The allocated string on success
  39. NULL else
  40. --*/
  41. {
  42. DWORD dwNeeded = 128;
  43. LPTSTR pszStr;
  44. if (! (pszStr = LocalAllocMem (dwNeeded * sizeof (*pszStr))))
  45. return NULL;
  46. if (SetupQueryInfVersionInformation(pSpInfInfo, 0, pszKey, pszStr,
  47. dwNeeded, &dwNeeded)) {
  48. return pszStr;
  49. }
  50. else {
  51. LocalFreeMem (pszStr);
  52. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER ) return NULL;
  53. // Allocate Memory
  54. if (! (pszStr = LocalAllocMem (dwNeeded * sizeof (*pszStr))))
  55. return NULL;
  56. if (!SetupQueryInfVersionInformation(pSpInfInfo, 0, pszKey, pszStr,
  57. dwNeeded, &dwNeeded)){
  58. LocalFreeMem (pszStr);
  59. return NULL;
  60. }
  61. else
  62. return pszStr;
  63. }
  64. }
  65. BOOL
  66. SetSelectDevParams(
  67. IN HDEVINFO hDevInfo,
  68. IN PSP_DEVINFO_DATA pDevInfoData,
  69. IN BOOL bWin95,
  70. IN LPCTSTR pszModel OPTIONAL
  71. )
  72. /*++
  73. Routine Description:
  74. Sets the select device parameters by calling setup apis
  75. Arguments:
  76. hDevInfo : Handle to the printer class device information list
  77. bWin95 : TRUE if selecting Win95 driver, else WinNT driver
  78. pszModel : Printer model we are looking for -- only for Win95 case
  79. Return Value:
  80. TRUE on success
  81. FALSE else
  82. --*/
  83. {
  84. SP_SELECTDEVICE_PARAMS SelectDevParams;
  85. LPTSTR pszWin95Instn;
  86. SelectDevParams.ClassInstallHeader.cbSize
  87. = sizeof(SelectDevParams.ClassInstallHeader);
  88. SelectDevParams.ClassInstallHeader.InstallFunction
  89. = DIF_SELECTDEVICE;
  90. //
  91. // Get current SelectDevice parameters, and then set the fields
  92. // we want to be different from default
  93. //
  94. if ( !SetupDiGetClassInstallParams(
  95. hDevInfo,
  96. pDevInfoData,
  97. &SelectDevParams.ClassInstallHeader,
  98. sizeof(SelectDevParams),
  99. NULL) ) {
  100. if ( GetLastError() != ERROR_NO_CLASSINSTALL_PARAMS )
  101. return FALSE;
  102. ZeroMemory(&SelectDevParams, sizeof(SelectDevParams)); // NEEDED 10/11 ?
  103. SelectDevParams.ClassInstallHeader.cbSize
  104. = sizeof(SelectDevParams.ClassInstallHeader);
  105. SelectDevParams.ClassInstallHeader.InstallFunction
  106. = DIF_SELECTDEVICE;
  107. }
  108. //
  109. // Set the strings to use on the select driver page ..
  110. //
  111. LoadString(ghInst,
  112. IDS_PRINTERWIZARD,
  113. SelectDevParams.Title,
  114. SIZECHARS(SelectDevParams.Title));
  115. //
  116. // For Win95 drivers instructions are different than NT drivers
  117. //
  118. if ( bWin95 ) {
  119. pszWin95Instn = GetStringFromRcFile(IDS_WIN95DEV_INSTRUCT);
  120. if ( !pszWin95Instn )
  121. return FALSE;
  122. if ( lstrlen(pszWin95Instn) + lstrlen(pszModel) + 1
  123. > sizeof(SelectDevParams.Instructions) ) {
  124. LocalFreeMem(pszWin95Instn);
  125. return FALSE;
  126. }
  127. wsprintf(SelectDevParams.Instructions, pszWin95Instn, pszModel);
  128. LocalFreeMem(pszWin95Instn);
  129. } else {
  130. LoadString(ghInst,
  131. IDS_WINNTDEV_INSTRUCT,
  132. SelectDevParams.Instructions,
  133. SIZECHARS(SelectDevParams.Instructions));
  134. }
  135. LoadString(ghInst,
  136. IDS_SELECTDEV_LABEL,
  137. SelectDevParams.ListLabel,
  138. SIZECHARS(SelectDevParams.ListLabel));
  139. return SetupDiSetClassInstallParams(
  140. hDevInfo,
  141. pDevInfoData,
  142. &SelectDevParams.ClassInstallHeader,
  143. sizeof(SelectDevParams));
  144. }
  145. BOOL
  146. PSetupSetSelectDevTitleAndInstructions(
  147. HDEVINFO hDevInfo,
  148. LPCTSTR pszTitle,
  149. LPCTSTR pszSubTitle,
  150. LPCTSTR pszInstn
  151. )
  152. {
  153. SP_SELECTDEVICE_PARAMS SelectDevParams;
  154. if ( pszTitle && lstrlen(pszTitle) + 1 > MAX_TITLE_LEN ) {
  155. SetLastError(ERROR_INVALID_PARAMETER);
  156. return FALSE;
  157. }
  158. if ( pszSubTitle && lstrlen(pszSubTitle) + 1 > MAX_SUBTITLE_LEN ) {
  159. SetLastError(ERROR_INVALID_PARAMETER);
  160. return FALSE;
  161. }
  162. if ( pszInstn && lstrlen(pszInstn) + 1 > MAX_INSTRUCTION_LEN ) {
  163. SetLastError(ERROR_INVALID_PARAMETER);
  164. return FALSE;
  165. }
  166. SelectDevParams.ClassInstallHeader.cbSize
  167. = sizeof(SelectDevParams.ClassInstallHeader);
  168. SelectDevParams.ClassInstallHeader.InstallFunction
  169. = DIF_SELECTDEVICE;
  170. if ( !SetupDiGetClassInstallParams(hDevInfo,
  171. NULL,
  172. &SelectDevParams.ClassInstallHeader,
  173. sizeof(SelectDevParams),
  174. NULL) )
  175. return FALSE;
  176. if ( pszTitle )
  177. lstrcpy(SelectDevParams.Title, pszTitle);
  178. if ( pszSubTitle )
  179. lstrcpy(SelectDevParams.SubTitle, pszSubTitle);
  180. if ( pszInstn )
  181. lstrcpy(SelectDevParams.Instructions, pszInstn);
  182. return SetupDiSetClassInstallParams(
  183. hDevInfo,
  184. NULL,
  185. &SelectDevParams.ClassInstallHeader,
  186. sizeof(SelectDevParams));
  187. }
  188. BOOL
  189. PSetupSelectDeviceButtons(
  190. HDEVINFO hDevInfo,
  191. DWORD dwFlagsSet,
  192. DWORD dwFlagsClear
  193. )
  194. {
  195. PSP_DEVINFO_DATA pDevInfoData = NULL;
  196. SP_DEVINSTALL_PARAMS DevInstallParams;
  197. // Check that no flags are both set & cleared
  198. if (dwFlagsSet & dwFlagsClear)
  199. {
  200. SetLastError(ERROR_INVALID_PARAMETER);
  201. return FALSE;
  202. }
  203. //
  204. // Get current SelectDevice parameters, and then set the fields
  205. // we wanted changed from default
  206. //
  207. DevInstallParams.cbSize = sizeof(DevInstallParams);
  208. if ( !SetupDiGetDeviceInstallParams(hDevInfo,
  209. pDevInfoData,
  210. &DevInstallParams) ) {
  211. return FALSE;
  212. }
  213. //
  214. // Set Flag based on Argument for Web Button
  215. if ( dwFlagsSet & SELECT_DEVICE_FROMWEB )
  216. DevInstallParams.FlagsEx |= DI_FLAGSEX_SHOWWINDOWSUPDATE;
  217. if ( dwFlagsClear & SELECT_DEVICE_FROMWEB )
  218. DevInstallParams.FlagsEx &= ~DI_FLAGSEX_SHOWWINDOWSUPDATE;
  219. if ( dwFlagsSet & SELECT_DEVICE_HAVEDISK )
  220. DevInstallParams.Flags |= DI_SHOWOEM;
  221. if ( dwFlagsClear & SELECT_DEVICE_HAVEDISK )
  222. DevInstallParams.Flags &= ~DI_SHOWOEM;
  223. return SetupDiSetDeviceInstallParams(hDevInfo,
  224. pDevInfoData,
  225. &DevInstallParams);
  226. }
  227. BOOL
  228. SetDevInstallParams(
  229. IN HDEVINFO hDevInfo,
  230. IN PSP_DEVINFO_DATA pDevInfoData,
  231. IN LPCTSTR pszDriverPath OPTIONAL
  232. )
  233. /*++
  234. Routine Description:
  235. Sets the device installation parameters by calling setup apis
  236. Arguments:
  237. hDevInfo : Handle to the printer class device information list
  238. pszDriverPath : Path where INF file should be searched
  239. Return Value:
  240. TRUE on success
  241. FALSE else
  242. --*/
  243. {
  244. SP_DEVINSTALL_PARAMS DevInstallParams;
  245. //
  246. // Get current SelectDevice parameters, and then set the fields
  247. // we wanted changed from default
  248. //
  249. DevInstallParams.cbSize = sizeof(DevInstallParams);
  250. if ( !SetupDiGetDeviceInstallParams(hDevInfo,
  251. pDevInfoData,
  252. &DevInstallParams) ) {
  253. return FALSE;
  254. }
  255. //
  256. // Drivers are class drivers,
  257. // ntprint.inf is sorted do not waste time sorting,
  258. // show Have Disk button,
  259. // use our strings on the select driver page
  260. //
  261. DevInstallParams.Flags |= DI_SHOWCLASS | DI_INF_IS_SORTED
  262. | DI_SHOWOEM
  263. | DI_USECI_SELECTSTRINGS;
  264. if ( pszDriverPath && *pszDriverPath )
  265. lstrcpy(DevInstallParams.DriverPath, pszDriverPath);
  266. return SetupDiSetDeviceInstallParams(hDevInfo,
  267. pDevInfoData,
  268. &DevInstallParams);
  269. }
  270. BOOL
  271. PSetupBuildDriversFromPath(
  272. IN HDEVINFO hDevInfo,
  273. IN LPCTSTR pszDriverPath,
  274. IN BOOL bEnumSingleInf
  275. )
  276. /*++
  277. Routine Description:
  278. Builds the list of printer drivers from infs from a specified path.
  279. Path could specify a directory or a single inf.
  280. Arguments:
  281. hDevInfo : Handle to the printer class device information list
  282. pszDriverPath : Path where INF file should be searched
  283. bEnumSingleInf : If TRUE pszDriverPath is a filename instead of path
  284. Return Value:
  285. TRUE on success
  286. FALSE else
  287. --*/
  288. {
  289. SP_DEVINSTALL_PARAMS DevInstallParams;
  290. //
  291. // Get current SelectDevice parameters, and then set the fields
  292. // we wanted changed from default
  293. //
  294. DevInstallParams.cbSize = sizeof(DevInstallParams);
  295. if ( !SetupDiGetDeviceInstallParams(hDevInfo,
  296. NULL,
  297. &DevInstallParams) ) {
  298. return FALSE;
  299. }
  300. DevInstallParams.Flags |= DI_INF_IS_SORTED;
  301. if ( bEnumSingleInf )
  302. DevInstallParams.Flags |= DI_ENUMSINGLEINF;
  303. lstrcpy(DevInstallParams.DriverPath, pszDriverPath);
  304. SetupDiDestroyDriverInfoList(hDevInfo,
  305. NULL,
  306. SPDIT_CLASSDRIVER);
  307. return SetupDiSetDeviceInstallParams(hDevInfo,
  308. NULL,
  309. &DevInstallParams) &&
  310. SetupDiBuildDriverInfoList(hDevInfo, NULL, SPDIT_CLASSDRIVER);
  311. }
  312. BOOL
  313. DestroyOnlyPrinterDeviceInfoList(
  314. IN HDEVINFO hDevInfo
  315. )
  316. /*++
  317. Routine Description:
  318. This routine should be called at the end to destroy the printer device
  319. info list
  320. Arguments:
  321. hDevInfo : Handle to the printer class device information list
  322. Return Value:
  323. TRUE on success, FALSE on error
  324. --*/
  325. {
  326. return hDevInfo == INVALID_HANDLE_VALUE
  327. ? TRUE : SetupDiDestroyDeviceInfoList(hDevInfo);
  328. }
  329. BOOL
  330. PSetupDestroyPrinterDeviceInfoList(
  331. IN HDEVINFO hDevInfo
  332. )
  333. /*++
  334. Routine Description:
  335. This routine should be called at the end to destroy the printer device
  336. info list
  337. Arguments:
  338. hDevInfo : Handle to the printer class device information list
  339. Return Value:
  340. TRUE on success, FALSE on error
  341. --*/
  342. {
  343. // Cleanup and CDM Context created by windows update.
  344. DestroyCodedownload( gpCodeDownLoadInfo );
  345. gpCodeDownLoadInfo = NULL;
  346. return DestroyOnlyPrinterDeviceInfoList(hDevInfo);
  347. }
  348. HDEVINFO
  349. CreatePrinterDeviceInfoList(
  350. IN HWND hwnd
  351. )
  352. {
  353. return SetupDiCreateDeviceInfoList((LPGUID)&GUID_DEVCLASS_PRINTER, hwnd);
  354. }
  355. HDEVINFO
  356. PSetupCreatePrinterDeviceInfoList(
  357. IN HWND hwnd
  358. )
  359. /*++
  360. Routine Description:
  361. This routine should be called at the beginning to do the initialization
  362. It returns a handle which will be used on any subsequent calls to the
  363. driver setup routines.
  364. Arguments:
  365. None
  366. Return Value:
  367. On success a handle to an empty printer device information set.
  368. If the function fails INVALID_HANDLE_VALUE is returned
  369. --*/
  370. {
  371. HDEVINFO hDevInfo;
  372. hDevInfo = SetupDiCreateDeviceInfoList((LPGUID)&GUID_DEVCLASS_PRINTER, hwnd);
  373. if ( hDevInfo != INVALID_HANDLE_VALUE ) {
  374. if ( !SetSelectDevParams(hDevInfo, NULL, FALSE, NULL) ||
  375. !SetDevInstallParams(hDevInfo, NULL, NULL) ) {
  376. DestroyOnlyPrinterDeviceInfoList(hDevInfo);
  377. hDevInfo = INVALID_HANDLE_VALUE;
  378. }
  379. }
  380. return hDevInfo;
  381. }
  382. HPROPSHEETPAGE
  383. PSetupCreateDrvSetupPage(
  384. IN HDEVINFO hDevInfo,
  385. IN HWND hwnd
  386. )
  387. /*++
  388. Routine Description:
  389. Returns the print driver selection property page
  390. Arguments:
  391. hDevInfo : Handle to the printer class device information list
  392. hwnd : Window handle that owns the UI
  393. Return Value:
  394. Handle to the property page, NULL on failure -- use GetLastError()
  395. --*/
  396. {
  397. SP_INSTALLWIZARD_DATA InstallWizardData;
  398. ZeroMemory(&InstallWizardData, sizeof(InstallWizardData));
  399. InstallWizardData.ClassInstallHeader.cbSize
  400. = sizeof(InstallWizardData.ClassInstallHeader);
  401. InstallWizardData.ClassInstallHeader.InstallFunction
  402. = DIF_INSTALLWIZARD;
  403. InstallWizardData.DynamicPageFlags = DYNAWIZ_FLAG_PAGESADDED;
  404. InstallWizardData.hwndWizardDlg = hwnd;
  405. return SetupDiGetWizardPage(hDevInfo,
  406. NULL,
  407. &InstallWizardData,
  408. SPWPT_SELECTDEVICE,
  409. 0);
  410. }
  411. PPSETUP_LOCAL_DATA
  412. BuildInternalData(
  413. IN HDEVINFO hDevInfo,
  414. IN PSP_DEVINFO_DATA pSpDevInfoData
  415. )
  416. /*++
  417. Routine Description:
  418. Fills out the selected driver info in the SELECTED_DRV_INFO structure
  419. Arguments:
  420. hDevInfo : Handle to the printer class device information list
  421. pSpDevInfoData : Gives the selected device info element.
  422. Return Value:
  423. On success a non-NULL pointer to PSETUP_LOCAL_DATA struct
  424. NULL on error
  425. --*/
  426. {
  427. PSP_DRVINFO_DETAIL_DATA pDrvInfoDetailData;
  428. PSP_DRVINSTALL_PARAMS pDrvInstallParams;
  429. PPSETUP_LOCAL_DATA pLocalData;
  430. PSELECTED_DRV_INFO pDrvInfo;
  431. SP_DRVINFO_DATA DrvInfoData;
  432. DWORD dwNeeded;
  433. BOOL bRet = FALSE;
  434. pLocalData = (PPSETUP_LOCAL_DATA) LocalAllocMem(sizeof(*pLocalData));
  435. pDrvInfoDetailData = (PSP_DRVINFO_DETAIL_DATA)
  436. LocalAllocMem(sizeof(*pDrvInfoDetailData));
  437. pDrvInstallParams = (PSP_DRVINSTALL_PARAMS) LocalAllocMem(sizeof(*pDrvInstallParams));
  438. if ( !pLocalData || !pDrvInstallParams || !pDrvInfoDetailData )
  439. goto Cleanup;
  440. pDrvInfo = &pLocalData->DrvInfo;
  441. pLocalData->DrvInfo.pDevInfoData = pSpDevInfoData;
  442. pLocalData->signature = PSETUP_SIGNATURE;
  443. DrvInfoData.cbSize = sizeof(DrvInfoData);
  444. if ( !SetupDiGetSelectedDriver(hDevInfo, pSpDevInfoData, &DrvInfoData) )
  445. goto Cleanup;
  446. // Need to Check the flag in the DrvInstallParms
  447. pDrvInstallParams->cbSize = sizeof(*pDrvInstallParams);
  448. if ( !SetupDiGetDriverInstallParams(hDevInfo,
  449. pSpDevInfoData,
  450. &DrvInfoData,
  451. pDrvInstallParams) ) {
  452. goto Cleanup;
  453. }
  454. //
  455. // Did the user press the "Web" button
  456. //
  457. if ( pDrvInstallParams->Flags & DNF_INET_DRIVER )
  458. pDrvInfo->Flags |= SDFLAG_CDM_DRIVER;
  459. LocalFreeMem(pDrvInstallParams);
  460. pDrvInstallParams = NULL;
  461. dwNeeded = sizeof(*pDrvInfoDetailData);
  462. pDrvInfoDetailData->cbSize = dwNeeded;
  463. if ( !SetupDiGetDriverInfoDetail(hDevInfo,
  464. pSpDevInfoData,
  465. &DrvInfoData,
  466. pDrvInfoDetailData,
  467. dwNeeded,
  468. &dwNeeded) ) {
  469. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) {
  470. goto Cleanup;
  471. }
  472. LocalFreeMem(pDrvInfoDetailData);
  473. pDrvInfoDetailData = (PSP_DRVINFO_DETAIL_DATA) LocalAllocMem(dwNeeded);
  474. if ( !pDrvInfoDetailData )
  475. goto Cleanup;
  476. pDrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  477. if ( !SetupDiGetDriverInfoDetail(hDevInfo,
  478. pSpDevInfoData,
  479. &DrvInfoData,
  480. pDrvInfoDetailData,
  481. dwNeeded,
  482. NULL) ) {
  483. goto Cleanup;
  484. }
  485. }
  486. pDrvInfo->pszInfName = AllocStr(pDrvInfoDetailData->InfFileName);
  487. pDrvInfo->pszDriverSection = AllocStr(pDrvInfoDetailData->SectionName);
  488. pDrvInfo->pszModelName = AllocStr(DrvInfoData.Description);
  489. pDrvInfo->pszManufacturer = AllocStr(DrvInfoData.MfgName);
  490. pDrvInfo->pszProvider = AllocStr(DrvInfoData.ProviderName);
  491. pDrvInfo->ftDriverDate = DrvInfoData.DriverDate;
  492. pDrvInfo->dwlDriverVersion = DrvInfoData.DriverVersion;
  493. if ( pDrvInfoDetailData->HardwareID && *pDrvInfoDetailData->HardwareID ) {
  494. pDrvInfo->pszHardwareID = AllocStr(pDrvInfoDetailData->HardwareID);
  495. if(!pDrvInfo->pszHardwareID)
  496. goto Cleanup;
  497. }
  498. bRet = pDrvInfo->pszInfName &&
  499. pDrvInfo->pszDriverSection &&
  500. pDrvInfo->pszModelName &&
  501. pDrvInfo->pszProvider &&
  502. pDrvInfo->pszManufacturer;
  503. Cleanup:
  504. LocalFreeMem(pDrvInfoDetailData);
  505. LocalFreeMem(pDrvInstallParams);
  506. if ( bRet ) {
  507. return pLocalData;
  508. } else {
  509. //
  510. // On failure we will leave the old private local data around
  511. //
  512. DestroyLocalData(pLocalData);
  513. return NULL;
  514. }
  515. }
  516. PPSETUP_LOCAL_DATA
  517. PSetupGetSelectedDriverInfo(
  518. IN HDEVINFO hDevInfo
  519. )
  520. {
  521. return BuildInternalData(hDevInfo, NULL);
  522. }
  523. #if 0
  524. DWORD GetDriverNumber (HDEVINFO hDevInfo)
  525. /*++
  526. Routine Description:
  527. This routine returns the number of drivers in a particular INF file
  528. Arguments:
  529. hDevInfo : Handle got by calling PSetupCreateDrvSetupParams
  530. Return Value:
  531. Number of drivers (from 1 if no error happens)
  532. ++*/
  533. {
  534. SP_DRVINFO_DATA DrvInfoData;
  535. DWORD dwLast = 0;
  536. DWORD dwMiddle;
  537. DWORD dwLastFailed = 10;
  538. DrvInfoData.cbSize = sizeof (DrvInfoData);
  539. // Expand the number
  540. while (SetupDiEnumDriverInfo (hDevInfo, NULL,SPDIT_CLASSDRIVER,
  541. dwLastFailed, &DrvInfoData)) {
  542. dwLast = dwLastFailed;
  543. dwLastFailed *= 2;
  544. }
  545. if (GetLastError() == ERROR_NO_MORE_ITEMS) {
  546. // We've got an boundary, the number is between dwLast and dwLastFailed
  547. while (dwLastFailed - dwLast > 1) {
  548. dwMiddle = (dwLastFailed + dwLast) / 2;
  549. if (!SetupDiEnumDriverInfo (hDevInfo, NULL,SPDIT_CLASSDRIVER,
  550. dwMiddle, &DrvInfoData)) {
  551. if (GetLastError() == ERROR_NO_MORE_ITEMS)
  552. dwLastFailed = dwMiddle;
  553. else
  554. // Some other errors. Ignore them by assuming the driver number is 0
  555. return 0;
  556. }
  557. else dwLast = dwMiddle;
  558. }
  559. return dwLast + 1;
  560. }
  561. else
  562. return 0;
  563. }
  564. BOOL
  565. IsSubSet (
  566. IN HDEVINFO hDevInfoA,
  567. IN HDEVINFO hDevInfoB
  568. )
  569. /*++
  570. Routine Description:
  571. This routine checks if the driver list in hDevInfoA is a subset of
  572. the driver list in hDevInfoB
  573. Arguments:
  574. hDevInfoA : The handle of the driver list A
  575. hDevInfoB : The handle of the driver list B
  576. Return Value:
  577. TRUE if A is a subset of B, FALSE else
  578. ++*/
  579. {
  580. SP_DRVINFO_DATA DrvInfoDataA;
  581. SP_DRVINFO_DATA DrvInfoDataB;
  582. DWORD j,k;
  583. DWORD lastUnmatched;
  584. BOOL found;
  585. BOOL bRet = FALSE;
  586. BOOL bSameMfgName;
  587. DrvInfoDataA.cbSize = sizeof (DrvInfoDataA);
  588. DrvInfoDataB.cbSize = sizeof (DrvInfoDataB);
  589. j = 0;
  590. lastUnmatched = 0;
  591. // Get a set of driver data
  592. while (bRet = SetupDiEnumDriverInfo (hDevInfoA, NULL,
  593. SPDIT_CLASSDRIVER, j, &DrvInfoDataA)) {
  594. //Compare the old one with the new driver set to see if it is in the set
  595. k = lastUnmatched;
  596. found = FALSE;
  597. bSameMfgName = FALSE;
  598. while (SetupDiEnumDriverInfo (hDevInfoB, NULL, SPDIT_CLASSDRIVER, k,
  599. &DrvInfoDataB) && !found) {
  600. if (lstrcmpi (DrvInfoDataA.MfgName, DrvInfoDataB.MfgName)) {
  601. if (bSameMfgName) {
  602. // This means, we've scanned all the entries with the
  603. // same manufacture name, but none of them matches
  604. // So the list A contains an entry which the list B
  605. // does not. Stop,
  606. return FALSE;
  607. }
  608. // Different Manufacture name, never visit it again
  609. k++;
  610. lastUnmatched = k;
  611. }
  612. else {
  613. bSameMfgName = TRUE; // Set the flag
  614. // Manufacture matched
  615. if (DrvInfoDataB.DriverType == DrvInfoDataA.DriverType &&
  616. !lstrcmpi (DrvInfoDataB.Description, DrvInfoDataA.Description)) {
  617. found = TRUE;
  618. // A match
  619. if (lastUnmatched == k) { // Continuous match
  620. k++;
  621. lastUnmatched = k;
  622. }
  623. else {
  624. // It is a match, but some models in the new list is not on the
  625. // old list
  626. // Don't update lastUnmatched, because we've to revisit it again.
  627. k++;
  628. }
  629. }
  630. else { // does not match
  631. k++;
  632. }
  633. }
  634. }
  635. // Can not delete the existing driver, quit the loop
  636. if (!found) return FALSE;
  637. // Otherwise, check the next existing driver in the list A
  638. j++;
  639. }
  640. if (GetLastError() == ERROR_NO_MORE_ITEMS)
  641. // All the drivers in the list A have been found in list B
  642. return TRUE;
  643. else
  644. return FALSE;
  645. }
  646. BOOL
  647. CopyOEMInfFileAndGiveUniqueName(
  648. IN HDEVINFO hDevInfo,
  649. IN PSP_DEVINFO_DATA pSpDevInfoData,
  650. IN LPTSTR pszInfFile
  651. )
  652. /*++
  653. Routine Description:
  654. This routine checks if an OEM driver list is a subset of the driver
  655. to be installed and if so
  656. copies the OEM printer inf file to "<systemroot>\Inf\OEM<n>.INF".
  657. Where n is the first unused file number.
  658. Arguments:
  659. hDevInfo : Handle got by calling PSetupCreateDrvSetupParams
  660. pszInfFile : Fully qualified path of OEM inf file
  661. Return Value:
  662. TRUE if no error, FALSE else
  663. ++*/
  664. {
  665. HANDLE hFile = INVALID_HANDLE_VALUE;
  666. TCHAR szNewFileName[MAX_PATH];
  667. TCHAR szSystemDir[MAX_PATH];
  668. DWORD i,j;
  669. BOOL bRet = FALSE;
  670. SP_DRVINFO_DATA DrvInfoData;
  671. DWORD dwNeeded;
  672. PSP_INF_INFORMATION pSpInfInfo = NULL;
  673. LPTSTR pszProviderName = NULL;
  674. LPTSTR pszNewProvider = NULL;
  675. LPTSTR pszInfFullName = NULL;
  676. LPTSTR pszInfName = NULL;
  677. HDEVINFO hOldDevInfo = INVALID_HANDLE_VALUE;
  678. SP_DEVINSTALL_PARAMS DevInstallParams;
  679. DWORD dwNumNewDrivers;
  680. DWORD dwNumOldDrivers;
  681. DWORD dwLen;
  682. WIN32_FIND_DATA FindData;
  683. HANDLE hFindFile = INVALID_HANDLE_VALUE;
  684. HANDLE hInfFile = INVALID_HANDLE_VALUE;
  685. UINT uErrorLine;
  686. DWORD dwInfNeeded = 2048;
  687. // Since to get file list takes long time,
  688. // so we try to use the previous values to
  689. // Allocate the memeory first.
  690. DevInstallParams.cbSize = sizeof(DevInstallParams);
  691. DevInstallParams.DriverPath[0] = 0;
  692. DrvInfoData.cbSize = sizeof (DrvInfoData);
  693. //
  694. // Check DeviceInstallParams to see if OEM driver list is built
  695. //
  696. if ( !SetupDiGetDeviceInstallParams(hDevInfo,
  697. pSpDevInfoData,
  698. &DevInstallParams) )
  699. return FALSE;
  700. // If DriverPath is clear then not an OEM driver
  701. if ( !DevInstallParams.DriverPath[0] ) {
  702. return TRUE;
  703. }
  704. if (!GetSystemDirectory(szSystemDir, SIZECHARS (szSystemDir)))
  705. return FALSE;
  706. dwLen = lstrlen (szSystemDir);
  707. // 2 mean equal. If pszInfFile is in the system directory, don't copy it
  708. if (2 == CompareString(LOCALE_SYSTEM_DEFAULT,
  709. NORM_IGNORECASE,
  710. szSystemDir,
  711. dwLen,
  712. pszInfFile,
  713. dwLen))
  714. return TRUE;
  715. if ( !GetWindowsDirectory(szSystemDir,SIZECHARS(szSystemDir)))
  716. goto Cleanup;
  717. // Check to see if there is any existing .INF files which are subsets of the
  718. // new driver to be installed
  719. if (! PSetupBuildDriversFromPath(hDevInfo, pszInfFile, TRUE)) goto Cleanup;
  720. dwNumNewDrivers = GetDriverNumber (hDevInfo);
  721. // Get a set of driver data
  722. if (!SetupDiEnumDriverInfo (hDevInfo, NULL, SPDIT_CLASSDRIVER, 0, &DrvInfoData))
  723. goto Cleanup;
  724. if (! (pszNewProvider = AllocStr (DrvInfoData.ProviderName))) goto Cleanup;
  725. // Allocate enough memeory for the full path
  726. if (! (pszInfFullName = LocalAllocMem ((lstrlen (szSystemDir) + lstrlen (cszINF)
  727. + MAX_PATH + 1) * sizeof (TCHAR))))
  728. goto Cleanup;
  729. lstrcpy (pszInfFullName, szSystemDir);
  730. lstrcat (pszInfFullName, cszINF);
  731. // pszInfName always points to the begining of the name
  732. pszInfName = pszInfFullName + lstrlen (pszInfFullName);
  733. lstrcpy (pszInfName, cszInfWildCard);
  734. hFindFile = FindFirstFile (pszInfFullName, &FindData);
  735. if (hFindFile != INVALID_HANDLE_VALUE) {
  736. do {
  737. //
  738. // Skip directories
  739. //
  740. if(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  741. continue;
  742. }
  743. // We've got a name
  744. lstrcpy (pszInfName, FindData.cFileName);
  745. hInfFile = SetupOpenInfFile(pszInfFullName,
  746. cszPrinter,
  747. INF_STYLE_WIN4 | INF_STYLE_OLDNT,
  748. &uErrorLine);
  749. if (hInfFile == INVALID_HANDLE_VALUE)
  750. continue;
  751. // We've opened a file which has a printer as the class name
  752. if (! (pSpInfInfo = LocalAllocMem (dwInfNeeded * sizeof (TCHAR)))) goto NextFile;
  753. // use dwNeeded so that dwInfNeeded is modified only when the buffer is insufficient
  754. dwNeeded = dwInfNeeded;
  755. if (!SetupGetInfInformation (hInfFile, INFINFO_INF_SPEC_IS_HINF, pSpInfInfo,
  756. dwInfNeeded, &dwNeeded)) {
  757. if (ERROR_INSUFFICIENT_BUFFER == GetLastError ()) {
  758. LocalFree (pSpInfInfo);
  759. if (! (pSpInfInfo = LocalAllocMem (dwNeeded * sizeof (TCHAR)))) goto NextFile;
  760. dwInfNeeded = dwNeeded;
  761. if (!SetupGetInfInformation (hInfFile, INFINFO_INF_SPEC_IS_HINF,
  762. pSpInfInfo, dwInfNeeded, &dwNeeded))
  763. goto NextFile;
  764. }
  765. else goto NextFile;
  766. }
  767. if (! (pszProviderName = GetInfQueryString(pSpInfInfo, cszProvider)))
  768. goto NextFile;
  769. if (!lstrcmpi (pszNewProvider, pszProviderName)) {
  770. // If both INF files are from the same provider, try to check if it can be deleted
  771. if ((hOldDevInfo = SetupDiCreateDeviceInfoList(
  772. (LPGUID)&GUID_DEVCLASS_PRINTER, NULL)) == INVALID_HANDLE_VALUE)
  773. goto NextFile;
  774. if (! PSetupBuildDriversFromPath(hOldDevInfo, pszInfFullName, TRUE))
  775. goto NextFile;
  776. dwNumOldDrivers = GetDriverNumber (hOldDevInfo);
  777. // It is not possible to be a subset of the new one
  778. if (dwNumOldDrivers >= dwNumNewDrivers) {
  779. if (IsSubSet (hDevInfo, hOldDevInfo)) {
  780. // No need to copy the new one
  781. bRet = TRUE;
  782. goto Cleanup;
  783. }
  784. }
  785. if (dwNumOldDrivers <= dwNumNewDrivers) {
  786. if (IsSubSet (hOldDevInfo, hDevInfo)) {
  787. // All the drivers in the current file have been found in the new
  788. // driver file, delete the old file
  789. DeleteFile (pszInfFullName);
  790. // and its corresponding .PNF file
  791. lstrcpyn (pszInfName + lstrlen (pszInfName) - 3, cszPNF, 4);
  792. DeleteFile (pszInfFullName);
  793. }
  794. }
  795. // Else Close the file and continue on the next one
  796. } // End of provider name comparison
  797. NextFile:
  798. if (hInfFile != INVALID_HANDLE_VALUE) {
  799. SetupCloseInfFile (hInfFile);
  800. hInfFile = INVALID_HANDLE_VALUE;
  801. }
  802. if (hOldDevInfo != INVALID_HANDLE_VALUE) {
  803. SetupDiDestroyDeviceInfoList (hOldDevInfo);
  804. hOldDevInfo = INVALID_HANDLE_VALUE;
  805. }
  806. if (hFile != INVALID_HANDLE_VALUE) {
  807. CloseHandle (hFile);
  808. hFile = INVALID_HANDLE_VALUE;
  809. }
  810. // Clear the pointers so that the clean up won't free them again
  811. LocalFreeMem (pSpInfInfo);
  812. pSpInfInfo = NULL;
  813. } // End of the loop
  814. while (FindNextFile(hFindFile,&FindData));
  815. }
  816. // All the duplicate files are deleted. Let's create a new one
  817. for ( i = 0 ; i < 10000 ; ++i ) {
  818. wsprintf(szNewFileName, cszOEMInfGen, szSystemDir, i);
  819. //
  820. // By using the CREATE_NEW flag we reserve the file name and
  821. // will not end up overwriting another file which gets created
  822. // by another setup (some inf) thread
  823. //
  824. hFile = CreateFile(szNewFileName,
  825. 0,
  826. FILE_SHARE_READ | FILE_SHARE_WRITE,
  827. NULL,
  828. CREATE_NEW,
  829. FILE_ATTRIBUTE_NORMAL,
  830. NULL);
  831. if ( hFile != INVALID_HANDLE_VALUE ) {
  832. CloseHandle(hFile);
  833. hFile = INVALID_HANDLE_VALUE;
  834. bRet = CopyFile(pszInfFile, szNewFileName, FALSE);
  835. goto Cleanup;
  836. }
  837. else if ( GetLastError() != ERROR_FILE_EXISTS )
  838. break;
  839. }
  840. Cleanup:
  841. if (hFindFile != INVALID_HANDLE_VALUE)
  842. FindClose (hFindFile);
  843. if (hInfFile != INVALID_HANDLE_VALUE)
  844. SetupCloseInfFile (hInfFile);
  845. if (hOldDevInfo != INVALID_HANDLE_VALUE)
  846. SetupDiDestroyDeviceInfoList (hOldDevInfo);
  847. if (hFile != INVALID_HANDLE_VALUE)
  848. CloseHandle (hFile);
  849. LocalFreeMem (pszInfFullName);
  850. LocalFreeMem (pszNewProvider);
  851. LocalFreeMem (pszProviderName);
  852. LocalFreeMem (pSpInfInfo);
  853. return bRet;
  854. }
  855. #endif
  856. BOOL
  857. PSetupSelectDriver(
  858. IN HDEVINFO hDevInfo
  859. )
  860. /*++
  861. Routine Description:
  862. Display manufacturer/model information and have the user select a
  863. printer driver. Selected driver is remembered and PSetupGetSelectedDriver
  864. call will give the selected driver.
  865. Arguments:
  866. hDevInfo - Handle to the printer class device information list
  867. Return Value:
  868. TRUE on success, FALSE on error
  869. --*/
  870. {
  871. return BuildClassDriverList(hDevInfo) &&
  872. SetupDiSelectDevice(hDevInfo, NULL);
  873. }
  874. VOID
  875. GetDriverPath(
  876. IN HDEVINFO hDevInfo,
  877. IN PPSETUP_LOCAL_DATA pLocalData,
  878. OUT TCHAR szDriverPath[MAX_PATH]
  879. )
  880. /*++
  881. Routine Description:
  882. Gets the path where driver files should be searched first to copy from
  883. Arguments:
  884. pszDriverPath : Pointer to a buffer of MAX_PATH size. Gives path where
  885. system was installed from
  886. Return Value:
  887. Nothing
  888. --*/
  889. {
  890. BOOL bOemDriver = FALSE;
  891. LPTSTR *List, psz;
  892. DWORD dwCount;
  893. LPTSTR pszTempPath = NULL;
  894. //
  895. // For OEM drivers look at the place where the inf came from, else
  896. // look at the place we installed NT from
  897. //
  898. if ( pLocalData &&
  899. !(IsSystemNTPrintInf(pLocalData->DrvInfo.pszInfName) || (pLocalData->DrvInfo.Flags & SDFLAG_CDM_DRIVER ))) {
  900. lstrcpy(szDriverPath, pLocalData->DrvInfo.pszInfName);
  901. if ( psz = FileNamePart(szDriverPath) ) {
  902. *psz = TEXT('\0');
  903. return;
  904. }
  905. }
  906. pszTempPath = GetSystemInstallPath();
  907. if ( pszTempPath != NULL )
  908. {
  909. lstrcpy(szDriverPath, pszTempPath);
  910. LocalFreeMem(pszTempPath);
  911. }
  912. else
  913. // Default put A:\ since we have to give something to setup
  914. lstrcpy(szDriverPath, TEXT("A:\\"));
  915. }
  916. BOOL
  917. BuildClassDriverList(
  918. IN HDEVINFO hDevInfo
  919. )
  920. /*++
  921. Routine Description:
  922. Build the class driver list.
  923. Note: If driver list is already built this comes back immediately
  924. Arguments:
  925. hDevInfo : Handle to the printer class device information list
  926. Return Value:
  927. TRUE on success, FALSE on error
  928. --*/
  929. {
  930. DWORD dwLastError;
  931. SP_DRVINFO_DATA DrvInfoData;
  932. //
  933. // Build the class driver list and also make sure there is atleast one driver
  934. //
  935. if ( !SetupDiBuildDriverInfoList(hDevInfo, NULL, SPDIT_CLASSDRIVER) )
  936. return FALSE;
  937. DrvInfoData.cbSize = sizeof(DrvInfoData);
  938. if ( !SetupDiEnumDriverInfo(hDevInfo,
  939. NULL,
  940. SPDIT_CLASSDRIVER,
  941. 0,
  942. &DrvInfoData) &&
  943. GetLastError() == ERROR_NO_MORE_ITEMS ) {
  944. SetLastError(SPAPI_E_DI_BAD_PATH);
  945. return FALSE;
  946. }
  947. return TRUE;
  948. }
  949. BOOL
  950. PSetupRefreshDriverList(
  951. IN HDEVINFO hDevInfo
  952. )
  953. /*++
  954. Routine Description:
  955. Destroy current driver list and build new one if currently an OEM driver
  956. list is associated. This way if you go back after choosing HaveDisk you
  957. would still see drivers from inf directory instead of the OEM inf ...
  958. Arguments:
  959. hDevInfo : Handle to the printer class device information list
  960. Return Value:
  961. TRUE on success, FALSE on error
  962. --*/
  963. {
  964. SP_DEVINSTALL_PARAMS DevInstallParams = { 0 };
  965. DevInstallParams.cbSize = sizeof(DevInstallParams);
  966. //
  967. // Check DeviceInstallParams to see if OEM driver list is built
  968. //
  969. if ( SetupDiGetDeviceInstallParams(hDevInfo,
  970. NULL,
  971. &DevInstallParams) &&
  972. !DevInstallParams.DriverPath[0] ) {
  973. return TRUE;
  974. }
  975. //
  976. // Destroy current list and build another one
  977. //
  978. SetupDiDestroyDriverInfoList(hDevInfo,
  979. NULL,
  980. SPDIT_CLASSDRIVER);
  981. DevInstallParams.DriverPath[0] = sZero;
  982. return SetupDiSetDeviceInstallParams(hDevInfo,
  983. NULL,
  984. &DevInstallParams) &&
  985. BuildClassDriverList(hDevInfo);
  986. }
  987. BOOL
  988. IsNTPrintInf(
  989. IN LPCTSTR pszInfName
  990. )
  991. /*
  992. Function: IsNTPrintInf
  993. Purpose: Verifies is the inf file being copied is a system inf - ntprint.inf.
  994. Parameters:
  995. pszInfName - the fully qualified inf name that is being installed.
  996. Notes: This is needed to make the decision of whether to zero or even copy the inf
  997. with SetupCopyOEMInf.
  998. Should we be doing a deeper comparison than this to decide?
  999. */
  1000. {
  1001. BOOL bRet = FALSE;
  1002. PTCHAR pFileName = FileNamePart( pszInfName );
  1003. if( pFileName )
  1004. {
  1005. bRet = ( 0 == lstrcmpi( pFileName, cszNtprintInf ) );
  1006. }
  1007. return bRet;
  1008. }
  1009. BOOL
  1010. IsSystemNTPrintInf(
  1011. IN PCTSTR pszInfName
  1012. )
  1013. /*
  1014. Function: IsSystemNTPrintInf
  1015. Purpose: Verifies if the inf file the one system printer inf : %windir\inf\ntprint.inf.
  1016. Parameters:
  1017. pszInfName - the fully qualified inf name that is being verified.
  1018. Notes: Needed to decide whether to downrank our inbox drivers
  1019. */
  1020. {
  1021. BOOL bRet = FALSE;
  1022. TCHAR szSysInf[MAX_PATH] = {0};
  1023. UINT Len;
  1024. PCTSTR pRelInfPath = _T("inf\\ntprint.inf");
  1025. Len = GetSystemWindowsDirectory(szSysInf, MAX_PATH);
  1026. if (
  1027. (Len != 0) &&
  1028. (Len + _tcslen(pRelInfPath) + 2 < MAX_PATH)
  1029. )
  1030. {
  1031. if (szSysInf[Len-1] != _T('\\'))
  1032. {
  1033. szSysInf[Len++] = _T('\\');
  1034. }
  1035. _tcscat(szSysInf, pRelInfPath);
  1036. if (!_tcsicmp(szSysInf, pszInfName))
  1037. {
  1038. bRet = TRUE;
  1039. }
  1040. }
  1041. return bRet;
  1042. }
  1043. BOOL
  1044. PSetupIsOemDriver(
  1045. IN HDEVINFO hDevInfo,
  1046. IN PPSETUP_LOCAL_DATA pLocalData,
  1047. IN PBOOL pbIsOemDriver
  1048. )
  1049. /*++
  1050. Routine Description:
  1051. Returns indication if the currently selected driver list
  1052. is an OEM driver list.
  1053. Arguments:
  1054. hDevInfo : Handle to the printer class device information list
  1055. pLocalData : Gives the selected driver information
  1056. pbIsOemDriver : Pointer to bool where to return OEM driver indicator.
  1057. Set to TRUE if driver is an OEM driver.
  1058. Set to FALSE if driver is not an OEM driver.
  1059. Return Value:
  1060. TRUE on success, FALSE on error.
  1061. --*/
  1062. {
  1063. TCHAR szSystemDir[MAX_PATH];
  1064. BOOL bRet = FALSE;
  1065. DWORD dwLen;
  1066. //
  1067. // Ideally Setup API should have an export for this. But rather than
  1068. // waiting for them to do this let me write the code and get it done with
  1069. //
  1070. if ( pLocalData &&
  1071. ( pLocalData->DrvInfo.Flags & SDFLAG_CDM_DRIVER ) )
  1072. {
  1073. *pbIsOemDriver = FALSE;
  1074. bRet = TRUE;
  1075. }
  1076. else if ( dwLen = GetSystemWindowsDirectory(szSystemDir, SIZECHARS(szSystemDir)) )
  1077. {
  1078. bRet = TRUE;
  1079. //
  1080. // If Inf is not under %windir% then it is OEM
  1081. //
  1082. *pbIsOemDriver = lstrncmpi(pLocalData->DrvInfo.pszInfName,
  1083. szSystemDir,
  1084. dwLen) != 0;
  1085. }
  1086. return bRet;
  1087. }
  1088. BOOL
  1089. PSetupPreSelectDriver(
  1090. IN HDEVINFO hDevInfo,
  1091. IN LPCTSTR pszManufacturer,
  1092. IN LPCTSTR pszModel
  1093. )
  1094. /*++
  1095. Routine Description:
  1096. Preselect a manufacturer and model for the driver dialog
  1097. If same model is found select it, else if a manufacturer is given and
  1098. a match in manufacturer is found select first driver for the manufacturer.
  1099. Arguments:
  1100. hDevInfo : Handle to the printer class device information list
  1101. pszManufacturer : Manufacterer name to preselect
  1102. pszModel : Model name to preselect
  1103. Return Value:
  1104. TRUE on a model or manufacturer match
  1105. FALSE else
  1106. --*/
  1107. {
  1108. SP_DRVINFO_DATA DrvInfoData;
  1109. DWORD dwIndex, dwManf, dwMod;
  1110. if ( !BuildClassDriverList(hDevInfo) ) {
  1111. return FALSE;
  1112. }
  1113. dwIndex = 0;
  1114. //
  1115. // To do only one check later
  1116. //
  1117. if ( pszManufacturer && !*pszManufacturer )
  1118. pszManufacturer = NULL;
  1119. if ( pszModel && !*pszModel )
  1120. pszModel = NULL;
  1121. //
  1122. // If no model/manf given select first driver
  1123. //
  1124. if ( pszManufacturer || pszModel ) {
  1125. dwManf = dwMod = MAX_DWORD;
  1126. DrvInfoData.cbSize = sizeof(DrvInfoData);
  1127. while ( SetupDiEnumDriverInfo(hDevInfo, NULL, SPDIT_CLASSDRIVER,
  1128. dwIndex, &DrvInfoData) ) {
  1129. if ( pszManufacturer &&
  1130. dwManf == MAX_DWORD &&
  1131. !lstrcmpi(pszManufacturer, DrvInfoData.MfgName) ) {
  1132. dwManf = dwIndex;
  1133. }
  1134. if ( pszModel &&
  1135. !lstrcmpi(pszModel, DrvInfoData.Description) ) {
  1136. dwMod = dwIndex;
  1137. break; // the for loop
  1138. }
  1139. DrvInfoData.cbSize = sizeof(DrvInfoData);
  1140. ++dwIndex;
  1141. }
  1142. if ( dwMod != MAX_DWORD ) {
  1143. dwIndex = dwMod;
  1144. } else if ( dwManf != MAX_DWORD ) {
  1145. dwIndex = dwManf;
  1146. } else {
  1147. SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
  1148. return FALSE;
  1149. }
  1150. }
  1151. DrvInfoData.cbSize = sizeof(DrvInfoData);
  1152. if ( SetupDiEnumDriverInfo(hDevInfo, NULL, SPDIT_CLASSDRIVER,
  1153. dwIndex, &DrvInfoData) &&
  1154. SetupDiSetSelectedDriver(hDevInfo, NULL, &DrvInfoData) ) {
  1155. return TRUE;
  1156. }
  1157. return FALSE;
  1158. }
  1159. PPSETUP_LOCAL_DATA
  1160. PSetupDriverInfoFromName(
  1161. IN HDEVINFO hDevInfo,
  1162. IN LPCTSTR pszModel
  1163. )
  1164. {
  1165. return PSetupPreSelectDriver(hDevInfo, NULL, pszModel) ?
  1166. BuildInternalData(hDevInfo, NULL) :
  1167. NULL;
  1168. }
  1169. LPDRIVER_INFO_6
  1170. Win95DriverInfo6FromName(
  1171. IN HDEVINFO hDevInfo,
  1172. IN PPSETUP_LOCAL_DATA* ppLocalData,
  1173. IN LPCTSTR pszModel,
  1174. IN LPCTSTR pszzPreviousNames
  1175. )
  1176. {
  1177. LPDRIVER_INFO_6 pDriverInfo6=NULL;
  1178. PPSETUP_LOCAL_DATA pLocalData;
  1179. BOOL bFound;
  1180. LPCTSTR pszName;
  1181. bFound = PSetupPreSelectDriver(hDevInfo, NULL, pszModel);
  1182. for ( pszName = pszzPreviousNames ;
  1183. !bFound && pszName && *pszName ;
  1184. pszName += lstrlen(pszName) + 1 ) {
  1185. bFound = PSetupPreSelectDriver(hDevInfo, NULL, pszName);
  1186. }
  1187. if ( !bFound )
  1188. return NULL;
  1189. if ( (pLocalData = BuildInternalData(hDevInfo, NULL)) &&
  1190. ParseInf(hDevInfo, pLocalData, PlatformWin95, NULL, 0) ) {
  1191. pDriverInfo6 = CloneDriverInfo6(&pLocalData->InfInfo.DriverInfo6,
  1192. pLocalData->InfInfo.cbDriverInfo6);
  1193. *ppLocalData = pLocalData;
  1194. }
  1195. if (!pDriverInfo6 && pLocalData)
  1196. {
  1197. DestroyLocalData(pLocalData);
  1198. *ppLocalData = NULL;
  1199. }
  1200. return pDriverInfo6;
  1201. }
  1202. BOOL
  1203. PSetupDestroySelectedDriverInfo(
  1204. IN PPSETUP_LOCAL_DATA pLocalData
  1205. )
  1206. {
  1207. ASSERT(pLocalData && pLocalData->signature == PSETUP_SIGNATURE);
  1208. DestroyLocalData(pLocalData);
  1209. return TRUE;
  1210. }
  1211. BOOL
  1212. PSetupGetDriverInfForPrinter(
  1213. IN HDEVINFO hDevInfo,
  1214. IN LPCTSTR pszPrinterName,
  1215. IN OUT LPTSTR pszInfName,
  1216. IN OUT LPDWORD pcbInfNameSize
  1217. )
  1218. {
  1219. BOOL bRet = FALSE;
  1220. DWORD dwSize, dwIndex;
  1221. HANDLE hPrinter;
  1222. LPTSTR pszInf;
  1223. PPSETUP_LOCAL_DATA pLocalData = NULL;
  1224. LPDRIVER_INFO_6 pDriverInfo6 = NULL;
  1225. SP_DRVINFO_DATA DrvInfoData;
  1226. if ( !OpenPrinter((LPTSTR)pszPrinterName, &hPrinter, NULL) )
  1227. return FALSE;
  1228. if ( !BuildClassDriverList(hDevInfo) )
  1229. goto Cleanup;
  1230. GetPrinterDriver(hPrinter,
  1231. NULL,
  1232. 6,
  1233. NULL,
  1234. 0,
  1235. &dwSize);
  1236. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  1237. goto Cleanup;
  1238. if ( !((LPBYTE)pDriverInfo6 = LocalAllocMem(dwSize)) ||
  1239. !GetPrinterDriver(hPrinter,
  1240. NULL,
  1241. 6,
  1242. (LPBYTE)pDriverInfo6,
  1243. dwSize,
  1244. &dwSize) ) {
  1245. goto Cleanup;
  1246. }
  1247. dwIndex = 0;
  1248. DrvInfoData.cbSize = sizeof(DrvInfoData);
  1249. while ( SetupDiEnumDriverInfo(hDevInfo, NULL, SPDIT_CLASSDRIVER,
  1250. dwIndex, &DrvInfoData) ) {
  1251. //
  1252. // Is the driver name same?
  1253. //
  1254. if ( !lstrcmpi(pDriverInfo6->pName, DrvInfoData.Description) ) {
  1255. if ( !SetupDiSetSelectedDriver(hDevInfo, NULL, &DrvInfoData) ||
  1256. !(pLocalData = BuildInternalData(hDevInfo, NULL)) ||
  1257. !ParseInf(hDevInfo, pLocalData, MyPlatform, NULL, 0) ) {
  1258. if ( pLocalData ) {
  1259. DestroyLocalData(pLocalData);
  1260. pLocalData = NULL;
  1261. }
  1262. break;
  1263. }
  1264. //
  1265. // Are the DRIVER_INFO_6's identical?
  1266. //
  1267. if ( IdenticalDriverInfo6(&pLocalData->InfInfo.DriverInfo6,
  1268. pDriverInfo6) )
  1269. break;
  1270. DestroyLocalData(pLocalData);
  1271. pLocalData = NULL;
  1272. }
  1273. DrvInfoData.cbSize = sizeof(DrvInfoData);
  1274. ++dwIndex;
  1275. }
  1276. if ( pLocalData == NULL ) {
  1277. SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
  1278. goto Cleanup;
  1279. }
  1280. pszInf= pLocalData->DrvInfo.pszInfName;
  1281. dwSize = *pcbInfNameSize;
  1282. *pcbInfNameSize = (lstrlen(pszInf) + 1) * sizeof(TCHAR);
  1283. if ( dwSize < *pcbInfNameSize ) {
  1284. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1285. goto Cleanup;
  1286. }
  1287. lstrcpy(pszInfName, pszInf);
  1288. bRet = TRUE;
  1289. Cleanup:
  1290. ClosePrinter(hPrinter);
  1291. LocalFreeMem(pDriverInfo6);
  1292. DestroyLocalData(pLocalData);
  1293. return bRet;
  1294. }