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.

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