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.

719 lines
19 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: E N U M . C P P
  7. //
  8. // Contents: Implementation of LAN connection enumerator object
  9. //
  10. // Notes:
  11. //
  12. // Author: danielwe 2 Oct 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "enuml.h"
  18. #include "lan.h"
  19. #include "lancmn.h"
  20. #include "ncnetcfg.h"
  21. #include "ncreg.h"
  22. #include "ncsetup.h"
  23. LONG g_CountLanConnectionEnumerators;
  24. HRESULT CLanConnectionManagerEnumConnection::CreateInstance(
  25. NETCONMGR_ENUM_FLAGS Flags,
  26. REFIID riid,
  27. LPVOID *ppv)
  28. {
  29. HRESULT hr = E_OUTOFMEMORY;
  30. CLanConnectionManagerEnumConnection* pObj;
  31. Assert(ppv);
  32. *ppv = NULL;
  33. pObj = new CComObject<CLanConnectionManagerEnumConnection>;
  34. if (pObj)
  35. {
  36. // Do the standard CComCreator::CreateInstance stuff.
  37. //
  38. pObj->SetVoid(NULL);
  39. pObj->InternalFinalConstructAddRef();
  40. hr = pObj->FinalConstruct();
  41. pObj->InternalFinalConstructRelease();
  42. if (SUCCEEDED(hr))
  43. {
  44. hr = pObj->QueryInterface(riid, ppv);
  45. }
  46. if (FAILED(hr))
  47. {
  48. delete pObj;
  49. }
  50. }
  51. TraceError("CLanConnectionManagerEnumConnection::CreateInstance", hr);
  52. return hr;
  53. }
  54. //+---------------------------------------------------------------------------
  55. //
  56. // Member: CLanConnectionManagerEnumConnection::~CLanConnectionManagerEnumConnection
  57. //
  58. // Purpose: Called when the enumeration object is released for the last
  59. // time.
  60. //
  61. // Arguments:
  62. // (none)
  63. //
  64. // Returns: Nothing
  65. //
  66. // Author: danielwe 2 Oct 1997
  67. //
  68. // Notes:
  69. //
  70. CLanConnectionManagerEnumConnection::~CLanConnectionManagerEnumConnection()
  71. {
  72. SetupDiDestroyDeviceInfoListSafe(m_hdi);
  73. InterlockedDecrement(&g_CountLanConnectionEnumerators);
  74. }
  75. //+---------------------------------------------------------------------------
  76. // IEnumNetConnection
  77. //
  78. //+---------------------------------------------------------------------------
  79. //
  80. // Member: CLanConnectionManagerEnumConnection::Next
  81. //
  82. // Purpose: Retrieves the next celt LAN connection objects
  83. //
  84. // Arguments:
  85. // celt [in] Number to retrieve
  86. // rgelt [out] Array of INetConnection objects retrieved
  87. // pceltFetched [out] Returns Number in array
  88. //
  89. // Returns: S_OK if succeeded, OLE or Win32 error otherwise
  90. //
  91. // Author: danielwe 2 Oct 1997
  92. //
  93. // Notes:
  94. //
  95. STDMETHODIMP CLanConnectionManagerEnumConnection::Next(ULONG celt,
  96. INetConnection **rgelt,
  97. ULONG *pceltFetched)
  98. {
  99. HRESULT hr = S_OK;
  100. // Validate parameters.
  101. //
  102. if (!rgelt || (!pceltFetched && (1 != celt)))
  103. {
  104. hr = E_POINTER;
  105. goto done;
  106. }
  107. // Initialize output parameters.
  108. //
  109. if (pceltFetched)
  110. {
  111. *pceltFetched = 0;
  112. }
  113. // Handle the request for zero elements. Also do nothing if the enumerator
  114. // was created without valid parameters.
  115. //
  116. if (0 == celt || FIsDebugFlagSet(dfidSkipLanEnum))
  117. {
  118. hr = S_FALSE;
  119. goto done;
  120. }
  121. hr = HrNextOrSkip(celt, rgelt, pceltFetched);
  122. done:
  123. TraceError("CLanConnectionManagerEnumConnection::Next",
  124. (hr == S_FALSE) ? S_OK : hr);
  125. return hr;
  126. }
  127. //+---------------------------------------------------------------------------
  128. //
  129. // Member: CLanConnectionManagerEnumConnection::Skip
  130. //
  131. // Purpose: Skips over celt number of connections
  132. //
  133. // Arguments:
  134. // celt [in] Number of connections to skip
  135. //
  136. // Returns: S_OK if successful, otherwise Win32 error
  137. //
  138. // Author: danielwe 2 Oct 1997
  139. //
  140. // Notes:
  141. //
  142. STDMETHODIMP CLanConnectionManagerEnumConnection::Skip(ULONG celt)
  143. {
  144. HRESULT hr = S_OK;
  145. hr = HrNextOrSkip(celt, NULL, NULL);
  146. TraceError("CLanConnectionManagerEnumConnection::Skip",
  147. (hr == S_FALSE) ? S_OK : hr);
  148. return hr;
  149. }
  150. //+---------------------------------------------------------------------------
  151. //
  152. // Member: CLanConnectionManagerEnumConnection::Reset
  153. //
  154. // Purpose: Resets the enumerator to the beginning
  155. //
  156. // Arguments:
  157. // (none)
  158. //
  159. // Returns: S_OK
  160. //
  161. // Author: danielwe 2 Oct 1997
  162. //
  163. // Notes:
  164. //
  165. STDMETHODIMP CLanConnectionManagerEnumConnection::Reset()
  166. {
  167. HRESULT hr;
  168. m_dwIndex = 0;
  169. // refresh so that we have a new view of what adapters are installed
  170. // each time reset is called
  171. //
  172. SetupDiDestroyDeviceInfoListSafe(m_hdi);
  173. hr = HrSetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL,
  174. DIGCF_PRESENT, &m_hdi);
  175. TraceError("CLanConnectionManagerEnumConnection::Reset", hr);
  176. return hr;
  177. }
  178. //+---------------------------------------------------------------------------
  179. //
  180. // Member: CLanConnectionManagerEnumConnection::Clone
  181. //
  182. // Purpose: Creates a new enumeration object pointing at the same location
  183. // as this object
  184. //
  185. // Arguments:
  186. // ppenum [out] New enumeration object
  187. //
  188. // Returns: S_OK if successful, otherwise OLE or Win32 error
  189. //
  190. // Author: danielwe 19 Mar 1998
  191. //
  192. // Notes:
  193. //
  194. STDMETHODIMP CLanConnectionManagerEnumConnection::Clone(IEnumNetConnection **ppenum)
  195. {
  196. HRESULT hr = E_OUTOFMEMORY;
  197. // Validate parameters.
  198. //
  199. if (!ppenum)
  200. {
  201. hr = E_POINTER;
  202. }
  203. else
  204. {
  205. CLanConnectionManagerEnumConnection * pObj;
  206. // Initialize output parameter.
  207. //
  208. *ppenum = NULL;
  209. pObj = new CComObject <CLanConnectionManagerEnumConnection>;
  210. if (pObj)
  211. {
  212. hr = S_OK;
  213. CExceptionSafeComObjectLock EsLock (this);
  214. // Copy our internal state.
  215. //
  216. pObj->m_dwIndex = m_dwIndex;
  217. // Return the object with a ref count of 1 on this
  218. // interface.
  219. pObj->m_dwRef = 1;
  220. *ppenum = pObj;
  221. }
  222. }
  223. TraceError ("CLanConnectionManagerEnumConnection::Clone", hr);
  224. return hr;
  225. }
  226. //
  227. // Helper functions
  228. //
  229. //+---------------------------------------------------------------------------
  230. //
  231. // Member: CLanConnectionManagerEnumConnection::HrCreateLanConnectionInstance
  232. //
  233. // Purpose: Helper function to create a LAN connection object instance
  234. //
  235. // Arguments:
  236. // deid [in] Device info data
  237. // rgelt [in] Array of connection objects
  238. // ulEntry [in] Index of connection object
  239. //
  240. // Returns: S_OK if success, Win32 or OLE error otherwise
  241. //
  242. // Author: danielwe 8 Jan 1998
  243. //
  244. // Notes:
  245. //
  246. HRESULT CLanConnectionManagerEnumConnection::HrCreateLanConnectionInstance(
  247. SP_DEVINFO_DATA &deid,
  248. INetConnection **rgelt,
  249. ULONG ulEntry)
  250. {
  251. HRESULT hr;
  252. WCHAR szPnpId[MAX_DEVICE_ID_LEN];
  253. hr = HrSetupDiGetDeviceInstanceId(m_hdi, &deid, szPnpId,
  254. MAX_DEVICE_ID_LEN, NULL);
  255. if (S_OK == hr)
  256. {
  257. HDEVINFO hdiCopy;
  258. SP_DEVINFO_DATA deidCopy;
  259. hr = HrSetupDiCreateDeviceInfoList(&GUID_DEVCLASS_NET,
  260. NULL, &hdiCopy);
  261. if (S_OK == hr)
  262. {
  263. BOOL fDestroyCopy = TRUE;
  264. hr = HrSetupDiOpenDeviceInfo(hdiCopy, szPnpId,
  265. NULL, DIOD_INHERIT_CLASSDRVS, &deidCopy);
  266. if (S_OK == hr)
  267. {
  268. fDestroyCopy = FALSE;
  269. hr = CLanConnection::CreateInstance(hdiCopy,
  270. deidCopy,
  271. szPnpId,
  272. IID_INetConnection,
  273. reinterpret_cast<LPVOID *>
  274. (rgelt + ulEntry));
  275. }
  276. // CLanConnection::CreateInstance() will hand off the hdiCopy. So
  277. // even if that fails, we don't want to destroy hdiCopy anymore.
  278. //
  279. if (fDestroyCopy)
  280. {
  281. // If we fail to continue, free the copy we just made
  282. //
  283. (VOID) SetupDiDestroyDeviceInfoList(hdiCopy);
  284. }
  285. }
  286. }
  287. TraceError("CLanConnectionManagerEnumConnection::"
  288. "HrCreateLanConnectionInstance", hr);
  289. return hr;
  290. }
  291. //+---------------------------------------------------------------------------
  292. //
  293. // Function: FIsHidden
  294. //
  295. // Purpose: Returns TRUE if the given hkey references the device instance
  296. // of a hidden adapter (virtual or otherwise)
  297. //
  298. // Arguments:
  299. // hkey [in] HKEY of device instance for adapter (i.e. {GUID}\0000)
  300. //
  301. // Returns: TRUE if it is hidden, FALSE if not
  302. //
  303. // Author: danielwe 17 Apr 1998
  304. //
  305. // Notes:
  306. //
  307. BOOL FIsHidden(HKEY hkey)
  308. {
  309. DWORD dwCharacter;
  310. if (S_OK == HrRegQueryDword(hkey, L"Characteristics", &dwCharacter))
  311. {
  312. return !!(dwCharacter & NCF_HIDDEN);
  313. }
  314. return FALSE;
  315. }
  316. //+---------------------------------------------------------------------------
  317. //
  318. // Function: FIsHiddenElan
  319. //
  320. // Purpose: Returns TRUE if the given hkey references the device instance
  321. // of a hidden ELAN adapter (when the physical ATM adapter is not
  322. // available)
  323. //
  324. // Arguments:
  325. // hdi [in] HDEVINFO structure for this adapter
  326. // hkey [in] HKEY of device instance for adapter (i.e. {GUID}\0000)
  327. //
  328. //
  329. // Returns: TRUE if it is hidden, FALSE if not
  330. //
  331. // Author: tongl 9/10/98
  332. //
  333. // Notes:
  334. //
  335. BOOL FIsHiddenElan(HDEVINFO hdi, HKEY hkey)
  336. {
  337. BOOL fRet = FALSE;
  338. HRESULT hr;
  339. PWSTR pszAtmAdapterPnpId;
  340. hr = HrRegQuerySzWithAlloc(hkey, L"AtmAdapterPnpId", &pszAtmAdapterPnpId);
  341. if (S_OK == hr)
  342. {
  343. SP_DEVINFO_DATA deid;
  344. hr = HrSetupDiOpenDeviceInfo(hdi, pszAtmAdapterPnpId, NULL, 0, &deid);
  345. if (S_OK == hr)
  346. {
  347. // Elan should be hidden if the physical adapter is not functioning
  348. // and is hidden in the folder
  349. fRet = !FIsFunctioning(&deid);
  350. }
  351. MemFree(pszAtmAdapterPnpId);
  352. }
  353. return fRet;
  354. }
  355. //+---------------------------------------------------------------------------
  356. //
  357. // Member: CLanConnectionManagerEnumConnection::HrNextOrSkip
  358. //
  359. // Purpose: Helper function to handle the ::Next or ::Skip method
  360. // implementation
  361. //
  362. // Arguments:
  363. // celt [in] Number of items to advance
  364. // rgelt [in] Array in which to place connection objects
  365. // pceltFetched [out] Returns number of items fetched
  366. //
  367. // Returns: S_OK if success, OLE or Win32 error otherwise
  368. //
  369. // Author: danielwe 8 Jan 1998
  370. //
  371. // Notes:
  372. //
  373. HRESULT CLanConnectionManagerEnumConnection::HrNextOrSkip(
  374. ULONG celt,
  375. INetConnection **rgelt,
  376. ULONG *pceltFetched)
  377. {
  378. HRESULT hr = S_OK;
  379. SP_DEVINFO_DATA deid = {0};
  380. ULONG ulEntry = 0;
  381. if (rgelt)
  382. {
  383. // Important to initialize rgelt so that in case we fail, we can
  384. // release only what we put in rgelt.
  385. //
  386. ZeroMemory(rgelt, sizeof (*rgelt) * celt);
  387. }
  388. Assert(celt > 0);
  389. if (!m_hdi)
  390. {
  391. hr = HrSetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL,
  392. DIGCF_PRESENT, &m_hdi);
  393. }
  394. while (celt &&
  395. SUCCEEDED(hr) &&
  396. SUCCEEDED(hr = HrSetupDiEnumDeviceInfo(m_hdi,m_dwIndex, &deid)))
  397. {
  398. HKEY hkey;
  399. m_dwIndex++;
  400. hr = HrSetupDiOpenDevRegKey(m_hdi, &deid, DICS_FLAG_GLOBAL, 0,
  401. DIREG_DRV, KEY_READ, &hkey);
  402. if (SUCCEEDED(hr))
  403. {
  404. hr = HrIsLanCapableAdapterFromHkey(hkey);
  405. if (S_OK == hr)
  406. {
  407. if (FIsFunctioning(&deid) && FIsValidNetCfgDevice(hkey) &&
  408. !FIsHidden(hkey) && !FIsHiddenElan(m_hdi, hkey))
  409. {
  410. // On Skip, don't create an instance
  411. //
  412. if (rgelt)
  413. {
  414. hr = HrCreateLanConnectionInstance(deid, rgelt,
  415. ulEntry);
  416. }
  417. ulEntry++;
  418. celt--;
  419. }
  420. }
  421. RegCloseKey(hkey);
  422. }
  423. else
  424. {
  425. // skip device entirely if error trying to open it
  426. hr = S_OK;
  427. }
  428. }
  429. if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
  430. {
  431. hr = S_OK;
  432. }
  433. if (SUCCEEDED(hr))
  434. {
  435. TraceTag (ttidLanCon, "Enumerated %lu LAN connections", ulEntry);
  436. if (pceltFetched)
  437. {
  438. *pceltFetched = ulEntry;
  439. }
  440. // If celt is positive then we couldn't satisfy the request completely
  441. hr = (celt > 0) ? S_FALSE : S_OK;
  442. }
  443. else
  444. {
  445. // For any failures, we need to release what we were about to return.
  446. // Set any output parameters to NULL.
  447. //
  448. if (rgelt)
  449. {
  450. for (ULONG ulIndex = 0; ulIndex < ulEntry; ulIndex++)
  451. {
  452. ReleaseObj(rgelt[ulIndex]);
  453. rgelt[ulIndex] = NULL;
  454. }
  455. }
  456. if (pceltFetched)
  457. {
  458. *pceltFetched = 0;
  459. }
  460. }
  461. TraceError("CLanConnectionManagerEnumConnection::HrNextOrSkip",
  462. (hr == S_FALSE) ? S_OK : hr);
  463. return hr;
  464. }
  465. //
  466. // Private helper functions
  467. //
  468. extern const WCHAR c_szRegKeyInterfacesFromInstance[];
  469. extern const WCHAR c_szRegValueUpperRange[];
  470. extern const WCHAR c_szRegValueLowerRange[];
  471. static const WCHAR c_chComma = L',';
  472. extern const WCHAR c_szBiNdis4[];
  473. extern const WCHAR c_szBiNdis5[];
  474. extern const WCHAR c_szBiNdis5Ip[];
  475. extern const WCHAR c_szBiNdisAtm[];
  476. extern const WCHAR c_szBiNdis1394[];
  477. extern const WCHAR c_szBiNdisBda[];
  478. extern const WCHAR c_szBiLocalTalk[];
  479. //+---------------------------------------------------------------------------
  480. //
  481. // Function: HrIsLanCapableAdapterFromHkey
  482. //
  483. // Purpose: Determines if the given HKEY describes a LAN capable adapter
  484. //
  485. // Arguments:
  486. // hkey [in] HKEY under Control\Class\{GUID}\<instance> (aka driver key)
  487. //
  488. // Returns: S_OK if device is LAN capable, S_FALSE if not, Win32 error
  489. // otherwise
  490. //
  491. // Author: danielwe 7 Jan 1998
  492. //
  493. // Notes:
  494. //
  495. HRESULT HrIsLanCapableAdapterFromHkey(HKEY hkey)
  496. {
  497. HRESULT hr = S_OK;
  498. WCHAR szBuf[256];
  499. DWORD cbBuf = sizeof(szBuf);
  500. list<tstring *> lstr;
  501. list<tstring *>::iterator lstrIter;
  502. BOOL fMatch = FALSE;
  503. HKEY hkeyInterfaces;
  504. hr = HrRegOpenKeyEx(hkey, c_szRegKeyInterfacesFromInstance,
  505. KEY_READ, &hkeyInterfaces);
  506. if (SUCCEEDED(hr))
  507. {
  508. hr = HrRegQuerySzBuffer(hkeyInterfaces, c_szRegValueUpperRange,
  509. szBuf, &cbBuf);
  510. if (SUCCEEDED(hr))
  511. {
  512. ConvertStringToColString(szBuf, c_chComma, lstr);
  513. for (lstrIter = lstr.begin(); lstrIter != lstr.end(); lstrIter++)
  514. {
  515. // See if it matches one of these
  516. if (!lstrcmpiW((*lstrIter)->c_str(), c_szBiNdis4) ||
  517. !lstrcmpiW((*lstrIter)->c_str(), c_szBiNdis5) ||
  518. !lstrcmpiW((*lstrIter)->c_str(), c_szBiNdis5Ip) ||
  519. !lstrcmpiW((*lstrIter)->c_str(), c_szBiNdisAtm) ||
  520. !lstrcmpiW((*lstrIter)->c_str(), c_szBiNdis1394) ||
  521. !lstrcmpiW((*lstrIter)->c_str(), c_szBiNdisBda))
  522. {
  523. fMatch = TRUE;
  524. break;
  525. }
  526. }
  527. DeleteColString(&lstr);
  528. }
  529. if (!fMatch)
  530. {
  531. cbBuf = sizeof(szBuf);
  532. hr = HrRegQuerySzBuffer(hkeyInterfaces, c_szRegValueLowerRange,
  533. szBuf, &cbBuf);
  534. if (SUCCEEDED(hr))
  535. {
  536. ConvertStringToColString(szBuf, c_chComma, lstr);
  537. for (lstrIter = lstr.begin(); lstrIter != lstr.end(); lstrIter++)
  538. {
  539. // See if it matches one of these
  540. if (!lstrcmpiW((*lstrIter)->c_str(), c_szBiLocalTalk))
  541. {
  542. fMatch = TRUE;
  543. break;
  544. }
  545. }
  546. DeleteColString(&lstr);
  547. }
  548. }
  549. RegCloseKey(hkeyInterfaces);
  550. }
  551. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  552. {
  553. hr = S_OK;
  554. }
  555. if (SUCCEEDED(hr))
  556. {
  557. if (fMatch)
  558. {
  559. hr = S_OK;
  560. }
  561. else
  562. {
  563. hr = S_FALSE;
  564. }
  565. }
  566. TraceHr (ttidError, FAL, hr, S_FALSE == hr,
  567. "HrIsLanCapableAdapterFromHkey");
  568. return hr;
  569. }
  570. static const WCHAR c_szKeyFmt[] = L"%s\\%s\\%s";
  571. extern const WCHAR c_szRegValueNetCfgInstanceId[];
  572. extern const WCHAR c_szRegKeyComponentClasses[];
  573. extern const WCHAR c_szRegValueInstallerAction[];
  574. //+---------------------------------------------------------------------------
  575. //
  576. // Function: FIsValidNetCfgDevice
  577. //
  578. // Purpose: Determines if the given HKEY is that of a valid NetCfg adapter
  579. //
  580. // Arguments:
  581. // hkey [in] HKEY under Control\Class\{GUID}\<instance> (aka driver key)
  582. //
  583. // Returns: TRUE if valid, FALSE otherwise
  584. //
  585. // Author: danielwe 7 Jan 1998
  586. //
  587. // Notes:
  588. //
  589. BOOL FIsValidNetCfgDevice(HKEY hkey)
  590. {
  591. HRESULT hr;
  592. WCHAR szGuid[c_cchGuidWithTerm + 1];
  593. DWORD cbBuf = sizeof(szGuid);
  594. hr = HrRegQuerySzBuffer(hkey, c_szRegValueNetCfgInstanceId,
  595. szGuid, &cbBuf);
  596. return (S_OK == hr);
  597. }
  598. //+---------------------------------------------------------------------------
  599. //
  600. // Function: FIsFunctioning
  601. //
  602. // Purpose: Determines if the given dev node is a functioning device
  603. //
  604. // Arguments:
  605. // pdeid [in] Dev info data for device
  606. //
  607. // Returns: TRUE if device is functioning, FALSE if not
  608. //
  609. // Author: danielwe 2 Sep 1998
  610. //
  611. // Notes: "Functioning" means the device is enabled and started with
  612. // no problem codes, or it is disabled and stopped with no
  613. // problem codes.
  614. //
  615. BOOL FIsFunctioning(SP_DEVINFO_DATA * pdeid)
  616. {
  617. ULONG ulStatus;
  618. ULONG ulProblem;
  619. CONFIGRET cfgRet;
  620. cfgRet = CM_Get_DevNode_Status_Ex(&ulStatus, &ulProblem, pdeid->DevInst,
  621. 0, NULL);
  622. if (CR_SUCCESS == cfgRet)
  623. {
  624. TraceTag(ttidLanCon, "CM_Get_DevNode_Status_Ex (enum): ulProblem "
  625. "= 0x%08X, ulStatus = 0x%08X.",
  626. ulProblem, ulStatus);
  627. return FIsDeviceFunctioning(ulProblem);
  628. }
  629. // By default return FALSE
  630. return FALSE;
  631. }