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.

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