Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5754 lines
190 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. clasinst.c
  5. Abstract:
  6. Routines for the following 'built-in' class installers:
  7. Keyboard
  8. Mouse
  9. NtApm
  10. DeviceBay
  11. Author:
  12. Lonny McMichael 26-February-1996
  13. Revision History:
  14. 28-Aug-96 Andy Thornton (andrewth)
  15. Added DisableService, IsOnlyKeyboardDriver, RetrieveDriversStatus,
  16. CountDevicesControlled & pSetupAcquireSCMLock routines and modified the
  17. keyboard & mouse class installers to disable the old driver services
  18. under certain circumstances. This is part of a fix for bug R56351 for
  19. NT 4.0 SP1.
  20. 09-Apr-97 Lonny McMichael (lonnym)
  21. Moved pSetupAcquireSCMLock to setupapi and exposed it as a private export.
  22. 19-Jun-97 Jim Cavalaris (t-jcaval)
  23. Added CriticalDeviceCoInstaller co-installer to store the ServiceName
  24. used by devices considered critical to getting the system up into
  25. user mode.
  26. 25-Sep-98 Bryan Willman (bryanwi)
  27. Added apm support.
  28. 11-May-01 Lonny McMichael (lonnym)
  29. Removed support for legacy INFs.
  30. --*/
  31. #include "setupp.h"
  32. #pragma hdrstop
  33. //
  34. // include common INF strings headerfile.
  35. //
  36. #include <infstr.h>
  37. //
  38. // instantiate device class GUIDs.
  39. //
  40. #include <initguid.h>
  41. #include <devguid.h>
  42. #ifdef UNICODE
  43. #define _UNICODE
  44. #endif
  45. #include <tchar.h>
  46. #include <strsafe.h>
  47. //
  48. // Just to make sure no one is trying to use this obsolete string definition.
  49. //
  50. #ifdef IDS_DEVINSTALL_ERROR
  51. #undef IDS_DEVINSTALL_ERROR
  52. #endif
  53. //
  54. // Some debugging aids for us kernel types
  55. //
  56. //#define CHKPRINT 1
  57. #define CHKPRINT 0
  58. #if CHKPRINT
  59. #define ChkPrintEx(_x_) DbgPrint _x_ // use: ChkPrintEx(( "%x", var, ... ));
  60. #define ChkBreak() DbgBreakPoint()
  61. #else
  62. #define ChkPrintEx(_x_)
  63. #define ChkBreak()
  64. #endif
  65. //
  66. // Declare a string containing the character representation of the Display class GUID.
  67. //
  68. CONST WCHAR szDisplayClassGuid[] = L"{4D36E968-E325-11CE-BFC1-08002BE10318}";
  69. //
  70. // Define a string for the service install section suffix.
  71. //
  72. #define SVCINSTALL_SECTION_SUFFIX (TEXT(".") INFSTR_SUBKEY_SERVICES)
  73. //
  74. // Define the size (in characters) of a GUID string, including terminating NULL.
  75. //
  76. #define GUID_STRING_LEN (39)
  77. //
  78. // Define the string for the load order group for keyboards
  79. //
  80. #define SZ_KEYBOARD_LOAD_ORDER_GROUP TEXT("Keyboard Port")
  81. //
  82. // Define a structure for specifying what Plug&Play driver node is used to install
  83. // a particular service.
  84. //
  85. typedef struct _SERVICE_NODE {
  86. struct _SERVICE_NODE *Next;
  87. WCHAR ServiceName[MAX_SERVICE_NAME_LEN];
  88. DWORD DriverNodeIndex;
  89. } SERVICE_NODE, *PSERVICE_NODE;
  90. //
  91. // Define a structure for specifying a legacy INF that is included in a class driver list.
  92. //
  93. typedef struct _LEGACYINF_NODE {
  94. struct _LEGACYINF_NODE *Next;
  95. WCHAR InfFileName[MAX_PATH];
  96. } LEGACYINF_NODE, *PLEGACYINF_NODE;
  97. //
  98. // Define the context structure used by the critical device co-installer
  99. //
  100. typedef struct _CDC_CONTEXT {
  101. TCHAR OldMatchingDevId[MAX_DEVICE_ID_LEN]; // previous matching device id
  102. TCHAR OldServiceName[MAX_SERVICE_NAME_LEN]; // previous controlling service
  103. // or empty string if none.
  104. } CDC_CONTEXT, *PCDC_CONTEXT;
  105. //
  106. // Strings used in ntapm detection
  107. //
  108. WCHAR rgzMultiFunctionAdapter[] =
  109. L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter";
  110. WCHAR rgzConfigurationData[] = L"Configuration Data";
  111. WCHAR rgzIdentifier[] = L"Identifier";
  112. WCHAR rgzGoodBadKey[] =
  113. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Biosinfo\\APM";
  114. WCHAR rgzGoodBadValue[] =
  115. L"Attributes";
  116. WCHAR rgzAcpiKey[] =
  117. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\ACPI\\Enum";
  118. WCHAR rgzAcpiCount[] =
  119. L"Count";
  120. WCHAR rgzApmLegalHalKey[] =
  121. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ApmLegalHal";
  122. WCHAR rgzApmHalPresent[] =
  123. L"Present";
  124. //
  125. // Internal function prototypes.
  126. //
  127. DWORD
  128. DrvTagToFrontOfGroupOrderList(
  129. IN HDEVINFO DeviceInfoSet,
  130. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  131. );
  132. BOOL
  133. UserBalksAtSharedDrvMsg(
  134. IN HDEVINFO DeviceInfoSet,
  135. IN PSP_DEVINFO_DATA DeviceInfoData,
  136. IN PSP_DEVINSTALL_PARAMS DeviceInstallParams
  137. );
  138. VOID
  139. CopyFixedUpDeviceId(
  140. OUT LPWSTR DestinationString,
  141. IN LPCWSTR SourceString,
  142. IN DWORD SourceStringLen
  143. );
  144. VOID
  145. MigrateLegacyDisplayDevices(
  146. IN HDEVINFO hDevInfo
  147. );
  148. DWORD
  149. DisableService(
  150. IN LPTSTR ServiceName
  151. );
  152. DWORD
  153. IsKeyboardDriver(
  154. IN PCWSTR ServiceName,
  155. OUT PBOOL pResult
  156. );
  157. DWORD
  158. IsOnlyKeyboardDriver(
  159. IN PCWSTR ServiceName,
  160. OUT PBOOL pResult
  161. );
  162. DWORD
  163. GetServiceStartType(
  164. IN PCWSTR ServiceName
  165. );
  166. LONG
  167. CountDevicesControlled(
  168. IN LPTSTR ServiceName
  169. );
  170. DWORD
  171. InstallNtApm(
  172. IN HDEVINFO DevInfoHandle,
  173. IN BOOLEAN InstallDisabled
  174. );
  175. DWORD
  176. AllowInstallNtApm(
  177. IN HDEVINFO DevInfoHandle,
  178. IN PSP_DEVINFO_DATA DevInfoData OPTIONAL
  179. );
  180. #define NTAPM_NOWORK 0
  181. #define NTAPM_INST_DISABLED 1
  182. #define NTAPM_INST_ENABLED 2
  183. DWORD
  184. DecideNtApm(
  185. VOID
  186. );
  187. #define APM_NOT_PRESENT 0
  188. #define APM_PRESENT_BUT_NOT_USABLE 1
  189. #define APM_ON_GOOD_LIST 2
  190. #define APM_NEUTRAL 3
  191. #define APM_ON_BAD_LIST 4
  192. BOOL
  193. IsProductTypeApmLegal(
  194. VOID
  195. );
  196. DWORD
  197. IsApmPresent(
  198. VOID
  199. );
  200. BOOL
  201. IsAcpiMachine(
  202. VOID
  203. );
  204. BOOL
  205. IsApmLegalHalMachine(
  206. VOID
  207. );
  208. HKEY
  209. OpenCDDRegistryKey(
  210. IN PCTSTR DeviceId,
  211. IN BOOL Create
  212. );
  213. //
  214. // Function definitions
  215. //
  216. BOOL
  217. pInGUISetup(
  218. IN HDEVINFO DeviceInfoSet,
  219. IN PSP_DEVINFO_DATA DeviceInfoData
  220. )
  221. {
  222. SP_DEVINSTALL_PARAMS dip;
  223. ZeroMemory(&dip, sizeof(SP_DEVINSTALL_PARAMS));
  224. dip.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  225. if (SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &dip)) {
  226. if ((dip.Flags & DI_QUIETINSTALL) ||
  227. (dip.FlagsEx & DI_FLAGSEX_IN_SYSTEM_SETUP)) {
  228. return TRUE;
  229. }
  230. else {
  231. return FALSE;
  232. }
  233. }
  234. else {
  235. return FALSE;
  236. }
  237. }
  238. BOOLEAN
  239. MigrateToDevnode(
  240. IN HDEVINFO DeviceInfoSet,
  241. IN PSP_DEVINFO_DATA DeviceInfoData
  242. )
  243. /*++
  244. Routine Description:
  245. This routine will look for a section in the inf that describes what service's
  246. values to migrate up to the new device's devnode. The section's name is
  247. %DecoratedInstallName%.MigrateToDevnode. Under this section the following
  248. entry is looked for:
  249. service-name=value-name[,value-name]...
  250. Each of the value-nanmes are read from
  251. ...\CurrentControlSet\service-name\Parameters and written to the devnode
  252. The primary use of this function is that all of the user modified values are
  253. propagated during upgrade.
  254. Arguments:
  255. DeviceInfoSet - Supplies a handle to the device information set being
  256. acted upon by this install action.
  257. DeviceInfoData - Optionally, supplies the address of a device information
  258. element being acted upon by this install action.
  259. Return Value:
  260. If this function successfully migrates the values listed, it returns TRUE.
  261. If this function cannot successfully migrate the values, then it returns
  262. FALSE.
  263. If this function is being run on a devnode that has already been migrated,
  264. then it returns TRUE.
  265. --*/
  266. {
  267. HKEY hDestination = (HKEY) INVALID_HANDLE_VALUE,
  268. hSource = (HKEY) INVALID_HANDLE_VALUE;
  269. SP_DRVINFO_DETAIL_DATA didd;
  270. SP_DRVINFO_DATA did;
  271. HINF hInf = INVALID_HANDLE_VALUE;
  272. INFCONTEXT infContext;
  273. TCHAR szSectionName[LINE_LEN];
  274. PTCHAR szService = NULL, szServicePath = NULL,
  275. szValueNames = NULL, szCurrentName = NULL;
  276. DWORD dwSize, res, regDataType, regSize, migrated;
  277. BOOLEAN success = FALSE;
  278. PBYTE buffer = NULL;
  279. TCHAR szMigrated[] = L"Migrated";
  280. TCHAR szRegServices[] = L"System\\CurrentControlSet\\Services\\";
  281. TCHAR szParameters[] = L"\\Parameters";
  282. TCHAR szMigrateToDevnode[] = L".MigrateToDevnode";
  283. #define DEFAULT_BUFFER_SIZE 100
  284. if ((hDestination = SetupDiCreateDevRegKey(DeviceInfoSet,
  285. DeviceInfoData,
  286. DICS_FLAG_GLOBAL,
  287. 0,
  288. DIREG_DEV,
  289. NULL,
  290. NULL)) == INVALID_HANDLE_VALUE) {
  291. goto cleanup;
  292. }
  293. dwSize = sizeof(DWORD);
  294. migrated = 0;
  295. if (RegQueryValueEx(hDestination,
  296. szMigrated,
  297. 0,
  298. &regDataType,
  299. (PBYTE) &migrated,
  300. &dwSize) == ERROR_SUCCESS &&
  301. regDataType == REG_DWORD &&
  302. migrated != 0) {
  303. //
  304. // We have migrated to the devnode before (ie a previous upgrade) and
  305. // the user might have changed the respective values, just quit.
  306. //
  307. success = TRUE;
  308. goto cleanup;
  309. }
  310. else {
  311. migrated = TRUE;
  312. RegSetValueEx(hDestination,
  313. szMigrated,
  314. 0,
  315. REG_DWORD,
  316. (PBYTE) &migrated,
  317. sizeof(DWORD));
  318. }
  319. //
  320. // Retrieve information about the driver node selected for this device.
  321. //
  322. did.cbSize = sizeof(SP_DRVINFO_DATA);
  323. if(!SetupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData, &did)) {
  324. goto cleanup;
  325. }
  326. didd.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  327. if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  328. DeviceInfoData,
  329. &did,
  330. &didd,
  331. sizeof(didd),
  332. NULL)
  333. && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
  334. //
  335. // For some reason we couldn't get detail data--this should never happen.
  336. //
  337. goto cleanup;
  338. }
  339. //
  340. // Open the INF that installs this driver node, so we can 'pre-run' the AddReg
  341. // entries in its install section.
  342. //
  343. hInf = SetupOpenInfFile(didd.InfFileName,
  344. NULL,
  345. INF_STYLE_WIN4,
  346. NULL
  347. );
  348. if (hInf == INVALID_HANDLE_VALUE) {
  349. //
  350. // For some reason we couldn't open the INF--this should never happen.
  351. //
  352. goto cleanup;
  353. }
  354. if (!SetupDiGetActualSectionToInstall(hInf,
  355. didd.SectionName,
  356. szSectionName,
  357. sizeof(szSectionName) / sizeof(TCHAR),
  358. NULL,
  359. NULL
  360. ) ||
  361. FAILED(StringCchCat(szSectionName, SIZECHARS(szSectionName), szMigrateToDevnode)) ||
  362. (!SetupFindFirstLine(hInf,
  363. szSectionName,
  364. NULL,
  365. &infContext))) {
  366. goto cleanup;
  367. }
  368. dwSize = 0;
  369. if (SetupGetStringField(&infContext, 0, NULL, 0, &dwSize)) {
  370. //
  371. // Increment the count to hold the null and alloc. The count returned
  372. // is the number of characters in the strings, NOT the number of bytes
  373. // needed.
  374. //
  375. dwSize++;
  376. szService = (PTCHAR) LocalAlloc(LPTR, dwSize * sizeof(TCHAR));
  377. if (!szService ||
  378. !SetupGetStringField(&infContext, 0, szService, dwSize, &dwSize)) {
  379. goto cleanup;
  380. }
  381. }
  382. else {
  383. goto cleanup;
  384. }
  385. dwSize = wcslen(szRegServices)+wcslen(szService)+wcslen(szParameters)+1;
  386. dwSize *= sizeof(TCHAR);
  387. szServicePath = (PTCHAR) LocalAlloc(LPTR, dwSize);
  388. if (!szServicePath) {
  389. res = GetLastError();
  390. goto cleanup;
  391. }
  392. if (FAILED(StringCbCopy(szServicePath, dwSize, szRegServices)) ||
  393. FAILED(StringCbCat(szServicePath, dwSize, szService)) ||
  394. FAILED(StringCbCat(szServicePath, dwSize, szParameters)) ||
  395. (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  396. szServicePath,
  397. 0,
  398. KEY_ALL_ACCESS,
  399. &hSource) != ERROR_SUCCESS)) {
  400. goto cleanup;
  401. }
  402. dwSize = 0;
  403. if (SetupGetMultiSzField(&infContext, 1, NULL, 0, &dwSize)) {
  404. //
  405. // Increment the count to hold the null and alloc. The count returned
  406. // is the number of characters in the strings, NOT the number of bytes
  407. // needed.
  408. //
  409. dwSize++;
  410. szValueNames = (PTCHAR) LocalAlloc(LPTR, dwSize * sizeof(TCHAR));
  411. if (!szValueNames ||
  412. !SetupGetMultiSzField(&infContext, 1, szValueNames, dwSize, &dwSize)) {
  413. goto cleanup;
  414. }
  415. }
  416. else {
  417. goto cleanup;
  418. }
  419. regSize = dwSize = DEFAULT_BUFFER_SIZE;
  420. buffer = (PBYTE) LocalAlloc(LPTR, regSize);
  421. if (!buffer) {
  422. goto cleanup;
  423. }
  424. for (szCurrentName = szValueNames;
  425. *szCurrentName;
  426. regSize = dwSize, szCurrentName += wcslen(szCurrentName) + 1) {
  427. getbits:
  428. res = RegQueryValueEx(hSource,
  429. szCurrentName,
  430. 0,
  431. &regDataType,
  432. (PBYTE) buffer,
  433. &regSize);
  434. if (res == ERROR_MORE_DATA) {
  435. //
  436. // regSize contains new buffer size, free and reallocate
  437. //
  438. dwSize = regSize;
  439. LocalFree(buffer);
  440. buffer = LocalAlloc(LPTR, dwSize);
  441. if (buffer) {
  442. goto getbits;
  443. }
  444. else {
  445. goto cleanup;
  446. }
  447. }
  448. else if (res == ERROR_SUCCESS) {
  449. RegSetValueEx(hDestination,
  450. szCurrentName,
  451. 0,
  452. regDataType,
  453. buffer,
  454. regSize);
  455. }
  456. }
  457. success = TRUE;
  458. cleanup:
  459. //
  460. // Clean up and leave
  461. //
  462. if (hInf != (HKEY) INVALID_HANDLE_VALUE) {
  463. SetupCloseInfFile(hInf);
  464. }
  465. if (hDestination != (HKEY) INVALID_HANDLE_VALUE) {
  466. RegCloseKey(hDestination);
  467. }
  468. if (hSource != (HKEY) INVALID_HANDLE_VALUE) {
  469. RegCloseKey(hSource);
  470. }
  471. if (buffer) {
  472. LocalFree(buffer);
  473. }
  474. if (szService) {
  475. LocalFree(szService);
  476. }
  477. if (szServicePath) {
  478. LocalFree(szServicePath);
  479. }
  480. if (szValueNames) {
  481. LocalFree(szValueNames);
  482. }
  483. return success;
  484. }
  485. void
  486. MarkDriverNodesBad(
  487. IN HDEVINFO DeviceInfoSet,
  488. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  489. IN DWORD DriverType
  490. )
  491. {
  492. SP_DRVINSTALL_PARAMS drvInstallParams;
  493. SP_DRVINFO_DATA drvData;
  494. ULONG index = 0;
  495. //
  496. // Only mark driver nodes as bad during gui setup
  497. //
  498. if (!pInGUISetup(DeviceInfoSet, DeviceInfoData)) {
  499. return;
  500. }
  501. if (SetupDiBuildDriverInfoList(DeviceInfoSet, DeviceInfoData, DriverType))
  502. {
  503. ZeroMemory(&drvData, sizeof(SP_DRVINFO_DATA));
  504. drvData.cbSize = sizeof(SP_DRVINFO_DATA);
  505. while (SetupDiEnumDriverInfo(DeviceInfoSet,
  506. DeviceInfoData,
  507. DriverType,
  508. index++,
  509. &drvData)) {
  510. if (drvData.DriverVersion == 0) {
  511. ZeroMemory(&drvInstallParams, sizeof(SP_DRVINSTALL_PARAMS));
  512. drvInstallParams.cbSize = sizeof(SP_DRVINSTALL_PARAMS);
  513. if (SetupDiGetDriverInstallParams(DeviceInfoSet,
  514. DeviceInfoData,
  515. &drvData,
  516. &drvInstallParams))
  517. {
  518. drvInstallParams.Flags |= DNF_BAD_DRIVER;
  519. SetupDiSetDriverInstallParams(DeviceInfoSet,
  520. DeviceInfoData,
  521. &drvData,
  522. &drvInstallParams);
  523. }
  524. }
  525. ZeroMemory(&drvData, sizeof(SP_DRVINFO_DATA));
  526. drvData.cbSize = sizeof(SP_DRVINFO_DATA);
  527. }
  528. }
  529. }
  530. DWORD
  531. ConfirmWHQLInputRequirements(
  532. IN HDEVINFO DeviceInfoSet,
  533. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  534. IN LPTSTR Services,
  535. IN LPCTSTR CompatInfName,
  536. IN DI_FUNCTION InstallFunction
  537. )
  538. /*++
  539. Routine Description:
  540. This function enforces the WHQL requirements that a 3rd party vendor or OEM
  541. cannot replace the ImagePath of the input drivers (mouclass.sys for instance).
  542. This does not stop the OEMs from disabling our drivers and installing their
  543. own services though.
  544. Arguments:
  545. DeviceInfoSet - Supplies a handle to the device information set being
  546. acted upon by this install action.
  547. DeviceInfoData - Optionally, supplies the address of a device information
  548. element being acted upon by this install action.
  549. Services - A multi-sz of service names to check
  550. CompatInfName - name of the system inf to set the match to if we detect an
  551. an INF that is actually trying to replace an image
  552. InstallFunction - The InstallFunction for which this function was called for.
  553. The function does different things if InstallFunction is equal to
  554. DIF_SELECTBESTCOMPATDRV.
  555. Return Value:
  556. If this function determines that the INF in question matches the WHQL
  557. requirement, returns ERROR_DI_DO_DEFAULT
  558. If the default determines that the INF violates the requirements and we find
  559. a match, returns NO_ERROR
  560. If the default determines that the INF violates the requirements and we
  561. don't find a match or the InstallFunction is not select best compat drv,
  562. returns ERROR_DI_DONT_INSTALL.
  563. If an error occurred while attempting to perform the requested action, a
  564. Win32 error code is returned (via GetLastError)
  565. --*/
  566. {
  567. HINF hInf;
  568. SP_DRVINFO_DATA drvData;
  569. SP_DRVINFO_DETAIL_DATA drvDetData;
  570. DWORD dwSize;
  571. TCHAR szSection[LINE_LEN],
  572. szNewService[LINE_LEN],
  573. szBinary[LINE_LEN],
  574. szServiceInstallSection[LINE_LEN];
  575. LPTSTR szCurrentService;
  576. INFCONTEXT infContext, infContextService;
  577. DWORD ret = ERROR_DI_DO_DEFAULT;
  578. BOOLEAN badServiceEntry = FALSE;
  579. if (InstallFunction == DIF_SELECTBESTCOMPATDRV) {
  580. MarkDriverNodesBad(DeviceInfoSet, DeviceInfoData, SPDIT_COMPATDRIVER);
  581. if (!SetupDiSelectBestCompatDrv(DeviceInfoSet, DeviceInfoData)) {
  582. return GetLastError();
  583. }
  584. }
  585. ZeroMemory(&drvData, sizeof(SP_DRVINFO_DATA));
  586. drvData.cbSize = sizeof(SP_DRVINFO_DATA);
  587. if (!SetupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData, &drvData)) {
  588. return GetLastError();
  589. }
  590. ZeroMemory(&drvDetData, sizeof(SP_DRVINFO_DETAIL_DATA));
  591. drvDetData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  592. if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  593. DeviceInfoData,
  594. &drvData,
  595. &drvDetData,
  596. drvDetData.cbSize,
  597. &dwSize) &&
  598. GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  599. return GetLastError();
  600. }
  601. hInf = SetupOpenInfFile(drvDetData.InfFileName,
  602. NULL,
  603. INF_STYLE_WIN4,
  604. NULL);
  605. if (hInf == INVALID_HANDLE_VALUE) {
  606. return ERROR_DI_DO_DEFAULT;
  607. }
  608. //
  609. // Get the actual section name so we can find the .Services section
  610. //
  611. if (!SetupDiGetActualSectionToInstall(hInf,
  612. drvDetData.SectionName,
  613. szSection,
  614. sizeof(szSection) / sizeof(TCHAR),
  615. NULL,
  616. NULL)) {
  617. ret = GetLastError();
  618. goto Done;
  619. }
  620. if (FAILED(StringCchCat(szSection, SIZECHARS(szSection), SVCINSTALL_SECTION_SUFFIX))) {
  621. ret = ERROR_INSUFFICIENT_BUFFER;
  622. goto Done;
  623. }
  624. if (SetupFindFirstLine(hInf, szSection, TEXT("AddService"), &infContext)) {
  625. do {
  626. //
  627. // Get the name of the service to install
  628. //
  629. dwSize = LINE_LEN;
  630. if (!SetupGetStringField(&infContext,
  631. 1,
  632. szNewService,
  633. dwSize,
  634. &dwSize)) {
  635. continue;
  636. }
  637. _tcsupr(szNewService);
  638. for (szCurrentService = Services;
  639. *szCurrentService;
  640. szCurrentService += lstrlen(szCurrentService) + 1) {
  641. if (lstrcmp(szCurrentService, szNewService) != 0) {
  642. continue;
  643. }
  644. dwSize = LINE_LEN;
  645. if (!SetupGetStringField(&infContext,
  646. 3,
  647. szServiceInstallSection,
  648. dwSize,
  649. &dwSize)) {
  650. continue;
  651. }
  652. if (!SetupFindFirstLine(hInf,
  653. szServiceInstallSection,
  654. TEXT("ServiceBinary"),
  655. &infContextService)) {
  656. //
  657. // If no ServiceBinary is present, the system looks for a .sys with the
  658. // same name as the service so we are OK
  659. //
  660. continue;
  661. }
  662. //
  663. // Get the actual binary's image name
  664. //
  665. dwSize = LINE_LEN;
  666. if (!SetupGetStringField(&infContextService,
  667. 1,
  668. szBinary,
  669. dwSize,
  670. &dwSize)) {
  671. //
  672. // couldn't get the name, assume the worst
  673. //
  674. badServiceEntry = TRUE;
  675. }
  676. else {
  677. _tcsupr(szBinary);
  678. if (_tcsstr(szBinary, szNewService) == NULL) {
  679. //
  680. // The service name is NOT the same as the binary's name
  681. //
  682. badServiceEntry = TRUE;
  683. }
  684. }
  685. //
  686. // No need to continue searching the list, we already found our
  687. // match
  688. //
  689. break;
  690. }
  691. if (badServiceEntry) {
  692. SP_DRVINFO_DATA drvDataAlt;
  693. SP_DRVINFO_DETAIL_DATA drvDetDataAlt;
  694. TCHAR szFmt[256];
  695. TCHAR szMsgTxt[256];
  696. int i = 0;
  697. ret = ERROR_DI_DONT_INSTALL;
  698. SetupOpenLog(FALSE);
  699. if (InstallFunction != DIF_SELECTBESTCOMPATDRV) {
  700. //
  701. // We will try to pick a better one if we find new hardware,
  702. // but for the update driver / manual install case,
  703. // fail it!
  704. //
  705. LoadString(MyModuleHandle,
  706. IDS_FAIL_INPUT_WHQL_REQS,
  707. szFmt,
  708. SIZECHARS(szFmt));
  709. StringCchPrintf(szMsgTxt,
  710. SIZECHARS(szMsgTxt),
  711. szFmt,
  712. drvDetData.InfFileName,
  713. szNewService);
  714. SetupLogError(szMsgTxt, LogSevError);
  715. SetupCloseLog();
  716. break;
  717. }
  718. //
  719. // We should have a match in the system provided inf
  720. //
  721. drvDataAlt.cbSize = sizeof(SP_DRVINFO_DATA);
  722. while (SetupDiEnumDriverInfo(DeviceInfoSet,
  723. DeviceInfoData,
  724. SPDIT_COMPATDRIVER,
  725. i++,
  726. &drvDataAlt)) {
  727. PCTSTR name;
  728. drvDetDataAlt.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  729. if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  730. DeviceInfoData,
  731. &drvDataAlt,
  732. &drvDetDataAlt,
  733. drvDetDataAlt.cbSize,
  734. &dwSize) &&
  735. GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  736. //
  737. // Do something here!
  738. //
  739. // return GetLastError();
  740. }
  741. //
  742. // Find just the inf file name w/out the path
  743. //
  744. name = pSetupGetFileTitle(drvDetDataAlt.InfFileName);
  745. if (lstrcmpi(name, CompatInfName) == 0) {
  746. //
  747. // Set the known good entry as the selected device
  748. //
  749. SetupDiSetSelectedDriver(DeviceInfoSet,
  750. DeviceInfoData,
  751. &drvDataAlt);
  752. ret = ERROR_SUCCESS;
  753. break;
  754. }
  755. }
  756. if (ret == ERROR_SUCCESS) {
  757. LoadString(MyModuleHandle,
  758. IDS_FAIL_INPUT_WHQL_REQS_AVERTED,
  759. szFmt,
  760. SIZECHARS(szFmt));
  761. StringCchPrintf(szMsgTxt,
  762. SIZECHARS(szMsgTxt),
  763. szFmt,
  764. drvDetData.InfFileName,
  765. szNewService,
  766. CompatInfName);
  767. }
  768. else {
  769. LoadString(MyModuleHandle,
  770. IDS_FAIL_INPUT_WHQL_REQS_NO_ALT,
  771. szFmt,
  772. SIZECHARS(szFmt));
  773. StringCchPrintf(szMsgTxt,
  774. SIZECHARS(szMsgTxt),
  775. szFmt,
  776. drvDetData.InfFileName,
  777. szNewService,
  778. CompatInfName);
  779. }
  780. SetupLogError(szMsgTxt, LogSevWarning);
  781. SetupCloseLog();
  782. break;
  783. }
  784. } while (SetupFindNextMatchLine(&infContext, TEXT("AddService"), &infContext));
  785. }
  786. Done:
  787. SetupCloseInfFile(hInf);
  788. return ret;
  789. }
  790. #define InputClassOpenLog() SetupOpenLog(FALSE)
  791. #define InputClassCloseLog() SetupCloseLog()
  792. BOOL CDECL
  793. InputClassLogError(
  794. LogSeverity Severity,
  795. TCHAR *MsgFormat,
  796. ...
  797. )
  798. /*++
  799. Outputs a message to the setup log. Prepends "Input Install: " to the
  800. strings and appends the correct newline chars (\r\n)
  801. --*/
  802. {
  803. int cch;
  804. TCHAR ach[MAX_PATH+4]; // Largest path plus extra
  805. va_list vArgs;
  806. BOOL result;
  807. InputClassOpenLog();
  808. *ach = 0;
  809. StringCchPrintf(ach, SIZECHARS(ach), TEXT("Input Install: "));
  810. cch = lstrlen(ach);
  811. va_start(vArgs, MsgFormat);
  812. wvnsprintf(&ach[cch], MAX_PATH-cch, MsgFormat, vArgs);
  813. StringCchCat(ach, SIZECHARS(ach), TEXT("\r\n"));
  814. va_end(vArgs);
  815. result = SetupLogError(ach, Severity);
  816. InputClassCloseLog();
  817. return result;
  818. }
  819. TCHAR szPS2Driver[] = TEXT("i8042prt");
  820. VOID
  821. FixUpPS2Mouse(
  822. IN HDEVINFO DeviceInfoSet,
  823. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  824. IN LPCTSTR NewServiceName
  825. )
  826. {
  827. HKEY hDevnode, hKeySystem;
  828. DWORD dwSize, dwDetect = 0, dwType;
  829. TCHAR szDetect[] = TEXT("EnableWheelDetection");
  830. TCHAR szBadBios[] = TEXT("PS2_Inst.NoInterruptInit.Bioses");
  831. TCHAR szSection[] = TEXT("PS2_Inst.NoInterruptInit");
  832. TCHAR szDescSystem[] = TEXT("HARDWARE\\DESCRIPTION\\SYSTEM");
  833. TCHAR szSystemBiosVersion[] = TEXT("SystemBiosVersion");
  834. PTCHAR szBadBiosNames = NULL,
  835. szCurrentBadName,
  836. szBiosNames = NULL,
  837. szCurrentBiosName;
  838. SP_DRVINFO_DETAIL_DATA didd;
  839. SP_DRVINFO_DATA did;
  840. BOOL bad;
  841. HINF hInf = INVALID_HANDLE_VALUE;
  842. INFCONTEXT infContext;
  843. if (lstrcmpi(NewServiceName, szPS2Driver) != 0) {
  844. InputClassLogError(LogSevInformation, TEXT("Not a PS2 device."));
  845. return;
  846. }
  847. hDevnode = SetupDiOpenDevRegKey(DeviceInfoSet,
  848. DeviceInfoData,
  849. DICS_FLAG_GLOBAL,
  850. 0,
  851. DIREG_DEV,
  852. KEY_ALL_ACCESS);
  853. if (hDevnode == INVALID_HANDLE_VALUE) {
  854. return;
  855. }
  856. //
  857. // We are forcing the wheel detection to assume wheel is present for i8042prt.
  858. // If we get negative feedback from this, we will remove this code, other-
  859. // wise this will save us the hassle of OEM wheel mice that we
  860. // can't detect at all.
  861. //
  862. dwSize = sizeof(DWORD);
  863. if (RegQueryValueEx(hDevnode,
  864. szDetect,
  865. NULL,
  866. NULL,
  867. (PBYTE) &dwDetect,
  868. &dwSize) != ERROR_SUCCESS || dwDetect == 1) {
  869. dwDetect = 2;
  870. RegSetValueEx(hDevnode,
  871. szDetect,
  872. 0,
  873. REG_DWORD,
  874. (PBYTE) &dwDetect,
  875. sizeof(DWORD));
  876. }
  877. //
  878. // See if this system can't handle init via the interrupt
  879. //
  880. //
  881. // Get the system bios description (a multi sz)
  882. //
  883. dwSize = 0;
  884. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  885. szDescSystem,
  886. 0,
  887. KEY_READ,
  888. &hKeySystem) != ERROR_SUCCESS ||
  889. RegQueryValueEx(hKeySystem,
  890. szSystemBiosVersion,
  891. NULL,
  892. NULL,
  893. NULL,
  894. &dwSize) != ERROR_SUCCESS || dwSize == 0) {
  895. goto finished;
  896. }
  897. dwSize++;
  898. szBiosNames = (PTCHAR) LocalAlloc(LPTR, dwSize * sizeof(TCHAR));
  899. dwType = 0;
  900. if (!szBiosNames ||
  901. RegQueryValueEx(hKeySystem,
  902. szSystemBiosVersion,
  903. NULL,
  904. &dwType,
  905. (PBYTE) szBiosNames,
  906. &dwSize) != ERROR_SUCCESS || dwType != REG_MULTI_SZ) {
  907. goto finished;
  908. }
  909. //
  910. // Retrieve information about the driver node selected for this device.
  911. //
  912. did.cbSize = sizeof(SP_DRVINFO_DATA);
  913. if(!SetupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData, &did)) {
  914. goto finished;
  915. }
  916. didd.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  917. if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  918. DeviceInfoData,
  919. &did,
  920. &didd,
  921. sizeof(didd),
  922. NULL)
  923. && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
  924. //
  925. // For some reason we couldn't get detail data--this should never happen.
  926. //
  927. InputClassLogError(LogSevInformation, TEXT("Couldn't get driver info detail."));
  928. goto finished;
  929. }
  930. //
  931. // Open the INF that installs this driver node, so we can 'pre-run' the AddReg
  932. // entries in its install section.
  933. //
  934. hInf = SetupOpenInfFile(didd.InfFileName,
  935. NULL,
  936. INF_STYLE_WIN4,
  937. NULL);
  938. if (hInf == INVALID_HANDLE_VALUE) {
  939. //
  940. // For some reason we couldn't open the INF--this should never happen.
  941. //
  942. InputClassLogError(LogSevInformation, TEXT("Couldn't open inf."));
  943. goto finished;
  944. }
  945. dwSize = 0;
  946. if (!SetupFindFirstLine(hInf, szBadBios, NULL, &infContext) ||
  947. !SetupGetMultiSzField(&infContext, 1, NULL, 0, &dwSize)) {
  948. goto finished;
  949. }
  950. //
  951. // Increment the count to hold the null and alloc. The count returned
  952. // is the number of characters in the strings, NOT the number of bytes
  953. // needed.
  954. //
  955. dwSize++;
  956. szBadBiosNames = (PTCHAR) LocalAlloc(LPTR, dwSize * sizeof(TCHAR));
  957. if (!szBadBiosNames ||
  958. !SetupGetMultiSzField(&infContext, 1, szBadBiosNames, dwSize, &dwSize)) {
  959. goto finished;
  960. }
  961. bad = FALSE;
  962. for (szCurrentBadName = szBadBiosNames;
  963. *szCurrentBadName;
  964. szCurrentBadName += wcslen(szCurrentBadName) + 1) {
  965. _tcsupr(szCurrentBadName);
  966. for (szCurrentBiosName = szBiosNames;
  967. *szCurrentBiosName;
  968. szCurrentBiosName += wcslen(szCurrentBiosName) + 1) {
  969. if (szCurrentBadName == szBadBiosNames) {
  970. _tcsupr(szCurrentBiosName);
  971. }
  972. if (_tcsstr(szCurrentBiosName, szCurrentBadName)) {
  973. bad =
  974. SetupInstallFromInfSection(NULL,
  975. hInf,
  976. szSection,
  977. SPINST_REGISTRY,
  978. hDevnode,
  979. NULL,
  980. 0,
  981. NULL,
  982. NULL,
  983. DeviceInfoSet,
  984. DeviceInfoData);
  985. break;
  986. }
  987. }
  988. if (bad) {
  989. break;
  990. }
  991. }
  992. finished:
  993. if (szBiosNames) {
  994. LocalFree(szBiosNames);
  995. szBiosNames = NULL;
  996. }
  997. if (szBadBiosNames) {
  998. LocalFree(szBadBiosNames);
  999. szBadBiosNames = NULL;
  1000. }
  1001. if (hInf != INVALID_HANDLE_VALUE) {
  1002. SetupCloseInfFile(hInf);
  1003. hInf = INVALID_HANDLE_VALUE;
  1004. }
  1005. if (hDevnode != INVALID_HANDLE_VALUE) {
  1006. RegCloseKey(hDevnode);
  1007. hDevnode = INVALID_HANDLE_VALUE;
  1008. }
  1009. if (hKeySystem != INVALID_HANDLE_VALUE) {
  1010. RegCloseKey(hKeySystem);
  1011. hKeySystem = INVALID_HANDLE_VALUE;
  1012. }
  1013. }
  1014. TCHAR szMouclassParameters[] = TEXT("System\\CurrentControlSet\\Services\\Mouclass\\Parameters");
  1015. TCHAR szNativeMouseInf[] = TEXT("msmouse.inf");
  1016. TCHAR szNativeMouseServices[] =
  1017. TEXT("MOUCLASS\0")
  1018. TEXT("I8042PRT\0")
  1019. TEXT("SERMOUSE\0")
  1020. TEXT("MOUHID\0")
  1021. TEXT("INPORT\0")
  1022. TEXT("\0");
  1023. typedef struct _MULTI_SZ {
  1024. LPTSTR String;
  1025. DWORD Size;
  1026. } MULTI_SZ, *PMULTI_SZ;
  1027. typedef struct _FILTERS {
  1028. MULTI_SZ Lower;
  1029. MULTI_SZ Upper;
  1030. } FILTERS, *PFILTERS;
  1031. void GetFilterInfo(
  1032. IN HDEVINFO DeviceInfoSet,
  1033. IN PSP_DEVINFO_DATA DeviceInfoData,
  1034. IN DWORD Property,
  1035. OUT PMULTI_SZ MultiSz
  1036. )
  1037. {
  1038. BOOL res;
  1039. ZeroMemory(MultiSz, sizeof(MULTI_SZ));
  1040. //
  1041. // Will return FALSE and set the last error to insufficient buffer if
  1042. // this property is present.
  1043. //
  1044. res = SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1045. DeviceInfoData,
  1046. Property,
  1047. NULL,
  1048. NULL,
  1049. 0,
  1050. &MultiSz->Size);
  1051. if (res == FALSE && GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
  1052. MultiSz->Size > 0) {
  1053. MultiSz->String = (LPTSTR) LocalAlloc(LPTR, MultiSz->Size);
  1054. if (MultiSz->String) {
  1055. if (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1056. DeviceInfoData,
  1057. Property,
  1058. NULL,
  1059. (PBYTE) MultiSz->String,
  1060. MultiSz->Size,
  1061. NULL)) {
  1062. LocalFree(MultiSz->String);
  1063. MultiSz->String = NULL;
  1064. }
  1065. else {
  1066. //
  1067. // Blow away the values. If there is failure, RestoreDeviceFilters
  1068. // will set the values back. If this functions fails, there is
  1069. // not much we can do!
  1070. //
  1071. SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
  1072. DeviceInfoData,
  1073. Property,
  1074. NULL,
  1075. 0);
  1076. }
  1077. }
  1078. }
  1079. }
  1080. void
  1081. GetDeviceFilters(
  1082. IN HDEVINFO DeviceInfoSet,
  1083. IN PSP_DEVINFO_DATA DeviceInfoData,
  1084. OUT PFILTERS Filters
  1085. )
  1086. {
  1087. GetFilterInfo(DeviceInfoSet, DeviceInfoData, SPDRP_LOWERFILTERS, &Filters->Lower);
  1088. GetFilterInfo(DeviceInfoSet, DeviceInfoData, SPDRP_UPPERFILTERS, &Filters->Upper);
  1089. }
  1090. void
  1091. FreeDeviceFilters(
  1092. OUT PFILTERS Filters
  1093. )
  1094. {
  1095. if (Filters->Lower.String) {
  1096. LocalFree(Filters->Lower.String);
  1097. ZeroMemory(&Filters->Lower, sizeof(MULTI_SZ));
  1098. }
  1099. if (Filters->Upper.String) {
  1100. LocalFree(Filters->Upper.String);
  1101. ZeroMemory(&Filters->Upper, sizeof(MULTI_SZ));
  1102. }
  1103. }
  1104. void
  1105. RestoreDeviceFilters(
  1106. IN HDEVINFO DeviceInfoSet,
  1107. IN PSP_DEVINFO_DATA DeviceInfoData,
  1108. OUT PFILTERS Filters
  1109. )
  1110. {
  1111. if (Filters->Lower.String) {
  1112. SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
  1113. DeviceInfoData,
  1114. SPDRP_LOWERFILTERS,
  1115. (CONST PBYTE) Filters->Lower.String,
  1116. Filters->Lower.Size);
  1117. }
  1118. if (Filters->Upper.String) {
  1119. SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
  1120. DeviceInfoData,
  1121. SPDRP_UPPERFILTERS,
  1122. (CONST PBYTE) Filters->Upper.String,
  1123. Filters->Upper.Size);
  1124. }
  1125. FreeDeviceFilters(Filters);
  1126. }
  1127. DWORD
  1128. MouseClassInstaller(
  1129. IN DI_FUNCTION InstallFunction,
  1130. IN HDEVINFO DeviceInfoSet,
  1131. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  1132. )
  1133. /*++
  1134. Routine Description:
  1135. This routine acts as the class installer for Mouse devices. In general,
  1136. the default behavior is all that is required for mice. The exceptions are:
  1137. 1. For DIF_INSTALLDEVICE, we first check to see if this driver also controls
  1138. other devices that we should warn the user about (e.g., PS/2 mouse driver
  1139. also controls i8042 port). Unless the user cancels out at that point, we
  1140. then do the default behavior of calling SetupDiInstallDevice. Next, we
  1141. delete the FriendlyName property, then move the GroupOrderList tag to the
  1142. front of the list, to ensure that the driver controlling this device loads
  1143. before any other drivers in this load order group.
  1144. 2. For DIF_ALLOW_INSTALL, we make sure that the driver node selected by the
  1145. user has a service install section. If not, then we assume it's a
  1146. Win95-only INF, and return ERROR_NON_WINDOWS_NT_DRIVER.
  1147. Arguments:
  1148. InstallFunction - Specifies the device installer function code indicating
  1149. the action being performed.
  1150. DeviceInfoSet - Supplies a handle to the device information set being
  1151. acted upon by this install action.
  1152. DeviceInfoData - Optionally, supplies the address of a device information
  1153. element being acted upon by this install action.
  1154. Return Value:
  1155. If this function successfully completed the requested action, the return
  1156. value is NO_ERROR.
  1157. If the default behavior is to be performed for the requested action, the
  1158. return value is ERROR_DI_DO_DEFAULT.
  1159. If an error occurred while attempting to perform the requested action, a
  1160. Win32 error code is returned.
  1161. --*/
  1162. {
  1163. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  1164. DWORD Err;
  1165. TCHAR DeviceDescription[LINE_LEN];
  1166. DWORD DeviceDescriptionLen;
  1167. TCHAR NewServiceName[MAX_SERVICE_NAME_LEN], OldServiceName[MAX_SERVICE_NAME_LEN];
  1168. BOOL IsKbdDriver, IsOnlyKbdDriver;
  1169. ULONG DevsControlled;
  1170. FILTERS filters;
  1171. ULONG DevStatus, DevProblem;
  1172. CONFIGRET Result;
  1173. BOOLEAN bDisableService;
  1174. switch(InstallFunction) {
  1175. case DIF_SELECTBESTCOMPATDRV:
  1176. //
  1177. // First, retrieve the device install parameters to see whether or not this is a
  1178. // silent install. If so, then we don't prompt the user during DIF_ALLOW_INSTALL.
  1179. //
  1180. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  1181. DeviceInstallParams.ClassInstallReserved = (ULONG_PTR)NULL;
  1182. if(SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams)) {
  1183. DeviceInstallParams.ClassInstallReserved = (ULONG_PTR)DeviceInstallParams.Flags;
  1184. SetupDiSetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams);
  1185. }
  1186. return ConfirmWHQLInputRequirements(DeviceInfoSet,
  1187. DeviceInfoData,
  1188. szNativeMouseServices,
  1189. szNativeMouseInf,
  1190. InstallFunction);
  1191. case DIF_ALLOW_INSTALL :
  1192. //
  1193. // Check to make sure the selected driver node supports NT.
  1194. //
  1195. Err = ConfirmWHQLInputRequirements(DeviceInfoSet,
  1196. DeviceInfoData,
  1197. szNativeMouseServices,
  1198. szNativeMouseInf,
  1199. InstallFunction);
  1200. if (Err == ERROR_DI_DO_DEFAULT || Err == ERROR_SUCCESS) {
  1201. if (DriverNodeSupportsNT(DeviceInfoSet, DeviceInfoData)) {
  1202. Err = NO_ERROR;
  1203. if (UserBalksAtSharedDrvMsg(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams)) {
  1204. Err = ERROR_DI_DONT_INSTALL;
  1205. }
  1206. }
  1207. else {
  1208. Err = ERROR_NON_WINDOWS_NT_DRIVER;
  1209. }
  1210. }
  1211. return Err;
  1212. case DIF_INSTALLDEVICE :
  1213. //
  1214. // Retrieve and cache the name of the service that's controlling this device.
  1215. //
  1216. if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1217. DeviceInfoData,
  1218. SPDRP_SERVICE,
  1219. NULL,
  1220. (PBYTE)OldServiceName,
  1221. sizeof(OldServiceName),
  1222. NULL)) {
  1223. //
  1224. // We could not determine the old service - assume it is a null driver
  1225. //
  1226. OldServiceName[0] = (TCHAR) 0;
  1227. }
  1228. //
  1229. // Retrieve the status of this device instance.
  1230. //
  1231. Result = CM_Get_DevNode_Status(&DevStatus,
  1232. &DevProblem,
  1233. DeviceInfoData->DevInst,
  1234. 0);
  1235. if ((Result == CR_SUCCESS) &&
  1236. (DevStatus & DN_HAS_PROBLEM) &&
  1237. (DevProblem == CM_PROB_DISABLED_SERVICE)) {
  1238. InputClassLogError(LogSevInformation, TEXT("Mouse service is disabled, so will be disabling."));
  1239. bDisableService = TRUE;
  1240. }
  1241. else {
  1242. bDisableService = FALSE;
  1243. }
  1244. //
  1245. // Before we do anything, migrate the values from the services key
  1246. // up to the devnode
  1247. //
  1248. MigrateToDevnode(DeviceInfoSet, DeviceInfoData);
  1249. GetDeviceFilters(DeviceInfoSet, DeviceInfoData, &filters);
  1250. //
  1251. // We first want to perform the default behavior of calling
  1252. // SetupDiInstallDevice.
  1253. //
  1254. if(SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData)) {
  1255. //
  1256. // Retrieve the name of the service which will now control the device
  1257. //
  1258. if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1259. DeviceInfoData,
  1260. SPDRP_SERVICE,
  1261. NULL,
  1262. (PBYTE)NewServiceName,
  1263. sizeof(NewServiceName),
  1264. NULL)) {
  1265. InputClassLogError(LogSevInformation, TEXT("Couldn't get service name."));
  1266. //
  1267. // We must have the name of this service - fail if we can't find it
  1268. //
  1269. return GetLastError();
  1270. }
  1271. FixUpPS2Mouse(DeviceInfoSet, DeviceInfoData, NewServiceName);
  1272. //
  1273. // Only consider disabling the service if it has changed and we know the old service name
  1274. //
  1275. if (lstrcmpi(OldServiceName, NewServiceName) && OldServiceName[0] != (TCHAR)0) {
  1276. if ((Err = IsKeyboardDriver(OldServiceName, &IsKbdDriver)) != NO_ERROR) {
  1277. InputClassLogError(LogSevInformation, TEXT("Couldn't tell if keyboard or not."));
  1278. RestoreDeviceFilters(DeviceInfoSet, DeviceInfoData, &filters);
  1279. return Err;
  1280. }
  1281. if ((DevsControlled = CountDevicesControlled(OldServiceName)) != -1) {
  1282. // Disable the old driver service if:
  1283. // - it controls a keyboard, and a total of <= 2 devices (ie kbd & mouse) and it is not the
  1284. // only keyboard driver
  1285. // - it is just a mouse driver controling one device (it the mouse) and
  1286. // doesn't dynamically load
  1287. if (IsKbdDriver) {
  1288. InputClassLogError(LogSevInformation, TEXT("This is a keyboard driver."));
  1289. if((Err = IsOnlyKeyboardDriver(OldServiceName,&IsOnlyKbdDriver)) != NO_ERROR) {
  1290. InputClassLogError(LogSevInformation, TEXT("Couldn't tell if this is only keyboard."));
  1291. RestoreDeviceFilters(DeviceInfoSet, DeviceInfoData, &filters);
  1292. return Err;
  1293. }
  1294. if (DevsControlled <= 2 && !IsOnlyKbdDriver) {
  1295. InputClassLogError(LogSevInformation, TEXT("Not the only keyboard. Disabling."));
  1296. DisableService(OldServiceName);
  1297. }
  1298. } else {
  1299. if(DevsControlled == 1 &&
  1300. GetServiceStartType(OldServiceName) != SERVICE_DEMAND_START) {
  1301. InputClassLogError(LogSevInformation, TEXT("Only controls one mouse device and not demand start."));
  1302. DisableService(OldServiceName);
  1303. }
  1304. }
  1305. }
  1306. //
  1307. // If the driver service has changed we need to move the tag for this driver to the front
  1308. // of its group order list.
  1309. //
  1310. DrvTagToFrontOfGroupOrderList(DeviceInfoSet, DeviceInfoData);
  1311. }
  1312. Err = NO_ERROR;
  1313. //
  1314. // We may have previously had an 'unknown' driver controlling
  1315. // this device, with a FriendlyName generated by the user-mode
  1316. // PnP Manager. Delete this FriendlyName, since it's no longer
  1317. // applicable (the DeviceDescription will be used from now on
  1318. // in referring to this device).
  1319. //
  1320. SetupDiSetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_FRIENDLYNAME, NULL, 0);
  1321. //
  1322. // Only disable the PS2 driver, all the other OEM driver replacements
  1323. // will not work becuase of PNP. This is especially true for
  1324. // serial mice.
  1325. //
  1326. if (bDisableService &&
  1327. lstrcmpi(NewServiceName, szPS2Driver) == 0) {
  1328. InputClassLogError(LogSevInformation, TEXT("Disabling mouse."));
  1329. Err = DisableService(NewServiceName);
  1330. }
  1331. FreeDeviceFilters(&filters);
  1332. return NO_ERROR;
  1333. } else {
  1334. Err = GetLastError();
  1335. InputClassLogError(LogSevInformation, TEXT("SetupDiInstallDevice failed with status %x."), Err);
  1336. if(Err != ERROR_CANCELLED) {
  1337. //
  1338. // If the error was for anything other than a user cancel, then bail now.
  1339. //
  1340. return Err;
  1341. }
  1342. //
  1343. // Is there a driver installed for this device? If so, then the user started to
  1344. // change the driver, then changed their mind. We don't want to do anything special
  1345. // in this case.
  1346. //
  1347. if(SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1348. DeviceInfoData,
  1349. SPDRP_SERVICE,
  1350. NULL,
  1351. (PBYTE)DeviceDescription,
  1352. sizeof(DeviceDescription),
  1353. NULL))
  1354. {
  1355. return ERROR_CANCELLED;
  1356. }
  1357. //
  1358. // The user cancelled out of the installation. There are two scenarios where
  1359. // this could happen:
  1360. //
  1361. // 1. There really was a mouse to be installed, but the user changed their
  1362. // mind, didn't have the source media, etc.
  1363. // 2. There wasn't really a mouse. This happens with certain modems that
  1364. // fool ntdetect into thinking that they're really mice. The poor user
  1365. // doesn't get a chance to nip this in the bud earlier, because umpnpmgr
  1366. // generates an ID that yields a rank-0 match.
  1367. //
  1368. // Scenario (2) is particularly annoying, because the user will get the popup
  1369. // again and again, until they finally agree to install the sermouse driver (even
  1370. // though they don't have a serial mouse).
  1371. //
  1372. // To work around this problem, we special case the user-cancel scenario by going
  1373. // ahead and installing the NULL driver for this device. This will keep the user
  1374. // from getting any more popups. However, it doesn't mess up the user who cancelled
  1375. // because of scenario (1). That's because this device is still of class "Mouse",
  1376. // and thus will show up in the mouse cpl. We write out a friendly name for it that
  1377. // has the text " (no driver)" at the end, to indicate that this device currently has
  1378. // the NULL driver installed. That way, if the user really experienced scenario (1),
  1379. // they can later go to the Mouse cpl, select the no-driver device, and click the
  1380. // "Change" button to install the correct driver for it.
  1381. //
  1382. if (SetupDiSetSelectedDriver(DeviceInfoSet, DeviceInfoData, NULL)) {
  1383. SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData);
  1384. }
  1385. if(SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1386. DeviceInfoData,
  1387. SPDRP_DEVICEDESC,
  1388. NULL,
  1389. (PBYTE)DeviceDescription,
  1390. sizeof(DeviceDescription),
  1391. &DeviceDescriptionLen))
  1392. {
  1393. //
  1394. // Need length in characters, not bytes.
  1395. //
  1396. DeviceDescriptionLen /= sizeof(TCHAR);
  1397. //
  1398. // Don't count trailing NULL.
  1399. //
  1400. DeviceDescriptionLen--;
  1401. } else {
  1402. //
  1403. // We couldn't get the device description--fall back to our default description.
  1404. //
  1405. DeviceDescriptionLen = LoadString(MyModuleHandle,
  1406. IDS_DEVNAME_UNK,
  1407. DeviceDescription,
  1408. SIZECHARS(DeviceDescription)
  1409. );
  1410. }
  1411. //
  1412. // Now, append our " (no driver)" text.
  1413. //
  1414. LoadString(MyModuleHandle,
  1415. IDS_NODRIVER,
  1416. &(DeviceDescription[DeviceDescriptionLen]),
  1417. SIZECHARS(DeviceDescription) - DeviceDescriptionLen
  1418. );
  1419. //
  1420. // And, finally, set the friendly name for this device to be the description we
  1421. // just generated.
  1422. //
  1423. SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
  1424. DeviceInfoData,
  1425. SPDRP_FRIENDLYNAME,
  1426. (PBYTE)DeviceDescription,
  1427. (lstrlen(DeviceDescription) + 1) * sizeof(TCHAR)
  1428. );
  1429. RestoreDeviceFilters(DeviceInfoSet, DeviceInfoData, &filters);
  1430. return ERROR_CANCELLED;
  1431. }
  1432. case DIF_ADDPROPERTYPAGE_ADVANCED:
  1433. if (DeviceInfoData) {
  1434. //
  1435. // Retrieve the status of this device instance.
  1436. //
  1437. Result = CM_Get_DevNode_Status(&DevStatus,
  1438. &DevProblem,
  1439. DeviceInfoData->DevInst,
  1440. 0);
  1441. if ((Result == CR_SUCCESS) &&
  1442. (DevStatus & DN_HAS_PROBLEM) &&
  1443. (DevProblem == CM_PROB_DISABLED_SERVICE)) {
  1444. //
  1445. // If the controlling service has been disabled, this device
  1446. // is most likely under the control of a legacy driver. We
  1447. // should not let device manager display the standard
  1448. // driver, resource, or power property pages by claiming to
  1449. // have added them here.
  1450. //
  1451. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  1452. if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
  1453. DeviceInfoData,
  1454. &DeviceInstallParams)) {
  1455. DeviceInstallParams.Flags |= (DI_DRIVERPAGE_ADDED | DI_RESOURCEPAGE_ADDED);
  1456. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_POWERPAGE_ADDED;
  1457. SetupDiSetDeviceInstallParams(DeviceInfoSet,
  1458. DeviceInfoData,
  1459. &DeviceInstallParams);
  1460. }
  1461. return NO_ERROR;
  1462. }
  1463. }
  1464. return ERROR_DI_DO_DEFAULT;
  1465. default :
  1466. //
  1467. // Just do the default action.
  1468. //
  1469. return ERROR_DI_DO_DEFAULT;
  1470. }
  1471. }
  1472. typedef struct _VALUE_INFORMATION {
  1473. DWORD dwSize;
  1474. DWORD dwType;
  1475. PVOID pData;
  1476. PTCHAR szName;
  1477. } VALUE_INFORMATION, *PVALUE_INFORMATION;
  1478. BOOL
  1479. KeyboardClassInstallDevice(
  1480. IN HDEVINFO DeviceInfoSet,
  1481. IN PSP_DEVINFO_DATA DeviceInfoData
  1482. )
  1483. {
  1484. PVALUE_INFORMATION values = NULL, currentValue;
  1485. ULONG numValues = 0;
  1486. HKEY hSource = (HKEY) INVALID_HANDLE_VALUE;
  1487. SP_DRVINFO_DETAIL_DATA didd;
  1488. SP_DRVINFO_DATA did;
  1489. HINF hInf = INVALID_HANDLE_VALUE;
  1490. INFCONTEXT infContext;
  1491. DWORD dwSize;
  1492. TCHAR szSectionName[LINE_LEN];
  1493. PTCHAR szService = NULL, szServicePath = NULL,
  1494. szValueNames = NULL, szCurrentName = NULL;
  1495. BOOL success = FALSE;
  1496. TCHAR szRegServices[] = TEXT("System\\CurrentControlSet\\Services\\");
  1497. TCHAR szParameters[] = TEXT("\\Parameters");
  1498. TCHAR szMaintain[] = TEXT(".KeepValues");
  1499. BOOL installedDevice = FALSE;
  1500. FILTERS filters;
  1501. //
  1502. // Only save the values if we are in gui mode setup
  1503. //
  1504. if (!pInGUISetup(DeviceInfoSet, DeviceInfoData)) {
  1505. goto cleanup;
  1506. }
  1507. //
  1508. // Retrieve information about the driver node selected for this device.
  1509. //
  1510. did.cbSize = sizeof(SP_DRVINFO_DATA);
  1511. if(!SetupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData, &did)) {
  1512. InputClassLogError(LogSevInformation, TEXT("SetupDiGetSelectedDriver failed."));
  1513. goto cleanup;
  1514. }
  1515. didd.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  1516. if (!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  1517. DeviceInfoData,
  1518. &did,
  1519. &didd,
  1520. sizeof(didd),
  1521. NULL)
  1522. && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
  1523. InputClassLogError(LogSevInformation, TEXT("Couldn't get driver details."));
  1524. //
  1525. // For some reason we couldn't get detail data--this should never happen.
  1526. //
  1527. goto cleanup;
  1528. }
  1529. //
  1530. // Open the INF that installs this driver node
  1531. //
  1532. hInf = SetupOpenInfFile(didd.InfFileName,
  1533. NULL,
  1534. INF_STYLE_WIN4,
  1535. NULL
  1536. );
  1537. if (hInf == INVALID_HANDLE_VALUE) {
  1538. //
  1539. // For some reason we couldn't open the INF--this should never happen.
  1540. //
  1541. goto cleanup;
  1542. }
  1543. if (!SetupDiGetActualSectionToInstall(hInf,
  1544. didd.SectionName,
  1545. szSectionName,
  1546. sizeof(szSectionName) / sizeof(TCHAR),
  1547. NULL,
  1548. NULL
  1549. ) ||
  1550. FAILED(StringCchCat(szSectionName, SIZECHARS(szSectionName), szMaintain)) ||
  1551. (!SetupFindFirstLine(hInf,
  1552. szSectionName,
  1553. NULL,
  1554. &infContext))) {
  1555. //
  1556. // No such section, just install the device and return
  1557. //
  1558. goto cleanup;
  1559. }
  1560. dwSize = 0;
  1561. if (SetupGetStringField(&infContext, 0, NULL, 0, &dwSize)) {
  1562. //
  1563. // Increment the count to hold the null and alloc. The count returned
  1564. // is the number of characters in the strings, NOT the number of bytes
  1565. // needed.
  1566. //
  1567. dwSize++;
  1568. szService = (PTCHAR) LocalAlloc(LPTR, dwSize * sizeof(TCHAR));
  1569. if (!szService ||
  1570. !SetupGetStringField(&infContext, 0, szService, dwSize, &dwSize)) {
  1571. goto cleanup;
  1572. }
  1573. }
  1574. else {
  1575. goto cleanup;
  1576. }
  1577. dwSize = wcslen(szRegServices)+wcslen(szService)+wcslen(szParameters)+1;
  1578. dwSize *= sizeof(TCHAR);
  1579. szServicePath = (PTCHAR) LocalAlloc(LPTR, dwSize);
  1580. if (!szServicePath) {
  1581. goto cleanup;
  1582. }
  1583. if (FAILED(StringCbCopy(szServicePath, dwSize, szRegServices)) ||
  1584. FAILED(StringCbCat(szServicePath, dwSize, szService)) ||
  1585. FAILED(StringCbCat(szServicePath, dwSize, szParameters)) ||
  1586. (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1587. szServicePath,
  1588. 0,
  1589. KEY_ALL_ACCESS,
  1590. &hSource) != ERROR_SUCCESS)) {
  1591. goto cleanup;
  1592. }
  1593. dwSize = 0;
  1594. if (SetupGetMultiSzField(&infContext, 1, NULL, 0, &dwSize)) {
  1595. //
  1596. // Increment the count to hold the null and alloc. The count returned
  1597. // is the number of characters in the strings, NOT the number of bytes
  1598. // needed.
  1599. //
  1600. dwSize++;
  1601. szValueNames = (PTCHAR) LocalAlloc(LPTR, dwSize * sizeof(TCHAR));
  1602. if (!szValueNames ||
  1603. !SetupGetMultiSzField(&infContext, 1, szValueNames, dwSize, &dwSize)) {
  1604. goto cleanup;
  1605. }
  1606. }
  1607. else {
  1608. goto cleanup;
  1609. }
  1610. numValues = SetupGetFieldCount(&infContext);
  1611. values = (PVALUE_INFORMATION)
  1612. LocalAlloc(LPTR, (numValues + 1) * sizeof(VALUE_INFORMATION));
  1613. if (!values) {
  1614. goto cleanup;
  1615. }
  1616. currentValue = values;
  1617. for (szCurrentName = szValueNames;
  1618. *szCurrentName;
  1619. szCurrentName += wcslen(szCurrentName) + 1) {
  1620. if (RegQueryValueEx(hSource,
  1621. szCurrentName,
  1622. 0,
  1623. &currentValue->dwType,
  1624. (PBYTE) NULL,
  1625. &currentValue->dwSize) == ERROR_SUCCESS) {
  1626. currentValue->szName = szCurrentName;
  1627. currentValue->pData = LocalAlloc(LPTR, currentValue->dwSize);
  1628. if (!currentValue->pData) {
  1629. ZeroMemory(currentValue, sizeof(VALUE_INFORMATION));
  1630. continue;
  1631. }
  1632. if (RegQueryValueEx(hSource,
  1633. currentValue->szName,
  1634. 0,
  1635. &currentValue->dwType,
  1636. (PBYTE) currentValue->pData,
  1637. &currentValue->dwSize) == ERROR_SUCCESS) {
  1638. currentValue++;
  1639. }
  1640. else {
  1641. ZeroMemory(currentValue, sizeof(VALUE_INFORMATION));
  1642. }
  1643. }
  1644. }
  1645. GetDeviceFilters(DeviceInfoSet, DeviceInfoData, &filters);
  1646. installedDevice = TRUE;
  1647. success = SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData);
  1648. for (currentValue = values; ; currentValue++) {
  1649. if (currentValue->pData) {
  1650. if (success) {
  1651. RegSetValueEx(hSource,
  1652. currentValue->szName,
  1653. 0,
  1654. currentValue->dwType,
  1655. (PBYTE) currentValue->pData,
  1656. currentValue->dwSize);
  1657. }
  1658. LocalFree(currentValue->pData);
  1659. }
  1660. else {
  1661. //
  1662. // if currentValue->pData is blank, no other entries exist
  1663. //
  1664. break;
  1665. }
  1666. }
  1667. LocalFree(values);
  1668. cleanup:
  1669. //
  1670. // Clean up and leave
  1671. //
  1672. if (hInf != (HKEY) INVALID_HANDLE_VALUE) {
  1673. SetupCloseInfFile(hInf);
  1674. }
  1675. if (hSource != (HKEY) INVALID_HANDLE_VALUE) {
  1676. RegCloseKey(hSource);
  1677. }
  1678. if (szService) {
  1679. LocalFree(szService);
  1680. }
  1681. if (szServicePath) {
  1682. LocalFree(szServicePath);
  1683. }
  1684. if (szValueNames) {
  1685. LocalFree(szValueNames);
  1686. }
  1687. if (!installedDevice) {
  1688. GetDeviceFilters(DeviceInfoSet, DeviceInfoData, &filters);
  1689. success = SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData);
  1690. }
  1691. if (success) {
  1692. FreeDeviceFilters(&filters);
  1693. }
  1694. else {
  1695. RestoreDeviceFilters(DeviceInfoSet, DeviceInfoData, &filters);
  1696. }
  1697. return success;
  1698. }
  1699. TCHAR szKbdclassParameters[] = TEXT("System\\CurrentControlSet\\Services\\Kbdclass\\Parameters");
  1700. TCHAR szNativeKeyboardInf[] = TEXT("keyboard.inf");
  1701. TCHAR szNativeKeyboardServices[] =
  1702. TEXT("KBDCLASS\0")
  1703. TEXT("I8042PRT\0")
  1704. TEXT("KBDHID\0")
  1705. TEXT("\0");
  1706. DWORD
  1707. KeyboardClassInstaller(
  1708. IN DI_FUNCTION InstallFunction,
  1709. IN HDEVINFO DeviceInfoSet,
  1710. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  1711. )
  1712. /*++
  1713. Routine Description:
  1714. This routine acts as the class installer for Keyboard devices. In general,
  1715. the default behavior is all that is required for keyboards. The exceptions are:
  1716. 1. For DIF_INSTALLDEVICE, we first check to see if this driver also controls
  1717. other devices that we should warn the user about (e.g., i8042 keyboard driver
  1718. also controls PS/2 mouse port). Unless the user cancels out at that point, we
  1719. then do the default behavior of calling SetupDiInstallDevice. Next, we
  1720. delete the FriendlyName property, then move the GroupOrderList tag to the
  1721. front of the list, to ensure that the driver controlling this device loads
  1722. before any other drivers in this load order group.
  1723. 2. For DIF_ALLOW_INSTALL, we make sure that the driver node selected by the
  1724. user has a service install section. If not, then we assume it's a
  1725. Win95-only INF, and return ERROR_NON_WINDOWS_NT_DRIVER.
  1726. Arguments:
  1727. InstallFunction - Specifies the device installer function code indicating
  1728. the action being performed.
  1729. DeviceInfoSet - Supplies a handle to the device information set being
  1730. acted upon by this install action.
  1731. DeviceInfoData - Optionally, supplies the address of a device information
  1732. element being acted upon by this install action.
  1733. Return Value:
  1734. If this function successfully completed the requested action, the return
  1735. value is NO_ERROR.
  1736. If the default behavior is to be performed for the requested action, the
  1737. return value is ERROR_DI_DO_DEFAULT.
  1738. If an error occurred while attempting to perform the requested action, a
  1739. Win32 error code is returned.
  1740. --*/
  1741. {
  1742. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  1743. TCHAR OldServiceName[MAX_SERVICE_NAME_LEN], NewServiceName[MAX_SERVICE_NAME_LEN];
  1744. DWORD Err;
  1745. ULONG DevStatus, DevProblem;
  1746. CONFIGRET Result;
  1747. BOOLEAN bDisableService;
  1748. switch(InstallFunction) {
  1749. case DIF_SELECTBESTCOMPATDRV:
  1750. //
  1751. // First, retrieve the device install parameters to see whether or not this is a
  1752. // silent install. If so, then we don't prompt the user during DIF_ALLOW_INSTALL.
  1753. //
  1754. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  1755. DeviceInstallParams.ClassInstallReserved = (ULONG_PTR)NULL;
  1756. if(SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams)) {
  1757. DeviceInstallParams.ClassInstallReserved = (ULONG_PTR)DeviceInstallParams.Flags;
  1758. SetupDiSetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams);
  1759. }
  1760. return ConfirmWHQLInputRequirements(DeviceInfoSet,
  1761. DeviceInfoData,
  1762. szNativeKeyboardServices,
  1763. szNativeKeyboardInf,
  1764. InstallFunction);
  1765. case DIF_ALLOW_INSTALL :
  1766. //
  1767. // Check to make sure the selected driver node supports NT.
  1768. //
  1769. Err = ConfirmWHQLInputRequirements(DeviceInfoSet,
  1770. DeviceInfoData,
  1771. szNativeKeyboardServices,
  1772. szNativeKeyboardInf,
  1773. InstallFunction);
  1774. if (Err == ERROR_DI_DO_DEFAULT || Err == ERROR_SUCCESS) {
  1775. if (DriverNodeSupportsNT(DeviceInfoSet, DeviceInfoData)) {
  1776. Err = NO_ERROR;
  1777. if (UserBalksAtSharedDrvMsg(DeviceInfoSet, DeviceInfoData, &DeviceInstallParams)) {
  1778. Err = ERROR_DI_DONT_INSTALL;
  1779. }
  1780. }
  1781. else {
  1782. Err = ERROR_NON_WINDOWS_NT_DRIVER;
  1783. }
  1784. }
  1785. return Err;
  1786. case DIF_INSTALLDEVICE :
  1787. //
  1788. // Retrieve and cache the name of the service that's controlling this device.
  1789. //
  1790. if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1791. DeviceInfoData,
  1792. SPDRP_SERVICE,
  1793. NULL,
  1794. (PBYTE)OldServiceName,
  1795. sizeof(OldServiceName),
  1796. NULL)) {
  1797. //
  1798. // We could not determine the old service - assume it is a null driver
  1799. //
  1800. OldServiceName[0] = (TCHAR) 0;
  1801. }
  1802. //
  1803. // Before we do anything, migrate the values from the services key
  1804. // up to the devnode
  1805. //
  1806. MigrateToDevnode(DeviceInfoSet, DeviceInfoData);
  1807. //
  1808. // Retrieve the status of this device instance.
  1809. //
  1810. Result = CM_Get_DevNode_Status(&DevStatus,
  1811. &DevProblem,
  1812. DeviceInfoData->DevInst,
  1813. 0);
  1814. if ((Result == CR_SUCCESS) &&
  1815. (DevStatus & DN_HAS_PROBLEM) &&
  1816. (DevProblem == CM_PROB_DISABLED_SERVICE)) {
  1817. InputClassLogError(LogSevInformation, TEXT("Keyboard is disabled, so will disable."));
  1818. bDisableService = TRUE;
  1819. }
  1820. else {
  1821. bDisableService = FALSE;
  1822. }
  1823. //
  1824. // Perform the default behavior of calling SetupDiInstallDevice.
  1825. //
  1826. if(KeyboardClassInstallDevice(DeviceInfoSet, DeviceInfoData)) {
  1827. //
  1828. // Retrieve the name of the service which will now control the device
  1829. //
  1830. if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1831. DeviceInfoData,
  1832. SPDRP_SERVICE,
  1833. NULL,
  1834. (PBYTE)NewServiceName,
  1835. sizeof(NewServiceName),
  1836. NULL)) {
  1837. return GetLastError();
  1838. }
  1839. //
  1840. // Only consider disabling the service if it has changed and we know the old service name
  1841. //
  1842. if(lstrcmpi(OldServiceName, NewServiceName) && OldServiceName[0] != (TCHAR)0) {
  1843. //
  1844. // Disable the old service that was controlling the device
  1845. //
  1846. InputClassLogError(LogSevInformation, TEXT("Disabling old service to start new one."));
  1847. if((Err = DisableService(OldServiceName)) != NO_ERROR) {
  1848. return Err;
  1849. }
  1850. //
  1851. // If the driver service has changed we need to move the tag for this driver to the front
  1852. // of its group order list.
  1853. //
  1854. DrvTagToFrontOfGroupOrderList(DeviceInfoSet, DeviceInfoData);
  1855. }
  1856. Err = NO_ERROR;
  1857. //
  1858. // We may have previously had an 'unknown' driver controlling
  1859. // this device, with a FriendlyName generated by the user-mode
  1860. // PnP Manager. Delete this FriendlyName, since it's no longer
  1861. // applicable (the DeviceDescription will be used from now on
  1862. // in referring to this device).
  1863. //
  1864. SetupDiSetDeviceRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_FRIENDLYNAME, NULL, 0);
  1865. if (bDisableService &&
  1866. lstrcmpi(NewServiceName, szPS2Driver) == 0) {
  1867. InputClassLogError(LogSevInformation, TEXT("Disabling PS2 keyboard."));
  1868. Err = DisableService(NewServiceName);
  1869. }
  1870. return Err;
  1871. } else {
  1872. InputClassLogError(LogSevInformation, TEXT("KeyboardClassInstallDevice failed."));
  1873. return GetLastError();
  1874. }
  1875. case DIF_ADDPROPERTYPAGE_ADVANCED:
  1876. if (DeviceInfoData) {
  1877. //
  1878. // Retrieve the status of this device instance.
  1879. //
  1880. Result = CM_Get_DevNode_Status(&DevStatus,
  1881. &DevProblem,
  1882. DeviceInfoData->DevInst,
  1883. 0);
  1884. if ((Result == CR_SUCCESS) &&
  1885. (DevStatus & DN_HAS_PROBLEM) &&
  1886. (DevProblem == CM_PROB_DISABLED_SERVICE)) {
  1887. //
  1888. // If the controlling service has been disabled, this device
  1889. // is most likely under the control of a legacy driver. We
  1890. // should not let device manager display the standard
  1891. // driver, resource, or power property pages by claiming to
  1892. // have added them here.
  1893. //
  1894. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  1895. if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
  1896. DeviceInfoData,
  1897. &DeviceInstallParams)) {
  1898. DeviceInstallParams.Flags |= (DI_DRIVERPAGE_ADDED | DI_RESOURCEPAGE_ADDED);
  1899. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_POWERPAGE_ADDED;
  1900. SetupDiSetDeviceInstallParams(DeviceInfoSet,
  1901. DeviceInfoData,
  1902. &DeviceInstallParams);
  1903. }
  1904. return NO_ERROR;
  1905. }
  1906. }
  1907. return ERROR_DI_DO_DEFAULT;
  1908. default :
  1909. //
  1910. // Just do the default action.
  1911. //
  1912. return ERROR_DI_DO_DEFAULT;
  1913. }
  1914. }
  1915. DWORD
  1916. DrvTagToFrontOfGroupOrderList(
  1917. IN HDEVINFO DeviceInfoSet,
  1918. IN PSP_DEVINFO_DATA DeviceInfoData
  1919. )
  1920. /*++
  1921. Routine Description:
  1922. This routine moves the tag value for the specified device's driver to the
  1923. front of its corresponding GroupOrderList entry.
  1924. ********** We don't do the following any more *************************
  1925. It also marks the device's service with a PlugPlayServiceType value of
  1926. 0x2 (PlugPlayServicePeripheral), so that we won't attempt to generate a
  1927. legacy device instance for this service in the future.
  1928. ***********************************************************************
  1929. Arguments:
  1930. DeviceInfoSet - Supplies a handle to the device information set containing
  1931. the device whose driver is being modified.
  1932. DeviceInfoData - Supplies the address of a device information element whose
  1933. driver is being modified.
  1934. Return Value:
  1935. If the function is successful, the return value is NO_ERROR.
  1936. If the function fails, the return value is a Win32 error code.
  1937. --*/
  1938. {
  1939. TCHAR ServiceName[MAX_SERVICE_NAME_LEN];
  1940. SC_HANDLE SCMHandle = NULL, ServiceHandle = NULL;
  1941. DWORD Err;
  1942. LPQUERY_SERVICE_CONFIG ServiceConfig;
  1943. //
  1944. // Retrieve the name of the service that's controlling this device.
  1945. //
  1946. if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  1947. DeviceInfoData,
  1948. SPDRP_SERVICE,
  1949. NULL,
  1950. (PBYTE)ServiceName,
  1951. sizeof(ServiceName),
  1952. NULL)) {
  1953. return GetLastError();
  1954. }
  1955. //
  1956. // Now open this service, and call some private Setup API helper routines to
  1957. // retrieve the tag, and move it to the front of the GroupOrderList.
  1958. //
  1959. if(!(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  1960. return GetLastError();
  1961. }
  1962. if(!(ServiceHandle = OpenService(SCMHandle, ServiceName, SERVICE_ALL_ACCESS))) {
  1963. Err = GetLastError();
  1964. goto clean0;
  1965. }
  1966. if((Err = pSetupRetrieveServiceConfig(ServiceHandle, &ServiceConfig)) != NO_ERROR) {
  1967. goto clean0;
  1968. }
  1969. //
  1970. // Only do this if this is a kernel or filesystem driver, and it's a member of
  1971. // a load group (with a tag assigned). This should always be the case for keyboard
  1972. // and mouse drivers, but this is just to be safe.
  1973. //
  1974. if(ServiceConfig->lpLoadOrderGroup && *(ServiceConfig->lpLoadOrderGroup) &&
  1975. (ServiceConfig->dwServiceType & (SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER))) {
  1976. //
  1977. // This driver meets all the criteria--it better have a tag!!!
  1978. //
  1979. MYASSERT(ServiceConfig->dwTagId);
  1980. //
  1981. // Move the tag to the front of the list.
  1982. //
  1983. Err = pSetupAddTagToGroupOrderListEntry(ServiceConfig->lpLoadOrderGroup,
  1984. ServiceConfig->dwTagId,
  1985. TRUE
  1986. );
  1987. }
  1988. MyFree(ServiceConfig);
  1989. clean0:
  1990. if (ServiceHandle) {
  1991. CloseServiceHandle(ServiceHandle);
  1992. }
  1993. if (SCMHandle) {
  1994. CloseServiceHandle(SCMHandle);
  1995. }
  1996. return Err;
  1997. }
  1998. BOOL
  1999. UserBalksAtSharedDrvMsg(
  2000. IN HDEVINFO DeviceInfoSet,
  2001. IN PSP_DEVINFO_DATA DeviceInfoData,
  2002. IN PSP_DEVINSTALL_PARAMS DeviceInstallParams
  2003. )
  2004. /*++
  2005. Routine Description:
  2006. This routine finds out if there are any other devices affected by the impending
  2007. device installation, and if so, warns the user about it (unless this is a quiet
  2008. installation).
  2009. Arguments:
  2010. DeviceInfoSet - Supplies a handle to the device information set containing
  2011. the device whose driver is being modified.
  2012. DeviceInfoData - Supplies the address of a device information element whose
  2013. driver is being modified.
  2014. DeviceInstallParams - Supplies the address of a device install parameters structure
  2015. to be used in this routine. Since callers of this routine always have this
  2016. structure 'laying around', they provide it to this routine to be used as a
  2017. workspace.
  2018. Return Value:
  2019. If the user decides not to go through with it, the return value is TRUE, otherwise
  2020. it is FALSE.
  2021. --*/
  2022. {
  2023. SP_DRVINFO_DATA DriverInfoData;
  2024. SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
  2025. HINF hInf;
  2026. BOOL b, result;
  2027. INFCONTEXT InfContext;
  2028. PCTSTR SectionName, AffectedComponentsString;
  2029. //
  2030. // First, retrieve the device install parameters to see whether or not this is a
  2031. // silent install. If so, then we don't prompt the user. We saved away these
  2032. // params during DIF_SELECTBESTCOMPATDRV, so check this first.
  2033. //
  2034. DeviceInstallParams->cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  2035. if(SetupDiGetDeviceInstallParams(DeviceInfoSet, DeviceInfoData, DeviceInstallParams)) {
  2036. if((DeviceInstallParams->Flags & DI_QUIETINSTALL) ||
  2037. (DeviceInstallParams->ClassInstallReserved & DI_QUIETINSTALL)) {
  2038. InputClassLogError(LogSevInformation, TEXT("Quiet install requested."));
  2039. return FALSE;
  2040. }
  2041. } else {
  2042. //
  2043. // Couldn't retrieve the device install params--initialize the parent window handle
  2044. // to NULL, in case we need it later for the user prompt dialog.
  2045. //
  2046. DeviceInstallParams->hwndParent = NULL;
  2047. }
  2048. //
  2049. // Retrieve the currently-selected driver we're about to install.
  2050. //
  2051. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  2052. if(!SetupDiGetSelectedDriver(DeviceInfoSet,
  2053. DeviceInfoData,
  2054. &DriverInfoData)) {
  2055. return FALSE;
  2056. }
  2057. //
  2058. // Retrieve information about the INF install section for the selected driver.
  2059. //
  2060. DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  2061. if(!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  2062. DeviceInfoData,
  2063. &DriverInfoData,
  2064. &DriverInfoDetailData,
  2065. sizeof(DriverInfoDetailData),
  2066. NULL)
  2067. && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
  2068. {
  2069. //
  2070. // Then we failed, and it wasn't simply because we didn't provide the extra
  2071. // space for hardware/compatible IDs.
  2072. //
  2073. return FALSE;
  2074. }
  2075. //
  2076. // Open the associated INF file.
  2077. //
  2078. if((hInf = SetupOpenInfFile(DriverInfoDetailData.InfFileName,
  2079. NULL,
  2080. INF_STYLE_WIN4,
  2081. NULL)) == INVALID_HANDLE_VALUE) {
  2082. return FALSE;
  2083. }
  2084. //
  2085. // Now look through the [ControlFlags] section at all 'SharedDriver' entries, to
  2086. // see if any of them reference an install section that matches what we're about
  2087. // to install.
  2088. //
  2089. for(b = SetupFindFirstLine(hInf, INFSTR_CONTROLFLAGS_SECTION, TEXT("SharedDriver"), &InfContext);
  2090. b;
  2091. b = SetupFindNextMatchLine(&InfContext, TEXT("SharedDriver"), &InfContext))
  2092. {
  2093. //
  2094. // The format of the line is SharedDriver=<InstallSection>,<AffectedComponentsString>
  2095. //
  2096. if((SectionName = pSetupGetField(&InfContext, 1)) &&
  2097. !lstrcmpi(SectionName, DriverInfoDetailData.SectionName)) {
  2098. //
  2099. // We found a match--now retrieve the string describing the other component(s) that
  2100. // are affected by this installation.
  2101. //
  2102. if(AffectedComponentsString = pSetupGetField(&InfContext, 2)) {
  2103. break;
  2104. }
  2105. }
  2106. }
  2107. if(!b) {
  2108. //
  2109. // Then we never found a match.
  2110. //
  2111. result = FALSE;
  2112. }
  2113. else {
  2114. //
  2115. // We need to popup a message box to the user--retrieve the parent window handle for this
  2116. // device information element.
  2117. //
  2118. result = (IDNO == MessageBoxFromMessage(DeviceInstallParams->hwndParent,
  2119. MSG_CONFIRM_SHAREDDRV_INSTALL,
  2120. NULL,
  2121. IDS_CONFIRM_DEVINSTALL,
  2122. MB_ICONWARNING | MB_YESNO,
  2123. AffectedComponentsString));
  2124. }
  2125. SetupCloseInfFile(hInf);
  2126. return result;
  2127. }
  2128. VOID
  2129. CopyFixedUpDeviceId(
  2130. OUT LPWSTR DestinationString,
  2131. IN LPCWSTR SourceString,
  2132. IN DWORD SourceStringLen
  2133. )
  2134. /*++
  2135. Routine Description:
  2136. This routine copies a device id, fixing it up as it does the copy.
  2137. 'Fixing up' means that the string is made upper-case, and that the
  2138. following character ranges are turned into underscores (_):
  2139. c <= 0x20 (' ')
  2140. c > 0x7F
  2141. c == 0x2C (',')
  2142. (NOTE: This algorithm is also implemented in the Config Manager APIs,
  2143. and must be kept in sync with that routine. To maintain device identifier
  2144. compatibility, these routines must work the same as Win95.)
  2145. Arguments:
  2146. DestinationString - Supplies a pointer to the destination string buffer
  2147. where the fixed-up device id is to be copied. This buffer must
  2148. be large enough to hold a copy of the source string (including
  2149. terminating NULL).
  2150. SourceString - Supplies a pointer to the (null-terminated) source
  2151. string to be fixed up.
  2152. SourceStringLen - Supplies the length, in characters, of the source
  2153. string (not including terminating NULL).
  2154. Return Value:
  2155. None. If an exception occurs during processing, the DestinationString will
  2156. be empty upon return.
  2157. --*/
  2158. {
  2159. PWCHAR p;
  2160. try {
  2161. CopyMemory(DestinationString,
  2162. SourceString,
  2163. (SourceStringLen + 1) * sizeof(TCHAR)
  2164. );
  2165. CharUpperBuff(DestinationString, SourceStringLen);
  2166. for(p = DestinationString; *p; p++) {
  2167. if((*p <= TEXT(' ')) || (*p > (WCHAR)0x7F) || (*p == TEXT(','))) {
  2168. *p = TEXT('_');
  2169. }
  2170. }
  2171. } except(EXCEPTION_EXECUTE_HANDLER) {
  2172. *DestinationString = TEXT('\0');
  2173. }
  2174. }
  2175. DWORD
  2176. PnPInitializationThread(
  2177. IN PVOID ThreadParam
  2178. )
  2179. /*++
  2180. Routine Description:
  2181. This routine handles the PnP operations that go on asynchronously to the rest of the
  2182. system installation. This thread operates silently, and the only clue the user will
  2183. have that it's running is that their disk will be working (precompiling INFs, etc.),
  2184. while they're interacting with the UI.
  2185. Arguments:
  2186. ThreadParam - ignored.
  2187. Return Value:
  2188. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error code.
  2189. No one cares about this thread's success or failure (yet).
  2190. --*/
  2191. {
  2192. DWORD Err = NO_ERROR;
  2193. HDEVINFO hDevInfo;
  2194. DWORD i;
  2195. SP_DEVINFO_DATA DeviceInfoData;
  2196. SP_DEVINSTALL_PARAMS DevInstallParams;
  2197. UNREFERENCED_PARAMETER(ThreadParam);
  2198. //
  2199. // Retrieve a list of all devices of unknown class. We will process the device information
  2200. // elements in this list to do the migration.
  2201. //
  2202. if((hDevInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVCLASS_LEGACYDRIVER,
  2203. L"Root",
  2204. NULL,
  2205. 0)) != INVALID_HANDLE_VALUE) {
  2206. //
  2207. // First, migrate any display devices. (As a side effect, every device instance that
  2208. // this routine doesn't migrate is returned with its ClassInstallReserved field set to
  2209. // point to the corresponding service's configuration information.)
  2210. //
  2211. MigrateLegacyDisplayDevices(hDevInfo);
  2212. //
  2213. // Enumerate each device information element in the set, freeing any remaining service
  2214. // configs.
  2215. //
  2216. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  2217. DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  2218. for(i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) {
  2219. if(SetupDiGetDeviceInstallParams(hDevInfo, &DeviceInfoData, &DevInstallParams)) {
  2220. //
  2221. // A non-zero ClassInstallReserved field means we have to free the associated
  2222. // service config.
  2223. //
  2224. if(DevInstallParams.ClassInstallReserved) {
  2225. MyFree((PVOID)(DevInstallParams.ClassInstallReserved));
  2226. }
  2227. }
  2228. }
  2229. SetupDiDestroyDeviceInfoList(hDevInfo);
  2230. }
  2231. return Err;
  2232. }
  2233. VOID
  2234. MigrateLegacyDisplayDevices(
  2235. IN HDEVINFO hDevInfo
  2236. )
  2237. /*++
  2238. Routine Description:
  2239. This routine examines each device in the supplied device information set,
  2240. looking for elements controlled by a driver that is a member of the "Video"
  2241. load order group. For any such elements that it finds, it converts the
  2242. element to be of class "Display". If the device is not found to be of
  2243. class "Display", then the service configuration (which we retrieved to make
  2244. the determination), is stored away in the device install params as the
  2245. ClassInstallReserved value. This may be used by the caller for other
  2246. migration purposes, although presently it is not used. After calling this
  2247. routine, it is the caller's responsibility to loop through all devices in
  2248. this hDevInfo set, and free the ClassInstallReserved data (via MyFree) for
  2249. each device that has a non-zero value.
  2250. Arguments:
  2251. hDevInfo - Supplies a handle to the device information set containing all
  2252. devices of class "Unknown".
  2253. Return Value:
  2254. None.
  2255. --*/
  2256. {
  2257. SC_HANDLE SCMHandle, ServiceHandle;
  2258. DWORD i;
  2259. SP_DEVINFO_DATA DevInfoData, DisplayDevInfoData;
  2260. WCHAR ServiceName[MAX_SERVICE_NAME_LEN];
  2261. LPQUERY_SERVICE_CONFIG ServiceConfig;
  2262. HDEVINFO TempDevInfoSet = INVALID_HANDLE_VALUE;
  2263. WCHAR DevInstId[MAX_DEVICE_ID_LEN];
  2264. SP_DEVINSTALL_PARAMS DevInstallParams;
  2265. //
  2266. // First, open a handle to the Service Controller.
  2267. //
  2268. if(!(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  2269. //
  2270. // If this fails, there's nothing we can do.
  2271. //
  2272. return;
  2273. }
  2274. DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  2275. DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  2276. for(i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DevInfoData); i++) {
  2277. //
  2278. // Retrieve the name of the controlling service for this device instance.
  2279. //
  2280. if(!SetupDiGetDeviceRegistryProperty(hDevInfo,
  2281. &DevInfoData,
  2282. SPDRP_SERVICE,
  2283. NULL,
  2284. (PBYTE)ServiceName,
  2285. sizeof(ServiceName),
  2286. NULL)) {
  2287. //
  2288. // No controlling service listed--just skip this element and continue
  2289. // with the next one.
  2290. //
  2291. continue;
  2292. }
  2293. //
  2294. // Open a handle to this service.
  2295. //
  2296. if(!(ServiceHandle = OpenService(SCMHandle, ServiceName, SERVICE_ALL_ACCESS))) {
  2297. continue;
  2298. }
  2299. //
  2300. // Now retrieve the service's configuration information.
  2301. //
  2302. if(pSetupRetrieveServiceConfig(ServiceHandle, &ServiceConfig) == NO_ERROR) {
  2303. //
  2304. // If this is a SERVICE_KERNEL_DRIVER that is a member of the "Video" load order
  2305. // group, then we have ourselves a display device.
  2306. //
  2307. if((ServiceConfig->dwServiceType == SERVICE_KERNEL_DRIVER) &&
  2308. ServiceConfig->lpLoadOrderGroup &&
  2309. !lstrcmpi(ServiceConfig->lpLoadOrderGroup, L"Video")) {
  2310. //
  2311. // If we haven't already done so, create a new device information set without
  2312. // an associated class, to hold our element while we munge it.
  2313. //
  2314. if(TempDevInfoSet == INVALID_HANDLE_VALUE) {
  2315. TempDevInfoSet = SetupDiCreateDeviceInfoList(NULL, NULL);
  2316. }
  2317. if(TempDevInfoSet != INVALID_HANDLE_VALUE) {
  2318. //
  2319. // OK, we have a working space to hold this element while we change its class.
  2320. // Retrieve the name of this device instance.
  2321. //
  2322. if(!SetupDiGetDeviceInstanceId(hDevInfo,
  2323. &DevInfoData,
  2324. DevInstId,
  2325. SIZECHARS(DevInstId),
  2326. NULL)) {
  2327. *DevInstId = L'\0';
  2328. }
  2329. //
  2330. // Now open this element in our new, class-agnostic set.
  2331. //
  2332. DisplayDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  2333. if(SetupDiOpenDeviceInfo(TempDevInfoSet,
  2334. DevInstId,
  2335. NULL,
  2336. 0,
  2337. &DisplayDevInfoData)) {
  2338. //
  2339. // Now set the device's ClassGUID property to the Display class GUID. The
  2340. // API will take care of cleaning up the old driver keys, etc.
  2341. //
  2342. SetupDiSetDeviceRegistryProperty(TempDevInfoSet,
  2343. &DisplayDevInfoData,
  2344. SPDRP_CLASSGUID,
  2345. (PBYTE)szDisplayClassGuid,
  2346. sizeof(szDisplayClassGuid)
  2347. );
  2348. }
  2349. }
  2350. MyFree(ServiceConfig);
  2351. } else {
  2352. //
  2353. // This device information element isn't a Display device. If
  2354. // the service isn't disabled, then store the service
  2355. // configuration information away in the device install params,
  2356. // for use later.
  2357. //
  2358. if((ServiceConfig->dwStartType != SERVICE_DISABLED) &&
  2359. SetupDiGetDeviceInstallParams(hDevInfo, &DevInfoData, &DevInstallParams)) {
  2360. DevInstallParams.ClassInstallReserved = (ULONG_PTR)ServiceConfig;
  2361. if(SetupDiSetDeviceInstallParams(hDevInfo, &DevInfoData, &DevInstallParams)) {
  2362. //
  2363. // We successfully stored a pointer to the
  2364. // ServiceConfig information. Set our pointer to NULL,
  2365. // so we won't try to free the buffer.
  2366. //
  2367. ServiceConfig = NULL;
  2368. }
  2369. }
  2370. //
  2371. // If we get to here, and ServiceConfig isn't NULL, then we
  2372. // need to free it.
  2373. //
  2374. if(ServiceConfig) {
  2375. MyFree(ServiceConfig);
  2376. }
  2377. }
  2378. }
  2379. CloseServiceHandle(ServiceHandle);
  2380. }
  2381. CloseServiceHandle(SCMHandle);
  2382. if(TempDevInfoSet != INVALID_HANDLE_VALUE) {
  2383. SetupDiDestroyDeviceInfoList(TempDevInfoSet);
  2384. }
  2385. }
  2386. BOOL
  2387. DriverNodeSupportsNT(
  2388. IN HDEVINFO DeviceInfoSet,
  2389. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  2390. )
  2391. /*++
  2392. Routine Description:
  2393. This routine determines whether the driver node selected for the specified parameters
  2394. support Windows NT. This determination is made based on whether or not the driver node
  2395. has a service install section.
  2396. Arguments:
  2397. DeviceInfoSet - Supplies a handle to the device information set
  2398. DeviceInfoData - Optionally, supplies the address of the device information element
  2399. within the set for which a driver node is selected. If this parameter is not
  2400. specified, then the driver node selected from the global class driver list will
  2401. be used instead.
  2402. Return Value:
  2403. If the driver node supports NT, the return value is TRUE, otherwise, it is FALSE (if
  2404. any errors are encountered, FALSE is also returned).
  2405. --*/
  2406. {
  2407. SP_DRVINFO_DATA DriverInfoData;
  2408. SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
  2409. HINF hInf;
  2410. WCHAR ActualSectionName[255]; // real max. section length as defined in ..\setupapi\inf.h
  2411. LONG LineCount = -1;
  2412. //
  2413. // First, retrieve the selected driver node.
  2414. //
  2415. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  2416. if(!SetupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData, &DriverInfoData)) {
  2417. return FALSE;
  2418. }
  2419. //
  2420. // Now, find out what INF it came from.
  2421. //
  2422. DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  2423. if(!SetupDiGetDriverInfoDetail(DeviceInfoSet,
  2424. DeviceInfoData,
  2425. &DriverInfoData,
  2426. &DriverInfoDetailData,
  2427. sizeof(DriverInfoDetailData),
  2428. NULL) &&
  2429. (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
  2430. {
  2431. return FALSE;
  2432. }
  2433. //
  2434. // Open the associated INF file.
  2435. //
  2436. if((hInf = SetupOpenInfFile(DriverInfoDetailData.InfFileName,
  2437. NULL,
  2438. INF_STYLE_WIN4,
  2439. NULL)) == INVALID_HANDLE_VALUE) {
  2440. return TRUE;
  2441. }
  2442. //
  2443. // Retrieve the actual name of the install section to be used for this driver node.
  2444. //
  2445. if (SetupDiGetActualSectionToInstall(hInf,
  2446. DriverInfoDetailData.SectionName,
  2447. ActualSectionName,
  2448. SIZECHARS(ActualSectionName),
  2449. NULL,
  2450. NULL
  2451. ) &&
  2452. SUCCEEDED(StringCchCat(ActualSectionName,
  2453. SIZECHARS(ActualSectionName),
  2454. SVCINSTALL_SECTION_SUFFIX
  2455. ))) {
  2456. LineCount = SetupGetLineCount(hInf, ActualSectionName);
  2457. SetupCloseInfFile(hInf);
  2458. }
  2459. return (LineCount != -1);
  2460. }
  2461. DWORD
  2462. DisableService(
  2463. IN LPTSTR ServiceName
  2464. )
  2465. /*++
  2466. Routine Description:
  2467. This routine sets the start configuration setting of the named service to disabled
  2468. Arguments:
  2469. ServiceName - the name of the service to disable
  2470. Return Value:
  2471. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error code.
  2472. Remarks:
  2473. This operation will fail if the SCM database remains locked for a long period (see
  2474. pSetupAcquireSCMLock for detail)
  2475. --*/
  2476. {
  2477. DWORD Err = NO_ERROR;
  2478. SC_HANDLE SCMHandle = NULL, ServiceHandle = NULL;
  2479. SC_LOCK SCMLock = NULL;
  2480. //
  2481. // Open a handle to Service Control Manager
  2482. //
  2483. if(!(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  2484. Err = GetLastError();
  2485. goto clean0;
  2486. }
  2487. //
  2488. // Lock the SCM database
  2489. //
  2490. SetupDebugPrint1(L"LegacyDriver_OnApply: Locking ServiceDatabase for service %s", ServiceName);
  2491. if((Err = pSetupAcquireSCMLock(SCMHandle, &SCMLock)) != NO_ERROR) {
  2492. goto clean0;
  2493. }
  2494. //
  2495. // Open a handle to this service
  2496. //
  2497. if(!(ServiceHandle = OpenService(SCMHandle, ServiceName, SERVICE_CHANGE_CONFIG))) {
  2498. Err = GetLastError();
  2499. goto clean0;
  2500. }
  2501. //
  2502. // Perform change service config
  2503. //
  2504. if(!ChangeServiceConfig(ServiceHandle,
  2505. SERVICE_NO_CHANGE,
  2506. SERVICE_DISABLED,
  2507. SERVICE_NO_CHANGE,
  2508. NULL,
  2509. NULL,
  2510. NULL,
  2511. NULL,
  2512. NULL,
  2513. NULL,
  2514. NULL)) {
  2515. Err = GetLastError();
  2516. }
  2517. clean0:
  2518. //
  2519. // Close handle to service
  2520. //
  2521. if (ServiceHandle) {
  2522. CloseServiceHandle(ServiceHandle);
  2523. }
  2524. //
  2525. // Unlock the SCM database
  2526. //
  2527. if (SCMLock) {
  2528. UnlockServiceDatabase(SCMLock);
  2529. SetupDebugPrint1(L"LegacyDriver_OnApply: Unlocked ServiceDatabase for service %s", ServiceName);
  2530. }
  2531. //
  2532. // Close handle to Service Control Manager
  2533. //
  2534. if (SCMHandle) {
  2535. CloseServiceHandle(SCMHandle);
  2536. }
  2537. return Err;
  2538. }
  2539. DWORD
  2540. RetrieveDriversStatus(
  2541. IN SC_HANDLE SCMHandle,
  2542. OUT LPENUM_SERVICE_STATUS *ppServices,
  2543. OUT LPDWORD pServicesCount
  2544. )
  2545. /*++
  2546. Routine Description:
  2547. This routine allocates a buffer to hold the status information for all the driver
  2548. services in the specified SCM database and retrieves that information into the
  2549. buffer. The caller is responsible for freeing the buffer.
  2550. Arguments:
  2551. SCMHandle - supplies a handle to the service control manager
  2552. ppServices - supplies the address of an ENUM_SERVICE_STATUS pointer that receives
  2553. the address of the allocated buffer containing the requested information.
  2554. pServicesCount - supplies the address of a variable that receives the number of elements
  2555. in the returned ppServices array
  2556. Return Value:
  2557. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error code.
  2558. Remarks:
  2559. The pointer whose address is contained in ppServices is guaranteed to be NULL upon
  2560. return if any error occurred.
  2561. --*/
  2562. {
  2563. DWORD CurrentSize = 0, BytesNeeded = 0, ResumeHandle = 0, Err = NO_ERROR;
  2564. LPENUM_SERVICE_STATUS Buffer = NULL;
  2565. *ppServices = NULL;
  2566. *pServicesCount = 0;
  2567. while(!EnumServicesStatus(SCMHandle,
  2568. SERVICE_DRIVER,
  2569. SERVICE_ACTIVE | SERVICE_INACTIVE,
  2570. Buffer,
  2571. CurrentSize,
  2572. &BytesNeeded,
  2573. pServicesCount,
  2574. &ResumeHandle)) {
  2575. if((Err = GetLastError()) == ERROR_MORE_DATA) {
  2576. //
  2577. // Resize the buffer
  2578. //
  2579. if(!(Buffer = MyRealloc(Buffer, BytesNeeded))) {
  2580. //
  2581. // Can't resize buffer - free resources and report error
  2582. //
  2583. if( *ppServices ) {
  2584. MyFree(*ppServices);
  2585. *ppServices = NULL;
  2586. }
  2587. return ERROR_NOT_ENOUGH_MEMORY;
  2588. }
  2589. *ppServices = Buffer;
  2590. CurrentSize = BytesNeeded;
  2591. } else {
  2592. //
  2593. // An error we can't handle
  2594. //
  2595. if( *ppServices ) {
  2596. MyFree(*ppServices);
  2597. *ppServices = NULL;
  2598. }
  2599. return Err;
  2600. }
  2601. }
  2602. return NO_ERROR;
  2603. }
  2604. DWORD
  2605. IsOnlyKeyboardDriver(
  2606. IN PCWSTR ServiceName,
  2607. OUT PBOOL pResult
  2608. )
  2609. /*++
  2610. Routine Description:
  2611. This routines examines all the drivers in the system and determines if the named
  2612. driver service is the only one that controls the keyboard
  2613. Arguments:
  2614. ServiceName - supplies the name of the driver service
  2615. pResult - pointer to a boolean value that receives the result
  2616. Return Value:
  2617. NO_ERROR is the routine succedes, otherwise a Win32 error code
  2618. Remarks:
  2619. The test to determine if another keyboard driver is available is based on membership
  2620. of the keyboard load order group. All members of this group are assumed to be capable of
  2621. controling the keyboard.
  2622. --*/
  2623. {
  2624. SC_HANDLE SCMHandle = NULL, ServiceHandle;
  2625. LPENUM_SERVICE_STATUS pServices = NULL;
  2626. DWORD ServicesCount, Count, Err = NO_ERROR;
  2627. LPQUERY_SERVICE_CONFIG pServiceConfig;
  2628. MYASSERT(pResult);
  2629. *pResult = TRUE;
  2630. //
  2631. // Open a handle to Service Control Manager
  2632. //
  2633. if(!(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  2634. Err = GetLastError();
  2635. goto clean0;
  2636. }
  2637. //
  2638. // Get a list of all the driver services and their stati
  2639. //
  2640. if((Err = RetrieveDriversStatus(SCMHandle, &pServices, &ServicesCount)) != NO_ERROR) {
  2641. goto clean0;
  2642. }
  2643. MYASSERT(pServices);
  2644. //
  2645. // Examine the configuration of each service
  2646. //
  2647. for(Count=0; Count < ServicesCount; Count++) {
  2648. //
  2649. // Check this is not our new service
  2650. //
  2651. if(lstrcmpi(pServices[Count].lpServiceName, ServiceName)) {
  2652. //
  2653. // Open a handle to this service
  2654. //
  2655. if(!(ServiceHandle = OpenService(SCMHandle,
  2656. pServices[Count].lpServiceName,
  2657. SERVICE_QUERY_CONFIG))) {
  2658. //
  2659. // We can't open a service handle then record the error and continue
  2660. //
  2661. Err = GetLastError();
  2662. continue;
  2663. }
  2664. //
  2665. // Get this services configuration data
  2666. //
  2667. pServiceConfig = NULL;
  2668. if((Err = pSetupRetrieveServiceConfig(ServiceHandle, &pServiceConfig)) != NO_ERROR) {
  2669. //
  2670. // We can't get service config then free any buffer, close the service
  2671. // handle and continue, the error has been recorded
  2672. //
  2673. MyFree(pServiceConfig);
  2674. CloseServiceHandle(ServiceHandle);
  2675. continue;
  2676. }
  2677. MYASSERT(pServiceConfig);
  2678. //
  2679. // Check if it is in the keyboard load order group and it has a start of
  2680. // SERVICE_BOOT_START OR SERVICE_SYSTEM_START. Do the start compare first as
  2681. // it is less expensive
  2682. //
  2683. if((pServiceConfig->dwStartType == SERVICE_BOOT_START
  2684. || pServiceConfig->dwStartType == SERVICE_SYSTEM_START)
  2685. && !lstrcmpi(pServiceConfig->lpLoadOrderGroup, SZ_KEYBOARD_LOAD_ORDER_GROUP)) {
  2686. *pResult = FALSE;
  2687. }
  2688. //
  2689. // Release the buffer
  2690. //
  2691. MyFree(pServiceConfig);
  2692. //
  2693. // Close the service handle
  2694. //
  2695. CloseServiceHandle(ServiceHandle);
  2696. //
  2697. // If we have found another keyboard driver then break out of the loop
  2698. //
  2699. if(!*pResult) {
  2700. break;
  2701. }
  2702. }
  2703. }
  2704. //
  2705. // Deallocate the buffer allocated by RetrieveDriversStatus
  2706. //
  2707. MyFree(pServices);
  2708. clean0:
  2709. //
  2710. // Close handle to Service Control Manager
  2711. //
  2712. if (SCMHandle) {
  2713. CloseServiceHandle(SCMHandle);
  2714. }
  2715. //
  2716. // If an error occured in the loop - ie we didn't check all the services - but we did
  2717. // find another keyboard driver in those we did check then we can ignore the error
  2718. // otherwise we must report it
  2719. //
  2720. if(NO_ERROR != Err && FALSE == *pResult) {
  2721. Err = NO_ERROR;
  2722. }
  2723. return Err;
  2724. }
  2725. DWORD
  2726. GetServiceStartType(
  2727. IN PCWSTR ServiceName
  2728. )
  2729. /*++
  2730. Routine Description:
  2731. This routines examines all the drivers in the system and determines if the named
  2732. driver service is the only one that controls the keyboard
  2733. Arguments:
  2734. ServiceName - supplies the name of the driver service
  2735. pResult - pointer to a boolean value that receives the result
  2736. Return Value:
  2737. NO_ERROR is the routine succedes, otherwise a Win32 error code
  2738. Remarks:
  2739. The test to determine if another keyboard driver is available is based on membership
  2740. of the keyboard load order group. All members of this group are assumed to be capable of
  2741. controling the keyboard.
  2742. --*/
  2743. {
  2744. SC_HANDLE SCMHandle = NULL, ServiceHandle = NULL;
  2745. DWORD dwStartType = (DWORD)-1;
  2746. LPQUERY_SERVICE_CONFIG pServiceConfig = NULL;
  2747. //
  2748. // Open a handle to Service Control Manager
  2749. //
  2750. if (!(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  2751. goto clean0;
  2752. }
  2753. //
  2754. // Open a handle to this service
  2755. //
  2756. if (!(ServiceHandle = OpenService(SCMHandle,
  2757. ServiceName,
  2758. SERVICE_QUERY_CONFIG))) {
  2759. goto clean0;
  2760. }
  2761. //
  2762. // Get this services configuration data
  2763. //
  2764. if (pSetupRetrieveServiceConfig(ServiceHandle, &pServiceConfig) != NO_ERROR) {
  2765. goto clean0;
  2766. }
  2767. MYASSERT(pServiceConfig);
  2768. if( !pServiceConfig ) {
  2769. goto clean0;
  2770. }
  2771. //
  2772. // store the start type, clean up, and exit
  2773. //
  2774. dwStartType = pServiceConfig->dwStartType;
  2775. clean0:
  2776. if (pServiceConfig) {
  2777. MyFree(pServiceConfig);
  2778. }
  2779. //
  2780. // Close the service handle
  2781. //
  2782. if (ServiceHandle) {
  2783. CloseServiceHandle(ServiceHandle);
  2784. }
  2785. //
  2786. // Close handle to Service Control Manager
  2787. //
  2788. if (SCMHandle) {
  2789. CloseServiceHandle(SCMHandle);
  2790. }
  2791. return dwStartType;
  2792. }
  2793. LONG
  2794. CountDevicesControlled(
  2795. IN LPTSTR ServiceName
  2796. )
  2797. /*++
  2798. Routine Description:
  2799. This routine return the number of devices controlled by a given device service
  2800. based on information from the configuration manager
  2801. Arguments:
  2802. ServiceName - supplies the name of the driver service
  2803. Return Value:
  2804. The number of devices controlled by ServiceName
  2805. Remarks:
  2806. When an error occurs the value 0 is returned - as the only place this routine is used
  2807. is in a test for one driver installed or not this is legitimate. This is because the
  2808. configuration manager returns its own errors which are cannot be returned as Win32
  2809. error codes. A mapping of config manager to Win32 errors would resolve this.
  2810. --*/
  2811. {
  2812. ULONG BufferSize=1024;
  2813. LONG DeviceCount=-1;
  2814. CONFIGRET Err;
  2815. PTSTR pBuffer = NULL, pNext;
  2816. //
  2817. // Allocate a 1k buffer as a first attempt
  2818. //
  2819. if(!(pBuffer = MyMalloc(BufferSize))) {
  2820. goto clean0;
  2821. }
  2822. while((Err = CM_Get_Device_ID_List(ServiceName,
  2823. pBuffer,
  2824. BufferSize,
  2825. CM_GETIDLIST_FILTER_SERVICE)) != CR_SUCCESS) {
  2826. if(Err == CR_BUFFER_SMALL) {
  2827. //
  2828. // Find out how large a buffer is required
  2829. //
  2830. if(CM_Get_Device_ID_List_Size(&BufferSize,
  2831. ServiceName,
  2832. CM_GETIDLIST_FILTER_SERVICE) != CR_SUCCESS) {
  2833. //
  2834. // We can't calculate the size of the buffer required therefore we can't complete
  2835. //
  2836. goto clean0;
  2837. }
  2838. //
  2839. // Deallocate any old buffer
  2840. //
  2841. MyFree(pBuffer);
  2842. //
  2843. // Allocate new buffer
  2844. //
  2845. if(!(pBuffer = MyMalloc(BufferSize))) {
  2846. goto clean0;
  2847. }
  2848. } else {
  2849. //
  2850. // An error we can't handle - free up resources and return
  2851. //
  2852. goto clean0;
  2853. }
  2854. }
  2855. //
  2856. // Traverse the buffer counting the number of strings encountered
  2857. //
  2858. pNext = pBuffer;
  2859. DeviceCount = 0;
  2860. while(*pNext != (TCHAR)0) {
  2861. DeviceCount++;
  2862. pNext += lstrlen(pNext)+1;
  2863. }
  2864. clean0:
  2865. //
  2866. // Deallocate the buffer
  2867. //
  2868. if (pBuffer) {
  2869. MyFree(pBuffer);
  2870. }
  2871. return DeviceCount;
  2872. }
  2873. DWORD
  2874. IsKeyboardDriver(
  2875. IN PCWSTR ServiceName,
  2876. OUT PBOOL pResult
  2877. )
  2878. /*++
  2879. Routine Description:
  2880. This routine examines all the drivers in the system and determines if the named
  2881. driver service is the only one that controls the keyboard.
  2882. Arguments:
  2883. ServiceName - supplies the name of the driver service
  2884. pResult - pointer to a boolean value that receives the result
  2885. Return Value:
  2886. NO_ERROR is the routine succedes, otherwise a Win32 error code
  2887. Remarks:
  2888. The test to determine if another keyboard driver is available is based on membership
  2889. of the keyboard load order group. All members of this group are assumed to be capable of
  2890. controling the keyboard.
  2891. --*/
  2892. {
  2893. SC_HANDLE SCMHandle = NULL, ServiceHandle = NULL;
  2894. DWORD Err = NO_ERROR;
  2895. LPQUERY_SERVICE_CONFIG pServiceConfig;
  2896. MYASSERT(pResult);
  2897. //
  2898. // Open a handle to Service Control Manager
  2899. //
  2900. if(!(SCMHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
  2901. Err = GetLastError();
  2902. goto clean0;
  2903. }
  2904. //
  2905. // Open a handle to this service
  2906. //
  2907. if(!(ServiceHandle = OpenService(SCMHandle,
  2908. ServiceName,
  2909. SERVICE_QUERY_CONFIG))) {
  2910. Err = GetLastError();
  2911. goto clean0;
  2912. }
  2913. //
  2914. // Get this services configuration data
  2915. //
  2916. pServiceConfig = NULL;
  2917. if((Err = pSetupRetrieveServiceConfig(ServiceHandle, &pServiceConfig)) != NO_ERROR) {
  2918. goto clean0;
  2919. }
  2920. MYASSERT(pServiceConfig);
  2921. if( !pServiceConfig ) {
  2922. Err = GetLastError();
  2923. goto clean0;
  2924. }
  2925. //
  2926. // Check if it is in the keyboard load order group and it has a start of
  2927. // SERVICE_BOOT_START OR SERVICE_SYSTEM_START. Do the start compare first as
  2928. // it is less expensive
  2929. //
  2930. *pResult = (pServiceConfig->dwStartType == SERVICE_BOOT_START
  2931. || pServiceConfig->dwStartType == SERVICE_SYSTEM_START)
  2932. && !lstrcmpi(pServiceConfig->lpLoadOrderGroup, SZ_KEYBOARD_LOAD_ORDER_GROUP);
  2933. //
  2934. // Release the buffer
  2935. //
  2936. MyFree(pServiceConfig);
  2937. clean0:
  2938. //
  2939. // Close the service handle
  2940. //
  2941. if (ServiceHandle) {
  2942. CloseServiceHandle(ServiceHandle);
  2943. }
  2944. //
  2945. // Close handle to Service Control Manager
  2946. //
  2947. if (SCMHandle) {
  2948. CloseServiceHandle(SCMHandle);
  2949. }
  2950. return Err;
  2951. }
  2952. VOID
  2953. ReplaceSlashWithHash(
  2954. IN PWSTR Str
  2955. )
  2956. /*++
  2957. Routine Description:
  2958. Replaces all backslash chars with hash chars so that the string can be used
  2959. as a key name in the registry
  2960. --*/
  2961. {
  2962. for ( ; *Str ; Str++) {
  2963. if (*Str == L'\\') {
  2964. *Str = L'#';
  2965. }
  2966. }
  2967. }
  2968. HANDLE
  2969. UtilpGetDeviceHandle(
  2970. HDEVINFO DevInfo,
  2971. PSP_DEVINFO_DATA DevInfoData,
  2972. LPGUID ClassGuid,
  2973. DWORD DesiredAccess
  2974. )
  2975. /*++
  2976. Routine Description:
  2977. gets a handle for a device
  2978. Arguments:
  2979. the name of the device to open
  2980. Return Value:
  2981. handle to the device opened, which must be later closed by the caller.
  2982. Notes:
  2983. this function is also in storage proppage (storprop.dll)
  2984. so please propogate fixes there as well
  2985. --*/
  2986. {
  2987. BOOL status;
  2988. ULONG i;
  2989. HANDLE fileHandle = INVALID_HANDLE_VALUE;
  2990. SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
  2991. HDEVINFO devInfoWithInterface = NULL;
  2992. PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL;
  2993. PTSTR deviceInstanceId = NULL;
  2994. TCHAR * devicePath = NULL;
  2995. ULONG deviceInterfaceDetailDataSize;
  2996. ULONG deviceInstanceIdSize;
  2997. //
  2998. // get the ID for this device
  2999. //
  3000. for (i=deviceInstanceIdSize=0; i<2; i++) {
  3001. if (deviceInstanceIdSize != 0) {
  3002. deviceInstanceId =
  3003. LocalAlloc(LPTR, deviceInstanceIdSize * sizeof(TCHAR));
  3004. if (deviceInstanceId == NULL) {
  3005. ChkPrintEx(("SysSetup.GetDeviceHandle => Unable to "
  3006. "allocate for deviceInstanceId\n"));
  3007. goto cleanup;
  3008. }
  3009. }
  3010. status = SetupDiGetDeviceInstanceId(DevInfo,
  3011. DevInfoData,
  3012. deviceInstanceId,
  3013. deviceInstanceIdSize,
  3014. &deviceInstanceIdSize
  3015. );
  3016. }
  3017. if (!status) {
  3018. ChkPrintEx(("SysSetup.GetDeviceHandle => Unable to get "
  3019. "Device IDs\n"));
  3020. goto cleanup;
  3021. }
  3022. //
  3023. // Get all the cdroms in the system
  3024. //
  3025. devInfoWithInterface = SetupDiGetClassDevs(ClassGuid,
  3026. deviceInstanceId,
  3027. NULL,
  3028. DIGCF_DEVICEINTERFACE
  3029. );
  3030. if (devInfoWithInterface == NULL) {
  3031. ChkPrintEx(("SysSetup.GetDeviceHandle => Unable to get "
  3032. "list of CdRom's in system\n"));
  3033. goto cleanup;
  3034. }
  3035. memset(&deviceInterfaceData, 0, sizeof(SP_DEVICE_INTERFACE_DATA));
  3036. deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  3037. status = SetupDiEnumDeviceInterfaces(devInfoWithInterface,
  3038. NULL,
  3039. ClassGuid,
  3040. 0,
  3041. &deviceInterfaceData
  3042. );
  3043. if (!status) {
  3044. ChkPrintEx(("SysSetup.GetDeviceHandle => Unable to get "
  3045. "SP_DEVICE_INTERFACE_DATA\n"));
  3046. goto cleanup;
  3047. }
  3048. for (i=deviceInterfaceDetailDataSize=0; i<2; i++) {
  3049. if (deviceInterfaceDetailDataSize != 0) {
  3050. deviceInterfaceDetailData =
  3051. LocalAlloc (LPTR, deviceInterfaceDetailDataSize);
  3052. if (deviceInterfaceDetailData == NULL) {
  3053. ChkPrintEx(("SysSetup.GetDeviceHandle => Unable to "
  3054. "allocate for deviceInterfaceDetailData\n"));
  3055. goto cleanup;
  3056. }
  3057. deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  3058. }
  3059. status = SetupDiGetDeviceInterfaceDetail(devInfoWithInterface,
  3060. &deviceInterfaceData,
  3061. deviceInterfaceDetailData,
  3062. deviceInterfaceDetailDataSize,
  3063. &deviceInterfaceDetailDataSize,
  3064. NULL);
  3065. }
  3066. if (!status) {
  3067. ChkPrintEx(("SysSetup.GetDeviceHandle => Unable to get "
  3068. "DeviceInterfaceDetail\n"));
  3069. goto cleanup;
  3070. }
  3071. devicePath = LocalAlloc(LPTR, deviceInterfaceDetailDataSize);
  3072. if (devicePath == NULL) {
  3073. ChkPrintEx(("SysSetup.GetDeviceHandle => Unable to alloc %x "
  3074. "bytes for devicePath\n"));
  3075. goto cleanup;
  3076. }
  3077. memcpy (devicePath,
  3078. deviceInterfaceDetailData->DevicePath,
  3079. deviceInterfaceDetailDataSize);
  3080. fileHandle = CreateFile(devicePath,
  3081. DesiredAccess,
  3082. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3083. NULL,
  3084. OPEN_EXISTING,
  3085. 0,
  3086. NULL);
  3087. if (fileHandle == INVALID_HANDLE_VALUE) {
  3088. ChkPrintEx(("SysSetup.GetDeviceHandle => Final CreateFile() "
  3089. "failed\n"));
  3090. goto cleanup;
  3091. }
  3092. ChkPrintEx(("SysSetup.GetDeviceHandle => handle %x opened\n",
  3093. fileHandle));
  3094. cleanup:
  3095. if (devInfoWithInterface != NULL) {
  3096. SetupDiDestroyDeviceInfoList(devInfoWithInterface);
  3097. }
  3098. if (deviceInterfaceDetailData != NULL) {
  3099. LocalFree (deviceInterfaceDetailData);
  3100. }
  3101. if (devicePath != NULL) {
  3102. LocalFree (devicePath);
  3103. }
  3104. return fileHandle;
  3105. }
  3106. DWORD
  3107. CriticalDeviceCoInstaller(
  3108. IN DI_FUNCTION InstallFunction,
  3109. IN HDEVINFO DeviceInfoSet,
  3110. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  3111. IN OUT PCOINSTALLER_CONTEXT_DATA Context
  3112. )
  3113. /*++
  3114. Routine Description:
  3115. This routine acts as a co-installer for critical devices. It is presently
  3116. registered (via hivesys.inf) for CDROM, DiskDrive, System, Scsi, Hdc, and
  3117. Keyboard classes.
  3118. The purpose of this co-installer is to save away the services used by these
  3119. classes of device into the CriticalDeviceDatabase registry key. The reason
  3120. for this is so that we can determine what drivers should be used for new
  3121. critical devices that are found while the system is booting, and enable
  3122. them at that time. This solves the problem that arises when a device that
  3123. is critical to getting the system up and running (such as the boot device),
  3124. is moved to a new location. When we find a new critical device for which
  3125. we know what service to start, we can start the device and continue to boot
  3126. without failure.
  3127. Arguments:
  3128. InstallFunction - Specifies the device installer function code indicating
  3129. the action being performed.
  3130. DeviceInfoSet - Supplies a handle to the device information set being
  3131. acted upon by this install action.
  3132. DeviceInfoData - Optionally, supplies the address of a device information
  3133. element being acted upon by this install action.
  3134. Context - Supplies the installation context that is per-install request and
  3135. per-coinstaller.
  3136. Return Value:
  3137. For pre-processing, this function only cares about DIF_INSTALLDEVICE. For
  3138. all other DIF requests, it returns NO_ERROR. For DIF_INSTALLDEVICE, it
  3139. will request post-processing by returning ERROR_DI_POSTPROCESSING_REQUIRED
  3140. (or catastrophic error such as ERROR_NOT_ENOUGH_MEMORY).
  3141. For post-processing, this function will always propagate the install result
  3142. passed in to it via the co-installer Context structure.
  3143. --*/
  3144. {
  3145. HKEY hkDrv, hkCDD;
  3146. DWORD matchingDeviceIdSize, serviceNameSize, classGUIDSize, lowerFiltersSize,
  3147. upperFiltersSize, Err, driverSize, devtype, exclusive, characteristics,
  3148. securitySize;
  3149. TCHAR serviceName[MAX_SERVICE_NAME_LEN],
  3150. classGUID[GUID_STRING_LEN],
  3151. matchingDeviceId[MAX_DEVICE_ID_LEN];
  3152. PCTSTR driverMatch = TEXT("\\Driver");
  3153. PTSTR lowerFilters, upperFilters;
  3154. BOOL foundService, foundClassGUID, foundLowerFilters, foundUpperFilters,
  3155. foundSecurity, foundDevtype, foundExclusive, foundCharacteristics;
  3156. PCDC_CONTEXT CDCContext;
  3157. PBYTE security;
  3158. switch(InstallFunction) {
  3159. //
  3160. // We only care about DIF_INSTALLDEVICE...
  3161. //
  3162. case DIF_INSTALLDEVICE :
  3163. DbgPrintEx(DPFLTR_SETUP_ID,
  3164. DPFLTR_INFO_LEVEL,
  3165. "CriticalDeviceCoInstaller: DIF_INSTALLDEVICE called\n");
  3166. if(Context->PostProcessing) {
  3167. //
  3168. // Track whether or not we've populated the critical device
  3169. // database with the newly-installed settings.
  3170. //
  3171. BOOL CDDPopulated = FALSE;
  3172. //
  3173. // We're 'on the way out' of an installation. We may have some
  3174. // data squirrelled away for us while we were "on the way in".
  3175. //
  3176. CDCContext = (PCDC_CONTEXT)(Context->PrivateData);
  3177. //
  3178. // Make sure that the matchingDeviceId buffer is initialized to
  3179. // an empty string.
  3180. //
  3181. *matchingDeviceId = TEXT('\0');
  3182. //
  3183. // Initialize our lowerFilters and upperFilters buffer pointers
  3184. // to NULL, so we can track whether or not we've allocated
  3185. // memory that must be freed.
  3186. //
  3187. upperFilters = lowerFilters = NULL;
  3188. security = NULL;
  3189. if (Context->InstallResult != NO_ERROR) {
  3190. //
  3191. // If an error occurred prior to this call, abort and
  3192. // propagate that error.
  3193. //
  3194. goto InstallDevPostProcExit;
  3195. }
  3196. //
  3197. // Get the serviceName for this device.
  3198. //
  3199. foundService = SetupDiGetDeviceRegistryProperty(
  3200. DeviceInfoSet,
  3201. DeviceInfoData,
  3202. SPDRP_SERVICE,
  3203. NULL,
  3204. (PBYTE)serviceName,
  3205. sizeof(serviceName),
  3206. &serviceNameSize);
  3207. if (foundService) {
  3208. //
  3209. // Make sure the service name isn't something like \Driver\PCI_HAL
  3210. //
  3211. driverSize = wcslen(driverMatch);
  3212. if (wcslen(serviceName) >= driverSize &&
  3213. _wcsnicmp(serviceName, driverMatch, driverSize) == 0) {
  3214. goto InstallDevPostProcExit;
  3215. }
  3216. }
  3217. foundClassGUID = SetupDiGetDeviceRegistryProperty(
  3218. DeviceInfoSet,
  3219. DeviceInfoData,
  3220. SPDRP_CLASSGUID,
  3221. NULL,
  3222. (PBYTE)classGUID,
  3223. sizeof(classGUID),
  3224. &classGUIDSize);
  3225. //
  3226. // The LowerFilters and UpperFilters properties are variable-
  3227. // length, so we must dynamically size buffers to accommodate
  3228. // their contents.
  3229. //
  3230. foundLowerFilters =
  3231. (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  3232. DeviceInfoData,
  3233. SPDRP_LOWERFILTERS,
  3234. NULL,
  3235. NULL,
  3236. 0,
  3237. &lowerFiltersSize)
  3238. && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  3239. && (lowerFiltersSize > sizeof(TCHAR)));
  3240. if(foundLowerFilters) {
  3241. lowerFilters = MyMalloc(lowerFiltersSize);
  3242. if(!lowerFilters) {
  3243. goto InstallDevPostProcExit;
  3244. }
  3245. if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  3246. DeviceInfoData,
  3247. SPDRP_LOWERFILTERS,
  3248. NULL,
  3249. (PBYTE)lowerFilters,
  3250. lowerFiltersSize,
  3251. NULL)) {
  3252. //
  3253. // This shouldn't happen--we know we have a big enough
  3254. // buffer.
  3255. //
  3256. goto InstallDevPostProcExit;
  3257. }
  3258. }
  3259. foundUpperFilters =
  3260. (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  3261. DeviceInfoData,
  3262. SPDRP_UPPERFILTERS,
  3263. NULL,
  3264. NULL,
  3265. 0,
  3266. &upperFiltersSize)
  3267. && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  3268. && (upperFiltersSize > sizeof(TCHAR)));
  3269. if(foundUpperFilters) {
  3270. upperFilters = MyMalloc(upperFiltersSize);
  3271. if(!upperFilters) {
  3272. goto InstallDevPostProcExit;
  3273. }
  3274. if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  3275. DeviceInfoData,
  3276. SPDRP_UPPERFILTERS,
  3277. NULL,
  3278. (PBYTE)upperFilters,
  3279. upperFiltersSize,
  3280. NULL)) {
  3281. //
  3282. // This shouldn't happen--we know we have a big enough
  3283. // buffer.
  3284. //
  3285. goto InstallDevPostProcExit;
  3286. }
  3287. }
  3288. //
  3289. // Open Driver information key
  3290. //
  3291. if((hkDrv = SetupDiOpenDevRegKey(DeviceInfoSet,
  3292. DeviceInfoData,
  3293. DICS_FLAG_GLOBAL,
  3294. 0,
  3295. DIREG_DRV,
  3296. KEY_READ)) == INVALID_HANDLE_VALUE) {
  3297. goto InstallDevPostProcExit;
  3298. } else {
  3299. //
  3300. // Get matchingDeviceId
  3301. //
  3302. matchingDeviceIdSize = sizeof(matchingDeviceId);
  3303. Err = RegQueryValueEx(hkDrv,
  3304. REGSTR_VAL_MATCHINGDEVID,
  3305. NULL,
  3306. NULL,
  3307. (PBYTE)matchingDeviceId,
  3308. &matchingDeviceIdSize);
  3309. RegCloseKey(hkDrv);
  3310. if(Err != ERROR_SUCCESS) {
  3311. //
  3312. // Ensure that matchingDeviceId is still an empty string
  3313. //
  3314. *matchingDeviceId = TEXT('\0');
  3315. goto InstallDevPostProcExit;
  3316. }
  3317. }
  3318. foundDevtype = SetupDiGetDeviceRegistryProperty(
  3319. DeviceInfoSet,
  3320. DeviceInfoData,
  3321. SPDRP_DEVTYPE,
  3322. NULL,
  3323. (PBYTE)&devtype,
  3324. sizeof(DWORD),
  3325. NULL);
  3326. foundExclusive = SetupDiGetDeviceRegistryProperty(
  3327. DeviceInfoSet,
  3328. DeviceInfoData,
  3329. SPDRP_EXCLUSIVE,
  3330. NULL,
  3331. (PBYTE)&exclusive,
  3332. sizeof(DWORD),
  3333. NULL);
  3334. foundCharacteristics = SetupDiGetDeviceRegistryProperty(
  3335. DeviceInfoSet,
  3336. DeviceInfoData,
  3337. SPDRP_CHARACTERISTICS,
  3338. NULL,
  3339. (PBYTE)&characteristics,
  3340. sizeof(DWORD),
  3341. NULL);
  3342. foundSecurity =
  3343. (!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  3344. DeviceInfoData,
  3345. SPDRP_SECURITY,
  3346. NULL,
  3347. NULL,
  3348. 0,
  3349. &securitySize)
  3350. && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  3351. && (securitySize > 0));
  3352. if(foundSecurity) {
  3353. security = MyMalloc(securitySize);
  3354. if(!security) {
  3355. goto InstallDevPostProcExit;
  3356. }
  3357. if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  3358. DeviceInfoData,
  3359. SPDRP_SECURITY,
  3360. NULL,
  3361. (PBYTE)security,
  3362. securitySize,
  3363. NULL)) {
  3364. //
  3365. // This shouldn't happen--we know we have a big enough
  3366. // buffer.
  3367. //
  3368. goto InstallDevPostProcExit;
  3369. }
  3370. }
  3371. hkCDD = OpenCDDRegistryKey(matchingDeviceId, TRUE);
  3372. if(hkCDD != INVALID_HANDLE_VALUE) {
  3373. //
  3374. // Store all the values (service, classguid, lower and upper
  3375. // filters, deleting any that aren't present in the newly installed
  3376. // device (which might have been present from a previous install)
  3377. //
  3378. if (foundService) {
  3379. RegSetValueEx(hkCDD,
  3380. REGSTR_VAL_SERVICE,
  3381. 0,
  3382. REG_SZ,
  3383. (PBYTE)&serviceName,
  3384. serviceNameSize);
  3385. }
  3386. else {
  3387. RegDeleteValue(hkCDD, REGSTR_VAL_SERVICE);
  3388. }
  3389. if (foundClassGUID) {
  3390. RegSetValueEx(hkCDD,
  3391. REGSTR_VAL_CLASSGUID,
  3392. 0,
  3393. REG_SZ,
  3394. (PBYTE)&classGUID,
  3395. classGUIDSize);
  3396. }
  3397. else {
  3398. RegDeleteValue(hkCDD, REGSTR_VAL_CLASSGUID);
  3399. }
  3400. if (foundLowerFilters) {
  3401. RegSetValueEx(hkCDD,
  3402. REGSTR_VAL_LOWERFILTERS,
  3403. 0,
  3404. REG_MULTI_SZ,
  3405. (PBYTE)lowerFilters,
  3406. lowerFiltersSize);
  3407. }
  3408. else {
  3409. RegDeleteValue(hkCDD, REGSTR_VAL_LOWERFILTERS);
  3410. }
  3411. if (foundUpperFilters) {
  3412. RegSetValueEx(hkCDD,
  3413. REGSTR_VAL_UPPERFILTERS,
  3414. 0,
  3415. REG_MULTI_SZ,
  3416. (PBYTE)upperFilters,
  3417. upperFiltersSize);
  3418. }
  3419. else {
  3420. RegDeleteValue(hkCDD, REGSTR_VAL_UPPERFILTERS);
  3421. }
  3422. if (foundDevtype) {
  3423. DbgPrintEx(DPFLTR_SETUP_ID,
  3424. DPFLTR_INFO_LEVEL,
  3425. "CriticalDeviceCoInstaller: Found devtype %x for %ws\n",
  3426. devtype,
  3427. matchingDeviceId);
  3428. RegSetValueEx(hkCDD,
  3429. REGSTR_VAL_DEVICE_TYPE,
  3430. 0,
  3431. REG_DWORD,
  3432. (PBYTE)&devtype,
  3433. sizeof(DWORD));
  3434. } else {
  3435. RegDeleteValue(hkCDD, REGSTR_VAL_DEVICE_TYPE);
  3436. }
  3437. if (foundExclusive) {
  3438. DbgPrintEx(DPFLTR_SETUP_ID,
  3439. DPFLTR_INFO_LEVEL,
  3440. "CriticalDeviceCoInstaller: Found exclusive %x for %ws\n",
  3441. exclusive,
  3442. matchingDeviceId);
  3443. RegSetValueEx(hkCDD,
  3444. REGSTR_VAL_DEVICE_EXCLUSIVE,
  3445. 0,
  3446. REG_DWORD,
  3447. (PBYTE)&exclusive,
  3448. sizeof(DWORD));
  3449. } else {
  3450. RegDeleteValue(hkCDD, REGSTR_VAL_DEVICE_EXCLUSIVE);
  3451. }
  3452. if (foundCharacteristics) {
  3453. DbgPrintEx(DPFLTR_SETUP_ID,
  3454. DPFLTR_INFO_LEVEL,
  3455. "CriticalDeviceCoInstaller: Found characteristics %x for %ws\n",
  3456. characteristics,
  3457. matchingDeviceId);
  3458. RegSetValueEx(hkCDD,
  3459. REGSTR_VAL_DEVICE_CHARACTERISTICS,
  3460. 0,
  3461. REG_DWORD,
  3462. (PBYTE)&characteristics,
  3463. sizeof(DWORD));
  3464. } else {
  3465. RegDeleteValue(hkCDD, REGSTR_VAL_DEVICE_CHARACTERISTICS);
  3466. }
  3467. if (foundSecurity) {
  3468. DbgPrintEx(DPFLTR_SETUP_ID,
  3469. DPFLTR_INFO_LEVEL,
  3470. "CriticalDeviceCoInstaller: Found security %x for %ws\n",
  3471. security,
  3472. matchingDeviceId);
  3473. RegSetValueEx(hkCDD,
  3474. REGSTR_VAL_DEVICE_SECURITY_DESCRIPTOR,
  3475. 0,
  3476. REG_BINARY,
  3477. (PBYTE)security,
  3478. securitySize);
  3479. } else {
  3480. RegDeleteValue(hkCDD, REGSTR_VAL_DEVICE_SECURITY_DESCRIPTOR);
  3481. }
  3482. RegCloseKey(hkCDD);
  3483. CDDPopulated = TRUE;
  3484. }
  3485. InstallDevPostProcExit:
  3486. if(lowerFilters) {
  3487. MyFree(lowerFilters);
  3488. }
  3489. if(upperFilters) {
  3490. MyFree(upperFilters);
  3491. }
  3492. if (security) {
  3493. MyFree(security);
  3494. }
  3495. if(CDCContext) {
  3496. //
  3497. // If we have a private context, that means that the device
  3498. // was installed previously, and that it had a CDD entry.
  3499. // We want to restore the previous controlling service
  3500. // stored in this CDD entry in the following two scenarios:
  3501. //
  3502. // 1. The CDD entry for the new installation is different
  3503. // than the old one.
  3504. // 2. We didn't end up populating the CDD entry with the
  3505. // newly-installed settings (probably because the
  3506. // InstallResult we were handed indicated that the
  3507. // install failed.
  3508. //
  3509. if(lstrcmpi(matchingDeviceId, CDCContext->OldMatchingDevId)
  3510. || !CDDPopulated) {
  3511. hkCDD = OpenCDDRegistryKey(CDCContext->OldMatchingDevId,
  3512. FALSE
  3513. );
  3514. if(hkCDD != INVALID_HANDLE_VALUE) {
  3515. if(*(CDCContext->OldServiceName)) {
  3516. RegSetValueEx(hkCDD,
  3517. REGSTR_VAL_SERVICE,
  3518. 0,
  3519. REG_SZ,
  3520. (PBYTE)(CDCContext->OldServiceName),
  3521. (lstrlen(CDCContext->OldServiceName) + 1) * sizeof(TCHAR)
  3522. );
  3523. } else {
  3524. RegDeleteValue(hkCDD, REGSTR_VAL_SERVICE);
  3525. }
  3526. RegCloseKey(hkCDD);
  3527. }
  3528. }
  3529. MyFree(CDCContext);
  3530. }
  3531. //
  3532. // Regardless of success or failure, we always want to propagate
  3533. // the existing install result. In other words, any failure we
  3534. // encounter in post-processing isn't considered critical.
  3535. //
  3536. return Context->InstallResult;
  3537. } else {
  3538. //
  3539. // We're "on the way in". We need to check and see if this
  3540. // device already has a critical device database entry
  3541. // associated with it. If so, then we want to remember the
  3542. // controlling service currently listed in the CDD (in case we
  3543. // need to restore it in post-processing if the install fails).
  3544. // We then clear this entry out of the CDD, so that, if a null
  3545. // driver install is taking place, that we won't try to re-apply
  3546. // the now-bogus CDD entry. This can get us into a nasty
  3547. // infinite loop in GUI setup where we keep finding the device
  3548. // because it's marked as finish-install, yet every time we
  3549. // install it, the (bogus) CDD entry gets re-applied, and the
  3550. // devnode gets marked yet again with finish-install.
  3551. //
  3552. // NTRAID #59238 1999/09/01 lonnym
  3553. // This fix is reliant upon the current
  3554. // (somewhat broken) behavior of the kernel-mode PnP manager's
  3555. // IopProcessCriticalDeviceRoutine. That routine will skip any
  3556. // CDD entries it finds that don't specify a controlling
  3557. // service. For NT5.1, we should remove this co-installer hack
  3558. // and fix the kernel-mode CDD functionality so that it is only
  3559. // applied when the devnode has a problem of not-configured (as
  3560. // opposed to its present behavior of attempting CDD
  3561. // application whenever there's no controlling service).
  3562. //
  3563. //
  3564. // First, open driver key to retrieve the current (i.e., pre-
  3565. // update) matching device ID.
  3566. //
  3567. if((hkDrv = SetupDiOpenDevRegKey(DeviceInfoSet,
  3568. DeviceInfoData,
  3569. DICS_FLAG_GLOBAL,
  3570. 0,
  3571. DIREG_DRV,
  3572. KEY_READ)) == INVALID_HANDLE_VALUE) {
  3573. //
  3574. // No need to allocate a private data structure to hand off
  3575. // to post-processing.
  3576. //
  3577. return ERROR_DI_POSTPROCESSING_REQUIRED;
  3578. } else {
  3579. //
  3580. // Get matchingDeviceId
  3581. //
  3582. matchingDeviceIdSize = sizeof(matchingDeviceId);
  3583. Err = RegQueryValueEx(hkDrv,
  3584. REGSTR_VAL_MATCHINGDEVID,
  3585. NULL,
  3586. NULL,
  3587. (PBYTE)matchingDeviceId,
  3588. &matchingDeviceIdSize);
  3589. RegCloseKey(hkDrv);
  3590. if (Err != ERROR_SUCCESS) {
  3591. //
  3592. // In this case as well, we've no need for private data
  3593. // during post-processing
  3594. //
  3595. return ERROR_DI_POSTPROCESSING_REQUIRED;
  3596. }
  3597. }
  3598. //
  3599. // If we get to here, then we've retrieved a "MatchingDeviceId"
  3600. // string from the device's driver key. Now let's see if there
  3601. // is a critical device entry for this ID...
  3602. //
  3603. hkCDD = OpenCDDRegistryKey(matchingDeviceId, FALSE);
  3604. if(hkCDD == INVALID_HANDLE_VALUE) {
  3605. //
  3606. // No existing CDD entry for this device, hence no need for
  3607. // private data to be passed off to post-processing.
  3608. //
  3609. return ERROR_DI_POSTPROCESSING_REQUIRED;
  3610. }
  3611. //
  3612. // If we get to here, we know that the device has been
  3613. // previously installed, and that there exists a CDD entry for
  3614. // that installation. We need to allocate a private data
  3615. // context structure to hand off to post-processing that
  3616. // contains (a) the currently in-effect matching device id, and
  3617. // (b) the currently in-effect controlling service (if any).
  3618. //
  3619. CDCContext = MyMalloc(sizeof(CDC_CONTEXT));
  3620. if(!CDCContext) {
  3621. //
  3622. // Can't allocate memory for our structure!
  3623. //
  3624. RegCloseKey(hkCDD);
  3625. return ERROR_NOT_ENOUGH_MEMORY;
  3626. }
  3627. StringCchCopy(CDCContext->OldMatchingDevId,
  3628. SIZECHARS(CDCContext->OldMatchingDevId),
  3629. matchingDeviceId);
  3630. serviceNameSize = sizeof(CDCContext->OldServiceName);
  3631. Err = RegQueryValueEx(hkCDD,
  3632. REGSTR_VAL_SERVICE,
  3633. NULL,
  3634. NULL,
  3635. (PBYTE)(CDCContext->OldServiceName),
  3636. &serviceNameSize
  3637. );
  3638. if(Err == ERROR_SUCCESS) {
  3639. //
  3640. // Successfully retrieved the controlling service name--now
  3641. // delete the value entry.
  3642. //
  3643. RegDeleteValue(hkCDD, REGSTR_VAL_SERVICE);
  3644. } else {
  3645. //
  3646. // Couldn't retrieve controlling service name (most likely
  3647. // because there is none). Set OldServiceName to empty
  3648. // string.
  3649. //
  3650. *(CDCContext->OldServiceName) = TEXT('\0');
  3651. }
  3652. RegCloseKey(hkCDD);
  3653. Context->PrivateData = CDCContext;
  3654. return ERROR_DI_POSTPROCESSING_REQUIRED;
  3655. }
  3656. default :
  3657. //
  3658. // We should always be 'on the way in', since we never request
  3659. // postprocessing except for DIF_INSTALLDEVICE.
  3660. //
  3661. MYASSERT(!Context->PostProcessing);
  3662. return NO_ERROR;
  3663. }
  3664. }
  3665. HKEY
  3666. OpenCDDRegistryKey(
  3667. IN PCTSTR DeviceId,
  3668. IN BOOL Create
  3669. )
  3670. /*++
  3671. Routine Description:
  3672. This routine opens (and optionally, creates if necessary) a critical device
  3673. registry key entry for a specified device ID.
  3674. Arguments:
  3675. DeviceId - supplies the device ID identifying the desired critical device
  3676. database entry (registry key)
  3677. Create - if non-zero, the registry key will be created if it doesn't
  3678. already exist.
  3679. Return Value:
  3680. If successful, the return value is a handle to the requested registry key.
  3681. If failure, the return value is INVALID_HANDLE_VALUE.
  3682. --*/
  3683. {
  3684. TCHAR MungedDeviceId[MAX_DEVICE_ID_LEN];
  3685. HKEY hkParent, hkRet;
  3686. //
  3687. // Open or create for read/write access to key under
  3688. // HKLM\System\CurrentControlSet\Control\CriticalDeviceDatabase
  3689. //
  3690. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  3691. REGSTR_PATH_CRITICALDEVICEDATABASE,
  3692. 0,
  3693. NULL,
  3694. REG_OPTION_NON_VOLATILE,
  3695. KEY_READ | KEY_WRITE,
  3696. NULL,
  3697. &hkParent,
  3698. NULL) != ERROR_SUCCESS) {
  3699. return INVALID_HANDLE_VALUE;
  3700. }
  3701. //
  3702. // Make a copy of the caller-supplied device ID so we can munge it.
  3703. //
  3704. StringCchCopy(MungedDeviceId, SIZECHARS(MungedDeviceId), DeviceId);
  3705. ReplaceSlashWithHash(MungedDeviceId);
  3706. if(Create) {
  3707. if(RegCreateKeyEx(hkParent,
  3708. MungedDeviceId,
  3709. 0,
  3710. NULL,
  3711. REG_OPTION_NON_VOLATILE,
  3712. KEY_READ | KEY_WRITE,
  3713. NULL,
  3714. &hkRet,
  3715. NULL) != ERROR_SUCCESS) {
  3716. hkRet = INVALID_HANDLE_VALUE;
  3717. }
  3718. } else {
  3719. if(RegOpenKeyEx(hkParent,
  3720. MungedDeviceId,
  3721. 0,
  3722. KEY_READ | KEY_WRITE,
  3723. &hkRet) != ERROR_SUCCESS) {
  3724. hkRet = INVALID_HANDLE_VALUE;
  3725. }
  3726. }
  3727. RegCloseKey(hkParent);
  3728. return hkRet;
  3729. }
  3730. DWORD
  3731. NtApmClassInstaller(
  3732. IN DI_FUNCTION DiFunction,
  3733. IN HDEVINFO DevInfoHandle,
  3734. IN PSP_DEVINFO_DATA DevInfoData OPTIONAL
  3735. )
  3736. /*++
  3737. Routine Description:
  3738. NOTE: When does Susan's clean up code run? When does the win0x
  3739. migration code run? Do we need to call off to either of
  3740. them in here?
  3741. NOTE: Be sure that this works at initial install AND when the
  3742. user does detect new hardare.
  3743. This is the class installer for nt apm support.
  3744. This routine installs, or thwarts installation, of the NT5 apm solution,
  3745. depending on whether the machine is an APCI machine, is an APM machine,
  3746. and has a good, bad, or unknown apm bios.
  3747. This version is copied directly from the battery class driver.
  3748. Arguments:
  3749. InstallFunction - Specifies the device installer function code indicating
  3750. the action being performed.
  3751. DeviceInfoSet - Supplies a handle to the device information set being
  3752. acted upon by this install action.
  3753. DeviceInfoData - Optionally, supplies the address of a device information
  3754. element being acted upon by this install action.
  3755. Return Value:
  3756. If this function successfully completed the requested action, the return
  3757. value is NO_ERROR.
  3758. If the default behavior is to be performed for the requested action, the
  3759. return value is ERROR_DI_DO_DEFAULT.
  3760. If an error occurred while attempting to perform the requested action, a
  3761. Win32 error code is returned.
  3762. --*/
  3763. {
  3764. DWORD status, worktype;
  3765. BOOLEAN InstallDisabled;
  3766. ChkPrintEx(("syssetup: NtApmClassInstaller:"));
  3767. ChkPrintEx(("DiFunction %08lx\n", DiFunction));
  3768. //
  3769. // Dispatch the InstallFunction
  3770. //
  3771. InstallDisabled = FALSE;
  3772. switch (DiFunction) {
  3773. ChkPrintEx(("syssetup: NtApmClassInstaller: DiFunction = %08lx\n",
  3774. DiFunction));
  3775. case DIF_FIRSTTIMESETUP:
  3776. case DIF_DETECT:
  3777. worktype = DecideNtApm();
  3778. //
  3779. // NOTE: We assume that if we say "do default" and we
  3780. // have not created a device info structure for
  3781. // ntapm, the installer will do *nothing*.
  3782. //
  3783. if (worktype == NTAPM_NOWORK) {
  3784. ChkPrintEx(("syssetup: NtApmClassInstaller returning ERROR_DI_DO_DEFAULT"));
  3785. return ERROR_DI_DO_DEFAULT;
  3786. }
  3787. if (worktype == NTAPM_INST_DISABLED) {
  3788. InstallDisabled = TRUE;
  3789. }
  3790. ChkPrintEx(("syssetup: NtApmClassInstaller: calling InstallNtApm\n"));
  3791. status = InstallNtApm(DevInfoHandle, InstallDisabled);
  3792. ChkPrintEx(("syssetup: NtApmClassInstaller: InstallNtApm returned "
  3793. "%08lx\n", status));
  3794. if (status == ERROR_SUCCESS) {
  3795. //
  3796. // Let the default device installer actually install ntapm.
  3797. //
  3798. status = ERROR_DI_DO_DEFAULT;
  3799. }
  3800. break;
  3801. case DIF_ALLOW_INSTALL:
  3802. //
  3803. // NOTE: If we are here, it means that either DIF_FIRSTIMESETUP
  3804. // has installed apm (either enabled or disabled) OR
  3805. // this is an upgrad of a machine where it was installed
  3806. // in the past. So all we want to do is make sure
  3807. // that if apm is currently disabled, it stays disabled.
  3808. //
  3809. ChkPrintEx(("syssetup: NtApmClassIntaller: DIF_ALLOW_INSTALL\n"));
  3810. return AllowInstallNtApm(DevInfoHandle, DevInfoData);
  3811. break;
  3812. case DIF_TROUBLESHOOTER:
  3813. ChkPrintEx(("syssetup: NtApmClassInstaller: DIF_TROUBLESHOOTER\n"));
  3814. return NO_ERROR;
  3815. break;
  3816. default:
  3817. //
  3818. // NOTE: We assume that if we say "do default" and we
  3819. // have not created a device info structure for ntapm,
  3820. // the installer will do *nothing*.
  3821. //
  3822. ChkPrintEx(("syssetup: NtApmClassInstaller: default:\n"));
  3823. status = ERROR_DI_DO_DEFAULT;
  3824. break;
  3825. }
  3826. ChkPrintEx(("syssetup: NtApmClassInstaller returning %08lx\n", status));
  3827. return status;
  3828. }
  3829. DWORD
  3830. DecideNtApm(
  3831. VOID
  3832. )
  3833. /*++
  3834. Routine Description:
  3835. This function decides if NtApm should be installed on the machine,
  3836. and if it should, whether it should be installed enabled or disabled.
  3837. This little bit of code is isolated here to make it easy to change
  3838. policies.
  3839. Arguments:
  3840. Return Value:
  3841. NTAPM_NOWORK - ACPI machine or no usable APM - do nothing
  3842. NTAPM_INST_DISABLED - APM machine, on neutral list, install disabled
  3843. NTAPM_INST_ENABLED - APM machine, on validated good list, install enabled
  3844. --*/
  3845. {
  3846. DWORD BiosType;
  3847. //
  3848. // NOTE: The following two tests are somewhat redundent.
  3849. // (In theory, you cannot be ApmLegalHal AND Acpi
  3850. // at the same time.) But, this belt and suspenders
  3851. // approach is very cheap, and will insure we do the
  3852. // right thing in certain upgrade and reinstall scenarios.
  3853. // So we leave both in.
  3854. //
  3855. ChkPrintEx(("syssetup: DecideNtApm: entered\n"));
  3856. if ( ! IsProductTypeApmLegal()) {
  3857. // it's not a workstation, so do nothing.
  3858. return NTAPM_NOWORK;
  3859. }
  3860. if (IsAcpiMachine()) {
  3861. //
  3862. // It's an ACPI machine, so do nothing
  3863. //
  3864. ChkPrintEx(("syssetup: DecideNtApm: acpi box, return NTAPM_NOWORK\n"));
  3865. return NTAPM_NOWORK;
  3866. }
  3867. if (IsApmLegalHalMachine() == FALSE) {
  3868. //
  3869. // It's NOT a standard Hal machine as required
  3870. // by ntapm, so do nothing.
  3871. //
  3872. ChkPrintEx(("syssetup: DecideNtApm: not apm legal, return NTAPM_NOWORK\n"));
  3873. return NTAPM_NOWORK;
  3874. }
  3875. BiosType = IsApmPresent();
  3876. if (BiosType == APM_ON_GOOD_LIST) {
  3877. ChkPrintEx(("syssetup: DecideNtApm: return NTAPM_INST_ENABLED\n"));
  3878. return NTAPM_INST_ENABLED;
  3879. } else if (BiosType == APM_NEUTRAL) {
  3880. ChkPrintEx(("syssetup: DecideNtApm: return NTAPM_INST_DISABLED\n"));
  3881. return NTAPM_INST_DISABLED;
  3882. } else {
  3883. ChkPrintEx(("syssetup: DecideNtApm: return NTAPM_NOWORK\n"));
  3884. return NTAPM_NOWORK;
  3885. }
  3886. }
  3887. DWORD
  3888. InstallNtApm(
  3889. IN HDEVINFO DevInfoHandle,
  3890. IN BOOLEAN InstallDisabled
  3891. )
  3892. /*++
  3893. Routine Description:
  3894. This function installs the composite battery if it hasn't already been
  3895. installed.
  3896. Arguments:
  3897. DevInfoHandle - Handle to a device information set
  3898. InstallDisabled - TRUE if caller wants us to install disabled
  3899. Return Value:
  3900. --*/
  3901. {
  3902. DWORD status;
  3903. SP_DRVINFO_DATA driverInfoData;
  3904. TCHAR tmpBuffer[100];
  3905. DWORD bufferLen;
  3906. PSP_DEVINFO_DATA DevInfoData;
  3907. SP_DEVINSTALL_PARAMS DevInstallParams;
  3908. ChkPrintEx(("syssetup: InstallNtApm: DevInfoHandle = %08lx installdisabled = %08lx\n", DevInfoHandle, InstallDisabled));
  3909. DevInfoData = LocalAlloc(LPTR, sizeof(SP_DEVINFO_DATA));
  3910. if ( ! DevInfoData) {
  3911. status = GetLastError();
  3912. goto clean0;
  3913. }
  3914. DevInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
  3915. DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  3916. //
  3917. // Attempt to manufacture a new device information element for the root enumerated
  3918. // ntapm device.
  3919. //
  3920. if(!SetupDiCreateDeviceInfo(DevInfoHandle,
  3921. TEXT("ROOT\\NTAPM\\0000"),
  3922. (LPGUID)&GUID_DEVCLASS_APMSUPPORT,
  3923. TEXT("NT Apm Legacy Support"),
  3924. NULL,
  3925. 0,
  3926. DevInfoData))
  3927. {
  3928. status = GetLastError();
  3929. if (status == ERROR_DEVINST_ALREADY_EXISTS) {
  3930. //
  3931. // NtApm is already installed.
  3932. //
  3933. ChkPrintEx(("ntapm Already Installed\n"));
  3934. status = ERROR_SUCCESS;
  3935. goto clean1;
  3936. } else {
  3937. ChkPrintEx(("Error creating ntapm devinfo - %x\n", status));
  3938. goto clean1;
  3939. }
  3940. }
  3941. //
  3942. // Set device to Install Disabled if the caller wants that
  3943. //
  3944. if (InstallDisabled) {
  3945. if (!SetupDiGetDeviceInstallParams(DevInfoHandle, DevInfoData, &DevInstallParams)) {
  3946. status = GetLastError();
  3947. goto clean1;
  3948. }
  3949. DevInstallParams.Flags |= DI_INSTALLDISABLED;
  3950. if (!SetupDiSetDeviceInstallParams(DevInfoHandle, DevInfoData, &DevInstallParams)) {
  3951. status = GetLastError();
  3952. goto clean1;
  3953. }
  3954. }
  3955. //
  3956. // Register the device so it is not a phantom anymore
  3957. //
  3958. if (!SetupDiRegisterDeviceInfo(DevInfoHandle, DevInfoData, 0, NULL, NULL, NULL)) {
  3959. status = GetLastError();
  3960. SetupDebugPrint1(L"Couldn't register device - %x\n", status);
  3961. goto clean3;
  3962. }
  3963. //
  3964. // Set the hardware ID. "NTAPM"
  3965. //
  3966. memset (tmpBuffer, 0, sizeof(tmpBuffer));
  3967. StringCchCopy (tmpBuffer, SIZECHARS(tmpBuffer), TEXT("NTAPM"));
  3968. bufferLen = (lstrlen(tmpBuffer) + 1) * sizeof(TCHAR);
  3969. //SetupDebugPrint2(L"tmpBuffer - %ws\n with strlen = %x\n", tmpBuffer, bufferLen);
  3970. //SetupDebugPrint1(L"tmpBuffer@ = %08lx\n", tmpBuffer);
  3971. status = SetupDiSetDeviceRegistryProperty (
  3972. DevInfoHandle,
  3973. DevInfoData,
  3974. SPDRP_HARDWAREID,
  3975. (PBYTE)tmpBuffer,
  3976. bufferLen
  3977. );
  3978. if (!status) {
  3979. status = GetLastError();
  3980. //SetupDebugPrint1(L"Couldn't set the HardwareID - %x\n", status);
  3981. goto clean3;
  3982. }
  3983. //
  3984. // Build a compatible driver list for this new device...
  3985. //
  3986. if(!SetupDiBuildDriverInfoList(DevInfoHandle, DevInfoData, SPDIT_COMPATDRIVER)) {
  3987. status = GetLastError();
  3988. //SetupDebugPrint1(L"Couldn't build class driver list - %x\n", status);
  3989. goto clean3;
  3990. }
  3991. //
  3992. // Select the first driver in the list as this will be the most compatible
  3993. //
  3994. driverInfoData.cbSize = sizeof (SP_DRVINFO_DATA);
  3995. if (!SetupDiEnumDriverInfo(DevInfoHandle, DevInfoData, SPDIT_COMPATDRIVER, 0, &driverInfoData)) {
  3996. status = GetLastError();
  3997. //SetupDebugPrint1(L"Couldn't get driver list - %x\n", status);
  3998. goto clean3;
  3999. } else {
  4000. //SetupDebugPrint4(L"Driver info - \n"
  4001. // L"------------- DriverType %x\n"
  4002. // L"------------- Description %s\n"
  4003. // L"------------- MfgName %s\n"
  4004. // L"------------- ProviderName %s\n\n",
  4005. // driverInfoData.DriverType,
  4006. // driverInfoData.Description,
  4007. // driverInfoData.MfgName,
  4008. // driverInfoData.ProviderName);
  4009. if (!SetupDiSetSelectedDriver(DevInfoHandle, DevInfoData, &driverInfoData)) {
  4010. status = GetLastError();
  4011. //SetupDebugPrint1(L"Couldn't select driver - %x\n", status);
  4012. goto clean3;
  4013. }
  4014. }
  4015. if (!SetupDiInstallDevice (DevInfoHandle, DevInfoData)) {
  4016. status = GetLastError();
  4017. //SetupDebugPrint1(L"Couldn't install device - %x\n", status);
  4018. goto clean3;
  4019. }
  4020. //
  4021. // If we got here we were successful
  4022. //
  4023. status = ERROR_SUCCESS;
  4024. SetLastError (status);
  4025. goto clean1;
  4026. clean3:
  4027. SetupDiDeleteDeviceInfo (DevInfoHandle, DevInfoData);
  4028. clean1:
  4029. LocalFree (DevInfoData);
  4030. clean0:
  4031. return status;
  4032. }
  4033. DWORD
  4034. AllowInstallNtApm(
  4035. IN HDEVINFO DevInfoHandle,
  4036. IN PSP_DEVINFO_DATA DevInfoData OPTIONAL
  4037. )
  4038. /*++
  4039. Routine Description:
  4040. This function decides whether to allow install (which will do
  4041. an enabled install at least in the upgrade case) or force
  4042. an install disbled.
  4043. Arguments:
  4044. DevInfoHandle - Handle to a device information set
  4045. DeviceInfoData - Optionally, supplies the address of a device information
  4046. element being acted upon by this install action.
  4047. N.B. If this is null, we have a problem.
  4048. Return Value:
  4049. status.
  4050. --*/
  4051. {
  4052. ULONG DevStatus;
  4053. ULONG DevProblem;
  4054. SP_DEVINSTALL_PARAMS DevInstallParams = {0};
  4055. CONFIGRET Result;
  4056. ChkPrintEx(("syssetup: AllowInstallNtApm: entered\n"));
  4057. if ( ! IsProductTypeApmLegal()) {
  4058. // it's not a workstation, so disallow install
  4059. ChkPrintEx(("syssetup: AllowInstallNtApm #0: not a work station => return ERROR_DI_DONT_INSTALL\n"));
  4060. return ERROR_DI_DONT_INSTALL;
  4061. }
  4062. if (! DevInfoData) {
  4063. //
  4064. // If DevInfoData is null, we don't actually know
  4065. // what is going on, so say "OK" and hope for the best
  4066. //
  4067. ChkPrintEx(("sysetup: AllowInstallNtApm #1: no DevInfoData => return ERROR_DI_DO_DEFAULT\n"));
  4068. return ERROR_DI_DO_DEFAULT;
  4069. }
  4070. //
  4071. // Call the CM and ask it what it knows about this devinst
  4072. //
  4073. Result = CM_Get_DevNode_Status(&DevStatus, &DevProblem, DevInfoData->DevInst, 0);
  4074. ChkPrintEx(("syssetup: AllowInstallNtApm #2: DevStatus = %08lx\n", DevStatus));
  4075. ChkPrintEx(("syssetup: AllowInstallNtApm #3: DevProblem = %08lx\n", DevProblem));
  4076. if (Result != CR_SUCCESS) {
  4077. ChkPrintEx(("syssetup: AllowInstallNtApm #4: return ERROR_DI_DONT_INSTALL\n"));
  4078. return ERROR_DI_DONT_INSTALL;
  4079. }
  4080. if (DevStatus & DN_HAS_PROBLEM) {
  4081. if (DevProblem == CM_PROB_DISABLED) {
  4082. //
  4083. // it's supposed to be disabled
  4084. //
  4085. DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  4086. if (!SetupDiGetDeviceInstallParams(DevInfoHandle, DevInfoData, &DevInstallParams)) {
  4087. ChkPrintEx(("syssetup: AllowInstallNtApm #5: return ERROR_DI_DONT_INSTALL\n"));
  4088. return ERROR_DI_DONT_INSTALL;
  4089. }
  4090. DevInstallParams.Flags |= DI_INSTALLDISABLED;
  4091. if (!SetupDiSetDeviceInstallParams(DevInfoHandle, DevInfoData, &DevInstallParams)) {
  4092. ChkPrintEx(("syssetup: AllowInstallNtApm #6: return ERROR_DI_DONT_INSTALL\n"));
  4093. return ERROR_DI_DONT_INSTALL;
  4094. }
  4095. }
  4096. }
  4097. ChkPrintEx(("syssetup: AllowInstallNtApm #7: return ERROR_DI_DO_DEFAULT\n"));
  4098. return ERROR_DI_DO_DEFAULT;
  4099. }
  4100. BOOL
  4101. IsProductTypeApmLegal()
  4102. /*++
  4103. Routine Description:
  4104. Determines if we are running on workstation (win2000 pro) or not.
  4105. If we are, return TRUE. else return FALSE.
  4106. This is used to overcome weirdness in setup AND to prevent people from
  4107. getting themselves into trouble by allowing apm to run on a server.
  4108. Return Value:
  4109. TRUE - it's workstation, it's OK to run APM
  4110. FALSE - it's server, DON'T let APM run
  4111. --*/
  4112. {
  4113. OSVERSIONINFOEX OsVersionInfo;
  4114. OsVersionInfo.dwOSVersionInfoSize = sizeof(OsVersionInfo);
  4115. if (!GetVersionEx((OSVERSIONINFO *) &OsVersionInfo)) {
  4116. ChkPrintEx(("GetVersionEx failed, return server (FALSE)\n"));
  4117. return FALSE;
  4118. }
  4119. if (OsVersionInfo.wProductType == VER_NT_WORKSTATION) {
  4120. return TRUE;
  4121. }
  4122. return FALSE;
  4123. }
  4124. //
  4125. // Ideally these would be defined in a header file somewhere,
  4126. // but that's hard to do becuase they are set up in an INF.
  4127. // SO - simply be sure that they match up with these lines in
  4128. // biosinfo.inf:
  4129. //
  4130. // For KNOWN_BAD:
  4131. // [DisableApmAddReg]
  4132. // HKLM,System\CurrentControlSet\Control\Biosinfo\APM,Attributes,0x00010001,00000002
  4133. //
  4134. // For KNOWN_GOOD:
  4135. // [AutoEnableApmAddReg]
  4136. // HKLM,System\CurrentControlSet\Control\Biosinfo\APM,Attributes,0x00010001,00000001
  4137. //
  4138. #define APM_BIOS_KNOWN_GOOD 0x00000001
  4139. #define APM_BIOS_KNOWN_BAD 0x00000002
  4140. DWORD
  4141. IsApmPresent()
  4142. /*++
  4143. Routine Description:
  4144. IsApmPresent runs the same code as ntapm.sys does to decide
  4145. if ntdetect has found and reported a usable APM bios.
  4146. It then checks to see what, if any, bios lists this machine
  4147. and bios are one.
  4148. It factors this data together to report the existence/non-existence
  4149. of apm on the machine, and its usability and suitability.
  4150. Return Value:
  4151. APM_NOT_PRESENT - apm does not appear to be present on this machine
  4152. APM_PRESENT_BUT_NOT_USABLE - there appears to be an apm bios, but
  4153. it did not allow connection correctly (version or api support problem)
  4154. APM_ON_GOOD_LIST - there is a bios and it's on the good bios list
  4155. APM_NEUTRAL - there is a bios, it appears to be usable,
  4156. it is not on the good bios list, but it's also not
  4157. on the bad bios list.
  4158. APM_ON_BAD_LIST - there is a bios, but it's on the bad bios list.
  4159. --*/
  4160. {
  4161. //
  4162. // first part of this code is copied from ...\ntos\dd\ntapm\i386\apm.c
  4163. // keep it in sync with that code
  4164. //
  4165. UNICODE_STRING unicodeString, ConfigName, IdentName;
  4166. OBJECT_ATTRIBUTES objectAttributes;
  4167. HANDLE hMFunc, hBus, hGoodBad;
  4168. NTSTATUS status;
  4169. PCM_PARTIAL_RESOURCE_DESCRIPTOR PDesc;
  4170. PCM_FULL_RESOURCE_DESCRIPTOR Desc;
  4171. PKEY_VALUE_FULL_INFORMATION ValueInfo;
  4172. PKEY_VALUE_PARTIAL_INFORMATION pvpi;
  4173. PAPM_REGISTRY_INFO ApmEntry;
  4174. UCHAR buffer [sizeof(APM_REGISTRY_INFO) + 99];
  4175. WCHAR wstr[8];
  4176. ULONG i, junk;
  4177. PWSTR p;
  4178. PULONG pdw;
  4179. DWORD BiosType;
  4180. // ----------------------------------------------------------------------
  4181. //
  4182. // First Part - See if ntdetect.com found APM....
  4183. //
  4184. // ----------------------------------------------------------------------
  4185. //
  4186. // Look in the registery for the "APM bus" data
  4187. //
  4188. RtlInitUnicodeString(&unicodeString, rgzMultiFunctionAdapter);
  4189. InitializeObjectAttributes(
  4190. &objectAttributes,
  4191. &unicodeString,
  4192. OBJ_CASE_INSENSITIVE,
  4193. NULL, // handle
  4194. NULL
  4195. );
  4196. status = NtOpenKey(&hMFunc, KEY_READ, &objectAttributes);
  4197. if (!NT_SUCCESS(status)) {
  4198. return APM_NOT_PRESENT;
  4199. }
  4200. unicodeString.Buffer = wstr;
  4201. unicodeString.MaximumLength = sizeof (wstr);
  4202. RtlInitUnicodeString(&ConfigName, rgzConfigurationData);
  4203. RtlInitUnicodeString(&IdentName, rgzIdentifier);
  4204. ValueInfo = (PKEY_VALUE_FULL_INFORMATION) buffer;
  4205. for (i=0;; i++) {
  4206. RtlIntegerToUnicodeString(i, 10, &unicodeString);
  4207. InitializeObjectAttributes(
  4208. &objectAttributes,
  4209. &unicodeString,
  4210. OBJ_CASE_INSENSITIVE,
  4211. hMFunc,
  4212. NULL
  4213. );
  4214. status = NtOpenKey(&hBus, KEY_READ, &objectAttributes);
  4215. if (!NT_SUCCESS(status)) {
  4216. //
  4217. // Out of Multifunction adapter entries...
  4218. //
  4219. NtClose(hMFunc);
  4220. return APM_NOT_PRESENT;
  4221. }
  4222. //
  4223. // Check the Indentifier to see if this is a APM entry
  4224. //
  4225. status = NtQueryValueKey (
  4226. hBus,
  4227. &IdentName,
  4228. KeyValueFullInformation,
  4229. ValueInfo,
  4230. sizeof (buffer),
  4231. &junk
  4232. );
  4233. if (!NT_SUCCESS (status)) {
  4234. NtClose(hBus);
  4235. continue;
  4236. }
  4237. p = (PWSTR) ((PUCHAR) ValueInfo + ValueInfo->DataOffset);
  4238. if (p[0] != L'A' || p[1] != L'P' || p[2] != L'M' || p[3] != 0) {
  4239. NtClose (hBus);
  4240. continue;
  4241. }
  4242. status = NtQueryValueKey(
  4243. hBus,
  4244. &ConfigName,
  4245. KeyValueFullInformation,
  4246. ValueInfo,
  4247. sizeof (buffer),
  4248. &junk
  4249. );
  4250. NtClose(hBus);
  4251. if (!NT_SUCCESS(status)) {
  4252. continue ;
  4253. }
  4254. Desc = (PCM_FULL_RESOURCE_DESCRIPTOR) ((PUCHAR)
  4255. ValueInfo + ValueInfo->DataOffset);
  4256. PDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)
  4257. Desc->PartialResourceList.PartialDescriptors);
  4258. if (PDesc->Type == CmResourceTypeDeviceSpecific) {
  4259. // got it..
  4260. ApmEntry = (PAPM_REGISTRY_INFO) (PDesc+1);
  4261. break;
  4262. }
  4263. }
  4264. NtClose(hMFunc);
  4265. if ( (ApmEntry->Signature[0] != 'A') ||
  4266. (ApmEntry->Signature[1] != 'P') ||
  4267. (ApmEntry->Signature[2] != 'M') )
  4268. {
  4269. return APM_NOT_PRESENT;
  4270. }
  4271. if (ApmEntry->Valid != 1) {
  4272. return APM_PRESENT_BUT_NOT_USABLE;
  4273. }
  4274. // --------------------------------------------------------------------
  4275. //
  4276. // Second Part - what sort of APM bios is it?
  4277. //
  4278. // --------------------------------------------------------------------
  4279. //
  4280. // If we get this far, then we think there is an APM bios present
  4281. // on the machine, and ntdetect thinks it's usable.
  4282. // This means we found it, and it has a version we like, and claims
  4283. // to support the interfaces we like.
  4284. // But we still don't know if its good, bad, or neutral.
  4285. // Find Out.
  4286. //
  4287. //
  4288. // The machine/bios good/bad list code will leave a flag in the
  4289. // registry for us to check to see if it is a known good or known bad
  4290. // apm bios.
  4291. //
  4292. RtlInitUnicodeString(&unicodeString, rgzGoodBadKey);
  4293. InitializeObjectAttributes(
  4294. &objectAttributes,
  4295. &unicodeString,
  4296. OBJ_CASE_INSENSITIVE,
  4297. NULL,
  4298. NULL
  4299. );
  4300. status = NtOpenKey(&hGoodBad, KEY_READ, &objectAttributes);
  4301. if (! NT_SUCCESS(status)) {
  4302. return APM_NEUTRAL;
  4303. }
  4304. RtlInitUnicodeString(&IdentName, rgzGoodBadValue);
  4305. pvpi = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
  4306. status = NtQueryValueKey(
  4307. hGoodBad,
  4308. &IdentName,
  4309. KeyValuePartialInformation,
  4310. pvpi,
  4311. sizeof(buffer),
  4312. &junk
  4313. );
  4314. NtClose(hGoodBad);
  4315. if ( (NT_SUCCESS(status)) &&
  4316. (pvpi->Type == REG_DWORD) &&
  4317. (pvpi->DataLength == sizeof(ULONG)) )
  4318. {
  4319. pdw = (PULONG)&(pvpi->Data[0]);
  4320. BiosType = *pdw;
  4321. } else {
  4322. return APM_NEUTRAL;
  4323. }
  4324. if (BiosType & APM_BIOS_KNOWN_GOOD) {
  4325. return APM_ON_GOOD_LIST;
  4326. } else if (BiosType & APM_BIOS_KNOWN_BAD) {
  4327. return APM_ON_BAD_LIST;
  4328. } else {
  4329. return APM_NEUTRAL;
  4330. }
  4331. }
  4332. BOOL
  4333. IsAcpiMachine(
  4334. VOID
  4335. )
  4336. /*++
  4337. Routine Description:
  4338. IsAcpiMachine reports whether the OS thinks this is an ACPI
  4339. machine or not.
  4340. Return Value:
  4341. FALSE - this is NOT an acpi machine
  4342. TRUE - this IS an acpi machine
  4343. --*/
  4344. {
  4345. UNICODE_STRING unicodeString;
  4346. OBJECT_ATTRIBUTES objectAttributes;
  4347. HANDLE hKey;
  4348. NTSTATUS status;
  4349. PKEY_VALUE_PARTIAL_INFORMATION pvpi;
  4350. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(DWORD)+1];
  4351. ULONG junk;
  4352. PULONG pdw;
  4353. ChkPrintEx(("syssetup: IsAcpiMachine: entered\n"));
  4354. RtlInitUnicodeString(&unicodeString, rgzAcpiKey);
  4355. InitializeObjectAttributes(
  4356. &objectAttributes,
  4357. &unicodeString,
  4358. OBJ_CASE_INSENSITIVE,
  4359. NULL,
  4360. NULL
  4361. );
  4362. status = NtOpenKey(&hKey, KEY_READ, &objectAttributes);
  4363. if (!NT_SUCCESS(status)) {
  4364. ChkPrintEx(("syssetup: IsAcpiMachine: returning FALSE, no key\n"));
  4365. return FALSE;
  4366. }
  4367. RtlInitUnicodeString(&unicodeString, rgzAcpiCount);
  4368. pvpi = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
  4369. status = NtQueryValueKey(
  4370. hKey,
  4371. &unicodeString,
  4372. KeyValuePartialInformation,
  4373. pvpi,
  4374. sizeof(buffer),
  4375. &junk
  4376. );
  4377. if ( (NT_SUCCESS(status)) &&
  4378. (pvpi->Type == REG_DWORD) &&
  4379. (pvpi->DataLength == sizeof(ULONG)) )
  4380. {
  4381. pdw = (PULONG)&(pvpi->Data[0]);
  4382. if (*pdw) {
  4383. NtClose(hKey);
  4384. ChkPrintEx(("syssetup: IsAcpiMachine: returning TRUE\n"));
  4385. return TRUE;
  4386. }
  4387. }
  4388. NtClose(hKey);
  4389. ChkPrintEx(("syssetup: IsAcpiMachine: returning FALSE, no match\n"));
  4390. return FALSE;
  4391. }
  4392. BOOL
  4393. IsApmLegalHalMachine(
  4394. VOID
  4395. )
  4396. /*++
  4397. Routine Description:
  4398. IsApmLegalHalMachine reports whether setup claims to have
  4399. installed the standard halx86 Hal that APM requires to function.
  4400. Return Value:
  4401. TRUE - this IS an ApmLegalHal machine, apm install may proceed.
  4402. FALSE - this is NOT an ApmLegalHal machine, do not install APM.
  4403. --*/
  4404. {
  4405. UNICODE_STRING unicodeString;
  4406. OBJECT_ATTRIBUTES objectAttributes;
  4407. HANDLE hKey;
  4408. NTSTATUS status;
  4409. PKEY_VALUE_PARTIAL_INFORMATION pvpi;
  4410. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION)+sizeof(DWORD)+1];
  4411. ULONG junk;
  4412. PULONG pdw;
  4413. ChkPrintEx(("syssetup: IsApmLegalHalMAchine: entered\n"));
  4414. RtlInitUnicodeString(&unicodeString, rgzApmLegalHalKey);
  4415. InitializeObjectAttributes(
  4416. &objectAttributes,
  4417. &unicodeString,
  4418. OBJ_CASE_INSENSITIVE,
  4419. NULL,
  4420. NULL
  4421. );
  4422. status = NtOpenKey(&hKey, KEY_READ, &objectAttributes);
  4423. if (!NT_SUCCESS(status)) {
  4424. ChkPrintEx(("syssetup: IsApmLegalHalMAchine: returning FALSE, no key\n"));
  4425. return FALSE;
  4426. }
  4427. RtlInitUnicodeString(&unicodeString, rgzApmHalPresent);
  4428. pvpi = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
  4429. status = NtQueryValueKey(
  4430. hKey,
  4431. &unicodeString,
  4432. KeyValuePartialInformation,
  4433. pvpi,
  4434. sizeof(buffer),
  4435. &junk
  4436. );
  4437. if ( (NT_SUCCESS(status)) &&
  4438. (pvpi->Type == REG_DWORD) &&
  4439. (pvpi->DataLength == sizeof(ULONG)) )
  4440. {
  4441. pdw = (PULONG)&(pvpi->Data[0]);
  4442. if (*pdw == 1) {
  4443. NtClose(hKey);
  4444. ChkPrintEx(("syssetup: IsApmLegalHalMAchine: returning TRUE\n"));
  4445. return TRUE;
  4446. }
  4447. }
  4448. NtClose(hKey);
  4449. ChkPrintEx(("syssetup: IsApmLegalHalMAchine: returning FALSE, no match\n"));
  4450. return FALSE;
  4451. }
  4452. typedef
  4453. BOOL
  4454. (*PRESTART_DEVICE) (
  4455. IN HDEVINFO DeviceInfoSet,
  4456. IN PSP_DEVINFO_DATA DeviceInfoData
  4457. );
  4458. BOOL
  4459. IsUSBController(
  4460. IN HDEVINFO DeviceInfoSet,
  4461. IN PSP_DEVINFO_DATA DeviceInfoData
  4462. )
  4463. {
  4464. HKEY hKey;
  4465. TCHAR szController[] = TEXT("Controller");
  4466. DWORD dwType, dwSize;
  4467. BYTE data;
  4468. hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
  4469. DeviceInfoData,
  4470. DICS_FLAG_GLOBAL,
  4471. 0,
  4472. DIREG_DRV,
  4473. KEY_READ);
  4474. //
  4475. // Check for a REG_BINARY (1-byte) 'Controller' value entry set to 0.
  4476. //
  4477. dwSize = sizeof(data);
  4478. if (RegQueryValueEx(hKey,
  4479. szController,
  4480. NULL,
  4481. &dwType,
  4482. &data,
  4483. &dwSize) != ERROR_SUCCESS ||
  4484. dwSize != sizeof(BYTE) ||
  4485. dwType != REG_BINARY) {
  4486. data = 0;
  4487. }
  4488. RegCloseKey(hKey);
  4489. return data;
  4490. }
  4491. void
  4492. DeviceBayRestartDevices(
  4493. CONST GUID * Guid,
  4494. PRESTART_DEVICE RestartDevice
  4495. )
  4496. {
  4497. HDEVINFO hDevInfo;
  4498. SP_DEVINFO_DATA did;
  4499. SP_DEVINSTALL_PARAMS dip;
  4500. int i;
  4501. hDevInfo = SetupDiGetClassDevs(Guid, NULL, NULL, 0);
  4502. if (hDevInfo != INVALID_HANDLE_VALUE) {
  4503. ZeroMemory(&did, sizeof(SP_DEVINFO_DATA));
  4504. did.cbSize = sizeof(SP_DEVINFO_DATA);
  4505. for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &did); i++) {
  4506. if (!RestartDevice || RestartDevice(hDevInfo, &did)) {
  4507. //
  4508. // restart the controller so that the filter driver is in
  4509. // place
  4510. //
  4511. ZeroMemory(&dip, sizeof(SP_DEVINSTALL_PARAMS));
  4512. dip.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  4513. if (SetupDiGetDeviceInstallParams(hDevInfo, &did, &dip)) {
  4514. dip.Flags |= DI_PROPERTIES_CHANGE;
  4515. SetupDiSetDeviceInstallParams(hDevInfo, &did, &dip);
  4516. }
  4517. }
  4518. }
  4519. SetupDiDestroyDeviceInfoList(hDevInfo);
  4520. }
  4521. }
  4522. BOOLEAN
  4523. AddDeviceBayFilter(
  4524. HKEY ClassKey
  4525. )
  4526. {
  4527. DWORD dwType, dwSize;
  4528. ULONG res,
  4529. filterLength,
  4530. length;
  4531. BOOLEAN added = FALSE,
  4532. addFilter;
  4533. TCHAR szFilter[] = TEXT("dbfilter\0");
  4534. PTCHAR szCurrentFilter, szOffset, szUpperFilters;
  4535. filterLength = lstrlen(szFilter);
  4536. dwSize = 0;
  4537. res = RegQueryValueEx(ClassKey,
  4538. REGSTR_VAL_UPPERFILTERS,
  4539. NULL,
  4540. &dwType,
  4541. NULL,
  4542. &dwSize);
  4543. if (res == ERROR_FILE_NOT_FOUND || dwType != REG_MULTI_SZ) {
  4544. //
  4545. // Value isn't there,
  4546. //
  4547. RegSetValueEx(ClassKey,
  4548. REGSTR_VAL_UPPERFILTERS,
  4549. 0,
  4550. REG_MULTI_SZ,
  4551. (PBYTE) szFilter,
  4552. (filterLength + 2) * sizeof(TCHAR) );
  4553. added = TRUE;
  4554. }
  4555. else if (res == ERROR_SUCCESS) {
  4556. szUpperFilters = (PTCHAR)
  4557. LocalAlloc(LPTR, dwSize + (filterLength + 1) * sizeof(TCHAR));
  4558. if (!szUpperFilters) {
  4559. return FALSE;
  4560. }
  4561. szOffset = szUpperFilters + filterLength + 1;
  4562. res = RegQueryValueEx(ClassKey,
  4563. REGSTR_VAL_UPPERFILTERS,
  4564. NULL,
  4565. &dwType,
  4566. (PBYTE) szOffset,
  4567. &dwSize);
  4568. if (res == ERROR_SUCCESS) {
  4569. addFilter = TRUE;
  4570. for (szCurrentFilter = szOffset; *szCurrentFilter; ) {
  4571. length = lstrlen(szCurrentFilter);
  4572. if (lstrcmpi(szFilter, szCurrentFilter) == 0) {
  4573. addFilter = FALSE;
  4574. break;
  4575. }
  4576. szCurrentFilter += (length + 1);
  4577. }
  4578. if (addFilter) {
  4579. length = (filterLength + 1) * sizeof(TCHAR);
  4580. memcpy(szUpperFilters, szFilter, length);
  4581. dwSize += length;
  4582. res = RegSetValueEx(ClassKey,
  4583. REGSTR_VAL_UPPERFILTERS,
  4584. 0,
  4585. REG_MULTI_SZ,
  4586. (PBYTE) szUpperFilters,
  4587. dwSize);
  4588. added = (BOOLEAN)(res == ERROR_SUCCESS);
  4589. }
  4590. }
  4591. LocalFree(szUpperFilters);
  4592. }
  4593. return added;
  4594. }
  4595. DWORD
  4596. DeviceBayClassInstaller(
  4597. IN DI_FUNCTION InstallFunction,
  4598. IN HDEVINFO DeviceInfoSet,
  4599. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  4600. )
  4601. /*++
  4602. Routine Description:
  4603. This routine is the class installer function for storage volumes.
  4604. Arguments:
  4605. InstallFunction - Supplies the install function.
  4606. DeviceInfoSet - Supplies the device info set.
  4607. DeviceInfoData - Supplies the device info data.
  4608. Return Value:
  4609. If this function successfully completed the requested action, the return
  4610. value is NO_ERROR.
  4611. If the default behavior is to be performed for the requested action, the
  4612. return value is ERROR_DI_DO_DEFAULT.
  4613. If an error occurred while attempting to perform the requested action, a
  4614. Win32 error code is returned.
  4615. --*/
  4616. {
  4617. HKEY hKeyClass;
  4618. switch (InstallFunction) {
  4619. case DIF_INSTALLDEVICE:
  4620. if (!SetupDiInstallDevice(DeviceInfoSet, DeviceInfoData)) {
  4621. return GetLastError();
  4622. }
  4623. hKeyClass = SetupDiOpenClassRegKey(&GUID_DEVCLASS_USB, KEY_ALL_ACCESS);
  4624. if (hKeyClass != INVALID_HANDLE_VALUE) {
  4625. if (AddDeviceBayFilter(hKeyClass)) {
  4626. //
  4627. // Restart all the USB devices
  4628. //
  4629. DeviceBayRestartDevices(&GUID_DEVCLASS_USB,
  4630. IsUSBController);
  4631. }
  4632. RegCloseKey(hKeyClass);
  4633. }
  4634. hKeyClass = SetupDiOpenClassRegKey(&GUID_DEVCLASS_1394, KEY_ALL_ACCESS);
  4635. if (hKeyClass != INVALID_HANDLE_VALUE) {
  4636. if (AddDeviceBayFilter(hKeyClass)) {
  4637. //
  4638. // Restart all the 1394 controllers
  4639. //
  4640. DeviceBayRestartDevices(&GUID_DEVCLASS_1394, NULL);
  4641. }
  4642. RegCloseKey(hKeyClass);
  4643. }
  4644. //
  4645. // We might want to do something with the friendly name in the future...
  4646. //
  4647. return NO_ERROR;
  4648. }
  4649. return ERROR_DI_DO_DEFAULT;
  4650. }
  4651. DWORD
  4652. EisaUpHalCoInstaller(
  4653. IN DI_FUNCTION InstallFunction,
  4654. IN HDEVINFO DeviceInfoSet,
  4655. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL,
  4656. IN OUT PCOINSTALLER_CONTEXT_DATA Context
  4657. )
  4658. {
  4659. #if defined(_AMD64_) || defined(_X86_)
  4660. return PciHalCoInstaller(InstallFunction, DeviceInfoSet, DeviceInfoData, Context);
  4661. #else
  4662. return NO_ERROR;
  4663. #endif
  4664. }
  4665. DWORD
  4666. ComputerClassInstaller(
  4667. IN DI_FUNCTION InstallFunction,
  4668. IN HDEVINFO DeviceInfoSet,
  4669. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  4670. )
  4671. /*++
  4672. Routine Description:
  4673. This routine acts as the class installer for Computer class (HAL) devices.
  4674. Arguments:
  4675. InstallFunction - Specifies the device installer function code indicating
  4676. the action being performed.
  4677. DeviceInfoSet - Supplies a handle to the device information set being
  4678. acted upon by this install action.
  4679. DeviceInfoData - Optionally, supplies the address of a device information
  4680. element being acted upon by this install action.
  4681. Return Value:
  4682. If this function successfully completed the requested action, the return
  4683. value is NO_ERROR.
  4684. If the default behavior is to be performed for the requested action, the
  4685. return value is ERROR_DI_DO_DEFAULT.
  4686. If an error occurred while attempting to perform the requested action, a
  4687. Win32 error code is returned.
  4688. --*/
  4689. {
  4690. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  4691. switch(InstallFunction) {
  4692. case DIF_SELECTDEVICE:
  4693. DeviceInstallParams.cbSize = sizeof(DeviceInstallParams);
  4694. if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
  4695. DeviceInfoData,
  4696. &DeviceInstallParams
  4697. )) {
  4698. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_FILTERSIMILARDRIVERS;
  4699. SetupDiSetDeviceInstallParams(DeviceInfoSet,
  4700. DeviceInfoData,
  4701. &DeviceInstallParams
  4702. );
  4703. }
  4704. //
  4705. // We are not returning an error here because we want to break out and
  4706. // return ERROR_DI_DO_DEFAULT.
  4707. //
  4708. break;
  4709. }
  4710. return ERROR_DI_DO_DEFAULT;
  4711. }