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.

15412 lines
586 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. devinstd.c
  5. Abstract:
  6. Default install handlers for SetupDiCallClassInstaller DIF_* functions.
  7. Author:
  8. Lonny McMichael (lonnym) 1-Aug-1995
  9. Revision History:
  10. Jamie Hunter (jamiehun) 20-January-1998 Added backup functionality in
  11. _SetupDiInstallDevice - DI_FLAGSEX_BACKUPOLDFILES
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. //
  16. // Global strings for use inside this file only.
  17. //
  18. CONST TCHAR pszDisplayName[] = INFSTR_KEY_DISPLAYNAME,
  19. pszServiceType[] = INFSTR_KEY_SERVICETYPE,
  20. pszStartType[] = INFSTR_KEY_STARTTYPE,
  21. pszErrorControl[] = INFSTR_KEY_ERRORCONTROL,
  22. pszServiceBinary[] = INFSTR_KEY_SERVICEBINARY,
  23. pszLoadOrderGroup[] = INFSTR_KEY_LOADORDERGROUP,
  24. pszDependencies[] = INFSTR_KEY_DEPENDENCIES,
  25. pszStartName[] = INFSTR_KEY_STARTNAME,
  26. pszSystemRoot[] = TEXT("%SystemRoot%\\"),
  27. pszSecurity[] = INFSTR_KEY_SECURITY,
  28. pszDescription[] = INFSTR_KEY_DESCRIPTION;
  29. //
  30. // Define function prototype for legacy INF interpreter supplied
  31. // by setupdll.dll
  32. //
  33. typedef BOOL (WINAPI *LEGACY_INF_INTERP_PROC)(
  34. IN HWND OwnerWindow,
  35. IN PCSTR InfFilename,
  36. IN PCSTR InfSection,
  37. IN PCHAR ExtraVariables,
  38. OUT PSTR InfResult,
  39. IN DWORD BufferSize,
  40. OUT INT *InterpResult,
  41. IN PCSTR InfSourceDir OPTIONAL
  42. );
  43. //
  44. // Define the various copy scenarios that can be returned from GetNewInfName().
  45. //
  46. typedef enum _NEWINF_COPYTYPE {
  47. NewInfCopyYes, // new INF placeholder created--need to copy real INF
  48. NewInfCopyNo, // no need to copy--INF already present in destination
  49. NewInfCopyZeroLength // previously-existing zero-length INF match found
  50. } NEWINF_COPYTYPE, *PNEWINF_COPYTYPE;
  51. //
  52. // Define function prototype for legacy INF routine that returns a list
  53. // of all services modified during an INF 'run' via LegacyInfInterpret().
  54. //
  55. typedef DWORD (WINAPI *LEGACY_INF_GETSVCLIST_PROC)(
  56. IN LPSTR SvcNameBuffer,
  57. IN UINT SvcNameBufferSize,
  58. OUT PUINT RequiredSize
  59. );
  60. //
  61. // Define the legacy INF interpreter exit codes (copied from setup\legacy\dll\_shell.h
  62. //
  63. #define SETUP_ERROR_SUCCESS 0
  64. #define SETUP_ERROR_USERCANCEL 1
  65. #define SETUP_ERROR_GENERAL 2
  66. //
  67. // Define a list node to hold an interface class to be installed.
  68. //
  69. typedef struct _INTERFACE_CLASS_TO_INSTALL {
  70. struct _INTERFACE_CLASS_TO_INSTALL *Next;
  71. GUID InterfaceGuid;
  72. DWORD Flags;
  73. TCHAR InstallSection[MAX_SECT_NAME_LEN];
  74. } INTERFACE_CLASS_TO_INSTALL, *PINTERFACE_CLASS_TO_INSTALL;
  75. //
  76. // Define a list node to hold an INF that has been newly-installed during
  77. // SetupDiInstallDevice, hence must be cleaned up if SetupDiInstallDevice
  78. // subsequently encounters a failure.
  79. //
  80. typedef struct _INSTALLED_INF_CLEANUP {
  81. struct _INSTALLED_INF_CLEANUP *Next;
  82. TCHAR InfName[MAX_PATH];
  83. } INSTALLED_INF_CLEANUP, *PINSTALLED_INF_CLEANUP;
  84. //
  85. // Private function prototypes
  86. //
  87. BOOL
  88. _SetupDiInstallDevice(
  89. IN HDEVINFO DeviceInfoSet,
  90. IN OUT PSP_DEVINFO_DATA DeviceInfoData,
  91. IN BOOL DoFullInstall
  92. );
  93. DWORD
  94. InstallHW(
  95. IN HDEVINFO DeviceInfoSet,
  96. IN PSP_DEVINFO_DATA DeviceInfoData,
  97. IN HINF hDeviceInf,
  98. IN PCTSTR szSectionName,
  99. OUT PBOOL DeleteDevKey
  100. );
  101. BOOL
  102. AssociateDevInstWithDefaultService(
  103. IN PDEVINFO_ELEM DevInfoElem,
  104. OUT PTSTR ServiceName,
  105. IN OUT PDWORD ServiceNameSize
  106. );
  107. BOOL
  108. CheckIfDevStarted(
  109. IN PDEVINFO_ELEM DevInfoElem,
  110. IN PDEVICE_INFO_SET pDeviceInfoSet
  111. );
  112. DWORD
  113. pSetupAddService(
  114. IN PINFCONTEXT LineContext,
  115. OUT PSVCNAME_NODE * SvcListHead,
  116. IN DWORD Flags,
  117. IN DEVINST DevInst, OPTIONAL
  118. OUT PBOOL NullDriverInstalled,
  119. IN PSETUP_LOG_CONTEXT LogContext
  120. );
  121. DWORD
  122. pSetupDeleteService(
  123. IN PINFCONTEXT LineContext,
  124. IN DWORD Flags,
  125. IN PSETUP_LOG_CONTEXT LogContext
  126. );
  127. DWORD
  128. DeleteServicesInList(
  129. IN PSVCNAME_NODE ServicesToDelete,
  130. IN PSETUP_LOG_CONTEXT LogContext
  131. );
  132. BOOL
  133. IsDevRemovedFromAllHwProfiles(
  134. IN PCTSTR DeviceInstanceId,
  135. IN HMACHINE hMachine
  136. );
  137. DWORD
  138. GetDevInstConfigFlags(
  139. IN DEVINST DevInst,
  140. IN DWORD Default,
  141. IN HMACHINE hMachine
  142. );
  143. DWORD
  144. pSetupRunLegacyInf(
  145. IN DEVINST DevInst,
  146. IN HWND OwnerWindow,
  147. IN PCTSTR InfFileName,
  148. IN PCTSTR InfOptionName,
  149. IN PCTSTR InfLanguageName,
  150. IN HINF InfHandle
  151. );
  152. PTSTR
  153. pSetupCmdLineAppendString(
  154. IN PTSTR CmdLine,
  155. IN PCTSTR Key,
  156. IN PCTSTR Value, OPTIONAL
  157. IN OUT PUINT StrLen,
  158. IN OUT PUINT BufSize
  159. );
  160. PTSTR
  161. DoServiceModsForLegacyInf(
  162. IN PTSTR ServiceList
  163. );
  164. BOOL
  165. _SetupDiInstallInterfaceDevices(
  166. IN HDEVINFO DeviceInfoSet,
  167. IN PSP_DEVINFO_DATA DeviceInfoData,
  168. IN BOOL DoFullInstall,
  169. IN HINF hDeviceInf, OPTIONAL
  170. IN HSPFILEQ UserFileQ OPTIONAL
  171. );
  172. BOOL
  173. _SetupDiRegisterCoDeviceInstallers(
  174. IN HDEVINFO DeviceInfoSet,
  175. IN PSP_DEVINFO_DATA DeviceInfoData,
  176. IN BOOL DoFullInstall,
  177. IN HINF hDeviceInf, OPTIONAL
  178. IN HSPFILEQ UserFileQ OPTIONAL
  179. );
  180. BOOL
  181. RetrieveAllDevNodesSharingDriversWithDevice(
  182. IN PDEVINFO_ELEM DevInfoElem,
  183. OUT PTSTR *Drivers,
  184. OUT PDEVNODE *DevNodes,
  185. OUT ULONG *NumberOfDevNodes,
  186. IN HMACHINE hMachine
  187. );
  188. VOID
  189. RestartSingleDevice(
  190. IN PDEVINFO_ELEM DevInfoElem,
  191. IN PDEVICE_INFO_SET pDeviceInfoSet,
  192. IN BOOL NullDriverInstall,
  193. IN PSETUP_LOG_CONTEXT LogContext
  194. );
  195. VOID
  196. RestartAllDevicesUsingDrivers(
  197. IN PDEVINFO_ELEM DevInfoElem,
  198. IN PDEVICE_INFO_SET pDeviceInfoSet,
  199. IN BOOL NullDriverInstall,
  200. IN PSETUP_LOG_CONTEXT LogContext
  201. );
  202. DWORD
  203. GetNewInfName(
  204. IN HWND Owner, OPTIONAL
  205. IN PCTSTR OemInfName,
  206. IN PCTSTR OemInfOriginalName,
  207. IN PCTSTR OemInfCatName, OPTIONAL
  208. OUT PTSTR NewInfName,
  209. IN DWORD NewInfNameSize,
  210. OUT PDWORD RequiredSize,
  211. OUT PNEWINF_COPYTYPE CopyNeeded,
  212. IN BOOL ReplaceOnly,
  213. IN PCTSTR DeviceDesc, OPTIONAL
  214. IN DWORD DriverSigningPolicy,
  215. IN DWORD Flags,
  216. IN PCTSTR AltCatalogFile, OPTIONAL
  217. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  218. OUT PDWORD DriverSigningError, OPTIONAL
  219. OUT PTSTR CatalogFilenameOnSystem,
  220. IN PSETUP_LOG_CONTEXT LogContext,
  221. IN OUT HCATADMIN *hCatAdmin OPTIONAL
  222. );
  223. VOID
  224. _WriteVetoLogEntry(
  225. IN PSETUP_LOG_CONTEXT LogContext,
  226. IN DWORD Level,
  227. IN DWORD MessageId,
  228. IN PCTSTR szDevID,
  229. IN PCTSTR szVetoName,
  230. IN PNP_VETO_TYPE dwVetoType
  231. )
  232. {
  233. static LPCTSTR VetoMap[] = {
  234. TEXT("PNP_VetoTypeUnknown"),
  235. TEXT("PNP_VetoLegacyDevice"),
  236. TEXT("PNP_VetoPendingClose"),
  237. TEXT("PNP_VetoWindowsApp"),
  238. TEXT("PNP_VetoWindowsService"),
  239. TEXT("PNP_VetoOutstandingOpen"),
  240. TEXT("PNP_VetoDevice"),
  241. TEXT("PNP_VetoDriver"),
  242. TEXT("PNP_VetoIllegalDeviceRequest"),
  243. TEXT("PNP_VetoInsufficientPower"),
  244. TEXT("PNP_VetoNonDisableable"),
  245. TEXT("PNP_VetoLegacyDriver"),
  246. TEXT("PNP_VetoInsufficientRights")
  247. };
  248. MYASSERT(dwVetoType < ARRAYSIZE(VetoMap));
  249. WriteLogEntry(
  250. LogContext,
  251. Level,
  252. MessageId,
  253. NULL,
  254. szDevID,
  255. szVetoName,
  256. dwVetoType,
  257. dwVetoType < ARRAYSIZE(VetoMap) ? VetoMap[dwVetoType] : TEXT("????")
  258. );
  259. }
  260. LPCTSTR
  261. _MapCmProbToString(
  262. IN DWORD prob
  263. )
  264. {
  265. #define PROBLEM_MAP_SIZE 0x32
  266. #if PROBLEM_MAP_SIZE != NUM_CM_PROB
  267. #error Add new problem code to ProbMap and update PROBLEM_MAP_SIZE.
  268. #endif
  269. static LPCTSTR ProbMap [PROBLEM_MAP_SIZE] = {
  270. NULL,
  271. TEXT("CM_PROB_NOT_CONFIGURED"),
  272. TEXT("CM_PROB_DEVLOADER_FAILED"),
  273. TEXT("CM_PROB_OUT_OF_MEMORY"),
  274. TEXT("CM_PROB_ENTRY_IS_WRONG_TYPE"),
  275. TEXT("CM_PROB_LACKED_ARBITRATOR"),
  276. TEXT("CM_PROB_BOOT_CONFIG_CONFLICT"),
  277. TEXT("CM_PROB_FAILED_FILTER"),
  278. TEXT("CM_PROB_DEVLOADER_NOT_FOUND"),
  279. TEXT("CM_PROB_INVALID_DATA"),
  280. TEXT("CM_PROB_FAILED_START"),
  281. TEXT("CM_PROB_LIAR"),
  282. TEXT("CM_PROB_NORMAL_CONFLICT"),
  283. TEXT("CM_PROB_NOT_VERIFIED"),
  284. TEXT("CM_PROB_NEED_RESTART"),
  285. TEXT("CM_PROB_REENUMERATION"),
  286. TEXT("CM_PROB_PARTIAL_LOG_CONF"),
  287. TEXT("CM_PROB_UNKNOWN_RESOURCE"),
  288. TEXT("CM_PROB_REINSTALL"),
  289. TEXT("CM_PROB_REGISTRY"),
  290. NULL,
  291. TEXT("CM_PROB_WILL_BE_REMOVED"),
  292. TEXT("CM_PROB_DISABLED"),
  293. TEXT("CM_PROB_DEVLOADER_NOT_READY"),
  294. TEXT("CM_PROB_DEVICE_NOT_THERE"),
  295. TEXT("CM_PROB_MOVED"),
  296. TEXT("CM_PROB_TOO_EARLY"),
  297. TEXT("CM_PROB_NO_VALID_LOG_CONF"),
  298. TEXT("CM_PROB_FAILED_INSTALL"),
  299. TEXT("CM_PROB_HARDWARE_DISABLED"),
  300. TEXT("CM_PROB_CANT_SHARE_IRQ"),
  301. TEXT("CM_PROB_FAILED_ADD"),
  302. TEXT("CM_PROB_DISABLED_SERVICE"),
  303. TEXT("CM_PROB_TRANSLATION_FAILED"),
  304. TEXT("CM_PROB_NO_SOFTCONFIG"),
  305. TEXT("CM_PROB_BIOS_TABLE"),
  306. TEXT("CM_PROB_IRQ_TRANSLATION_FAILED"),
  307. TEXT("CM_PROB_FAILED_DRIVER_ENTRY"),
  308. TEXT("CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD"),
  309. TEXT("CM_PROB_DRIVER_FAILED_LOAD"),
  310. TEXT("CM_PROB_DRIVER_SERVICE_KEY_INVALID"),
  311. TEXT("CM_PROB_LEGACY_SERVICE_NO_DEVICES"),
  312. TEXT("CM_PROB_DUPLICATE_DEVICE"),
  313. TEXT("CM_PROB_FAILED_POST_START"),
  314. TEXT("CM_PROB_HALTED"),
  315. TEXT("CM_PROB_PHANTOM"),
  316. TEXT("CM_PROB_SYSTEM_SHUTDOWN"),
  317. TEXT("CM_PROB_HELD_FOR_EJECT"),
  318. TEXT("CM_PROB_DRIVER_BLOCKED"),
  319. TEXT("CM_PROB_REGISTRY_TOO_LARGE")
  320. };
  321. LPCTSTR ProbText = NULL;
  322. MYASSERT(ARRAYSIZE(ProbMap)==NUM_CM_PROB);
  323. MYASSERT(prob<NUM_CM_PROB);
  324. if(prob < ARRAYSIZE(ProbMap)) {
  325. ProbText = ProbMap[prob];
  326. }
  327. if(!ProbText) {
  328. ProbText = TEXT("????");
  329. }
  330. return ProbText;
  331. }
  332. LPCTSTR
  333. _MapCmRetToString(
  334. IN DWORD cr
  335. )
  336. {
  337. LPCTSTR RetText = NULL;
  338. static LPCTSTR RetMap [] = {
  339. TEXT("CR_SUCCESS"),
  340. TEXT("CR_DEFAULT"),
  341. TEXT("CR_OUT_OF_MEMORY"),
  342. TEXT("CR_INVALID_POINTER"),
  343. TEXT("CR_INVALID_FLAG"),
  344. TEXT("CR_INVALID_DEVNODE"),
  345. TEXT("CR_INVALID_RES_DES"),
  346. TEXT("CR_INVALID_LOG_CONF"),
  347. TEXT("CR_INVALID_ARBITRATOR"),
  348. TEXT("CR_INVALID_NODELIST"),
  349. TEXT("CR_DEVNODE_HAS_REQS"),
  350. TEXT("CR_INVALID_RESOURCEID"),
  351. TEXT("CR_DLVXD_NOT_FOUND"),
  352. TEXT("CR_NO_SUCH_DEVNODE"),
  353. TEXT("CR_NO_MORE_LOG_CONF"),
  354. TEXT("CR_NO_MORE_RES_DES"),
  355. TEXT("CR_ALREADY_SUCH_DEVNODE"),
  356. TEXT("CR_INVALID_RANGE_LIST"),
  357. TEXT("CR_INVALID_RANGE"),
  358. TEXT("CR_FAILURE"),
  359. TEXT("CR_NO_SUCH_LOGICAL_DEV"),
  360. TEXT("CR_CREATE_BLOCKED"),
  361. TEXT("CR_NOT_SYSTEM_VM"),
  362. TEXT("CR_REMOVE_VETOED"),
  363. TEXT("CR_APM_VETOED"),
  364. TEXT("CR_INVALID_LOAD_TYPE"),
  365. TEXT("CR_BUFFER_SMALL"),
  366. TEXT("CR_NO_ARBITRATOR"),
  367. TEXT("CR_NO_REGISTRY_HANDLE"),
  368. TEXT("CR_REGISTRY_ERROR"),
  369. TEXT("CR_INVALID_DEVICE_ID"),
  370. TEXT("CR_INVALID_DATA"),
  371. TEXT("CR_INVALID_API"),
  372. TEXT("CR_DEVLOADER_NOT_READY"),
  373. TEXT("CR_NEED_RESTART"),
  374. TEXT("CR_NO_MORE_HW_PROFILES"),
  375. TEXT("CR_DEVICE_NOT_THERE"),
  376. TEXT("CR_NO_SUCH_VALUE"),
  377. TEXT("CR_WRONG_TYPE"),
  378. TEXT("CR_INVALID_PRIORITY"),
  379. TEXT("CR_NOT_DISABLEABLE"),
  380. TEXT("CR_FREE_RESOURCES"),
  381. TEXT("CR_QUERY_VETOED"),
  382. TEXT("CR_CANT_SHARE_IRQ"),
  383. TEXT("CR_NO_DEPENDENT"),
  384. TEXT("CR_SAME_RESOURCES"),
  385. TEXT("CR_NO_SUCH_REGISTRY_KEY"),
  386. TEXT("CR_INVALID_MACHINENAME"),
  387. TEXT("CR_REMOTE_COMM_FAILURE"),
  388. TEXT("CR_MACHINE_UNAVAILABLE"),
  389. TEXT("CR_NO_CM_SERVICES"),
  390. TEXT("CR_ACCESS_DENIED"),
  391. TEXT("CR_CALL_NOT_IMPLEMENTED"),
  392. TEXT("CR_INVALID_PROPERTY"),
  393. TEXT("CR_DEVICE_INTERFACE_ACTIVE"),
  394. TEXT("CR_NO_SUCH_DEVICE_INTERFACE"),
  395. TEXT("CR_INVALID_REFERENCE_STRING"),
  396. TEXT("CR_INVALID_CONFLICT_LIST"),
  397. TEXT("CR_INVALID_INDEX"),
  398. TEXT("CR_INVALID_STRUCTURE_SIZE")
  399. };
  400. MYASSERT(ARRAYSIZE(RetMap)==NUM_CR_RESULTS);
  401. MYASSERT(cr<NUM_CR_RESULTS);
  402. if(cr < ARRAYSIZE(RetMap)) {
  403. RetText = RetMap[cr];
  404. }
  405. if(!RetText) {
  406. RetText = TEXT("????");
  407. }
  408. return RetText;
  409. }
  410. BOOL
  411. WINAPI
  412. SetupDiInstallDevice(
  413. IN HDEVINFO DeviceInfoSet,
  414. IN OUT PSP_DEVINFO_DATA DeviceInfoData
  415. )
  416. /*++
  417. Routine Description:
  418. Default handler for DIF_INSTALLDEVICE
  419. This routine will install a device by performing a SetupInstallFromInfSection
  420. for the install section of the selected driver for the specified device
  421. information element. The device will then be started (if possible).
  422. NOTE: This API actually supports an OS/architecture-specific extension that
  423. may be used to specify multiple installation behaviors for a single device,
  424. based on the environment we're running under. The algorithm is as follows:
  425. We take the install section name, as specified in the driver node (for this
  426. example, it's "InstallSec"), and attempt to find one of the following INF
  427. sections (searched for in the order specified):
  428. If we're running under Windows 95:
  429. 1. InstallSec.Win
  430. 2. InstallSec
  431. If we're running under Windows NT:
  432. 1. InstallSec.NT<platform> (platform is "x86", "MIPS", "Alpha", or "PPC")
  433. 2. InstallSec.NT
  434. 3. InstallSec
  435. The first section that we find is the one we'll use to do the installation. This
  436. section name is also what we'll base our ".Hw" and ".Services" installation against.
  437. (E.g., if we match on "InstallSec.NTAlpha", then the service install section must be
  438. named "InstallSec.NTAlpha.Services".)
  439. The original install section name (i.e., the one specified in the driver node), will
  440. be written as-is to the driver key's "InfSection" value entry, just as it was in the
  441. past. The extension that we use (if any) will be stored in the device's driver key
  442. as the REG_SZ value, "InfSectionExt". E.g.,
  443. InfSection : REG_SZ : "InstallSec"
  444. InfSectionExt : REG_SZ : ".NTMIPS"
  445. If we successfully install the device, we'll kick off RunOnce. NOTE: We
  446. must do this _regardless_ of whether or not the device was dynamically
  447. brought on-line with its newly-installed driver/settings. This is because,
  448. for server-side device installations, the RunOnce processing is done by the
  449. user-mode PnP manager. We can't put this off until 'later'. Also, since
  450. anyone can kick off a RunOnce at any time, you really would have no
  451. assurance that the RunOnce would be postponed until after reboot anyway.
  452. Arguments:
  453. DeviceInfoSet - Supplies a handle to the device information set for which a
  454. driver is to be installed.
  455. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure for which
  456. a driver is to be installed. This is an IN OUT parameter, since the
  457. DevInst field of the structure may be updated with a new handle value upon
  458. return.
  459. Return Value:
  460. If the function succeeds, the return value is TRUE.
  461. If the function fails, the return value is FALSE. To get extended error
  462. information, call GetLastError.
  463. Remarks:
  464. If no driver is selected for the specified device information element, then a
  465. NULL driver will be installed.
  466. Upon return, the install parameters Flags will indicate whether the system
  467. needs to be rebooted or restarted in order for the device to be started.
  468. During GUI-mode setup on Windows NT, quiet-install behavior is always
  469. employed in the absence of a user-supplied file queue, regardless of
  470. whether the device information element has the DI_QUIETINSTALL flag set.
  471. --*/
  472. {
  473. return _SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData, TRUE);
  474. }
  475. BOOL
  476. _SetupDiInstallDevice(
  477. IN HDEVINFO DeviceInfoSet,
  478. IN OUT PSP_DEVINFO_DATA DeviceInfoData,
  479. IN BOOL DoFullInstall
  480. )
  481. /*++
  482. Routine Description:
  483. Worker routine for both SetupDiInstallDevice and SetupDiInstallDriverFiles.
  484. See the description of SetupDiInstallDevice for more information.
  485. (jamiehun) If backups are enabled (DI_FLAGSEX_BACKUPOLDFILES or DI_FLAGSEX_BACKUPONREPLACE)
  486. then old inf file is backed up.
  487. Arguments:
  488. DeviceInfoSet - Supplies a handle to the device information set for which a
  489. driver is to be installed.
  490. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure for which
  491. a driver is to be installed. This is an IN OUT parameter, since the
  492. DevInst field of the structure may be updated with a new handle value upon
  493. return.
  494. DoFullInstall - If TRUE, then an entire device installation is performed,
  495. otherwise, only the driver files are copied.
  496. Return Value:
  497. If the function succeeds, the return value is TRUE.
  498. If the function fails, the return value is FALSE. To get extended error
  499. information, call GetLastError.
  500. --*/
  501. {
  502. PDEVICE_INFO_SET pDeviceInfoSet;
  503. DWORD Err, ScanQueueResult;
  504. PDEVINFO_ELEM DevInfoElem = NULL;
  505. PTSTR szInfFileName, szInfSectionName;
  506. PTSTR szInfSectionExt = NULL;
  507. TCHAR InfSectionWithExt[MAX_PATH];
  508. DWORD InfSectionWithExtLength;
  509. HINF hDeviceInf = INVALID_HANDLE_VALUE;
  510. HKEY hkDrv = INVALID_HANDLE_VALUE;
  511. PSP_FILE_CALLBACK MsgHandler;
  512. PVOID MsgHandlerContext;
  513. BOOL MsgHandlerIsNativeCharWidth;
  514. HSPFILEQ UserFileQ;
  515. INFCONTEXT InfContext;
  516. DWORD dwConfigFlags=0;
  517. ULONG cbData;
  518. PTSTR DevIdBuffer = NULL;
  519. PCTSTR TempString;
  520. ULONG ulStatus, ulProblem;
  521. DEVINST dnReenum = 0;
  522. TCHAR szNewName[MAX_PATH];
  523. BOOL OemInfFileToCopy = FALSE;
  524. BOOL InfFromOemPath = FALSE;
  525. BOOL DeleteDevKey = FALSE;
  526. PSVCNAME_NODE DeleteServiceList = NULL;
  527. BOOL FreeMsgHandlerContext = FALSE;
  528. BOOL CloseUserFileQ = FALSE;
  529. HWND hwndParent;
  530. BOOL DoFileCopying;
  531. DWORD DevInstCapabilities;
  532. TCHAR DeviceFullID[MAX_DEVICE_ID_LEN];
  533. DWORD BackupFlags = 0;
  534. BOOL NullDriverInstall = FALSE;
  535. PINSTALLED_INF_CLEANUP InfsToCleanUp = NULL;
  536. INT FileQueueNeedsReboot;
  537. PSETUP_LOG_CONTEXT LogContext = NULL;
  538. DWORD slot_deviceID = 0;
  539. DWORD slot_section = 0;
  540. DWORD FileQueueFlags;
  541. BOOL NoProgressUI;
  542. TCHAR className[MAX_CLASS_NAME_LEN];
  543. PSP_ALTPLATFORM_INFO_V2 ValidationPlatform = NULL;
  544. #ifndef UNICODE
  545. TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
  546. #endif
  547. #if MAX_SECT_NAME_LEN > MAX_PATH
  548. #error MAX_SECT_NAME_LEN is larger than MAX_PATH--fix InfSectionWithExt!
  549. #endif
  550. ASSERT_HEAP_IS_VALID();
  551. //
  552. // We can only install a device if a device was specified.
  553. //
  554. if(!DeviceInfoData) {
  555. SetLastError(ERROR_INVALID_PARAMETER);
  556. return FALSE;
  557. }
  558. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  559. SetLastError(ERROR_INVALID_HANDLE);
  560. return FALSE;
  561. }
  562. //
  563. // Make sure we're local
  564. //
  565. if(NULL != pDeviceInfoSet->hMachine ) { //&& !g_ReadOnlyRemote ??
  566. //
  567. // hDevInfo may be valid, but it's not for this machine
  568. //
  569. UnlockDeviceInfoSet(pDeviceInfoSet);
  570. SetLastError(ERROR_INVALID_HANDLE);
  571. return FALSE;
  572. }
  573. Err = NO_ERROR;
  574. try {
  575. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  576. DeviceInfoData,
  577. NULL))) {
  578. Err = ERROR_INVALID_PARAMETER;
  579. goto clean0;
  580. }
  581. //
  582. // This routine can't install a non-native driver
  583. //
  584. if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_ALTPLATFORM_DRVSEARCH) {
  585. Err = ERROR_INVALID_FLAGS;
  586. goto clean0;
  587. }
  588. //
  589. // Make sure we only use the devinfo element's window if it's valid.
  590. //
  591. if(hwndParent = DevInfoElem->InstallParamBlock.hwndParent) {
  592. if(!IsWindow(hwndParent)) {
  593. hwndParent = NULL;
  594. }
  595. }
  596. //
  597. // set the local log context before it gets used.
  598. //
  599. LogContext = DevInfoElem->InstallParamBlock.LogContext;
  600. WriteLogEntry(
  601. LogContext,
  602. DRIVER_LOG_TIME,
  603. MSG_LOG_BEGIN_INSTALL_TIME,
  604. NULL); // text message
  605. //
  606. // obtain the full id of the device we are (re)installing
  607. //
  608. if( CM_Get_Device_ID(DevInfoElem->DevInst,
  609. DeviceFullID,
  610. SIZECHARS(DeviceFullID),
  611. 0
  612. ) != CR_SUCCESS ) {
  613. Err = ERROR_INVALID_HANDLE;
  614. goto clean0;
  615. }
  616. //
  617. // If we are installing a driver, then the selected driver pointer will be
  618. // non-NULL, otherwise we are actually removing the driver (i.e., installing the
  619. // NULL driver)
  620. //
  621. if(DevInfoElem->SelectedDriver) {
  622. if(DoFullInstall) {
  623. if(slot_deviceID == 0) {
  624. slot_deviceID = AllocLogInfoSlotOrLevel(LogContext,DRIVER_LOG_INFO,FALSE);
  625. }
  626. WriteLogEntry(
  627. LogContext,
  628. slot_deviceID,
  629. MSG_LOG_DO_FULL_INSTALL,
  630. NULL, // text message
  631. DeviceFullID);
  632. //
  633. // Create the Driver Reg Key.
  634. //
  635. if((hkDrv = SetupDiCreateDevRegKey(DeviceInfoSet,
  636. DeviceInfoData,
  637. DICS_FLAG_GLOBAL,
  638. 0,
  639. DIREG_DRV,
  640. NULL,
  641. NULL)) == INVALID_HANDLE_VALUE) {
  642. Err = GetLastError();
  643. goto clean0;
  644. }
  645. } else {
  646. DWORD slot = slot_deviceID;
  647. if(slot_deviceID == 0) {
  648. if(DevInfoElem->InstallParamBlock.Flags & DI_NOVCP) {
  649. slot = AllocLogInfoSlotOrLevel(LogContext,DRIVER_LOG_VERBOSE,TRUE); // may be being copied for someone else - keep this around
  650. } else {
  651. slot_deviceID = slot = AllocLogInfoSlotOrLevel(LogContext,DRIVER_LOG_INFO,FALSE); // we do copy ourselves
  652. }
  653. }
  654. WriteLogEntry(
  655. LogContext,
  656. slot,
  657. MSG_LOG_DO_COPY_INSTALL,
  658. NULL, // text message
  659. DeviceFullID);
  660. //
  661. // Make sure we aren't trying to do a copy-only install on a legacy
  662. // driver--we don't know how to do that!
  663. //
  664. if(DevInfoElem->SelectedDriver->Flags & DNF_LEGACYINF) {
  665. Err = ERROR_WRONG_INF_STYLE;
  666. goto clean0;
  667. }
  668. }
  669. szInfFileName = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  670. DevInfoElem->SelectedDriver->InfFileName
  671. );
  672. szInfSectionName = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  673. DevInfoElem->SelectedDriver->InfSectionName
  674. );
  675. if((hDeviceInf = SetupOpenInfFile(szInfFileName,
  676. NULL,
  677. ((DevInfoElem->SelectedDriver->Flags & DNF_LEGACYINF)
  678. ? INF_STYLE_OLDNT
  679. : INF_STYLE_WIN4),
  680. NULL)) == INVALID_HANDLE_VALUE) {
  681. Err = GetLastError();
  682. goto clean0;
  683. }
  684. //
  685. // Give the INF whatever the local log context is.
  686. //
  687. InheritLogContext(LogContext, &((PLOADED_INF) hDeviceInf)->LogContext);
  688. SetLogSectionName(LogContext, TEXT("Driver Install"));
  689. //
  690. // Figure out whether we need to copy files. (Ignore the DI_NOFILECOPY flag if we're
  691. // doing a copy-only installation--that's what setupx does.)
  692. //
  693. DoFileCopying = (!(DevInfoElem->InstallParamBlock.Flags & DI_NOFILECOPY) || !DoFullInstall);
  694. //
  695. // Unless we happen to be installing from a legacy INF, we want to find out the 'real'
  696. // install section we should be using (i.e., the potentially OS/architecture-specific
  697. // one.
  698. //
  699. if(!(DevInfoElem->SelectedDriver->Flags & DNF_LEGACYINF)) {
  700. if(!SetupDiGetActualSectionToInstall(hDeviceInf,
  701. szInfSectionName,
  702. InfSectionWithExt,
  703. SIZECHARS(InfSectionWithExt),
  704. &InfSectionWithExtLength,
  705. &szInfSectionExt
  706. )) {
  707. Err = GetLastError();
  708. goto clean0;
  709. }
  710. //
  711. // Append the layout INF, if necessary.
  712. //
  713. if(DoFileCopying) {
  714. SetupOpenAppendInfFile(NULL, hDeviceInf, NULL);
  715. }
  716. //
  717. // Append-load any included INFs specified in an "include=" line in our
  718. // install section.
  719. //
  720. AppendLoadIncludedInfs(hDeviceInf, szInfFileName, InfSectionWithExt, DoFileCopying);
  721. }
  722. ASSERT_HEAP_IS_VALID();
  723. //
  724. // Now perform file installation activities...
  725. //
  726. if(!DoFileCopying || (DevInfoElem->SelectedDriver->Flags & DNF_LEGACYINF)) {
  727. //
  728. // We're not supposed to do any file copying, or we're installing
  729. // from a legacy INF (where file copying is handled differently).
  730. // In either case, we still need to have the INF copied to the
  731. // INF directory (along with its associated catalog, if any).
  732. //
  733. if(pSetupInfIsFromOemLocation(szInfFileName, TRUE)) {
  734. TCHAR CatalogName[MAX_PATH];
  735. TCHAR OriginalInfName[MAX_PATH];
  736. TCHAR CatalogFilenameOnSystem[MAX_PATH];
  737. BOOL DifferentOriginalName, UseOriginalInfName;
  738. DWORD PolicyToUse;
  739. //
  740. // Retrieve (potentially decorated) CatalogFile= entry, if
  741. // present, from [version] section.
  742. //
  743. // Note: We're safe in casting our INF handle straight to a
  744. // PLOADED_INF (without even locking it), since this INF
  745. // handle will never be seen outside of this routine.
  746. //
  747. Err = pGetInfOriginalNameAndCatalogFile(
  748. (PLOADED_INF)hDeviceInf,
  749. NULL,
  750. &DifferentOriginalName,
  751. OriginalInfName,
  752. SIZECHARS(OriginalInfName),
  753. CatalogName,
  754. SIZECHARS(CatalogName),
  755. NULL // always native OS/arch (ver doesn't matter for CatalogFile=)
  756. );
  757. if(Err == NO_ERROR) {
  758. if(*CatalogName) {
  759. TempString = CatalogName;
  760. } else {
  761. TempString = NULL;
  762. }
  763. } else {
  764. goto clean0;
  765. }
  766. PolicyToUse = GetCodeSigningPolicyForInf(LogContext,
  767. hDeviceInf,
  768. &ValidationPlatform,
  769. &UseOriginalInfName
  770. );
  771. //
  772. // An exception INF can't be used in a device installation!
  773. //
  774. if(UseOriginalInfName) {
  775. Err = ERROR_INVALID_CLASS;
  776. goto clean0;
  777. }
  778. //
  779. // If this is a legacy INF, then we _do_ want to copy it if
  780. // it doesn't already exist ('cause this is the only chance
  781. // we get!). However, if this is not a legacy INF, that
  782. // means we aren't supposed to be copying files, hence we
  783. // want to fail if the INF doesn't already exist in the
  784. // Inf directory.
  785. //
  786. if(_SetupCopyOEMInf(szInfFileName,
  787. NULL, // default source location to where INF presently is
  788. (DevInfoElem->SelectedDriver->Flags & DNF_INET_DRIVER)
  789. ? SPOST_URL : SPOST_PATH,
  790. ((DevInfoElem->SelectedDriver->Flags & DNF_LEGACYINF)
  791. ? SP_COPY_NOOVERWRITE
  792. : SP_COPY_REPLACEONLY),
  793. szNewName,
  794. SIZECHARS(szNewName),
  795. NULL,
  796. NULL,
  797. (DifferentOriginalName ? OriginalInfName
  798. : pSetupGetFileTitle(szInfFileName)),
  799. TempString,
  800. hwndParent,
  801. pStringTableStringFromId(pDeviceInfoSet->StringTable,
  802. DevInfoElem->SelectedDriver->DrvDescription),
  803. PolicyToUse,
  804. SCOI_TRY_UPDATE_PNF // not fatal if existing PNF locked
  805. | ((DevInfoElem->SelectedDriver->Flags & DNF_LEGACYINF)
  806. ? 0 : SCOI_NO_UI_ON_SIGFAIL),
  807. NULL,
  808. ValidationPlatform,
  809. NULL,
  810. CatalogFilenameOnSystem,
  811. LogContext,
  812. NULL)) {
  813. //
  814. // If this was a legacy INF, we successfully copied this
  815. // INF to a new filename in the INF directory--set a
  816. // flag that to let us know if we need to clean it up
  817. // later in case we encounter an error.
  818. //
  819. if(DevInfoElem->SelectedDriver->Flags & DNF_LEGACYINF) {
  820. OemInfFileToCopy = TRUE;
  821. }
  822. } else {
  823. Err = GetLastError();
  824. if(Err == ERROR_FILE_EXISTS) {
  825. //
  826. // We couldn't copy the legacy INF because it
  827. // already exists in the %windir%\Inf directory.
  828. // Since it probably has better source path
  829. // information than we do, it's best to leave the
  830. // PNF alone. We also need this information about
  831. // the INF's existence to that we know whether or
  832. // not to blow away the INF later in case we hit a
  833. // failure.
  834. //
  835. MYASSERT(DevInfoElem->SelectedDriver->Flags & DNF_LEGACYINF);
  836. Err = NO_ERROR;
  837. } else {
  838. //
  839. // SetupCopyOEMInf failed for some reason other than
  840. // file-already-exists (most likely, because we were
  841. // dealing with a new-style device INF that didn't
  842. // already exist in the Inf directory). Bail now.
  843. //
  844. goto clean0;
  845. }
  846. }
  847. }
  848. if(DevInfoElem->SelectedDriver->Flags & DNF_LEGACYINF) {
  849. PTSTR szLegacyInfLangName;
  850. //
  851. // We're doing a script-driven install using a legacy INF.
  852. // Since we can't control what takes place when this INF
  853. // gets run, we can't split this out into various phases
  854. // (file copying, registry modification, etc.). So we
  855. // consider the legacy INF installation action to be a file
  856. // copy action. No other actions are performed with this
  857. // INF throughout the rest of the installation.
  858. //
  859. szLegacyInfLangName = pStringTableStringFromId(
  860. pDeviceInfoSet->StringTable,
  861. DevInfoElem->SelectedDriver->LegacyInfLang
  862. );
  863. Err = pSetupRunLegacyInf(DevInfoElem->DevInst,
  864. hwndParent,
  865. szInfFileName,
  866. szInfSectionName,
  867. szLegacyInfLangName,
  868. hDeviceInf
  869. );
  870. if(Err != NO_ERROR) {
  871. goto clean0;
  872. }
  873. }
  874. } else {
  875. //
  876. // If the DI_NOVCP flag is set, then just queue up the file
  877. // copy/rename/delete operations. Otherwise, perform the
  878. // actions.
  879. //
  880. if(DevInfoElem->InstallParamBlock.Flags & DI_NOVCP) {
  881. //
  882. // We must have a user-supplied file queue.
  883. //
  884. MYASSERT(DevInfoElem->InstallParamBlock.UserFileQ);
  885. UserFileQ = DevInfoElem->InstallParamBlock.UserFileQ;
  886. } else {
  887. //
  888. // Since we may need to check the queued files to determine
  889. // whether file copy is necessary, we have to open our own
  890. // queue, and commit it ourselves.
  891. //
  892. if((UserFileQ = SetupOpenFileQueue()) != INVALID_HANDLE_VALUE) {
  893. CloseUserFileQ = TRUE;
  894. } else {
  895. //
  896. // SetupOpenFileQueue sets actual error
  897. //
  898. Err = GetLastError();
  899. goto clean0;
  900. }
  901. }
  902. //
  903. // Maybe replace the file queue's log context with the Inf's
  904. //
  905. if (LogContext) {
  906. InheritLogContext(LogContext,
  907. &((PSP_FILE_QUEUE) UserFileQ)->LogContext);
  908. }
  909. if(slot_section == 0) {
  910. //
  911. // we haven't done anything about logging section yet...
  912. //
  913. slot_section = AllocLogInfoSlotOrLevel(LogContext,DRIVER_LOG_VERBOSE,FALSE);
  914. //
  915. // Say what section is about to be installed.
  916. //
  917. WriteLogEntry(LogContext,
  918. slot_section,
  919. MSG_LOG_INSTALLING_SECTION_FROM,
  920. NULL,
  921. InfSectionWithExt,
  922. szInfFileName);
  923. }
  924. //
  925. // DI_FLAGSEX_PREINSTALLBACKUP has precedence over DI_FLAGSEX_BACKUPONREPLACE
  926. //
  927. if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_PREINSTALLBACKUP) {
  928. BackupFlags |= SP_BKFLG_PREBACKUP | SP_BKFLG_CALLBACK;
  929. } else if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_BACKUPONREPLACE) {
  930. BackupFlags |= SP_BKFLG_LATEBACKUP | SP_BKFLG_CALLBACK;
  931. }
  932. if(BackupFlags != 0) {
  933. WriteLogEntry(
  934. LogContext,
  935. DRIVER_LOG_TIME,
  936. MSG_LOG_BEGIN_PREP_BACKUP_TIME,
  937. NULL); // text message
  938. pSetupGetBackupQueue(DeviceFullID, UserFileQ, BackupFlags);
  939. //
  940. // We don't care about errors here
  941. //
  942. }
  943. ASSERT_HEAP_IS_VALID();
  944. WriteLogEntry(
  945. LogContext,
  946. DRIVER_LOG_TIME,
  947. MSG_LOG_BEGIN_INSTALL_FROM_INF_TIME,
  948. NULL); // text message
  949. Err = InstallFromInfSectionAndNeededSections(NULL,
  950. hDeviceInf,
  951. InfSectionWithExt,
  952. SPINST_FILES,
  953. NULL,
  954. NULL,
  955. SP_COPY_NEWER_OR_SAME | SP_COPY_LANGUAGEAWARE |
  956. ((DevInfoElem->InstallParamBlock.Flags & DI_NOBROWSE) ? SP_COPY_NOBROWSE : 0),
  957. NULL,
  958. NULL,
  959. INVALID_HANDLE_VALUE,
  960. NULL,
  961. UserFileQ
  962. );
  963. //
  964. // If we're not doing a full install (i.e., file copy-only), then we also want to
  965. // queue up any file operations for co-installer registration and device interface
  966. // installation.
  967. //
  968. if(!DoFullInstall && (Err == NO_ERROR)) {
  969. WriteLogEntry(
  970. LogContext,
  971. DRIVER_LOG_TIME,
  972. MSG_LOG_BEGIN_CO_INSTALLER_COPY_TIME,
  973. NULL); // text message
  974. if(!_SetupDiRegisterCoDeviceInstallers(DeviceInfoSet, DeviceInfoData, FALSE, hDeviceInf, UserFileQ) ||
  975. !_SetupDiInstallInterfaceDevices(DeviceInfoSet, DeviceInfoData, FALSE, hDeviceInf, UserFileQ)) {
  976. Err = GetLastError();
  977. }
  978. }
  979. //
  980. // Mark the queue as a device install queue (and make sure
  981. // there's a catalog node representing our device INF in the
  982. // queue).
  983. //
  984. Err = MarkQueueForDeviceInstall(UserFileQ,
  985. hDeviceInf,
  986. pStringTableStringFromId(
  987. pDeviceInfoSet->StringTable,
  988. DevInfoElem->SelectedDriver->DrvDescription)
  989. );
  990. if(CloseUserFileQ) {
  991. if(Err == NO_ERROR) {
  992. //
  993. // If the parameter block contains an install message handler, then use it,
  994. // otherwise, initialize our default one.
  995. //
  996. if(DevInfoElem->InstallParamBlock.InstallMsgHandler) {
  997. MsgHandler = DevInfoElem->InstallParamBlock.InstallMsgHandler;
  998. MsgHandlerContext = DevInfoElem->InstallParamBlock.InstallMsgHandlerContext;
  999. MsgHandlerIsNativeCharWidth = DevInfoElem->InstallParamBlock.InstallMsgHandlerIsNativeCharWidth;
  1000. } else {
  1001. NoProgressUI = (GuiSetupInProgress || (DevInfoElem->InstallParamBlock.Flags & DI_QUIETINSTALL));
  1002. MsgHandlerContext = SetupInitDefaultQueueCallbackEx(
  1003. hwndParent,
  1004. (NoProgressUI ? INVALID_HANDLE_VALUE : NULL),
  1005. 0,
  1006. 0,
  1007. NULL
  1008. );
  1009. if(MsgHandlerContext) {
  1010. FreeMsgHandlerContext = TRUE;
  1011. MsgHandler = SetupDefaultQueueCallback;
  1012. MsgHandlerIsNativeCharWidth = TRUE;
  1013. } else {
  1014. Err = ERROR_NOT_ENOUGH_MEMORY;
  1015. }
  1016. }
  1017. //
  1018. // Call _SetupVerifyQueuedCatalogs separately (i.e.,
  1019. // don't let it happen automatically as a result of
  1020. // scanning/committing the queue that happens below).
  1021. // We do this beforehand so that we know what unique
  1022. // name was generated when an OEM INF was installed into
  1023. // %windir%\Inf (in case we need to delete the
  1024. // INF/PNF/CAT files later if we encounter an error).
  1025. //
  1026. if(Err == NO_ERROR) {
  1027. WriteLogEntry(
  1028. LogContext,
  1029. DRIVER_LOG_TIME,
  1030. MSG_LOG_BEGIN_VERIFY_CAT_TIME,
  1031. NULL); // text message
  1032. Err = _SetupVerifyQueuedCatalogs(
  1033. hwndParent,
  1034. UserFileQ,
  1035. (VERCAT_INSTALL_INF_AND_CAT |
  1036. ((DevInfoElem->SelectedDriver->Flags & DNF_INET_DRIVER) ? VERCAT_PRIMARY_DEVICE_INF_FROM_INET : 0)),
  1037. szNewName,
  1038. &OemInfFileToCopy
  1039. );
  1040. WriteLogEntry(
  1041. LogContext,
  1042. DRIVER_LOG_TIME,
  1043. MSG_LOG_END_VERIFY_CAT_TIME,
  1044. NULL); // text message
  1045. }
  1046. ASSERT_HEAP_IS_VALID();
  1047. if (Err == NO_ERROR) {
  1048. //
  1049. // We successfully queued up the file operations and
  1050. // we have a message handler to use--now we need to
  1051. // commit the queue. First off, though, we should
  1052. // check to see if the files are already there.
  1053. //
  1054. // ScanQueueResult can have 1 of 3 values:
  1055. //
  1056. // 0: Some files were missing or not valid--must
  1057. // commit queue.
  1058. //
  1059. // 1: All files to be copied are already present and
  1060. // valid, and the queue is empty--skip committing
  1061. // queue.
  1062. //
  1063. // 2: All files to be copied are present and valid,
  1064. // but del/ren/backup queues not empty--must
  1065. // commit queue. The copy queue will have been
  1066. // emptied, so only del/ren/backup functions will
  1067. // be performed.
  1068. //
  1069. // (jamiehun) If DI_FLAGSEX_PREINSTALLBACKUP is
  1070. // specified and there are items to be backed up, it
  1071. // is covered in (2) the inf file will have already
  1072. // been backed up
  1073. //
  1074. WriteLogEntry(
  1075. LogContext,
  1076. DRIVER_LOG_TIME,
  1077. MSG_LOG_BEGIN_PRESCAN_TIME,
  1078. NULL); // text message
  1079. if(!SetupScanFileQueue(UserFileQ,
  1080. SPQ_SCAN_FILE_VALIDITY |
  1081. SPQ_SCAN_PRUNE_COPY_QUEUE,
  1082. hwndParent,
  1083. NULL,
  1084. NULL,
  1085. &ScanQueueResult)) {
  1086. //
  1087. // SetupScanFileQueue should really never
  1088. // fail when you don't ask it to call a
  1089. // callback routine, but if it does, just
  1090. // go ahead and commit the queue.
  1091. //
  1092. ScanQueueResult = 0;
  1093. }
  1094. if(ScanQueueResult != 1) {
  1095. //
  1096. // Copy enqueued files.
  1097. //
  1098. WriteLogEntry(
  1099. LogContext,
  1100. DRIVER_LOG_TIME,
  1101. MSG_LOG_BEGIN_COMMIT_TIME,
  1102. NULL); // text message
  1103. if(_SetupCommitFileQueue(hwndParent,
  1104. UserFileQ,
  1105. MsgHandler,
  1106. MsgHandlerContext,
  1107. MsgHandlerIsNativeCharWidth
  1108. )) {
  1109. //
  1110. // Check to see whether a reboot is required
  1111. // as a result of committing the queue (i.e.,
  1112. // because files were in use, or the INF
  1113. // requested a reboot).
  1114. //
  1115. FileQueueNeedsReboot = SetupPromptReboot(UserFileQ, NULL, TRUE);
  1116. //
  1117. // This should never fail...
  1118. //
  1119. MYASSERT(FileQueueNeedsReboot != -1);
  1120. if(FileQueueNeedsReboot) {
  1121. SetDevnodeNeedsRebootProblem(DevInfoElem, pDeviceInfoSet, MSG_LOG_REBOOT_REASON_INUSE);
  1122. }
  1123. } else {
  1124. Err = GetLastError();
  1125. }
  1126. }
  1127. //
  1128. // If no files were modified as a result of commiting
  1129. // the file queue, then set the DI_FLAGSEX_RESTART_DEVICE_ONLY
  1130. // flag so that we only restart this one device, as opposed
  1131. // to restarting this device and all other device that
  1132. // are sharing a driver or filter with this device.
  1133. //
  1134. if (SetupGetFileQueueFlags(UserFileQ, &FileQueueFlags) &&
  1135. !(FileQueueFlags & SPQ_FLAG_FILES_MODIFIED)) {
  1136. DevInfoElem->InstallParamBlock.FlagsEx |= DI_FLAGSEX_RESTART_DEVICE_ONLY;
  1137. }
  1138. //
  1139. // Terminate the default queue callback, if it was created.
  1140. //
  1141. if(FreeMsgHandlerContext) {
  1142. SetupTermDefaultQueueCallback(MsgHandlerContext);
  1143. FreeMsgHandlerContext = FALSE;
  1144. }
  1145. }
  1146. }
  1147. //
  1148. // Close our file queue handle.
  1149. //
  1150. SetupCloseFileQueue(UserFileQ);
  1151. CloseUserFileQ = FALSE;
  1152. }
  1153. if(Err != NO_ERROR) {
  1154. goto clean0;
  1155. }
  1156. }
  1157. //
  1158. // If the copy succeeded (or in setup's case was queued), then
  1159. // it's time to update the registry and ini files.
  1160. //
  1161. if(Err == NO_ERROR) {
  1162. //
  1163. // We've got some registry modifications to do, but we don't want to
  1164. // do them if this is a copy-only installation.
  1165. //
  1166. if(DoFullInstall) {
  1167. //
  1168. // Do every thing left over (but only if we're not installing from a
  1169. // legacy INF).
  1170. //
  1171. if(!(DevInfoElem->SelectedDriver->Flags & DNF_LEGACYINF)) {
  1172. //
  1173. // Skip installation of basic log configs if this is an enumerated device.
  1174. //
  1175. if((CM_Get_DevInst_Status_Ex(&ulStatus, &ulProblem, DevInfoElem->DevInst, 0,pDeviceInfoSet->hMachine) != CR_SUCCESS) ||
  1176. (ulStatus & DN_ROOT_ENUMERATED)) {
  1177. LOG_CONF LogConf;
  1178. WriteLogEntry(
  1179. LogContext,
  1180. DRIVER_LOG_TIME,
  1181. MSG_LOG_BEGIN_WRITE_BASIC_CFGS_TIME,
  1182. NULL); // text message
  1183. //
  1184. // Clean out all existing BASIC_LOG_CONF LogConfigs before writing out new ones from
  1185. // the INF.
  1186. //
  1187. while(CM_Get_First_Log_Conf_Ex(&LogConf, DevInfoElem->DevInst, BASIC_LOG_CONF,pDeviceInfoSet->hMachine) == CR_SUCCESS) {
  1188. CM_Free_Log_Conf(LogConf, 0);
  1189. CM_Free_Log_Conf_Handle(LogConf);
  1190. }
  1191. //
  1192. // Now write out the new basic log configs.
  1193. //
  1194. Err = InstallFromInfSectionAndNeededSections(NULL,
  1195. hDeviceInf,
  1196. InfSectionWithExt,
  1197. SPINST_LOGCONFIG,
  1198. NULL,
  1199. NULL,
  1200. 0,
  1201. NULL,
  1202. NULL,
  1203. DeviceInfoSet,
  1204. DeviceInfoData,
  1205. NULL
  1206. );
  1207. } else {
  1208. //
  1209. // For non-root-enumerated devices, check to see if there's an [<InstallSec>.LogConfigOverride]
  1210. // section, and if so, run it.
  1211. //
  1212. CopyMemory(&(InfSectionWithExt[InfSectionWithExtLength - 1]),
  1213. pszLogConfigOverrideSectionSuffix,
  1214. sizeof(pszLogConfigOverrideSectionSuffix)
  1215. );
  1216. if(SetupFindFirstLine(hDeviceInf, InfSectionWithExt, NULL, &InfContext)) {
  1217. LOG_CONF LogConf;
  1218. WriteLogEntry(
  1219. LogContext,
  1220. DRIVER_LOG_TIME,
  1221. MSG_LOG_BEGIN_WRITE_OVERRIDE_CFGS_TIME,
  1222. NULL); // text message
  1223. //
  1224. // Clean out all existing OVERRIDE_LOG_CONF LogConfigs before writing out new ones from
  1225. // the INF.
  1226. //
  1227. while(CM_Get_First_Log_Conf_Ex(&LogConf, DevInfoElem->DevInst,
  1228. OVERRIDE_LOG_CONF,pDeviceInfoSet->hMachine) == CR_SUCCESS) {
  1229. CM_Free_Log_Conf(LogConf, 0);
  1230. CM_Free_Log_Conf_Handle(LogConf);
  1231. }
  1232. //
  1233. // Now write out the new override log configs.
  1234. //
  1235. Err = InstallFromInfSectionAndNeededSections(NULL,
  1236. hDeviceInf,
  1237. InfSectionWithExt,
  1238. SPINST_LOGCONFIG | SPINST_LOGCONFIGS_ARE_OVERRIDES,
  1239. NULL,
  1240. NULL,
  1241. 0,
  1242. NULL,
  1243. NULL,
  1244. DeviceInfoSet,
  1245. DeviceInfoData,
  1246. NULL
  1247. );
  1248. }
  1249. //
  1250. // Make sure we strip off the ".LogConfigOverride" we added above.
  1251. //
  1252. InfSectionWithExt[InfSectionWithExtLength - 1] = TEXT('\0');
  1253. }
  1254. if((Err == NO_ERROR) && !(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY)) {
  1255. //
  1256. // (Don't pass devinfo set and element here, because we're writing
  1257. // to the _driver_ key, not the _device_ key.)
  1258. //
  1259. WriteLogEntry(
  1260. LogContext,
  1261. DRIVER_LOG_TIME,
  1262. MSG_LOG_BEGIN_INSTALL_REG_TIME,
  1263. NULL); // text message
  1264. Err = InstallFromInfSectionAndNeededSections(NULL,
  1265. hDeviceInf,
  1266. InfSectionWithExt,
  1267. SPINST_INIFILES
  1268. | SPINST_REGISTRY
  1269. | SPINST_INI2REG
  1270. | SPINST_BITREG
  1271. | SPINST_REGSVR
  1272. | SPINST_UNREGSVR
  1273. | SPINST_PROFILEITEMS,
  1274. hkDrv,
  1275. NULL,
  1276. 0,
  1277. NULL,
  1278. NULL,
  1279. INVALID_HANDLE_VALUE,
  1280. NULL,
  1281. NULL
  1282. );
  1283. if(Err == NO_ERROR) {
  1284. //
  1285. // Install extra HardWare registry section (if any).
  1286. //
  1287. Err = InstallHW(DeviceInfoSet,
  1288. DeviceInfoData,
  1289. hDeviceInf,
  1290. InfSectionWithExt,
  1291. &DeleteDevKey
  1292. );
  1293. }
  1294. }
  1295. //
  1296. // Set appropriate flags if we need to reboot or restart after
  1297. // this installation.
  1298. //
  1299. if(SetupFindFirstLine(hDeviceInf, InfSectionWithExt, pszReboot, &InfContext)) {
  1300. SetDevnodeNeedsRebootProblemWithArg2(DevInfoElem,pDeviceInfoSet,
  1301. MSG_LOG_REBOOT_REASON_KEY,
  1302. (ULONG_PTR)pszReboot,
  1303. (ULONG_PTR)InfSectionWithExt);
  1304. } else if(SetupFindFirstLine(hDeviceInf, InfSectionWithExt, pszRestart, &InfContext)) {
  1305. //
  1306. // NOTE: This behavior is taken from setupx. In both "Reboot"
  1307. // and "Restart" cases, it sets the DI_NEEDREBOOT flag.
  1308. //
  1309. SetDevnodeNeedsRebootProblemWithArg2(DevInfoElem,pDeviceInfoSet,
  1310. MSG_LOG_REBOOT_REASON_KEY,
  1311. (ULONG_PTR)pszRestart,
  1312. (ULONG_PTR)InfSectionWithExt);
  1313. }
  1314. }
  1315. //
  1316. // Set the value to write for the config flags, only if there
  1317. // are no config flags yet. If they exist, i.e., we are updating
  1318. // an existing device, just clear the re-install flag.
  1319. //
  1320. dwConfigFlags = GetDevInstConfigFlags(
  1321. DevInfoElem->DevInst,
  1322. (DevInfoElem->InstallParamBlock.Flags & DI_INSTALLDISABLED)
  1323. ? CONFIGFLAG_DISABLED
  1324. : 0,
  1325. pDeviceInfoSet->hMachine
  1326. );
  1327. //
  1328. // Always clear the REINSTALL bit and the FAILEDINSTALL bit
  1329. // when installing a device.
  1330. // (Also, clear the CONFIGFLAG_FINISH_INSTALL bit, which is used for
  1331. // Raw and driver-detected devnodes.)
  1332. //
  1333. dwConfigFlags &= ~(CONFIGFLAG_REINSTALL | CONFIGFLAG_FAILEDINSTALL | CONFIGFLAG_FINISH_INSTALL);
  1334. }
  1335. //
  1336. // If we're doing a copy-only installation, then we're done.
  1337. //
  1338. if(!DoFullInstall) {
  1339. goto clean0;
  1340. }
  1341. WriteLogEntry(
  1342. LogContext,
  1343. DRIVER_LOG_TIME,
  1344. MSG_LOG_BEGIN_WRITE_REG_TIME,
  1345. NULL); // text message
  1346. //
  1347. // Insert Driver Specific strings into the registry.
  1348. //
  1349. if(InfFromOemPath = pSetupInfIsFromOemLocation(szInfFileName, TRUE)) {
  1350. TempString = pSetupGetFileTitle(szNewName);
  1351. } else {
  1352. TempString = pSetupGetFileTitle(szInfFileName);
  1353. }
  1354. RegSetValueEx(hkDrv,
  1355. pszInfPath,
  1356. 0,
  1357. REG_SZ,
  1358. (PBYTE)TempString,
  1359. (lstrlen(TempString) + 1) * sizeof(TCHAR)
  1360. );
  1361. RegSetValueEx(hkDrv,
  1362. pszInfSection,
  1363. 0,
  1364. REG_SZ,
  1365. (PBYTE)szInfSectionName,
  1366. (lstrlen(szInfSectionName) + 1) * sizeof(TCHAR)
  1367. );
  1368. if(szInfSectionExt) {
  1369. RegSetValueEx(hkDrv,
  1370. pszInfSectionExt,
  1371. 0,
  1372. REG_SZ,
  1373. (PBYTE)szInfSectionExt,
  1374. (lstrlen(szInfSectionExt) + 1) * sizeof(TCHAR)
  1375. );
  1376. } else {
  1377. //
  1378. // This wasn't an OS/architecture-specific install section, _or_ we are
  1379. // installing from a legacy INF. Make sure there's no value hanging
  1380. // around from a previous installation.
  1381. //
  1382. RegDeleteValue(hkDrv, pszInfSectionExt);
  1383. }
  1384. if(DevInfoElem->SelectedDriver->ProviderDisplayName == -1) {
  1385. //
  1386. // No provider specified--delete any previously existing value entry.
  1387. //
  1388. RegDeleteValue(hkDrv, pszProviderName);
  1389. } else {
  1390. //
  1391. // Retrieve the Provider name, and store it in the driver key.
  1392. //
  1393. TempString = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  1394. DevInfoElem->SelectedDriver->ProviderDisplayName
  1395. );
  1396. RegSetValueEx(hkDrv,
  1397. pszProviderName,
  1398. 0,
  1399. REG_SZ,
  1400. (PBYTE)TempString,
  1401. (lstrlen(TempString) + 1) * sizeof(TCHAR)
  1402. );
  1403. }
  1404. if (DevInfoElem->SelectedDriver->DriverDate.dwLowDateTime != 0 ||
  1405. DevInfoElem->SelectedDriver->DriverDate.dwHighDateTime != 0) {
  1406. SYSTEMTIME SystemTime;
  1407. TCHAR Date[20];
  1408. //
  1409. // Save the driver date in binary (FILETIME) format in the registry
  1410. // so it can be localized by other components.
  1411. //
  1412. RegSetValueEx(hkDrv,
  1413. pszDriverDateData,
  1414. 0,
  1415. REG_BINARY,
  1416. (LPBYTE)&DevInfoElem->SelectedDriver->DriverDate,
  1417. sizeof(DevInfoElem->SelectedDriver->DriverDate)
  1418. );
  1419. //
  1420. // Save the driver date in string format for compatibility.
  1421. //
  1422. if (FileTimeToSystemTime(&(DevInfoElem->SelectedDriver->DriverDate), &SystemTime)) {
  1423. wsprintf(Date, TEXT("%d-%d-%d"), SystemTime.wMonth, SystemTime.wDay,
  1424. SystemTime.wYear);
  1425. RegSetValueEx(hkDrv,
  1426. pszDriverDate,
  1427. 0,
  1428. REG_SZ,
  1429. (PBYTE)Date,
  1430. (lstrlen(Date) + 1) * sizeof(TCHAR)
  1431. );
  1432. }
  1433. } else {
  1434. //
  1435. //No driver date for this driver--delete any previously existing value entry.
  1436. //
  1437. RegDeleteValue(hkDrv, pszDriverDateData);
  1438. RegDeleteValue(hkDrv, pszDriverDate);
  1439. }
  1440. if (DevInfoElem->SelectedDriver->DriverVersion != 0) {
  1441. ULARGE_INTEGER Version;
  1442. TCHAR VersionString[LINE_LEN];
  1443. Version.QuadPart = DevInfoElem->SelectedDriver->DriverVersion;
  1444. wsprintf(VersionString, TEXT("%0d.%0d.%0d.%0d"),
  1445. HIWORD(Version.HighPart), LOWORD(Version.HighPart),
  1446. HIWORD(Version.LowPart), LOWORD(Version.LowPart));
  1447. RegSetValueEx(hkDrv,
  1448. pszDriverVersion,
  1449. 0,
  1450. REG_SZ,
  1451. (PBYTE)VersionString,
  1452. (lstrlen(VersionString) + 1) * sizeof(TCHAR)
  1453. );
  1454. } else {
  1455. //
  1456. //No driver version for this driver--delete any previously existing value entry.
  1457. //
  1458. RegDeleteValue(hkDrv, pszDriverVersion);
  1459. }
  1460. //
  1461. // Set the Class property for this device.
  1462. //
  1463. SetupDiClassNameFromGuid(&DevInfoElem->ClassGuid, className, MAX_CLASS_NAME_LEN, NULL);
  1464. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1465. CM_DRP_CLASS,
  1466. className,
  1467. (lstrlen(className) + 1) * sizeof(TCHAR),
  1468. 0,
  1469. pDeviceInfoSet->hMachine);
  1470. //
  1471. // Set the MFG device registry property.
  1472. //
  1473. TempString = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  1474. DevInfoElem->SelectedDriver->MfgDisplayName
  1475. );
  1476. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1477. CM_DRP_MFG,
  1478. TempString,
  1479. (lstrlen(TempString) + 1) * sizeof(TCHAR),
  1480. 0,
  1481. pDeviceInfoSet->hMachine);
  1482. //
  1483. // Add hardware and compatible IDs to the hardware key if they exist
  1484. // in the driver node and don't already exist in the registry. This
  1485. // sets up an ID for manually installed devices.
  1486. //
  1487. if(!(DevInfoElem->InstallParamBlock.Flags & DI_NOWRITE_IDS) && // Want IDs written?
  1488. (DevInfoElem->SelectedDriver->HardwareId != -1)) // ID in driver node?
  1489. {
  1490. //
  1491. // Don't write IDs if either Hardware or Compatible IDs already
  1492. // exist in the registry. Note that I use cbData as an IN/OUT parameter
  1493. // to both CM calls. This is OK, however, since cbSize will not be modified
  1494. // on a CR_NO_SUCH_VALUE return, and I won't try to re-use it otherwise.
  1495. //
  1496. cbData = 0;
  1497. if((DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_ALWAYSWRITEIDS) ||
  1498. ((CM_Get_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1499. CM_DRP_HARDWAREID,
  1500. NULL,
  1501. NULL,
  1502. &cbData,
  1503. 0,
  1504. pDeviceInfoSet->hMachine) == CR_NO_SUCH_VALUE) &&
  1505. (CM_Get_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1506. CM_DRP_COMPATIBLEIDS,
  1507. NULL,
  1508. NULL,
  1509. &cbData,
  1510. 0,
  1511. pDeviceInfoSet->hMachine) == CR_NO_SUCH_VALUE)))
  1512. {
  1513. DWORD CurStringLen, TotalStringLen, i;
  1514. //
  1515. // Compute the maximum buffer size needed to hold our REG_MULTI_SZ
  1516. // ID lists.
  1517. //
  1518. TotalStringLen = (((DevInfoElem->SelectedDriver->NumCompatIds) ?
  1519. DevInfoElem->SelectedDriver->NumCompatIds : 1)
  1520. * MAX_DEVICE_ID_LEN) + 1;
  1521. if(!(DevIdBuffer = MyMalloc(TotalStringLen * sizeof(TCHAR)))) {
  1522. Err = ERROR_NOT_ENOUGH_MEMORY;
  1523. goto clean0;
  1524. }
  1525. //
  1526. // Build a multi-sz list of the (single) HardwareID, and set it.
  1527. //
  1528. TempString = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  1529. DevInfoElem->SelectedDriver->HardwareId
  1530. );
  1531. TotalStringLen = lstrlen(TempString) + 1;
  1532. CopyMemory(DevIdBuffer, TempString, TotalStringLen * sizeof(TCHAR));
  1533. DevIdBuffer[TotalStringLen++] = TEXT('\0'); // Add extra terminating NULL;
  1534. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1535. CM_DRP_HARDWAREID,
  1536. DevIdBuffer,
  1537. TotalStringLen * sizeof(TCHAR),
  1538. 0,
  1539. pDeviceInfoSet->hMachine );
  1540. //
  1541. // Build a multi-sz list of the zero or more CompatibleIDs, and set it
  1542. //
  1543. TotalStringLen = 0;
  1544. for(i = 0; i < DevInfoElem->SelectedDriver->NumCompatIds; i++) {
  1545. TempString = pStringTableStringFromId(
  1546. pDeviceInfoSet->StringTable,
  1547. DevInfoElem->SelectedDriver->CompatIdList[i]);
  1548. CurStringLen = lstrlen(TempString) + 1;
  1549. CopyMemory(&(DevIdBuffer[TotalStringLen]),
  1550. TempString,
  1551. CurStringLen * sizeof(TCHAR));
  1552. TotalStringLen += CurStringLen;
  1553. }
  1554. if(TotalStringLen) {
  1555. DevIdBuffer[TotalStringLen++] = TEXT('\0'); // Add extra terminating NULL;
  1556. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1557. CM_DRP_COMPATIBLEIDS,
  1558. DevIdBuffer,
  1559. TotalStringLen * sizeof(TCHAR),
  1560. 0,
  1561. pDeviceInfoSet->hMachine);
  1562. }
  1563. }
  1564. }
  1565. //
  1566. // Write out the 'MatchingDeviceId' value entry to the driver key that indicates which
  1567. // device ID (hardware or compatible) was used to pick this driver. For a compatible
  1568. // driver, this is the device ID that the compatible match was based on. For a class
  1569. // driver, this is the driver node's HardwareId (if present), or best CompatibleId. If
  1570. // the class driver node didn't specify a hardware or compatible IDs, then this value
  1571. // will not be written (we'll actually delete it to make sure it doesn't exist from a
  1572. // previous driver installation).
  1573. //
  1574. TempString = NULL;
  1575. if(DevInfoElem->SelectedDriverType == SPDIT_COMPATDRIVER) {
  1576. if(DevInfoElem->SelectedDriver->MatchingDeviceId == -1) {
  1577. //
  1578. // We have a HardwareID match.
  1579. //
  1580. TempString = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  1581. DevInfoElem->SelectedDriver->HardwareId
  1582. );
  1583. } else {
  1584. //
  1585. // We have a CompatibleID match.
  1586. //
  1587. MYASSERT((DevInfoElem->SelectedDriver->MatchingDeviceId >= 0) &&
  1588. ((DWORD)(DevInfoElem->SelectedDriver->MatchingDeviceId) < DevInfoElem->SelectedDriver->NumCompatIds));
  1589. TempString = pStringTableStringFromId(
  1590. pDeviceInfoSet->StringTable,
  1591. DevInfoElem->SelectedDriver->CompatIdList[DevInfoElem->SelectedDriver->MatchingDeviceId]
  1592. );
  1593. }
  1594. } else if(DevInfoElem->SelectedDriver->HardwareId != -1) {
  1595. //
  1596. // There's no notion of compatibility for class drivers--pick the device ID with the
  1597. // highest order of preference.
  1598. //
  1599. TempString = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  1600. DevInfoElem->SelectedDriver->HardwareId
  1601. );
  1602. if(!(*TempString)) {
  1603. //
  1604. // The HardwareID was an empty string--use the first CompatibleID.
  1605. //
  1606. if(DevInfoElem->SelectedDriver->NumCompatIds) {
  1607. TempString = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  1608. DevInfoElem->SelectedDriver->CompatIdList[0]
  1609. );
  1610. } else {
  1611. TempString = NULL;
  1612. }
  1613. }
  1614. }
  1615. if(TempString) {
  1616. RegSetValueEx(hkDrv,
  1617. pszMatchingDeviceId,
  1618. 0,
  1619. REG_SZ,
  1620. (PBYTE)TempString,
  1621. (lstrlen(TempString) + 1) * sizeof(TCHAR)
  1622. );
  1623. } else {
  1624. //
  1625. // We have an override situation where the user picked a class driver that didn't
  1626. // specify any hardware or compatible IDs. Make sure there's no value hanging
  1627. // around from a previous installation.
  1628. //
  1629. RegDeleteValue(hkDrv, pszMatchingDeviceId);
  1630. }
  1631. //
  1632. // If we're running under Windows NT, and we've successfully installed the device instance,
  1633. // then we need to install any required services.
  1634. //
  1635. if((Err == NO_ERROR) && (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
  1636. PTSTR pServiceInstallSection;
  1637. WriteLogEntry(
  1638. LogContext,
  1639. DRIVER_LOG_TIME,
  1640. MSG_LOG_BEGIN_SERVICE_TIME,
  1641. NULL); // text message
  1642. if(DevInfoElem->SelectedDriver->Flags & DNF_LEGACYINF) {
  1643. pServiceInstallSection = NULL;
  1644. } else {
  1645. //
  1646. // The install section name is of the form:
  1647. //
  1648. // <InfSectionWithExt>.Services
  1649. //
  1650. CopyMemory(&(InfSectionWithExt[InfSectionWithExtLength - 1]),
  1651. pszServicesSectionSuffix,
  1652. sizeof(pszServicesSectionSuffix)
  1653. );
  1654. pServiceInstallSection = InfSectionWithExt;
  1655. }
  1656. Err = InstallNtService(DevInfoElem,
  1657. hDeviceInf,
  1658. szInfFileName,
  1659. pServiceInstallSection,
  1660. &DeleteServiceList,
  1661. 0,
  1662. &NullDriverInstall
  1663. );
  1664. }
  1665. if ((Err == NO_ERROR)
  1666. && DoFullInstall
  1667. && !(DevInfoElem->SelectedDriver->Flags & DNF_LEGACYINF)) {
  1668. InfSectionWithExt[InfSectionWithExtLength - 1] = TEXT('\0');
  1669. pSetupCopyRelatedInfs(hDeviceInf,
  1670. szInfFileName,
  1671. InfSectionWithExt,
  1672. (DevInfoElem->SelectedDriver->Flags & DNF_INET_DRIVER)
  1673. ? SPOST_URL : SPOST_PATH,
  1674. LogContext);
  1675. }
  1676. }
  1677. } else {
  1678. //
  1679. // Installing the NULL driver.
  1680. // This means to set the Config flags, and nothing else.
  1681. // Config Flags get set to enabled in this case, so the device
  1682. // gets assigned the correct config. (Win95 bug 26320)
  1683. //
  1684. WriteLogEntry(
  1685. LogContext,
  1686. DRIVER_LOG_INFO,
  1687. MSG_LOG_INSTALL_NULL,
  1688. NULL, // text message
  1689. DeviceFullID);
  1690. NullDriverInstall = TRUE;
  1691. if(DoFullInstall) {
  1692. BOOL NullDrvInstallOK = FALSE;
  1693. //
  1694. // Check to see if the devnode is raw-capable, or if it already has a controlling
  1695. // service. If neither of those conditions are met, then we should fail this call
  1696. // unless the caller has explicitly passed us the DI_FLAGSEX_SETFAILEDINSTALL flag.
  1697. //
  1698. cbData = sizeof(DevInstCapabilities);
  1699. if(CR_SUCCESS == CM_Get_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1700. CM_DRP_CAPABILITIES,
  1701. NULL,
  1702. &DevInstCapabilities,
  1703. &cbData,
  1704. 0,
  1705. pDeviceInfoSet->hMachine))
  1706. {
  1707. NullDrvInstallOK = (DevInstCapabilities & CM_DEVCAP_RAWDEVICEOK);
  1708. }
  1709. if(!NullDrvInstallOK) {
  1710. //
  1711. // The devnode isn't raw-capable. Check to see if it already has a
  1712. // controlling service (e.g., because it was created as a result of
  1713. // a driver's call to IoReportDetectedDevice).
  1714. //
  1715. cbData = 0;
  1716. if(CR_BUFFER_SMALL == CM_Get_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1717. CM_DRP_SERVICE,
  1718. NULL,
  1719. NULL,
  1720. &cbData,
  1721. 0,
  1722. pDeviceInfoSet->hMachine))
  1723. {
  1724. NullDrvInstallOK = TRUE;
  1725. }
  1726. }
  1727. if(!NullDrvInstallOK &&
  1728. !(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_SETFAILEDINSTALL)) {
  1729. Err = ERROR_NO_ASSOCIATED_SERVICE;
  1730. } else {
  1731. dwConfigFlags = GetDevInstConfigFlags(DevInfoElem->DevInst, 0,pDeviceInfoSet->hMachine) &
  1732. ~(CONFIGFLAG_DISABLED | CONFIGFLAG_REINSTALL | CONFIGFLAG_FINISH_INSTALL);
  1733. //
  1734. // Delete all driver (software) keys associated with the device, and clear
  1735. // the "Driver" registry property.
  1736. //
  1737. SetupDiDeleteDevRegKey(DeviceInfoSet,
  1738. DeviceInfoData,
  1739. DICS_FLAG_GLOBAL | DICS_FLAG_CONFIGGENERAL,
  1740. 0,
  1741. DIREG_DRV
  1742. );
  1743. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst, CM_DRP_DRIVER,
  1744. NULL, 0, 0,pDeviceInfoSet->hMachine);
  1745. //
  1746. // Delete the controlling (FDO) Service property, as well as the UpperFilters and
  1747. // LowerFilters properties. Only do this if the devnode is not root-enumerated,
  1748. // however, since NT can have root-enumerated devnodes reported by drivers via
  1749. // IoReportDetectedDevice for which there's no corresponding INF (hence, the user
  1750. // must do a null-driver install in order to silence the "New Hardware Found" popups
  1751. // for these devices.
  1752. //
  1753. if((CM_Get_DevInst_Status_Ex(&ulStatus, &ulProblem, DevInfoElem->DevInst,
  1754. 0,pDeviceInfoSet->hMachine) == CR_SUCCESS) &&
  1755. !(ulStatus & DN_ROOT_ENUMERATED)) {
  1756. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst, CM_DRP_SERVICE,
  1757. NULL, 0, 0,pDeviceInfoSet->hMachine);
  1758. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst, CM_DRP_UPPERFILTERS,
  1759. NULL, 0, 0,pDeviceInfoSet->hMachine);
  1760. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst, CM_DRP_LOWERFILTERS,
  1761. NULL, 0, 0,pDeviceInfoSet->hMachine);
  1762. }
  1763. }
  1764. } else {
  1765. //
  1766. // It is an error to not have a selected driver in the copy-only case.
  1767. //
  1768. Err = ERROR_NO_DRIVER_SELECTED;
  1769. }
  1770. }
  1771. //
  1772. // If all went well above, then write some configflags, and re-enumerate
  1773. // the parent device instance if necessary
  1774. //
  1775. if(Err == NO_ERROR) {
  1776. //
  1777. // Write the Driver Description to the Registry, if there
  1778. // is an lpSelectedDriver, and the Device Description also
  1779. //
  1780. WriteLogEntry(
  1781. LogContext,
  1782. DRIVER_LOG_TIME,
  1783. MSG_LOG_BEGIN_WRITE_REG2_TIME,
  1784. NULL); // text message
  1785. if(DevInfoElem->SelectedDriver) {
  1786. TempString = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  1787. DevInfoElem->SelectedDriver->DrvDescription
  1788. );
  1789. RegSetValueEx(hkDrv,
  1790. pszDrvDesc,
  1791. 0,
  1792. REG_SZ,
  1793. (PBYTE)TempString,
  1794. (lstrlen(TempString) + 1) * sizeof(TCHAR)
  1795. );
  1796. //
  1797. // (setupx BUG 12721) always update the DevDesc in the registry with the
  1798. // value from the INF (ie only do this if we have a SELECTED driver)
  1799. // The semantics are weird, but the SelectedDriver NODE contains the
  1800. // INF Device description, and DRV description
  1801. //
  1802. TempString = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  1803. DevInfoElem->SelectedDriver->DevDescriptionDisplayName
  1804. );
  1805. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1806. CM_DRP_DEVICEDESC,
  1807. TempString,
  1808. (lstrlen(TempString) + 1) * sizeof(TCHAR),
  1809. 0,
  1810. pDeviceInfoSet->hMachine);
  1811. } else {
  1812. //
  1813. // No driver is selected, so use the description stored with the device
  1814. // information element itself for the device description. However, only set this
  1815. // if it isn't already present.
  1816. //
  1817. cbData = 0;
  1818. if(CM_Get_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1819. CM_DRP_DEVICEDESC,
  1820. NULL,
  1821. NULL,
  1822. &cbData,
  1823. 0,
  1824. pDeviceInfoSet->hMachine) == CR_NO_SUCH_VALUE) {
  1825. if(DevInfoElem->DeviceDescriptionDisplayName != -1) {
  1826. TempString = pStringTableStringFromId(
  1827. pDeviceInfoSet->StringTable,
  1828. DevInfoElem->DeviceDescriptionDisplayName
  1829. );
  1830. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1831. CM_DRP_DEVICEDESC,
  1832. TempString,
  1833. (lstrlen(TempString) + 1) * sizeof(TCHAR),
  1834. 0,
  1835. pDeviceInfoSet->hMachine);
  1836. }
  1837. }
  1838. }
  1839. //
  1840. // Unless the caller explicitly requested that this device be installed disabled, clear
  1841. // the CONFIGFLAG_DISABLED bit.
  1842. //
  1843. if(!(DevInfoElem->InstallParamBlock.Flags & DI_INSTALLDISABLED)) {
  1844. dwConfigFlags &= ~CONFIGFLAG_DISABLED;
  1845. }
  1846. //
  1847. // Write the config flags. If no selected driver means we should mark the install
  1848. // as a failure, then do so.
  1849. //
  1850. if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_SETFAILEDINSTALL) {
  1851. dwConfigFlags |= CONFIGFLAG_FAILEDINSTALL;
  1852. }
  1853. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1854. CM_DRP_CONFIGFLAGS,
  1855. &dwConfigFlags,
  1856. sizeof(dwConfigFlags),
  1857. 0,
  1858. pDeviceInfoSet->hMachine);
  1859. if(!(DevInfoElem->InstallParamBlock.Flags & (DI_DONOTCALLCONFIGMG | DI_NEEDREBOOT | DI_NEEDRESTART))) {
  1860. if (DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_RESTART_DEVICE_ONLY) {
  1861. //
  1862. // Restart this device only.
  1863. //
  1864. // This should only be done if no files were copied during
  1865. // DIF_INSTALLDEVICEFILES.
  1866. //
  1867. RestartSingleDevice(DevInfoElem,
  1868. pDeviceInfoSet,
  1869. NullDriverInstall,
  1870. LogContext);
  1871. } else {
  1872. //
  1873. // Restart this device as well as any other device that is
  1874. // using one of the same drivers as this device. This
  1875. // includes the function driver as well as the device and
  1876. // class upper and lower filter drivers.
  1877. //
  1878. // This only needs to be used if files were copied during
  1879. // DIF_INSTALLDEVICEFILES.
  1880. //
  1881. RestartAllDevicesUsingDrivers(DevInfoElem,
  1882. pDeviceInfoSet,
  1883. NullDriverInstall,
  1884. LogContext);
  1885. }
  1886. }
  1887. }
  1888. if((Err == NO_ERROR) && !GuiSetupInProgress) {
  1889. MYASSERT(DoFullInstall);
  1890. //
  1891. // Kick off RunOnce.
  1892. //
  1893. WriteLogEntry(
  1894. LogContext,
  1895. DRIVER_LOG_TIME,
  1896. MSG_LOG_BEGIN_INSTALLSTOP_TIME,
  1897. NULL); // text message
  1898. Err = pSetupInstallStopEx(TRUE, INSTALLSTOP_NO_GRPCONV, LogContext);
  1899. }
  1900. clean0: ; // nothing to do
  1901. } except(EXCEPTION_EXECUTE_HANDLER) {
  1902. //
  1903. // If our exception was an AV, then use Win32 invalid param error,
  1904. // otherwise, assume it was an inpage error dealing with a mapped-in
  1905. // file.
  1906. //
  1907. Err = (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? ERROR_INVALID_PARAMETER : ERROR_READ_FAULT;
  1908. if(FreeMsgHandlerContext) {
  1909. SetupTermDefaultQueueCallback(MsgHandlerContext);
  1910. }
  1911. if(CloseUserFileQ) {
  1912. SetupCloseFileQueue(UserFileQ);
  1913. }
  1914. //
  1915. // Access the following variables so that the compiler will respect our
  1916. // statement ordering w.r.t. these values. Otherwise, we may not be
  1917. // able to know with certainty whether or not we should release their
  1918. // corresponding resources.
  1919. //
  1920. DevInfoElem = DevInfoElem;
  1921. hDeviceInf = hDeviceInf;
  1922. hkDrv = hkDrv;
  1923. DevIdBuffer = DevIdBuffer;
  1924. DeleteServiceList = DeleteServiceList;
  1925. OemInfFileToCopy = OemInfFileToCopy;
  1926. }
  1927. //
  1928. // Clean up the registry if the install didn't go well. Along with other
  1929. // error paths, this handles the case where the user cancels the install
  1930. // while copying files
  1931. //
  1932. if(Err != NO_ERROR) {
  1933. WriteLogEntry(
  1934. LogContext,
  1935. DRIVER_LOG_TIME,
  1936. MSG_LOG_BEGIN_CLEANUP_TIME,
  1937. NULL); // text message
  1938. if(DevInfoElem && DoFullInstall) {
  1939. //
  1940. // Disable the device if the error wasn't a user cancel.
  1941. //
  1942. if(Err != ERROR_CANCELLED) {
  1943. DWORD dwConfigFlagsSize;
  1944. //
  1945. // The device is in an unknown state. Disable it by setting the
  1946. // CONFIGFLAG_DISABLED config flag.
  1947. //
  1948. dwConfigFlagsSize = sizeof(DWORD);
  1949. if(CM_Get_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1950. CM_DRP_CONFIGFLAGS,
  1951. NULL,
  1952. &dwConfigFlags,
  1953. &dwConfigFlagsSize,
  1954. 0,
  1955. pDeviceInfoSet->hMachine) == CR_SUCCESS) {
  1956. dwConfigFlags |= (CONFIGFLAG_DISABLED | CONFIGFLAG_REINSTALL);
  1957. //
  1958. // Also, make sure we clear the finish-install flag.
  1959. //
  1960. dwConfigFlags &= ~CONFIGFLAG_FINISH_INSTALL;
  1961. } else {
  1962. dwConfigFlags = CONFIGFLAG_DISABLED;
  1963. }
  1964. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1965. CM_DRP_CONFIGFLAGS,
  1966. &dwConfigFlags,
  1967. sizeof(dwConfigFlags),
  1968. 0,
  1969. pDeviceInfoSet->hMachine);
  1970. //
  1971. // Delete the Driver= entry from the Dev Reg Key and delete the
  1972. // DrvRegKey (as well as the DevRegKey if it didn't previously exist).
  1973. //
  1974. if(DevInfoElem->SelectedDriver) {
  1975. SetupDiDeleteDevRegKey(DeviceInfoSet,
  1976. DeviceInfoData,
  1977. DICS_FLAG_GLOBAL | DICS_FLAG_CONFIGGENERAL,
  1978. 0,
  1979. (DeleteDevKey ? DIREG_BOTH : DIREG_DRV)
  1980. );
  1981. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst, CM_DRP_DRIVER,
  1982. NULL, 0, 0,pDeviceInfoSet->hMachine);
  1983. }
  1984. //
  1985. // If necessary, delete any service entries created for this device instance.
  1986. //
  1987. if(DeleteServiceList) {
  1988. DeleteServicesInList(DeleteServiceList,LogContext);
  1989. }
  1990. }
  1991. }
  1992. //
  1993. // If we copied the OEM INF into the INF directory under a
  1994. // newly-generated name, delete it now.
  1995. //
  1996. if(OemInfFileToCopy) {
  1997. pSetupUninstallOEMInf(szNewName, LogContext, SUOI_FORCEDELETE, NULL);
  1998. }
  1999. }
  2000. UnlockDeviceInfoSet(pDeviceInfoSet);
  2001. if(hDeviceInf != INVALID_HANDLE_VALUE) {
  2002. SetupCloseInfFile(hDeviceInf);
  2003. }
  2004. if(hkDrv != INVALID_HANDLE_VALUE) {
  2005. RegCloseKey(hkDrv);
  2006. }
  2007. if(DevIdBuffer) {
  2008. MyFree(DevIdBuffer);
  2009. }
  2010. if(ValidationPlatform) {
  2011. MyFree(ValidationPlatform);
  2012. }
  2013. if(DeleteServiceList) {
  2014. PSVCNAME_NODE TmpSvcNode;
  2015. for(TmpSvcNode = DeleteServiceList; TmpSvcNode; TmpSvcNode = DeleteServiceList) {
  2016. DeleteServiceList = DeleteServiceList->Next;
  2017. MyFree(TmpSvcNode);
  2018. }
  2019. }
  2020. if (Err == NO_ERROR) {
  2021. //
  2022. // give a +ve affirmation of install
  2023. // if copy install, only do in Verbose-Logging, else do for standard Info-Logging
  2024. //
  2025. WriteLogEntry(
  2026. LogContext,
  2027. DoFullInstall?DRIVER_LOG_INFO:DRIVER_LOG_VERBOSE,
  2028. MSG_LOG_INSTALLED,
  2029. NULL,
  2030. DeviceFullID);
  2031. } else {
  2032. //
  2033. // indicate install failed, display error
  2034. //
  2035. WriteLogEntry(
  2036. LogContext,
  2037. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  2038. MSG_LOG_INSTALL_ERROR_ENCOUNTERED,
  2039. NULL);
  2040. WriteLogError(
  2041. LogContext,
  2042. DRIVER_LOG_ERROR,
  2043. Err);
  2044. }
  2045. if (slot_deviceID) {
  2046. ReleaseLogInfoSlot(LogContext,slot_deviceID);
  2047. }
  2048. if (slot_section) {
  2049. ReleaseLogInfoSlot(LogContext,slot_section);
  2050. }
  2051. WriteLogEntry(
  2052. LogContext,
  2053. DRIVER_LOG_TIME,
  2054. MSG_LOG_END_INSTALL_TIME,
  2055. NULL); // text message
  2056. SetLastError(Err);
  2057. return(Err == NO_ERROR);
  2058. }
  2059. BOOL
  2060. WINAPI
  2061. SetupDiInstallDriverFiles(
  2062. IN HDEVINFO DeviceInfoSet,
  2063. IN PSP_DEVINFO_DATA DeviceInfoData
  2064. )
  2065. /*++
  2066. Routine Description:
  2067. Default handler for DIF_INSTALLDEVICEFILES
  2068. This routine is similiar to a combination of SetupDiRegisterCoDeviceInstallers,
  2069. SetupDiInstallDeviceInterfaces, and SetupDiInstallDevice, but it only performs
  2070. the file copy commands in the install sections, and will not attempt to
  2071. configure the device in any way. This API is useful for pre-copying a device's
  2072. driver files.
  2073. Arguments:
  2074. DeviceInfoSet - Supplies a handle to the device information set containing
  2075. a device information element to be installed.
  2076. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure for which
  2077. a driver is to be installed.
  2078. Return Value:
  2079. If the function succeeds, the return value is TRUE.
  2080. If the function fails, the return value is FALSE. To get extended error
  2081. information, call GetLastError.
  2082. Remarks:
  2083. A driver must be selected for the specified device information element before
  2084. calling this API.
  2085. --*/
  2086. {
  2087. return _SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData, FALSE);
  2088. }
  2089. BOOL
  2090. WINAPI
  2091. SetupDiRemoveDevice(
  2092. IN HDEVINFO DeviceInfoSet,
  2093. IN OUT PSP_DEVINFO_DATA DeviceInfoData
  2094. )
  2095. /*++
  2096. Routine Description:
  2097. Default handler for DIF_REMOVE
  2098. This routine removes a device from the system.
  2099. Arguments:
  2100. DeviceInfoSet - Supplies a handle to the device information set for which a
  2101. device is to be removed.
  2102. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure for
  2103. which a device is to be removed. This is an IN OUT parameter, since the
  2104. DevInst field of the structure may be updated with a new handle value upon
  2105. return. (If this is a global removal, or the last hardware profile-specific
  2106. removal, then all traces of the devinst are removed from the registry, and
  2107. the handle becomes NULL at that point.)
  2108. Return Value:
  2109. If the function succeeds, the return value is TRUE.
  2110. If the function fails, the return value is FALSE. To get extended error
  2111. information, call GetLastError.
  2112. Remarks:
  2113. This routine will remove the device from the system, deleting both of its
  2114. registry keys, and dynamically stopping the device if its DevInst is 'live'.
  2115. If the device cannot be dynamically stopped, then flags will be set in the
  2116. install parameter block that will eventually cause the user to be prompted
  2117. to shut the system down. The removal is either global to all hardware
  2118. profiles, or specific to one hardware profile depending on the contents of
  2119. the ClassInstallParams field.
  2120. --*/
  2121. {
  2122. PDEVICE_INFO_SET pDeviceInfoSet;
  2123. DWORD Err, ConfigFlags;
  2124. PDEVINFO_ELEM DevInfoElem;
  2125. PDEVINSTALL_PARAM_BLOCK dipb;
  2126. TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
  2127. PSP_REMOVEDEVICE_PARAMS RemoveDevParams;
  2128. BOOL IsCurrentHwProfile = FALSE;
  2129. ULONG HwProfFlags;
  2130. DWORD HwProfileToRemove;
  2131. HWPROFILEINFO HwProfileInfo;
  2132. BOOL RemoveDevInst = FALSE, NukeDevInst = FALSE;
  2133. BOOL RemoveGlobally;
  2134. DEVINST DevNodeRemoved = 0;
  2135. DWORD i;
  2136. PINTERFACE_DEVICE_NODE InterfaceDeviceNode;
  2137. CONFIGRET cr;
  2138. ULONG ulStatus;
  2139. ULONG ulProblem;
  2140. PSETUP_LOG_CONTEXT LogContext = NULL;
  2141. DWORD slot_deviceID = 0;
  2142. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  2143. Err = ERROR_INVALID_HANDLE;
  2144. goto clean1;
  2145. }
  2146. LogContext = pDeviceInfoSet->InstallParamBlock.LogContext;
  2147. Err = NO_ERROR;
  2148. try {
  2149. //
  2150. // Locate the devinfo element to be removed.
  2151. //
  2152. if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  2153. DeviceInfoData,
  2154. NULL)) {
  2155. dipb = &(DevInfoElem->InstallParamBlock);
  2156. LogContext = dipb->LogContext;
  2157. } else {
  2158. Err = ERROR_INVALID_PARAMETER;
  2159. goto clean0;
  2160. }
  2161. //
  2162. // This routine can't be called if non-native drivers are involved.
  2163. // (Note: while presently this doesn't matter, it's possible that in
  2164. // the future uninstall will involve running one or more INF "uninstall"
  2165. // sections, and I don't want to limit that possibility by introducing
  2166. // the complication of non-native driver nodes.)
  2167. //
  2168. if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_ALTPLATFORM_DRVSEARCH) {
  2169. Err = ERROR_INVALID_FLAGS;
  2170. goto clean0;
  2171. }
  2172. if(CM_Get_DevInst_Status_Ex(&ulStatus, &ulProblem, DevInfoElem->DevInst, 0,pDeviceInfoSet->hMachine) == CR_SUCCESS &&
  2173. (ulStatus & DN_ROOT_ENUMERATED) &&
  2174. !(ulStatus & DN_DISABLEABLE)) {
  2175. //
  2176. // we cannot remove a root enumerated non-disableable device
  2177. //
  2178. Err = ERROR_NOT_DISABLEABLE;
  2179. goto clean0;
  2180. }
  2181. //
  2182. // Retrieve the name of the device instance. This is necessary, because
  2183. // we're about to remove the DEVINST, but we need to be able to locate it
  2184. // again, as a phantom. This should never fail.
  2185. //
  2186. if(CM_Get_Device_ID_Ex(DevInfoElem->DevInst,
  2187. DeviceInstanceId,
  2188. SIZECHARS(DeviceInstanceId),
  2189. 0,
  2190. pDeviceInfoSet->hMachine) != CR_SUCCESS) {
  2191. MYASSERT(!CR_SUCCESS);
  2192. Err = ERROR_INVALID_DATA;
  2193. goto clean0;
  2194. }
  2195. if(slot_deviceID == 0) {
  2196. slot_deviceID = AllocLogInfoSlotOrLevel(LogContext,DRIVER_LOG_INFO,FALSE);
  2197. }
  2198. WriteLogEntry(
  2199. LogContext,
  2200. slot_deviceID,
  2201. MSG_LOG_DO_REMOVE,
  2202. NULL, // text message
  2203. DeviceInstanceId);
  2204. //
  2205. // See if there's a SP_REMOVEDEVICE_PARAMS structure we need to pay
  2206. // attention to.
  2207. //
  2208. if((dipb->Flags & DI_CLASSINSTALLPARAMS) &&
  2209. (dipb->ClassInstallHeader->InstallFunction == DIF_REMOVE)) {
  2210. RemoveDevParams = (PSP_REMOVEDEVICE_PARAMS)(dipb->ClassInstallHeader);
  2211. if(RemoveGlobally = (RemoveDevParams->Scope == DI_REMOVEDEVICE_GLOBAL)) {
  2212. //
  2213. // We are doing a global removal. We still want to set CSCONFIGFLAG_DO_NOT_CREATE
  2214. // for this device in the current hardware profile, so that someone else happening
  2215. // to do an enumeration won't turn this guy back on before we get a chance to
  2216. // remove it.
  2217. //
  2218. HwProfileToRemove = 0;
  2219. } else {
  2220. //
  2221. // Remove device from a particular hardware profile.
  2222. //
  2223. HwProfileToRemove = RemoveDevParams->HwProfile;
  2224. //
  2225. // Set the CSCONFIGFLAG_DO_NOT_CREATE flag for the specified hardware profile.
  2226. //
  2227. if(CM_Get_HW_Prof_Flags_Ex(DeviceInstanceId,
  2228. HwProfileToRemove,
  2229. &HwProfFlags,
  2230. 0,
  2231. pDeviceInfoSet->hMachine) == CR_SUCCESS) {
  2232. HwProfFlags |= CSCONFIGFLAG_DO_NOT_CREATE;
  2233. } else {
  2234. HwProfFlags = CSCONFIGFLAG_DO_NOT_CREATE;
  2235. }
  2236. Err = MapCrToSpError(
  2237. CM_Set_HW_Prof_Flags_Ex(DeviceInstanceId, HwProfileToRemove,
  2238. HwProfFlags, 0,pDeviceInfoSet->hMachine),
  2239. ERROR_INVALID_DATA
  2240. );
  2241. if(Err != NO_ERROR) {
  2242. goto clean0;
  2243. }
  2244. //
  2245. // Determine if we are deleting the device from the current hw profile.
  2246. //
  2247. if((HwProfileToRemove == 0) ||
  2248. ((CM_Get_Hardware_Profile_Info_Ex((ULONG)-1, &HwProfileInfo,
  2249. 0,pDeviceInfoSet->hMachine) == CR_SUCCESS) &&
  2250. (HwProfileInfo.HWPI_ulHWProfile == HwProfileToRemove))) {
  2251. IsCurrentHwProfile = TRUE;
  2252. }
  2253. }
  2254. //
  2255. // Is this the current hardware profile or a global removal AND
  2256. // is there a present device?
  2257. //
  2258. if((IsCurrentHwProfile || RemoveGlobally) &&
  2259. !(DevInfoElem->DiElemFlags & DIE_IS_PHANTOM) &&
  2260. !(dipb->Flags & DI_DONOTCALLCONFIGMG)) {
  2261. RemoveDevInst = TRUE;
  2262. }
  2263. } else {
  2264. //
  2265. // No device removal params given, so do a global removal.
  2266. //
  2267. RemoveGlobally = TRUE;
  2268. HwProfileToRemove = 0;
  2269. if(!(dipb->Flags & DI_DONOTCALLCONFIGMG)) {
  2270. RemoveDevInst = TRUE;
  2271. }
  2272. }
  2273. //
  2274. // If this is a global removal, or the last hardware profile-specific one, then clean up
  2275. // the registry.
  2276. //
  2277. if(RemoveGlobally || IsDevRemovedFromAllHwProfiles(DeviceInstanceId,pDeviceInfoSet->hMachine)) {
  2278. NukeDevInst = TRUE;
  2279. }
  2280. if(RemoveDevInst) {
  2281. TCHAR VetoName[MAX_PATH];
  2282. PNP_VETO_TYPE VetoType;
  2283. #ifdef UNICODE
  2284. cr = CM_Query_And_Remove_SubTree_Ex(DevInfoElem->DevInst,
  2285. &VetoType,
  2286. VetoName,
  2287. SIZECHARS(VetoName),
  2288. CM_REMOVE_NO_RESTART |
  2289. (DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_NOUIONQUERYREMOVE)
  2290. ? CM_REMOVE_UI_NOT_OK
  2291. : CM_REMOVE_UI_OK,
  2292. pDeviceInfoSet->hMachine
  2293. );
  2294. if(cr == CR_SUCCESS) {
  2295. //
  2296. // Device instance successfully removed--now locate it as a phantom.
  2297. //
  2298. CM_Locate_DevInst_Ex(&(DevInfoElem->DevInst),
  2299. (DEVINSTID)DeviceInstanceId,
  2300. CM_LOCATE_DEVINST_PHANTOM,
  2301. pDeviceInfoSet->hMachine);
  2302. DevInfoElem->DiElemFlags |= DIE_IS_PHANTOM;
  2303. //
  2304. // Set the DevNodeRemoved DevNode so that we know we need to
  2305. // call CM_Setup_DevInst with the CM_SETUP_DEVNODE_RESET flag
  2306. // to allow this devnode to come back online on the next
  2307. // enumeration.
  2308. //
  2309. DevNodeRemoved = DevInfoElem->DevInst;
  2310. } else {
  2311. //
  2312. // If the failure was due to a veto, then log information about
  2313. // who vetoed us.
  2314. //
  2315. // SPLOG--write out an entry with real logging.
  2316. //
  2317. if(cr == CR_REMOVE_VETOED) {
  2318. //
  2319. // get the LogContext from dipb which should be a pointer
  2320. // to the appropriate DevInstallParamBlock
  2321. //
  2322. _WriteVetoLogEntry(
  2323. dipb->LogContext,
  2324. DRIVER_LOG_WARNING,
  2325. MSG_LOG_REMOVE_VETOED_IN_UNINSTALL,
  2326. DeviceInstanceId,
  2327. VetoName,
  2328. VetoType);
  2329. }
  2330. if (cr != CR_INVALID_DEVNODE) {
  2331. SetDevnodeNeedsRebootProblemWithArg2(DevInfoElem,
  2332. pDeviceInfoSet,
  2333. MSG_LOG_REBOOT_REASON_QR_VETOED_UNINSTALL,
  2334. cr,
  2335. (ULONG_PTR)_MapCmRetToString(cr)
  2336. );
  2337. }
  2338. }
  2339. #else
  2340. //
  2341. // It appears that some people (who are broken)
  2342. // do rely on setupapi to install devices
  2343. // so old code conditionally re-introduced to try and fix them
  2344. //
  2345. WriteLogEntry(
  2346. LogContext,
  2347. DRIVER_LOG_ERROR,
  2348. MSG_LOG_NOT_FOR_THIS_OS,
  2349. NULL);
  2350. if((CM_Query_Remove_SubTree(DevInfoElem->DevInst, CM_QUERY_REMOVE_UI_OK) == CR_SUCCESS) &&
  2351. (CM_Remove_SubTree(DevInfoElem->DevInst, CM_REMOVE_UI_OK) == CR_SUCCESS)) {
  2352. //
  2353. // Device instance successfully removed--now locate it as a phantom.
  2354. //
  2355. CM_Locate_DevInst(&(DevInfoElem->DevInst),
  2356. (DEVINSTID)DeviceInstanceId,
  2357. CM_LOCATE_DEVINST_PHANTOM
  2358. );
  2359. DevInfoElem->DiElemFlags |= DIE_IS_PHANTOM;
  2360. } else {
  2361. dipb->Flags |= DI_NEEDREBOOT;
  2362. }
  2363. #endif
  2364. }
  2365. if(NukeDevInst) {
  2366. //
  2367. // Remove all traces of this device from the registry.
  2368. //
  2369. pSetupDeleteDevRegKeys(DevInfoElem->DevInst,
  2370. DICS_FLAG_GLOBAL | DICS_FLAG_CONFIGSPECIFIC,
  2371. (DWORD)-1,
  2372. DIREG_BOTH,
  2373. TRUE
  2374. );
  2375. cr = CM_Uninstall_DevInst_Ex(DevInfoElem->DevInst, 0,pDeviceInfoSet->hMachine);
  2376. if (cr != CR_SUCCESS) {
  2377. //
  2378. // we try to catch this earlier
  2379. //
  2380. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  2381. goto clean0;
  2382. }
  2383. //
  2384. // The above API will also remove all interface devices associated with this
  2385. // device instance. Now we need to mark every interface device node that we
  2386. // are tracking for this devinfo element to indicate that they have been removed.
  2387. //
  2388. for(i = 0; i < DevInfoElem->InterfaceClassListSize; i++) {
  2389. for(InterfaceDeviceNode = DevInfoElem->InterfaceClassList[i].InterfaceDeviceNode;
  2390. InterfaceDeviceNode;
  2391. InterfaceDeviceNode = InterfaceDeviceNode->Next) {
  2392. InterfaceDeviceNode->Flags |= SPINT_REMOVED;
  2393. }
  2394. }
  2395. //
  2396. // Mark this device information element as unregistered, and set its
  2397. // devinst handle to NULL.
  2398. //
  2399. DevInfoElem->DiElemFlags &= ~DIE_IS_REGISTERED;
  2400. DevInfoElem->DevInst = (DEVINST)0;
  2401. }
  2402. //
  2403. // Now update the DevInst field of the DeviceInfoData structure with the new
  2404. // value of the devinst handle (possibly NULL).
  2405. //
  2406. DeviceInfoData->DevInst = DevInfoElem->DevInst;
  2407. clean0: ; // nothing to do.
  2408. //
  2409. // If the DevNode was really removed then we need to call CM_Setup_DevInst
  2410. // with the CM_SETUP_DEVNODE_RESET flag to allow the devnode to come back
  2411. // on the next enumeration.
  2412. //
  2413. if (DevNodeRemoved) {
  2414. CM_Setup_DevInst_Ex(DevNodeRemoved,
  2415. CM_SETUP_DEVNODE_RESET,
  2416. pDeviceInfoSet->hMachine
  2417. );
  2418. }
  2419. } except(EXCEPTION_EXECUTE_HANDLER) {
  2420. Err = ERROR_INVALID_PARAMETER;
  2421. }
  2422. UnlockDeviceInfoSet(pDeviceInfoSet);
  2423. clean1:
  2424. if (slot_deviceID) {
  2425. if (Err == NO_ERROR) {
  2426. //
  2427. // give a +ve affirmation of remove
  2428. //
  2429. WriteLogEntry(
  2430. LogContext,
  2431. DRIVER_LOG_INFO,
  2432. MSG_LOG_REMOVED,
  2433. NULL);
  2434. } else {
  2435. //
  2436. // indicate remove failed, display error
  2437. //
  2438. WriteLogEntry(
  2439. LogContext,
  2440. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  2441. MSG_LOG_REMOVE_ERROR,
  2442. NULL);
  2443. WriteLogError(
  2444. LogContext,
  2445. DRIVER_LOG_ERROR,
  2446. Err);
  2447. }
  2448. ReleaseLogInfoSlot(LogContext,slot_deviceID);
  2449. }
  2450. SetLastError(Err);
  2451. return(Err == NO_ERROR);
  2452. }
  2453. BOOL
  2454. WINAPI
  2455. SetupDiUnremoveDevice(
  2456. IN HDEVINFO DeviceInfoSet,
  2457. IN OUT PSP_DEVINFO_DATA DeviceInfoData
  2458. )
  2459. /*++
  2460. Routine Description:
  2461. Default handler for DIF_UNREMOVE
  2462. This routine unremoves a device from the system.
  2463. Arguments:
  2464. DeviceInfoSet - Supplies a handle to the device information set for which a
  2465. device is to be unremoved.
  2466. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure for
  2467. which a device is to be unremoved. This is an IN OUT parameter, since the
  2468. DevInst field of the structure may be updated with a new handle value upon
  2469. return.
  2470. This device must contain class install parameters for DIF_UNREMOVE
  2471. or the API will fail with ERROR_NO_CLASSINSTALL_PARAMS.
  2472. Return Value:
  2473. If the function succeeds, the return value is TRUE.
  2474. If the function fails, the return value is FALSE. To get extended error
  2475. information, call GetLastError.
  2476. Remarks:
  2477. This function will unremove the the device on the system, dynamically starting
  2478. the device if possible. If the device cannot be dynamically started, then flags
  2479. will be set in the device install parameters that will eventually cause the user
  2480. to be prompted to shut the system down.
  2481. The unremoval is specific to one configuration, specified in the HwProfile field
  2482. of the SP_UNREMOVEDEVICE_PARAMS class install parameters associated with this
  2483. device information element. (The Scope field of this structure must be set to
  2484. DI_UNREMOVEDEVICE_CONFIGSPECIFIC.)
  2485. --*/
  2486. {
  2487. PDEVICE_INFO_SET pDeviceInfoSet;
  2488. DWORD Err;
  2489. PDEVINFO_ELEM DevInfoElem;
  2490. PDEVINSTALL_PARAM_BLOCK dipb;
  2491. PSP_UNREMOVEDEVICE_PARAMS UnremoveDevParams;
  2492. TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
  2493. ULONG HwProfFlags;
  2494. HWPROFILEINFO HwProfileInfo;
  2495. DEVINST dnRoot;
  2496. PSETUP_LOG_CONTEXT LogContext = NULL;
  2497. CONFIGRET cr;
  2498. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  2499. Err = ERROR_INVALID_HANDLE;
  2500. goto clean1;
  2501. }
  2502. LogContext = pDeviceInfoSet->InstallParamBlock.LogContext;
  2503. Err = NO_ERROR;
  2504. try {
  2505. //
  2506. // Locate the devinfo element to be unremoved.
  2507. //
  2508. if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  2509. DeviceInfoData,
  2510. NULL)) {
  2511. dipb = &(DevInfoElem->InstallParamBlock);
  2512. LogContext = dipb->LogContext;
  2513. } else {
  2514. Err = ERROR_INVALID_PARAMETER;
  2515. goto clean0;
  2516. }
  2517. //
  2518. // This routine can't be called if non-native drivers are involved.
  2519. // (Note: while presently this doesn't matter, it's possible that in
  2520. // the future this operation could involve running one or more INF
  2521. // sections, and I don't want to limit that possibility by introducing
  2522. // the complication of non-native driver nodes.)
  2523. //
  2524. if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_ALTPLATFORM_DRVSEARCH) {
  2525. Err = ERROR_INVALID_FLAGS;
  2526. goto clean0;
  2527. }
  2528. //
  2529. // We'd better have DIF_UNREMOVE class install params
  2530. //
  2531. if(!(dipb->Flags & DI_CLASSINSTALLPARAMS) ||
  2532. (dipb->ClassInstallHeader->InstallFunction != DIF_UNREMOVE)) {
  2533. Err = ERROR_NO_CLASSINSTALL_PARAMS;
  2534. goto clean0;
  2535. }
  2536. UnremoveDevParams = (PSP_UNREMOVEDEVICE_PARAMS)(dipb->ClassInstallHeader);
  2537. //
  2538. // This only works in a hardware profile-specific manner.
  2539. //
  2540. MYASSERT(UnremoveDevParams->Scope == DI_UNREMOVEDEVICE_CONFIGSPECIFIC);
  2541. //
  2542. // Retrieve the name of the device instance. We need to do this because
  2543. // accessing hardware profile-specific config flags is done via name instead
  2544. // of devnode handle. (Also, we'll need this later after re-enumerating
  2545. // this device's parent.)
  2546. //
  2547. if((cr = CM_Get_Device_ID_Ex(DevInfoElem->DevInst,
  2548. DeviceInstanceId,
  2549. SIZECHARS(DeviceInstanceId),
  2550. 0,
  2551. pDeviceInfoSet->hMachine)) != CR_SUCCESS) {
  2552. Err = MapCrToSpError(cr,ERROR_INVALID_DATA);
  2553. goto clean0;
  2554. }
  2555. if(CM_Get_HW_Prof_Flags_Ex(DeviceInstanceId,
  2556. UnremoveDevParams->HwProfile,
  2557. &HwProfFlags,
  2558. 0,
  2559. pDeviceInfoSet->hMachine) == CR_SUCCESS) {
  2560. HwProfFlags &= ~CSCONFIGFLAG_DO_NOT_CREATE;
  2561. Err = MapCrToSpError(
  2562. CM_Set_HW_Prof_Flags_Ex(DeviceInstanceId, UnremoveDevParams->HwProfile,
  2563. HwProfFlags, 0,pDeviceInfoSet->hMachine),
  2564. ERROR_INVALID_DATA
  2565. );
  2566. if(Err != NO_ERROR) {
  2567. goto clean0;
  2568. }
  2569. }
  2570. //
  2571. // Determine if we are trying to un-remove the device in the current
  2572. // hardware profile.
  2573. //
  2574. if((UnremoveDevParams->HwProfile == 0) ||
  2575. ((CM_Get_Hardware_Profile_Info_Ex((ULONG)-1, &HwProfileInfo,
  2576. 0,pDeviceInfoSet->hMachine) == CR_SUCCESS) &&
  2577. (HwProfileInfo.HWPI_ulHWProfile == UnremoveDevParams->HwProfile))) {
  2578. //
  2579. // Make sure the device has started correctly.
  2580. //
  2581. if(CM_Locate_DevInst_Ex(&dnRoot, NULL, CM_LOCATE_DEVINST_NORMAL,pDeviceInfoSet->hMachine) == CR_SUCCESS) {
  2582. //
  2583. // Try to get this device enumerated
  2584. //
  2585. CM_Reenumerate_DevInst_Ex(dnRoot, CM_REENUMERATE_SYNCHRONOUS,pDeviceInfoSet->hMachine);
  2586. if(CM_Locate_DevInst_Ex(&(DevInfoElem->DevInst),
  2587. (DEVINSTID)DeviceInstanceId,
  2588. CM_LOCATE_DEVINST_NORMAL,
  2589. pDeviceInfoSet->hMachine) == CR_SUCCESS) {
  2590. CheckIfDevStarted(DevInfoElem, pDeviceInfoSet);
  2591. } else {
  2592. //
  2593. // We couldn't locate the devnode. We don't need to
  2594. // request a reboot, because if the devnode ever shows up
  2595. // again, we should be able to bring it back on-line just
  2596. // fine.
  2597. //
  2598. // Retrieve the devnode as a phantom
  2599. //
  2600. CM_Locate_DevInst_Ex(&(DevInfoElem->DevInst),
  2601. (DEVINSTID)DeviceInstanceId,
  2602. CM_LOCATE_DEVINST_PHANTOM,
  2603. pDeviceInfoSet->hMachine
  2604. );
  2605. DevInfoElem->DiElemFlags |= DIE_IS_PHANTOM;
  2606. }
  2607. //
  2608. // Update the caller's buffer to reflect the new device instance handle
  2609. //
  2610. DeviceInfoData->DevInst = DevInfoElem->DevInst;
  2611. } else {
  2612. //
  2613. // We couldn't locate the root of the hardware tree! This should never happen...
  2614. //
  2615. Err = ERROR_INVALID_DATA;
  2616. }
  2617. }
  2618. clean0: ; // nothing to do.
  2619. } except(EXCEPTION_EXECUTE_HANDLER) {
  2620. Err = ERROR_INVALID_PARAMETER;
  2621. }
  2622. UnlockDeviceInfoSet(pDeviceInfoSet);
  2623. clean1:
  2624. if (Err == NO_ERROR) {
  2625. //
  2626. // give a +ve affirmation of unremove
  2627. //
  2628. WriteLogEntry(
  2629. LogContext,
  2630. DRIVER_LOG_INFO,
  2631. MSG_LOG_UNREMOVED,
  2632. NULL);
  2633. } else {
  2634. //
  2635. // indicate unremove failed, display error
  2636. //
  2637. WriteLogEntry(
  2638. LogContext,
  2639. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  2640. MSG_LOG_UNREMOVE_ERROR,
  2641. NULL);
  2642. WriteLogError(
  2643. LogContext,
  2644. DRIVER_LOG_ERROR,
  2645. Err);
  2646. }
  2647. SetLastError(Err);
  2648. return(Err == NO_ERROR);
  2649. }
  2650. BOOL
  2651. WINAPI
  2652. SetupDiMoveDuplicateDevice(
  2653. IN HDEVINFO DeviceInfoSet,
  2654. IN PSP_DEVINFO_DATA DestinationDeviceInfoData
  2655. )
  2656. /*++
  2657. Routine Description:
  2658. Default handler for DIF_MOVEDEVICE
  2659. This routine moves a device to a new location in the Enum branch.
  2660. Arguments:
  2661. DeviceInfoSet - Supplies a handle to the device information set for which
  2662. a device is to be moved.
  2663. DestinationDeviceInfoData - Supplies the address of a SP_DEVINFO_DATA
  2664. structure for the device instance that is the destination of the move.
  2665. This device must contain class install parameters for DIF_MOVEDEVICE,
  2666. or the API will fail with ERROR_NO_CLASSINSTALL_PARAMS.
  2667. Return Value:
  2668. If the function succeeds, the return value is TRUE.
  2669. If the function fails, the return value is FALSE. To get extended error
  2670. information, call GetLastError.
  2671. --*/
  2672. {
  2673. PDEVICE_INFO_SET pDeviceInfoSet;
  2674. DWORD Err;
  2675. PDEVINFO_ELEM SourceDevInfoElem, DestDevInfoElem;
  2676. PDEVINSTALL_PARAM_BLOCK dipb;
  2677. PSP_MOVEDEV_PARAMS MoveDevParams;
  2678. BOOL bUnlockDestDevInfoElem, bUnlockSourceDevInfoElem, bRestoreConfigMgrBehavior;
  2679. DWORD ConfigFlags;
  2680. TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
  2681. BOOL RemoveSucceeded;
  2682. CONFIGRET cr;
  2683. PSETUP_LOG_CONTEXT LogContext = NULL;
  2684. //
  2685. // A device information element must be specified for this routine.
  2686. //
  2687. if(!DestinationDeviceInfoData) {
  2688. Err = ERROR_INVALID_PARAMETER;
  2689. goto clean1;
  2690. }
  2691. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  2692. Err = ERROR_INVALID_HANDLE;
  2693. goto clean1;
  2694. }
  2695. LogContext = pDeviceInfoSet->InstallParamBlock.LogContext;
  2696. Err = NO_ERROR;
  2697. bUnlockDestDevInfoElem = bUnlockSourceDevInfoElem = bRestoreConfigMgrBehavior = FALSE;
  2698. try {
  2699. //
  2700. // Locate the destination devinfo element.
  2701. //
  2702. if(DestDevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  2703. DestinationDeviceInfoData,
  2704. NULL)) {
  2705. dipb = &(DestDevInfoElem->InstallParamBlock);
  2706. LogContext = dipb->LogContext;
  2707. } else {
  2708. Err = ERROR_INVALID_PARAMETER;
  2709. goto clean0;
  2710. }
  2711. //
  2712. // This routine can't be called if non-native drivers are involved.
  2713. // (Note: while presently this doesn't matter, it's possible that in
  2714. // the future this operation could involve running one or more INF
  2715. // sections, and I don't want to limit that possibility by introducing
  2716. // the complication of non-native driver nodes.)
  2717. //
  2718. if(dipb->FlagsEx & DI_FLAGSEX_ALTPLATFORM_DRVSEARCH) {
  2719. Err = ERROR_INVALID_FLAGS;
  2720. goto clean0;
  2721. }
  2722. //
  2723. // We'd better have DIF_MOVEDEVICE class install params
  2724. //
  2725. if(!(dipb->Flags & DI_CLASSINSTALLPARAMS) ||
  2726. (dipb->ClassInstallHeader->InstallFunction != DIF_MOVEDEVICE)) {
  2727. Err = ERROR_NO_CLASSINSTALL_PARAMS;
  2728. goto clean0;
  2729. }
  2730. MoveDevParams = (PSP_MOVEDEV_PARAMS)(dipb->ClassInstallHeader);
  2731. //
  2732. // Find the source device.
  2733. //
  2734. if(!(SourceDevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  2735. &(MoveDevParams->SourceDeviceInfoData),
  2736. NULL))) {
  2737. Err = ERROR_INVALID_PARAMETER;
  2738. goto clean0;
  2739. }
  2740. //
  2741. // We're about to call the class installer to handle device install (and possibly
  2742. // device selection as well). We don't want the class installer to do something
  2743. // slimy like delete the devices out from under us, so we'll lock 'em down.
  2744. //
  2745. if(!(DestDevInfoElem->DiElemFlags & DIE_IS_LOCKED)) {
  2746. DestDevInfoElem->DiElemFlags |= DIE_IS_LOCKED;
  2747. bUnlockDestDevInfoElem = TRUE;
  2748. }
  2749. if(!(SourceDevInfoElem->DiElemFlags & DIE_IS_LOCKED)) {
  2750. SourceDevInfoElem->DiElemFlags |= DIE_IS_LOCKED;
  2751. bUnlockSourceDevInfoElem = TRUE;
  2752. }
  2753. //
  2754. // We don't want the following calls to cause the ConfigMgr to do re-enumeration, etc.
  2755. //
  2756. if(!(dipb->Flags & DI_DONOTCALLCONFIGMG)) {
  2757. dipb->Flags |= DI_DONOTCALLCONFIGMG;
  2758. bRestoreConfigMgrBehavior = TRUE;
  2759. }
  2760. //
  2761. // We need to unlock the HDEVINFO before calling the class installer.
  2762. //
  2763. UnlockDeviceInfoSet(pDeviceInfoSet);
  2764. pDeviceInfoSet = NULL;
  2765. //
  2766. // If the destination device doesn't have a selected driver, then get one.
  2767. //
  2768. if(!DestDevInfoElem->SelectedDriver) {
  2769. if(!_SetupDiCallClassInstaller(DIF_SELECTDEVICE,
  2770. DeviceInfoSet,
  2771. DestinationDeviceInfoData,
  2772. CALLCI_LOAD_HELPERS | CALLCI_CALL_HELPERS)) {
  2773. Err = GetLastError();
  2774. goto clean0;
  2775. }
  2776. }
  2777. if(!_SetupDiCallClassInstaller(DIF_INSTALLDEVICE,
  2778. DeviceInfoSet,
  2779. DestinationDeviceInfoData,
  2780. CALLCI_LOAD_HELPERS | CALLCI_CALL_HELPERS)) {
  2781. Err = GetLastError();
  2782. goto clean0;
  2783. }
  2784. //
  2785. // Re-acquire the HDEVINFO lock.
  2786. //
  2787. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  2788. //
  2789. // we should never hit this code path
  2790. //
  2791. MYASSERT(pDeviceInfoSet);
  2792. Err = ERROR_INVALID_HANDLE;
  2793. goto clean0;
  2794. }
  2795. //
  2796. // Retrieve the name of the device instance. This is necessary, because
  2797. // we may attempt to remove the DEVINST, but we need to be able to locate
  2798. // it again, as a phantom. This should never fail.
  2799. //
  2800. if(CM_Get_Device_ID_Ex(SourceDevInfoElem->DevInst,
  2801. DeviceInstanceId,
  2802. SIZECHARS(DeviceInstanceId),
  2803. 0,
  2804. pDeviceInfoSet->hMachine) != CR_SUCCESS) {
  2805. MYASSERT(!CR_SUCCESS);
  2806. Err = ERROR_INVALID_DATA;
  2807. goto clean0;
  2808. }
  2809. //
  2810. // Delete all the user-accessible registry keys associated with the source
  2811. // device in preparation for the move.
  2812. //
  2813. pSetupDeleteDevRegKeys(SourceDevInfoElem->DevInst,
  2814. DICS_FLAG_GLOBAL | DICS_FLAG_CONFIGSPECIFIC,
  2815. (DWORD)-1,
  2816. DIREG_BOTH,
  2817. TRUE
  2818. );
  2819. //
  2820. // Check to see if we can remove the source device dynamically.
  2821. //
  2822. // NOTE: The ConfigFlags of the _destination_ device are retrieved, and checked
  2823. // for the presence of the CONFIGFLAG_CANTSTOPACHILD flag. PierreYs assures me
  2824. // that this is the correct behavior.
  2825. //
  2826. ConfigFlags = GetDevInstConfigFlags(DestDevInfoElem->DevInst, 0,pDeviceInfoSet->hMachine);
  2827. if(ConfigFlags & CONFIGFLAG_CANTSTOPACHILD) {
  2828. RemoveSucceeded = FALSE;
  2829. } else {
  2830. TCHAR VetoName[MAX_PATH];
  2831. PNP_VETO_TYPE VetoType;
  2832. #ifdef UNICODE
  2833. cr = CM_Query_And_Remove_SubTree_Ex(SourceDevInfoElem->DevInst,
  2834. &VetoType,
  2835. VetoName,
  2836. SIZECHARS(VetoName),
  2837. (SourceDevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_NOUIONQUERYREMOVE)
  2838. ? CM_REMOVE_UI_NOT_OK
  2839. : CM_REMOVE_UI_OK,
  2840. pDeviceInfoSet->hMachine
  2841. );
  2842. if(cr == CR_SUCCESS) {
  2843. RemoveSucceeded = TRUE;
  2844. } else {
  2845. //
  2846. // If the failure was due to a veto, then log information about
  2847. // who vetoed us.
  2848. //
  2849. // SPLOG--write out a log entry
  2850. //
  2851. if(cr == CR_REMOVE_VETOED) {
  2852. //
  2853. // get the LogContext from dipb which should be a pointer
  2854. // to the appropriate DevInstallParamBlock
  2855. //
  2856. _WriteVetoLogEntry(
  2857. dipb->LogContext,
  2858. DRIVER_LOG_WARNING,
  2859. MSG_LOG_REMOVE_VETOED_IN_MOVE,
  2860. DeviceInstanceId,
  2861. VetoName,
  2862. VetoType);
  2863. }
  2864. RemoveSucceeded = FALSE;
  2865. }
  2866. #else
  2867. //
  2868. // It appears that some people (who are broken)
  2869. // do rely on setupapi to install devices
  2870. //
  2871. WriteLogEntry(
  2872. LogContext,
  2873. DRIVER_LOG_ERROR,
  2874. MSG_LOG_NOT_FOR_THIS_OS,
  2875. NULL);
  2876. RemoveSucceeded = FALSE;
  2877. #endif
  2878. }
  2879. if(RemoveSucceeded) {
  2880. //
  2881. // Source device instance successfully removed--now locate it as a phantom.
  2882. //
  2883. CM_Locate_DevInst_Ex(&(SourceDevInfoElem->DevInst),
  2884. (DEVINSTID)DeviceInstanceId,
  2885. CM_LOCATE_DEVINST_PHANTOM,
  2886. pDeviceInfoSet->hMachine);
  2887. SourceDevInfoElem->DiElemFlags |= DIE_IS_PHANTOM;
  2888. //
  2889. // Totally remove the source device from the system.
  2890. //
  2891. cr = CM_Uninstall_DevInst_Ex(SourceDevInfoElem->DevInst, 0, pDeviceInfoSet->hMachine);
  2892. if (cr != CR_SUCCESS) {
  2893. //
  2894. // we try to catch this earlier
  2895. //
  2896. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  2897. goto clean0;
  2898. }
  2899. //
  2900. // Tell ConfigMgr to start the new (destination) device instance.
  2901. //
  2902. CM_Setup_DevInst_Ex(DestDevInfoElem->DevInst, CM_SETUP_DEVINST_READY, pDeviceInfoSet->hMachine);
  2903. CheckIfDevStarted(DestDevInfoElem, pDeviceInfoSet);
  2904. } else {
  2905. //
  2906. // Can't remove the device. Since we don't have a working
  2907. // CM_Move_DevNode, we're stuck. Fail the call, and write out a
  2908. // log entry indicating the cause of the failure.
  2909. //
  2910. WriteLogEntry(dipb->LogContext,
  2911. DRIVER_LOG_ERROR,
  2912. MSG_LOG_MOVE_FAILED_CANT_REMOVE,
  2913. NULL
  2914. );
  2915. Err = ERROR_CANT_REMOVE_DEVINST;
  2916. goto clean0;
  2917. }
  2918. //
  2919. // Mark the source device instance as unregistered, and clear its DevInst
  2920. // handle.
  2921. //
  2922. SourceDevInfoElem->DiElemFlags &= ~DIE_IS_REGISTERED;
  2923. SourceDevInfoElem->DevInst = (DEVINST)0;
  2924. clean0: ; // nothing to do.
  2925. } except(EXCEPTION_EXECUTE_HANDLER) {
  2926. Err = ERROR_INVALID_PARAMETER;
  2927. //
  2928. // Reference the following variables so that the compiler will respect our statement
  2929. // ordering w.r.t. assignment.
  2930. //
  2931. pDeviceInfoSet = pDeviceInfoSet;
  2932. bUnlockDestDevInfoElem = bUnlockDestDevInfoElem;
  2933. bUnlockSourceDevInfoElem = bUnlockSourceDevInfoElem;
  2934. }
  2935. if(bUnlockDestDevInfoElem || bUnlockSourceDevInfoElem || bRestoreConfigMgrBehavior) {
  2936. if(!pDeviceInfoSet) {
  2937. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  2938. //
  2939. // we should never hit this code path
  2940. //
  2941. MYASSERT(pDeviceInfoSet);
  2942. if (Err == NO_ERROR) {
  2943. Err = ERROR_INVALID_HANDLE;
  2944. }
  2945. }
  2946. }
  2947. try {
  2948. if(bUnlockDestDevInfoElem) {
  2949. DestDevInfoElem->DiElemFlags &= ~DIE_IS_LOCKED;
  2950. }
  2951. if(bUnlockSourceDevInfoElem) {
  2952. SourceDevInfoElem->DiElemFlags &= ~DIE_IS_LOCKED;
  2953. }
  2954. if(bRestoreConfigMgrBehavior) {
  2955. dipb->Flags &= ~DI_DONOTCALLCONFIGMG;
  2956. }
  2957. } except(EXCEPTION_EXECUTE_HANDLER) {
  2958. ; // nothing to do
  2959. }
  2960. }
  2961. if(pDeviceInfoSet) {
  2962. UnlockDeviceInfoSet(pDeviceInfoSet);
  2963. }
  2964. clean1:
  2965. if (Err == NO_ERROR) {
  2966. //
  2967. // give a +ve affirmation of move
  2968. //
  2969. WriteLogEntry(
  2970. LogContext,
  2971. DRIVER_LOG_INFO,
  2972. MSG_LOG_MOVED,
  2973. NULL);
  2974. } else {
  2975. //
  2976. // indicate move failed, display error
  2977. //
  2978. WriteLogEntry(
  2979. LogContext,
  2980. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  2981. MSG_LOG_MOVE_ERROR,
  2982. NULL);
  2983. WriteLogError(
  2984. LogContext,
  2985. DRIVER_LOG_ERROR,
  2986. Err);
  2987. }
  2988. SetLastError(Err);
  2989. return(Err == NO_ERROR);
  2990. }
  2991. BOOL
  2992. WINAPI
  2993. SetupDiChangeState(
  2994. IN HDEVINFO DeviceInfoSet,
  2995. IN OUT PSP_DEVINFO_DATA DeviceInfoData
  2996. )
  2997. /*++
  2998. Routine Description:
  2999. Default handler for DIF_PROPERTYCHANGE
  3000. This routine is used to change the state of an installed device.
  3001. Arguments:
  3002. DeviceInfoSet - Supplies a handle to the device information set for which a
  3003. device's state is to be changed.
  3004. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure identifying
  3005. the device whose state is to be changed. This is an IN OUT parameter, since
  3006. the DevInst field of the structure may be updated with a new handle value upon
  3007. return.
  3008. Return Value:
  3009. If the function succeeds, and there are files to be copied, the return value is TRUE.
  3010. If the function fails, the return value is FALSE, and GetLastError returns the cause
  3011. of failure.
  3012. --*/
  3013. {
  3014. PDEVICE_INFO_SET pDeviceInfoSet;
  3015. DWORD Err;
  3016. PDEVINFO_ELEM DevInfoElem;
  3017. PDEVINSTALL_PARAM_BLOCK dipb = NULL;
  3018. DWORD dwConfigFlags;
  3019. HKEY hk;
  3020. DEVINST dnToReenum;
  3021. DWORD dwStateChange;
  3022. DWORD dwFlags;
  3023. ULONG lParam;
  3024. TCHAR szDevID[MAX_DEVICE_ID_LEN];
  3025. DWORD dwHWProfFlags;
  3026. HWPROFILEINFO HwProfileInfo;
  3027. CONFIGRET cr;
  3028. DWORD slot_deviceID = 0;
  3029. DWORD action = MSG_LOG_PROPERTYCHANGE_ERROR;
  3030. DWORD actionerr = MSG_LOG_PROPERTYCHANGE_ERROR;
  3031. #ifndef UNICODE
  3032. ULONG ulStatus;
  3033. ULONG ulProblem;
  3034. #endif
  3035. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  3036. SetLastError(ERROR_INVALID_HANDLE);
  3037. return FALSE;
  3038. }
  3039. Err = NO_ERROR;
  3040. try {
  3041. //
  3042. // Locate the devinfo element whose state is to be changed.
  3043. //
  3044. if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  3045. DeviceInfoData,
  3046. NULL)) {
  3047. dipb = &(DevInfoElem->InstallParamBlock);
  3048. } else {
  3049. Err = ERROR_INVALID_PARAMETER;
  3050. goto clean0;
  3051. }
  3052. if((cr = CM_Get_Device_ID_Ex(DevInfoElem->DevInst,
  3053. szDevID,
  3054. SIZECHARS(szDevID),
  3055. 0,
  3056. pDeviceInfoSet->hMachine)) != CR_SUCCESS) {
  3057. //
  3058. // this should never fail
  3059. //
  3060. MYASSERT(!CR_SUCCESS);
  3061. Err = ERROR_INVALID_PARAMETER;
  3062. goto clean0;
  3063. }
  3064. slot_deviceID = AllocLogInfoSlotOrLevel(dipb->LogContext,DRIVER_LOG_INFO,FALSE);
  3065. if(slot_deviceID) {
  3066. WriteLogEntry(
  3067. dipb->LogContext,
  3068. slot_deviceID,
  3069. MSG_LOG_DO_PROPERTYCHANGE,
  3070. NULL, // text message
  3071. szDevID);
  3072. }
  3073. //
  3074. // This routine can't be called if non-native drivers are involved.
  3075. // (Note: while presently this doesn't matter, it's possible that in
  3076. // the future this operation could involve running one or more INF
  3077. // sections, and I don't want to limit that possibility by introducing
  3078. // the complication of non-native driver nodes.)
  3079. //
  3080. if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_ALTPLATFORM_DRVSEARCH) {
  3081. Err = ERROR_INVALID_FLAGS;
  3082. goto clean0;
  3083. }
  3084. if(!(dipb->Flags & DI_CLASSINSTALLPARAMS) ||
  3085. (dipb->ClassInstallHeader->InstallFunction != DIF_PROPERTYCHANGE)) {
  3086. //
  3087. // Don't have any class install parameters to tell us what needs to be done!
  3088. //
  3089. Err = ERROR_NO_CLASSINSTALL_PARAMS;
  3090. goto clean0;
  3091. }
  3092. if(!DevInfoElem->DevInst) {
  3093. Err = ERROR_NO_SUCH_DEVINST;
  3094. goto clean0;
  3095. }
  3096. dwStateChange = ((PSP_PROPCHANGE_PARAMS)(dipb->ClassInstallHeader))->StateChange;
  3097. dwFlags = ((PSP_PROPCHANGE_PARAMS)(dipb->ClassInstallHeader))->Scope;
  3098. lParam = ((PSP_PROPCHANGE_PARAMS)(dipb->ClassInstallHeader))->HwProfile;
  3099. //
  3100. // DICS_FLAG_CONFIGGENERAL is allowed below and is ignored
  3101. // people are relying on this broken behaviour
  3102. //
  3103. switch(dwStateChange) {
  3104. case DICS_ENABLE:
  3105. if(dwFlags == DICS_FLAG_GLOBAL) {
  3106. action = MSG_LOG_PROPERTYCHANGE_ENABLE_GLOBAL;
  3107. actionerr = MSG_LOG_PROPERTYCHANGE_ENABLE_GLOBAL_ERR;
  3108. //
  3109. // Clear the Disabled config flag, and attempt to enumerate the
  3110. // device. Presumably it has a device node, it is just dormant (ie
  3111. // prob 80000001).
  3112. //
  3113. dwConfigFlags = GetDevInstConfigFlags(DevInfoElem->DevInst,
  3114. 0,pDeviceInfoSet->hMachine) & ~CONFIGFLAG_DISABLED;
  3115. //
  3116. // Set the New config flags value
  3117. //
  3118. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  3119. CM_DRP_CONFIGFLAGS,
  3120. &dwConfigFlags,
  3121. sizeof(dwConfigFlags),
  3122. 0,
  3123. pDeviceInfoSet->hMachine);
  3124. if(!(dipb->Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))) {
  3125. if(CM_Enable_DevNode_Ex(DevInfoElem->DevInst, 0,pDeviceInfoSet->hMachine) == CR_SUCCESS) {
  3126. //
  3127. // Find the parent of this devnode and reenumerate it to bring this devnode online.
  3128. //
  3129. if (CM_Get_Parent_Ex(&dnToReenum, DevInfoElem->DevInst, 0, pDeviceInfoSet->hMachine) == CR_SUCCESS) {
  3130. //
  3131. // Process this devnode now.
  3132. //
  3133. CM_Reenumerate_DevNode_Ex(dnToReenum, CM_REENUMERATE_SYNCHRONOUS,pDeviceInfoSet->hMachine);
  3134. }
  3135. //
  3136. // See if we sucessfully started dynamically.
  3137. //
  3138. CheckIfDevStarted(DevInfoElem, pDeviceInfoSet);
  3139. } else {
  3140. //
  3141. // We could not enable so we should restart
  3142. //
  3143. SetDevnodeNeedsRebootProblem(DevInfoElem,pDeviceInfoSet,
  3144. MSG_LOG_REBOOT_REASON_ENABLE_FAILED);
  3145. }
  3146. }
  3147. } else {
  3148. action = MSG_LOG_PROPERTYCHANGE_ENABLE_PROFILE;
  3149. actionerr = MSG_LOG_PROPERTYCHANGE_ENABLE_PROFILE_ERR;
  3150. //
  3151. // Get the hardware profile-specific flags
  3152. //
  3153. if(CM_Get_HW_Prof_Flags_Ex(szDevID, lParam, &dwHWProfFlags, 0,pDeviceInfoSet->hMachine) == CR_SUCCESS) {
  3154. //
  3155. // Clear the Disabled bit.
  3156. //
  3157. dwHWProfFlags &= ~CSCONFIGFLAG_DISABLED;
  3158. } else {
  3159. dwHWProfFlags = 0;
  3160. }
  3161. //
  3162. // Set the profile Flags for this device to Enabled. Setting the flags will
  3163. // also bring the devnode on-line, if we're modifying the current hardware
  3164. // profile.
  3165. //
  3166. cr = CM_Set_HW_Prof_Flags_Ex(szDevID, lParam, dwHWProfFlags, 0, pDeviceInfoSet->hMachine);
  3167. if(cr == CR_NEED_RESTART) {
  3168. SetDevnodeNeedsRebootProblem(DevInfoElem,pDeviceInfoSet,
  3169. MSG_LOG_REBOOT_REASON_HW_PROF_ENABLE_FAILED);
  3170. } else if(cr != CR_SUCCESS) {
  3171. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  3172. goto clean0;
  3173. }
  3174. }
  3175. break;
  3176. case DICS_DISABLE:
  3177. if(dwFlags == DICS_FLAG_GLOBAL) {
  3178. BOOL disabled = FALSE;
  3179. action = MSG_LOG_PROPERTYCHANGE_DISABLE_GLOBAL;
  3180. actionerr = MSG_LOG_PROPERTYCHANGE_DISABLE_GLOBAL_ERR;
  3181. //
  3182. // we try to dynamically disable a device
  3183. // if it fails with anything but CR_NOT_DISABLEABLE
  3184. // then we set flag to try to disable it on reboot
  3185. //
  3186. if(!(dipb->Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))) {
  3187. cr = CM_Disable_DevNode_Ex(DevInfoElem->DevInst,
  3188. CM_DISABLE_POLITE | CM_DISABLE_UI_NOT_OK,
  3189. pDeviceInfoSet->hMachine
  3190. );
  3191. if (cr == CR_SUCCESS) {
  3192. //
  3193. // we managed to disable it immediately
  3194. //
  3195. disabled = TRUE;
  3196. } else if (cr == CR_NOT_DISABLEABLE) {
  3197. //
  3198. // we couldn't and shouldn't try to disable it
  3199. //
  3200. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  3201. goto clean0;
  3202. } else {
  3203. //
  3204. // set flag to indicate a reboot is required to disable this
  3205. //
  3206. SetDevnodeNeedsRebootProblem(DevInfoElem,pDeviceInfoSet,
  3207. MSG_LOG_REBOOT_REASON_DISABLE_FAILED);
  3208. }
  3209. }
  3210. //
  3211. // Note: There is a case where reboot-disabled device becomes non-disableable
  3212. // nothing we can do about this!
  3213. //
  3214. // Try and set the Disabled config flag if not already set, even if we managed to disable it
  3215. //
  3216. dwConfigFlags = GetDevInstConfigFlags(DevInfoElem->DevInst,
  3217. 0,pDeviceInfoSet->hMachine);
  3218. if ((dwConfigFlags & CONFIGFLAG_DISABLED) == 0) {
  3219. dwConfigFlags |= CONFIGFLAG_DISABLED;
  3220. //
  3221. // Set the New config flags value
  3222. //
  3223. cr = CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  3224. CM_DRP_CONFIGFLAGS,
  3225. &dwConfigFlags,
  3226. sizeof(dwConfigFlags),
  3227. 0,
  3228. pDeviceInfoSet->hMachine);
  3229. if (cr != CR_SUCCESS) {
  3230. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  3231. goto clean0;
  3232. }
  3233. }
  3234. } else {
  3235. action = MSG_LOG_PROPERTYCHANGE_DISABLE_PROFILE;
  3236. actionerr = MSG_LOG_PROPERTYCHANGE_DISABLE_PROFILE_ERR;
  3237. //
  3238. // Get the hardware profile-specific flags
  3239. //
  3240. if(CM_Get_HW_Prof_Flags_Ex(szDevID, lParam,
  3241. &dwHWProfFlags, 0,pDeviceInfoSet->hMachine) != CR_SUCCESS) {
  3242. dwHWProfFlags = 0;
  3243. }
  3244. //
  3245. // Set the Disabled bit.
  3246. //
  3247. dwHWProfFlags |= CSCONFIGFLAG_DISABLED;
  3248. //
  3249. // Set the profile Flags for this device to Disabled. Setting this
  3250. // flag will also take this device off-line, if we're modifying the
  3251. // current hardware profile.
  3252. //
  3253. cr = CM_Set_HW_Prof_Flags_Ex(szDevID,
  3254. lParam,
  3255. dwHWProfFlags,
  3256. CM_SET_HW_PROF_FLAGS_UI_NOT_OK,
  3257. pDeviceInfoSet->hMachine
  3258. );
  3259. if(cr == CR_NEED_RESTART) {
  3260. SetDevnodeNeedsRebootProblem(DevInfoElem,pDeviceInfoSet,
  3261. MSG_LOG_REBOOT_REASON_HW_PROF_DISABLE_FAILED);
  3262. } else if(cr != CR_SUCCESS) {
  3263. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  3264. goto clean0;
  3265. }
  3266. }
  3267. break;
  3268. case DICS_PROPCHANGE:
  3269. //
  3270. // Properties have changed, so we need to remove the Devnode, and
  3271. // re-enumerate its parent.
  3272. //
  3273. // Don't remove/reenumerate if reboot/restart is required, or if DI_DONOTCALLCONFIGMG
  3274. // is set (the device may implement some form of 'non-stop' property change mechanism).
  3275. //
  3276. if(dipb->Flags & (DI_DONOTCALLCONFIGMG | DI_NEEDREBOOT | DI_NEEDRESTART)) {
  3277. action = MSG_LOG_PROPERTYCHANGE_NORESTART;
  3278. } else {
  3279. TCHAR VetoName[MAX_PATH];
  3280. PNP_VETO_TYPE VetoType;
  3281. action = MSG_LOG_PROPERTYCHANGE_RESTART;
  3282. actionerr = MSG_LOG_PROPERTYCHANGE_RESTART_ERR;
  3283. CM_Get_Parent_Ex(&dnToReenum, DevInfoElem->DevInst, 0,pDeviceInfoSet->hMachine);
  3284. #ifdef UNICODE
  3285. cr = CM_Query_And_Remove_SubTree_Ex(DevInfoElem->DevInst,
  3286. &VetoType,
  3287. VetoName,
  3288. SIZECHARS(VetoName),
  3289. (DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_NOUIONQUERYREMOVE)
  3290. ? CM_REMOVE_UI_NOT_OK
  3291. : CM_REMOVE_UI_OK,
  3292. pDeviceInfoSet->hMachine
  3293. );
  3294. if(cr == CR_SUCCESS) {
  3295. CM_Reenumerate_DevInst_Ex(dnToReenum, CM_REENUMERATE_SYNCHRONOUS,pDeviceInfoSet->hMachine);
  3296. DevInfoElem->DevInst = 0;
  3297. if(CM_Locate_DevInst_Ex(&(DevInfoElem->DevInst),
  3298. (DEVINSTID)szDevID,
  3299. CM_LOCATE_DEVINST_NORMAL,
  3300. pDeviceInfoSet->hMachine) == CR_SUCCESS) {
  3301. //
  3302. // Make sure the device instance started OK
  3303. //
  3304. if(!CheckIfDevStarted(DevInfoElem,pDeviceInfoSet)) {
  3305. action = MSG_LOG_PROPERTYCHANGE_RESTART_FAILED;
  3306. }
  3307. } else {
  3308. //
  3309. // We couldn't locate the devnode. We don't need
  3310. // to request a reboot, because if the devnode ever
  3311. // shows up again, we should be able to bring it
  3312. // back on-line just fine.
  3313. //
  3314. // Retrieve the devnode as a phantom
  3315. //
  3316. CM_Locate_DevInst_Ex(&(DevInfoElem->DevInst),
  3317. (DEVINSTID)szDevID,
  3318. CM_LOCATE_DEVINST_PHANTOM,
  3319. pDeviceInfoSet->hMachine
  3320. );
  3321. DevInfoElem->DiElemFlags |= DIE_IS_PHANTOM;
  3322. }
  3323. //
  3324. // Update the caller's buffer to reflect the new device instance handle
  3325. //
  3326. DeviceInfoData->DevInst = DevInfoElem->DevInst;
  3327. } else {
  3328. //
  3329. // If the failure was due to a veto, then log
  3330. // information about who vetoed us.
  3331. //
  3332. // SPLOG--write a log entry
  3333. //
  3334. if(cr == CR_REMOVE_VETOED) {
  3335. //
  3336. // get the LogContext from dipb which should be a pointer
  3337. // to the appropriate DevInstallParamBlock
  3338. //
  3339. _WriteVetoLogEntry(
  3340. dipb->LogContext,
  3341. DRIVER_LOG_WARNING,
  3342. MSG_LOG_REMOVE_VETOED_IN_PROPCHANGE,
  3343. szDevID,
  3344. VetoName,
  3345. VetoType);
  3346. }
  3347. SetDevnodeNeedsRebootProblem(DevInfoElem,pDeviceInfoSet,
  3348. MSG_LOG_REBOOT_VETOED_IN_PROPCHANGE);
  3349. action = MSG_LOG_PROPERTYCHANGE_RESTART_FAILED;
  3350. }
  3351. #else
  3352. //
  3353. // It appears that some people (who are broken)
  3354. // do rely on setupapi to install devices
  3355. // so old code conditionally re-introduced to try and fix them
  3356. //
  3357. WriteLogEntry(
  3358. dipb->LogContext,
  3359. DRIVER_LOG_ERROR,
  3360. MSG_LOG_NOT_FOR_THIS_OS,
  3361. NULL);
  3362. if(CM_Query_Remove_SubTree(DevInfoElem->DevInst, 0) == CR_SUCCESS) {
  3363. CM_Get_Parent(&dnToReenum, DevInfoElem->DevInst, 0);
  3364. CM_Remove_SubTree(DevInfoElem->DevInst, 0);
  3365. CM_Reenumerate_DevInst(dnToReenum, CM_REENUMERATE_SYNCHRONOUS);
  3366. DevInfoElem->DevInst = 0;
  3367. if(CM_Locate_DevInst(&(DevInfoElem->DevInst),
  3368. (DEVINSTID)szDevID,
  3369. CM_LOCATE_DEVINST_NORMAL) != CR_SUCCESS) {
  3370. dipb->Flags |= DI_NEEDREBOOT;
  3371. action = MSG_LOG_PROPERTYCHANGE_RESTART_FAILED;
  3372. //
  3373. // Retrieve the devinst as a phantom
  3374. //
  3375. CM_Locate_DevInst(&(DevInfoElem->DevInst),
  3376. (DEVINSTID)szDevID,
  3377. CM_LOCATE_DEVINST_PHANTOM
  3378. );
  3379. DevInfoElem->DiElemFlags |= DIE_IS_PHANTOM;
  3380. //
  3381. // Update the caller's buffer to reflect the new device instance handle
  3382. //
  3383. DeviceInfoData->DevInst = DevInfoElem->DevInst;
  3384. }
  3385. //
  3386. // Make Sure the device instance started OK
  3387. //
  3388. if((CM_Get_DevNode_Status(&ulStatus, &ulProblem, DevInfoElem->DevInst, 0) == CR_SUCCESS) && !(ulStatus & DN_STARTED)) {
  3389. dipb->Flags |= DI_NEEDREBOOT;
  3390. action = MSG_LOG_PROPERTYCHANGE_RESTART_FAILED;
  3391. }
  3392. } else {
  3393. dipb->Flags |= DI_NEEDREBOOT;
  3394. action = MSG_LOG_PROPERTYCHANGE_RESTART_FAILED;
  3395. }
  3396. #endif
  3397. }
  3398. break;
  3399. case DICS_START:
  3400. action = MSG_LOG_PROPERTYCHANGE_START;
  3401. actionerr = MSG_LOG_PROPERTYCHANGE_START_ERR;
  3402. //
  3403. // DICS_START is always config specific (we enforce this in SetupDiSetClassInstallParams).
  3404. //
  3405. MYASSERT(dwFlags == DICS_FLAG_CONFIGSPECIFIC);
  3406. //
  3407. // Get the Profile Flags.
  3408. //
  3409. if(CM_Get_HW_Prof_Flags_Ex(szDevID, lParam, &dwHWProfFlags, 0,pDeviceInfoSet->hMachine) == CR_SUCCESS) {
  3410. //
  3411. // Clear the "don't start" bit.
  3412. //
  3413. dwHWProfFlags &= ~CSCONFIGFLAG_DO_NOT_START;
  3414. } else {
  3415. dwHWProfFlags = 0;
  3416. }
  3417. cr = CM_Set_HW_Prof_Flags_Ex(szDevID, lParam, dwHWProfFlags, 0, pDeviceInfoSet->hMachine);
  3418. if(cr == CR_NEED_RESTART) {
  3419. //
  3420. // Since setting/clearing the CSCONFIGFLAG_DO_NOT_START doesn't
  3421. // automatically effect a change, we should never get here.
  3422. //
  3423. SetDevnodeNeedsRebootProblem(DevInfoElem,pDeviceInfoSet,
  3424. MSG_LOG_REBOOT_REASON_CLEAR_CSCONFIGFLAG_DO_NOT_START);
  3425. action = MSG_LOG_PROPERTYCHANGE_START_FAILED;
  3426. } else if(cr != CR_SUCCESS) {
  3427. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  3428. goto clean0;
  3429. }
  3430. //
  3431. // Start the device instance if this is for the current config (ie dwConfigID/lparam == 0)
  3432. //
  3433. if((lParam == 0) ||
  3434. ((CM_Get_Hardware_Profile_Info_Ex((ULONG)-1, &HwProfileInfo,
  3435. 0,pDeviceInfoSet->hMachine) == CR_SUCCESS) &&
  3436. (HwProfileInfo.HWPI_ulHWProfile == lParam)))
  3437. {
  3438. //
  3439. // Try to start the devnode.
  3440. //
  3441. if(!(dipb->Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))) {
  3442. CM_Setup_DevNode_Ex(DevInfoElem->DevInst, CM_SETUP_DEVNODE_READY,pDeviceInfoSet->hMachine);
  3443. if(!CheckIfDevStarted(DevInfoElem, pDeviceInfoSet)) {
  3444. action = MSG_LOG_PROPERTYCHANGE_START_FAILED;
  3445. }
  3446. } else {
  3447. action = MSG_LOG_PROPERTYCHANGE_START_FAILED;
  3448. }
  3449. }
  3450. break;
  3451. case DICS_STOP:
  3452. action = MSG_LOG_PROPERTYCHANGE_STOP;
  3453. actionerr = MSG_LOG_PROPERTYCHANGE_STOP_ERR;
  3454. //
  3455. // DICS_STOP is always config specific (we enforce this in SetupDiSetClassInstallParams).
  3456. //
  3457. MYASSERT(dwFlags == DICS_FLAG_CONFIGSPECIFIC);
  3458. //
  3459. // Get the Profile Flags.
  3460. //
  3461. if(CM_Get_HW_Prof_Flags_Ex(szDevID, lParam, &dwHWProfFlags,
  3462. 0,pDeviceInfoSet->hMachine) != CR_SUCCESS) {
  3463. dwHWProfFlags = 0;
  3464. }
  3465. //
  3466. // Set the "don't start" bit.
  3467. //
  3468. dwHWProfFlags |= CSCONFIGFLAG_DO_NOT_START;
  3469. cr = CM_Set_HW_Prof_Flags_Ex(szDevID,
  3470. lParam,
  3471. dwHWProfFlags,
  3472. CM_SET_HW_PROF_FLAGS_UI_NOT_OK,
  3473. pDeviceInfoSet->hMachine
  3474. );
  3475. if(cr == CR_NEED_RESTART) {
  3476. //
  3477. // Since setting/clearing the CSCONFIGFLAG_DO_NOT_START doesn't
  3478. // automatically effect a change, we should never get here.
  3479. //
  3480. SetDevnodeNeedsRebootProblem(DevInfoElem,pDeviceInfoSet,
  3481. MSG_LOG_REBOOT_REASON_SET_CSCONFIGFLAG_DO_NOT_START);
  3482. action = MSG_LOG_PROPERTYCHANGE_STOP_FAILED;
  3483. } else if(cr != CR_SUCCESS) {
  3484. Err = MapCrToSpError(cr, ERROR_INVALID_DATA);
  3485. goto clean0;
  3486. }
  3487. //
  3488. // Stop the device instance if this is for the current config (ie dwConfigID/lparam == 0)
  3489. //
  3490. if((lParam == 0) ||
  3491. ((CM_Get_Hardware_Profile_Info_Ex((ULONG)-1, &HwProfileInfo,
  3492. 0,pDeviceInfoSet->hMachine) == CR_SUCCESS) &&
  3493. (HwProfileInfo.HWPI_ulHWProfile == lParam)))
  3494. {
  3495. //
  3496. // Try to stop the devnode.
  3497. //
  3498. if(!(dipb->Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))) {
  3499. TCHAR VetoName[MAX_PATH];
  3500. PNP_VETO_TYPE VetoType;
  3501. //
  3502. // Remove the device instance in order to stop the device.
  3503. //
  3504. #ifdef UNICODE
  3505. cr = CM_Query_And_Remove_SubTree_Ex(DevInfoElem->DevInst,
  3506. &VetoType,
  3507. VetoName,
  3508. SIZECHARS(VetoName),
  3509. (DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_NOUIONQUERYREMOVE)
  3510. ? CM_REMOVE_UI_NOT_OK
  3511. : CM_REMOVE_UI_OK,
  3512. pDeviceInfoSet->hMachine
  3513. );
  3514. if(cr == CR_SUCCESS) {
  3515. //
  3516. // Device instance successfully removed--now locate it as a phantom.
  3517. //
  3518. CM_Locate_DevInst_Ex(&(DevInfoElem->DevInst),
  3519. (DEVINSTID)szDevID,
  3520. CM_LOCATE_DEVINST_PHANTOM,
  3521. pDeviceInfoSet->hMachine);
  3522. DevInfoElem->DiElemFlags |= DIE_IS_PHANTOM;
  3523. //
  3524. // Update the caller's buffer to reflect the new device instance handle.
  3525. //
  3526. DeviceInfoData->DevInst = DevInfoElem->DevInst;
  3527. } else {
  3528. //
  3529. // If the failure was due to a veto, then log
  3530. // information about who vetoed us.
  3531. //
  3532. // SPLOG--write out a real log entry
  3533. //
  3534. if(cr == CR_REMOVE_VETOED) {
  3535. //
  3536. // get the LogContext from dipb which should be a pointer
  3537. // to the appropriate DevInstallParamBlock
  3538. //
  3539. _WriteVetoLogEntry(
  3540. dipb->LogContext,
  3541. DRIVER_LOG_WARNING,
  3542. MSG_LOG_REMOVE_VETOED_IN_STOP,
  3543. szDevID,
  3544. VetoName,
  3545. VetoType);
  3546. }
  3547. SetDevnodeNeedsRebootProblemWithArg2(DevInfoElem,
  3548. pDeviceInfoSet,
  3549. MSG_LOG_REBOOT_QR_VETOED_IN_STOP,
  3550. cr,
  3551. (ULONG_PTR)_MapCmRetToString(cr)
  3552. );
  3553. }
  3554. #else
  3555. //
  3556. // It appears that some people (who are broken)
  3557. // do rely on setupapi to install devices
  3558. // so old code remains for Win9x version of setupapi.dll
  3559. //
  3560. WriteLogEntry(
  3561. dipb->LogContext,
  3562. DRIVER_LOG_ERROR,
  3563. MSG_LOG_NOT_FOR_THIS_OS,
  3564. NULL);
  3565. //
  3566. // Remove the device instance in order to stop the device.
  3567. //
  3568. if((CM_Query_Remove_SubTree(DevInfoElem->DevInst, CM_QUERY_REMOVE_UI_OK) == CR_SUCCESS) &&
  3569. (CM_Remove_SubTree(DevInfoElem->DevInst, CM_REMOVE_UI_OK) == CR_SUCCESS)) {
  3570. //
  3571. // Device instance successfully removed--now locate it as a phantom.
  3572. //
  3573. CM_Locate_DevInst(&(DevInfoElem->DevInst),
  3574. (DEVINSTID)szDevID,
  3575. CM_LOCATE_DEVINST_PHANTOM
  3576. );
  3577. DevInfoElem->DiElemFlags |= DIE_IS_PHANTOM;
  3578. //
  3579. // Update the caller's buffer to reflect the new device instance handle.
  3580. //
  3581. DeviceInfoData->DevInst = DevInfoElem->DevInst;
  3582. } else {
  3583. dipb->Flags |= DI_NEEDREBOOT;
  3584. action = MSG_LOG_PROPERTYCHANGE_STOP_FAILED;
  3585. }
  3586. #endif
  3587. } else {
  3588. action = MSG_LOG_PROPERTYCHANGE_STOP_FAILED;
  3589. }
  3590. }
  3591. break;
  3592. default:
  3593. action = actionerr = MSG_LOG_PROPERTYCHANGE_UNKNOWN;
  3594. Err = ERROR_DI_DO_DEFAULT;
  3595. }
  3596. clean0: ; // nothing to do.
  3597. } except(EXCEPTION_EXECUTE_HANDLER) {
  3598. Err = ERROR_INVALID_PARAMETER;
  3599. }
  3600. if(slot_deviceID) {
  3601. if ((Err == NO_ERROR) || (Err == ERROR_DI_DO_DEFAULT)) {
  3602. //
  3603. // give a +ve affirmation of property change
  3604. //
  3605. WriteLogEntry(
  3606. dipb->LogContext,
  3607. Err ? DRIVER_LOG_ERROR : DRIVER_LOG_INFO,
  3608. action,
  3609. NULL,
  3610. dwStateChange,
  3611. dwFlags,
  3612. lParam
  3613. );
  3614. } else {
  3615. //
  3616. // indicate property change failed, display error
  3617. //
  3618. WriteLogEntry(
  3619. dipb->LogContext,
  3620. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  3621. actionerr,
  3622. NULL,
  3623. dwStateChange,
  3624. dwFlags,
  3625. lParam
  3626. );
  3627. WriteLogError(
  3628. dipb->LogContext,
  3629. DRIVER_LOG_ERROR,
  3630. Err);
  3631. }
  3632. ReleaseLogInfoSlot(dipb->LogContext,slot_deviceID);
  3633. }
  3634. UnlockDeviceInfoSet(pDeviceInfoSet);
  3635. SetLastError(Err);
  3636. return(Err == NO_ERROR);
  3637. }
  3638. DWORD
  3639. GetNewInfName(
  3640. IN HWND Owner, OPTIONAL
  3641. IN PCTSTR OemInfName,
  3642. IN PCTSTR OemInfOriginalName,
  3643. IN PCTSTR OemInfCatName, OPTIONAL
  3644. OUT PTSTR NewInfName,
  3645. IN DWORD NewInfNameSize,
  3646. OUT PDWORD RequiredSize,
  3647. OUT PNEWINF_COPYTYPE CopyNeeded,
  3648. IN BOOL ReplaceOnly,
  3649. IN PCTSTR DeviceDesc, OPTIONAL
  3650. IN DWORD DriverSigningPolicy,
  3651. IN DWORD Flags,
  3652. IN PCTSTR AltCatalogFile, OPTIONAL
  3653. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  3654. OUT PDWORD DriverSigningError, OPTIONAL
  3655. OUT PTSTR CatalogFilenameOnSystem,
  3656. IN PSETUP_LOG_CONTEXT LogContext,
  3657. IN OUT HCATADMIN *hCatAdmin OPTIONAL
  3658. )
  3659. /*++
  3660. Routine Description:
  3661. This routine finds a unique INF name of the form "<systemroot>\Inf\OEM<n>.INF",
  3662. and returns it in the supplied buffer. It leaves an (empty) file of that
  3663. name in the INF directory, so that anyone else who attempts to generate a
  3664. unique filename won't pick the same name.
  3665. NOTE: We will search the INF directory to determine if the specified INF is
  3666. already present there based on the criteria outlined for SetupCopyOEMInf.
  3667. If so, then we will return the existing name. This name may be an
  3668. OEM<n>.INF form, or it may be the same name as the source INF.
  3669. Arguments:
  3670. Owner - supplies window to own any signature verification problem dialogs
  3671. that must be displayed.
  3672. OemInfName - Supplies the full pathname of the OEM INF that needs to be
  3673. copied into the Inf directory (under a unique name).
  3674. OemInfOriginalName - Supplies the original (simple) filename of the INF, to
  3675. be used for digital signature verification (i.e., the INF is only known
  3676. to the catalog under its original name).
  3677. OemInfCatName - Optionally, supplies the simple filename of the catalog file
  3678. specified by the OEM INF via a CatalogFile= entry in its [Version]
  3679. section.
  3680. NewInfName - supplies the address of a character buffer to store the unique
  3681. name in.
  3682. NewInfNameSize - Specifies the size, in characters, of the NewInfName buffer.
  3683. RequiredSize - supplies the address of a variable that receives the size, in
  3684. characters, required to store the full new filename.
  3685. CopyNeeded - Supplies the address of an enum variable that is set upon
  3686. successful return to indicate whether or not the OEM INF actually needs
  3687. to be copied (and whether or not the previously-existing INF, if found,
  3688. is zero-length. This variable will be set to one of the following
  3689. values:
  3690. NewInfCopyNo - no need to copy--INF already present in destination
  3691. NewInfCopyYes, - new INF placeholder created--need to copy real INF
  3692. NewInfCopyZeroLength - previously-existing zero-length INF match found
  3693. ReplaceOnly - If this flag is set, then this routine will fail if it doesn't
  3694. find that the INF/CAT is already installed.
  3695. DeviceDesc - Optionally, supplies the device description to be used in the
  3696. digital signature verification error dialogs that may be popped up.
  3697. DriverSigningPolicy - supplies the driver signing policy currently in
  3698. effect. Used when calling pSetupHandleFailedVerification, if necessary.
  3699. Flags - supplies flags which alter the behavior of the routine. May be a
  3700. combination of the following values:
  3701. SCOI_NO_UI_ON_SIGFAIL - indicates whether user should be prompted (per
  3702. DriverSigningPolicy) if a digital signature
  3703. failure is encountered. Used when calling
  3704. pSetupHandleFailedVerification, if necessary.
  3705. SCOI_NO_ERRLOG_ON_MISSING_CATALOG - if there's a signature verification
  3706. failure due to the INF lacking a
  3707. CatalogFile= entry, then that error
  3708. will be ignored if this flag is set
  3709. (no UI will be given, and no log
  3710. entry will be generated).
  3711. SCOI_KEEP_INF_AND_CAT_ORIGINAL_NAMES - Install the INF and CAT under
  3712. their original (current) names
  3713. (i.e., don't generate a unique
  3714. oem<n>.inf/cat name). Used only
  3715. for exception INFs.
  3716. SCOI_ABORT_IF_UNSIGNED - If the INF is unsigned (and user wants to copy
  3717. it anyway, or policy is Ignore), then _don't_
  3718. copy the INF and instead return the error
  3719. ERROR_SET_SYSTEM_RESTORE_POINT. This gives
  3720. the caller a chance to set a system restore
  3721. point prior to installing the unsigned package.
  3722. SCOI_TRY_UPDATE_PNF - If an existing PNF cannot be updated, don't
  3723. consider it fatal.
  3724. AltCatalogFile - Optionally, supplies the full pathname of a catalog file to
  3725. be installed and used for verification of the INF in cases where the INF
  3726. doesn't specify a CatalogFile= entry (i.e., when the OemInfCatName
  3727. parameter is not specified.
  3728. If this parameter is specified (and OemInfCatName isn't specified), then
  3729. this catalog will be used to validate the INF, and if successful, the
  3730. catalog will be installed into the system using its current name (thus
  3731. overwriting any existing catalog having that name). Nothing more will
  3732. be done with the INF--we won't even create a zero-length placeholder for
  3733. it in this case.
  3734. AltPlatformInfo - Optionally, supplies alternate platform information to be
  3735. used in digital signature verification instead of the default (native)
  3736. platform info.
  3737. DriverSigningError - Optionally, supplies the address of a variable that
  3738. receives the error encountered when attempting to verify the digital
  3739. signature of either the INF or associated catalog. If no digital
  3740. signature problems were encountered, this is set to NO_ERROR. (Note
  3741. that this value can come back as NO_ERROR, yet GetNewInfName still
  3742. failed for some other reason).
  3743. CatalogFilenameOnSystem - receives the fully-qualified path of the catalog
  3744. file within the catalog store where this INF's catalog file was
  3745. installed to. This buffer should be at least MAX_PATH bytes (ANSI
  3746. version) or chars (Unicode version).
  3747. LogContext - supplies a LogContext to be used throughout the function.
  3748. hCatAdmin - optionally, supplies the address of an HCATADMIN handle. If
  3749. the handle pointed to is NULL, a handle will be acquired (if possible)
  3750. via CryptCATAdminAcquireContext and returned to the caller. If the
  3751. handle pointed to is non-NULL, then that handle will be used for any
  3752. validation done via this routine. If the pointer itself is NULL, then
  3753. an hCatAdmin will be acquired for the duration of this call, and
  3754. released before returning.
  3755. NOTE: it is the caller's responsibility to free the crypto context
  3756. handle returned by this routine by calling CryptCATAdminReleaseContext.
  3757. This handle may be opened in either success or failure cases, so the
  3758. caller must check for non-NULL returned handle in both cases.
  3759. Return Value:
  3760. If the function succeeds, the return value is NO_ERROR, otherwise, it is a
  3761. Win32 error code.
  3762. --*/
  3763. {
  3764. INT i;
  3765. HANDLE h;
  3766. DWORD Err, SavedErr;
  3767. TCHAR lpszNewName[MAX_PATH];
  3768. WIN32_FIND_DATA FindData;
  3769. HANDLE FindHandle;
  3770. PTSTR FilenamePart;
  3771. DWORD OemInfFileSize, CatalogFileSize;
  3772. HANDLE OemInfFileHandle, OemInfMappingHandle;
  3773. HANDLE CatalogFileHandle, CatalogMappingHandle;
  3774. PVOID OemInfBaseAddress, CatalogBaseAddress;
  3775. DWORD CurInfFileSize;
  3776. HANDLE CurInfFileHandle, CurInfMappingHandle;
  3777. PVOID CurInfBaseAddress;
  3778. BOOL FileOfSameNameExists, MoreInfsToCheck;
  3779. WIN32_FILE_ATTRIBUTE_DATA FileAttribData;
  3780. BOOL FoundMatchingInf;
  3781. TCHAR PathBuffer[MAX_PATH];
  3782. TCHAR CatalogName[MAX_PATH];
  3783. SetupapiVerifyProblem Problem = SetupapiVerifyNoProblem;
  3784. PCTSTR ProblemFile;
  3785. DWORD NumCatalogsConsidered;
  3786. PTSTR LastResortInf;
  3787. BOOL FileNewlyCreated;
  3788. //
  3789. // Initially, assume that the specified INF isn't already present in the Inf
  3790. // directory.
  3791. //
  3792. *CopyNeeded = NewInfCopyYes;
  3793. //
  3794. // Initialize the driver signing error output parameter to success, and set
  3795. // the CatalogFilenameOnSystem character buffer to an empty string.
  3796. //
  3797. if(DriverSigningError) {
  3798. *DriverSigningError = NO_ERROR;
  3799. }
  3800. *CatalogFilenameOnSystem = TEXT('\0');
  3801. if(OemInfCatName || !AltCatalogFile) {
  3802. //
  3803. // The INF has a CatalogFile= entry, or we don't have an override. This
  3804. // means we want to do the 'normal' behavior of looking for an existing
  3805. // match in the INF directory, using default rules for which catalog
  3806. // files we'll consider during validation, etc.
  3807. //
  3808. // Examine all the existing OEM INFs in the Inf directory, to see if
  3809. // this INF already exists there. If so, we'll just return the name of
  3810. // the previously-existing file.
  3811. //
  3812. lstrcpyn(lpszNewName, InfDirectory, SIZECHARS(lpszNewName));
  3813. pSetupConcatenatePaths(lpszNewName, pszOemInfWildcard, SIZECHARS(lpszNewName), NULL);
  3814. //
  3815. // If we're supposed to install the INF and CAT under their original
  3816. // names, then we don't want to look at any of the oem<n>.inf files.
  3817. //
  3818. if(Flags & SCOI_KEEP_INF_AND_CAT_ORIGINAL_NAMES) {
  3819. FindHandle = INVALID_HANDLE_VALUE;
  3820. } else {
  3821. FindHandle = FindFirstFile(lpszNewName, &FindData);
  3822. }
  3823. //
  3824. // Now reuse our buffer to look for an INF in the Inf directory having
  3825. // the same name as our OEM INF's original name.
  3826. //
  3827. FilenamePart = (PTSTR)pSetupGetFileTitle(lpszNewName);
  3828. lstrcpy(FilenamePart, OemInfOriginalName);
  3829. FileOfSameNameExists = GetFileAttributesEx (lpszNewName, GetFileExInfoStandard, &FileAttribData);
  3830. if(FileOfSameNameExists && !OemInfCatName) {
  3831. //
  3832. // We can try to match up an OEM INF with a system INF having the same
  3833. // name even if the INF doesn't specify a CatalogFile= entry, but _not_
  3834. // if the system INF is zero-length!
  3835. //
  3836. if(!FileAttribData.nFileSizeLow) {
  3837. FileOfSameNameExists = FALSE;
  3838. }
  3839. }
  3840. if((FindHandle != INVALID_HANDLE_VALUE) || FileOfSameNameExists) {
  3841. //
  3842. // We have at least one INF to compare against, so open our source INF in preparation.
  3843. //
  3844. if(pSetupOpenAndMapFileForRead(OemInfName,
  3845. &OemInfFileSize,
  3846. &OemInfFileHandle,
  3847. &OemInfMappingHandle,
  3848. &OemInfBaseAddress) == NO_ERROR) {
  3849. if(OemInfCatName) {
  3850. //
  3851. // INF has an associated catalog--map it into memory for
  3852. // subsequent comparisons with existing installed catalogs.
  3853. //
  3854. lstrcpy(CatalogName, OemInfName);
  3855. lstrcpy((PTSTR)pSetupGetFileTitle(CatalogName), OemInfCatName);
  3856. if(pSetupOpenAndMapFileForRead(CatalogName,
  3857. &CatalogFileSize,
  3858. &CatalogFileHandle,
  3859. &CatalogMappingHandle,
  3860. &CatalogBaseAddress) != NO_ERROR) {
  3861. //
  3862. // Act as if the INF specified no CatalogFile. This
  3863. // will allow us to match up with any OEM<n>.INF that
  3864. // binary-compares with this one. We will consider
  3865. // this a digital signature verification failure,
  3866. // however. (Refer to code below that explicitly fails
  3867. // OEM<n>.INF files that don't have a CatalogFile
  3868. // entry.)
  3869. //
  3870. // Note, also, in this case we don't want to consider
  3871. // a previously-existing INF in the Inf directory that
  3872. // has this OEM INF's original name. That's because
  3873. // this would trip us up later because we'd believe we
  3874. // could do global validation on it (i.e., we'd think
  3875. // it was a system INF).
  3876. //
  3877. CatalogBaseAddress = NULL; // don't try to unmap and close later
  3878. if(FindHandle == INVALID_HANDLE_VALUE) {
  3879. //
  3880. // There are no OEM<n>.INF files to check--go ahead
  3881. // and bail.
  3882. //
  3883. goto FinishedCheckingOemInfs;
  3884. }
  3885. //
  3886. // There are some OEM<n>.INF files to check--make sure
  3887. // we _don't_ consider the originally-named file in
  3888. // %windir%\Inf, if it happens to exist.
  3889. //
  3890. FileOfSameNameExists = FALSE;
  3891. //
  3892. // Now make it look like the INF had no CatalogFile=
  3893. // entry in the first place.
  3894. //
  3895. OemInfCatName = NULL;
  3896. CatalogFileSize = 0;
  3897. }
  3898. } else {
  3899. //
  3900. // INF didn't have a CatalogFile= entry in its version
  3901. // section. This means we'll do global validation if we
  3902. // find an existing INF having this name that binary-compares
  3903. // identical. If the verification succeeds, then we'll consider
  3904. // this a match. Basically, this means you'll be able to
  3905. // re-install from system INFs, even if you point at them
  3906. // elsewhere (e.g., you point back at system.inf on the
  3907. // distribution media, but system.inf is already installed in
  3908. // your %windir%\Inf directory).
  3909. //
  3910. // If our INF doesn't specify a CatalogFile= entry, then
  3911. // we'll drop back to our pre-driver-signing behavior where
  3912. // we'll simply check to see if the INF's binary compare.
  3913. // If they do, then we know that there is no INF installed
  3914. // based on that matching INF's OEM name, thus we'll just
  3915. // drop out of the search loop and consider this a driver
  3916. // signing failure (which it is).
  3917. //
  3918. CatalogBaseAddress = NULL;
  3919. CatalogFileSize = 0;
  3920. }
  3921. LastResortInf = NULL;
  3922. do {
  3923. if(FileOfSameNameExists) {
  3924. if(FileAttribData.nFileSizeHigh) {
  3925. goto CheckNextOemInf;
  3926. }
  3927. if(FileAttribData.nFileSizeLow &&
  3928. (FileAttribData.nFileSizeLow != OemInfFileSize)) {
  3929. goto CheckNextOemInf;
  3930. }
  3931. //
  3932. // Note: We will consider a zero-length system INF that has
  3933. // the same name as our OEM INF, even if our OEM INF doesn't
  3934. // have a CatalogFile= entry in its version section. This
  3935. // allows us to re-use this name as long as we find our
  3936. // catalog is already installed.
  3937. //
  3938. CurInfFileSize = FileAttribData.nFileSizeLow;
  3939. } else {
  3940. if(FindData.nFileSizeHigh) {
  3941. goto CheckNextOemInf;
  3942. }
  3943. if(FindData.nFileSizeLow &&
  3944. (FindData.nFileSizeLow != OemInfFileSize)) {
  3945. goto CheckNextOemInf;
  3946. }
  3947. CurInfFileSize = FindData.nFileSizeLow;
  3948. //
  3949. // Build the fully-qualified path to the INF being compared.
  3950. //
  3951. lstrcpy(FilenamePart, FindData.cFileName);
  3952. }
  3953. //
  3954. // If the INF isn't zero-length, then map it into memory to
  3955. // see if it matches our OEM INF.
  3956. //
  3957. if(CurInfFileSize) {
  3958. if(pSetupOpenAndMapFileForRead(lpszNewName,
  3959. &CurInfFileSize,
  3960. &CurInfFileHandle,
  3961. &CurInfMappingHandle,
  3962. &CurInfBaseAddress) == NO_ERROR) {
  3963. //
  3964. // Surround the following in try/except, in case we get an inpage error.
  3965. //
  3966. try {
  3967. //
  3968. // We've found a potential match.
  3969. //
  3970. FoundMatchingInf = !memcmp(OemInfBaseAddress,
  3971. CurInfBaseAddress,
  3972. OemInfFileSize
  3973. );
  3974. } except(EXCEPTION_EXECUTE_HANDLER) {
  3975. FoundMatchingInf = FALSE;
  3976. }
  3977. pSetupUnmapAndCloseFile(CurInfFileHandle,
  3978. CurInfMappingHandle,
  3979. CurInfBaseAddress
  3980. );
  3981. } else {
  3982. FoundMatchingInf = FALSE;
  3983. }
  3984. if(!FoundMatchingInf) {
  3985. goto CheckNextOemInf;
  3986. }
  3987. //
  3988. // If this is an OEM*.INF name and the INF has no
  3989. // CatalogFile= entry, then we've found our match. Set
  3990. // up our driver signing problem variables to indicate
  3991. // that there was an INF failure (since there was no
  3992. // catalog.
  3993. //
  3994. if(!OemInfCatName && !FileOfSameNameExists) {
  3995. *CopyNeeded = NewInfCopyNo;
  3996. Problem = SetupapiVerifyInfProblem;
  3997. ProblemFile = OemInfName;
  3998. Err = ERROR_NO_CATALOG_FOR_OEM_INF;
  3999. //
  4000. // go to end of loop (we'll drop out since we've
  4001. // found a match).
  4002. //
  4003. goto CheckNextOemInf;
  4004. }
  4005. } else {
  4006. //
  4007. // The current INF we're considering for a match is
  4008. // zero-length. This won't work for us if the INF we're
  4009. // searching for doesn't have a CatalogFile= entry, and
  4010. // this isn't an INF having the same name.
  4011. //
  4012. if(!OemInfCatName && !FileOfSameNameExists) {
  4013. goto CheckNextOemInf;
  4014. }
  4015. }
  4016. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  4017. //
  4018. // We aren't using crypto, so if the file we found
  4019. // isn't zero-length, we've found our match.
  4020. //
  4021. if(CurInfFileSize) {
  4022. Err = NO_ERROR;
  4023. } else {
  4024. //
  4025. // File is zero-length. Keep looking.
  4026. //
  4027. goto CheckNextOemInf;
  4028. }
  4029. } else {
  4030. //
  4031. // OK, the files binary compare OK (unless the one
  4032. // we're currently examining is zero length!), but
  4033. // we're not out of the woods yet! If the INF we're
  4034. // examining had a CatalogFile= entry, then generate
  4035. // the catalog name to be used for verification (based
  4036. // on the filename of the INF we're examining).
  4037. //
  4038. if(OemInfCatName) {
  4039. lstrcpy(CatalogName, FilenamePart);
  4040. lstrcpy(_tcsrchr(CatalogName, TEXT('.')), pszCatSuffix);
  4041. }
  4042. //
  4043. // Now verify the INF's signature against the specified
  4044. // catalog (or globally if the INF doesn't specify a
  4045. // catalog).
  4046. //
  4047. Err = _VerifyFile(LogContext,
  4048. hCatAdmin,
  4049. NULL,
  4050. (OemInfCatName ? CatalogName : NULL),
  4051. CatalogBaseAddress,
  4052. CatalogFileSize,
  4053. OemInfOriginalName,
  4054. OemInfName,
  4055. &Problem,
  4056. PathBuffer,
  4057. FALSE,
  4058. AltPlatformInfo,
  4059. (VERIFY_FILE_IGNORE_SELFSIGNED
  4060. | VERIFY_FILE_USE_OEM_CATALOGS
  4061. | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  4062. CatalogFilenameOnSystem,
  4063. &NumCatalogsConsidered,
  4064. NULL,
  4065. NULL
  4066. );
  4067. }
  4068. if(Err == NO_ERROR) {
  4069. //
  4070. // We've found this INF/CAT combination already installed,
  4071. // and the signatures check out!
  4072. //
  4073. *CopyNeeded = CurInfFileSize ? NewInfCopyNo
  4074. : NewInfCopyZeroLength;
  4075. Problem = SetupapiVerifyNoProblem;
  4076. } else {
  4077. //
  4078. // If we failed because of SetupapiVerifyCatalogProblem,
  4079. // then our supplied catalog image must've matched up with
  4080. // an installed catalog (albeit, a bogus one), and PathBuffer
  4081. // will tell us that catalog's name.
  4082. //
  4083. // If we failed because of SetupapiVerifyFileProblem, then
  4084. // there are two possibilities:
  4085. // 1. Our catalog was fine (it's just the INF that's messed
  4086. // up), and CatalogFilenameOnSystem will be filled in
  4087. // with the name of the installed catalog that matches
  4088. // ours.
  4089. // 2. We didn't find our catalog among the ones
  4090. // enumerated based on the OEM INF's hash. In that
  4091. // case, CatalogFilenameOnSystem will be an empty
  4092. // string.
  4093. //
  4094. if((Problem == SetupapiVerifyFileProblem) &&
  4095. !(*CatalogFilenameOnSystem)) {
  4096. //
  4097. // We didn't find a catalog match--move on to the next
  4098. // INF (note: there still might be a match later on,
  4099. // because if the INF specified a CatalogFile= entry, we
  4100. // must match on _both_ the catalog filename _and_ the
  4101. // catalog's image.
  4102. //
  4103. // However, if the number of catalogs we considered when
  4104. // examining this INF/CAT combination was zero, that
  4105. // means that there is no installed catalog for this
  4106. // INF, thus we can use it if we don't find anything
  4107. // better. The reason why we'd rather not use this INF
  4108. // is that it obviously wasn't properly installed, hence
  4109. // the original source name and location info is almost
  4110. // certainly bogus. (One more thing--make sure the
  4111. // catalog isn't zero length. If it is, then that
  4112. // definitely implies that this was being used as a
  4113. // placeholder by setupapi, and we don't want to touch
  4114. // it!)
  4115. //
  4116. if(!NumCatalogsConsidered &&
  4117. !LastResortInf &&
  4118. CurInfFileSize)
  4119. {
  4120. LastResortInf = DuplicateString(lpszNewName);
  4121. SavedErr = Err;
  4122. }
  4123. goto CheckNextOemInf;
  4124. }
  4125. //
  4126. // At this point, we know that the INF and CAT are installed
  4127. // on the user's system, but that one of them has a problem
  4128. // (indicated by our Problem value).
  4129. // Drop out of the search here, and then handle any warnings
  4130. // that need to go to the user.
  4131. //
  4132. ProblemFile = PathBuffer;
  4133. *CopyNeeded = CurInfFileSize ? NewInfCopyNo
  4134. : NewInfCopyZeroLength;
  4135. }
  4136. CheckNextOemInf:
  4137. if(FileOfSameNameExists) {
  4138. FileOfSameNameExists = FALSE;
  4139. MoreInfsToCheck = (FindHandle != INVALID_HANDLE_VALUE);
  4140. } else {
  4141. MoreInfsToCheck = FindNextFile(FindHandle, &FindData);
  4142. }
  4143. } while((*CopyNeeded == NewInfCopyYes) && MoreInfsToCheck);
  4144. if(LastResortInf) {
  4145. if(*CopyNeeded == NewInfCopyYes) {
  4146. //
  4147. // We didn't find any better INF, so we'll try to use the
  4148. // incorrectly-installed INF.
  4149. //
  4150. // If this INF doesn't specify a CatalogFile= entry, then
  4151. // we'll just automatically set up the digital signature
  4152. // verification failure parameters, because that's the state
  4153. // we're in.
  4154. //
  4155. if(!OemInfCatName) {
  4156. Err = SavedErr;
  4157. Problem = SetupapiVerifyInfProblem;
  4158. lstrcpy(PathBuffer, OemInfName);
  4159. ProblemFile = PathBuffer;
  4160. } else {
  4161. //
  4162. // Attempt to verify our OEM INF's catalog, and if
  4163. // it verifies, then install it. We clear the
  4164. // problem set earlier, since we really don't have
  4165. // a problem (yet). If we do encounter a failure
  4166. // below, we'll set the failure as appropriate.
  4167. //
  4168. Problem = SetupapiVerifyNoProblem;
  4169. lstrcpy(CatalogName, OemInfName);
  4170. *((PTSTR)pSetupGetFileTitle(CatalogName)) = TEXT('\0');
  4171. pSetupConcatenatePaths(CatalogName,
  4172. OemInfCatName,
  4173. SIZECHARS(CatalogName),
  4174. NULL
  4175. );
  4176. Err = _VerifyFile(LogContext,
  4177. hCatAdmin,
  4178. NULL,
  4179. CatalogName,
  4180. NULL,
  4181. 0,
  4182. OemInfOriginalName,
  4183. OemInfName,
  4184. &Problem,
  4185. PathBuffer,
  4186. FALSE,
  4187. AltPlatformInfo,
  4188. (VERIFY_FILE_IGNORE_SELFSIGNED
  4189. | VERIFY_FILE_USE_OEM_CATALOGS
  4190. | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  4191. NULL,
  4192. NULL,
  4193. NULL,
  4194. NULL
  4195. );
  4196. if(Err != NO_ERROR) {
  4197. if(Problem != SetupapiVerifyCatalogProblem) {
  4198. MYASSERT(Problem != SetupapiVerifyNoProblem);
  4199. //
  4200. // If the problem was not a catalog problem,
  4201. // then it's an INF problem (the _VerifyFile
  4202. // routine doesn't know the file we passed
  4203. // it is an INF).
  4204. //
  4205. Problem = SetupapiVerifyInfProblem;
  4206. }
  4207. ProblemFile = PathBuffer;
  4208. } else {
  4209. //
  4210. // Only attempt to install a catalog if we're
  4211. // not running in "minimal embedded" mode...
  4212. //
  4213. if(!(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED)) {
  4214. //
  4215. // Take the INF's new, unique name and
  4216. // generate a unique catalog filename under
  4217. // setupapi's namespace by simply replacing
  4218. // ".INF" with ".CAT".
  4219. //
  4220. lstrcpy(PathBuffer, pSetupGetFileTitle(LastResortInf));
  4221. lstrcpy(_tcsrchr(PathBuffer, TEXT('.')),
  4222. pszCatSuffix
  4223. );
  4224. //
  4225. // At this point, PathBuffer contains the
  4226. // basename to be used for the catalog on
  4227. // the system, and CatalogName is the fully-
  4228. // qualified path of the catalog file in
  4229. // the oem location.
  4230. //
  4231. Err = pSetupInstallCatalog(
  4232. CatalogName,
  4233. PathBuffer,
  4234. CatalogFilenameOnSystem
  4235. );
  4236. if(Err != NO_ERROR) {
  4237. Problem = SetupapiVerifyCatalogProblem;
  4238. ProblemFile = CatalogName;
  4239. }
  4240. }
  4241. }
  4242. }
  4243. lstrcpy(lpszNewName, LastResortInf);
  4244. //
  4245. // We will never consider a zero-length INF as a last-resort
  4246. // candidate, thus if we get here we know the previously-
  4247. // existing INF wasn't zero-length.
  4248. //
  4249. *CopyNeeded = NewInfCopyNo;
  4250. }
  4251. MyFree(LastResortInf);
  4252. }
  4253. FinishedCheckingOemInfs:
  4254. if(CatalogBaseAddress) {
  4255. pSetupUnmapAndCloseFile(CatalogFileHandle, CatalogMappingHandle, CatalogBaseAddress);
  4256. }
  4257. pSetupUnmapAndCloseFile(OemInfFileHandle, OemInfMappingHandle, OemInfBaseAddress);
  4258. }
  4259. if(FindHandle != INVALID_HANDLE_VALUE) {
  4260. FindClose(FindHandle);
  4261. }
  4262. }
  4263. } else {
  4264. //
  4265. // The INF has no CatalogFile= entry, and we have an alternate catalog
  4266. // to use. Validate our INF using the specified alternate catalog.
  4267. //
  4268. Err = _VerifyFile(LogContext,
  4269. hCatAdmin,
  4270. NULL,
  4271. AltCatalogFile,
  4272. NULL,
  4273. 0,
  4274. OemInfOriginalName,
  4275. OemInfName,
  4276. &Problem,
  4277. PathBuffer,
  4278. FALSE,
  4279. AltPlatformInfo,
  4280. (VERIFY_FILE_IGNORE_SELFSIGNED
  4281. | VERIFY_FILE_USE_OEM_CATALOGS
  4282. | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  4283. NULL,
  4284. NULL,
  4285. NULL,
  4286. NULL
  4287. );
  4288. if(Err != NO_ERROR) {
  4289. if(Problem != SetupapiVerifyCatalogProblem) {
  4290. MYASSERT(Problem != SetupapiVerifyNoProblem);
  4291. //
  4292. // If the problem was not a catalog problem,
  4293. // then it's an INF problem (the _VerifyFile
  4294. // routine doesn't know the file we passed
  4295. // it is an INF).
  4296. //
  4297. Problem = SetupapiVerifyInfProblem;
  4298. }
  4299. ProblemFile = PathBuffer;
  4300. } else {
  4301. //
  4302. // Only attempt to install a catalog if we're not running in
  4303. // "minimal embedded" mode...
  4304. //
  4305. if(!(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED)) {
  4306. Err = pSetupInstallCatalog(
  4307. AltCatalogFile,
  4308. pSetupGetFileTitle(AltCatalogFile),
  4309. CatalogFilenameOnSystem
  4310. );
  4311. if(Err != NO_ERROR) {
  4312. Problem = SetupapiVerifyCatalogProblem;
  4313. ProblemFile = AltCatalogFile;
  4314. }
  4315. }
  4316. }
  4317. //
  4318. // An INF copy is never needed when we're using an alternate catalog.
  4319. //
  4320. *CopyNeeded = NewInfCopyNo;
  4321. //
  4322. // Setup lpszNewName to be the same as the INF's present full pathname.
  4323. // Since we didn't copy this into the INF directory (or even create a
  4324. // zero-length placeholder), the only reasonable path to return is the
  4325. // INF's current full pathname.
  4326. //
  4327. lstrcpy(lpszNewName, OemInfName);
  4328. }
  4329. if(*CopyNeeded != NewInfCopyYes) {
  4330. //
  4331. // Then this INF already exists in the Inf directory (or at least its
  4332. // zero-length placeholder does), and its associated catalog (if it has
  4333. // one) is already installed, too. If either of these files had a
  4334. // signature verification problem, then inform the user now (based on
  4335. // policy).
  4336. //
  4337. if(Problem != SetupapiVerifyNoProblem) {
  4338. BOOL result;
  4339. MYASSERT(Err != NO_ERROR);
  4340. if(DriverSigningError) {
  4341. *DriverSigningError = Err;
  4342. }
  4343. if(((Err == ERROR_NO_CATALOG_FOR_OEM_INF) && (Flags & SCOI_NO_ERRLOG_ON_MISSING_CATALOG)) ||
  4344. (Flags & SCOI_NO_ERRLOG_IF_INF_ALREADY_PRESENT)) {
  4345. //
  4346. // We shouldn't do any UI/logging because of one of the two
  4347. // following reasons:
  4348. //
  4349. // 1. This may be a valid INF after all (i.e., if it uses
  4350. // layout.inf for source media info, or doesn't copy any
  4351. // files at all).
  4352. //
  4353. // 2. We were asked not to. The public API, SetupCopyOEMInf
  4354. // doesn't want/need anything to happen here, because the
  4355. // INF is already present, and we haven't really done
  4356. // anything (except potentially update the source path
  4357. // information contained in the PNF), thus there's no
  4358. // reason to make noise about this.
  4359. //
  4360. result = TRUE;
  4361. } else {
  4362. result = pSetupHandleFailedVerification(
  4363. Owner,
  4364. Problem,
  4365. ProblemFile,
  4366. DeviceDesc,
  4367. DriverSigningPolicy,
  4368. (Flags & SCOI_NO_UI_ON_SIGFAIL),
  4369. Err,
  4370. LogContext,
  4371. NULL,
  4372. NULL
  4373. );
  4374. if(result) {
  4375. //
  4376. // The user wants to proceed with the unsigned installation
  4377. // (or policy is Ignore, so they weren't even informed).
  4378. // If the caller wants a chance to set a system restore
  4379. // point prior to doing any unsigned installations, then we
  4380. // abort now with a "special" error code that tells them
  4381. // what to do...
  4382. //
  4383. if(Flags & SCOI_ABORT_IF_UNSIGNED) {
  4384. return ERROR_SET_SYSTEM_RESTORE_POINT;
  4385. }
  4386. }
  4387. }
  4388. if (!result) {
  4389. return Err;
  4390. }
  4391. }
  4392. //
  4393. // There was no problem, or the user elected to install in spite of a
  4394. // problem, so return the INF name we found.
  4395. //
  4396. *RequiredSize = lstrlen(lpszNewName) + 1;
  4397. if(*RequiredSize < NewInfNameSize) {
  4398. CopyMemory(NewInfName, lpszNewName, *RequiredSize * sizeof(TCHAR));
  4399. return NO_ERROR;
  4400. } else {
  4401. return ERROR_INSUFFICIENT_BUFFER;
  4402. }
  4403. }
  4404. //
  4405. // If we're in 'replace only' mode, then the fact that we didn't find the
  4406. // INF/CAT already installed above means we should fail with
  4407. // ERROR_FILE_NOT_FOUND.
  4408. //
  4409. if(ReplaceOnly) {
  4410. return ERROR_FILE_NOT_FOUND;
  4411. }
  4412. //
  4413. // OK, so the INF isn't presently in the Inf directory--find a unique name
  4414. // for it. (Note: We'll go into the loop below even if we're meant to be
  4415. // installing the INF and CAT under their original names. We'll just skip
  4416. // the auto-generation part, and then we'll break out of the loop once
  4417. // we've made the attempt at INF/CAT installation.)
  4418. //
  4419. for(i = 0; i < 100000; i++) {
  4420. if(Flags & SCOI_KEEP_INF_AND_CAT_ORIGINAL_NAMES) {
  4421. lstrcpyn(lpszNewName, InfDirectory, MAX_PATH);
  4422. pSetupConcatenatePaths(lpszNewName, OemInfOriginalName, SIZECHARS(lpszNewName), NULL);
  4423. } else {
  4424. wsprintf(lpszNewName, pszOemInfGenerate, InfDirectory, i);
  4425. }
  4426. if((h = CreateFile(lpszNewName,
  4427. GENERIC_READ | GENERIC_WRITE,
  4428. FILE_SHARE_READ,
  4429. NULL,
  4430. OPEN_ALWAYS,
  4431. FILE_ATTRIBUTE_NORMAL,
  4432. NULL)) != INVALID_HANDLE_VALUE) {
  4433. //
  4434. // Then we either opened an existing file (that we need to leave
  4435. // alone, unless we're replacing it with a new exception INF), or
  4436. // we created a new file (in which case, we've found our unique
  4437. // name). These two cases are identified by the value of
  4438. // GetLastError().
  4439. //
  4440. Err = GetLastError();
  4441. //
  4442. // Before we decide what to do, close the file handle.
  4443. //
  4444. CloseHandle(h);
  4445. FileNewlyCreated = (Err != ERROR_ALREADY_EXISTS);
  4446. if(FileNewlyCreated || (Flags & SCOI_KEEP_INF_AND_CAT_ORIGINAL_NAMES)) {
  4447. //
  4448. // We've either (a) created a new file, or (b) found that we
  4449. // can replace an existing exception INF. Determine whether
  4450. // the filename fits in the caller-supplied buffer.
  4451. //
  4452. *RequiredSize = lstrlen(lpszNewName) + 1;
  4453. if(*RequiredSize < NewInfNameSize) {
  4454. //
  4455. // OK, we have a unique filename, and the caller-
  4456. // supplied buffer is large enough to hold that name.
  4457. //
  4458. // get LastKnownGood in on the loop
  4459. // if this is a newly created file, it will get deleted on revert
  4460. //
  4461. pSetupDoLastKnownGoodBackup(NULL,
  4462. lpszNewName,
  4463. SP_LKG_FLAG_FORCECOPY|SP_LKG_FLAG_DELETEIFNEW|(FileNewlyCreated?SP_LKG_FLAG_DELETEEXISTING:0),
  4464. LogContext);
  4465. //
  4466. // Now we need to verify the INF and its associated
  4467. // CAT.
  4468. //
  4469. if(!OemInfCatName) {
  4470. //
  4471. // An OEM INF without a CatalogFile= entry is
  4472. // automatically a digital signature failure!
  4473. //
  4474. Err = ERROR_NO_CATALOG_FOR_OEM_INF;
  4475. Problem = SetupapiVerifyInfProblem;
  4476. ProblemFile = OemInfName;
  4477. } else {
  4478. //
  4479. // Now verify the catalog file and INF, which must
  4480. // both be in the same directory.
  4481. //
  4482. lstrcpy(CatalogName, OemInfName);
  4483. *((PTSTR)pSetupGetFileTitle(CatalogName)) = TEXT('\0');
  4484. pSetupConcatenatePaths(CatalogName, OemInfCatName, SIZECHARS(CatalogName), NULL);
  4485. Err = _VerifyFile(LogContext,
  4486. hCatAdmin,
  4487. NULL,
  4488. CatalogName,
  4489. NULL,
  4490. 0,
  4491. OemInfOriginalName,
  4492. OemInfName,
  4493. &Problem,
  4494. PathBuffer,
  4495. FALSE,
  4496. AltPlatformInfo,
  4497. (VERIFY_FILE_IGNORE_SELFSIGNED
  4498. | VERIFY_FILE_USE_OEM_CATALOGS
  4499. | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  4500. NULL,
  4501. NULL,
  4502. NULL,
  4503. NULL
  4504. );
  4505. if(Err != NO_ERROR) {
  4506. if(Problem != SetupapiVerifyCatalogProblem) {
  4507. MYASSERT(Problem != SetupapiVerifyNoProblem);
  4508. //
  4509. // If the problem was not a catalog problem,
  4510. // then it's an INF problem (the _VerifyFile
  4511. // routine doesn't know the file we passed
  4512. // it is an INF).
  4513. //
  4514. Problem = SetupapiVerifyInfProblem;
  4515. }
  4516. ProblemFile = PathBuffer;
  4517. } else {
  4518. //
  4519. // Only attempt to install a catalog if we're not
  4520. // running in "minimal embedded" mode...
  4521. //
  4522. if(!(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED)) {
  4523. //
  4524. // Take the INF's new, unique name and generate
  4525. // a unique catalog filename under setupapi's
  4526. // namespace by simply replacing ".INF" with
  4527. // ".CAT".
  4528. //
  4529. lstrcpy(PathBuffer, pSetupGetFileTitle(lpszNewName));
  4530. lstrcpy(_tcsrchr(PathBuffer, TEXT('.')),
  4531. pszCatSuffix
  4532. );
  4533. //
  4534. // At this point, PathBuffer contains the
  4535. // basename to be used for the catalog on the
  4536. // system, and CatalogName is the fully-
  4537. // qualified path of the catalog file in the oem
  4538. // location.
  4539. //
  4540. Err = pSetupInstallCatalog(
  4541. CatalogName,
  4542. PathBuffer,
  4543. CatalogFilenameOnSystem
  4544. );
  4545. if(Err != NO_ERROR) {
  4546. Problem = SetupapiVerifyCatalogProblem;
  4547. ProblemFile = CatalogName;
  4548. }
  4549. }
  4550. }
  4551. }
  4552. //
  4553. // At this point if Err isn't NO_ERROR, then we
  4554. // encountered some signature verification failure (or
  4555. // were unable to install the catalog). Prompt the
  4556. // user (based on policy) about what they want to do.
  4557. //
  4558. if(Err != NO_ERROR) {
  4559. if(DriverSigningError) {
  4560. *DriverSigningError = Err;
  4561. }
  4562. //
  4563. // Unless the error was due to missing CatalogFile=
  4564. // entry in the INF (and we were instructed to ignore
  4565. // such errors), then we need to handle the verification
  4566. // failure.
  4567. //
  4568. if((Err != ERROR_NO_CATALOG_FOR_OEM_INF) ||
  4569. !(Flags & SCOI_NO_ERRLOG_ON_MISSING_CATALOG)) {
  4570. if(!pSetupHandleFailedVerification(
  4571. Owner,
  4572. Problem,
  4573. ProblemFile,
  4574. DeviceDesc,
  4575. DriverSigningPolicy,
  4576. (Flags & SCOI_NO_UI_ON_SIGFAIL),
  4577. Err,
  4578. LogContext,
  4579. NULL,
  4580. NULL))
  4581. {
  4582. if(FileNewlyCreated) {
  4583. //
  4584. // Delete the INF (and PNF and CAT, if they
  4585. // exist).
  4586. //
  4587. pSetupUninstallOEMInf(lpszNewName,
  4588. LogContext,
  4589. SUOI_FORCEDELETE,
  4590. NULL
  4591. );
  4592. }
  4593. return Err;
  4594. }
  4595. //
  4596. // The user wants to proceed with the unsigned
  4597. // installation (or policy is Ignore, so they
  4598. // weren't even informed). If the caller wants a
  4599. // chance to set a system restore point prior to
  4600. // doing any unsigned installations, then we abort
  4601. // now with a "special" error code that tells them
  4602. // what to do...
  4603. //
  4604. if(Flags & SCOI_ABORT_IF_UNSIGNED) {
  4605. if(FileNewlyCreated) {
  4606. //
  4607. // Delete the INF (and PNF and CAT, if they
  4608. // exist)--we don't want these files to be
  4609. // present when the system restore point is
  4610. // created.
  4611. //
  4612. pSetupUninstallOEMInf(lpszNewName,
  4613. LogContext,
  4614. SUOI_FORCEDELETE,
  4615. NULL
  4616. );
  4617. }
  4618. return ERROR_SET_SYSTEM_RESTORE_POINT;
  4619. }
  4620. }
  4621. }
  4622. //
  4623. // Either there was no problem, or the user opted to
  4624. // ignore the problem (or was never told, in the case of
  4625. // the 'ignore' policy).
  4626. //
  4627. CopyMemory(NewInfName, lpszNewName, *RequiredSize * sizeof(TCHAR));
  4628. //
  4629. // If we're installing an unsigned INF, then clean out any
  4630. // existing CAT that might've previously been installed.
  4631. //
  4632. if(Err != NO_ERROR) {
  4633. lstrcpy(_tcsrchr(lpszNewName, TEXT('.')), pszCatSuffix);
  4634. pSetupUninstallCatalog(pSetupGetFileTitle(lpszNewName));
  4635. }
  4636. return NO_ERROR;
  4637. } else {
  4638. //
  4639. // The caller's buffer isn't large enough. We have to
  4640. // delete the file we created. We don't want to delete the
  4641. // file, however, if it already existed (i.e., for the
  4642. // exception INF case).
  4643. //
  4644. if(FileNewlyCreated) {
  4645. pSetupUninstallOEMInf(lpszNewName, LogContext, SUOI_FORCEDELETE, NULL);
  4646. }
  4647. return ERROR_INSUFFICIENT_BUFFER;
  4648. }
  4649. }
  4650. } else {
  4651. //
  4652. // We failed to open/create this oem inf. Check to see if the
  4653. // failure was access-denied. If so, then it's possible that the
  4654. // INF directory is ACL'ed such that we can't write to it. We want
  4655. // to bail in this case, otherwise we're going to spend a bunch of
  4656. // time trying all 100,000 oem<n>.inf filenames (with each one
  4657. // failing) before we give up.
  4658. //
  4659. // We check for this case by seeing if the file we were trying to
  4660. // create/open already exists. If so, then we want to keep going
  4661. // (e.g., maybe the individual file was ACL'ed, etc.). If, however,
  4662. // the file doesn't exist, then this indicates that we can't create
  4663. // files in the directory, and we should bail now.
  4664. //
  4665. Err = GetLastError();
  4666. if(Flags & SCOI_KEEP_INF_AND_CAT_ORIGINAL_NAMES) {
  4667. //
  4668. // If we're installing an exception INF, we don't care what the
  4669. // error is--we gotta bail.
  4670. //
  4671. return Err;
  4672. } else if((Err == ERROR_ACCESS_DENIED) && !FileExists(lpszNewName, NULL)) {
  4673. return ERROR_ACCESS_DENIED;
  4674. }
  4675. }
  4676. }
  4677. //
  4678. // We didn't find a unique OEM INF name to use!
  4679. //
  4680. return ERROR_FILE_NOT_FOUND;
  4681. }
  4682. DWORD
  4683. InstallHW(
  4684. IN HDEVINFO DeviceInfoSet,
  4685. IN PSP_DEVINFO_DATA DeviceInfoData,
  4686. IN HINF hDeviceInf,
  4687. IN PCTSTR szSectionName,
  4688. OUT PBOOL DeleteDevKey
  4689. )
  4690. /*++
  4691. Routine Description:
  4692. This routine appends a ".Hw" to the end of the install section name for the
  4693. specified device, and attempts to find that section name in the specified INF.
  4694. If found, it does a performs a registry installation against it.
  4695. Arguments:
  4696. DeviceInfoSet - Supplies a handle to the device information set to call
  4697. SetupInstallFromInfSection for.
  4698. DeviceInfoData - Supplies the address of a device information element structure
  4699. for which the installation action is to be performed.
  4700. hDeviceInf - Supplies a handle to the opened INF containing the device install
  4701. section.
  4702. szSectionName - Supplies the address of a string specifying the install section
  4703. name for this device. This string will be appended with ".Hw" to create
  4704. the corresponding hardware section name.
  4705. DeleteDevKey - Supplies the address of a variable that receives a boolean value
  4706. indicating whether or not a user-accessible device key was created as a
  4707. result of calling this routine. This output may be used to indicate whether
  4708. or not the key should be destroyed if the caller encounters some error later
  4709. on that requires clean-up.
  4710. Return Value:
  4711. If the function succeeds, the return value is NO_ERROR, otherwise it is an
  4712. ERROR_* code.
  4713. --*/
  4714. {
  4715. PDEVICE_INFO_SET pDeviceInfoSet;
  4716. PDEVINFO_ELEM DevInfoElem;
  4717. HKEY hKey;
  4718. DWORD Err;
  4719. TCHAR szHwSection[MAX_SECT_NAME_LEN];
  4720. INFCONTEXT InfContext;
  4721. PTSTR szInfFileName;
  4722. PTSTR NeedsSectionList, CurInstallSection;
  4723. BOOL b;
  4724. REGMOD_CONTEXT RegContext;
  4725. //
  4726. // Initially, assume the device key is already there, and therefore shouldn't be
  4727. // deleted during error clean-up.
  4728. //
  4729. *DeleteDevKey = FALSE;
  4730. //
  4731. // Form the hardware INF section name, and see if that section exists in the INF.
  4732. //
  4733. wsprintf(szHwSection, pszHwSectionFormat, szSectionName);
  4734. if(!SetupFindFirstLine(hDeviceInf, szHwSection, NULL, &InfContext)) {
  4735. return NO_ERROR;
  4736. }
  4737. if((hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
  4738. DeviceInfoData,
  4739. DICS_FLAG_GLOBAL,
  4740. 0,
  4741. DIREG_DEV,
  4742. KEY_ALL_ACCESS)) == INVALID_HANDLE_VALUE) {
  4743. //
  4744. // Open failed--try create.
  4745. //
  4746. if((hKey = SetupDiCreateDevRegKey(DeviceInfoSet,
  4747. DeviceInfoData,
  4748. DICS_FLAG_GLOBAL,
  4749. 0,
  4750. DIREG_DEV,
  4751. NULL,
  4752. NULL)) == INVALID_HANDLE_VALUE) {
  4753. return GetLastError();
  4754. } else {
  4755. *DeleteDevKey = TRUE;
  4756. }
  4757. }
  4758. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  4759. MYASSERT(pDeviceInfoSet);
  4760. RegCloseKey(hKey);
  4761. SetLastError(ERROR_INVALID_HANDLE);
  4762. return FALSE;
  4763. }
  4764. Err = NO_ERROR;
  4765. NeedsSectionList = NULL;
  4766. try {
  4767. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  4768. DeviceInfoData,
  4769. NULL))) {
  4770. Err = ERROR_INVALID_PARAMETER;
  4771. goto clean0;
  4772. }
  4773. szInfFileName = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  4774. DevInfoElem->SelectedDriver->InfFileName
  4775. );
  4776. //
  4777. // Append-load any included INFs specified in an "include=" line in our
  4778. // ".Hw" section.
  4779. //
  4780. AppendLoadIncludedInfs(hDeviceInf, szInfFileName, szHwSection, FALSE);
  4781. NeedsSectionList = GetMultiSzFromInf(hDeviceInf, szHwSection, TEXT("needs"), &b);
  4782. if(!NeedsSectionList && b) {
  4783. //
  4784. // Out of memory!
  4785. //
  4786. Err = ERROR_NOT_ENOUGH_MEMORY;
  4787. goto clean0;
  4788. }
  4789. ZeroMemory(&RegContext, sizeof(RegContext));
  4790. RegContext.Flags = INF_PFLAG_DEVPROP;
  4791. RegContext.UserRootKey = hKey;
  4792. RegContext.DevInst = DeviceInfoData->DevInst;
  4793. //
  4794. // Process the registry lines ("AddReg" and "DelReg") in this section, as well as
  4795. // those contained with any sections referenced in the "needs=" entry in this section.
  4796. //
  4797. for(CurInstallSection = szHwSection;
  4798. (CurInstallSection && *CurInstallSection);
  4799. CurInstallSection = (CurInstallSection == szHwSection)
  4800. ? NeedsSectionList
  4801. : (CurInstallSection + lstrlen(CurInstallSection) + 1))
  4802. {
  4803. if((Err = pSetupInstallRegistry(hDeviceInf, CurInstallSection, &RegContext)) != NO_ERROR) {
  4804. //
  4805. //Stop if we encounter an error while processing one of the section's registry entries
  4806. //
  4807. break;
  4808. }
  4809. }
  4810. clean0: ; // nothing to do.
  4811. } except(EXCEPTION_EXECUTE_HANDLER) {
  4812. //
  4813. // If our exception was an AV, then use Win32 invalid param error, otherwise, assume it was
  4814. // an inpage error dealing with a mapped-in file.
  4815. //
  4816. Err = (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? ERROR_INVALID_PARAMETER : ERROR_READ_FAULT;
  4817. }
  4818. UnlockDeviceInfoSet(pDeviceInfoSet);
  4819. RegCloseKey(hKey);
  4820. if(NeedsSectionList) {
  4821. MyFree(NeedsSectionList);
  4822. }
  4823. return Err;
  4824. }
  4825. BOOL
  4826. CheckIfDevStarted(
  4827. IN PDEVINFO_ELEM DevInfoElem,
  4828. IN PDEVICE_INFO_SET pDeviceInfoSet
  4829. )
  4830. /*++
  4831. Routine Description:
  4832. This routine calls CM_Get_DevInst_Status to see if the specified device
  4833. instance has been started. If the device hasn't been started, and it has
  4834. either the CM_PROB_NEED_RESTART or CM_PROB_NORMAL_CONFLICT problem codes,
  4835. the DI_NEEDREBOOT flag is set in the device information element. We also
  4836. set the CM_PROB_NEED_RESTART problem on the devnode.
  4837. Arguments:
  4838. DevInfoElem - Supplies the address of the device information element to
  4839. check.
  4840. pDeviceInfoSet - Supplies the address of the device info set
  4841. LogContext - Supplies a log context for logging the reason if a reboot is
  4842. needed.
  4843. Return Value:
  4844. None.
  4845. --*/
  4846. {
  4847. ULONG ulStatus, ulProblem;
  4848. BOOL restarted = FALSE;
  4849. if(CM_Get_DevInst_Status_Ex(&ulStatus, &ulProblem, DevInfoElem->DevInst, 0,pDeviceInfoSet->hMachine) == CR_SUCCESS) {
  4850. if(ulStatus & DN_STARTED) {
  4851. restarted = TRUE;
  4852. } else {
  4853. if (ulStatus & DN_HAS_PROBLEM) {
  4854. if((ulProblem == CM_PROB_NEED_RESTART) ||
  4855. (ulProblem == CM_PROB_NORMAL_CONFLICT) ||
  4856. (ulProblem == CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD) ||
  4857. (ulProblem == CM_PROB_HELD_FOR_EJECT)) {
  4858. //
  4859. // The device either has the problem CM_PROB_NEED_RESTART or
  4860. // CM_PROB_NORMAL_CONFLICT. - change into need reboot
  4861. // and log what problem code was
  4862. //
  4863. SetDevnodeNeedsRebootProblemWithArg2(DevInfoElem,
  4864. pDeviceInfoSet,
  4865. MSG_LOG_REBOOT_REASON_DEVHASPROBLEM,
  4866. (DWORD)ulProblem,
  4867. (ULONG_PTR)_MapCmProbToString((DWORD)ulProblem)
  4868. );
  4869. } else {
  4870. //
  4871. // The device has some other problem so we won't prompt for a reboot
  4872. // however these are interesting things to log
  4873. //
  4874. WriteLogEntry(
  4875. DevInfoElem->InstallParamBlock.LogContext,
  4876. DRIVER_LOG_INFO, // not worth a warning
  4877. MSG_LOG_NOTSTARTED_REASON_DEVHASPROBLEM,
  4878. NULL,
  4879. (DWORD)ulProblem,
  4880. _MapCmProbToString((DWORD)ulProblem)
  4881. );
  4882. }
  4883. } else if (ulStatus & DN_PRIVATE_PROBLEM) {
  4884. //
  4885. // some private problem, change into need reboot
  4886. // and log private problem
  4887. //
  4888. SetDevnodeNeedsRebootProblem(DevInfoElem, pDeviceInfoSet,
  4889. MSG_LOG_REBOOT_REASON_PRIVATEPROBLEM);
  4890. } else {
  4891. //
  4892. // not started for some other reason
  4893. // indicate reboot required and log this issue
  4894. //
  4895. SetDevnodeNeedsRebootProblem(DevInfoElem, pDeviceInfoSet,
  4896. MSG_LOG_REBOOT_REASON_NOTSTARTED);
  4897. }
  4898. }
  4899. }
  4900. return restarted;
  4901. }
  4902. DWORD
  4903. InstallNtService(
  4904. IN PDEVINFO_ELEM DevInfoElem, OPTIONAL
  4905. IN HINF hDeviceInf,
  4906. IN PCTSTR InfFileName, OPTIONAL
  4907. IN PCTSTR szSectionName, OPTIONAL
  4908. OUT PSVCNAME_NODE *ServicesToDelete, OPTIONAL
  4909. IN DWORD Flags,
  4910. OUT PBOOL NullDriverInstalled
  4911. )
  4912. /*++
  4913. Routine Description:
  4914. This routine looks for the specified INF section, and if found, it deletes
  4915. any services specified in "DelService" entries, then installs any services
  4916. specified in "AddService" entries. These entries have the following form:
  4917. AddService = [<ServiceName>], [<Flags>], <ServiceInstallSection>[, <EventLogInstallSection>[, [<EventLogType>] [, <EventName>]]]
  4918. DelService = <ServiceName>[, [<flags>] [, [<EventLogType>] [, <EventName>]]]
  4919. (<ServiceName> is only optional for an AddService entry if the
  4920. SPSVCINST_ASSOCSERVICE flag is set. This indicates that we're explicitly
  4921. installing a NULL driver for this device, even though the underlying bus
  4922. didn't report the device as being raw-capable. This is used for device such
  4923. as the BIOS-reported PIC, DMA controller, etc. devnodes that don't need a
  4924. driver (since the HAL runs them), yet need to have a NULL driver installed
  4925. so that they don't show up as yellow-banged in Device Manager.)
  4926. A linked list is built of newly-created services, and optionally returned to the
  4927. caller (in case a subsequent installation failure requires all modifications to
  4928. be undone).
  4929. After all service modifications are complete, this routine checks to see if we're
  4930. in the context of a device installation. If so, then it checks to see if the device
  4931. instance specifies a valid controlling service, and that the service is not disabled
  4932. (disabled services are assumed to be uninstalled). If the device's 'RawDeviceOK'
  4933. capability bit is set, then a device with no controlling service will be allowed.
  4934. Arguments:
  4935. DevInfoElem - Optionally, supplies the device information element for whom the
  4936. service installation is being performed. If this parameter is not specified,
  4937. then the service is not being installed in relation to a device instance.
  4938. hDeviceInf - Supplies a handle to the opened INF containing the service install
  4939. section.
  4940. InfFileName - Optionally, supplies the full path of the INF file containing the
  4941. service install section. If this parameter is NULL, the no Include= or Needs=
  4942. values will be processed in this section.
  4943. szSectionName - Optionally, supplies the name of the service install section in a
  4944. Win95-style device INF. If this parameter is NULL, then no AddService or
  4945. DelService lines will be processed.
  4946. ServicesToDelete - Optionally, supplies the address of a linked list head pointer,
  4947. that receives a list of services that were newly-created by this routine, and
  4948. as such, should be deleted if the installation fails later on. The caller must
  4949. free the memory allocated for the nodes in this list by calling MyFree() on each
  4950. one.
  4951. Flags - Supplies flags controlling how the services are to be installed. May be a
  4952. combination of the following values:
  4953. SPSVCINST_TAGTOFRONT - For every kernel or filesystem driver installed (that
  4954. has an associated LoadOrderGroup), always move this service's tag to the
  4955. front of the ordering list.
  4956. SPSVCINST_ASSOCSERVICE - This flag may only be specified if a device information
  4957. element is specified. If set, this flag specifies that the service being
  4958. installed is the owning service (i.e., function driver) for this device instance.
  4959. SPSVCINST_DELETEEVENTLOGENTRY - For every service specified in a DelService entry,
  4960. delete the associated event log entry (if there is one).
  4961. SPSVCINST_NOCLOBBER_DISPLAYNAME - If this flag is specified, then we will
  4962. not overwrite the service's display name, if it already exists.
  4963. SPSVCINST_NOCLOBBER_STARTTYPE - If this flag is specified, then we will
  4964. not overwrite the service's start type if the service already exists.
  4965. SPSVCINST_NOCLOBBER_ERRORCONTROL - If this flag is specified, then we
  4966. will not overwrite the service's error control value if the service
  4967. already exists.
  4968. SPSVCINST_NOCLOBBER_LOADORDERGROUP - If this flag is specified, then we
  4969. will not overwrite the service's load order group if it already
  4970. exists.
  4971. SPSVCINST_NOCLOBBER_DEPENDENCIES - If this flag is specified, then we
  4972. will not overwrite the service's dependencies list if it already
  4973. exists.
  4974. SPSVCINST_NO_DEVINST_CHECK - If this flag is specified, then we will not check
  4975. to ensure that a function driver is installed for the specified devinfo
  4976. element after running the service install section. This is a private flag
  4977. used only by SetupInstallServicesFromInfSection(Ex) and InstallHinfSection.
  4978. SPSVCINST_STOPSERVICE - If this flag is specified, then we will stop the service
  4979. before removing the service.
  4980. SPSVCINST_CLOBBER_SECURITY - If this flag is specified, security may be
  4981. overridden.
  4982. NullDriverInstalled - Supplies the address of a boolean variable that
  4983. indicates whether or not an explicit null driver installation was done
  4984. for this device.
  4985. Return Value:
  4986. If the function succeeds, the return value is NO_ERROR, otherwise it is an
  4987. ERROR_* code.
  4988. If NO_ERROR is returned, GetLastError may return ERROR_SUCCESS_REBOOT_REQUIRED
  4989. --*/
  4990. {
  4991. CONFIGRET cr;
  4992. TCHAR ServiceName[MAX_SERVICE_NAME_LEN];
  4993. ULONG ServiceNameSize;
  4994. DWORD Err = NO_ERROR, i;
  4995. SC_HANDLE SCMHandle, ServiceHandle, FilterServiceHandle;
  4996. LPQUERY_SERVICE_CONFIG ServiceConfig, FilterServiceConfig;
  4997. DWORD ServiceConfigSize;
  4998. PCTSTR Key;
  4999. INFCONTEXT LineContext;
  5000. PSVCNAME_NODE SvcListHead = NULL;
  5001. PSVCNAME_NODE TmpSvcNode;
  5002. SC_LOCK SCLock;
  5003. DWORD NewTag;
  5004. BOOL AssociatedService;
  5005. DWORD DevInstCapabilities;
  5006. ULONG DevInstCapabilitiesSize;
  5007. PTSTR FilterDrivers, CurFilterDriver;
  5008. BOOL FilterNeedsTag;
  5009. BOOL NullFunctionDriverAdded;
  5010. PTSTR NeedsSectionList, CurInstallSection;
  5011. BOOL b;
  5012. BOOL NeedsReboot;
  5013. DWORD slot_section = 0;
  5014. PSETUP_LOG_CONTEXT LogContext;
  5015. try {
  5016. LogContext = ((PLOADED_INF) hDeviceInf)->LogContext;
  5017. } except(EXCEPTION_EXECUTE_HANDLER) {
  5018. LogContext = NULL;
  5019. Err = (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? ERROR_INVALID_PARAMETER : ERROR_READ_FAULT;
  5020. goto FinalClean0;
  5021. }
  5022. //
  5023. // Initially, assume this is not a null driver install.
  5024. //
  5025. *NullDriverInstalled = FALSE;
  5026. NeedsReboot = FALSE;
  5027. if(szSectionName) {
  5028. //
  5029. // Surround the following in try/except, in case we get an inpage error.
  5030. //
  5031. try {
  5032. NeedsSectionList = NULL;
  5033. if (InfFileName) {
  5034. AppendLoadIncludedInfs(hDeviceInf, InfFileName, szSectionName, FALSE);
  5035. NeedsSectionList = GetMultiSzFromInf(hDeviceInf, szSectionName, TEXT("needs"), &b);
  5036. if(!NeedsSectionList && b) {
  5037. //
  5038. // Out of memory!
  5039. //
  5040. Err = ERROR_NOT_ENOUGH_MEMORY;
  5041. goto clean0;
  5042. }
  5043. }
  5044. if (slot_section == 0) {
  5045. slot_section = AllocLogInfoSlot(LogContext,FALSE);
  5046. }
  5047. //
  5048. // Make two passes through the section--once for deletions, and a
  5049. // second time for additions.
  5050. //
  5051. for(i = 0; i < 2; i++) {
  5052. //
  5053. // Find the relevent line (if there is one) in the given install section.
  5054. //
  5055. Key = (i) ? pszAddService : pszDelService;
  5056. //
  5057. // Process the service lines in this section, as well as
  5058. // those contained with any sections referenced in the "needs=" entry in this section.
  5059. //
  5060. for(CurInstallSection = (PTSTR)szSectionName;
  5061. (CurInstallSection && *CurInstallSection);
  5062. CurInstallSection = (CurInstallSection == szSectionName)
  5063. ? NeedsSectionList
  5064. : (CurInstallSection + lstrlen(CurInstallSection) + 1))
  5065. {
  5066. if(!SetupFindFirstLine(hDeviceInf, CurInstallSection, Key, &LineContext)) {
  5067. continue;
  5068. }
  5069. //
  5070. // Log which section we're installing if we log anything else
  5071. //
  5072. WriteLogEntry(
  5073. LogContext,
  5074. slot_section,
  5075. MSG_LOG_PROCESS_SERVICE_SECTION,
  5076. NULL,
  5077. CurInstallSection);
  5078. do {
  5079. //
  5080. // We have a line to act upon.
  5081. //
  5082. Err = (i) ? pSetupAddService(&LineContext,
  5083. &SvcListHead,
  5084. Flags,
  5085. (DevInfoElem ? DevInfoElem->DevInst : 0),
  5086. &NullFunctionDriverAdded,
  5087. LogContext)
  5088. : pSetupDeleteService(&LineContext,
  5089. Flags,
  5090. LogContext);
  5091. if(Err != NO_ERROR) {
  5092. //
  5093. // Log that an error occurred
  5094. //
  5095. WriteLogError(
  5096. LogContext,
  5097. // we don't know if it's a driver or not,
  5098. // so just allow both to work
  5099. SETUP_LOG_ERROR | DRIVER_LOG_ERROR,
  5100. Err);
  5101. goto clean0;
  5102. } else if(i) {
  5103. //
  5104. // We're processing AddService entries, so check to see
  5105. // if we just installed a null service (thus having no
  5106. // function driver on a non-raw-capable PDO should be
  5107. // allowed).
  5108. //
  5109. *NullDriverInstalled |= NullFunctionDriverAdded;
  5110. if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED) {
  5111. NeedsReboot |= TRUE;
  5112. }
  5113. }
  5114. } while(SetupFindNextMatchLine(&LineContext, Key, &LineContext));
  5115. }
  5116. }
  5117. clean0: ; // nothing to do
  5118. } except(EXCEPTION_EXECUTE_HANDLER) {
  5119. //
  5120. // If our exception was an AV, then use Win32 invalid param error, otherwise, assume it was
  5121. // an inpage error dealing with a mapped-in file.
  5122. //
  5123. Err = (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? ERROR_INVALID_PARAMETER : ERROR_READ_FAULT;
  5124. }
  5125. if (NeedsSectionList) {
  5126. MyFree(NeedsSectionList);
  5127. }
  5128. if((Err != NO_ERROR) || (Flags & SPSVCINST_NO_DEVINST_CHECK)) {
  5129. goto FinalClean0;
  5130. }
  5131. }
  5132. MYASSERT(DevInfoElem);
  5133. //
  5134. // Find out if the device instance already has an associated service.
  5135. //
  5136. ServiceNameSize = sizeof(ServiceName);
  5137. if(CR_SUCCESS == (cr = CM_Get_DevInst_Registry_Property(DevInfoElem->DevInst,
  5138. CM_DRP_SERVICE,
  5139. NULL,
  5140. ServiceName,
  5141. &ServiceNameSize,
  5142. 0)))
  5143. {
  5144. AssociatedService = TRUE;
  5145. //
  5146. // Make sure that the NullDriverInstalled output parameter is still FALSE.
  5147. // It typically would be, but might not be in the case where there are
  5148. // multiple AddService entries that specify SPSVCINST_ASSOCSERVICE (e.g.,
  5149. // when additional service install sections are pulled in via include=/needs=.
  5150. //
  5151. *NullDriverInstalled = FALSE;
  5152. } else {
  5153. //
  5154. // For the moment, there is no associated service.
  5155. //
  5156. AssociatedService = FALSE;
  5157. //
  5158. // Either the device instance has gone sour (in which case we return an error),
  5159. // or we couldn't retrieve an associated service name. In the latter case, we
  5160. // will make the association based on the default service for the class.
  5161. //
  5162. if(cr == CR_INVALID_DEVINST) {
  5163. Err = ERROR_NO_SUCH_DEVINST;
  5164. } else if(!*NullDriverInstalled) {
  5165. ServiceNameSize = sizeof(ServiceName);
  5166. AssociatedService = AssociateDevInstWithDefaultService(DevInfoElem,
  5167. ServiceName,
  5168. &ServiceNameSize
  5169. );
  5170. if(!AssociatedService) {
  5171. //
  5172. // If the device's capabilities report that it can be driven 'raw', then
  5173. // not having a function driver is OK. Otherwise, we have an error.
  5174. //
  5175. DevInstCapabilitiesSize = sizeof(DevInstCapabilities);
  5176. if(CR_SUCCESS != CM_Get_DevInst_Registry_Property(DevInfoElem->DevInst,
  5177. CM_DRP_CAPABILITIES,
  5178. NULL,
  5179. &DevInstCapabilities,
  5180. &DevInstCapabilitiesSize,
  5181. 0))
  5182. {
  5183. DevInstCapabilities = 0;
  5184. }
  5185. if(!(DevInstCapabilities & CM_DEVCAP_RAWDEVICEOK)) {
  5186. Err = ERROR_NO_ASSOCIATED_SERVICE;
  5187. }
  5188. }
  5189. }
  5190. if(!AssociatedService) {
  5191. //
  5192. // Either we hit an error, or the device can be driven 'raw'. In either case, we
  5193. // can skip the service controller checks that lie ahead.
  5194. //
  5195. goto FinalClean0;
  5196. }
  5197. }
  5198. //
  5199. // At this point, we have the name of the service with which the device instance is
  5200. // associated. Attempt to locate this service in the SCM database.
  5201. //
  5202. if(!(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  5203. Err = GetLastError();
  5204. WriteLogEntry(
  5205. LogContext,
  5206. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  5207. MSG_LOG_INSTSERVSCM_ERROR,
  5208. NULL);
  5209. WriteLogError(
  5210. LogContext,
  5211. DRIVER_LOG_ERROR,
  5212. Err);
  5213. goto FinalClean0;
  5214. }
  5215. if(!(ServiceHandle = OpenService(SCMHandle, ServiceName, SERVICE_ALL_ACCESS))) {
  5216. //
  5217. // We couldn't access the service--either because it doesn't exist, or because
  5218. // this is a detected device reported by a 'disembodied' driver object (e.g., the
  5219. // one the HAL creates for its driver object it got via IoCreateDriver).
  5220. //
  5221. // The former case is an error, the latter case is just fine.
  5222. //
  5223. Err = GetLastError();
  5224. if((lstrlen(ServiceName) > CSTRLEN(pszDriverObjectPathPrefix)) &&
  5225. CharUpper(ServiceName) &&
  5226. !memcmp(ServiceName, pszDriverObjectPathPrefix, CSTRLEN(pszDriverObjectPathPrefix)))
  5227. {
  5228. //
  5229. // The "service name" is actually a driver name (e.g., "\Driver\PCI_HAL"), so it's OK.
  5230. //
  5231. Err = NO_ERROR;
  5232. }
  5233. if(Err) {
  5234. WriteLogEntry(
  5235. LogContext,
  5236. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  5237. MSG_LOG_INSTSERVOPEN_ERROR,
  5238. NULL,
  5239. ServiceName
  5240. );
  5241. WriteLogError(
  5242. LogContext,
  5243. DRIVER_LOG_ERROR,
  5244. Err);
  5245. }
  5246. goto FinalClean1;
  5247. }
  5248. //
  5249. // The service exists. Make sure that it's not disabled.
  5250. //
  5251. if((Err = pSetupRetrieveServiceConfig(ServiceHandle, &ServiceConfig)) == NO_ERROR) {
  5252. if(ServiceConfig->dwStartType == SERVICE_DISABLED) {
  5253. WriteLogEntry(
  5254. LogContext,
  5255. DRIVER_LOG_ERROR,
  5256. MSG_LOG_INSTSERV_DISABLED,
  5257. NULL,
  5258. ServiceName
  5259. );
  5260. Err = ERROR_SERVICE_DISABLED;
  5261. } else {
  5262. //
  5263. // If this service has a load order group, and is a kernel or filesystem
  5264. // driver, then make sure that it has a tag.
  5265. //
  5266. // NOTE: We have to do this here, even though we ensure that all new services we install
  5267. // have their tags set up properly in pSetupAddService(). The reason is that the device may
  5268. // using an existing service that wasn't installed via a Win95-style INF.
  5269. //
  5270. if(ServiceConfig->lpLoadOrderGroup && *(ServiceConfig->lpLoadOrderGroup) &&
  5271. (ServiceConfig->dwServiceType & (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER))) {
  5272. //
  5273. // This service needs a tag--does it have one???
  5274. //
  5275. if(!(NewTag = ServiceConfig->dwTagId)) {
  5276. //
  5277. // Attempt to lock the service database before generating a tag. We'll go ahead
  5278. // and make the change, even if this fails.
  5279. //
  5280. pAcquireSCMLock(SCMHandle, &SCLock, LogContext);
  5281. if(!ChangeServiceConfig(ServiceHandle,
  5282. SERVICE_NO_CHANGE,
  5283. SERVICE_NO_CHANGE,
  5284. SERVICE_NO_CHANGE,
  5285. NULL,
  5286. ServiceConfig->lpLoadOrderGroup, // have to specify this to generate new tag.
  5287. &NewTag,
  5288. NULL,
  5289. NULL,
  5290. NULL,
  5291. NULL)) {
  5292. DWORD LastErr = GetLastError();
  5293. WriteLogEntry(
  5294. LogContext,
  5295. DRIVER_LOG_WARNING | SETUP_LOG_BUFFER,
  5296. MSG_LOG_INSTSERVTAG_WARN,
  5297. NULL,
  5298. ServiceName
  5299. );
  5300. WriteLogError(
  5301. LogContext,
  5302. DRIVER_LOG_WARNING,
  5303. LastErr);
  5304. NewTag = 0;
  5305. }
  5306. if(SCLock) {
  5307. UnlockServiceDatabase(SCLock);
  5308. }
  5309. }
  5310. //
  5311. // Make sure that the tag exists in the service's corresponding GroupOrderList entry.
  5312. //
  5313. if(NewTag) {
  5314. pSetupAddTagToGroupOrderListEntry(ServiceConfig->lpLoadOrderGroup,
  5315. NewTag,
  5316. Flags & SPSVCINST_TAGTOFRONT
  5317. );
  5318. }
  5319. }
  5320. //
  5321. // If the function driver is marked as boot-start, then make sure that all
  5322. // associated upper- and lower-filters (both class- and device-specific) are
  5323. // also boot-start drivers.
  5324. //
  5325. if((ServiceConfig->dwStartType == SERVICE_BOOT_START) &&
  5326. RetrieveAllDriversForDevice(DevInfoElem, &FilterDrivers,RADFD_FLAG_ALL_FILTERS,NULL)) {
  5327. //
  5328. // If FilterDrivers is NULL, then we hit an out-of-memory error.
  5329. //
  5330. if(!FilterDrivers) {
  5331. Err = ERROR_NOT_ENOUGH_MEMORY;
  5332. } else {
  5333. WriteLogEntry(
  5334. LogContext,
  5335. DRIVER_LOG_VERBOSE,
  5336. MSG_LOG_INSTSERV_BOOT,
  5337. NULL,
  5338. ServiceName
  5339. );
  5340. //
  5341. // Check each filter driver.
  5342. //
  5343. for(CurFilterDriver = FilterDrivers;
  5344. *CurFilterDriver;
  5345. CurFilterDriver += (lstrlen(CurFilterDriver) + 1)) {
  5346. if(!(FilterServiceHandle = OpenService(SCMHandle, CurFilterDriver, SERVICE_ALL_ACCESS))) {
  5347. //
  5348. // We couldn't access the service--probably because it doesn't exist.
  5349. // Bail now.
  5350. //
  5351. Err = GetLastError();
  5352. WriteLogEntry(
  5353. LogContext,
  5354. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  5355. MSG_LOG_BOOTFILTSERVOPEN_ERROR,
  5356. NULL,
  5357. CurFilterDriver);
  5358. WriteLogError(
  5359. LogContext,
  5360. DRIVER_LOG_ERROR,
  5361. Err);
  5362. break;
  5363. }
  5364. //
  5365. // The service exists. Make sure that it's not disabled.
  5366. //
  5367. Err = pSetupRetrieveServiceConfig(FilterServiceHandle, &FilterServiceConfig);
  5368. if(Err != NO_ERROR) {
  5369. WriteLogEntry(
  5370. LogContext,
  5371. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  5372. MSG_LOG_BOOTFILTSERVCONFIG_ERROR,
  5373. NULL,
  5374. CurFilterDriver);
  5375. WriteLogError(
  5376. LogContext,
  5377. DRIVER_LOG_ERROR,
  5378. Err);
  5379. goto CloseFilterSvcAndContinue;
  5380. }
  5381. if(FilterServiceConfig->dwStartType == SERVICE_DISABLED) {
  5382. WriteLogEntry(
  5383. LogContext,
  5384. DRIVER_LOG_ERROR,
  5385. MSG_LOG_BOOTFILTSERV_DISABLED,
  5386. NULL,
  5387. CurFilterDriver);
  5388. Err = ERROR_SERVICE_DISABLED;
  5389. } else {
  5390. //
  5391. // Ensure that this service is a boot-start kernel driver, and that it has
  5392. // a tag if necessary.
  5393. //
  5394. if(FilterServiceConfig->dwServiceType & SERVICE_KERNEL_DRIVER) {
  5395. if(FilterServiceConfig->lpLoadOrderGroup &&
  5396. *(FilterServiceConfig->lpLoadOrderGroup)) {
  5397. FilterNeedsTag = TRUE;
  5398. NewTag = FilterServiceConfig->dwTagId;
  5399. }
  5400. if((FilterNeedsTag && !NewTag) ||
  5401. (FilterServiceConfig->dwStartType != SERVICE_BOOT_START)) {
  5402. //
  5403. // Lock the service database before modifying this service.
  5404. //
  5405. Err = pAcquireSCMLock(SCMHandle, &SCLock, LogContext);
  5406. if(Err == NO_ERROR) {
  5407. //
  5408. // Make the modifications to the service (NOTE: Because the
  5409. // service controller is really bad when it comes to driver paths,
  5410. // we must explicitly pass the lpBinaryPathName in, even though we
  5411. // aren't changing it. Otherwise, the service controller will complain
  5412. // because it thinks all paths have to begin with \SystemRoot\.)
  5413. //
  5414. if(!ChangeServiceConfig(FilterServiceHandle,
  5415. SERVICE_NO_CHANGE,
  5416. (FilterServiceConfig->dwStartType != SERVICE_BOOT_START)
  5417. ? SERVICE_BOOT_START
  5418. : SERVICE_NO_CHANGE,
  5419. SERVICE_NO_CHANGE,
  5420. (FilterServiceConfig->dwStartType != SERVICE_BOOT_START)
  5421. ? FilterServiceConfig->lpBinaryPathName
  5422. : NULL,
  5423. (FilterNeedsTag && !NewTag)
  5424. ? FilterServiceConfig->lpLoadOrderGroup
  5425. : NULL,
  5426. (FilterNeedsTag && !NewTag)
  5427. ? &NewTag
  5428. : NULL,
  5429. NULL,
  5430. NULL,
  5431. NULL,
  5432. NULL)) {
  5433. Err = GetLastError();
  5434. WriteLogEntry(
  5435. LogContext,
  5436. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  5437. MSG_LOG_BOOTFILTSERVCHANGE_ERROR,
  5438. NULL,
  5439. CurFilterDriver);
  5440. WriteLogError(
  5441. LogContext,
  5442. DRIVER_LOG_ERROR,
  5443. Err);
  5444. } else {
  5445. WriteLogEntry(
  5446. LogContext,
  5447. DRIVER_LOG_VERBOSE,
  5448. MSG_LOG_BOOTFILTSERVCHANGE_OK,
  5449. NULL,
  5450. CurFilterDriver);
  5451. }
  5452. UnlockServiceDatabase(SCLock);
  5453. } else {
  5454. WriteLogEntry(
  5455. LogContext,
  5456. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  5457. MSG_LOG_BOOTFILTSERVSCM_ERROR,
  5458. NULL,
  5459. CurFilterDriver);
  5460. WriteLogError(
  5461. LogContext,
  5462. DRIVER_LOG_ERROR,
  5463. Err);
  5464. }
  5465. if((Err == NO_ERROR) && FilterNeedsTag) {
  5466. //
  5467. // Make sure that the tag exists in the service's corresponding GroupOrderList entry.
  5468. //
  5469. MYASSERT(NewTag);
  5470. pSetupAddTagToGroupOrderListEntry(FilterServiceConfig->lpLoadOrderGroup,
  5471. NewTag,
  5472. FALSE
  5473. );
  5474. }
  5475. }
  5476. } else {
  5477. //
  5478. // This is not a kernel driver. This is an error.
  5479. //
  5480. WriteLogEntry(
  5481. LogContext,
  5482. DRIVER_LOG_ERROR,
  5483. MSG_LOG_BOOTFILTSERV_KERN,
  5484. NULL,
  5485. CurFilterDriver);
  5486. Err = ERROR_INVALID_FILTER_DRIVER;
  5487. }
  5488. }
  5489. MyFree(FilterServiceConfig);
  5490. CloseFilterSvcAndContinue:
  5491. CloseServiceHandle(FilterServiceHandle);
  5492. if(Err) {
  5493. break;
  5494. }
  5495. }
  5496. MyFree(FilterDrivers);
  5497. }
  5498. }
  5499. }
  5500. MyFree(ServiceConfig);
  5501. } else {
  5502. WriteLogEntry(
  5503. LogContext,
  5504. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  5505. MSG_LOG_INSTSERVCONFIG_ERROR,
  5506. NULL,
  5507. ServiceName
  5508. );
  5509. WriteLogError(
  5510. LogContext,
  5511. DRIVER_LOG_ERROR,
  5512. Err);
  5513. }
  5514. CloseServiceHandle(ServiceHandle);
  5515. FinalClean1:
  5516. CloseServiceHandle(SCMHandle);
  5517. FinalClean0:
  5518. if(Err == NO_ERROR) {
  5519. //
  5520. // If requested, store the linked-list of newly-created service nodes in the output
  5521. // parameter, otherwise, delete the list.
  5522. //
  5523. if(ServicesToDelete) {
  5524. *ServicesToDelete = SvcListHead;
  5525. } else {
  5526. for(TmpSvcNode = SvcListHead; TmpSvcNode; TmpSvcNode = SvcListHead) {
  5527. SvcListHead = SvcListHead->Next;
  5528. MyFree(TmpSvcNode);
  5529. }
  5530. }
  5531. if (NeedsReboot) {
  5532. //
  5533. // this is intentional - return NO_ERROR but GetLastError = ERROR_SUCCESS_REBOOT_REQUIRED
  5534. //
  5535. SetLastError(ERROR_SUCCESS_REBOOT_REQUIRED);
  5536. }
  5537. } else {
  5538. //
  5539. // Something failed along the way, so we need to clean up any newly-created
  5540. // services.
  5541. //
  5542. if(Err && LogContext) {
  5543. WriteLogEntry(
  5544. LogContext,
  5545. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  5546. MSG_LOG_INSTSERV_ERROR,
  5547. NULL
  5548. );
  5549. WriteLogError(
  5550. LogContext,
  5551. DRIVER_LOG_ERROR,
  5552. Err);
  5553. }
  5554. if(SvcListHead) {
  5555. DeleteServicesInList(SvcListHead,LogContext);
  5556. for(TmpSvcNode = SvcListHead; TmpSvcNode; TmpSvcNode = SvcListHead) {
  5557. SvcListHead = SvcListHead->Next;
  5558. MyFree(TmpSvcNode);
  5559. }
  5560. }
  5561. }
  5562. if (slot_section != 0) {
  5563. ReleaseLogInfoSlot(LogContext,slot_section);
  5564. }
  5565. return Err;
  5566. }
  5567. BOOL
  5568. AssociateDevInstWithDefaultService(
  5569. IN PDEVINFO_ELEM DevInfoElem,
  5570. OUT PTSTR ServiceName,
  5571. IN OUT PDWORD ServiceNameSize
  5572. )
  5573. /*++
  5574. Routine Description:
  5575. This routine attempts to find out the default service with which to associate
  5576. the specified device. The default service (if there is one) is associated with
  5577. the device's class. If a default is found, the device instance is associated
  5578. with that service.
  5579. Arguments:
  5580. DeviceInfoData - Specifies the device information element to create a default
  5581. service association for.
  5582. ServiceName - Supplies the address of a character buffer that receives the name
  5583. of the service with which the device instance was associated (if this routine
  5584. is successful).
  5585. ServiceNameSize - Supplies the address of a variable containing the size, in bytes,
  5586. of the ServiceName buffer. On output, this variable receives the number of
  5587. bytes actually stored in ServiceName.
  5588. Return Value:
  5589. If the function succeeds, the return value is TRUE, otherwise it is FALSE.
  5590. --*/
  5591. {
  5592. HKEY hClassKey;
  5593. DWORD RegDataType;
  5594. BOOL Success;
  5595. //
  5596. // Open up the class key for this device's class.
  5597. //
  5598. if((hClassKey = SetupDiOpenClassRegKey(&(DevInfoElem->ClassGuid),
  5599. KEY_READ)) == INVALID_HANDLE_VALUE) {
  5600. return FALSE;
  5601. }
  5602. Success = FALSE; // assume failure
  5603. try {
  5604. //
  5605. // Retrieve the "Default Service" value from the class key. If present, this value entry
  5606. // indicates what service to associate the device with, when one isn't specified during
  5607. // installation.
  5608. //
  5609. if(RegQueryValueEx(hClassKey,
  5610. pszDefaultService,
  5611. NULL,
  5612. &RegDataType,
  5613. (PBYTE)ServiceName,
  5614. ServiceNameSize) != ERROR_SUCCESS) {
  5615. goto clean0;
  5616. }
  5617. if((RegDataType != REG_SZ) || (*ServiceNameSize < sizeof(TCHAR)) || !(*ServiceName)) {
  5618. goto clean0;
  5619. }
  5620. //
  5621. // We have successfully retrieved the default service name to be associated with this
  5622. // device instance. Perform the association now by setting the Service device registry
  5623. // property.
  5624. //
  5625. if(CM_Set_DevInst_Registry_Property(DevInfoElem->DevInst,
  5626. CM_DRP_SERVICE,
  5627. ServiceName,
  5628. *ServiceNameSize,
  5629. 0) == CR_SUCCESS) {
  5630. Success = TRUE;
  5631. }
  5632. clean0: ; // nothing to do
  5633. } except(EXCEPTION_EXECUTE_HANDLER) {
  5634. Success = FALSE;
  5635. }
  5636. RegCloseKey(hClassKey);
  5637. return Success;
  5638. }
  5639. DWORD
  5640. DeleteServicesInList(
  5641. IN PSVCNAME_NODE ServicesToDelete,
  5642. IN PSETUP_LOG_CONTEXT LogContext
  5643. )
  5644. /*++
  5645. Routine Description:
  5646. This routine deletes each service entry in the supplied linked list. This is
  5647. typically called to clean up if something goes wrong during a device's installation.
  5648. If the 'DeleteEventLog' flag for a particular node is TRUE, then the corresponding
  5649. event log entry under HKLM\System\CurrentControlSet\Services\EventLog\<EventLogType> is
  5650. also deleted.
  5651. Arguments:
  5652. ServicesToDelete - supplies a pointer to the head of a linked list of service names
  5653. to be deleted.
  5654. LogContext - context for logging failures
  5655. Return Value:
  5656. Error if we could not open service manager or acquire lock.
  5657. Note that we do not return error for individual services.
  5658. --*/
  5659. {
  5660. SC_HANDLE SCMHandle, ServiceHandle;
  5661. SC_LOCK SCLock;
  5662. HKEY hKeyEventLog = NULL, hKeyEventLogType;
  5663. TCHAR RegistryPath[SIZECHARS(REGSTR_PATH_SERVICES) + SIZECHARS(DISTR_EVENTLOG) + (2 * 256)];
  5664. DWORD Result = NO_ERROR;
  5665. DWORD LastErr;
  5666. if(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) {
  5667. Result = pAcquireSCMLock(SCMHandle, &SCLock, LogContext);
  5668. if(Result == NO_ERROR) {
  5669. for(; ServicesToDelete; ServicesToDelete = ServicesToDelete->Next) {
  5670. LastErr = NO_ERROR;
  5671. if(ServiceHandle = OpenService(SCMHandle,
  5672. ServicesToDelete->Name,
  5673. SERVICE_ALL_ACCESS)) {
  5674. //
  5675. // stop the service first if we're supposed to
  5676. // wait awhile for the service to stop before deleting the
  5677. // service, since we don't want the service to be in use when
  5678. // delete the service or the service binaries
  5679. if (ServicesToDelete->Flags & SPSVCINST_STOPSERVICE) {
  5680. SERVICE_STATUS ssStatus;
  5681. if (ControlService( ServiceHandle,
  5682. SERVICE_CONTROL_STOP ,
  5683. &ssStatus)
  5684. || (LastErr = GetLastError()) == ERROR_SERVICE_NOT_ACTIVE) {
  5685. #define SLEEP_TIME 4000
  5686. #define LOOP_COUNT 30
  5687. DWORD loopCount = 0;
  5688. do {
  5689. BOOL b;
  5690. b = QueryServiceStatus( ServiceHandle, &ssStatus);
  5691. if ( !b ) {
  5692. LastErr = GetLastError();
  5693. //
  5694. // query failed for some reason, but let's
  5695. // just delete the service anyway
  5696. //
  5697. WriteLogEntry(
  5698. LogContext,
  5699. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  5700. MSG_LOG_DELSERVSTAT_ERROR,
  5701. NULL,
  5702. ServicesToDelete->Name
  5703. );
  5704. WriteLogError(
  5705. LogContext,
  5706. DRIVER_LOG_ERROR,
  5707. LastErr);
  5708. break;
  5709. }
  5710. if (ssStatus.dwCurrentState == SERVICE_STOP_PENDING) {
  5711. if ( loopCount++ == LOOP_COUNT ) {
  5712. // still pending after LOOP_COUNT iterations...
  5713. // just delete the service anyway
  5714. //
  5715. WriteLogEntry(
  5716. LogContext,
  5717. DRIVER_LOG_ERROR,
  5718. MSG_LOG_DELSERVPEND_ERROR,
  5719. NULL,
  5720. ServicesToDelete->Name
  5721. );
  5722. break;
  5723. }
  5724. Sleep( SLEEP_TIME );
  5725. } else {
  5726. loopCount++;
  5727. }
  5728. } while ( ssStatus.dwCurrentState != SERVICE_STOPPED
  5729. && loopCount < LOOP_COUNT );
  5730. } else {
  5731. // control service failed for some reason...
  5732. // let's just continue on and try to delete the
  5733. // service anyway
  5734. //
  5735. WriteLogEntry(
  5736. LogContext,
  5737. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  5738. MSG_LOG_DELSERVCTRL_ERROR,
  5739. NULL,
  5740. ServicesToDelete->Name
  5741. );
  5742. WriteLogError(
  5743. LogContext,
  5744. DRIVER_LOG_ERROR,
  5745. LastErr);
  5746. }
  5747. }
  5748. if(DeleteService(ServiceHandle) ||
  5749. ((LastErr = GetLastError()) == ERROR_SERVICE_MARKED_FOR_DELETE)) {
  5750. //
  5751. // Delete succeeded, or we don't care
  5752. //
  5753. WriteLogEntry(
  5754. LogContext,
  5755. DRIVER_LOG_VERBOSE,
  5756. MSG_LOG_DELSERV_OK,
  5757. NULL,
  5758. ServicesToDelete->Name
  5759. );
  5760. } else {
  5761. // delete service failed for some reason...
  5762. //
  5763. WriteLogEntry(
  5764. LogContext,
  5765. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  5766. MSG_LOG_DELSERV_ERROR,
  5767. NULL,
  5768. ServicesToDelete->Name
  5769. );
  5770. WriteLogError(
  5771. LogContext,
  5772. DRIVER_LOG_ERROR,
  5773. LastErr);
  5774. }
  5775. CloseServiceHandle(ServiceHandle);
  5776. } else {
  5777. LastErr = GetLastError();
  5778. if(LastErr == ERROR_SERVICE_DOES_NOT_EXIST) {
  5779. WriteLogEntry(
  5780. LogContext,
  5781. DRIVER_LOG_VERBOSE,
  5782. MSG_LOG_DELSERVNOSERV,
  5783. NULL,
  5784. ServicesToDelete->Name
  5785. );
  5786. } else {
  5787. //
  5788. // open service failed for some reason
  5789. //
  5790. WriteLogEntry(
  5791. LogContext,
  5792. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  5793. MSG_LOG_DELSERVOPEN_ERROR,
  5794. NULL,
  5795. ServicesToDelete->Name
  5796. );
  5797. WriteLogError(
  5798. LogContext,
  5799. DRIVER_LOG_ERROR,
  5800. LastErr);
  5801. }
  5802. }
  5803. //
  5804. // Delete the event log entry (if required) if either (a) we succeeded in deleting
  5805. // the service, or (b) the service didn't exist.
  5806. //
  5807. if(ServicesToDelete->DeleteEventLog) {
  5808. if(ServiceHandle || (LastErr == ERROR_SERVICE_DOES_NOT_EXIST)) {
  5809. //
  5810. // We need to delete the associated event log for this service.
  5811. //
  5812. if(!hKeyEventLog) {
  5813. //
  5814. // We haven't opened up the EventLog registry key yet, so do that now.
  5815. //
  5816. CopyMemory(RegistryPath, pszServicesRegPath, sizeof(pszServicesRegPath));
  5817. CopyMemory(RegistryPath + CSTRLEN(REGSTR_PATH_SERVICES),
  5818. pszEventLog,
  5819. sizeof(pszEventLog)
  5820. );
  5821. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  5822. RegistryPath,
  5823. 0,
  5824. KEY_READ,
  5825. &hKeyEventLog) != ERROR_SUCCESS) {
  5826. hKeyEventLog = NULL; // make sure this value is still NULL!
  5827. continue;
  5828. }
  5829. }
  5830. //
  5831. // Now open up the event log type key.
  5832. //
  5833. if(RegOpenKeyEx(hKeyEventLog,
  5834. ServicesToDelete->EventLogType,
  5835. 0,
  5836. KEY_READ | KEY_WRITE,
  5837. &hKeyEventLogType) == ERROR_SUCCESS) {
  5838. pSetupRegistryDelnode(hKeyEventLogType, ServicesToDelete->EventLogName);
  5839. RegCloseKey(hKeyEventLogType);
  5840. }
  5841. }
  5842. }
  5843. }
  5844. if(hKeyEventLog) {
  5845. RegCloseKey(hKeyEventLog);
  5846. }
  5847. UnlockServiceDatabase(SCLock);
  5848. }
  5849. CloseServiceHandle(SCMHandle);
  5850. } else {
  5851. Result = GetLastError();
  5852. }
  5853. if (Result != NO_ERROR) {
  5854. WriteLogEntry(
  5855. LogContext,
  5856. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  5857. MSG_LOG_DELSERVSCM_ERROR,
  5858. NULL);
  5859. WriteLogError(
  5860. LogContext,
  5861. DRIVER_LOG_ERROR,
  5862. Result);
  5863. }
  5864. return Result;
  5865. }
  5866. BOOL
  5867. IsDevRemovedFromAllHwProfiles(
  5868. IN PCTSTR DeviceInstanceId,
  5869. IN HMACHINE hMachine
  5870. )
  5871. /*++
  5872. Routine Description:
  5873. This routine determines whether the specified device instance has been removed from
  5874. every hardware profile. The device has been removed from a particular profile if
  5875. its corresponding CsConfigFlags has the CSCONFIGFLAG_DO_NOT_CREATE bit set.
  5876. Arguments:
  5877. DeviceInstanceId - Supplies the name of the device instance to check.
  5878. Return Value:
  5879. If the device exists in only the specified profile, the return value is TRUE,
  5880. otherwise, it is FALSE.
  5881. --*/
  5882. {
  5883. CONFIGRET cr;
  5884. ULONG i = 0;
  5885. HWPROFILEINFO HwProfileInfo;
  5886. ULONG HwProfFlags;
  5887. //
  5888. // Enumerate all the hardware profiles.
  5889. //
  5890. do {
  5891. if((cr = CM_Get_Hardware_Profile_Info_Ex(i, &HwProfileInfo, 0,hMachine)) == CR_SUCCESS) {
  5892. if((CM_Get_HW_Prof_Flags_Ex((DEVINSTID)DeviceInstanceId,
  5893. HwProfileInfo.HWPI_ulHWProfile,
  5894. &HwProfFlags,
  5895. 0,
  5896. hMachine) != CR_SUCCESS) ||
  5897. !(HwProfFlags & CSCONFIGFLAG_DO_NOT_CREATE))
  5898. {
  5899. //
  5900. // If we couldn't retrieve the CSConfigFlags, or if the
  5901. // CSCONFIGFLAG_DO_NOT_CREATE bit was not set, then we've found
  5902. // a profile where the device still exists, so we can bail here.
  5903. //
  5904. return FALSE;
  5905. }
  5906. }
  5907. i++;
  5908. } while(cr != CR_NO_MORE_HW_PROFILES);
  5909. //
  5910. // We didn't find any hardware profile where the device wasn't removed.
  5911. //
  5912. return TRUE;
  5913. }
  5914. DWORD
  5915. GetDevInstConfigFlags(
  5916. IN DEVINST DevInst,
  5917. IN DWORD Default,
  5918. IN HMACHINE hMachine
  5919. )
  5920. /*++
  5921. Routine Description:
  5922. This routine retrieves the ConfigFlags for the specified device instance. If the
  5923. value can not be retrieved, the specified default is returned.
  5924. Arguments:
  5925. DevInst - Supplies the handle of the device instance for which the ConfigFlags value
  5926. is to be retrieved.
  5927. Default - Supplies the default value that should be returned if for some reason the
  5928. ConfigFlags cannot be retrieved.
  5929. Return Value:
  5930. The ConfigFlags value for the specified device instance.
  5931. Notes:
  5932. This is used for device install, and doesn't need to be remotable for 5.0
  5933. --*/
  5934. {
  5935. DWORD ConfigFlags;
  5936. ULONG ConfigFlagsSize = sizeof(ConfigFlags);
  5937. if(CM_Get_DevInst_Registry_Property_Ex(DevInst,
  5938. CM_DRP_CONFIGFLAGS,
  5939. NULL,
  5940. &ConfigFlags,
  5941. &ConfigFlagsSize,
  5942. 0,
  5943. hMachine) != CR_SUCCESS) {
  5944. ConfigFlags = Default;
  5945. }
  5946. return ConfigFlags;
  5947. }
  5948. DWORD
  5949. pSetupDeleteService(
  5950. IN PINFCONTEXT LineContext,
  5951. IN DWORD Flags,
  5952. IN PSETUP_LOG_CONTEXT LogContext
  5953. )
  5954. /*++
  5955. Routine Description:
  5956. This routine processes the specified DelService line in an INF's Service
  5957. install section. The line has the form:
  5958. DelService = <ServiceName>[, [<flags>] [, [<EventLogType>] [, <EventName>]]]
  5959. Flags :
  5960. SPSVCINST_DELETEEVENTLOGENTRY - delete the associated event log entry
  5961. for this service (if there is one).
  5962. If the EventLogType field isn't specified,
  5963. then it is assumed to be "System". If
  5964. the EventName field isn't specified, then
  5965. it is assumed to be the same as the service
  5966. name.
  5967. SPSVCINST_DELETEEVENTLOGENTRY - stop the service before deleting it
  5968. Arguments:
  5969. LineContext - Supplies the context of the DelService line to be processed.
  5970. Flags - specifies one or more SPSVCINST_* flags
  5971. LogContext - Supplies a pointer to a log context to be used for logging.
  5972. Return Value:
  5973. If field 1 on the specified line could not be retrieved, then an error
  5974. is returned. Otherwise, the routine returns NO_ERROR (i.e., the routine
  5975. is considered successful regardless of whether the service to delete
  5976. actually existed).
  5977. --*/
  5978. {
  5979. SVCNAME_NODE TempSvcNode;
  5980. DWORD DelServiceFlags;
  5981. PCTSTR EventLogType, EventLogName;
  5982. BOOL DeleteEventLogEntry;
  5983. DWORD Result = NO_ERROR;
  5984. //
  5985. // Initialize a service name node for a call to DeleteServicesInList.
  5986. //
  5987. if(!SetupGetStringField(LineContext,
  5988. 1,
  5989. TempSvcNode.Name,
  5990. SIZECHARS(TempSvcNode.Name),
  5991. NULL)) {
  5992. return GetLastError();
  5993. }
  5994. //
  5995. // Get the flags field.
  5996. //
  5997. if(!SetupGetIntField(LineContext, 2, (PINT)&DelServiceFlags)) {
  5998. DelServiceFlags = 0;
  5999. }
  6000. DeleteEventLogEntry = (Flags & SPSVCINST_DELETEEVENTLOGENTRY);
  6001. //
  6002. // If the caller specified that the associated event log entry should be
  6003. // deleted, then make sure that flag is set.
  6004. //
  6005. if(DeleteEventLogEntry) {
  6006. DelServiceFlags |= SPSVCINST_DELETEEVENTLOGENTRY;
  6007. }
  6008. if(TempSvcNode.DeleteEventLog = (DelServiceFlags & SPSVCINST_DELETEEVENTLOGENTRY)) {
  6009. //
  6010. // Retrieve the event log type (default is "System") and the event log name
  6011. // (default is the service name).
  6012. //
  6013. if(!(EventLogType = pSetupGetField(LineContext, 3)) || !(*EventLogType)) {
  6014. EventLogType = pszSystem;
  6015. }
  6016. if(!(EventLogName = pSetupGetField(LineContext, 4)) || !(*EventLogName)) {
  6017. EventLogName = TempSvcNode.Name;
  6018. }
  6019. lstrcpy(TempSvcNode.EventLogType, EventLogType);
  6020. lstrcpy(TempSvcNode.EventLogName, EventLogName);
  6021. }
  6022. TempSvcNode.Next = NULL;
  6023. TempSvcNode.Flags = DelServiceFlags | Flags;
  6024. Result = DeleteServicesInList(&TempSvcNode,LogContext);
  6025. return Result;
  6026. }
  6027. #ifdef UNICODE
  6028. BOOL
  6029. IsNativeDriver(
  6030. PCTSTR FullPath
  6031. )
  6032. /*++
  6033. Routine Description:
  6034. determines if a kernel-mode driver binary is valid
  6035. helps avoid bugchecks and catch problems earlier
  6036. Arguments:
  6037. FullPath - Fully qualified path to the binary to be processed
  6038. Return Value:
  6039. TRUE indicates that the file is a native driver
  6040. --*/
  6041. {
  6042. LOADED_IMAGE LoadedImage;
  6043. BOOL RetVal = FALSE;
  6044. PSTR FullPathCopy;
  6045. WORD WantedImage;
  6046. BOOL locked = FALSE;
  6047. #if defined(_IA64_)
  6048. WantedImage = IMAGE_FILE_MACHINE_IA64;
  6049. #elif defined(_AMD64_)
  6050. WantedImage = IMAGE_FILE_MACHINE_AMD64;
  6051. #elif defined(_X86_)
  6052. if(IsWow64) {
  6053. //
  6054. // we don't support installing drivers if in Wow64
  6055. //
  6056. return FALSE;
  6057. }
  6058. WantedImage = IMAGE_FILE_MACHINE_I386;
  6059. #else
  6060. #error Unknown platform
  6061. #endif
  6062. //
  6063. // imagehlp takes a non-const ANSI string, so convert it.
  6064. //
  6065. FullPathCopy = pSetupUnicodeToMultiByte(FullPath, CP_ACP);
  6066. if (!FullPathCopy) {
  6067. return(FALSE);
  6068. }
  6069. RtlZeroMemory(
  6070. &LoadedImage,
  6071. sizeof(LoadedImage) );
  6072. //
  6073. // get the image headers
  6074. //
  6075. try {
  6076. EnterCriticalSection(&ImageHlpMutex);
  6077. locked = TRUE;
  6078. } except(EXCEPTION_EXECUTE_HANDLER) {
  6079. }
  6080. if(!locked) {
  6081. MyFree(FullPathCopy);
  6082. return FALSE;
  6083. }
  6084. if (MapAndLoad(
  6085. FullPathCopy,
  6086. NULL,
  6087. &LoadedImage,
  6088. FALSE, // assume it's an exe if there isn't any file extension
  6089. TRUE /* read only */ )) {
  6090. if ((LoadedImage.FileHeader->Signature == IMAGE_NT_SIGNATURE)
  6091. && (LoadedImage.FileHeader->FileHeader.Machine == WantedImage)
  6092. && (LoadedImage.FileHeader->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) {
  6093. RetVal = TRUE;
  6094. }
  6095. UnMapAndLoad(&LoadedImage);
  6096. }
  6097. LeaveCriticalSection(&ImageHlpMutex);
  6098. MyFree(FullPathCopy);
  6099. return(RetVal);
  6100. }
  6101. #endif
  6102. DWORD
  6103. pSetupAddService(
  6104. IN PINFCONTEXT LineContext,
  6105. OUT PSVCNAME_NODE *SvcListHead,
  6106. IN DWORD Flags,
  6107. IN DEVINST DevInst, OPTIONAL
  6108. OUT PBOOL NullDriverInstalled,
  6109. IN PSETUP_LOG_CONTEXT LogContext
  6110. )
  6111. /*++
  6112. Routine Description:
  6113. This routine processes the specified AddService line in an INF's Service
  6114. install section. The line has the form:
  6115. AddService = <ServiceName>, [<Flags>], <ServiceInstallSection>[, <EventLogInstallSection>[, [<EventLogType>] [, <EventName>]]]
  6116. Currently, the following flags are defined:
  6117. SPSVCINST_TAGTOFRONT (0x1) - Move the tag for this service to the front of its
  6118. group order list
  6119. SPSVCINST_ASSOCSERVICE (0x2) - Associate this service with the device instance
  6120. being installed (only used if DevInst is non-zero)
  6121. SPSVCINST_NOCLOBBER_DISPLAYNAME (0x8) - If this flag is specified, then
  6122. we will not overwrite the service's
  6123. display name, if it already exists.
  6124. SPSVCINST_NOCLOBBER_STARTTYPE (0x10) - If this flag is specified, then
  6125. we will not overwrite the service's
  6126. start type if the service already exists.
  6127. SPSVCINST_NOCLOBBER_ERRORCONTROL (0x20) - If this flag is specified, then
  6128. we will not overwrite the service's
  6129. error control value if the service
  6130. already exists.
  6131. SPSVCINST_NOCLOBBER_LOADORDERGROUP (0x40) - If this flag is specified, then
  6132. we will not overwrite the service's
  6133. load order group if it already
  6134. exists.
  6135. SPSVCINST_NOCLOBBER_DEPENDENCIES (0x80) - If this flag is specified, then
  6136. we will not overwrite the service's
  6137. dependencies list if it already
  6138. exists.
  6139. SPSVCINST_CLOBBER_SECURITY (0x400) - If this flag is specified, then
  6140. security may be overridden.
  6141. A service with the name <ServiceName> is created. The parameters used in the
  6142. call to CreateService are retrieved from the <ServiceInstallSection>, and are
  6143. in the following format (lines not marked as optional must be present or the
  6144. routine will fail):
  6145. DisplayName = <string> ; (optional) 'Friendly name' for the service
  6146. ServiceType = <number> ; one of the SERVICE_* type codes
  6147. StartType = <number> ; one of the SERVICE_* start codes
  6148. ErrorControl = <number> ; one of the SERVICE_ERROR_* error control codes
  6149. ServiceBinary = <string> ; path to binary
  6150. LoadOrderGroup = <string> ; (optional) group to which this service belongs
  6151. Dependencies = <string>[[, <string>]...] ; (optional) list of groups (prefixed with '+')
  6152. ; and services this service depends on
  6153. StartName = <string> ; (optional) driver object name used to load the
  6154. ; driver--only used for drivers & filesystems
  6155. Security = <string> ; (optional) SDS specifying security
  6156. SetupInstallFromInfSection is then called for the <ServiceInstallSection>, which may
  6157. also contain registry modifications (SPINST_REGISTRY is the only flag used). HKR is
  6158. the service entry key.
  6159. Finally, if <EventLogInstallSection> is specified, then a key for this service is
  6160. created under HKLM\System\CurrentControlSet\Services\EventLog, and SetupInstallFromInfSection
  6161. is invoked to do registry modifications specified in that section, with HKR being the event log
  6162. entry (again, only SPINST_REGISTRY is used). By default, the event log type is "System" and the
  6163. event log name is the same as the service name.
  6164. Arguments:
  6165. LineContext - Supplies the context of the AddService line to be processed.
  6166. SvcListHead - Supplies the address of the linked-list head containing a list of
  6167. all services newly created as a result of the current installation. This
  6168. routine first checks for the presence of the service, and if it already exists,
  6169. then it simply modifies the existing one. If the service doesn't already exist,
  6170. then this routine creates a new SVCNAME_NODE, and fills it in with the name of
  6171. the newly-created service. Likewise, if an EventLog entry is given, then the
  6172. presence of an existing one is checked first, and the service node's
  6173. 'DeleteEventLog' field is set to TRUE only if the event log entry didn't
  6174. previously exist. This list is kept to allow for proper clean-up in case
  6175. of a later failure.
  6176. Flags - Specifies how the service should be installed. These flags are basically
  6177. overrides of what the AddService flags field specifies, as described above.
  6178. DevInst - If specified (i.e., non-zero), and if the SPSVCINST_ASSOCSERVICE flag is
  6179. set in either the Flags parameter or the AddService flags INF field, then we will
  6180. store this service name in the device instance's 'Service' registry property.
  6181. NullDriverInstalled - Supplies a pointer to a boolean variable that is set
  6182. upon successful return to indicate whether or not the service install
  6183. specified a null service (i.e., the service name field in the INF AddService
  6184. entry was empty).
  6185. LogContext - Supplies a pointer to a log context so that info may be logged.
  6186. Return Value:
  6187. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error code.
  6188. Remarks:
  6189. Note that we don't do anything special for SERVICE_ADAPTER and SERVICE_RECOGNIZER_DRIVER
  6190. service types. These types are invalid as far as the service contoller is concerned, so
  6191. we just let the create/change service APIs do the validation on them.
  6192. --*/
  6193. {
  6194. PCTSTR ServiceName, InstallSection, EventLogType, EventLogName;
  6195. HINF hInf;
  6196. INFCONTEXT InstallSectionContext;
  6197. DWORD ServiceType, StartType, ErrorControl, ServiceInstallFlags;
  6198. PCTSTR ServiceBinary;
  6199. PCTSTR ActualBinary = NULL;
  6200. TCHAR ServiceBinaryBuffer[MAX_PATH];
  6201. PCTSTR DisplayName = NULL, LoadOrderGroup = NULL,
  6202. StartName = NULL, Security = NULL, Description = NULL;
  6203. PTSTR DependenciesBuffer;
  6204. DWORD TagId;
  6205. PDWORD NewTag;
  6206. DWORD Err;
  6207. SC_HANDLE SCMHandle, ServiceHandle;
  6208. SC_LOCK SCLock;
  6209. HKEY hKeyService, hKeyEventLog;
  6210. TCHAR RegistryPath[SIZECHARS(REGSTR_PATH_SERVICES) + SIZECHARS(DISTR_EVENTLOG) + (2 * 256)];
  6211. DWORD EventLogKeyDisposition;
  6212. SVCNAME_NODE NewSvcNameNode;
  6213. PSVCNAME_NODE TmpNode;
  6214. BOOL NewService;
  6215. INT PathLen;
  6216. BOOL b, BinaryInSysRoot, ServiceHasTag;
  6217. LPQUERY_SERVICE_CONFIG ServiceConfig;
  6218. REGMOD_CONTEXT RegContext;
  6219. BOOL NeedsReboot;
  6220. //
  6221. // Initially, assume we're not doing a null service install.
  6222. //
  6223. *NullDriverInstalled = FALSE;
  6224. NeedsReboot = FALSE;
  6225. //
  6226. // Get the AddService flags.
  6227. //
  6228. if(!SetupGetIntField(LineContext, 2, (PINT)&ServiceInstallFlags)) {
  6229. ServiceInstallFlags = 0;
  6230. }
  6231. //
  6232. // Allow the caller-supplied flags to override the INF.
  6233. //
  6234. ServiceInstallFlags |= Flags;
  6235. //
  6236. // Now get the service name.
  6237. //
  6238. if(!(ServiceName = pSetupGetField(LineContext, 1)) || !(*ServiceName)) {
  6239. //
  6240. // This is only allowed if the SPSVCINST_ASSOCSERVICE flag is set. That
  6241. // indicates to PnP that a null driver installation is allowed, even
  6242. // though the underlying bus didn't report the device as raw-capable.
  6243. //
  6244. if(ServiceInstallFlags & SPSVCINST_ASSOCSERVICE) {
  6245. if(DevInst) {
  6246. CM_Set_DevInst_Registry_Property(DevInst,
  6247. CM_DRP_SERVICE,
  6248. NULL,
  6249. 0,
  6250. 0
  6251. );
  6252. }
  6253. *NullDriverInstalled = TRUE;
  6254. WriteLogEntry(
  6255. LogContext,
  6256. DRIVER_LOG_VERBOSE,
  6257. MSG_LOG_ADDSERV_NULL,
  6258. NULL);
  6259. return NO_ERROR;
  6260. } else {
  6261. return GetLastError();
  6262. }
  6263. }
  6264. //
  6265. // Next, get the name of the install section.
  6266. //
  6267. if(!(InstallSection = pSetupGetField(LineContext, 3))) {
  6268. return GetLastError();
  6269. }
  6270. //
  6271. // Locate the service install section.
  6272. //
  6273. hInf = LineContext->Inf;
  6274. //
  6275. // Retrieve the required values from this section. Don't do validation on them--leave
  6276. // that up to the Service Control Manager.
  6277. //
  6278. if(!SetupFindFirstLine(hInf, InstallSection, pszServiceType, &InstallSectionContext) ||
  6279. !SetupGetIntField(&InstallSectionContext, 1, (PINT)&ServiceType)) {
  6280. return ERROR_BAD_SERVICE_INSTALLSECT;
  6281. }
  6282. if(!SetupFindFirstLine(hInf, InstallSection, pszStartType, &InstallSectionContext) ||
  6283. !SetupGetIntField(&InstallSectionContext, 1, (PINT)&StartType)) {
  6284. return ERROR_BAD_SERVICE_INSTALLSECT;
  6285. }
  6286. if(!SetupFindFirstLine(hInf, InstallSection, pszErrorControl, &InstallSectionContext) ||
  6287. !SetupGetIntField(&InstallSectionContext, 1, (PINT)&ErrorControl)) {
  6288. return ERROR_BAD_SERVICE_INSTALLSECT;
  6289. }
  6290. BinaryInSysRoot = FALSE;
  6291. if(SetupFindFirstLine(hInf, InstallSection, pszServiceBinary, &InstallSectionContext) &&
  6292. (ServiceBinary = pSetupGetField(&InstallSectionContext, 1)) && *ServiceBinary) {
  6293. //
  6294. // Compare the initial part of this path with the WindowsDirectory path. If they're
  6295. // the same, then we strip off that part (including the dividing backslash), and use
  6296. // the rest of the path for the subsequent calls to SCM. This allows SCM to assign
  6297. // the special path to the binary, that is accessible, at any time (i.e, boot-loader on).
  6298. //
  6299. ActualBinary = ServiceBinary;
  6300. PathLen = lstrlen(WindowsDirectory);
  6301. MYASSERT(PathLen);
  6302. //
  6303. // Make sure that the it is possible for the WindowsDirectory to fit in the ServiceBinary
  6304. // path string.
  6305. //
  6306. if(PathLen < lstrlen(ServiceBinary)) {
  6307. //
  6308. // There will never be a trailing backslash in the WindowsDirectory path, unless the
  6309. // installation is at the root of a drive (e.g., C:\). Check this, just to be
  6310. // on the safe side.
  6311. //
  6312. // DBCS-unfriendly code ahead. This isn't a problem in the ANSI version of
  6313. // setupapi presently, because there's no such thing as service installation on Win9x.
  6314. //
  6315. b = (WindowsDirectory[PathLen - 1] == TEXT('\\'));
  6316. if(b || (ServiceBinary[PathLen] == TEXT('\\'))) {
  6317. //
  6318. // The path prefix is in the right format--now we need to see if the two
  6319. // paths actually match. Copy just the prefix part to another buffer, so
  6320. // that we can do the comparison.
  6321. //
  6322. CopyMemory(ServiceBinaryBuffer, ServiceBinary, PathLen * sizeof(TCHAR));
  6323. ServiceBinaryBuffer[PathLen] = TEXT('\0');
  6324. if(!lstrcmpi(WindowsDirectory, ServiceBinaryBuffer)) {
  6325. //
  6326. // We have a match--take the relative part of the path (relative to SystemRoot),
  6327. // and do one of the following:
  6328. //
  6329. // 1. If it's a driver, simply use the relative part (no preceding backslash).
  6330. // This tells the bootloader/NtLoadDriver that the path is relative to the
  6331. // SystemRoot, so the driver can be loaded no matter what phase it's loaded in.
  6332. //
  6333. // 2. If it's a Win32 service, prepend a %SystemRoot%, so that the service will
  6334. // still be able to start if the drive letter mappings change.
  6335. //
  6336. ServiceBinary += PathLen;
  6337. if(!b) {
  6338. ServiceBinary++;
  6339. }
  6340. if(ServiceType & SERVICE_WIN32) {
  6341. CopyMemory(ServiceBinaryBuffer, pszSystemRoot, sizeof(pszSystemRoot) - sizeof(TCHAR));
  6342. lstrcpy(ServiceBinaryBuffer + CSTRLEN(pszSystemRoot), ServiceBinary);
  6343. ServiceBinary = ServiceBinaryBuffer;
  6344. }
  6345. BinaryInSysRoot = TRUE;
  6346. }
  6347. }
  6348. }
  6349. } else {
  6350. return ERROR_BAD_SERVICE_INSTALLSECT;
  6351. }
  6352. //
  6353. // If this is a driver, then it has to be located under SystemRoot.
  6354. //
  6355. if(ServiceType & (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER)) {
  6356. if(!BinaryInSysRoot) {
  6357. //
  6358. // service install section is wrong, driver path is bad
  6359. //
  6360. return ERROR_BAD_SERVICE_INSTALLSECT;
  6361. }
  6362. #ifdef UNICODE
  6363. if(DevInst) {
  6364. if(!FileExists(ActualBinary,NULL)) {
  6365. //
  6366. // service install section is wrong, it doesn't point to existing
  6367. // binary
  6368. //
  6369. WriteLogEntry(
  6370. LogContext,
  6371. DRIVER_LOG_ERROR,
  6372. MSG_LOG_MISSING_DRIVER,
  6373. NULL,
  6374. ServiceName,
  6375. ActualBinary
  6376. );
  6377. return ERROR_BAD_SERVICE_INSTALLSECT;
  6378. }
  6379. if(!IsNativeDriver(ActualBinary)) {
  6380. //
  6381. // oh oh, we've come this far, only to find that we're going to try and use
  6382. // a non-native or bad driver
  6383. //
  6384. // we might be able to revert original binary if there was one
  6385. //
  6386. if(pSetupRestoreLastKnownGoodFile(ActualBinary,0,LogContext)
  6387. && IsNativeDriver(ActualBinary)) {
  6388. WriteLogEntry(
  6389. LogContext,
  6390. DRIVER_LOG_ERROR,
  6391. MSG_LOG_REVERTED_BAD_DRIVER,
  6392. NULL,
  6393. ServiceName,
  6394. ActualBinary
  6395. );
  6396. } else {
  6397. WriteLogEntry(
  6398. LogContext,
  6399. DRIVER_LOG_ERROR,
  6400. MSG_LOG_HAVE_BAD_DRIVER,
  6401. NULL,
  6402. ServiceName,
  6403. ActualBinary
  6404. );
  6405. }
  6406. return ERROR_DRIVER_NONNATIVE;
  6407. }
  6408. }
  6409. #endif
  6410. }
  6411. //
  6412. // if this is a boot start driver, we need a reboot for it to start running
  6413. //
  6414. if (StartType == SERVICE_BOOT_START) {
  6415. NeedsReboot = TRUE;
  6416. }
  6417. //
  6418. // Now check for the other, optional, parameters.
  6419. //
  6420. if(SetupFindFirstLine(hInf, InstallSection, pszDisplayName, &InstallSectionContext)) {
  6421. if((DisplayName = pSetupGetField(&InstallSectionContext, 1)) && !(*DisplayName)) {
  6422. DisplayName = NULL;
  6423. }
  6424. }
  6425. if(SetupFindFirstLine(hInf, InstallSection, pszLoadOrderGroup, &InstallSectionContext)) {
  6426. if((LoadOrderGroup = pSetupGetField(&InstallSectionContext, 1)) && !(*LoadOrderGroup)) {
  6427. LoadOrderGroup = NULL;
  6428. }
  6429. }
  6430. if(SetupFindFirstLine(hInf, InstallSection, pszSecurity, &InstallSectionContext)) {
  6431. if((Security = pSetupGetField(&InstallSectionContext, 1)) && !(*Security)) {
  6432. Security = NULL;
  6433. }
  6434. }
  6435. if(SetupFindFirstLine(hInf, InstallSection, pszDescription, &InstallSectionContext)) {
  6436. if((Description = pSetupGetField(&InstallSectionContext, 1)) && !(*Description)) {
  6437. Description = NULL;
  6438. }
  6439. }
  6440. //
  6441. // Only retrieve the StartName parameter for kernel-mode drivers and win32 services.
  6442. //
  6443. if(ServiceType & (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_WIN32)) {
  6444. if(SetupFindFirstLine(hInf, InstallSection, pszStartName, &InstallSectionContext)) {
  6445. if((StartName = pSetupGetField(&InstallSectionContext, 1)) &&
  6446. !(*StartName)) {
  6447. StartName = NULL;
  6448. }
  6449. }
  6450. }
  6451. //
  6452. // We now need to retrieve the multi-sz list of dependencies. This requires memory allocation,
  6453. // so we include everything from here on out in try/except, so that we can do proper clean-up
  6454. // in case we encounter an inpage error.
  6455. //
  6456. DependenciesBuffer = NULL;
  6457. SCMHandle = ServiceHandle = NULL;
  6458. SCLock = NULL;
  6459. hKeyService = hKeyEventLog = NULL;
  6460. Err = NO_ERROR;
  6461. NewService = FALSE;
  6462. ServiceConfig = NULL;
  6463. try {
  6464. if(!(DependenciesBuffer = GetMultiSzFromInf(hInf, InstallSection, pszDependencies, &b)) && b) {
  6465. //
  6466. // Then we failed to retrieve a dependencies list because of an out-of-memory error.
  6467. //
  6468. Err = ERROR_NOT_ENOUGH_MEMORY;
  6469. goto clean0;
  6470. }
  6471. //
  6472. // We've now retrieved all parameters necessary to create a service.
  6473. //
  6474. if(!(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  6475. Err = GetLastError();
  6476. WriteLogEntry(
  6477. LogContext,
  6478. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  6479. MSG_LOG_ADDSERVSCM_ERROR,
  6480. NULL);
  6481. WriteLogError(
  6482. LogContext,
  6483. DRIVER_LOG_ERROR,
  6484. Err);
  6485. goto clean0;
  6486. }
  6487. //
  6488. // Only generate a tag for this service if it has a load order group, and is a kernel or
  6489. // filesystem driver.
  6490. //
  6491. ServiceHasTag = (LoadOrderGroup &&
  6492. (ServiceType & (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER)));
  6493. NewTag = ServiceHasTag ? &TagId : NULL;
  6494. ServiceHandle = CreateService(SCMHandle,
  6495. ServiceName,
  6496. DisplayName,
  6497. SERVICE_CHANGE_CONFIG,
  6498. ServiceType,
  6499. StartType,
  6500. ErrorControl,
  6501. ServiceBinary,
  6502. LoadOrderGroup,
  6503. NewTag,
  6504. DependenciesBuffer,
  6505. StartName,
  6506. NULL
  6507. );
  6508. if(ServiceHandle) {
  6509. NewService = TRUE;
  6510. NewSvcNameNode.Next = NULL;
  6511. NewSvcNameNode.DeleteEventLog = FALSE;
  6512. lstrcpy(NewSvcNameNode.Name, ServiceName);
  6513. #ifdef UNICODE
  6514. if( Security ){
  6515. //
  6516. // Log security being set.
  6517. //
  6518. if( NO_ERROR != (Err = pSetupCallSCE( ST_SCE_SERVICES, ServiceName, NULL, Security, StartType, NULL )) ) {
  6519. WriteLogEntry(
  6520. LogContext,
  6521. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  6522. MSG_LOG_ADDSERVSECURE_ERROR,
  6523. NULL,
  6524. ServiceName
  6525. );
  6526. WriteLogError(
  6527. LogContext,
  6528. DRIVER_LOG_ERROR,
  6529. Err);
  6530. goto clean0;
  6531. }
  6532. }
  6533. #endif
  6534. WriteLogEntry(
  6535. LogContext,
  6536. DRIVER_LOG_VERBOSE,
  6537. MSG_LOG_ADDSERVCREATE_OK,
  6538. NULL,
  6539. ServiceName
  6540. );
  6541. } else {
  6542. //
  6543. // If we were unable to create the service, then check to see if the service already
  6544. // exists. If so, all we need to do is change the configuration parameters in the
  6545. // service.
  6546. //
  6547. if((Err = GetLastError()) != ERROR_SERVICE_EXISTS) {
  6548. WriteLogEntry(
  6549. LogContext,
  6550. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  6551. MSG_LOG_ADDSERVCREATE_ERROR,
  6552. NULL,
  6553. ServiceName
  6554. );
  6555. WriteLogError(
  6556. LogContext,
  6557. DRIVER_LOG_ERROR,
  6558. Err);
  6559. goto clean0;
  6560. }
  6561. //
  6562. // Lock the service database.
  6563. //
  6564. if(NO_ERROR != (Err = pAcquireSCMLock(SCMHandle, &SCLock, LogContext))) {
  6565. WriteLogEntry(
  6566. LogContext,
  6567. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  6568. MSG_LOG_ADDSERVLOCK_ERROR,
  6569. NULL
  6570. );
  6571. WriteLogError(
  6572. LogContext,
  6573. DRIVER_LOG_ERROR,
  6574. Err);
  6575. goto clean0;
  6576. }
  6577. if(!(ServiceHandle = OpenService(SCMHandle, ServiceName, SERVICE_ALL_ACCESS))) {
  6578. Err = GetLastError();
  6579. WriteLogEntry(
  6580. LogContext,
  6581. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  6582. MSG_LOG_ADDSERVOPEN_ERROR,
  6583. NULL,
  6584. ServiceName
  6585. );
  6586. WriteLogError(
  6587. LogContext,
  6588. DRIVER_LOG_ERROR,
  6589. Err);
  6590. goto clean0;
  6591. }
  6592. if((Err = pSetupRetrieveServiceConfig(ServiceHandle, &ServiceConfig)) != NO_ERROR) {
  6593. WriteLogEntry(
  6594. LogContext,
  6595. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  6596. MSG_LOG_ADDSERVCONFIG_ERROR,
  6597. NULL,
  6598. ServiceName
  6599. );
  6600. WriteLogError(
  6601. LogContext,
  6602. DRIVER_LOG_ERROR,
  6603. Err);
  6604. //
  6605. // Make sure our ServiceConfig pointer is still NULL.
  6606. //
  6607. ServiceConfig = NULL;
  6608. goto clean0;
  6609. }
  6610. //
  6611. // Since this is an existing driver, then it may already have a perfectly good tag. If
  6612. // so, we don't want to disturb it.
  6613. //
  6614. if(ServiceHasTag) {
  6615. if(ServiceConfig->lpLoadOrderGroup && *(ServiceConfig->lpLoadOrderGroup)) {
  6616. //
  6617. // The service already has a load order group specified.
  6618. // Check to see whether the load order group 'noclobber'
  6619. // flag is set.
  6620. //
  6621. if(ServiceInstallFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP) {
  6622. //
  6623. // We should leave the existing load order group as-is.
  6624. // We do this by replacing the INF-specified one with the
  6625. // previously-existing one. That way, our code below will
  6626. // still generate a tag if necessary.
  6627. //
  6628. LoadOrderGroup = ServiceConfig->lpLoadOrderGroup;
  6629. }
  6630. if(!lstrcmpi(ServiceConfig->lpLoadOrderGroup, LoadOrderGroup) && ServiceConfig->dwTagId) {
  6631. //
  6632. // The load order group hasn't changed, and there's already a tag assigned, so
  6633. // leave it alone.
  6634. //
  6635. NewTag = NULL;
  6636. TagId = ServiceConfig->dwTagId;
  6637. }
  6638. }
  6639. }
  6640. if(ServiceInstallFlags & SPSVCINST_NOCLOBBER_DISPLAYNAME) {
  6641. //
  6642. // If the service already has a display name, then we don't want
  6643. // to overwrite it.
  6644. //
  6645. if(ServiceConfig->lpDisplayName && *(ServiceConfig->lpDisplayName)) {
  6646. DisplayName = NULL;
  6647. }
  6648. }
  6649. if(ServiceInstallFlags & SPSVCINST_NOCLOBBER_DEPENDENCIES) {
  6650. //
  6651. // If the service already has a dependencies list, then we don't
  6652. // want to overwrite it.
  6653. //
  6654. if(ServiceConfig->lpDependencies && *(ServiceConfig->lpDependencies)) {
  6655. MyFree(DependenciesBuffer);
  6656. DependenciesBuffer = NULL;
  6657. }
  6658. }
  6659. if(!ChangeServiceConfig(ServiceHandle,
  6660. ServiceType,
  6661. (ServiceInstallFlags & SPSVCINST_NOCLOBBER_STARTTYPE)
  6662. ? SERVICE_NO_CHANGE : StartType,
  6663. (ServiceInstallFlags & SPSVCINST_NOCLOBBER_ERRORCONTROL)
  6664. ? SERVICE_NO_CHANGE : ErrorControl,
  6665. ServiceBinary,
  6666. LoadOrderGroup,
  6667. NewTag,
  6668. DependenciesBuffer,
  6669. StartName,
  6670. TEXT(""),
  6671. DisplayName)) {
  6672. Err = GetLastError();
  6673. WriteLogEntry(
  6674. LogContext,
  6675. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  6676. MSG_LOG_ADDSERVCHANGE_ERROR,
  6677. NULL,
  6678. ServiceName
  6679. );
  6680. WriteLogError(
  6681. LogContext,
  6682. DRIVER_LOG_ERROR,
  6683. Err);
  6684. goto clean0;
  6685. } else {
  6686. WriteLogEntry(
  6687. LogContext,
  6688. DRIVER_LOG_VERBOSE,
  6689. MSG_LOG_ADDSERVCHANGE_OK,
  6690. NULL,
  6691. ServiceName
  6692. );
  6693. }
  6694. #ifdef UNICODE
  6695. if( Security && (ServiceInstallFlags & SPSVCINST_CLOBBER_SECURITY)){
  6696. //
  6697. // Set/log security
  6698. // in this scenario, service was already running
  6699. // so don't fail if we can't change security
  6700. //
  6701. if( NO_ERROR != (Err = pSetupCallSCE( ST_SCE_SERVICES,
  6702. ServiceName,
  6703. NULL,
  6704. Security,
  6705. (ServiceInstallFlags & SPSVCINST_NOCLOBBER_STARTTYPE)
  6706. ? ServiceConfig->dwStartType
  6707. : StartType,
  6708. NULL )) ) {
  6709. WriteLogEntry(
  6710. LogContext,
  6711. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  6712. MSG_LOG_ADDSERVSECURE_ERROR,
  6713. NULL,
  6714. ServiceName
  6715. );
  6716. WriteLogError(
  6717. LogContext,
  6718. DRIVER_LOG_ERROR,
  6719. Err);
  6720. //goto clean0;
  6721. }
  6722. }
  6723. #endif
  6724. }
  6725. //
  6726. // we've added/updated the service, now handle the description, which is an oddball
  6727. // parameter since it's a new parameter and isn't present in the prior calls.
  6728. //
  6729. //
  6730. // we ignore failure at this point since this won't effect operation of the service.
  6731. //
  6732. #ifdef UNICODE
  6733. if ((NewService && Description) || ((ServiceInstallFlags & SPSVCINST_NOCLOBBER_DESCRIPTION) == 0)) {
  6734. SERVICE_DESCRIPTION ServiceDescription;
  6735. ServiceDescription.lpDescription = (LPTSTR)Description;
  6736. ChangeServiceConfig2(ServiceHandle, SERVICE_CONFIG_DESCRIPTION,&ServiceDescription);
  6737. }
  6738. #endif
  6739. //
  6740. // We've successfully created/updated the service. If this service has a load order group
  6741. // tag, then make sure it's in the appropriate GroupOrderList entry.
  6742. //
  6743. // (We ignore failure here, since the service should still work just fine without this.)
  6744. //
  6745. if(ServiceHasTag) {
  6746. pSetupAddTagToGroupOrderListEntry(LoadOrderGroup,
  6747. TagId,
  6748. ServiceInstallFlags & SPSVCINST_TAGTOFRONT);
  6749. }
  6750. //
  6751. // Now process any AddReg and DelReg entries found in this service install section.
  6752. //
  6753. CopyMemory(RegistryPath, pszServicesRegPath, sizeof(pszServicesRegPath));
  6754. pSetupConcatenatePaths(RegistryPath,
  6755. ServiceName,
  6756. SIZECHARS(RegistryPath),
  6757. NULL
  6758. );
  6759. if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  6760. RegistryPath,
  6761. 0,
  6762. KEY_READ | KEY_WRITE,
  6763. &hKeyService)) != ERROR_SUCCESS) {
  6764. goto clean0;
  6765. }
  6766. ZeroMemory(&RegContext, sizeof(RegContext));
  6767. RegContext.UserRootKey = hKeyService;
  6768. if((Err = pSetupInstallRegistry(hInf, InstallSection, &RegContext)) != NO_ERROR) {
  6769. goto clean0;
  6770. }
  6771. //
  6772. // Now, see if the INF also specifies an EventLog installation section. If so, create a
  6773. // key under HKLM\System\CurrentControlSet\Services\EventLog\System for that service, and
  6774. // run the registry modification lines in the specified install section.
  6775. //
  6776. if((InstallSection = pSetupGetField(LineContext, 4)) && *InstallSection) {
  6777. //
  6778. // Get the (optional) event log type and event log name strings.
  6779. //
  6780. if(!(EventLogType = pSetupGetField(LineContext, 5)) || !(*EventLogType)) {
  6781. EventLogType = pszSystem;
  6782. }
  6783. if(!(EventLogName = pSetupGetField(LineContext, 6)) || !(*EventLogName)) {
  6784. EventLogName = ServiceName;
  6785. }
  6786. //
  6787. // We already have the services database registry path in our registry path buffer. All
  6788. // we need to do is add the \EventLog\<EventLogType>\<EventLogName> part.
  6789. //
  6790. CopyMemory(RegistryPath + CSTRLEN(REGSTR_PATH_SERVICES),
  6791. pszEventLog,
  6792. sizeof(pszEventLog)
  6793. );
  6794. pSetupConcatenatePaths(RegistryPath,
  6795. EventLogType,
  6796. SIZECHARS(RegistryPath),
  6797. NULL
  6798. );
  6799. pSetupConcatenatePaths(RegistryPath,
  6800. EventLogName,
  6801. SIZECHARS(RegistryPath),
  6802. NULL
  6803. );
  6804. if((Err = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  6805. RegistryPath,
  6806. 0,
  6807. NULL,
  6808. REG_OPTION_NON_VOLATILE,
  6809. KEY_READ | KEY_WRITE,
  6810. NULL,
  6811. &hKeyEventLog,
  6812. &EventLogKeyDisposition)) != ERROR_SUCCESS) {
  6813. goto clean0;
  6814. }
  6815. if(EventLogKeyDisposition == REG_CREATED_NEW_KEY) {
  6816. NewSvcNameNode.DeleteEventLog = TRUE;
  6817. lstrcpy(NewSvcNameNode.EventLogType, EventLogType);
  6818. lstrcpy(NewSvcNameNode.EventLogName, EventLogName);
  6819. }
  6820. ZeroMemory(&RegContext, sizeof(RegContext));
  6821. RegContext.UserRootKey = hKeyEventLog;
  6822. if((Err = pSetupInstallRegistry(hInf, InstallSection, &RegContext)) != NO_ERROR) {
  6823. goto clean0;
  6824. }
  6825. }
  6826. //
  6827. // Service entry (and optional EventLog entry) were successfully installed. If the
  6828. // AddService flags field in the INF included the SPSVCINST_ASSOCSERVICE flag, _and_
  6829. // the caller supplied us with a non-zero DevInst handle, then we need to set the
  6830. // device instance's 'Service' property to indicate that it is associated with this
  6831. // service.
  6832. //
  6833. if(DevInst && (ServiceInstallFlags & SPSVCINST_ASSOCSERVICE)) {
  6834. CM_Set_DevInst_Registry_Property(DevInst,
  6835. CM_DRP_SERVICE,
  6836. ServiceName,
  6837. (lstrlen(ServiceName) + 1) * sizeof(TCHAR),
  6838. 0
  6839. );
  6840. }
  6841. //
  6842. // If a new service was created, then link a new service name node into the list we
  6843. // were passed in. Don't fret about the case where we can't allocate a node--it just
  6844. // means we won't know about this new service in case clean-up is required later.
  6845. //
  6846. if(NewService) {
  6847. if(TmpNode = MyMalloc(sizeof(SVCNAME_NODE))) {
  6848. lstrcpy(TmpNode->Name, NewSvcNameNode.Name);
  6849. if(TmpNode->DeleteEventLog = NewSvcNameNode.DeleteEventLog) {
  6850. lstrcpy(TmpNode->EventLogType, NewSvcNameNode.EventLogType);
  6851. lstrcpy(TmpNode->EventLogName, NewSvcNameNode.EventLogName);
  6852. }
  6853. TmpNode->Next = *SvcListHead;
  6854. *SvcListHead = TmpNode;
  6855. }
  6856. }
  6857. clean0: ; // nothing to do.
  6858. } except(EXCEPTION_EXECUTE_HANDLER) {
  6859. //
  6860. // If our exception was an AV, then use Win32 invalid param error, otherwise, assume it was
  6861. // an inpage error dealing with a mapped-in file.
  6862. //
  6863. Err = (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? ERROR_INVALID_PARAMETER : ERROR_READ_FAULT;
  6864. //
  6865. // Access the following variables so that the compiler will respect our statement ordering
  6866. // w.r.t. these values. Otherwise, we can't be sure that we know whether or not their
  6867. // corresponding resources should be freed.
  6868. //
  6869. DependenciesBuffer = DependenciesBuffer;
  6870. hKeyService = hKeyService;
  6871. hKeyEventLog = hKeyEventLog;
  6872. ServiceHandle = ServiceHandle;
  6873. SCLock = SCLock;
  6874. SCMHandle = SCMHandle;
  6875. NewService = NewService;
  6876. ServiceConfig = ServiceConfig;
  6877. }
  6878. if(ServiceConfig) {
  6879. MyFree(ServiceConfig);
  6880. }
  6881. if(DependenciesBuffer) {
  6882. MyFree(DependenciesBuffer);
  6883. }
  6884. if(hKeyService) {
  6885. RegCloseKey(hKeyService);
  6886. }
  6887. if(hKeyEventLog) {
  6888. RegCloseKey(hKeyEventLog);
  6889. }
  6890. if(ServiceHandle) {
  6891. CloseServiceHandle(ServiceHandle);
  6892. }
  6893. if(SCLock) {
  6894. UnlockServiceDatabase(SCLock);
  6895. }
  6896. if(SCMHandle) {
  6897. CloseServiceHandle(SCMHandle);
  6898. }
  6899. if (Err != NO_ERROR) {
  6900. if (NewService) {
  6901. //
  6902. // Then we failed part-way through, and need to clean up the service (and
  6903. // possibly event log entry) we created.
  6904. //
  6905. DeleteServicesInList(&NewSvcNameNode,LogContext);
  6906. }
  6907. } else {
  6908. if (NeedsReboot) {
  6909. SetLastError(ERROR_SUCCESS_REBOOT_REQUIRED);
  6910. }
  6911. }
  6912. return Err;
  6913. }
  6914. DWORD
  6915. pSetupRetrieveServiceConfig(
  6916. IN SC_HANDLE ServiceHandle,
  6917. OUT LPQUERY_SERVICE_CONFIG *ServiceConfig
  6918. )
  6919. /*++
  6920. Routine Description:
  6921. This routine allocates a buffer for the specified service's configuration parameters,
  6922. and retrieves those parameters into the buffer. The caller is responsible for freeing
  6923. the buffer.
  6924. Arguments:
  6925. ServiceHandle - supplies a handle to the service being queried
  6926. ServiceConfig - supplies the address of a QUERY_SERVICE_CONFIG pointer that receives
  6927. the address of the allocated buffer containing the requested information.
  6928. Return Value:
  6929. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error code.
  6930. Remarks:
  6931. The pointer whose address is contained in ServiceConfig is guaranteed to be NULL upon
  6932. return if any error occurred.
  6933. --*/
  6934. {
  6935. DWORD ServiceConfigSize = 0, Err;
  6936. MYASSERT(ServiceConfig);
  6937. *ServiceConfig = NULL;
  6938. while(TRUE) {
  6939. if(QueryServiceConfig(ServiceHandle, *ServiceConfig, ServiceConfigSize, &ServiceConfigSize)) {
  6940. MYASSERT(*ServiceConfig);
  6941. return NO_ERROR;
  6942. } else {
  6943. Err = GetLastError();
  6944. if(*ServiceConfig) {
  6945. MyFree(*ServiceConfig);
  6946. }
  6947. if(Err == ERROR_INSUFFICIENT_BUFFER) {
  6948. //
  6949. // Allocate a larger buffer, and try again.
  6950. //
  6951. if(!(*ServiceConfig = MyMalloc(ServiceConfigSize))) {
  6952. return ERROR_NOT_ENOUGH_MEMORY;
  6953. }
  6954. } else {
  6955. *ServiceConfig = NULL;
  6956. return Err;
  6957. }
  6958. }
  6959. }
  6960. }
  6961. #ifdef UNICODE
  6962. DWORD
  6963. RetrieveServiceConfig2(
  6964. IN SC_HANDLE ServiceHandle,
  6965. IN DWORD Level,
  6966. OUT LPBYTE *Buffer
  6967. )
  6968. /*++
  6969. Routine Description:
  6970. This routine allocates a buffer for the specified service's configuration parameters,
  6971. and retrieves those parameters into the buffer. The caller is responsible for freeing
  6972. the buffer.
  6973. Arguments:
  6974. ServiceHandle - supplies a handle to the service being queried
  6975. Level - specifies the information to query
  6976. Buffer - supplies the address of an opaque address to the buffer containing the info.
  6977. Return Value:
  6978. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error code.
  6979. Remarks:
  6980. The pointer whose address is contained in Buffer is guaranteed to be NULL upon
  6981. return if any error occurred.
  6982. --*/
  6983. {
  6984. DWORD ServiceConfigSize = 0, Err;
  6985. *Buffer = NULL;
  6986. while(TRUE) {
  6987. if(QueryServiceConfig2(ServiceHandle, Level, *Buffer, ServiceConfigSize, &ServiceConfigSize)) {
  6988. MYASSERT(*Buffer);
  6989. return NO_ERROR;
  6990. } else {
  6991. Err = GetLastError();
  6992. if(*Buffer) {
  6993. MyFree(*Buffer);
  6994. }
  6995. if(Err == ERROR_INSUFFICIENT_BUFFER) {
  6996. //
  6997. // Allocate a larger buffer, and try again.
  6998. //
  6999. if(!(*Buffer = MyMalloc(ServiceConfigSize))) {
  7000. return ERROR_NOT_ENOUGH_MEMORY;
  7001. }
  7002. } else {
  7003. *Buffer = NULL;
  7004. return Err;
  7005. }
  7006. }
  7007. }
  7008. }
  7009. #endif
  7010. DWORD
  7011. pSetupAddTagToGroupOrderListEntry(
  7012. IN PCTSTR LoadOrderGroup,
  7013. IN DWORD TagId,
  7014. IN BOOL MoveToFront
  7015. )
  7016. /*++
  7017. Routine Description:
  7018. This routine first creates the specified LoadOrderGroup value entry under
  7019. HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\GroupOrderList
  7020. if the value doesn't already exist. The routine then inserts the specified
  7021. tag into the list. If MoveToFront is TRUE, the tag is inserted at the front
  7022. of the list (or moved to the front of the list if it was already present in
  7023. the list). If MoveToFront is FALSE, then the new tag is inserted at the end
  7024. of the list, or left where it is if it already exists in the list.
  7025. Arguments:
  7026. LoadOrderGroup - Specifies the name of the LoadOrderGroup to insert this new
  7027. tag into.
  7028. TagId - Specifies the tag ID to be inserted into the list.
  7029. MoveToFront - If TRUE, place the tag at the front of the list. If FALSE, then
  7030. append the tag to the end of the list, unless it was already there, in which
  7031. case it is left where it was.
  7032. Return Value:
  7033. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error code.
  7034. --*/
  7035. {
  7036. DWORD Err;
  7037. HKEY hKey;
  7038. PDWORD GroupOrderList, p;
  7039. DWORD GroupOrderListSize, DataType, ExtraBytes, i, NumElements;
  7040. if((Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  7041. pszGroupOrderListPath,
  7042. 0,
  7043. KEY_ALL_ACCESS,
  7044. &hKey)) != ERROR_SUCCESS) {
  7045. return Err;
  7046. }
  7047. Err = QueryRegistryValue(hKey,
  7048. LoadOrderGroup,
  7049. (PVOID)(&GroupOrderList),
  7050. &DataType,
  7051. &GroupOrderListSize
  7052. );
  7053. if(Err == NO_ERROR) {
  7054. //
  7055. // Validate the list, and fix it if it's broken.
  7056. //
  7057. if(GroupOrderListSize < sizeof(DWORD)) {
  7058. if(GroupOrderList) {
  7059. MyFree(GroupOrderList);
  7060. }
  7061. if(GroupOrderList = MyMalloc(sizeof(DWORD))) {
  7062. *GroupOrderList = 0;
  7063. GroupOrderListSize = sizeof(DWORD);
  7064. } else {
  7065. Err = ERROR_NOT_ENOUGH_MEMORY;
  7066. goto clean0;
  7067. }
  7068. } else {
  7069. if(ExtraBytes = GroupOrderListSize % sizeof(DWORD)) {
  7070. if(p = MyRealloc(GroupOrderList, GroupOrderListSize + (sizeof(DWORD) - ExtraBytes))) {
  7071. GroupOrderList = p;
  7072. ZeroMemory((PBYTE)GroupOrderList + GroupOrderListSize, ExtraBytes);
  7073. GroupOrderListSize += ExtraBytes;
  7074. } else {
  7075. Err = ERROR_NOT_ENOUGH_MEMORY;
  7076. goto clean1;
  7077. }
  7078. }
  7079. }
  7080. MYASSERT(!(GroupOrderListSize % sizeof(DWORD)));
  7081. //
  7082. // We now have a list that's at least in the correct format. Now validate the list count,
  7083. // and adjust if necessary.
  7084. //
  7085. NumElements = (GroupOrderListSize / sizeof(DWORD)) - 1;
  7086. if(*GroupOrderList != NumElements) {
  7087. if(*GroupOrderList > NumElements) {
  7088. *GroupOrderList = NumElements;
  7089. } else {
  7090. NumElements = *GroupOrderList;
  7091. GroupOrderListSize = (NumElements + 1) * sizeof(DWORD);
  7092. }
  7093. }
  7094. } else {
  7095. //
  7096. // If we ran out of memory, then bail, otherwise, just assume
  7097. // there wasn't a list to retrieve.
  7098. //
  7099. if(Err == ERROR_NOT_ENOUGH_MEMORY) {
  7100. goto clean0;
  7101. } else {
  7102. //
  7103. // Allocate a list containing no tags.
  7104. //
  7105. if(GroupOrderList = MyMalloc(sizeof(DWORD))) {
  7106. *GroupOrderList = 0;
  7107. GroupOrderListSize = sizeof(DWORD);
  7108. } else {
  7109. Err = ERROR_NOT_ENOUGH_MEMORY;
  7110. goto clean0;
  7111. }
  7112. }
  7113. }
  7114. //
  7115. // Now we have a valid group order list to manipulate.
  7116. //
  7117. for(i = 0; i < *GroupOrderList; i++) {
  7118. if(GroupOrderList[i + 1] == TagId) {
  7119. //
  7120. // Tag already exists in the list.
  7121. //
  7122. break;
  7123. }
  7124. }
  7125. if(i == *GroupOrderList) {
  7126. //
  7127. // Then we didn't find the tag in the list. Add it either to the front, or
  7128. // the end, depending on the 'MoveToFront' flag.
  7129. //
  7130. if(p = MyRealloc(GroupOrderList, GroupOrderListSize + sizeof(DWORD))) {
  7131. GroupOrderList = p;
  7132. GroupOrderListSize += sizeof(DWORD);
  7133. } else {
  7134. Err = ERROR_NOT_ENOUGH_MEMORY;
  7135. goto clean1;
  7136. }
  7137. if(MoveToFront) {
  7138. MoveMemory(&(GroupOrderList[2]), &(GroupOrderList[1]), *GroupOrderList * sizeof(DWORD));
  7139. GroupOrderList[1] = TagId;
  7140. } else {
  7141. GroupOrderList[*GroupOrderList + 1] = TagId;
  7142. }
  7143. (*GroupOrderList)++;
  7144. } else if(MoveToFront && i) {
  7145. MoveMemory(&(GroupOrderList[2]), &(GroupOrderList[1]), i * sizeof(DWORD));
  7146. GroupOrderList[1] = TagId;
  7147. }
  7148. //
  7149. // Now write the value back to the registry.
  7150. //
  7151. Err = RegSetValueEx(hKey,
  7152. LoadOrderGroup,
  7153. 0,
  7154. REG_BINARY,
  7155. (PBYTE)GroupOrderList,
  7156. GroupOrderListSize
  7157. );
  7158. clean1:
  7159. MyFree(GroupOrderList);
  7160. clean0:
  7161. RegCloseKey(hKey);
  7162. return Err;
  7163. }
  7164. DWORD
  7165. pSetupRunLegacyInf(
  7166. IN DEVINST DevInst,
  7167. IN HWND OwnerWindow,
  7168. IN PCTSTR InfFileName,
  7169. IN PCTSTR InfOptionName,
  7170. IN PCTSTR InfLanguageName,
  7171. IN HINF InfHandle
  7172. )
  7173. /*++
  7174. Routine Description:
  7175. This routine build a command line, loads the legacy setup dll, and starts
  7176. the INF interpreter.
  7177. Arguments:
  7178. DevInst - supplies the CM device instance handle for the device being installed.
  7179. OwnerWindow - supplies the parent window for any UI that this INF generates.
  7180. InfFileName - supplies the name of the INF file to be interpreted.
  7181. InfOptionName - supplies the name of the INF section to execute.
  7182. InfLanguageName - supplies the name of the language the INF should use for any UI
  7183. (e.g., prompting, etc.)
  7184. InfHandle - supplies a handle to the legacy INF being installed from.
  7185. Return Value:
  7186. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error code.
  7187. Note that this says nothing about what the INF actually did, merely that we were
  7188. actually able to launch the INF.
  7189. --*/
  7190. {
  7191. HINSTANCE LegacySetupDllModule;
  7192. LEGACY_INF_INTERP_PROC pfnLegacyInfInterpret;
  7193. LEGACY_INF_GETSVCLIST_PROC pfnLegacyInfGetModifiedSvcList;
  7194. DWORD Err;
  7195. TCHAR TempBuffer[MAX_PATH];
  7196. PCTSTR LegacySourcePath;
  7197. PTSTR CmdLine, AssociatedService;
  7198. UINT CmdLineSize, BufSize;
  7199. PSTR AnsiLine;
  7200. PCSTR AnsiSourcePath;
  7201. PCSTR AnsiInfFileName;
  7202. BOOL b;
  7203. INT InterpResult;
  7204. CONFIGRET cr;
  7205. BOOL OnlyFreeSetupDllOnce = TRUE;
  7206. BOOL FreeSourceRoot;
  7207. DWORD InfSourceMediaType;
  7208. SPFUSIONINSTANCE spFusionInstance;
  7209. #ifdef UNICODE
  7210. CHAR AnsiBuffer[2*MAX_PATH]; // allow room for full Unicode->DBCS expansion,
  7211. // just to be on the safe side
  7212. #endif
  7213. spFusionEnterContext(NULL,&spFusionInstance);
  7214. if(!(LegacySetupDllModule = LoadLibrary(TEXT("SETUPDLL")))) {
  7215. spFusionLeaveContext(&spFusionInstance);
  7216. return GetLastError();
  7217. }
  7218. if(!(pfnLegacyInfInterpret =
  7219. (LEGACY_INF_INTERP_PROC)GetProcAddress(LegacySetupDllModule,
  7220. "LegacyInfInterpret"))) {
  7221. Err = GetLastError();
  7222. goto clean0;
  7223. }
  7224. if(!(pfnLegacyInfGetModifiedSvcList =
  7225. (LEGACY_INF_GETSVCLIST_PROC)GetProcAddress(LegacySetupDllModule,
  7226. "LegacyInfGetModifiedSvcList"))) {
  7227. Err = GetLastError();
  7228. goto clean0;
  7229. }
  7230. #ifdef UNICODE
  7231. //
  7232. // Convert the Unicode INF filename to ANSI
  7233. //
  7234. WideCharToMultiByte(CP_ACP,
  7235. 0,
  7236. InfFileName,
  7237. -1,
  7238. AnsiBuffer,
  7239. sizeof(AnsiBuffer),
  7240. NULL,
  7241. NULL
  7242. );
  7243. AnsiInfFileName = AnsiBuffer;
  7244. #else // else not UNICODE
  7245. //
  7246. // Filename is already ANSI--no conversion necessary.
  7247. //
  7248. AnsiInfFileName = InfFileName;
  7249. #endif // else not UNICODE
  7250. FreeSourceRoot = FALSE;
  7251. if(LegacySourcePath = pSetupGetDefaultSourcePath(InfHandle, SRCPATH_USEPNFINFORMATION, &InfSourceMediaType)) {
  7252. //
  7253. // If the INF is from the internet, just use the default OEM source path (A:\) instead.
  7254. //
  7255. if(InfSourceMediaType == SPOST_URL) {
  7256. MyFree(LegacySourcePath);
  7257. LegacySourcePath = NULL;
  7258. } else {
  7259. FreeSourceRoot = TRUE;
  7260. }
  7261. }
  7262. if(!LegacySourcePath) {
  7263. //
  7264. // Fall back to default OEM source path.
  7265. //
  7266. LegacySourcePath = pszOemInfDefaultPath;
  7267. }
  7268. //
  7269. // Build the command line to be passed to the legacy INF interpreter.
  7270. //
  7271. CmdLineSize = 1;
  7272. BufSize = 1024;
  7273. if(CmdLine = MyMalloc(BufSize * sizeof(TCHAR))) {
  7274. *CmdLine = TEXT('\0');
  7275. } else {
  7276. Err = ERROR_NOT_ENOUGH_MEMORY;
  7277. goto clean1;
  7278. }
  7279. if(!(CmdLine = pSetupCmdLineAppendString(CmdLine,
  7280. TEXT("STF_WINDOWSPATH"),
  7281. WindowsDirectory,
  7282. &CmdLineSize,
  7283. &BufSize))) {
  7284. Err = ERROR_NOT_ENOUGH_MEMORY;
  7285. goto clean1;
  7286. }
  7287. lstrcpyn(TempBuffer, WindowsDirectory, 3);
  7288. if(!(CmdLine = pSetupCmdLineAppendString(CmdLine,
  7289. TEXT("STF_NTDRIVE"),
  7290. TempBuffer,
  7291. &CmdLineSize,
  7292. &BufSize))) {
  7293. Err = ERROR_NOT_ENOUGH_MEMORY;
  7294. goto clean1;
  7295. }
  7296. if(!(CmdLine = pSetupCmdLineAppendString(CmdLine,
  7297. TEXT("STF_NTPATH"),
  7298. SystemDirectory,
  7299. &CmdLineSize,
  7300. &BufSize))) {
  7301. Err = ERROR_NOT_ENOUGH_MEMORY;
  7302. goto clean1;
  7303. }
  7304. if(!(CmdLine = pSetupCmdLineAppendString(CmdLine,
  7305. TEXT("STF_WINDOWSSYSPATH"),
  7306. SystemDirectory,
  7307. &CmdLineSize,
  7308. &BufSize))) {
  7309. Err = ERROR_NOT_ENOUGH_MEMORY;
  7310. goto clean1;
  7311. }
  7312. if(!(CmdLine = pSetupCmdLineAppendString(CmdLine,
  7313. TEXT("LEGACY_DODEVINSTALL"),
  7314. TEXT("YES"),
  7315. &CmdLineSize,
  7316. &BufSize))) {
  7317. Err = ERROR_NOT_ENOUGH_MEMORY;
  7318. goto clean1;
  7319. }
  7320. if(!(CmdLine = pSetupCmdLineAppendString(CmdLine,
  7321. TEXT("LEGACY_DI_LANG"),
  7322. InfLanguageName,
  7323. &CmdLineSize,
  7324. &BufSize))) {
  7325. Err = ERROR_NOT_ENOUGH_MEMORY;
  7326. goto clean1;
  7327. }
  7328. if(!(CmdLine = pSetupCmdLineAppendString(CmdLine,
  7329. TEXT("LEGACY_DI_OPTION"),
  7330. InfOptionName,
  7331. &CmdLineSize,
  7332. &BufSize))) {
  7333. Err = ERROR_NOT_ENOUGH_MEMORY;
  7334. goto clean1;
  7335. }
  7336. if(!(CmdLine = pSetupCmdLineAppendString(CmdLine,
  7337. TEXT("LEGACY_DI_SRCDIR"),
  7338. LegacySourcePath,
  7339. &CmdLineSize,
  7340. &BufSize))) {
  7341. Err = ERROR_NOT_ENOUGH_MEMORY;
  7342. goto clean1;
  7343. }
  7344. #ifdef UNICODE
  7345. //
  7346. // Allocate the correct amount of space for the ANSI version of the
  7347. // command line. Leave room for DBCS chars if there are any.
  7348. //
  7349. if(!(AnsiLine = MyMalloc(CmdLineSize * 2 * sizeof(CHAR)))) {
  7350. MyFree(CmdLine);
  7351. Err = ERROR_NOT_ENOUGH_MEMORY;
  7352. goto clean1;
  7353. }
  7354. //
  7355. // Convert the command line from UNICODE to ANSI
  7356. //
  7357. WideCharToMultiByte(CP_ACP,
  7358. 0,
  7359. CmdLine,
  7360. CmdLineSize,
  7361. AnsiLine,
  7362. 2 * CmdLineSize * sizeof(CHAR),
  7363. NULL,
  7364. NULL
  7365. );
  7366. MyFree(CmdLine);
  7367. //
  7368. // Convert the Unicode source path to ANSI.
  7369. //
  7370. if(!(AnsiSourcePath = pSetupUnicodeToAnsi(LegacySourcePath))) {
  7371. Err = ERROR_NOT_ENOUGH_MEMORY;
  7372. goto clean2;
  7373. }
  7374. if(FreeSourceRoot) {
  7375. MyFree(LegacySourcePath);
  7376. }
  7377. //
  7378. // Assign the new buffer back to LegacySourcePath, since that is the pointer that
  7379. // we will be freeing later.
  7380. //
  7381. LegacySourcePath = (PCTSTR)AnsiSourcePath;
  7382. //
  7383. // Regardless of whether or not the original source path needed to be freed, the new
  7384. // ANSI one will always need to be freed.
  7385. //
  7386. FreeSourceRoot = TRUE;
  7387. #else // else not UNICODE
  7388. //
  7389. // Since everything's already ANSI, no memory allocation/conversion is necessary.
  7390. //
  7391. AnsiLine = CmdLine;
  7392. AnsiSourcePath = LegacySourcePath;
  7393. #endif // else not UNICODE
  7394. //
  7395. // OK, now we're ready to call the old setup command line parser. (Do this within
  7396. // a try/except, in case setupdll falls over.)
  7397. //
  7398. try {
  7399. Err = pfnLegacyInfInterpret(OwnerWindow,
  7400. AnsiInfFileName,
  7401. "InstallOption",
  7402. AnsiLine,
  7403. (PSTR)TempBuffer,
  7404. sizeof(TempBuffer),
  7405. &InterpResult,
  7406. AnsiSourcePath)
  7407. ? NO_ERROR
  7408. : ERROR_NOT_ENOUGH_MEMORY;
  7409. } except(EXCEPTION_EXECUTE_HANDLER) {
  7410. Err = (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? ERROR_INVALID_DATA : ERROR_READ_FAULT;
  7411. }
  7412. if(Err == NO_ERROR) {
  7413. //
  7414. // We successfully ran the interpreter, so we know that we need to loop on a call to
  7415. // FreeLibrary until setupdll goes away.
  7416. //
  7417. OnlyFreeSetupDllOnce = FALSE;
  7418. } else {
  7419. goto clean2;
  7420. }
  7421. //
  7422. // The interpreter successfully ran the INF. Now we need to find out what the result was.
  7423. //
  7424. // NOTE: It seems that most legacy INFs aren't very good about distinguishing between
  7425. // SETUP_ERROR_USERCANCEL and SETUP_ERROR_GENERAL. Therefore, we can't reliably set
  7426. // our error to indicate that the user cancelled (as opposed to some other INF problem).
  7427. // Since almost all of the failures we'll encounter are because the user cancelled, we
  7428. // simply lump both these errors into the same category, and return ERROR_CANCELLED in
  7429. // both cases.
  7430. //
  7431. if(InterpResult != SETUP_ERROR_SUCCESS) {
  7432. Err = ERROR_CANCELLED;
  7433. goto clean2;
  7434. }
  7435. //
  7436. // We successfully installed the legacy INF option. Now we need to find out what services
  7437. // got installed as a result of this, so that we can associate the device instance we're
  7438. // installing with its controlling service.
  7439. //
  7440. try {
  7441. Err = pfnLegacyInfGetModifiedSvcList(NULL, 0, &BufSize);
  7442. } except(EXCEPTION_EXECUTE_HANDLER) {
  7443. Err = ERROR_NO_MORE_ITEMS;
  7444. }
  7445. //
  7446. // Since we didn't pass this routine a buffer, then it should always fail.
  7447. //
  7448. MYASSERT(Err != NO_ERROR);
  7449. if(Err == ERROR_NO_MORE_ITEMS) {
  7450. //
  7451. // No service modifications were performed by this INF. This may be OK, since there may
  7452. // be a default service for this device's class. Consider our legacy INF installation a
  7453. // success (at least, for now).
  7454. //
  7455. Err = NO_ERROR;
  7456. goto clean2;
  7457. }
  7458. MYASSERT(Err == ERROR_INSUFFICIENT_BUFFER); // the only other reason we should be failing.
  7459. //
  7460. // Allocate a buffer of the size necessary, and call this routine again to retrieve the service
  7461. // list. (Re-use AnsiLine to store the ANSI multi-sz list.)
  7462. //
  7463. MyFree(AnsiLine);
  7464. if(!(AnsiLine = MyMalloc(BufSize * sizeof(CHAR)))) {
  7465. Err = ERROR_NOT_ENOUGH_MEMORY;
  7466. goto clean2;
  7467. }
  7468. try {
  7469. Err = pfnLegacyInfGetModifiedSvcList(AnsiLine, BufSize, &BufSize);
  7470. } except(EXCEPTION_EXECUTE_HANDLER) {
  7471. Err = ERROR_NO_MORE_ITEMS;
  7472. }
  7473. if(Err != NO_ERROR) {
  7474. //
  7475. // The only time this should ever happen is if we hit an exception in setupdll.
  7476. // We'll ignore the error.
  7477. //
  7478. Err = NO_ERROR;
  7479. goto clean2;
  7480. }
  7481. #ifdef UNICODE
  7482. //
  7483. // Convert this multi-sz list to Unicode.
  7484. //
  7485. if(!(CmdLine = MyMalloc(BufSize * sizeof(WCHAR)))) {
  7486. Err = ERROR_NOT_ENOUGH_MEMORY;
  7487. goto clean2;
  7488. }
  7489. if(!MultiByteToWideChar(CP_ACP,
  7490. MB_PRECOMPOSED,
  7491. AnsiLine,
  7492. BufSize * sizeof(CHAR),
  7493. CmdLine,
  7494. BufSize)) {
  7495. Err = GetLastError();
  7496. MyFree(CmdLine);
  7497. goto clean2;
  7498. }
  7499. //
  7500. // Free the ANSI buffer, and set it equal to the Unicode one, so that we can free the same
  7501. // memory in both the ANSI and Unicode cases.
  7502. //
  7503. MyFree(AnsiLine);
  7504. AnsiLine = (PSTR)CmdLine;
  7505. #else // else not UNICODE
  7506. //
  7507. // We're not Unicode, so the ANSI list we have is just fine.
  7508. //
  7509. CmdLine = AnsiLine;
  7510. #endif // else not UNICODE
  7511. //
  7512. // OK, we now have the proper TCHAR-ized form of the multi-sz list. Process the services
  7513. // listed therein, and return the one that should be associated with this device instance.
  7514. //
  7515. if(AssociatedService = DoServiceModsForLegacyInf(CmdLine)) {
  7516. //
  7517. // Make the association between the service and the device.
  7518. //
  7519. if((cr = CM_Set_DevInst_Registry_Property(DevInst,
  7520. CM_DRP_SERVICE,
  7521. AssociatedService,
  7522. (lstrlen(AssociatedService) + 1) * sizeof(TCHAR),
  7523. 0)) != CR_SUCCESS) {
  7524. if(cr == CR_INVALID_DEVINST) {
  7525. Err = ERROR_NO_SUCH_DEVINST;
  7526. } else {
  7527. Err = ERROR_INVALID_DATA;
  7528. }
  7529. }
  7530. }
  7531. clean2:
  7532. if(AnsiLine) {
  7533. MyFree(AnsiLine);
  7534. }
  7535. clean1:
  7536. if(FreeSourceRoot) {
  7537. MyFree(LegacySourcePath);
  7538. }
  7539. clean0:
  7540. //
  7541. // Clean up
  7542. //
  7543. while(GetModuleFileName(LegacySetupDllModule, TempBuffer, SIZECHARS(TempBuffer))) {
  7544. FreeLibrary(LegacySetupDllModule);
  7545. if(OnlyFreeSetupDllOnce) {
  7546. break;
  7547. }
  7548. }
  7549. spFusionLeaveContext(&spFusionInstance);
  7550. return Err;
  7551. }
  7552. PTSTR
  7553. pSetupCmdLineAppendString(
  7554. IN PTSTR CmdLine,
  7555. IN PCTSTR Key,
  7556. IN PCTSTR Value, OPTIONAL
  7557. IN OUT PUINT StrLen,
  7558. IN OUT PUINT BufSize
  7559. )
  7560. /*++
  7561. Routine Description:
  7562. Forms a new (multi-sz) command line by appending a list of arguments to
  7563. the current command line. For example:
  7564. CmdLine = SpSetupCmdLineAppendString(
  7565. CmdLine,
  7566. "STF_PRODUCT",
  7567. "NTWKSTA"
  7568. );
  7569. would append "STF_PRODUCT\0NTWKSTA\0\0" to CmdLine.
  7570. Arguments:
  7571. CmdLine - Original CmdLine, to be appended to. THIS BUFFER MUST CONTAIN
  7572. AT LEAST A SINGLE NULL CHARACTER!
  7573. Key - Key identifier
  7574. Value - Value of Key
  7575. StrLen - How long the current string in -- save on strlens
  7576. BufSize - Size of Current Buffer
  7577. Returns:
  7578. Pointer to the new string, or NULL if out-of-memory (in that case, the
  7579. original CmdLine buffer is freed).
  7580. --*/
  7581. {
  7582. PTSTR Ptr;
  7583. UINT NewLen;
  7584. //
  7585. // Handle special cases so we don't end up with empty strings.
  7586. //
  7587. if(!Value || !(*Value)) {
  7588. Value = TEXT("\"\"");
  7589. }
  7590. //
  7591. // "\0" -> 1 chars
  7592. // "\0\0" -> 2 char
  7593. // but we have to back up 1 character...
  7594. //
  7595. NewLen = (*StrLen + 2 + lstrlen(Key) + lstrlen(Value));
  7596. //
  7597. // Allocate more space if necessary.
  7598. //
  7599. if(NewLen >= *BufSize) {
  7600. //
  7601. // Grow the current buffer
  7602. //
  7603. *BufSize += 1024;
  7604. if(Ptr = MyRealloc(CmdLine, (*BufSize) * sizeof(TCHAR))) {
  7605. CmdLine = Ptr;
  7606. } else {
  7607. //
  7608. // Free the memory here so the caller doesn't have to worry about it.
  7609. //
  7610. MyFree(CmdLine);
  7611. return NULL;
  7612. }
  7613. }
  7614. Ptr = &(CmdLine[*StrLen-1]);
  7615. lstrcpy(Ptr, Key);
  7616. Ptr = &(CmdLine[*StrLen+lstrlen(Key)]);
  7617. lstrcpy(Ptr, Value);
  7618. CmdLine[NewLen-1] = TEXT('\0');
  7619. //
  7620. // Update the length of the buffer that we are using
  7621. //
  7622. *StrLen = NewLen;
  7623. return CmdLine;
  7624. }
  7625. PTSTR
  7626. DoServiceModsForLegacyInf(
  7627. IN PTSTR ServiceList
  7628. )
  7629. /*++
  7630. Routine Description:
  7631. This routine processes the multi-sz list of service names it is given as
  7632. input, ensuring that each one is tagged appropriately. It also keeps track
  7633. of which one is the first to load, based on its start type and membership in
  7634. one of the load order groups listed under HKLM\System\CCS\Control\ServiceGroupOrder.
  7635. The one that is first to load is returned.
  7636. Arguments:
  7637. ServiceList - supplies the address of a character buffer containing a
  7638. multi-sz list of service names to be processed.
  7639. Returns:
  7640. Pointer to the service within the list that should be associated with the
  7641. device instance, or NULL if we don't find a suitable service.
  7642. --*/
  7643. {
  7644. PTSTR CurServiceName, ServiceGroupOrderList, CurGroupName;
  7645. DWORD ServiceGroupIndex;
  7646. TCHAR NullChar;
  7647. DWORD RegDataType, RegDataSize;
  7648. PTSTR AssocServiceName = NULL;
  7649. SC_HANDLE SCMHandle, ServiceHandle;
  7650. SC_LOCK SCLock;
  7651. LPQUERY_SERVICE_CONFIG ServiceConfig;
  7652. DWORD NewTag;
  7653. DWORD AssocStartType = SERVICE_DISABLED;
  7654. DWORD AssocGroupIndex = DWORD_MAX;
  7655. HKEY hKey;
  7656. if(!(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  7657. return NULL;
  7658. }
  7659. //
  7660. // Retrieve the 'List' multi-sz value entry under HKLM\System\CCS\Control\ServiceGroupOrder.
  7661. //
  7662. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, pszServiceGroupOrderPath, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
  7663. if(QueryRegistryValue(hKey, TEXT("List"), &ServiceGroupOrderList, &RegDataType, &RegDataSize) != NO_ERROR) {
  7664. //
  7665. // Couldn't retrieve the list--set up an empty list.
  7666. //
  7667. NullChar = TEXT('\0');
  7668. ServiceGroupOrderList = &NullChar;
  7669. } else {
  7670. //
  7671. // If the value entry was present, but zero-length, then setup an
  7672. // emtpy list.
  7673. //
  7674. if(!ServiceGroupOrderList) {
  7675. NullChar = TEXT('\0');
  7676. ServiceGroupOrderList = &NullChar;
  7677. }
  7678. }
  7679. RegCloseKey(hKey);
  7680. } else {
  7681. //
  7682. // Couldn't open the ServiceGroupOrder key--set up an empty list.
  7683. //
  7684. NullChar = TEXT('\0');
  7685. ServiceGroupOrderList = &NullChar;
  7686. }
  7687. for(CurServiceName = ServiceList;
  7688. *CurServiceName;
  7689. CurServiceName += (lstrlen(CurServiceName) + 1)) {
  7690. //
  7691. // Open this service.
  7692. //
  7693. if(!(ServiceHandle = OpenService(SCMHandle, CurServiceName, SERVICE_ALL_ACCESS))) {
  7694. //
  7695. // We couldn't access the service--possibly because it doesn't exist anymore.
  7696. // Continue on with the next service.
  7697. //
  7698. continue;
  7699. }
  7700. //
  7701. // Now retrieve the configuration for this service.
  7702. //
  7703. if(pSetupRetrieveServiceConfig(ServiceHandle, &ServiceConfig) != NO_ERROR) {
  7704. //
  7705. // There's not a lot we can do without knowing the service's configuration,
  7706. // either. Again, we'll just skip this service and continue with the next one.
  7707. //
  7708. goto clean0;
  7709. }
  7710. //
  7711. // If this service is marked as disabled, then we don't care about it.
  7712. //
  7713. if(ServiceConfig->dwStartType == SERVICE_DISABLED) {
  7714. goto clean1;
  7715. }
  7716. //
  7717. // If this service has a load order group, and is a kernel or filesystem
  7718. // driver, then make sure that it has a tag.
  7719. //
  7720. if(ServiceConfig->lpLoadOrderGroup && *(ServiceConfig->lpLoadOrderGroup) &&
  7721. (ServiceConfig->dwServiceType & (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER))) {
  7722. //
  7723. // This service needs a tag--does it have one???
  7724. //
  7725. if(!(NewTag = ServiceConfig->dwTagId)) {
  7726. //
  7727. // Attempt to lock the service database before generating a tag. We'll go ahead
  7728. // and make the change, even if this fails.
  7729. //
  7730. pAcquireSCMLock(SCMHandle, &SCLock, NULL);
  7731. if(!ChangeServiceConfig(ServiceHandle,
  7732. SERVICE_NO_CHANGE,
  7733. SERVICE_NO_CHANGE,
  7734. SERVICE_NO_CHANGE,
  7735. NULL,
  7736. ServiceConfig->lpLoadOrderGroup, // have to specify this to generate new tag.
  7737. &NewTag,
  7738. NULL,
  7739. NULL,
  7740. NULL,
  7741. NULL)) {
  7742. NewTag = 0;
  7743. }
  7744. if(SCLock) {
  7745. UnlockServiceDatabase(SCLock);
  7746. }
  7747. }
  7748. //
  7749. // Make sure that the tag exists in the service's corresponding GroupOrderList entry.
  7750. //
  7751. if(NewTag) {
  7752. pSetupAddTagToGroupOrderListEntry(ServiceConfig->lpLoadOrderGroup, NewTag, FALSE);
  7753. }
  7754. }
  7755. //
  7756. // Determine the index that this service's load group occupies in the multi-sz ServiceGroupOrder
  7757. // list we retrieved above.
  7758. //
  7759. if(ServiceConfig->lpLoadOrderGroup) {
  7760. for(CurGroupName = ServiceGroupOrderList, ServiceGroupIndex = 0;
  7761. *CurGroupName;
  7762. CurGroupName += (lstrlen(CurGroupName) + 1), ServiceGroupIndex++) {
  7763. if(!lstrcmpi(CurGroupName, ServiceConfig->lpLoadOrderGroup)) {
  7764. break;
  7765. }
  7766. }
  7767. if(!(*CurGroupName)) {
  7768. //
  7769. // Then we didn't find this group in our list--give it the maximum index value.
  7770. //
  7771. ServiceGroupIndex = DWORD_MAX;
  7772. }
  7773. } else {
  7774. //
  7775. // This service isn't a member of a group--give it the maximum index value.
  7776. //
  7777. ServiceGroupIndex = DWORD_MAX;
  7778. }
  7779. //
  7780. // Finally, determine if this service loads before any services we've encountered so far,
  7781. // and if so, then make it our new choice for associated service.
  7782. //
  7783. if(ServiceConfig->dwStartType < AssocStartType) {
  7784. //
  7785. // Then this service loads in an earlier load phase, so we're guaranteed it loads before
  7786. // any drivers we've previously seen.
  7787. //
  7788. AssocServiceName = CurServiceName;
  7789. AssocStartType = ServiceConfig->dwStartType;
  7790. AssocGroupIndex = ServiceGroupIndex;
  7791. } else if(ServiceConfig->dwStartType == AssocStartType) {
  7792. //
  7793. // This service starts in the same load phase as the current selection, so we need to
  7794. // compare the group load order indices to see if this one comes earlier.
  7795. //
  7796. if(ServiceGroupIndex < AssocGroupIndex) {
  7797. AssocServiceName = CurServiceName;
  7798. AssocGroupIndex = ServiceGroupIndex;
  7799. }
  7800. }
  7801. clean1:
  7802. MyFree(ServiceConfig);
  7803. clean0:
  7804. CloseServiceHandle(ServiceHandle);
  7805. }
  7806. if(ServiceGroupOrderList != &NullChar) {
  7807. MyFree(ServiceGroupOrderList);
  7808. }
  7809. CloseServiceHandle(SCMHandle);
  7810. return AssocServiceName;
  7811. }
  7812. #ifdef UNICODE
  7813. //
  7814. // ANSI version
  7815. //
  7816. BOOL
  7817. WINAPI
  7818. SetupDiGetActualSectionToInstallA(
  7819. IN HINF InfHandle,
  7820. IN PCSTR InfSectionName,
  7821. OUT PSTR InfSectionWithExt, OPTIONAL
  7822. IN DWORD InfSectionWithExtSize,
  7823. OUT PDWORD RequiredSize, OPTIONAL
  7824. OUT PSTR *Extension OPTIONAL
  7825. )
  7826. {
  7827. return SetupDiGetActualSectionToInstallExA(InfHandle,
  7828. InfSectionName,
  7829. NULL,
  7830. InfSectionWithExt,
  7831. InfSectionWithExtSize,
  7832. RequiredSize,
  7833. Extension,
  7834. NULL
  7835. );
  7836. }
  7837. #else
  7838. //
  7839. // Unicode stub
  7840. //
  7841. BOOL
  7842. WINAPI
  7843. SetupDiGetActualSectionToInstallW(
  7844. IN HINF InfHandle,
  7845. IN PCWSTR InfSectionName,
  7846. OUT PWSTR InfSectionWithExt, OPTIONAL
  7847. IN DWORD InfSectionWithExtSize,
  7848. OUT PDWORD RequiredSize, OPTIONAL
  7849. OUT PWSTR *Extension OPTIONAL
  7850. )
  7851. {
  7852. UNREFERENCED_PARAMETER(InfHandle);
  7853. UNREFERENCED_PARAMETER(InfSectionName);
  7854. UNREFERENCED_PARAMETER(InfSectionWithExt);
  7855. UNREFERENCED_PARAMETER(InfSectionWithExtSize);
  7856. UNREFERENCED_PARAMETER(RequiredSize);
  7857. UNREFERENCED_PARAMETER(Extension);
  7858. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  7859. return(FALSE);
  7860. }
  7861. #endif
  7862. BOOL
  7863. WINAPI
  7864. SetupDiGetActualSectionToInstall(
  7865. IN HINF InfHandle,
  7866. IN PCTSTR InfSectionName,
  7867. OUT PTSTR InfSectionWithExt, OPTIONAL
  7868. IN DWORD InfSectionWithExtSize,
  7869. OUT PDWORD RequiredSize, OPTIONAL
  7870. OUT PTSTR *Extension OPTIONAL
  7871. )
  7872. /*++
  7873. Routine Description:
  7874. (See description of SetupDiGetActualSectionToInstallEx)
  7875. --*/
  7876. {
  7877. return SetupDiGetActualSectionToInstallEx(InfHandle,
  7878. InfSectionName,
  7879. NULL,
  7880. InfSectionWithExt,
  7881. InfSectionWithExtSize,
  7882. RequiredSize,
  7883. Extension,
  7884. NULL
  7885. );
  7886. }
  7887. #ifdef UNICODE
  7888. //
  7889. // ANSI version
  7890. //
  7891. BOOL
  7892. WINAPI
  7893. SetupDiGetActualSectionToInstallExA(
  7894. IN HINF InfHandle,
  7895. IN PCSTR InfSectionName,
  7896. IN PSP_ALTPLATFORM_INFO_V2 AlternatePlatformInfo, OPTIONAL
  7897. OUT PSTR InfSectionWithExt, OPTIONAL
  7898. IN DWORD InfSectionWithExtSize,
  7899. OUT PDWORD RequiredSize, OPTIONAL
  7900. OUT PSTR *Extension, OPTIONAL
  7901. IN PVOID Reserved
  7902. )
  7903. {
  7904. PWSTR infsectionname;
  7905. DWORD rc;
  7906. BOOL b;
  7907. PWSTR extension;
  7908. UINT CharOffset,i;
  7909. PSTR p;
  7910. DWORD requiredsize;
  7911. WCHAR newsection[MAX_SECT_NAME_LEN];
  7912. PSTR ansi;
  7913. rc = pSetupCaptureAndConvertAnsiArg(InfSectionName,&infsectionname);
  7914. if(rc != NO_ERROR) {
  7915. SetLastError(rc);
  7916. return(FALSE);
  7917. }
  7918. b = SetupDiGetActualSectionToInstallExW(
  7919. InfHandle,
  7920. infsectionname,
  7921. AlternatePlatformInfo,
  7922. newsection,
  7923. MAX_SECT_NAME_LEN,
  7924. &requiredsize,
  7925. &extension,
  7926. Reserved
  7927. );
  7928. rc = GetLastError();
  7929. if(b) {
  7930. if(ansi = pSetupUnicodeToAnsi(newsection)) {
  7931. requiredsize = lstrlenA(ansi)+1;
  7932. if(RequiredSize) {
  7933. try {
  7934. *RequiredSize = requiredsize;
  7935. } except(EXCEPTION_EXECUTE_HANDLER) {
  7936. rc = ERROR_INVALID_PARAMETER;
  7937. b = FALSE;
  7938. }
  7939. }
  7940. if(b && InfSectionWithExt) {
  7941. if(requiredsize <= InfSectionWithExtSize) {
  7942. if(!lstrcpyA(InfSectionWithExt,ansi)) {
  7943. //
  7944. // lstrcpy faulted, so InfSectionWithExt must be bad
  7945. //
  7946. rc = ERROR_INVALID_PARAMETER;
  7947. b = FALSE;
  7948. }
  7949. } else {
  7950. rc = ERROR_INSUFFICIENT_BUFFER;
  7951. b = FALSE;
  7952. }
  7953. }
  7954. if(b && Extension) {
  7955. if(extension && InfSectionWithExt) {
  7956. //
  7957. // We need to figure out where the extension is
  7958. // in the converted string. To be DBCS safe we will
  7959. // count characters forward to find it.
  7960. //
  7961. CharOffset = (UINT)(extension - newsection);
  7962. p = InfSectionWithExt;
  7963. for(i=0; i<CharOffset; i++) {
  7964. p = CharNextA(p);
  7965. }
  7966. } else {
  7967. p = NULL;
  7968. }
  7969. try {
  7970. *Extension = p;
  7971. } except(EXCEPTION_EXECUTE_HANDLER) {
  7972. b = FALSE;
  7973. rc = ERROR_INVALID_PARAMETER;
  7974. }
  7975. }
  7976. MyFree(ansi);
  7977. } else {
  7978. rc = ERROR_NOT_ENOUGH_MEMORY;
  7979. b = FALSE;
  7980. }
  7981. }
  7982. MyFree(infsectionname);
  7983. SetLastError(rc);
  7984. return(b);
  7985. }
  7986. #else
  7987. //
  7988. // Unicode stub
  7989. //
  7990. BOOL
  7991. WINAPI
  7992. SetupDiGetActualSectionToInstallExW(
  7993. IN HINF InfHandle,
  7994. IN PCWSTR InfSectionName,
  7995. IN PSP_ALTPLATFORM_INFO_V2 AlternatePlatformInfo, OPTIONAL
  7996. OUT PWSTR InfSectionWithExt, OPTIONAL
  7997. IN DWORD InfSectionWithExtSize,
  7998. OUT PDWORD RequiredSize, OPTIONAL
  7999. OUT PWSTR *Extension, OPTIONAL
  8000. IN PVOID Reserved
  8001. )
  8002. {
  8003. UNREFERENCED_PARAMETER(InfHandle);
  8004. UNREFERENCED_PARAMETER(InfSectionName);
  8005. UNREFERENCED_PARAMETER(AlternatePlatformInfo);
  8006. UNREFERENCED_PARAMETER(InfSectionWithExt);
  8007. UNREFERENCED_PARAMETER(InfSectionWithExtSize);
  8008. UNREFERENCED_PARAMETER(RequiredSize);
  8009. UNREFERENCED_PARAMETER(Extension);
  8010. UNREFERENCED_PARAMETER(Reserved);
  8011. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  8012. return(FALSE);
  8013. }
  8014. #endif
  8015. BOOL
  8016. WINAPI
  8017. SetupDiGetActualSectionToInstallEx(
  8018. IN HINF InfHandle,
  8019. IN PCTSTR InfSectionName,
  8020. IN PSP_ALTPLATFORM_INFO_V2 AlternatePlatformInfo, OPTIONAL
  8021. OUT PTSTR InfSectionWithExt, OPTIONAL
  8022. IN DWORD InfSectionWithExtSize,
  8023. OUT PDWORD RequiredSize, OPTIONAL
  8024. OUT PTSTR *Extension, OPTIONAL
  8025. IN PVOID Reserved
  8026. )
  8027. /*++
  8028. Routine Description:
  8029. This API finds the appropriate install section to be used when installing
  8030. a device from a Win95-style device INF. Refer to the documentation for
  8031. SetupDiInstallDevice for details on how this determination is made.
  8032. Arguments:
  8033. InfHandle - Supplies the handle of the INF to be installed from.
  8034. InfSectionName - Supplies the name of the install section, as specified by
  8035. the driver node being installed.
  8036. AlternatePlatformInfo - Optionally, supplies alternate platform information
  8037. to be used in selecting the section. Presently, only the Platform and
  8038. ProcessorArchitecture fields are used in formulating the section
  8039. decoration. (NOTE: caller may actually pass in a V1 struct instead--
  8040. this is fine, as the fields we care about are shared in common between
  8041. the V1 and V2 structs.)
  8042. InfSectionWithExt - Optionally, supplies the address of a character buffer
  8043. that receives the actual install section name that should be used
  8044. during installation. If this parameter is NULL, then
  8045. InfSectionWithExtSize must be zero. In that case, the caller is only
  8046. interested in retrieving the required buffer size, so the API will
  8047. return TRUE, and RequiredSize (if supplied), will be set to the size,
  8048. in characters, necessary to store the actual install section name.
  8049. InfSectionWithExtSize - Supplies the size, in characters, of the
  8050. InfSectionWithExt buffer.
  8051. RequiredSize - Optionally, supplies the address of a variable that receives
  8052. the size, in characters, required to store the actual install section
  8053. name (including terminating NULL).
  8054. Extension - Optionally, supplies the address of a variable that receives a
  8055. pointer to the extension (including '.'), or NULL if no extension is to
  8056. be used. The pointer points to the extension within the caller-
  8057. supplied buffer. If the InfSectionWithExt buffer is not supplied, then
  8058. this variable will not be filled in.
  8059. Reserved - Must be NULL.
  8060. Returns:
  8061. If the function succeeds, the return value is TRUE.
  8062. If the function fails, the return value is FALSE. To get extended error
  8063. information, call GetLastError.
  8064. Remarks:
  8065. Presently, the only possible failures are ERROR_INVALID_PARAMETER
  8066. (bad caller-supplied pointers), and ERROR_INSUFFICIENT_BUFFER (if the
  8067. caller-supplied buffer isn't large enough). If we fall back to the
  8068. baseline (i.e., non-decorated) section name, then we simply return it,
  8069. without verifying that the section actually exists.
  8070. --*/
  8071. {
  8072. TCHAR TempInfSectionName[MAX_SECT_NAME_LEN];
  8073. DWORD SectionNameLen = (DWORD)lstrlen(InfSectionName);
  8074. DWORD ExtBufferLen;
  8075. BOOL ExtFound = TRUE;
  8076. DWORD Err = NO_ERROR;
  8077. DWORD Platform;
  8078. PCTSTR NtArchSuffix;
  8079. DWORD NtArchSuffixSize;
  8080. if(Reserved) {
  8081. SetLastError(ERROR_INVALID_PARAMETER);
  8082. return FALSE;
  8083. }
  8084. if(SectionNameLen >= MAX_SECT_NAME_LEN) {
  8085. SetLastError(ERROR_SECTION_NAME_TOO_LONG);
  8086. return FALSE;
  8087. }
  8088. //
  8089. // Both V1 and V2 SP_ALTPLATFORM_INFO structures share a common layout for
  8090. // the first 6 fields (including Platform and ProcessorArchitecture, which
  8091. // are the ones we're interested in here). Thus, all we need to do is
  8092. // verify that the cbSize field is one of the two valid values.
  8093. //
  8094. if(AlternatePlatformInfo) {
  8095. if((AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO_V2)) &&
  8096. (AlternatePlatformInfo->cbSize != sizeof(SP_ALTPLATFORM_INFO_V1))) {
  8097. SetLastError(ERROR_INVALID_PARAMETER);
  8098. return FALSE;
  8099. }
  8100. }
  8101. CopyMemory(TempInfSectionName, InfSectionName, SectionNameLen * sizeof(TCHAR));
  8102. Platform = AlternatePlatformInfo ? AlternatePlatformInfo->Platform
  8103. : OSVersionInfo.dwPlatformId;
  8104. if(Platform == VER_PLATFORM_WIN32_NT) {
  8105. //
  8106. // We're running on NT, so first try the NT architecture-specific
  8107. // extension, then the generic NT extension.
  8108. //
  8109. if(AlternatePlatformInfo) {
  8110. switch(AlternatePlatformInfo->ProcessorArchitecture) {
  8111. case PROCESSOR_ARCHITECTURE_INTEL :
  8112. NtArchSuffix = pszNtX86Suffix;
  8113. NtArchSuffixSize = sizeof(pszNtX86Suffix);
  8114. break;
  8115. case PROCESSOR_ARCHITECTURE_ALPHA :
  8116. NtArchSuffix = pszNtAlphaSuffix;
  8117. NtArchSuffixSize = sizeof(pszNtAlphaSuffix);
  8118. break;
  8119. case PROCESSOR_ARCHITECTURE_IA64 :
  8120. NtArchSuffix = pszNtIA64Suffix;
  8121. NtArchSuffixSize = sizeof(pszNtIA64Suffix);
  8122. break;
  8123. case PROCESSOR_ARCHITECTURE_ALPHA64 :
  8124. NtArchSuffix = pszNtAXP64Suffix;
  8125. NtArchSuffixSize = sizeof(pszNtAXP64Suffix);
  8126. break;
  8127. case PROCESSOR_ARCHITECTURE_AMD64 :
  8128. NtArchSuffix = pszNtAMD64Suffix;
  8129. NtArchSuffixSize = sizeof(pszNtAMD64Suffix);
  8130. break;
  8131. default:
  8132. //
  8133. // Unknown/invalid architecture
  8134. //
  8135. SetLastError(ERROR_INVALID_PARAMETER);
  8136. return FALSE;
  8137. }
  8138. } else {
  8139. NtArchSuffix = pszNtPlatformSuffix;
  8140. NtArchSuffixSize = sizeof(pszNtPlatformSuffix);
  8141. }
  8142. if(NtArchSuffixSize <=
  8143. sizeof(TempInfSectionName) - (SectionNameLen * sizeof(TCHAR))) {
  8144. CopyMemory(&(TempInfSectionName[SectionNameLen]),
  8145. NtArchSuffix,
  8146. NtArchSuffixSize
  8147. );
  8148. if(SetupGetLineCount(InfHandle, TempInfSectionName) != -1) {
  8149. goto clean0;
  8150. }
  8151. //
  8152. // We know the ".NT" suffix is always guaranteed to be shorter than
  8153. // any of the ".NT<architecture>" suffixes, thus we know this will
  8154. // fit in our MAX_SECT_NAME_LEN buffer. (Note: if the OS/arch.
  8155. // decoration is too big, then we won't even try the simple OS
  8156. // decoration. To do otherwise might be misleading, as we'd select
  8157. // a "<reallylongsectionname>.NT" section, even though the INF
  8158. // (erroneously) contains a "<reallylongsectionname>.NTx86" section
  8159. // that doesn't fit.)
  8160. //
  8161. CopyMemory(&(TempInfSectionName[SectionNameLen]),
  8162. pszNtSuffix,
  8163. sizeof(pszNtSuffix)
  8164. );
  8165. if(SetupGetLineCount(InfHandle, TempInfSectionName) != -1) {
  8166. goto clean0;
  8167. }
  8168. }
  8169. } else {
  8170. //
  8171. // We're running on Windows 95, so try the Windows-specific extension
  8172. //
  8173. if(sizeof(pszWinSuffix) <=
  8174. sizeof(TempInfSectionName) - (SectionNameLen * sizeof(TCHAR))) {
  8175. CopyMemory(&(TempInfSectionName[SectionNameLen]),
  8176. pszWinSuffix,
  8177. sizeof(pszWinSuffix)
  8178. );
  8179. if(SetupGetLineCount(InfHandle, TempInfSectionName) != -1) {
  8180. goto clean0;
  8181. }
  8182. }
  8183. }
  8184. //
  8185. // If we get to here, then we found no applicable extensions. We'll just use
  8186. // the install section specified.
  8187. //
  8188. TempInfSectionName[SectionNameLen] = TEXT('\0');
  8189. ExtFound = FALSE;
  8190. clean0:
  8191. //
  8192. // Now, determine whether the caller-supplied buffer is large enough to contain
  8193. // the section name.
  8194. //
  8195. ExtBufferLen = lstrlen(TempInfSectionName) + 1;
  8196. //
  8197. // Guard the rest of the routine in try/except, since we're dealing with caller-supplied
  8198. // memory.
  8199. //
  8200. try {
  8201. if(RequiredSize) {
  8202. *RequiredSize = ExtBufferLen;
  8203. }
  8204. if(InfSectionWithExt) {
  8205. if(ExtBufferLen > InfSectionWithExtSize) {
  8206. Err = ERROR_INSUFFICIENT_BUFFER;
  8207. } else {
  8208. CopyMemory(InfSectionWithExt, TempInfSectionName, ExtBufferLen * sizeof(TCHAR));
  8209. if(Extension) {
  8210. *Extension = ExtFound ? InfSectionWithExt + SectionNameLen : NULL;
  8211. }
  8212. }
  8213. }
  8214. } except(EXCEPTION_EXECUTE_HANDLER) {
  8215. Err = ERROR_INVALID_PARAMETER;
  8216. }
  8217. SetLastError(Err);
  8218. return (Err == NO_ERROR);
  8219. }
  8220. BOOL
  8221. pSetupInfIsFromOemLocation(
  8222. IN PCTSTR InfFileName,
  8223. IN BOOL InfDirectoryOnly
  8224. )
  8225. /*++
  8226. Routine Description:
  8227. This routine determines whether the specified INF came from one of the directories
  8228. in our INF search path list. This list can also be limited to just the %windir%\Inf
  8229. directory.
  8230. Arguments:
  8231. InfFileName - Supplies the fully-qualified path of the INF file.
  8232. InfDirectoryOnly - If TRUE, then consider the INF to be from an OEM location if it is
  8233. not in the %windir%\Inf directory (i.e., ignore any other directories in the INF
  8234. search path).
  8235. Returns:
  8236. If the file is from an OEM location (i.e., _not_ in our INF search path list), then
  8237. the return value is TRUE. Otherwise, it is FALSE.
  8238. --*/
  8239. {
  8240. PCTSTR CharPos, DirTruncPos;
  8241. INT DirectoryPathLen, CurSearchPathLen;
  8242. //
  8243. // First, retrieve just the directory path part of the specified filename.
  8244. //
  8245. CharPos = pSetupGetFileTitle(InfFileName);
  8246. DirTruncPos = CharPrev(InfFileName, CharPos);
  8247. //
  8248. // (We know pSetupGetFileTitle will never return a pointer to a path separator character,
  8249. // so the following check is valid.)
  8250. //
  8251. if(*DirTruncPos == TEXT('\\')) {
  8252. //
  8253. // If this is in a root directory (e.g., "A:\"), then we don't want to strip off
  8254. // the trailing backslash.
  8255. //
  8256. if(((DirTruncPos - InfFileName) != 2) || (*CharNext(InfFileName) != TEXT(':'))) {
  8257. CharPos = DirTruncPos;
  8258. }
  8259. }
  8260. DirectoryPathLen = (int)(CharPos - InfFileName);
  8261. //
  8262. // Now, see if this directory matches any of the ones in our search path list.
  8263. //
  8264. if(InfDirectoryOnly) {
  8265. CharPos = InfDirectory;
  8266. } else {
  8267. CharPos = InfSearchPaths;
  8268. }
  8269. do {
  8270. //
  8271. // If the current search path ends in a backslash, we want to strip it off.
  8272. //
  8273. CurSearchPathLen = lstrlen(CharPos);
  8274. if((DirectoryPathLen == CurSearchPathLen) &&
  8275. !_tcsnicmp(CharPos, InfFileName, CurSearchPathLen)) {
  8276. //
  8277. // We've found this directory in our list--we can return.
  8278. //
  8279. return FALSE;
  8280. }
  8281. if(InfDirectoryOnly) {
  8282. //
  8283. // We're only supposed to consider the %windir%\Inf directory--that failed,
  8284. // so we're done.
  8285. //
  8286. break;
  8287. } else {
  8288. //
  8289. // Move on to next component of INF search path.
  8290. //
  8291. CharPos += (CurSearchPathLen + 1);
  8292. }
  8293. } while(*CharPos);
  8294. //
  8295. // If we get to here, then we didn't find the directory in our search path list.
  8296. // Therefore, it's from an OEM location.
  8297. //
  8298. return TRUE;
  8299. }
  8300. BOOL
  8301. WINAPI
  8302. SetupDiInstallDeviceInterfaces(
  8303. IN HDEVINFO DeviceInfoSet,
  8304. IN PSP_DEVINFO_DATA DeviceInfoData
  8305. )
  8306. /*++
  8307. Routine Description:
  8308. Default handler for DIF_INSTALLINTERFACES.
  8309. This routine will install any device interface specified in an
  8310. [<InstallSec>.Interfaces] section, where <InstallSec> is the install
  8311. section name for the selected driver node, potentially decorated with
  8312. an OS/architecture-specific extension (e.g., "InstallSec.NTAlpha.Interfaces").
  8313. Presently, only "AddInterface" lines in this section are processed. Their
  8314. format is as follows:
  8315. AddInterface = <InterfaceClassGuid> [, [<RefString>] [, [<InstallSection>] [, <Flags>]]]
  8316. (There are currently no flags defined for the <Flags> field--must be zero.)
  8317. If the interface class specified by <InterfaceClassGuid> is not already
  8318. installed in the system, we will install it. An INF can optionally specify
  8319. installation actions to be done when this interface class is installed (just
  8320. like it can do for class installers via a [ClassInstall32] section. It does
  8321. this by including an [InterfaceInstall32] section with an entry for the
  8322. interface class to be installed. This section name does not allow os/architecture-
  8323. specific decoration. Instead, the install sections referenced by lines within
  8324. this section are processed with decoration rules. Thus, it is possible to have
  8325. an install entry for interface class <x> that applies to both Win9x and NT, and
  8326. have another install entry for interface class <y> that behaves differently
  8327. depending on whether we're running on Win9x or NT.
  8328. The format of an entry in the [InterfaceInstall32] section is as follows:
  8329. <InterfaceClassGuid> = <InstallSection> [, <Flags>]
  8330. (There are currently no flags defined for the <Flags> field--must be zero.)
  8331. Arguments:
  8332. DeviceInfoSet - Supplies a handle to the device information set containing
  8333. a device information element whose device interfaces are to be installed.
  8334. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure for which
  8335. device interfaces are to be installed.
  8336. Return Value:
  8337. If the function succeeds, the return value is TRUE.
  8338. If the function fails, the return value is FALSE. To get extended error
  8339. information, call GetLastError.
  8340. Remarks:
  8341. If no driver is selected (i.e., this is a null-driver installation), then
  8342. this routine does nothing.
  8343. --*/
  8344. {
  8345. return _SetupDiInstallInterfaceDevices(DeviceInfoSet,
  8346. DeviceInfoData,
  8347. TRUE,
  8348. INVALID_HANDLE_VALUE,
  8349. INVALID_HANDLE_VALUE
  8350. );
  8351. }
  8352. BOOL
  8353. _SetupDiInstallInterfaceDevices(
  8354. IN HDEVINFO DeviceInfoSet,
  8355. IN PSP_DEVINFO_DATA DeviceInfoData,
  8356. IN BOOL DoFullInstall,
  8357. IN HINF hDeviceInf, OPTIONAL
  8358. IN HSPFILEQ UserFileQ OPTIONAL
  8359. )
  8360. /*++
  8361. Routine Description:
  8362. Worker routine for both SetupDiInstallInterfaceDevices and SetupDiInstallDriverFiles.
  8363. See the description of SetupDiInstallInterfaceDevices for more information.
  8364. Arguments:
  8365. DeviceInfoSet - Supplies a handle to the device information set containing
  8366. a device information element whose interface devices are to be installed.
  8367. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure for which
  8368. interface devices are to be installed.
  8369. DoFullInstall - If TRUE, then the interface devices will be fully installed.
  8370. Otherwise, only the required files are copied.
  8371. hDeviceInf - Optionally, supplies a handle to the INF for which installation
  8372. is being performed. If this handle is not supplied, the INF specified in
  8373. the selected driver node will be opened. If this handle is not supplied,
  8374. this parameter must be set to INVALID_HANDLE_VALUE.
  8375. UserFileQ - Optionally, supplies a file queue where file operations should be added.
  8376. If this handle is not supplied, then the queue associated with this devinfo
  8377. element will be used (if the DI_NOVCP flag is set), or one will be automatically
  8378. generated and committed. If this handle is not supplied, this parameter must
  8379. be set to INVALID_HANDLE_VALUE.
  8380. Return Value:
  8381. If the function succeeds, the return value is TRUE.
  8382. If the function fails, the return value is FALSE. To get extended error
  8383. information, call GetLastError.
  8384. Remarks:
  8385. During GUI-mode setup on Windows NT, quiet-install behavior is always
  8386. employed in the absence of a user-supplied file queue, regardless of
  8387. whether the device information element has the DI_QUIETINSTALL flag set.
  8388. --*/
  8389. {
  8390. PDEVICE_INFO_SET pDeviceInfoSet;
  8391. DWORD Err, ScanQueueResult;
  8392. PDEVINFO_ELEM DevInfoElem;
  8393. HWND hwndParent;
  8394. PTSTR szInfFileName, szInfSectionName;
  8395. TCHAR InfSectionWithExt[MAX_SECT_NAME_LEN];
  8396. DWORD InfSectionWithExtLength;
  8397. INFCONTEXT InterfaceDeviceInstallLine, InterfaceClassInstallLine;
  8398. TCHAR InterfaceGuidString[GUID_STRING_LEN];
  8399. DWORD InstallFlags;
  8400. GUID InterfaceGuid;
  8401. HKEY hKeyInterfaceClass, hKeyDeviceClassesRoot, hKeyInterfaceDevice;
  8402. PINTERFACE_CLASS_TO_INSTALL InterfacesToInstall, InterfaceInstallNode, CurInterfaceInstallNode;
  8403. DWORD RegDisposition;
  8404. BOOL NeedToInstallInterfaceClass;
  8405. TCHAR InterfaceInstallSection[MAX_SECT_NAME_LEN];
  8406. BOOL DoFileCopying;
  8407. BOOL CloseUserFileQ;
  8408. BOOL FreeMsgHandlerContext;
  8409. PSP_FILE_CALLBACK MsgHandler;
  8410. PVOID MsgHandlerContext;
  8411. BOOL MsgHandlerIsNativeCharWidth;
  8412. TCHAR RefString[MAX_PATH];
  8413. SP_DEVICE_INTERFACE_DATA InterfaceDeviceData;
  8414. PCTSTR UndecoratedInstallSection;
  8415. BOOL CloseInfHandle;
  8416. PTSTR NeedsSectionList, CurInstallSection;
  8417. BOOL b;
  8418. INT FileQueueNeedsReboot;
  8419. PSETUP_LOG_CONTEXT LogContext = NULL;
  8420. BOOL NoProgressUI;
  8421. DWORD slot_section = 0;
  8422. TCHAR szNewName[MAX_PATH];
  8423. BOOL OemInfFileToCopy = FALSE;
  8424. //
  8425. // A device information element must be specified.
  8426. //
  8427. if(!DeviceInfoData) {
  8428. Err = ERROR_INVALID_PARAMETER;
  8429. goto clean1;
  8430. }
  8431. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  8432. Err = ERROR_INVALID_HANDLE;
  8433. goto clean1;
  8434. }
  8435. LogContext = pDeviceInfoSet->InstallParamBlock.LogContext;
  8436. Err = NO_ERROR;
  8437. hKeyDeviceClassesRoot = hKeyInterfaceClass = hKeyInterfaceDevice = INVALID_HANDLE_VALUE;
  8438. InterfacesToInstall = InterfaceInstallNode = NULL;
  8439. CloseUserFileQ = FALSE;
  8440. FreeMsgHandlerContext = FALSE;
  8441. CloseInfHandle = FALSE;
  8442. NeedsSectionList = NULL;
  8443. try {
  8444. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  8445. DeviceInfoData,
  8446. NULL))) {
  8447. Err = ERROR_INVALID_PARAMETER;
  8448. goto clean0;
  8449. }
  8450. //
  8451. // This routine can't install a non-native driver
  8452. //
  8453. if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_ALTPLATFORM_DRVSEARCH) {
  8454. Err = ERROR_INVALID_FLAGS;
  8455. goto clean0;
  8456. }
  8457. //
  8458. // set the LogContext for this function
  8459. //
  8460. LogContext = DevInfoElem->InstallParamBlock.LogContext;
  8461. //
  8462. // If there's no driver selected (i.e., this is a null driver install), or we're
  8463. // using a legacy INF, then there's nothing for us to do.
  8464. //
  8465. if(!(DevInfoElem->SelectedDriver) ||
  8466. (DevInfoElem->SelectedDriver->Flags & DNF_LEGACYINF)) {
  8467. goto clean0;
  8468. }
  8469. //
  8470. // Make sure we only use the devinfo element's window if it's valid.
  8471. //
  8472. if(hwndParent = DevInfoElem->InstallParamBlock.hwndParent) {
  8473. if(!IsWindow(hwndParent)) {
  8474. hwndParent = NULL;
  8475. }
  8476. }
  8477. //
  8478. // Ignore the DI_NOFILECOPY flag if we're doing a copy-only installation--that's
  8479. // what setupx does.
  8480. //
  8481. if(DoFileCopying = (!(DevInfoElem->InstallParamBlock.Flags & DI_NOFILECOPY) || !DoFullInstall)) {
  8482. if(UserFileQ == INVALID_HANDLE_VALUE) {
  8483. if(DevInfoElem->InstallParamBlock.Flags & DI_NOVCP) {
  8484. //
  8485. // We must have a user-supplied file queue.
  8486. //
  8487. MYASSERT(DevInfoElem->InstallParamBlock.UserFileQ);
  8488. UserFileQ = DevInfoElem->InstallParamBlock.UserFileQ;
  8489. } else {
  8490. //
  8491. // Create our own queue.
  8492. //
  8493. if((UserFileQ = SetupOpenFileQueue()) != INVALID_HANDLE_VALUE) {
  8494. CloseUserFileQ = TRUE;
  8495. } else {
  8496. //
  8497. // SetupOpenFileQueue sets actual error
  8498. //
  8499. Err = GetLastError();
  8500. goto clean0;
  8501. }
  8502. }
  8503. //
  8504. // Maybe replace the file queue's log context with the DevInfoElem's
  8505. //
  8506. InheritLogContext(LogContext,
  8507. &((PSP_FILE_QUEUE) UserFileQ)->LogContext);
  8508. }
  8509. }
  8510. szInfFileName = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  8511. DevInfoElem->SelectedDriver->InfFileName
  8512. );
  8513. szInfSectionName = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  8514. DevInfoElem->SelectedDriver->InfSectionName
  8515. );
  8516. if(hDeviceInf == INVALID_HANDLE_VALUE) {
  8517. if((hDeviceInf = SetupOpenInfFile(szInfFileName,
  8518. NULL,
  8519. INF_STYLE_WIN4,
  8520. NULL)) == INVALID_HANDLE_VALUE) {
  8521. Err = GetLastError();
  8522. goto clean0;
  8523. }
  8524. CloseInfHandle = TRUE;
  8525. }
  8526. //
  8527. // Find out the 'real' install section we should be using (i.e., the potentially
  8528. // OS/architecture-specific one.
  8529. //
  8530. if(!SetupDiGetActualSectionToInstall(hDeviceInf,
  8531. szInfSectionName,
  8532. InfSectionWithExt,
  8533. SIZECHARS(InfSectionWithExt),
  8534. &InfSectionWithExtLength,
  8535. NULL
  8536. )) {
  8537. Err = GetLastError();
  8538. goto clean0;
  8539. }
  8540. //
  8541. // Now append the ".Interfaces" extension to the install section name to find
  8542. // the interface install section to run.
  8543. //
  8544. CopyMemory(&(InfSectionWithExt[InfSectionWithExtLength - 1]),
  8545. pszInterfacesSectionSuffix,
  8546. sizeof(pszInterfacesSectionSuffix)
  8547. );
  8548. if(slot_section == 0) {
  8549. //
  8550. // we haven't done anything about logging section yet...
  8551. //
  8552. slot_section = AllocLogInfoSlotOrLevel(LogContext,DRIVER_LOG_VERBOSE,FALSE);
  8553. //
  8554. // Say what section is about to be installed.
  8555. //
  8556. WriteLogEntry(LogContext,
  8557. slot_section,
  8558. MSG_LOG_INSTALLING_SECTION_FROM,
  8559. NULL,
  8560. InfSectionWithExt,
  8561. szInfFileName);
  8562. }
  8563. //
  8564. // Append the layout INF, if necessary.
  8565. //
  8566. if(DoFileCopying) {
  8567. SetupOpenAppendInfFile(NULL, hDeviceInf, NULL);
  8568. }
  8569. //
  8570. // Append-load any included INFs specified in an "include=" line in our
  8571. // install section.
  8572. //
  8573. AppendLoadIncludedInfs(hDeviceInf, szInfFileName, InfSectionWithExt, DoFileCopying);
  8574. NeedsSectionList = GetMultiSzFromInf(hDeviceInf, InfSectionWithExt, TEXT("needs"), &b);
  8575. if(!NeedsSectionList && b) {
  8576. //
  8577. // Out of memory!
  8578. //
  8579. Err = ERROR_NOT_ENOUGH_MEMORY;
  8580. goto clean0;
  8581. }
  8582. //
  8583. // Process the "AddInterface" lines in this section, as well as those contained with any
  8584. // sections referenced in the "needs=" entry in this section.
  8585. //
  8586. for(CurInstallSection = InfSectionWithExt;
  8587. (CurInstallSection && *CurInstallSection);
  8588. CurInstallSection = (CurInstallSection == InfSectionWithExt)
  8589. ? NeedsSectionList
  8590. : (CurInstallSection + lstrlen(CurInstallSection) + 1))
  8591. {
  8592. if(SetupFindFirstLine(hDeviceInf, CurInstallSection, pszAddInterface, &InterfaceDeviceInstallLine)) {
  8593. do {
  8594. //
  8595. // Retrieve the interface class GUID for this interface device.
  8596. //
  8597. if(!SetupGetStringField(&InterfaceDeviceInstallLine,
  8598. 1,
  8599. InterfaceGuidString,
  8600. SIZECHARS(InterfaceGuidString),
  8601. NULL))
  8602. {
  8603. Err = ERROR_BAD_INTERFACE_INSTALLSECT;
  8604. goto clean0;
  8605. }
  8606. if(NO_ERROR != pSetupGuidFromString(InterfaceGuidString, &InterfaceGuid)) {
  8607. Err = ERROR_BAD_INTERFACE_INSTALLSECT;
  8608. goto clean0;
  8609. }
  8610. //
  8611. // Next, we need to check and see if the specified interface class is already present.
  8612. // If not, we'll need to install it, too.
  8613. //
  8614. NeedToInstallInterfaceClass = FALSE;
  8615. hKeyInterfaceClass = SetupDiOpenClassRegKeyEx(&InterfaceGuid,
  8616. KEY_READ,
  8617. DIOCR_INTERFACE,
  8618. NULL,
  8619. NULL
  8620. );
  8621. if(hKeyInterfaceClass != INVALID_HANDLE_VALUE) {
  8622. //
  8623. // OK, this interface class already exists. We don't need to install it.
  8624. //
  8625. RegCloseKey(hKeyInterfaceClass);
  8626. hKeyInterfaceClass = INVALID_HANDLE_VALUE;
  8627. } else {
  8628. //
  8629. // This interface class isn't currently installed. Check to see if we've
  8630. // already encountered this class (and added it to our list of interface
  8631. // classes to install).
  8632. //
  8633. for(CurInterfaceInstallNode = InterfacesToInstall;
  8634. CurInterfaceInstallNode;
  8635. CurInterfaceInstallNode = CurInterfaceInstallNode->Next)
  8636. {
  8637. if(IsEqualGUID(&InterfaceGuid, &(CurInterfaceInstallNode->InterfaceGuid))) {
  8638. //
  8639. // The installation of this interface class is already in our
  8640. // 'to do' list.
  8641. //
  8642. break;
  8643. }
  8644. }
  8645. if(!CurInterfaceInstallNode) {
  8646. NeedToInstallInterfaceClass = TRUE;
  8647. }
  8648. }
  8649. if(NeedToInstallInterfaceClass) {
  8650. //
  8651. // Look for this interface class GUID in the INF's [InterfaceInstall32] section
  8652. // (if present).
  8653. //
  8654. if(SetupFindFirstLine(hDeviceInf,
  8655. pszInterfaceInstall32,
  8656. InterfaceGuidString,
  8657. &InterfaceClassInstallLine)) {
  8658. //
  8659. // Get the name of the install section for this interface class.
  8660. //
  8661. if((UndecoratedInstallSection = pSetupGetField(&InterfaceClassInstallLine, 1))
  8662. && !(*UndecoratedInstallSection))
  8663. {
  8664. UndecoratedInstallSection = NULL;
  8665. }
  8666. if(!UndecoratedInstallSection) {
  8667. *InterfaceInstallSection = TEXT('\0');
  8668. } else {
  8669. //
  8670. // Get the (potentially) os/architecture-specific install section.
  8671. //
  8672. PTSTR SectionExtension;
  8673. if(!SetupDiGetActualSectionToInstall(hDeviceInf,
  8674. UndecoratedInstallSection,
  8675. InterfaceInstallSection,
  8676. SIZECHARS(InterfaceInstallSection),
  8677. NULL,
  8678. &SectionExtension
  8679. )) {
  8680. Err = GetLastError();
  8681. goto clean0;
  8682. }
  8683. //
  8684. // If this is the undecorated name, then make sure that the section actually exists.
  8685. //
  8686. if(!SectionExtension && (SetupGetLineCount(hDeviceInf, InterfaceInstallSection) == -1)) {
  8687. WriteLogEntry(LogContext,
  8688. DRIVER_LOG_ERROR,
  8689. MSG_LOG_NOSECTION,
  8690. NULL,
  8691. InterfaceInstallSection);
  8692. Err = ERROR_SECTION_NOT_FOUND;
  8693. goto clean0;
  8694. }
  8695. }
  8696. if(!SetupGetIntField(&InterfaceClassInstallLine, 2, (PINT)&InstallFlags)) {
  8697. InstallFlags = 0;
  8698. }
  8699. } else {
  8700. *InterfaceInstallSection = TEXT('\0');
  8701. InstallFlags = 0;
  8702. }
  8703. //
  8704. // At this point, we just want to queue up any file operations required.
  8705. //
  8706. if(DoFileCopying && *InterfaceInstallSection) {
  8707. Err = pSetupInstallFiles(hDeviceInf,
  8708. NULL,
  8709. InterfaceInstallSection,
  8710. NULL,
  8711. NULL,
  8712. NULL,
  8713. SP_COPY_NEWER_OR_SAME | SP_COPY_LANGUAGEAWARE |
  8714. ((DevInfoElem->InstallParamBlock.Flags & DI_NOBROWSE) ? SP_COPY_NOBROWSE : 0),
  8715. NULL,
  8716. UserFileQ,
  8717. TRUE
  8718. );
  8719. if(Err != NO_ERROR) {
  8720. goto clean0;
  8721. }
  8722. }
  8723. //
  8724. // Now add a node onto our 'to do' list of interface classes to install.
  8725. //
  8726. if(InterfaceInstallNode = MyMalloc(sizeof(INTERFACE_CLASS_TO_INSTALL))) {
  8727. CopyMemory(&(InterfaceInstallNode->InterfaceGuid),
  8728. &InterfaceGuid,
  8729. sizeof(InterfaceGuid)
  8730. );
  8731. lstrcpy(InterfaceInstallNode->InstallSection, InterfaceInstallSection);
  8732. InterfaceInstallNode->Flags = InstallFlags;
  8733. InterfaceInstallNode->Next = InterfacesToInstall;
  8734. InterfacesToInstall = InterfaceInstallNode;
  8735. //
  8736. // Now set newly allocated node pointer to NULL, so we won't try
  8737. // to free it if we hit an exception.
  8738. //
  8739. InterfaceInstallNode = NULL;
  8740. } else {
  8741. Err = ERROR_NOT_ENOUGH_MEMORY;
  8742. goto clean0;
  8743. }
  8744. }
  8745. //
  8746. // Now queue up any file operations for this particular device interface.
  8747. //
  8748. if(DoFileCopying
  8749. && SetupGetStringField(&InterfaceDeviceInstallLine,
  8750. 3,
  8751. InterfaceInstallSection,
  8752. SIZECHARS(InterfaceInstallSection),
  8753. NULL)
  8754. && *InterfaceInstallSection)
  8755. {
  8756. Err = pSetupInstallFiles(hDeviceInf,
  8757. NULL,
  8758. InterfaceInstallSection,
  8759. NULL,
  8760. NULL,
  8761. NULL,
  8762. SP_COPY_NEWER_OR_SAME | SP_COPY_LANGUAGEAWARE |
  8763. ((DevInfoElem->InstallParamBlock.Flags & DI_NOBROWSE)? SP_COPY_NOBROWSE : 0),
  8764. NULL,
  8765. UserFileQ,
  8766. TRUE
  8767. );
  8768. if(Err != NO_ERROR) {
  8769. goto clean0;
  8770. }
  8771. }
  8772. } while(SetupFindNextMatchLine(&InterfaceDeviceInstallLine, pszAddInterface, &InterfaceDeviceInstallLine));
  8773. }
  8774. }
  8775. //
  8776. // Mark the queue as a device install queue (and make sure there's a
  8777. // catalog node representing our device INF in the queue).
  8778. //
  8779. if(DoFileCopying) {
  8780. MYASSERT(UserFileQ && (UserFileQ != INVALID_HANDLE_VALUE));
  8781. Err = MarkQueueForDeviceInstall(UserFileQ,
  8782. hDeviceInf,
  8783. pStringTableStringFromId(
  8784. pDeviceInfoSet->StringTable,
  8785. DevInfoElem->SelectedDriver->DrvDescription)
  8786. );
  8787. }
  8788. //
  8789. // At this point, we have queued up all the files that need to be
  8790. // copied. If we weren't given a user-supplied queue, then commit our
  8791. // queue now.
  8792. //
  8793. if(CloseUserFileQ) {
  8794. if(Err == NO_ERROR) {
  8795. //
  8796. // Determine whether the queue actually needs to be committed.
  8797. //
  8798. // ScanQueueResult can have 1 of 3 values:
  8799. //
  8800. // 0: Some files were missing--must commit queue.
  8801. //
  8802. // 1: All files to be copied are already present and valid,
  8803. // and the queue is empty--skip committing queue.
  8804. //
  8805. // 2: All files to be copied are present/valid, but
  8806. // del/ren/backup queues not empty--must commit queue.
  8807. // The copy queue will have been emptied, so only
  8808. // del/ren/backup functions will be performed.
  8809. //
  8810. // (jamiehun) see previous case of SetupScanFileQueue for a
  8811. // discussion of DI_FLAGSEX_PREINSTALLBACKUP handling.
  8812. //
  8813. if(!SetupScanFileQueue(UserFileQ,
  8814. SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_PRUNE_COPY_QUEUE,
  8815. hwndParent,
  8816. NULL,
  8817. NULL,
  8818. &ScanQueueResult)) {
  8819. //
  8820. // SetupScanFileQueue should really never fail when you
  8821. // don't ask it to call a callback routine, but if it does,
  8822. // just go ahead and commit the queue.
  8823. //
  8824. ScanQueueResult = 0;
  8825. }
  8826. }
  8827. if((Err == NO_ERROR) && (ScanQueueResult != 1)) {
  8828. //
  8829. // We need to commit this file queue. Figure out what message
  8830. // handler to use.
  8831. //
  8832. if(DevInfoElem->InstallParamBlock.InstallMsgHandler) {
  8833. MsgHandler = DevInfoElem->InstallParamBlock.InstallMsgHandler;
  8834. MsgHandlerContext = DevInfoElem->InstallParamBlock.InstallMsgHandlerContext;
  8835. MsgHandlerIsNativeCharWidth = DevInfoElem->InstallParamBlock.InstallMsgHandlerIsNativeCharWidth;
  8836. } else {
  8837. NoProgressUI = (GuiSetupInProgress || (DevInfoElem->InstallParamBlock.Flags & DI_QUIETINSTALL));
  8838. if(MsgHandlerContext = SetupInitDefaultQueueCallbackEx(
  8839. hwndParent,
  8840. (NoProgressUI ? INVALID_HANDLE_VALUE : NULL),
  8841. 0,
  8842. 0,
  8843. NULL))
  8844. {
  8845. FreeMsgHandlerContext = TRUE;
  8846. MsgHandler = SetupDefaultQueueCallback;
  8847. MsgHandlerIsNativeCharWidth = TRUE;
  8848. } else {
  8849. Err = ERROR_NOT_ENOUGH_MEMORY;
  8850. }
  8851. }
  8852. //
  8853. // Copy enqueued files.
  8854. //
  8855. if(Err == NO_ERROR) {
  8856. //
  8857. // Call _SetupVerifyQueuedCatalogs separately (i.e., don't
  8858. // let it happen automatically as a result of committing
  8859. // the queue that happens below). We do this beforehand so
  8860. // that we know what unique name was generated when an OEM
  8861. // INF was installed into %windir%\Inf (in case we need to
  8862. // delete the INF/PNF/CAT files later if we encounter an
  8863. // error).
  8864. //
  8865. WriteLogEntry(
  8866. LogContext,
  8867. DRIVER_LOG_TIME,
  8868. MSG_LOG_BEGIN_INTFC_VERIFY_CAT_TIME,
  8869. NULL); // text message
  8870. Err = _SetupVerifyQueuedCatalogs(
  8871. hwndParent,
  8872. UserFileQ,
  8873. (VERCAT_INSTALL_INF_AND_CAT |
  8874. ((DevInfoElem->SelectedDriver->Flags & DNF_INET_DRIVER)
  8875. ? VERCAT_PRIMARY_DEVICE_INF_FROM_INET : 0)),
  8876. szNewName,
  8877. &OemInfFileToCopy
  8878. );
  8879. WriteLogEntry(
  8880. LogContext,
  8881. DRIVER_LOG_TIME,
  8882. MSG_LOG_END_INTFC_VERIFY_CAT_TIME,
  8883. NULL); // text message
  8884. if(Err == NO_ERROR) {
  8885. if(_SetupCommitFileQueue(hwndParent,
  8886. UserFileQ,
  8887. MsgHandler,
  8888. MsgHandlerContext,
  8889. MsgHandlerIsNativeCharWidth
  8890. )) {
  8891. //
  8892. // Check to see whether a reboot is required as a
  8893. // result of committing the queue (i.e., because files
  8894. // were in use, or the INF requested a reboot).
  8895. //
  8896. FileQueueNeedsReboot = SetupPromptReboot(UserFileQ, NULL, TRUE);
  8897. //
  8898. // This should never fail...
  8899. //
  8900. MYASSERT(FileQueueNeedsReboot != -1);
  8901. if(FileQueueNeedsReboot) {
  8902. SetDevnodeNeedsRebootProblem(DevInfoElem, pDeviceInfoSet,
  8903. MSG_LOG_REBOOT_REASON_INUSE);
  8904. }
  8905. } else {
  8906. Err = GetLastError();
  8907. }
  8908. }
  8909. }
  8910. }
  8911. //
  8912. // Close our file queue handle.
  8913. //
  8914. SetupCloseFileQueue(UserFileQ);
  8915. CloseUserFileQ = FALSE;
  8916. //
  8917. // Terminate the default queue callback, if it was created.
  8918. //
  8919. if(FreeMsgHandlerContext) {
  8920. SetupTermDefaultQueueCallback(MsgHandlerContext);
  8921. FreeMsgHandlerContext = FALSE;
  8922. }
  8923. if(Err != NO_ERROR) {
  8924. goto clean0;
  8925. }
  8926. }
  8927. //
  8928. // If all we were asked to do was copy files, then we're done.
  8929. //
  8930. if(!DoFullInstall) {
  8931. goto clean0;
  8932. }
  8933. //
  8934. // Now go through our list of interface classes to install, and install
  8935. // each one.
  8936. //
  8937. if(CurInterfaceInstallNode = InterfacesToInstall) {
  8938. //
  8939. // Open a handle to the root of the DeviceClasses registry branch.
  8940. //
  8941. hKeyDeviceClassesRoot = SetupDiOpenClassRegKeyEx(NULL,
  8942. KEY_ALL_ACCESS,
  8943. DIOCR_INTERFACE,
  8944. NULL,
  8945. NULL
  8946. );
  8947. if(hKeyDeviceClassesRoot == INVALID_HANDLE_VALUE) {
  8948. Err = GetLastError();
  8949. goto clean0;
  8950. }
  8951. do {
  8952. //
  8953. // Presently, the flags field, if present, must be zero.
  8954. //
  8955. if(CurInterfaceInstallNode->Flags) {
  8956. Err = ERROR_INVALID_FLAGS;
  8957. goto clean0;
  8958. }
  8959. pSetupStringFromGuid(&(CurInterfaceInstallNode->InterfaceGuid),
  8960. InterfaceGuidString,
  8961. SIZECHARS(InterfaceGuidString)
  8962. );
  8963. Err = RegCreateKeyEx(hKeyDeviceClassesRoot,
  8964. InterfaceGuidString,
  8965. 0,
  8966. NULL,
  8967. REG_OPTION_NON_VOLATILE,
  8968. KEY_ALL_ACCESS,
  8969. NULL,
  8970. &hKeyInterfaceClass,
  8971. &RegDisposition
  8972. );
  8973. if(Err != ERROR_SUCCESS) {
  8974. //
  8975. // Ensure that the registry handle is still invalid, so we won't try
  8976. // to close it.
  8977. //
  8978. hKeyInterfaceClass = INVALID_HANDLE_VALUE;
  8979. goto clean0;
  8980. }
  8981. //
  8982. // Now run the INF section for this newly-created key.
  8983. //
  8984. if(!SetupInstallFromInfSection(NULL,
  8985. hDeviceInf,
  8986. CurInterfaceInstallNode->InstallSection,
  8987. SPINST_INIFILES
  8988. | SPINST_REGISTRY
  8989. | SPINST_INI2REG
  8990. | SPINST_BITREG
  8991. | SPINST_REGSVR
  8992. | SPINST_UNREGSVR
  8993. | SPINST_PROFILEITEMS,
  8994. hKeyInterfaceClass,
  8995. NULL,
  8996. 0,
  8997. NULL,
  8998. NULL,
  8999. INVALID_HANDLE_VALUE,
  9000. NULL))
  9001. {
  9002. Err = GetLastError();
  9003. //
  9004. // Normally, we would want to clean up this newly-created key.
  9005. // However, the kernel-mode IoRegisterDeviceClassAssociation API
  9006. // will quite happily create the class key if it doesn't exist.
  9007. // Thus, a driver might have registered a device while we were
  9008. // trying to run the INF, and if we deleted the key that might
  9009. // really mess things up. Thus, we'll leave this alone. Since
  9010. // we should never see a failure with this call, this isn't a big
  9011. // deal anyway.
  9012. //
  9013. }
  9014. RegCloseKey(hKeyInterfaceClass);
  9015. hKeyInterfaceClass = INVALID_HANDLE_VALUE;
  9016. if(Err != NO_ERROR) {
  9017. goto clean0;
  9018. }
  9019. CurInterfaceInstallNode = CurInterfaceInstallNode->Next;
  9020. } while(CurInterfaceInstallNode);
  9021. }
  9022. //
  9023. // At this point, we've done everything except for actually registering the
  9024. // interface devices and (potentially) running INFs against their registry keys.
  9025. // Do that now...
  9026. //
  9027. InterfaceDeviceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  9028. for(CurInstallSection = InfSectionWithExt;
  9029. (CurInstallSection && *CurInstallSection);
  9030. CurInstallSection = (CurInstallSection == InfSectionWithExt)
  9031. ? NeedsSectionList
  9032. : (CurInstallSection + lstrlen(CurInstallSection) + 1))
  9033. {
  9034. if(SetupFindFirstLine(hDeviceInf, CurInstallSection, pszAddInterface, &InterfaceDeviceInstallLine)) {
  9035. do {
  9036. //
  9037. // Retrieve the interface class GUID for this interface device. (There's
  9038. // no need to check the return status of these two calls, since we've already
  9039. // done this once, and they were fine.
  9040. //
  9041. SetupGetStringField(&InterfaceDeviceInstallLine,
  9042. 1,
  9043. InterfaceGuidString,
  9044. SIZECHARS(InterfaceGuidString),
  9045. NULL
  9046. );
  9047. pSetupGuidFromString(InterfaceGuidString, &InterfaceGuid);
  9048. if(!SetupGetStringField(&InterfaceDeviceInstallLine,
  9049. 2,
  9050. RefString,
  9051. SIZECHARS(RefString),
  9052. NULL))
  9053. {
  9054. *RefString = TEXT('\0');
  9055. }
  9056. if(!SetupGetStringField(&InterfaceDeviceInstallLine,
  9057. 3,
  9058. InterfaceInstallSection,
  9059. SIZECHARS(InterfaceInstallSection),
  9060. NULL))
  9061. {
  9062. *InterfaceInstallSection = TEXT('\0');
  9063. }
  9064. if(!SetupGetIntField(&InterfaceDeviceInstallLine, 4, (PINT)&InstallFlags)) {
  9065. InstallFlags = 0;
  9066. }
  9067. //
  9068. // (Presently, no flags are defined--field, if present, must be zero.
  9069. //
  9070. if(InstallFlags) {
  9071. Err = ERROR_INVALID_FLAGS;
  9072. goto clean0;
  9073. }
  9074. //
  9075. // OK, we have all the information we need to create this interface device.
  9076. //
  9077. if(!SetupDiCreateDeviceInterface(DeviceInfoSet,
  9078. DeviceInfoData,
  9079. &InterfaceGuid,
  9080. (*RefString) ? RefString : NULL,
  9081. 0,
  9082. &InterfaceDeviceData)) {
  9083. Err = GetLastError();
  9084. goto clean0;
  9085. }
  9086. if(*InterfaceInstallSection) {
  9087. //
  9088. // Run the INF against this interface device's registry key.
  9089. //
  9090. hKeyInterfaceDevice = SetupDiCreateDeviceInterfaceRegKey(DeviceInfoSet,
  9091. &InterfaceDeviceData,
  9092. 0,
  9093. KEY_ALL_ACCESS,
  9094. INVALID_HANDLE_VALUE,
  9095. NULL
  9096. );
  9097. if(hKeyInterfaceDevice == INVALID_HANDLE_VALUE) {
  9098. Err = GetLastError();
  9099. goto clean0;
  9100. }
  9101. //
  9102. // Now run the INF section for this newly-created key.
  9103. //
  9104. if(!SetupInstallFromInfSection(NULL,
  9105. hDeviceInf,
  9106. InterfaceInstallSection,
  9107. SPINST_INIFILES
  9108. | SPINST_REGISTRY
  9109. | SPINST_INI2REG
  9110. | SPINST_BITREG
  9111. | SPINST_REGSVR
  9112. | SPINST_UNREGSVR
  9113. | SPINST_PROFILEITEMS,
  9114. hKeyInterfaceDevice,
  9115. NULL,
  9116. 0,
  9117. NULL,
  9118. NULL,
  9119. INVALID_HANDLE_VALUE,
  9120. NULL))
  9121. {
  9122. Err = GetLastError();
  9123. }
  9124. RegCloseKey(hKeyInterfaceDevice);
  9125. hKeyInterfaceDevice = INVALID_HANDLE_VALUE;
  9126. if(Err != NO_ERROR) {
  9127. goto clean0;
  9128. }
  9129. }
  9130. } while(SetupFindNextMatchLine(&InterfaceDeviceInstallLine, pszAddInterface, &InterfaceDeviceInstallLine));
  9131. }
  9132. }
  9133. clean0: ; // nothing to do.
  9134. } except(EXCEPTION_EXECUTE_HANDLER) {
  9135. Err = ERROR_INVALID_PARAMETER;
  9136. if(hKeyInterfaceClass != INVALID_HANDLE_VALUE) {
  9137. RegCloseKey(hKeyInterfaceClass);
  9138. }
  9139. if(hKeyInterfaceDevice != INVALID_HANDLE_VALUE) {
  9140. RegCloseKey(hKeyInterfaceDevice);
  9141. }
  9142. if(InterfaceInstallNode) {
  9143. MyFree(InterfaceInstallNode);
  9144. }
  9145. if(FreeMsgHandlerContext) {
  9146. SetupTermDefaultQueueCallback(MsgHandlerContext);
  9147. }
  9148. if(CloseUserFileQ) {
  9149. SetupCloseFileQueue(UserFileQ);
  9150. }
  9151. //
  9152. // Reference the following variables so the compiler will respect statement
  9153. // ordering w.r.t. assignment.
  9154. //
  9155. InterfacesToInstall = InterfacesToInstall;
  9156. CloseInfHandle = CloseInfHandle;
  9157. NeedsSectionList = NeedsSectionList;
  9158. OemInfFileToCopy = OemInfFileToCopy;
  9159. }
  9160. UnlockDeviceInfoSet(pDeviceInfoSet);
  9161. for(CurInterfaceInstallNode = InterfacesToInstall;
  9162. CurInterfaceInstallNode;
  9163. CurInterfaceInstallNode = InterfacesToInstall) {
  9164. InterfacesToInstall = CurInterfaceInstallNode->Next;
  9165. MyFree(CurInterfaceInstallNode);
  9166. }
  9167. if(hKeyDeviceClassesRoot != INVALID_HANDLE_VALUE) {
  9168. RegCloseKey(hKeyDeviceClassesRoot);
  9169. }
  9170. if(CloseInfHandle) {
  9171. MYASSERT(hDeviceInf != INVALID_HANDLE_VALUE);
  9172. SetupCloseInfFile(hDeviceInf);
  9173. }
  9174. if(NeedsSectionList) {
  9175. MyFree(NeedsSectionList);
  9176. }
  9177. clean1:
  9178. if (Err == NO_ERROR) {
  9179. //
  9180. // give a +ve affirmation of Success
  9181. //
  9182. WriteLogEntry(
  9183. LogContext,
  9184. DoFullInstall ? DRIVER_LOG_INFO : DRIVER_LOG_VERBOSE,
  9185. MSG_LOG_INSTALLEDINTERFACES,
  9186. NULL);
  9187. } else {
  9188. //
  9189. // indicate failed, display error
  9190. //
  9191. WriteLogEntry(
  9192. LogContext,
  9193. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  9194. MSG_LOG_INSTALLINTERFACES_ERROR,
  9195. NULL);
  9196. WriteLogError(
  9197. LogContext,
  9198. DRIVER_LOG_ERROR,
  9199. Err);
  9200. //
  9201. // If we copied the OEM INF into the INF directory under a newly-
  9202. // generated name, delete it now.
  9203. //
  9204. if(OemInfFileToCopy) {
  9205. pSetupUninstallOEMInf(szNewName, LogContext, SUOI_FORCEDELETE, NULL);
  9206. }
  9207. }
  9208. if (slot_section) {
  9209. ReleaseLogInfoSlot(LogContext,slot_section);
  9210. }
  9211. SetLastError(Err);
  9212. return(Err == NO_ERROR);
  9213. }
  9214. BOOL
  9215. pSetupGetSourceMediaTypeFromPnf(
  9216. PCTSTR InfName,
  9217. PDWORD SourceMediaType
  9218. )
  9219. /*++
  9220. Routine Description:
  9221. This function will get the Source Media Type from the PNF for a given INF
  9222. file. If the INF does not have a PNF file then the API will fail.
  9223. Arguments:
  9224. InfFileName - Supplies the full path of the INF that we will get the source
  9225. media type from it's PNF.
  9226. SourceMediaType - Supplies a pointer that will be filled in the the source
  9227. media type from the PNF.
  9228. Return Value:
  9229. TRUE if the INF has a PNF and we are able to get a valid source media type
  9230. FALSE if their is no PNF for this INF.
  9231. Remarks:
  9232. --*/
  9233. {
  9234. PLOADED_INF Inf;
  9235. BOOL PnfWasUsed;
  9236. WIN32_FIND_DATA InfFileData;
  9237. UINT ErrorLineNumber;
  9238. BOOL bReturn = FALSE;
  9239. if (FileExists(InfName, &InfFileData)) {
  9240. if(LoadInfFile(InfName,
  9241. &InfFileData,
  9242. INF_STYLE_WIN4,
  9243. LDINF_FLAG_IGNORE_VOLATILE_DIRIDS,
  9244. NULL,
  9245. NULL,
  9246. NULL,
  9247. NULL,
  9248. NULL,
  9249. &Inf,
  9250. &ErrorLineNumber,
  9251. &PnfWasUsed) == NO_ERROR) {
  9252. if (PnfWasUsed) {
  9253. //
  9254. // We were able to open the INF with a PNF. Now get the
  9255. // InfSourceMediaType.
  9256. //
  9257. LockInf(Inf);
  9258. *SourceMediaType = Inf->InfSourceMediaType;
  9259. UnlockInf(Inf);
  9260. bReturn = TRUE;
  9261. }
  9262. FreeInfFile(Inf);
  9263. }
  9264. }
  9265. return bReturn;
  9266. }
  9267. #ifdef UNICODE
  9268. //
  9269. // ANSI version
  9270. //
  9271. BOOL
  9272. WINAPI
  9273. SetupCopyOEMInfA(
  9274. IN PCSTR SourceInfFileName,
  9275. IN PCSTR OEMSourceMediaLocation, OPTIONAL
  9276. IN DWORD OEMSourceMediaType,
  9277. IN DWORD CopyStyle,
  9278. OUT PSTR DestinationInfFileName, OPTIONAL
  9279. IN DWORD DestinationInfFileNameSize,
  9280. OUT PDWORD RequiredSize, OPTIONAL
  9281. OUT PSTR *DestinationInfFileNameComponent OPTIONAL
  9282. )
  9283. {
  9284. PWSTR UnicodeSourceInfFileName, UnicodeOEMSourceMediaLocation, UnicodeFileNameComponent;
  9285. WCHAR UnicodeDestinationInfFileName[MAX_PATH];
  9286. PSTR AnsiDestinationInfFileName;
  9287. DWORD AnsiRequiredSize;
  9288. DWORD rc;
  9289. BOOL b;
  9290. DWORD CharOffset, i;
  9291. PSTR p;
  9292. WCHAR SourceInfCatalogName[MAX_PATH];
  9293. WCHAR CatalogFilenameOnSystem[MAX_PATH];
  9294. BOOL DifferentOriginalName;
  9295. TCHAR OriginalInfName[MAX_PATH];
  9296. HINF hInf;
  9297. DWORD CodeSigningPolicy;
  9298. BOOL UseOriginalInfName;
  9299. PSETUP_LOG_CONTEXT LogContext = NULL;
  9300. PSP_ALTPLATFORM_INFO_V2 ValidationPlatform;
  9301. rc = pSetupCaptureAndConvertAnsiArg(SourceInfFileName,
  9302. &UnicodeSourceInfFileName
  9303. );
  9304. if(rc != NO_ERROR) {
  9305. SetLastError(rc);
  9306. return FALSE;
  9307. }
  9308. //
  9309. // Open the specified INF.
  9310. //
  9311. hInf = SetupOpenInfFile(UnicodeSourceInfFileName,
  9312. NULL,
  9313. INF_STYLE_OLDNT | INF_STYLE_WIN4,
  9314. NULL
  9315. );
  9316. if(hInf == INVALID_HANDLE_VALUE) {
  9317. rc = GetLastError();
  9318. MyFree(UnicodeSourceInfFileName);
  9319. SetLastError(rc);
  9320. return FALSE;
  9321. }
  9322. ValidationPlatform = NULL;
  9323. //
  9324. // GetCodeSigningPolicyForInf() presently can generate an unhandled
  9325. // exception, so guard the code below in try/except to protect ourselves...
  9326. //
  9327. try {
  9328. if(NO_ERROR != InheritLogContext(((PLOADED_INF)hInf)->LogContext,
  9329. &LogContext)) {
  9330. LogContext = NULL;
  9331. }
  9332. //
  9333. // Retrieve the CatalogFile entry (if present) from this INF's version
  9334. // section.
  9335. //
  9336. rc = pGetInfOriginalNameAndCatalogFile(
  9337. (PLOADED_INF)hInf,
  9338. NULL,
  9339. &DifferentOriginalName,
  9340. OriginalInfName,
  9341. SIZECHARS(OriginalInfName),
  9342. SourceInfCatalogName,
  9343. SIZECHARS(SourceInfCatalogName),
  9344. NULL // always native OS/arch (ver doesn't matter for CatalogFile=)
  9345. );
  9346. if(rc == NO_ERROR) {
  9347. CodeSigningPolicy = GetCodeSigningPolicyForInf(LogContext,
  9348. hInf,
  9349. &ValidationPlatform,
  9350. &UseOriginalInfName
  9351. );
  9352. if(UseOriginalInfName) {
  9353. //
  9354. // If we're looking at an exception INF, make sure it's under its
  9355. // original name.
  9356. //
  9357. if(DifferentOriginalName) {
  9358. rc = ERROR_INVALID_CLASS;
  9359. }
  9360. }
  9361. }
  9362. } except(EXCEPTION_EXECUTE_HANDLER) {
  9363. //
  9364. // If we hit an AV, then use invalid parameter error, otherwise, assume
  9365. // an inpage error when dealing with a mapped-in file (e.g., in the
  9366. // call to GetCodeSigningPolicyForInf).
  9367. //
  9368. rc = (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? ERROR_INVALID_PARAMETER : ERROR_READ_FAULT;
  9369. }
  9370. //
  9371. // We're done with the INF handle
  9372. //
  9373. SetupCloseInfFile(hInf);
  9374. if(rc == NO_ERROR) {
  9375. if(OEMSourceMediaLocation) {
  9376. rc = pSetupCaptureAndConvertAnsiArg(OEMSourceMediaLocation,
  9377. &UnicodeOEMSourceMediaLocation
  9378. );
  9379. } else {
  9380. UnicodeOEMSourceMediaLocation = NULL;
  9381. }
  9382. }
  9383. if(rc != NO_ERROR) {
  9384. MyFree(UnicodeSourceInfFileName);
  9385. if(ValidationPlatform) {
  9386. MyFree(ValidationPlatform);
  9387. }
  9388. SetLastError(rc);
  9389. return FALSE;
  9390. }
  9391. b = _SetupCopyOEMInf(UnicodeSourceInfFileName,
  9392. UnicodeOEMSourceMediaLocation,
  9393. OEMSourceMediaType,
  9394. CopyStyle,
  9395. UnicodeDestinationInfFileName,
  9396. SIZECHARS(UnicodeDestinationInfFileName),
  9397. NULL,
  9398. &UnicodeFileNameComponent,
  9399. (DifferentOriginalName ? OriginalInfName
  9400. : pSetupGetFileTitle(UnicodeSourceInfFileName)),
  9401. (*SourceInfCatalogName ? SourceInfCatalogName : NULL),
  9402. NULL, // no HWND for UI!
  9403. NULL,
  9404. CodeSigningPolicy,
  9405. SCOI_NO_ERRLOG_IF_INF_ALREADY_PRESENT |
  9406. (UseOriginalInfName ? SCOI_KEEP_INF_AND_CAT_ORIGINAL_NAMES : 0),
  9407. NULL,
  9408. ValidationPlatform,
  9409. NULL,
  9410. CatalogFilenameOnSystem,
  9411. LogContext, // either made-up or thread log context
  9412. NULL
  9413. );
  9414. rc = GetLastError();
  9415. if(b || (rc == ERROR_FILE_EXISTS)) {
  9416. if(DestinationInfFileName || RequiredSize) {
  9417. if(AnsiDestinationInfFileName = pSetupUnicodeToAnsi(UnicodeDestinationInfFileName)) {
  9418. AnsiRequiredSize = lstrlenA(AnsiDestinationInfFileName) + 1;
  9419. if(RequiredSize) {
  9420. try {
  9421. *RequiredSize = AnsiRequiredSize;
  9422. } except(EXCEPTION_EXECUTE_HANDLER) {
  9423. b = FALSE;
  9424. rc = ERROR_INVALID_PARAMETER;
  9425. }
  9426. }
  9427. if((b || (rc == ERROR_FILE_EXISTS)) && DestinationInfFileName) {
  9428. if(AnsiRequiredSize <= DestinationInfFileNameSize) {
  9429. if(!lstrcpyA(DestinationInfFileName, AnsiDestinationInfFileName)) {
  9430. //
  9431. // lstrcpy faulted; DestinationInfFileName must be bad
  9432. //
  9433. b = FALSE;
  9434. rc = ERROR_INVALID_PARAMETER;
  9435. } else if(DestinationInfFileNameComponent) {
  9436. //
  9437. // We need to figure out where the extension is
  9438. // in the converted string. To be DBCS safe we will
  9439. // count characters forward to find it.
  9440. //
  9441. CharOffset = (DWORD)(UnicodeFileNameComponent - UnicodeDestinationInfFileName);
  9442. p = DestinationInfFileName;
  9443. for(i = 0; i < CharOffset; i++) {
  9444. p = CharNextA(p);
  9445. }
  9446. try {
  9447. *DestinationInfFileNameComponent = p;
  9448. } except(EXCEPTION_EXECUTE_HANDLER) {
  9449. b = FALSE;
  9450. rc = ERROR_INVALID_PARAMETER;
  9451. }
  9452. }
  9453. } else {
  9454. rc = ERROR_INSUFFICIENT_BUFFER;
  9455. b = FALSE;
  9456. }
  9457. }
  9458. MyFree(AnsiDestinationInfFileName);
  9459. } else {
  9460. b = FALSE;
  9461. rc = ERROR_NOT_ENOUGH_MEMORY;
  9462. }
  9463. } else {
  9464. //
  9465. // It would be dumb to request the filename part of the destination INF path when
  9466. // the path itself wasn't requested, but let's make sure we set this to NULL if
  9467. // that happens.
  9468. //
  9469. if(DestinationInfFileNameComponent) {
  9470. try {
  9471. *DestinationInfFileNameComponent = NULL;
  9472. } except(EXCEPTION_EXECUTE_HANDLER) {
  9473. b = FALSE;
  9474. rc = ERROR_INVALID_PARAMETER;
  9475. }
  9476. }
  9477. }
  9478. }
  9479. MyFree(UnicodeSourceInfFileName);
  9480. if(UnicodeOEMSourceMediaLocation) {
  9481. MyFree(UnicodeOEMSourceMediaLocation);
  9482. }
  9483. if(ValidationPlatform) {
  9484. MyFree(ValidationPlatform);
  9485. }
  9486. DeleteLogContext(LogContext);
  9487. SetLastError(rc);
  9488. return b;
  9489. }
  9490. #else
  9491. //
  9492. // Unicode stub
  9493. //
  9494. BOOL
  9495. WINAPI
  9496. SetupCopyOEMInfW(
  9497. IN PCWSTR SourceInfFileName,
  9498. IN PCWSTR OEMSourceMediaLocation, OPTIONAL
  9499. IN DWORD OEMSourceMediaType,
  9500. IN DWORD CopyStyle,
  9501. OUT PWSTR DestinationInfFileName, OPTIONAL
  9502. IN DWORD DestinationInfFileNameSize,
  9503. OUT PDWORD RequiredSize, OPTIONAL
  9504. OUT PWSTR *DestinationInfFileNameComponent OPTIONAL
  9505. )
  9506. {
  9507. UNREFERENCED_PARAMETER(SourceInfFileName);
  9508. UNREFERENCED_PARAMETER(OEMSourceMediaLocation);
  9509. UNREFERENCED_PARAMETER(OEMSourceMediaType);
  9510. UNREFERENCED_PARAMETER(CopyStyle);
  9511. UNREFERENCED_PARAMETER(DestinationInfFileName);
  9512. UNREFERENCED_PARAMETER(DestinationInfFileNameSize);
  9513. UNREFERENCED_PARAMETER(RequiredSize);
  9514. UNREFERENCED_PARAMETER(DestinationInfFileNameComponent);
  9515. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  9516. return FALSE;
  9517. }
  9518. #endif
  9519. BOOL
  9520. WINAPI
  9521. SetupCopyOEMInf(
  9522. IN PCTSTR SourceInfFileName,
  9523. IN PCTSTR OEMSourceMediaLocation, OPTIONAL
  9524. IN DWORD OEMSourceMediaType,
  9525. IN DWORD CopyStyle,
  9526. OUT PTSTR DestinationInfFileName, OPTIONAL
  9527. IN DWORD DestinationInfFileNameSize,
  9528. OUT PDWORD RequiredSize, OPTIONAL
  9529. OUT PTSTR *DestinationInfFileNameComponent OPTIONAL
  9530. )
  9531. /*++
  9532. Routine Description:
  9533. This API copies an INF into %windir%\Inf, giving it a unique name if it
  9534. doesn't already exist there. We determine whether the INF already exists
  9535. in the INF directory as follows:
  9536. 1. All INFs of the form "OEM*.INF" are enumerated, and any that have the
  9537. same file size as that of our INF are binary-compared with it.
  9538. 2. We also look for the INF using its source filename. If a file of the
  9539. same name exists, and is the same size as that of our INF, we
  9540. binary-compare the two to see if they are identical.
  9541. If the INF already exists (by either of the two criteria described above),
  9542. then we will further check to see if the INF specifies a CatalogFile= entry
  9543. in its version section. If so, we will see if that catalog is already
  9544. installed (using the INF's %windir%\Inf primary filename with a ".CAT"
  9545. extension). If there is a catalog installed, but it isn't the same as the
  9546. catalog associated with the source INF, then we won't consider that INF to
  9547. be a match, and we'll keep enumerating looking for a match. This means
  9548. it's possible to have multiple identical INFs contained in %windir%\Inf,
  9549. each having its own unique catalog. (In general, this shouldn't happen,
  9550. since driver package updates should also update the DriverVer information
  9551. in the INF, thus you wouldn't get identical INFs in the first place.) If
  9552. we don't find an existing match (i.e., both INF and CAT), then we'll
  9553. install the INF and CAT under a new, unique name.
  9554. OEM INFs that don't specify a CatalogFile= entry are considered invalid
  9555. w.r.t. digital signature verification.
  9556. In cases where the INF must be copied to %windir%\Inf (i.e., it wasn't
  9557. already there), we'll report any digital signature verification failures
  9558. (based on applicable policy).
  9559. If we decide that the INF/CAT files already exist, then we will use that
  9560. name, and our replacement behavior is based on the caller-specified
  9561. CopyStyle flags. (NOTE: Replacement behavior here refers solely to the
  9562. source media information stored in the PNF. We will not blow away existing
  9563. INFs/PNFs/CATs under any circumstances.)
  9564. Arguments:
  9565. SourceInfFileName - Specifies the full path to the INF to be copied.
  9566. OEMSourceMediaLocation - Specifies source location information to be stored
  9567. in the precompiled INF (.PNF), thus allowing the system to go to the
  9568. correct location for files when installing from this INF. This location
  9569. information is specific to the source media type specified.
  9570. OEMSourceMediaType - Specifies the type of source media that the location
  9571. information references. May be one of the following values:
  9572. SPOST_NONE - No source media information should be stored in the PNF
  9573. file. (OEMSourceMediaLocation is ignored in this case.)
  9574. SPOST_PATH - OEMSourceMediaLocation contains a path to the source media.
  9575. For example, if the media is on a floppy, this path might
  9576. be "A:\". If OEMSourceMediaLocation is NULL, then the path
  9577. is assumed to be the path where the INF is located (unless
  9578. the INF has a corresponding PNF in that location, in which
  9579. case that PNF's source media information will be
  9580. transferred to the destination PNF).
  9581. SPOST_URL - OEMSourceMediaLocation contains a URL indicating the
  9582. internet location where the INF/driver files were retrieved
  9583. from. If OEMSourceMediaLocation is NULL, then it is
  9584. assumed that the default Code Download Manager location was
  9585. used.
  9586. CopyStyle - Specifies flags that control how the INF is copied into the INF
  9587. directory. May be a combination of the following flags (all other
  9588. SP_COPY_* flags are ignored).
  9589. SP_COPY_DELETESOURCE - Delete source file on successful copy.
  9590. SP_COPY_REPLACEONLY - Copy only if this file already exists in the INF
  9591. directory. This could be used to update the
  9592. source location information for an existing INF.
  9593. SP_COPY_NOOVERWRITE - Copy only if this files doesn't already exist in
  9594. the INF directory. If the INF _does_ already
  9595. exist, this API will fail with GetLastError
  9596. returning ERROR_FILE_EXISTS. In this case, the
  9597. destination INF file information output buffers
  9598. will be filled in for the existing INF's filename.
  9599. SP_COPY_OEMINF_CATALOG_ONLY - Don't copy the INF into %windir%\Inf--just
  9600. install its corresponding catalog file.
  9601. If this flag is specified, then the
  9602. destination filename information will only
  9603. be filled out upon successful return if
  9604. the INF is already in the Inf directory.
  9605. SP_COPY_OEM_F6_INF - The Inf was installed by the user during textmode
  9606. setup using F6.
  9607. DestinationInfFileName - Optionally, supplies a character buffer that
  9608. receives the name that the INF was assigned when it was copied into the
  9609. INF directory. If the SP_COPY_NOOVERWRITE flag is specified, and the
  9610. API fails with ERROR_FILE_EXISTS, then this buffer will contain the name
  9611. of the existing INF.
  9612. If the SP_COPY_OEMINF_CATALOG_ONLY flag was specified, then this buffer
  9613. will only be filled in with a destination INF filename if the INF is
  9614. already in the INF directory. Otherwise, this buffer will be set to the
  9615. empty string.
  9616. DestinationInfFileNameSize - Specifies the size, in characters, of the
  9617. DestinationInfFileName buffer, or zero if the buffer is not specified.
  9618. If DestinationInfFileName is specified, and this buffer size is less
  9619. than the size required to return the destination INF name (including
  9620. full path), then this API will fail, and GetLastError will return
  9621. ERROR_INSUFFICIENT_BUFFER.
  9622. RequiredSize - Optionally, supplies the address of a variable that receives
  9623. the size (in characters) required to store the destination INF file name
  9624. (including terminating NULL.
  9625. If the SP_COPY_OEMINF_CATALOG_ONLY flag was specified, then this
  9626. variable will only receive a string length if the INF is already in the
  9627. INF directory. Otherwise, this variable will be set to zero.
  9628. DestinationInfFileNameComponent - Optionally, supplies the address of a
  9629. character pointer that is set, upon successful return (or
  9630. ERROR_FILE_EXISTS), to point to the beginning of the filename component
  9631. of the path stored in DestinationInfFileName.
  9632. If the SP_COPY_OEMINF_CATALOG_ONLY flag was specified, then the
  9633. DestinationInfFileName may be an empty string (see above). In that case
  9634. this character pointer will be set to NULL upon successful return.
  9635. Return Value:
  9636. If the function succeeds, the return value is TRUE.
  9637. If the function fails, the return value is FALSE. To get extended error
  9638. information, call GetLastError.
  9639. --*/
  9640. {
  9641. TCHAR SourceInfCatalogName[MAX_PATH];
  9642. TCHAR CatalogFilenameOnSystem[MAX_PATH];
  9643. DWORD rc;
  9644. BOOL DifferentOriginalName;
  9645. TCHAR OriginalInfName[MAX_PATH];
  9646. HINF hInf;
  9647. DWORD CodeSigningPolicy;
  9648. BOOL UseOriginalInfName;
  9649. PSETUP_LOG_CONTEXT LogContext = NULL;
  9650. PSP_ALTPLATFORM_INFO_V2 ValidationPlatform;
  9651. //
  9652. // Open the specified INF.
  9653. //
  9654. hInf = SetupOpenInfFile(SourceInfFileName,
  9655. NULL,
  9656. INF_STYLE_OLDNT | INF_STYLE_WIN4,
  9657. NULL
  9658. );
  9659. if(hInf == INVALID_HANDLE_VALUE) {
  9660. //
  9661. // last error already set.
  9662. //
  9663. return FALSE;
  9664. }
  9665. ValidationPlatform = NULL;
  9666. //
  9667. // GetCodeSigningPolicyForInf() presently can generate an unhandled
  9668. // exception, so guard the code below in try/except to protect ourselves...
  9669. //
  9670. try {
  9671. if(NO_ERROR != InheritLogContext(((PLOADED_INF)hInf)->LogContext,
  9672. &LogContext)) {
  9673. LogContext = NULL;
  9674. }
  9675. //
  9676. // Retrieve the CatalogFile entry (if present) from this INF's version
  9677. // section.
  9678. //
  9679. rc = pGetInfOriginalNameAndCatalogFile(
  9680. NULL,
  9681. SourceInfFileName,
  9682. &DifferentOriginalName,
  9683. OriginalInfName,
  9684. SIZECHARS(OriginalInfName),
  9685. SourceInfCatalogName,
  9686. SIZECHARS(SourceInfCatalogName),
  9687. NULL // always native OS/arch (ver doesn't matter for CatalogFile=)
  9688. );
  9689. if(rc == NO_ERROR) {
  9690. CodeSigningPolicy = GetCodeSigningPolicyForInf(LogContext,
  9691. hInf,
  9692. &ValidationPlatform,
  9693. &UseOriginalInfName
  9694. );
  9695. if(UseOriginalInfName) {
  9696. //
  9697. // If we're looking at an exception INF, make sure it's under its
  9698. // original name.
  9699. //
  9700. if(DifferentOriginalName) {
  9701. rc = ERROR_INVALID_CLASS;
  9702. }
  9703. }
  9704. }
  9705. } except(EXCEPTION_EXECUTE_HANDLER) {
  9706. //
  9707. // If we hit an AV, then use invalid parameter error, otherwise, assume
  9708. // an inpage error when dealing with a mapped-in file (e.g., in the
  9709. // call to GetCodeSigningPolicyForInf).
  9710. //
  9711. rc = (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? ERROR_INVALID_PARAMETER : ERROR_READ_FAULT;
  9712. }
  9713. //
  9714. // We're done with the INF handle
  9715. //
  9716. SetupCloseInfFile(hInf);
  9717. if(rc != NO_ERROR) {
  9718. goto final;
  9719. }
  9720. if(_SetupCopyOEMInf(SourceInfFileName,
  9721. OEMSourceMediaLocation,
  9722. OEMSourceMediaType,
  9723. CopyStyle,
  9724. DestinationInfFileName,
  9725. DestinationInfFileNameSize,
  9726. RequiredSize,
  9727. DestinationInfFileNameComponent,
  9728. (DifferentOriginalName ? OriginalInfName
  9729. : pSetupGetFileTitle(SourceInfFileName)),
  9730. (*SourceInfCatalogName ? SourceInfCatalogName : NULL),
  9731. NULL, // no HWND for UI!
  9732. NULL,
  9733. CodeSigningPolicy,
  9734. SCOI_NO_ERRLOG_IF_INF_ALREADY_PRESENT |
  9735. (UseOriginalInfName ? SCOI_KEEP_INF_AND_CAT_ORIGINAL_NAMES : 0),
  9736. NULL,
  9737. ValidationPlatform,
  9738. NULL,
  9739. CatalogFilenameOnSystem,
  9740. LogContext, // either made-up or thread log context
  9741. NULL
  9742. )) {
  9743. rc = NO_ERROR;
  9744. } else {
  9745. rc = GetLastError();
  9746. }
  9747. final:
  9748. if(ValidationPlatform) {
  9749. MyFree(ValidationPlatform);
  9750. }
  9751. DeleteLogContext(LogContext);
  9752. if(rc != NO_ERROR) {
  9753. SetLastError(rc);
  9754. return FALSE;
  9755. } else {
  9756. return TRUE;
  9757. }
  9758. }
  9759. BOOL
  9760. _SetupCopyOEMInf(
  9761. IN PCTSTR SourceInfFileName,
  9762. IN PCTSTR OEMSourceMediaLocation, OPTIONAL
  9763. IN DWORD OEMSourceMediaType,
  9764. IN DWORD CopyStyle,
  9765. OUT PTSTR DestinationInfFileName, OPTIONAL
  9766. IN DWORD DestinationInfFileNameSize,
  9767. OUT PDWORD RequiredSize, OPTIONAL
  9768. OUT PTSTR *DestinationInfFileNameComponent, OPTIONAL
  9769. IN PCTSTR SourceInfOriginalName,
  9770. IN PCTSTR SourceInfCatalogName, OPTIONAL
  9771. IN HWND Owner,
  9772. IN PCTSTR DeviceDesc, OPTIONAL
  9773. IN DWORD DriverSigningPolicy,
  9774. IN DWORD Flags,
  9775. IN PCTSTR AltCatalogFile, OPTIONAL
  9776. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  9777. OUT PDWORD DriverSigningError, OPTIONAL
  9778. OUT PTSTR CatalogFilenameOnSystem,
  9779. IN PSETUP_LOG_CONTEXT LogContext,
  9780. IN OUT HCATADMIN *hCatAdmin OPTIONAL
  9781. )
  9782. /*++
  9783. Routine Description:
  9784. (See SetupCopyOEMInf)
  9785. Arguments:
  9786. (See SetupCopyOEMInf)
  9787. SourceInfOriginalName - supplies the simple filename (no path) that this INF
  9788. originally had. This will typically be the same as its current name,
  9789. except in cases where there's a valid PNF for that INF, and the PNF
  9790. specifies a different original name.
  9791. SourceInfCatalogName - Optionally, supplies the simple filename of the
  9792. catalog file specified by the OEM INF via a CatalogFile= entry in its
  9793. [Version] section. If this parameter is not specified, then the INF
  9794. doesn't specify an associated catalog. (NOTE: One may still be used if
  9795. the AltCatalogFile parameter is specified.
  9796. Owner - supplies window handle to be used for any UI related to digital
  9797. signature verification failures.
  9798. DeviceDesc - Optionally, supplies the device description to be used in the
  9799. digital signature verification error dialogs that may be popped up.
  9800. DriverSigningPolicy - supplies the driver signing policy currently in
  9801. effect. Used when calling pSetupHandleFailedVerification, if necessary.
  9802. Flags - supplies flags which alter the behavior of the routine. May be a
  9803. combination of the following values:
  9804. SCOI_NO_UI_ON_SIGFAIL - indicates whether user should be prompted (per
  9805. DriverSigningPolicy) if a digital signature
  9806. failure is encountered. Used when calling
  9807. pSetupHandleFailedVerification, if necessary.
  9808. SCOI_NO_ERRLOG_ON_MISSING_CATALOG - if there's a signature verification
  9809. failure due to the INF lacking a
  9810. CatalogFile= entry, then that error
  9811. will be ignored if this flag is set
  9812. (no UI will be given, and no log
  9813. entry will be generated).
  9814. SCOI_NO_ERRLOG_IF_INF_ALREADY_PRESENT - If we discover that the INF
  9815. already exists in %windir%\Inf,
  9816. then don't popup any UI and
  9817. don't even generate an error
  9818. log entry.
  9819. SCOI_KEEP_INF_AND_CAT_ORIGINAL_NAMES - Install the INF and CAT under
  9820. their original (current) names
  9821. (i.e., don't generate a unique
  9822. oem<n>.inf/cat name). Used only
  9823. for exception INFs.
  9824. SCOI_ABORT_IF_UNSIGNED - If the INF is unsigned (and user wants to copy
  9825. it anyway, or policy is Ignore), then _don't_
  9826. copy the INF and instead return the error
  9827. ERROR_SET_SYSTEM_RESTORE_POINT. This gives
  9828. the caller a chance to set a system restore
  9829. point prior to installing the unsigned package.
  9830. SCOI_TRY_UPDATE_PNF - If an existing PNF cannot be updated, don't
  9831. consider it fatal.
  9832. AltCatalogFile - Optionally, supplies the name of a catalog file to be
  9833. installed and used for verification of the INF in cases where the INF
  9834. doesn't specify a CatalogFile= entry (i.e., when the
  9835. SourceInfCatalogName parameter is not specified.
  9836. AltPlatformInfo - Optionally, supplies alternate platform information to be
  9837. used in digital signature verification instead of the default (native)
  9838. platform info.
  9839. DriverSigningError - Optionally, supplies the address of a variable that
  9840. receives the error encountered when attempting to verify the digital
  9841. signature of either the INF or associated catalog. If no digital
  9842. signature problems were encountered, this is set to NO_ERROR. (Note
  9843. that this value can come back as NO_ERROR, yet _SetupCopyOEMInf still
  9844. failed for some other reason).
  9845. CatalogFilenameOnSystem - Receives the fully-qualified path of the catalog
  9846. file within the catalog store where this INF's catalog file was
  9847. installed to. This buffer should be at least MAX_PATH bytes (ANSI
  9848. version) or chars (Unicode version).
  9849. LogContext - supplies a LogContext to be passed to GetNewInfName.
  9850. hCatAdmin - optionally, supplies the address of an HCATADMIN handle. If
  9851. the handle pointed to is NULL, a handle will be acquired (if possible)
  9852. via CryptCATAdminAcquireContext and returned to the caller. If the
  9853. handle pointed to is non-NULL, then that handle will be used for any
  9854. validation done via this routine. If the pointer itself is NULL, then
  9855. an hCatAdmin will be acquired for the duration of this call, and
  9856. released before returning.
  9857. NOTE: it is the caller's responsibility to free the crypto context
  9858. handle returned by this routine by calling CryptCATAdminReleaseContext.
  9859. This handle may be opened in either success or failure cases, so the
  9860. caller must check for non-NULL returned handle in both cases.
  9861. Return Value:
  9862. If the function succeeds, the return value is TRUE.
  9863. If the function fails, the return value is FALSE. To get extended error
  9864. information, call GetLastError.
  9865. --*/
  9866. {
  9867. TCHAR NewName[MAX_PATH];
  9868. DWORD TempRequiredSize, Err;
  9869. NEWINF_COPYTYPE CopyNeeded;
  9870. WIN32_FIND_DATA FindData;
  9871. PLOADED_INF PrecompiledNewInf;
  9872. UINT ErrorLineNumber;
  9873. TCHAR TempOemSourceMediaLocation[MAX_PATH];
  9874. PTSTR TempCharPtr;
  9875. BOOL AlternateCatInstalled;
  9876. DWORD TempDriverSigningError;
  9877. DWORD DefaultSourceMediaType;
  9878. HINF hInf;
  9879. if (DriverSigningError) {
  9880. *DriverSigningError = NO_ERROR;
  9881. }
  9882. //
  9883. // If the DestinationInfFileName buffer is NULL, the size had better be
  9884. // zero. Also, make sure the caller passed us a valid OEMSourceMediaType.
  9885. //
  9886. if((!DestinationInfFileName && DestinationInfFileNameSize) ||
  9887. (OEMSourceMediaType >= SPOST_MAX))
  9888. {
  9889. MYASSERT(!DriverSigningError);
  9890. SetLastError(ERROR_INVALID_PARAMETER);
  9891. return FALSE;
  9892. }
  9893. //
  9894. // If we're installing an exception INF, it's illegal to request that we
  9895. // not copy the INF.
  9896. //
  9897. if((Flags & SCOI_KEEP_INF_AND_CAT_ORIGINAL_NAMES) &&
  9898. (CopyStyle & SP_COPY_OEMINF_CATALOG_ONLY))
  9899. {
  9900. SetLastError(ERROR_INVALID_PARAMETER);
  9901. return FALSE;
  9902. }
  9903. Err = NO_ERROR;
  9904. CopyNeeded = NewInfCopyNo;
  9905. AlternateCatInstalled = FALSE;
  9906. TempCharPtr = NULL;
  9907. hInf = INVALID_HANDLE_VALUE;
  9908. try {
  9909. //
  9910. // Check to see if the INF is already in the %windir%\Inf directory, and
  9911. // create a uniquely-named, zero-length placeholder file if it isn't.
  9912. //
  9913. Err = GetNewInfName(Owner,
  9914. SourceInfFileName,
  9915. SourceInfOriginalName,
  9916. SourceInfCatalogName,
  9917. NewName,
  9918. SIZECHARS(NewName),
  9919. &TempRequiredSize,
  9920. &CopyNeeded,
  9921. CopyStyle & SP_COPY_REPLACEONLY,
  9922. DeviceDesc,
  9923. DriverSigningPolicy,
  9924. Flags,
  9925. AltCatalogFile,
  9926. AltPlatformInfo,
  9927. &TempDriverSigningError,
  9928. CatalogFilenameOnSystem,
  9929. LogContext,
  9930. hCatAdmin
  9931. );
  9932. if(DriverSigningError) {
  9933. *DriverSigningError = TempDriverSigningError;
  9934. }
  9935. if(Err != NO_ERROR) {
  9936. //
  9937. // Value of CopyNeeded parameter is undefined upon error, but we do
  9938. // know that no clean-up will be necessary if GetNewInfName fails.
  9939. //
  9940. CopyNeeded = NewInfCopyNo;
  9941. //
  9942. // If we were only trying to get the catalog installed, and the
  9943. // failure was for some reason _other_ than a digital signature
  9944. // verification failure (e.g., we couldn't create the placeholder
  9945. // INF in %windir%\Inf), then we want to treat this as if it were
  9946. // a signature verification failure. Since we aren't trying to
  9947. // install the full INF, this implies that we aren't doing a device
  9948. // install, thus the policy is going to be non-driver-signing
  9949. // policy. This has the default of "Ignore", which is fortunate,
  9950. // since the dialog complains about an unsigned driver package when
  9951. // in fact we don't really know whether or not the package is
  9952. // unsigned--all we know is that we couldn't install its catalog,
  9953. // even if it had one.
  9954. //
  9955. // Note: if the user clicks the "More Info..." button, we will tell
  9956. // them that the catalog installation failed, and what a possible
  9957. // cause might be (e.g., no write access to Windows directory).
  9958. //
  9959. if((CopyStyle & SP_COPY_OEMINF_CATALOG_ONLY) &&
  9960. (TempDriverSigningError == NO_ERROR)) {
  9961. if(SourceInfCatalogName) {
  9962. //
  9963. // Typical case (INF specified a catalog), give the user
  9964. // some indication (via codesigning popup based on policy)
  9965. // about what went wrong...
  9966. //
  9967. if(pSetupHandleFailedVerification(
  9968. Owner,
  9969. SetupapiVerifyCatalogInstallProblem,
  9970. SourceInfCatalogName,
  9971. DeviceDesc,
  9972. DriverSigningPolicy,
  9973. (Flags & SCOI_NO_UI_ON_SIGFAIL),
  9974. Err,
  9975. LogContext,
  9976. NULL,
  9977. NULL))
  9978. {
  9979. TempDriverSigningError = Err;
  9980. if(DriverSigningError) {
  9981. *DriverSigningError = TempDriverSigningError;
  9982. }
  9983. //
  9984. // The user wants to proceed with the unsigned
  9985. // installation (or policy is Ignore, so they weren't
  9986. // even informed). If the caller wants a chance to set
  9987. // a system restore point prior to doing any unsigned
  9988. // installations, then we abort now with a "special"
  9989. // error code that tells them what to do...
  9990. //
  9991. if(Flags & SCOI_ABORT_IF_UNSIGNED) {
  9992. Err = ERROR_SET_SYSTEM_RESTORE_POINT;
  9993. } else {
  9994. //
  9995. // We should consider the operation a success, even
  9996. // though we couldn't install the catalog.
  9997. //
  9998. Err = NO_ERROR;
  9999. }
  10000. }
  10001. } else {
  10002. //
  10003. // Unlikely scenario (INF didn't specify a catalog, yet we
  10004. // were called with SP_COPY_OEMINF_CATALOG_ONLY???), just
  10005. // ignore the issue, generate a setupapi.log entry, and
  10006. // proceed...
  10007. //
  10008. WriteLogEntry(LogContext,
  10009. SETUP_LOG_ERROR | SETUP_LOG_BUFFER,
  10010. MSG_LOG_FAILED_INF_INSTALL,
  10011. NULL,
  10012. SourceInfFileName
  10013. );
  10014. WriteLogError(LogContext,
  10015. SETUP_LOG_ERROR,
  10016. Err
  10017. );
  10018. TempDriverSigningError = Err;
  10019. if(DriverSigningError) {
  10020. *DriverSigningError = TempDriverSigningError;
  10021. }
  10022. Err = NO_ERROR;
  10023. }
  10024. if(Err == NO_ERROR) {
  10025. //
  10026. // In this case, we don't have a filename to return to the
  10027. // caller.
  10028. //
  10029. if(RequiredSize) {
  10030. *RequiredSize = 0;
  10031. }
  10032. if(DestinationInfFileName && DestinationInfFileNameSize) {
  10033. *DestinationInfFileName = TEXT('\0');
  10034. }
  10035. if(DestinationInfFileNameComponent) {
  10036. *DestinationInfFileNameComponent = NULL;
  10037. }
  10038. }
  10039. }
  10040. goto clean0;
  10041. }
  10042. //
  10043. // OK, we have a filename to copy to, now copy the file (if necessary),
  10044. // unless the caller doesn't want to overwrite the existing file.
  10045. //
  10046. if(CopyNeeded != NewInfCopyNo) {
  10047. //
  10048. // We either created a new zero-length placeholder file ourselves,
  10049. // or we found an existing placeholder that we could use.
  10050. //
  10051. // Copy our INF over the top of this placeholder file, unless the
  10052. // caller specified the SP_COPY_OEMINF_CATALOG_ONLY flag, in which
  10053. // case we want to leave the zero-length file as-is (and mark it
  10054. // hidden), so that no other OEM INFs can subsequently get this name
  10055. // (hence causing namespace collisions for the catalog files).
  10056. //
  10057. if(!(CopyStyle & SP_COPY_OEMINF_CATALOG_ONLY)) {
  10058. //
  10059. // Reset the existing file's attributes prior to attempting the
  10060. // copy.
  10061. //
  10062. SetFileAttributes(NewName, FILE_ATTRIBUTE_NORMAL);
  10063. if(!CopyFile(SourceInfFileName, NewName, FALSE)) {
  10064. Err = GetLastError();
  10065. goto clean0;
  10066. }
  10067. } else {
  10068. //
  10069. // If we didn't encounter a driver signing error, or if the
  10070. // zero-length file was already present, then just make sure
  10071. // it's marked as hidden.
  10072. //
  10073. if((TempDriverSigningError == NO_ERROR) || (CopyNeeded == NewInfCopyZeroLength)) {
  10074. //
  10075. // Mark the zero-length file as hidden.
  10076. //
  10077. SetFileAttributes(NewName, FILE_ATTRIBUTE_HIDDEN);
  10078. } else {
  10079. //
  10080. // Delete the newly-created zero-length placeholder INF,
  10081. // because it serves no purpose.
  10082. //
  10083. SetFileAttributes(NewName, FILE_ATTRIBUTE_NORMAL);
  10084. DeleteFile(NewName);
  10085. }
  10086. //
  10087. // Since we only have a zero-length placeholder (or possibly, no
  10088. // placeholder at all if catalog installation failed), we
  10089. // shouldn't return a filename to the caller.
  10090. //
  10091. if(RequiredSize) {
  10092. *RequiredSize = 0;
  10093. }
  10094. if(DestinationInfFileName && DestinationInfFileNameSize) {
  10095. *DestinationInfFileName = TEXT('\0');
  10096. }
  10097. if(DestinationInfFileNameComponent) {
  10098. *DestinationInfFileNameComponent = NULL;
  10099. }
  10100. //
  10101. // We're done!
  10102. //
  10103. goto clean0;
  10104. }
  10105. } else {
  10106. //
  10107. // If the original INF name and the new INF name are different, then
  10108. // we know this wasn't an alternate catalog-only install.
  10109. //
  10110. AlternateCatInstalled = !lstrcmpi(SourceInfFileName, NewName);
  10111. if((CopyStyle & SP_COPY_NOOVERWRITE) && !AlternateCatInstalled) {
  10112. //
  10113. // OK, the INF already exists in the INF directory, and the
  10114. // caller has specified that they _do not_ want to wipe out the
  10115. // existing PNF. We may need to return back the name of the
  10116. // existing INF if they requested it, however.
  10117. //
  10118. Err = ERROR_FILE_EXISTS;
  10119. }
  10120. }
  10121. //
  10122. // If we get to here, then the INF exists in %windir%\Inf, and we either
  10123. // have no error, or ERROR_FILE_EXISTS. Next, we need to store the name
  10124. // of the INF in the caller's buffer (if supplied).
  10125. //
  10126. if(RequiredSize) {
  10127. *RequiredSize = TempRequiredSize;
  10128. }
  10129. if(DestinationInfFileName) {
  10130. if(DestinationInfFileNameSize >= TempRequiredSize) {
  10131. CopyMemory(DestinationInfFileName, NewName, TempRequiredSize * sizeof(TCHAR));
  10132. //
  10133. // If requested by the caller, return a pointer to the filename
  10134. // part of this path.
  10135. //
  10136. if(DestinationInfFileNameComponent) {
  10137. *DestinationInfFileNameComponent = (PTSTR)pSetupGetFileTitle(DestinationInfFileName);
  10138. }
  10139. } else {
  10140. Err = ERROR_INSUFFICIENT_BUFFER;
  10141. }
  10142. } else {
  10143. //
  10144. // Nobody should be requesting a pointer to the filename component of
  10145. // the path when they don't supply us a buffer to store the full path.
  10146. // If anyone does do this, make sure we set the pointer to NULL.
  10147. //
  10148. if(DestinationInfFileNameComponent) {
  10149. *DestinationInfFileNameComponent = NULL;
  10150. }
  10151. }
  10152. if((Err != NO_ERROR) || AlternateCatInstalled) {
  10153. goto clean0;
  10154. }
  10155. //
  10156. // If the code calling this API claims that this INF is from the Internet we
  10157. // first want to check if there is a PNF for this INF and that the PNF agrees
  10158. // that this INF is from the Internet. If the PNF says the INF is from a location
  10159. // other than the Internet then we will change the OEMSourceMediaType to this
  10160. // other media type. We will also set teh OEMSourceMediaLocation to NULL. This has
  10161. // the desired affect of us falling through the next if statement which will read the
  10162. // SourceMediaLocation from the PNF instead of the current INF location.
  10163. // If their is no PNF for the given INF then we just leave OEMSourceMediaType alone.
  10164. //
  10165. if (OEMSourceMediaType == SPOST_URL) {
  10166. if (pSetupGetSourceMediaTypeFromPnf(SourceInfFileName, &DefaultSourceMediaType) &&
  10167. (DefaultSourceMediaType != SPOST_URL)) {
  10168. OEMSourceMediaType = DefaultSourceMediaType;
  10169. OEMSourceMediaLocation = NULL;
  10170. }
  10171. }
  10172. if(!OEMSourceMediaLocation && (OEMSourceMediaType == SPOST_PATH)) {
  10173. //
  10174. // The caller wants to store the OEM source path, but they didn't
  10175. // provide us with one to use. Thus, we'll use the path where the
  10176. // INF existed (unless there's a valid PNF there, in which case
  10177. // we'll use its SPOST_PATH information, if it has any).
  10178. // pSetupGetDefaultSourcePath() does just what we want.
  10179. //
  10180. hInf = SetupOpenInfFile(SourceInfFileName,
  10181. NULL,
  10182. INF_STYLE_WIN4 | INF_STYLE_OLDNT,
  10183. NULL
  10184. );
  10185. if(hInf == INVALID_HANDLE_VALUE) {
  10186. Err = GetLastError();
  10187. MYASSERT(Err != NO_ERROR);
  10188. goto clean0;
  10189. }
  10190. TempCharPtr = pSetupGetDefaultSourcePath(hInf, SRCPATH_USEINFLOCATION, &DefaultSourceMediaType);
  10191. //
  10192. // We don't need the INF handle anymore.
  10193. //
  10194. SetupCloseInfFile(hInf);
  10195. hInf = INVALID_HANDLE_VALUE;
  10196. MYASSERT(DefaultSourceMediaType == SPOST_PATH);
  10197. if(TempCharPtr) {
  10198. lstrcpy(TempOemSourceMediaLocation, TempCharPtr);
  10199. OEMSourceMediaLocation = TempOemSourceMediaLocation;
  10200. //
  10201. // We no longer need the buffer allocated for us by
  10202. // pSetupGetDefaultSourcePath.
  10203. //
  10204. MyFree(TempCharPtr);
  10205. //
  10206. // Reset this pointer so we won't try to free it should we
  10207. // subsequently encounter an exception.
  10208. //
  10209. TempCharPtr = NULL;
  10210. } else {
  10211. Err = GetLastError();
  10212. MYASSERT(Err != NO_ERROR);
  10213. goto clean0;
  10214. }
  10215. }
  10216. if(!FileExists(NewName, &FindData)) {
  10217. Err = GetLastError();
  10218. goto clean0;
  10219. }
  10220. Err = LoadInfFile(NewName,
  10221. &FindData,
  10222. INF_STYLE_WIN4 | INF_STYLE_OLDNT,
  10223. LDINF_FLAG_ALWAYS_TRY_PNF
  10224. | LDINF_FLAG_REGENERATE_PNF
  10225. | ((Flags & SCOI_TRY_UPDATE_PNF) ? LDINF_FLAG_ALLOW_PNF_SHARING_LOCK : 0)
  10226. | ((OEMSourceMediaType == SPOST_URL) ? LDINF_FLAG_SRCPATH_IS_URL : 0)
  10227. | ((CopyStyle & SP_COPY_OEM_F6_INF) ? LDINF_FLAG_OEM_F6_INF : 0),
  10228. NULL,
  10229. (OEMSourceMediaType == SPOST_NONE) ? NULL : OEMSourceMediaLocation,
  10230. (lstrcmpi(SourceInfOriginalName, pSetupGetFileTitle(NewName))
  10231. ? SourceInfOriginalName
  10232. : NULL),
  10233. NULL,
  10234. LogContext,
  10235. &PrecompiledNewInf,
  10236. &ErrorLineNumber,
  10237. NULL
  10238. );
  10239. if(Err != NO_ERROR) {
  10240. goto clean0;
  10241. }
  10242. //
  10243. // The INF was successfully precompiled.
  10244. //
  10245. FreeInfFile(PrecompiledNewInf);
  10246. //
  10247. // Finally, delete the source INF file if the caller requested it.
  10248. //
  10249. if(CopyStyle & SP_COPY_DELETESOURCE) {
  10250. DeleteFile(SourceInfFileName);
  10251. }
  10252. clean0: ; // nothing to do.
  10253. } except(EXCEPTION_EXECUTE_HANDLER) {
  10254. Err = ERROR_INVALID_PARAMETER;
  10255. if(TempCharPtr) {
  10256. MyFree(TempCharPtr);
  10257. }
  10258. if(hInf != INVALID_HANDLE_VALUE) {
  10259. SetupCloseInfFile(hInf);
  10260. }
  10261. //
  10262. // Reference the following variable so the compiler will respect statement
  10263. // ordering w.r.t. assignment.
  10264. //
  10265. CopyNeeded = CopyNeeded;
  10266. }
  10267. if((Err != NO_ERROR) && (CopyNeeded == NewInfCopyYes)) {
  10268. //
  10269. // We encountered an error, after GetNewInfName created a new, unique
  10270. // INF for us. Delete it now.
  10271. //
  10272. // (Note: we don't do clean-up when GetNewInfName found an existing,
  10273. // zero-length file for us to use, even if we may have subsequently
  10274. // copied the 'real' INF over the top of it. Since we believed the
  10275. // existing file to be a duplicate of our OEM INF, this should be OK--
  10276. // the worst that's going to happen is that an INF that was once zero-
  10277. // length is now a full-blown INF after SetupCopyOEMInf encountered an
  10278. // error.)
  10279. //
  10280. pSetupUninstallOEMInf(NewName, LogContext, SUOI_FORCEDELETE, NULL);
  10281. //
  10282. // NTRAID#256075-2000/08/18-JamieHun Handle Rollback of INF/PNF/CAT files
  10283. //
  10284. // If we were installing an exception INF and encountered an
  10285. // error, we may have already blown away a previous INF/CAT. In the
  10286. // future, we might want to look into doing a backup on the old INF/CAT
  10287. // before installing the new INF/CAT over the top of them.
  10288. //
  10289. }
  10290. SetLastError(Err);
  10291. return (Err == NO_ERROR);
  10292. }
  10293. #ifdef UNICODE
  10294. //
  10295. // ANSI version
  10296. //
  10297. BOOL
  10298. WINAPI
  10299. SetupUninstallOEMInfA(
  10300. IN PCSTR InfFileName,
  10301. IN DWORD Flags,
  10302. IN PVOID Reserved
  10303. )
  10304. {
  10305. DWORD Err;
  10306. PCWSTR UnicodeInfFileName;
  10307. BOOL b;
  10308. Err = pSetupCaptureAndConvertAnsiArg(InfFileName, &UnicodeInfFileName);
  10309. if(Err != NO_ERROR) {
  10310. SetLastError(Err);
  10311. return FALSE;
  10312. }
  10313. b = SetupUninstallOEMInfW(UnicodeInfFileName, Flags, Reserved);
  10314. Err = GetLastError();
  10315. MyFree(UnicodeInfFileName);
  10316. SetLastError(Err);
  10317. return b;
  10318. }
  10319. #else
  10320. //
  10321. // Unicode stub
  10322. //
  10323. BOOL
  10324. WINAPI
  10325. SetupUninstallOEMInfW(
  10326. IN PCWSTR InfFileName,
  10327. IN DWORD Flags,
  10328. IN PVOID Reserved
  10329. )
  10330. {
  10331. UNREFERENCED_PARAMETER(InfFileName);
  10332. UNREFERENCED_PARAMETER(Flags);
  10333. UNREFERENCED_PARAMETER(Reserved);
  10334. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  10335. return FALSE;
  10336. }
  10337. #endif
  10338. BOOL
  10339. WINAPI
  10340. SetupUninstallOEMInf(
  10341. IN PCTSTR InfFileName,
  10342. IN DWORD Flags,
  10343. IN PVOID Reserved
  10344. )
  10345. /*++
  10346. Routine Description:
  10347. This API uninstalls the specified INF file, and deletes the associated
  10348. .PNF and .CAT files, if they exist.
  10349. The default behavior of this API is to first verify that there are no
  10350. other devices, live or phantom, that are using this INF. If another
  10351. device is using this INF then it will not be uninstalled. This behavior
  10352. can be overwritten by the SUOI_FORCEDELETE flag.
  10353. Arguments:
  10354. InfFileName - Supplies the simple filename (no path) of the INF to be
  10355. uninstalled.
  10356. Flags - Supplies flags that alter the behavior of this API.
  10357. SUOI_FORCEDELETE - forces the INF, PNF, and CAT to be uninstalled, even
  10358. if another device is using this INF.
  10359. Reserved - Reserved for future use. Must be NULL.
  10360. Return Value:
  10361. If the function succeeds, the return value is TRUE.
  10362. If the function fails, the return value is FALSE. To get extended error
  10363. information, call GetLastError.
  10364. --*/
  10365. {
  10366. DWORD Err;
  10367. TCHAR InfFullPath[MAX_PATH];
  10368. if(Flags & ~(SUOI_FORCEDELETE)) {
  10369. SetLastError(ERROR_INVALID_FLAGS);
  10370. return FALSE;
  10371. }
  10372. if(Reserved) {
  10373. SetLastError(ERROR_INVALID_PARAMETER);
  10374. return FALSE;
  10375. }
  10376. try {
  10377. //
  10378. // INF filename must not contain path
  10379. //
  10380. if(InfFileName != pSetupGetFileTitle(InfFileName)) {
  10381. Err = ERROR_INVALID_PARAMETER;
  10382. goto clean0;
  10383. }
  10384. //
  10385. // Look for specified INF in %windir%\Inf...
  10386. //
  10387. lstrcpyn(InfFullPath, InfDirectory,SIZECHARS(InfFullPath));
  10388. pSetupConcatenatePaths(InfFullPath,
  10389. InfFileName,
  10390. SIZECHARS(InfFullPath),
  10391. NULL
  10392. );
  10393. if(!pSetupFileExists(InfFullPath, NULL)) {
  10394. Err = GetLastError();
  10395. goto clean0;
  10396. }
  10397. pSetupUninstallOEMInf(InfFullPath, NULL, Flags, &Err);
  10398. clean0:
  10399. ; // nothing to do
  10400. } except(EXCEPTION_EXECUTE_HANDLER) {
  10401. Err = ERROR_INVALID_PARAMETER;
  10402. }
  10403. SetLastError(Err);
  10404. return(Err == NO_ERROR);
  10405. }
  10406. BOOL
  10407. WINAPI
  10408. SetupDiRegisterCoDeviceInstallers(
  10409. IN HDEVINFO DeviceInfoSet,
  10410. IN PSP_DEVINFO_DATA DeviceInfoData
  10411. )
  10412. /*++
  10413. Routine Description:
  10414. Default handler for DIF_REGISTER_COINSTALLERS
  10415. This routine will install any (device-specific) co-installers specified
  10416. in an [<InstallSec>.CoInstallers] section, where <InstallSec> is the install
  10417. section name for the selected driver node, potentially decorated with
  10418. an OS/architecture-specific extension (e.g., "InstallSec.NTAlpha.CoInstallers").
  10419. AddReg entries listed in a CoInstallers section use the device's driver key
  10420. for their HKR. To register a device-specific co-installer, a REG_MULTI_SZ entry
  10421. titled "CoInstallers32" must be written to the driver key. Each entry in this list
  10422. has the following format:
  10423. dll[,procname]
  10424. where dll is the name of the module to load and procname is an optional entry
  10425. point name. If procname is not specified, then the entry point name
  10426. "CoDeviceInstall" will be used.
  10427. Arguments:
  10428. DeviceInfoSet - Supplies a handle to the device information set containing
  10429. a device information element for whom co-installers are to be registered.
  10430. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure for whom
  10431. co-installers are to be registered.
  10432. Return Value:
  10433. If the function succeeds, the return value is TRUE.
  10434. If the function fails, the return value is FALSE. To get extended error
  10435. information, call GetLastError.
  10436. Remarks:
  10437. If no driver is selected (i.e., this is a null-driver installation), then
  10438. this routine does nothing.
  10439. --*/
  10440. {
  10441. return _SetupDiRegisterCoDeviceInstallers(DeviceInfoSet,
  10442. DeviceInfoData,
  10443. TRUE,
  10444. INVALID_HANDLE_VALUE,
  10445. INVALID_HANDLE_VALUE
  10446. );
  10447. }
  10448. BOOL
  10449. _SetupDiRegisterCoDeviceInstallers(
  10450. IN HDEVINFO DeviceInfoSet,
  10451. IN PSP_DEVINFO_DATA DeviceInfoData,
  10452. IN BOOL DoFullInstall,
  10453. IN HINF hDeviceInf, OPTIONAL
  10454. IN HSPFILEQ UserFileQ OPTIONAL
  10455. )
  10456. /*++
  10457. Routine Description:
  10458. Worker routine for both SetupDiRegisterCoDeviceInstallers and SetupDiInstallDriverFiles.
  10459. See the description of SetupDiRegisterCoDeviceInstallers for more information.
  10460. Arguments:
  10461. DeviceInfoSet - Supplies a handle to the device information set containing
  10462. a device information element for whom co-installers are to be registered.
  10463. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure for whom
  10464. co-installers are to be registered.
  10465. DoFullInstall - If TRUE (non-zero), then the co-installers are completely registered,
  10466. otherwise, only files are copied.
  10467. hDeviceInf - Optionally, supplies a handle to the INF for which installation
  10468. is being performed. If this handle is not supplied, the INF specified in
  10469. the selected driver node will be opened. If this handle is not supplied,
  10470. this parameter must be set to INVALID_HANDLE_VALUE.
  10471. UserFileQ - Optionally, supplies a file queue where file operations should be added.
  10472. If this handle is not supplied, then the queue associated with this devinfo
  10473. element will be used (if the DI_NOVCP flag is set), or one will be automatically
  10474. generated and committed. If this handle is not supplied, this parameter must
  10475. be set to INVALID_HANDLE_VALUE.
  10476. Return Value:
  10477. If the function succeeds, the return value is TRUE.
  10478. If the function fails, the return value is FALSE. To get extended error
  10479. information, call GetLastError.
  10480. Remarks:
  10481. During GUI-mode setup on Windows NT, quiet-install behavior is always
  10482. employed in the absence of a user-supplied file queue, regardless of
  10483. whether the device information element has the DI_QUIETINSTALL flag set.
  10484. --*/
  10485. {
  10486. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  10487. DWORD Err, ScanQueueResult;
  10488. PDEVINFO_ELEM DevInfoElem;
  10489. HWND hwndParent;
  10490. BOOL CloseUserFileQ;
  10491. PTSTR szInfFileName, szInfSectionName;
  10492. TCHAR InfSectionWithExt[MAX_SECT_NAME_LEN];
  10493. DWORD InfSectionWithExtLength;
  10494. BOOL FreeMsgHandlerContext;
  10495. PSP_FILE_CALLBACK MsgHandler;
  10496. PVOID MsgHandlerContext;
  10497. BOOL MsgHandlerIsNativeCharWidth, DeleteDrvRegKey;
  10498. HKEY hkDrv;
  10499. BOOL CloseInfHandle;
  10500. BOOL DoFileCopying;
  10501. INT FileQueueNeedsReboot;
  10502. PSETUP_LOG_CONTEXT LogContext = NULL;
  10503. DWORD slot_section = 0;
  10504. BOOL NoProgressUI;
  10505. TCHAR szNewName[MAX_PATH];
  10506. BOOL OemInfFileToCopy = FALSE;
  10507. //
  10508. // A device information element must be specified.
  10509. //
  10510. if(!DeviceInfoData) {
  10511. Err = ERROR_INVALID_PARAMETER;
  10512. goto clean1;
  10513. }
  10514. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  10515. Err = ERROR_INVALID_HANDLE;
  10516. goto clean1;
  10517. }
  10518. LogContext = pDeviceInfoSet->InstallParamBlock.LogContext;
  10519. Err = NO_ERROR;
  10520. hDeviceInf = INVALID_HANDLE_VALUE;
  10521. CloseUserFileQ = FALSE;
  10522. FreeMsgHandlerContext = FALSE;
  10523. hkDrv = INVALID_HANDLE_VALUE;
  10524. DeleteDrvRegKey = FALSE;
  10525. CloseInfHandle = FALSE;
  10526. try {
  10527. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  10528. DeviceInfoData,
  10529. NULL))) {
  10530. Err = ERROR_INVALID_PARAMETER;
  10531. goto clean0;
  10532. }
  10533. //
  10534. // This routine can't install a non-native driver
  10535. //
  10536. if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_ALTPLATFORM_DRVSEARCH) {
  10537. Err = ERROR_INVALID_FLAGS;
  10538. goto clean0;
  10539. }
  10540. //
  10541. // set the LogContext for this function
  10542. //
  10543. LogContext = DevInfoElem->InstallParamBlock.LogContext;
  10544. //
  10545. // If there's no driver selected (i.e., this is a null driver install), or we're
  10546. // using a legacy INF, then there's nothing for us to do.
  10547. //
  10548. if(!(DevInfoElem->SelectedDriver) ||
  10549. (DevInfoElem->SelectedDriver->Flags & DNF_LEGACYINF)) {
  10550. goto clean0;
  10551. }
  10552. //
  10553. // Make sure we only use the devinfo element's window if it's valid.
  10554. //
  10555. if(hwndParent = DevInfoElem->InstallParamBlock.hwndParent) {
  10556. if(!IsWindow(hwndParent)) {
  10557. hwndParent = NULL;
  10558. }
  10559. }
  10560. szInfFileName = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  10561. DevInfoElem->SelectedDriver->InfFileName
  10562. );
  10563. szInfSectionName = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  10564. DevInfoElem->SelectedDriver->InfSectionName
  10565. );
  10566. if(hDeviceInf == INVALID_HANDLE_VALUE) {
  10567. if((hDeviceInf = SetupOpenInfFile(szInfFileName,
  10568. NULL,
  10569. INF_STYLE_WIN4,
  10570. NULL)) == INVALID_HANDLE_VALUE) {
  10571. Err = GetLastError();
  10572. goto clean0;
  10573. }
  10574. CloseInfHandle = TRUE;
  10575. }
  10576. //
  10577. // see if we should give the INF the same LogContext as the DevInfoElem
  10578. //
  10579. InheritLogContext(LogContext,
  10580. &((PLOADED_INF) hDeviceInf)->LogContext);
  10581. slot_section = AllocLogInfoSlot(LogContext,FALSE);
  10582. //
  10583. // Find out the 'real' install section we should be using (i.e., the potentially
  10584. // OS/architecture-specific one.
  10585. //
  10586. if(!SetupDiGetActualSectionToInstall(hDeviceInf,
  10587. szInfSectionName,
  10588. InfSectionWithExt,
  10589. SIZECHARS(InfSectionWithExt),
  10590. &InfSectionWithExtLength,
  10591. NULL
  10592. )) {
  10593. Err = GetLastError();
  10594. goto clean0;
  10595. }
  10596. //
  10597. // Now append the ".CoInstallers" extension to the install section name to find
  10598. // the co-installer INF section to run.
  10599. //
  10600. CopyMemory(&(InfSectionWithExt[InfSectionWithExtLength - 1]),
  10601. pszCoInstallersSectionSuffix,
  10602. sizeof(pszCoInstallersSectionSuffix)
  10603. );
  10604. //
  10605. // Figure out whether we need to do file copying. (Ignore the DI_NOFILECOPY
  10606. // flag if we're doing a copy-only installation--that's what setupx does.)
  10607. //
  10608. DoFileCopying = (!(DevInfoElem->InstallParamBlock.Flags & DI_NOFILECOPY) || !DoFullInstall);
  10609. //
  10610. // Append the layout INF, if necessary.
  10611. //
  10612. if(DoFileCopying) {
  10613. SetupOpenAppendInfFile(NULL, hDeviceInf, NULL);
  10614. }
  10615. //
  10616. // Append-load any included INFs specified in an "include=" line in our
  10617. // install section.
  10618. //
  10619. AppendLoadIncludedInfs(hDeviceInf, szInfFileName, InfSectionWithExt, DoFileCopying);
  10620. //
  10621. // Now copy the files, if necessary.
  10622. //
  10623. if(DoFileCopying) {
  10624. if(UserFileQ == INVALID_HANDLE_VALUE) {
  10625. //
  10626. // If the DI_NOVCP flag is set, then just queue up the file
  10627. // copy/rename/delete operations. Otherwise, perform the
  10628. // actions.
  10629. //
  10630. if(DevInfoElem->InstallParamBlock.Flags & DI_NOVCP) {
  10631. //
  10632. // We must have a user-supplied file queue.
  10633. //
  10634. MYASSERT(DevInfoElem->InstallParamBlock.UserFileQ);
  10635. UserFileQ = DevInfoElem->InstallParamBlock.UserFileQ;
  10636. } else {
  10637. //
  10638. // Since we may need to check the queued files to determine whether file copy
  10639. // is necessary, we have to open our own queue, and commit it ourselves.
  10640. //
  10641. if((UserFileQ = SetupOpenFileQueue()) != INVALID_HANDLE_VALUE) {
  10642. CloseUserFileQ = TRUE;
  10643. } else {
  10644. //
  10645. // SetupOpenFileQueue sets actual error
  10646. //
  10647. Err = GetLastError();
  10648. goto clean0;
  10649. }
  10650. }
  10651. }
  10652. //
  10653. // See if we should replace the file queue's log context with the
  10654. // DevInfoElem's
  10655. //
  10656. InheritLogContext(LogContext,
  10657. &((PSP_FILE_QUEUE) UserFileQ)->LogContext);
  10658. WriteLogEntry(LogContext,
  10659. slot_section,
  10660. MSG_LOG_COINSTALLER_REGISTRATION,
  10661. NULL,
  10662. InfSectionWithExt);
  10663. Err = InstallFromInfSectionAndNeededSections(NULL,
  10664. hDeviceInf,
  10665. InfSectionWithExt,
  10666. SPINST_FILES,
  10667. NULL,
  10668. NULL,
  10669. SP_COPY_NEWER_OR_SAME | SP_COPY_LANGUAGEAWARE |
  10670. ((DevInfoElem->InstallParamBlock.Flags & DI_NOBROWSE) ? SP_COPY_NOBROWSE : 0),
  10671. NULL,
  10672. NULL,
  10673. INVALID_HANDLE_VALUE,
  10674. NULL,
  10675. UserFileQ
  10676. );
  10677. //
  10678. // Mark the queue as a device install queue (and make sure there's a
  10679. // catalog node representing our device INF in the queue).
  10680. //
  10681. Err = MarkQueueForDeviceInstall(UserFileQ,
  10682. hDeviceInf,
  10683. pStringTableStringFromId(
  10684. pDeviceInfoSet->StringTable,
  10685. DevInfoElem->SelectedDriver->DrvDescription)
  10686. );
  10687. //
  10688. // At this point, we have queued up all the files that need to be copied. If
  10689. // we weren't given a user-supplied queue, then commit our queue now.
  10690. //
  10691. if(CloseUserFileQ) {
  10692. if(Err == NO_ERROR) {
  10693. //
  10694. // Determine whether the queue actually needs to be
  10695. // committed.
  10696. //
  10697. // ScanQueueResult can have 1 of 3 values:
  10698. //
  10699. // 0: Some files were missing--must commit queue.
  10700. //
  10701. // 1: All files to be copied are already present and
  10702. // queue is empty--skip committing queue.
  10703. //
  10704. // 2: All files to be copied are present, but
  10705. // del/ren/backup queues not empty--must commit
  10706. // queue. The copy queue will have been emptied, so
  10707. // only del/ren/backup functions will be performed.
  10708. //
  10709. // (jamiehun) see previous case of SetupScanFileQueue
  10710. // for a discussion of DI_FLAGSEX_PREINSTALLBACKUP
  10711. // handling.
  10712. //
  10713. if(!SetupScanFileQueue(UserFileQ,
  10714. SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_PRUNE_COPY_QUEUE,
  10715. hwndParent,
  10716. NULL,
  10717. NULL,
  10718. &ScanQueueResult)) {
  10719. //
  10720. // SetupScanFileQueue should really never fail when
  10721. // you don't ask it to call a callback routine, but
  10722. // if it does, just go ahead and commit the queue.
  10723. //
  10724. ScanQueueResult = 0;
  10725. }
  10726. }
  10727. if((Err == NO_ERROR) && (ScanQueueResult != 1)) {
  10728. //
  10729. // We need to commit this file queue. Figure out what
  10730. // message handler to use.
  10731. //
  10732. if(DevInfoElem->InstallParamBlock.InstallMsgHandler) {
  10733. MsgHandler = DevInfoElem->InstallParamBlock.InstallMsgHandler;
  10734. MsgHandlerContext = DevInfoElem->InstallParamBlock.InstallMsgHandlerContext;
  10735. MsgHandlerIsNativeCharWidth = DevInfoElem->InstallParamBlock.InstallMsgHandlerIsNativeCharWidth;
  10736. } else {
  10737. NoProgressUI = (GuiSetupInProgress || (DevInfoElem->InstallParamBlock.Flags & DI_QUIETINSTALL));
  10738. if(MsgHandlerContext = SetupInitDefaultQueueCallbackEx(
  10739. hwndParent,
  10740. (NoProgressUI ? INVALID_HANDLE_VALUE : NULL),
  10741. 0,
  10742. 0,
  10743. NULL))
  10744. {
  10745. FreeMsgHandlerContext = TRUE;
  10746. MsgHandler = SetupDefaultQueueCallback;
  10747. MsgHandlerIsNativeCharWidth = TRUE;
  10748. } else {
  10749. Err = ERROR_NOT_ENOUGH_MEMORY;
  10750. }
  10751. }
  10752. //
  10753. // Copy enqueued files.
  10754. //
  10755. if(Err == NO_ERROR) {
  10756. //
  10757. // Call _SetupVerifyQueuedCatalogs separately (i.e.,
  10758. // don't let it happen automatically as a result of
  10759. // committing the queue that happens below). We do
  10760. // this beforehand so that we know what unique name was
  10761. // generated when an OEM INF was installed into
  10762. // %windir%\Inf (in case we need to delete the
  10763. // INF/PNF/CAT files later if we encounter an error).
  10764. //
  10765. WriteLogEntry(
  10766. LogContext,
  10767. DRIVER_LOG_TIME,
  10768. MSG_LOG_BEGIN_COINST_VERIFY_CAT_TIME,
  10769. NULL); // text message
  10770. Err = _SetupVerifyQueuedCatalogs(
  10771. hwndParent,
  10772. UserFileQ,
  10773. (VERCAT_INSTALL_INF_AND_CAT |
  10774. ((DevInfoElem->SelectedDriver->Flags & DNF_INET_DRIVER)
  10775. ? VERCAT_PRIMARY_DEVICE_INF_FROM_INET : 0)),
  10776. szNewName,
  10777. &OemInfFileToCopy
  10778. );
  10779. WriteLogEntry(
  10780. LogContext,
  10781. DRIVER_LOG_TIME,
  10782. MSG_LOG_END_COINST_VERIFY_CAT_TIME,
  10783. NULL); // text message
  10784. if(Err == NO_ERROR) {
  10785. if(_SetupCommitFileQueue(hwndParent,
  10786. UserFileQ,
  10787. MsgHandler,
  10788. MsgHandlerContext,
  10789. MsgHandlerIsNativeCharWidth
  10790. )) {
  10791. //
  10792. // Check to see whether a reboot is required as a
  10793. // result of committing the queue (i.e., because
  10794. // files were in use, or the INF requested a reboot).
  10795. //
  10796. FileQueueNeedsReboot = SetupPromptReboot(UserFileQ, NULL, TRUE);
  10797. //
  10798. // This should never fail...
  10799. //
  10800. MYASSERT(FileQueueNeedsReboot != -1);
  10801. if(FileQueueNeedsReboot) {
  10802. SetDevnodeNeedsRebootProblem(DevInfoElem, pDeviceInfoSet,
  10803. MSG_LOG_REBOOT_REASON_INUSE);
  10804. }
  10805. } else {
  10806. Err = GetLastError();
  10807. }
  10808. }
  10809. }
  10810. }
  10811. //
  10812. // Close our file queue handle.
  10813. //
  10814. SetupCloseFileQueue(UserFileQ);
  10815. CloseUserFileQ = FALSE;
  10816. //
  10817. // Terminate the default queue callback, if it was created.
  10818. //
  10819. if(FreeMsgHandlerContext) {
  10820. SetupTermDefaultQueueCallback(MsgHandlerContext);
  10821. FreeMsgHandlerContext = FALSE;
  10822. }
  10823. if(Err != NO_ERROR) {
  10824. goto clean0;
  10825. }
  10826. }
  10827. }
  10828. //
  10829. // If all we were asked to do was copy files, then we're done.
  10830. //
  10831. if(!DoFullInstall ||
  10832. (DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_NO_DRVREG_MODIFY)) {
  10833. goto clean0;
  10834. }
  10835. //
  10836. // Open/create the Driver Reg Key.
  10837. //
  10838. if((hkDrv = SetupDiOpenDevRegKey(DeviceInfoSet,
  10839. DeviceInfoData,
  10840. DICS_FLAG_GLOBAL,
  10841. 0,
  10842. DIREG_DRV,
  10843. KEY_READ | KEY_WRITE)) == INVALID_HANDLE_VALUE) {
  10844. //
  10845. // Assume the driver key doesn't already exist--try to create it.
  10846. //
  10847. if((hkDrv = SetupDiCreateDevRegKey(DeviceInfoSet,
  10848. DeviceInfoData,
  10849. DICS_FLAG_GLOBAL,
  10850. 0,
  10851. DIREG_DRV,
  10852. NULL,
  10853. NULL)) != INVALID_HANDLE_VALUE) {
  10854. //
  10855. // We successfully created the driver key. Set a flag so we'll know
  10856. // to delete it in case we hit an error and need to clean up.
  10857. //
  10858. DeleteDrvRegKey = TRUE;
  10859. } else {
  10860. Err = GetLastError();
  10861. goto clean0;
  10862. }
  10863. }
  10864. //
  10865. // We don't pass a msg handler so no need to worry about ansi
  10866. // vs. unicode issues here.
  10867. //
  10868. Err = InstallFromInfSectionAndNeededSections(NULL,
  10869. hDeviceInf,
  10870. InfSectionWithExt,
  10871. SPINST_INIFILES
  10872. | SPINST_REGISTRY
  10873. | SPINST_INI2REG
  10874. | SPINST_BITREG
  10875. | SPINST_REGSVR
  10876. | SPINST_UNREGSVR
  10877. | SPINST_PROFILEITEMS,
  10878. hkDrv,
  10879. NULL,
  10880. 0,
  10881. NULL,
  10882. NULL,
  10883. INVALID_HANDLE_VALUE,
  10884. NULL,
  10885. NULL
  10886. );
  10887. if(Err == NO_ERROR) {
  10888. //
  10889. // Registering co-installers invalidates our existing co-installer
  10890. // list. Reset this list (migrating the module handles to the devinfo
  10891. // set's list of "things to clean up later".
  10892. // (NOTE: SetupDiCallClassInstaller also does this when its handling
  10893. // DIF_REGISTER_COINSTALLERS, but since we can't be guaranteed we're
  10894. // being called in the context of SetupDiCallClassInstaller, we have
  10895. // to do this ourselves as well.)
  10896. //
  10897. Err = InvalidateHelperModules(DeviceInfoSet,
  10898. DeviceInfoData,
  10899. IHM_COINSTALLERS_ONLY
  10900. );
  10901. }
  10902. clean0: ; // nothing to do
  10903. } except(EXCEPTION_EXECUTE_HANDLER) {
  10904. Err = ERROR_INVALID_PARAMETER;
  10905. if(FreeMsgHandlerContext) {
  10906. SetupTermDefaultQueueCallback(MsgHandlerContext);
  10907. }
  10908. if(CloseUserFileQ) {
  10909. SetupCloseFileQueue(UserFileQ);
  10910. }
  10911. //
  10912. // Reference the following variables so the compiler will respect our statement
  10913. // ordering w.r.t. assignment.
  10914. //
  10915. DeleteDrvRegKey = DeleteDrvRegKey;
  10916. CloseInfHandle = CloseInfHandle;
  10917. OemInfFileToCopy = OemInfFileToCopy;
  10918. }
  10919. if(hkDrv != INVALID_HANDLE_VALUE) {
  10920. RegCloseKey(hkDrv);
  10921. if((Err != NO_ERROR) && DeleteDrvRegKey) {
  10922. SetupDiDeleteDevRegKey(DeviceInfoSet,
  10923. DeviceInfoData,
  10924. DICS_FLAG_GLOBAL | DICS_FLAG_CONFIGGENERAL,
  10925. 0,
  10926. DIREG_DRV
  10927. );
  10928. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst, CM_DRP_DRIVER, NULL, 0, 0,pDeviceInfoSet->hMachine);
  10929. }
  10930. }
  10931. if(CloseInfHandle) {
  10932. MYASSERT(hDeviceInf != INVALID_HANDLE_VALUE);
  10933. SetupCloseInfFile(hDeviceInf);
  10934. }
  10935. clean1:
  10936. if (Err == NO_ERROR) {
  10937. //
  10938. // give a +ve affirmation of Success
  10939. //
  10940. WriteLogEntry(
  10941. LogContext,
  10942. DoFullInstall ? DRIVER_LOG_INFO : DRIVER_LOG_VERBOSE,
  10943. MSG_LOG_REGISTEREDCOINSTALLERS,
  10944. NULL);
  10945. } else {
  10946. //
  10947. // indicate failed, display error
  10948. //
  10949. WriteLogEntry(
  10950. LogContext,
  10951. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  10952. MSG_LOG_REGISTERCOINSTALLERS_ERROR,
  10953. NULL);
  10954. WriteLogError(
  10955. LogContext,
  10956. DRIVER_LOG_ERROR,
  10957. Err);
  10958. //
  10959. // If we copied the OEM INF into the INF directory under a newly-
  10960. // generated name, delete it now.
  10961. //
  10962. if(OemInfFileToCopy) {
  10963. pSetupUninstallOEMInf(szNewName, LogContext, SUOI_FORCEDELETE, NULL);
  10964. }
  10965. }
  10966. if (slot_section) {
  10967. ReleaseLogInfoSlot(LogContext,slot_section);
  10968. }
  10969. if (pDeviceInfoSet) {
  10970. UnlockDeviceInfoSet(pDeviceInfoSet);
  10971. }
  10972. SetLastError(Err);
  10973. return(Err == NO_ERROR);
  10974. }
  10975. BOOL
  10976. WINAPI
  10977. SetupDiSelectBestCompatDrv(
  10978. IN HDEVINFO DeviceInfoSet,
  10979. IN OUT PSP_DEVINFO_DATA DeviceInfoData
  10980. )
  10981. /*++
  10982. Routine Description:
  10983. Default handler for DIF_SELECTBESTCOMPATDRV
  10984. This routine will select the best driver from the device information element's
  10985. compatible driver list.
  10986. This function will enumerate through all of the drivers and find the one with
  10987. the Best Rank (this is the lowest Rank number). If there are multiple drivers
  10988. with the same Best Rank then we will take the driver with the newest DriverDate.
  10989. Arguments:
  10990. DeviceInfoSet - Supplies a handle to the device information set containing
  10991. the element for which the best compatible driver is to be selected.
  10992. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure for
  10993. which the best compatible driver is to be selected. This element must
  10994. already have a (non-empty) compatible driver list built for it, or this
  10995. API will fail and GetLastError will return ERROR_NO_COMPAT_DRIVERS.
  10996. This is an IN OUT parameter because the class GUID for the device will be
  10997. updated to reflect the class of the selected driver.
  10998. Return Value:
  10999. If the function succeeds, the return value is TRUE.
  11000. If the function fails, the return value is FALSE. To get extended error
  11001. information, call GetLastError.
  11002. --*/
  11003. {
  11004. SP_DRVINFO_DATA DriverInfoData;
  11005. SP_DRVINSTALL_PARAMS DriverInstallParams;
  11006. DWORD BestRank, BasicBestRank;
  11007. DWORDLONG BestDriverVersion, BasicBestDriverVersion;
  11008. DWORD MemberIndex;
  11009. INT BestMemberIndex, BasicBestMemberIndex;
  11010. PSETUP_LOG_CONTEXT LogContext = NULL;
  11011. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  11012. DWORD Err = NO_ERROR;
  11013. PDEVINFO_ELEM DevInfoElem = NULL;
  11014. FILETIME BestDriverDate, BasicBestDriverDate;
  11015. BestRank = BasicBestRank = RANK_NO_MATCH;
  11016. BestMemberIndex = BasicBestMemberIndex = -1;
  11017. BestDriverVersion = BasicBestDriverVersion = 0;
  11018. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  11019. Err = ERROR_INVALID_HANDLE;
  11020. goto clean1;
  11021. }
  11022. LogContext = pDeviceInfoSet->InstallParamBlock.LogContext;
  11023. if(DeviceInfoData
  11024. && (DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  11025. DeviceInfoData,
  11026. NULL))!=NULL) {
  11027. LogContext = DevInfoElem->InstallParamBlock.LogContext;
  11028. }
  11029. //
  11030. //Enumerate through all of the drivers and find the Best Rank
  11031. //
  11032. MemberIndex = 0;
  11033. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  11034. while (SetupDiEnumDriverInfo(DeviceInfoSet,
  11035. DeviceInfoData,
  11036. SPDIT_COMPATDRIVER,
  11037. MemberIndex,
  11038. &DriverInfoData)) {
  11039. DriverInstallParams.cbSize = sizeof(SP_DRVINSTALL_PARAMS);
  11040. if ((SetupDiGetDriverInstallParams(DeviceInfoSet,
  11041. DeviceInfoData,
  11042. &DriverInfoData,
  11043. &DriverInstallParams))) {
  11044. if(DriverInstallParams.Flags & DNF_BAD_DRIVER) {
  11045. //
  11046. // This driver was marked as bad--we don't want to use it, but
  11047. // we should log an informational message as to why it wasn't
  11048. // considered.
  11049. //
  11050. SP_DRVINFO_DETAIL_DATA Data;
  11051. Data.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  11052. if(SetupDiGetDriverInfoDetail(DeviceInfoSet,
  11053. DeviceInfoData,
  11054. &DriverInfoData,
  11055. &Data,
  11056. Data.cbSize,
  11057. NULL) ||
  11058. (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  11059. WriteLogEntry(
  11060. LogContext,
  11061. DRIVER_LOG_INFO,
  11062. MSG_LOG_SELECTBEST_BAD_DRIVER,
  11063. NULL,
  11064. Data.DrvDescription,
  11065. Data.InfFileName,
  11066. Data.SectionName
  11067. );
  11068. }
  11069. } else if(DriverInstallParams.Flags & DNF_BASIC_DRIVER) {
  11070. //
  11071. // This driver is flagged as a "basic functionality" driver.
  11072. // We'll keep track of the best such driver we encounter, but
  11073. // we'll only use a basic driver if there exists no non-basic
  11074. // signed drivers.
  11075. //
  11076. if(DriverInstallParams.Rank <= BasicBestRank) {
  11077. if(BasicBestMemberIndex == -1) {
  11078. //
  11079. // This is the first acceptable basic driver we've
  11080. // encountered...
  11081. //
  11082. BasicBestDriverDate = DriverInfoData.DriverDate;
  11083. BasicBestMemberIndex = (INT)MemberIndex;
  11084. BasicBestDriverVersion = DriverInfoData.DriverVersion;
  11085. } else {
  11086. if((DriverInstallParams.Rank < BasicBestRank) ||
  11087. (CompareFileTime(&BasicBestDriverDate, &(DriverInfoData.DriverDate)) == -1)) {
  11088. //
  11089. // If this new driver has a better (smaller) Rank than
  11090. // the current Best Driver or it has a newer date then
  11091. // make it the Best Driver.
  11092. //
  11093. BasicBestDriverDate = DriverInfoData.DriverDate;
  11094. BasicBestMemberIndex = (INT)MemberIndex;
  11095. BasicBestDriverVersion = DriverInfoData.DriverVersion;
  11096. } else if ((DriverInstallParams.Rank == BasicBestRank) &&
  11097. (CompareFileTime(&BasicBestDriverDate, &(DriverInfoData.DriverDate)) == 0) &&
  11098. (DriverInfoData.DriverVersion > BasicBestDriverVersion)) {
  11099. //
  11100. // If the Rank and DriverDate of the new driver
  11101. // are identical to the current Best driver,
  11102. // then check if the new driver has a newer
  11103. // DriverVersion and if so make it the Best Driver.
  11104. //
  11105. BasicBestDriverDate = DriverInfoData.DriverDate;
  11106. BasicBestMemberIndex = (INT)MemberIndex;
  11107. BasicBestDriverVersion = DriverInfoData.DriverVersion;
  11108. }
  11109. }
  11110. BasicBestRank = DriverInstallParams.Rank;
  11111. }
  11112. } else {
  11113. //
  11114. // This isn't a basic driver. If it's the best one we've seen,
  11115. // remember it.
  11116. //
  11117. if(DriverInstallParams.Rank <= BestRank) {
  11118. if(BestMemberIndex == -1) {
  11119. //
  11120. // This is the first acceptable non-basic driver we've
  11121. // encountered...
  11122. //
  11123. BestDriverDate = DriverInfoData.DriverDate;
  11124. BestMemberIndex = (INT)MemberIndex;
  11125. BestDriverVersion = DriverInfoData.DriverVersion;
  11126. } else {
  11127. //
  11128. // If this new driver has a better (smaller) Rank than
  11129. // the current Best Driver or it has a newer date then
  11130. // make it the Best Driver.
  11131. //
  11132. if((DriverInstallParams.Rank < BestRank) ||
  11133. (CompareFileTime(&BestDriverDate, &(DriverInfoData.DriverDate)) == -1)) {
  11134. BestDriverDate = DriverInfoData.DriverDate;
  11135. BestMemberIndex = (INT)MemberIndex;
  11136. BestDriverVersion = DriverInfoData.DriverVersion;
  11137. } else if ((DriverInstallParams.Rank == BestRank) &&
  11138. (CompareFileTime(&BestDriverDate, &(DriverInfoData.DriverDate)) == 0) &&
  11139. (DriverInfoData.DriverVersion > BestDriverVersion)) {
  11140. //
  11141. // If the Rank and DriverDate of the new driver
  11142. // are identical to the current Best driver,
  11143. // then check if the new driver has a newer
  11144. // DriverVersion and if so make it the Best Driver.
  11145. //
  11146. BestDriverDate = DriverInfoData.DriverDate;
  11147. BestMemberIndex = (INT)MemberIndex;
  11148. BestDriverVersion = DriverInfoData.DriverVersion;
  11149. }
  11150. }
  11151. BestRank = DriverInstallParams.Rank;
  11152. }
  11153. }
  11154. }
  11155. MemberIndex++;
  11156. }
  11157. //
  11158. // If BestRank and BasicBestRank still equal RANK_NO_MATCH then we don't
  11159. // have any compatible drivers
  11160. //
  11161. if((BestRank == RANK_NO_MATCH) && (BasicBestRank == RANK_NO_MATCH)) {
  11162. Err = ERROR_NO_COMPAT_DRIVERS;
  11163. goto clean1;
  11164. }
  11165. //
  11166. // Select best driver from among basic and full-featured offerings as
  11167. // follows:
  11168. //
  11169. // 1. Full-featured, signed driver
  11170. // 2. Basic signed driver
  11171. // 3. Best rank/newest date between full-featured and basic unsigned
  11172. // driver (note: it will be rare that we encounter a basic unsigned
  11173. // driver since this will typically be used only for our in-box
  11174. // offerings, which are always signed)
  11175. //
  11176. if(BestRank < DRIVER_UNTRUSTED_RANK) {
  11177. MemberIndex = (DWORD)BestMemberIndex;
  11178. } else if(BasicBestRank < DRIVER_UNTRUSTED_RANK) {
  11179. MemberIndex = (DWORD)BasicBestMemberIndex;
  11180. } else {
  11181. if(BestRank < BasicBestRank) {
  11182. MemberIndex = (DWORD)BestMemberIndex;
  11183. } else if(BasicBestRank < BestRank) {
  11184. MemberIndex = (DWORD)BasicBestMemberIndex;
  11185. } else {
  11186. //
  11187. // We have both a basic driver and full-featured one, both of which
  11188. // are unsigned, and both of which are equivalently ranked. Pick
  11189. // the newer one. In the unlikely event that they're the same
  11190. // date, pick the full-featured one.
  11191. //
  11192. // We have both a basic driver and full-featured one, both of which
  11193. // are unsigned, and both of which are equivalently ranked. If the
  11194. // driver dates are the same, then pick the one with the newer
  11195. // driver version, otherwise pick the one with the newest date.
  11196. // In the unlikely event that the DriverDate and DriverVersion are
  11197. // the same, pick the full-featured one.
  11198. //
  11199. if (CompareFileTime(&BestDriverDate, &BasicBestDriverDate) == 0) {
  11200. //
  11201. // Driver dates are the same, so take the one with the newest
  11202. // driver version.
  11203. //
  11204. if (BasicBestDriverVersion > BestDriverVersion) {
  11205. MemberIndex = (DWORD)BasicBestMemberIndex;
  11206. } else {
  11207. MemberIndex = (DWORD)BestMemberIndex;
  11208. }
  11209. } else if(CompareFileTime(&BestDriverDate, &BasicBestDriverDate) == -1) {
  11210. MemberIndex = (DWORD)BasicBestMemberIndex;
  11211. } else {
  11212. MemberIndex = (DWORD)BestMemberIndex;
  11213. }
  11214. }
  11215. }
  11216. //
  11217. // (Re-)retrieve the driver info data for the best driver we found.
  11218. //
  11219. if(!SetupDiEnumDriverInfo(DeviceInfoSet,
  11220. DeviceInfoData,
  11221. SPDIT_COMPATDRIVER,
  11222. MemberIndex,
  11223. &DriverInfoData)) {
  11224. //
  11225. // We should never see this error, since we retrieved this driver node
  11226. // just moments ago, and we have the HDEVINFO locked, so no one could
  11227. // have deleted it out from under us.
  11228. //
  11229. Err = GetLastError();
  11230. goto clean1;
  11231. }
  11232. if(!SetupDiSetSelectedDriver(DeviceInfoSet,
  11233. DeviceInfoData,
  11234. &DriverInfoData)) {
  11235. Err = GetLastError();
  11236. }
  11237. clean1:
  11238. if(Err == NO_ERROR) {
  11239. //
  11240. // give a +ve affirmation of Success
  11241. //
  11242. WriteLogEntry(
  11243. LogContext,
  11244. DRIVER_LOG_INFO,
  11245. MSG_LOG_SELECTEDBEST,
  11246. NULL);
  11247. //
  11248. // If we had a basic driver but didn't use it, log an information entry
  11249. //
  11250. if((BasicBestMemberIndex != -1) &&
  11251. (BasicBestMemberIndex != (INT)MemberIndex)) {
  11252. if(SetupDiEnumDriverInfo(DeviceInfoSet,
  11253. DeviceInfoData,
  11254. SPDIT_COMPATDRIVER,
  11255. (DWORD)BasicBestMemberIndex,
  11256. &DriverInfoData)) {
  11257. SP_DRVINFO_DETAIL_DATA Data;
  11258. Data.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  11259. if(SetupDiGetDriverInfoDetail(DeviceInfoSet,
  11260. DeviceInfoData,
  11261. &DriverInfoData,
  11262. &Data,
  11263. Data.cbSize,
  11264. NULL) ||
  11265. (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  11266. WriteLogEntry(
  11267. LogContext,
  11268. DRIVER_LOG_INFO,
  11269. MSG_LOG_SELECTBEST_BASIC_DRIVER_SKIPPED,
  11270. NULL,
  11271. Data.DrvDescription,
  11272. Data.InfFileName,
  11273. Data.SectionName
  11274. );
  11275. }
  11276. }
  11277. }
  11278. } else {
  11279. //
  11280. // indicate failed, display error
  11281. //
  11282. WriteLogEntry(
  11283. LogContext,
  11284. ((Err == ERROR_NO_COMPAT_DRIVERS) ?
  11285. DRIVER_LOG_WARNING :
  11286. DRIVER_LOG_ERROR)
  11287. | SETUP_LOG_BUFFER,
  11288. MSG_LOG_SELECTBEST_ERROR,
  11289. NULL);
  11290. WriteLogError(
  11291. LogContext,
  11292. ((Err == ERROR_NO_COMPAT_DRIVERS) ?
  11293. DRIVER_LOG_WARNING :
  11294. DRIVER_LOG_ERROR),
  11295. Err);
  11296. }
  11297. if (pDeviceInfoSet) {
  11298. UnlockDeviceInfoSet(pDeviceInfoSet);
  11299. }
  11300. SetLastError(Err);
  11301. return(Err == NO_ERROR);
  11302. }
  11303. BOOL
  11304. RetrieveAllDriversForDevice(
  11305. IN PDEVINFO_ELEM DevInfoElem,
  11306. OUT PTSTR *DriverList,
  11307. IN DWORD Flags,
  11308. IN HMACHINE hMachine
  11309. )
  11310. /*++
  11311. Routine Description:
  11312. This routine returns a multi-sz list of all filter drivers (both upper and
  11313. lower, class-specific and device-specific) for the specified device information
  11314. element.
  11315. Arguments:
  11316. DevInfoElem - Specifies the device information element whose list of filter
  11317. drivers are to be retrieved.
  11318. DriverList - If this routine returns TRUE (i.e., there was at least one
  11319. filter driver for this device), then this pointer is filled in to point
  11320. to a newly-allocated buffer containing a multi-sz list of all filters
  11321. associated with this device. If we encountered an out-of-memory error,
  11322. this pointer will be set to NULL.
  11323. Flags - can be one of the following:
  11324. RADFD_FLAG_FUNCTION_DRIVER - include the function driver in the
  11325. DriverList return value.
  11326. RADFD_FLAG_DEVICE_UPPER_FILTERS - include the device upper filters in
  11327. the DriverList return value.
  11328. RADFD_FLAG_DEVICE_LOWER_FILTERS - include the device lower filters in
  11329. the DriverList return value.
  11330. RADFD_FLAG_CLASS_UPPER_FILTERS - include the class upper filters in the
  11331. DriverList return value.
  11332. RADFD_FLAG_CLASS_LOWER_FILTERS - include the class lower filters in the
  11333. DriverList return value.
  11334. RADFD_FLAG_DEVICE_FILTERS - include both the device upper and lower
  11335. filters in the DriverList return value.
  11336. RADFD_FLAG_CLASS_FILTERS include both the class upper and lower filters
  11337. in the DriverList return value.
  11338. Return Value:
  11339. If there is at least one filter driver for the specified device (or we couldn't
  11340. tell because we ran out of memory), the return value is TRUE.
  11341. Otherwise, it is FALSE.
  11342. --*/
  11343. {
  11344. PTSTR Buffer, NewBuffer, CurPos, p;
  11345. DWORD BufferSize, UsedSize, RequiredSize;
  11346. DWORD i, NumLists, Err;
  11347. CONFIGRET cr;
  11348. DWORD RegDataType;
  11349. HKEY hk;
  11350. ULONG ulProperty;
  11351. *DriverList = NULL;
  11352. BufferSize = 1024 * sizeof(TCHAR); // start out with a reasonably-sized buffer.
  11353. Buffer = MyMalloc(BufferSize);
  11354. if(Buffer) {
  11355. UsedSize = 0;
  11356. CurPos = Buffer;
  11357. } else {
  11358. //
  11359. // We really don't know whether there were any filters for this device, but
  11360. // if we return TRUE, the NULL DriverList OUT parameter will signal to the
  11361. // caller that we encountered an out-of-memory condition.
  11362. //
  11363. return TRUE;
  11364. }
  11365. //
  11366. // Attempt to open the class key so we can retrieve the class-specific filter lists.
  11367. //
  11368. hk = SetupDiOpenClassRegKey(&(DevInfoElem->ClassGuid), KEY_READ);
  11369. NumLists = (hk == INVALID_HANDLE_VALUE) ? 3 : 5;
  11370. //
  11371. // First, retrieve the UpperFilters and LowerFilters device properties (i.e.,
  11372. // the device-specific filters).
  11373. //
  11374. for(i = 0; i < NumLists; i++) {
  11375. RequiredSize = 0;
  11376. while(TRUE) {
  11377. //
  11378. // Do we need a larger buffer?
  11379. //
  11380. if(RequiredSize > (BufferSize - UsedSize)) {
  11381. BufferSize = UsedSize + RequiredSize;
  11382. NewBuffer = MyRealloc(Buffer, BufferSize);
  11383. if(NewBuffer) {
  11384. //
  11385. // Adjust our current position pointer.
  11386. //
  11387. CurPos = NewBuffer + (CurPos - Buffer);
  11388. Buffer = NewBuffer;
  11389. } else {
  11390. MyFree(Buffer);
  11391. if(hk != INVALID_HANDLE_VALUE) {
  11392. RegCloseKey(hk);
  11393. }
  11394. return TRUE;
  11395. }
  11396. } else {
  11397. RequiredSize = BufferSize - UsedSize;
  11398. }
  11399. if(i < 3) {
  11400. //
  11401. // Then we're retrieving the device-specific lists.
  11402. //
  11403. if (i == 0) {
  11404. //
  11405. // Check to see if we need to include the function driver
  11406. //
  11407. if (!(Flags & RADFD_FLAG_FUNCTION_DRIVER)) {
  11408. //
  11409. // Skip the function driver.
  11410. //
  11411. break;
  11412. }
  11413. ulProperty = CM_DRP_SERVICE;
  11414. } else if (i == 1) {
  11415. //
  11416. // Check to see if we need to include the device lower filters.
  11417. //
  11418. if (!(Flags & RADFD_FLAG_DEVICE_LOWER_FILTERS)) {
  11419. //
  11420. // Skip the device lower filters.
  11421. //
  11422. break;
  11423. }
  11424. ulProperty = CM_DRP_LOWERFILTERS;
  11425. } else {
  11426. //
  11427. // Check to see if we need to include the device upper filters.
  11428. //
  11429. if (!(Flags & RADFD_FLAG_DEVICE_UPPER_FILTERS)) {
  11430. //
  11431. // Skip the device upper filters.
  11432. //
  11433. break;
  11434. }
  11435. ulProperty = CM_DRP_UPPERFILTERS;
  11436. }
  11437. cr = CM_Get_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  11438. ulProperty,
  11439. NULL,
  11440. CurPos,
  11441. &RequiredSize,
  11442. 0,
  11443. hMachine);
  11444. switch(cr) {
  11445. case CR_SUCCESS :
  11446. Err = ERROR_SUCCESS;
  11447. break;
  11448. case CR_BUFFER_SMALL :
  11449. Err = ERROR_MORE_DATA;
  11450. break;
  11451. default :
  11452. Err = ERROR_INVALID_DATA; // any old error will do.
  11453. break;
  11454. }
  11455. } else {
  11456. //
  11457. // We're retrieving the class-specific lists.
  11458. //
  11459. if (i == 3) {
  11460. //
  11461. // Check to see if we need to include the class lower filters
  11462. //
  11463. if (!(Flags & RADFD_FLAG_CLASS_LOWER_FILTERS)) {
  11464. //
  11465. // Skip the class lower filters.
  11466. //
  11467. break;
  11468. }
  11469. } else {
  11470. //
  11471. // Check to see if we need to include the class upper filters.
  11472. //
  11473. if (!(Flags & RADFD_FLAG_CLASS_UPPER_FILTERS)) {
  11474. //
  11475. // Skip the class upper filters.
  11476. //
  11477. break;
  11478. }
  11479. }
  11480. Err = RegQueryValueEx(hk,
  11481. ((i == 3) ? pszLowerFilters : pszUpperFilters),
  11482. NULL,
  11483. &RegDataType,
  11484. (PBYTE)CurPos,
  11485. &RequiredSize
  11486. );
  11487. }
  11488. if(Err == ERROR_SUCCESS) {
  11489. //
  11490. // Walk through the service names in the multi-sz list we just retrieved to find
  11491. // the end (just in case someone screwed up when saving out this list and didn't
  11492. // size it properly, etc.)
  11493. //
  11494. // (We use _tcslen instead of strlen, so it'll generate an exception if the list
  11495. // isn't double-null terminated and we go off into la-la land.)
  11496. //
  11497. p = CurPos;
  11498. try {
  11499. while(*CurPos) {
  11500. CurPos += _tcslen(CurPos);
  11501. if(CurPos >= (PTSTR)((PBYTE)Buffer + BufferSize)) {
  11502. //
  11503. // We found a list that wasn't properly double-null terminated, but
  11504. // it didn't cause an exception.
  11505. //
  11506. CurPos = p;
  11507. *CurPos = TEXT('\0');
  11508. break;
  11509. } else {
  11510. CurPos++;
  11511. if(CurPos == (PTSTR)((PBYTE)Buffer + BufferSize)) {
  11512. //
  11513. // Reallocate the buffer to accommodate a terminating null (which the
  11514. // list we retrieved didn't provide).
  11515. //
  11516. BufferSize += sizeof(TCHAR);
  11517. NewBuffer = MyRealloc(Buffer, BufferSize);
  11518. if(!NewBuffer) {
  11519. MyFree(Buffer);
  11520. Buffer = NULL;
  11521. goto clean0;
  11522. }
  11523. //
  11524. // Adjust CurPos to point to same location in reallocated buffer.
  11525. //
  11526. CurPos = NewBuffer + (CurPos - Buffer);
  11527. Buffer = NewBuffer;
  11528. *CurPos = TEXT('\0');
  11529. } else if (i == 0) {
  11530. //
  11531. // This is the SPDRP_SERVICE case, which returns a REG_SZ and
  11532. // not a multi-sz string. So tack on an ending NULL.
  11533. //
  11534. *CurPos = TEXT('\0');
  11535. }
  11536. }
  11537. p = CurPos;
  11538. }
  11539. clean0:
  11540. ; // nothing to do.
  11541. } except(EXCEPTION_EXECUTE_HANDLER) {
  11542. MYASSERT(CurPos != p);
  11543. CurPos = p;
  11544. *CurPos = TEXT('\0');
  11545. }
  11546. if(!Buffer) {
  11547. //
  11548. // We needed to resize the buffer to fix an improperly-terminated list, but
  11549. // we ran out of memory.
  11550. //
  11551. if(hk != INVALID_HANDLE_VALUE) {
  11552. RegCloseKey(hk);
  11553. }
  11554. return TRUE;
  11555. }
  11556. UsedSize = (DWORD)((PBYTE)CurPos - (PBYTE)Buffer) + sizeof(TCHAR);
  11557. MYASSERT(UsedSize <= BufferSize);
  11558. break;
  11559. } else if(Err != ERROR_MORE_DATA) {
  11560. //
  11561. // We failed for some reason other than buffer-too-small. Move on to the
  11562. // next filter driver list.
  11563. //
  11564. break;
  11565. }
  11566. }
  11567. }
  11568. if(hk != INVALID_HANDLE_VALUE) {
  11569. RegCloseKey(hk);
  11570. }
  11571. if(UsedSize) {
  11572. //
  11573. // We retrieved a list of services to return to the caller.
  11574. //
  11575. *DriverList = Buffer;
  11576. return TRUE;
  11577. }
  11578. MYASSERT(Buffer);
  11579. MyFree(Buffer);
  11580. return FALSE;
  11581. }
  11582. BOOL
  11583. RetrieveAllDevNodesSharingDriversWithDevice(
  11584. IN PDEVINFO_ELEM DevInfoElem,
  11585. OUT PTSTR *Drivers,
  11586. OUT PDEVNODE *DevNodes,
  11587. OUT ULONG *NumberOfDevNodes,
  11588. IN HMACHINE hMachine
  11589. )
  11590. /*++
  11591. Routine Description:
  11592. This routine returns a multi-sz list of all the devnodes that share a
  11593. driver with the specified device. This includes the device's function driver
  11594. and all filter drivers (both upper and lower, class-specific and device-
  11595. specific).
  11596. This routine returns a multi-sz list of all filter drivers (both upper and
  11597. lower device-specific) for the specified device information
  11598. element.
  11599. Arguments:
  11600. DevInfoElem - Specifies the device information element.
  11601. Drivers -
  11602. DevNodes -
  11603. NumberOfDevNodes -
  11604. Return Value:
  11605. TRUE unless there is an unexpected error such as out of memory.
  11606. --*/
  11607. {
  11608. DWORD Err = ERROR_SUCCESS;
  11609. PTSTR p, Buffer = NULL;
  11610. ULONG BufferSize = 1024;
  11611. PTSTR DriversList = NULL, CurDriver;
  11612. DEVNODE DevNode;
  11613. PDEVNODE NewBuffer, ArrayOfDevNodes;
  11614. ULONG DevNodeArraySize = 10;
  11615. ULONG i;
  11616. CONFIGRET cr;
  11617. *NumberOfDevNodes = 0;
  11618. try {
  11619. //
  11620. // Allocate an array of devnodes. Start with 10 and we will grow it below
  11621. // if we have more.
  11622. //
  11623. if ((ArrayOfDevNodes = MyMalloc(DevNodeArraySize * sizeof(DEVNODE))) == NULL) {
  11624. Err = ERROR_NOT_ENOUGH_MEMORY;
  11625. goto clean0;
  11626. }
  11627. //
  11628. // Always include the devnode that was passed in.
  11629. //
  11630. ArrayOfDevNodes[*NumberOfDevNodes] = DevInfoElem->DevInst;
  11631. (*NumberOfDevNodes)++;
  11632. //
  11633. // Now get a list of all the filter drivers (both upper and lower
  11634. // device-specific) that this device is using and
  11635. // then add any devnode using one of these services to our list.
  11636. //
  11637. if (RetrieveAllDriversForDevice(DevInfoElem,
  11638. &DriversList,
  11639. RADFD_FLAG_FUNCTION_DRIVER | RADFD_FLAG_DEVICE_FILTERS,
  11640. hMachine)) {
  11641. //
  11642. // We need a buffer when we call CM_Get_Device_ID_list_Ex, we will
  11643. // start with a 1024 buffer and grow it as needed.
  11644. //
  11645. Buffer = MyMalloc(BufferSize * sizeof(TCHAR));
  11646. if (!Buffer) {
  11647. Err = ERROR_NOT_ENOUGH_MEMORY;
  11648. goto clean0;
  11649. }
  11650. //
  11651. // Enumerate through all the filters and build up a list of drivers
  11652. // they are using.
  11653. //
  11654. for (CurDriver=DriversList; *CurDriver; CurDriver+=(lstrlen(CurDriver)+1)) {
  11655. while ((cr = CM_Get_Device_ID_List_Ex(
  11656. CurDriver,
  11657. Buffer,
  11658. BufferSize,
  11659. CM_GETIDLIST_FILTER_SERVICE |
  11660. CM_GETIDLIST_DONOTGENERATE,
  11661. hMachine
  11662. )) == CR_BUFFER_SMALL) {
  11663. //
  11664. // If the buffer is too small then we need to reallocate a
  11665. // larger one.
  11666. //
  11667. PTSTR TempBuffer;
  11668. CM_Get_Device_ID_List_Size_Ex(&BufferSize,
  11669. CurDriver,
  11670. CM_GETIDLIST_FILTER_SERVICE,
  11671. hMachine);
  11672. TempBuffer = MyRealloc(Buffer, BufferSize * sizeof(TCHAR));
  11673. if (TempBuffer) {
  11674. Buffer = TempBuffer;
  11675. } else {
  11676. //
  11677. // We couldn't create a larger buffer!
  11678. //
  11679. Err = ERROR_NOT_ENOUGH_MEMORY;
  11680. goto clean0;
  11681. }
  11682. }
  11683. if (cr == CR_SUCCESS) {
  11684. //
  11685. // Enumerate through all the device instance Ids and add them
  11686. // to the list of devnodes.
  11687. //
  11688. for (p=Buffer; *p; p+=(lstrlen(p)+1)) {
  11689. if (CM_Locate_DevInst_Ex(&DevNode,
  11690. p,
  11691. 0,
  11692. hMachine
  11693. ) == CR_SUCCESS) {
  11694. //
  11695. // Check to see if this devnode already exists in
  11696. // our list.
  11697. //
  11698. for (i=0; i<*NumberOfDevNodes; i++) {
  11699. if (ArrayOfDevNodes[i] == DevNode) {
  11700. break;
  11701. }
  11702. }
  11703. if (i == *NumberOfDevNodes) {
  11704. //
  11705. // Check to see if we need to increase our devnode array.
  11706. //
  11707. if (DevNodeArraySize <= *NumberOfDevNodes) {
  11708. DevNodeArraySize += 10;
  11709. NewBuffer = MyRealloc(ArrayOfDevNodes, DevNodeArraySize * sizeof(DEVNODE));
  11710. if (NewBuffer) {
  11711. ArrayOfDevNodes = NewBuffer;
  11712. } else {
  11713. Err = ERROR_NOT_ENOUGH_MEMORY;
  11714. goto clean0;
  11715. }
  11716. }
  11717. ArrayOfDevNodes[*NumberOfDevNodes] = DevNode;
  11718. (*NumberOfDevNodes)++;
  11719. }
  11720. }
  11721. }
  11722. } else {
  11723. //
  11724. // We got another error back so we will fail.
  11725. //
  11726. Err = ERROR_INVALID_DATA;
  11727. goto clean0;
  11728. }
  11729. }
  11730. }
  11731. } except(EXCEPTION_EXECUTE_HANDLER) {
  11732. Err = ERROR_INVALID_PARAMETER;
  11733. //
  11734. // Access the following variables, so that the compiler will respect our
  11735. // statement ordering w.r.t. their assignment.
  11736. //
  11737. Buffer = Buffer;
  11738. ArrayOfDevNodes = ArrayOfDevNodes;
  11739. DriversList = DriversList;
  11740. }
  11741. clean0:
  11742. if (Buffer) {
  11743. MyFree(Buffer);
  11744. }
  11745. if (Err == ERROR_SUCCESS) {
  11746. *DevNodes = ArrayOfDevNodes;
  11747. *Drivers = DriversList;
  11748. } else {
  11749. //
  11750. // If we failed then free all the memory and set the pointers
  11751. // to NULL.
  11752. //
  11753. if (ArrayOfDevNodes) {
  11754. MyFree(ArrayOfDevNodes);
  11755. *DevNodes = NULL;
  11756. }
  11757. if (DriversList) {
  11758. MyFree(DriversList);
  11759. *Drivers = NULL;
  11760. }
  11761. }
  11762. return (Err == ERROR_SUCCESS);
  11763. }
  11764. BOOL
  11765. AnyServicesLoaded(
  11766. IN PCTSTR ServiceNameList,
  11767. OUT PTSTR LoadedService, OPTIONAL
  11768. IN ULONG LoadedServiceSize
  11769. )
  11770. /*++
  11771. Routine Description:
  11772. This routine will determine if any of the services passed in our currently
  11773. loaded.
  11774. Arguments:
  11775. ServiceNameList - multi-sz list of service names.
  11776. LoadedService - buffer that will receive the service the first service in
  11777. the list that is still loaded into memory. This value is only valid
  11778. if the API returns TRUE.
  11779. LoadedServiceSize - size of the LoadedService buffer.
  11780. Return Value:
  11781. TRUE if any of the services in the list are loaded, FALSE if none of them
  11782. are currently loaded.
  11783. --*/
  11784. {
  11785. #ifdef UNICODE
  11786. NTSTATUS Status;
  11787. BOOL bObjectIsLoaded = FALSE;
  11788. DWORD BufSize = 1024;
  11789. PUCHAR Buffer = NULL;
  11790. UNICODE_STRING UnicodeStringDriver;
  11791. UNICODE_STRING UnicodeStringService;
  11792. OBJECT_ATTRIBUTES Attributes;
  11793. HANDLE DirectoryHandle = INVALID_HANDLE_VALUE;
  11794. POBJECT_DIRECTORY_INFORMATION DirInfo;
  11795. POBJECT_NAME_INFORMATION NameInfo;
  11796. ULONG Context = 0;
  11797. ULONG ReturnedLength;
  11798. PTSTR CurServiceName;
  11799. try {
  11800. if (LoadedService) {
  11801. LoadedService[0] = TEXT('\0');
  11802. }
  11803. //
  11804. // If no services were passed in then just leave.
  11805. //
  11806. if (!ServiceNameList) {
  11807. goto clean0;
  11808. }
  11809. Buffer = MyMalloc(BufSize);
  11810. if (!Buffer) {
  11811. goto clean0;
  11812. }
  11813. ZeroMemory(Buffer, BufSize);
  11814. RtlInitUnicodeString(&UnicodeStringDriver, TEXT("\\Driver"));
  11815. InitializeObjectAttributes(&Attributes,
  11816. &UnicodeStringDriver,
  11817. OBJ_CASE_INSENSITIVE,
  11818. NULL,
  11819. NULL
  11820. );
  11821. Status = NtOpenDirectoryObject(&DirectoryHandle,
  11822. DIRECTORY_QUERY,
  11823. &Attributes
  11824. );
  11825. if (!NT_SUCCESS(Status)) {
  11826. goto clean0;
  11827. }
  11828. //
  11829. // Get the actual name of the object directory object.
  11830. //
  11831. NameInfo = (POBJECT_NAME_INFORMATION)Buffer;
  11832. if (!NT_SUCCESS(Status = NtQueryObject(DirectoryHandle,
  11833. ObjectNameInformation,
  11834. NameInfo,
  11835. BufSize,
  11836. (PULONG)NULL))) {
  11837. goto clean0;
  11838. }
  11839. //
  11840. // Grab the driver objects in chuncks instead of one at a time.
  11841. //
  11842. for (Status = NtQueryDirectoryObject(DirectoryHandle,
  11843. Buffer,
  11844. BufSize,
  11845. FALSE,
  11846. FALSE,
  11847. &Context,
  11848. &ReturnedLength
  11849. );
  11850. NT_SUCCESS(Status) && !bObjectIsLoaded;
  11851. Status = NtQueryDirectoryObject(DirectoryHandle,
  11852. Buffer,
  11853. BufSize,
  11854. FALSE,
  11855. FALSE,
  11856. &Context,
  11857. &ReturnedLength
  11858. )) {
  11859. if (!NT_SUCCESS(Status)) {
  11860. break;
  11861. }
  11862. DirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer;
  11863. while (TRUE) {
  11864. //
  11865. // Check if there is another record. If there isn't, then get out
  11866. // of the loop now.
  11867. //
  11868. if (DirInfo->Name.Length == 0) {
  11869. break;
  11870. }
  11871. for (CurServiceName=(PTSTR)ServiceNameList;
  11872. *CurServiceName;
  11873. CurServiceName+=(lstrlen(CurServiceName)+1)) {
  11874. RtlInitUnicodeString(&UnicodeStringService, CurServiceName);
  11875. if (RtlCompareUnicodeString(&UnicodeStringService, &(DirInfo->Name), TRUE) == 0) {
  11876. bObjectIsLoaded = TRUE;
  11877. if (LoadedService) {
  11878. lstrcpyn(LoadedService, CurServiceName, LoadedServiceSize);
  11879. }
  11880. break;
  11881. }
  11882. }
  11883. //
  11884. // If one of the drivers is loaded then just stop now.
  11885. //
  11886. if (bObjectIsLoaded) {
  11887. break;
  11888. }
  11889. DirInfo = (POBJECT_DIRECTORY_INFORMATION)(((PUCHAR)DirInfo) +
  11890. sizeof(OBJECT_DIRECTORY_INFORMATION));
  11891. }
  11892. ZeroMemory(Buffer, BufSize);
  11893. }
  11894. } except(EXCEPTION_EXECUTE_HANDLER) {
  11895. bObjectIsLoaded = TRUE;
  11896. //
  11897. // Access the following variables, so that the compiler will respect our
  11898. // statement ordering w.r.t. their assignment.
  11899. //
  11900. Buffer = Buffer;
  11901. }
  11902. clean0:
  11903. if (DirectoryHandle != INVALID_HANDLE_VALUE) {
  11904. NtClose(DirectoryHandle);
  11905. }
  11906. if (Buffer) {
  11907. MyFree(Buffer);
  11908. }
  11909. return bObjectIsLoaded;
  11910. #else
  11911. return TRUE;
  11912. #endif
  11913. }
  11914. VOID
  11915. RestartSingleDevice(
  11916. IN PDEVINFO_ELEM DevInfoElem,
  11917. IN PDEVICE_INFO_SET pDeviceInfoSet,
  11918. IN BOOL NullDriverInstall,
  11919. IN PSETUP_LOG_CONTEXT LogContext
  11920. )
  11921. /*++
  11922. Routine Description:
  11923. Arguments:
  11924. DevInfoElem -
  11925. pDeviceInfoSet -
  11926. NullDriverInstall -
  11927. LogContext -
  11928. Return Value:
  11929. --*/
  11930. {
  11931. #ifdef UNICODE
  11932. DWORD DevInstCapabilities;
  11933. ULONG cbData;
  11934. ULONG ulStatus, ulProblem;
  11935. TCHAR DeviceFullID[MAX_DEVICE_ID_LEN];
  11936. //
  11937. // Retrieve the device's capabilities. We need to know whether the device is
  11938. // capable of being driven 'raw' (i.e., without a function driver).
  11939. //
  11940. cbData = sizeof(DevInstCapabilities);
  11941. if(CR_SUCCESS != CM_Get_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  11942. CM_DRP_CAPABILITIES,
  11943. NULL,
  11944. &DevInstCapabilities,
  11945. &cbData,
  11946. 0,
  11947. pDeviceInfoSet->hMachine))
  11948. {
  11949. DevInstCapabilities = 0;
  11950. }
  11951. //
  11952. // If the device instance has a problem but is not disabled. Just
  11953. // restart it. This should be 90% of the cases.
  11954. //
  11955. if((CM_Get_DevInst_Status_Ex(&ulStatus, &ulProblem, DevInfoElem->DevInst,
  11956. 0,pDeviceInfoSet->hMachine) == CR_SUCCESS) &&
  11957. ((ulStatus & DN_HAS_PROBLEM) || !(ulStatus & DN_DRIVER_LOADED))) {
  11958. //
  11959. // Poke at Config Manager to make it load the driver.
  11960. //
  11961. WriteLogEntry(
  11962. LogContext,
  11963. DRIVER_LOG_TIME,
  11964. MSG_LOG_BEGIN_RESTART_TIME,
  11965. NULL); // text message
  11966. CM_Setup_DevInst_Ex(DevInfoElem->DevInst, CM_SETUP_DEVINST_READY, pDeviceInfoSet->hMachine);
  11967. WriteLogEntry(
  11968. LogContext,
  11969. DRIVER_LOG_TIME,
  11970. MSG_LOG_END_RESTART_TIME,
  11971. NULL); // text message
  11972. //
  11973. // If we're installing a 'real' driver (i.e., not null), or if the device is
  11974. // raw-capable, then we want to check and see if the device actually started as
  11975. // a result of CM_Setup_DevInst. If not, a reboot is in order. (There's no need
  11976. // to check when we're doing a null driver install for a non-raw devnode. We know
  11977. // it can't start, and we definitely don't want to generate a 'need reboot' popup
  11978. // in this case!)
  11979. //
  11980. if(!NullDriverInstall || (DevInstCapabilities & CM_DEVCAP_RAWDEVICEOK)) {
  11981. CheckIfDevStarted(DevInfoElem, pDeviceInfoSet);
  11982. }
  11983. } else {
  11984. CONFIGRET cr;
  11985. TCHAR VetoName[MAX_PATH];
  11986. PNP_VETO_TYPE VetoType;
  11987. //
  11988. // If there is a device instance with no problem, then we
  11989. // should remove it (to unload the current drivers off of
  11990. // it), and then call CM_Setup_DevInst on it. If the
  11991. // device instance refuses to remove, then set the flags
  11992. // that say we need to reboot.
  11993. //
  11994. // NOTE: In Win9x, virtual removal of a devnode (e.g., to
  11995. // unload the driver(s) for it), resulted in the devnode's
  11996. // deletion. Thus, on Win9x, it was necessary to
  11997. // re-enumerate the devnode's parent to cause the devnode
  11998. // to be re-created (and subsequently started). This is
  11999. // inefficient, especially if we're dealing with a root-
  12000. // enumerated device (hence requiring a reenumeration of
  12001. // the entire tree). Since the device installer
  12002. // functionality of setupapi will apparently never be used
  12003. // on Win9x, we can optimize this such that we just call
  12004. // CM_Setup_DevInst on this devnode. We know it didn't
  12005. // actually go away, because devnodes only go away on NT
  12006. // when their underlying hardware is physically removed.
  12007. //
  12008. WriteLogEntry(
  12009. LogContext,
  12010. DRIVER_LOG_TIME,
  12011. MSG_LOG_BEGIN_REMOVE_TIME,
  12012. NULL); // text message
  12013. cr = CM_Query_And_Remove_SubTree_Ex(DevInfoElem->DevInst,
  12014. &VetoType,
  12015. VetoName,
  12016. SIZECHARS(VetoName),
  12017. (DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_NOUIONQUERYREMOVE)
  12018. ? CM_REMOVE_UI_NOT_OK
  12019. : CM_REMOVE_UI_OK,
  12020. pDeviceInfoSet->hMachine
  12021. );
  12022. WriteLogEntry(
  12023. LogContext,
  12024. DRIVER_LOG_TIME,
  12025. MSG_LOG_END_REMOVE_TIME,
  12026. NULL); // text message
  12027. if(cr == CR_SUCCESS) {
  12028. WriteLogEntry(
  12029. LogContext,
  12030. DRIVER_LOG_TIME,
  12031. MSG_LOG_BEGIN_RESTART_TIME,
  12032. NULL); // text message
  12033. CM_Setup_DevInst_Ex(DevInfoElem->DevInst,
  12034. CM_SETUP_DEVINST_READY,
  12035. pDeviceInfoSet->hMachine
  12036. );
  12037. WriteLogEntry(
  12038. LogContext,
  12039. DRIVER_LOG_TIME,
  12040. MSG_LOG_END_RESTART_TIME,
  12041. NULL); // text message
  12042. //
  12043. // If we're installing a 'real' driver (i.e., not null),
  12044. // or if the device is raw-capable, then we want to
  12045. // check and see if the device actually started as a
  12046. // result of CM_Setup_DevInst. If not, a reboot is in
  12047. // order. (There's no need to check when we're doing a
  12048. // null driver install for a non-raw devnode. We know
  12049. // it can't start, and we definitely don't want to
  12050. // generate a 'need reboot' popup in this case!)
  12051. //
  12052. if(!NullDriverInstall || (DevInstCapabilities & CM_DEVCAP_RAWDEVICEOK)) {
  12053. CheckIfDevStarted(DevInfoElem,pDeviceInfoSet);
  12054. }
  12055. } else {
  12056. //
  12057. // If the failure was due to a veto, then log
  12058. // information about who vetoed us.
  12059. //
  12060. // SPLOG-- write out a log entry
  12061. //
  12062. if(cr == CR_REMOVE_VETOED) {
  12063. if( CM_Get_Device_ID(DevInfoElem->DevInst,
  12064. DeviceFullID,
  12065. SIZECHARS(DeviceFullID),
  12066. 0
  12067. ) == CR_SUCCESS ) {
  12068. _WriteVetoLogEntry(
  12069. LogContext,
  12070. DRIVER_LOG_WARNING,
  12071. MSG_LOG_REMOVE_VETOED_IN_INSTALL,
  12072. DeviceFullID,
  12073. VetoName,
  12074. VetoType);
  12075. }
  12076. }
  12077. //
  12078. // If the failure was due to the device not being there,
  12079. // then prompting for reboot isn't going to help
  12080. // anything (plus, you can't set a problem on a non-
  12081. // existent devnode anyway). This could happen, for
  12082. // example, if the user plugged in a USB mouse, then
  12083. // unplugged it again before we got a chance to
  12084. // complete the device installation. In this case,
  12085. // we'll just ignore the failure and continue on.
  12086. //
  12087. if(cr != CR_INVALID_DEVNODE) {
  12088. SetDevnodeNeedsRebootProblemWithArg2(DevInfoElem,
  12089. pDeviceInfoSet,
  12090. MSG_LOG_REBOOT_REASON_QR_VETOED,
  12091. cr,
  12092. (ULONG_PTR)_MapCmRetToString(cr)
  12093. );
  12094. }
  12095. }
  12096. }
  12097. #else
  12098. //
  12099. // For ANSI just set the reboot flag.
  12100. //
  12101. CM_Set_DevInst_Problem_Ex(DevInfoElem->DevInst,
  12102. CM_PROB_NEED_RESTART,
  12103. CM_SET_DEVINST_PROBLEM_OVERRIDE,
  12104. pDeviceInfoSet->hMachine);
  12105. #endif
  12106. }
  12107. VOID
  12108. RestartAllDevicesUsingDrivers(
  12109. IN PDEVINFO_ELEM DevInfoElem,
  12110. IN PDEVICE_INFO_SET pDeviceInfoSet,
  12111. IN BOOL NullDriverInstall,
  12112. IN PSETUP_LOG_CONTEXT LogContext
  12113. )
  12114. /*++
  12115. Routine Description:
  12116. Arguments:
  12117. DevInfoElem -
  12118. pDeviceInfoSet -
  12119. NullDriverInstall -
  12120. LogContext -
  12121. Return Value:
  12122. --*/
  12123. {
  12124. #ifdef UNICODE
  12125. BOOL bNeedReboot = FALSE;
  12126. PTSTR CurDriver, DriverList = NULL;
  12127. PDEVNODE DevNodeList = NULL;
  12128. ULONG NumberOfDevNodes, LastDevNodeStopped, i;
  12129. ULONG ulStatus, ulProblem;
  12130. PBOOL DevNodeStartedList = NULL;
  12131. TCHAR DeviceFullID[MAX_DEVICE_ID_LEN];
  12132. TCHAR LoadedService[MAX_SERVICE_NAME_LEN];
  12133. CONFIGRET cr;
  12134. try {
  12135. if (RetrieveAllDevNodesSharingDriversWithDevice(DevInfoElem,
  12136. &DriverList,
  12137. &DevNodeList,
  12138. &NumberOfDevNodes,
  12139. pDeviceInfoSet->hMachine)) {
  12140. //
  12141. // Allocate an array of BOOLs so we can remember if each devnode was
  12142. // started before we tried to unload all of the drivers.
  12143. //
  12144. if (NumberOfDevNodes) {
  12145. DevNodeStartedList = MyMalloc(NumberOfDevNodes * sizeof(BOOL));
  12146. if (!DevNodeStartedList) {
  12147. bNeedReboot = TRUE;
  12148. goto clean0;
  12149. }
  12150. }
  12151. //
  12152. // First we will enumerate through all of the devices and remember
  12153. // if they were started before we remove/restart them all. We need
  12154. // to do this step first since we don't have any devnode dependency
  12155. // information so stopping the first one could affect one of the
  12156. // others in the list.
  12157. //
  12158. for (i=0; i<NumberOfDevNodes; i++) {
  12159. if((CM_Get_DevInst_Status_Ex(&ulStatus, &ulProblem, DevNodeList[i],
  12160. 0,pDeviceInfoSet->hMachine) == CR_SUCCESS) &&
  12161. (!(ulStatus & DN_HAS_PROBLEM) && (ulStatus & DN_DRIVER_LOADED))) {
  12162. DevNodeStartedList[i] = TRUE;
  12163. } else {
  12164. DevNodeStartedList[i] = FALSE;
  12165. }
  12166. }
  12167. //
  12168. // Next stop all of the devnodes that are using one of the drivers
  12169. // associated with our new device.
  12170. //
  12171. for (i=0; i<NumberOfDevNodes; i++) {
  12172. //
  12173. // Remember the last devnode that we tried to stop.
  12174. //
  12175. LastDevNodeStopped = i;
  12176. if(CM_Get_Device_ID(DevNodeList[i],
  12177. DeviceFullID,
  12178. SIZECHARS(DeviceFullID),
  12179. 0
  12180. ) != CR_SUCCESS ) {
  12181. DeviceFullID[0] = TEXT('\0');
  12182. }
  12183. //
  12184. // Only attempt to stop the device if it is currently started.
  12185. //
  12186. if((CM_Get_DevInst_Status_Ex(&ulStatus, &ulProblem, DevNodeList[i],
  12187. 0,pDeviceInfoSet->hMachine) == CR_SUCCESS) &&
  12188. (!(ulStatus & DN_HAS_PROBLEM) && (ulStatus & DN_DRIVER_LOADED))) {
  12189. //
  12190. // Since the devnode is started we need to query remove it.
  12191. //
  12192. TCHAR VetoName[MAX_PATH];
  12193. PNP_VETO_TYPE VetoType;
  12194. //
  12195. // Remove the devnode (to unload the current drivers off of
  12196. // it). If the device instance refuses to remove, then set
  12197. // the flags that say we need to reboot.
  12198. //
  12199. WriteLogEntry(
  12200. LogContext,
  12201. DRIVER_LOG_TIME,
  12202. MSG_LOG_BEGIN_REMOVE_TIME_DEVICE,
  12203. NULL,
  12204. DeviceFullID);
  12205. cr = CM_Query_And_Remove_SubTree_Ex(DevNodeList[i],
  12206. &VetoType,
  12207. VetoName,
  12208. SIZECHARS(VetoName),
  12209. CM_REMOVE_NO_RESTART |
  12210. (DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_NOUIONQUERYREMOVE)
  12211. ? CM_REMOVE_UI_NOT_OK
  12212. : CM_REMOVE_UI_OK,
  12213. pDeviceInfoSet->hMachine
  12214. );
  12215. WriteLogEntry(
  12216. LogContext,
  12217. DRIVER_LOG_TIME,
  12218. MSG_LOG_END_REMOVE_TIME_DEVICE,
  12219. NULL,
  12220. DeviceFullID);
  12221. if(cr != CR_SUCCESS) {
  12222. //
  12223. // If the failure was due to a veto, then log
  12224. // information about who vetoed us.
  12225. //
  12226. // SPLOG-- write out a log entry
  12227. //
  12228. if(cr == CR_REMOVE_VETOED) {
  12229. _WriteVetoLogEntry(
  12230. LogContext,
  12231. DRIVER_LOG_WARNING,
  12232. MSG_LOG_REMOVE_VETOED_IN_INSTALL,
  12233. DeviceFullID,
  12234. VetoName,
  12235. VetoType);
  12236. }
  12237. //
  12238. // If the failure was due to the device not being there,
  12239. // then prompting for reboot isn't going to help
  12240. // anything (plus, you can't set a problem on a non-
  12241. // existent devnode anyway). This could happen, for
  12242. // example, if the user plugged in a USB mouse, then
  12243. // unplugged it again before we got a chance to
  12244. // complete the device installation. In this case,
  12245. // we'll just ignore the failure and continue on.
  12246. //
  12247. if(cr != CR_INVALID_DEVNODE) {
  12248. bNeedReboot = TRUE;
  12249. WriteLogEntry(
  12250. LogContext,
  12251. DRIVER_LOG_WARNING, // should this be a warning?
  12252. MSG_LOG_REBOOT_REASON_QR_VETOED,
  12253. NULL,
  12254. cr,
  12255. (ULONG_PTR)_MapCmRetToString(cr),
  12256. DeviceFullID);
  12257. }
  12258. }
  12259. }
  12260. //
  12261. // Don't bother stopping the rest of the drivers if we need a reboot
  12262. //
  12263. if (bNeedReboot) {
  12264. break;
  12265. }
  12266. }
  12267. if (!bNeedReboot) {
  12268. //
  12269. // Verify that all of the drivers have unloaded. If just one did not
  12270. // unload then we need to prompt for a reboot.
  12271. //
  12272. if (AnyServicesLoaded(DriverList, LoadedService, SIZECHARS(LoadedService))) {
  12273. bNeedReboot = TRUE;
  12274. WriteLogEntry(
  12275. LogContext,
  12276. DRIVER_LOG_WARNING,
  12277. MSG_LOG_REBOOT_REASON_DRIVER_LOADED,
  12278. NULL,
  12279. LoadedService);
  12280. }
  12281. }
  12282. //
  12283. // Now start up all the devices that we stopped.
  12284. //
  12285. for (i=0; i<=LastDevNodeStopped; i++) {
  12286. if(CM_Get_Device_ID(DevNodeList[i],
  12287. DeviceFullID,
  12288. SIZECHARS(DeviceFullID),
  12289. 0
  12290. ) != CR_SUCCESS ) {
  12291. DeviceFullID[0] = TEXT('\0');
  12292. }
  12293. WriteLogEntry(
  12294. LogContext,
  12295. DRIVER_LOG_TIME,
  12296. MSG_LOG_BEGIN_RESTART_TIME_DEVICE,
  12297. NULL,
  12298. DeviceFullID);
  12299. CM_Setup_DevInst_Ex(DevNodeList[i],
  12300. CM_SETUP_DEVNODE_READY,
  12301. pDeviceInfoSet->hMachine);
  12302. WriteLogEntry(
  12303. LogContext,
  12304. DRIVER_LOG_TIME,
  12305. MSG_LOG_END_RESTART_TIME_DEVICE,
  12306. NULL,
  12307. DeviceFullID);
  12308. }
  12309. //
  12310. // Finally make one last pass through all the devnodes and verify
  12311. // that the ones that were started initially are started now.
  12312. // If the devnode wasn't started initially then it is OK that it
  12313. // isn't started now.
  12314. //
  12315. // This last pass can be skipped if we already need a reboot, since
  12316. // it is simply a verification pass.
  12317. //
  12318. if (!bNeedReboot) {
  12319. for (i=0; i<NumberOfDevNodes; i++) {
  12320. if (DevNodeStartedList[i]) {
  12321. if(CM_Get_Device_ID(DevNodeList[i],
  12322. DeviceFullID,
  12323. SIZECHARS(DeviceFullID),
  12324. 0
  12325. ) != CR_SUCCESS ) {
  12326. DeviceFullID[0] = TEXT('\0');
  12327. }
  12328. if ((cr = CM_Get_DevNode_Status_Ex(&ulStatus, &ulProblem, DevNodeList[i],
  12329. 0, pDeviceInfoSet->hMachine)) == CR_SUCCESS) {
  12330. if (!(ulStatus & DN_STARTED)) {
  12331. //
  12332. // This device was started before and now it isn't started,
  12333. // so a reboot is needed.
  12334. //
  12335. bNeedReboot = TRUE;
  12336. if (ulStatus & DN_HAS_PROBLEM) {
  12337. //
  12338. // The device now has a problem when it was
  12339. // working fine before. Log the problem.
  12340. //
  12341. WriteLogEntry(
  12342. LogContext,
  12343. DRIVER_LOG_WARNING,
  12344. MSG_LOG_REBOOT_REASON_DEVHASPROBLEM,
  12345. NULL,
  12346. (DWORD)ulProblem,
  12347. _MapCmProbToString((DWORD)ulProblem),
  12348. DeviceFullID);
  12349. } else if (ulStatus & DN_PRIVATE_PROBLEM) {
  12350. //
  12351. // some private problem, change into need reboot
  12352. // and log private problem
  12353. //
  12354. WriteLogEntry(
  12355. LogContext,
  12356. DRIVER_LOG_WARNING,
  12357. MSG_LOG_REBOOT_REASON_PRIVATEPROBLEM,
  12358. NULL,
  12359. NULL,
  12360. NULL,
  12361. DeviceFullID);
  12362. } else {
  12363. //
  12364. // not started for some other reason
  12365. // indicate reboot required and log this issue
  12366. //
  12367. WriteLogEntry(
  12368. LogContext,
  12369. DRIVER_LOG_WARNING,
  12370. MSG_LOG_REBOOT_REASON_NOTSTARTED,
  12371. NULL,
  12372. NULL,
  12373. NULL,
  12374. DeviceFullID);
  12375. }
  12376. }
  12377. } else {
  12378. bNeedReboot = TRUE;
  12379. WriteLogEntry(
  12380. LogContext,
  12381. DRIVER_LOG_WARNING,
  12382. MSG_LOG_REBOOT_REASON_DEVHASPROBLEM,
  12383. NULL,
  12384. cr,
  12385. (ULONG_PTR)_MapCmRetToString(cr),
  12386. DeviceFullID);
  12387. }
  12388. }
  12389. }
  12390. }
  12391. } else {
  12392. //
  12393. // If we can't get the list of drivers for some reason then just
  12394. // set the needs reboot flag.
  12395. //
  12396. bNeedReboot = TRUE;
  12397. }
  12398. if (!bNeedReboot) {
  12399. //
  12400. // At this point we need to check that the device that we just installed
  12401. // is actually started, unless it is a NULL driver install.
  12402. //
  12403. DWORD DevInstCapabilities;
  12404. ULONG cbData;
  12405. cbData = sizeof(DevInstCapabilities);
  12406. if(CR_SUCCESS != CM_Get_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  12407. CM_DRP_CAPABILITIES,
  12408. NULL,
  12409. &DevInstCapabilities,
  12410. &cbData,
  12411. 0,
  12412. pDeviceInfoSet->hMachine))
  12413. {
  12414. DevInstCapabilities = 0;
  12415. }
  12416. if(!NullDriverInstall || (DevInstCapabilities & CM_DEVCAP_RAWDEVICEOK)) {
  12417. CheckIfDevStarted(DevInfoElem,pDeviceInfoSet);
  12418. }
  12419. }
  12420. } except(EXCEPTION_EXECUTE_HANDLER) {
  12421. bNeedReboot = TRUE;
  12422. //
  12423. // Access the following variables, so that the compiler will respect our
  12424. // statement ordering w.r.t. their assignment.
  12425. //
  12426. DriverList = DriverList;
  12427. DevNodeList = DevNodeList;
  12428. DevNodeStartedList = DevNodeStartedList;
  12429. }
  12430. clean0:
  12431. if (DriverList) {
  12432. MyFree(DriverList);
  12433. }
  12434. if (DevNodeList) {
  12435. MyFree(DevNodeList);
  12436. }
  12437. if (DevNodeStartedList) {
  12438. MyFree(DevNodeStartedList);
  12439. }
  12440. if (bNeedReboot) {
  12441. CM_Set_DevInst_Problem_Ex(DevInfoElem->DevInst,
  12442. CM_PROB_NEED_RESTART,
  12443. CM_SET_DEVINST_PROBLEM_OVERRIDE,
  12444. pDeviceInfoSet->hMachine);
  12445. }
  12446. #else
  12447. //
  12448. // For ANSI just set the reboot flag.
  12449. //
  12450. CM_Set_DevInst_Problem_Ex(DevInfoElem->DevInst,
  12451. CM_PROB_NEED_RESTART,
  12452. CM_SET_DEVINST_PROBLEM_OVERRIDE,
  12453. pDeviceInfoSet->hMachine);
  12454. #endif
  12455. }
  12456. VOID
  12457. AppendLoadIncludedInfs(
  12458. IN HINF hDeviceInf,
  12459. IN PCTSTR InfFileName,
  12460. IN PCTSTR InfSectionName,
  12461. IN BOOL AppendLayoutInfs
  12462. )
  12463. /*++
  12464. Routine Description:
  12465. This routine processes the "include=" line in the specified section of the
  12466. specified INF. For each filename entry on this line, it attempts to append-load
  12467. that file to the supplied INF (first, from the location where the original INF
  12468. was located, and if that fails, then using the default INF search path).
  12469. Arguments:
  12470. hDeviceInf - supplies a handle to the INF containing the section specified by
  12471. InfSectionName. Upon return, this INF handle will also contain any additional
  12472. INFs that were append-loaded based on INFs listed in the "include=" entry of
  12473. the InfSectionName section.
  12474. InfFileName - supplies the full path of the INF whose handle was supplied in
  12475. the hDeviceInf parameter. The path component is used in an attempt to first
  12476. locate the specified included INFs in the same location as that of the original
  12477. INF.
  12478. InfSectionName - supplies the name of the section containing an "include=" line
  12479. whose fields are simply filenames of INFs to be append loaded to the original
  12480. INF whose handle is supplied in the hDeviceInf parameter.
  12481. AppendLayoutInfs - if non-zero (TRUE), then we will attempt to append-load the
  12482. corresponding layout INF for each included INF.
  12483. Return Value:
  12484. none.
  12485. --*/
  12486. {
  12487. TCHAR DefaultInfPath[MAX_PATH];
  12488. PTSTR FileNamePos;
  12489. INFCONTEXT InfContext;
  12490. DWORD FieldIndex;
  12491. BOOL b;
  12492. //
  12493. // Store the full directory path to where the supplied INF is located, so we
  12494. // can first attempt to append-load the included INFs from that same directory.
  12495. //
  12496. lstrcpyn(DefaultInfPath, InfFileName, SIZECHARS(DefaultInfPath));
  12497. FileNamePos = (PTSTR)pSetupGetFileTitle(DefaultInfPath);
  12498. if(SetupFindFirstLine(hDeviceInf, InfSectionName, TEXT("include"), &InfContext)) {
  12499. for(FieldIndex = 1;
  12500. SetupGetStringField(&InfContext,
  12501. FieldIndex,
  12502. FileNamePos,
  12503. (DWORD)((DefaultInfPath + SIZECHARS(DefaultInfPath)) - FileNamePos),
  12504. NULL);
  12505. FieldIndex++)
  12506. {
  12507. //
  12508. // Try full path and if that fails just use the inf name
  12509. // and let the open routine try to locate the inf.
  12510. // Ignore errors. We'll catch them later, during the install phases.
  12511. //
  12512. b = SetupOpenAppendInfFile(DefaultInfPath, hDeviceInf, NULL);
  12513. if(!b) {
  12514. b = SetupOpenAppendInfFile(FileNamePos, hDeviceInf, NULL);
  12515. }
  12516. //
  12517. // If we successfully append-loaded the included INF, and if we're also
  12518. // supposed to be append-loading any associated layout INFs, then do that
  12519. // now.
  12520. //
  12521. if(b && AppendLayoutInfs) {
  12522. SetupOpenAppendInfFile(NULL, hDeviceInf, NULL);
  12523. }
  12524. }
  12525. }
  12526. }
  12527. DWORD
  12528. InstallFromInfSectionAndNeededSections(
  12529. IN HWND Owner, OPTIONAL
  12530. IN HINF InfHandle,
  12531. IN PCTSTR SectionName,
  12532. IN UINT Flags,
  12533. IN HKEY RelativeKeyRoot, OPTIONAL
  12534. IN PCTSTR SourceRootPath, OPTIONAL
  12535. IN UINT CopyFlags,
  12536. IN PSP_FILE_CALLBACK MsgHandler,
  12537. IN PVOID Context, OPTIONAL
  12538. IN HDEVINFO DeviceInfoSet, OPTIONAL
  12539. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  12540. IN HSPFILEQ UserFileQ OPTIONAL
  12541. )
  12542. /*++
  12543. Routine Description:
  12544. This routine calls SetupInstallFromInfSection for the specified install section,
  12545. as well as for any additional sections specified in a "needs=" line contained in
  12546. that section.
  12547. Arguments:
  12548. Same as for SetupInstallFromInfSection, except for UserFileQ. If UserFileQ is
  12549. non-NULL, then we will only install files (via pSetupInstallFiles) using this
  12550. file queue.
  12551. Return Value:
  12552. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error code
  12553. indicating the cause of the failure.
  12554. --*/
  12555. {
  12556. DWORD FieldIndex, Err;
  12557. INFCONTEXT InfContext;
  12558. BOOL NeedsEntriesToProcess;
  12559. TCHAR SectionToInstall[MAX_SECT_NAME_LEN];
  12560. lstrcpyn(SectionToInstall, SectionName, SIZECHARS(SectionToInstall));
  12561. NeedsEntriesToProcess = SetupFindFirstLine(InfHandle,
  12562. SectionName,
  12563. TEXT("needs"),
  12564. &InfContext
  12565. );
  12566. Err = NO_ERROR;
  12567. for(FieldIndex = 0; (!FieldIndex || NeedsEntriesToProcess); FieldIndex++) {
  12568. if(FieldIndex) {
  12569. //
  12570. // Get next section name on "needs=" line to be processed.
  12571. //
  12572. if(!SetupGetStringField(&InfContext,
  12573. FieldIndex,
  12574. SectionToInstall,
  12575. SIZECHARS(SectionToInstall),
  12576. NULL)) {
  12577. //
  12578. // We've exhausted all the extra sections we needed to install.
  12579. //
  12580. break;
  12581. }
  12582. }
  12583. if(UserFileQ) {
  12584. //
  12585. // The caller supplied their own file queue, so all we can do is copy
  12586. // files. Make sure that file copying is all they want, and that they
  12587. // gave us a valid file queue handle.
  12588. //
  12589. MYASSERT(Flags == SPINST_FILES);
  12590. MYASSERT(UserFileQ != INVALID_HANDLE_VALUE);
  12591. Err = pSetupInstallFiles(InfHandle,
  12592. NULL,
  12593. SectionToInstall,
  12594. SourceRootPath,
  12595. MsgHandler,
  12596. Context,
  12597. CopyFlags,
  12598. Owner,
  12599. UserFileQ,
  12600. TRUE
  12601. );
  12602. } else {
  12603. //
  12604. // The caller didn't supply their own file queue, so we can just use
  12605. // SetupInstallFromInfSection.
  12606. //
  12607. if(!_SetupInstallFromInfSection(Owner,
  12608. InfHandle,
  12609. SectionToInstall,
  12610. Flags,
  12611. RelativeKeyRoot,
  12612. SourceRootPath,
  12613. CopyFlags,
  12614. MsgHandler,
  12615. Context,
  12616. DeviceInfoSet,
  12617. DeviceInfoData,
  12618. TRUE,
  12619. NULL)) {
  12620. Err = GetLastError();
  12621. break;
  12622. }
  12623. }
  12624. }
  12625. return Err;
  12626. }
  12627. DWORD
  12628. pSetupCopyRelatedInfs(
  12629. IN HINF hInf,
  12630. IN PCTSTR InfFileName, OPTIONAL
  12631. IN PCTSTR InfSectionName,
  12632. IN DWORD OEMSourceMediaType,
  12633. IN PSETUP_LOG_CONTEXT LogContext OPTIONAL
  12634. )
  12635. /*++
  12636. Routine Description:
  12637. This routine processes "CopyINF" directives in the DDInstall section of the
  12638. primary INF.
  12639. CopyINF is not processed under following cases:
  12640. Primary INF is in driver search path
  12641. The CopyINF is specified in an included section.
  12642. Arguments:
  12643. hInf - supplies a handle to the INF containing the section specified by
  12644. InfSectionName.
  12645. InfFileName - supplies the full path of the INF whose handle was supplied in
  12646. the hDeviceInf parameter. The path component is used in an attempt to
  12647. locate the specified INFs. If not specified, we try to get this from hInf
  12648. InfSectionName - supplies the name of the section containing "CopyINF=" lines.
  12649. OEMSourceMediaType - Specifies the type of source media that the location
  12650. information references. May be one of the following values:
  12651. SPOST_NONE - No source media information should be stored in the PNF
  12652. file. (OEMSourceMediaLocation is ignored in this case.)
  12653. SPOST_PATH - OEMSourceMediaLocation contains a path to the source media.
  12654. For example, if the media is on a floppy, this path might
  12655. be "A:\". If OEMSourceMediaLocation is NULL, then the path
  12656. is assumed to be the path where the INF is located (unless
  12657. the INF has a corresponding PNF in that location, in which
  12658. case that PNF's source media information will be
  12659. transferred to the destination PNF).
  12660. SPOST_URL - OEMSourceMediaLocation contains a URL indicating the
  12661. internet location where the INF/driver files were retrieved
  12662. from. If OEMSourceMediaLocation is NULL, then it is
  12663. assumed that the default Code Download Manager location was
  12664. used.
  12665. LogContext - used for logging. If not specified, we get this from hInf
  12666. Return Value:
  12667. none.
  12668. --*/
  12669. {
  12670. INFCONTEXT CopyInfLineContext;
  12671. TCHAR CombinedPath[MAX_PATH*2];
  12672. TCHAR FullSourcePath[MAX_PATH];
  12673. PTSTR Title;
  12674. PCTSTR Field;
  12675. PCTSTR SourcePath;
  12676. DWORD Status;
  12677. DWORD FieldCount;
  12678. DWORD FieldIndex;
  12679. DWORD RetVal;
  12680. PLOADED_INF pInf = NULL;
  12681. if(hInf == NULL || InfSectionName == NULL) {
  12682. return ERROR_INVALID_PARAMETER;
  12683. }
  12684. pInf = (PLOADED_INF)hInf;
  12685. if(!LockInf(pInf)) {
  12686. return ERROR_INVALID_HANDLE;
  12687. }
  12688. if(!LogContext) {
  12689. LogContext = pInf->LogContext;
  12690. }
  12691. if(!InfFileName) {
  12692. InfFileName = pInf->VersionBlock.Filename;
  12693. }
  12694. //
  12695. // if primary INF is from OEM location, then process CopyINF directives
  12696. // note that if the INF is in search path, we ignore CopyINF
  12697. // we also ignore CopyINF's pulled in from other INF's (ie, don't process
  12698. // Include/Needs).
  12699. //
  12700. if(!pSetupInfIsFromOemLocation(InfFileName, FALSE)) {
  12701. //
  12702. // Primary INF is on search path, ignore CopyINF directives
  12703. //
  12704. Status = NO_ERROR;
  12705. goto final;
  12706. }
  12707. lstrcpyn(CombinedPath,InfFileName,MAX_PATH);
  12708. Title = (PTSTR)pSetupGetFileTitle(CombinedPath);
  12709. if (!Title) {
  12710. //
  12711. // shouldn't happen
  12712. //
  12713. MYASSERT(Title);
  12714. Status = ERROR_INVALID_PARAMETER;
  12715. goto final;
  12716. }
  12717. //
  12718. // we look for keyword "CopyInf" in the install section
  12719. //
  12720. if (SetupFindFirstLine(hInf,
  12721. InfSectionName,
  12722. SZ_KEY_COPYINF,
  12723. &CopyInfLineContext)) {
  12724. PSETUP_LOG_CONTEXT SavedLogContext = NULL;
  12725. BOOL ChangedThreadLogContext = SetThreadLogContext(LogContext,&SavedLogContext);
  12726. //
  12727. // we've pushed log context so SetupCopyOemInf will log correctly
  12728. //
  12729. do {
  12730. //
  12731. // CopyInf = a.inf,b.inf,c.inf...
  12732. // a.inf will be at index 1.
  12733. //
  12734. FieldCount = SetupGetFieldCount(&CopyInfLineContext);
  12735. for(FieldIndex = 1;FieldIndex<=FieldCount;FieldIndex++) {
  12736. Status = NO_ERROR;
  12737. Field = pSetupGetField(&CopyInfLineContext,FieldIndex);
  12738. lstrcpyn(Title,Field,MAX_PATH);
  12739. //
  12740. // we have a listed INF, obtain canonical pathname
  12741. // for this INF
  12742. // (note that we assume the INF is relative
  12743. // to original INF and is typically just a filename)
  12744. //
  12745. RetVal = GetFullPathName(CombinedPath,
  12746. MAX_PATH,
  12747. FullSourcePath,
  12748. NULL);
  12749. if (RetVal == 0 || RetVal > MAX_PATH) {
  12750. SourcePath = CombinedPath;
  12751. } else {
  12752. SourcePath = FullSourcePath;
  12753. }
  12754. if(!SetupCopyOEMInf(FullSourcePath,
  12755. NULL,
  12756. OEMSourceMediaType,
  12757. 0,
  12758. NULL,
  12759. 0,
  12760. NULL,
  12761. NULL)) {
  12762. Status = GetLastError();
  12763. }
  12764. if (Status != NO_ERROR) {
  12765. WriteLogEntry(
  12766. LogContext,
  12767. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  12768. MSG_LOG_COPYINF_ERROR,
  12769. NULL,
  12770. FullSourcePath);
  12771. WriteLogError(
  12772. LogContext,
  12773. DRIVER_LOG_ERROR,
  12774. Status);
  12775. } else {
  12776. WriteLogEntry(
  12777. LogContext,
  12778. DRIVER_LOG_INFO,
  12779. MSG_LOG_COPYINF_OK,
  12780. NULL,
  12781. FullSourcePath);
  12782. }
  12783. }
  12784. } while (SetupFindNextMatchLine(&CopyInfLineContext,
  12785. SZ_KEY_COPYINF,
  12786. &CopyInfLineContext));
  12787. if (ChangedThreadLogContext) {
  12788. //
  12789. // restore thread log context
  12790. //
  12791. SetThreadLogContext(SavedLogContext,NULL);
  12792. }
  12793. }
  12794. Status = NO_ERROR;
  12795. final:
  12796. if(pInf) {
  12797. UnlockInf(pInf);
  12798. }
  12799. return Status;
  12800. }
  12801. VOID
  12802. SetDevnodeNeedsRebootProblemWithArg2(
  12803. IN PDEVINFO_ELEM DevInfoElem,
  12804. IN PDEVICE_INFO_SET pDevInfoSet,
  12805. IN DWORD Reason, OPTIONAL
  12806. IN ULONG_PTR Arg1, OPTIONAL
  12807. IN ULONG_PTR Arg2 OPTIONAL
  12808. )
  12809. /*++
  12810. Routine Description:
  12811. This routine sets DI_NEEDREBOOT,
  12812. sets the problem of the specified devnode to be CM_PROB_NEED_RESTART
  12813. and logs information about why we did this
  12814. Arguments:
  12815. DevInfoElem )_ identify the devnode with the problem
  12816. DevInfoSet )
  12817. Reason - Supplies a string resource ID for logging the reason a reboot is
  12818. required. If this is 0, nothing will be logged.
  12819. Arg1/Arg2 - optional arguments %1 and %2 of the logged message
  12820. Return Value:
  12821. none.
  12822. --*/
  12823. {
  12824. TCHAR szDevID[MAX_DEVICE_ID_LEN];
  12825. CONFIGRET cr;
  12826. DevInfoElem->InstallParamBlock.Flags |= DI_NEEDREBOOT;
  12827. if((cr = CM_Get_Device_ID_Ex(DevInfoElem->DevInst,
  12828. szDevID,
  12829. SIZECHARS(szDevID),
  12830. 0,
  12831. pDevInfoSet->hMachine)) != CR_SUCCESS) {
  12832. szDevID[0] = TEXT('\0');
  12833. }
  12834. CM_Set_DevInst_Problem_Ex(DevInfoElem->DevInst,
  12835. CM_PROB_NEED_RESTART,
  12836. CM_SET_DEVINST_PROBLEM_OVERRIDE,
  12837. pDevInfoSet->hMachine);
  12838. if (Reason) {
  12839. //
  12840. // if the caller gave a reason, log why a reboot is required
  12841. //
  12842. WriteLogEntry(
  12843. DevInfoElem->InstallParamBlock.LogContext,
  12844. DRIVER_LOG_WARNING, // should this be a warning?
  12845. Reason,
  12846. NULL,
  12847. Arg1,
  12848. Arg2,
  12849. szDevID);
  12850. }
  12851. }
  12852. DWORD
  12853. MarkQueueForDeviceInstall(
  12854. IN HSPFILEQ QueueHandle,
  12855. IN HINF DeviceInfHandle,
  12856. IN PCTSTR DeviceDesc OPTIONAL
  12857. )
  12858. /*++
  12859. Routine Description:
  12860. This routine adds catalog info entries (if not already present) into a file
  12861. queue for the INFs represented by the supplied INF handle. It also marks
  12862. the first INF's catalog entry (whether newly-created or not) with a flag
  12863. indicating that this is the 'primary' device INF for this installation. It
  12864. then sets a flag in the queue indicating that the behavior when subsequently
  12865. calling _SetupVerifyQueuedCatalogs should be to copy the INF into the
  12866. %windir%\Inf directory (as opposed to merely creating a zero-length file
  12867. there of the correct name so that the catfile's name is guaranteed unique).
  12868. Finally, it retrieves the driver signing policy and associates it with the
  12869. queue (up until this point, the queue has associated with it the non-driver
  12870. signing policy).
  12871. Arguments:
  12872. QueueHandle - supplies a handle to the file queue to be marked as a device
  12873. install file queue.
  12874. DeviceInfHandle - supplies a handle to the device INF upon which this
  12875. installation is based. In addition to the "primary" device INF, this
  12876. handle may also contain one or more append-loaded INFs.
  12877. Return Value:
  12878. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error
  12879. code indicating the cause of the failure.
  12880. --*/
  12881. {
  12882. PSP_FILE_QUEUE Queue;
  12883. TCHAR TempBuffer[MAX_PATH];
  12884. LONG InfStringId, CatStringId, OriginalInfStringId;
  12885. PLOADED_INF pInf;
  12886. DWORD Err;
  12887. PTSTR InfDeviceDesc;
  12888. PSPQ_CATALOG_INFO CatalogNode, PrevCatalogNode, NewCatalogNode;
  12889. BOOL DifferentOriginalName;
  12890. TCHAR OriginalInfName[MAX_PATH];
  12891. BOOL UnlockInf;
  12892. BOOL UseOriginalInfName;
  12893. //
  12894. // Queue handle is actually a pointer to the queue structure.
  12895. //
  12896. Queue = (PSP_FILE_QUEUE)QueueHandle;
  12897. NewCatalogNode = NULL;
  12898. Err = NO_ERROR;
  12899. InfDeviceDesc = NULL;
  12900. UnlockInf = FALSE;
  12901. try {
  12902. if(LockInf((PLOADED_INF)DeviceInfHandle)) {
  12903. UnlockInf = TRUE;
  12904. } else {
  12905. Err = ERROR_INVALID_HANDLE;
  12906. goto clean0;
  12907. }
  12908. //
  12909. // We want to process each INF in the LOADED_INF list...
  12910. //
  12911. for(pInf = (PLOADED_INF)DeviceInfHandle; pInf; pInf = pInf->Next) {
  12912. //
  12913. // First, get the (potentially decorated) CatalogFile= entry from
  12914. // the version block of this INF member, as well as the INF's
  12915. // original name (if different from the INF's current name).
  12916. //
  12917. Err = pGetInfOriginalNameAndCatalogFile(
  12918. pInf,
  12919. NULL,
  12920. &DifferentOriginalName,
  12921. OriginalInfName,
  12922. SIZECHARS(OriginalInfName),
  12923. TempBuffer,
  12924. SIZECHARS(TempBuffer),
  12925. NULL // always native OS/arch (ver doesn't matter for CatalogFile=)
  12926. );
  12927. if(Err != NO_ERROR) {
  12928. goto clean0;
  12929. }
  12930. if(DifferentOriginalName) {
  12931. //
  12932. // Add the INF's original (simple) filename to our string table.
  12933. //
  12934. OriginalInfStringId = pSetupStringTableAddString(
  12935. Queue->StringTable,
  12936. OriginalInfName,
  12937. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE
  12938. );
  12939. if(OriginalInfStringId == -1) {
  12940. Err = ERROR_NOT_ENOUGH_MEMORY;
  12941. goto clean0;
  12942. }
  12943. } else {
  12944. //
  12945. // INF's original name is the same as its present name.
  12946. //
  12947. OriginalInfStringId = -1;
  12948. }
  12949. if(*TempBuffer) {
  12950. CatStringId = pSetupStringTableAddString(Queue->StringTable,
  12951. TempBuffer,
  12952. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE
  12953. );
  12954. if(CatStringId == -1) {
  12955. Err = ERROR_NOT_ENOUGH_MEMORY;
  12956. goto clean0;
  12957. }
  12958. } else {
  12959. //
  12960. // This INF doesn't have a CatalogFile= entry.
  12961. //
  12962. CatStringId = -1;
  12963. }
  12964. //
  12965. // Now, get the INF's full path.
  12966. //
  12967. lstrcpyn(TempBuffer, pInf->VersionBlock.Filename, SIZECHARS(TempBuffer));
  12968. InfStringId = pSetupStringTableAddString(Queue->StringTable,
  12969. TempBuffer,
  12970. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE
  12971. );
  12972. if(InfStringId == -1) {
  12973. Err = ERROR_NOT_ENOUGH_MEMORY;
  12974. goto clean0;
  12975. }
  12976. //
  12977. // Now search for an existing catalog node (there'll typically be
  12978. // one unless the device INF doesn't copy any files, such as a
  12979. // modem INF).
  12980. //
  12981. for(PrevCatalogNode=NULL, CatalogNode=Queue->CatalogList;
  12982. CatalogNode;
  12983. CatalogNode=CatalogNode->Next) {
  12984. if(CatalogNode->InfFullPath == InfStringId) {
  12985. //
  12986. // Already in there. No need to create a new node.
  12987. // Break out here, with CatalogNode pointing at the
  12988. // proper node for this catalog file.
  12989. //
  12990. // In this case, PrevCatalogNode should not be used later,
  12991. // but it shouldn't need to be used, since we won't be
  12992. // adding anything new onto the list of catalog nodes.
  12993. //
  12994. // NOTE: Our alternate catalog should be correct because
  12995. // either (a) the altplatform info was in effect when the
  12996. // INF was added, or (b) the altplatform info was applied
  12997. // after the INF's addition, and it was updated at that
  12998. // time.
  12999. //
  13000. MYASSERT(CatalogNode->CatalogFileFromInf == CatStringId);
  13001. MYASSERT(CatalogNode->InfOriginalName == OriginalInfStringId);
  13002. break;
  13003. }
  13004. //
  13005. // PrevCatalogNode will end up pointing to the final node
  13006. // currently in the linked list, in the case where we need
  13007. // to allocate a new node. This is useful so we don't have to
  13008. // traverse the list again later when we add the new catalog
  13009. // node to the list for this queue.
  13010. //
  13011. PrevCatalogNode = CatalogNode;
  13012. }
  13013. //
  13014. // If we didn't find an existing catalog node, then add one now.
  13015. //
  13016. if(!CatalogNode) {
  13017. //
  13018. // Need to create a new catalog node.
  13019. //
  13020. NewCatalogNode = MyMalloc(sizeof(SPQ_CATALOG_INFO));
  13021. if(!NewCatalogNode) {
  13022. Err = ERROR_NOT_ENOUGH_MEMORY;
  13023. goto clean0;
  13024. }
  13025. ZeroMemory(NewCatalogNode, sizeof(SPQ_CATALOG_INFO));
  13026. NewCatalogNode->CatalogFileFromInf = CatStringId;
  13027. NewCatalogNode->InfOriginalName = OriginalInfStringId;
  13028. NewCatalogNode->InfFullPath = InfStringId;
  13029. NewCatalogNode->InfFinalPath = -1;
  13030. NewCatalogNode->AltCatalogFileFromInfPending = -1;
  13031. //
  13032. // If this queue has alternate platform info associated with
  13033. // it, then we need to retrieve the alternate catalog to be
  13034. // used for digital signature verification.
  13035. //
  13036. if(Queue->Flags & FQF_USE_ALT_PLATFORM) {
  13037. if(pSetupGetCatalogFileValue(&(pInf->VersionBlock),
  13038. TempBuffer,
  13039. SIZECHARS(TempBuffer),
  13040. &(Queue->AltPlatformInfo))) {
  13041. NewCatalogNode->AltCatalogFileFromInf =
  13042. pSetupStringTableAddString(Queue->StringTable,
  13043. TempBuffer,
  13044. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE
  13045. );
  13046. if(NewCatalogNode->AltCatalogFileFromInf == -1) {
  13047. Err = ERROR_NOT_ENOUGH_MEMORY;
  13048. goto clean0;
  13049. }
  13050. } else {
  13051. //
  13052. // This INF doesn't have a CatalogFile= entry.
  13053. //
  13054. NewCatalogNode->AltCatalogFileFromInf = -1;
  13055. }
  13056. } else {
  13057. //
  13058. // No alternate platform info associated with the queue at
  13059. // this time.
  13060. //
  13061. NewCatalogNode->AltCatalogFileFromInf = -1;
  13062. }
  13063. if(Queue->CatalogList) {
  13064. PrevCatalogNode->Next = NewCatalogNode;
  13065. } else {
  13066. Queue->CatalogList = NewCatalogNode;
  13067. }
  13068. //
  13069. // Reset NewCatalogNode so we won't try to free it in case we
  13070. // encounter a subsequent error.
  13071. //
  13072. CatalogNode = NewCatalogNode;
  13073. NewCatalogNode = NULL;
  13074. //
  13075. // We've successfully added a new, as yet unvalidated, catalog
  13076. // node. We must therefore reset the the "catalog
  13077. // verifications done" flags so that we'll redo them later.
  13078. //
  13079. Queue->Flags &= ~(FQF_DID_CATALOGS_OK | FQF_DID_CATALOGS_FAILED);
  13080. }
  13081. if(pInf == (PLOADED_INF)DeviceInfHandle) {
  13082. //
  13083. // At this point, CatalogNode points to the node representing
  13084. // the device INF upon which this device installation is based.
  13085. // Mark this node as such, so that _SetupVerifyQueuedCatalogs
  13086. // can return the INF's new name if it's an OEM INF.
  13087. //
  13088. CatalogNode->Flags |= CATINFO_FLAG_PRIMARY_DEVICE_INF;
  13089. }
  13090. }
  13091. if(!(Queue->Flags & FQF_DEVICE_INSTALL)) {
  13092. //
  13093. // This queue wasn't previously known to be a device install queue,
  13094. // so it's possible the catalog nodes have already been verified
  13095. // subject to non-driver signing policy. Further, it's possible
  13096. // (albeit unlikely) that a non-device INF was passed into this
  13097. // routine, and that a catalog node for that INF already existed in
  13098. // our catalog list. In that case, one of our "catalog
  13099. // verifications done" flags would be set, but would not have been
  13100. // cleared above since we didn't add any catalog nodes. All of
  13101. // this discussion simply to justify that we really do need to
  13102. // clear the bits here too... :-(
  13103. //
  13104. Queue->Flags &= ~(FQF_DID_CATALOGS_OK | FQF_DID_CATALOGS_FAILED);
  13105. //
  13106. // Note: We don't clear the CATINFO_FLAG_NEWLY_COPIED flags for any
  13107. // of the catalog nodes, because we want to make sure we re-use
  13108. // those same names when re-doing verification (e.g., maybe the
  13109. // first time around the INF was installed into %windir%\Inf as a
  13110. // zero-length file--we want to re-use the same filename to now hold
  13111. // our INF).
  13112. //
  13113. //
  13114. // Since we previously didn't know this was a device install queue,
  13115. // we shouldn't have a ValidationPlatform. Make sure that's the
  13116. // case, because the call below would blow away any we had (thus
  13117. // causing a memory leak).
  13118. //
  13119. MYASSERT(!(Queue->ValidationPlatform));
  13120. //
  13121. // Retrieve the codesigning policy in effect for this device (thus
  13122. // replacing the default non-driver signing policy that was
  13123. // associated with the queue when it was originally created).
  13124. //
  13125. IsInfForDeviceInstall(Queue->LogContext,
  13126. NULL,
  13127. (PLOADED_INF)DeviceInfHandle,
  13128. (DeviceDesc ? NULL : &InfDeviceDesc),
  13129. &(Queue->ValidationPlatform),
  13130. &(Queue->DriverSigningPolicy),
  13131. &UseOriginalInfName
  13132. );
  13133. if(UseOriginalInfName) {
  13134. Queue->Flags |= FQF_KEEP_INF_AND_CAT_ORIGINAL_NAMES;
  13135. }
  13136. //
  13137. // If the caller supplied us with a device description (or we got
  13138. // one from IsInfForDeviceInstall), attempt to add that string to
  13139. // the queue's string table in case we need to give a digital
  13140. // signature verification failure popup for this queue.
  13141. //
  13142. //
  13143. // NOTE: When adding the following string to the string table, we
  13144. // cast away its CONST-ness to avoid a compiler warning. Since we
  13145. // are adding it case-sensitively, we are guaranteed it will not be
  13146. // modified.
  13147. //
  13148. if(DeviceDesc) {
  13149. Queue->DeviceDescStringId = pSetupStringTableAddString(Queue->StringTable,
  13150. (PTSTR)DeviceDesc,
  13151. STRTAB_CASE_SENSITIVE
  13152. );
  13153. } else if(InfDeviceDesc) {
  13154. //
  13155. // Use the more generic description based on the device's class
  13156. //
  13157. Queue->DeviceDescStringId = pSetupStringTableAddString(Queue->StringTable,
  13158. InfDeviceDesc,
  13159. STRTAB_CASE_SENSITIVE
  13160. );
  13161. }
  13162. //
  13163. // Set a flag in the queue that indicates this is for a device
  13164. // installation. If we're doing a native platform installation
  13165. // (i.e., the FQF_USE_ALT_PLATFORM isn't set), then this also
  13166. // causes us to copy the INF into %windir%\Inf instead of merely
  13167. // creating a zero-length placeholder file there upon which the
  13168. // corresponding CAT file's installation is based.
  13169. //
  13170. Queue->Flags |= FQF_DEVICE_INSTALL;
  13171. } else {
  13172. //
  13173. // This queue has previously been marked as a device install queue.
  13174. // However, we still want to update the device description, if the
  13175. // caller supplied one.
  13176. //
  13177. if(DeviceDesc) {
  13178. Queue->DeviceDescStringId = pSetupStringTableAddString(Queue->StringTable,
  13179. (PTSTR)DeviceDesc,
  13180. STRTAB_CASE_SENSITIVE
  13181. );
  13182. }
  13183. }
  13184. clean0: ; // nothing to do.
  13185. } except(EXCEPTION_EXECUTE_HANDLER) {
  13186. //
  13187. // If we hit an AV, then use invalid parameter error, otherwise, assume
  13188. // an inpage error when dealing with a mapped-in file.
  13189. //
  13190. Err = (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
  13191. ? ERROR_INVALID_PARAMETER
  13192. : ERROR_READ_FAULT;
  13193. //
  13194. // Access the following variables, so that the compiler will respect our
  13195. // statement ordering w.r.t. their assignment.
  13196. //
  13197. UnlockInf = UnlockInf;
  13198. NewCatalogNode = NewCatalogNode;
  13199. }
  13200. if(UnlockInf) {
  13201. UnlockInf((PLOADED_INF)DeviceInfHandle);
  13202. }
  13203. if(NewCatalogNode) {
  13204. MyFree(NewCatalogNode);
  13205. }
  13206. if(InfDeviceDesc) {
  13207. MyFree(InfDeviceDesc);
  13208. }
  13209. return Err;
  13210. }