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

2271 lines
62 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: L A N . C P P
  7. //
  8. // Contents: Implementation of LAN connection objects
  9. //
  10. // Notes:
  11. //
  12. // Author: danielwe 2 Oct 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include <ncreg.h>
  18. #include <ncsetup.h>
  19. #include "lan.h"
  20. #include "lancmn.h"
  21. #include "nccom.h"
  22. #include "ncmisc.h"
  23. #include "ncnetcon.h"
  24. #include "sensapip.h" // For SensNotifyNetconEvent
  25. #include "ncstring.h"
  26. #include "ncras.h"
  27. #include "naming.h"
  28. #include "wzcsvc.h"
  29. #include "cobase.h"
  30. #include "gpnla.h"
  31. #include "ncperms.h"
  32. #include "nmpolicy.h"
  33. LONG g_CountLanConnectionObjects;
  34. extern CGroupPolicyNetworkLocationAwareness* g_pGPNLA;
  35. static const WCHAR c_szConnName[] = L"Name";
  36. static const WCHAR c_szShowIcon[] = L"ShowIcon";
  37. static const WCHAR c_szAutoConnect[] = L"AutoConnect";
  38. extern const WCHAR c_szRegKeyInterfacesFromInstance[];
  39. extern const WCHAR c_szRegValueUpperRange[];
  40. static const WCHAR c_chComma = L',';
  41. extern const WCHAR c_szBiNdisAtm[];
  42. static const DWORD c_cchMaxConnNameLen = 256;
  43. static const CLSID CLSID_LanConnectionUi =
  44. {0x7007ACC5,0x3202,0x11D1,{0xAA,0xD2,0x00,0x80,0x5F,0xC1,0x27,0x0E}};
  45. typedef DWORD (APIENTRY *PFNSENSNOTIFY) (PSENS_NOTIFY_NETCON pEvent);
  46. #define NETCFG_S_NOTEXIST 0x00000002
  47. //
  48. // CComObject overrides
  49. //
  50. //+---------------------------------------------------------------------------
  51. //
  52. // Member: CLanConnection::CreateInstance
  53. //
  54. // Purpose: Static function to create an instance of a LAN connection
  55. // object
  56. //
  57. // Arguments:
  58. // hdi [in] Device installer device info
  59. // deid [in] Device installer device info
  60. // riid [in] Initial interface to query for
  61. // ppv [out] Returns the new interface pointer
  62. //
  63. // Returns: S_OK if success, otherwise OLE or Win32 error code
  64. //
  65. // Author: danielwe 2 Oct 1997
  66. //
  67. // Notes:
  68. //
  69. HRESULT CLanConnection::CreateInstance(IN HDEVINFO hdi,
  70. IN const SP_DEVINFO_DATA &deid,
  71. IN PCWSTR pszPnpId,
  72. IN REFIID riid,
  73. OUT LPVOID *ppv)
  74. {
  75. HRESULT hr = E_OUTOFMEMORY;
  76. CLanConnection * pObj;
  77. pObj = new CComObject<CLanConnection>;
  78. if (pObj)
  79. {
  80. // Initialize our members.
  81. //
  82. pObj->m_hkeyConn = NULL;
  83. pObj->m_hdi = hdi;
  84. pObj->m_deid = deid;
  85. // Do the standard CComCreator::CreateInstance stuff.
  86. //
  87. pObj->SetVoid (NULL);
  88. pObj->InternalFinalConstructAddRef();
  89. hr = pObj->FinalConstruct();
  90. pObj->InternalFinalConstructRelease();
  91. if (SUCCEEDED(hr))
  92. {
  93. hr = pObj->HrInitialize(pszPnpId);
  94. if (SUCCEEDED(hr))
  95. {
  96. hr = pObj->GetUnknown()->QueryInterface(riid, ppv);
  97. }
  98. }
  99. if (FAILED(hr))
  100. {
  101. delete pObj;
  102. }
  103. }
  104. else
  105. {
  106. SetupDiDestroyDeviceInfoList(hdi);
  107. }
  108. TraceError("CLanConnection::CreateInstance", hr);
  109. return hr;
  110. }
  111. BOOL VerifyUniqueConnectionName(IN const CIntelliName *pIntelliName,
  112. IN PCWSTR pszPotentialName,
  113. OUT NETCON_MEDIATYPE *pncm,
  114. OUT NETCON_SUBMEDIATYPE *pncms)
  115. {
  116. HRESULT hr = S_OK;
  117. DWORD dwSuffix = 2;
  118. HKEY hkey;
  119. BOOL fDupFound = FALSE;
  120. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\"
  121. L"Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
  122. KEY_READ, &hkey);
  123. if (S_OK == hr)
  124. {
  125. FILETIME ft;
  126. DWORD dwIndex = 0;
  127. WCHAR szKeyName[MAX_PATH];
  128. DWORD cchName = celems(szKeyName);
  129. while (!fDupFound && (S_OK == (hr = HrRegEnumKeyEx(hkey, dwIndex, szKeyName,
  130. &cchName, NULL, NULL, &ft))) )
  131. {
  132. HKEY hkeyConn;
  133. WCHAR szSubKey[MAX_PATH];
  134. wsprintfW(szSubKey, L"%s\\Connection", szKeyName);
  135. hr = HrRegOpenKeyEx(hkey, szSubKey, KEY_READ, &hkeyConn);
  136. if (S_OK == hr)
  137. {
  138. tstring strName;
  139. hr = HrRegQueryString(hkeyConn, c_szConnName, &strName);
  140. if (S_OK == hr)
  141. {
  142. if (!lstrcmpiW(pszPotentialName, strName.c_str()))
  143. {
  144. fDupFound = TRUE;
  145. CLSID guidName;
  146. if (SUCCEEDED(CLSIDFromString(szKeyName, &guidName)))
  147. {
  148. hr = pIntelliName->HrGetPseudoMediaTypes(guidName, pncm, pncms);
  149. if (FAILED(hr))
  150. {
  151. *pncm = NCM_LAN;
  152. *pncms = NCSM_LAN;
  153. }
  154. }
  155. else
  156. {
  157. AssertSz(FALSE, "This doesn't look like a GUID.");
  158. }
  159. break;
  160. }
  161. else
  162. {
  163. dwIndex++;
  164. }
  165. }
  166. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  167. {
  168. // If value doesn't exist, that's ok. This is a new
  169. // connection.
  170. hr = S_OK;
  171. dwIndex++;
  172. }
  173. RegCloseKey(hkeyConn);
  174. }
  175. else
  176. {
  177. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  178. {
  179. // If key doesn't exist, that's ok. This is not a
  180. // connection.
  181. hr = S_OK;
  182. dwIndex++;
  183. }
  184. }
  185. cchName = celems(szKeyName);
  186. }
  187. RegCloseKey(hkey);
  188. }
  189. return fDupFound;
  190. }
  191. //+---------------------------------------------------------------------------
  192. //
  193. // Member: CLanConnection::HrInitialize
  194. //
  195. // Purpose: Initializes the connection object for the first time.
  196. //
  197. // Arguments:
  198. // (none)
  199. //
  200. // Returns: S_OK if success, Win32 or OLE error code otherwise
  201. //
  202. // Author: danielwe 4 Nov 1997
  203. //
  204. // Notes: This function is only called when the object is created for
  205. // the very first time and has no identity.
  206. //
  207. HRESULT CLanConnection::HrInitialize(
  208. IN PCWSTR pszPnpId)
  209. {
  210. HRESULT hr = S_OK;
  211. GUID guid;
  212. AssertSz(m_hdi, "We should have a component at this point!");
  213. Assert(pszPnpId);
  214. hr = HrGetInstanceGuid(m_hdi, m_deid, &guid);
  215. if (S_OK == hr)
  216. {
  217. // Open the main connection key. If it doesn't exist, we'll create it
  218. // here.
  219. hr = HrOpenConnectionKey(&guid, NULL, KEY_READ_WRITE,
  220. OCCF_CREATE_IF_NOT_EXIST, pszPnpId,
  221. &m_hkeyConn);
  222. if (SUCCEEDED(hr))
  223. {
  224. tstring strName;
  225. // First see if a name already exists for this connection
  226. hr = HrRegQueryString(m_hkeyConn, c_szConnName, &strName);
  227. if (FAILED(hr))
  228. {
  229. // no name?
  230. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  231. {
  232. //$ REVIEW (danielwe) 30 Oct 1997: If I can be assured
  233. // that get_Name is never called before Rename, I
  234. // don't need this function to be called.
  235. // Note: (danielwe) 31 Oct 1997: This could result in
  236. // duplicate names, but we cannot check for duplicates
  237. // without recursing infinitely
  238. // Set default connection name
  239. CIntelliName IntelliName(_Module.GetResourceInstance(), VerifyUniqueConnectionName);
  240. GUID gdDevice;
  241. LPWSTR szNewName = NULL;
  242. hr = HrGetInstanceGuid(m_hdi, m_deid, &gdDevice);
  243. Assert(SUCCEEDED(hr));
  244. if (SUCCEEDED(hr))
  245. {
  246. BOOL fNetworkBridge;
  247. hr = HrIsConnectionNetworkBridge(&fNetworkBridge);
  248. if (SUCCEEDED(hr) && fNetworkBridge)
  249. {
  250. hr = IntelliName.GenerateName(gdDevice, NCM_BRIDGE, 0, NULL, &szNewName);
  251. }
  252. else
  253. {
  254. hr = IntelliName.GenerateName(gdDevice, NCM_LAN, 0, NULL, &szNewName);
  255. }
  256. if (SUCCEEDED(hr))
  257. {
  258. hr = HrRegSetSz(m_hkeyConn, c_szConnName, szNewName);
  259. CoTaskMemFree(szNewName);
  260. }
  261. }
  262. Assert(SUCCEEDED(hr));
  263. }
  264. }
  265. }
  266. }
  267. if (SUCCEEDED(hr))
  268. {
  269. m_fInitialized = TRUE;
  270. }
  271. TraceError("CLanConnection::HrInitialize", hr);
  272. return hr;
  273. }
  274. //+---------------------------------------------------------------------------
  275. //
  276. // Member: CLanConnection::HrOpenRegistryKeys
  277. //
  278. // Purpose: Opens the registry keys that this LAN connection object will
  279. // use
  280. //
  281. // Arguments:
  282. // guid [in] Guid of adapter that this connection uses
  283. //
  284. // Returns: S_OK if success, Win32 error otherwise
  285. //
  286. // Author: danielwe 11 Nov 1997
  287. //
  288. // Notes: Keys are expected to exist and this will fail if either do
  289. // not
  290. //
  291. HRESULT CLanConnection::HrOpenRegistryKeys(IN const GUID &guid)
  292. {
  293. HRESULT hr = S_OK;
  294. AssertSz(!m_hkeyConn, "Don't call this more than once "
  295. "on the same connection object!");
  296. // This should only be called from HrLoad so these keys had better be
  297. // there.
  298. hr = HrOpenConnectionKey(&guid, NULL, KEY_READ_WRITE,
  299. OCCF_NONE, NULL, &m_hkeyConn);
  300. TraceError("CLanConnection::HrOpenRegistryKeys", hr);
  301. return hr;
  302. }
  303. //+---------------------------------------------------------------------------
  304. //
  305. // Member: CLanConnection::HrLoad
  306. //
  307. // Purpose: Implements the bulk of IPersistNetConnection::Load.
  308. //
  309. // Arguments:
  310. // guid [in] GUID from which to receive identity
  311. //
  312. // Returns: S_OK if success, OLE or Win32 error code otherwise
  313. //
  314. // Author: danielwe 4 Nov 1997
  315. //
  316. // Notes:
  317. //
  318. HRESULT CLanConnection::HrLoad(IN const GUID &guid)
  319. {
  320. HRESULT hr = S_OK;
  321. hr = HrLoadDevInfoFromGuid(guid);
  322. if (SUCCEEDED(hr))
  323. {
  324. hr = HrOpenRegistryKeys(guid);
  325. if (SUCCEEDED(hr))
  326. {
  327. // No need to call HrInitialize because this object should
  328. // already be created properly at a previous time
  329. m_fInitialized = TRUE;
  330. }
  331. }
  332. TraceError("CLanConnection::HrLoad", hr);
  333. return hr;
  334. }
  335. //+---------------------------------------------------------------------------
  336. //
  337. // Member: CLanConnection::~CLanConnection
  338. //
  339. // Purpose: Called when the connection object is released for the last
  340. // time.
  341. //
  342. // Arguments:
  343. // (none)
  344. //
  345. // Returns: Nothing
  346. //
  347. // Author: danielwe 3 Oct 1997
  348. //
  349. // Notes:
  350. //
  351. CLanConnection::~CLanConnection() throw()
  352. {
  353. RegSafeCloseKey(m_hkeyConn);
  354. SetupDiDestroyDeviceInfoListSafe(m_hdi);
  355. InterlockedDecrement(&g_CountLanConnectionObjects);
  356. CoTaskMemFree(m_pHNetProperties);
  357. }
  358. //
  359. // INetConnection
  360. //
  361. //+---------------------------------------------------------------------------
  362. //
  363. // Member: CLanConnection::Rename
  364. //
  365. // Purpose: Changes the name of the connection
  366. //
  367. // Arguments:
  368. // pszName [in] New connection name (must be valid)
  369. //
  370. // Returns: S_OK if success, OLE error code otherwise
  371. //
  372. // Author: danielwe 2 Oct 1997
  373. //
  374. // Notes:
  375. //
  376. STDMETHODIMP CLanConnection::Rename(IN PCWSTR pszName)
  377. {
  378. HRESULT hr = S_OK;
  379. if (!pszName)
  380. {
  381. hr = E_POINTER;
  382. }
  383. else if (!*pszName)
  384. {
  385. hr = E_INVALIDARG;
  386. }
  387. else if (!m_fInitialized)
  388. {
  389. hr = E_UNEXPECTED;
  390. }
  391. else if (!FIsValidConnectionName(pszName))
  392. {
  393. // Bad connection name
  394. hr = E_INVALIDARG;
  395. }
  396. else
  397. {
  398. AssertSz(m_hkeyConn, "Why don't I have a connection key?");
  399. // Get the current name for this connection
  400. tstring strName;
  401. hr = HrRegQueryString(m_hkeyConn, c_szConnName, &strName);
  402. if (S_OK == hr)
  403. {
  404. // Only do something if names are different
  405. if (lstrcmpiW(pszName, strName.c_str()))
  406. {
  407. hr = HrPutName(pszName);
  408. }
  409. }
  410. }
  411. TraceError("CLanConnection::Rename", hr);
  412. return hr;
  413. }
  414. //+---------------------------------------------------------------------------
  415. //
  416. // Member: CLanConnection::HrPutName
  417. //
  418. // Purpose: Sets the connection name using the given name
  419. //
  420. // Arguments:
  421. // pszName [in] New name for connection
  422. //
  423. // Returns: S_OK if success, OLE error code otherwise
  424. //
  425. // Author: danielwe 31 Oct 1997
  426. //
  427. // Notes: Doesn't check if name is already set to this
  428. //
  429. HRESULT CLanConnection::HrPutName(IN PCWSTR pszName)
  430. {
  431. HRESULT hr = S_OK;
  432. GUID guid;
  433. // Get my device guid first
  434. hr = GetDeviceGuid(&guid);
  435. if (S_OK == hr)
  436. {
  437. hr = HrIsConnectionNameUnique(guid, pszName);
  438. if (S_OK == hr)
  439. {
  440. hr = HrRegSetSz(m_hkeyConn, c_szConnName, pszName);
  441. if (S_OK == hr)
  442. {
  443. LanEventNotify(CONNECTION_RENAMED, NULL, pszName, &guid);
  444. }
  445. }
  446. else if (S_FALSE == hr)
  447. {
  448. hr = HRESULT_FROM_WIN32(ERROR_DUP_NAME);
  449. }
  450. }
  451. TraceErrorOptional("CLanConnection::HrPutName", hr,
  452. (hr == HRESULT_FROM_WIN32(ERROR_DUP_NAME)));
  453. return hr;
  454. }
  455. //+---------------------------------------------------------------------------
  456. //
  457. // Member: CLanConnection::FIsMediaPresent
  458. //
  459. // Purpose: Determines as best as can be basically whether the cable is
  460. // plugged in to the network card.
  461. //
  462. // Arguments:
  463. // (none)
  464. //
  465. // Returns: TRUE if cable is plugged in, FALSE if not
  466. //
  467. // Author: danielwe 22 Sep 1998
  468. //
  469. // Notes: This function returns TRUE by default.
  470. //
  471. BOOL CLanConnection::FIsMediaPresent() throw()
  472. {
  473. BOOL fRet = TRUE;
  474. GUID guid;
  475. if (S_OK == GetDeviceGuid(&guid))
  476. {
  477. fRet = ::FIsMediaPresent(&guid);
  478. }
  479. return fRet;
  480. }
  481. //+---------------------------------------------------------------------------
  482. //
  483. // Member: CLanConnection::GetStatus
  484. //
  485. // Purpose: Returns the status of this LAN connection
  486. //
  487. // Arguments:
  488. // pStatus [out] Returns status value
  489. //
  490. // Returns: S_OK if success, OLE or Win32 error code otherwise
  491. //
  492. // Author: danielwe 3 Oct 1997
  493. //
  494. // Notes:
  495. //
  496. HRESULT CLanConnection::GetStatus(OUT NETCON_STATUS *pStatus)
  497. {
  498. HRESULT hr;
  499. if (!pStatus)
  500. {
  501. hr = E_POINTER;
  502. }
  503. else if (!m_fInitialized)
  504. {
  505. hr = E_UNEXPECTED;
  506. }
  507. else
  508. {
  509. GUID guid;
  510. hr = GetDeviceGuid(&guid);
  511. if (S_OK == hr)
  512. {
  513. hr = HrGetDevInstStatus(m_deid.DevInst, &guid, pStatus);
  514. }
  515. }
  516. TraceError("CLanConnection::GetStatus", hr);
  517. return hr;
  518. }
  519. //+---------------------------------------------------------------------------
  520. //
  521. // Member: CLanConnection::GetDeviceName
  522. //
  523. // Purpose: Returns the name of the device being used by this connection
  524. //
  525. // Arguments:
  526. // ppszwDeviceName [out] Receives device name
  527. //
  528. // Returns: S_OK if success, OLE error code otherwise
  529. //
  530. // Author: danielwe 2 Oct 1997
  531. //
  532. // Notes: Returned string must be freed with CoTaskMemFree.
  533. //
  534. HRESULT CLanConnection::GetDeviceName(OUT PWSTR* ppszwDeviceName)
  535. {
  536. Assert (ppszwDeviceName);
  537. Assert(m_hdi);
  538. // Initialize the output parameter.
  539. *ppszwDeviceName = NULL;
  540. PWSTR szDesc;
  541. HRESULT hr = HrSetupDiGetDeviceName(m_hdi, &m_deid, &szDesc);
  542. if (SUCCEEDED(hr))
  543. {
  544. hr = HrCoTaskMemAllocAndDupSz (szDesc, ppszwDeviceName, NETCON_MAX_NAME_LEN);
  545. delete [] reinterpret_cast<BYTE*>(szDesc);
  546. }
  547. TraceError("CLanConnection::GetDeviceName", hr);
  548. return hr;
  549. }
  550. //+---------------------------------------------------------------------------
  551. //
  552. // Member: CLanConnection::GetCharacteristics
  553. //
  554. // Purpose: Returns the characteristics of this connection type
  555. //
  556. // Arguments:
  557. // pdwFlags [out] Returns characteristics flags
  558. //
  559. // Returns: S_OK if successful, OLE or Win32 error code otherwise
  560. //
  561. // Author: danielwe 3 Oct 1997
  562. //
  563. // Notes:
  564. //
  565. HRESULT CLanConnection::GetCharacteristics(IN NETCON_MEDIATYPE ncm,
  566. OUT DWORD* pdwFlags)
  567. {
  568. Assert (pdwFlags);
  569. *pdwFlags = NCCF_ALL_USERS | NCCF_ALLOW_RENAME;
  570. DWORD dwValue;
  571. HRESULT hr = HrRegQueryDword(m_hkeyConn, c_szShowIcon, &dwValue);
  572. if (SUCCEEDED(hr) && dwValue)
  573. {
  574. *pdwFlags |= NCCF_SHOW_ICON;
  575. }
  576. BOOL fShared;
  577. hr = HrIsConnectionIcsPublic(&fShared);
  578. if(SUCCEEDED(hr) && TRUE == fShared)
  579. {
  580. *pdwFlags |= NCCF_SHARED;
  581. }
  582. BOOL fBridged;
  583. hr = HrIsConnectionBridged(&fBridged);
  584. if(SUCCEEDED(hr) && TRUE == fBridged)
  585. {
  586. *pdwFlags |= NCCF_BRIDGED;
  587. }
  588. BOOL bFirewalled;
  589. hr = HrIsConnectionFirewalled(&bFirewalled);
  590. if(SUCCEEDED(hr) && TRUE == bFirewalled)
  591. {
  592. *pdwFlags |= NCCF_FIREWALLED;
  593. }
  594. if(NCM_BRIDGE == ncm)
  595. {
  596. hr = HrEnsureValidNlaPolicyEngine();
  597. if(SUCCEEDED(hr))
  598. {
  599. BOOL fHasPermission;
  600. hr = m_pNetMachinePolicies->VerifyPermission(NCPERM_AllowNetBridge_NLA, &fHasPermission);
  601. if(SUCCEEDED(hr) && fHasPermission)
  602. {
  603. *pdwFlags |= NCCF_ALLOW_REMOVAL;
  604. }
  605. }
  606. }
  607. hr = S_OK;
  608. TraceError("CLanConnection::GetCharacteristics", hr);
  609. return hr;
  610. }
  611. //+---------------------------------------------------------------------------
  612. //
  613. // Member: CLanConnection::GetUiObjectClassId
  614. //
  615. // Purpose: Returns the CLSID of the object that handles UI for this
  616. // connection type
  617. //
  618. // Arguments:
  619. // pclsid [out] Returns CLSID of UI object
  620. //
  621. // Returns: S_OK if success, OLE error code otherwise
  622. //
  623. // Author: danielwe 6 Oct 1997
  624. //
  625. // Notes:
  626. //
  627. STDMETHODIMP CLanConnection::GetUiObjectClassId(OUT CLSID *pclsid)
  628. {
  629. HRESULT hr = S_OK;
  630. // Validate parameters.
  631. //
  632. if (!pclsid)
  633. {
  634. hr = E_POINTER;
  635. }
  636. else if (!m_fInitialized)
  637. {
  638. hr = E_UNEXPECTED;
  639. }
  640. else
  641. {
  642. *pclsid = CLSID_LanConnectionUi;
  643. }
  644. TraceError("CLanConnection::GetUiObjectClassId", hr);
  645. return hr;
  646. }
  647. static const WCHAR c_szLibPath[] = L"sens.dll";
  648. static const CHAR c_szaFunction[] = "SensNotifyNetconEvent";
  649. //+---------------------------------------------------------------------------
  650. //
  651. // Member: CLanConnection::HrCallSens
  652. //
  653. // Purpose: Calls the external SENS notification DLL to let it know that
  654. // we connected or disconnected.
  655. //
  656. // Arguments:
  657. // fConnect [in] TRUE if connecting, FALSE if disconnecting
  658. //
  659. // Returns: S_OK if success, Win32 error code otherwise
  660. //
  661. // Author: danielwe 16 Jun 1998
  662. //
  663. // Notes:
  664. //
  665. HRESULT CLanConnection::HrCallSens(IN BOOL fConnect)
  666. {
  667. HRESULT hr = S_OK;
  668. HMODULE hmod;
  669. PFNSENSNOTIFY pfnSensNotifyNetconEvent;
  670. hr = HrLoadLibAndGetProc(c_szLibPath, c_szaFunction, &hmod,
  671. reinterpret_cast<FARPROC *>(&pfnSensNotifyNetconEvent));
  672. if (SUCCEEDED(hr))
  673. {
  674. DWORD dwErr;
  675. SENS_NOTIFY_NETCON snl = {0};
  676. snl.eType = fConnect ? SENS_NOTIFY_LAN_CONNECT :
  677. SENS_NOTIFY_LAN_DISCONNECT;
  678. snl.pINetConnection = this;
  679. TraceTag(ttidLanCon, "Calling SENS to notify of %s.",
  680. fConnect ? "connect" : "disconnect");
  681. dwErr = pfnSensNotifyNetconEvent(&snl);
  682. if (dwErr != ERROR_SUCCESS)
  683. {
  684. hr = HRESULT_FROM_WIN32(dwErr);
  685. }
  686. else
  687. {
  688. TraceTag(ttidLanCon, "Successfully notified SENS.");
  689. }
  690. FreeLibrary(hmod);
  691. }
  692. TraceError("CLanConnection::HrCallSens", hr);
  693. return hr;
  694. }
  695. //+---------------------------------------------------------------------------
  696. //
  697. // Member: CLanConnection::HrConnectOrDisconnect
  698. //
  699. // Purpose: Connects or disconnects this LAN connection
  700. //
  701. // Arguments:
  702. // fConnect [in] TRUE if connect, FALSE if disconnect
  703. //
  704. // Returns: S_OK if success, OLE or Win32 error code otherwise
  705. //
  706. // Author: danielwe 4 Dec 1997
  707. //
  708. // Notes:
  709. //
  710. HRESULT CLanConnection::HrConnectOrDisconnect(IN BOOL fConnect)
  711. {
  712. HRESULT hr = S_OK;
  713. if (!m_hdi)
  714. {
  715. hr = E_UNEXPECTED;
  716. }
  717. else if (!m_fInitialized)
  718. {
  719. hr = E_UNEXPECTED;
  720. }
  721. else
  722. {
  723. // Before attempting to connect, check media state. If it is
  724. // disconnected, return error code that indicates that network is
  725. // not present because the cable is unplugged.
  726. //
  727. if (fConnect)
  728. {
  729. if (!FIsMediaPresent())
  730. {
  731. hr = HRESULT_FROM_WIN32(ERROR_NOT_CONNECTED);
  732. }
  733. }
  734. if (SUCCEEDED(hr))
  735. {
  736. //
  737. // Enable both on global and config-specific profile
  738. // do global first and see if that succeeded in enabling the device
  739. // (global enable doesn't mark reboot required if device is still
  740. // disabled on current config whereas vice-versa isn't true)
  741. //
  742. // However, disable in global config only.
  743. hr = HrSetupDiSendPropertyChangeNotification(m_hdi, &m_deid,
  744. fConnect ? DICS_ENABLE : DICS_DISABLE,
  745. DICS_FLAG_GLOBAL, 0);
  746. if ( fConnect && SUCCEEDED(hr) )
  747. {
  748. hr = HrSetupDiSendPropertyChangeNotification(m_hdi, &m_deid,
  749. DICS_ENABLE,
  750. DICS_FLAG_CONFIGSPECIFIC, 0);
  751. }
  752. if (SUCCEEDED(hr))
  753. {
  754. NETCON_STATUS status;
  755. hr = GetStatus(&status);
  756. if (SUCCEEDED(hr))
  757. {
  758. if (fConnect)
  759. {
  760. int nSecondsToWait = 5;
  761. HRESULT hrRetry = S_OK;
  762. while ((nSecondsToWait) && SUCCEEDED(hrRetry) &&
  763. ((NCS_CONNECTING == status) || (NCS_MEDIA_DISCONNECTED == status) || (NCS_INVALID_ADDRESS == status)))
  764. {
  765. //#300520: check a few more times since the connection is
  766. // still coming up
  767. Sleep(1000);
  768. hrRetry = GetStatus(&status);
  769. nSecondsToWait --;
  770. }
  771. if (status != NCS_CONNECTED)
  772. {
  773. // did not connect successfully
  774. hr = HRESULT_FROM_WIN32(ERROR_RETRY);
  775. TraceError("HrConnectOrDisconnect - failed to "
  776. "connect!", hr);
  777. }
  778. }
  779. else
  780. {
  781. if (status != NCS_DISCONNECTED)
  782. {
  783. // did not disconnect successfully
  784. hr = HRESULT_FROM_WIN32(ERROR_RETRY);
  785. TraceError("HrConnectOrDisconnect - failed to "
  786. "disconnect!", hr);
  787. }
  788. }
  789. }
  790. if (SUCCEEDED(hr))
  791. {
  792. hr = HrCallSens(fConnect);
  793. if (FAILED(hr))
  794. {
  795. TraceTag(ttidLanCon, "Failed to notify SENS on %s. "
  796. "Non-fatal 0x%08X",
  797. fConnect ? "connect" : "disconnect", hr);
  798. hr = S_OK;
  799. }
  800. }
  801. }
  802. }
  803. }
  804. TraceError("CLanConnection::HrConnectOrDisconnect", hr);
  805. return hr;
  806. }
  807. //+---------------------------------------------------------------------------
  808. //
  809. // Member: CLanConnection::Connect
  810. //
  811. // Purpose: Activates the current LAN connection by telling its underlying
  812. // adapter to activate itself.
  813. //
  814. // Arguments:
  815. // (none)
  816. //
  817. // Returns: S_OK if success, OLE or Win32 error code otherwise
  818. //
  819. // Author: danielwe 14 Oct 1997
  820. //
  821. // Notes: Causes auto-connect value of TRUE to be written for this
  822. // connection in the current hardware profile.
  823. //
  824. STDMETHODIMP CLanConnection::Connect()
  825. {
  826. HRESULT hr = S_OK;
  827. hr = HrConnectOrDisconnect(TRUE);
  828. TraceError("CLanConnection::Connect", hr);
  829. return hr;
  830. }
  831. //+---------------------------------------------------------------------------
  832. //
  833. // Member: CLanConnection::Disconnect
  834. //
  835. // Purpose: Deactivates the current LAN connection by telling its
  836. // underlying adapter to deactivate itself.
  837. //
  838. // Arguments:
  839. // (none)
  840. //
  841. // Returns: S_OK if success, OLE or Win32 error code otherwise
  842. //
  843. // Author: danielwe 14 Oct 1997
  844. //
  845. // Notes: Causes auto-connect value of FALSE to be written for this
  846. // connection in the current hardware profile.
  847. //
  848. STDMETHODIMP CLanConnection::Disconnect()
  849. {
  850. HRESULT hr = S_OK;
  851. hr = HrConnectOrDisconnect(FALSE);
  852. TraceError("CLanConnection::Disconnect", hr);
  853. return hr;
  854. }
  855. //+---------------------------------------------------------------------------
  856. //
  857. // Member: CLanConnection::Delete
  858. //
  859. // Purpose: Delete the LAN/BRIDGE connection.
  860. //
  861. // Arguments:
  862. // (none)
  863. //
  864. // Returns: E_UNEXPECTED;
  865. //
  866. // Author: shaunco 21 Jan 1998
  867. //
  868. // Notes: This function is only expected to be called for a bridge.
  869. //
  870. STDMETHODIMP CLanConnection::Delete()
  871. {
  872. HRESULT hr;
  873. NETCON_PROPERTIES* pProperties;
  874. hr = GetProperties(&pProperties);
  875. if(SUCCEEDED(hr))
  876. {
  877. if(NCM_BRIDGE == pProperties->MediaType)
  878. {
  879. IHNetConnection *pHNetConnection;
  880. IHNetBridge* pNetBridge;
  881. Assert(m_fInitialized);
  882. hr = HrGetIHNetConnection(&pHNetConnection);
  883. if (SUCCEEDED(hr))
  884. {
  885. hr = pHNetConnection->GetControlInterface(
  886. IID_IHNetBridge,
  887. reinterpret_cast<void**>(&pNetBridge)
  888. );
  889. ReleaseObj(pHNetConnection);
  890. AssertSz(SUCCEEDED(hr), "Unable to retrieve IHNetBridge");
  891. }
  892. if(SUCCEEDED(hr))
  893. {
  894. hr = pNetBridge->Destroy();
  895. ReleaseObj(pNetBridge);
  896. }
  897. }
  898. else
  899. {
  900. hr = E_FAIL; // can't delete anything but NCM_BRIDGE
  901. }
  902. FreeNetconProperties(pProperties);
  903. }
  904. return hr;
  905. }
  906. STDMETHODIMP CLanConnection::Duplicate (
  907. IN PCWSTR pszDuplicateName,
  908. OUT INetConnection** ppCon)
  909. {
  910. return E_NOTIMPL;
  911. }
  912. //+---------------------------------------------------------------------------
  913. //
  914. // Member: CLanConnection::GetProperties
  915. //
  916. // Purpose: Get all of the properties associated with the connection.
  917. // Returning all of them at once saves us RPCs vs. returning
  918. // each one individually.
  919. //
  920. // Arguments:
  921. // ppProps [out] Returned block of properties.
  922. //
  923. // Returns: S_OK or an error.
  924. //
  925. // Author: shaunco 1 Feb 1998
  926. //
  927. // Notes:
  928. //
  929. STDMETHODIMP CLanConnection::GetProperties (
  930. OUT NETCON_PROPERTIES** ppProps)
  931. {
  932. HRESULT hr = S_OK;
  933. // Validate parameters.
  934. //
  935. if (!ppProps)
  936. {
  937. hr = E_POINTER;
  938. }
  939. else if (!m_fInitialized)
  940. {
  941. hr = E_UNEXPECTED;
  942. }
  943. else
  944. {
  945. // Initialize the output parameter.
  946. //
  947. *ppProps = NULL;
  948. NETCON_PROPERTIES* pProps;
  949. NETCON_STATUS ncStatus;
  950. hr = HrCoTaskMemAlloc (sizeof (NETCON_PROPERTIES),
  951. reinterpret_cast<void**>(&pProps));
  952. if (SUCCEEDED(hr))
  953. {
  954. HRESULT hrT;
  955. ZeroMemory (pProps, sizeof (NETCON_PROPERTIES));
  956. // guidId
  957. //
  958. hrT = GetDeviceGuid(&pProps->guidId);
  959. if (FAILED(hrT))
  960. {
  961. hr = hrT;
  962. }
  963. // pszwName
  964. //
  965. tstring strName;
  966. hrT = HrRegQueryString(m_hkeyConn, c_szConnName, &strName);
  967. if (SUCCEEDED(hrT))
  968. {
  969. hrT = HrCoTaskMemAllocAndDupSz (strName.c_str(),
  970. &pProps->pszwName, NETCON_MAX_NAME_LEN);
  971. }
  972. if (FAILED(hrT))
  973. {
  974. hr = hrT;
  975. }
  976. // pszwDeviceName
  977. //
  978. PWSTR szDesc;
  979. hrT = HrSetupDiGetDeviceName(m_hdi, &m_deid, &szDesc);
  980. if (SUCCEEDED(hrT))
  981. {
  982. hrT = HrCoTaskMemAllocAndDupSz (szDesc,
  983. &pProps->pszwDeviceName, NETCON_MAX_NAME_LEN);
  984. delete [] reinterpret_cast<BYTE*>(szDesc);
  985. }
  986. if (FAILED(hrT))
  987. {
  988. hr = hrT;
  989. }
  990. // Status
  991. //
  992. hrT = GetStatus (&pProps->Status);
  993. if (FAILED(hrT))
  994. {
  995. hr = hrT;
  996. }
  997. // Get additional Status information from 802.1X
  998. //
  999. if ((NCS_CONNECTED == pProps->Status)
  1000. || (NCS_INVALID_ADDRESS == pProps->Status)
  1001. || (NCS_MEDIA_DISCONNECTED == pProps->Status))
  1002. {
  1003. hrT = WZCQueryGUIDNCSState(&pProps->guidId, &ncStatus);
  1004. if (S_OK == hrT)
  1005. {
  1006. pProps->Status = ncStatus;
  1007. }
  1008. }
  1009. // Type
  1010. //
  1011. BOOL fNetworkBridge;
  1012. hrT = HrIsConnectionNetworkBridge(&fNetworkBridge);
  1013. if(SUCCEEDED(hrT) && TRUE == fNetworkBridge)
  1014. {
  1015. pProps->MediaType = NCM_BRIDGE;
  1016. }
  1017. else
  1018. {
  1019. pProps->MediaType = NCM_LAN;
  1020. }
  1021. // dwCharacter
  1022. //
  1023. hrT = GetCharacteristics (pProps->MediaType, &pProps->dwCharacter);
  1024. if (FAILED(hrT))
  1025. {
  1026. hr = hrT;
  1027. }
  1028. // clsidThisObject
  1029. //
  1030. pProps->clsidThisObject = CLSID_LanConnection;
  1031. // clsidUiObject
  1032. //
  1033. pProps->clsidUiObject = CLSID_LanConnectionUi;
  1034. // Assign the output parameter or cleanup if we had any failures.
  1035. //
  1036. if (SUCCEEDED(hr))
  1037. {
  1038. *ppProps = pProps;
  1039. }
  1040. else
  1041. {
  1042. Assert (NULL == *ppProps);
  1043. FreeNetconProperties (pProps);
  1044. }
  1045. }
  1046. }
  1047. TraceError ("CLanConnection::GetProperties", hr);
  1048. return hr;
  1049. }
  1050. //
  1051. // INetLanConnection
  1052. //
  1053. //+---------------------------------------------------------------------------
  1054. //
  1055. // Member: CLanConnection::GetInfo
  1056. //
  1057. // Purpose: Returns information about this connection
  1058. //
  1059. // Arguments:
  1060. // dwMask [in] Flags that control which fields to return. Use
  1061. // LCIF_ALL to get all fields.
  1062. // pLanConInfo [out] Structure that holds returned information
  1063. //
  1064. // Returns: S_OK if success, OLE error code otherwise
  1065. //
  1066. // Author: danielwe 6 Oct 1997
  1067. //
  1068. // Notes: Caller should delete the szwConnName value.
  1069. //
  1070. STDMETHODIMP CLanConnection::GetInfo(IN DWORD dwMask,
  1071. OUT LANCON_INFO* pLanConInfo)
  1072. {
  1073. HRESULT hr = S_OK;
  1074. if (!pLanConInfo)
  1075. {
  1076. hr = E_POINTER;
  1077. }
  1078. else if (!m_hdi)
  1079. {
  1080. hr = E_UNEXPECTED;
  1081. }
  1082. else if (!m_fInitialized)
  1083. {
  1084. hr = E_UNEXPECTED;
  1085. }
  1086. else
  1087. {
  1088. ZeroMemory(pLanConInfo, sizeof(LANCON_INFO));
  1089. if (dwMask & LCIF_COMP)
  1090. {
  1091. GUID guid;
  1092. hr = HrGetInstanceGuid(m_hdi, m_deid, &guid);
  1093. pLanConInfo->guid = guid;
  1094. }
  1095. if (dwMask & LCIF_NAME)
  1096. {
  1097. hr = GetDeviceName(&pLanConInfo->szwConnName);
  1098. }
  1099. if (dwMask & LCIF_ICON)
  1100. {
  1101. if (SUCCEEDED(hr))
  1102. {
  1103. DWORD dwValue;
  1104. hr = HrRegQueryDword(m_hkeyConn, c_szShowIcon, &dwValue);
  1105. // OK if value not there. Default to FALSE always.
  1106. //
  1107. if (S_OK == hr)
  1108. {
  1109. pLanConInfo->fShowIcon = !!(dwValue);
  1110. }
  1111. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  1112. {
  1113. hr = NETCFG_S_NOTEXIST;
  1114. }
  1115. }
  1116. }
  1117. }
  1118. // Mask S_FALSE if it slipped thru.
  1119. if (S_FALSE == hr)
  1120. {
  1121. hr = S_OK;
  1122. }
  1123. TraceError("CLanConnection::GetInfo", hr);
  1124. return hr;
  1125. }
  1126. //+---------------------------------------------------------------------------
  1127. //
  1128. // Member: CLanConnection::SetInfo
  1129. //
  1130. // Purpose: Sets information about this connection.
  1131. //
  1132. // Arguments:
  1133. // dwMask [in] Flags that control which fields to set
  1134. // pLanConInfo [in] Structure containing information to set
  1135. //
  1136. // Returns: S_OK if success, OLE or Win32 error code otherwise
  1137. //
  1138. // Author: danielwe 6 Oct 1997
  1139. //
  1140. // Notes: The guid member can only be set if the object is not yet
  1141. // initialized.
  1142. // The AutoConnect value is never set because it is set only upon
  1143. // connect or disconnect.
  1144. // If szwConnName is NULL, it is left unchanged.
  1145. //
  1146. STDMETHODIMP CLanConnection::SetInfo(IN DWORD dwMask,
  1147. IN const LANCON_INFO* pLanConInfo)
  1148. {
  1149. HRESULT hr = S_OK;
  1150. if (!pLanConInfo)
  1151. {
  1152. hr = E_POINTER;
  1153. }
  1154. else if (!m_fInitialized)
  1155. {
  1156. // If we're not yet initialized, the only thing we will allow is the
  1157. // flag that gets us initialized
  1158. if (dwMask != LCIF_COMP)
  1159. {
  1160. hr = E_UNEXPECTED;
  1161. }
  1162. else
  1163. {
  1164. hr = HrLoad(pLanConInfo->guid);
  1165. if (SUCCEEDED(hr))
  1166. {
  1167. WCHAR szPnpId[MAX_DEVICE_ID_LEN];
  1168. hr = HrSetupDiGetDeviceInstanceId(m_hdi, &m_deid, szPnpId,
  1169. MAX_DEVICE_ID_LEN, NULL);
  1170. if (S_OK == hr)
  1171. {
  1172. hr = HrInitialize(szPnpId);
  1173. }
  1174. }
  1175. }
  1176. }
  1177. else
  1178. {
  1179. if (dwMask & LCIF_NAME)
  1180. {
  1181. AssertSz(pLanConInfo->szwConnName,
  1182. "If you're going to set it, set it!");
  1183. // Set connection name
  1184. hr = Rename(pLanConInfo->szwConnName);
  1185. }
  1186. if (dwMask & LCIF_ICON)
  1187. {
  1188. if (SUCCEEDED(hr))
  1189. {
  1190. // Set ShowIcon value
  1191. hr = HrRegSetDword(m_hkeyConn, c_szShowIcon,
  1192. pLanConInfo->fShowIcon);
  1193. }
  1194. }
  1195. if (SUCCEEDED(hr))
  1196. {
  1197. LanEventNotify(CONNECTION_MODIFIED, this, NULL, NULL);
  1198. }
  1199. }
  1200. TraceError("CLanConnection::SetInfo", hr);
  1201. return hr;
  1202. }
  1203. //+---------------------------------------------------------------------------
  1204. //
  1205. // Member: CLanConnection::GetDeviceGuid
  1206. //
  1207. // Purpose: Returns the instance GUID of the device being used by this
  1208. // connection
  1209. //
  1210. // Arguments:
  1211. // pguid [out] Receives GUID of device
  1212. //
  1213. // Returns: S_OK if success, NetCfg error code otherwise
  1214. //
  1215. // Author: danielwe 2 Oct 1997
  1216. //
  1217. // Notes:
  1218. //
  1219. STDMETHODIMP CLanConnection::GetDeviceGuid(OUT GUID *pguid)
  1220. {
  1221. HRESULT hr;
  1222. AssertSz(m_hdi, "No component?!");
  1223. if (!pguid)
  1224. {
  1225. hr = E_POINTER;
  1226. }
  1227. else if (!m_fInitialized)
  1228. {
  1229. hr = E_UNEXPECTED;
  1230. }
  1231. else
  1232. {
  1233. hr = HrGetInstanceGuid(m_hdi, m_deid, pguid);
  1234. }
  1235. TraceError("CLanConnection::GetDeviceGuid", hr);
  1236. return hr;
  1237. }
  1238. //+---------------------------------------------------------------------------
  1239. // IPersistNetConnection
  1240. //
  1241. //+---------------------------------------------------------------------------
  1242. //
  1243. // Member: CLanConnection::GetClassID
  1244. //
  1245. // Purpose: Returns the CLSID of LAN connection objects
  1246. //
  1247. // Arguments:
  1248. // pclsid [out] Returns CLSID to caller
  1249. //
  1250. // Returns: S_OK if success, OLE error otherwise
  1251. //
  1252. // Author: danielwe 4 Nov 1997
  1253. //
  1254. // Notes:
  1255. //
  1256. STDMETHODIMP CLanConnection::GetClassID(OUT CLSID* pclsid)
  1257. {
  1258. HRESULT hr = S_OK;
  1259. // Validate parameters.
  1260. //
  1261. if (!pclsid)
  1262. {
  1263. hr = E_POINTER;
  1264. }
  1265. else
  1266. {
  1267. *pclsid = CLSID_LanConnection;
  1268. }
  1269. TraceError("CLanConnection::GetClassID", hr);
  1270. return hr;
  1271. }
  1272. //+---------------------------------------------------------------------------
  1273. //
  1274. // Member: CLanConnection::GetSizeMax
  1275. //
  1276. // Purpose: Returns the maximum size of the persistence data
  1277. //
  1278. // Arguments:
  1279. // pcbSize [out] Returns size
  1280. //
  1281. // Returns: S_OK if success, OLE error otherwise
  1282. //
  1283. // Author: danielwe 4 Nov 1997
  1284. //
  1285. // Notes:
  1286. //
  1287. STDMETHODIMP CLanConnection::GetSizeMax(OUT ULONG *pcbSize)
  1288. {
  1289. HRESULT hr = S_OK;
  1290. // Validate parameters.
  1291. //
  1292. if (!pcbSize)
  1293. {
  1294. hr = E_POINTER;
  1295. }
  1296. else if (!m_fInitialized)
  1297. {
  1298. hr = E_UNEXPECTED;
  1299. }
  1300. else
  1301. {
  1302. *pcbSize = sizeof(GUID);
  1303. }
  1304. TraceError("CLanConnection::GetSizeMax", hr);
  1305. return hr;
  1306. }
  1307. //+---------------------------------------------------------------------------
  1308. //
  1309. // Member: CLanConnection::Load
  1310. //
  1311. // Purpose: Allows the connection object to initialize (restore) itself
  1312. // from previously persisted data
  1313. //
  1314. // Arguments:
  1315. // pbBuf [in] Private data to use for restoring
  1316. // cbSize [in] Size of data
  1317. //
  1318. // Returns: S_OK if success, OLE error otherwise
  1319. //
  1320. // Author: danielwe 4 Nov 1997
  1321. //
  1322. // Notes:
  1323. //
  1324. STDMETHODIMP CLanConnection::Load(IN const BYTE *pbBuf,
  1325. IN ULONG cbSize)
  1326. {
  1327. HRESULT hr = E_INVALIDARG;
  1328. // Validate parameters.
  1329. //
  1330. if (!pbBuf)
  1331. {
  1332. hr = E_POINTER;
  1333. }
  1334. else if (cbSize != sizeof(GUID))
  1335. {
  1336. hr = E_INVALIDARG;
  1337. }
  1338. // We can only accept one call on this method and only if we're not
  1339. // already initialized.
  1340. //
  1341. else if (m_fInitialized)
  1342. {
  1343. hr = E_UNEXPECTED;
  1344. }
  1345. else
  1346. {
  1347. GUID guid;
  1348. CopyMemory(&guid, pbBuf, sizeof(GUID));
  1349. hr = HrLoad(guid);
  1350. }
  1351. TraceError("CLanConnection::Load", hr);
  1352. return hr;
  1353. }
  1354. //+---------------------------------------------------------------------------
  1355. //
  1356. // Member: CLanConnection::Save
  1357. //
  1358. // Purpose: Provides the caller with data to use in restoring this object
  1359. // at a later time.
  1360. //
  1361. // Arguments:
  1362. // pbBuf [out] Returns data to use for restoring
  1363. // cbSize [in] Size of data buffer
  1364. //
  1365. // Returns: S_OK if success, OLE error otherwise
  1366. //
  1367. // Author: danielwe 4 Nov 1997
  1368. //
  1369. // Notes:
  1370. //
  1371. STDMETHODIMP CLanConnection::Save(OUT BYTE *pbBuf, IN ULONG cbSize)
  1372. {
  1373. HRESULT hr;
  1374. // Validate parameters.
  1375. //
  1376. if (!pbBuf)
  1377. {
  1378. hr = E_POINTER;
  1379. }
  1380. else if (!m_fInitialized || !m_hdi)
  1381. {
  1382. hr = E_UNEXPECTED;
  1383. }
  1384. else
  1385. {
  1386. GUID guid;
  1387. hr = HrGetInstanceGuid(m_hdi, m_deid, &guid);
  1388. if (S_OK == hr)
  1389. {
  1390. CopyMemory(pbBuf, &guid, cbSize);
  1391. }
  1392. }
  1393. TraceError("CLanConnection::Save", hr);
  1394. return hr;
  1395. }
  1396. //
  1397. // Private functions
  1398. //
  1399. extern const WCHAR c_szRegValueNetCfgInstanceId[];
  1400. //+---------------------------------------------------------------------------
  1401. //
  1402. // Function: HrGetInstanceGuid
  1403. //
  1404. // Purpose: Given device info, returns the NetCfg instance GUID of the
  1405. // connection.
  1406. //
  1407. // Arguments:
  1408. // hdi [in] SetupAPI data
  1409. // deid [in] SetupAPI data
  1410. // pguid [out] GUID of netcfg component
  1411. //
  1412. // Returns: S_OK if success, Win32 or SetupAPI error otherwise
  1413. //
  1414. // Author: danielwe 7 Jan 1998
  1415. //
  1416. // Notes:
  1417. //
  1418. HRESULT HrGetInstanceGuid(IN HDEVINFO hdi,
  1419. IN const SP_DEVINFO_DATA &deid,
  1420. OUT LPGUID pguid)
  1421. {
  1422. HRESULT hr;
  1423. HKEY hkey;
  1424. Assert(pguid);
  1425. hr = HrSetupDiOpenDevRegKey(hdi, const_cast<SP_DEVINFO_DATA *>(&deid),
  1426. DICS_FLAG_GLOBAL, 0,
  1427. DIREG_DRV, KEY_READ, &hkey);
  1428. if (S_OK == hr)
  1429. {
  1430. WCHAR szGuid[c_cchGuidWithTerm];
  1431. DWORD cbBuf = sizeof(szGuid);
  1432. hr = HrRegQuerySzBuffer(hkey, c_szRegValueNetCfgInstanceId,
  1433. szGuid, &cbBuf);
  1434. if (S_OK == hr)
  1435. {
  1436. IIDFromString(szGuid, pguid);
  1437. }
  1438. RegCloseKey(hkey);
  1439. }
  1440. TraceError("HrInstanceGuidFromDeid", hr);
  1441. return hr;
  1442. }
  1443. static const WCHAR c_szKeyFmt[] = L"%s\\%s\\%s\\Connection";
  1444. extern const WCHAR c_szRegKeyComponentClasses[];
  1445. extern const WCHAR c_szRegValuePnpInstanceId[];
  1446. //+---------------------------------------------------------------------------
  1447. //
  1448. // Function: HrLoadDevInfoFromGuid
  1449. //
  1450. // Purpose: Given a NetCfg instance GUID, loads the m_hdi and m_deid
  1451. // members from the device installer.
  1452. //
  1453. // Arguments:
  1454. // guid [in] GUID of connection
  1455. //
  1456. // Returns: S_OK if success, Win32 or SetupAPI error otherwise
  1457. //
  1458. // Author: danielwe 7 Jan 1998
  1459. //
  1460. // Notes:
  1461. //
  1462. HRESULT CLanConnection::HrLoadDevInfoFromGuid(IN const GUID &guid)
  1463. {
  1464. HRESULT hr = S_OK;
  1465. SP_DEVINFO_DATA deid = {0};
  1466. HKEY hkeyNetCfg;
  1467. WCHAR szRegPath[c_cchMaxRegKeyLengthWithNull];
  1468. WCHAR szGuid[c_cchGuidWithTerm];
  1469. WCHAR szClassGuid[c_cchGuidWithTerm];
  1470. StringFromGUID2(GUID_DEVCLASS_NET, szClassGuid, c_cchGuidWithTerm);
  1471. StringFromGUID2(guid, szGuid, c_cchGuidWithTerm);
  1472. wsprintfW(szRegPath, c_szKeyFmt, c_szRegKeyComponentClasses,
  1473. szClassGuid, szGuid);
  1474. // Open the Control\Network\{CLASS}\{Instance GUID} key
  1475. //
  1476. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegPath,
  1477. KEY_READ, &hkeyNetCfg);
  1478. if (SUCCEEDED(hr))
  1479. {
  1480. tstring strInstanceId;
  1481. hr = HrRegQueryString(hkeyNetCfg, c_szRegValuePnpInstanceId,
  1482. &strInstanceId);
  1483. if (SUCCEEDED(hr))
  1484. {
  1485. hr = HrSetupDiCreateDeviceInfoList(&GUID_DEVCLASS_NET,
  1486. NULL, &m_hdi);
  1487. if (SUCCEEDED(hr))
  1488. {
  1489. hr = HrSetupDiOpenDeviceInfo(m_hdi, strInstanceId.c_str(),
  1490. NULL, 0, &m_deid);
  1491. }
  1492. }
  1493. RegCloseKey(hkeyNetCfg);
  1494. }
  1495. TraceError("HrLoadDevInfoFromGuid", hr);
  1496. return hr;
  1497. }
  1498. //+---------------------------------------------------------------------------
  1499. //
  1500. // Function: HrIsAtmAdapterFromHkey
  1501. //
  1502. // Purpose: Determines if the given HKEY describes an ATM physical adapter
  1503. //
  1504. // Arguments:
  1505. // hkey [in] HKEY under Control\Class\{GUID}\<instance> (aka driver key)
  1506. //
  1507. // Returns: S_OK if device is ATM physical adapter, S_FALSE if not,
  1508. // Win32 error otherwise
  1509. //
  1510. // Author: tongl 10 Dec 1998
  1511. //
  1512. // Notes:
  1513. //
  1514. HRESULT CLanConnection::HrIsAtmAdapterFromHkey(IN HKEY hkey)
  1515. {
  1516. HRESULT hr = S_OK;
  1517. WCHAR szBuf[256];
  1518. DWORD cbBuf = sizeof(szBuf);
  1519. list<tstring *> lstr;
  1520. list<tstring *>::iterator lstrIter;
  1521. BOOL fMatch = FALSE;
  1522. HKEY hkeyInterfaces;
  1523. hr = HrRegOpenKeyEx(hkey, c_szRegKeyInterfacesFromInstance,
  1524. KEY_READ, &hkeyInterfaces);
  1525. if (SUCCEEDED(hr))
  1526. {
  1527. hr = HrRegQuerySzBuffer(hkeyInterfaces, c_szRegValueUpperRange,
  1528. szBuf, &cbBuf);
  1529. if (SUCCEEDED(hr))
  1530. {
  1531. ConvertStringToColString(szBuf, c_chComma, lstr);
  1532. for (lstrIter = lstr.begin(); lstrIter != lstr.end(); lstrIter++)
  1533. {
  1534. // See if it matches one of these
  1535. if (!lstrcmpiW((*lstrIter)->c_str(), c_szBiNdisAtm))
  1536. {
  1537. fMatch = TRUE;
  1538. break;
  1539. }
  1540. }
  1541. DeleteColString(&lstr);
  1542. }
  1543. RegCloseKey(hkeyInterfaces);
  1544. }
  1545. if (SUCCEEDED(hr))
  1546. {
  1547. if (fMatch)
  1548. {
  1549. hr = S_OK;
  1550. }
  1551. else
  1552. {
  1553. hr = S_FALSE;
  1554. }
  1555. }
  1556. TraceError("HrIsAtmAdapterFromHkey", (hr == S_FALSE) ? S_OK : hr);
  1557. return hr;
  1558. }
  1559. //+---------------------------------------------------------------------------
  1560. //
  1561. // Function: HrIsAtmElanFromHkey
  1562. //
  1563. // Purpose: Determines if the given HKEY describes an ATM ELAN adapter
  1564. //
  1565. // Arguments:
  1566. // hkey [in] HKEY under Control\Class\{GUID}\<instance> (aka driver key)
  1567. //
  1568. // Returns: S_OK if device is ELAN capable, S_FALSE if not, Win32 error
  1569. // otherwise
  1570. //
  1571. // Author: tongl 21 Oct 1998
  1572. //
  1573. // Notes:
  1574. //
  1575. HRESULT CLanConnection::HrIsAtmElanFromHkey(IN HKEY hkey)
  1576. {
  1577. HRESULT hr;
  1578. // pszInfId should have enough characters to hold "ms_atmelan".
  1579. // If the registry value is bigger than that, we know we don't have
  1580. // a match.
  1581. //
  1582. WCHAR pszInfId [24];
  1583. DWORD cbInfId = sizeof(pszInfId);
  1584. hr = HrRegQuerySzBuffer(hkey, L"ComponentId", pszInfId, &cbInfId);
  1585. if ((S_OK != hr) || (0 != _wcsicmp(pszInfId, L"ms_atmelan")))
  1586. {
  1587. hr = S_FALSE;
  1588. }
  1589. Assert ((S_OK == hr) || (S_FALSE == hr));
  1590. TraceError("HrIsAtmElanFromHkey", (hr == S_FALSE) ? S_OK : hr);
  1591. return hr;
  1592. }
  1593. //+---------------------------------------------------------------------------
  1594. //
  1595. // Function: HrIsConnectionBridged
  1596. //
  1597. // Purpose: Determines if connection is a member of a brigde
  1598. //
  1599. // Arguments:
  1600. // pfBridged [in] A boolean for the result
  1601. //
  1602. // Returns: S_OK if pfBridged is valid
  1603. // S_FALSE if pfBridged can't currently be determined
  1604. // Error otherwise
  1605. //
  1606. // Author: kenwic 11 July 2000
  1607. //
  1608. // Notes:
  1609. //
  1610. HRESULT CLanConnection::HrIsConnectionBridged(OUT BOOL* pfBridged)
  1611. {
  1612. *pfBridged = FALSE;
  1613. HRESULT hResult = S_OK;
  1614. hResult = HrEnsureHNetPropertiesCached();
  1615. if (S_OK == hResult)
  1616. {
  1617. *pfBridged = m_pHNetProperties->fPartOfBridge;
  1618. }
  1619. return hResult;
  1620. }
  1621. //+---------------------------------------------------------------------------
  1622. //
  1623. // Function: HrIsConnectionFirewalled
  1624. //
  1625. // Purpose: Determines if connection is firewalled
  1626. //
  1627. // Arguments:
  1628. // pfFirewalled [in] A boolean for the result
  1629. //
  1630. // Returns: S_OK if pfFirewalled is valid
  1631. // S_FALSE if pfFirewalled can't currently be determined
  1632. // Error otherwise
  1633. //
  1634. // Author: kenwic 11 July 2000
  1635. //
  1636. // Notes:
  1637. //
  1638. HRESULT CLanConnection::HrIsConnectionFirewalled(OUT BOOL* pfFirewalled)
  1639. {
  1640. HRESULT hr = S_OK;
  1641. BOOL fHasPermission = FALSE;
  1642. *pfFirewalled = FALSE;
  1643. hr = HrEnsureHNetPropertiesCached();
  1644. if (S_OK == hr)
  1645. {
  1646. *pfFirewalled = m_pHNetProperties->fFirewalled;
  1647. if (*pfFirewalled)
  1648. {
  1649. // A Connection is only firewalled if the firewall is currently running, so
  1650. // we return FALSE if the permission denies the firewall from running.
  1651. hr = HrEnsureValidNlaPolicyEngine();
  1652. TraceHr(ttidError, FAL, hr, (S_FALSE == hr), "CLanConnection::HrIsConnectionFirewalled calling HrEnsureValidNlaPolicyEngine", hr);
  1653. if (SUCCEEDED(hr))
  1654. {
  1655. hr = m_pNetMachinePolicies->VerifyPermission(NCPERM_PersonalFirewallConfig, &fHasPermission);
  1656. if (SUCCEEDED(hr) && !fHasPermission)
  1657. {
  1658. *pfFirewalled = FALSE;
  1659. }
  1660. }
  1661. }
  1662. }
  1663. return hr;
  1664. }
  1665. //+---------------------------------------------------------------------------
  1666. //
  1667. // Function: HrIsConnectionNetworkBridge
  1668. //
  1669. // Purpose: Determines if a brigde
  1670. //
  1671. // Arguments:
  1672. // pfNetworkBridge [in] A boolean for the result
  1673. //
  1674. // Returns: S_OK if pfNetworkBridge is valid
  1675. // S_FALSE if pfNetworkBridge can't currently be determined
  1676. // Error otherwise
  1677. //
  1678. // Author: kenwic 11 July 2000
  1679. //
  1680. // Notes:
  1681. //
  1682. static const WCHAR c_szNetworkBridgeComponentId[] = L"ms_bridgemp";
  1683. extern const WCHAR c_szRegValueComponentId[];
  1684. HRESULT CLanConnection::HrIsConnectionNetworkBridge(OUT BOOL* pfNetworkBridge)
  1685. {
  1686. *pfNetworkBridge = FALSE;
  1687. HRESULT hr = S_OK;
  1688. HKEY hkey;
  1689. hr = HrSetupDiOpenDevRegKey(m_hdi, const_cast<SP_DEVINFO_DATA *>(&m_deid),
  1690. DICS_FLAG_GLOBAL, 0,
  1691. DIREG_DRV, KEY_READ, &hkey);
  1692. if (S_OK == hr)
  1693. {
  1694. WCHAR szComponentId[60]; // if it's bigger than this, it's not the bridge, but make it big to shut up the tracing
  1695. DWORD cbBuf = sizeof(szComponentId);
  1696. hr = HrRegQuerySzBuffer(hkey, c_szRegValueComponentId,
  1697. szComponentId, &cbBuf);
  1698. if (S_OK == hr || HRESULT_FROM_WIN32(ERROR_MORE_DATA) == hr)
  1699. {
  1700. if(0 == lstrcmp(szComponentId, c_szNetworkBridgeComponentId))
  1701. {
  1702. *pfNetworkBridge = TRUE;
  1703. }
  1704. hr = S_OK;
  1705. }
  1706. RegCloseKey(hkey);
  1707. }
  1708. TraceError("HrIsConnectionNetworkBridge", hr);
  1709. return hr;
  1710. }
  1711. //+---------------------------------------------------------------------------
  1712. //
  1713. // Function: HrIsConnectionIcsPublic
  1714. //
  1715. // Purpose: Determines if connection is shared (ICS public)
  1716. //
  1717. // Arguments:
  1718. // pfIcsPublic [out] A boolean for the result
  1719. //
  1720. // Returns: S_OK if pfIcsPublic is valid
  1721. // S_FALSE if pfIcsPublic can't currently be determined
  1722. // Error otherwise
  1723. //
  1724. // Author: jonburs 31 July 2000
  1725. //
  1726. // Notes:
  1727. //
  1728. HRESULT CLanConnection::HrIsConnectionIcsPublic(OUT BOOL* pfIcsPublic)
  1729. {
  1730. Assert(NULL != pfIcsPublic);
  1731. *pfIcsPublic = FALSE;
  1732. HRESULT hResult = S_OK;
  1733. hResult = HrEnsureHNetPropertiesCached();
  1734. if (S_OK == hResult)
  1735. {
  1736. *pfIcsPublic = m_pHNetProperties->fIcsPublic;
  1737. }
  1738. return hResult;
  1739. }
  1740. //+---------------------------------------------------------------------------
  1741. //
  1742. // Function: HrEnsureHNetPropertiesCached
  1743. //
  1744. // Purpose: Makes sure home networking properties are up-to-date
  1745. //
  1746. // Arguments:
  1747. //
  1748. // Returns: S_OK if m_pHNetProperties is now valid (success)
  1749. // S_FALSE if it's not currently possible to update the properties
  1750. // (e.g., recursive attempt to update)
  1751. //
  1752. // Author: jonburs 16 August 2000
  1753. //
  1754. // Notes:
  1755. //
  1756. HRESULT CLanConnection::HrEnsureHNetPropertiesCached(VOID)
  1757. {
  1758. HRESULT hr = S_OK;
  1759. Assert(TRUE == m_fInitialized);
  1760. if (!m_fHNetPropertiesCached
  1761. || m_lHNetModifiedEra != g_lHNetModifiedEra)
  1762. {
  1763. //
  1764. // Our cached properties are possibly out of date. Check
  1765. // to see that this is not a recursive entry
  1766. //
  1767. if (0 == InterlockedExchange(&m_lUpdatingHNetProperties, 1))
  1768. {
  1769. IHNetConnection *pHNetConn;
  1770. HNET_CONN_PROPERTIES *pProps;
  1771. hr = HrGetIHNetConnection(&pHNetConn);
  1772. if (SUCCEEDED(hr))
  1773. {
  1774. hr = pHNetConn->GetProperties(&pProps);
  1775. ReleaseObj(pHNetConn);
  1776. if (SUCCEEDED(hr))
  1777. {
  1778. //
  1779. // Store new properties, and free old. Note that CoTaskMemFree
  1780. // properly handles NULL input.
  1781. //
  1782. pProps =
  1783. reinterpret_cast<HNET_CONN_PROPERTIES*>(
  1784. InterlockedExchangePointer(
  1785. reinterpret_cast<PVOID*>(&m_pHNetProperties),
  1786. reinterpret_cast<PVOID>(pProps)
  1787. )
  1788. );
  1789. CoTaskMemFree(pProps);
  1790. //
  1791. // Update our era, and note that we have valid properties
  1792. //
  1793. InterlockedExchange(&m_lHNetModifiedEra, g_lHNetModifiedEra);
  1794. m_fHNetPropertiesCached = TRUE;
  1795. hr = S_OK;
  1796. }
  1797. }
  1798. else
  1799. {
  1800. //
  1801. // If we don't yet have a record of this connection w/in the
  1802. // home networking store, HrGetIHNetConnection will fail (as
  1803. // we ask it not to create new entries). We therefore convert
  1804. // failure to S_FALSE, which means we can't retrieve this info
  1805. // right now.
  1806. //
  1807. hr = S_FALSE;
  1808. }
  1809. //
  1810. // We're no longer updating our properties
  1811. //
  1812. InterlockedExchange(&m_lUpdatingHNetProperties, 0);
  1813. }
  1814. else
  1815. {
  1816. //
  1817. // Update is alredy going on (possibly an earlier call on
  1818. // the same thread). Return S_FALSE.
  1819. //
  1820. hr = S_FALSE;
  1821. }
  1822. }
  1823. return hr;
  1824. }
  1825. //+---------------------------------------------------------------------------
  1826. //
  1827. // Function: HrGetIHNetConnection
  1828. //
  1829. // Purpose: Retrieves the IHNetConnection for this connection
  1830. //
  1831. // Arguments:
  1832. //
  1833. // Returns: S_OK on success; error otherwise
  1834. //
  1835. // Author: jonburs 16 August 2000
  1836. //
  1837. // Notes:
  1838. //
  1839. HRESULT CLanConnection::HrGetIHNetConnection(OUT IHNetConnection **ppHNetConnection)
  1840. {
  1841. HRESULT hr;
  1842. IHNetCfgMgr *pCfgMgr;
  1843. GUID guid;
  1844. Assert(ppHNetConnection);
  1845. hr = GetDeviceGuid(&guid);
  1846. if (SUCCEEDED(hr))
  1847. {
  1848. hr = HrGetHNetCfgMgr(&pCfgMgr);
  1849. }
  1850. if (SUCCEEDED(hr))
  1851. {
  1852. hr = pCfgMgr->GetIHNetConnectionForGuid(
  1853. &guid,
  1854. TRUE,
  1855. FALSE,
  1856. ppHNetConnection
  1857. );
  1858. ReleaseObj(pCfgMgr);
  1859. }
  1860. return hr;
  1861. }
  1862. //+---------------------------------------------------------------------------
  1863. //
  1864. // Function: ShowIcon
  1865. //
  1866. // Purpose: Sets the Icon state for the systray, fires an event to notify
  1867. // NetShell of the Change
  1868. //
  1869. // Arguments:
  1870. //
  1871. // Returns: S_OK on success; error otherwise
  1872. //
  1873. // Author: ckotze 25 September 2000
  1874. //
  1875. // Notes:
  1876. //
  1877. HRESULT CLanConnection::ShowIcon(IN const BOOL bShowIcon)
  1878. {
  1879. HRESULT hr;
  1880. LANCON_INFO lcInfo;
  1881. hr = GetInfo(LCIF_ICON, &lcInfo);
  1882. if (SUCCEEDED(hr))
  1883. {
  1884. lcInfo.fShowIcon = bShowIcon;
  1885. hr = SetInfo(LCIF_ICON, &lcInfo);
  1886. }
  1887. return hr;
  1888. }
  1889. //+---------------------------------------------------------------------------
  1890. //
  1891. // Function: IconStateChanged
  1892. //
  1893. // Purpose: Fires an event to notify NetShell of a Change occuring in an
  1894. // incoming connection.
  1895. //
  1896. // Arguments:
  1897. //
  1898. // Returns: S_OK on success; error otherwise
  1899. //
  1900. // Author: ckotze 25 September 2000
  1901. //
  1902. // Notes:
  1903. //
  1904. inline
  1905. HRESULT CLanConnection::IconStateChanged()
  1906. {
  1907. return E_NOTIMPL;
  1908. }
  1909. //+---------------------------------------------------------------------------
  1910. //
  1911. // Member: CLanConnection::GetProperties
  1912. //
  1913. // Purpose: Get all of the properties associated with the connection.
  1914. // Returning all of them at once saves us RPCs vs. returning
  1915. // each one individually.
  1916. //
  1917. // Arguments:
  1918. // ppProps [out] Returned block of properties.
  1919. //
  1920. // Returns: S_OK or an error.
  1921. //
  1922. // Author: shaunco 1 Feb 1998
  1923. //
  1924. // Notes:
  1925. //
  1926. HRESULT CLanConnection::GetPropertiesEx(OUT NETCON_PROPERTIES_EX** ppConnectionPropertiesEx)
  1927. {
  1928. HRESULT hr = S_OK;
  1929. *ppConnectionPropertiesEx = NULL;
  1930. if (!m_fInitialized)
  1931. {
  1932. hr = E_UNEXPECTED;
  1933. }
  1934. else
  1935. {
  1936. NETCON_PROPERTIES* pProps;
  1937. NETCON_PROPERTIES_EX* pPropsEx = reinterpret_cast<NETCON_PROPERTIES_EX*>(CoTaskMemAlloc(sizeof(NETCON_PROPERTIES_EX)));
  1938. if (pPropsEx)
  1939. {
  1940. ZeroMemory(pPropsEx, sizeof(NETCON_PROPERTIES_EX));
  1941. hr = GetProperties(&pProps);
  1942. if (SUCCEEDED(hr))
  1943. {
  1944. hr = HrBuildPropertiesExFromProperties(pProps, pPropsEx, dynamic_cast<IPersistNetConnection *>(this));
  1945. if (SUCCEEDED(hr))
  1946. {
  1947. if (NCM_LAN == pPropsEx->ncMediaType)
  1948. {
  1949. CIntelliName inName(NULL, NULL);
  1950. NETCON_MEDIATYPE ncm;
  1951. NETCON_SUBMEDIATYPE ncsm;
  1952. hr = inName.HrGetPseudoMediaTypes(pPropsEx->guidId, &ncm, &ncsm);
  1953. if (FAILED(hr))
  1954. {
  1955. hr = HrGetPseudoMediaTypeFromConnection(pPropsEx->guidId, &ncsm);
  1956. TraceError("HrGetPseudoMediaTypeFromConnection failed.", hr);
  1957. hr = S_OK;
  1958. }
  1959. pPropsEx->ncSubMediaType = ncsm;
  1960. if (NCSM_WIRELESS == ncsm)
  1961. {
  1962. LANCON_INFO LanConInfo;
  1963. hr = GetInfo(LCIF_ICON, &LanConInfo);
  1964. if (NETCFG_S_NOTEXIST == hr)
  1965. {
  1966. LanConInfo.fShowIcon = TRUE;
  1967. hr = SetInfo(LCIF_ICON, &LanConInfo);
  1968. TraceError("SetInfo", hr);
  1969. pPropsEx->dwCharacter |= NCCF_SHOW_ICON;
  1970. hr = S_OK;
  1971. }
  1972. }
  1973. }
  1974. else
  1975. {
  1976. pPropsEx->ncSubMediaType = NCSM_NONE;
  1977. }
  1978. if (SUCCEEDED(hr))
  1979. {
  1980. *ppConnectionPropertiesEx = pPropsEx;
  1981. }
  1982. }
  1983. FreeNetconProperties(pProps);
  1984. }
  1985. if (FAILED(hr))
  1986. {
  1987. *ppConnectionPropertiesEx = NULL;
  1988. HrFreeNetConProperties2(pPropsEx);
  1989. }
  1990. }
  1991. else
  1992. {
  1993. hr = E_OUTOFMEMORY;
  1994. }
  1995. }
  1996. TraceError ("CLanConnection::GetPropertiesEx", hr);
  1997. return hr;
  1998. }
  1999. HRESULT CLanConnection::HrEnsureValidNlaPolicyEngine()
  2000. {
  2001. HRESULT hr = S_FALSE; // Assume we already have the object
  2002. if (!m_pNetMachinePolicies)
  2003. {
  2004. hr = CoCreateInstance(CLSID_NetGroupPolicies, NULL, CLSCTX_INPROC, IID_INetMachinePolicies, reinterpret_cast<void**>(&m_pNetMachinePolicies));
  2005. }
  2006. return hr;
  2007. }