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

3301 lines
105 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1999.
  5. //
  6. // File: C L A S S I N S T . C P P
  7. //
  8. // Contents: Defines the interface between the binding engine and the
  9. // network class installer.
  10. //
  11. // Notes:
  12. //
  13. // Author: billbe 15 Jan 1999
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.h>
  17. #pragma hdrstop
  18. #include "adapter.h"
  19. #include "benchmrk.h"
  20. #include "classinst.h"
  21. #include "filtdev.h"
  22. #include "netcfg.h"
  23. #include "iatl.h"
  24. #include "lockdown.h"
  25. #include "ncatl.h"
  26. #include "ncoc.h"
  27. #include "ncreg.h"
  28. #include "ncsetup.h"
  29. #include "ncui.h"
  30. #include "ncwins.h"
  31. #include "persist.h"
  32. #include "provider.h"
  33. #include "resource.h"
  34. #include "util.h"
  35. // HrRegisterNotificationDll functions
  36. enum ciRegisterDllFunction {CIRDF_REGISTER, CIRDF_UNREGISTER};
  37. //+--------------------------------------------------------------------------
  38. //
  39. // Function: HrCiRegDeleteComponentNetworkKey
  40. //
  41. // Purpose: This function deletes the component key strInstanceGuid
  42. // (and its subkeys) under the Network\<guidClass> tree.
  43. //
  44. // Arguments:
  45. // Class [in] The class of the component
  46. // pszInstanceGuid [in] The instance guid of the component
  47. //
  48. // Returns: HRESULT. S_OK if successful, an error code otherwise.
  49. //
  50. // Author: billbe 27 Apr 1997
  51. //
  52. // Notes:
  53. //
  54. HRESULT
  55. HrCiRegDeleteComponentNetworkKey (
  56. IN NETCLASS Class,
  57. IN PCWSTR pszInstanceGuid)
  58. {
  59. HRESULT hr = S_OK;
  60. HKEY hkeyClass = NULL;
  61. PCWSTR pszNetworkSubtreePath = MAP_NETCLASS_TO_NETWORK_SUBTREE[Class];
  62. // Open the proper class key in the Network tree
  63. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, pszNetworkSubtreePath,
  64. KEY_WRITE, &hkeyClass);
  65. // Delete the instance key tree
  66. //
  67. if (S_OK == hr)
  68. {
  69. hr = HrRegDeleteKeyTree(hkeyClass, pszInstanceGuid);
  70. RegSafeCloseKey(hkeyClass);
  71. }
  72. TraceHr (ttidError, FAL, hr, FALSE, "HrCiRegDeleteComponentKey");
  73. return hr;
  74. }
  75. //+--------------------------------------------------------------------------
  76. //
  77. // Function: HrCiRegisterNotificationDll
  78. //
  79. // Purpose: Registers or Unregisters a component's notification dll with
  80. // COM
  81. //
  82. // Arguments:
  83. // hkeyInstance [in] The handle to the instance key for the component
  84. // crdf [in] CIRDF_REGISTER if we are registering,
  85. // CIRDF_UNREGISTER if we are unregistering
  86. //
  87. // Returns: HRESULT. S_OK on if dll is successfully registered,
  88. // S_FALSE, if the component has no dll to
  89. // register, error code otherwise
  90. //
  91. // Author: billbe 23 Mar 1997
  92. //
  93. // Notes:
  94. //
  95. HRESULT
  96. HrCiRegisterNotificationDll(
  97. IN HKEY hkeyInstance,
  98. IN ciRegisterDllFunction crdf)
  99. {
  100. Assert(hkeyInstance);
  101. HKEY hkeyNdi;
  102. HRESULT hr;
  103. // Open the ndi key in the component's instance key so we can get the
  104. // Dll path.
  105. hr = HrRegOpenKeyEx (hkeyInstance, L"Ndi", KEY_READ, &hkeyNdi);
  106. if (S_OK == hr)
  107. {
  108. // Get the notification dll path
  109. tstring strDllPath;
  110. hr = HrRegQueryString (hkeyNdi, L"ComponentDLL", &strDllPath);
  111. if (S_OK == hr)
  112. {
  113. TraceTag (ttidClassInst,
  114. "Attempting to (un)register notification dll '%S'",
  115. strDllPath.c_str());
  116. hr = (CIRDF_REGISTER == crdf) ?
  117. HrRegisterComObject (strDllPath.c_str()) :
  118. HrUnregisterComObject (strDllPath.c_str());
  119. }
  120. else
  121. {
  122. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  123. {
  124. // The presence of the value is optional, so return
  125. // S_OK if it was not found
  126. hr = S_OK;
  127. }
  128. }
  129. RegCloseKey (hkeyNdi);
  130. }
  131. TraceHr (ttidError, FAL, hr, FALSE, "HrCiRegisterNotificationDll");
  132. return hr;
  133. }
  134. //+--------------------------------------------------------------------------
  135. //
  136. // Function: HrCiInstallServices
  137. //
  138. // Purpose: Processes any Inf service sections using strInfSection as a
  139. // base name
  140. //
  141. // Arguments:
  142. // hinfFile [in] A handle to the inf file
  143. // pszInfSection [in] The base section name
  144. //
  145. // Returns: HRESULT. S_OK if successful, error code otherwise
  146. //
  147. // Author: billbe 2 Apr 1997
  148. //
  149. // Notes: See SetupInstallServicesFromInfSection in SetupApi for more
  150. // info.
  151. //
  152. HRESULT
  153. HrCiInstallServices(
  154. IN HINF hinfFile,
  155. IN PCWSTR pszInfSection)
  156. {
  157. Assert (IsValidHandle(hinfFile));
  158. Assert (pszInfSection && *pszInfSection);
  159. BOOL fSuccess;
  160. WCHAR szServiceSection[_MAX_PATH];
  161. // append .Services to the section name
  162. //
  163. swprintf (szServiceSection, L"%s.%s", pszInfSection,
  164. INFSTR_SUBKEY_SERVICES);
  165. // Process the Services section
  166. fSuccess = SetupInstallServicesFromInfSection (hinfFile,
  167. szServiceSection, 0);
  168. if (!fSuccess)
  169. {
  170. // Since the section is optional, we can ignore
  171. // ERROR_SECTION_NOT_FOUND
  172. if (ERROR_SECTION_NOT_FOUND == GetLastError())
  173. {
  174. fSuccess = TRUE;
  175. }
  176. }
  177. // Any errors must be converted
  178. HRESULT hr = S_OK;
  179. if (!fSuccess)
  180. {
  181. hr = HrFromLastWin32Error();
  182. }
  183. TraceHr (ttidError, FAL, hr, FALSE,
  184. "HrCiInstallServices (%S)", szServiceSection);
  185. return hr;
  186. }
  187. //+--------------------------------------------------------------------------
  188. //
  189. // Function: HrCiInstallFromInfSection
  190. //
  191. // Purpose: A wrapper function for SetupInstallFromInfSection. This
  192. // function handles setting up the copy files process for
  193. // SetupInstallFromInfSection as well.
  194. //
  195. // Arguments:
  196. // hinfFile [in] A handle to the inf file to install from
  197. // pszInfSectionName [in] The section to install
  198. // hkeyRelative [in] The key that will be used as the section's
  199. // HKR
  200. // hwndParent [in] The HWND to the parent window, used for UI
  201. // dwInstallFlags [in] See SetupInstallFromInfSection for info on
  202. // these flags
  203. //
  204. // Returns: HRESULT. S_OK if successful, error code otherwise
  205. //
  206. // Author: billbe 4 Apr 1997
  207. //
  208. // Notes: See SetupApi documentation for more info on
  209. // SetupInstallFromInfSection and
  210. // SetupInstallFilesFromInfSection
  211. //
  212. HRESULT
  213. HrCiInstallFromInfSection(
  214. IN HINF hinfFile,
  215. IN PCWSTR pszInfSectionName,
  216. IN HKEY hkeyRelative,
  217. IN HWND hwndParent,
  218. IN DWORD dwInstallFlags)
  219. {
  220. Assert (IsValidHandle (hinfFile));
  221. Assert (pszInfSectionName && *pszInfSectionName);
  222. HRESULT hr = S_OK;
  223. if (dwInstallFlags & SPINST_FILES)
  224. {
  225. // The next three variables are used for SetupApi's copy files process
  226. PSP_FILE_CALLBACK pfc;
  227. PVOID pvCtx;
  228. HSPFILEQ hfq;
  229. // If the inf file has a layout entry in its version section
  230. // we need to append its information for proper locations
  231. // of any files we need to copy. If the call fails we can
  232. // still install, it just means the prompt for files will not
  233. // have the correct directory to begin with
  234. (VOID) SetupOpenAppendInfFile (NULL, hinfFile, NULL);
  235. // We need to create our own file queue so we can scan all the
  236. // files to be copied. Scanning before committing our queue will
  237. // prompt the user if the files already exist in the destination
  238. //
  239. hr = HrSetupOpenFileQueue (&hfq);
  240. if (S_OK == hr)
  241. {
  242. BOOL fInGuiModeSetup = FInSystemSetup();
  243. hr = HrSetupInstallFilesFromInfSection (hinfFile, NULL, hfq,
  244. pszInfSectionName, NULL, 0);
  245. // Set the default callback context
  246. // If the we are in system setup, we need to make sure the
  247. // callback doesn't display UI
  248. //
  249. if (S_OK == hr)
  250. {
  251. hr = HrSetupInitDefaultQueueCallbackEx (hwndParent,
  252. (fInGuiModeSetup ? (HWND)INVALID_HANDLE_VALUE : NULL),
  253. 0, 0, NULL, &pvCtx);
  254. if (S_OK == hr)
  255. {
  256. // Not doing anything special so use SetupApi default
  257. // handler for file copy.
  258. pfc = SetupDefaultQueueCallback;
  259. // Scan the queue to see if the files are already in the
  260. // destination and if so, prune them out.
  261. DWORD dwScanResult;
  262. hr = HrSetupScanFileQueueWithNoCallback (hfq,
  263. SPQ_SCAN_FILE_VALIDITY |
  264. SPQ_SCAN_PRUNE_COPY_QUEUE, hwndParent,
  265. &dwScanResult);
  266. // Now commit the queue so any files needing to be
  267. // copied, will be. If the scan result is 1 then there
  268. // is nothing to commit.
  269. //
  270. if ((S_OK == hr) && (1 != dwScanResult))
  271. {
  272. hr = HrSetupCommitFileQueue (hwndParent, hfq, pfc, pvCtx);
  273. }
  274. // We need to release the default context and close our
  275. // file queue
  276. //
  277. SetupTermDefaultQueueCallback (pvCtx);
  278. SetupCloseFileQueue (hfq);
  279. }
  280. }
  281. }
  282. }
  283. if ((S_OK == hr) && (dwInstallFlags & ~SPINST_FILES))
  284. {
  285. Assert (hkeyRelative);
  286. // Now we run all sections but CopyFiles
  287. hr = HrSetupInstallFromInfSection (hwndParent, hinfFile,
  288. pszInfSectionName, (dwInstallFlags & ~SPINST_FILES),
  289. hkeyRelative, NULL, 0, NULL, NULL, NULL, NULL);
  290. }
  291. TraceHr (ttidError, FAL, hr, HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr,
  292. "HrCiInstallFromInfSection");
  293. return hr;
  294. }
  295. //+--------------------------------------------------------------------------
  296. //
  297. // Function: HrCiDoCompleteSectionInstall
  298. //
  299. // Purpose: Runs all relevant sections of an inf file using strSection
  300. // as the base section name.
  301. //
  302. // Arguments:
  303. // hinfFile [in] SetupApi handle to an inf file
  304. // hkeyRelative [in] The registry key that will be the HKR
  305. // key during inf processing.
  306. // pszSection [in] Section name to install
  307. // hwndParent [in] The handle to the parent, for
  308. // displaying UI
  309. // fEnumerated [in] TRUE if this component is PnP enumerated
  310. // FALSE otherwise
  311. //
  312. // Returns: HRESULT. S_OK if sucessful, error code otherwise
  313. //
  314. // Author: billbe 15 Apr 1997
  315. //
  316. // Notes:
  317. //
  318. HRESULT
  319. HrCiDoCompleteSectionInstall(
  320. IN HINF hinfFile,
  321. IN HKEY hkeyRelative,
  322. IN PCWSTR pszSection,
  323. IN HWND hwndParent,
  324. IN BOOL fEnumerated)
  325. {
  326. Assert (IsValidHandle (hinfFile));
  327. Assert (FImplies (!fEnumerated, hkeyRelative));
  328. HRESULT hr = S_OK;
  329. // Only do this if there is a section name to work with
  330. if (pszSection && *pszSection)
  331. {
  332. // If this is an enumerated device, the service section and
  333. // the copy files section will be processed by the Device Installer
  334. // fcn SetupDiInstallDevice so we can exclude it from the following
  335. // calls. But we do some processing based on registry and log config
  336. // entries so we will pre-run the registry section for enumerated
  337. // devices and exclude the others
  338. //
  339. // Run the section found using hkeyRelative as the HKR
  340. hr = HrCiInstallFromInfSection (hinfFile, pszSection,
  341. hkeyRelative, hwndParent,
  342. (fEnumerated ? (SPINST_REGISTRY | SPINST_LOGCONFIG) :
  343. SPINST_ALL & ~SPINST_REGSVR));
  344. if (!fEnumerated)
  345. {
  346. // We need to run the Services section and
  347. // check for Winsock dependency if they aren't specified to be
  348. // excluded.
  349. //
  350. // Note: Other sections may be added later. The default is to
  351. // run all sections not listed in dwExcludeSectionFlags
  352. //
  353. if (S_OK == hr)
  354. {
  355. // run services section if it exists
  356. hr = HrCiInstallServices (hinfFile, pszSection);
  357. if (S_OK == hr)
  358. {
  359. // Bug #383239: Wait till services are installed before
  360. // running the RegisterDlls section
  361. //
  362. hr = HrCiInstallFromInfSection (hinfFile, pszSection,
  363. hkeyRelative, hwndParent,
  364. SPINST_REGSVR);
  365. }
  366. }
  367. }
  368. if (S_OK == hr)
  369. {
  370. //sb This part can be called for either add or remove. We
  371. //sb are moving only the remove part forward. This should
  372. //sb still be performed for add.
  373. //
  374. // Determine if a .Winsock section exists for the
  375. // section specified in szActualSection
  376. PCWSTR pszSubSection = wcsstr(pszSection, L".Remove");
  377. if(!pszSubSection || wcscmp(pszSubSection, L".Remove"))
  378. {
  379. hr = HrAddOrRemoveWinsockDependancy (hinfFile, pszSection);
  380. }
  381. // These other extensions are undocumented and some have been
  382. // added by external groups. We don't want any of them
  383. // processed for enumerated components.
  384. //
  385. if ((S_OK == hr) && !fEnumerated)
  386. {
  387. // Process the additional INF extensions (SNMP Agent,
  388. // PrintMonitors, etc.)
  389. //
  390. hr = HrProcessAllINFExtensions (hinfFile, pszSection);
  391. }
  392. }
  393. }
  394. TraceHr (ttidError, FAL, hr, (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr),
  395. "HrCiDoCompleteSectionInstall");
  396. return hr;
  397. }
  398. //+--------------------------------------------------------------------------
  399. //
  400. // Function: HrCiRemoveNonEnumeratedComponent
  401. //
  402. // Purpose: This will run the remove section and delete the network
  403. // instance key for the component if necessary. This
  404. // function is called for partially (i.e. failed install)
  405. // and fully installed components
  406. //
  407. // Arguments:
  408. // hinf [in] The handle to the component's inf file
  409. // hkeyInstance [in] The handle to the component's instance key
  410. // Class [in] The class of the component
  411. // InstanceGuid [in] The instance guid of the component
  412. // pstrRemoveSection [out] Optional pointer to a tstring which receives
  413. // the remove section name.
  414. //
  415. // Returns: HRESULT. S_OK if successful, NETCFG_S_REBOOT if successful
  416. // but a reboot is required, or an error code otherwise
  417. //
  418. // Author: billbe 10 Dec 1996
  419. // Revised 27 Apr 1997
  420. //
  421. // Notes:
  422. //
  423. HRESULT
  424. HrCiRemoveNonEnumeratedComponent(
  425. IN HINF hinf,
  426. IN HKEY hkeyInstance,
  427. IN NETCLASS Class,
  428. IN const GUID& InstanceGuid,
  429. OUT tstring* pstrRemoveSection OPTIONAL)
  430. {
  431. Assert (IsValidHandle (hinf));
  432. Assert (IsValidHandle (hkeyInstance));
  433. static const WCHAR c_szRemoveSectionSuffix[] = L".Remove";
  434. // We get the remove section name and process all relevant sections
  435. // We also try to unregister any Notify objects available
  436. //
  437. WCHAR szRemoveSection[_MAX_PATH];
  438. DWORD cbBuffer = sizeof (szRemoveSection);
  439. HRESULT hr = HrRegQuerySzBuffer (hkeyInstance, REGSTR_VAL_INFSECTION,
  440. szRemoveSection, &cbBuffer);
  441. if (S_OK == hr)
  442. {
  443. wcscat (szRemoveSection, c_szRemoveSectionSuffix);
  444. if (pstrRemoveSection)
  445. {
  446. pstrRemoveSection->assign(szRemoveSection);
  447. }
  448. hr = HrCiDoCompleteSectionInstall (hinf, hkeyInstance,
  449. szRemoveSection, NULL, NULL);
  450. }
  451. // Whether unregistering the notify object is successful or not,
  452. // we must fully remove the component.
  453. (VOID) HrCiRegisterNotificationDll (hkeyInstance, CIRDF_UNREGISTER);
  454. // Now we need to remove the component key in the Network tree
  455. // We need to do this regardless of any previous errors
  456. // so we don't need the return value.
  457. WCHAR szGuid[c_cchGuidWithTerm];
  458. StringFromGUID2 (InstanceGuid, szGuid, c_cchGuidWithTerm);
  459. (VOID) HrCiRegDeleteComponentNetworkKey (Class, szGuid);
  460. // if all went well, set the return value based on whether a reboot
  461. // is required or not or any error from HrRegisterNotificationDll.
  462. //
  463. if (S_FALSE == hr)
  464. {
  465. // S_FALSE is okay but should not be returned by this fcn.
  466. hr = S_OK;
  467. }
  468. TraceHr (ttidError, FAL, hr, FALSE, "HrCiRemoveNonEnumeratedComponent");
  469. return hr;
  470. }
  471. //+--------------------------------------------------------------------------
  472. //
  473. // Function: HrCiRemoveComponent
  474. //
  475. // Purpose: Called from INetCfg, this will uninstall a network component.
  476. //
  477. // Arguments:
  478. // pComponent [in] The component to uninstall.
  479. // pstrRemoveSection [out] Optional pointer to a tstring which receives
  480. // the remove section name.
  481. //
  482. // Returns: HRESULT. S_OK if successful, NETCFG_S_REBOOT if successful
  483. // but a reboot is required, or an error code otherwise
  484. //
  485. // Author: billbe 10 Dec 1996
  486. // Revised 27 Apr 1997
  487. //
  488. // Notes:
  489. //
  490. HRESULT
  491. HrCiRemoveComponent(
  492. IN const CComponent* pComponent,
  493. OUT tstring* pstrRemoveSection OPTIONAL)
  494. {
  495. Assert (pComponent);
  496. HINF hinf = NULL;
  497. HDEVINFO hdi = NULL;
  498. SP_DEVINFO_DATA deid;
  499. HKEY hkeyInstance = NULL;
  500. HRESULT hr = S_OK;
  501. // If this is an enumerated net class component, then we need to
  502. // create the Device Installer structures for HrSetupDiRemoveDevice
  503. //
  504. if (FIsEnumerated (pComponent->Class()))
  505. {
  506. if (pComponent->m_dwCharacter & NCF_PHYSICAL)
  507. {
  508. // The binding engine calls us to remove physical devices
  509. // only when we need to potentially cleanup the information
  510. // we saved away when the class installer removed the device.
  511. // This happens when the class installer is told to remove
  512. // the device (which it does) and then notifies the binding
  513. // engine to remove it from its data structures. The binding
  514. // engine then calls this method to cleanup this info we
  515. // set so that the binding engine could notify components of
  516. // its removal.
  517. //
  518. // We can also be called here when a physical component is
  519. // removed (with the binding engine write lock held by someone)
  520. // and then readded immediately. The new component will get
  521. // the same PnpId as the removed one but the bindng engine still
  522. // has the removed component in its structures. When this
  523. // condition is detected, the binding engine will remove the
  524. // old instance (by calling us here). In this case, if we were
  525. // to open the device info on pComponent->m_pszPnpId, we'd open
  526. // the new instance that was added. We don't want to do this.
  527. // We just want to cleanup any of the information that we set
  528. // for the binding engine when we first removed the device.
  529. //
  530. HKEY hkeyComponent;
  531. hr = HrRegOpenKeyEx (HKEY_LOCAL_MACHINE,
  532. c_szTempNetcfgStorageForUninstalledEnumeratedComponent,
  533. KEY_WRITE, &hkeyComponent);
  534. if (S_OK == hr)
  535. {
  536. WCHAR szGuid[c_cchGuidWithTerm];
  537. INT cch = StringFromGUID2 (pComponent->m_InstanceGuid, szGuid,
  538. c_cchGuidWithTerm);
  539. Assert (c_cchGuidWithTerm == cch);
  540. (VOID) HrRegDeleteKeyTree (hkeyComponent, szGuid);
  541. RegCloseKey (hkeyComponent);
  542. }
  543. }
  544. else
  545. {
  546. // Create a device info list
  547. hr = HrOpenDeviceInfo (pComponent->Class(),
  548. pComponent->m_pszPnpId, &hdi, &deid);
  549. if (S_OK == hr)
  550. {
  551. // removals must go through device installer
  552. // hook (NetClassInstaller). The function we are
  553. // in can only be called if the caller has the write lock
  554. // so we need to indicate this to the device installer hook
  555. // through our reserved data.
  556. ADAPTER_REMOVE_PARAMS arp = {0};
  557. CiSetReservedField (hdi, &deid, &arp);
  558. // removals must go through device installer
  559. // hook (NetClassInstaller).
  560. hr = HrSetupDiCallClassInstaller (DIF_REMOVE, hdi, &deid);
  561. // clear the reserved field so we don't delete it later
  562. CiClearReservedField (hdi, &deid);
  563. if (S_OK == hr)
  564. {
  565. hr = FSetupDiCheckIfRestartNeeded (hdi, &deid) ?
  566. NETCFG_S_REBOOT : S_OK;
  567. #ifdef ENABLETRACE
  568. if (NETCFG_S_REBOOT == hr)
  569. {
  570. TraceTag (ttidClassInst, "***********************************"
  571. "**************************************************");
  572. TraceTag (ttidClassInst, "The component %S needs a reboot "
  573. "in order to function", pComponent->m_pszPnpId);
  574. TraceTag (ttidClassInst, "***********************************"
  575. "**************************************************");
  576. }
  577. #endif //ENABLETRACE
  578. }
  579. SetupDiDestroyDeviceInfoList (hdi);
  580. }
  581. }
  582. }
  583. else
  584. {
  585. // For non enumerated components, the instance key is the
  586. // component key
  587. hr = pComponent->HrOpenInstanceKey (KEY_ALL_ACCESS, &hkeyInstance,
  588. NULL, NULL);
  589. if (S_OK == hr)
  590. {
  591. if (NC_NETCLIENT == pComponent->Class ())
  592. {
  593. hr = HrCiDeleteNetProviderInfo (hkeyInstance, NULL, NULL);
  594. }
  595. if (S_OK == hr)
  596. {
  597. hr = pComponent->HrOpenInfFile(&hinf);
  598. if( S_OK == hr )
  599. {
  600. // Remove the component
  601. hr = HrCiRemoveNonEnumeratedComponent ( hinf,
  602. hkeyInstance, pComponent->Class(),
  603. pComponent->m_InstanceGuid,
  604. pstrRemoveSection);
  605. }
  606. }
  607. }
  608. RegSafeCloseKey (hkeyInstance);
  609. }
  610. TraceHr (ttidError, FAL, hr, NETCFG_S_REBOOT == hr,
  611. "HrCiRemoveComponent (%S)", pComponent->PszGetPnpIdOrInfId());
  612. return hr;
  613. }
  614. //+--------------------------------------------------------------------------
  615. //
  616. // Function: HrCiGetDriverInfo
  617. //
  618. // Purpose: Finds a component's driver information (in the inf file) and
  619. // creates a Device Info Data structure containing that
  620. // information as the structure's selected driver.
  621. // (see Device Installer Api for more info).
  622. //
  623. // Arguments:
  624. // hdi [in] See Device Installer Api documentation for more info.
  625. // pdeid [in, out] See Device Installer Api documentation for
  626. // more info. Should be allocated by caller, but empty.
  627. // guidClass [in] The class guid for the component.
  628. // pszInfId [in] The id of the component as found in its inf.
  629. // pszInfFile [in] Optional. The inf file for the component.
  630. //
  631. // Returns: HRESULT. S_OK if successful, error code otherwise.
  632. //
  633. // Author: billbe 11 Mar 1997
  634. //
  635. // Notes:
  636. //
  637. HRESULT
  638. HrCiGetDriverInfo (
  639. IN HDEVINFO hdi,
  640. IN OUT PSP_DEVINFO_DATA pdeid,
  641. IN const GUID& guidClass,
  642. IN PCWSTR pszInfId,
  643. IN PCWSTR pszInfFile OPTIONAL)
  644. {
  645. HRESULT hr;
  646. Assert (IsValidHandle (hdi));
  647. Assert (pdeid);
  648. Assert (pszInfId);
  649. // Copy the Id since we may need to change it.
  650. //
  651. WCHAR szId[_MAX_PATH];
  652. wcscpy (szId, pszInfId);
  653. // We cannot generate ids via HrSetupDiCreateDeviceInfo if they contain
  654. // slashes (e.g. Eisa\*pnp0232), so we need to convert any slashes in
  655. // the instance id to ampersands.
  656. //
  657. int iPos = 0;
  658. while (szId[iPos])
  659. {
  660. if (L'\\' == szId[iPos])
  661. {
  662. szId[iPos] = L'&';
  663. }
  664. ++iPos;
  665. }
  666. // First, create a [temporary] device info. This will be used to
  667. // find the component's Inf file.
  668. hr = HrSetupDiCreateDeviceInfo (hdi, szId, guidClass, NULL, NULL,
  669. DICD_GENERATE_ID, pdeid);
  670. if (S_OK == hr)
  671. {
  672. // In order to find the Inf file, Device Installer Api needs the
  673. // component id which it calls the Hardware id.
  674. //
  675. // We need to include an extra null since this registry value is a
  676. // multi-sz
  677. //
  678. wcsncpy (szId, pszInfId, iPos);
  679. szId[iPos + 1] = 0;
  680. hr = HrSetupDiSetDeviceRegistryProperty (hdi, pdeid, SPDRP_HARDWAREID,
  681. (const BYTE*)szId, CbOfSzAndTerm (szId) + sizeof(WCHAR));
  682. if (S_OK == hr)
  683. {
  684. // Get the install params and set the class for compat flag
  685. // This will use the device's class guid as a filter when
  686. // searching through infs, speeding things up. We can also
  687. // let Device Installer Api know that we want to use a single
  688. // inf. if we can't get the params and set it it isn't an error
  689. // since it only slows things down a bit
  690. //
  691. SP_DEVINSTALL_PARAMS deip;
  692. hr = HrSetupDiGetDeviceInstallParams (hdi, pdeid, &deip);
  693. if (S_OK == hr)
  694. {
  695. deip.FlagsEx |= DI_FLAGSEX_USECLASSFORCOMPAT;
  696. // If we were not given an inf file to use...
  697. // We have a map of known components and their inf files.
  698. // If this component is in the map then we can set the
  699. // driver path in the device info data and
  700. // set the enumerate a single inf flag. This will
  701. // cause the device installer to just look at the specified
  702. // inf file for the driver node.
  703. //
  704. // We only do this if the node doesn't already have a file
  705. // name set.
  706. //
  707. if (!(*deip.DriverPath))
  708. {
  709. if (pszInfFile && *pszInfFile)
  710. {
  711. wcscpy (deip.DriverPath, pszInfFile);
  712. }
  713. else
  714. {
  715. FInfFileFromComponentId (pszInfId, deip.DriverPath);
  716. }
  717. }
  718. if (*deip.DriverPath)
  719. {
  720. TraceTag (ttidClassInst, "Class Installer was given %S "
  721. "as a filename for %S", deip.DriverPath,
  722. pszInfId);
  723. deip.Flags |= DI_ENUMSINGLEINF;
  724. if ((0 == _wcsicmp(L"netrasa.inf", deip.DriverPath)) ||
  725. (0 == _wcsicmp(L"netpsa.inf", deip.DriverPath)))
  726. {
  727. deip.Flags |= DI_NOFILECOPY;
  728. }
  729. }
  730. #ifdef ENABLETRACE
  731. else
  732. {
  733. TraceTag (ttidNetcfgBase,
  734. "Perf Warning: No knowledge of INF file for the '%S' "
  735. "component. SetupApi is now thrashing the disk looking for it.",
  736. pszInfId);
  737. }
  738. #endif // ENABLETRACE
  739. // For non-device classes, we need to allow excluded
  740. // drivers in order to get any driver list returned.
  741. if (!FIsEnumerated (guidClass))
  742. {
  743. deip.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
  744. }
  745. (VOID) HrSetupDiSetDeviceInstallParams (hdi, pdeid, &deip);
  746. }
  747. // Now we let Device Installer Api build a driver list based on
  748. // the information we have given so far. This will result in the
  749. // Inf file being found if it exists in the usual Inf directory
  750. //
  751. #ifdef ENABLETRACE
  752. CBenchmark bmrk;
  753. bmrk.Start ("SetupDiBuildDriverInfoList");
  754. #endif //ENABLETRACE
  755. hr = HrSetupDiBuildDriverInfoList (hdi, pdeid,
  756. SPDIT_COMPATDRIVER);
  757. #ifdef ENABLETRACE
  758. bmrk.Stop();
  759. TraceTag (ttidBenchmark, "%s : %s seconds",
  760. bmrk.SznDescription(), bmrk.SznBenchmarkSeconds (2));
  761. #endif //ENABLETRACE
  762. if (S_OK == hr)
  763. {
  764. // HrSetupDiSelectBestCompatDrv finds and selects the best
  765. // driver for the device.
  766. //
  767. SP_DRVINFO_DATA drid;
  768. hr = HrSetupDiSelectBestCompatDrv(hdi, pdeid);
  769. if (HRESULT_FROM_SETUPAPI(ERROR_NO_COMPAT_DRIVERS) == hr)
  770. {
  771. // Make the ERROR_NO_COMPAT_DRIVERS case look like what
  772. // it really means -- the requested component's driver
  773. // info (i.e. inf) could not be found.
  774. //
  775. hr = SPAPI_E_NO_DRIVER_SELECTED;
  776. }
  777. }
  778. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  779. {
  780. // We couldn't find an inf file which means we cannot
  781. // selected the driver for this component.
  782. //
  783. hr = SPAPI_E_NO_DRIVER_SELECTED;
  784. }
  785. }
  786. // if anything failed, we should remove the device node we created
  787. if (FAILED(hr))
  788. {
  789. (VOID) SetupDiDeleteDeviceInfo (hdi, pdeid);
  790. }
  791. }
  792. TraceHr (ttidError, FAL, hr, FALSE, "HrCiGetDriverInfo");
  793. return hr;
  794. }
  795. //+--------------------------------------------------------------------------
  796. //
  797. // Function: HrCiGetClassAndInfFileOfInfId
  798. //
  799. // Purpose: Finds a component's class and inf file.
  800. //
  801. // Arguments:
  802. // pszInfId [in] The Id of the component as found in its Inf.
  803. // pClass [out] The class of the component.
  804. // pszInfFile [out] The filename of the component's inf
  805. // (must be _MAX_PATH long).
  806. //
  807. // Returns: HRESULT. S_OK if successful, error code otherwise.
  808. //
  809. // Author: billbe 16 Mar 1998
  810. //
  811. // Notes:
  812. //
  813. HRESULT
  814. HrCiGetClassAndInfFileOfInfId (
  815. IN PCWSTR pszInfId,
  816. OUT NETCLASS* pClass,
  817. OUT PWSTR pszInfFile) // Must be _MAX_PATH long
  818. {
  819. HRESULT hr;
  820. const COMPONENT_INFO* pCompInfo;
  821. HDEVINFO hdi;
  822. Assert (pszInfId && *pszInfId);
  823. Assert (pClass);
  824. Assert (pszInfFile);
  825. hr = S_OK;
  826. // First, try the fast route by seeing if it's in our internal map.
  827. //
  828. pCompInfo = PComponentInfoFromComponentId (pszInfId);
  829. if (pCompInfo)
  830. {
  831. *pClass = NetClassEnumFromGuid (*pCompInfo->pguidClass);
  832. if (FIsValidNetClass (*pClass))
  833. {
  834. wcsncpy (pszInfFile, pCompInfo->pszInfFile, _MAX_PATH);
  835. pszInfFile [_MAX_PATH - 1] = 0;
  836. }
  837. else
  838. {
  839. hr = SPAPI_E_INVALID_CLASS;
  840. }
  841. }
  842. else
  843. {
  844. // Create a device info list.
  845. //
  846. hr = HrSetupDiCreateDeviceInfoList (NULL, NULL, &hdi);
  847. if (S_OK == hr)
  848. {
  849. SP_DEVINFO_DATA deid;
  850. // Get the driver info for the component and set it as the
  851. // selected driver
  852. //
  853. hr = HrCiGetDriverInfo (hdi, &deid, GUID_NULL, pszInfId, NULL);
  854. if (S_OK == hr)
  855. {
  856. SP_DRVINFO_DATA drid;
  857. // Get the selected driver.
  858. //
  859. hr = HrSetupDiGetSelectedDriver (hdi, &deid, &drid);
  860. if (S_OK == hr)
  861. {
  862. // Set the class output parameter from the dev info data
  863. // structure (HrGetDriverInfo updates this field if a driver
  864. // was found)
  865. //
  866. *pClass = NetClassEnumFromGuid (deid.ClassGuid);
  867. if (!FIsValidNetClass (*pClass))
  868. {
  869. hr = SPAPI_E_INVALID_CLASS;
  870. }
  871. else
  872. {
  873. PSP_DRVINFO_DETAIL_DATA pdridd;
  874. // Now get the driver's detailed information
  875. //
  876. hr = HrCiGetDriverDetail (hdi, &deid, &drid,
  877. &pdridd);
  878. if (S_OK == hr)
  879. {
  880. // Get the inf filename and set the
  881. // output parameter.
  882. //
  883. wcsncpy (pszInfFile, pdridd->InfFileName,
  884. _MAX_PATH);
  885. pszInfFile[_MAX_PATH - 1] = 0;
  886. MemFree (pdridd);
  887. }
  888. }
  889. }
  890. }
  891. SetupDiDestroyDeviceInfoList (hdi);
  892. }
  893. }
  894. if (S_OK != hr)
  895. {
  896. *pClass = NC_INVALID;
  897. *pszInfFile = 0;
  898. }
  899. TraceHr (ttidError, FAL, hr, FALSE, "HrCiGetClassAndInfFileOfInfId");
  900. return hr;
  901. }
  902. //+--------------------------------------------------------------------------
  903. //
  904. // Function: HrCiGetDriverDetail
  905. //
  906. // Purpose: Creates and fills a PSP_DRVINFO_DETAIL_DATA structure
  907. // with detailed information about the pDevInfoData's
  908. // selected driver
  909. //
  910. // Arguments:
  911. // hdi [in] See Device Installer Api documentation for more info
  912. // pdeid [in] See Device Installer Api documentation for more info
  913. // This value is NULL for non-physical net
  914. // components.
  915. // pdrid [in] See Device Installer Api documentation for more info
  916. // ppdridd [out] See Device Installer Api documentation for more info
  917. //
  918. // Returns: HRESULT. S_OK if successful, error code otherwise
  919. //
  920. // Author: billbe 11 Mar 1997
  921. //
  922. // Notes:
  923. //
  924. HRESULT
  925. HrCiGetDriverDetail (
  926. IN HDEVINFO hdi,
  927. IN PSP_DEVINFO_DATA pdeid OPTIONAL,
  928. OUT PSP_DRVINFO_DATA pdrid,
  929. OUT PSP_DRVINFO_DETAIL_DATA* ppdridd)
  930. {
  931. Assert(IsValidHandle(hdi));
  932. Assert(pdrid);
  933. Assert(ppdridd);
  934. // initialize pdrid and set its cbSize field
  935. ZeroMemory (pdrid, sizeof (SP_DRVINFO_DATA));
  936. pdrid->cbSize = sizeof (SP_DRVINFO_DATA);
  937. HRESULT hr = S_OK;
  938. *ppdridd = NULL;
  939. // Get the selected driver for the component
  940. hr = HrSetupDiGetSelectedDriver (hdi, pdeid, pdrid);
  941. if (S_OK == hr)
  942. {
  943. // Get driver detail info
  944. hr = HrSetupDiGetDriverInfoDetail (hdi, pdeid, pdrid, ppdridd);
  945. }
  946. // clean up on failure
  947. if (FAILED(hr))
  948. {
  949. if (*ppdridd)
  950. {
  951. MemFree (*ppdridd);
  952. *ppdridd = NULL;
  953. }
  954. }
  955. TraceHr (ttidError, FAL, hr, FALSE, "HrCiGetDriverDetail");
  956. return hr;
  957. }
  958. //+--------------------------------------------------------------------------
  959. //
  960. // Function: HrCiRegSetComponentInformation
  961. //
  962. // Purpose: Stores component information under the instance key of
  963. // the component.
  964. //
  965. // Arguments:
  966. // hkeyInstance [in] Component's instance registry key.
  967. // pcii [in] Component's information to store in hkeyInstance.
  968. //
  969. // Returns: HRESULT. S_OK if successful, error code otherwise.
  970. //
  971. // Author: billbe 11 Mar 1997
  972. //
  973. // Notes:
  974. //
  975. HRESULT
  976. HrCiRegSetComponentInformation(
  977. IN HKEY hkeyInstance,
  978. IN COMPONENT_INSTALL_INFO* pcii)
  979. {
  980. Assert(hkeyInstance);
  981. Assert(pcii);
  982. HRESULT hr = S_OK;
  983. BOOL fIsEnumerated = FIsEnumerated (pcii->Class);
  984. // Store the characteristics, inf path, and main
  985. // install section for the component
  986. //
  987. hr = HrRegSetDword (hkeyInstance, L"Characteristics", pcii->dwCharacter);
  988. if (FAILED(hr))
  989. {
  990. goto exit;
  991. }
  992. if (!fIsEnumerated)
  993. {
  994. hr = HrRegSetSz (hkeyInstance, L"InfPath" /*REGSTR_VAL_INFPATH*/,
  995. pcii->pszInfFile);
  996. if (FAILED(hr))
  997. {
  998. goto exit;
  999. }
  1000. hr = HrRegSetSz (hkeyInstance, L"InfSection"/*REGSTR_VAL_INFSECTION*/,
  1001. pcii->pszSectionName);
  1002. if (FAILED(hr))
  1003. {
  1004. goto exit;
  1005. }
  1006. }
  1007. // For non-enumerated components, store description into the registry.
  1008. //
  1009. if (!fIsEnumerated)
  1010. {
  1011. hr = HrRegSetSz (hkeyInstance, L"Description", pcii->pszDescription);
  1012. if (FAILED(hr))
  1013. {
  1014. goto exit;
  1015. }
  1016. }
  1017. // If this component is already installed, then there is no need to write
  1018. // the following information
  1019. //
  1020. if (FIsEnumerated (pcii->Class) && !pcii->fPreviouslyInstalled &&
  1021. FIsPhysicalAdapter (pcii->Class, pcii->dwCharacter) &&
  1022. (InterfaceTypeUndefined != pcii->BusType))
  1023. {
  1024. hr = HrRegSetSzAsUlong (hkeyInstance, L"BusType",
  1025. pcii->BusType, c_nBase10);
  1026. if (FAILED(hr))
  1027. {
  1028. goto exit;
  1029. }
  1030. }
  1031. hr = HrRegSetSz (hkeyInstance, L"ComponentId", pcii->pszInfId);
  1032. exit:
  1033. TraceHr (ttidError, FAL, hr, FALSE, "HrCiRegSetComponentInformation");
  1034. return hr;
  1035. }
  1036. //+--------------------------------------------------------------------------
  1037. //
  1038. // Function: HrCiCreateInstanceKey
  1039. //
  1040. // Purpose: Creates an instance key for the component. For enumerated
  1041. // devices, this is
  1042. // HKLM\System\CCS\Control\Class\<net guid>\<instance id>
  1043. // For non-enumerated components, this is under
  1044. // HKLM\System\CCS\Control\Network\<Class Guid>\<Instance Guid>
  1045. //
  1046. // Arguments:
  1047. // pcii [inout] Component install info structure.
  1048. // phkeyInstance [out] The component's registry instance key.
  1049. //
  1050. // Returns: HRESULT
  1051. //
  1052. // Author: billbe 22 Mar 1997
  1053. //
  1054. // Notes:
  1055. //
  1056. HRESULT
  1057. HrCiCreateInstanceKey(
  1058. IN COMPONENT_INSTALL_INFO* pcii,
  1059. OUT HKEY* phkeyInstance)
  1060. {
  1061. Assert (pcii);
  1062. Assert (phkeyInstance);
  1063. Assert (FImplies (FIsEnumerated (pcii->Class),
  1064. IsValidHandle (pcii->hdi) && pcii->pdeid));
  1065. HRESULT hr = S_OK;
  1066. // initialize the HKEY parameter
  1067. *phkeyInstance = NULL;
  1068. // Create the instance key for this component under the
  1069. // Network\<net guid> tree. This will be the component's
  1070. // instance key for all but physical net class components. Their
  1071. // instance key is created by Device Installer Api and lives under the
  1072. // Pnp Net Class driver tree.
  1073. // If the object is an enumerated component then we let
  1074. // the Device Installer api do the work
  1075. //
  1076. if (FIsEnumerated (pcii->Class))
  1077. {
  1078. // We need to create the adapter's driver key under
  1079. // the Pnp Net Class Driver tree.
  1080. //
  1081. hr = HrSetupDiCreateDevRegKey (pcii->hdi,
  1082. pcii->pdeid, DICS_FLAG_GLOBAL, 0, DIREG_DRV,
  1083. NULL, NULL, phkeyInstance);
  1084. }
  1085. else
  1086. {
  1087. // Not a physical net adapter so the component key is
  1088. // the instance key
  1089. // First, create the instance GUID
  1090. hr = CoCreateGuid (&pcii->InstanceGuid);
  1091. // Now create the key
  1092. if (S_OK == hr)
  1093. {
  1094. WCHAR szInstanceKeyPath[_MAX_PATH];
  1095. CreateInstanceKeyPath (pcii->Class, pcii->InstanceGuid,
  1096. szInstanceKeyPath);
  1097. hr = HrRegCreateKeyEx (HKEY_LOCAL_MACHINE,
  1098. szInstanceKeyPath,
  1099. REG_OPTION_NON_VOLATILE,
  1100. KEY_ALL_ACCESS,
  1101. NULL,
  1102. phkeyInstance,
  1103. NULL);
  1104. }
  1105. }
  1106. TraceHr (ttidError, FAL, hr, FALSE, "HrCiCreateInstanceKey");
  1107. return hr;
  1108. }
  1109. //+--------------------------------------------------------------------------
  1110. //
  1111. // Function: HrCiGetPropertiesFromInf
  1112. //
  1113. // Purpose: Retrieves a set of the component's proerties from the inf
  1114. // file.
  1115. //
  1116. // Arguments:
  1117. // hinfFile [in] A handle to the component's inf file
  1118. // pcii [inout] The component info structure
  1119. // See compinfo.h for more info
  1120. //
  1121. // Returns: HRESULT. S_OK if successful, error code otherwise
  1122. //
  1123. // Author: billbe 14 Jun 1997
  1124. //
  1125. // Notes:
  1126. //
  1127. HRESULT
  1128. HrCiGetPropertiesFromInf (
  1129. IN HINF hinfFile,
  1130. IN OUT COMPONENT_INSTALL_INFO* pcii)
  1131. {
  1132. Assert (IsValidHandle (hinfFile));
  1133. Assert (pcii);
  1134. Assert (pcii->pszSectionName);
  1135. // Find the inf line that contains Characteristics and retrieve it
  1136. HRESULT hr = HrSetupGetFirstDword (hinfFile, pcii->pszSectionName,
  1137. L"Characteristics", &pcii->dwCharacter);
  1138. if ((S_OK == hr) &&
  1139. (FIsPhysicalAdapter(pcii->Class, pcii->dwCharacter)))
  1140. {
  1141. hr = HrCiGetBusInfoFromInf (hinfFile, pcii);
  1142. }
  1143. #ifdef DBG
  1144. else if (FAILED(hr))
  1145. {
  1146. TraceTag(ttidError, "Inf contains no Characteristics field");
  1147. }
  1148. #endif // DBG
  1149. TraceHr (ttidError, FAL, hr, FALSE, "HrCiGetPropertiesFromInf");
  1150. return hr;
  1151. }
  1152. //+--------------------------------------------------------------------------
  1153. //
  1154. // Function: HrCiIsInstalledComponent
  1155. //
  1156. // Purpose: Checks if the component is already installed
  1157. //
  1158. //
  1159. // Arguments:
  1160. // pcici [in] A structure containing the component information
  1161. // See compinst.h for definition
  1162. // phkey [out] The registry instance key of the adapter
  1163. // during inf processing. only set if fcn returns S_OK
  1164. //
  1165. // Returns: HRESULT - S_OK if the component is already installed
  1166. // S_FALSE if the component is not already installed
  1167. // A win32 converted error otherwise
  1168. //
  1169. // Author: billbe 17 Sep 1997
  1170. //
  1171. // Notes:
  1172. //
  1173. HRESULT
  1174. HrCiIsInstalledComponent (
  1175. IN COMPONENT_INSTALL_INFO* pcii,
  1176. OUT HKEY* phkey)
  1177. {
  1178. HRESULT hr;
  1179. Assert(pcii);
  1180. if (phkey)
  1181. {
  1182. *phkey = NULL;
  1183. }
  1184. // If this is an enumerated component, we just check for NetCfgInstanceId
  1185. // in the instance (driver) key.
  1186. //
  1187. if (FIsEnumerated (pcii->Class))
  1188. {
  1189. HKEY hkey;
  1190. hr = HrSetupDiOpenDevRegKey (pcii->hdi, pcii->pdeid, DICS_FLAG_GLOBAL,
  1191. 0, DIREG_DRV, KEY_ALL_ACCESS, &hkey);
  1192. if (S_OK == hr)
  1193. {
  1194. WCHAR szGuid[c_cchGuidWithTerm];
  1195. DWORD cbGuid = sizeof (szGuid);
  1196. hr = HrRegQuerySzBuffer (hkey, L"NetCfgInstanceId", szGuid,
  1197. &cbGuid);
  1198. if (S_OK == hr)
  1199. {
  1200. IIDFromString (szGuid, &pcii->InstanceGuid);
  1201. if (phkey)
  1202. {
  1203. *phkey = hkey;
  1204. }
  1205. }
  1206. else
  1207. {
  1208. RegCloseKey (hkey);
  1209. hr = S_FALSE;
  1210. }
  1211. }
  1212. else if ((SPAPI_E_KEY_DOES_NOT_EXIST == hr) ||
  1213. (SPAPI_E_DEVINFO_NOT_REGISTERED == hr))
  1214. {
  1215. TraceTag(ttidClassInst, "Component is not known by Net Config");
  1216. hr = S_FALSE;
  1217. }
  1218. }
  1219. else
  1220. {
  1221. // For non-enumerated components, we check the netcfg "config blob" to
  1222. // determine if this component is isntalled.
  1223. CNetConfig NetConfig;
  1224. hr = HrLoadNetworkConfigurationFromRegistry (KEY_READ, &NetConfig);
  1225. if (S_OK == hr)
  1226. {
  1227. CComponent* pComponent;
  1228. pComponent = NetConfig.Core.Components.
  1229. PFindComponentByInfId(pcii->pszInfId, NULL);
  1230. if (pComponent)
  1231. {
  1232. pcii->InstanceGuid = pComponent->m_InstanceGuid;
  1233. if (phkey)
  1234. {
  1235. hr = pComponent->HrOpenInstanceKey(KEY_ALL_ACCESS, phkey,
  1236. NULL, NULL);
  1237. }
  1238. }
  1239. else
  1240. {
  1241. hr = S_FALSE;
  1242. }
  1243. }
  1244. }
  1245. TraceHr (ttidError, FAL, hr, S_FALSE == hr, "HrCiIsInstalledComponent");
  1246. return hr;
  1247. }
  1248. //+--------------------------------------------------------------------------
  1249. //
  1250. // Function: HrCiCreateInstanceKeyAndProcessMainInfSection
  1251. //
  1252. // Purpose: Processes a component's main inf section and
  1253. // storing, in the registry, any extra information needed for
  1254. // component initialization
  1255. //
  1256. // Arguments:
  1257. // hinf [in] Handle to the component's inf file.
  1258. // pcii [inout] Will be filled with information about the
  1259. // component.
  1260. // phkey [out] Handle to the component's registry instance key.
  1261. //
  1262. //
  1263. // Returns: HRESULT. S_OK if successful, error code otherwise
  1264. //
  1265. // Author: billbe 15 Nov 1996
  1266. //
  1267. // Notes:
  1268. //
  1269. HRESULT
  1270. HrCiCreateInstanceKeyAndProcessMainInfSection(
  1271. IN HINF hinf,
  1272. IN COMPONENT_INSTALL_INFO* pcii,
  1273. OUT HKEY* phkey)
  1274. {
  1275. #if defined(REMOTE_BOOT)
  1276. GUID c_guidRemoteBoot;
  1277. static const WCHAR c_szRemoteBootAdapterGuid[] =
  1278. L"{54C7D140-09EF-11D1-B25A-F5FE627ED95E}";
  1279. DEFINE_GUID(c_guidRemoteBoot, 0x54c7d140, 0x09ef, 0x11d1, 0xb2, 0x5a, 0xf5, 0xfe, 0x62, 0x7e, 0xd9, 0x5e);
  1280. #endif // defined(REMOTE_BOOT)
  1281. Assert (IsValidHandle (hinf));
  1282. Assert (pcii);
  1283. Assert (phkey);
  1284. // The properties retrieved here will be written to the registry
  1285. // later.
  1286. HRESULT hr = HrCiGetPropertiesFromInf (hinf, pcii);
  1287. if (S_OK == hr)
  1288. {
  1289. BOOL fEnumerated = FIsEnumerated (pcii->Class);
  1290. // If this component is enumerated, then we need to know if it
  1291. // is a remote boot adapter.
  1292. if (fEnumerated)
  1293. {
  1294. Assert (IsValidHandle (pcii->hdi));
  1295. Assert (pcii->pdeid);
  1296. #if defined(REMOTE_BOOT)
  1297. // If this adapter is a remote boot adapter, then we have
  1298. // to use a pre-determined GUID
  1299. //
  1300. if (S_OK == HrIsRemoteBootAdapter(pcii->hdi, pcii->pdeid))
  1301. {
  1302. pcai->m_fRemoteBoot = TRUE;
  1303. pcii->InstanceGuid = c_guidRemoteBoot;
  1304. }
  1305. #endif // defined(REMOTE_BOOT)
  1306. }
  1307. // Is this a fresh install or a reinstall?
  1308. hr = HrCiIsInstalledComponent(pcii, phkey);
  1309. if (S_FALSE == hr)
  1310. {
  1311. hr = S_OK;
  1312. // Fresh install
  1313. //
  1314. if (S_OK == hr)
  1315. {
  1316. // For non-physical components, the relative key will
  1317. // be the driver instance key which is under the class
  1318. // branch of the Network key. Its form is
  1319. // <Class GUID>/<instance GUID>.
  1320. // For physical components, the key is under
  1321. // the Pnp class driver tree. The next call will
  1322. // create this key
  1323. hr = HrCiCreateInstanceKey(pcii, phkey);
  1324. if (fEnumerated)
  1325. {
  1326. // If we don't have an instance
  1327. // guid (i.e. not remote boot adapter),
  1328. // get one
  1329. if (GUID_NULL == pcii->InstanceGuid)
  1330. {
  1331. hr = CoCreateGuid(&pcii->InstanceGuid);
  1332. #ifdef ENABLETRACE
  1333. WCHAR szGuid[c_cchGuidWithTerm];
  1334. StringFromGUID2(pcii->InstanceGuid, szGuid,
  1335. c_cchGuidWithTerm);
  1336. TraceTag(ttidClassInst, "NetCfg Instance Guid %S "
  1337. "generated for %S",
  1338. szGuid,
  1339. pcii->pszInfId);
  1340. #endif // ENABLETRACE
  1341. }
  1342. }
  1343. }
  1344. }
  1345. else if (S_OK == hr)
  1346. {
  1347. // This component is being reinstalled
  1348. pcii->fPreviouslyInstalled = TRUE;
  1349. }
  1350. if (S_OK == hr)
  1351. {
  1352. // Now that the instance key is created, we need to run
  1353. // the main inf sections
  1354. //
  1355. hr = HrCiDoCompleteSectionInstall(hinf, *phkey,
  1356. pcii->pszSectionName,
  1357. pcii->hwndParent, fEnumerated);
  1358. // On failure of fresh installs, remove components
  1359. if (FAILED(hr) && !pcii->fPreviouslyInstalled)
  1360. {
  1361. if (!fEnumerated)
  1362. {
  1363. HrCiRemoveNonEnumeratedComponent (hinf, *phkey,
  1364. pcii->Class, pcii->InstanceGuid, NULL);
  1365. }
  1366. }
  1367. }
  1368. }
  1369. TraceHr (ttidError, FAL, hr, FALSE,
  1370. "HrCiCreateInstanceKeyAndProcessMainInfSection");
  1371. return hr;
  1372. }
  1373. //+--------------------------------------------------------------------------
  1374. //
  1375. // Function: HrCiDoOemFileCopyIfNeeded
  1376. //
  1377. // Purpose: Calls HrSetupCopyOemInf if strInfPath is not already in the
  1378. // inf directory. This will copy an Oem inf to the inf
  1379. // directory with a new name.
  1380. //
  1381. // Arguments:
  1382. // pszInfPath [in] Path to the inf file
  1383. // pszNewName [out] The new name of the copied inf file
  1384. //
  1385. // Returns: HRESULT. S_OK if successful, error code otherwise
  1386. //
  1387. // Author: billbe 15 May 1997
  1388. //
  1389. // Notes:
  1390. //
  1391. HRESULT
  1392. HrCiDoOemFileCopyIfNeeded(
  1393. IN PCWSTR pszInfPath,
  1394. OUT PWSTR pszNewName)
  1395. {
  1396. Assert (pszInfPath);
  1397. Assert (pszNewName);
  1398. HRESULT hr = S_OK;
  1399. WCHAR szInfDir[_MAX_PATH] = {0};
  1400. // fill buffer with path to %windir%
  1401. GetSystemWindowsDirectory (szInfDir, _MAX_PATH);
  1402. // the inf directory is %windir%\inf
  1403. //
  1404. wcscat (szInfDir, L"\\");
  1405. wcscat (szInfDir, L"Inf");
  1406. // Extract the directory from the filename
  1407. //
  1408. PWSTR pszEnd = wcsrchr (pszInfPath, L'\\');
  1409. DWORD cch;
  1410. if (pszEnd)
  1411. {
  1412. cch = pszEnd - pszInfPath;
  1413. }
  1414. else
  1415. {
  1416. cch = wcslen (pszInfPath);
  1417. }
  1418. // if the inf is not already in the inf directory, copy it there
  1419. //
  1420. if ((cch != wcslen (szInfDir)) ||
  1421. (0 != _wcsnicmp (pszInfPath, szInfDir, cch)))
  1422. {
  1423. WCHAR szDestFilePath[_MAX_PATH];
  1424. PWSTR pszDestFilename;
  1425. hr = HrSetupCopyOemInfBuffer (pszInfPath, NULL, SPOST_PATH, 0,
  1426. szDestFilePath, _MAX_PATH, &pszDestFilename);
  1427. if (S_OK == hr)
  1428. {
  1429. wcscpy (pszNewName, pszDestFilename);
  1430. }
  1431. }
  1432. else
  1433. {
  1434. // The inf is already in the right directory so just copy the
  1435. // current filename component.
  1436. if (pszEnd)
  1437. {
  1438. wcscpy (pszNewName, pszEnd + 1);
  1439. }
  1440. else
  1441. {
  1442. wcscpy (pszNewName, pszInfPath);
  1443. }
  1444. }
  1445. TraceHr (ttidError, FAL, hr, FALSE, "HrCiDoOemFileCopyIfNeeded");
  1446. return hr;
  1447. }
  1448. //+--------------------------------------------------------------------------
  1449. //
  1450. // Function: HrCiInstallNonEnumeratedComponent
  1451. //
  1452. // Purpose: This function completes the installation of a non-enumerated
  1453. // component
  1454. //
  1455. // Arguments:
  1456. // hinf [in] SetupApi handle to an inf file
  1457. // hkey [in] The registry instance key of the adapter
  1458. // during inf processing.
  1459. // pcii [in] A structure containing the component information
  1460. //
  1461. // Returns: HRESULT. S_OK if successful, or error code otherwise
  1462. //
  1463. // Author: billbe 28 Apr 1997
  1464. //
  1465. // Notes:
  1466. //
  1467. HRESULT
  1468. HrCiInstallNonEnumeratedComponent (
  1469. IN HINF hinf,
  1470. IN HKEY hkey,
  1471. IN COMPONENT_INSTALL_INFO* pcii)
  1472. {
  1473. // Register the notification dll for this component,
  1474. // if it exists.
  1475. HRESULT hr = HrCiRegisterNotificationDll(hkey, CIRDF_REGISTER);
  1476. // Device Installer Api handles OEM files for
  1477. // enumerated components in InstallDevice
  1478. // Since this component is non-enumerated
  1479. // we need to handle any oem files
  1480. // manually.
  1481. //
  1482. // Copy the inf file if needed then store
  1483. // the new inf name
  1484. // Note: if the inf file does not need to
  1485. // be copied, the new name will be the
  1486. // old name without the directory info.
  1487. //
  1488. if (S_OK == hr)
  1489. {
  1490. WCHAR szNewName[_MAX_PATH];;
  1491. hr = HrCiDoOemFileCopyIfNeeded (pcii->pszInfFile, szNewName);
  1492. if (S_OK == hr)
  1493. {
  1494. // set the new path value in the registry.
  1495. hr = HrRegSetSz (hkey, REGSTR_VAL_INFPATH, szNewName);
  1496. if ((S_OK == hr) && (NC_NETCLIENT == pcii->Class))
  1497. {
  1498. // if this is a network client, do appropriate processing.
  1499. hr = HrCiAddNetProviderInfo (hinf, pcii->pszSectionName,
  1500. hkey, pcii->fPreviouslyInstalled);
  1501. }
  1502. }
  1503. }
  1504. // On failures of first time installs, remove the component.
  1505. //
  1506. if (FAILED(hr) && !pcii->fPreviouslyInstalled)
  1507. {
  1508. TraceTag (ttidClassInst, "Install canceled. Removing...");
  1509. (VOID) HrCiRemoveNonEnumeratedComponent (hinf, hkey, pcii->Class,
  1510. pcii->InstanceGuid, NULL);
  1511. }
  1512. TraceHr (ttidError, FAL, hr, FALSE, "HrCiInstallNonEnumeratedComponent");
  1513. return hr;
  1514. }
  1515. //+--------------------------------------------------------------------------
  1516. //
  1517. // Function: HrCiInstallComponentInternal
  1518. //
  1519. // Purpose: Installs a component
  1520. //
  1521. // Arguments:
  1522. // pcii [in, out] Will be filled with information about the
  1523. // component.
  1524. //
  1525. // Returns: HRESULT. S_OK if successful, error code otherwise
  1526. //
  1527. // Author: billbe 15 Nov 1996
  1528. //
  1529. // Notes:
  1530. //
  1531. HRESULT
  1532. HrCiInstallComponentInternal (
  1533. IN OUT COMPONENT_INSTALL_INFO* pcii)
  1534. {
  1535. HRESULT hr = S_OK;
  1536. HINF hinfInstallFile = NULL;
  1537. HKEY hkeyInstance = NULL;
  1538. TraceTag (ttidClassInst, "Installing %S from %S",
  1539. pcii->pszInfId, pcii->pszInfFile);
  1540. // Open the component's inf file.
  1541. hr = HrSetupOpenInfFile (pcii->pszInfFile, NULL, INF_STYLE_WIN4,
  1542. NULL, &hinfInstallFile);
  1543. // Continue only if we have opened the file.
  1544. if (S_OK == hr)
  1545. {
  1546. // The section we have currently might need to be decorated
  1547. // with OS and Platform specific suffixes. The next call
  1548. // will return the actual decorated section name or our
  1549. // current section name if the decorated one does not exist.
  1550. //
  1551. // Store the original section name pointer so we can restore
  1552. // it after we have finished.
  1553. PCWSTR pszOriginalSectionName = pcii->pszSectionName;
  1554. // Now we get the actual section name.
  1555. //
  1556. WCHAR szActualSection[_MAX_PATH];
  1557. hr = HrSetupDiGetActualSectionToInstallWithBuffer (hinfInstallFile,
  1558. pcii->pszSectionName, szActualSection, _MAX_PATH, NULL,
  1559. NULL);
  1560. if (S_OK == hr)
  1561. {
  1562. pcii->pszSectionName = szActualSection;
  1563. hr = HrCiCreateInstanceKeyAndProcessMainInfSection (
  1564. hinfInstallFile, pcii, &hkeyInstance);
  1565. if (S_OK == hr)
  1566. {
  1567. // Set up the registry with the component info.
  1568. hr = HrCiRegSetComponentInformation (hkeyInstance, pcii);
  1569. if (S_OK == hr)
  1570. {
  1571. // We do different things during install based
  1572. // on whether PnP knows about the component
  1573. // (i.e. enumerated) or not.
  1574. if (FIsEnumerated (pcii->Class))
  1575. {
  1576. hr = HrCiInstallEnumeratedComponent (
  1577. hinfInstallFile, hkeyInstance, *pcii);
  1578. }
  1579. else
  1580. {
  1581. hr = HrCiInstallNonEnumeratedComponent (
  1582. hinfInstallFile, hkeyInstance, pcii);
  1583. }
  1584. }
  1585. RegSafeCloseKey(hkeyInstance);
  1586. }
  1587. // set the section name back
  1588. pcii->pszSectionName = pszOriginalSectionName;
  1589. }
  1590. SetupCloseInfFile(hinfInstallFile);
  1591. }
  1592. TraceHr (ttidError, FAL, hr, FALSE, "HrCiInstallComponentInternal");
  1593. return hr;
  1594. }
  1595. //+--------------------------------------------------------------------------
  1596. //
  1597. // Function: HrCiCallClassInstallerToInstallComponent
  1598. //
  1599. // Purpose: This function invokes the class installer to install an
  1600. // enumerated component.
  1601. //
  1602. // Arguments:
  1603. // hdi [in] See Device Installer docs for more info.
  1604. // pdeid [in]
  1605. //
  1606. // Returns: HRESULT. S_OK if successful, or error code otherwise
  1607. //
  1608. // Author: billbe 28 Apr 1997
  1609. //
  1610. // Notes: This should only be called while the INetCfg lock is held.
  1611. //
  1612. HRESULT
  1613. HrCiCallClassInstallerToInstallComponent(HDEVINFO hdi, PSP_DEVINFO_DATA pdeid)
  1614. {
  1615. HRESULT hr;
  1616. Assert(IsValidHandle(hdi));
  1617. Assert(pdeid);
  1618. // We need to register the device before we do any work on it.
  1619. hr = HrSetupDiCallClassInstaller (DIF_REGISTERDEVICE, hdi, pdeid);
  1620. if (S_OK == hr)
  1621. {
  1622. // Check if we can install of this component. i.e. is the inf
  1623. // a valid Windows 2000 inf.
  1624. hr = HrSetupDiCallClassInstaller (DIF_ALLOW_INSTALL, hdi, pdeid);
  1625. if (S_OK == hr)
  1626. {
  1627. BOOL fFileCopy = TRUE;
  1628. SP_DEVINSTALL_PARAMS deip;
  1629. // Fu fu fu: SetupApi is ignoring DI_NOFILECOPY so we'll overcome
  1630. // their shortcomings and do it ourselves.
  1631. //
  1632. hr = HrSetupDiGetDeviceInstallParams (hdi, pdeid, &deip);
  1633. if (S_OK == hr)
  1634. {
  1635. if (deip.Flags & DI_NOFILECOPY)
  1636. {
  1637. fFileCopy = FALSE;
  1638. }
  1639. }
  1640. if (fFileCopy)
  1641. {
  1642. // Install needed files.
  1643. hr = HrSetupDiCallClassInstaller (DIF_INSTALLDEVICEFILES, hdi,
  1644. pdeid);
  1645. }
  1646. if (S_OK == hr)
  1647. {
  1648. // Now that all files have been copied, we need to set the
  1649. // no file copy flag. Otherwise, setupapi will try to copy
  1650. // files at each dif code. This results in multiple (1 per
  1651. // dif code) unsigned driver popups if the driver was
  1652. // unsigned.
  1653. // We'll only do this if the no copy file flag wasn't already
  1654. // set. i.e. if fFileCopy is TRUE.
  1655. //
  1656. if (fFileCopy)
  1657. {
  1658. // An error here isn't bad enough to stop installation.
  1659. //
  1660. HRESULT hrTemp;
  1661. hrTemp = HrSetupDiSetDeipFlags (hdi, pdeid, DI_NOFILECOPY,
  1662. SDDFT_FLAGS, SDFBO_OR);
  1663. TraceHr (ttidError, FAL, hrTemp, FALSE,
  1664. "HrCiCallClassInstallerToInstallComponent: "
  1665. "HrSetupDiSetDeipFlags");
  1666. }
  1667. // Device co-installers need to be registered at this point
  1668. // so they can do work.
  1669. hr = HrSetupDiCallClassInstaller (DIF_REGISTER_COINSTALLERS,
  1670. hdi, pdeid);
  1671. if (S_OK == hr)
  1672. {
  1673. hr = HrSetupDiCallClassInstaller (DIF_INSTALLINTERFACES,
  1674. hdi, pdeid);
  1675. if (S_OK == hr)
  1676. {
  1677. hr = HrSetupDiCallClassInstaller (DIF_INSTALLDEVICE,
  1678. hdi, pdeid);
  1679. }
  1680. }
  1681. }
  1682. }
  1683. // If we failed for any reason, we need to clean up since
  1684. // we initiated this install.
  1685. if (FAILED(hr))
  1686. {
  1687. ADAPTER_REMOVE_PARAMS arp;
  1688. arp.fBadDevInst = TRUE;
  1689. arp.fNotifyINetCfg = FALSE;
  1690. CiSetReservedField (hdi, pdeid, &arp);
  1691. HrSetupDiCallClassInstaller (DIF_REMOVE, hdi, pdeid);
  1692. CiClearReservedField (hdi, pdeid);
  1693. }
  1694. }
  1695. TraceHr (ttidError, FAL, hr, FALSE,
  1696. "HrCiCallClassInstallerToInstallComponent");
  1697. return hr;
  1698. }
  1699. //+--------------------------------------------------------------------------
  1700. //
  1701. // Function: HrCiInstallComponent
  1702. //
  1703. // Purpose: This function takes a Network Component's Id and its class
  1704. // guid and gathers the information needed by
  1705. // HrCiInstallComponent. Since it is called from INetCfg, we
  1706. // have the write lock
  1707. //
  1708. // Arguments:
  1709. // Params [in] Component install params. See install.h
  1710. // ppComponent [out] A created CComponent representing the installed
  1711. // component.
  1712. // pdwNewCharacter [out] Optional pointer to a DWORD to receive the
  1713. // characteristics of the component.
  1714. //
  1715. // Returns: HRESULT. S_OK is successful, NETCFG_S_REBOOT if a reboot is
  1716. // needed to start the device, or an error code
  1717. //
  1718. // Author: billbe 16 Mar 1997
  1719. //
  1720. // Notes:
  1721. //
  1722. HRESULT
  1723. HrCiInstallComponent (
  1724. IN const COMPONENT_INSTALL_PARAMS& Params,
  1725. OUT CComponent** ppComponent,
  1726. OUT DWORD* pdwNewCharacter)
  1727. {
  1728. Assert (FIsValidNetClass (Params.Class));
  1729. Assert (Params.pszInfId && *Params.pszInfId);
  1730. Assert (!Params.pComponent);
  1731. HRESULT hr = S_OK;
  1732. HDEVINFO hdi = NULL;
  1733. SP_DEVINFO_DATA deid;
  1734. const GUID* pguidClass = MAP_NETCLASS_TO_GUID[Params.Class];
  1735. if (ppComponent)
  1736. {
  1737. *ppComponent = NULL;
  1738. }
  1739. if (pdwNewCharacter)
  1740. {
  1741. *pdwNewCharacter = 0;
  1742. }
  1743. // If we're about to install the component, it better not be in
  1744. // lockdown.
  1745. //
  1746. Assert (!FIsComponentLockedDown (Params.pszInfId));
  1747. // First create a device info set
  1748. hr = HrSetupDiCreateDeviceInfoList (pguidClass, NULL, &hdi);
  1749. if (S_OK == hr)
  1750. {
  1751. // This will create an node in the enum tree for this component.
  1752. // If it is enumerated, we will register it which will make
  1753. // it persist. If non-enumerated, we will not register it and
  1754. // the node will be deleted in the call to SetDiDestroyDeviceInfoList.
  1755. //
  1756. hr = HrCiGetDriverInfo (hdi, &deid, *pguidClass,
  1757. Params.pszInfId, Params.pszInfFile);
  1758. // Get the driver info for the component
  1759. if (S_OK == hr)
  1760. {
  1761. BASIC_COMPONENT_DATA Data = {0};
  1762. Data.Class = Params.Class;
  1763. Data.pszInfId = Params.pszInfId;
  1764. if (FIsEnumerated (Params.Class))
  1765. {
  1766. // If the component is enumerated, we will need a place to
  1767. // store its pnp id.
  1768. WCHAR szPnpId[MAX_DEVICE_ID_LEN];
  1769. ADAPTER_OUT_PARAMS AdapterOutParams;
  1770. ZeroMemory (&AdapterOutParams, sizeof(AdapterOutParams));
  1771. // Net class components have to go through the device
  1772. // installer hook (aka NetClassInstaller)
  1773. //
  1774. if (FInSystemSetup())
  1775. {
  1776. // if we are in GUI mode we need to make the
  1777. // device install quiet and always copy from
  1778. // the source location even if the files are
  1779. // already present. We also need to set
  1780. // the in system setup flag. This is what
  1781. // syssetup would do if it initiated the install
  1782. // so INetCfg initiated installs must do the same.
  1783. //
  1784. // We should also set the parent hwnd.
  1785. //
  1786. SP_DEVINSTALL_PARAMS deip;
  1787. HRESULT hrTemp = HrSetupDiGetDeviceInstallParams (
  1788. hdi, &deid, &deip);
  1789. if (S_OK == hr)
  1790. {
  1791. deip.hwndParent = Params.hwndParent;
  1792. deip.Flags |= DI_QUIETINSTALL | DI_FORCECOPY;
  1793. deip.FlagsEx |= DI_FLAGSEX_IN_SYSTEM_SETUP;
  1794. hrTemp = HrSetupDiSetDeviceInstallParams (
  1795. hdi, &deid, &deip);
  1796. }
  1797. TraceHr (ttidError, FAL, hrTemp, FALSE, "Error "
  1798. "getting and setting device params.");
  1799. }
  1800. CiSetReservedField (hdi, &deid, &AdapterOutParams);
  1801. // Officially call the class installer to install
  1802. // this device
  1803. //
  1804. hr = HrCiCallClassInstallerToInstallComponent (hdi, &deid);
  1805. CiClearReservedField (hdi, &deid);
  1806. Data.dwCharacter = AdapterOutParams.dwCharacter;
  1807. Data.InstanceGuid = AdapterOutParams.InstanceGuid;
  1808. if (S_OK == hr)
  1809. {
  1810. hr = HrSetupDiGetDeviceInstanceId (hdi, &deid, szPnpId,
  1811. MAX_DEVICE_ID_LEN, NULL);
  1812. if (S_OK == hr)
  1813. {
  1814. Data.pszPnpId = szPnpId;
  1815. }
  1816. }
  1817. }
  1818. else // Non-net class components
  1819. {
  1820. COMPONENT_INSTALL_INFO cii;
  1821. PSP_DRVINFO_DETAIL_DATA pdridd = NULL;
  1822. SP_DRVINFO_DATA drid;
  1823. // Now get the driver's detailed information
  1824. hr = HrCiGetDriverDetail (hdi, &deid, &drid, &pdridd);
  1825. if (S_OK == hr)
  1826. {
  1827. ZeroMemory (&cii, sizeof(cii));
  1828. cii.Class = Params.Class;
  1829. cii.pszInfId = Params.pszInfId;
  1830. cii.pszInfFile = pdridd->InfFileName;
  1831. cii.hwndParent = Params.hwndParent;
  1832. cii.pszDescription = drid.Description;
  1833. cii.pszSectionName = pdridd->SectionName;
  1834. HINF hinf;
  1835. hr = HrSetupOpenInfFile (pdridd->InfFileName, NULL,
  1836. INF_STYLE_WIN4, NULL, &hinf);
  1837. if (S_OK == hr)
  1838. {
  1839. // Make sure this is an NT5 inf network inf
  1840. //
  1841. hr = HrSetupIsValidNt5Inf (hinf);
  1842. SetupCloseInfFile (hinf);
  1843. }
  1844. if (S_OK == hr)
  1845. {
  1846. hr = HrCiInstallComponentInternal (&cii);
  1847. if (S_OK == hr)
  1848. {
  1849. Data.InstanceGuid = cii.InstanceGuid;
  1850. Data.dwCharacter = cii.dwCharacter;
  1851. }
  1852. }
  1853. MemFree (pdridd);
  1854. }
  1855. }
  1856. if ((S_OK == hr) && ppComponent) // !previously installed
  1857. {
  1858. CComponent* pComponent;
  1859. hr = CComponent::HrCreateInstance (
  1860. &Data,
  1861. CCI_ENSURE_EXTERNAL_DATA_LOADED,
  1862. Params.pOboToken,
  1863. &pComponent);
  1864. if (S_OK == hr)
  1865. {
  1866. *ppComponent = pComponent;
  1867. }
  1868. }
  1869. if ((S_OK == hr) && pdwNewCharacter)
  1870. {
  1871. *pdwNewCharacter = Data.dwCharacter;
  1872. }
  1873. }
  1874. SetupDiDestroyDeviceInfoList(hdi);
  1875. }
  1876. #ifdef ENABLETRACE
  1877. if (S_OK == hr)
  1878. {
  1879. TraceTag(ttidClassInst, "Component now installed!");
  1880. }
  1881. #endif //ENABLETRACE
  1882. TraceHr (ttidError, FAL, hr, FALSE,
  1883. "HrCiInstallComponent (%S)", Params.pszInfId);
  1884. return hr;
  1885. }
  1886. //+--------------------------------------------------------------------------
  1887. //
  1888. // Function: SetBadDriverFlagIfNeededInList
  1889. //
  1890. // Purpose: Enumerates a driver list setting the DNF_BAD_DRIVER flag
  1891. // in every node that has a DNF_EXCLUDEFROMLIST flag.
  1892. //
  1893. // Arguments:
  1894. // hdi [in] See Device Installer Api documentaion for details
  1895. //
  1896. // Returns: HRESULT. S_OK
  1897. //
  1898. // Author: billbe 24 Nov 1998
  1899. //
  1900. // Notes: SetupDi forces us to use the DNF_BAD_DRIVER flag for non-netdevice
  1901. // classes if we want to exclude them from the select device dialog.
  1902. // This means to non-netclass components that
  1903. // DNF_BAD_DRIVER = DNF_EXCLUDEFROMLIST.
  1904. //
  1905. VOID
  1906. SetBadDriverFlagIfNeededInList(HDEVINFO hdi)
  1907. {
  1908. Assert(IsValidHandle(hdi));
  1909. HRESULT hr = S_OK;
  1910. SP_DRVINSTALL_PARAMS drip;
  1911. SP_DRVINFO_DATA drid;
  1912. DWORD dwIndex = 0;
  1913. // Enumerate each driver in hdi
  1914. while (S_OK == (hr = HrSetupDiEnumDriverInfo(hdi, NULL,
  1915. SPDIT_CLASSDRIVER, dwIndex++, &drid)))
  1916. {
  1917. hr = HrSetupDiGetDriverInstallParams(hdi, NULL, &drid, &drip);
  1918. if (S_OK == hr)
  1919. {
  1920. // If the driver already has the bad driver flag set,
  1921. // go on to the next one.
  1922. if (drip.Flags & DNF_BAD_DRIVER)
  1923. {
  1924. continue;
  1925. }
  1926. // If the driver has the exclude flag set, then set the
  1927. // bad driver flag.
  1928. if (drip.Flags & DNF_EXCLUDEFROMLIST)
  1929. {
  1930. drip.Flags |= DNF_BAD_DRIVER;
  1931. (VOID) HrSetupDiSetDriverInstallParams(hdi, NULL, &drid,
  1932. &drip);
  1933. }
  1934. }
  1935. }
  1936. if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
  1937. {
  1938. hr = S_OK;
  1939. }
  1940. TraceHr (ttidError, FAL, hr, FALSE, "SetBadDriverFlagIfNeededInList");
  1941. }
  1942. //+--------------------------------------------------------------------------
  1943. //
  1944. // Function: HrCiExcludeNonNetClassDriverFromSelectUsingInfId
  1945. //
  1946. // Purpose: Locates a driver in a driver list and sets its exclude from
  1947. // select flag.
  1948. //
  1949. // Arguments:
  1950. // hdi [in] See Device Installer Api documentaion for details
  1951. // pszInfId [in] The INF id of the component to exclude
  1952. //
  1953. // Returns: HRESULT. S_OK
  1954. //
  1955. // Author: billbe 29 Oct 1998
  1956. //
  1957. // Notes:
  1958. //
  1959. HRESULT
  1960. HrCiExcludeNonNetClassDriverFromSelectUsingInfId(
  1961. IN HDEVINFO hdi,
  1962. IN PCWSTR pszInfId)
  1963. {
  1964. Assert(IsValidHandle(hdi));
  1965. Assert(pszInfId);
  1966. HRESULT hr = S_OK;
  1967. SP_DRVINSTALL_PARAMS drip;
  1968. SP_DRVINFO_DATA drid;
  1969. PSP_DRVINFO_DETAIL_DATA pdridd;
  1970. DWORD dwIndex = 0;
  1971. // Enumerate each driver in hdi
  1972. while (S_OK == (hr = HrSetupDiEnumDriverInfo (hdi, NULL,
  1973. SPDIT_CLASSDRIVER, dwIndex++, &drid)))
  1974. {
  1975. (VOID) HrSetupDiGetDriverInstallParams (hdi, NULL, &drid, &drip);
  1976. // If the driver is already excluded for some other reason
  1977. // don't bother trying to determine if it should be excluded.
  1978. // Note that setupdi forces us to use DNF_BAD_DRIVER to exclude
  1979. // non-device drivers rather than using DNF_EXCLUDEFROMLIST.
  1980. if (drip.Flags & DNF_BAD_DRIVER)
  1981. {
  1982. continue;
  1983. }
  1984. // Get driver detail info
  1985. hr = HrSetupDiGetDriverInfoDetail (hdi, NULL, &drid, &pdridd);
  1986. if (S_OK == hr)
  1987. {
  1988. // If the IDs match, exclude it from the dialog
  1989. //
  1990. if (0 == lstrcmpiW (pdridd->HardwareID, pszInfId))
  1991. {
  1992. // Non-device drivers can't use DNF_EXCLUDEFROMLIST
  1993. // and must use DNF_BAD_DRIVER.
  1994. drip.Flags |= DNF_BAD_DRIVER;
  1995. (VOID) HrSetupDiSetDriverInstallParams (hdi, NULL,
  1996. &drid, &drip);
  1997. }
  1998. MemFree (pdridd);
  1999. }
  2000. }
  2001. if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
  2002. {
  2003. hr = S_OK;
  2004. }
  2005. TraceHr (ttidError, FAL, hr, FALSE,
  2006. "HrCiExcludeNonNetClassDriverFromSelectUsingInfId");
  2007. return hr;
  2008. }
  2009. //+---------------------------------------------------------------------------
  2010. //
  2011. // Function: ExcludeLockedDownComponents
  2012. //
  2013. // Purpose: A callback function compatible with EnumLockedDownComponents
  2014. // that is used to exclude locked down components from
  2015. // selection. Called from HrCiPrepareSelectDeviceDialog.
  2016. // This call back is called for each locked down component.
  2017. //
  2018. // Arguments:
  2019. // pszInfId [in] the INF ID to exclude.
  2020. // pvCallerData [in] the HDEVINFO cast to PVOID
  2021. //
  2022. // Returns: nothing
  2023. //
  2024. // Author: shaunco 24 May 1999
  2025. //
  2026. // Notes: The callback interface was chosen so that the class installer
  2027. // is not burdended with the details of how/where the locked
  2028. // down components are implemented.
  2029. //
  2030. VOID
  2031. CALLBACK
  2032. ExcludeLockedDownComponents (
  2033. IN PCWSTR pszInfId,
  2034. IN PVOID pvCallerData)
  2035. {
  2036. Assert (pszInfId && *pszInfId);
  2037. Assert (pvCallerData);
  2038. HDEVINFO hdi = (HDEVINFO)pvCallerData;
  2039. HrCiExcludeNonNetClassDriverFromSelectUsingInfId (hdi, pszInfId);
  2040. }
  2041. //+--------------------------------------------------------------------------
  2042. //
  2043. // Function: HrCiBuildExcludedDriverList
  2044. //
  2045. // Purpose: Non-Net class components can only be installed once
  2046. // So we need to iterate through the installed
  2047. // components, find their matching driver node in
  2048. // a Device Installer Api built driver list for the class,
  2049. // and set their exclude from select flag. This list
  2050. // will then be given to SetupDiSelectDevice which
  2051. // will not display the nodes with the exclude flag set.
  2052. //
  2053. // Arguments:
  2054. // hdi [in] See Device Installer Api documentaion for details
  2055. // guidClass [in] The class of components to build a driver list for
  2056. // pNetCfg [out] The current network configuration (i.e. what is
  2057. // installed).
  2058. //
  2059. // Returns: HRESULT. S_OK
  2060. //
  2061. // Author: billbe 10 Dec 1996
  2062. //
  2063. // Notes: Device Installer Api builds the driver list by rummaging
  2064. // through the inf directory and finding the components
  2065. // that are in files with the same class guid as the
  2066. // HDEVINFO. This is the same processing done
  2067. // in SetupDiSelectDevice, but the process is
  2068. // not repeated twice because we will give the
  2069. // list we built here to SetupDiSelectDevice.
  2070. //
  2071. HRESULT
  2072. HrCiBuildExcludedDriverList(
  2073. IN HDEVINFO hdi,
  2074. IN NETCLASS Class,
  2075. IN CNetConfig* pNetConfig)
  2076. {
  2077. HRESULT hr;
  2078. Assert(IsValidHandle(hdi));
  2079. Assert(pNetConfig);
  2080. // This might take some time. We are doing the same work as
  2081. // SetupDiSelectDevice would do. When we are done, we will
  2082. // hand the driver list to SetupDiSelectDevice so it won't
  2083. // need to rummage through the inf directory
  2084. //
  2085. CWaitCursor wc;
  2086. // For non-device classes, we need to allow excluded drivers
  2087. // in order to get a list returned.
  2088. hr = HrSetupDiSetDeipFlags(hdi, NULL,
  2089. DI_FLAGSEX_ALLOWEXCLUDEDDRVS,
  2090. SDDFT_FLAGSEX, SDFBO_OR);
  2091. if (S_OK == hr)
  2092. {
  2093. #ifdef ENABLETRACE
  2094. CBenchmark bmrk;
  2095. bmrk.Start("SetupDiBuildDriverInfoList");
  2096. #endif //ENABLETRACE
  2097. hr = HrSetupDiBuildDriverInfoList(hdi, NULL, SPDIT_CLASSDRIVER);
  2098. #ifdef ENABLETRACE
  2099. bmrk.Stop();
  2100. TraceTag(ttidBenchmark, "%s : %s seconds",
  2101. bmrk.SznDescription(), bmrk.SznBenchmarkSeconds(2));
  2102. #endif //ENABLETRACE
  2103. }
  2104. // Go through the network configuration and hide already installed
  2105. // components. Note: We only do this the first time. We show installed
  2106. // components if the user selects Have Disk on the dialog.
  2107. CComponent* pComponent;
  2108. CComponentList::const_iterator iter;
  2109. for (iter = pNetConfig->Core.Components.begin();
  2110. iter != pNetConfig->Core.Components.end();
  2111. iter++)
  2112. {
  2113. pComponent = *iter;
  2114. Assert (pComponent);
  2115. if (Class == pComponent->Class())
  2116. {
  2117. // Hide the driver
  2118. hr = HrCiExcludeNonNetClassDriverFromSelectUsingInfId(
  2119. hdi, pComponent->m_pszInfId);
  2120. }
  2121. }
  2122. TraceHr (ttidError, FAL, hr, FALSE, "HrCiBuildExcludedDriverList");
  2123. return hr;
  2124. }
  2125. //+--------------------------------------------------------------------------
  2126. //
  2127. // Function: HrCiSelectComponent
  2128. //
  2129. // Purpose: This function displays the Select Device dialog for the
  2130. // class of components specified by guidClass. Once the
  2131. // component has been selected, it is installed.. Since
  2132. // this fcn is called from INetCfg, we have the write lock.
  2133. //
  2134. // Arguments:
  2135. // Class [in] The class of components to display in the
  2136. // Select Device dialog
  2137. // hwndParent [in] The HWND of the parent window, used to display
  2138. // the UI
  2139. // pcfi [in] A structure used to determine what
  2140. // components should be filtered out of
  2141. // the select dialog (defined in netcfg.h)
  2142. // ppParams [out] Params used to install the component.
  2143. //
  2144. // Returns: HRESULT. S_OK if successful, S_FALSE if the component
  2145. // selected is being reinstalled instead of fresh
  2146. // installed, an error code otherwise
  2147. //
  2148. // Author: billbe 11 Nov 1996
  2149. //
  2150. // Notes: Filtering is only performed when selecting protocols,
  2151. // services, and clients.
  2152. //
  2153. HRESULT
  2154. HrCiSelectComponent(
  2155. IN NETCLASS Class,
  2156. IN HWND hwndParent,
  2157. IN const CI_FILTER_INFO* pcfi,
  2158. OUT COMPONENT_INSTALL_PARAMS** ppParams)
  2159. {
  2160. Assert (ppParams);
  2161. Assert (!FIsEnumerated (Class));
  2162. HRESULT hr;
  2163. HDEVINFO hdi;
  2164. // We need to create a DeviceInfoSet item to use the SelectDevice dialog.
  2165. hr = HrSetupDiCreateDeviceInfoList(
  2166. MAP_NETCLASS_TO_GUID[Class], hwndParent, &hdi);
  2167. if (S_OK == hr)
  2168. {
  2169. // call the class installer to bring up the select device dialog
  2170. // for enumerated components. This will notify any coinstallers
  2171. //
  2172. // This will be a map of component ids to instance guids
  2173. // for all installed components of Class.
  2174. CNetConfig NetConfig;
  2175. hr = HrLoadNetworkConfigurationFromRegistry (KEY_READ, &NetConfig);
  2176. if (S_OK == hr)
  2177. {
  2178. hr = HrCiBuildExcludedDriverList (hdi, Class, &NetConfig);
  2179. }
  2180. if (S_OK == hr)
  2181. {
  2182. // Store the filter info in the hdi
  2183. CiSetReservedField(hdi, NULL, pcfi);
  2184. // We want the Have disk button, but if the call fails we can
  2185. // still continue
  2186. (VOID) HrSetupDiSetDeipFlags(hdi, NULL, DI_SHOWOEM,
  2187. SDDFT_FLAGS, SDFBO_OR);
  2188. // Bring up the dialog
  2189. hr = HrSetupDiCallClassInstaller(DIF_SELECTDEVICE, hdi, NULL);
  2190. if (S_OK == hr)
  2191. {
  2192. SP_DRVINFO_DATA drid;
  2193. PSP_DRVINFO_DETAIL_DATA pdridd;
  2194. // Now get the driver's detailed information
  2195. hr = HrCiGetDriverDetail (hdi, NULL, &drid, &pdridd);
  2196. if (S_OK == hr)
  2197. {
  2198. DWORD cbInfId = CbOfSzAndTerm(pdridd->HardwareID);
  2199. DWORD cbInfFile = CbOfSzAndTerm(pdridd->InfFileName);
  2200. // Create a component install params structure so we
  2201. // can install the component.
  2202. hr = E_OUTOFMEMORY;
  2203. *ppParams = new (extrabytes, cbInfId + cbInfFile)
  2204. COMPONENT_INSTALL_PARAMS;
  2205. if (*ppParams)
  2206. {
  2207. ZeroMemory (*ppParams,
  2208. sizeof (COMPONENT_INSTALL_PARAMS));
  2209. (*ppParams)->Class = Class;
  2210. (*ppParams)->hwndParent = hwndParent;
  2211. (*ppParams)->pszInfId = (PCWSTR)(*ppParams + 1);
  2212. wcscpy ((PWSTR)(*ppParams)->pszInfId,
  2213. pdridd->HardwareID);
  2214. (*ppParams)->pszInfFile =
  2215. (PCWSTR)((BYTE*)(*ppParams)->pszInfId +
  2216. cbInfId);
  2217. wcscpy ((PWSTR)(*ppParams)->pszInfFile,
  2218. pdridd->InfFileName);
  2219. hr = S_OK;
  2220. }
  2221. MemFree (pdridd);
  2222. }
  2223. }
  2224. // Clear the field so we don't try to destroy it later
  2225. // via DIF_DESTROYPRIVATEDATA
  2226. CiClearReservedField(hdi, NULL);
  2227. }
  2228. SetupDiDestroyDeviceInfoList(hdi);
  2229. }
  2230. TraceHr (ttidError, FAL, hr, HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr,
  2231. "HrCiSelectComponent");
  2232. return hr;
  2233. }
  2234. //+--------------------------------------------------------------------------
  2235. //
  2236. // Function: HrCiHideIrrelevantRasProtocols
  2237. //
  2238. // Purpose: Hides protocols from the SelectDevice dialog that RAS does
  2239. // not interact with.
  2240. //
  2241. // Arguments:
  2242. // hdi [in] Contains a list of available drivers.
  2243. // See Device Installer Api documentation for
  2244. // more info
  2245. // eFilter [in] Either FC_RASSRV or FC_RASCLI.
  2246. //
  2247. // Returns: HRESULT. S_OK if successful, error code otherwise
  2248. //
  2249. // Author: billbe 18 May 1998
  2250. //
  2251. // Notes:
  2252. //
  2253. HRESULT
  2254. HrCiHideIrrelevantRasProtocols (
  2255. IN HDEVINFO hdi,
  2256. IN CI_FILTER_COMPONENT eFilter)
  2257. {
  2258. DWORD dwIndex = 0;
  2259. SP_DRVINFO_DATA drid;
  2260. SP_DRVINSTALL_PARAMS drip;
  2261. PSP_DRVINFO_DETAIL_DATA pdridd;
  2262. HRESULT hr;
  2263. extern const WCHAR c_szInfId_MS_AppleTalk[];
  2264. extern const WCHAR c_szInfId_MS_NetMon[];
  2265. extern const WCHAR c_szInfId_MS_NWIPX[];
  2266. extern const WCHAR c_szInfId_MS_TCPIP[];
  2267. static const WCHAR* const c_aszServerProtocols[] = {
  2268. c_szInfId_MS_AppleTalk,
  2269. c_szInfId_MS_NetMon,
  2270. c_szInfId_MS_NWIPX,
  2271. c_szInfId_MS_TCPIP
  2272. };
  2273. static const WCHAR* const c_aszClientProtocols[] = {
  2274. c_szInfId_MS_NetMon,
  2275. c_szInfId_MS_NWIPX,
  2276. c_szInfId_MS_TCPIP
  2277. };
  2278. Assert ((FC_RASSRV == eFilter) || (FC_RASCLI == eFilter));
  2279. const WCHAR* const* aszProtocols;
  2280. DWORD cProtocols;
  2281. // What we show as available protocols to install differs between
  2282. // ras server and ras client (aka Incoming connectoid and Dial-up).
  2283. //
  2284. if (FC_RASSRV == eFilter)
  2285. {
  2286. aszProtocols = c_aszServerProtocols;
  2287. cProtocols = celems(c_aszServerProtocols);
  2288. }
  2289. else
  2290. {
  2291. aszProtocols = c_aszClientProtocols;
  2292. cProtocols = celems(c_aszClientProtocols);
  2293. }
  2294. // Enumerate each driver in hdi
  2295. while (S_OK == (hr = HrSetupDiEnumDriverInfo(hdi, NULL,
  2296. SPDIT_CLASSDRIVER, dwIndex++, &drid)))
  2297. {
  2298. (VOID) HrSetupDiGetDriverInstallParams(hdi, NULL, &drid, &drip);
  2299. // If the driver is already excluded for some other reason
  2300. // don't bother trying to determine if it should be excluded
  2301. // Note that setupdi forces us to use DNF_BAD_DRIVER to exclude
  2302. // non-device drivers rather than using DNF_EXCLUDEFROMLIST.
  2303. if (drip.Flags & DNF_BAD_DRIVER)
  2304. {
  2305. continue;
  2306. }
  2307. // Get driver detail info
  2308. hr = HrSetupDiGetDriverInfoDetail(hdi, NULL, &drid, &pdridd);
  2309. if (S_OK == hr)
  2310. {
  2311. // go through the list of relevant protocols to find which
  2312. // ones can be shown
  2313. //
  2314. // Assume we are going to hide this protocol
  2315. BOOL fHideProtocol = TRUE;
  2316. for (DWORD i = 0; i < cProtocols; i++)
  2317. {
  2318. // If the protocol is on the guest list, we won't boot
  2319. // it out
  2320. //
  2321. if (0 == _wcsicmp(aszProtocols[i], pdridd->HardwareID))
  2322. {
  2323. fHideProtocol = FALSE;
  2324. }
  2325. }
  2326. if (fHideProtocol)
  2327. {
  2328. // exclude from select
  2329. // Note that setupdi forces us to use DNF_BAD_DRIVER to
  2330. // exclude non-device drivers rather than using
  2331. // DNF_EXCLUDEFROMLIST.
  2332. drip.Flags |= DNF_BAD_DRIVER;
  2333. (VOID) HrSetupDiSetDriverInstallParams(hdi, NULL,
  2334. &drid, &drip);
  2335. }
  2336. MemFree (pdridd);
  2337. }
  2338. }
  2339. if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
  2340. {
  2341. hr = S_OK;
  2342. }
  2343. TraceHr (ttidError, FAL, hr, FALSE, "HrCiHideIrrelevantRasProtocols");
  2344. return hr;
  2345. }
  2346. //+--------------------------------------------------------------------------
  2347. //
  2348. // Function: HrCiHideIrrelevantDrivers
  2349. //
  2350. // Purpose: Enumerates a driver list, opening each driver file and
  2351. // processing its registry entries into a temporary key.
  2352. // The lower range of each driver is then examined for
  2353. // a match with pszUpperRange. If no match is
  2354. // found, the driver's DNF_BAD_DRIVER flag is set
  2355. // which will prevent it from being shown in the
  2356. // Select Device Dialog
  2357. //
  2358. // Arguments:
  2359. // hdi [in] Contains a list of available drivers.
  2360. // See Device Installer Api documentation for
  2361. // more info
  2362. // pszUpperRange [in] The upper range will be used to hide irrelevant
  2363. // drivers.
  2364. //
  2365. // Returns: HRESULT. S_OK if successful, error code otherwise
  2366. //
  2367. // Author: billbe 7 May 1998
  2368. //
  2369. // Notes:
  2370. //
  2371. HRESULT
  2372. HrCiHideIrrelevantDrivers(
  2373. IN HDEVINFO hdi,
  2374. IN PCWSTR pszUpperRange)
  2375. {
  2376. Assert(IsValidHandle(hdi));
  2377. Assert(pszUpperRange);
  2378. static const WCHAR c_szRegKeyTemp[] =
  2379. L"System\\CurrentControlSet\\Control\\Network\\FTempKey";
  2380. // Create a temporary key so we can process each protocol's
  2381. // registry entries in an effort to get its supported
  2382. // lower range of interfaces
  2383. HKEY hkeyTemp;
  2384. HRESULT hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyTemp,
  2385. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
  2386. &hkeyTemp, NULL);
  2387. if (S_OK == hr)
  2388. {
  2389. DWORD dwIndex = 0;
  2390. SP_DRVINFO_DATA drid;
  2391. SP_DRVINSTALL_PARAMS drip;
  2392. HKEY hkeyInterfaces;
  2393. // Enumerate each driver in hdi
  2394. while (S_OK == (hr = HrSetupDiEnumDriverInfo(hdi, NULL,
  2395. SPDIT_CLASSDRIVER, dwIndex++, &drid)))
  2396. {
  2397. (VOID) HrSetupDiGetDriverInstallParams(hdi, NULL, &drid, &drip);
  2398. // If the driver is already excluded for some other reason
  2399. // don't bother trying to determine if it should be exluded.
  2400. // Note that setupdi forces us to use DNF_BAD_DRIVER to exclude
  2401. // non-device drivers rather than using DNF_EXCLUDEFROMLIST.
  2402. if (drip.Flags & DNF_BAD_DRIVER)
  2403. {
  2404. continue;
  2405. }
  2406. // Get driver detail info
  2407. PSP_DRVINFO_DETAIL_DATA pdridd = NULL;
  2408. hr = HrSetupDiGetDriverInfoDetail(hdi, NULL, &drid, &pdridd);
  2409. if (S_OK == hr)
  2410. {
  2411. HINF hinf = NULL;
  2412. // Open the driver inf
  2413. hr = HrSetupOpenInfFile(pdridd->InfFileName,
  2414. NULL, INF_STYLE_WIN4, NULL, &hinf);
  2415. WCHAR szActual[_MAX_PATH];
  2416. if (S_OK == hr)
  2417. {
  2418. // Get the actual install section name (i.e. with
  2419. // os/platform extension if it exists)
  2420. hr = HrSetupDiGetActualSectionToInstallWithBuffer (hinf,
  2421. pdridd->SectionName, szActual, _MAX_PATH, NULL,
  2422. NULL);
  2423. if (S_OK == hr)
  2424. {
  2425. // Run the registry sections into the temporary key
  2426. hr = HrCiInstallFromInfSection(hinf, szActual,
  2427. hkeyTemp, NULL, SPINST_REGISTRY);
  2428. }
  2429. }
  2430. if (S_OK == hr)
  2431. {
  2432. // Open the interfaces key of the driver
  2433. hr = HrRegOpenKeyEx(hkeyTemp, L"Ndi\\Interfaces",
  2434. KEY_ALL_ACCESS, &hkeyInterfaces);
  2435. if (S_OK == hr)
  2436. {
  2437. PWSTR pszLowerRange = NULL;
  2438. // Read the lower interfaces value.
  2439. //
  2440. hr = HrRegQuerySzWithAlloc (hkeyInterfaces,
  2441. L"LowerRange", &pszLowerRange);
  2442. // If we succeeded in reading the list and
  2443. // there is no match with one of the upper
  2444. // interfaces...
  2445. if ((S_OK == hr) &&
  2446. !FSubstringMatch (pszUpperRange,
  2447. pszLowerRange, NULL, NULL))
  2448. {
  2449. // exclude from select
  2450. drip.Flags |= DNF_BAD_DRIVER;
  2451. (VOID) HrSetupDiSetDriverInstallParams(hdi,
  2452. NULL, &drid, &drip);
  2453. }
  2454. // Clear lower interface list for next component
  2455. MemFree(pszLowerRange);
  2456. RegDeleteValue (hkeyInterfaces, L"LowerRange");
  2457. RegCloseKey(hkeyInterfaces);
  2458. }
  2459. }
  2460. SetupCloseInfFileSafe(hinf);
  2461. MemFree (pdridd);
  2462. }
  2463. }
  2464. if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
  2465. {
  2466. hr = S_OK;
  2467. }
  2468. RegCloseKey(hkeyTemp);
  2469. HrRegDeleteKeyTree(HKEY_LOCAL_MACHINE, c_szRegKeyTemp);
  2470. }
  2471. TraceHr (ttidError, FAL, hr, FALSE, "HrCiHideIrrelevantDrivers");
  2472. return hr;
  2473. }
  2474. //+--------------------------------------------------------------------------
  2475. //
  2476. // Function: HrCiSetSelectDeviceDialogStrings
  2477. //
  2478. // Purpose: This function sets the strings displayed in the Select Device
  2479. // dialog based on the class of devices being selected.
  2480. //
  2481. // Arguments:
  2482. // hdi [in] See Device Installer Api
  2483. // pdeid [in]
  2484. // guidClass [in] The class of device being selected
  2485. //
  2486. // Returns: HRESULT. S_OK if successful, an error code otherwise
  2487. //
  2488. // Author: billbe 11 Nov 1996
  2489. //
  2490. // Notes:
  2491. //
  2492. HRESULT
  2493. HrCiSetSelectDeviceDialogStrings(
  2494. IN HDEVINFO hdi,
  2495. IN PSP_DEVINFO_DATA pdeid,
  2496. IN const GUID& guidClass)
  2497. {
  2498. Assert(IsValidHandle(hdi));
  2499. SP_SELECTDEVICE_PARAMS sdep;
  2500. // The strings used in the dialog are specified through the
  2501. // SP_SELECTDEVICE_PARAMS structure
  2502. //
  2503. HRESULT hr = HrSetupDiGetFixedSizeClassInstallParams(hdi, pdeid,
  2504. (PSP_CLASSINSTALL_HEADER)&sdep, sizeof(sdep));
  2505. if (FAILED(hr))
  2506. {
  2507. // If the error is ERROR_NO_CLASSINSTALL_PARAMS then this function
  2508. // didn't really fail since it is possible
  2509. if (SPAPI_E_NO_CLASSINSTALL_PARAMS == hr)
  2510. {
  2511. hr = S_OK;
  2512. }
  2513. }
  2514. else if (DIF_SELECTDEVICE != sdep.ClassInstallHeader.InstallFunction)
  2515. {
  2516. TraceTag(ttidClassInst, "Incorrect function in Class Install Header "
  2517. "Expected DIF_SELECTDEVICE, got %lX",
  2518. sdep.ClassInstallHeader.InstallFunction);
  2519. }
  2520. BOOL fHaveDiskShown = FALSE;
  2521. if (S_OK == hr)
  2522. {
  2523. // Get the install params and check if the DI_SHOWOEM flag is set
  2524. // if so, the Have Disk button will be shown
  2525. //
  2526. SP_DEVINSTALL_PARAMS deip;
  2527. // If the call fails we can still go on unfazed.
  2528. (VOID) HrSetupDiGetDeviceInstallParams(hdi, pdeid, &deip);
  2529. if (deip.Flags & DI_SHOWOEM)
  2530. {
  2531. fHaveDiskShown = TRUE;
  2532. }
  2533. // Now we set the strings based on the type of component we are
  2534. // selecting
  2535. if (GUID_DEVCLASS_NETCLIENT == guidClass)
  2536. {
  2537. wcscpy (sdep.Title, SzLoadIds (IDS_SELECTDEVICECLIENTTITLE));
  2538. wcscpy (sdep.ListLabel,
  2539. SzLoadIds (IDS_SELECTDEVICECLIENTLISTLABEL));
  2540. wcscpy (sdep.Instructions,
  2541. SzLoadIds (IDS_SELECTDEVICECLIENTINSTRUCTIONS));
  2542. }
  2543. else if (GUID_DEVCLASS_NETSERVICE == guidClass)
  2544. {
  2545. wcscpy (sdep.Title, SzLoadIds (IDS_SELECTDEVICESERVICETITLE));
  2546. wcscpy (sdep.ListLabel,
  2547. SzLoadIds (IDS_SELECTDEVICESERVICELISTLABEL));
  2548. wcscpy (sdep.Instructions,
  2549. SzLoadIds (IDS_SELECTDEVICESERVICEINSTRUCTIONS));
  2550. }
  2551. else if (GUID_DEVCLASS_NETTRANS == guidClass)
  2552. {
  2553. wcscpy (sdep.Title, SzLoadIds (IDS_SELECTDEVICEPROTOCOLTITLE));
  2554. wcscpy (sdep.ListLabel,
  2555. SzLoadIds (IDS_SELECTDEVICEPROTOCOLLISTLABEL));
  2556. wcscpy (sdep.Instructions,
  2557. SzLoadIds (IDS_SELECTDEVICEPROTOCOLINSTRUCTIONS));
  2558. }
  2559. else if (GUID_DEVCLASS_NET == guidClass)
  2560. {
  2561. wcscpy (sdep.Title, SzLoadIds (IDS_SELECTDEVICEADAPTERTITLE));
  2562. wcscpy (sdep.SubTitle,
  2563. SzLoadIds (IDS_SELECTDEVICEADAPTERSUBTITLE));
  2564. wcscpy (sdep.ListLabel,
  2565. SzLoadIds (IDS_SELECTDEVICEADAPTERLISTLABEL));
  2566. wcscpy (sdep.Instructions,
  2567. SzLoadIds (IDS_SELECTDEVICEADAPTERINSTRUCTIONS));
  2568. }
  2569. else if (GUID_DEVCLASS_INFRARED == guidClass)
  2570. {
  2571. wcscpy (sdep.Title, SzLoadIds (IDS_SELECTDEVICEINFRAREDTITLE));
  2572. wcscpy (sdep.SubTitle,
  2573. SzLoadIds (IDS_SELECTDEVICEINFRAREDSUBTITLE));
  2574. wcscpy (sdep.ListLabel,
  2575. SzLoadIds (IDS_SELECTDEVICEINFRAREDLISTLABEL));
  2576. wcscpy (sdep.Instructions,
  2577. SzLoadIds (IDS_SELECTDEVICEINFRAREDINSTRUCTIONS));
  2578. }
  2579. else
  2580. {
  2581. // We should never get here
  2582. AssertSz(FALSE, "Invalid Class");
  2583. }
  2584. // If the Have Disk button is shown, we need to add instructions for
  2585. // it
  2586. if (fHaveDiskShown)
  2587. {
  2588. wcscat (sdep.Instructions, SzLoadIds (IDS_HAVEDISK_INSTRUCTIONS));
  2589. }
  2590. sdep.ClassInstallHeader.InstallFunction = DIF_SELECTDEVICE;
  2591. // Now we update the parameters.
  2592. hr = HrSetupDiSetClassInstallParams (hdi, pdeid,
  2593. (PSP_CLASSINSTALL_HEADER)&sdep,
  2594. sizeof(SP_SELECTDEVICE_PARAMS));
  2595. }
  2596. TraceHr (ttidError, FAL, hr, FALSE, "HrCiSetSelectDeviceDialogStrings");
  2597. return hr;
  2598. }
  2599. //+--------------------------------------------------------------------------
  2600. //
  2601. // Function: HrCiPrepareSelectDeviceDialog
  2602. //
  2603. // Purpose: Sets the strings that will appear in the Select Device
  2604. // dialog based on class type. Also, filters out components
  2605. // based on filtering criteria (note: only for non-net
  2606. // class components
  2607. //
  2608. // Arguments:
  2609. // hdi [in] See Device Installer Api documentation for more info
  2610. // pdeid [in]
  2611. //
  2612. // Returns: HRESULT. S_OK if successful, error code otherwise
  2613. //
  2614. // Author: billbe 26 Jun 1997
  2615. //
  2616. // Notes:
  2617. //
  2618. HRESULT
  2619. HrCiPrepareSelectDeviceDialog(
  2620. IN HDEVINFO hdi,
  2621. IN PSP_DEVINFO_DATA pdeid)
  2622. {
  2623. Assert(IsValidHandle(hdi));
  2624. GUID guidClass;
  2625. CI_FILTER_INFO* pcfi;
  2626. HRESULT hr = S_OK;
  2627. static const WCHAR c_szNetwareInfId[] = L"MS_NwClient";
  2628. static const WCHAR c_szQosInfId[] = L"MS_PSched";
  2629. if (pdeid)
  2630. {
  2631. // Get the class guid from the specified device element
  2632. guidClass = pdeid->ClassGuid;
  2633. }
  2634. else
  2635. {
  2636. // otherwise, get it from the hdi
  2637. hr = HrSetupDiGetDeviceInfoListClass (hdi, &guidClass);
  2638. }
  2639. if ((S_OK == hr) && !FIsEnumerated (guidClass))
  2640. {
  2641. // This might take some time. We are doing the same work as
  2642. // SetupDiSelectDevice would do. When we are done, we will
  2643. // hand the driver list to SetupDiSelectDevice so it won't
  2644. // need to rummage through the inf directory
  2645. //
  2646. CWaitCursor wc;
  2647. // For non-device classes, we need to allow excluded drivers
  2648. // in order to get a list returned.
  2649. hr = HrSetupDiSetDeipFlags(hdi, NULL,
  2650. DI_FLAGSEX_ALLOWEXCLUDEDDRVS,
  2651. SDDFT_FLAGSEX, SDFBO_OR);
  2652. if (S_OK == hr)
  2653. {
  2654. #ifdef ENABLETRACE
  2655. CBenchmark bmrk;
  2656. bmrk.Start("SetupDiBuildDriverInfoList");
  2657. #endif //ENABLETRACE
  2658. // If we have already built a driver list, this will return
  2659. // immediately.
  2660. //
  2661. hr = HrSetupDiBuildDriverInfoList(hdi, NULL, SPDIT_CLASSDRIVER);
  2662. #ifdef ENABLETRACE
  2663. bmrk.Stop();
  2664. TraceTag(ttidBenchmark, "%s : %s seconds",
  2665. bmrk.SznDescription(), bmrk.SznBenchmarkSeconds(2));
  2666. #endif //ENABLETRACE
  2667. }
  2668. if (S_OK == hr)
  2669. {
  2670. // Go through every driver node and set DNF_BAD_DRIVER
  2671. // if DNF_EXCLUDEFROMLIST is set. Note: SetupDi forces us
  2672. // to do this for non netclass driver lists.
  2673. SetBadDriverFlagIfNeededInList(hdi);
  2674. // Exclude components that are in lockdown.
  2675. //
  2676. EnumLockedDownComponents (ExcludeLockedDownComponents, hdi);
  2677. SP_DEVINSTALL_PARAMS deip;
  2678. hr = HrSetupDiGetDeviceInstallParams (hdi, pdeid, &deip);
  2679. if (S_OK == hr)
  2680. {
  2681. pcfi = (CI_FILTER_INFO*)deip.ClassInstallReserved;
  2682. // if filter info was present and we are selecting protocols...
  2683. if (pcfi)
  2684. {
  2685. if (GUID_DEVCLASS_NETTRANS == guidClass)
  2686. {
  2687. // If the filter is for lan or atm and pvReserved is
  2688. // not null...
  2689. if (((FC_LAN == pcfi->eFilter) ||
  2690. (FC_ATM == pcfi->eFilter))
  2691. && pcfi->pvReserved)
  2692. {
  2693. // Hide any drivers that can't bind to pvReserved
  2694. hr = HrCiHideIrrelevantDrivers(hdi,
  2695. (PCWSTR)pcfi->pvReserved);
  2696. }
  2697. else if ((FC_RASSRV == pcfi->eFilter) ||
  2698. (FC_RASCLI == pcfi->eFilter))
  2699. {
  2700. // Hide from the select dialog any protocols RAS does
  2701. // not support
  2702. hr = HrCiHideIrrelevantRasProtocols (hdi,
  2703. pcfi->eFilter);
  2704. }
  2705. }
  2706. else if ((GUID_DEVCLASS_NETCLIENT == guidClass) &&
  2707. (FC_ATM == pcfi->eFilter))
  2708. {
  2709. // ATM adapters don't bind to Netware Client so
  2710. // we need to try to hide it from the dialog
  2711. (VOID) HrCiExcludeNonNetClassDriverFromSelectUsingInfId(
  2712. hdi, c_szNetwareInfId);
  2713. }
  2714. else if ((GUID_DEVCLASS_NETSERVICE == guidClass) &&
  2715. (FC_ATM == pcfi->eFilter))
  2716. {
  2717. // ATM adapters don't bind to QoS so try to hide it
  2718. (VOID) HrCiExcludeNonNetClassDriverFromSelectUsingInfId(
  2719. hdi, c_szQosInfId);
  2720. }
  2721. }
  2722. }
  2723. }
  2724. }
  2725. if (S_OK == hr)
  2726. {
  2727. // Set the strings for the Select Device dialog.
  2728. // This is done by changing the parameters in the DeviceInfoSet.
  2729. // The next call will create this InfoSet
  2730. // If the call fails, we can still go on, we'll just have
  2731. // slightly odd descriptions in the dialog. This is done after
  2732. // the section above because strings change based on the existence
  2733. // of the Have Disk button
  2734. (VOID) HrCiSetSelectDeviceDialogStrings(hdi, pdeid, guidClass);
  2735. // Now we need to indicate that we created a class install params
  2736. // header in the structures and set the select device dialog strings
  2737. // in it. If the call fails, we can still proceed though the
  2738. // dialog will appear a bit strange
  2739. (VOID) HrSetupDiSetDeipFlags(hdi, pdeid,
  2740. DI_USECI_SELECTSTRINGS | DI_CLASSINSTALLPARAMS,
  2741. SDDFT_FLAGS, SDFBO_OR);
  2742. }
  2743. TraceHr (ttidError, FAL, hr, FALSE, "HrCiPrepareSelectDeviceDialog");
  2744. return hr;
  2745. }
  2746. HRESULT
  2747. HrCiInstallFilterDevice (
  2748. IN HDEVINFO hdi,
  2749. IN PCWSTR pszInfId,
  2750. IN CComponent* pAdapter,
  2751. IN CComponent* pFilter,
  2752. IN CFilterDevice** ppFilterDevice)
  2753. {
  2754. HRESULT hr;
  2755. SP_DEVINFO_DATA deid;
  2756. Assert (hdi);
  2757. Assert (pszInfId && *pszInfId);
  2758. Assert (pAdapter);
  2759. Assert (FIsEnumerated(pAdapter->Class()));
  2760. Assert (pFilter);
  2761. Assert (pFilter->FIsFilter());
  2762. Assert (NC_NETSERVICE == pFilter->Class());
  2763. Assert (ppFilterDevice);
  2764. *ppFilterDevice = NULL;
  2765. // Initialize the devinfo data corresponding to the driver the
  2766. // caller wants us to install.
  2767. //
  2768. hr = HrCiGetDriverInfo (hdi, &deid, *MAP_NETCLASS_TO_GUID[NC_NET],
  2769. pszInfId, NULL);
  2770. if (S_OK == hr)
  2771. {
  2772. ADAPTER_OUT_PARAMS AdapterOutParams;
  2773. ZeroMemory (&AdapterOutParams, sizeof(AdapterOutParams));
  2774. CiSetReservedField (hdi, &deid, &AdapterOutParams);
  2775. // Perform the installation.
  2776. //
  2777. hr = HrCiCallClassInstallerToInstallComponent (hdi, &deid);
  2778. CiClearReservedField (hdi, &deid);
  2779. if (S_OK == hr)
  2780. {
  2781. WCHAR szInstanceGuid[c_cchGuidWithTerm];
  2782. INT cch;
  2783. HKEY hkeyInstance;
  2784. // Convert the instance guid to a string.
  2785. //
  2786. cch = StringFromGUID2 (
  2787. AdapterOutParams.InstanceGuid,
  2788. szInstanceGuid,
  2789. c_cchGuidWithTerm);
  2790. Assert (c_cchGuidWithTerm == cch);
  2791. // Open the instance key of the newly installed device
  2792. // so we can write the instance guid and the back pointer
  2793. // to the filter.
  2794. //
  2795. hr = HrSetupDiOpenDevRegKey (hdi, &deid,
  2796. DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_WRITE,
  2797. &hkeyInstance);
  2798. if (S_OK == hr)
  2799. {
  2800. // Write the instance guid.
  2801. //
  2802. hr = HrRegSetSz (hkeyInstance, L"NetCfgInstanceId",
  2803. szInstanceGuid);
  2804. // Write the inf id of the parent filter.
  2805. //
  2806. hr = HrRegSetSz (hkeyInstance, L"FilterInfId",
  2807. pFilter->m_pszInfId);
  2808. RegCloseKey (hkeyInstance);
  2809. }
  2810. // Set the friendly name to include the adapter being
  2811. // filtered.
  2812. //
  2813. if (S_OK == hr)
  2814. {
  2815. PWSTR pszFilterDesc;
  2816. hr = HrSetupDiGetDeviceRegistryPropertyWithAlloc (
  2817. hdi, &deid, SPDRP_DEVICEDESC,
  2818. NULL, (BYTE**)&pszFilterDesc);
  2819. if (S_OK == hr)
  2820. {
  2821. #define SZ_NAME_SEP L" - "
  2822. PWSTR pszName;
  2823. ULONG cb;
  2824. // sizeof(SZ_NAME_SEP) includes the NULL-terminator
  2825. // so that will automatically add room for the
  2826. // NULL-terminator we need to allocate for pszName.
  2827. //
  2828. cb = CbOfSzSafe (pAdapter->Ext.PszDescription()) +
  2829. sizeof(SZ_NAME_SEP) +
  2830. CbOfSzSafe (pszFilterDesc);
  2831. pszName = (PWSTR)MemAlloc (cb);
  2832. if (pszName)
  2833. {
  2834. wcscpy (pszName, pAdapter->Ext.PszDescription());
  2835. wcscat (pszName, SZ_NAME_SEP);
  2836. wcscat (pszName, pszFilterDesc);
  2837. Assert (cb == CbOfSzAndTerm(pszName));
  2838. hr = HrSetupDiSetDeviceRegistryProperty (
  2839. hdi, &deid,
  2840. SPDRP_FRIENDLYNAME,
  2841. (const BYTE*)pszName,
  2842. cb);
  2843. MemFree (pszName);
  2844. }
  2845. MemFree (pszFilterDesc);
  2846. }
  2847. // If the above fails, its not a big deal.
  2848. //
  2849. hr = S_OK;
  2850. }
  2851. if (S_OK == hr)
  2852. {
  2853. hr = CFilterDevice::HrCreateInstance (
  2854. pAdapter,
  2855. pFilter,
  2856. &deid,
  2857. szInstanceGuid,
  2858. ppFilterDevice);
  2859. }
  2860. }
  2861. }
  2862. TraceHr (ttidError, FAL, hr, FALSE, "HrCiInstallFilterDevice");
  2863. return hr;
  2864. }
  2865. HRESULT
  2866. HrCiRemoveFilterDevice (
  2867. IN HDEVINFO hdi,
  2868. IN SP_DEVINFO_DATA* pdeid)
  2869. {
  2870. HRESULT hr;
  2871. ADAPTER_REMOVE_PARAMS arp = {0};
  2872. Assert (hdi);
  2873. Assert (pdeid);
  2874. CiSetReservedField (hdi, pdeid, &arp);
  2875. hr = HrSetupDiCallClassInstaller (DIF_REMOVE, hdi, pdeid);
  2876. CiClearReservedField (hdi, pdeid);
  2877. TraceHr (ttidError, FAL, hr, FALSE, "HrCiRemoveFilterDevice");
  2878. return hr;
  2879. }