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.

1158 lines
35 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: S N E T C F G . C P P
  7. //
  8. // Contents: Sample code that demonstrates how to:
  9. // - find out if a component is installed
  10. // - install a net component
  11. // - install an OEM net component
  12. // - uninstall a net component
  13. // - enumerate net components
  14. // - enumerate net adapters using Setup API
  15. // - enumerate binding paths of a component
  16. //
  17. // Notes:
  18. //
  19. //----------------------------------------------------------------------------
  20. #include "pch.h"
  21. #pragma hdrstop
  22. #include "netcfg.h"
  23. #include "msg.h"
  24. #include <libmsg.h>
  25. //----------------------------------------------------------------------------
  26. // Globals
  27. //
  28. static const GUID* c_aguidClass[] =
  29. {
  30. &GUID_DEVCLASS_NET,
  31. &GUID_DEVCLASS_NETTRANS,
  32. &GUID_DEVCLASS_NETSERVICE,
  33. &GUID_DEVCLASS_NETCLIENT
  34. };
  35. //----------------------------------------------------------------------------
  36. // Prototypes of helper functions
  37. //
  38. HRESULT HrInstallNetComponent(IN INetCfg* pnc, IN PCWSTR szComponentId,
  39. IN const GUID* pguidClass);
  40. HRESULT HrUninstallNetComponent(IN INetCfg* pnc, IN PCWSTR szComponentId);
  41. HRESULT HrGetINetCfg(IN BOOL fGetWriteLock, INetCfg** ppnc);
  42. HRESULT HrReleaseINetCfg(BOOL fHasWriteLock, INetCfg* pnc);
  43. void ShowHrMessage(IN HRESULT hr);
  44. inline ULONG ReleaseObj(IUnknown* punk)
  45. {
  46. return (punk) ? punk->Release () : 0;
  47. }
  48. //+---------------------------------------------------------------------------
  49. //
  50. // Function: HrIsComponentInstalled
  51. //
  52. // Purpose: Find out if a component is installed
  53. //
  54. // Arguments:
  55. // szComponentId [in] id of component to search
  56. //
  57. // Returns: S_OK if installed,
  58. // S_FALSE if not installed,
  59. // otherwise an error code
  60. //
  61. // Author: kumarp 11-February-99
  62. //
  63. // Notes:
  64. //
  65. HRESULT HrIsComponentInstalled(IN PCWSTR szComponentId)
  66. {
  67. HRESULT hr=S_OK;
  68. INetCfg* pnc;
  69. INetCfgComponent* pncc;
  70. hr = HrGetINetCfg(FALSE, &pnc);
  71. if (S_OK == hr)
  72. {
  73. hr = pnc->FindComponent(szComponentId, &pncc);
  74. if (S_OK == hr)
  75. {
  76. ReleaseObj(pncc);
  77. }
  78. (void) HrReleaseINetCfg(FALSE, pnc);
  79. }
  80. return hr;
  81. }
  82. //+---------------------------------------------------------------------------
  83. //
  84. // Function: FindIfComponentInstalled
  85. //
  86. // Purpose: Find out if a component is installed
  87. //
  88. // Arguments:
  89. // szComponentId [in] id of component to locate
  90. //
  91. // Returns: None
  92. //
  93. // Author: kumarp 11-February-99
  94. //
  95. // Notes:
  96. //
  97. void FindIfComponentInstalled(IN PCWSTR szComponentId)
  98. {
  99. HRESULT hr=S_OK;
  100. hr = HrIsComponentInstalled(szComponentId);
  101. if (S_OK == hr)
  102. {
  103. _putts( GetFormattedMessage( ThisModule,
  104. FALSE,
  105. Message,
  106. sizeof(Message)/sizeof(Message[0]),
  107. MSG_COMPONENT_INSTALLED,
  108. szComponentId) );
  109. }
  110. else if (S_FALSE == hr)
  111. {
  112. _putts( GetFormattedMessage( ThisModule,
  113. FALSE,
  114. Message,
  115. sizeof(Message)/sizeof(Message[0]),
  116. MSG_COMPONENT_NOT_INSTALLED,
  117. szComponentId) );
  118. }
  119. else
  120. {
  121. _putts( GetFormattedMessage( ThisModule,
  122. FALSE,
  123. Message,
  124. sizeof(Message)/sizeof(Message[0]),
  125. MSG_INSTALLATION_NOT_CONFIRMED,
  126. szComponentId,
  127. hr) );
  128. }
  129. }
  130. //+---------------------------------------------------------------------------
  131. //
  132. // Function: HrInstallNetComponent
  133. //
  134. // Purpose: Install the specified net component
  135. //
  136. // Arguments:
  137. // szComponentId [in] component to install
  138. // nc [in] class of the component
  139. // szInfFullPath [in] full path to primary INF file
  140. // required if the primary INF and other
  141. // associated files are not pre-copied to
  142. // the right destination dirs.
  143. // Not required when installing MS components
  144. // since the files are pre-copied by
  145. // Windows NT Setup.
  146. //
  147. // Returns: S_OK or NETCFG_S_REBOOT on success, otherwise an error code
  148. //
  149. // Notes:
  150. //
  151. HRESULT HrInstallNetComponent(IN PCWSTR szComponentId,
  152. IN enum NetClass nc,
  153. IN PCWSTR szInfFullPath)
  154. {
  155. HRESULT hr=S_OK;
  156. INetCfg* pnc;
  157. // cannot install net adapters this way. they have to be
  158. // enumerated/detected and installed by PnP
  159. if ((nc == NC_NetProtocol) ||
  160. (nc == NC_NetService) ||
  161. (nc == NC_NetClient))
  162. {
  163. _putts( GetFormattedMessage( ThisModule,
  164. FALSE,
  165. Message,
  166. sizeof(Message)/sizeof(Message[0]),
  167. MSG_TRYING_TO_INSTALL,
  168. szComponentId) );
  169. // if full path to INF has been specified, the INF
  170. // needs to be copied using Setup API to ensure that any other files
  171. // that the primary INF copies will be correctly found by Setup API
  172. //
  173. if (!MiniNTMode && szInfFullPath && wcslen(szInfFullPath))
  174. {
  175. WCHAR szInfNameAfterCopy[MAX_PATH+1];
  176. szInfNameAfterCopy[0] = NULL;
  177. if (SetupCopyOEMInf(
  178. szInfFullPath,
  179. NULL, // other files are in the
  180. // same dir. as primary INF
  181. SPOST_PATH, // first param. contains path to INF
  182. 0, // default copy style
  183. szInfNameAfterCopy, // receives the name of the INF
  184. // after it is copied to %windir%\inf
  185. MAX_PATH, // max buf. size for the above
  186. NULL, // receives required size if non-null
  187. NULL)) // optionally retrieves filename
  188. // component of szInfNameAfterCopy
  189. {
  190. _putts( GetFormattedMessage( ThisModule,
  191. FALSE,
  192. Message,
  193. sizeof(Message)/sizeof(Message[0]),
  194. MSG_COPY_NOTIFICATION,
  195. szInfFullPath,
  196. szInfNameAfterCopy) );
  197. }
  198. else
  199. {
  200. DWORD dwError = GetLastError();
  201. hr = HRESULT_FROM_WIN32(dwError);
  202. }
  203. }
  204. if (S_OK == hr)
  205. {
  206. // get INetCfg interface
  207. hr = HrGetINetCfg(TRUE, &pnc);
  208. if (SUCCEEDED(hr))
  209. {
  210. // install szComponentId
  211. hr = HrInstallNetComponent(pnc, szComponentId,
  212. c_aguidClass[nc]);
  213. if (SUCCEEDED(hr))
  214. {
  215. // Apply the changes
  216. hr = pnc->Apply();
  217. }
  218. // release INetCfg
  219. (void) HrReleaseINetCfg(TRUE, pnc);
  220. }
  221. }
  222. //
  223. // Don't show the reboot message in WinPE case
  224. //
  225. if (MiniNTMode && (hr == NETCFG_S_REBOOT)) {
  226. hr = S_OK;
  227. }
  228. // show success/failure message
  229. ShowHrMessage(hr);
  230. }
  231. return hr;
  232. }
  233. //+---------------------------------------------------------------------------
  234. //
  235. // Function: HrInstallNetComponent
  236. //
  237. // Purpose: Install the specified net component
  238. //
  239. // Arguments:
  240. // pnc [in] pointer to INetCfg object
  241. // szComponentId [in] component to install
  242. // pguidClass [in] class guid of the component
  243. //
  244. // Returns: S_OK or NETCFG_S_REBOOT on success, otherwise an error code
  245. //
  246. // Notes:
  247. //
  248. HRESULT HrInstallNetComponent(IN INetCfg* pnc,
  249. IN PCWSTR szComponentId,
  250. IN const GUID* pguidClass)
  251. {
  252. HRESULT hr=S_OK;
  253. OBO_TOKEN OboToken;
  254. INetCfgClassSetup* pncClassSetup;
  255. INetCfgComponent* pncc;
  256. // OBO_TOKEN specifies the entity on whose behalf this
  257. // component is being installed
  258. // set it to OBO_USER so that szComponentId will be installed
  259. // On-Behalf-Of "user"
  260. ZeroMemory (&OboToken, sizeof(OboToken));
  261. OboToken.Type = OBO_USER;
  262. hr = pnc->QueryNetCfgClass (pguidClass, IID_INetCfgClassSetup,
  263. (void**)&pncClassSetup);
  264. if (SUCCEEDED(hr))
  265. {
  266. hr = pncClassSetup->Install(szComponentId,
  267. &OboToken,
  268. NSF_POSTSYSINSTALL,
  269. 0, // <upgrade-from-build-num>
  270. NULL, // answerfile name
  271. NULL, // answerfile section name
  272. &pncc);
  273. if (S_OK == hr)
  274. {
  275. // we dont want to use pncc (INetCfgComponent), release it
  276. ReleaseObj(pncc);
  277. }
  278. ReleaseObj(pncClassSetup);
  279. }
  280. return hr;
  281. }
  282. //+---------------------------------------------------------------------------
  283. //
  284. // Function: HrUninstallNetComponent
  285. //
  286. // Purpose: Initialize INetCfg and uninstall a component
  287. //
  288. // Arguments:
  289. // szComponentId [in] InfId of component to uninstall (e.g. MS_TCPIP)
  290. //
  291. // Returns: S_OK or NETCFG_S_REBOOT on success, otherwise an error code
  292. //
  293. // Notes:
  294. //
  295. HRESULT HrUninstallNetComponent(IN PCWSTR szComponentId)
  296. {
  297. HRESULT hr=S_OK;
  298. INetCfg* pnc;
  299. _putts( GetFormattedMessage( ThisModule,
  300. FALSE,
  301. Message,
  302. sizeof(Message)/sizeof(Message[0]),
  303. MSG_UNINSTALL_NOTIFICATION,
  304. szComponentId) );
  305. // get INetCfg interface
  306. hr = HrGetINetCfg(TRUE, &pnc);
  307. if (SUCCEEDED(hr))
  308. {
  309. // uninstall szComponentId
  310. hr = HrUninstallNetComponent(pnc, szComponentId);
  311. if (S_OK == hr)
  312. {
  313. // Apply the changes
  314. hr = pnc->Apply();
  315. }
  316. else if (S_FALSE == hr)
  317. {
  318. _putts( GetFormattedMessage( ThisModule,
  319. FALSE,
  320. Message,
  321. sizeof(Message)/sizeof(Message[0]),
  322. MSG_NOT_INSTALLED_NOTIFICATION,
  323. szComponentId) );
  324. }
  325. // release INetCfg
  326. (void) HrReleaseINetCfg(TRUE, pnc);
  327. }
  328. // show success/failure message
  329. ShowHrMessage(hr);
  330. return hr;
  331. }
  332. //+---------------------------------------------------------------------------
  333. //
  334. // Function: HrUninstallNetComponent
  335. //
  336. // Purpose: Uninstall the specified component.
  337. //
  338. // Arguments:
  339. // pnc [in] pointer to INetCfg object
  340. // szComponentId [in] component to uninstall
  341. //
  342. // Returns: S_OK or NETCFG_S_REBOOT on success, otherwise an error code
  343. //
  344. // Notes:
  345. //
  346. HRESULT HrUninstallNetComponent(IN INetCfg* pnc, IN PCWSTR szComponentId)
  347. {
  348. HRESULT hr=S_OK;
  349. OBO_TOKEN OboToken;
  350. INetCfgComponent* pncc;
  351. GUID guidClass;
  352. INetCfgClass* pncClass;
  353. INetCfgClassSetup* pncClassSetup;
  354. // OBO_TOKEN specifies the entity on whose behalf this
  355. // component is being uninstalld
  356. // set it to OBO_USER so that szComponentId will be uninstalld
  357. // On-Behalf-Of "user"
  358. ZeroMemory (&OboToken, sizeof(OboToken));
  359. OboToken.Type = OBO_USER;
  360. // see if the component is really installed
  361. hr = pnc->FindComponent(szComponentId, &pncc);
  362. if (S_OK == hr)
  363. {
  364. // yes, it is installed. obtain INetCfgClassSetup and DeInstall
  365. hr = pncc->GetClassGuid(&guidClass);
  366. if (S_OK == hr)
  367. {
  368. hr = pnc->QueryNetCfgClass(&guidClass, IID_INetCfgClass,
  369. (void**)&pncClass);
  370. if (SUCCEEDED(hr))
  371. {
  372. hr = pncClass->QueryInterface(IID_INetCfgClassSetup,
  373. (void**)&pncClassSetup);
  374. if (SUCCEEDED(hr))
  375. {
  376. hr = pncClassSetup->DeInstall (pncc, &OboToken, NULL);
  377. ReleaseObj (pncClassSetup);
  378. }
  379. ReleaseObj(pncClass);
  380. }
  381. }
  382. ReleaseObj(pncc);
  383. }
  384. return hr;
  385. }
  386. //+---------------------------------------------------------------------------
  387. //
  388. // Function: HrShowNetAdapters
  389. //
  390. // Purpose: Display all installed net class devices using Setup API
  391. //
  392. // Arguments: None
  393. //
  394. // Returns: S_OK on success, otherwise an error code
  395. //
  396. // Notes:
  397. //
  398. HRESULT HrShowNetAdapters()
  399. {
  400. #define MAX_COMP_INSTID 4096
  401. #define MAX_COMP_DESC 4096
  402. HRESULT hr=S_OK;
  403. HDEVINFO hdi;
  404. DWORD dwIndex=0;
  405. SP_DEVINFO_DATA deid;
  406. BOOL fSuccess=FALSE;
  407. DWORD cchRequiredSize;
  408. LPTSTR lpszCompInstanceId;
  409. LPTSTR lpszCompDescription;
  410. DWORD dwRegType;
  411. BOOL fFound=FALSE;
  412. // get a list of all devices of class 'GUID_DEVCLASS_NET'
  413. hdi = SetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT);
  414. // Allocate the buffer for the device instance ID
  415. //
  416. lpszCompInstanceId = (LPTSTR) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, (MAX_COMP_INSTID * sizeof(WCHAR)) );
  417. // Allocate the buffer for the device description
  418. //
  419. lpszCompDescription = (LPTSTR) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, (MAX_COMP_DESC * sizeof(WCHAR)) );
  420. if ( (NULL != lpszCompInstanceId) &&
  421. (NULL != lpszCompDescription) &&
  422. (INVALID_HANDLE_VALUE != hdi) )
  423. {
  424. // enumerate over each device
  425. while (deid.cbSize = sizeof(SP_DEVINFO_DATA),
  426. SetupDiEnumDeviceInfo(hdi, dwIndex, &deid))
  427. {
  428. dwIndex++;
  429. // the right thing to do here would be to call this function
  430. // to get the size required to hold the instance ID and then
  431. // to call it second time with a buffer large enough for that size.
  432. // However, that would tend to obscure the control flow in
  433. // the sample code. Lets keep things simple by keeping the
  434. // buffer large enough.
  435. // get the device instance ID
  436. fSuccess = SetupDiGetDeviceInstanceId(hdi, &deid,
  437. lpszCompInstanceId,
  438. MAX_COMP_INSTID, NULL);
  439. if (fSuccess)
  440. {
  441. // get the description for this instance
  442. fSuccess =
  443. SetupDiGetDeviceRegistryProperty(hdi, &deid,
  444. SPDRP_DEVICEDESC,
  445. &dwRegType,
  446. (BYTE*) lpszCompDescription,
  447. MAX_COMP_DESC,
  448. NULL);
  449. if (fSuccess)
  450. {
  451. if (!fFound)
  452. {
  453. fFound = TRUE;
  454. _putts( GetFormattedMessage( ThisModule,
  455. FALSE,
  456. Message,
  457. sizeof(Message)/sizeof(Message[0]),
  458. MSG_INSTANCE_DESCRIPTION ) );
  459. }
  460. _putts( GetFormattedMessage( ThisModule,
  461. FALSE,
  462. Message,
  463. sizeof(Message)/sizeof(Message[0]),
  464. MSG_COMPONENT_DESCRIPTION,
  465. lpszCompInstanceId,
  466. lpszCompDescription ) );
  467. }
  468. }
  469. }
  470. // release the device info list
  471. SetupDiDestroyDeviceInfoList(hdi);
  472. }
  473. // Free the device instance buffer
  474. //
  475. if ( lpszCompInstanceId )
  476. HeapFree( GetProcessHeap(), 0, lpszCompInstanceId );
  477. // Free the device description buffer
  478. //
  479. if ( lpszCompDescription )
  480. HeapFree( GetProcessHeap(), 0, lpszCompDescription );
  481. if (!fSuccess)
  482. {
  483. DWORD dwError = GetLastError();
  484. hr = HRESULT_FROM_WIN32(dwError);
  485. }
  486. return hr;
  487. }
  488. //+---------------------------------------------------------------------------
  489. //
  490. // Function: HrShowNetComponents
  491. //
  492. // Purpose: Display the list of installed components of the
  493. // specified class.
  494. //
  495. // Arguments:
  496. // pnc [in] pointer to INetCfg object
  497. // pguidClass [in] pointer to class GUID
  498. //
  499. // Returns: S_OK on success, otherwise an error code
  500. //
  501. // Notes:
  502. //
  503. HRESULT HrShowNetComponents(IN INetCfg* pnc,
  504. IN const GUID* pguidClass)
  505. {
  506. HRESULT hr=S_OK;
  507. PWSTR szInfId;
  508. PWSTR szDisplayName;
  509. DWORD dwcc;
  510. INetCfgComponent* pncc;
  511. INetCfgClass* pncclass;
  512. IEnumNetCfgComponent* pencc;
  513. ULONG celtFetched;
  514. hr = pnc->QueryNetCfgClass(pguidClass, IID_INetCfgClass,
  515. (void**)&pncclass);
  516. if (SUCCEEDED(hr))
  517. {
  518. // get IEnumNetCfgComponent so that we can enumerate
  519. hr = pncclass->EnumComponents(&pencc);
  520. ReleaseObj(pncclass);
  521. while (SUCCEEDED(hr) &&
  522. (S_OK == (hr = pencc->Next(1, &pncc, &celtFetched))))
  523. {
  524. if (pguidClass == &GUID_DEVCLASS_NET)
  525. {
  526. // we are interested only in physical netcards
  527. //
  528. hr = pncc->GetCharacteristics(&dwcc);
  529. if (FAILED(hr) || !(dwcc & NCF_PHYSICAL))
  530. {
  531. hr = S_OK;
  532. ReleaseObj(pncc);
  533. continue;
  534. }
  535. }
  536. hr = pncc->GetId(&szInfId);
  537. if (S_OK == hr)
  538. {
  539. hr = pncc->GetDisplayName(&szDisplayName);
  540. if (SUCCEEDED(hr))
  541. {
  542. _putts( GetFormattedMessage( ThisModule,
  543. FALSE,
  544. Message,
  545. sizeof(Message)/sizeof(Message[0]),
  546. MSG_DISPLAY_NAME,
  547. szInfId,
  548. szDisplayName) );
  549. CoTaskMemFree(szDisplayName);
  550. }
  551. CoTaskMemFree(szInfId);
  552. }
  553. // we dont want to stop enumeration just because 1 component
  554. // failed either GetId or GetDisplayName, therefore reset hr to S_OK
  555. hr = S_OK;
  556. ReleaseObj(pncc);
  557. }
  558. ReleaseObj(pencc);
  559. }
  560. if (S_FALSE == hr)
  561. {
  562. hr = S_OK;
  563. }
  564. return hr;
  565. }
  566. //+---------------------------------------------------------------------------
  567. //
  568. // Function: HrShowNetComponents
  569. //
  570. // Purpose: Display installed net components.
  571. //
  572. // Arguments: None
  573. //
  574. // Returns: S_OK on success, otherwise an error code
  575. //
  576. // Notes:
  577. //
  578. HRESULT HrShowNetComponents()
  579. {
  580. HRESULT hr=S_OK;
  581. PCWSTR szClassName;
  582. static const PCWSTR c_aszClassNames[] =
  583. {
  584. L"Network Adapters",
  585. L"Network Protocols",
  586. L"Network Services",
  587. L"Network Clients"
  588. };
  589. INetCfg* pnc;
  590. // get INetCfg interface
  591. hr = HrGetINetCfg(FALSE, &pnc);
  592. if (SUCCEEDED(hr))
  593. {
  594. for (int i=0; i<4; i++)
  595. {
  596. _putts( GetFormattedMessage( ThisModule,
  597. FALSE,
  598. Message,
  599. sizeof(Message)/sizeof(Message[0]),
  600. MSG_NET_COMPONENTS,
  601. c_aszClassNames[i]) );
  602. (void) HrShowNetComponents(pnc, c_aguidClass[i]);
  603. }
  604. // release INetCfg
  605. hr = HrReleaseINetCfg(FALSE, pnc);
  606. }
  607. return hr;
  608. }
  609. //+---------------------------------------------------------------------------
  610. //
  611. // Function: HrGetNextBindingInterface
  612. //
  613. // Purpose: Enumerate over binding interfaces that constitute
  614. // the given binding path
  615. //
  616. // Arguments:
  617. // pncbp [in] pointer to INetCfgBindingPath object
  618. // ppncbi [out] pointer to pointer to INetCfgBindingInterface object
  619. //
  620. // Returns: S_OK on success, otherwise an error code
  621. //
  622. // Notes:
  623. //
  624. HRESULT HrGetNextBindingInterface(IN INetCfgBindingPath* pncbp,
  625. OUT INetCfgBindingInterface** ppncbi)
  626. {
  627. HRESULT hr=S_OK;
  628. INetCfgBindingInterface* pncbi=NULL;
  629. static IEnumNetCfgBindingInterface* pencbi=NULL;
  630. *ppncbi = NULL;
  631. // if this is the first call in the enumeration, obtain
  632. // the IEnumNetCfgBindingInterface interface
  633. //
  634. if (!pencbi)
  635. {
  636. hr = pncbp->EnumBindingInterfaces(&pencbi);
  637. }
  638. if (S_OK == hr)
  639. {
  640. ULONG celtFetched;
  641. // get next binding interface
  642. hr = pencbi->Next(1, &pncbi, &celtFetched);
  643. }
  644. // on the last call (hr == S_FALSE) or on error, release resources
  645. if (S_OK == hr)
  646. {
  647. *ppncbi = pncbi;
  648. }
  649. else
  650. {
  651. ReleaseObj(pencbi);
  652. pencbi = NULL;
  653. }
  654. return hr;
  655. }
  656. //+---------------------------------------------------------------------------
  657. //
  658. // Function: HrGetNextBindingPath
  659. //
  660. // Purpose: Enumerate over binding paths that start with
  661. // the specified component
  662. //
  663. // Arguments:
  664. // pncc [in] pointer to INetCfgComponent object
  665. // dwBindingPathType [in] type of binding path to retrieve
  666. // ppncbp [out] pointer to INetCfgBindingPath interface
  667. //
  668. // Returns: S_OK on success, otherwise an error code
  669. //
  670. // Notes:
  671. //
  672. HRESULT HrGetNextBindingPath(IN INetCfgComponent* pncc,
  673. IN DWORD dwBindingPathType,
  674. OUT INetCfgBindingPath** ppncbp)
  675. {
  676. HRESULT hr=S_OK;
  677. INetCfgBindingPath* pncbp=NULL;
  678. static IEnumNetCfgBindingPath* pebp=NULL;
  679. *ppncbp = NULL;
  680. // if this is the first call in the enumeration, obtain
  681. // the IEnumNetCfgBindingPath interface
  682. if (!pebp)
  683. {
  684. INetCfgComponentBindings* pnccb=NULL;
  685. hr = pncc->QueryInterface(IID_INetCfgComponentBindings,
  686. (void**) &pnccb);
  687. if (S_OK == hr)
  688. {
  689. hr = pnccb->EnumBindingPaths(dwBindingPathType, &pebp);
  690. ReleaseObj(pnccb);
  691. }
  692. }
  693. if (S_OK == hr)
  694. {
  695. ULONG celtFetched;
  696. // get next binding path
  697. hr = pebp->Next(1, &pncbp, &celtFetched);
  698. }
  699. // on the last call (hr == S_FALSE) or on error, release resources
  700. if (S_OK == hr)
  701. {
  702. *ppncbp = pncbp;
  703. }
  704. else
  705. {
  706. ReleaseObj(pebp);
  707. pebp = NULL;
  708. }
  709. return hr;
  710. }
  711. //+---------------------------------------------------------------------------
  712. //
  713. // Function: HrShowBindingPath
  714. //
  715. // Purpose: Display components of a binding path in the format:
  716. // foo -> bar -> adapter
  717. //
  718. // Arguments:
  719. // pncbp [in] pointer to INetCfgBindingPath object
  720. //
  721. // Returns: S_OK on success, otherwise an error code
  722. //
  723. // Notes:
  724. //
  725. HRESULT HrShowBindingPath(IN INetCfgBindingPath* pncbp)
  726. {
  727. HRESULT hr=S_OK;
  728. INetCfgBindingInterface* pncbi;
  729. INetCfgComponent* pncc = NULL;
  730. BOOL fFirstInterface=TRUE;
  731. PWSTR szComponentId;
  732. while (SUCCEEDED(hr) &&
  733. (S_OK == (hr = HrGetNextBindingInterface(pncbp, &pncbi))))
  734. {
  735. // for the first (top) interface we need to get the upper as well as
  736. // the lower component. for other interfaces we need to get
  737. // only the lower component.
  738. if (fFirstInterface)
  739. {
  740. fFirstInterface = FALSE;
  741. hr = pncbi->GetUpperComponent(&pncc);
  742. if (SUCCEEDED(hr))
  743. {
  744. // get id so that we can display it
  745. //
  746. // for readability of the output, we have used the GetId
  747. // function. For non net class components, this
  748. // does not pose a problem. In case of net class components,
  749. // there may be more than one net adapters of the same type
  750. // in which case, GetId will return the same string. This will
  751. // make it impossible to distinguish between two binding
  752. // paths that end in two distinct identical cards. In such case,
  753. // it may be better to use the GetInstanceGuid function because
  754. // it will return unique GUID for each instance of an adapter.
  755. //
  756. hr = pncc->GetId(&szComponentId);
  757. ReleaseObj(pncc);
  758. if (SUCCEEDED(hr))
  759. {
  760. _putts( GetFormattedMessage( ThisModule,
  761. FALSE,
  762. Message,
  763. sizeof(Message)/sizeof(Message[0]),
  764. MSG_COMPONENT_ID,
  765. szComponentId) );
  766. CoTaskMemFree(szComponentId);
  767. }
  768. }
  769. }
  770. if (SUCCEEDED(hr))
  771. {
  772. hr = pncbi->GetLowerComponent(&pncc);
  773. if (SUCCEEDED(hr))
  774. {
  775. hr = pncc->GetId(&szComponentId);
  776. if (SUCCEEDED(hr))
  777. {
  778. _putts( GetFormattedMessage( ThisModule,
  779. FALSE,
  780. Message,
  781. sizeof(Message)/sizeof(Message[0]),
  782. MSG_LOWER_COMPONENTS,
  783. szComponentId) );
  784. CoTaskMemFree(szComponentId);
  785. }
  786. ReleaseObj(pncc);
  787. }
  788. }
  789. ReleaseObj(pncbi);
  790. }
  791. _tprintf(L"\n");
  792. if (hr == S_FALSE)
  793. {
  794. hr = S_OK;
  795. }
  796. return hr;
  797. }
  798. //+---------------------------------------------------------------------------
  799. //
  800. // Function: HrShowBindingPathsBelowComponent
  801. //
  802. // Purpose: Display all binding paths that start with
  803. // the specified component
  804. //
  805. // Arguments:
  806. // szComponentId [in] id of given component (e.g. MS_TCPIP)
  807. //
  808. // Returns: S_OK on success, otherwise an error code
  809. //
  810. // Notes:
  811. //
  812. HRESULT HrShowBindingPathsOfComponent(IN PCWSTR szComponentId)
  813. {
  814. HRESULT hr=S_OK;
  815. INetCfg* pnc=NULL;
  816. INetCfgComponent* pncc=NULL;
  817. INetCfgBindingPath* pncbp=NULL;
  818. // get INetCfg interface
  819. hr = HrGetINetCfg(FALSE, &pnc);
  820. if (SUCCEEDED(hr))
  821. {
  822. // get INetCfgComponent for szComponentId
  823. hr = pnc->FindComponent(szComponentId, &pncc);
  824. if (S_OK == hr)
  825. {
  826. _putts( GetFormattedMessage( ThisModule,
  827. FALSE,
  828. Message,
  829. sizeof(Message)/sizeof(Message[0]),
  830. MSG_BINDING_PATHS_START,
  831. szComponentId) );
  832. while (S_OK == (hr = HrGetNextBindingPath(pncc, EBP_BELOW,
  833. &pncbp)))
  834. {
  835. // display the binding path
  836. hr = HrShowBindingPath(pncbp);
  837. ReleaseObj(pncbp);
  838. }
  839. _putts( GetFormattedMessage( ThisModule,
  840. FALSE,
  841. Message,
  842. sizeof(Message)/sizeof(Message[0]),
  843. MSG_BINDING_PATHS_END,
  844. szComponentId) );
  845. while (S_OK == (hr = HrGetNextBindingPath(pncc, EBP_ABOVE,
  846. &pncbp)))
  847. {
  848. // display the binding path
  849. hr = HrShowBindingPath(pncbp);
  850. ReleaseObj(pncbp);
  851. }
  852. ReleaseObj(pncc);
  853. }
  854. // release INetCfg
  855. hr = HrReleaseINetCfg(FALSE, pnc);
  856. }
  857. return hr;
  858. }
  859. //+---------------------------------------------------------------------------
  860. //
  861. // Function: HrGetINetCfg
  862. //
  863. // Purpose: Initialize COM, create and initialize INetCfg.
  864. // Obtain write lock if indicated.
  865. //
  866. // Arguments:
  867. // fGetWriteLock [in] whether to get write lock
  868. // ppnc [in] pointer to pointer to INetCfg object
  869. //
  870. // Returns: S_OK on success, otherwise an error code
  871. //
  872. // Notes:
  873. //
  874. HRESULT HrGetINetCfg(IN BOOL fGetWriteLock,
  875. INetCfg** ppnc)
  876. {
  877. HRESULT hr=S_OK;
  878. // Initialize the output parameters.
  879. *ppnc = NULL;
  880. // initialize COM
  881. hr = CoInitializeEx(NULL,
  882. COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED );
  883. if (SUCCEEDED(hr))
  884. {
  885. // Create the object implementing INetCfg.
  886. //
  887. INetCfg* pnc;
  888. hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER,
  889. IID_INetCfg, (void**)&pnc);
  890. if (SUCCEEDED(hr))
  891. {
  892. INetCfgLock * pncLock = NULL;
  893. if (fGetWriteLock)
  894. {
  895. // Get the locking interface
  896. hr = pnc->QueryInterface(IID_INetCfgLock,
  897. (LPVOID *)&pncLock);
  898. if (SUCCEEDED(hr))
  899. {
  900. // Attempt to lock the INetCfg for read/write
  901. static const ULONG c_cmsTimeout = 15000;
  902. static const WCHAR c_szSampleNetcfgApp[] =
  903. L"Sample Netcfg Application (netcfg.exe)";
  904. PWSTR szLockedBy;
  905. hr = pncLock->AcquireWriteLock(c_cmsTimeout,
  906. c_szSampleNetcfgApp,
  907. &szLockedBy);
  908. if (S_FALSE == hr)
  909. {
  910. hr = NETCFG_E_NO_WRITE_LOCK;
  911. _putts( GetFormattedMessage( ThisModule,
  912. FALSE,
  913. Message,
  914. sizeof(Message)/sizeof(Message[0]),
  915. MSG_NETCFG_ALREADY_LOCKED,
  916. szLockedBy) );
  917. }
  918. }
  919. }
  920. if (SUCCEEDED(hr))
  921. {
  922. // Initialize the INetCfg object.
  923. //
  924. hr = pnc->Initialize(NULL);
  925. if (SUCCEEDED(hr))
  926. {
  927. *ppnc = pnc;
  928. pnc->AddRef();
  929. }
  930. else
  931. {
  932. // initialize failed, if obtained lock, release it
  933. if (pncLock)
  934. {
  935. pncLock->ReleaseWriteLock();
  936. }
  937. }
  938. }
  939. ReleaseObj(pncLock);
  940. ReleaseObj(pnc);
  941. }
  942. if (FAILED(hr))
  943. {
  944. CoUninitialize();
  945. }
  946. }
  947. return hr;
  948. }
  949. //+---------------------------------------------------------------------------
  950. //
  951. // Function: HrReleaseINetCfg
  952. //
  953. // Purpose: Uninitialize INetCfg, release write lock (if present)
  954. // and uninitialize COM.
  955. //
  956. // Arguments:
  957. // fHasWriteLock [in] whether write lock needs to be released.
  958. // pnc [in] pointer to INetCfg object
  959. //
  960. // Returns: S_OK on success, otherwise an error code
  961. //
  962. // Notes:
  963. //
  964. HRESULT HrReleaseINetCfg(BOOL fHasWriteLock, INetCfg* pnc)
  965. {
  966. HRESULT hr = S_OK;
  967. // uninitialize INetCfg
  968. hr = pnc->Uninitialize();
  969. // if write lock is present, unlock it
  970. if (SUCCEEDED(hr) && fHasWriteLock)
  971. {
  972. INetCfgLock* pncLock;
  973. // Get the locking interface
  974. hr = pnc->QueryInterface(IID_INetCfgLock,
  975. (LPVOID *)&pncLock);
  976. if (SUCCEEDED(hr))
  977. {
  978. hr = pncLock->ReleaseWriteLock();
  979. ReleaseObj(pncLock);
  980. }
  981. }
  982. ReleaseObj(pnc);
  983. CoUninitialize();
  984. return hr;
  985. }
  986. //+---------------------------------------------------------------------------
  987. //
  988. // Function: ShowHrMessage
  989. //
  990. // Purpose: Helper function to display the status of the last action
  991. // as indicated by the given HRESULT
  992. //
  993. // Arguments:
  994. // hr [in] status code
  995. //
  996. // Returns: None
  997. //
  998. // Notes:
  999. //
  1000. void ShowHrMessage(IN HRESULT hr)
  1001. {
  1002. if (SUCCEEDED(hr))
  1003. {
  1004. _putts( GetFormattedMessage( ThisModule,
  1005. FALSE,
  1006. Message,
  1007. sizeof(Message)/sizeof(Message[0]),
  1008. MSG_DONE) );
  1009. if (NETCFG_S_REBOOT == hr)
  1010. {
  1011. _putts(GetFormattedMessage( ThisModule,
  1012. FALSE,
  1013. Message,
  1014. sizeof(Message)/sizeof(Message[0]),
  1015. MSG_MACHINE_REBOOT_REQUIRED) );
  1016. }
  1017. }
  1018. else
  1019. {
  1020. _putts( GetFormattedMessage( ThisModule,
  1021. FALSE,
  1022. Message,
  1023. sizeof(Message)/sizeof(Message[0]),
  1024. MSG_FAILURE_NOTIFICATION) );
  1025. }
  1026. }