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.

1162 lines
36 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1999.
  5. //
  6. // File: D I H O O K. C P P
  7. //
  8. // Contents: Class installer functions called via the device installer.
  9. //
  10. // Notes:
  11. //
  12. // Author: billbe 25 Nov 1996
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "adapter.h"
  18. #include "benchmrk.h"
  19. #include "classinst.h"
  20. #include "compdefs.h"
  21. #include "iatl.h"
  22. #include "isdnhook.h"
  23. #include "ncatl.h"
  24. #include "ncreg.h"
  25. #include "nceh.h"
  26. #include "netsetup.h"
  27. #include "resource.h"
  28. #include "util.h"
  29. #include "netconp.h"
  30. EXTERN_C const CLSID CLSID_InstallQueue;
  31. const DWORD c_cmsWaitForINetCfgWrite = 2000;
  32. inline
  33. BOOL
  34. FIsValidErrorFromINetCfgForDiHook (
  35. IN HRESULT hr)
  36. {
  37. return (NETCFG_E_NO_WRITE_LOCK == hr) ||
  38. (NETCFG_E_NEED_REBOOT == hr);
  39. }
  40. inline
  41. BOOL
  42. FIsHandledByClassInstaller(
  43. IN const GUID& guidClass)
  44. {
  45. return FIsEnumerated(guidClass) ||
  46. (GUID_DEVCLASS_NETTRANS == guidClass) ||
  47. (GUID_DEVCLASS_NETCLIENT == guidClass) ||
  48. (GUID_DEVCLASS_NETSERVICE == guidClass);
  49. }
  50. //+--------------------------------------------------------------------------
  51. //
  52. // Function: HrDiAddComponentToINetCfg
  53. //
  54. // Purpose: This function adds or updates a device In InetCfg.
  55. //
  56. // Arguments:
  57. // pinc [in] INetCfg interface
  58. // pinci [in] INetCfgInstaller interface
  59. // guidClass [in] The class guid of the component
  60. // pszwPnpid [in] The pnp instance id of the device
  61. // eType [in] The install type (NCI_INSTALL or NCI_UPDATE)
  62. // pszInstanceGuid [in] The netcfg instance guid of the component
  63. //
  64. // Returns: HRESULT. S_OK if successful, error code otherwise
  65. //
  66. // Author: billbe 29 Jul 1997
  67. //
  68. // Notes:
  69. //
  70. EXTERN_C
  71. HRESULT
  72. WINAPI
  73. HrDiAddComponentToINetCfg(
  74. IN INetCfg* pINetCfg,
  75. IN INetCfgInternalSetup* pInternalSetup,
  76. IN const NIQ_INFO* pInfo)
  77. {
  78. Assert (pINetCfg);
  79. Assert (pInternalSetup);
  80. Assert (pInfo);
  81. Assert (pInfo->pszPnpId && *(pInfo->pszPnpId));
  82. Assert (NCI_REMOVE != pInfo->eType);
  83. HRESULT hr = S_OK;
  84. NC_TRY
  85. {
  86. CComponent* pComponent;
  87. BASIC_COMPONENT_DATA Data;
  88. ZeroMemory (&Data, sizeof(Data));
  89. Data.InstanceGuid = pInfo->InstanceGuid;
  90. Data.Class = NetClassEnumFromGuid (pInfo->ClassGuid);
  91. Data.pszPnpId = pInfo->pszPnpId;
  92. Data.pszInfId = pInfo->pszInfId;
  93. Data.dwCharacter = pInfo->dwCharacter;
  94. Data.dwDeipFlags = pInfo->dwDeipFlags;
  95. hr = CComponent::HrCreateInstance (
  96. &Data,
  97. CCI_ENSURE_EXTERNAL_DATA_LOADED,
  98. NULL,
  99. &pComponent);
  100. if (S_OK == hr)
  101. {
  102. hr = pInternalSetup->EnumeratedComponentInstalled (pComponent);
  103. }
  104. }
  105. NC_CATCH_ALL
  106. {
  107. hr = E_UNEXPECTED;
  108. }
  109. TraceHr (ttidError, FAL, hr, NETCFG_S_REBOOT == hr,
  110. "HrDiAddComponentToINetCfg");
  111. return hr;
  112. }
  113. //+--------------------------------------------------------------------------
  114. //
  115. // Function: HrDiNotifyINetCfgOfInstallation
  116. //
  117. // Purpose: This function notifies INetCfg that a net class component
  118. // has been installed or updated.
  119. //
  120. // Arguments:
  121. // hdi [in] See Device Installer Api for more info
  122. // pdeid [in] See Device Installer Api for more info
  123. // pszwPnpid [in] The pnp instance id of the device
  124. // pszInstanceGuid [in] The netcfg instance guid of the device
  125. // eType [in] NCI_INSTALL if the component was installed
  126. // NCI_UPDATE, if it was updated
  127. //
  128. // Returns: HRESULT. S_OK if successful, error code otherwise
  129. //
  130. // Author: billbe 29 Jul 1997
  131. //
  132. // Notes:
  133. //
  134. HRESULT
  135. HrDiNotifyINetCfgOfInstallation (
  136. IN const NIQ_INFO* pInfo)
  137. {
  138. Assert(pInfo);
  139. Assert((NCI_INSTALL == pInfo->eType) || (NCI_UPDATE == pInfo->eType));
  140. static const WCHAR c_szInstaller[] = L"INetCfg Installer Interface";
  141. INetCfg* pinc;
  142. BOOL fInitCom = TRUE;
  143. BOOL fReboot = FALSE;
  144. #ifdef ENABLETRACE
  145. CBenchmark bmrk2;
  146. bmrk2.Start ("Notifying INetCfg of installation");
  147. #endif //ENABLETRACE
  148. TraceTag(ttidClassInst, "Attempting to notify INetCfg.");
  149. HRESULT hr = HrCreateAndInitializeINetCfg(&fInitCom, &pinc, TRUE,
  150. c_cmsWaitForINetCfgWrite,
  151. c_szInstaller, NULL);
  152. if (S_OK == hr)
  153. {
  154. // Get the INetCfgInternalSetup interface.
  155. INetCfgInternalSetup* pInternalSetup;
  156. hr = pinc->QueryInterface (IID_INetCfgInternalSetup,
  157. (VOID**)&pInternalSetup);
  158. if (S_OK == hr)
  159. {
  160. if (NCI_INSTALL == pInfo->eType)
  161. {
  162. hr = HrDiAddComponentToINetCfg(pinc, pInternalSetup, pInfo);
  163. }
  164. else // NCI_UPDATE
  165. {
  166. hr = pInternalSetup->EnumeratedComponentUpdated (
  167. pInfo->pszPnpId);
  168. }
  169. if (NETCFG_S_REBOOT == hr)
  170. {
  171. fReboot = TRUE;
  172. hr = S_OK;
  173. }
  174. ReleaseObj(pInternalSetup);
  175. }
  176. // Whether we succeeded or not, we are done and it's
  177. // time to clean up. If there was a previous error
  178. // we want to preserve that error code so we assign
  179. // Uninitialize's result to a temporary then assign
  180. // it to hr if there was no previous error.
  181. //
  182. HRESULT hrT = HrUninitializeAndReleaseINetCfg (fInitCom, pinc, TRUE);
  183. hr = (S_OK == hr) ? hrT : hr;
  184. }
  185. if ((S_OK == hr) && fReboot)
  186. {
  187. TraceTag(ttidClassInst, "INetCfg returned NETCFG_S_REBOOT");
  188. hr = NETCFG_S_REBOOT;
  189. }
  190. #ifdef ENABLETRACE
  191. bmrk2.Stop();
  192. TraceTag(ttidBenchmark, "%s : %s seconds",
  193. bmrk2.SznDescription(), bmrk2.SznBenchmarkSeconds(2));
  194. #endif //ENABLETRACE
  195. TraceHr (ttidError, FAL, hr,
  196. NETCFG_S_REBOOT == hr || FIsValidErrorFromINetCfgForDiHook (hr),
  197. "HrDiNotifyINetCfgOfInstallation");
  198. return hr;
  199. }
  200. //+--------------------------------------------------------------------------
  201. //
  202. // Function: InsertItemIntoInstallQueue
  203. //
  204. // Purpose: This function uses the InstallQueue object to insert a
  205. // workitem to be processed at a later time. The workitem:
  206. // a device that was installed, removed, or updated and
  207. // INetCfg needs to be notified.
  208. //
  209. // Arguments:
  210. // pguid [in] The class guid of the device
  211. // pszwDeviceId [in] The Id of the device (PnP instance Id if the device
  212. // was added or updated, its netcfg instance guid if
  213. // it was removed
  214. //
  215. // Returns: hresult. S_OK if successful, an error code otherwise.
  216. //
  217. // Author: billbe 8 Sep 1998
  218. //
  219. // Notes:
  220. //
  221. HRESULT
  222. HrInsertItemIntoInstallQueue (
  223. IN const NIQ_INFO* pInfo)
  224. {
  225. // Initialize COM
  226. BOOL fInitCom = TRUE;
  227. HRESULT hr = CoInitializeEx (NULL, COINIT_MULTITHREADED |
  228. COINIT_DISABLE_OLE1DDE);
  229. // We may have changed mode but that's okay
  230. if (RPC_E_CHANGED_MODE == hr)
  231. {
  232. hr = S_OK;
  233. fInitCom = FALSE;
  234. }
  235. if (SUCCEEDED(hr))
  236. {
  237. // Create the Install Queue object and get the
  238. // INetInstallQueue interface
  239. //
  240. INetInstallQueue* pniq;
  241. hr = HrCreateInstance(
  242. CLSID_InstallQueue,
  243. CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
  244. &pniq);
  245. TraceHr (ttidError, FAL, hr, FALSE, "HrCreateInstance");
  246. if (S_OK == hr)
  247. {
  248. TraceTag (ttidClassInst, "Adding item %S to queue.",
  249. pInfo->pszPnpId);
  250. // Add the device info and the install type to the queue
  251. hr = pniq->AddItem (pInfo);
  252. pniq->Release();
  253. }
  254. if (fInitCom)
  255. {
  256. CoUninitialize();
  257. }
  258. }
  259. TraceHr (ttidError, FAL, hr, FALSE, "InsertItemIntoInstallQueue");
  260. return hr;
  261. }
  262. //+--------------------------------------------------------------------------
  263. //
  264. // Function: HrDiInstallNetAdapter
  265. //
  266. // Purpose: This function preinstalls the NetAdapter, notifies the
  267. // COM interfaces through CINetCfgClass that the
  268. // component was added. Then it finalizes the install
  269. // by applying all changes to INetCfg.
  270. // Arguments:
  271. // hdi [in] See Device Installer Api for more info
  272. // pdeid [in] See Device Installer Api for more info
  273. // hwndParent [in] The handle to the parent window, used for UI
  274. //
  275. // Returns: HRESULT. S_OK if successful, error code otherwise
  276. //
  277. // Author: billbe 24 Apr 1997
  278. //
  279. // Notes:
  280. //
  281. HRESULT
  282. HrDiInstallNetAdapter(
  283. IN COMPONENT_INSTALL_INFO* pcii)
  284. {
  285. HRESULT hr = S_OK;
  286. ADAPTER_OUT_PARAMS* pAdapterOutParams = NULL;
  287. SP_DEVINSTALL_PARAMS deip;
  288. BOOL fNotifyINetCfg = TRUE;
  289. // If we were called from INetCfg, we have to store the results of the
  290. // install in the out params structure placed in the reserved field.
  291. //
  292. (VOID) HrSetupDiGetDeviceInstallParams (pcii->hdi, pcii->pdeid, &deip);
  293. if (deip.ClassInstallReserved)
  294. {
  295. pAdapterOutParams = (ADAPTER_OUT_PARAMS*)deip.ClassInstallReserved;
  296. fNotifyINetCfg = FALSE;
  297. }
  298. PSP_DRVINFO_DETAIL_DATA pdridd = NULL;
  299. SP_DRVINFO_DATA drid;
  300. hr = HrCiGetDriverDetail (pcii->hdi, pcii->pdeid, &drid, &pdridd);
  301. if (S_OK == hr)
  302. {
  303. pcii->pszInfFile = pdridd->InfFileName;
  304. pcii->pszSectionName = pdridd->SectionName;
  305. pcii->pszInfId = pdridd->HardwareID;
  306. pcii->pszDescription = drid.Description;
  307. }
  308. else if (SPAPI_E_NO_DRIVER_SELECTED == hr)
  309. {
  310. // If we are in GUI mode and the device was previously installed,
  311. // then this device should be removed since its inf file could not
  312. // be found.
  313. //
  314. if (FInSystemSetup() &&
  315. (S_OK == HrCiIsInstalledComponent (pcii, NULL)))
  316. {
  317. // This dev node was is being reinstalled but has no driver
  318. // info. In this case, we are going to remove the devnode.
  319. TraceTag (ttidClassInst, "We are in GUI mode and were told to "
  320. "install a device that has no driver. We will remove "
  321. "device instead.");
  322. // We need to set the reserved field in the pdeid so that the
  323. // remove code will know that this is a bad instance that
  324. // should be removed regardless of the NCF_NOT_USER_REMOVABLE
  325. // characteristic.
  326. //
  327. ADAPTER_REMOVE_PARAMS arp;
  328. arp.fBadDevInst = TRUE;
  329. arp.fNotifyINetCfg = fNotifyINetCfg;
  330. CiSetReservedField (pcii->hdi, pcii->pdeid, &arp);
  331. (VOID) HrSetupDiCallClassInstaller (DIF_REMOVE,
  332. pcii->hdi, pcii->pdeid);
  333. CiClearReservedField (pcii->hdi, pcii->pdeid);
  334. }
  335. }
  336. if (S_OK == hr)
  337. {
  338. TraceTag (ttidClassInst, "Calling HrCiInstallComponentInternal");
  339. #ifdef ENABLETRACE
  340. CBenchmark bmrk1;
  341. bmrk1.Start ("HrCiInstallComponentInternal");
  342. #endif //ENABLETRACE
  343. // Install (or reinstall) the component
  344. hr = HrCiInstallComponentInternal (pcii);
  345. #ifdef ENABLETRACE
  346. bmrk1.Stop();
  347. TraceTag (ttidBenchmark, "%s : %s seconds",
  348. bmrk1.SznDescription(), bmrk1.SznBenchmarkSeconds (2));
  349. #endif //ENABLETRACE
  350. // if we have succeeded so far and we have to notify INetcfg.
  351. // We also have to update the NT4 legacy registry for adapters.
  352. // Note that this is not done for filter devices.
  353. if (S_OK == hr)
  354. {
  355. if (fNotifyINetCfg && !FIsFilterDevice (pcii->hdi, pcii->pdeid))
  356. {
  357. NIQ_INFO Info;
  358. ZeroMemory(&Info, sizeof (Info));
  359. Info.eType = pcii->fPreviouslyInstalled ?
  360. NCI_UPDATE : NCI_INSTALL;
  361. Info.ClassGuid = pcii->pdeid->ClassGuid;
  362. Info.InstanceGuid = pcii->InstanceGuid;
  363. Info.dwCharacter = pcii->dwCharacter;
  364. Info.dwDeipFlags = deip.Flags;
  365. Info.pszInfId = pcii->pszInfId;
  366. Info.pszPnpId = pcii->pszPnpId;
  367. hr = HrDiNotifyINetCfgOfInstallation (&Info);
  368. if (FIsValidErrorFromINetCfgForDiHook (hr))
  369. {
  370. WCHAR szGuid[c_cchGuidWithTerm];
  371. INT cch = StringFromGUID2 (pcii->InstanceGuid, szGuid,
  372. c_cchGuidWithTerm);
  373. Assert (c_cchGuidWithTerm == cch);
  374. // use queue
  375. hr = HrInsertItemIntoInstallQueue (&Info);
  376. }
  377. else if (NETCFG_S_REBOOT == hr)
  378. {
  379. (VOID) HrSetupDiSetDeipFlags (pcii->hdi, pcii->pdeid,
  380. DI_NEEDREBOOT, SDDFT_FLAGS, SDFBO_OR);
  381. hr = S_OK;
  382. }
  383. }
  384. else // !fNotifyINetCfg or is a filter device.
  385. {
  386. // Since we installed this enumerated device from INetCfg
  387. // we need to set the out params so they can be retrieved
  388. // when DIF_INSTALLDEVICE has finished.
  389. //
  390. if (pAdapterOutParams)
  391. {
  392. Assert (!pcii->fPreviouslyInstalled);
  393. pAdapterOutParams->dwCharacter = pcii->dwCharacter;
  394. pAdapterOutParams->InstanceGuid = pcii->InstanceGuid;
  395. }
  396. }
  397. // Write out the NT4 legacy registry info for app. compatibility.
  398. // Note, we only do this for physical net devices.
  399. if ((NCF_PHYSICAL & pcii->dwCharacter) &&
  400. (GUID_DEVCLASS_NET == pcii->pdeid->ClassGuid))
  401. {
  402. AddOrRemoveLegacyNt4AdapterKey (pcii->hdi, pcii->pdeid,
  403. &pcii->InstanceGuid, pcii->pszDescription,
  404. LEGACY_NT4_KEY_ADD);
  405. }
  406. }
  407. MemFree (pdridd);
  408. }
  409. // All success codes should be mapped to S_OK since they have no meaning
  410. // along this code path.
  411. if (SUCCEEDED(hr))
  412. {
  413. hr = S_OK;
  414. }
  415. TraceHr (ttidError, FAL, hr, FALSE, "HrDiInstallNetAdapter");
  416. return hr;
  417. }
  418. //+--------------------------------------------------------------------------
  419. //
  420. // Function: HrDiNotifyINetCfgOfRemoval
  421. //
  422. // Purpose: This function notifies INetCfg that a net class component has
  423. // been removed
  424. //
  425. // Arguments:
  426. // hdi [in] See Device Installer api for more info
  427. // pdeid [in]
  428. // szInstanceGuid [in] The instance guid of the component
  429. //
  430. // Returns: HRESULT. S_OK if successful, error code otherwise
  431. //
  432. // Author: billbe 29 Jul 1997
  433. //
  434. // Notes:
  435. //
  436. HRESULT
  437. HrDiNotifyINetCfgOfRemoval (
  438. IN PCWSTR pszPnpId)
  439. {
  440. static const WCHAR c_szUninstaller[] = L"INetCfg UnInstaller Interface";
  441. INetCfg* pINetCfg;
  442. BOOL fInitCom = TRUE;
  443. HRESULT hr = HrCreateAndInitializeINetCfg(&fInitCom, &pINetCfg, TRUE,
  444. c_cmsWaitForINetCfgWrite, c_szUninstaller, NULL);
  445. if (SUCCEEDED(hr))
  446. {
  447. BOOL fNeedReboot = FALSE;
  448. // Get the INetCfgInternalSetup interface.
  449. INetCfgInternalSetup* pInternalSetup;
  450. hr = pINetCfg->QueryInterface (IID_INetCfgInternalSetup,
  451. (VOID**)&pInternalSetup);
  452. if (SUCCEEDED(hr))
  453. {
  454. hr = pInternalSetup->EnumeratedComponentRemoved (pszPnpId);
  455. if (NETCFG_S_REBOOT == hr)
  456. {
  457. fNeedReboot = TRUE;
  458. }
  459. }
  460. // Whether we succeeded or not, we are done and it's
  461. // time to clean up. If there was a previous error
  462. // we want to preserve that error code so we assign
  463. // Uninitialize's result to a temporary then assign
  464. // it to hr if there was no previous error.
  465. //
  466. HRESULT hrT = HrUninitializeAndReleaseINetCfg (TRUE, pINetCfg, TRUE);
  467. // If everything was successful then set the return value to be
  468. // the return of HrUninitializeAndReleaseINetCfg
  469. hr = SUCCEEDED(hr) ? hrT : hr;
  470. if (SUCCEEDED(hr) && fNeedReboot)
  471. {
  472. hr = NETCFG_S_REBOOT;
  473. }
  474. }
  475. TraceHr (ttidError, FAL, hr,
  476. NETCFG_S_REBOOT == hr || FIsValidErrorFromINetCfgForDiHook (hr),
  477. "HrNcNotifyINetCfgOfRemoval");
  478. return hr;
  479. }
  480. VOID
  481. StoreInfoForINetCfg (
  482. IN HKEY hkeyInstance)
  483. {
  484. HKEY hkeyInterfaceStore = NULL;
  485. HKEY hkeyNdiStore = NULL;
  486. WCHAR szGuid[c_cchGuidWithTerm];
  487. DWORD cbGuid = sizeof (szGuid);
  488. WCHAR szNdiPath[_MAX_PATH];
  489. HRESULT hr = HrRegQuerySzBuffer (hkeyInstance, L"NetCfgInstanceId", szGuid,
  490. &cbGuid);
  491. if (S_OK == hr)
  492. {
  493. wcscpy (szNdiPath,
  494. c_szTempNetcfgStorageForUninstalledEnumeratedComponent);
  495. wcscat (szNdiPath, szGuid);
  496. wcscat (szNdiPath, L"\\Ndi");
  497. hr = HrRegCreateKeyEx (HKEY_LOCAL_MACHINE, szNdiPath,
  498. REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
  499. &hkeyNdiStore, NULL);
  500. if (S_OK == hr)
  501. {
  502. hr = HrRegCreateKeyEx (hkeyNdiStore, L"Interfaces",
  503. REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
  504. &hkeyInterfaceStore, NULL);
  505. }
  506. }
  507. if (S_OK == hr)
  508. {
  509. HKEY hkeyNdi;
  510. hr = HrRegOpenKeyEx (hkeyInstance, L"Ndi", KEY_READ, &hkeyNdi);
  511. if (S_OK == hr)
  512. {
  513. PWSTR pszRequiredList;
  514. hr = HrRegQuerySzWithAlloc (hkeyNdi, L"RequiredAll",
  515. &pszRequiredList);
  516. if (S_OK == hr)
  517. {
  518. hr = HrRegSetSz (hkeyNdiStore, L"RequiredAll",
  519. pszRequiredList);
  520. MemFree (pszRequiredList);
  521. }
  522. if (HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND) == hr)
  523. {
  524. hr = S_OK;
  525. }
  526. TraceHr (ttidError, FAL, hr, FALSE, "Writing RequiredAll key "
  527. "for INetCfg removal notify");
  528. RegCloseKey (hkeyNdi);
  529. }
  530. HKEY hkeyInterfaces;
  531. hr = HrRegOpenKeyEx (hkeyInstance, L"Ndi\\Interfaces", KEY_READ,
  532. &hkeyInterfaces);
  533. if (S_OK == hr)
  534. {
  535. PWSTR pszUpper;
  536. PWSTR pszLower;
  537. hr = HrRegQuerySzWithAlloc (hkeyInterfaces, L"UpperRange",
  538. &pszUpper);
  539. if (S_OK == hr)
  540. {
  541. (VOID) HrRegSetSz (hkeyInterfaceStore, L"UpperRange",
  542. pszUpper);
  543. MemFree ((VOID*) pszUpper);
  544. }
  545. hr = HrRegQuerySzWithAlloc (hkeyInterfaces, L"LowerRange",
  546. &pszLower);
  547. if (S_OK == hr)
  548. {
  549. (VOID) HrRegSetSz (hkeyInterfaceStore, L"LowerRange",
  550. pszLower);
  551. MemFree ((VOID*) pszLower);
  552. }
  553. RegCloseKey (hkeyInterfaces);
  554. }
  555. }
  556. RegSafeCloseKey (hkeyInterfaceStore);
  557. RegSafeCloseKey (hkeyNdiStore);
  558. }
  559. //+--------------------------------------------------------------------------
  560. //
  561. // Function: HrDiRemoveNetAdapter
  562. //
  563. // Purpose: This function removes a net adapter, notifies the
  564. // COM interfaces through CINetCfgClass that the
  565. // component was removed. Then it finalizes the remove
  566. // by applying all changes to INetCfg.
  567. // Arguments:
  568. // hdi [in] See Device Installer Api for more info
  569. // pdeid [in] See Device Installer Api for more info
  570. // pszPnPId [in] The pnp instance id of the adapter
  571. // hwndParent [in] The handle to the parent window, used for UI
  572. //
  573. // Returns: HRESULT. S_OK if successful, error code otherwise
  574. //
  575. // Author: billbe 24 Apr 1997
  576. //
  577. // Notes:
  578. //
  579. HRESULT
  580. HrDiRemoveNetAdapter (HDEVINFO hdi, PSP_DEVINFO_DATA pdeid,
  581. PWSTR pszPnpId, HWND hwndParent)
  582. {
  583. BOOL fAllowRemove = TRUE;
  584. SP_DEVINSTALL_PARAMS deip;
  585. BOOL fNotifyINetCfg = TRUE;
  586. BOOL fBadDevInst = FALSE;
  587. HRESULT hr = S_OK;
  588. // Check for the existence of a CComponentInfo and retrieve the
  589. // value of the write lock flag
  590. //
  591. (VOID) HrSetupDiGetDeviceInstallParams (hdi, pdeid, &deip);
  592. if (deip.ClassInstallReserved)
  593. {
  594. ADAPTER_REMOVE_PARAMS* parp = reinterpret_cast<ADAPTER_REMOVE_PARAMS*>
  595. (deip.ClassInstallReserved);
  596. fNotifyINetCfg = parp->fNotifyINetCfg;
  597. fBadDevInst = parp->fBadDevInst;
  598. }
  599. if (fNotifyINetCfg)
  600. {
  601. // The component is not being removed programmatically (we can tell
  602. // this because we wouldn't have to notify INetCfg if it was
  603. // being removed through INetCfg). Because of this. we have to
  604. // make sure the user is allowed to do this by checking the
  605. // component's characteristics
  606. //
  607. HKEY hkey;
  608. hr = HrSetupDiOpenDevRegKey (hdi, pdeid, DICS_FLAG_GLOBAL, 0,
  609. DIREG_DRV, KEY_READ, &hkey);
  610. if (S_OK == hr)
  611. {
  612. // If we are removing a bad device instance, don't bother
  613. // checking if we are allowed to. We need to get rid of it.
  614. //
  615. if (!fBadDevInst)
  616. {
  617. DWORD dwCharacter;
  618. hr = HrRegQueryDword (hkey, L"Characteristics", &dwCharacter);
  619. if (S_OK == hr)
  620. {
  621. // Is the not removable characteristic present?
  622. fAllowRemove = !(dwCharacter & NCF_NOT_USER_REMOVABLE);
  623. }
  624. }
  625. if (fAllowRemove)
  626. {
  627. StoreInfoForINetCfg (hkey);
  628. // We need to remove this adapter from the old NT4 registry
  629. // location.
  630. //
  631. if (GUID_DEVCLASS_NET == pdeid->ClassGuid)
  632. {
  633. AddOrRemoveLegacyNt4AdapterKey (hdi, pdeid, NULL, NULL,
  634. LEGACY_NT4_KEY_REMOVE);
  635. }
  636. }
  637. else
  638. {
  639. hr = HRESULT_FROM_WIN32 (ERROR_ACCESS_DENIED);
  640. TraceTag (ttidClassInst, "User is trying to remove a "
  641. "non user-removable device.");
  642. }
  643. RegCloseKey (hkey);
  644. }
  645. else if (SPAPI_E_KEY_DOES_NOT_EXIST == hr)
  646. {
  647. hr = S_OK;
  648. }
  649. }
  650. if ((S_OK == hr) && fAllowRemove)
  651. {
  652. // Remove the device
  653. //
  654. // Open the device's device parameters key
  655. //
  656. HKEY hkeyDevice;
  657. hr = HrSetupDiOpenDevRegKey (hdi, pdeid, DICS_FLAG_GLOBAL,
  658. 0, DIREG_DEV, KEY_READ, &hkeyDevice);
  659. if (S_OK == hr)
  660. {
  661. // Delete this adapter's index number from the in-use list
  662. // so it can be reused.
  663. //
  664. // First retrieve the index
  665. //
  666. DWORD dwInstanceIndex;
  667. hr = HrRegQueryDword (hkeyDevice, L"InstanceIndex",
  668. &dwInstanceIndex);
  669. if (S_OK == hr)
  670. {
  671. // Get the description for the adapter so we can
  672. // access the index list of that description
  673. //
  674. PWSTR pszDescription;
  675. hr = HrSetupDiGetDeviceRegistryPropertyWithAlloc (hdi, pdeid,
  676. SPDRP_DEVICEDESC, NULL,
  677. (BYTE**)&pszDescription);
  678. if (S_OK == hr)
  679. {
  680. // Delete the index
  681. (VOID) HrCiUpdateDescriptionIndexList (
  682. NetClassEnumFromGuid(pdeid->ClassGuid),
  683. pszDescription, DM_DELETE,
  684. &dwInstanceIndex);
  685. MemFree (pszDescription);
  686. }
  687. }
  688. RegCloseKey (hkeyDevice);
  689. }
  690. // Note: Yes we can walk over the last hr result.
  691. // We can still go on even if we failed to remove the index
  692. // from the in-use list.
  693. // remove the adapter
  694. #ifdef ENABLETRACE
  695. CBenchmark bmrk;
  696. bmrk.Start ("SetupDiRemoveDevice");
  697. #endif //ENABLETRACE
  698. hr = HrSetupDiRemoveDevice (hdi, pdeid);
  699. #ifdef ENABLETRACE
  700. bmrk.Stop();
  701. TraceTag(ttidBenchmark, "%s : %s seconds",
  702. bmrk.SznDescription(), bmrk.SznBenchmarkSeconds(2));
  703. #endif //ENABLETRACE
  704. TraceHr (ttidError, FAL, hr, FALSE,
  705. "HrRemoveNetAdapter::HrSetupDiRemoveDevice");
  706. // Notify INetCfg if needed.
  707. if ((S_OK == hr) && fNotifyINetCfg)
  708. {
  709. hr = HrDiNotifyINetCfgOfRemoval (pszPnpId);
  710. if (FIsValidErrorFromINetCfgForDiHook (hr))
  711. {
  712. NIQ_INFO Info;
  713. ZeroMemory(&Info, sizeof(Info));
  714. Info.ClassGuid = pdeid->ClassGuid;
  715. Info.eType = NCI_REMOVE;
  716. Info.pszInfId = L"";
  717. Info.pszPnpId = pszPnpId;
  718. // Use Queue
  719. hr = HrInsertItemIntoInstallQueue (&Info);
  720. }
  721. if (NETCFG_S_REBOOT == hr)
  722. {
  723. (VOID) HrSetupDiSetDeipFlags (hdi, pdeid, DI_NEEDREBOOT,
  724. SDDFT_FLAGS, SDFBO_OR);
  725. hr = S_OK;
  726. }
  727. }
  728. }
  729. if(SUCCEEDED(hr) && GUID_DEVCLASS_NET == pdeid->ClassGuid)
  730. {
  731. INetConnectionRefresh * pRefresh = NULL;
  732. HRESULT hrTemp = HrCreateInstance(
  733. CLSID_ConnectionManager,
  734. CLSCTX_LOCAL_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
  735. &pRefresh);
  736. if(SUCCEEDED(hrTemp))
  737. {
  738. hrTemp = pRefresh->RefreshAll();
  739. ReleaseObj(pRefresh);
  740. }
  741. }
  742. TraceHr (ttidError, FAL, hr, FALSE, "HrDiRemoveNetAdapter");
  743. return hr;
  744. }
  745. //+--------------------------------------------------------------------------
  746. //
  747. // Function: HrNetClassInstaller
  748. //
  749. // Purpose: This function is called by the Device Installer for a
  750. // variety of functions defined by dif.
  751. // See SetupDiCallClassInstaller in the Device Installer
  752. // documentation for more information.
  753. // Arguments:
  754. // dif [in] See Device Installer Api
  755. // hdi [in]
  756. // pdeid [in]
  757. //
  758. // Returns: DWORD. Win32/Device Installer error code
  759. //
  760. // Author: billbe 8 May 1997
  761. //
  762. // Notes:
  763. //
  764. HRESULT _HrNetClassInstaller(DI_FUNCTION dif,
  765. HDEVINFO hdi,
  766. PSP_DEVINFO_DATA pdeid)
  767. {
  768. HRESULT hr = SPAPI_E_DI_DO_DEFAULT;
  769. // The time it takes to remove a device.
  770. static const DWORD c_cmsNetComponentRemove = 30000;
  771. if ((DIF_INSTALLDEVICE == dif) || (DIF_REMOVE == dif))
  772. {
  773. WCHAR szPnpId[MAX_DEVICE_ID_LEN] = {0};
  774. hr = HrSetupDiGetDeviceInstanceId(hdi, pdeid, szPnpId,
  775. MAX_DEVICE_ID_LEN, NULL);
  776. if (S_OK == hr)
  777. {
  778. #ifdef DBG
  779. if (FIsDebugFlagSet (dfidBreakOnNetInstall))
  780. {
  781. AssertSz(FALSE, "THIS IS NOT A BUG! The debug flag "
  782. "\"BreakOnNetInstall\" has been set. Set your breakpoints now.");
  783. }
  784. #endif // DBG
  785. HWND hwndParent = NULL;
  786. // If this call fails we don't really care since it is a convenience.
  787. (VOID) HrSetupDiGetParentWindow (hdi, pdeid, &hwndParent);
  788. #ifdef ENABLETRACE
  789. CBenchmark bmrk;
  790. const int c_cchBenchmarkDesc = 156;
  791. CHAR szBenchmarkDesc[c_cchBenchmarkDesc];
  792. #endif // ENABLETRACE
  793. if (DIF_INSTALLDEVICE == dif)
  794. {
  795. COMPONENT_INSTALL_INFO cii;
  796. ZeroMemory(&cii, sizeof(cii));
  797. cii.hwndParent = hwndParent;
  798. cii.hdi = hdi;
  799. cii.pdeid = pdeid;
  800. cii.Class = NetClassEnumFromGuid (pdeid->ClassGuid);
  801. cii.BusType = InterfaceTypeUndefined;
  802. cii.InstanceGuid = GUID_NULL;
  803. cii.pszPnpId = szPnpId;
  804. #ifdef ENABLETRACE
  805. TraceTag (ttidClassInst, "Installing %S", szPnpId);
  806. _snprintf (szBenchmarkDesc, c_cchBenchmarkDesc,
  807. "Installing %S", szPnpId);
  808. bmrk.Start (szBenchmarkDesc);
  809. #endif // ENABLETRACE
  810. // Add the adapter to the network configuration.
  811. hr = HrDiInstallNetAdapter (&cii);
  812. }
  813. else // DIF_REMOVEDEVICE
  814. {
  815. #ifdef ENABLETRACE
  816. TraceTag (ttidClassInst, "Removing %S", szPnpId);
  817. _snprintf (szBenchmarkDesc, c_cchBenchmarkDesc,
  818. "Total Time Removing %S", szPnpId);
  819. #endif //ENABLETRACE
  820. // We need to reset the hresult from SPAPI_E_DO_DEFAULT to S_OK
  821. // since we check for success a bit later.
  822. hr = S_OK;
  823. // Check to see it another net class installer thread is
  824. // currently deleting this component.
  825. //
  826. // The event name will be the adapter instance Id with slashes
  827. // converted to ampersands. If we can't get the instance
  828. // id, we will attempt to remove the adapter without it
  829. //
  830. // convert the slashes in the instance id to ampersands
  831. //
  832. WCHAR szEventName[MAX_DEVICE_ID_LEN];
  833. wcscpy (szEventName, szPnpId);
  834. for (UINT i = 0; i < wcslen (szEventName); ++i)
  835. {
  836. if ('\\' == szEventName[i])
  837. {
  838. szEventName[i] = L'&';
  839. }
  840. }
  841. // create the event in the non-signaled state
  842. BOOL fAlreadyExists;
  843. HANDLE hRemoveEvent = NULL;
  844. hr = HrCreateEventWithWorldAccess (szEventName, FALSE, FALSE,
  845. &fAlreadyExists, &hRemoveEvent);
  846. if ((S_OK == hr) && fAlreadyExists)
  847. {
  848. // another instance of netclassinstaller is deleting this
  849. // component, so wait till it is finished. If the following
  850. // times out, we still return success. We are only waiting to
  851. // give the other NetClassInstaller time to finish the state
  852. // of this component
  853. DWORD dwRet = WaitForSingleObject (hRemoveEvent,
  854. c_cmsNetComponentRemove);
  855. // if the other installer finished okay, we have the event
  856. // so we signal (in case yet another process is waiting
  857. // for the remove to finish) and close the handle.
  858. // If we timeout, we just close the handle
  859. if (WAIT_ABANDONED != dwRet)
  860. {
  861. if (WAIT_OBJECT_0 == dwRet)
  862. {
  863. SetEvent (hRemoveEvent);
  864. }
  865. CloseHandle (hRemoveEvent);
  866. return S_OK;
  867. }
  868. // The event was abandoned so let's try to finish the job
  869. //
  870. }
  871. else if (!hRemoveEvent)
  872. {
  873. hr = HrFromLastWin32Error ();
  874. }
  875. if (S_OK == hr)
  876. {
  877. // We created an event so we must make sure to remove it
  878. // even if there is an exception.
  879. //
  880. NC_TRY
  881. {
  882. #ifdef ENABLETRACE
  883. bmrk.Start (szBenchmarkDesc);
  884. #endif // ENABLETRACE
  885. hr = HrDiRemoveNetAdapter (hdi, pdeid, szPnpId,
  886. hwndParent);
  887. }
  888. NC_CATCH_ALL
  889. {
  890. hr = E_UNEXPECTED;
  891. }
  892. // We are done. If we created an event, we need to
  893. // signal it and close our handle.
  894. if (hRemoveEvent)
  895. {
  896. SetEvent (hRemoveEvent);
  897. CloseHandle (hRemoveEvent);
  898. }
  899. }
  900. }
  901. #ifdef ENABLETRACE
  902. if (S_OK == hr)
  903. {
  904. bmrk.Stop ();
  905. TraceTag (ttidBenchmark, "%s : %s seconds",
  906. bmrk.SznDescription (), bmrk.SznBenchmarkSeconds (2));
  907. }
  908. #endif // ENABLETRACE
  909. }
  910. }
  911. else if (DIF_DESTROYPRIVATEDATA == dif)
  912. {
  913. SP_DEVINSTALL_PARAMS deip;
  914. hr = HrSetupDiGetDeviceInstallParams(hdi, pdeid, &deip);
  915. MemFree ((VOID*)deip.ClassInstallReserved);
  916. }
  917. else if (DIF_REGISTERDEVICE == dif)
  918. {
  919. // We handle 5 classes of components but we only
  920. // want to allow registration for two of them
  921. // (The ones considered NetClassComponents)
  922. Assert(pdeid);
  923. if (pdeid)
  924. {
  925. if (FIsHandledByClassInstaller(pdeid->ClassGuid))
  926. {
  927. if (!FIsEnumerated(pdeid->ClassGuid))
  928. {
  929. // Don't let the device installer register
  930. // devices that are not considered net class
  931. hr = S_OK;
  932. }
  933. }
  934. }
  935. }
  936. else if (DIF_SELECTDEVICE == dif)
  937. {
  938. // This will set the proper description strings in the select device
  939. // dialog. If it fails, we can still show the dialog
  940. (VOID) HrCiPrepareSelectDeviceDialog(hdi, pdeid);
  941. }
  942. else if (DIF_NEWDEVICEWIZARD_FINISHINSTALL == dif)
  943. {
  944. hr = HrAddIsdnWizardPagesIfAppropriate(hdi, pdeid);
  945. }
  946. else if (DIF_ALLOW_INSTALL == dif)
  947. {
  948. // Get the selected driver for this device
  949. //
  950. SP_DRVINFO_DATA drid;
  951. hr = HrSetupDiGetSelectedDriver(hdi, pdeid, &drid);
  952. if (S_OK == hr)
  953. {
  954. // Now get the driver's detailed information
  955. //
  956. PSP_DRVINFO_DETAIL_DATA pdridd = NULL;
  957. hr = HrSetupDiGetDriverInfoDetail(hdi, pdeid,
  958. &drid, &pdridd);
  959. if (S_OK == hr)
  960. {
  961. // Open the component's inf file
  962. //
  963. HINF hinf = NULL;
  964. hr = HrSetupOpenInfFile(pdridd->InfFileName, NULL,
  965. INF_STYLE_WIN4, NULL, &hinf);
  966. if (S_OK == hr)
  967. {
  968. // Make sure this is an NT5 inf network inf
  969. //
  970. hr = HrSetupIsValidNt5Inf(hinf);
  971. SetupCloseInfFile(hinf);
  972. if (S_OK == hr)
  973. {
  974. hr = SPAPI_E_DI_DO_DEFAULT;
  975. }
  976. }
  977. MemFree (pdridd);
  978. }
  979. }
  980. }
  981. else if (DIF_POWERMESSAGEWAKE == dif)
  982. {
  983. SP_POWERMESSAGEWAKE_PARAMS_W wakeParams;
  984. // Get the power message wake params.
  985. //
  986. hr = HrSetupDiGetFixedSizeClassInstallParams(hdi, pdeid,
  987. (PSP_CLASSINSTALL_HEADER)&wakeParams, sizeof(wakeParams));
  988. if (S_OK == hr)
  989. {
  990. Assert (DIF_POWERMESSAGEWAKE ==
  991. wakeParams.ClassInstallHeader.InstallFunction);
  992. // Copy in our string for the power tab.
  993. wcscpy (wakeParams.PowerMessageWake, SzLoadIds(IDS_POWER_MESSAGE_WAKE));
  994. // Now we update the parameters.
  995. hr = HrSetupDiSetClassInstallParams (hdi, pdeid,
  996. (PSP_CLASSINSTALL_HEADER)&wakeParams,
  997. sizeof(SP_POWERMESSAGEWAKE_PARAMS_W));
  998. // If we failed to set the text just allow the device installer
  999. // to do the default.
  1000. if (FAILED(hr))
  1001. {
  1002. hr = SPAPI_E_DI_DO_DEFAULT;
  1003. }
  1004. }
  1005. }
  1006. TraceHr (ttidClassInst, FAL, hr, (SPAPI_E_DI_DO_DEFAULT == hr) ||
  1007. (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr),
  1008. "HrNetClassInstaller");
  1009. return hr;
  1010. }