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

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