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.

875 lines
19 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000-2001 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // CEnumCfgNetworks.cpp
  7. //
  8. // Description:
  9. // CEnumCfgNetworks implementation.
  10. //
  11. // Maintained By:
  12. // Galen Barbee (GalenB) 02-AUG-2000
  13. //
  14. //////////////////////////////////////////////////////////////////////////////
  15. //////////////////////////////////////////////////////////////////////////////
  16. // Include Files
  17. //////////////////////////////////////////////////////////////////////////////
  18. #include "Pch.h"
  19. #include "CProxyCfgNetworkInfo.h"
  20. #include "CEnumCfgNetworks.h"
  21. //////////////////////////////////////////////////////////////////////////////
  22. // Constant Definitions
  23. //////////////////////////////////////////////////////////////////////////////
  24. DEFINE_THISCLASS("CEnumCfgNetworks")
  25. //////////////////////////////////////////////////////////////////////////////
  26. //++
  27. //
  28. // CEnumCfgNetworks::S_HrCreateInstance
  29. //
  30. // Description:
  31. // Create a CClusCfgClusterInfo instance.
  32. //
  33. // Arguments:
  34. // None.
  35. //
  36. // Return Values:
  37. // S_OK
  38. // Success.
  39. //
  40. // E_POINTER
  41. // A passed in argument is NULL.
  42. //
  43. // E_OUTOFMEMORY
  44. // Out of memory.
  45. //
  46. // Other HRESULT error.
  47. //
  48. //--
  49. //////////////////////////////////////////////////////////////////////////////
  50. HRESULT
  51. CEnumCfgNetworks::S_HrCreateInstance(
  52. IUnknown ** ppunkOut,
  53. IUnknown * punkOuterIn,
  54. HCLUSTER * phClusterIn,
  55. CLSID * pclsidMajorIn
  56. )
  57. {
  58. TraceFunc( "" );
  59. HRESULT hr = S_OK;
  60. CEnumCfgNetworks * pcecn = NULL;
  61. if ( ppunkOut == NULL )
  62. {
  63. hr = THR( E_POINTER );
  64. goto Cleanup;
  65. } // if
  66. pcecn = new CEnumCfgNetworks;
  67. if ( pcecn == NULL )
  68. {
  69. hr = THR( E_OUTOFMEMORY );
  70. goto Cleanup;
  71. } // if:
  72. hr = THR( pcecn->HrInit( punkOuterIn, phClusterIn, pclsidMajorIn ) );
  73. if ( FAILED( hr ) )
  74. {
  75. goto Cleanup;
  76. } // if:
  77. hr = THR( pcecn->TypeSafeQI( IUnknown, ppunkOut ) );
  78. Cleanup:
  79. if ( pcecn != NULL )
  80. {
  81. pcecn->Release();
  82. } // if:
  83. HRETURN( hr );
  84. } //*** CEnumCfgNetworks::S_HrCreateInstance
  85. //////////////////////////////////////////////////////////////////////////////
  86. //++
  87. //
  88. // CEnumCfgNetworks::CEnumCfgNetworks
  89. //
  90. // Description:
  91. // Constructor of the CEnumCfgNetworks class. This initializes
  92. // the m_cRef variable to 1 instead of 0 to account of possible
  93. // QueryInterface failure in DllGetClassObject.
  94. //
  95. // Arguments:
  96. // None.
  97. //
  98. // Return Value:
  99. // None.
  100. //
  101. // Remarks:
  102. // None.
  103. //
  104. //--
  105. //////////////////////////////////////////////////////////////////////////////
  106. CEnumCfgNetworks::CEnumCfgNetworks( void )
  107. : m_cRef( 1 )
  108. {
  109. TraceFunc( "" );
  110. InterlockedIncrement( &g_cObjects );
  111. Assert( m_cRef == 1 );
  112. Assert( m_pcccb == NULL );
  113. Assert( m_phCluster == NULL );
  114. Assert( m_pclsidMajor == NULL );
  115. Assert( m_dwIndex == 0 );
  116. Assert( m_hClusEnum == NULL );
  117. TraceFuncExit();
  118. } //*** CEnumCfgNetworks::CEnumCfgNetworks
  119. //////////////////////////////////////////////////////////////////////////////
  120. //++
  121. //
  122. // CEnumCfgNetworks::~CEnumCfgNetworks
  123. //
  124. // Description:
  125. // Desstructor of the CEnumCfgNetworks class.
  126. //
  127. // Arguments:
  128. // None.
  129. //
  130. // Return Value:
  131. // None.
  132. //
  133. // Remarks:
  134. // None.
  135. //
  136. //--
  137. //////////////////////////////////////////////////////////////////////////////
  138. CEnumCfgNetworks::~CEnumCfgNetworks( void )
  139. {
  140. TraceFunc( "" );
  141. // m_cRef - noop
  142. if ( m_pcccb )
  143. {
  144. m_pcccb->Release();
  145. } //if:
  146. // m_phCluster - DO NOT CLOSE!
  147. // m_pclsidMajor - noop
  148. // m_dwIndex - noop
  149. if ( m_hClusEnum != NULL )
  150. ClusterCloseEnum( m_hClusEnum );
  151. InterlockedDecrement( &g_cObjects );
  152. TraceFuncExit();
  153. } //*** CEnumCfgNetworks::~CEnumCfgNetworks
  154. //////////////////////////////////////////////////////////////////////////////
  155. //++
  156. //
  157. // CEnumCfgNetworks::HrInit
  158. //
  159. // Description:
  160. // Initialize this component.
  161. //
  162. // Arguments:
  163. //
  164. // Return Value:
  165. //
  166. // Remarks:
  167. // None.
  168. //
  169. //--
  170. //////////////////////////////////////////////////////////////////////////////
  171. HRESULT
  172. CEnumCfgNetworks::HrInit(
  173. IUnknown * punkOuterIn,
  174. HCLUSTER * phClusterIn,
  175. CLSID * pclsidMajorIn
  176. )
  177. {
  178. TraceFunc( "" );
  179. HRESULT hr;
  180. // IUnknown
  181. Assert( m_cRef == 1 );
  182. if ( punkOuterIn != NULL )
  183. {
  184. m_punkOuter = punkOuterIn;
  185. m_punkOuter->AddRef();
  186. }
  187. if ( phClusterIn == NULL )
  188. goto InvalidArg;
  189. m_phCluster = phClusterIn;
  190. if ( pclsidMajorIn != NULL )
  191. {
  192. m_pclsidMajor = pclsidMajorIn;
  193. }
  194. else
  195. {
  196. m_pclsidMajor = (CLSID *) &TASKID_Major_Client_And_Server_Log;
  197. }
  198. if ( punkOuterIn != NULL )
  199. {
  200. hr = THR( punkOuterIn->TypeSafeQI( IClusCfgCallback, &m_pcccb ) );
  201. if ( FAILED( hr ) )
  202. goto Cleanup;
  203. }
  204. //
  205. // Open the enumer.
  206. //
  207. m_hClusEnum = ClusterOpenEnum( *m_phCluster, CLUSTER_ENUM_NETWORK );
  208. if ( m_hClusEnum == NULL )
  209. {
  210. hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
  211. SSR_W2KPROXY_STATUS( TASKID_Major_Client_And_Server_Log, TASKID_Minor_HrInit_ClusterOpenEnum_Failed, hr );
  212. goto Cleanup;
  213. }
  214. hr = S_OK;
  215. Cleanup:
  216. HRETURN( hr );
  217. InvalidArg:
  218. hr = THR( E_INVALIDARG );
  219. SSR_W2KPROXY_STATUS( TASKID_Major_Client_And_Server_Log, TASKID_Minor_HrInit_InvalidArg, hr );
  220. goto Cleanup;
  221. } //*** CEnumCfgNetworks::HrInit
  222. //*************************************************************************//
  223. /////////////////////////////////////////////////////////////////////////////
  224. // CEnumCfgNetworks -- IUknkown interface.
  225. /////////////////////////////////////////////////////////////////////////////
  226. //////////////////////////////////////////////////////////////////////////////
  227. //++
  228. //
  229. // CEnumCfgNetworks::QueryInterface
  230. //
  231. // Description:
  232. // Query this object for the passed in interface.
  233. //
  234. // Arguments:
  235. // riidIn
  236. // Id of interface requested.
  237. //
  238. // ppvOut
  239. // Pointer to the requested interface.
  240. //
  241. // Return Value:
  242. // S_OK
  243. // If the interface is available on this object.
  244. //
  245. // E_NOINTERFACE
  246. // If the interface is not available.
  247. //
  248. // E_POINTER
  249. // ppvOut was NULL.
  250. //
  251. // Remarks:
  252. // None.
  253. //
  254. //--
  255. //////////////////////////////////////////////////////////////////////////////
  256. STDMETHODIMP
  257. CEnumCfgNetworks::QueryInterface(
  258. REFIID riidIn
  259. , void ** ppvOut
  260. )
  261. {
  262. TraceQIFunc( riidIn, ppvOut );
  263. HRESULT hr = S_OK;
  264. //
  265. // Validate arguments.
  266. //
  267. Assert( ppvOut != NULL );
  268. if ( ppvOut == NULL )
  269. {
  270. hr = THR( E_POINTER );
  271. goto Cleanup;
  272. }
  273. //
  274. // Handle known interfaces.
  275. //
  276. if ( IsEqualIID( riidIn, IID_IUnknown ) )
  277. {
  278. *ppvOut = static_cast< IEnumClusCfgNetworks * >( this );
  279. } // if: IUnknown
  280. else if ( IsEqualIID( riidIn, IID_IEnumClusCfgNetworks ) )
  281. {
  282. *ppvOut = TraceInterface( __THISCLASS__, IEnumClusCfgNetworks, this, 0 );
  283. } // else if: IEnumClusCfgNetworks
  284. else
  285. {
  286. *ppvOut = NULL;
  287. hr = E_NOINTERFACE;
  288. } // else
  289. //
  290. // Add a reference to the interface if successful.
  291. //
  292. if ( SUCCEEDED( hr ) )
  293. {
  294. ((IUnknown*) *ppvOut)->AddRef();
  295. } // if: success
  296. Cleanup:
  297. QIRETURN_IGNORESTDMARSHALLING( hr, riidIn );
  298. } //*** CEnumCfgNetworks::QueryInterface
  299. //////////////////////////////////////////////////////////////////////////////
  300. //++
  301. //
  302. // CEnumCfgNetworks::AddRef
  303. //
  304. // Description:
  305. // Increment the reference count of this object by one.
  306. //
  307. // Arguments:
  308. // None.
  309. //
  310. // Return Value:
  311. // The new reference count.
  312. //
  313. // Remarks:
  314. // None.
  315. //
  316. //--
  317. //////////////////////////////////////////////////////////////////////////////
  318. STDMETHODIMP_( ULONG )
  319. CEnumCfgNetworks::AddRef( void )
  320. {
  321. TraceFunc( "[IUnknown]" );
  322. InterlockedIncrement( &m_cRef );
  323. CRETURN( m_cRef );
  324. } //*** CEnumCfgNetworks::AddRef
  325. //////////////////////////////////////////////////////////////////////////////
  326. //++
  327. //
  328. // CEnumCfgNetworks::Release
  329. //
  330. // Description:
  331. // Decrement the reference count of this object by one.
  332. //
  333. // Arguments:
  334. // None.
  335. //
  336. // Return Value:
  337. // The new reference count.
  338. //
  339. // Remarks:
  340. // None.
  341. //
  342. //--
  343. //////////////////////////////////////////////////////////////////////////////
  344. STDMETHODIMP_( ULONG )
  345. CEnumCfgNetworks::Release( void )
  346. {
  347. TraceFunc( "[IUnknown]" );
  348. LONG cRef;
  349. cRef = InterlockedDecrement( &m_cRef );
  350. if ( cRef == 0 )
  351. {
  352. TraceDo( delete this );
  353. }
  354. CRETURN( cRef );
  355. } //*** CEnumCfgNetworks::Release
  356. //*************************************************************************//
  357. /////////////////////////////////////////////////////////////////////////////
  358. // CEnumCfgNetworks -- IEnumClusCfgNetworks interface
  359. /////////////////////////////////////////////////////////////////////////////
  360. //////////////////////////////////////////////////////////////////////////////
  361. //++
  362. //
  363. // CEnumCfgNetworks::Next
  364. //
  365. // Description:
  366. //
  367. // Arguments:
  368. //
  369. // Return Value:
  370. //
  371. // Remarks:
  372. // None.
  373. //
  374. //--
  375. //////////////////////////////////////////////////////////////////////////////
  376. STDMETHODIMP
  377. CEnumCfgNetworks::Next(
  378. ULONG cNumberRequestedIn,
  379. IClusCfgNetworkInfo ** rgpNetworkInfoOut,
  380. ULONG * pcNumberFetchedOut
  381. )
  382. {
  383. TraceFunc( "[IEnumClusCfgNetworks]" );
  384. HRESULT hr;
  385. ULONG cFetched = 0;
  386. if ( rgpNetworkInfoOut == NULL )
  387. goto InvalidPointer;
  388. for ( ; cFetched < cNumberRequestedIn; m_dwIndex ++ )
  389. {
  390. hr = STHR( HrGetItem( m_dwIndex, &(rgpNetworkInfoOut[ cFetched ]) ) );
  391. if ( FAILED( hr ) )
  392. goto Cleanup;
  393. if ( hr == S_FALSE )
  394. continue; // not a network
  395. if ( hr == MAKE_HRESULT( 0, FACILITY_WIN32, ERROR_NO_MORE_ITEMS ) )
  396. break; // no more items
  397. cFetched ++;
  398. } // for:
  399. if ( cFetched < cNumberRequestedIn )
  400. {
  401. hr = S_FALSE;
  402. } // if:
  403. else
  404. {
  405. hr = S_OK;
  406. } // else:
  407. Cleanup:
  408. if ( FAILED( hr ) )
  409. {
  410. ULONG idx;
  411. for ( idx = 0; idx < cFetched; idx++ )
  412. {
  413. (rgpNetworkInfoOut[ idx ])->Release();
  414. } // for:
  415. cFetched = 0;
  416. } // if:
  417. if ( pcNumberFetchedOut != NULL )
  418. {
  419. *pcNumberFetchedOut = cFetched;
  420. } // if:
  421. HRETURN( hr );
  422. InvalidPointer:
  423. hr = THR( E_POINTER );
  424. SSR_W2KPROXY_STATUS( TASKID_Major_Client_And_Server_Log, TASKID_Minor_Next_InvalidPointer, hr );
  425. goto Cleanup;
  426. } //*** CEnumCfgNetworks::Next
  427. //////////////////////////////////////////////////////////////////////////////
  428. //++
  429. //
  430. // CEnumCfgNetworks::Reset
  431. //
  432. // Description:
  433. //
  434. // Arguments:
  435. //
  436. // Return Value:
  437. //
  438. // Remarks:
  439. // None.
  440. //
  441. //--
  442. //////////////////////////////////////////////////////////////////////////////
  443. STDMETHODIMP
  444. CEnumCfgNetworks::Reset( void )
  445. {
  446. TraceFunc( "[IEnumClusCfgNetworks]" );
  447. m_dwIndex = 0;
  448. HRETURN( S_OK );
  449. } //*** CEnumCfgNetworks::Reset
  450. //////////////////////////////////////////////////////////////////////////////
  451. //++
  452. //
  453. // CEnumCfgNetworks::Skip
  454. //
  455. // Description:
  456. //
  457. // Arguments:
  458. //
  459. // Return Value:
  460. //
  461. // Remarks:
  462. // None.
  463. //
  464. //--
  465. //////////////////////////////////////////////////////////////////////////////
  466. STDMETHODIMP
  467. CEnumCfgNetworks::Skip( ULONG cNumberToSkipIn )
  468. {
  469. TraceFunc( "[IEnumClusCfgNetworks]" );
  470. HRESULT hr;
  471. DWORD idx;
  472. IClusCfgNetworkInfo * piccni = NULL;
  473. for ( idx = 0; idx < cNumberToSkipIn; m_dwIndex ++ )
  474. {
  475. hr = STHR( HrGetItem( m_dwIndex, &piccni ) );
  476. if ( FAILED( hr ) )
  477. goto Cleanup;
  478. if ( hr == S_FALSE )
  479. continue; // not a network
  480. if ( hr == MAKE_HRESULT( 0, FACILITY_WIN32, ERROR_NO_MORE_ITEMS ) )
  481. break; // no more items
  482. piccni->Release();
  483. piccni = NULL;
  484. idx ++;
  485. } // for:
  486. if ( idx < cNumberToSkipIn )
  487. {
  488. hr = S_FALSE;
  489. } // if:
  490. else
  491. {
  492. hr = S_OK;
  493. }
  494. Cleanup:
  495. Assert( piccni == NULL );
  496. HRETURN( hr );
  497. } //*** CEnumCfgNetworks::Skip
  498. //////////////////////////////////////////////////////////////////////////////
  499. //++
  500. //
  501. // CEnumCfgNetworks::Clone
  502. //
  503. // Description:
  504. //
  505. // Arguments:
  506. //
  507. // Return Value:
  508. //
  509. // Remarks:
  510. // None.
  511. //
  512. //--
  513. //////////////////////////////////////////////////////////////////////////////
  514. STDMETHODIMP
  515. CEnumCfgNetworks::Clone( IEnumClusCfgNetworks ** ppNetworkInfoOut )
  516. {
  517. TraceFunc( "[IEnumClusCfgNetworks]" );
  518. HRESULT hr = THR( E_NOTIMPL );
  519. HRETURN( hr );
  520. } //*** CEnumCfgNetworks::Clone
  521. //////////////////////////////////////////////////////////////////////////////
  522. //++
  523. //
  524. // CEnumCfgNetworks::Count
  525. //
  526. // Description:
  527. //
  528. // Arguments:
  529. //
  530. // Return Value:
  531. //
  532. // Remarks:
  533. // None.
  534. //
  535. //--
  536. //////////////////////////////////////////////////////////////////////////////
  537. STDMETHODIMP
  538. CEnumCfgNetworks::Count( DWORD * pnCountOut )
  539. {
  540. TraceFunc( "[IEnumClusCfgNetworks]" );
  541. Assert( m_hClusEnum != NULL );
  542. HRESULT hr = S_OK;
  543. if ( pnCountOut == NULL )
  544. {
  545. hr = THR( E_POINTER );
  546. goto Cleanup;
  547. }
  548. *pnCountOut = ClusterGetEnumCount(m_hClusEnum);
  549. Cleanup:
  550. HRETURN( hr );
  551. } //*** CEnumCfgNetworks::Count
  552. //****************************************************************************
  553. //
  554. // IClusCfgCallback
  555. //
  556. //****************************************************************************
  557. //////////////////////////////////////////////////////////////////////////////
  558. //++
  559. //
  560. // CEnumCfgNetworks::SendStatusReport
  561. //
  562. // Description:
  563. //
  564. // Arguments:
  565. //
  566. // Return Value:
  567. //
  568. // Remarks:
  569. // None.
  570. //
  571. //--
  572. //////////////////////////////////////////////////////////////////////////////
  573. STDMETHODIMP
  574. CEnumCfgNetworks::SendStatusReport(
  575. BSTR bstrNodeNameIn
  576. , CLSID clsidTaskMajorIn
  577. , CLSID clsidTaskMinorIn
  578. , ULONG ulMinIn
  579. , ULONG ulMaxIn
  580. , ULONG ulCurrentIn
  581. , HRESULT hrStatusIn
  582. , BSTR bstrDescriptionIn
  583. , FILETIME * pftTimeIn
  584. , BSTR bstrReferenceIn
  585. )
  586. {
  587. TraceFunc( "[IClusCfgCallback]" );
  588. HRESULT hr = S_OK;
  589. if ( m_pcccb != NULL )
  590. {
  591. hr = THR( m_pcccb->SendStatusReport(
  592. bstrNodeNameIn
  593. , clsidTaskMajorIn
  594. , clsidTaskMinorIn
  595. , ulMinIn
  596. , ulMaxIn
  597. , ulCurrentIn
  598. , hrStatusIn
  599. , bstrDescriptionIn
  600. , pftTimeIn
  601. , bstrReferenceIn
  602. ) );
  603. } // if:
  604. HRETURN( hr );
  605. } //*** CEnumCfgNetworks::SendStatusReport
  606. //*************************************************************************//
  607. /////////////////////////////////////////////////////////////////////////////
  608. // CEnumCfgNetworks -- Private methods.
  609. /////////////////////////////////////////////////////////////////////////////
  610. //////////////////////////////////////////////////////////////////////////////
  611. //++
  612. //
  613. // CEnumCfgNetworks::HrGetItem
  614. //
  615. // Description:
  616. //
  617. // Arguments:
  618. //
  619. // Return Value:
  620. //
  621. // Remarks:
  622. // None.
  623. //
  624. //--
  625. //////////////////////////////////////////////////////////////////////////////
  626. HRESULT
  627. CEnumCfgNetworks::HrGetItem(
  628. DWORD dwItem
  629. , IClusCfgNetworkInfo ** ppNetworkInfoOut
  630. )
  631. {
  632. TraceFunc( "" );
  633. HRESULT hr = S_OK;
  634. DWORD sc;
  635. DWORD dwTypeDummy;
  636. DWORD cchName = 64; // good starting value
  637. BSTR bstrName = NULL;
  638. IUnknown * punk = NULL;
  639. Assert( ppNetworkInfoOut != NULL );
  640. Assert( m_hClusEnum != NULL );
  641. bstrName = TraceSysAllocStringLen( NULL, cchName );
  642. if ( bstrName == NULL )
  643. {
  644. hr = THR( E_OUTOFMEMORY );
  645. goto Cleanup;
  646. }
  647. cchName ++; // SysAllocStringLen allocates cchName + 1.
  648. // We are wrapping this a cchName should be significantly large enough to handle
  649. // most of our testing.
  650. sc = ClusterEnum( m_hClusEnum, m_dwIndex, &dwTypeDummy, bstrName, &cchName );
  651. if ( sc == ERROR_MORE_DATA )
  652. {
  653. //
  654. // Our "typical" buffer is too small. Try make it to the size ClusterEnum
  655. // returned.
  656. //
  657. TraceSysFreeString( bstrName );
  658. bstrName = NULL;
  659. bstrName = TraceSysAllocStringLen( NULL, cchName );
  660. if ( bstrName == NULL )
  661. {
  662. hr = THR( E_OUTOFMEMORY );
  663. goto Cleanup;
  664. }
  665. cchName ++; // SysAllocStringLen allocates cchName + 1.
  666. sc = TW32( ClusterEnum( m_hClusEnum, m_dwIndex, &dwTypeDummy, bstrName, &cchName ) );
  667. }
  668. else if ( sc == ERROR_NO_MORE_ITEMS )
  669. {
  670. hr = MAKE_HRESULT( 0, FACILITY_WIN32, ERROR_NO_MORE_ITEMS );
  671. goto Cleanup;
  672. }
  673. if ( sc != ERROR_SUCCESS )
  674. {
  675. hr = HRESULT_FROM_WIN32( TW32( sc ) );
  676. SSR_W2KPROXY_STATUS( TASKID_Major_Client_And_Server_Log, TASKID_Minor_HrGetItem_ClusterEnum_Failed, hr );
  677. goto Cleanup;
  678. }
  679. Assert( dwTypeDummy == CLUSTER_ENUM_NETWORK );
  680. //
  681. // Create the requested object and store it.
  682. //
  683. hr = STHR( CProxyCfgNetworkInfo::S_HrCreateInstance( &punk, m_punkOuter, m_phCluster, m_pclsidMajor, bstrName ) );
  684. if ( FAILED( hr ) )
  685. {
  686. SSR_W2KPROXY_STATUS( TASKID_Major_Client_And_Server_Log, TASKID_Minor_HrGetItem_Create_CProxyCfgNetworkInfo_Failed, hr );
  687. goto Cleanup;
  688. }
  689. if ( hr == S_FALSE )
  690. {
  691. goto Cleanup; // This means that the object was not a network resource.
  692. }
  693. //
  694. // QI for the interface to return.
  695. //
  696. hr = THR( punk->TypeSafeQI( IClusCfgNetworkInfo, ppNetworkInfoOut ) );
  697. if ( FAILED( hr ) )
  698. {
  699. SSR_W2KPROXY_STATUS( TASKID_Major_Client_And_Server_Log, TASKID_Minor_HrGetItem_QI_Failed, hr );
  700. goto Cleanup;
  701. }
  702. Cleanup:
  703. TraceSysFreeString( bstrName );
  704. if ( punk != NULL )
  705. {
  706. punk->Release();
  707. }
  708. HRETURN( hr );
  709. } // *** CEnumCfgNetworks::HrGetItem