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.

6549 lines
248 KiB

  1. /*++
  2. Copyright (c) 1995-2001 Microsoft Corporation
  3. Module Name:
  4. syspnp.c
  5. Abstract:
  6. Device installation routines.
  7. Author:
  8. Jaime Sasson (jaimes) 6-Mar-1997
  9. Revision History:
  10. --*/
  11. #include "setupp.h"
  12. #pragma hdrstop
  13. //
  14. // Provide extern references to device (setup) class GUIDs instantiated in
  15. // clasinst.c.
  16. //
  17. #include <devguid.h>
  18. //
  19. // Define and initialize a global variable, GUID_NULL
  20. // (from coguid.h)
  21. //
  22. #include <initguid.h>
  23. //
  24. // UpdateDriverForPlugAndPlayDevices constants
  25. //
  26. #include <newdev.h>
  27. #include <strsafe.h>
  28. DEFINE_GUID(GUID_NULL, 0L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  29. #define PNP_NEW_HW_PIPE TEXT("\\\\.\\pipe\\PNP_New_HW_Found")
  30. #define PNP_CREATE_PIPE_EVENT TEXT("PNP_Create_Pipe_Event")
  31. #define PNP_BATCH_PROCESSED_EVENT TEXT("PNP_Batch_Processed_Event")
  32. #define PNP_PIPE_TIMEOUT 180000
  33. #ifdef PRERELEASE
  34. //
  35. // legacy-phase1 can take a long time in certain cases
  36. //
  37. #define PNP_LEGACY_PHASE1_TIMEOUT 2*60*1000
  38. #define PNP_LEGACY_PHASE2_TIMEOUT 1*60*1000
  39. #define PNP_LEGACY_PHASE3_TIMEOUT 1*60*1000
  40. #define PNP_ENUM_TIMEOUT 1*60*1000
  41. #define RUNONCE_TIMEOUT 1*60*1000
  42. #define RUNONCE_THRESHOLD 20 // * RUNONCE_TIMEOUT
  43. #else // PRERELEASE
  44. //
  45. // legacy-phase1 can take a long time in certain cases
  46. //
  47. #define PNP_LEGACY_PHASE1_TIMEOUT 4*60*1000
  48. #define PNP_LEGACY_PHASE2_TIMEOUT 2*60*1000
  49. #define PNP_LEGACY_PHASE3_TIMEOUT 2*60*1000
  50. #define PNP_ENUM_TIMEOUT 2*60*1000
  51. #define RUNONCE_TIMEOUT 2*60*1000
  52. #define RUNONCE_THRESHOLD 20 // * RUNONCE_TIMEOUT
  53. #endif // PRERELEASE
  54. //
  55. // Declare a private INF key string recogized only by syssetup during device
  56. // installation...
  57. //
  58. PWSTR szSyssetupPnPFlags = L"SyssetupPnPFlags";
  59. //
  60. // ...and define the flags that are valid for this value
  61. //
  62. #define PNPFLAG_DONOTCALLCONFIGMG 0x00000001
  63. //
  64. // REVIEW 2000/11/08 seanch - Old behavior that we don't want to regress.
  65. // Remove the #define below, after the network guys (jameelh) fix
  66. // the network class installer. This should happen before beta2
  67. //
  68. #define BB_PNP_NETWORK_TIMEOUT 10*60*1000
  69. #define BB_NETWORK_GUID_STRING L"{4D36E972-E325-11CE-BFC1-08002BE10318}"
  70. BOOL PrivilegeAlreadySet = FALSE;
  71. //
  72. // pnplog.txt is the file that lists the class installers
  73. // that hang during GUI setup, so that when GUI setup is restarted,
  74. // the offendig class installers will not be invoked again.
  75. // This file is created during GUI setup on %SystemRoot%, and is always
  76. // deleted during textmode setup (the file is listed on txtsetup.sif as
  77. // "delete on upgrade").
  78. // This file will never exist when the system first boots into GUI setup,
  79. // immediately after the completion of textmode setup. This is
  80. // to ensure that an old version of pnplog.txt will not affect the
  81. // upgrade case, or a clean install of a system that is installed on
  82. // a directory that already contains an NT system.
  83. //
  84. PWSTR szPnpLogFile = L"pnplog.txt";
  85. PWSTR szEnumDevSection = L"EnumeratedDevices";
  86. PWSTR szLegacyClassesSection = L"LegacyClasses";
  87. PWSTR szLegacyDevSection = L"LegacyDevices";
  88. //
  89. // multi-sz list of files that is passed to SfcInitProt that the initial scan
  90. // will not replace. This is used for non-signed drivers that are specified
  91. // by F6 during textmode setup.
  92. //
  93. MULTISZ EnumPtrSfcIgnoreFiles = {NULL, NULL, 0};
  94. //
  95. // Structure for thread parameter
  96. //
  97. typedef struct _PNP_THREAD_PARAMS {
  98. HWND Window;
  99. HWND ProgressWindow;
  100. DWORD ThreadId;
  101. HINF InfHandle;
  102. UINT ProgressWindowStartAtPercent;
  103. UINT ProgressWindowStopAtPercent;
  104. BOOL SendWmQuit;
  105. } PNP_THREAD_PARAMS, *PPNP_THREAD_PARAMS;
  106. typedef struct _INF_FILE_NAME {
  107. struct _INF_FILE_NAME *Next;
  108. PWSTR InfName;
  109. } *PINF_FILE_NAME, INF_FILE_NAME;
  110. typedef struct _PNP_ENUM_DEV_THREAD_PARAMS {
  111. HDEVINFO hDevInfo;
  112. SP_DEVINFO_DATA DeviceInfoData;
  113. PWSTR pDeviceDescription;
  114. PWSTR pDeviceId;
  115. PVOID DevicesInstalledStringTable;
  116. } PNP_ENUM_DEV_THREAD_PARAMS, *PPNP_ENUM_DEV_THREAD_PARAMS;
  117. typedef struct _PNP_PHASE1_LEGACY_DEV_THREAD_PARAMS {
  118. HDEVINFO hDevInfo;
  119. GUID Guid;
  120. PWSTR pClassDescription;
  121. HWND hwndParent;
  122. } PNP_PHASE1_LEGACY_DEV_THREAD_PARAMS, *PPNP_PHASE1_LEGACY_DEV_THREAD_PARAMS;
  123. typedef struct _PNP_PHASE2_LEGACY_DEV_THREAD_PARAMS {
  124. HDEVINFO hDevInfo;
  125. HSPFILEQ FileQ;
  126. SP_DEVINFO_DATA DeviceInfoData;
  127. PWSTR pClassDescription;
  128. PWSTR pDeviceId;
  129. } PNP_PHASE2_LEGACY_DEV_THREAD_PARAMS, *PPNP_PHASE2_LEGACY_DEV_THREAD_PARAMS;
  130. typedef struct _PNP_PHASE3_LEGACY_DEV_THREAD_PARAMS {
  131. HDEVINFO hDevInfo;
  132. SP_DEVINFO_DATA DeviceInfoData;
  133. PWSTR pDeviceId;
  134. PVOID DevicesInstalledStringTable;
  135. } PNP_PHASE3_LEGACY_DEV_THREAD_PARAMS, *PPNP_PHASE3_LEGACY_DEV_THREAD_PARAMS;
  136. //
  137. // private cfgmgr32 API that we use
  138. //
  139. DWORD
  140. CMP_WaitNoPendingInstallEvents(
  141. IN DWORD dwTimeout
  142. );
  143. //
  144. // for run-time loading of newdev.dll
  145. //
  146. typedef BOOL (WINAPI *ExternalUpdateDriverForPlugAndPlayDevicesW)(
  147. HWND hwndParent,
  148. LPCWSTR HardwareId,
  149. LPCWSTR FullInfPath,
  150. DWORD InstallFlags,
  151. PBOOL bRebootRequired OPTIONAL
  152. );
  153. //
  154. // Private routine prototypes
  155. //
  156. VOID
  157. SortClassGuidListForDetection(
  158. IN OUT LPGUID GuidList,
  159. IN ULONG GuidCount,
  160. OUT PULONG LastBatchedDetect
  161. );
  162. DWORD
  163. pPhase1InstallPnpLegacyDevicesThread(
  164. PPNP_PHASE1_LEGACY_DEV_THREAD_PARAMS ThreadParams
  165. );
  166. DWORD
  167. pPhase2InstallPnpLegacyDevicesThread(
  168. PPNP_PHASE2_LEGACY_DEV_THREAD_PARAMS ThreadParams
  169. );
  170. DWORD
  171. pPhase3InstallPnpLegacyDevicesThread(
  172. PPNP_PHASE3_LEGACY_DEV_THREAD_PARAMS ThreadParams
  173. );
  174. DWORD
  175. pInstallPnpEnumeratedDeviceThread(
  176. PPNP_ENUM_DEV_THREAD_PARAMS ThreadParams
  177. );
  178. BOOL
  179. GetDeviceConfigFlags(
  180. HDEVINFO hDevInfo,
  181. PSP_DEVINFO_DATA pDeviceInfoData,
  182. DWORD* pdwConfigFlags
  183. );
  184. BOOL
  185. SetDeviceConfigFlags(
  186. HDEVINFO hDevInfo,
  187. PSP_DEVINFO_DATA pDeviceInfoData,
  188. DWORD dwConfigFlags
  189. );
  190. BOOL
  191. InstallOEMInfs(
  192. VOID
  193. );
  194. VOID
  195. SfcExcludeMigratedDrivers (
  196. VOID
  197. );
  198. BOOL
  199. CallRunOnceAndWait();
  200. BOOL
  201. MarkPnpDevicesAsNeedReinstall(
  202. PVOID DevicesInstalledStringTable OPTIONAL
  203. );
  204. ULONG
  205. SyssetupGetPnPFlags(
  206. IN HDEVINFO hDevInfo,
  207. IN PSP_DEVINFO_DATA pDeviceInfoData,
  208. IN PSP_DRVINFO_DATA pDriverInfoData
  209. );
  210. BOOL
  211. IsInstalledInfFromOem(
  212. IN PCWSTR InfFileName
  213. );
  214. BOOL
  215. IsInfInLayoutInf(
  216. IN PCWSTR InfFileName
  217. );
  218. UINT
  219. pOemF6ScanQueueCallback(
  220. PVOID Context,
  221. UINT Notification,
  222. UINT_PTR Param1,
  223. UINT_PTR Param2
  224. )
  225. {
  226. PFILEPATHS FilePaths = (PFILEPATHS)Param1;
  227. //
  228. // Add the Target filename to the list of files that Sfc should ignore when
  229. // doing it's final scan at the end of GUI setup.
  230. //
  231. if (Notification == SPFILENOTIFY_QUEUESCAN_EX) {
  232. if (FilePaths->Target) {
  233. MultiSzAppendString(&EnumPtrSfcIgnoreFiles, FilePaths->Target);
  234. }
  235. }
  236. return NO_ERROR;
  237. }
  238. void
  239. AddOemF6DriversToSfcIgnoreFilesList(
  240. IN HDEVINFO hDevInfo,
  241. IN PSP_DEVINFO_DATA pDeviceInfoData
  242. )
  243. /*++
  244. Routine Description:
  245. Arguments:
  246. hDevInfo -
  247. pDeviceInfoData -
  248. Return Value:
  249. --*/
  250. {
  251. HSPFILEQ FileQueue = INVALID_HANDLE_VALUE;
  252. SP_DRVINFO_DATA DriverInfoData;
  253. SP_DRVINSTALL_PARAMS DriverInstallParams;
  254. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  255. DWORD ScanResult;
  256. //
  257. // First check that the selected driver that we just installed is an OEM F6
  258. // driver.
  259. //
  260. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  261. DriverInstallParams.cbSize = sizeof(SP_DRVINSTALL_PARAMS);
  262. if (SetupDiGetSelectedDriver(hDevInfo,
  263. pDeviceInfoData,
  264. &DriverInfoData) &&
  265. SetupDiGetDriverInstallParams(hDevInfo,
  266. pDeviceInfoData,
  267. &DriverInfoData,
  268. &DriverInstallParams) &&
  269. (DriverInstallParams.Flags & DNF_OEM_F6_INF)) {
  270. //
  271. // This is an OEM F6 driver.
  272. //
  273. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  274. if (!SetupDiGetDeviceInstallParams(hDevInfo,
  275. pDeviceInfoData,
  276. &DeviceInstallParams)) {
  277. goto clean0;
  278. }
  279. FileQueue = SetupOpenFileQueue();
  280. if (FileQueue == INVALID_HANDLE_VALUE) {
  281. goto clean0;
  282. }
  283. DeviceInstallParams.FileQueue = FileQueue;
  284. DeviceInstallParams.Flags |= DI_NOVCP;
  285. //
  286. // Set the device install params to use our file queue and call
  287. // DIF_INSTALLDEVICEFILES to build up a list of files for this device.
  288. //
  289. if (SetupDiSetDeviceInstallParams(hDevInfo,
  290. pDeviceInfoData,
  291. &DeviceInstallParams) &&
  292. SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES,
  293. hDevInfo,
  294. pDeviceInfoData)) {
  295. SetupScanFileQueue(FileQueue,
  296. SPQ_SCAN_USE_CALLBACKEX,
  297. NULL,
  298. pOemF6ScanQueueCallback,
  299. NULL,
  300. &ScanResult);
  301. }
  302. }
  303. clean0:
  304. if (FileQueue != INVALID_HANDLE_VALUE) {
  305. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  306. if (SetupDiGetDeviceInstallParams(hDevInfo,
  307. pDeviceInfoData,
  308. &DeviceInstallParams)) {
  309. DeviceInstallParams.Flags &= ~DI_NOVCP;
  310. DeviceInstallParams.FileQueue = INVALID_HANDLE_VALUE;
  311. SetupDiSetDeviceInstallParams(hDevInfo,
  312. pDeviceInfoData,
  313. &DeviceInstallParams);
  314. }
  315. SetupCloseFileQueue(FileQueue);
  316. }
  317. }
  318. BOOL
  319. GetClassGuidForInf(
  320. IN PCTSTR InfFileName,
  321. OUT LPGUID ClassGuid
  322. )
  323. {
  324. TCHAR ClassName[MAX_CLASS_NAME_LEN];
  325. DWORD NumGuids;
  326. if(!SetupDiGetINFClass(InfFileName,
  327. ClassGuid,
  328. ClassName,
  329. SIZECHARS(ClassName),
  330. NULL)) {
  331. return FALSE;
  332. }
  333. if(pSetupIsGuidNull(ClassGuid)) {
  334. //
  335. // Then we need to retrieve the GUID associated with the INF's class name.
  336. // (If this class name isn't installed (i.e., has no corresponding GUID),
  337. // or if it matches with multiple GUIDs, then we abort.
  338. //
  339. if(!SetupDiClassGuidsFromName(ClassName, ClassGuid, 1, &NumGuids) || !NumGuids) {
  340. return FALSE;
  341. }
  342. }
  343. return TRUE;
  344. }
  345. BOOL
  346. InstallPnpClassInstallers(
  347. IN HWND hwndParent,
  348. IN HINF InfHandle,
  349. IN HSPFILEQ FileQ
  350. )
  351. {
  352. INFCONTEXT InfContext;
  353. UINT LineCount,LineNo;
  354. PCWSTR SectionName = L"DeviceInfsToInstall";
  355. PCWSTR IfExistsSectionName = L"DeviceInfsToInstallIfExists";
  356. PCWSTR InfFileName;
  357. GUID InfClassGuid;
  358. HKEY hClassKey;
  359. BOOL b = TRUE;
  360. SC_HANDLE SCMHandle, ServiceHandle;
  361. SERVICE_STATUS ServiceStatus;
  362. //
  363. // Before we do anything else, we have to make sure that the Plug&Play service is up and
  364. // running, otherwise our ConfigMgr calls will fail, and we won't be able to migrate devices.
  365. //
  366. if(SCMHandle = OpenSCManager(NULL, NULL, GENERIC_READ)) {
  367. if(ServiceHandle = OpenService(SCMHandle, L"PlugPlay", SERVICE_QUERY_STATUS)) {
  368. for(;;) {
  369. if(!QueryServiceStatus(ServiceHandle, &ServiceStatus)) {
  370. //
  371. // Couldn't find out the status of the Plug&Play service--hope for the best
  372. // and trudge on ahead.
  373. //
  374. SetupDebugPrint1( L"SETUP: QueryServiceStatus() failed. Error = %d", GetLastError() );
  375. SetupDebugPrint( L"SETUP: Couldn't find out the status of the Plug&Play service" );
  376. break;
  377. }
  378. if(ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
  379. //
  380. // The service is up and running, we can do our business.
  381. //
  382. break;
  383. }
  384. //
  385. // The service hasn't started yet--print a message, then wait a second
  386. // and try again.
  387. //
  388. SetupDebugPrint( L"SETUP: PlugPlay service isn't running yet--sleeping 1 second..." );
  389. Sleep(1000);
  390. }
  391. CloseServiceHandle(ServiceHandle);
  392. }
  393. CloseServiceHandle(SCMHandle);
  394. }
  395. //
  396. // Get the number of lines in the section that contains the infs whose
  397. // classes are to be installed.
  398. // The section may be empty or non-existant; this is not an error condition.
  399. //
  400. LineCount = (UINT)SetupGetLineCount(InfHandle,SectionName);
  401. if((LONG)LineCount > 0) {
  402. for(LineNo=0; LineNo<LineCount; LineNo++) {
  403. if(SetupGetLineByIndex(InfHandle,SectionName,LineNo,&InfContext)
  404. && (InfFileName = pSetupGetField(&InfContext,1))) {
  405. if( !SetupDiInstallClass( hwndParent,
  406. InfFileName,
  407. DI_NOVCP | DI_FORCECOPY,
  408. FileQ ) ) {
  409. SetupDebugPrint2( L"SETUP: SetupDiInstallClass() failed. Filename = %ls Error = %lx.", InfFileName, GetLastError() );
  410. b = FALSE;
  411. }
  412. }
  413. }
  414. }
  415. //
  416. // Get the number of lines in the section that contains the infs whose
  417. // classes are to be installed if they already exist.
  418. // The section may be empty or non-existant; this is not an error condition.
  419. //
  420. LineCount = (UINT)SetupGetLineCount(InfHandle,IfExistsSectionName);
  421. if((LONG)LineCount > 0) {
  422. for(LineNo=0; LineNo<LineCount; LineNo++) {
  423. if(SetupGetLineByIndex(InfHandle,IfExistsSectionName,LineNo,&InfContext)
  424. && (InfFileName = pSetupGetField(&InfContext,1))) {
  425. //
  426. // Check to see if this section already exists in the registry
  427. //
  428. if (GetClassGuidForInf(InfFileName, &InfClassGuid)) {
  429. if (CM_Open_Class_Key(&InfClassGuid,
  430. NULL,
  431. KEY_READ,
  432. RegDisposition_OpenExisting,
  433. &hClassKey,
  434. CM_OPEN_CLASS_KEY_INSTALLER
  435. ) == CR_SUCCESS) {
  436. RegCloseKey(hClassKey);
  437. //
  438. // This class already exists so we need to reinstall it
  439. //
  440. if( !SetupDiInstallClass( hwndParent,
  441. InfFileName,
  442. DI_NOVCP | DI_FORCECOPY,
  443. FileQ ) ) {
  444. SetupDebugPrint2( L"SETUP: SetupDiInstallClass() failed. Filename = %ls Error = %lx.", InfFileName, GetLastError() );
  445. b = FALSE;
  446. }
  447. }
  448. }
  449. }
  450. }
  451. }
  452. return( b );
  453. }
  454. BOOL
  455. FlushFilesToDisk(
  456. IN PWSTR RootPath
  457. )
  458. /*++
  459. Routine Description:
  460. This function flushes the cache of a particular drive, to disk.
  461. Arguments:
  462. Path to the root directory of the drive whose cache is to be flushed.
  463. Return Value:
  464. Returns TRUE if the operation succeeds, or FALSE otherwise.
  465. --*/
  466. {
  467. HANDLE RootHandle;
  468. LONG Error;
  469. //
  470. // Enable backup privilege.
  471. //
  472. if( !PrivilegeAlreadySet ) {
  473. PrivilegeAlreadySet = pSetupEnablePrivilege(SE_BACKUP_NAME,TRUE) && pSetupEnablePrivilege(SE_RESTORE_NAME,TRUE);
  474. }
  475. RootHandle = CreateFile( RootPath,
  476. GENERIC_READ | GENERIC_WRITE,
  477. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  478. NULL,
  479. OPEN_EXISTING,
  480. FILE_FLAG_BACKUP_SEMANTICS,
  481. 0
  482. );
  483. if( RootHandle == INVALID_HANDLE_VALUE ) {
  484. SetupDebugPrint2( L"SETUP: Failed to open %ls. Error = %d", RootPath, GetLastError() );
  485. return( FALSE );
  486. }
  487. //
  488. // Flush the cache
  489. //
  490. Error = ( FlushFileBuffers( RootHandle ) )? ERROR_SUCCESS : GetLastError();
  491. CloseHandle( RootHandle );
  492. if( Error != ERROR_SUCCESS ) {
  493. SetupDebugPrint2( L"SETUP: FlushFileBuffers() failed. Root = %ls, Error = %d", RootPath, Error );
  494. }
  495. return( Error == ERROR_SUCCESS );
  496. }
  497. BOOL
  498. SyssetupInstallNullDriver(
  499. IN HDEVINFO hDevInfo,
  500. IN PSP_DEVINFO_DATA pDeviceInfoData,
  501. IN PVOID DevicesInstalledStringTable OPTIONAL
  502. )
  503. /*++
  504. Routine Description:
  505. This function installs a the null driver for a particular device.
  506. Arguments:
  507. hDevInfo -
  508. pDeviceInfoData -
  509. Return Value:
  510. Returns TRUE if the null driver was successfully installed.
  511. --*/
  512. {
  513. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  514. DWORD Error;
  515. PWSTR GUIDUnknownString = L"{4D36E97E-E325-11CE-BFC1-08002BE10318}";
  516. WCHAR DevInstId[MAX_DEVICE_ID_LEN];
  517. Error = ERROR_SUCCESS;
  518. //
  519. // Find out if the GUID of this device is GUID_NULL.
  520. // If it is then set it to GUID_DEVCLASS_UNKNOWN, so that after the sysstem
  521. // is installed, Device Manager can include this device in the device tree.
  522. //
  523. if(IsEqualGUID(&(pDeviceInfoData->ClassGuid), &GUID_NULL)) {
  524. SetupDebugPrint( L"SETUP: Setting GUID_DEVCLASS_UNKNOWN for this device" );
  525. if( !SetupDiSetDeviceRegistryProperty( hDevInfo,
  526. pDeviceInfoData,
  527. SPDRP_CLASSGUID,
  528. (PBYTE)GUIDUnknownString,
  529. (wcslen(GUIDUnknownString) + 1)*sizeof(WCHAR) ) ) {
  530. Error = GetLastError();
  531. if( ((LONG)Error) < 0 ) {
  532. //
  533. // Setupapi error code, display it in hex
  534. //
  535. SetupDebugPrint1( L"SETUP: SetupDiSetDeviceRegistryProperty(SPDRP_CLASSGUID) failed. Error = %lx", Error );
  536. } else {
  537. //
  538. // win32 error code, display it in decimal
  539. //
  540. SetupDebugPrint1( L"SETUP: SetupDiSetDeviceRegistryProperty(SPDRP_CLASSGUID) failed. Error = %d", Error );
  541. }
  542. //
  543. // In case of error we just ignore the error
  544. //
  545. Error = ERROR_SUCCESS;
  546. }
  547. } else {
  548. WCHAR GUIDString[ 64 ];
  549. pSetupStringFromGuid( &(pDeviceInfoData->ClassGuid), GUIDString, sizeof( GUIDString ) / sizeof( WCHAR ) );
  550. SetupDebugPrint1( L"SETUP: GUID = %ls", GUIDString );
  551. }
  552. if( !SetupDiSetSelectedDriver( hDevInfo,
  553. pDeviceInfoData,
  554. NULL ) ) {
  555. Error = GetLastError();
  556. if( ((LONG)Error) < 0 ) {
  557. //
  558. // Setupapi error code, display it in hex
  559. //
  560. SetupDebugPrint1( L"SETUP: SetupDiSetSelectedDriver() failed. Error = %lx", Error );
  561. } else {
  562. //
  563. // win32 error code, display it in decimal
  564. //
  565. SetupDebugPrint1( L"SETUP: SetupDiSetSelectedDriver() failed. Error = %d", Error );
  566. }
  567. return( FALSE );
  568. }
  569. //
  570. // Let the class installer/co-installers know they should be quiet.
  571. //
  572. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  573. if( !SetupDiGetDeviceInstallParams( hDevInfo,
  574. pDeviceInfoData,
  575. &DeviceInstallParams ) ) {
  576. Error = GetLastError();
  577. if( ((LONG)Error) < 0 ) {
  578. //
  579. // Setupapi error code, display it in hex
  580. //
  581. SetupDebugPrint1( L"SETUP: SetupDiGetDeviceInstallParams() failed. Error = %lx", Error );
  582. } else {
  583. //
  584. // win32 error code, display it in decimal
  585. //
  586. SetupDebugPrint1( L"SETUP: SetupDiGetDeviceInstallParams() failed. Error = %d", Error );
  587. }
  588. } else {
  589. DeviceInstallParams.Flags |= DI_QUIETINSTALL;
  590. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_RESTART_DEVICE_ONLY;
  591. if( !SetupDiSetDeviceInstallParams( hDevInfo,
  592. pDeviceInfoData,
  593. &DeviceInstallParams ) ) {
  594. Error = GetLastError();
  595. if( ((LONG)Error) < 0 ) {
  596. //
  597. // Setupapi error code, display it in hex
  598. //
  599. SetupDebugPrint1( L"SETUP: SetupDiSetDeviceInstallParams() failed. Error = %lx", Error );
  600. } else {
  601. //
  602. // win32 error code, display it in decimal
  603. //
  604. SetupDebugPrint1( L"SETUP: SetupDiSetDeviceInstallParams() failed. Error = %d", Error );
  605. }
  606. }
  607. }
  608. //
  609. // First, attempt to install the null driver without setting DI_FLAGSEX_SETFAILEDINSTALL.
  610. // Installation of LEGACY_* devices should succeed in this case.
  611. //
  612. // We do this through the class installer, in case it needs to clean-up
  613. // turds from a previous installation (see RAID #266793).
  614. //
  615. if(SetupDiCallClassInstaller(DIF_INSTALLDEVICE,
  616. hDevInfo,
  617. pDeviceInfoData)) {
  618. //
  619. // If we were passed in a devices installed string table then add this
  620. // device instance id to the string table.
  621. //
  622. if (DevicesInstalledStringTable) {
  623. if( SetupDiGetDeviceInstanceId( hDevInfo,
  624. pDeviceInfoData,
  625. DevInstId,
  626. sizeof( DevInstId ) / sizeof( WCHAR ),
  627. NULL ) ) {
  628. if (pSetupStringTableAddString(DevicesInstalledStringTable, DevInstId, STRTAB_CASE_INSENSITIVE) == -1) {
  629. SetupDebugPrint1( L"SETUP: ERROR: failed to add Device = %ls to the string table!", DevInstId );
  630. }
  631. }
  632. }
  633. //
  634. // Istallation succeeded.
  635. //
  636. return( TRUE );
  637. }
  638. Error = GetLastError();
  639. if( ((LONG)Error) < 0 ) {
  640. //
  641. // Setupapi error code, display it in hex
  642. //
  643. SetupDebugPrint1( L"SETUP: SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed on first attempt. Error = %lx", Error );
  644. } else {
  645. //
  646. // win32 error code, display it in decimal
  647. //
  648. SetupDebugPrint1( L"SETUP: SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed on first attempt. Error = %d", Error );
  649. }
  650. SetupDebugPrint( L"SETUP: Trying a second time with DI_FLAGSEX_SETFAILEDINSTALL set." );
  651. //
  652. // The first attempt to install the null driver (without setting DI_FLAGSEX_SETFAILEDINSTALL)
  653. // failed.
  654. // So we set the flag and try it again.
  655. //
  656. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  657. if( !SetupDiGetDeviceInstallParams( hDevInfo,
  658. pDeviceInfoData,
  659. &DeviceInstallParams ) ) {
  660. Error = GetLastError();
  661. if( ((LONG)Error) < 0 ) {
  662. //
  663. // Setupapi error code, display it in hex
  664. //
  665. SetupDebugPrint1( L"SETUP: SetupDiGetDeviceInstallParams() failed. Error = %lx", Error );
  666. } else {
  667. //
  668. // win32 error code, display it in decimal
  669. //
  670. SetupDebugPrint1( L"SETUP: SetupDiGetDeviceInstallParams() failed. Error = %d", Error );
  671. }
  672. return( FALSE );
  673. }
  674. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_SETFAILEDINSTALL;
  675. if( !SetupDiSetDeviceInstallParams( hDevInfo,
  676. pDeviceInfoData,
  677. &DeviceInstallParams ) ) {
  678. Error = GetLastError();
  679. if( ((LONG)Error) < 0 ) {
  680. //
  681. // Setupapi error code, display it in hex
  682. //
  683. SetupDebugPrint1( L"SETUP: SetupDiSetDeviceInstallParams() failed. Error = %lx", Error );
  684. } else {
  685. //
  686. // win32 error code, display it in decimal
  687. //
  688. SetupDebugPrint1( L"SETUP: SetupDiSetDeviceInstallParams() failed. Error = %d", Error );
  689. }
  690. return( FALSE );
  691. }
  692. if(!SetupDiCallClassInstaller(DIF_INSTALLDEVICE,
  693. hDevInfo,
  694. pDeviceInfoData)) {
  695. //
  696. // If we were passed in a devices installed string table then add this
  697. // device instance id to the string table.
  698. //
  699. if (DevicesInstalledStringTable) {
  700. if( SetupDiGetDeviceInstanceId( hDevInfo,
  701. pDeviceInfoData,
  702. DevInstId,
  703. sizeof( DevInstId ) / sizeof( WCHAR ),
  704. NULL ) ) {
  705. if (pSetupStringTableAddString(DevicesInstalledStringTable, DevInstId, STRTAB_CASE_INSENSITIVE) == -1) {
  706. SetupDebugPrint1( L"SETUP: ERROR: failed to add Device = %ls to the string table!", DevInstId );
  707. }
  708. }
  709. }
  710. Error = GetLastError();
  711. if( ((LONG)Error) < 0 ) {
  712. //
  713. // Setupapi error code, display it in hex
  714. //
  715. SetupDebugPrint1( L"SETUP: SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed. Error = %lx", Error );
  716. } else {
  717. //
  718. // win32 error code, display it in decimal
  719. //
  720. SetupDebugPrint1( L"SETUP: SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed. Error = %d", Error );
  721. }
  722. return( FALSE );
  723. }
  724. return( TRUE );
  725. }
  726. BOOL
  727. RebuildListWithoutOldInternetDrivers(
  728. IN HDEVINFO hDevInfo,
  729. IN PSP_DEVINFO_DATA pDeviceInfoData
  730. )
  731. /*++
  732. Routine Description:
  733. This function determins whether SetupDiBuildDriverInfoList will need to be
  734. called again with the DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS flag set. We first
  735. call SetupDiBuildDriverInfoList without this flag to allow old Internet drivers
  736. to be included in the best driver selection. If an old Internet driver is
  737. selected as the best then we need to do a validity check to verify that all
  738. the destination files are present on the system and correctly digitally signed.
  739. If both of these are true then we can allow this old internet driver to stay
  740. the best driver since it won't prompt for source files.
  741. We need to do this for the case when a user is running a previous OS and they
  742. get a better driver from Windows Update. We can't blindly replace the Windows
  743. Update driver with the drivers in the new OS since they might not be better.
  744. Arguments:
  745. hDevInfo -
  746. pDeviceInfoData -
  747. Return Value:
  748. Returns TRUE if the list needs to be rebuilt with the DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS
  749. flag and FALSE otherwise.
  750. Note if this API returns FALSE it either means the best driver was not an old
  751. internet driver or that it was but all of it's destination files are present
  752. and correctly digitally signed so no file copy will need to take place.
  753. --*/
  754. {
  755. BOOL RebuildList = FALSE;
  756. SP_DRVINFO_DATA DriverInfoData;
  757. SP_DRVINSTALL_PARAMS DriverInstallParams;
  758. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  759. HSPFILEQ FileQueue = INVALID_HANDLE_VALUE;
  760. DWORD ScanResult = 0;
  761. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  762. if (SetupDiGetSelectedDriver(hDevInfo, pDeviceInfoData, &DriverInfoData)) {
  763. DriverInstallParams.cbSize = sizeof(SP_DRVINSTALL_PARAMS);
  764. if (SetupDiGetDriverInstallParams(hDevInfo,
  765. pDeviceInfoData,
  766. &DriverInfoData,
  767. &DriverInstallParams
  768. ) &&
  769. (DriverInstallParams.Flags & DNF_OLD_INET_DRIVER)) {
  770. //
  771. // At this point we know that the best driver is an old Internet driver.
  772. // Now do a validity check which will verify all the source files are
  773. // present and digitally signed. We will also assume we need to rebuild
  774. // the list at this point unless we pass the validity check below.
  775. //
  776. RebuildList = TRUE;
  777. FileQueue = SetupOpenFileQueue();
  778. if (FileQueue != INVALID_HANDLE_VALUE) {
  779. //
  780. // Tell setupapi to use our file queue.
  781. //
  782. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  783. if (SetupDiGetDeviceInstallParams(hDevInfo,
  784. pDeviceInfoData,
  785. &DeviceInstallParams
  786. )) {
  787. DeviceInstallParams.Flags |= DI_NOVCP;
  788. DeviceInstallParams.FileQueue = FileQueue;
  789. if (SetupDiSetDeviceInstallParams(hDevInfo,
  790. pDeviceInfoData,
  791. &DeviceInstallParams
  792. )) {
  793. if (SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES,
  794. hDevInfo,
  795. pDeviceInfoData
  796. ) &&
  797. SetupScanFileQueue(FileQueue,
  798. SPQ_SCAN_FILE_VALIDITY,
  799. NULL,
  800. NULL,
  801. NULL,
  802. &ScanResult
  803. ) &&
  804. ((ScanResult == 1) ||
  805. (ScanResult == 2))) {
  806. //
  807. // if ScanResult is 1 or 2 then no copying needs to
  808. // take place because all the destination files are
  809. // in their place and digitally signed.
  810. //
  811. RebuildList = FALSE;
  812. }
  813. }
  814. }
  815. //
  816. // Clear out the file queue handle from the device install params
  817. // so that we can close the file queue.
  818. //
  819. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  820. if (SetupDiGetDeviceInstallParams(hDevInfo,
  821. pDeviceInfoData,
  822. &DeviceInstallParams
  823. )) {
  824. DeviceInstallParams.Flags &= ~DI_NOVCP;
  825. DeviceInstallParams.FileQueue = INVALID_HANDLE_VALUE;
  826. SetupDiSetDeviceInstallParams(hDevInfo,
  827. pDeviceInfoData,
  828. &DeviceInstallParams
  829. );
  830. }
  831. SetupCloseFileQueue(FileQueue);
  832. }
  833. }
  834. }
  835. return RebuildList;
  836. }
  837. BOOL
  838. pDoesExistingDriverNeedBackup(
  839. IN HDEVINFO hDevInfo,
  840. IN PSP_DEVINFO_DATA pDeviceInfoData,
  841. IN PWSTR InfPath,
  842. IN DWORD InfPathSize
  843. )
  844. /*++
  845. Routine Description:
  846. This function determins whether the currently install driver needs to be
  847. backed up or not. It does this by checking if the current driver is an
  848. oem driver, and verifying that it is not the same as the new driver
  849. we are about to install.
  850. Arguments:
  851. hDevInfo -
  852. pDeviceInfoData -
  853. Return Value:
  854. TRUE if the current driver needs to be backed up, FALSE otherwise.
  855. --*/
  856. {
  857. BOOL bBackupCurrentDriver = FALSE;
  858. HKEY Key = INVALID_HANDLE_VALUE;
  859. DWORD dwType, dwData;
  860. SP_DRVINFO_DATA DriverInfoData;
  861. SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
  862. if (InfPath) {
  863. InfPath[0] = TEXT('\0');
  864. }
  865. //
  866. // Open the driver key for this device.
  867. //
  868. Key = SetupDiOpenDevRegKey ( hDevInfo,
  869. pDeviceInfoData,
  870. DICS_FLAG_GLOBAL,
  871. 0,
  872. DIREG_DRV,
  873. KEY_READ );
  874. if (Key != INVALID_HANDLE_VALUE) {
  875. //
  876. // Get the 'InfPath' value from the registry.
  877. //
  878. dwType = REG_SZ;
  879. dwData = InfPathSize;
  880. if (RegQueryValueEx(Key,
  881. REGSTR_VAL_INFPATH,
  882. NULL,
  883. &dwType,
  884. (LPBYTE)InfPath,
  885. &dwData) == ERROR_SUCCESS) {
  886. //
  887. // Check if this is an oem inf
  888. //
  889. if (IsInstalledInfFromOem(InfPath)) {
  890. //
  891. // Retrieve the name of the INF associated with the selected driver
  892. // node.
  893. //
  894. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  895. if (SetupDiGetSelectedDriver(hDevInfo, pDeviceInfoData, &DriverInfoData)) {
  896. DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  897. if (SetupDiGetDriverInfoDetail(hDevInfo,
  898. pDeviceInfoData,
  899. &DriverInfoData,
  900. &DriverInfoDetailData,
  901. sizeof(DriverInfoDetailData),
  902. NULL) ||
  903. (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  904. //
  905. // If the two INFs are not the same then this means we
  906. // should backup the current drivers before installing
  907. // the new drivers.
  908. //
  909. if (lstrcmpi(pSetupGetFileTitle(DriverInfoDetailData.InfFileName),
  910. InfPath) != 0) {
  911. bBackupCurrentDriver = TRUE;
  912. }
  913. } else {
  914. SetupDebugPrint1( L"SETUP: SetupDiGetDriverInfoDetail() failed. Error = %d", GetLastError() );
  915. }
  916. } else {
  917. SetupDebugPrint1( L"SETUP: SetupDiGetSelectedDriver() failed. Error = %d", GetLastError() );
  918. }
  919. }
  920. }
  921. RegCloseKey(Key);
  922. }
  923. return bBackupCurrentDriver;
  924. }
  925. BOOL
  926. SelectBestDriver(
  927. IN HDEVINFO hDevInfo,
  928. IN PSP_DEVINFO_DATA pDeviceInfoData,
  929. OUT PBOOL pbOemF6Driver
  930. )
  931. /*++
  932. Routine Description:
  933. This function selects the best driver for the specified device.
  934. It is assumed that SetupDiBuildDriverInfoList was called before calling
  935. this API.
  936. This API will first check the list of driver nodes for this device and
  937. see if any have the DNF_OEM_F6_INF flag. If they do then this INF was
  938. specified by the user during text mode setup by doing an F6. We always
  939. want to use these drivers, even if they are not the 'best' according to
  940. setupapi. If there are no drivers in the list with this flag then we
  941. fall back to the default behavior of DIF_SELECTBESTCOMPATDRV.
  942. Arguments:
  943. hDevInfo -
  944. pDeviceInfoData -
  945. Return Value:
  946. Returns the result SetupDiCallClassInstaller with DIF_SELECTBESTCOMPATDRV.
  947. --*/
  948. {
  949. DWORD index;
  950. SP_DRVINFO_DATA DriverInfoData;
  951. SP_DRVINSTALL_PARAMS DriverInstallParams;
  952. BOOL bFoundOemF6Driver = FALSE;
  953. *pbOemF6Driver = FALSE;
  954. DriverInfoData.cbSize = sizeof(DriverInfoData);
  955. index = 0;
  956. //
  957. // First go through the list of drivers and see if there is an OEM F6 driver
  958. // in the list.
  959. //
  960. while (SetupDiEnumDriverInfo(hDevInfo,
  961. pDeviceInfoData,
  962. SPDIT_COMPATDRIVER,
  963. index++,
  964. &DriverInfoData
  965. )) {
  966. DriverInstallParams.cbSize = sizeof(SP_DRVINSTALL_PARAMS);
  967. if (SetupDiGetDriverInstallParams(hDevInfo,
  968. pDeviceInfoData,
  969. &DriverInfoData,
  970. &DriverInstallParams
  971. ) &&
  972. (DriverInstallParams.Flags & DNF_OEM_F6_INF)) {
  973. bFoundOemF6Driver = TRUE;
  974. SetupDebugPrint( L"SETUP: Using Oem F6 driver for this device." );
  975. break;
  976. }
  977. }
  978. //
  979. // If we found an Oem driver that was specified by F6 during text mode setup,
  980. // then we will go through the list again and mark all drivers that are
  981. // not OEM F6 drivers and BAD drivers. This way when we call
  982. // DIF_SELECTBESTCOMPATDRV it will only select from the OEM F6 drivers.
  983. //
  984. if (bFoundOemF6Driver) {
  985. *pbOemF6Driver = TRUE;
  986. DriverInfoData.cbSize = sizeof(DriverInfoData);
  987. index = 0;
  988. while (SetupDiEnumDriverInfo(hDevInfo,
  989. pDeviceInfoData,
  990. SPDIT_COMPATDRIVER,
  991. index++,
  992. &DriverInfoData
  993. )) {
  994. DriverInstallParams.cbSize = sizeof(SP_DRVINSTALL_PARAMS);
  995. if (SetupDiGetDriverInstallParams(hDevInfo,
  996. pDeviceInfoData,
  997. &DriverInfoData,
  998. &DriverInstallParams
  999. )) {
  1000. //
  1001. // If this driver node does not have the DNF_OEM_F6_INF flag
  1002. // then set the DNF_BAD_DRIVER flag so we will skip this
  1003. // driver later when we do DIF_SELECTBESTCOMPATDRV
  1004. //
  1005. if (!(DriverInstallParams.Flags & DNF_OEM_F6_INF)) {
  1006. DriverInstallParams.Flags |= DNF_BAD_DRIVER;
  1007. SetupDiSetDriverInstallParams(hDevInfo,
  1008. pDeviceInfoData,
  1009. &DriverInfoData,
  1010. &DriverInstallParams
  1011. );
  1012. }
  1013. }
  1014. }
  1015. }
  1016. return (SetupDiCallClassInstaller( DIF_SELECTBESTCOMPATDRV,
  1017. hDevInfo,
  1018. pDeviceInfoData ) );
  1019. }
  1020. BOOL
  1021. SkipDeviceInstallation(
  1022. IN HDEVINFO hDevInfo,
  1023. IN PSP_DEVINFO_DATA pDeviceInfoData,
  1024. IN HINF InfHandle,
  1025. IN PCWSTR GUIDString
  1026. )
  1027. /*++
  1028. Routine Description:
  1029. This function determines whether or not the installation of a particular device should be skipped.
  1030. It should be skipped if the following conditions are met:
  1031. - The device is already installed;
  1032. - The GUID for the device is listed in [InstalledDevicesToSkip], in syssetup.inf
  1033. Arguments:
  1034. hDevInfo -
  1035. pDeviceInfoData -
  1036. InfHandle - System setup inf handle (syssetup.inf).
  1037. GUIDString - GUID associated to the device being checked (in string format).
  1038. Return Value:
  1039. Returns TRUE if the installation of the device should be skipped. Otherwise, it returns FALSE.
  1040. --*/
  1041. {
  1042. BOOL DeviceAlreadyInstalled;
  1043. BOOL SafeClassInstaller = TRUE;
  1044. WCHAR PropertyBuffer[ MAX_PATH + 1 ];
  1045. HKEY Key;
  1046. //
  1047. // Attempt to open the dev node's driver key
  1048. //
  1049. Key = SetupDiOpenDevRegKey ( hDevInfo,
  1050. pDeviceInfoData,
  1051. DICS_FLAG_GLOBAL,
  1052. 0,
  1053. DIREG_DRV,
  1054. MAXIMUM_ALLOWED );
  1055. if( Key == INVALID_HANDLE_VALUE ) {
  1056. DeviceAlreadyInstalled = FALSE;
  1057. SetupDebugPrint( L"SETUP: Device not yet installed." );
  1058. } else {
  1059. RegCloseKey( Key );
  1060. DeviceAlreadyInstalled = TRUE;
  1061. SetupDebugPrint( L"SETUP: Device already installed." );
  1062. }
  1063. //
  1064. // In the case of MiniSetup, we're not doing an
  1065. // upgrade, so all we care about is if the device is
  1066. // already installed.
  1067. //
  1068. if( MiniSetup ) {
  1069. return( DeviceAlreadyInstalled );
  1070. }
  1071. if( DeviceAlreadyInstalled ) {
  1072. //
  1073. // If the device is already installed, then check if the class installer for this
  1074. // device is considered safe.
  1075. //
  1076. SafeClassInstaller = !SetupGetLineText( NULL,
  1077. InfHandle,
  1078. L"InstalledDevicesToSkip",
  1079. GUIDString,
  1080. PropertyBuffer,
  1081. sizeof( PropertyBuffer )/sizeof( WCHAR ),
  1082. NULL );
  1083. }
  1084. return( DeviceAlreadyInstalled && !SafeClassInstaller );
  1085. }
  1086. BOOL
  1087. PrecompileInfFiles(
  1088. IN HWND ProgressWindow,
  1089. IN ULONG StartAtPercent,
  1090. IN ULONG StopAtPercent
  1091. )
  1092. /*++
  1093. Routine Description:
  1094. This function precompiles all the infs in %SystemRoot%\inf.
  1095. and then builds the cache.
  1096. Arguments:
  1097. ProgressWindow - Handle to the progress bar.
  1098. StartAtPercent - Starting position in the progress bar.
  1099. It indicates that from position 0 to this position
  1100. the gauge is already filled.
  1101. StopAtPercent - Ending position of the progress bar.
  1102. The pnp thread should not fill the progress bar beyond
  1103. this position
  1104. Return Value:
  1105. Returns TRUE if at least one inf was pre-compiled. Otherwise, returns FALSE.
  1106. --*/
  1107. {
  1108. WCHAR SavedDirectory[ MAX_PATH + 1 ];
  1109. WCHAR InfDirectory[ MAX_PATH + 1 ];
  1110. UINT GaugeRange;
  1111. BOOL AlwaysFalse = FALSE;
  1112. PINF_FILE_NAME InfList = NULL;
  1113. PINF_FILE_NAME p;
  1114. WIN32_FIND_DATA FindData;
  1115. HANDLE FindHandle;
  1116. ULONG InfCount;
  1117. ULONG i = 0;
  1118. SetupDebugPrint( L"SETUP: Entering PrecompileInfFiles()" );
  1119. //
  1120. // Save current directory
  1121. //
  1122. GetCurrentDirectory( sizeof(SavedDirectory)/sizeof(WCHAR), SavedDirectory );
  1123. //
  1124. // Change current directory to %SystemRoot%\inf
  1125. //
  1126. if ((GetWindowsDirectory( InfDirectory, sizeof(InfDirectory)/sizeof(WCHAR) ) == 0) ||
  1127. !pSetupConcatenatePaths(InfDirectory, L"inf", sizeof(InfDirectory)/sizeof(WCHAR), NULL)) {
  1128. MYASSERT(FALSE);
  1129. return FALSE;
  1130. }
  1131. SetCurrentDirectory( InfDirectory );
  1132. //
  1133. // Find total number of inf files
  1134. //
  1135. InfCount = 0;
  1136. FindHandle = FindFirstFile( L"*.inf", &FindData );
  1137. if( FindHandle != INVALID_HANDLE_VALUE ) {
  1138. do {
  1139. //
  1140. // Skip directories
  1141. //
  1142. if( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  1143. continue;
  1144. }
  1145. p = MyMalloc( sizeof( INF_FILE_NAME ) ) ;
  1146. if( p != NULL ) {
  1147. p->InfName = pSetupDuplicateString( &FindData.cFileName[0] );
  1148. p->Next = InfList;
  1149. InfList = p;
  1150. InfCount++;
  1151. }
  1152. } while( FindNextFile( FindHandle, &FindData ) );
  1153. FindClose( FindHandle );
  1154. } else {
  1155. SetupDebugPrint1( L"SETUP: FindFirstFile( *.inf ) failed. Error = %d", GetLastError() );
  1156. }
  1157. //
  1158. // Initialize the gauge allow for pSetupInfCacheBuild step
  1159. //
  1160. GaugeRange = ((InfCount+1)*100/(StopAtPercent-StartAtPercent));
  1161. SendMessage(ProgressWindow, WMX_PROGRESSTICKS, (InfCount+1), 0);
  1162. SendMessage(ProgressWindow,PBM_SETRANGE,0,MAKELPARAM(0,GaugeRange));
  1163. SendMessage(ProgressWindow,PBM_SETPOS,GaugeRange*StartAtPercent/100,0);
  1164. SendMessage(ProgressWindow,PBM_SETSTEP,1,0);
  1165. //
  1166. // Prcompile each inf file
  1167. //
  1168. for( i = 0;
  1169. (
  1170. //
  1171. // Tick the gauge after we finished pre-compiling an inf.
  1172. // Note that we don't tick the gauge when i == 0 (no inf was yet processed),
  1173. // but we do tick the gauge when i == InfCount (all infs were pre-compiled).
  1174. // Note also that we use the flag AlwaysFalse, to enforce that all inf will be processed,
  1175. // even when SendMessage(PBM_SETPBIT) returns a non-zero value.
  1176. //
  1177. (i != 0) &&
  1178. SendMessage(ProgressWindow,PBM_STEPIT,0,0) &&
  1179. AlwaysFalse
  1180. ) ||
  1181. (i < InfCount);
  1182. i++
  1183. ) {
  1184. HINF hInf;
  1185. SetupDebugPrint1( L"SETUP: Pre-compiling file: %ls", InfList->InfName );
  1186. MYASSERT(InfList);
  1187. hInf = SetupOpenInfFile( InfList->InfName,
  1188. NULL,
  1189. INF_STYLE_WIN4,
  1190. NULL );
  1191. if( hInf != INVALID_HANDLE_VALUE ) {
  1192. SetupCloseInfFile( hInf );
  1193. } else {
  1194. DWORD Error;
  1195. Error = GetLastError();
  1196. if( ((LONG)Error) < 0 ) {
  1197. //
  1198. // Setupapi error code, display it in hex
  1199. //
  1200. SetupDebugPrint2( L"SETUP: SetupOpenInfFile() failed. FileName = %ls, Error = %lx", InfList->InfName, Error );
  1201. } else {
  1202. //
  1203. // win32 error code, display it in decimal
  1204. //
  1205. SetupDebugPrint2( L"SETUP: SetupOpenInfFile() failed. FileName = %ls, Error = %d", InfList->InfName, Error );
  1206. }
  1207. }
  1208. //
  1209. // The file name is no longer needed
  1210. //
  1211. p = InfList;
  1212. InfList = InfList->Next;
  1213. if( p->InfName != NULL ) {
  1214. MyFree( p->InfName );
  1215. }
  1216. MyFree( p );
  1217. }
  1218. SetupDebugPrint2( L"SETUP: Total inf files = %d, total precompiled: %d", InfCount, i );
  1219. SetupDebugPrint( L"SETUP: Calling pSetupInfCacheBuild()" );
  1220. pSetupInfCacheBuild(INFCACHEBUILD_REBUILD);
  1221. //
  1222. // Make sure that at this point, the gauge area is filled up to the end of
  1223. // the area reserved for the pre-compilation of inf files.
  1224. //
  1225. SendMessage(ProgressWindow,PBM_SETPOS,GaugeRange*StopAtPercent/100,0);
  1226. //
  1227. // Restore current directory
  1228. //
  1229. SetCurrentDirectory( SavedDirectory );
  1230. SetupDebugPrint( L"SETUP: Leaving PrecompileInfFiles()" );
  1231. return( i != 0 );
  1232. }
  1233. BOOL
  1234. InstallLegacyDevices(
  1235. IN HWND hwndParent,
  1236. IN HWND ProgressWindow,
  1237. IN ULONG StartAtPercent,
  1238. IN ULONG StopAtPercent,
  1239. IN PVOID DevicesInstalledStringTable OPTIONAL
  1240. )
  1241. {
  1242. ULONG Index;
  1243. SP_DEVINFO_DATA DeviceInfoData;
  1244. ULONG Error;
  1245. WCHAR GUIDString[ 64 ];
  1246. BOOL b = TRUE;
  1247. HSPFILEQ FileQ = INVALID_HANDLE_VALUE;
  1248. LPGUID GuidList = NULL;
  1249. ULONG GuidCount = 32;
  1250. ULONG GuidIndex;
  1251. ULONG LastBatchedDetect;
  1252. ULONG GuidLB, GuidUB;
  1253. HDEVINFO* InfoSetArray = NULL;
  1254. BOOL AlwaysFalse = FALSE;
  1255. UINT GaugeRange;
  1256. HANDLE ThreadHandle = NULL;
  1257. DWORD ThreadId;
  1258. PPNP_PHASE1_LEGACY_DEV_THREAD_PARAMS Phase1Context;
  1259. PPNP_PHASE2_LEGACY_DEV_THREAD_PARAMS Phase2Context;
  1260. WCHAR PnpLogPath[ MAX_PATH + 1 ];
  1261. WCHAR LoggedDescription[ LINE_LEN + 1 ];
  1262. DWORD ScanQueueResult;
  1263. SP_DRVINFO_DATA DriverInfoData;
  1264. ULONG PnPFlags;
  1265. DWORD Result;
  1266. SetupDebugPrint( L"SETUP: Entering InstallLegacyDevices()" );
  1267. //
  1268. // Build path to pnp log file
  1269. //
  1270. Result = GetWindowsDirectory( PnpLogPath, sizeof(PnpLogPath)/sizeof(WCHAR) );
  1271. if( Result == 0) {
  1272. MYASSERT(FALSE);
  1273. return FALSE;
  1274. }
  1275. if (!pSetupConcatenatePaths( PnpLogPath,
  1276. szPnpLogFile,
  1277. sizeof(PnpLogPath)/sizeof(WCHAR),
  1278. NULL )) {
  1279. MYASSERT(FALSE);
  1280. return FALSE;
  1281. }
  1282. //
  1283. // Do the migration of legacy devices.
  1284. // This is a quick operation and doesn't need to use the progress window.
  1285. //
  1286. // This is now performed before installation of true PnP devices
  1287. //
  1288. // PnPInitializationThread(NULL);
  1289. GuidList = ( LPGUID )MyMalloc( sizeof( GUID ) * GuidCount );
  1290. if( !GuidList ) {
  1291. return( FALSE );
  1292. }
  1293. if ( !SetupDiBuildClassInfoList( 0,
  1294. GuidList,
  1295. GuidCount,
  1296. &GuidCount ) ) {
  1297. Error = GetLastError();
  1298. if( Error != ERROR_INSUFFICIENT_BUFFER ) {
  1299. SetupDebugPrint1( L"SETUP: SetupDiBuildClassInfoList() failed. Error = %d", Error );
  1300. MyFree( GuidList );
  1301. //
  1302. // Fill the gauge up to the end of the area reserved for legacy devices.
  1303. //
  1304. GaugeRange = 100;
  1305. SendMessage(ProgressWindow,PBM_SETRANGE,0,MAKELPARAM(0,GaugeRange));
  1306. SendMessage(ProgressWindow,PBM_SETPOS,GaugeRange*StopAtPercent/100,0);
  1307. SetupDebugPrint( L"SETUP: Leaving InstallLegacyDevices()" );
  1308. return( FALSE );
  1309. }
  1310. GuidList = ( LPGUID )MyRealloc( GuidList, sizeof( GUID ) * GuidCount );
  1311. if( !SetupDiBuildClassInfoList( 0,
  1312. GuidList,
  1313. GuidCount,
  1314. &GuidCount ) ) {
  1315. MyFree( GuidList );
  1316. SetupDebugPrint1( L"SETUP: SetupDiBuildClassInfoList() failed. Error = %d", Error );
  1317. //
  1318. // Fill the gauge up to the end of the area reserved for legacy devices.
  1319. //
  1320. GaugeRange = 100;
  1321. SendMessage(ProgressWindow,PBM_SETRANGE,0,MAKELPARAM(0,GaugeRange));
  1322. SendMessage(ProgressWindow,PBM_SETPOS,GaugeRange*StopAtPercent/100,0);
  1323. SetupDebugPrint( L"SETUP: Leaving InstallLegacyDevices()" );
  1324. return( FALSE );
  1325. }
  1326. }
  1327. //
  1328. // Sort the class GUID list based on the detection ordering specified in syssetup.inf
  1329. //
  1330. SortClassGuidListForDetection(GuidList, GuidCount, &LastBatchedDetect);
  1331. InfoSetArray = (HDEVINFO*)MyMalloc( sizeof(HDEVINFO) * GuidCount );
  1332. //
  1333. // Initialize the gauge.
  1334. // Note that since we process the device classes twice (two big 'for
  1335. // loops'), we divide the area of the gauge reserved for the gauge
  1336. // reserved for the legacy devices in 2 pieces, one for each 'for loop'.
  1337. //
  1338. GaugeRange = (2*GuidCount*100/(StopAtPercent-StartAtPercent));
  1339. SendMessage(ProgressWindow, WMX_PROGRESSTICKS, 2*GuidCount, 0);
  1340. SendMessage(ProgressWindow,PBM_SETRANGE,0,MAKELPARAM(0,GaugeRange));
  1341. SendMessage(ProgressWindow,PBM_SETPOS,GaugeRange*StartAtPercent/100,0);
  1342. SendMessage(ProgressWindow,PBM_SETSTEP,1,0);
  1343. //
  1344. // On our first pass, we process all the detections that can be batched
  1345. // together. Then, on subsequent passes, we process any non-batchable
  1346. // detections individually...
  1347. //
  1348. for(GuidLB = 0, GuidUB = LastBatchedDetect; GuidLB < GuidCount; GuidLB = ++GuidUB) {
  1349. //
  1350. // First, create a file queue
  1351. //
  1352. FileQ = SetupOpenFileQueue();
  1353. if( FileQ == INVALID_HANDLE_VALUE ) {
  1354. SetupDebugPrint1( L"SETUP: Failed to create file queue. Error = %d", GetLastError() );
  1355. }
  1356. for( GuidIndex = GuidLB;
  1357. (
  1358. //
  1359. // Tick the gauge after we finished processing all the devices of a particular class.
  1360. // Note that we don't tick the gauge when GuidIndex == 0 (no device was yet processed),
  1361. // but we do tick the gauge when GuidIndex == GuidCount (all devices of the last class
  1362. // were processed).
  1363. // Note also that we use the flag AlwaysFalse, to enforce that all classes will be processed,
  1364. // even when SendMessage(PBM_SETPBIT) returns a non-zero value.
  1365. //
  1366. (GuidIndex != GuidLB) &&
  1367. SendMessage(ProgressWindow,PBM_STEPIT,0,0) &&
  1368. AlwaysFalse
  1369. ) ||
  1370. (GuidIndex <= GuidUB);
  1371. GuidIndex++ ) {
  1372. WCHAR ClassDescription[ LINE_LEN + 1 ];
  1373. InfoSetArray[ GuidIndex ] = INVALID_HANDLE_VALUE;
  1374. ClassDescription[0] = (WCHAR)'\0';
  1375. if( !SetupDiGetClassDescription( &GuidList[ GuidIndex ],
  1376. ClassDescription,
  1377. sizeof(ClassDescription)/sizeof(WCHAR),
  1378. NULL ) ) {
  1379. SetupDebugPrint1( L"SETUP: SetupDiGetClassDescription() failed. Error = %lx", GetLastError() );
  1380. ClassDescription[0] = (WCHAR)'\0';
  1381. }
  1382. pSetupStringFromGuid( &GuidList[ GuidIndex ], GUIDString, sizeof( GUIDString ) / sizeof( WCHAR ) );
  1383. SetupDebugPrint1( L"SETUP: Installing legacy devices of class: %ls ", ClassDescription );
  1384. SetupDebugPrint2( L"SETUP: GuidIndex = %d, Guid = %ls", GuidIndex, GUIDString );
  1385. #ifndef DBG
  1386. //
  1387. // Check if this class of devices is listed as a bad class
  1388. //
  1389. LoggedDescription[0] = L'\0';
  1390. if( (GetPrivateProfileString( szLegacyClassesSection,
  1391. GUIDString,
  1392. L"",
  1393. LoggedDescription,
  1394. sizeof(LoggedDescription)/sizeof(WCHAR),
  1395. PnpLogPath ) != 0) &&
  1396. ( wcslen( LoggedDescription ) != 0 )
  1397. ) {
  1398. //
  1399. // Skip the installation of this class of devices
  1400. //
  1401. SetupDebugPrint1( L"SETUP: Skipping installation of devices of class: %ls", ClassDescription );
  1402. continue;
  1403. }
  1404. #endif
  1405. //
  1406. // Start the thread that actually does the initial part of the installation of the legacy devices (DIF_FIRSTTIMESETUP)
  1407. //
  1408. Phase1Context = MyMalloc( sizeof( PNP_PHASE1_LEGACY_DEV_THREAD_PARAMS ) );
  1409. Phase1Context->hDevInfo = INVALID_HANDLE_VALUE;
  1410. Phase1Context->Guid = GuidList[ GuidIndex ];
  1411. Phase1Context->pClassDescription = pSetupDuplicateString(ClassDescription);
  1412. Phase1Context->hwndParent = hwndParent;
  1413. ThreadHandle = NULL;
  1414. ThreadHandle = CreateThread( NULL,
  1415. 0,
  1416. pPhase1InstallPnpLegacyDevicesThread,
  1417. Phase1Context,
  1418. 0,
  1419. &ThreadId );
  1420. if(ThreadHandle) {
  1421. DWORD WaitResult;
  1422. DWORD ExitCode;
  1423. BOOL KeepWaiting;
  1424. KeepWaiting = TRUE;
  1425. while( KeepWaiting ) {
  1426. int Result;
  1427. //
  1428. // REVIEW 2000/11/08 seanch - Old behavior that we don't want to regress.
  1429. // Fix the network timeout after the network guys fix their class installer
  1430. //
  1431. WaitResult = WaitForSingleObject( ThreadHandle,
  1432. (_wcsicmp( GUIDString, BB_NETWORK_GUID_STRING ) == 0)? BB_PNP_NETWORK_TIMEOUT :
  1433. PNP_LEGACY_PHASE1_TIMEOUT );
  1434. if( WaitResult == WAIT_TIMEOUT ) {
  1435. HANDLE hDialogEvent;
  1436. if( hDialogEvent = OpenEvent( EVENT_MODIFY_STATE, FALSE, SETUP_HAS_OPEN_DIALOG_EVENT ) ) {
  1437. //
  1438. // Setupapi is prompting the user for a file. Don't timeout.
  1439. //
  1440. CloseHandle( hDialogEvent );
  1441. KeepWaiting = TRUE;
  1442. continue;
  1443. }
  1444. //
  1445. // Class installer is hung
  1446. //
  1447. SetupDebugPrint1( L"SETUP: Class Installer appears to be hung (phase1). ClassDescription = %ls", ClassDescription );
  1448. #ifdef PRERELEASE
  1449. //
  1450. // Ask the user if he wants to skip the installation of this class of devices
  1451. //
  1452. if( !Unattended ) {
  1453. Result = MessageBoxFromMessage( hwndParent,
  1454. MSG_CLASS_INSTALLER_HUNG_FIRSTTIMESETUP,
  1455. NULL,
  1456. IDS_WINNT_SETUP,
  1457. MB_YESNO | MB_ICONWARNING,
  1458. ClassDescription );
  1459. } else {
  1460. Result = IDYES;
  1461. }
  1462. #else
  1463. Result = IDYES;
  1464. #endif
  1465. if(Result == IDYES) {
  1466. //
  1467. // User wants to skip this class of devices.
  1468. // First find out if the thread has already returned.
  1469. //
  1470. WaitResult = WaitForSingleObject( ThreadHandle, 0 );
  1471. if( WaitResult != WAIT_OBJECT_0 ) {
  1472. //
  1473. // Thread hasn't returned yet. Skip the installation of this class of devices
  1474. //
  1475. KeepWaiting = FALSE;
  1476. SetupDebugPrint1( L"SETUP: Skipping installation of legacy devices of class: %ls", ClassDescription );
  1477. b = FALSE;
  1478. //
  1479. // Remember this class so that it won't be installed if GUI setup is
  1480. // restarted
  1481. //
  1482. WritePrivateProfileString( szLegacyClassesSection,
  1483. GUIDString,
  1484. ClassDescription,
  1485. PnpLogPath );
  1486. } else{
  1487. //
  1488. // Thread has already returned.
  1489. // There is no need to skip the installation of this class of devices.
  1490. // We assume that the user decided not to skip the installation of this class,
  1491. // and next call to WaitForSingleObject will immediately return.
  1492. //
  1493. }
  1494. }
  1495. } else if( WaitResult == WAIT_OBJECT_0 ) {
  1496. //
  1497. // Device Installation Thread completed.
  1498. //
  1499. KeepWaiting = FALSE;
  1500. if( GetExitCodeThread( ThreadHandle, &ExitCode ) ) {
  1501. if( ExitCode == ERROR_SUCCESS ) {
  1502. //
  1503. // The installation was successful
  1504. //
  1505. InfoSetArray[ GuidIndex ] = Phase1Context->hDevInfo;
  1506. } else {
  1507. //
  1508. // The installation was not successful.
  1509. // There is no need to log the error, since the thread has already done it.
  1510. //
  1511. b = FALSE;
  1512. }
  1513. } else {
  1514. //
  1515. // Unable to retrieve exit code. Assume success.
  1516. //
  1517. InfoSetArray[ GuidIndex ] = Phase1Context->hDevInfo;
  1518. SetupDebugPrint1( L"SETUP: GetExitCode() failed. Error = %d", GetLastError() );
  1519. SetupDebugPrint( L"SETUP: Unable to retrieve thread exit code. Assuming devices successfully installed (phase1)." );
  1520. }
  1521. //
  1522. // Deallocate all the memory that was passed to the thread.
  1523. //
  1524. MyFree(Phase1Context->pClassDescription);
  1525. MyFree(Phase1Context);
  1526. } else {
  1527. //
  1528. // Should not occur.
  1529. // In this case we don't deallocate any memory, since the thread may be running.
  1530. //
  1531. KeepWaiting = FALSE;
  1532. SetupDebugPrint1( L"SETUP: WaitForSingleObject() returned %d", WaitResult );
  1533. b = FALSE;
  1534. }
  1535. }
  1536. //
  1537. // The thread handle is no longer needed at this point
  1538. //
  1539. CloseHandle(ThreadHandle);
  1540. } else {
  1541. //
  1542. // Just do it synchronously.
  1543. //
  1544. Error = GetLastError();
  1545. SetupDebugPrint1( L"SETUP: CreateThread() failed (phase1). Error = %d", Error );
  1546. if( pPhase1InstallPnpLegacyDevicesThread(Phase1Context) != ERROR_SUCCESS ) {
  1547. //
  1548. // The installation was not successful.
  1549. // There is no need to log the error, since the thread has already done it.
  1550. //
  1551. b = FALSE;
  1552. } else {
  1553. InfoSetArray[ GuidIndex ] = Phase1Context->hDevInfo;
  1554. }
  1555. //
  1556. // Deallocate the memory passed as argument
  1557. //
  1558. MyFree( Phase1Context->pClassDescription );
  1559. MyFree( Phase1Context );
  1560. }
  1561. //
  1562. // Find out if we should install devices of this class.
  1563. //
  1564. if( InfoSetArray[ GuidIndex ] == INVALID_HANDLE_VALUE ) {
  1565. //
  1566. // If we should not install this class of devices, then go process the next class.
  1567. //
  1568. continue;
  1569. }
  1570. //
  1571. // Now enumerate each device information element added to this set, registering
  1572. // and then installing the files for each one.
  1573. //
  1574. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  1575. for( Index = 0;
  1576. SetupDiEnumDeviceInfo( InfoSetArray[ GuidIndex ], Index, &DeviceInfoData );
  1577. Index++ ) {
  1578. WCHAR DevInstId[ MAX_DEVICE_ID_LEN ];
  1579. Error = ERROR_SUCCESS;
  1580. //
  1581. // Make sure the device is marked as 'Do not install'
  1582. //
  1583. if( !pSetupDiSetDeviceInfoContext( InfoSetArray[ GuidIndex ], &DeviceInfoData, FALSE ) ) {
  1584. SetupDebugPrint2( L"SETUP: pSetupDiSetDeviceInfoContext() failed. Error = %lx, Index = %d", GetLastError(), Index );
  1585. }
  1586. //
  1587. // Retrieve the string id for this device
  1588. //
  1589. DevInstId[0] = L'\0';
  1590. if( !SetupDiGetDeviceInstanceId( InfoSetArray[ GuidIndex ],
  1591. &DeviceInfoData,
  1592. DevInstId,
  1593. sizeof( DevInstId ) / sizeof( WCHAR ),
  1594. NULL ) ) {
  1595. SetupDebugPrint2( L"SETUP: Index = %d, SetupDiGetDeviceInstanceId() failed. Error = ", Index, GetLastError() );
  1596. }
  1597. #ifndef DBG
  1598. //
  1599. // Find out if this device is marked as a bad device
  1600. //
  1601. LoggedDescription[0] = L'\0';
  1602. if( (GetPrivateProfileString( szLegacyClassesSection,
  1603. DevInstId,
  1604. L"",
  1605. LoggedDescription,
  1606. sizeof(LoggedDescription)/sizeof(WCHAR),
  1607. PnpLogPath ) != 0) &&
  1608. ( wcslen( LoggedDescription ) != 0 )
  1609. ) {
  1610. //
  1611. // Skip the installation of this device
  1612. //
  1613. SetupDebugPrint1( L"SETUP: Skipping installation of legacy device: %ls", DevInstId );
  1614. continue;
  1615. }
  1616. #endif
  1617. SetupDebugPrint2( L"SETUP: Index = %d, DeviceId = %ls", Index, DevInstId );
  1618. Phase2Context = MyMalloc( sizeof( PNP_PHASE2_LEGACY_DEV_THREAD_PARAMS ) );
  1619. Phase2Context->hDevInfo = InfoSetArray[ GuidIndex ];
  1620. Phase2Context->FileQ = FileQ;
  1621. Phase2Context->DeviceInfoData = DeviceInfoData;
  1622. Phase2Context->pClassDescription = pSetupDuplicateString(ClassDescription);
  1623. Phase2Context->pDeviceId = pSetupDuplicateString(DevInstId);
  1624. ThreadHandle = NULL;;
  1625. ThreadHandle = CreateThread( NULL,
  1626. 0,
  1627. pPhase2InstallPnpLegacyDevicesThread,
  1628. Phase2Context,
  1629. 0,
  1630. &ThreadId );
  1631. if( ThreadHandle ) {
  1632. DWORD WaitResult;
  1633. DWORD ExitCode;
  1634. BOOL KeepWaiting;
  1635. KeepWaiting = TRUE;
  1636. while( KeepWaiting ) {
  1637. //
  1638. // REVIEW 2000/11/08 seanch - Old behavior that we don't want to regress.
  1639. // Fix the network timeout after the network guys fix their class installer
  1640. //
  1641. WaitResult = WaitForSingleObject( ThreadHandle,
  1642. (_wcsicmp( GUIDString, BB_NETWORK_GUID_STRING ) == 0)? BB_PNP_NETWORK_TIMEOUT :
  1643. PNP_LEGACY_PHASE2_TIMEOUT );
  1644. if( WaitResult == WAIT_TIMEOUT ) {
  1645. int Result;
  1646. HANDLE hDialogEvent;
  1647. if( hDialogEvent = OpenEvent( EVENT_MODIFY_STATE, FALSE, SETUP_HAS_OPEN_DIALOG_EVENT ) ) {
  1648. //
  1649. // Setupapi is prompting the user for a file. Don't timeout.
  1650. //
  1651. CloseHandle( hDialogEvent );
  1652. KeepWaiting = TRUE;
  1653. continue;
  1654. }
  1655. //
  1656. // Class installer is hung
  1657. //
  1658. SetupDebugPrint1( L"SETUP: Class Installer appears to be hung (phase2). DeviceId = %ls", DevInstId );
  1659. #ifdef PRERELEASE
  1660. //
  1661. // Ask the user if he wants to skip the installation of this device
  1662. //
  1663. if( !Unattended ) {
  1664. Result = MessageBoxFromMessage( hwndParent,
  1665. MSG_CLASS_INSTALLER_HUNG,
  1666. NULL,
  1667. IDS_WINNT_SETUP,
  1668. MB_YESNO | MB_ICONWARNING,
  1669. DevInstId );
  1670. } else {
  1671. Result = IDYES;
  1672. }
  1673. #else
  1674. Result = IDYES;
  1675. #endif
  1676. if(Result == IDYES) {
  1677. //
  1678. // User wants to skip this class of devices.
  1679. // First find out if the thread has already returned.
  1680. //
  1681. WaitResult = WaitForSingleObject( ThreadHandle, 0 );
  1682. if( WaitResult != WAIT_OBJECT_0 ) {
  1683. //
  1684. // Thread hasn't returned yet. Skip the installation of this device
  1685. //
  1686. KeepWaiting = FALSE;
  1687. SetupDebugPrint1( L"SETUP: Skipping installation of legacy device (phase2). Device = %ls", DevInstId );
  1688. b = FALSE;
  1689. //
  1690. // Remember this device so that it won't be installed if GUI setup is
  1691. // restarted
  1692. //
  1693. WritePrivateProfileString( szLegacyDevSection,
  1694. DevInstId,
  1695. ClassDescription,
  1696. PnpLogPath );
  1697. } else{
  1698. //
  1699. // Thread has already returned.
  1700. // There is no need to skip the installation of this device.
  1701. // We assume that the user decided not to skip the installation of this device,
  1702. // and next call to WaitForSingleObject will immediately return.
  1703. //
  1704. }
  1705. }
  1706. } else if( WaitResult == WAIT_OBJECT_0 ) {
  1707. //
  1708. // Device Installation Thread completed.
  1709. // Find out the outcome of this phase of the installation.
  1710. //
  1711. KeepWaiting = FALSE;
  1712. if( GetExitCodeThread( ThreadHandle, &ExitCode ) ) {
  1713. if( ExitCode ) {
  1714. //
  1715. // The installation was successful
  1716. //
  1717. } else {
  1718. //
  1719. // The installation was not successful.
  1720. // There is no need to log the error, since the thread has already done it.
  1721. //
  1722. b = FALSE;
  1723. }
  1724. } else {
  1725. //
  1726. // Unable to retrieve exit code. Assume success.
  1727. //
  1728. SetupDebugPrint1( L"SETUP: GetExitCode() failed. Error = %d", GetLastError() );
  1729. SetupDebugPrint( L"SETUP: Unable to retrieve thread exit code. Assuming device successfully installed (phase2)." );
  1730. }
  1731. //
  1732. // Deallocate the memory passed to the thread.
  1733. //
  1734. MyFree(Phase2Context->pClassDescription);
  1735. MyFree(Phase2Context->pDeviceId);
  1736. MyFree(Phase2Context);
  1737. } else {
  1738. //
  1739. // Should not occur.
  1740. // In this case we do not deallocate the memory passed to the thread, since the thread may be running.
  1741. //
  1742. KeepWaiting = FALSE;
  1743. SetupDebugPrint1( L"SETUP: WaitForSingleObject() returned %d", WaitResult );
  1744. b = FALSE;
  1745. }
  1746. }
  1747. //
  1748. // The thread handle is no longer needed at this point
  1749. //
  1750. CloseHandle(ThreadHandle);
  1751. } else {
  1752. //
  1753. // Unable to create the thread. Just do it syncronously
  1754. //
  1755. Error = GetLastError();
  1756. SetupDebugPrint1( L"SETUP: CreateThread() failed (phase2). Error = %d", Error );
  1757. if( !pPhase2InstallPnpLegacyDevicesThread(Phase2Context) ) {
  1758. //
  1759. // The installation was not successful.
  1760. // There is no need to log the error, since the thread has already done it.
  1761. //
  1762. SetupDebugPrint( L"SETUP: Device not successfully installed (phase2)." );
  1763. b = FALSE;
  1764. }
  1765. //
  1766. // Deallocate the memory that was passed as argument.
  1767. //
  1768. MyFree( Phase2Context->pClassDescription );
  1769. MyFree( Phase2Context->pDeviceId );
  1770. MyFree( Phase2Context );
  1771. }
  1772. }
  1773. //
  1774. // Find out why SetupDiEnumDeviceInfo() failed.
  1775. //
  1776. Error = GetLastError();
  1777. if( Error != ERROR_NO_MORE_ITEMS ) {
  1778. SetupDebugPrint2( L"SETUP: Device = %d, SetupDiEnumDeviceInfo() failed. Error = %d", Index, Error );
  1779. b = FALSE;
  1780. } else {
  1781. if( Index == 0 ) {
  1782. SetupDebugPrint1( L"SETUP: DeviceInfoSet is empty. ClassDescription = %ls", ClassDescription );
  1783. }
  1784. }
  1785. }
  1786. //
  1787. // If the file queue exists, then commit it.
  1788. //
  1789. if( FileQ != INVALID_HANDLE_VALUE ) {
  1790. PVOID Context;
  1791. //
  1792. // Commit file queue
  1793. //
  1794. if(Context = InitSysSetupQueueCallbackEx(hwndParent,
  1795. INVALID_HANDLE_VALUE,
  1796. 0,
  1797. 0,
  1798. NULL)) {
  1799. WCHAR RootPath[ MAX_PATH + 1];
  1800. if(!SetupScanFileQueue(
  1801. FileQ,
  1802. SPQ_SCAN_FILE_VALIDITY |
  1803. SPQ_SCAN_PRUNE_COPY_QUEUE |
  1804. SPQ_SCAN_PRUNE_DELREN,
  1805. hwndParent,
  1806. NULL,
  1807. NULL,
  1808. &ScanQueueResult)) {
  1809. //
  1810. // SetupScanFileQueue should really never
  1811. // fail when you don't ask it to call a
  1812. // callback routine, but if it does, just
  1813. // go ahead and commit the queue.
  1814. //
  1815. ScanQueueResult = 0;
  1816. }
  1817. if( ScanQueueResult != 1 ){
  1818. if( !SetupCommitFileQueue(hwndParent,FileQ,SysSetupQueueCallback,Context) ) {
  1819. b = FALSE;
  1820. }
  1821. }
  1822. TermSysSetupQueueCallback(Context);
  1823. GetWindowsDirectory(RootPath,sizeof(RootPath)/sizeof(WCHAR));
  1824. RootPath[3] = L'\0';
  1825. FlushFilesToDisk( RootPath );
  1826. }
  1827. }
  1828. //
  1829. // Now that the files were already copied, call the class installer
  1830. // with DIF_INSTALLDEVICE so that we can complete the installation
  1831. // of the device.
  1832. //
  1833. for( GuidIndex = GuidLB;
  1834. (
  1835. //
  1836. // Tick the gauge after we finished processing all the devices of a particular class.
  1837. // Note that we don't tick the gauge when GuidIndex == 0 (no device was yet processed),
  1838. // but we do tick the gauge when GuidIndex == GuidCount (all devices of the last class
  1839. // were processed).
  1840. // Note also that we use the flag AlwaysFalse, to enforce that all classes will be processed,
  1841. // even when SendMessage(PBM_SETPBIT) returns a non-zero value.
  1842. //
  1843. (GuidIndex != GuidLB) &&
  1844. SendMessage(ProgressWindow,PBM_STEPIT,0,0) &&
  1845. AlwaysFalse
  1846. ) ||
  1847. (GuidIndex <= GuidUB);
  1848. GuidIndex++ ) {
  1849. SP_DEVINFO_DATA TempDeviceInfoData;
  1850. if( InfoSetArray[ GuidIndex ] == INVALID_HANDLE_VALUE ) {
  1851. continue;
  1852. }
  1853. //
  1854. // REVIEW 2000/11/08 seanch - Old behavior that we don't want to regress.
  1855. // Remove the line below after the network guys fix their class installer
  1856. //
  1857. pSetupStringFromGuid( &GuidList[ GuidIndex ], GUIDString, sizeof( GUIDString ) / sizeof( WCHAR ) );
  1858. TempDeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  1859. for( Index = 0; SetupDiEnumDeviceInfo( InfoSetArray[ GuidIndex ], Index, &TempDeviceInfoData ); Index++ ) {
  1860. WCHAR DevInstId[ MAX_DEVICE_ID_LEN ];
  1861. DWORD InstallDevice;
  1862. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  1863. PPNP_PHASE3_LEGACY_DEV_THREAD_PARAMS Phase3Context;
  1864. //
  1865. // Retrieve the string id for this device
  1866. //
  1867. DevInstId[0] = L'\0';
  1868. if( !SetupDiGetDeviceInstanceId( InfoSetArray[ GuidIndex ],
  1869. &TempDeviceInfoData,
  1870. DevInstId,
  1871. sizeof( DevInstId ) / sizeof( WCHAR ),
  1872. NULL ) ) {
  1873. SetupDebugPrint1( L"SETUP: SetupDiGetDeviceInstanceId() failed. Error = ", GetLastError() );
  1874. }
  1875. //
  1876. // Find out if we need to call DIF_INSTALLDEVICE for this device
  1877. //
  1878. InstallDevice = 0;
  1879. if( !pSetupDiGetDeviceInfoContext( InfoSetArray[ GuidIndex ], &TempDeviceInfoData, &InstallDevice ) ) {
  1880. SetupDebugPrint2( L"SETUP: pSetupDiSetDeviceInfoContext() failed. Error = %lx, DeviceId = %ls ", GetLastError(), DevInstId );
  1881. continue;
  1882. }
  1883. if( !InstallDevice ) {
  1884. //
  1885. // No need to install the device
  1886. //
  1887. SetupDebugPrint1( L"SETUP: Skipping device. DeviceId = %ls ", DevInstId );
  1888. continue;
  1889. }
  1890. #ifndef DBG
  1891. //
  1892. // Find out if this device is marked as a bad device
  1893. //
  1894. LoggedDescription[0] = L'\0';
  1895. if( (GetPrivateProfileString( szLegacyClassesSection,
  1896. DevInstId,
  1897. L"",
  1898. LoggedDescription,
  1899. sizeof(LoggedDescription)/sizeof(WCHAR),
  1900. PnpLogPath ) != 0) &&
  1901. ( wcslen( LoggedDescription ) != 0 )
  1902. ) {
  1903. //
  1904. // Skip the installation of this device
  1905. //
  1906. SetupDebugPrint1( L"SETUP: Skipping installation of legacy device: %ls", DevInstId );
  1907. continue;
  1908. }
  1909. #endif
  1910. //
  1911. // Retrieve information about the driver node selected above.
  1912. //
  1913. DriverInfoData.cbSize = sizeof( SP_DRVINFO_DATA );
  1914. if( !SetupDiGetSelectedDriver( InfoSetArray[ GuidIndex ],
  1915. &TempDeviceInfoData,
  1916. &DriverInfoData ) ) {
  1917. SetupDebugPrint1( L"SETUP: SetupDiGetSelectedDriver() failed. Error = %d", GetLastError() );
  1918. b = FALSE;
  1919. continue;
  1920. }
  1921. //
  1922. // Retrieve syssetup PnP flags (if any) the INF specifies for this
  1923. // device.
  1924. //
  1925. PnPFlags = SyssetupGetPnPFlags(InfoSetArray[ GuidIndex ],
  1926. &TempDeviceInfoData,
  1927. &DriverInfoData
  1928. );
  1929. SetupDebugPrint3( L"SETUP: Installing device: %ls, GuidIndex = %d, Index = %d", DevInstId, GuidIndex, Index );
  1930. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  1931. if(!SetupDiGetDeviceInstallParams(InfoSetArray[ GuidIndex ], &TempDeviceInfoData, &DeviceInstallParams)) {
  1932. SetupDebugPrint1( L"SETUP: SetupDiGetDeviceInstallParams() failed. Error = %d", GetLastError() );
  1933. b = FALSE;
  1934. continue;
  1935. }
  1936. DeviceInstallParams.Flags &= ~DI_FORCECOPY;
  1937. DeviceInstallParams.Flags &= ~DI_NOVCP;
  1938. DeviceInstallParams.Flags |= DI_NOFILECOPY;
  1939. DeviceInstallParams.FileQueue = NULL;
  1940. if(PnPFlags & PNPFLAG_DONOTCALLCONFIGMG) {
  1941. //
  1942. // We _do not_ honor this flag for devices reported via
  1943. // DIF_FIRSTTIMESETUP. The intent of this flag is to
  1944. // prevent us from perturbing correctly-functioning devices
  1945. // and potentially causing problems (e.g., moving PCI
  1946. // bridges or COM ports off of their boot configs). This
  1947. // concern does not apply to legacy-detected devnodes. We
  1948. // definitely _do_ want to bring these devices on-line now,
  1949. // or else devices attached to them (whether PnP or legacy)
  1950. // won't be found and installed.
  1951. //
  1952. SetupDebugPrint( L"SETUP: Clearing PNPFLAG_DONOTCALLCONFIGMG since this is a detected device." );
  1953. PnPFlags &= ~PNPFLAG_DONOTCALLCONFIGMG;
  1954. }
  1955. if(!SetupDiSetDeviceInstallParams(InfoSetArray[ GuidIndex ], &TempDeviceInfoData, &DeviceInstallParams)) {
  1956. SetupDebugPrint1( L"SETUP: SetupDiSetDeviceInstallParams() failed. Error = %d", GetLastError() );
  1957. b = FALSE;
  1958. continue;
  1959. }
  1960. Phase3Context = MyMalloc( sizeof( PNP_PHASE3_LEGACY_DEV_THREAD_PARAMS ) );
  1961. Phase3Context->hDevInfo = InfoSetArray[ GuidIndex ];
  1962. Phase3Context->DeviceInfoData = TempDeviceInfoData;
  1963. Phase3Context->pDeviceId = pSetupDuplicateString( DevInstId );
  1964. Phase3Context->DevicesInstalledStringTable = DevicesInstalledStringTable;
  1965. ThreadHandle = NULL;
  1966. ThreadHandle = CreateThread( NULL,
  1967. 0,
  1968. pPhase3InstallPnpLegacyDevicesThread,
  1969. Phase3Context,
  1970. 0,
  1971. &ThreadId );
  1972. if( ThreadHandle ) {
  1973. DWORD WaitResult;
  1974. DWORD ExitCode;
  1975. BOOL KeepWaiting;
  1976. KeepWaiting = TRUE;
  1977. while( KeepWaiting ) {
  1978. //
  1979. // REVIEW 2000/11/08 seanch - Old behavior that we don't want to regress.
  1980. // Fix the network timeout after the network guys fix their class installer
  1981. //
  1982. WaitResult = WaitForSingleObject( ThreadHandle,
  1983. (_wcsicmp( GUIDString, BB_NETWORK_GUID_STRING ) == 0)? BB_PNP_NETWORK_TIMEOUT :
  1984. PNP_LEGACY_PHASE3_TIMEOUT );
  1985. if( WaitResult == WAIT_TIMEOUT ) {
  1986. int Result;
  1987. HANDLE hDialogEvent;
  1988. if( hDialogEvent = OpenEvent( EVENT_MODIFY_STATE, FALSE, SETUP_HAS_OPEN_DIALOG_EVENT ) ) {
  1989. //
  1990. // Setupapi is prompting the user for a file. Don't timeout.
  1991. //
  1992. CloseHandle( hDialogEvent );
  1993. KeepWaiting = TRUE;
  1994. continue;
  1995. } else {
  1996. }
  1997. //
  1998. // Class installer is hung
  1999. //
  2000. SetupDebugPrint1( L"SETUP: Class Installer appears to be hung (phase3). DeviceId = %ls", DevInstId );
  2001. #ifdef PRERELEASE
  2002. //
  2003. // Ask the user if he wants to skip the installation of this class of devices
  2004. //
  2005. if( !Unattended ) {
  2006. Result = MessageBoxFromMessage( hwndParent,
  2007. MSG_CLASS_INSTALLER_HUNG,
  2008. NULL,
  2009. IDS_WINNT_SETUP,
  2010. MB_YESNO | MB_ICONWARNING,
  2011. DevInstId );
  2012. } else {
  2013. Result = IDYES;
  2014. }
  2015. #else
  2016. Result = IDYES;
  2017. #endif
  2018. if(Result == IDYES) {
  2019. //
  2020. // User wants to skip this device.
  2021. // First find out if the thread has already returned.
  2022. //
  2023. WaitResult = WaitForSingleObject( ThreadHandle, 0 );
  2024. if( WaitResult != WAIT_OBJECT_0 ) {
  2025. //
  2026. // Thread hasn't returned yet. Skip the installation of this device
  2027. //
  2028. KeepWaiting = FALSE;
  2029. SetupDebugPrint1( L"SETUP: Skipping installation of legacy device (phase3). Device = %ls", DevInstId );
  2030. b = FALSE;
  2031. if( !SetupDiGetClassDescription( &GuidList[ GuidIndex ],
  2032. LoggedDescription,
  2033. sizeof(LoggedDescription)/sizeof(WCHAR),
  2034. NULL ) ) {
  2035. SetupDebugPrint1( L"SETUP: SetupDiGetClassDescription() failed. Error = %lx", GetLastError() );
  2036. //
  2037. // Assume anything for class description, since we don't really care about it,
  2038. // for logging purposes. The class description only helps identify the problematic
  2039. // device.
  2040. //
  2041. StringCchCopy( LoggedDescription,
  2042. sizeof(LoggedDescription)/sizeof(WCHAR),
  2043. L"1" );
  2044. }
  2045. //
  2046. // Remember this device so that it won't be installed if GUI setup is
  2047. // restarted
  2048. //
  2049. WritePrivateProfileString( szLegacyDevSection,
  2050. DevInstId,
  2051. LoggedDescription,
  2052. PnpLogPath );
  2053. } else{
  2054. //
  2055. // Thread has already returned.
  2056. // There is no need to skip the installation of this device.
  2057. // We assume that the user decided not to skip the installation of this device,
  2058. // and next call to WaitForSingleObject will immediately return.
  2059. //
  2060. }
  2061. }
  2062. } else if( WaitResult == WAIT_OBJECT_0 ) {
  2063. //
  2064. // Device Installation Thread completed.
  2065. // Find out the outcome of this phase of the installation.
  2066. //
  2067. KeepWaiting = FALSE;
  2068. if( GetExitCodeThread( ThreadHandle, &ExitCode ) ) {
  2069. if( !ExitCode ) {
  2070. //
  2071. // The installation was not successful.
  2072. // There is no need to log the error, since the thread has already done it.
  2073. //
  2074. b = FALSE;
  2075. }
  2076. } else {
  2077. //
  2078. // Unable to retrieve exit code. Assume success.
  2079. //
  2080. SetupDebugPrint1( L"SETUP: GetExitCode() failed. Error = %d", GetLastError() );
  2081. SetupDebugPrint( L"SETUP: Unable to retrieve thread exit code. Assuming device successfully installed (phase3)." );
  2082. }
  2083. MyFree(Phase3Context->pDeviceId);
  2084. MyFree(Phase3Context);
  2085. } else {
  2086. //
  2087. // Should not occur
  2088. //
  2089. KeepWaiting = FALSE;
  2090. SetupDebugPrint1( L"SETUP: WaitForSingleObject() returned %d", WaitResult );
  2091. b = FALSE;
  2092. }
  2093. }
  2094. //
  2095. // The thread handle is no longer needed at this point
  2096. //
  2097. CloseHandle(ThreadHandle);
  2098. } else {
  2099. //
  2100. // Unable to create the thread. Just do it syncronously.
  2101. //
  2102. Error = GetLastError();
  2103. SetupDebugPrint1( L"SETUP: CreateThread() failed (phase3). Error = %d", Error );
  2104. if( !pPhase3InstallPnpLegacyDevicesThread(Phase3Context) ) {
  2105. //
  2106. // The installation was not successful.
  2107. // There is no need to log the error, since the thread has already done it.
  2108. //
  2109. b = FALSE;
  2110. }
  2111. MyFree( Phase3Context->pDeviceId );
  2112. MyFree( Phase3Context );
  2113. }
  2114. }
  2115. Error = GetLastError();
  2116. if( Error != ERROR_NO_MORE_ITEMS ) {
  2117. SetupDebugPrint2( L"SETUP: Device = %d, SetupDiEnumDeviceInfo() failed. Error = %d", Index, Error );
  2118. b = FALSE;
  2119. }
  2120. }
  2121. //
  2122. // Get rid of the file queue, if it exists
  2123. //
  2124. if( FileQ != INVALID_HANDLE_VALUE) {
  2125. SetupCloseFileQueue(FileQ);
  2126. }
  2127. }
  2128. //
  2129. // Make sure that at this point, the gauge area is filled up to the end of
  2130. // the area reserved for the installation of legacy devices.
  2131. //
  2132. SendMessage(ProgressWindow,PBM_SETPOS,GaugeRange*StopAtPercent/100,0);
  2133. //
  2134. // Get rid of the list of GUIDs.
  2135. //
  2136. if( GuidList != NULL ) {
  2137. MyFree( GuidList );
  2138. }
  2139. //
  2140. // Get rid of InfoSetArray, and all info sets stored on it.
  2141. //
  2142. if( InfoSetArray != NULL ) {
  2143. for( GuidIndex = 0; GuidIndex < GuidCount; GuidIndex++ ) {
  2144. if( InfoSetArray[ GuidIndex ] != INVALID_HANDLE_VALUE ) {
  2145. SetupDiDestroyDeviceInfoList( InfoSetArray[ GuidIndex ] );
  2146. }
  2147. }
  2148. MyFree( InfoSetArray );
  2149. }
  2150. SetupDebugPrint( L"SETUP: Leaving InstallLegacyDevices()" );
  2151. return( b );
  2152. }
  2153. BOOL
  2154. InstallEnumeratedDevices(
  2155. IN HWND hwndParent,
  2156. IN HINF InfHandle,
  2157. IN HWND ProgressWindow,
  2158. IN ULONG StartAtPercent,
  2159. IN ULONG StopAtPercent,
  2160. IN PVOID DevicesInstalledStringTable OPTIONAL
  2161. )
  2162. /*++
  2163. Routine Description:
  2164. This function enumerates and install all new PnP devices detected during
  2165. GUI setup.
  2166. Arguments:
  2167. hwndParent - Handle to a top level window that may be used for UI purposes.
  2168. InfHandle - System setup inf handle (syssetup.inf).
  2169. ProgressWindow -
  2170. StartAtPercent -
  2171. StopAtPercent -
  2172. DevicesInstalledStringTable - If present, every device that is successfully
  2173. installed should have their device instance
  2174. Id added to the string table.
  2175. Return Value:
  2176. Returns TRUE if all enumerated hardware were installed successfully.
  2177. --*/
  2178. {
  2179. HANDLE hPipeEvent = NULL;
  2180. HANDLE hPipe = INVALID_HANDLE_VALUE;
  2181. ULONG Index = 0;
  2182. ULONG Error;
  2183. ULONG ulSize = 0;
  2184. HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
  2185. WCHAR szBuffer[MAX_PATH];
  2186. BOOL b = TRUE;
  2187. UINT GaugeRange = 100;
  2188. WCHAR RootPath[ MAX_PATH + 1];
  2189. WCHAR PnpLogPath[ MAX_PATH + 1];
  2190. PAF_DRIVERS AfDrivers;
  2191. PAF_DRIVER_ATTRIBS SelectedAfDriver;
  2192. PSP_DEVINFO_DATA pDeviceInfoData = NULL;
  2193. ULONG PnPFlags;
  2194. HANDLE hBatchEvent = NULL;
  2195. DWORD Result;
  2196. SetupDebugPrint( L"SETUP: Entering InstallEnumeratedDevices()" );
  2197. //
  2198. // Build path to pnp log file
  2199. //
  2200. Result = GetWindowsDirectory( PnpLogPath, sizeof(PnpLogPath)/sizeof(WCHAR) );
  2201. if( Result == 0) {
  2202. MYASSERT(FALSE);
  2203. return FALSE;
  2204. }
  2205. if (!pSetupConcatenatePaths( PnpLogPath,
  2206. szPnpLogFile,
  2207. sizeof(PnpLogPath)/sizeof(WCHAR),
  2208. NULL )) {
  2209. MYASSERT(FALSE);
  2210. return FALSE;
  2211. }
  2212. //
  2213. // Initialize RootPath with empty string
  2214. //
  2215. RootPath[0] = L'\0';
  2216. //
  2217. // Initialize answer file table
  2218. //
  2219. AfDrivers = CreateAfDriverTable();
  2220. //
  2221. // Attempt to create the event that will be used to signal the successfull
  2222. // creation of the named pipe
  2223. //
  2224. hPipeEvent = CreateEvent( NULL, TRUE, FALSE, PNP_CREATE_PIPE_EVENT );
  2225. if (hPipeEvent == NULL) {
  2226. Error = GetLastError();
  2227. if( Error != ERROR_ALREADY_EXISTS ) {
  2228. SetupDebugPrint1( L"SETUP: CreateEvent() failed. Error = %d", Error );
  2229. b = FALSE;
  2230. goto Clean0;
  2231. }
  2232. //
  2233. // If umpnpmgr has already created the event, then just open the event
  2234. //
  2235. hPipeEvent = OpenEvent(EVENT_MODIFY_STATE,
  2236. FALSE,
  2237. PNP_CREATE_PIPE_EVENT);
  2238. if (hPipeEvent == NULL) {
  2239. SetupDebugPrint1( L"SETUP: OpenEvent() failed. Error = %d", GetLastError() );
  2240. b = FALSE;
  2241. goto Clean0;
  2242. }
  2243. }
  2244. //
  2245. // Attempt to create the event that will be used to signal the completion of
  2246. // processing of the last batch of devices.
  2247. //
  2248. hBatchEvent = CreateEvent( NULL, TRUE, FALSE, PNP_BATCH_PROCESSED_EVENT );
  2249. if (hBatchEvent == NULL) {
  2250. Error = GetLastError();
  2251. if( Error != ERROR_ALREADY_EXISTS ) {
  2252. SetupDebugPrint1( L"SETUP: CreateEvent() failed. Error = %d", Error );
  2253. b = FALSE;
  2254. goto Clean0;
  2255. }
  2256. //
  2257. // If umpnpmgr has already created the event, then just open the event
  2258. //
  2259. hBatchEvent = OpenEvent(EVENT_MODIFY_STATE,
  2260. FALSE,
  2261. PNP_BATCH_PROCESSED_EVENT);
  2262. if (hBatchEvent == NULL) {
  2263. SetupDebugPrint1( L"SETUP: OpenEvent() failed. Error = %d", GetLastError() );
  2264. b = FALSE;
  2265. goto Clean0;
  2266. }
  2267. }
  2268. //
  2269. // create the named pipe, umpnpmgr will write requests to
  2270. // this pipe if new hardware is found
  2271. //
  2272. hPipe = CreateNamedPipe(PNP_NEW_HW_PIPE,
  2273. PIPE_ACCESS_INBOUND,
  2274. PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
  2275. 1, // only one connection
  2276. sizeof(szBuffer), // out buffer size
  2277. sizeof(szBuffer), // in buffer size
  2278. PNP_PIPE_TIMEOUT, // default timeout
  2279. NULL // default security
  2280. );
  2281. //
  2282. // signal the event now
  2283. //
  2284. SetEvent(hPipeEvent);
  2285. if (hPipe == INVALID_HANDLE_VALUE) {
  2286. SetupDebugPrint1( L"SETUP: CreateNamedPipe() failed. Error = %d", GetLastError() );
  2287. b = FALSE;
  2288. goto Clean0;
  2289. }
  2290. //
  2291. // Connect to the newly created named pipe.
  2292. // If umpnpmgr is not already connected to the named pipe, then ConnectNamedPipe()
  2293. // will succeed. Otherwise, it will fail with ERROR_PIPE_CONNECTED. Note however that
  2294. // this is not an error condition.
  2295. //
  2296. if (ConnectNamedPipe(hPipe, NULL) ||
  2297. ((Error = GetLastError()) == ERROR_PIPE_CONNECTED) ) {
  2298. //
  2299. // REVIEW 2000/11/08 seanch - Old behavior that we don't want to regress.
  2300. // This is gauge related and needs to be fixed.
  2301. // We are assuming a total of 50 enumerated device.
  2302. //
  2303. BOOL AlwaysFalse = FALSE;
  2304. UINT BogusValue = 50;
  2305. //
  2306. // Initialize the gauge
  2307. // REVIEW 2000/11/08 seanch - Old behavior that we don't want to regress.
  2308. // Fix this - We are assuming a fixed number of devices
  2309. //
  2310. GaugeRange = (BogusValue*100/(StopAtPercent-StartAtPercent));
  2311. SendMessage(ProgressWindow, WMX_PROGRESSTICKS, BogusValue, 0);
  2312. SendMessage(ProgressWindow,PBM_SETRANGE,0,MAKELPARAM(0,GaugeRange));
  2313. SendMessage(ProgressWindow,PBM_SETPOS,GaugeRange*StartAtPercent/100,0);
  2314. SendMessage(ProgressWindow,PBM_SETSTEP,1,0);
  2315. //
  2316. // listen to the named pipe by submitting read
  2317. // requests until the named pipe is broken on the
  2318. // other end.
  2319. //
  2320. for( Index = 0;
  2321. //
  2322. // REVIEW 2000/11/08 seanch - Old behavior that we don't want to regress.
  2323. // This is gauge related and needs to be fixed.
  2324. // We are assuming a constant number of enumerated devices
  2325. //
  2326. ( (Index != 0) &&
  2327. (Index < BogusValue) &&
  2328. SendMessage(ProgressWindow,PBM_STEPIT,0,0) &&
  2329. AlwaysFalse
  2330. ) || // This is a trick to force the gauge to be upgraded after a
  2331. // device is processed, and the pipe to be read.
  2332. ReadFile( hPipe,
  2333. (LPBYTE)szBuffer, // device instance id
  2334. sizeof(szBuffer),
  2335. &ulSize,
  2336. NULL );
  2337. Index++ ) {
  2338. SP_DRVINFO_DATA DriverInfoData;
  2339. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  2340. WCHAR GUIDString[ 64 ];
  2341. WCHAR ClassDescription[ LINE_LEN + 1 ];
  2342. HANDLE ThreadHandle = NULL;
  2343. DWORD ThreadId;
  2344. PPNP_ENUM_DEV_THREAD_PARAMS Context;
  2345. BOOL DeviceInstalled;
  2346. WCHAR LoggedDescription[ LINE_LEN + 1 ];
  2347. BOOL bOemF6Driver;
  2348. if (lstrlen(szBuffer) == 0) {
  2349. SetEvent(hBatchEvent);
  2350. continue;
  2351. }
  2352. SetupDebugPrint2( L"SETUP: Index = %d, DeviceId = %ls", Index, szBuffer );
  2353. //
  2354. // Check if this device is listed as a bad device
  2355. //
  2356. LoggedDescription[0] = L'\0';
  2357. if( (GetPrivateProfileString( szEnumDevSection,
  2358. szBuffer,
  2359. L"",
  2360. LoggedDescription,
  2361. sizeof(LoggedDescription)/sizeof(WCHAR),
  2362. PnpLogPath ) != 0) &&
  2363. ( wcslen( LoggedDescription ) != 0 )
  2364. ) {
  2365. #ifndef DBG
  2366. //
  2367. // Skip the installation of this device
  2368. //
  2369. SetupDebugPrint1( L"SETUP: Skipping installation of device %ls", szBuffer );
  2370. continue;
  2371. #endif
  2372. }
  2373. BEGIN_SECTION(LoggedDescription);
  2374. //
  2375. // Find out if we need to create an hDevinfo.
  2376. // We will need to create one if this is the first device that we are installing (Index == 0),
  2377. // or the class installer for the previous device (Index == Index - 1) is hung. If the class
  2378. // installer is hung then we cannot use the same hDevinfo, since the class installer has a lock
  2379. // on it. So we just create a new one.
  2380. // If the class installer for the previous device didn't hang, then there is no need to create
  2381. // a new hDevinfo, since we can re-use it. We do this for performance reasons.
  2382. //
  2383. if( hDevInfo == INVALID_HANDLE_VALUE ) {
  2384. //
  2385. // create a devinfo handle and device info data set to
  2386. // pass to DevInstall
  2387. //
  2388. if((hDevInfo = SetupDiCreateDeviceInfoList(NULL, hwndParent))
  2389. == INVALID_HANDLE_VALUE) {
  2390. b = FALSE;
  2391. SetupDebugPrint1( L"SETUP: SetupDiCreateDeviceInfoList() failed. Error = %d", GetLastError() );
  2392. goto Clean0;
  2393. }
  2394. pDeviceInfoData = MyMalloc(sizeof(SP_DEVINFO_DATA));
  2395. if( pDeviceInfoData == NULL ) {
  2396. b = FALSE;
  2397. SetupDebugPrint( L"SETUP: Unable to create pDeviceInfoData. MyMalloc() failed." );
  2398. goto Clean0;
  2399. }
  2400. pDeviceInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
  2401. }
  2402. if(!SetupDiOpenDeviceInfo(hDevInfo, szBuffer, hwndParent, 0, pDeviceInfoData)) {
  2403. SetupDebugPrint1( L"SETUP: SetupDiOpenDeviceInfo() failed. Error = %d", GetLastError() );
  2404. b = FALSE;
  2405. END_SECTION(LoggedDescription);
  2406. continue;
  2407. }
  2408. //
  2409. // Answer file support: Test the answer file to see if it has a driver
  2410. // in its [DeviceDrivers] section. This overrides the NT-supplied driver,
  2411. // if one exists.
  2412. //
  2413. if (!SyssetupInstallAnswerFileDriver (
  2414. AfDrivers,
  2415. hDevInfo,
  2416. pDeviceInfoData,
  2417. &SelectedAfDriver
  2418. )) {
  2419. //
  2420. // No answer file driver, proceed with the standard device install
  2421. //
  2422. SetupDebugPrint( L"SETUP: Device was NOT installed via answer file driver" );
  2423. //
  2424. // Build a list of compatible drivers for this device
  2425. // (This call can be time consuming the first time it is called)
  2426. //
  2427. if( !SetupDiBuildDriverInfoList( hDevInfo, pDeviceInfoData, SPDIT_COMPATDRIVER ) ) {
  2428. SetupDebugPrint1( L"SETUP: SetupDiBuildDriverInfoList() failed. Error = %d", GetLastError() );
  2429. b = FALSE;
  2430. continue;
  2431. }
  2432. //
  2433. // Select the best compatible driver for this device.
  2434. //
  2435. if( !SelectBestDriver( hDevInfo,
  2436. pDeviceInfoData,
  2437. &bOemF6Driver ) ) {
  2438. Error = GetLastError();
  2439. if( Error != ERROR_NO_COMPAT_DRIVERS ) {
  2440. SetupDebugPrint1( L"SETUP: SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV) failed. Error = %d", Error );
  2441. b = FALSE;
  2442. END_SECTION(LoggedDescription);
  2443. continue;
  2444. }
  2445. SetupDebugPrint( L"SETUP: Compatible driver List is empty" );
  2446. SetupDebugPrint( L"SETUP: Installing the null driver for this device" );
  2447. //
  2448. // Install the null driver for this device.
  2449. // This is to avoid the "Found New Hardware" popup when the
  2450. // user first logs on after the system is installed.
  2451. //
  2452. if( !SyssetupInstallNullDriver( hDevInfo, pDeviceInfoData, DevicesInstalledStringTable ) ) {
  2453. SetupDebugPrint( L"SETUP: Unable to install null driver" );
  2454. }
  2455. END_SECTION(LoggedDescription);
  2456. continue;
  2457. }
  2458. //
  2459. // Check if we need to rebuild the driver list without including the
  2460. // old Internet drivers.
  2461. //
  2462. if (RebuildListWithoutOldInternetDrivers(hDevInfo, pDeviceInfoData)) {
  2463. SetupDiDestroyDriverInfoList( hDevInfo, pDeviceInfoData, SPDIT_COMPATDRIVER );
  2464. //
  2465. // OR in the DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS flag so that we don't include
  2466. // old internet drivers in the list that build.
  2467. //
  2468. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  2469. if (SetupDiGetDeviceInstallParams(hDevInfo,
  2470. pDeviceInfoData,
  2471. &DeviceInstallParams
  2472. ))
  2473. {
  2474. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS;
  2475. SetupDiSetDeviceInstallParams(hDevInfo,
  2476. pDeviceInfoData,
  2477. &DeviceInstallParams
  2478. );
  2479. }
  2480. //
  2481. // Build a list of compatible drivers for this device
  2482. // (This call can be time consuming the first time it is called)
  2483. //
  2484. if( !SetupDiBuildDriverInfoList( hDevInfo, pDeviceInfoData, SPDIT_COMPATDRIVER ) ) {
  2485. SetupDebugPrint1( L"SETUP: SetupDiBuildDriverInfoList() failed. Error = %d", GetLastError() );
  2486. b = FALSE;
  2487. continue;
  2488. }
  2489. //
  2490. // Select the best compatible driver for this device.
  2491. //
  2492. if( !SelectBestDriver( hDevInfo,
  2493. pDeviceInfoData,
  2494. &bOemF6Driver ) ) {
  2495. Error = GetLastError();
  2496. if( Error != ERROR_NO_COMPAT_DRIVERS ) {
  2497. SetupDebugPrint1( L"SETUP: SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV) failed. Error = %d", Error );
  2498. b = FALSE;
  2499. END_SECTION(LoggedDescription);
  2500. continue;
  2501. }
  2502. SetupDebugPrint( L"SETUP: Compatible driver List is empty" );
  2503. SetupDebugPrint( L"SETUP: Installing the null driver for this device" );
  2504. //
  2505. // Install the null driver for this device.
  2506. // This is to avoid the "Found New Hardware" popup when the
  2507. // user first logs on after the system is installed.
  2508. //
  2509. if( !SyssetupInstallNullDriver( hDevInfo, pDeviceInfoData, DevicesInstalledStringTable ) ) {
  2510. SetupDebugPrint( L"SETUP: Unable to install null driver" );
  2511. }
  2512. END_SECTION(LoggedDescription);
  2513. continue;
  2514. }
  2515. }
  2516. } else {
  2517. SetupDebugPrint( L"SETUP: Device was installed via answer file driver" );
  2518. }
  2519. //
  2520. // Retrieve information about the driver node selected above.
  2521. //
  2522. DriverInfoData.cbSize = sizeof( SP_DRVINFO_DATA );
  2523. if( !SetupDiGetSelectedDriver( hDevInfo,
  2524. pDeviceInfoData,
  2525. &DriverInfoData ) ) {
  2526. SetupDebugPrint1( L"SETUP: SetupDiGetSelectedDriver() failed. Error = %d", GetLastError() );
  2527. b = FALSE;
  2528. continue;
  2529. }
  2530. //
  2531. // Get the GUID string for this device
  2532. //
  2533. GUIDString[0] = (WCHAR)'\0';
  2534. pSetupStringFromGuid( &(pDeviceInfoData->ClassGuid), GUIDString, sizeof( GUIDString ) / sizeof( WCHAR ) );
  2535. SetupDebugPrint1( L"SETUP: DriverType = %lx", DriverInfoData.DriverType );
  2536. SetupDebugPrint1( L"SETUP: Description = %ls", &(DriverInfoData.Description[0]) );
  2537. SetupDebugPrint1( L"SETUP: MfgName = %ls", &(DriverInfoData.MfgName[0]) );
  2538. SetupDebugPrint1( L"SETUP: ProviderName = %ls", &(DriverInfoData.ProviderName[0]) );
  2539. SetupDebugPrint1( L"SETUP: GUID = %ls", GUIDString );
  2540. ClassDescription[0] = (WCHAR)'\0';
  2541. if( !SetupDiGetClassDescription( &(pDeviceInfoData->ClassGuid),
  2542. ClassDescription,
  2543. sizeof(ClassDescription)/sizeof(WCHAR),
  2544. NULL ) ) {
  2545. SetupDebugPrint1( L"SETUP: SetupDiGetClassDescription() failed. Error = %lx", GetLastError() );
  2546. ClassDescription[0] = (WCHAR)'\0';
  2547. }
  2548. SetupDebugPrint1( L"SETUP: DeviceClass = %ls", ClassDescription );
  2549. //
  2550. // Retrieve syssetup PnP flags (if any) the INF specifies for this
  2551. // device.
  2552. //
  2553. PnPFlags = SyssetupGetPnPFlags(hDevInfo, pDeviceInfoData, &DriverInfoData);
  2554. if( SkipDeviceInstallation( hDevInfo,
  2555. pDeviceInfoData,
  2556. InfHandle,
  2557. GUIDString ) ) {
  2558. SetupDebugPrint( L"SETUP: Skipping installation of this device" );
  2559. END_SECTION(LoggedDescription);
  2560. continue;
  2561. }
  2562. //
  2563. // If the PnP flag was set that said we shouldn't call ConfigMgr
  2564. // for this device, then set the appropriate flag in the device's
  2565. // install params.
  2566. //
  2567. if(PnPFlags & PNPFLAG_DONOTCALLCONFIGMG) {
  2568. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  2569. if( !SetupDiGetDeviceInstallParams( hDevInfo,
  2570. pDeviceInfoData,
  2571. &DeviceInstallParams ) ) {
  2572. Error = GetLastError();
  2573. if( ((LONG)Error) < 0 ) {
  2574. //
  2575. // Setupapi error code, display it in hex
  2576. //
  2577. SetupDebugPrint1( L"SETUP: SetupDiGetDeviceInstallParams() failed. Error = %lx", Error );
  2578. } else {
  2579. //
  2580. // win32 error code, display it in decimal
  2581. //
  2582. SetupDebugPrint1( L"SETUP: SetupDiGetDeviceInstallParams() failed. Error = %d", Error );
  2583. }
  2584. } else {
  2585. DeviceInstallParams.Flags |= DI_DONOTCALLCONFIGMG;
  2586. if( !SetupDiSetDeviceInstallParams( hDevInfo,
  2587. pDeviceInfoData,
  2588. &DeviceInstallParams ) ) {
  2589. Error = GetLastError();
  2590. if( ((LONG)Error) < 0 ) {
  2591. //
  2592. // Setupapi error code, display it in hex
  2593. //
  2594. SetupDebugPrint1( L"SETUP: SetupDiSetDeviceInstallParams() failed. Error = %lx", Error );
  2595. } else {
  2596. //
  2597. // win32 error code, display it in decimal
  2598. //
  2599. SetupDebugPrint1( L"SETUP: SetupDiSetDeviceInstallParams() failed. Error = %d", Error );
  2600. }
  2601. }
  2602. }
  2603. }
  2604. //
  2605. // Start the thread that actually does the installation of the device
  2606. //
  2607. Context = MyMalloc( sizeof(PNP_ENUM_DEV_THREAD_PARAMS) );
  2608. Context->hDevInfo = hDevInfo;
  2609. Context->DeviceInfoData = *pDeviceInfoData;
  2610. Context->pDeviceDescription = pSetupDuplicateString(&(DriverInfoData.Description[0]));
  2611. Context->pDeviceId = pSetupDuplicateString(szBuffer);
  2612. Context->DevicesInstalledStringTable = DevicesInstalledStringTable;
  2613. DeviceInstalled = FALSE;
  2614. ThreadHandle = CreateThread( NULL,
  2615. 0,
  2616. pInstallPnpEnumeratedDeviceThread,
  2617. Context,
  2618. 0,
  2619. &ThreadId );
  2620. if(ThreadHandle) {
  2621. DWORD WaitResult;
  2622. DWORD ExitCode;
  2623. BOOL KeepWaiting;
  2624. KeepWaiting = TRUE;
  2625. while( KeepWaiting ) {
  2626. //
  2627. // REVIEW 2000/11/08 seanch - Old behavior that we don't want to regress.
  2628. // Fix the network timeout after the network guys fix their class installer
  2629. //
  2630. WaitResult = WaitForSingleObject( ThreadHandle,
  2631. (_wcsicmp( GUIDString, BB_NETWORK_GUID_STRING ) == 0)? BB_PNP_NETWORK_TIMEOUT :
  2632. PNP_ENUM_TIMEOUT );
  2633. if( WaitResult == WAIT_TIMEOUT ) {
  2634. int Result;
  2635. HANDLE hDialogEvent;
  2636. if( hDialogEvent = OpenEvent( EVENT_MODIFY_STATE, FALSE, SETUP_HAS_OPEN_DIALOG_EVENT ) ) {
  2637. //
  2638. // Setupapi is prompting the user for a file. Don't timeout.
  2639. //
  2640. CloseHandle( hDialogEvent );
  2641. KeepWaiting = TRUE;
  2642. continue;
  2643. }
  2644. //
  2645. // Class installer is hung
  2646. //
  2647. SetupDebugPrint1( L"SETUP: Class Installer appears to be hung. Device = %ls", &(DriverInfoData.Description[0]) );
  2648. #ifdef PRERELEASE
  2649. //
  2650. // Ask the user if he wants to skip the installation of this device.
  2651. //
  2652. if( !Unattended ) {
  2653. Result = MessageBoxFromMessage( hwndParent,
  2654. MSG_CLASS_INSTALLER_HUNG,
  2655. NULL,
  2656. IDS_WINNT_SETUP,
  2657. MB_YESNO | MB_ICONWARNING,
  2658. &(DriverInfoData.Description[0]) );
  2659. } else {
  2660. Result = IDYES;
  2661. }
  2662. #else
  2663. Result = IDYES;
  2664. #endif
  2665. if(Result == IDYES) {
  2666. //
  2667. // User wants to skip this device.
  2668. // First find out if the thread has already returned.
  2669. //
  2670. WaitResult = WaitForSingleObject( ThreadHandle, 0 );
  2671. if( WaitResult != WAIT_OBJECT_0 ) {
  2672. //
  2673. // Thread hasn't returned yet. Skip the installation of this device.
  2674. //
  2675. KeepWaiting = FALSE;
  2676. SetupDebugPrint1( L"SETUP: Skipping installation of enumerated device. Device = %ls", &(DriverInfoData.Description[0]) );
  2677. b = FALSE;
  2678. //
  2679. // Remember this device so that it won't be installed if GUI setup is
  2680. // restarted
  2681. //
  2682. WritePrivateProfileString( szEnumDevSection,
  2683. szBuffer,
  2684. &(DriverInfoData.Description[0]),
  2685. PnpLogPath );
  2686. //
  2687. // Since the class installer is hung, we cannot re-use the hDevInfo that was passed
  2688. // to the class installer. So we just ignore this one. We will create a new one for
  2689. // the next device to be installed.
  2690. //
  2691. hDevInfo = INVALID_HANDLE_VALUE;
  2692. pDeviceInfoData = NULL;
  2693. } else{
  2694. //
  2695. // Thread has already returned.
  2696. // There is no need to skip the installation of this device.
  2697. // We assume that the user decided not to skip the installation of this device,
  2698. // and next call to WaitForSingleObject will immediately return.
  2699. //
  2700. }
  2701. }
  2702. } else if( WaitResult == WAIT_OBJECT_0 ) {
  2703. //
  2704. // Device Installation Thread completed.
  2705. //
  2706. KeepWaiting = FALSE;
  2707. //
  2708. // Deallocate memory passed to the thread.
  2709. //
  2710. MyFree( Context->pDeviceDescription );
  2711. MyFree( Context->pDeviceId );
  2712. MyFree( Context );
  2713. if( GetExitCodeThread( ThreadHandle, &ExitCode ) ) {
  2714. if( ExitCode == ERROR_SUCCESS ) {
  2715. //
  2716. // The installation was successful
  2717. //
  2718. DeviceInstalled = TRUE;
  2719. SetupDebugPrint( L"SETUP: Device successfully installed." );
  2720. } else {
  2721. //
  2722. // The installation was not successful.
  2723. // There is no need to log the error, since the thread has already done it.
  2724. //
  2725. SetupDebugPrint( L"SETUP: Device not successfully installed." );
  2726. b = FALSE;
  2727. }
  2728. } else {
  2729. //
  2730. // Unable to retrieve exit code. Assume success.
  2731. //
  2732. SetupDebugPrint1( L"SETUP: GetExitCode() failed. Error = %d", GetLastError() );
  2733. SetupDebugPrint( L"SETUP: Unable to retrieve thread exit code. Assuming device successfully installed." );
  2734. }
  2735. } else {
  2736. //
  2737. // Should not occur
  2738. //
  2739. KeepWaiting = FALSE;
  2740. SetupDebugPrint1( L"SETUP: WaitForSingleObject() returned %d", WaitResult );
  2741. // MyFree( Context->pDeviceDescription );
  2742. // MyFree( Context->pDeviceId );
  2743. // MyFree( Context );
  2744. b = FALSE;
  2745. }
  2746. }
  2747. //
  2748. // The thread handle is no longer needed.
  2749. //
  2750. CloseHandle(ThreadHandle);
  2751. } else {
  2752. //
  2753. // Just do it synchronously.
  2754. //
  2755. SetupDebugPrint1( L"SETUP: CreateThread() failed (enumerated device). Error = %d", GetLastError() );
  2756. if( pInstallPnpEnumeratedDeviceThread(Context) != ERROR_SUCCESS ) {
  2757. //
  2758. // The installation was not successful.
  2759. // There is no need to log the error, since the thread has already done it.
  2760. //
  2761. SetupDebugPrint( L"SETUP: Device not successfully installed." );
  2762. b = FALSE;
  2763. } else {
  2764. DeviceInstalled = TRUE;
  2765. }
  2766. MyFree( Context->pDeviceDescription );
  2767. MyFree( Context->pDeviceId );
  2768. MyFree( Context );
  2769. }
  2770. if( DeviceInstalled ) {
  2771. //
  2772. // If this device came from the answer file, then change the original
  2773. // media path from the local temp dir to the original path (typically
  2774. // the floppy drive).
  2775. //
  2776. if (SelectedAfDriver) {
  2777. SyssetupFixAnswerFileDriverPath (
  2778. SelectedAfDriver,
  2779. hDevInfo,
  2780. pDeviceInfoData
  2781. );
  2782. }
  2783. //
  2784. // If the driver we just installed was an Oem F6 driver then
  2785. // we need to add it to the list of files that SfcInitProt
  2786. // will leave alone during its scan.
  2787. //
  2788. if (bOemF6Driver) {
  2789. AddOemF6DriversToSfcIgnoreFilesList(hDevInfo, pDeviceInfoData);
  2790. }
  2791. }
  2792. END_SECTION(LoggedDescription);
  2793. }
  2794. //
  2795. // Find out why we stopped reading the pipe. If it was because the connetion
  2796. // to the pipe was broken by umpnp, then there was nothing else to read from
  2797. // the pipe. Otherwise, there was an error condition.
  2798. //
  2799. if( ( Error = GetLastError() ) != ERROR_BROKEN_PIPE ) {
  2800. SetupDebugPrint1( L"SETUP: ReadFile( hPipe ) failed. Error = %d", GetLastError() );
  2801. b = FALSE;
  2802. goto Clean0;
  2803. }
  2804. } else {
  2805. SetupDebugPrint1( L"SETUP: ConnectNamedPipe() failed. Error = %d", GetLastError() );
  2806. b = FALSE;
  2807. goto Clean0;
  2808. }
  2809. Clean0:
  2810. BEGIN_SECTION(L"InstallEnumeratedDevices cleanup");
  2811. //
  2812. // Make sure that at this point the gauge is filled up to the end of the
  2813. // region reserved for the installation of the enumerated devices.
  2814. //
  2815. SendMessage(ProgressWindow,PBM_SETPOS,GaugeRange*StopAtPercent/100,0);
  2816. if (hPipe != INVALID_HANDLE_VALUE) {
  2817. DisconnectNamedPipe(hPipe);
  2818. CloseHandle(hPipe);
  2819. }
  2820. if (hPipeEvent != NULL) {
  2821. CloseHandle(hPipeEvent);
  2822. }
  2823. if (hBatchEvent != NULL) {
  2824. CloseHandle(hBatchEvent);
  2825. }
  2826. if( hDevInfo != INVALID_HANDLE_VALUE ) {
  2827. SetupDiDestroyDeviceInfoList( hDevInfo );
  2828. }
  2829. DestroyAfDriverTable (AfDrivers);
  2830. if( pDeviceInfoData != NULL ) {
  2831. MyFree( pDeviceInfoData );
  2832. }
  2833. SetupDebugPrint( L"SETUP: Leaving InstallEnumeratedDevices()" );
  2834. END_SECTION(L"InstallEnumeratedDevices cleanup");
  2835. return( b );
  2836. }
  2837. DWORD
  2838. pInstallPnpDevicesThread(
  2839. PPNP_THREAD_PARAMS ThreadParams
  2840. )
  2841. /*++
  2842. Routine Description:
  2843. This is the thread that does the installation of the PnP devices.
  2844. Arguments:
  2845. ThreadParams - Points to a structure that contains the information
  2846. passed to this thread.
  2847. Return Value:
  2848. Returnd TRUE if the operation succeeds, or FALSE otherwise.
  2849. --*/
  2850. {
  2851. BOOL b;
  2852. PPNP_THREAD_PARAMS Context;
  2853. ULONG StartAtPercent;
  2854. ULONG StopAtPercent;
  2855. ULONG DeltaPercent;
  2856. PVOID DevicesInstalledStringTable = NULL;
  2857. Context = ThreadParams;
  2858. //
  2859. // Assume success.
  2860. //
  2861. b = TRUE;
  2862. //
  2863. // We don't want SetupAPI to do any RunOnce calls, as we'll do it manually
  2864. //
  2865. pSetupSetGlobalFlags(pSetupGetGlobalFlags()|PSPGF_NO_RUNONCE);
  2866. //
  2867. // Initialize some variables that are related to the progress bar.
  2868. // We divide the progress window area reserved for pnp installation in 3 regions
  2869. // of equal size, and they will be used in the following steps:
  2870. // . Pre-compilation of infs
  2871. // . Installation of enumerated devices
  2872. // . Installation of legacy devices
  2873. // . Installation of enumerated devices that may have appeared after the installation of legacy devices
  2874. //
  2875. DeltaPercent = (Context->ProgressWindowStopAtPercent - Context->ProgressWindowStartAtPercent) / 4;
  2876. StartAtPercent = Context->ProgressWindowStartAtPercent;
  2877. StopAtPercent = Context->ProgressWindowStartAtPercent + DeltaPercent;
  2878. //
  2879. // Pre-compile inf files
  2880. //
  2881. //
  2882. // Before we can start precompiling inf files, let's "seed" the INF
  2883. // directory with any OEM-supplied INFs that need to be present during
  2884. // detection. This should be really quick and doesn't require the
  2885. // updating the progress window
  2886. //
  2887. RemainingTime = CalcTimeRemaining(Phase_PrecompileInfs);
  2888. SetRemainingTime(RemainingTime);
  2889. BEGIN_SECTION(L"Installing OEM infs");
  2890. InstallOEMInfs();
  2891. //
  2892. // Add migrated drivers to the SFC exclusion list
  2893. //
  2894. SfcExcludeMigratedDrivers ();
  2895. END_SECTION(L"Installing OEM infs");
  2896. BEGIN_SECTION(L"Precompiling infs");
  2897. PrecompileInfFiles( Context->ProgressWindow,
  2898. StartAtPercent,
  2899. StopAtPercent );
  2900. END_SECTION(L"Precompiling infs");
  2901. //
  2902. // Initialize a string table that will be used to track which devices have
  2903. // drivers successfully installed.
  2904. //
  2905. DevicesInstalledStringTable = pSetupStringTableInitialize();
  2906. //
  2907. // This operation is very fast, so we don't need to upgrade the progress bar.
  2908. //
  2909. if( !MiniSetup ) {
  2910. BEGIN_SECTION(L"Mark PnP devices for reinstall");
  2911. MarkPnpDevicesAsNeedReinstall(DevicesInstalledStringTable);
  2912. END_SECTION(L"Mark PnP devices for reinstall");
  2913. }
  2914. //
  2915. // Do the migration of legacy devices...at the moment all that PnPInit does
  2916. // is migrate all the device nodes who belong to the vid load order group to
  2917. // be put into the display class. This is the desired result.
  2918. //
  2919. // This is a quick operation and doesn't need to use the progress window.
  2920. //
  2921. PnPInitializationThread(NULL);
  2922. //
  2923. // Do installation of enumerated devices
  2924. //
  2925. StartAtPercent += DeltaPercent;
  2926. StopAtPercent += DeltaPercent;
  2927. RemainingTime = CalcTimeRemaining(Phase_InstallEnumDevices1);
  2928. SetRemainingTime(RemainingTime);
  2929. BEGIN_SECTION(L"Installing enumerated devices");
  2930. b = InstallEnumeratedDevices( Context->Window,
  2931. Context->InfHandle,
  2932. Context->ProgressWindow,
  2933. StartAtPercent,
  2934. StopAtPercent,
  2935. DevicesInstalledStringTable );
  2936. //
  2937. // devices installs may exist in RunOnce entries
  2938. // they are processed as a batch, as opposed to per-device
  2939. // during syssetup
  2940. //
  2941. CallRunOnceAndWait();
  2942. END_SECTION(L"Installing enumerated devices");
  2943. //
  2944. // Do the installation of legacy pnp devices.
  2945. //
  2946. StartAtPercent += DeltaPercent;
  2947. StopAtPercent += DeltaPercent;
  2948. BEGIN_SECTION(L"Installing legacy devices");
  2949. RemainingTime = CalcTimeRemaining(Phase_InstallLegacyDevices);
  2950. SetRemainingTime(RemainingTime);
  2951. b = InstallLegacyDevices( Context->Window,
  2952. Context->ProgressWindow,
  2953. StartAtPercent,
  2954. StopAtPercent,
  2955. DevicesInstalledStringTable ) && b;
  2956. //
  2957. // devices installs may exist in RunOnce entries
  2958. // they are processed as a batch, as opposed to per-device
  2959. // during syssetup
  2960. //
  2961. CallRunOnceAndWait();
  2962. END_SECTION(L"Installing legacy devices");
  2963. // Install the remaining enumerated devices that may have appeared after the
  2964. // installation of the legacy devices.
  2965. // Since this step uses the last region of the progress window,
  2966. // use as StopAtPercent, the value that was passed to this function,
  2967. // instead of the calulated value (by adding DeltaPorcent). This will
  2968. // ensure that at the end of this step, the gauge will be filled up
  2969. // completely. If we use the calculated value, then rounding error
  2970. // can cause the gauge not to be completelly filled up at the end of
  2971. // this step.
  2972. //
  2973. StartAtPercent += DeltaPercent;
  2974. StopAtPercent = Context->ProgressWindowStopAtPercent;
  2975. BEGIN_SECTION(L"Install enumerated devices triggered by legacy devices");
  2976. RemainingTime = CalcTimeRemaining(Phase_InstallEnumDevices2);
  2977. SetRemainingTime(RemainingTime);
  2978. b = InstallEnumeratedDevices( Context->Window,
  2979. Context->InfHandle,
  2980. Context->ProgressWindow,
  2981. StartAtPercent,
  2982. StopAtPercent,
  2983. DevicesInstalledStringTable ) && b;
  2984. //
  2985. // devices installs may exist in RunOnce entries
  2986. // they are processed as a batch, as opposed to per-device
  2987. // during syssetup
  2988. //
  2989. // since we will not be calling RunOnce again after this
  2990. // allow devices to call RunOnce immediately
  2991. // (other device install threads may be still running)
  2992. //
  2993. pSetupSetGlobalFlags(pSetupGetGlobalFlags()&~PSPGF_NO_RUNONCE);
  2994. CallRunOnceAndWait();
  2995. END_SECTION(L"Install enumerated devices triggered by legacy devices");
  2996. //
  2997. // Mark all non-present devices as needing re-install
  2998. // we do this a 2nd time in case a device "disappeared" due to the
  2999. // re-installation of a parent device
  3000. // This operation is very fast, so we don't need to upgrade the progress bar.
  3001. //
  3002. if( !MiniSetup ) {
  3003. MarkPnpDevicesAsNeedReinstall(DevicesInstalledStringTable);
  3004. }
  3005. if (DevicesInstalledStringTable) {
  3006. pSetupStringTableDestroy(DevicesInstalledStringTable);
  3007. }
  3008. if( Context->SendWmQuit ) {
  3009. ULONG Error = ERROR_SUCCESS;
  3010. //
  3011. // We send WM_QUIT only if this routine was started as a separate thread.
  3012. // Otherwise, the WM_QUIT will be processed by the wizard, and it will make it stop.
  3013. //
  3014. do {
  3015. if( !PostThreadMessage(Context->ThreadId,WM_QUIT,b,0) ) {
  3016. Error = GetLastError();
  3017. SetupDebugPrint1( L"SETUP: PostThreadMessage(WM_QUIT) failed. Error = %d", Error );
  3018. }
  3019. } while ( Error != ERROR_SUCCESS );
  3020. }
  3021. return( b );
  3022. }
  3023. BOOL
  3024. InstallPnpDevices(
  3025. IN HWND hwndParent,
  3026. IN HINF InfHandle,
  3027. IN HWND ProgressWindow,
  3028. IN ULONG StartAtPercent,
  3029. IN ULONG StopAtPercent
  3030. )
  3031. /*++
  3032. Routine Description:
  3033. This function creates and starts the thread responsible for installation of
  3034. PnP devices.
  3035. Arguments:
  3036. hwndParent - Handle to a top level window that may be used for UI purposes
  3037. InfHandle - System setup inf handle (syssetup.inf).
  3038. ProgressWindow - Handle to the progress bar.
  3039. StartAtPercent - Starting position in the progress bar.
  3040. It indicates that from position 0 to this position
  3041. the gauge is already filled.
  3042. StopAtPercent - Ending position of the progress bar.
  3043. The pnp thread should not fill the progress bar beyond
  3044. this position
  3045. Return Value:
  3046. Returns TRUE if all the PnP devices installed successfully.
  3047. --*/
  3048. {
  3049. BOOL Success = TRUE;
  3050. DWORD ThreadId;
  3051. HANDLE ThreadHandle = NULL;
  3052. PNP_THREAD_PARAMS Context;
  3053. MSG msg;
  3054. Context.ThreadId = GetCurrentThreadId();
  3055. Context.Window = hwndParent;
  3056. Context.ProgressWindow = ProgressWindow;
  3057. Context.InfHandle = InfHandle;
  3058. Context.ProgressWindowStartAtPercent = StartAtPercent;
  3059. Context.ProgressWindowStopAtPercent = StopAtPercent;
  3060. Context.SendWmQuit = TRUE;
  3061. ThreadHandle = CreateThread(
  3062. NULL,
  3063. 0,
  3064. pInstallPnpDevicesThread,
  3065. &Context,
  3066. 0,
  3067. &ThreadId
  3068. );
  3069. if(ThreadHandle) {
  3070. CloseHandle(ThreadHandle);
  3071. //
  3072. // Pump the message queue and wait for the thread to finish.
  3073. //
  3074. do {
  3075. GetMessage(&msg,NULL,0,0);
  3076. if(msg.message != WM_QUIT) {
  3077. DispatchMessage(&msg);
  3078. }
  3079. } while(msg.message != WM_QUIT);
  3080. Success = (BOOL)msg.wParam;
  3081. } else {
  3082. //
  3083. // Just do it synchronously.
  3084. //
  3085. Context.SendWmQuit = FALSE;
  3086. Success = pInstallPnpDevicesThread(&Context);
  3087. }
  3088. return(Success);
  3089. }
  3090. BOOL
  3091. UpdatePnpDeviceDrivers(
  3092. )
  3093. /*++
  3094. Routine Description:
  3095. This function goes through all the installed devices and makes sure
  3096. it has the latest and greatest driver.
  3097. Arguments:
  3098. Return Value:
  3099. Returns TRUE if there are no fatal errors.
  3100. --*/
  3101. {
  3102. BOOL bRet = FALSE;
  3103. HINSTANCE hInstNewDev;
  3104. ExternalUpdateDriverForPlugAndPlayDevicesW pUpdateDriverForPlugAndPlayDevicesW = NULL;
  3105. HDEVINFO DeviceInfoSet;
  3106. //
  3107. // We need the "UpdateDriverForPlugAndPlayDevices" function from newdev.dll.
  3108. //
  3109. if ( NULL == (hInstNewDev = LoadLibrary(L"newdev.dll")) )
  3110. {
  3111. SetupDebugPrint1(L"SETUP: Failed to load newdev.dll. Error = %d", GetLastError());
  3112. return bRet;
  3113. }
  3114. pUpdateDriverForPlugAndPlayDevicesW =
  3115. (ExternalUpdateDriverForPlugAndPlayDevicesW) GetProcAddress(hInstNewDev, "UpdateDriverForPlugAndPlayDevicesW");
  3116. if ( NULL == pUpdateDriverForPlugAndPlayDevicesW )
  3117. {
  3118. SetupDebugPrint1(L"SETUP: Failed to get UpdateDriverForPlugAndPlayDevicesW. Error = %d", GetLastError());
  3119. }
  3120. //
  3121. // Create a device information set that will be the container for
  3122. // the device interfaces.
  3123. //
  3124. else if ( INVALID_HANDLE_VALUE == (DeviceInfoSet = SetupDiCreateDeviceInfoList(NULL, NULL)) )
  3125. {
  3126. SetupDebugPrint1(L"SETUP: Failed SetupDiCreateDeviceInfoList(). Error = %d", GetLastError());
  3127. }
  3128. else
  3129. {
  3130. HDEVINFO NewDeviceInfoSet;
  3131. //
  3132. // Get the list of all present devices.
  3133. //
  3134. NewDeviceInfoSet = SetupDiGetClassDevsEx(NULL,
  3135. NULL,
  3136. NULL,
  3137. DIGCF_ALLCLASSES | DIGCF_PRESENT,
  3138. DeviceInfoSet,
  3139. NULL,
  3140. NULL);
  3141. if ( INVALID_HANDLE_VALUE == NewDeviceInfoSet )
  3142. {
  3143. SetupDebugPrint1(L"SETUP: Failed SetupDiGetClassDevsEx(). Error = %d", GetLastError());
  3144. }
  3145. else
  3146. {
  3147. SP_DEVINFO_DATA DeviceInfoData;
  3148. DWORD dwDevice;
  3149. //
  3150. // Once we get this far, the default return is TRUE.
  3151. //
  3152. bRet = TRUE;
  3153. //
  3154. // Setup the device info data structutre.
  3155. //
  3156. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  3157. //
  3158. // Loop through all the devices.
  3159. //
  3160. for ( dwDevice = 0; SetupDiEnumDeviceInfo(NewDeviceInfoSet, dwDevice, &DeviceInfoData); dwDevice++ )
  3161. {
  3162. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  3163. SP_DRVINFO_DATA NewDriverInfoData;
  3164. PSP_DRVINFO_DETAIL_DATA pNewDriverInfoDetailData = NULL;
  3165. DWORD cbBytesNeeded = 0;
  3166. TCHAR szDeviceID[MAX_DEVICE_ID_LEN];
  3167. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  3168. NewDriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  3169. if ( SetupDiGetDeviceInstallParams(NewDeviceInfoSet,
  3170. &DeviceInfoData,
  3171. &DeviceInstallParams) )
  3172. {
  3173. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS;
  3174. SetupDiSetDeviceInstallParams(NewDeviceInfoSet,
  3175. &DeviceInfoData,
  3176. &DeviceInstallParams);
  3177. }
  3178. //
  3179. // Build the list of possible drivers for this device.
  3180. // Select the best compatible driver for this device.
  3181. // Retrieve information about the driver node selected above.
  3182. // Get driver info details.
  3183. //
  3184. if ( ( SetupDiBuildDriverInfoList(NewDeviceInfoSet,
  3185. &DeviceInfoData,
  3186. SPDIT_COMPATDRIVER ) ) &&
  3187. ( SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV,
  3188. NewDeviceInfoSet,
  3189. &DeviceInfoData ) ) &&
  3190. ( SetupDiGetSelectedDriver(NewDeviceInfoSet,
  3191. &DeviceInfoData,
  3192. &NewDriverInfoData ) ) &&
  3193. ( ( SetupDiGetDriverInfoDetail(NewDeviceInfoSet,
  3194. &DeviceInfoData,
  3195. &NewDriverInfoData,
  3196. NULL,
  3197. 0,
  3198. &cbBytesNeeded) ) ||
  3199. ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) ) &&
  3200. ( cbBytesNeeded ) &&
  3201. ( pNewDriverInfoDetailData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBytesNeeded) ) &&
  3202. ( 0 != (pNewDriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA)) ) &&
  3203. ( SetupDiGetDriverInfoDetail(NewDeviceInfoSet,
  3204. &DeviceInfoData,
  3205. &NewDriverInfoData,
  3206. pNewDriverInfoDetailData,
  3207. cbBytesNeeded,
  3208. NULL) ) &&
  3209. ( SetupDiGetDeviceRegistryProperty(NewDeviceInfoSet,
  3210. &DeviceInfoData,
  3211. SPDRP_HARDWAREID,
  3212. NULL,
  3213. (LPBYTE) szDeviceID,
  3214. sizeof(szDeviceID),
  3215. NULL) ) )
  3216. {
  3217. HKEY hDevRegKey;
  3218. BOOL bUpdate = TRUE,
  3219. bRebootFlag;
  3220. //
  3221. // Get the device's regkey, so that we can get the
  3222. // version of the currently installed driver.
  3223. //
  3224. if ( INVALID_HANDLE_VALUE != (hDevRegKey = SetupDiOpenDevRegKey(NewDeviceInfoSet,
  3225. &DeviceInfoData,
  3226. DICS_FLAG_GLOBAL,
  3227. 0,
  3228. DIREG_DRV,
  3229. KEY_READ)) )
  3230. {
  3231. TCHAR szInfPath[MAX_PATH],
  3232. szInfName[MAX_PATH];
  3233. DWORD dwSize = sizeof(szInfName),
  3234. dwType;
  3235. szInfPath[0] = L'\0';
  3236. GetSystemWindowsDirectory(szInfPath, sizeof(szInfPath) / sizeof(TCHAR));
  3237. if ( ( szInfPath[0] ) &&
  3238. ( pSetupConcatenatePaths(szInfPath,
  3239. L"INF",
  3240. sizeof(szInfPath) / sizeof(TCHAR),
  3241. NULL) ) &&
  3242. ( ERROR_SUCCESS == RegQueryValueEx(hDevRegKey,
  3243. REGSTR_VAL_INFPATH,
  3244. NULL,
  3245. &dwType,
  3246. (LPBYTE) &szInfName,
  3247. &dwSize) ) &&
  3248. ( pSetupConcatenatePaths(szInfPath,
  3249. szInfName,
  3250. sizeof(szInfPath) / sizeof(TCHAR),
  3251. NULL) ) &&
  3252. ( CSTR_EQUAL == CompareString(LOCALE_SYSTEM_DEFAULT,
  3253. NORM_IGNORECASE,
  3254. pNewDriverInfoDetailData->InfFileName,
  3255. -1,
  3256. szInfPath,
  3257. -1) ) )
  3258. {
  3259. //
  3260. // The inf we found is already in the %windir%\inf folder and is already
  3261. // installed. So we don't want to install this inf again.
  3262. //
  3263. bUpdate = FALSE;
  3264. }
  3265. //
  3266. // Make sure we close the key.
  3267. //
  3268. RegCloseKey(hDevRegKey);
  3269. }
  3270. //
  3271. // Check to see if we have the possibility of a better driver and
  3272. // try to install it if we do.
  3273. //
  3274. if ( bUpdate &&
  3275. !pUpdateDriverForPlugAndPlayDevicesW(NULL,
  3276. szDeviceID,
  3277. pNewDriverInfoDetailData->InfFileName,
  3278. 0,
  3279. &bRebootFlag) )
  3280. {
  3281. SetupDebugPrint1(L"SETUP: Failed to install updated driver. Error = %d", GetLastError());
  3282. bRet = FALSE;
  3283. }
  3284. }
  3285. //
  3286. // Free this if allocated.
  3287. //
  3288. if ( pNewDriverInfoDetailData )
  3289. {
  3290. HeapFree(GetProcessHeap(), 0, pNewDriverInfoDetailData);
  3291. }
  3292. }
  3293. //
  3294. // Make sure we clean up the list.
  3295. //
  3296. SetupDiDestroyDeviceInfoList(NewDeviceInfoSet);
  3297. }
  3298. //
  3299. // Make sure we clean up the list.
  3300. //
  3301. SetupDiDestroyDeviceInfoList(DeviceInfoSet);
  3302. }
  3303. FreeLibrary(hInstNewDev);
  3304. return bRet;
  3305. }
  3306. VOID
  3307. SortClassGuidListForDetection(
  3308. IN OUT LPGUID GuidList,
  3309. IN ULONG GuidCount,
  3310. OUT PULONG LastBatchedDetect
  3311. )
  3312. /*++
  3313. Routine Description:
  3314. This routine sorts the supplied list of GUID based on a (partial)
  3315. ordering specified in the [DetectionOrder] and [NonBatchedDetection]
  3316. sections of syssetup.inf. This allows us to maintain a detection
  3317. ordering similar to previous versions of NT, and also to allow for
  3318. class installers that may depend upon the successful installation of
  3319. devices detected by other class installers.
  3320. Arguments:
  3321. GuidList - address of the array of GUIDs to be sorted.
  3322. GuidCount - the number of GUIDs in the array. This number must be > 0.
  3323. LastBatchedDetect - Supplies the address of a variable that will
  3324. receive the index of the last GUID in the array that may be batched
  3325. together (i.e., all detections are run, all files queued into one
  3326. big queue, etc.). Any GUIDs existing at higher indices must be
  3327. processed individually, and such processing will happen _after_ the
  3328. batched detection is completed.
  3329. Return Value:
  3330. none.
  3331. --*/
  3332. {
  3333. LONG LineCount, LineIndex, GuidIndex, NextTopmost;
  3334. PCWSTR CurGuidString;
  3335. INFCONTEXT InfContext;
  3336. GUID CurGuid;
  3337. MYASSERT(GuidCount > 0);
  3338. *LastBatchedDetect = GuidCount - 1;
  3339. //
  3340. // First, sort the classes in syssetup.inf's [DetectionOrder] list to the
  3341. // front...
  3342. //
  3343. LineCount = SetupGetLineCount(SyssetupInf, L"DetectionOrder");
  3344. NextTopmost = 0;
  3345. for(LineIndex = 0; LineIndex < LineCount; LineIndex++) {
  3346. if(!SetupGetLineByIndex(SyssetupInf, L"DetectionOrder", LineIndex, &InfContext) ||
  3347. ((CurGuidString = pSetupGetField(&InfContext, 1)) == NULL) ||
  3348. (pSetupGuidFromString(CurGuidString, &CurGuid) != NO_ERROR)) {
  3349. continue;
  3350. }
  3351. //
  3352. // Search through the GUID list looking for this GUID. If found, move the GUID from
  3353. // it's current position to the next topmost position.
  3354. //
  3355. for(GuidIndex = 0; GuidIndex < (LONG)GuidCount; GuidIndex++) {
  3356. if(IsEqualGUID(&CurGuid, &(GuidList[GuidIndex]))) {
  3357. if(NextTopmost != GuidIndex) {
  3358. //
  3359. // We should never be moving the GUID _down_ the list.
  3360. //
  3361. MYASSERT(NextTopmost < GuidIndex);
  3362. MoveMemory(&(GuidList[NextTopmost + 1]),
  3363. &(GuidList[NextTopmost]),
  3364. (GuidIndex - NextTopmost) * sizeof(GUID)
  3365. );
  3366. CopyMemory(&(GuidList[NextTopmost]),
  3367. &CurGuid,
  3368. sizeof(GUID)
  3369. );
  3370. }
  3371. NextTopmost++;
  3372. break;
  3373. }
  3374. }
  3375. }
  3376. //
  3377. // Now, move any classes in syssetup.inf's [NonBatchedDetection] list to
  3378. // the end...
  3379. //
  3380. LineCount = SetupGetLineCount(SyssetupInf, L"NonBatchedDetection");
  3381. for(LineIndex = 0; LineIndex < LineCount; LineIndex++) {
  3382. if(!SetupGetLineByIndex(SyssetupInf, L"NonBatchedDetection", LineIndex, &InfContext) ||
  3383. ((CurGuidString = pSetupGetField(&InfContext, 1)) == NULL) ||
  3384. (pSetupGuidFromString(CurGuidString, &CurGuid) != NO_ERROR)) {
  3385. continue;
  3386. }
  3387. //
  3388. // Search through the GUID list looking for this GUID. If found, move
  3389. // the GUID from it's current position to the end of the list.
  3390. //
  3391. for(GuidIndex = 0; GuidIndex < (LONG)GuidCount; GuidIndex++) {
  3392. if(IsEqualGUID(&CurGuid, &(GuidList[GuidIndex]))) {
  3393. //
  3394. // We found a non-batched class--decrement our index that
  3395. // points to the last batched detection class.
  3396. //
  3397. (*LastBatchedDetect)--;
  3398. //
  3399. // Now shift all the GUIDs after this one up, and move this one
  3400. // to the last position in the array (unless, of course, it was
  3401. // already at the last position in the array).
  3402. //
  3403. if(GuidIndex < (LONG)(GuidCount - 1)) {
  3404. MoveMemory(&(GuidList[GuidIndex]),
  3405. &(GuidList[GuidIndex+1]),
  3406. (GuidCount - (GuidIndex+1)) * sizeof(GUID)
  3407. );
  3408. CopyMemory(&(GuidList[GuidCount-1]),
  3409. &CurGuid,
  3410. sizeof(GUID)
  3411. );
  3412. }
  3413. break;
  3414. }
  3415. }
  3416. }
  3417. }
  3418. DWORD
  3419. pPhase1InstallPnpLegacyDevicesThread(
  3420. PPNP_PHASE1_LEGACY_DEV_THREAD_PARAMS ThreadParams
  3421. )
  3422. /*++
  3423. Routine Description:
  3424. This thread does the initial part of the installation installation
  3425. of legacy Pnp devices of a particular class.
  3426. It invokes a class installer of a particular class with:
  3427. - DIF_FIRSTTIMESETUP
  3428. If it successds, it returns in the structure passed as argument
  3429. a device info list that contains the detected legacy devices.
  3430. Arguments:
  3431. ThreadParams - Points to a structure that contains the information
  3432. passed to this thread.
  3433. Return Value:
  3434. Returns a Win32 error code.
  3435. --*/
  3436. {
  3437. PPNP_PHASE1_LEGACY_DEV_THREAD_PARAMS Context;
  3438. LPGUID pGuid;
  3439. PWSTR pClassDescription;
  3440. HDEVINFO hEmptyDevInfo;
  3441. ULONG Error;
  3442. //
  3443. // Initialize variables
  3444. //
  3445. Context = ThreadParams;
  3446. Context->hDevInfo = INVALID_HANDLE_VALUE;
  3447. pGuid = &(Context->Guid);
  3448. pClassDescription = Context->pClassDescription;
  3449. //
  3450. // Assume success
  3451. //
  3452. Error = ERROR_SUCCESS;
  3453. //
  3454. // DIF_FIRSTTIME
  3455. //
  3456. if((hEmptyDevInfo = SetupDiCreateDeviceInfoList(pGuid,
  3457. Context->hwndParent))
  3458. == INVALID_HANDLE_VALUE) {
  3459. Error = GetLastError();
  3460. SetupDebugPrint2( L"SETUP: SetupDiCreateDeviceInfoList() failed (phase1). Error = %d, ClassDescription = %ls", Error, pClassDescription );
  3461. goto phase1_legacy_dev_thread_exit;
  3462. }
  3463. if( !SetupDiCallClassInstaller( DIF_FIRSTTIMESETUP,
  3464. hEmptyDevInfo,
  3465. NULL ) ) {
  3466. Error = GetLastError();
  3467. if( Error != ERROR_DI_DO_DEFAULT ) {
  3468. SetupDebugPrint2( L"SETUP: SetupDiCallClassInstaller(DIF_FIRSTTIMESETUP) failed (phase1). Error = %lx, ClassDescription = %ls", Error, pClassDescription );
  3469. } else {
  3470. SetupDebugPrint2( L"SETUP: SetupDiCallClassInstaller(DIF_FIRSTTIMESETUP) failed (phase1). Error = %lx, ClassDescription = %ls", Error, pClassDescription );
  3471. }
  3472. SetupDiDestroyDeviceInfoList(hEmptyDevInfo);
  3473. goto phase1_legacy_dev_thread_exit;
  3474. }
  3475. //
  3476. // Save the info set after DIF_FIRSTTIMESETUP
  3477. //
  3478. Context->hDevInfo = hEmptyDevInfo;
  3479. SetupDebugPrint1( L"SETUP: SetupDiCallClassInstaller(DIF_FIRSTTIMESETUP) succeeded (phase1). ClassDescription = %ls", pClassDescription );
  3480. phase1_legacy_dev_thread_exit:
  3481. return(Error);
  3482. }
  3483. DWORD
  3484. pPhase2InstallPnpLegacyDevicesThread(
  3485. PPNP_PHASE2_LEGACY_DEV_THREAD_PARAMS ThreadParams
  3486. )
  3487. /*++
  3488. Routine Description:
  3489. This thread does a partial installation of a legacy device.
  3490. It invokes a class installer with:
  3491. - DIF_REGISTERDEVICE
  3492. - DIF_ALLOW_INSTALL
  3493. - DIF_INSTALLDEVICEFILES
  3494. Note that the call with DIF_INSTALLDEVICEFILES only queue the files on the queue
  3495. created by the parent of this handle.
  3496. Arguments:
  3497. ThreadParams - Points to a structure that contains the information
  3498. passed to this thread.
  3499. Return Value:
  3500. Returns TRUE is all calls to the class installer were successfull.
  3501. Otherwise, returns FALSE.
  3502. --*/
  3503. {
  3504. PPNP_PHASE2_LEGACY_DEV_THREAD_PARAMS Context;
  3505. HDEVINFO hDevInfo;
  3506. HSPFILEQ FileQ;
  3507. HSPFILEQ TempFileQ = INVALID_HANDLE_VALUE;
  3508. PSP_DEVINFO_DATA pDeviceInfoData;
  3509. PWSTR pClassDescription;
  3510. PWSTR pDeviceId;
  3511. BOOL b;
  3512. ULONG Error;
  3513. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  3514. DWORD ScanQueueResult;
  3515. //
  3516. // Initialize variables
  3517. //
  3518. Context = ThreadParams;
  3519. hDevInfo = Context->hDevInfo;
  3520. FileQ = Context->FileQ;
  3521. pDeviceInfoData = &(Context->DeviceInfoData);
  3522. pClassDescription = Context->pClassDescription;
  3523. pDeviceId = Context->pDeviceId;
  3524. //
  3525. // Assume success
  3526. //
  3527. Error = ERROR_SUCCESS;
  3528. b = TRUE;
  3529. //
  3530. // Let the class installer/co-installers know they should be quiet.
  3531. //
  3532. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  3533. if(!SetupDiGetDeviceInstallParams(hDevInfo, pDeviceInfoData, &DeviceInstallParams)) {
  3534. SetupDebugPrint2( L"SETUP: SetupDiGetDeviceInstallParams() failed (phase2). Error = %d, DeviceId = %ls", GetLastError(), pDeviceId );
  3535. b = FALSE;
  3536. goto phase2_legacy_dev_thread_exit;
  3537. }
  3538. DeviceInstallParams.Flags |= DI_QUIETINSTALL;
  3539. if(!SetupDiSetDeviceInstallParams(hDevInfo, pDeviceInfoData, &DeviceInstallParams)) {
  3540. SetupDebugPrint2( L"SETUP: SetupDiSetDeviceInstallParams() failed (phase2). Error = %d, DeviceId = %ls", GetLastError(), pDeviceId );
  3541. b = FALSE;
  3542. goto phase2_legacy_dev_thread_exit;
  3543. }
  3544. //
  3545. // Register the device
  3546. //
  3547. if( !SetupDiCallClassInstaller( DIF_REGISTERDEVICE,
  3548. hDevInfo,
  3549. pDeviceInfoData ) ) {
  3550. SetupDebugPrint2( L"SETUP: SetupDiCallClassInstaller(DIF_REGISTERDEVICE) failed (phase2). Error = %lx, DeviceId = %ls", GetLastError(), pDeviceId );
  3551. b = FALSE;
  3552. goto phase2_legacy_dev_thread_exit;
  3553. }
  3554. //
  3555. // Verify with the class installer and class-specific co-installers that the
  3556. // driver we're about to install isn't blacklisted.
  3557. //
  3558. if( !SetupDiCallClassInstaller( DIF_ALLOW_INSTALL,
  3559. hDevInfo,
  3560. pDeviceInfoData ) ) {
  3561. Error = GetLastError();
  3562. if( Error != ERROR_DI_DO_DEFAULT ) {
  3563. SetupDebugPrint2( L"SETUP: SetupDiCallClassInstaller(DIF_ALLOW_INSTALL) failed (phase2). Error = %d, DeviceId = %ls", Error, pDeviceId );
  3564. b = FALSE;
  3565. goto phase2_legacy_dev_thread_exit;
  3566. }
  3567. }
  3568. //
  3569. // In general, any devices being installed as a result of DIF_FIRSTTIMESETUP
  3570. // will be using in-box drivers, and as such, will be signed. However, it
  3571. // is possible that a built-in class installer will report a detected device
  3572. // that's using a 3rd-party, unsigned driver. The ScsiAdapter class is such
  3573. // a case. If we _do_ encounter unsigned driver packages, we want to avoid
  3574. // media prompting, just like we do when installing PnP-enumerated devices.
  3575. // Unfortunately, this is complicated in the legacy case by the fact that we
  3576. // queue all files into one big queue, then commit the queue in an all-or-
  3577. // nothing fashion. Thus, we don't have the same granularity that we have
  3578. // when installing PnP-enumerated devices in a one-at-a-time fashion.
  3579. //
  3580. // To address this, we will first queue up all files to a "temporary" queue,
  3581. // which we will then examine in a similar fashion to the way we handle the
  3582. // per-device queues for PnP-enumerated devices. If the catalog nodes
  3583. // associated with the queue are all signed, then we'll queue up those same
  3584. // files to our "real" queue. If one or more catalog nodes are not signed,
  3585. // we'll then do a queue scan based on presence checking. If all files
  3586. // required are present, then we'll add nothing to the "real" queue, but
  3587. // allow the device to be subsequently installed. If one or more required
  3588. // files are found to be missing, we're in a bad state, because queueing
  3589. // these files up to our "real" queue means the user will (potentially) see
  3590. // a driver signing warning popup and/or media prompt, either of which they
  3591. // may cancel out of. Since the legacy device install queue is one big
  3592. // queue containing fileops for all such device installs, cancelling its
  3593. // committal would result in none of the files being copied for any phase2
  3594. // install. Thus, multimedia codecs, non-motherboard legacy COM ports, and
  3595. // other (signed) system devices wouldn't get installed. Since this is
  3596. // obviously unacceptable, we instead simply skip installation for this
  3597. // device, just as if DIF_ALLOWINSTALL had failed. This isn't as bad as it
  3598. // sounds, because it would be _exceedingly_ rare if a 3rd-party driver's
  3599. // device were reported, yet all necessary files weren't present.
  3600. //
  3601. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  3602. if(!SetupDiGetDeviceInstallParams(hDevInfo, pDeviceInfoData, &DeviceInstallParams)) {
  3603. SetupDebugPrint2( L"SETUP: SetupDiGetDeviceInstallParams() failed for TempFileQueue (phase2). Error = %d, DeviceId = %ls", GetLastError(), pDeviceId );
  3604. b = FALSE;
  3605. goto phase2_legacy_dev_thread_exit;
  3606. }
  3607. //
  3608. // Note: this code has had the following comment (and behavior) for a _long_
  3609. // time...
  3610. //
  3611. // "we may rely on this flag being set this early"
  3612. //
  3613. // The DI_FORCECOPY flag actually has no effect on any setupapi activity
  3614. // except for installation of class installer files via
  3615. // SetupDiInstallClass(Ex). However, it's possible some class-/co-installer
  3616. // has developed a dependency on its presence, and since it doesn't hurt
  3617. // anything, we'll continue to set it.
  3618. //
  3619. DeviceInstallParams.Flags |= DI_FORCECOPY;
  3620. TempFileQ = SetupOpenFileQueue();
  3621. if(TempFileQ == INVALID_HANDLE_VALUE) {
  3622. SetupDebugPrint2( L"SETUP: SetupOpenFileQueue() failed for TempFileQueue (phase2). Error = %d, DeviceId = %ls", GetLastError(), pDeviceId );
  3623. b = FALSE;
  3624. goto phase2_legacy_dev_thread_exit;
  3625. }
  3626. DeviceInstallParams.Flags |= DI_NOVCP;
  3627. DeviceInstallParams.FileQueue = TempFileQ;
  3628. if(!SetupDiSetDeviceInstallParams(hDevInfo, pDeviceInfoData, &DeviceInstallParams)) {
  3629. SetupDebugPrint2( L"SETUP: SetupDiSetDeviceInstallParams() failed for TempFileQueue (phase2). Error = %d, DeviceId = %ls", GetLastError(), pDeviceId );
  3630. b = FALSE;
  3631. goto phase2_legacy_dev_thread_exit;
  3632. }
  3633. //
  3634. // Queue the device files into our temporary file queue
  3635. //
  3636. if(SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES,
  3637. hDevInfo,
  3638. pDeviceInfoData)) {
  3639. Error = ERROR_SUCCESS;
  3640. } else {
  3641. Error = GetLastError();
  3642. if(Error == ERROR_DI_DO_DEFAULT) {
  3643. //
  3644. // This isn't actually an error
  3645. //
  3646. Error = ERROR_SUCCESS;
  3647. } else {
  3648. SetupDebugPrint2( L"SETUP: SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) failed for TempFileQueue (phase2). Error = %lx, DeviceId = %ls", Error, pDeviceId );
  3649. }
  3650. }
  3651. //
  3652. // Disassociate the temporary file queue from the device information
  3653. // element so that we can free it later...
  3654. //
  3655. DeviceInstallParams.Flags &= ~DI_NOVCP;
  3656. DeviceInstallParams.FileQueue = INVALID_HANDLE_VALUE;
  3657. if(!SetupDiSetDeviceInstallParams(hDevInfo, pDeviceInfoData, &DeviceInstallParams)) {
  3658. SetupDebugPrint2( L"SETUP: SetupDiSetDeviceInstallParams() failed for disassociating TempFileQueue (phase2). Error = %d, DeviceId = %ls", GetLastError(), pDeviceId );
  3659. b = FALSE;
  3660. goto phase2_legacy_dev_thread_exit;
  3661. }
  3662. if(Error == ERROR_SUCCESS) {
  3663. SetupDebugPrint1( L"SETUP: SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) suceeded for TempFileQueue (phase2). DeviceId = %ls", pDeviceId );
  3664. } else {
  3665. b = FALSE;
  3666. goto phase2_legacy_dev_thread_exit;
  3667. }
  3668. //
  3669. // Now that we've retrieved all files operations into our temporary file
  3670. // queue, we can "pre-verify" the catalog nodes in the queue. If an OEM
  3671. // INF in %windir%\Inf is unsigned, we scan the queue to see if all
  3672. // required files are present (although not validated) in their target
  3673. // locations. If we're doing an upgrade, and all files are in-place, we'll
  3674. // forego queue committal. If we're doing a fresh-install, and all files
  3675. // are in-place, we'll commit the empty queue on-the-spot, so that the user
  3676. // will get the driver signing popup (based on policy), thus may
  3677. // potentially abort the installation of this device. If all files aren't
  3678. // already in-place, we silently abort the device installation, as we can't
  3679. // run the risk of queueing up potentially-cancellable fileops to the
  3680. // "real" legacy device install queue.
  3681. //
  3682. if(NO_ERROR != pSetupVerifyQueuedCatalogs(TempFileQ)) {
  3683. //
  3684. // We only want to prune based on presence check for OEM INFs living in
  3685. // %windir%\Inf.
  3686. //
  3687. SP_DRVINFO_DATA DriverInfoData;
  3688. SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
  3689. //
  3690. // Retrieve the name of the INF associated with the selected driver
  3691. // node.
  3692. //
  3693. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  3694. if(!SetupDiGetSelectedDriver(hDevInfo, pDeviceInfoData, &DriverInfoData)) {
  3695. SetupDebugPrint2( L"SETUP: SetupDiGetSelectedDriver() failed. Error = %d, Device = %ls", GetLastError(), pDeviceId );
  3696. b = FALSE;
  3697. goto phase2_legacy_dev_thread_exit;
  3698. }
  3699. DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  3700. if(!SetupDiGetDriverInfoDetail(hDevInfo,
  3701. pDeviceInfoData,
  3702. &DriverInfoData,
  3703. &DriverInfoDetailData,
  3704. sizeof(DriverInfoDetailData),
  3705. NULL) &&
  3706. (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
  3707. SetupDebugPrint2( L"SETUP: SetupDiGetDriverInfoDetail() failed. Error = %d, Device = %ls", GetLastError(), pDeviceId );
  3708. b = FALSE;
  3709. goto phase2_legacy_dev_thread_exit;
  3710. }
  3711. if(pSetupInfIsFromOemLocation(DriverInfoDetailData.InfFileName, TRUE) ||
  3712. IsInfInLayoutInf(DriverInfoDetailData.InfFileName)) {
  3713. //
  3714. // Either the INF lives somewhere other than %windir%\Inf, or its
  3715. // an in-box unsigned INF. In either case, we want to
  3716. // abort installation of this device, otherwise we risk having the
  3717. // user cancel the queue committal, and wipe out all the other
  3718. // detected device installs as well.
  3719. //
  3720. SetupDebugPrint2( L"SETUP: Skipping unsigned driver install for detected device (phase2). DeviceId = %ls, Inf = %ls", pDeviceId, DriverInfoDetailData.InfFileName );
  3721. b = FALSE;
  3722. goto phase2_legacy_dev_thread_exit;
  3723. } else {
  3724. //
  3725. // Note: it doesn't really matter whether we do an "all-or-nothing"
  3726. // scan or a pruning scan here, because we're going to abort the
  3727. // install on anything other than a fully empty (post-scan) queue.
  3728. // We request pruning here, because that fits better with the
  3729. // semantics of SPQ_SCAN_PRUNE_DELREN (this flag's semantics
  3730. // don't really fit with a non-pruning scan, as discussed in RAID
  3731. // #280543).
  3732. //
  3733. if(!SetupScanFileQueue(TempFileQ,
  3734. SPQ_SCAN_FILE_PRESENCE |
  3735. SPQ_SCAN_PRUNE_COPY_QUEUE |
  3736. SPQ_SCAN_PRUNE_DELREN,
  3737. NULL,
  3738. NULL,
  3739. NULL,
  3740. &ScanQueueResult)) {
  3741. //
  3742. // SetupScanFileQueue failed for some reason (rare). We'll
  3743. // just commit the whole file queue...
  3744. //
  3745. ScanQueueResult = 0;
  3746. }
  3747. if(ScanQueueResult != 1) {
  3748. //
  3749. // Abort installation of this device, otherwise we risk having
  3750. // the user cancel the queue committal, and wipe out all the
  3751. // other detected device installs as well.
  3752. //
  3753. SetupDebugPrint1( L"SETUP: Skipping unsigned driver install for detected device due to missing files (phase2). DeviceId = %ls", pDeviceId );
  3754. b = FALSE;
  3755. goto phase2_legacy_dev_thread_exit;
  3756. }
  3757. if(!Upgrade) {
  3758. PVOID QCBContext;
  3759. //
  3760. // No fileops left in queue, but we're doing a fresh install,
  3761. // so we still want to give user driver signing popup (logging
  3762. // the event to setupapi.log), and let them potentially abort
  3763. // the unsigned installation...
  3764. //
  3765. QCBContext = InitSysSetupQueueCallbackEx(
  3766. DeviceInstallParams.hwndParent,
  3767. INVALID_HANDLE_VALUE,
  3768. 0,
  3769. 0,
  3770. NULL
  3771. );
  3772. if(!QCBContext) {
  3773. SetupDebugPrint1( L"SETUP: Failed to allocate queue callback context (phase2). DeviceId = %ls", pDeviceId );
  3774. b = FALSE;
  3775. goto phase2_legacy_dev_thread_exit;
  3776. }
  3777. if(!SetupCommitFileQueue(DeviceInstallParams.hwndParent,
  3778. TempFileQ,
  3779. SysSetupQueueCallback,
  3780. QCBContext)) {
  3781. //
  3782. // User elected not to proceed with the unsigned installation.
  3783. //
  3784. SetupDebugPrint2( L"SETUP: SetupCommitFileQueue() failed (phase2). Error = %d, Device = %ls", GetLastError(), pDeviceId );
  3785. b = FALSE;
  3786. }
  3787. TermSysSetupQueueCallback(QCBContext);
  3788. if(!b) {
  3789. goto phase2_legacy_dev_thread_exit;
  3790. }
  3791. }
  3792. }
  3793. } else {
  3794. //
  3795. // Queue the files to be copied for this device to the "real" file queue
  3796. //
  3797. if( FileQ != INVALID_HANDLE_VALUE ) {
  3798. DeviceInstallParams.Flags |= DI_NOVCP;
  3799. DeviceInstallParams.FileQueue = FileQ;
  3800. }
  3801. if(!SetupDiSetDeviceInstallParams(hDevInfo, pDeviceInfoData, &DeviceInstallParams)) {
  3802. SetupDebugPrint2( L"SETUP: SetupDiSetDeviceInstallParams() failed (phase2). Error = %d, DeviceId = %ls", GetLastError(), pDeviceId );
  3803. b = FALSE;
  3804. goto phase2_legacy_dev_thread_exit;
  3805. }
  3806. //
  3807. // Install the device files (queue the files)
  3808. //
  3809. Error = ERROR_SUCCESS;
  3810. if( !SetupDiCallClassInstaller( DIF_INSTALLDEVICEFILES,
  3811. hDevInfo,
  3812. pDeviceInfoData ) &&
  3813. ( ( Error = GetLastError() ) != ERROR_DI_DO_DEFAULT )
  3814. ) {
  3815. SetupDebugPrint2( L"SETUP: SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) failed (phase2). Error = %lx, DeviceId = %ls", Error, pDeviceId );
  3816. b = FALSE;
  3817. goto phase2_legacy_dev_thread_exit;
  3818. }
  3819. SetupDebugPrint1( L"SETUP: SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) suceeded (phase2). DeviceId = %ls", pDeviceId );
  3820. }
  3821. //
  3822. // Mark the device as 'Do install'
  3823. //
  3824. if( !pSetupDiSetDeviceInfoContext( hDevInfo, pDeviceInfoData, TRUE ) ) {
  3825. SetupDebugPrint2( L"SETUP: pSetupDiSetDeviceInfoContext() failed (phase2). Error = %lx, DeviceId = %ls", GetLastError(), pDeviceId );
  3826. b = FALSE;
  3827. goto phase2_legacy_dev_thread_exit;
  3828. }
  3829. phase2_legacy_dev_thread_exit:
  3830. if(TempFileQ != INVALID_HANDLE_VALUE) {
  3831. SetupCloseFileQueue(TempFileQ);
  3832. }
  3833. return(b);
  3834. }
  3835. BOOL
  3836. CheckIfDeviceHasWizardPages( HDEVINFO hDevInfo,
  3837. PSP_DEVINFO_DATA pDeviceInfoData
  3838. )
  3839. /*++
  3840. Routine Description:
  3841. This routine invokes the class installer with
  3842. DIF_NEWDEVICEWIZARD_FINISHINSTALL to determine if the device has wizard
  3843. pages to display.
  3844. Arguments:
  3845. hDevInfo - The device info set.
  3846. pDeviceInfoData - The device that needs to be marked
  3847. Return Value:
  3848. Returns TRUE if the device has FINISHINSTALL wizard pages, FALSE otherwise
  3849. --*/
  3850. {
  3851. SP_NEWDEVICEWIZARD_DATA ndwd = {0};
  3852. BOOL b;
  3853. // Check if this device has wizard pages that need to be shown as
  3854. // part of the install. If so, we will mark the device as
  3855. // nneding a reinstall so the UI can be display later
  3856. //
  3857. ndwd.ClassInstallHeader.cbSize = sizeof( SP_CLASSINSTALL_HEADER );
  3858. ndwd.ClassInstallHeader.InstallFunction = DIF_NEWDEVICEWIZARD_FINISHINSTALL;
  3859. // Set the install params for the function
  3860. b = SetupDiSetClassInstallParams( hDevInfo, pDeviceInfoData,
  3861. (PSP_CLASSINSTALL_HEADER) ( &ndwd ),
  3862. sizeof( ndwd ) );
  3863. if ( b ) {
  3864. // Invoke the class installer (and co-installers)
  3865. b = SetupDiCallClassInstaller( DIF_NEWDEVICEWIZARD_FINISHINSTALL,
  3866. hDevInfo,
  3867. pDeviceInfoData );
  3868. if ( b || (ERROR_DI_DO_DEFAULT == GetLastError())) {
  3869. // Retrieve the install params
  3870. b = SetupDiGetClassInstallParams( hDevInfo,
  3871. pDeviceInfoData,
  3872. (PSP_CLASSINSTALL_HEADER)&ndwd,
  3873. sizeof(ndwd),
  3874. NULL );
  3875. if ( b ) {
  3876. // Are there any pages?
  3877. if ( 0 == ndwd.NumDynamicPages ) {
  3878. b = FALSE;
  3879. }
  3880. else {
  3881. // b is already TRUE if we made it here so no need to set
  3882. UINT i;
  3883. // We don't need the pages so destroy them
  3884. for ( i = 0; i < ndwd.NumDynamicPages; i++ ) {
  3885. DestroyPropertySheetPage( ndwd.DynamicPages[i] );
  3886. }
  3887. }
  3888. }
  3889. else {
  3890. SetupDebugPrint1( L"SETUP: SetupDiGetClassInstallParams failed (phase3). Error = %lx", GetLastError() );
  3891. }
  3892. }
  3893. else if ( ERROR_DI_DO_DEFAULT != GetLastError() ) {
  3894. SetupDebugPrint1( L"SETUP: SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_FINISHINSTALL) failed (phase3). Error = %lx", GetLastError() );
  3895. }
  3896. }
  3897. else {
  3898. SetupDebugPrint1( L"SETUP: SetupDiSetClassInstallParams failed. Error = %lx", GetLastError() );
  3899. }
  3900. return b;
  3901. }
  3902. BOOL
  3903. MarkDeviceAsNeedsReinstallIfNeeded(
  3904. HDEVINFO hDevInfo,
  3905. PSP_DEVINFO_DATA pDeviceInfoData
  3906. )
  3907. /*++
  3908. Routine Description:
  3909. This function checks if a device has wizard pages
  3910. (DIF_NEWDEVICEWIZARD_FINISHINSTALL pages) and sets the REINSTALL
  3911. config flag if it does.
  3912. Arguments:
  3913. hDevInfo - The device info set.
  3914. pDeviceInfoData - The device whose config flags will set.
  3915. Return Value:
  3916. Returns TRUE if successful, FALSE on error.
  3917. --*/
  3918. {
  3919. DWORD ConfigFlags;
  3920. BOOL b = TRUE;
  3921. if (CheckIfDeviceHasWizardPages( hDevInfo, pDeviceInfoData ) ) {
  3922. SetupDebugPrint( L"SETUP: Device has wizard pages, marking as need reinstall." );
  3923. //
  3924. // Get the config flags for the device and set the reinstall bit
  3925. //
  3926. if ( !( b = GetDeviceConfigFlags(hDevInfo, pDeviceInfoData, &ConfigFlags ) ) ) {
  3927. SetupDebugPrint( L"SETUP: GetDeviceConfigFlags failed. " );
  3928. }
  3929. if ( b ) {
  3930. ConfigFlags |= CONFIGFLAG_REINSTALL;
  3931. if ( !( b = SetDeviceConfigFlags(hDevInfo, pDeviceInfoData, ConfigFlags ) ) ) {
  3932. SetupDebugPrint( L"SETUP: SetDeviceConfigFlags failed. " );
  3933. }
  3934. }
  3935. }
  3936. return b;
  3937. }
  3938. DWORD
  3939. pPhase3InstallPnpLegacyDevicesThread(
  3940. PPNP_PHASE3_LEGACY_DEV_THREAD_PARAMS ThreadParams
  3941. )
  3942. /*++
  3943. Routine Description:
  3944. This thread completes the installation of a legacy device.
  3945. It invokes a class installer with:
  3946. - DIF_REGISTER_COINSTALLERS
  3947. - DIF_INSTALLINTERFACES
  3948. - DIF_INSTALLDEVICE
  3949. Arguments:
  3950. ThreadParams - Points to a structure that contains the information
  3951. passed to this thread.
  3952. Return Value:
  3953. Returns TRUE if all calls to the class installer were successfull.
  3954. Otherwise, returns FALSE.
  3955. --*/
  3956. {
  3957. PPNP_PHASE3_LEGACY_DEV_THREAD_PARAMS Context;
  3958. HDEVINFO hDevInfo;
  3959. PSP_DEVINFO_DATA pDeviceInfoData;
  3960. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  3961. PWSTR pDeviceId;
  3962. BOOL b;
  3963. WCHAR DeviceDescription[MAX_PATH];
  3964. DWORD Status;
  3965. DWORD Problem;
  3966. BOOL fNewDevice = FALSE;
  3967. PVOID DevicesInstalledStringTable;
  3968. Context = ThreadParams;
  3969. hDevInfo = Context->hDevInfo;
  3970. pDeviceInfoData = &(Context->DeviceInfoData);
  3971. pDeviceId = Context->pDeviceId;
  3972. DevicesInstalledStringTable = Context->DevicesInstalledStringTable;
  3973. b = TRUE;
  3974. //
  3975. // Register any device-specific co-installers for this device.
  3976. //
  3977. if( !SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, hDevInfo, pDeviceInfoData ) ) {
  3978. SetupDebugPrint2( L"SETUP: SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS) failed (phase3). Error = %d, DeviceId = %ls", GetLastError(), pDeviceId );
  3979. b = FALSE;
  3980. goto phase3_legacy_dev_thread_exit;
  3981. }
  3982. //
  3983. // Install any INF/class installer-specified interfaces.
  3984. //
  3985. if( !SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, hDevInfo, pDeviceInfoData) ) {
  3986. SetupDebugPrint2( L"SETUP: SetupDiCallClassInstaller(DIF_REGISTER_INSTALLINTERFACES) failed (phase3). Error = %d, DeviceId = %ls", GetLastError(), pDeviceId );
  3987. b = FALSE;
  3988. goto phase3_legacy_dev_thread_exit;
  3989. }
  3990. //
  3991. // Before we install this device, we need to find out if it is a new
  3992. // device or a reinstall. If the problem CM_PROB_NOT_CONFIGURED is set
  3993. // then we will consider it as a new device and check if it has wizard
  3994. // pages after DIF_INSTALLDEVICE
  3995. //
  3996. if ( CR_SUCCESS == CM_Get_DevInst_Status(&Status,
  3997. &Problem,
  3998. (DEVINST)pDeviceInfoData->DevInst,
  3999. 0 ) && (Problem & CM_PROB_NOT_CONFIGURED) )
  4000. {
  4001. fNewDevice = TRUE;
  4002. }
  4003. //
  4004. // Set the DI_FLAGSEX_RESTART_DEVICE_ONLY for legacy device installs. This
  4005. // flag tells setupapi to only stop/start this one device and not all
  4006. // devices that share the same drivers with this device.
  4007. //
  4008. // This is not critical if this fails since by default setupapi will just
  4009. // stop/start all devices that share drivers with this device, including
  4010. // the device itself. This can cause stop/start to take a little longer
  4011. // if there are lots of devices sharing drivers with this device.
  4012. //
  4013. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  4014. if(SetupDiGetDeviceInstallParams(hDevInfo, pDeviceInfoData, &DeviceInstallParams)) {
  4015. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_RESTART_DEVICE_ONLY;
  4016. SetupDiSetDeviceInstallParams(hDevInfo, pDeviceInfoData, &DeviceInstallParams);
  4017. }
  4018. if( !SetupDiCallClassInstaller( DIF_INSTALLDEVICE,
  4019. hDevInfo,
  4020. pDeviceInfoData ) ) {
  4021. SetupDebugPrint2( L"SETUP: SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed (phase3). Error = %lx, DeviceId = %ls", GetLastError(), pDeviceId );
  4022. b = FALSE;
  4023. goto phase3_legacy_dev_thread_exit;
  4024. } else {
  4025. //
  4026. // If we have been passed a string table then add the device instance Id
  4027. // to the string table of devices that have been successfully installed.
  4028. if (DevicesInstalledStringTable) {
  4029. if (pSetupStringTableAddString(DevicesInstalledStringTable, pDeviceId, STRTAB_CASE_INSENSITIVE) == -1) {
  4030. SetupDebugPrint1( L"SETUP: ERROR: failed to add Legacy Device = %ls to the string table!", pDeviceId );
  4031. }
  4032. }
  4033. }
  4034. DeviceDescription[0] = L'\0';
  4035. if( !SetupDiGetDeviceRegistryProperty( hDevInfo,
  4036. pDeviceInfoData,
  4037. SPDRP_DEVICEDESC,
  4038. NULL,
  4039. (PBYTE)DeviceDescription,
  4040. sizeof( DeviceDescription ),
  4041. NULL ) ) {
  4042. SetupDebugPrint2( L"SETUP: SetupDiGetDeviceRegistryProperty() failed. Error = %d, DeviceId = %ls", GetLastError(), pDeviceId );
  4043. }
  4044. SetupDebugPrint2( L"SETUP: Device installed. DeviceId = %ls, Description = %ls", pDeviceId, DeviceDescription );
  4045. //
  4046. // If the device has wizard pages to show (in response to
  4047. // DIF_NEWDEVICEWIZARD_FINISHINSTALL) then it needs to be marked as need
  4048. // reinstall so that pages get a chance to be shown at a later time
  4049. //
  4050. if ( fNewDevice ) {
  4051. b = MarkDeviceAsNeedsReinstallIfNeeded( hDevInfo, pDeviceInfoData);
  4052. }
  4053. phase3_legacy_dev_thread_exit:
  4054. return( b );
  4055. }
  4056. BOOL
  4057. GetDeviceConfigFlags(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDeviceInfoData,
  4058. DWORD* pdwConfigFlags)
  4059. /*++
  4060. Routine Description:
  4061. This function gets the configflags of a device.
  4062. Arguments:
  4063. hDevInfo - The device info set.
  4064. pDeviceInfoData - The device whose config flags will be retrieved.
  4065. pdwConfigFlags - The buffer that will receive the current flags.
  4066. Return Value:
  4067. Returns TRUE if successful, FALSE on error.
  4068. --*/
  4069. {
  4070. BOOL b = TRUE;
  4071. DWORD Error;
  4072. //
  4073. // Clear the output parameter
  4074. //
  4075. *pdwConfigFlags = 0;
  4076. // Get the config flags for the device
  4077. if( !SetupDiGetDeviceRegistryProperty( hDevInfo,
  4078. pDeviceInfoData,
  4079. SPDRP_CONFIGFLAGS,
  4080. NULL,
  4081. (PBYTE)pdwConfigFlags,
  4082. sizeof( *pdwConfigFlags ),
  4083. NULL ) ) {
  4084. Error = GetLastError();
  4085. //
  4086. // ERROR_INVALID_DATA is ok. It means that the device doesn't have config flags set yet.
  4087. //
  4088. if( Error != ERROR_INVALID_DATA ) {
  4089. if( ((LONG)Error) < 0 ) {
  4090. //
  4091. // Setupapi error code, display it in hex
  4092. //
  4093. SetupDebugPrint1( L"SETUP: GetDeviceConfigFlags failed. Error = %lx", Error );
  4094. } else {
  4095. //
  4096. // win32 error code, display it in decimal
  4097. //
  4098. SetupDebugPrint1( L"SETUP: GetDeviceConfigFlags failed. Error = %d", Error );
  4099. }
  4100. b = FALSE;
  4101. }
  4102. }
  4103. return b;
  4104. }
  4105. BOOL
  4106. SetDeviceConfigFlags(HDEVINFO hDevInfo, PSP_DEVINFO_DATA pDeviceInfoData,
  4107. DWORD dwConfigFlags)
  4108. /*++
  4109. Routine Description:
  4110. This function sets the configflags of a device.
  4111. Arguments:
  4112. hDevInfo - The device info set.
  4113. pDeviceInfoData - The device whose config flags will set.
  4114. dwConfigFlags - The config flags to set.
  4115. Return Value:
  4116. Returns TRUE if successful, FALSE on error.
  4117. --*/
  4118. {
  4119. BOOL b = TRUE;
  4120. DWORD Error;
  4121. if( !SetupDiSetDeviceRegistryProperty( hDevInfo,
  4122. pDeviceInfoData,
  4123. SPDRP_CONFIGFLAGS,
  4124. (PBYTE)&dwConfigFlags,
  4125. sizeof( dwConfigFlags ) ) ) {
  4126. Error = GetLastError();
  4127. if( ((LONG)Error) < 0 ) {
  4128. //
  4129. // Setupapi error code, display it in hex
  4130. //
  4131. SetupDebugPrint1( L"SETUP: SetDeviceConfigFlags failed. Error = %lx", Error );
  4132. } else {
  4133. //
  4134. // win32 error code, display it in decimal
  4135. //
  4136. SetupDebugPrint1( L"SETUP: SetDeviceConfigFlags failed. Error = %d", Error );
  4137. }
  4138. b = FALSE;
  4139. }
  4140. return b;
  4141. }
  4142. DWORD
  4143. pInstallPnpEnumeratedDeviceThread(
  4144. PPNP_ENUM_DEV_THREAD_PARAMS ThreadParams
  4145. )
  4146. /*++
  4147. Routine Description:
  4148. This is the thread that does the installation of an enumerated PnP device.
  4149. Arguments:
  4150. ThreadParams - Points to a structure that contains the information
  4151. passed to this thread.
  4152. Return Value:
  4153. Returns a Win32 error code.
  4154. --*/
  4155. {
  4156. PPNP_ENUM_DEV_THREAD_PARAMS Context;
  4157. HDEVINFO hDevInfo;
  4158. PSP_DEVINFO_DATA pDeviceInfoData;
  4159. PSP_DEVINSTALL_PARAMS pDeviceInstallParams;
  4160. PWSTR pDeviceDescription;
  4161. PWSTR pDeviceId;
  4162. ULONG Error;
  4163. WCHAR RootPath[ MAX_PATH + 1];
  4164. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  4165. DWORD Status;
  4166. DWORD Problem;
  4167. BOOL fNewDevice = FALSE;
  4168. HSPFILEQ FileQ;
  4169. PVOID QContext;
  4170. HSPFILEQ SavedFileQ;
  4171. DWORD SavedFlags;
  4172. DWORD ScanQueueResult;
  4173. HWND hwndParent;
  4174. SP_DRVINFO_DATA pDriverInfoData;
  4175. HKEY hClassKey;
  4176. WCHAR InfPath[MAX_PATH];
  4177. BOOL fCommitFileQueue = TRUE;
  4178. BOOL fDriversChanged = FALSE;
  4179. DWORD FileQueueFlags;
  4180. PVOID DevicesInstalledStringTable;
  4181. Context = ThreadParams;
  4182. hDevInfo = Context->hDevInfo;
  4183. pDeviceInfoData = &(Context->DeviceInfoData);
  4184. pDeviceInstallParams = &DeviceInstallParams;
  4185. pDeviceDescription = Context->pDeviceDescription;
  4186. pDeviceId = Context->pDeviceId;
  4187. DevicesInstalledStringTable = Context->DevicesInstalledStringTable;
  4188. InfPath[0] = TEXT('\0');
  4189. Error = ERROR_SUCCESS;
  4190. //
  4191. // Queue all files to be copied into our own file queue.
  4192. //
  4193. FileQ = SetupOpenFileQueue();
  4194. if ( FileQ == (HSPFILEQ)INVALID_HANDLE_VALUE ) {
  4195. Error = GetLastError();
  4196. SetupDebugPrint2( L"SETUP: SetupOpenFileQueue() failed. Error = %d, Device = %ls", Error, pDeviceDescription );
  4197. goto enum_dev_thread_exit;
  4198. }
  4199. pDeviceInstallParams->cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  4200. if(!SetupDiGetDeviceInstallParams(hDevInfo, pDeviceInfoData, pDeviceInstallParams)) {
  4201. Error = GetLastError();
  4202. SetupDebugPrint2( L"SETUP: SetupDiGetDeviceInstallParams() failed. Error = %d, Device = %ls", Error, pDeviceDescription );
  4203. goto enum_dev_thread_exit;
  4204. }
  4205. //
  4206. // Let the class installer/co-installers know that they should be quiet
  4207. //
  4208. pDeviceInstallParams->Flags |= DI_QUIETINSTALL;
  4209. if(!SetupDiSetDeviceInstallParams(hDevInfo, pDeviceInfoData, pDeviceInstallParams)) {
  4210. Error = GetLastError();
  4211. SetupDebugPrint2( L"SETUP: SetupDiSetDeviceInstallParams() failed. Error = %d, Device = %ls", Error, pDeviceDescription );
  4212. goto enum_dev_thread_exit;
  4213. }
  4214. //
  4215. // Install the class if it does not exist.
  4216. //
  4217. if (CM_Open_Class_Key(&pDeviceInfoData->ClassGuid,
  4218. NULL,
  4219. KEY_READ,
  4220. RegDisposition_OpenExisting,
  4221. &hClassKey,
  4222. CM_OPEN_CLASS_KEY_INSTALLER
  4223. ) != CR_SUCCESS) {
  4224. HSPFILEQ ClassFileQ;
  4225. PVOID ClassQContext;
  4226. SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
  4227. ClassFileQ = SetupOpenFileQueue();
  4228. if ( ClassFileQ == (HSPFILEQ)INVALID_HANDLE_VALUE ) {
  4229. Error = GetLastError();
  4230. SetupDebugPrint2( L"SETUP: SetupOpenFileQueue() failed. Error = %d, Device = %ls", Error, pDeviceDescription );
  4231. goto enum_dev_thread_exit;
  4232. }
  4233. //
  4234. // First, we have to retrieve the name of the INF associated with the
  4235. // selected driver node.
  4236. //
  4237. pDriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  4238. if (!SetupDiGetSelectedDriver(hDevInfo, pDeviceInfoData, &pDriverInfoData)) {
  4239. Error = GetLastError();
  4240. SetupDebugPrint2( L"SETUP: SetupDiGetSelectedDriver() failed. Error = %d, Device = %ls", Error, pDeviceDescription );
  4241. goto enum_dev_thread_exit;
  4242. }
  4243. DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  4244. if (!SetupDiGetDriverInfoDetail(hDevInfo,
  4245. pDeviceInfoData,
  4246. &pDriverInfoData,
  4247. &DriverInfoDetailData,
  4248. sizeof(DriverInfoDetailData),
  4249. NULL) &&
  4250. (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
  4251. Error = GetLastError();
  4252. SetupDebugPrint2( L"SETUP: SetupDiGetDriverInfoDetail() failed. Error = %d, Device = %ls", Error, pDeviceDescription );
  4253. goto enum_dev_thread_exit;
  4254. }
  4255. if (!SetupDiInstallClass(NULL,
  4256. DriverInfoDetailData.InfFileName,
  4257. DI_NOVCP | DI_FORCECOPY,
  4258. ClassFileQ)) {
  4259. Error = GetLastError();
  4260. SetupDebugPrint3( L"SETUP: SetupDiInstallClass(%s) failed. Error = %d, Device = %ls", DriverInfoDetailData.InfFileName, Error, pDeviceDescription );
  4261. goto enum_dev_thread_exit;
  4262. }
  4263. //
  4264. // Commit the file queue.
  4265. //
  4266. ClassQContext = InitSysSetupQueueCallbackEx(
  4267. NULL,
  4268. INVALID_HANDLE_VALUE,
  4269. 0,0,NULL);
  4270. if( ClassQContext == NULL) {
  4271. Error = GetLastError();
  4272. SetupDebugPrint1( L"SETUP: InitSysSetupQueueCallbackEx() failed. Error = %d", Error );
  4273. goto enum_dev_thread_exit;
  4274. }
  4275. if (!SetupCommitFileQueue(
  4276. NULL,
  4277. ClassFileQ,
  4278. SysSetupQueueCallback,
  4279. ClassQContext
  4280. )) {
  4281. Error = GetLastError();
  4282. }
  4283. TermSysSetupQueueCallback(ClassQContext);
  4284. if ( ClassFileQ != (HSPFILEQ)INVALID_HANDLE_VALUE ) {
  4285. SetupCloseFileQueue( ClassFileQ );
  4286. }
  4287. if (Error == NO_ERROR) {
  4288. SetupDebugPrint1( L"SETUP: SetupDiInstallClass() succeeded. Device = %ls", pDeviceDescription );
  4289. } else {
  4290. //
  4291. // We failed while installing the class so don't bother installing
  4292. // the device.
  4293. //
  4294. SetupDebugPrint3( L"SETUP: SetupCommitFileQueue(%s) failed while installing Class. Error = %d, Device = %ls", DriverInfoDetailData.InfFileName, Error, pDeviceDescription );
  4295. goto enum_dev_thread_exit;
  4296. }
  4297. } else {
  4298. //
  4299. // The class already exists.
  4300. //
  4301. RegCloseKey(hClassKey);
  4302. }
  4303. //
  4304. // Verify with the class installer and class-specific co-installers that the
  4305. // driver we're about to install isn't blacklisted.
  4306. //
  4307. if( !SetupDiCallClassInstaller(DIF_ALLOW_INSTALL,
  4308. hDevInfo,
  4309. pDeviceInfoData ) ) {
  4310. Error = GetLastError();
  4311. if( Error != ERROR_DI_DO_DEFAULT ) {
  4312. SetupDebugPrint2( L"SETUP: SetupDiCallClassInstaller(DIF_ALLOW_INSTALL) failed. Error = %d, Device = %ls", Error, pDeviceDescription );
  4313. goto enum_dev_thread_exit;
  4314. }
  4315. }
  4316. SetupDebugPrint1( L"SETUP: SetupDiCallClassInstaller(DIF_ALLOW_INSTALL) succeeded. Device = %ls", pDeviceDescription );
  4317. //
  4318. // Everything checks out. We're ready to pre-copy the driver files for this device.
  4319. //
  4320. pDeviceInstallParams->cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  4321. if(!SetupDiGetDeviceInstallParams(hDevInfo, pDeviceInfoData, pDeviceInstallParams)) {
  4322. Error = GetLastError();
  4323. SetupDebugPrint2( L"SETUP: SetupDiGetDeviceInstallParams() failed. Error = %d, Device = %ls", Error, pDeviceDescription );
  4324. goto enum_dev_thread_exit;
  4325. }
  4326. pDeviceInstallParams->Flags |= DI_FORCECOPY;
  4327. SavedFileQ = pDeviceInstallParams->FileQueue;
  4328. SavedFlags = pDeviceInstallParams->Flags;
  4329. pDeviceInstallParams->FileQueue = FileQ;
  4330. pDeviceInstallParams->Flags |= DI_NOVCP;
  4331. //
  4332. // If the old, or existing, driver is an 3rd party driver and not the same
  4333. // as the current driver we are about to install, then back up the existing
  4334. // drivers.
  4335. //
  4336. if (pDoesExistingDriverNeedBackup(hDevInfo, pDeviceInfoData, InfPath, sizeof(InfPath)/sizeof(WCHAR))) {
  4337. SetupDebugPrint1( L"SETUP: Backing up 3rd party drivers for Device = %ls", pDeviceDescription );
  4338. pDeviceInstallParams->FlagsEx |= DI_FLAGSEX_PREINSTALLBACKUP;
  4339. }
  4340. //
  4341. // Remember the parent HWND because we may need it later...
  4342. //
  4343. hwndParent = pDeviceInstallParams->hwndParent;
  4344. if(!SetupDiSetDeviceInstallParams(hDevInfo, pDeviceInfoData, pDeviceInstallParams)) {
  4345. Error = GetLastError();
  4346. SetupDebugPrint2( L"SETUP: SetupDiSetDeviceInstallParams() failed. Error = %d, Device = %ls", Error, pDeviceDescription );
  4347. goto enum_dev_thread_exit;
  4348. }
  4349. //
  4350. // Install the device files
  4351. //
  4352. Error = ERROR_SUCCESS;
  4353. if( !SetupDiCallClassInstaller( DIF_INSTALLDEVICEFILES,
  4354. hDevInfo,
  4355. pDeviceInfoData ) &&
  4356. ( ( Error = GetLastError() ) != ERROR_DI_DO_DEFAULT )
  4357. ) {
  4358. SetupDebugPrint2( L"SETUP: SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) failed. Error = %lx, Device = %ls ", Error, pDeviceDescription );
  4359. goto enum_dev_thread_exit;
  4360. }
  4361. SetupDebugPrint1( L"SETUP: SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) succeeded. Device = %ls", pDeviceDescription );
  4362. //
  4363. // Commit the file queue.
  4364. //
  4365. QContext = InitSysSetupQueueCallbackEx(
  4366. NULL,
  4367. INVALID_HANDLE_VALUE,
  4368. 0,0,NULL);
  4369. //
  4370. // "Pre-verify" the catalog nodes in the file queue. If an OEM INF in
  4371. // %windir%\Inf is unsigned, we scan the queue to see if all required files
  4372. // are present (although not validated) in their target locations. If
  4373. // we're doing an upgrade, and all files are in-place, we'll forego queue
  4374. // committal. If we're doing a fresh install, we'll still commit the
  4375. // queue, even if all files were present. This will result in a driver
  4376. // signing popup (based on policy). We do this to prevent subversion of
  4377. // driver signing due to someone "sneaking" all the files into place prior
  4378. // to GUI setup.
  4379. //
  4380. if(NO_ERROR != pSetupVerifyQueuedCatalogs(FileQ)) {
  4381. //
  4382. // We only want to prune based on presence check for OEM INFs living in
  4383. // %windir%\Inf.
  4384. //
  4385. SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
  4386. //
  4387. // Retrieve the name of the INF associated with the selected driver
  4388. // node.
  4389. //
  4390. pDriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  4391. if (!SetupDiGetSelectedDriver(hDevInfo, pDeviceInfoData, &pDriverInfoData)) {
  4392. Error = GetLastError();
  4393. SetupDebugPrint2( L"SETUP: SetupDiGetSelectedDriver() failed. Error = %d, Device = %ls", Error, pDeviceDescription );
  4394. goto enum_dev_thread_exit;
  4395. }
  4396. DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  4397. if (!SetupDiGetDriverInfoDetail(hDevInfo,
  4398. pDeviceInfoData,
  4399. &pDriverInfoData,
  4400. &DriverInfoDetailData,
  4401. sizeof(DriverInfoDetailData),
  4402. NULL) &&
  4403. ((Error = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)) {
  4404. SetupDebugPrint2( L"SETUP: SetupDiGetDriverInfoDetail() failed. Error = %d, Device = %ls", Error, pDeviceDescription );
  4405. goto enum_dev_thread_exit;
  4406. }
  4407. //
  4408. // There is only one case where we want to skip commiting the file queue
  4409. // for an unsigned drivers, and all of the following must be true:
  4410. //
  4411. // - This is an upgrade.
  4412. // - The INF lives under %windir%\INF
  4413. // - The INF is NOT an in-box INF
  4414. // - The INF has the same name as the previous INF (if there was
  4415. // a previous INF)
  4416. // - No file copy operations (copy, delete, rename) need to be done.
  4417. //
  4418. if(Upgrade &&
  4419. !pSetupInfIsFromOemLocation(DriverInfoDetailData.InfFileName, TRUE) &&
  4420. !IsInfInLayoutInf(DriverInfoDetailData.InfFileName) &&
  4421. ((InfPath[0] == TEXT('\0')) ||
  4422. (lstrcmpi(InfPath, pSetupGetFileTitle(DriverInfoDetailData.InfFileName)) == 0)) &&
  4423. SetupScanFileQueue(FileQ,
  4424. SPQ_SCAN_FILE_PRESENCE |
  4425. SPQ_SCAN_PRUNE_DELREN,
  4426. hwndParent,
  4427. NULL,
  4428. NULL,
  4429. &ScanQueueResult) &&
  4430. (ScanQueueResult == 1)) {
  4431. fCommitFileQueue = FALSE;
  4432. }
  4433. } else {
  4434. //
  4435. // Prun the file queue.
  4436. //
  4437. SetupScanFileQueue(FileQ,
  4438. SPQ_SCAN_FILE_VALIDITY |
  4439. SPQ_SCAN_PRUNE_COPY_QUEUE |
  4440. SPQ_SCAN_PRUNE_DELREN,
  4441. NULL,
  4442. NULL,
  4443. NULL,
  4444. &ScanQueueResult);
  4445. }
  4446. //
  4447. // If this device is the computer itself (i.e., the HAL, kernel, and other
  4448. // platform-specific files), then we shouldn't need to copy anything, since
  4449. // all the right files were copied during textmode setup. However, these
  4450. // files will _not_ have been pruned from the file queue if they came from
  4451. // HAL.INF because they're marked as COPYFLG_NOPRUNE in that INF. This is
  4452. // done so that doing an "update driver" from a UP HAL to an MP one works
  4453. // properly. (Pruning gets in the way here, since we consider the properly-
  4454. // signed UP files on the system to be perfectly acceptable, thus don't
  4455. // bother with copying over the MP versions.)
  4456. //
  4457. // In order to avoid re-copying the HAL, kernel, etc., we just always skip
  4458. // this queue committal if the device is of class "Computer".
  4459. //
  4460. if(IsEqualGUID(&(pDeviceInfoData->ClassGuid), &GUID_DEVCLASS_COMPUTER)) {
  4461. fCommitFileQueue = FALSE;
  4462. }
  4463. Error = ERROR_SUCCESS;
  4464. if (fCommitFileQueue) {
  4465. if (!SetupCommitFileQueue(
  4466. NULL,
  4467. FileQ,
  4468. SysSetupQueueCallback,
  4469. QContext
  4470. )) {
  4471. Error = GetLastError();
  4472. }
  4473. }
  4474. if (SetupGetFileQueueFlags(FileQ, &FileQueueFlags) &&
  4475. (FileQueueFlags & SPQ_FLAG_FILES_MODIFIED)) {
  4476. //
  4477. // One of the driver files has changed for this device. This means
  4478. // a full restart of the device, and all other devices shareing
  4479. // one of its drivers is in order.
  4480. //
  4481. fDriversChanged = TRUE;
  4482. }
  4483. TermSysSetupQueueCallback(QContext);
  4484. if (Error != ERROR_SUCCESS) {
  4485. SetupDebugPrint2( L"SETUP: SetupCommitFileQueue() failed. Error = %d, Device = %ls", Error, pDeviceDescription );
  4486. goto enum_dev_thread_exit;
  4487. }
  4488. //
  4489. // If no driver files changed then we only need to restart this device.
  4490. //
  4491. if (!fDriversChanged) {
  4492. pDeviceInstallParams->FlagsEx |= DI_FLAGSEX_RESTART_DEVICE_ONLY;
  4493. }
  4494. pDeviceInstallParams->FileQueue = SavedFileQ;
  4495. pDeviceInstallParams->Flags = (SavedFlags | DI_NOFILECOPY) ;
  4496. if(!SetupDiSetDeviceInstallParams(hDevInfo, pDeviceInfoData, pDeviceInstallParams)) {
  4497. Error = GetLastError();
  4498. SetupDebugPrint2( L"SETUP: SetupDiSetDeviceInstallParams() failed. Error = %d, Device = %ls", Error, pDeviceDescription );
  4499. goto enum_dev_thread_exit;
  4500. }
  4501. //
  4502. // Make sure that the files get flushed to disk
  4503. //
  4504. GetWindowsDirectory(RootPath,sizeof(RootPath)/sizeof(WCHAR));
  4505. RootPath[3] = L'\0';
  4506. FlushFilesToDisk( RootPath );
  4507. //
  4508. // Register any device-specific co-installers for this device.
  4509. //
  4510. if( !SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS,
  4511. hDevInfo,
  4512. pDeviceInfoData ) ) {
  4513. Error = GetLastError();
  4514. SetupDebugPrint2( L"SETUP: SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS) failed. Error = %d, Device = %ls", Error, pDeviceDescription );
  4515. goto enum_dev_thread_exit;
  4516. }
  4517. SetupDebugPrint1( L"SETUP: SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS) succeeded. Device = %ls", pDeviceDescription );
  4518. //
  4519. // Install any INF/class installer-specified interfaces.
  4520. //
  4521. if( !SetupDiCallClassInstaller(DIF_INSTALLINTERFACES,
  4522. hDevInfo,
  4523. pDeviceInfoData) ) {
  4524. Error = GetLastError();
  4525. SetupDebugPrint2( L"SETUP: SetupDiCallClassInstaller(DIF_REGISTER_INSTALLINTERFACES) failed. Error = %d, Device = %ls", Error, pDeviceDescription );
  4526. goto enum_dev_thread_exit;
  4527. }
  4528. SetupDebugPrint1( L"SETUP: SetupDiCallClassInstaller(DIF_INSTALLINTERFACES) succeeded. Device = %ls", pDeviceDescription );
  4529. //
  4530. // Before we install this device, we need to find out if it is a new
  4531. // device or a reinstall. If the problem CM_PROB_NOT_CONFIGURED is set
  4532. // then we will consider it as a new device and check if it has wizard
  4533. // pages after DIF_INSTALLDEVICE
  4534. //
  4535. if ( CR_SUCCESS == CM_Get_DevInst_Status(&Status,
  4536. &Problem,
  4537. (DEVINST)pDeviceInfoData->DevInst,
  4538. 0 ) && (Problem & CM_PROB_NOT_CONFIGURED) )
  4539. {
  4540. fNewDevice = TRUE;
  4541. }
  4542. //
  4543. // Install the device
  4544. //
  4545. Error = ERROR_SUCCESS;
  4546. if( !SetupDiCallClassInstaller( DIF_INSTALLDEVICE,
  4547. hDevInfo,
  4548. pDeviceInfoData ) &&
  4549. ( ( Error = GetLastError() ) != ERROR_DI_DO_DEFAULT )
  4550. ) {
  4551. SetupDebugPrint2( L"SETUP: SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed. Error = %lx, Device = %ls ", Error, pDeviceDescription );
  4552. goto enum_dev_thread_exit;
  4553. } else {
  4554. //
  4555. // If we have been passed a string table then add the device instance Id
  4556. // to the string table of devices that have been successfully installed.
  4557. if (DevicesInstalledStringTable) {
  4558. if (pSetupStringTableAddString(DevicesInstalledStringTable, pDeviceId, STRTAB_CASE_INSENSITIVE) == -1) {
  4559. SetupDebugPrint1( L"SETUP: ERROR: failed to add PnP Device = %ls to the string table!", pDeviceId );
  4560. }
  4561. }
  4562. SetupDebugPrint1( L"SETUP: SetupDiCallClassInstaller(DIF_INSTALLDEVICE) suceeded. Device = %ls ", pDeviceDescription );
  4563. }
  4564. //
  4565. // If the device has wizard pages to show (in response to
  4566. // DIF_NEWDEVICEWIZARD_FINISHINSTALL) then it needs to be marked as need
  4567. // reinstall so that pages get a chance to be shown at a later time
  4568. // note that we have to do this even for a re-install
  4569. //
  4570. if (!MarkDeviceAsNeedsReinstallIfNeeded( hDevInfo, pDeviceInfoData) ) {
  4571. Error = GetLastError();
  4572. }
  4573. enum_dev_thread_exit:
  4574. if ( FileQ != (HSPFILEQ)INVALID_HANDLE_VALUE ) {
  4575. if(SetupDiGetDeviceInstallParams(hDevInfo, pDeviceInfoData, pDeviceInstallParams)) {
  4576. pDeviceInstallParams->FileQueue = INVALID_HANDLE_VALUE;
  4577. pDeviceInstallParams->Flags &= ~DI_NOVCP;
  4578. SetupDiSetDeviceInstallParams(hDevInfo, pDeviceInfoData, pDeviceInstallParams);
  4579. }
  4580. SetupCloseFileQueue( FileQ );
  4581. }
  4582. if (Error != ERROR_SUCCESS) {
  4583. //
  4584. // Device installed failed, so install the NULL driver on this device.
  4585. //
  4586. SetupDebugPrint( L"SETUP: Installing the null driver for this device" );
  4587. if( !SyssetupInstallNullDriver( hDevInfo, pDeviceInfoData, DevicesInstalledStringTable ) ) {
  4588. SetupDebugPrint( L"SETUP: Unable to install null driver" );
  4589. }
  4590. }
  4591. return( Error );
  4592. }
  4593. BOOL
  4594. MarkPnpDevicesAsNeedReinstall(
  4595. PVOID DevicesInstalledStringTable OPTIONAL
  4596. )
  4597. /*++
  4598. Routine Description:
  4599. This function marks all non-present Pnp devices as 'need reinstall'.
  4600. Arguments:
  4601. DevicesInstalledStringTable - If present, a string table that contains all
  4602. the device instance Ids of successfully
  4603. installed devices. If a device was
  4604. successfully installed then it should NOT be
  4605. marked as needing a reinstall.
  4606. Return Value:
  4607. Returns TRUE if the null if all devices were marked successfull.
  4608. --*/
  4609. {
  4610. HDEVINFO hDevInfo;
  4611. SP_DEVINFO_DATA DeviceInfoData;
  4612. ULONG Index = 0;
  4613. BOOL b;
  4614. DWORD Error;
  4615. WCHAR DevInstId[MAX_DEVICE_ID_LEN];
  4616. SetupDebugPrint( L"SETUP: Entering MarkPnpDevicesAsNeedReinstall()." );
  4617. Error = ERROR_SUCCESS;
  4618. //
  4619. // Get a list of all devices
  4620. //
  4621. hDevInfo = SetupDiGetClassDevs( NULL,
  4622. NULL,
  4623. NULL,
  4624. DIGCF_ALLCLASSES );
  4625. if( hDevInfo == INVALID_HANDLE_VALUE ) {
  4626. Error = GetLastError();
  4627. if( ((LONG)Error) < 0 ) {
  4628. //
  4629. // Setupapi error code, display it in hex
  4630. //
  4631. SetupDebugPrint1( L"SETUP: SetupDiGetClassDevs(DIGCF_ALLCLASSES) failed. Error = %lx", Error );
  4632. } else {
  4633. //
  4634. // win32 error code, display it in decimal
  4635. //
  4636. SetupDebugPrint1( L"SETUP: SetupDiGetClassDevs(DIGCF_ALLCLASSES) failed. Error = %d", Error );
  4637. }
  4638. SetupDebugPrint( L"SETUP: Leaving MarkPnpDevicesAsNeedReinstall(). No devices marked." );
  4639. return( FALSE );
  4640. }
  4641. //
  4642. // Assume success
  4643. //
  4644. b = TRUE;
  4645. //
  4646. // Now enumerate each device information element added to this set, and
  4647. // mark it as 'need reinstall' if it isn't a live devnode.
  4648. //
  4649. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  4650. for( Index = 0;
  4651. SetupDiEnumDeviceInfo( hDevInfo, Index, &DeviceInfoData );
  4652. Index++ ) {
  4653. DWORD ConfigFlags;
  4654. ULONG Status, Problem;
  4655. if(CR_SUCCESS == CM_Get_DevInst_Status(&Status,
  4656. &Problem,
  4657. (DEVINST)DeviceInfoData.DevInst,
  4658. 0))
  4659. {
  4660. //
  4661. // Since we were able to retrieve the devnode's status, we know that
  4662. // it is a live devnode (not necessarily started, but at least
  4663. // present in the hardware tree). Thus, we don't want to mark it
  4664. // as needing reinstall--it'll automatically get reinstalled as part
  4665. // of our installation of all present devices (i.e., that we get
  4666. // from the UMPNPMGR named pipe).
  4667. //
  4668. continue;
  4669. }
  4670. //
  4671. // Check if this device instance Id is in the string table of devices
  4672. // that have already been installed during GUI setup. If it has then
  4673. // don't mark it with the reinstall bit since it has already been
  4674. // installed.
  4675. //
  4676. // NOTE: For Windows XP we will only do this for device's in the volume
  4677. // class.
  4678. //
  4679. if (DevicesInstalledStringTable &&
  4680. IsEqualGUID(&(DeviceInfoData.ClassGuid), &GUID_DEVCLASS_VOLUME)) {
  4681. if( SetupDiGetDeviceInstanceId( hDevInfo,
  4682. &DeviceInfoData,
  4683. DevInstId,
  4684. sizeof( DevInstId ) / sizeof( WCHAR ),
  4685. NULL ) ) {
  4686. if (pSetupStringTableLookUpString( DevicesInstalledStringTable,
  4687. DevInstId,
  4688. STRTAB_CASE_INSENSITIVE
  4689. ) != -1) {
  4690. //
  4691. // We have already installed drivers on this device during
  4692. // GUI setup, so don't mark it with the reinstall config flag.
  4693. //
  4694. SetupDebugPrint1( L"SETUP: Not-present Device has already been installed: %ls", DevInstId );
  4695. continue;
  4696. }
  4697. } else {
  4698. SetupDebugPrint1( L"SETUP: SetupDiGetDeviceInstanceId failed. Index = %d", Index );
  4699. }
  4700. }
  4701. //
  4702. // Get the config flags for the device and set the reinstall bit
  4703. //
  4704. if ( !( b = GetDeviceConfigFlags(hDevInfo, &DeviceInfoData, &ConfigFlags ) ) )
  4705. {
  4706. SetupDebugPrint1( L"SETUP: GetDeviceConfigFlags failed. Index = %d", Index );
  4707. continue;
  4708. }
  4709. ConfigFlags |= CONFIGFLAG_REINSTALL;
  4710. if ( !( b = SetDeviceConfigFlags(hDevInfo, &DeviceInfoData, ConfigFlags ) ) ) {
  4711. SetupDebugPrint1( L"SETUP: SetDeviceConfigFlags failed. Index = %d", Index );
  4712. continue;
  4713. }
  4714. }
  4715. //
  4716. // Find out why SetupDiEnumDeviceInfo() failed.
  4717. //
  4718. Error = GetLastError();
  4719. if( Error != ERROR_NO_MORE_ITEMS ) {
  4720. SetupDebugPrint2( L"SETUP: Device = %d, SetupDiEnumDeviceInfo() failed. Error = %d", Index, Error );
  4721. b = FALSE;
  4722. }
  4723. SetupDebugPrint1( L"SETUP: Leaving MarkPnpDevicesAsNeedReinstall(). Devices marked = %d", Index );
  4724. SetupDiDestroyDeviceInfoList( hDevInfo );
  4725. return( b );
  4726. }
  4727. //
  4728. // devices installs may exist in RunOnce entries
  4729. // they are processed as a batch, as opposed to per-device
  4730. // during syssetup
  4731. //
  4732. BOOL
  4733. CallRunOnceAndWait(
  4734. )
  4735. /*++
  4736. Routine Description:
  4737. This function calls RunOnce and waits for a "reasonable" amount of time for it to complete
  4738. if we don't return within a reasonable amount of time, we leave RunOnce going
  4739. and continue with rest of install process
  4740. if we underestimate timeout, we can cause a whole series of "class installer appears to have hung" messages
  4741. Arguments:
  4742. None.
  4743. Return Value:
  4744. Returns TRUE if we completed successfully
  4745. FALSE should not be considered a fatal error, and can be ignored
  4746. --*/
  4747. {
  4748. static CONST TCHAR pszPathRunOnce[] = REGSTR_PATH_RUNONCE;
  4749. BOOL Success = FALSE;
  4750. STARTUPINFO StartupInfo;
  4751. PROCESS_INFORMATION ProcessInformation;
  4752. BOOL started;
  4753. TCHAR cmdline[MAX_PATH];
  4754. HKEY hKey = NULL;
  4755. LONG l;
  4756. DWORD nValues = 0;
  4757. DWORD timeout;
  4758. SetupDebugPrint( L"SETUP: Entering CallRunOnceAndWait. ");
  4759. try {
  4760. //
  4761. // First, open the key "HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce"
  4762. // to see if we have anything to do
  4763. //
  4764. if((l = RegOpenKeyEx(HKEY_LOCAL_MACHINE,pszPathRunOnce,0,KEY_QUERY_VALUE,&hKey)) != ERROR_SUCCESS) {
  4765. //
  4766. // not considered an error
  4767. //
  4768. SetupDebugPrint( L"SETUP: CallRunOnceAndWait: could not open RunOnce registry, assuming no entries. ");
  4769. Success = TRUE;
  4770. leave;
  4771. }
  4772. //
  4773. // we want to know how many items we'll be executing in RunOnce to estimate a timeout
  4774. //
  4775. l = RegQueryInfoKey(hKey,NULL,NULL,NULL,
  4776. NULL, NULL, NULL,
  4777. &nValues,
  4778. NULL, NULL, NULL, NULL);
  4779. if ( l != ERROR_SUCCESS ) {
  4780. SetupDebugPrint( L"SETUP: CallRunOnceAndWait: could not get number of entries, assuming no entries. ");
  4781. nValues = 0;
  4782. }
  4783. RegCloseKey(hKey);
  4784. //
  4785. // estimating timeout is a black art
  4786. // we can try and guess for any entries in the HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce key
  4787. // but we're in the dark if any new keys are added
  4788. // we add '5' items to the timeout to "account" for this uncertainty. We also always run RunOnce
  4789. //
  4790. if (nValues == 0) {
  4791. SetupDebugPrint( L"SETUP: CallRunOnceAndWait: calling RunOnce (no detected entries). ");
  4792. nValues = 5;
  4793. } else {
  4794. SetupDebugPrint1( L"SETUP: CallRunOnceAndWait: calling RunOnce (%u known entries). ", nValues);
  4795. nValues += 5;
  4796. }
  4797. if (nValues < RUNONCE_THRESHOLD) {
  4798. timeout = nValues * RUNONCE_TIMEOUT;
  4799. } else {
  4800. timeout = RUNONCE_THRESHOLD * RUNONCE_TIMEOUT;
  4801. }
  4802. ZeroMemory(&StartupInfo,sizeof(StartupInfo));
  4803. ZeroMemory(&ProcessInformation,sizeof(ProcessInformation));
  4804. StartupInfo.cb = sizeof(StartupInfo);
  4805. if (SUCCEEDED(StringCchCopy(cmdline, SIZECHARS(cmdline),TEXT("runonce -r")))) {
  4806. started = CreateProcess(NULL, // use application name below
  4807. cmdline, // command to execute
  4808. NULL, // default process security
  4809. NULL, // default thread security
  4810. FALSE, // don't inherit handles
  4811. 0, // default flags
  4812. NULL, // inherit environment
  4813. NULL, // inherit current directory
  4814. &StartupInfo,
  4815. &ProcessInformation);
  4816. if(started) {
  4817. DWORD WaitProcStatus;
  4818. do {
  4819. WaitProcStatus = WaitForSingleObjectEx(ProcessInformation.hProcess, timeout , TRUE);
  4820. } while (WaitProcStatus == WAIT_IO_COMPLETION);
  4821. if (WaitProcStatus == WAIT_TIMEOUT) {
  4822. //
  4823. // RunOnce is still running
  4824. //
  4825. SetupDebugPrint( L"SETUP: CallRunOnceAndWait: RunOnce may have hung and has been abandoned. ");
  4826. } else if (WaitProcStatus == (DWORD)(-1)) {
  4827. //
  4828. // huh?
  4829. //
  4830. DWORD WaitProcError = GetLastError();
  4831. SetupDebugPrint1( L"SETUP: CallRunOnceAndWait: WaitForSingleObjectEx failed. Error = %lx ", WaitProcError );
  4832. } else {
  4833. //
  4834. // we ran, we waited, we returned
  4835. //
  4836. Success = TRUE;
  4837. }
  4838. CloseHandle(ProcessInformation.hThread);
  4839. CloseHandle(ProcessInformation.hProcess);
  4840. } else {
  4841. DWORD CreateProcError;
  4842. //
  4843. // The runonce task should get picked up later by someone else (e.g., at next
  4844. // login).
  4845. //
  4846. CreateProcError = GetLastError();
  4847. SetupDebugPrint1( L"SETUP: CallRunOnceAndWait: start RunOnce failed. Error = %lx ", CreateProcError );
  4848. }
  4849. } else {
  4850. SetupDebugPrint( L"SETUP: CallRunOnceAndWait: failed to create command line." );
  4851. }
  4852. } except(EXCEPTION_EXECUTE_HANDLER) {
  4853. SetupDebugPrint( L"SETUP: CallRunOnceAndWait: Exception! ");
  4854. Success = FALSE;
  4855. }
  4856. SetupDebugPrint( L"SETUP: Leaving CallRunOnceAndWait. ");
  4857. return Success;
  4858. }
  4859. //
  4860. // obsolete function from devmgr.c. keep the export in place for backwards compatibility
  4861. //
  4862. BOOL
  4863. DevInstallW(
  4864. HDEVINFO hDevInfo,
  4865. PSP_DEVINFO_DATA pDeviceInfoData
  4866. )
  4867. {
  4868. UNREFERENCED_PARAMETER(hDevInfo);
  4869. UNREFERENCED_PARAMETER(pDeviceInfoData);
  4870. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  4871. return FALSE;
  4872. }
  4873. ULONG
  4874. SyssetupGetPnPFlags(
  4875. IN HDEVINFO hDevInfo,
  4876. IN PSP_DEVINFO_DATA pDeviceInfoData,
  4877. IN PSP_DRVINFO_DATA pDriverInfoData
  4878. )
  4879. {
  4880. DWORD Err;
  4881. BOOL b;
  4882. SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
  4883. HINF hInf;
  4884. WCHAR InfSectionWithExt[255]; // MAX_SECT_NAME_LEN from setupapi\inf.h
  4885. INFCONTEXT InfContext;
  4886. ULONG ret = 0;
  4887. //
  4888. // First retrieve the name of the INF for this driver node.
  4889. //
  4890. DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  4891. if(!SetupDiGetDriverInfoDetail(hDevInfo,
  4892. pDeviceInfoData,
  4893. pDriverInfoData,
  4894. &DriverInfoDetailData,
  4895. sizeof(DriverInfoDetailData),
  4896. NULL)) {
  4897. //
  4898. // If we failed with ERROR_INSUFFICIENT_BUFFER, that's OK. We're
  4899. // guaranteed to have gotten all the static fields in the driver info
  4900. // detail structure filled in (including the INF name and section
  4901. // name fields).
  4902. //
  4903. Err = GetLastError();
  4904. MYASSERT(Err == ERROR_INSUFFICIENT_BUFFER);
  4905. if(Err != ERROR_INSUFFICIENT_BUFFER) {
  4906. return ret;
  4907. }
  4908. }
  4909. //
  4910. // Now open up the INF associated with this driver node.
  4911. //
  4912. hInf = SetupOpenInfFile(DriverInfoDetailData.InfFileName,
  4913. NULL,
  4914. INF_STYLE_WIN4,
  4915. NULL
  4916. );
  4917. if(hInf == INVALID_HANDLE_VALUE) {
  4918. //
  4919. // This will fail, for example, if the INF is an old-style INF.
  4920. //
  4921. return ret;
  4922. }
  4923. //
  4924. // Get the potentially decorated install section name.
  4925. //
  4926. b = SetupDiGetActualSectionToInstall(hInf,
  4927. DriverInfoDetailData.SectionName,
  4928. InfSectionWithExt,
  4929. SIZECHARS(InfSectionWithExt),
  4930. NULL,
  4931. NULL
  4932. );
  4933. MYASSERT(b);
  4934. if(!b) {
  4935. goto clean0;
  4936. }
  4937. //
  4938. // Now look to see if there's a "SyssetupPnPFlags" entry in that section.
  4939. //
  4940. if(!SetupFindFirstLine(hInf,
  4941. InfSectionWithExt,
  4942. szSyssetupPnPFlags,
  4943. &InfContext)) {
  4944. //
  4945. // We didn't find such a line in this section.
  4946. //
  4947. goto clean0;
  4948. }
  4949. if(!SetupGetIntField(&InfContext, 1, (PINT)&ret)) {
  4950. //
  4951. // We failed--ensure return value is still zero.
  4952. //
  4953. ret = 0;
  4954. goto clean0;
  4955. }
  4956. clean0:
  4957. SetupCloseInfFile(hInf);
  4958. return ret;
  4959. }
  4960. //
  4961. // this function will tell umpnpmgr to stop server-side installs
  4962. //
  4963. VOID
  4964. PnpStopServerSideInstall(
  4965. VOID
  4966. )
  4967. /*++
  4968. Routine Description:
  4969. After phase-2, server-side installs kick in to pick up software-enumerated drivers
  4970. Call this when it's critical that we need to stop installing
  4971. Arguments:
  4972. None.
  4973. Return Value:
  4974. None.
  4975. Returns when it is safe to proceed.
  4976. --*/
  4977. {
  4978. //
  4979. // since when we're called there should be nobody generating new devnodes, we're pretty safe
  4980. //
  4981. CMP_WaitNoPendingInstallEvents(INFINITE);
  4982. }
  4983. //
  4984. // this function will update HAL+kernel from NewInf
  4985. //
  4986. VOID
  4987. PnpUpdateHAL(
  4988. VOID
  4989. )
  4990. /*++
  4991. Routine Description:
  4992. At very end of MiniSetup, OEM may indicate (via Unattend) that a different HAL should be installed
  4993. This must be done very last due to that way that HAL's need to be installed, if we do this earlier
  4994. then an app or service may pick the wrong HAL/Kernel32/other
  4995. Arguments:
  4996. None
  4997. Return Value:
  4998. None.
  4999. There is nothing meaningful that can be done if this fails
  5000. --*/
  5001. {
  5002. HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
  5003. SP_DEVINFO_DATA DevInfoData;
  5004. WCHAR HardwareID[MAX_PATH+2];
  5005. WCHAR InfPath[MAX_PATH];
  5006. WCHAR Answer[MAX_PATH];
  5007. WCHAR AnswerFile[2*MAX_PATH];
  5008. DWORD HardwareIdSize;
  5009. DWORD dwLen;
  5010. HINSTANCE hInstNewDev = NULL;
  5011. ExternalUpdateDriverForPlugAndPlayDevicesW pUpdateDriverForPlugAndPlayDevicesW = NULL;
  5012. PWSTR pSrch = NULL;
  5013. PWSTR pHwID = NULL;
  5014. PWSTR pInfPath = NULL;
  5015. BOOL RebootFlag = FALSE;
  5016. SYSTEM_INFO info;
  5017. GetSystemDirectory(AnswerFile,MAX_PATH);
  5018. pSetupConcatenatePaths(AnswerFile,WINNT_GUI_FILE,MAX_PATH,NULL);
  5019. //
  5020. // If we determine we are only running on one processor (based on System Info)
  5021. // allow use of UpdateUPHAL
  5022. //
  5023. GetSystemInfo(&info);
  5024. Answer[0]=L'\0';
  5025. if(info.dwNumberOfProcessors==1) {
  5026. if( GetPrivateProfileString( WINNT_UNATTENDED,
  5027. WINNT_U_UPDATEUPHAL,
  5028. pwNull,
  5029. Answer,
  5030. MAX_PATH,
  5031. AnswerFile )) {
  5032. SetupDebugPrint1( L"SETUP: UpdateUPHAL=\"%ls\"",Answer);
  5033. }
  5034. }
  5035. if(!Answer[0]) {
  5036. //
  5037. // we didn't explicitly get an answer based on being UP - try catch-all
  5038. //
  5039. if( GetPrivateProfileString( WINNT_UNATTENDED,
  5040. WINNT_U_UPDATEHAL,
  5041. pwNull,
  5042. Answer,
  5043. MAX_PATH,
  5044. AnswerFile )) {
  5045. SetupDebugPrint1( L"SETUP: UpdateHAL=\"%ls\"",Answer);
  5046. }
  5047. }
  5048. if(!Answer[0]) {
  5049. //
  5050. // no update request
  5051. //
  5052. return;
  5053. }
  5054. //
  5055. // split Answer into HardwareID & INF
  5056. //
  5057. pHwID = Answer;
  5058. pSrch = wcschr(Answer,L',');
  5059. if(pSrch == NULL) {
  5060. SetupDebugPrint( L"SETUP: Required Syntax: \"hwid,inffile\"");
  5061. return;
  5062. }
  5063. pInfPath = pSrch+1;
  5064. //
  5065. // trim HardwareID & prepare as a MULTI-SZ
  5066. //
  5067. while(pHwID[0]==L' '||pHwID[0]==L'\t') {
  5068. pHwID++;
  5069. }
  5070. while(pSrch != pHwID && (pSrch[-1]==L' '||pSrch[-1]==L'\t')) {
  5071. pSrch--;
  5072. }
  5073. pSrch[0]=0;
  5074. if(!pHwID[0]) {
  5075. SetupDebugPrint( L"SETUP: Required Syntax: \"hwid,inffile\"");
  5076. return;
  5077. }
  5078. if (FAILED(StringCchCopy(HardwareID, SIZECHARS(HardwareID) ,pHwID))) {
  5079. SetupDebugPrint( L"SETUP: Failed to copy HAL hardware Id." );
  5080. goto clean0;
  5081. }
  5082. HardwareIdSize = wcslen(HardwareID)+1;
  5083. //
  5084. // now pre-process the INF, trim & allow %windir% expansion
  5085. //
  5086. while(pInfPath[0]==L' '|| pInfPath[0]==L'\t') {
  5087. pInfPath++;
  5088. }
  5089. pSrch = pInfPath+wcslen(pInfPath);
  5090. while(pSrch != pInfPath && (pSrch[-1]==L' '||pSrch[-1]==L'\t')) {
  5091. pSrch--;
  5092. }
  5093. pSrch[0]=0;
  5094. if(!pInfPath[0]) {
  5095. SetupDebugPrint( L"SETUP: Required Syntax: \"hwid,inffile\"");
  5096. return;
  5097. }
  5098. dwLen=ExpandEnvironmentStrings(pInfPath,InfPath,MAX_PATH);
  5099. if(dwLen==0 || dwLen > MAX_PATH) {
  5100. SetupDebugPrint1( L"SETUP: Expansion of \"%ls\" failed",InfPath);
  5101. return;
  5102. }
  5103. SetupDebugPrint2( L"SETUP: Preparing to install new HAL %ls from %ls",HardwareID,InfPath);
  5104. // we need "UpdateDriverForPlugAndPlayDevices"
  5105. // make sure we can get this before changing hardware ID
  5106. //
  5107. hInstNewDev = LoadLibrary(L"newdev.dll");
  5108. if(hInstNewDev == NULL) {
  5109. SetupDebugPrint1( L"SETUP: Failed to load newdev.dll. Error = %d", GetLastError() );
  5110. goto clean0;
  5111. }
  5112. pUpdateDriverForPlugAndPlayDevicesW = (ExternalUpdateDriverForPlugAndPlayDevicesW)
  5113. GetProcAddress(hInstNewDev,
  5114. "UpdateDriverForPlugAndPlayDevicesW");
  5115. if(pUpdateDriverForPlugAndPlayDevicesW==NULL) {
  5116. SetupDebugPrint1( L"SETUP: Failed to get UpdateDriverForPlugAndPlayDevicesW. Error = %d", GetLastError() );
  5117. goto clean0;
  5118. }
  5119. //
  5120. // we enumerate the Computer class, GUID={4D36E966-E325-11CE-BFC1-08002BE10318}
  5121. // and should find a single DevNode, which is the one we need to update
  5122. // when we actually update, we consider this a safe thing to do
  5123. // since it should not involve any Co-Installers
  5124. //
  5125. hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_COMPUTER,NULL,NULL,DIGCF_PRESENT|DIGCF_PROFILE);
  5126. if(hDevInfo == INVALID_HANDLE_VALUE) {
  5127. SetupDebugPrint1( L"SETUP: SetupDiGetClassDevs() failed. Error = %d", GetLastError() );
  5128. goto clean0;
  5129. }
  5130. DevInfoData.cbSize = sizeof(DevInfoData);
  5131. if(!SetupDiEnumDeviceInfo(hDevInfo,0,&DevInfoData)) {
  5132. SetupDebugPrint1( L"SETUP: SetupDiEnumDeviceInfo() failed. Error = %d", GetLastError() );
  5133. SetupDiDestroyDeviceInfoList(hDevInfo);
  5134. goto clean0;
  5135. }
  5136. //
  5137. // change the harware ID
  5138. //
  5139. if(!SetupDiSetDeviceRegistryProperty(hDevInfo,
  5140. &DevInfoData,
  5141. SPDRP_HARDWAREID,
  5142. (PBYTE)HardwareID,
  5143. sizeof(HardwareID[0])*HardwareIdSize
  5144. )) {
  5145. SetupDebugPrint1( L"SETUP: SetupDiSetDeviceRegistryProperty() failed. Error = %d", GetLastError() );
  5146. SetupDiDestroyDeviceInfoList(hDevInfo);
  5147. goto clean0;
  5148. }
  5149. SetupDiDestroyDeviceInfoList(hDevInfo);
  5150. //
  5151. // now effect an update
  5152. //
  5153. if(!pUpdateDriverForPlugAndPlayDevicesW(NULL,HardwareID,InfPath,INSTALLFLAG_FORCE,&RebootFlag)) {
  5154. SetupDebugPrint1( L"SETUP: UpdateDriverForPlugAndPlayDevices() failed. Error = %d", GetLastError() );
  5155. } else {
  5156. SetupDebugPrint( L"SETUP: ... new HAL installed and will be active on reboot");
  5157. }
  5158. clean0:
  5159. if(hInstNewDev != NULL) {
  5160. FreeLibrary(hInstNewDev);
  5161. }
  5162. }
  5163. BOOL
  5164. InstallOEMInfs(
  5165. VOID
  5166. )
  5167. /*++
  5168. Routine Description:
  5169. This routine will install any OEM supplied INFs (and their corresponding
  5170. catalogs) that may have been supplied to the system during an earlier phase
  5171. of setup. For example, the OEM can currently supply an INF for unsupported
  5172. hardware during the textmode phase of setup by pressing "F6".
  5173. The list of OEM INFs to be installed is supplied to us via the answer
  5174. file in the following format:
  5175. [Data]
  5176. OEMDrivers=<driver-section-1>,<driver-section-2>,...
  5177. [driver-section-1]
  5178. OemDriverPathName=<path> (path to the driver (may use environment variables)
  5179. OemInfName=<inf name> name of the inf to be installed from the above
  5180. directory (there can be one or more infs in this directory, so
  5181. this is a comma separated list)
  5182. OemDriverFlags=<flags>
  5183. valid flags are:
  5184. SETUP_OEM_LDR_DEVICE 0x00000001
  5185. //indicates that the driver was supplied via the textmode "F6" mechanism
  5186. SETUP_OEM_MIGRATED_DRIVER 0x00000002
  5187. //indicates that the driver was migrated from the previous system
  5188. This function is really just a wrapper for SetupCopyOEMInf, which does
  5189. everything we need
  5190. Arguments:
  5191. None.
  5192. Return Value:
  5193. TRUE indicates that all answer file-supplied drivers were installed properly
  5194. --*/
  5195. {
  5196. HINF hAnswerFile = INVALID_HANDLE_VALUE;
  5197. BOOL RetVal;
  5198. INFCONTEXT LineContext;
  5199. DWORD FieldCount, InfNameCount;
  5200. DWORD Field, InfCount;
  5201. DWORD CchSize;
  5202. PCTSTR SectionName;
  5203. INFCONTEXT FirstLineContext,InfLineContext;
  5204. PCWSTR OemDriverPathName;
  5205. PCWSTR OemInfName;
  5206. DWORD OemFlags;
  5207. WCHAR FullInfPathBuffer[MAX_PATH];
  5208. WCHAR FullInfPathBufferWithInf[MAX_PATH];
  5209. RetVal = TRUE;
  5210. hAnswerFile = pOpenAnswerFile();
  5211. if (hAnswerFile == INVALID_HANDLE_VALUE) {
  5212. //
  5213. // if there is no answer file, then we can't continue.
  5214. //
  5215. RetVal = FALSE;
  5216. goto clean0;
  5217. }
  5218. if (!SetupFindFirstLine(hAnswerFile,WINNT_DATA,WINNT_OEMDRIVERS,&LineContext)) {
  5219. //
  5220. // we were successful in doing nothing
  5221. //
  5222. RetVal = TRUE;
  5223. goto clean0;
  5224. }
  5225. do {
  5226. //
  5227. // Each value on the line in the given section
  5228. // is the name of another section.
  5229. //
  5230. FieldCount = SetupGetFieldCount(&LineContext);
  5231. for(Field=1; Field<=FieldCount; Field++) {
  5232. OemDriverPathName = NULL;
  5233. OemInfName = NULL;
  5234. OemFlags = 0;
  5235. FullInfPathBuffer[0] = '\0';
  5236. FullInfPathBufferWithInf[0] = '\0';
  5237. if((SectionName = pSetupGetField(&LineContext,Field))
  5238. && SetupFindFirstLine(hAnswerFile,SectionName,WINNT_OEMDRIVERS_PATHNAME,&FirstLineContext)) {
  5239. //
  5240. // the section points to a valid section, so process it.
  5241. //
  5242. OemDriverPathName = pSetupGetField(&FirstLineContext,1);
  5243. if (SetupFindFirstLine(hAnswerFile,SectionName,WINNT_OEMDRIVERS_FLAGS,&FirstLineContext)) {
  5244. SetupGetIntField(&FirstLineContext,1,&OemFlags);
  5245. }
  5246. if (OemDriverPathName) {
  5247. CchSize = ExpandEnvironmentStrings( OemDriverPathName,
  5248. FullInfPathBuffer,
  5249. sizeof(FullInfPathBuffer)/sizeof(WCHAR) );
  5250. if ((CchSize == 0) ||
  5251. (CchSize > SIZECHARS(FullInfPathBuffer))) {
  5252. //
  5253. // The OemDriverPathName value, when expanded, will not
  5254. // fit into our local buffer.
  5255. //
  5256. RetVal = FALSE;
  5257. goto clean0;
  5258. }
  5259. }
  5260. if (SetupFindFirstLine(hAnswerFile,SectionName,WINNT_OEMDRIVERS_INFNAME,&InfLineContext)) {
  5261. InfNameCount = SetupGetFieldCount(&InfLineContext);
  5262. for (InfCount = 1; InfCount <= InfNameCount; InfCount++) {
  5263. OemInfName = pSetupGetField(&InfLineContext,InfCount);
  5264. if (OemDriverPathName && OemInfName) {
  5265. if (SUCCEEDED(StringCchCopy( FullInfPathBufferWithInf,
  5266. SIZECHARS(FullInfPathBufferWithInf),
  5267. FullInfPathBuffer )) &&
  5268. pSetupConcatenatePaths(
  5269. FullInfPathBufferWithInf,
  5270. OemInfName,
  5271. sizeof(FullInfPathBufferWithInf)/sizeof(WCHAR),
  5272. 0 )) {
  5273. if (!SetupCopyOEMInf(
  5274. FullInfPathBufferWithInf,
  5275. (OemFlags & SETUP_OEM_MIGRATED_DRIVER) ? NULL : FullInfPathBuffer,
  5276. (OemFlags & SETUP_OEM_MIGRATED_DRIVER) ? SPOST_NONE : SPOST_PATH,
  5277. (OemFlags & (SETUP_OEM_MIGRATED_DRIVER | SETUP_OEM_LDR_DEVICE)) ? SP_COPY_OEM_F6_INF : 0,
  5278. NULL,
  5279. 0,
  5280. NULL,
  5281. NULL)) {
  5282. RetVal = FALSE;
  5283. }
  5284. if (OemFlags & SETUP_OEM_LDR_DEVICE) {
  5285. //
  5286. // if this flag is set, we know that there is an
  5287. // additional oemXXX##.inf file in the system32
  5288. // directory which corresponds to the INF file we
  5289. // have already copied from this directory. We need
  5290. // to seek out that file and remove it, since the INF
  5291. // file we have just copied is "better" than that file.
  5292. //
  5293. WIN32_FIND_DATA fd;
  5294. HANDLE hFind;
  5295. WCHAR OldInfBuffer[MAX_PATH];
  5296. PWSTR p;
  5297. CchSize = ExpandEnvironmentStringsW(
  5298. L"%SystemRoot%\\system32\\",
  5299. OldInfBuffer,
  5300. sizeof(OldInfBuffer)/sizeof(WCHAR));
  5301. if ((CchSize != 0) &&
  5302. (CchSize <= SIZECHARS(OldInfBuffer))) {
  5303. //
  5304. // Set the pointer 'p' to the end of
  5305. // the path.
  5306. //
  5307. p = wcsrchr( OldInfBuffer, L'\\' );
  5308. p += 1;
  5309. if (pSetupConcatenatePaths(
  5310. OldInfBuffer,
  5311. L"oem?????.inf",
  5312. sizeof(OldInfBuffer)/sizeof(WCHAR),
  5313. 0 )) {
  5314. if ((hFind = FindFirstFile(OldInfBuffer, &fd)) != INVALID_HANDLE_VALUE) {
  5315. do {
  5316. p = L'\0';
  5317. if (pSetupConcatenatePaths(
  5318. OldInfBuffer,
  5319. fd.cFileName,
  5320. sizeof(OldInfBuffer)/sizeof(WCHAR),
  5321. 0 )) {
  5322. if (DoFilesMatch( FullInfPathBufferWithInf, OldInfBuffer )) {
  5323. SetFileAttributes(OldInfBuffer, FILE_ATTRIBUTE_NORMAL );
  5324. DeleteFile( OldInfBuffer );
  5325. }
  5326. }
  5327. } while(FindNextFile( hFind, &fd ));
  5328. FindClose( hFind );
  5329. }
  5330. }
  5331. }
  5332. }
  5333. } else {
  5334. //
  5335. // We could not fit the FullInfPathBuffer with
  5336. // the INF name into our local buffer.
  5337. //
  5338. RetVal = FALSE;
  5339. }
  5340. } else {
  5341. RetVal = FALSE;
  5342. }
  5343. }
  5344. }
  5345. }
  5346. }
  5347. } while(SetupFindNextMatchLine(&LineContext,NULL,&LineContext));
  5348. clean0:
  5349. if (hAnswerFile != INVALID_HANDLE_VALUE) {
  5350. SetupCloseInfFile( hAnswerFile );
  5351. }
  5352. return(RetVal);
  5353. }
  5354. VOID
  5355. SfcExcludeMigratedDrivers (
  5356. VOID
  5357. )
  5358. /*++
  5359. Routine Description:
  5360. Adds all OEM migrated boot drivers (via unsupdrv.inf) to the SFC exclusion list
  5361. Arguments:
  5362. None
  5363. Return Value:
  5364. None
  5365. --*/
  5366. {
  5367. TCHAR unsupInfPath[MAX_PATH];
  5368. TCHAR windir[MAX_PATH];
  5369. HINF unsupdrvInf;
  5370. INFCONTEXT ic;
  5371. TCHAR driverId[MAX_PATH];
  5372. TCHAR sectionFiles[MAX_PATH];
  5373. INFCONTEXT ic2;
  5374. TCHAR driverFilename[MAX_PATH];
  5375. TCHAR driverSubDir[MAX_PATH];
  5376. TCHAR driverPath[MAX_PATH];
  5377. #if defined(_AMD64_) || defined(_X86_)
  5378. if (!FloppylessBootPath[0] ||
  5379. !BuildPath (unsupInfPath, ARRAYSIZE(unsupInfPath), FloppylessBootPath, TEXT("$WIN_NT$.~BT")) ||
  5380. !pSetupConcatenatePaths (unsupInfPath, TEXT("unsupdrv.inf"), ARRAYSIZE(unsupInfPath), NULL)) {
  5381. return;
  5382. }
  5383. #elif defined(_IA64_)
  5384. if (!LegacySourcePath[0] ||
  5385. !BuildPath (unsupInfPath, ARRAYSIZE(unsupInfPath), LegacySourcePath, TEXT("unsupdrv.inf"))) {
  5386. return;
  5387. }
  5388. #else
  5389. #error "No Target Architecture"
  5390. #endif
  5391. unsupdrvInf = SetupOpenInfFile (unsupInfPath, NULL, INF_STYLE_WIN4, NULL);
  5392. if (unsupdrvInf == INVALID_HANDLE_VALUE) {
  5393. return;
  5394. }
  5395. if (!GetWindowsDirectory (windir, ARRAYSIZE(windir))) {
  5396. return;
  5397. }
  5398. if(SetupFindFirstLine (
  5399. unsupdrvInf,
  5400. TEXT("Devices"),
  5401. NULL,
  5402. &ic)) {
  5403. do {
  5404. if (!SetupGetStringField (&ic, 1, driverId, ARRAYSIZE(driverId), NULL)) {
  5405. continue;
  5406. }
  5407. if (_sntprintf (sectionFiles, ARRAYSIZE(sectionFiles) - 1, TEXT("Files.%s"), driverId) < 0) {
  5408. continue;
  5409. }
  5410. sectionFiles[ARRAYSIZE(sectionFiles) - 1] = 0;
  5411. if(SetupFindFirstLine (
  5412. unsupdrvInf,
  5413. sectionFiles,
  5414. NULL,
  5415. &ic2)) {
  5416. do {
  5417. if (!SetupGetStringField (&ic2, 1, driverFilename, ARRAYSIZE(driverFilename), NULL)) {
  5418. continue;
  5419. }
  5420. if (!SetupGetStringField (&ic2, 2, driverSubDir, ARRAYSIZE(driverSubDir), NULL)) {
  5421. continue;
  5422. }
  5423. if (_sntprintf (driverPath, ARRAYSIZE(driverPath) - 1, TEXT("%s\\%s\\%s"), windir, driverSubDir, driverFilename) < 0) {
  5424. continue;
  5425. }
  5426. driverPath[ARRAYSIZE(driverPath) - 1] = 0;
  5427. if (FileExists (driverPath, NULL)) {
  5428. MultiSzAppendString(&EnumPtrSfcIgnoreFiles, driverPath);
  5429. }
  5430. } while (SetupFindNextLine(&ic2, &ic2));
  5431. }
  5432. } while (SetupFindNextLine(&ic, &ic));
  5433. }
  5434. SetupCloseInfFile (unsupdrvInf);
  5435. }
  5436. BOOL
  5437. IsInstalledInfFromOem(
  5438. IN PCWSTR InfFileName
  5439. )
  5440. /*++
  5441. Routine Description:
  5442. Determine if an INF file is OEM-supplied (i.e., it's name is of the form
  5443. "OEM<n>.INF").
  5444. Arguments:
  5445. InfFileName - supplies name (may include path) of INF. No checking is done
  5446. to ensure INF lives in %windir%\Inf--this is caller's responsibility.
  5447. Return Value:
  5448. If TRUE, this is an OEM INF. If FALSE, it's an in-box INF (or possibly one
  5449. that was illegally copied directly into %windir%\Inf).
  5450. --*/
  5451. {
  5452. PCWSTR p = pSetupGetFileTitle(InfFileName);
  5453. //
  5454. // First check that the first 3 characters are OEM
  5455. //
  5456. if((*p != L'o') && (*p != L'O')) {
  5457. return FALSE;
  5458. }
  5459. p++;
  5460. if((*p != L'e') && (*p != L'E')) {
  5461. return FALSE;
  5462. }
  5463. p++;
  5464. if((*p != L'm') && (*p != L'M')) {
  5465. return FALSE;
  5466. }
  5467. p++;
  5468. //
  5469. // Now make sure that all subsequent characters up to the dot (.) are
  5470. // numeric.
  5471. //
  5472. while((*p != L'\0') && (*p != L'.')) {
  5473. if((*p < L'0') || (*p > L'9')) {
  5474. return FALSE;
  5475. }
  5476. p++;
  5477. }
  5478. //
  5479. // Finally, verify that the last 4 characters are ".inf"
  5480. //
  5481. if(lstrcmpi(p, L".inf")) {
  5482. return FALSE;
  5483. }
  5484. //
  5485. // This is an OEM INF
  5486. //
  5487. return TRUE;
  5488. }
  5489. BOOL
  5490. IsInfInLayoutInf(
  5491. IN PCWSTR InfFileName
  5492. )
  5493. /*++
  5494. Routine Description:
  5495. Determine if an INF file is shiped in-box with the operating system.
  5496. This is acomplished by looking up the INF name in the [SourceDisksFiles]
  5497. section of layout.inf
  5498. Arguments:
  5499. InfFileName - supplies name (may include path) of INF. No checking is done
  5500. to ensure INF lives in %windir%\Inf--this is caller's responsibility.
  5501. Return Value:
  5502. If TRUE, this is an in-box INF. If FALSE, it's not an in-box INF, this
  5503. could be an OEM<n>.INF or an inf illegaly copied into the INF directory.
  5504. --*/
  5505. {
  5506. BOOL bInBoxInf = FALSE;
  5507. HINF hInf = INVALID_HANDLE_VALUE;
  5508. UINT SourceId;
  5509. hInf = SetupOpenInfFile(TEXT("layout.inf"), NULL, INF_STYLE_WIN4, NULL);
  5510. if (hInf != INVALID_HANDLE_VALUE) {
  5511. if(SetupGetSourceFileLocation(hInf,
  5512. NULL,
  5513. pSetupGetFileTitle(InfFileName),
  5514. &SourceId,
  5515. NULL,
  5516. 0,
  5517. NULL)) {
  5518. bInBoxInf = TRUE;
  5519. }
  5520. SetupCloseInfFile(hInf);
  5521. }
  5522. return bInBoxInf;
  5523. }