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.

1430 lines
39 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1998.
  5. //
  6. // File: S M C E N T . C P P
  7. //
  8. // Contents: The central object that controls statistic engines.
  9. //
  10. // Notes:
  11. //
  12. // Author: CWill 2 Dec 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "sminc.h"
  18. #include "ncreg.h"
  19. #include "ncnetcon.h"
  20. //
  21. // External data
  22. //
  23. extern const WCHAR c_szDevice[];
  24. extern SM_TOOL_FLAGS g_asmtfMap[];
  25. extern INT c_cAsmtfMap;
  26. //
  27. // Global Data
  28. //
  29. const UINT c_uiStatCentralRefreshID = 7718;
  30. const UINT c_uiStatCentralRefreshRate = 1000; // Refresh rate in milliseconds
  31. CRITICAL_SECTION g_csStatmonData;
  32. CStatCentralCriticalSection CNetStatisticsCentral::g_csStatCentral;
  33. //
  34. // Tool Registry Keys
  35. //
  36. // Required fields
  37. //
  38. static const WCHAR c_szRegKeyToolsRoot[] = L"System\\CurrentControlSet\\Control\\Network\\Connections\\StatMon\\Tools";
  39. static const WCHAR c_szRegKeyToolsDisplayName[] = L"DisplayName";
  40. static const WCHAR c_szRegKeyToolsManufacturer[] = L"Manufacturer";
  41. static const WCHAR c_szRegKeyToolsCommandLine[] = L"CommandLine";
  42. static const WCHAR c_szRegKeyToolsDescription[] = L"Description";
  43. // Optional fields
  44. //
  45. static const WCHAR c_szRegKeyToolsCriteria[] = L"Criteria";
  46. static const WCHAR c_szRegKeyToolsComponentID[] = L"ComponentID";
  47. static const WCHAR c_szRegKeyToolsConnectionType[] = L"ConnectionType";
  48. static const WCHAR c_szRegKeyToolsMedia[] = L"MediaType";
  49. static const WCHAR c_szRegKeyToolsFlags[] = L"Flags";
  50. //////////////////////////////////////////////////////////////////////////////
  51. // //
  52. // CNetStatisticsCentral //
  53. // //
  54. //////////////////////////////////////////////////////////////////////////////
  55. //
  56. // Make the global instance
  57. //
  58. CNetStatisticsCentral * g_pnscCentral = NULL;
  59. //+---------------------------------------------------------------------------
  60. //
  61. // Member: CNetStatisticsCentral::CNetStatisticsCentral
  62. //
  63. // Purpose: Creator
  64. //
  65. // Arguments: None
  66. //
  67. // Returns: Nil
  68. //
  69. CNetStatisticsCentral::CNetStatisticsCentral(VOID) :
  70. m_cRef(0),
  71. m_fProcessingTimerEvent(FALSE),
  72. m_unTimerId(0)
  73. {
  74. TraceFileFunc(ttidStatMon);
  75. InitializeCriticalSection(&g_csStatmonData);
  76. }
  77. //+---------------------------------------------------------------------------
  78. //
  79. // Member: CNetStatisticsCentral::~CNetStatisticsCentral
  80. //
  81. // Purpose: Destructor
  82. //
  83. // Arguments: None
  84. //
  85. // Returns: Nil
  86. //
  87. CNetStatisticsCentral::~CNetStatisticsCentral(VOID)
  88. {
  89. Assert(0 == m_cRef);
  90. AssertSz(m_pnselst.empty(), "Someone leaked a INetStatisticsEngine");
  91. AssertSz(0 == m_unTimerId, "Someone forgot to stop the timer");
  92. // Get rid of the global pointer
  93. //
  94. g_pnscCentral = NULL;
  95. EnterCriticalSection(&g_csStatmonData);
  96. __try
  97. {
  98. // Release the list of engines
  99. ::FreeCollectionAndItem(m_lstpsmte);
  100. }
  101. __except(EXCEPTION_EXECUTE_HANDLER)
  102. {
  103. AssertSz(FALSE, "An exception occurred while freeing the connection list");
  104. }
  105. LeaveCriticalSection(&g_csStatmonData);
  106. // delete the critical section
  107. DeleteCriticalSection(&g_csStatmonData);
  108. }
  109. //
  110. // Function: CNetStatisticsCentral::AddRef
  111. //
  112. // Purpose: Increment the reference count on this object
  113. //
  114. // Parameters: none
  115. //
  116. // Returns: ULONG
  117. //
  118. STDMETHODIMP_(ULONG) CNetStatisticsCentral::AddRef()
  119. {
  120. TraceFileFunc(ttidStatMon);
  121. return ++m_cRef;
  122. }
  123. //
  124. // Function: CNetStatisticsCentral::Release
  125. //
  126. // Purpose: Decrement the reference count on this object
  127. //
  128. // Parameters: none
  129. //
  130. // Returns: ULONG
  131. //
  132. STDMETHODIMP_(ULONG) CNetStatisticsCentral::Release()
  133. {
  134. TraceFileFunc(ttidStatMon);
  135. ULONG cRef = --m_cRef;
  136. if (cRef == 0)
  137. {
  138. delete this;
  139. }
  140. return cRef;
  141. }
  142. //
  143. // Function: CNetStatisticsCentral::QueryInterface
  144. //
  145. // Purpose: Allows for the querying of alternate interfaces
  146. //
  147. // Parameters: riid [IN] - Interface to retrieve
  148. // ppvObj [OUT] - Retrieved interface if function succeeds
  149. //
  150. // Returns: HRESULT, S_OK on success E_NOINTERFACE on failure
  151. //
  152. STDMETHODIMP CNetStatisticsCentral::QueryInterface(REFIID riid, LPVOID FAR *ppvObj)
  153. {
  154. TraceFileFunc(ttidStatMon);
  155. HRESULT hr = S_OK;
  156. *ppvObj = NULL;
  157. if (riid == IID_IUnknown)
  158. {
  159. *ppvObj = (LPVOID)this;
  160. AddRef();
  161. }
  162. else
  163. {
  164. hr = E_NOINTERFACE;
  165. }
  166. return hr;
  167. }
  168. //+---------------------------------------------------------------------------
  169. //
  170. // Member: CNetStatisticsCentral::HrGetNetStatisticsCentral
  171. //
  172. // Purpose: This procedure gets and returns a pointer to the one
  173. // CNetStatisticsCentral object. Creating it if both necessary
  174. // and required.
  175. //
  176. // Arguments: ppnsc [OUT] - Pointer to the CNetStatisticsCentral object
  177. // fCreate [IN] - If TRUE, and the object does not already
  178. // exist, then create it.
  179. //
  180. // Returns: S_OK - if the object is returned.
  181. // E_OUTOFMEMORY - if fCreate==TRUE and creation failed
  182. // E_NOINTERFACE - if fCreate==FALSE and the object doesn't exist
  183. //
  184. HRESULT
  185. CNetStatisticsCentral::HrGetNetStatisticsCentral(
  186. CNetStatisticsCentral ** ppnsc,
  187. BOOL fCreate)
  188. {
  189. TraceFileFunc(ttidStatMon);
  190. HRESULT hr = E_NOINTERFACE;
  191. // Note: scottbri - need critical section to protect creation
  192. #if DBG
  193. Assert( g_csStatCentral.Enter() == S_OK );
  194. #else
  195. g_csStatCentral.Enter();
  196. #endif
  197. if ((NULL == g_pnscCentral) && fCreate)
  198. {
  199. g_pnscCentral = new CNetStatisticsCentral;
  200. #if DBG
  201. // This test is only needed during DBG. The assert will catch
  202. // the problem, bringing it to out attention, and the test and
  203. // return will allow the user to press ignore and not crash
  204. Assert(g_pnscCentral);
  205. if (NULL == g_pnscCentral)
  206. {
  207. g_csStatCentral.Leave();
  208. return E_OUTOFMEMORY;
  209. }
  210. #endif
  211. }
  212. g_csStatCentral.Leave();
  213. AddRefObj(g_pnscCentral);
  214. *ppnsc = g_pnscCentral;
  215. return((*ppnsc) ? S_OK : hr);
  216. }
  217. //+---------------------------------------------------------------------------
  218. //
  219. // Member: CNetStatisticsCentral::TimerCallback
  220. //
  221. // Purpose: This is the procedure that gets called by the timer when it is
  222. // time to update the statistics
  223. //
  224. // Arguments: Standard timer procedure
  225. //
  226. // Returns: Nothing
  227. //
  228. VOID
  229. CALLBACK
  230. CNetStatisticsCentral::TimerCallback(
  231. HWND hwnd,
  232. UINT uMsg,
  233. UINT_PTR unEvent,
  234. DWORD dwTime)
  235. {
  236. TraceFileFunc(ttidStatMon);
  237. CNetStatisticsCentral* pnsc;
  238. if (SUCCEEDED(HrGetNetStatisticsCentral(&pnsc, FALSE)))
  239. {
  240. // Prevent same-thread re-entrancy. Any Win32 call made while
  241. // processing RefreshStatistics that returns control to the message
  242. // loop may cause this timer callback to be invoked again.
  243. //
  244. if ((!pnsc->m_fProcessingTimerEvent) && pnsc->m_unTimerId)
  245. {
  246. Assert(pnsc->m_unTimerId == unEvent);
  247. pnsc->m_fProcessingTimerEvent = TRUE;
  248. pnsc->RefreshStatistics(dwTime);
  249. pnsc->m_fProcessingTimerEvent = FALSE;
  250. }
  251. else
  252. {
  253. TraceTag (ttidStatMon, "CNetStatisticsCentral::TimerCallback "
  254. "re-entered on same thread. Ignoring.");
  255. }
  256. ReleaseObj(pnsc);
  257. }
  258. }
  259. //+---------------------------------------------------------------------------
  260. //
  261. // Member: CNetStatisticsCentral::RefreshStatistics
  262. //
  263. // Purpose: To get all the statistics engines held by central to update
  264. // their statistics
  265. //
  266. // Arguments:
  267. //
  268. // Returns: Nothing
  269. //
  270. VOID CNetStatisticsCentral::RefreshStatistics(DWORD dwTime)
  271. {
  272. TraceFileFunc(ttidStatMon);
  273. static BOOL fInRefreshStatistics = FALSE;
  274. if (fInRefreshStatistics)
  275. return;
  276. fInRefreshStatistics = TRUE;
  277. CExceptionSafeComObjectLock EsLock(this);
  278. HRESULT hr = S_OK;
  279. list<INetStatisticsEngine *>::iterator iterPnse;
  280. // Get the statistics to refresh themselves
  281. //
  282. INetStatisticsEngine * pnse = NULL;
  283. iterPnse = m_pnselst.begin();
  284. while (iterPnse != m_pnselst.end())
  285. {
  286. AssertSz (*iterPnse, "Shouldn't we always have non-NULL "
  287. "entries in our statistics engine list?");
  288. pnse = *iterPnse;
  289. if (pnse)
  290. {
  291. BOOL fNoLongerConnected;
  292. hr = pnse->UpdateStatistics(&fNoLongerConnected);
  293. if (SUCCEEDED(hr) && fNoLongerConnected)
  294. {
  295. TraceTag (ttidStatMon, "CNetStatisticsCentral::RefreshStatistics - "
  296. "UpdateStatistics reports that the connection is no longer connected.");
  297. }
  298. }
  299. iterPnse++;
  300. }
  301. // Since we possibly removed one or more engines from the list, stop
  302. // the timer if there are no more engines present.
  303. //
  304. if (m_pnselst.empty())
  305. {
  306. // Stop the timer
  307. //
  308. if (m_unTimerId)
  309. {
  310. ::KillTimer(NULL, m_unTimerId);
  311. m_unTimerId = 0;
  312. }
  313. }
  314. fInRefreshStatistics = FALSE;
  315. TraceError("CNetStatisticsCentral::RefreshStatistics", hr);
  316. return;
  317. }
  318. //+---------------------------------------------------------------------------
  319. //
  320. // Member: CNetStatisticsCentral::UpdateTitle
  321. //
  322. // Purpose: To update the title of a renamed connection if the statmon UI
  323. // is up.
  324. //
  325. // Arguments:
  326. //
  327. // Returns: Nothing
  328. //
  329. VOID CNetStatisticsCentral::UpdateTitle(const GUID * pguidId,
  330. PCWSTR pszNewName)
  331. {
  332. TraceFileFunc(ttidStatMon);
  333. CExceptionSafeComObjectLock EsLock(this);
  334. INetStatisticsEngine * pnse;
  335. if (FEngineInList(pguidId, &pnse))
  336. {
  337. pnse->UpdateTitle(pszNewName);
  338. ReleaseObj(pnse);
  339. }
  340. }
  341. //+---------------------------------------------------------------------------
  342. //
  343. // Member: CNetStatisticsCentral::CloseStatusMonitor
  344. //
  345. // Purpose: To close the status monitor UI if the connection is disconnected
  346. //
  347. // Arguments:
  348. //
  349. // Returns: Nothing
  350. //
  351. VOID CNetStatisticsCentral::CloseStatusMonitor(const GUID * pguidId)
  352. {
  353. TraceFileFunc(ttidStatMon);
  354. CExceptionSafeComObjectLock EsLock(this);
  355. INetStatisticsEngine * pnse;
  356. if (FEngineInList(pguidId, &pnse))
  357. {
  358. pnse->CloseStatusMonitor();
  359. ReleaseObj(pnse);
  360. }
  361. }
  362. //+---------------------------------------------------------------------------
  363. //
  364. // Member: CNetStatisticsCentral::UpdateRasLinkList
  365. //
  366. // Purpose: To update the RAS connections's multi-link list
  367. //
  368. // Arguments:
  369. //
  370. // Returns: Nothing
  371. //
  372. VOID CNetStatisticsCentral::UpdateRasLinkList(const GUID * pguidId)
  373. {
  374. TraceFileFunc(ttidStatMon);
  375. CExceptionSafeComObjectLock EsLock(this);
  376. INetStatisticsEngine * pnse;
  377. if (FEngineInList(pguidId, &pnse))
  378. {
  379. pnse->UpdateRasLinkList();
  380. ReleaseObj(pnse);
  381. }
  382. }
  383. //+---------------------------------------------------------------------------
  384. //
  385. // Member: CNetStatisticsCentral::HrCreateNewEngineType
  386. //
  387. // Purpose: Creates the implementation of each type of statistics engine
  388. //
  389. // Arguments: nctNew - Type of engine to create
  390. // ncMediaNew - The media type of the connection
  391. // dwCharacterNew - The character of the connection
  392. // ppStatEngine - Where to return the newly created stat engine
  393. //
  394. // Returns: Error code
  395. //
  396. HRESULT
  397. CNetStatisticsCentral::HrCreateNewEngineType (
  398. const CONFOLDENTRY& ccfe,
  399. CNetStatisticsEngine** ppStatEngine)
  400. {
  401. TraceFileFunc(ttidStatMon);
  402. HRESULT hr = S_OK;
  403. // Create the engine of the right type
  404. //
  405. if (ccfe.GetNetConMediaType() == NCM_LAN || ccfe.GetNetConMediaType() == NCM_BRIDGE)
  406. {
  407. // LAN connection
  408. Assert(!(ccfe.GetCharacteristics() & NCCF_INCOMING_ONLY));
  409. Assert(!(ccfe.GetCharacteristics() & NCCF_OUTGOING_ONLY));
  410. CLanStatEngine* pLanObj = NULL;
  411. INetLanConnection* pnlcNew = NULL;
  412. tstring strDeviceName;
  413. pLanObj = new CComObject <CLanStatEngine>;
  414. *ppStatEngine = pLanObj;
  415. if (!pLanObj)
  416. {
  417. hr = E_OUTOFMEMORY;
  418. }
  419. else
  420. {
  421. pLanObj->put_MediaType(ccfe.GetNetConMediaType(), ccfe.GetNetConSubMediaType());
  422. // Get some LAN specific info
  423. //
  424. hr = ccfe.HrGetNetCon(IID_INetLanConnection,
  425. reinterpret_cast<VOID**>(&pnlcNew));
  426. if (SUCCEEDED(hr))
  427. {
  428. GUID guidDevice;
  429. // Find the interface
  430. //
  431. hr = pnlcNew->GetDeviceGuid(&guidDevice);
  432. if (SUCCEEDED(hr))
  433. {
  434. WCHAR achGuid[c_cchGuidWithTerm];
  435. // Make the device name
  436. //
  437. StringFromGUID2( guidDevice, achGuid,
  438. c_cchGuidWithTerm);
  439. strDeviceName = c_szDevice;
  440. strDeviceName.append(achGuid);
  441. hr = pLanObj->put_Device(&strDeviceName);
  442. }
  443. ReleaseObj(pnlcNew);
  444. }
  445. }
  446. }
  447. else if (ccfe.GetNetConMediaType() == NCM_SHAREDACCESSHOST_LAN || ccfe.GetNetConMediaType() == NCM_SHAREDACCESSHOST_RAS)
  448. {
  449. CComObject<CSharedAccessStatEngine>* pEngine;
  450. hr = CComObject<CSharedAccessStatEngine>::CreateInstance(&pEngine);
  451. if(pEngine)
  452. {
  453. INetSharedAccessConnection* pNetSharedAccessConnection;
  454. hr = ccfe.HrGetNetCon(IID_INetSharedAccessConnection, reinterpret_cast<void**>(&pNetSharedAccessConnection));
  455. if(SUCCEEDED(hr))
  456. {
  457. hr = pEngine->Initialize(ccfe.GetNetConMediaType(), pNetSharedAccessConnection);
  458. if(SUCCEEDED(hr))
  459. {
  460. *ppStatEngine = pEngine;
  461. }
  462. ReleaseObj(pNetSharedAccessConnection);
  463. }
  464. if(FAILED(hr))
  465. {
  466. delete pEngine;
  467. }
  468. }
  469. else
  470. {
  471. hr = E_OUTOFMEMORY;
  472. }
  473. }
  474. else
  475. {
  476. // RAS connections ..
  477. CRasStatEngine* pRasObj = NULL;
  478. pRasObj = new CComObject <CRasStatEngine>;
  479. *ppStatEngine = pRasObj;
  480. if (!pRasObj)
  481. {
  482. hr = E_OUTOFMEMORY;
  483. }
  484. else
  485. {
  486. // Pass in the specific type
  487. pRasObj->put_MediaType(ccfe.GetNetConMediaType(), ccfe.GetNetConSubMediaType());
  488. pRasObj->put_Character(ccfe.GetCharacteristics());
  489. // Get RAS specific data
  490. //
  491. if (ccfe.GetCharacteristics() & NCCF_INCOMING_ONLY)
  492. {
  493. // RAS incoming connection
  494. Assert(ccfe.GetNetConMediaType() != NCM_LAN);
  495. Assert(!(ccfe.GetCharacteristics() & NCCF_OUTGOING_ONLY));
  496. INetInboundConnection* pnicNew;
  497. hr = ccfe.HrGetNetCon(IID_INetInboundConnection,
  498. reinterpret_cast<VOID**>(&pnicNew));
  499. if (SUCCEEDED(hr))
  500. {
  501. HRASCONN hRasConn;
  502. hr = pnicNew->GetServerConnectionHandle(
  503. reinterpret_cast<ULONG_PTR*>(&hRasConn));
  504. if (SUCCEEDED(hr))
  505. {
  506. pRasObj->put_RasConn(hRasConn);
  507. }
  508. ReleaseObj(pnicNew);
  509. }
  510. }
  511. else if (ccfe.GetCharacteristics() & NCCF_OUTGOING_ONLY)
  512. {
  513. // RAS outgoing connection
  514. Assert(ccfe.GetNetConMediaType() != NCM_LAN);
  515. Assert(!(ccfe.GetCharacteristics() & NCCF_INCOMING_ONLY));
  516. INetRasConnection* pnrcNew;
  517. hr = ccfe.HrGetNetCon(IID_INetRasConnection,
  518. reinterpret_cast<VOID**>(&pnrcNew));
  519. if (SUCCEEDED(hr))
  520. {
  521. HRASCONN hRasConn;
  522. hr = pnrcNew->GetRasConnectionHandle(
  523. reinterpret_cast<ULONG_PTR*>(&hRasConn));
  524. if (S_OK == hr)
  525. {
  526. pRasObj->put_RasConn(hRasConn);
  527. }
  528. else if (S_FALSE == hr)
  529. {
  530. hr = HRESULT_FROM_WIN32(ERROR_CONNECTION_UNAVAIL);
  531. }
  532. ReleaseObj(pnrcNew);
  533. }
  534. }
  535. else
  536. {
  537. AssertSz(FALSE, "Unknown connection type...");
  538. }
  539. }
  540. }
  541. TraceError("CNetStatisticsCentral::HrCreateNewEngineType", hr);
  542. return hr;
  543. }
  544. //+---------------------------------------------------------------------------
  545. //
  546. // Member: CNetStatisticsCentral::HrCreateStatisticsEngineForEntry
  547. //
  548. // Purpose: Creates a new statistics engine for the connection
  549. // represented by the folder entry.
  550. //
  551. // Arguments:
  552. // ccfe [in] Folder entry to create statistics engine for.
  553. // ppnseNew [out] Returned interface.
  554. //
  555. // Returns: S_OK or an error code.
  556. //
  557. // Author: shaunco 5 Nov 1998
  558. //
  559. // Notes: This MUST be called with this object's lock held.
  560. //
  561. HRESULT
  562. CNetStatisticsCentral::HrCreateStatisticsEngineForEntry(
  563. const CONFOLDENTRY& ccfe,
  564. INetStatisticsEngine** ppnseNew)
  565. {
  566. TraceFileFunc(ttidStatMon);
  567. Assert (!ccfe.empty());
  568. Assert (ppnseNew);
  569. HRESULT hr;
  570. // Initialize the out parameter
  571. //
  572. *ppnseNew = NULL;
  573. // Create the base engine after initializing the different types
  574. //
  575. CNetStatisticsEngine* pStatEngine;
  576. hr = HrCreateNewEngineType(ccfe, &pStatEngine);
  577. if (SUCCEEDED(hr))
  578. {
  579. // Do the standard initialize
  580. //
  581. hr = pStatEngine->HrInitStatEngine(ccfe);
  582. if (SUCCEEDED(hr))
  583. {
  584. // Standard CComCreator::CreateInstance stuff
  585. //
  586. pStatEngine->SetVoid(NULL);
  587. pStatEngine->InternalFinalConstructAddRef();
  588. hr = pStatEngine->FinalConstruct();
  589. pStatEngine->InternalFinalConstructRelease();
  590. // If all went well, add it to our list
  591. //
  592. if (SUCCEEDED(hr))
  593. {
  594. INetStatisticsEngine* pnseInter;
  595. hr = pStatEngine->GetUnknown()->QueryInterface(
  596. IID_INetStatisticsEngine,
  597. reinterpret_cast<VOID**>(&pnseInter));
  598. // All has gone well, add it to the list
  599. //
  600. if (SUCCEEDED(hr))
  601. {
  602. // Add the new entry to our list
  603. //
  604. m_pnselst.push_back(pnseInter);
  605. // Now that the central object owns this
  606. // engine, have the engine AddRef the
  607. // net statistics central object
  608. //
  609. pStatEngine->SetParent(this);
  610. AddRefObj(*ppnseNew = pStatEngine);
  611. }
  612. ReleaseObj(pnseInter);
  613. }
  614. }
  615. // Clean up the object on failure
  616. //
  617. if (FAILED(hr))
  618. {
  619. delete pStatEngine;
  620. }
  621. }
  622. if (SUCCEEDED(hr))
  623. {
  624. g_csStatCentral.Enter();
  625. // Do the one time initializations
  626. //
  627. if (!m_unTimerId)
  628. {
  629. // Make sure to start the timer
  630. //
  631. m_unTimerId = ::SetTimer(NULL,
  632. c_uiStatCentralRefreshID,
  633. c_uiStatCentralRefreshRate,
  634. TimerCallback);
  635. TraceTag(ttidStatMon, "Created Statistics Central Timer with ID of 0x%08x", m_unTimerId);
  636. }
  637. g_csStatCentral.Leave();
  638. }
  639. TraceError("CNetStatisticsCentral::CreateNetStatisticsEngine", hr);
  640. return hr;
  641. }
  642. HRESULT
  643. HrGetStatisticsEngineForEntry (
  644. const CONFOLDENTRY& ccfe,
  645. INetStatisticsEngine** ppnse,
  646. BOOL fCreate)
  647. {
  648. TraceFileFunc(ttidStatMon);
  649. HRESULT hr;
  650. CNetStatisticsCentral* pnsc;
  651. // Get the central object. Create if needed.
  652. //
  653. hr = CNetStatisticsCentral::HrGetNetStatisticsCentral(&pnsc, fCreate);
  654. if (SUCCEEDED(hr))
  655. {
  656. pnsc->Lock();
  657. // If the engine is already in the list, FEngineInList will
  658. // AddRef it for return. If not, we'll create it.
  659. //
  660. if (!pnsc->FEngineInList(&(ccfe.GetGuidID()), ppnse))
  661. {
  662. if (fCreate)
  663. {
  664. hr = pnsc->HrCreateStatisticsEngineForEntry(ccfe, ppnse);
  665. }
  666. else
  667. {
  668. hr = E_NOINTERFACE;
  669. }
  670. }
  671. pnsc->Unlock();
  672. ReleaseObj(pnsc);
  673. }
  674. TraceError("HrGetStatisticsEngineForEntry", hr);
  675. return hr;
  676. }
  677. //+---------------------------------------------------------------------------
  678. //
  679. // Member: CNetStatisticsCentral::RemoveNetStatisticsEngine
  680. //
  681. // Purpose: Removes a statistics engine from the list
  682. //
  683. // Arguments: pguidId - Identifies the engine to remove
  684. //
  685. // Returns: Error code
  686. //
  687. HRESULT
  688. CNetStatisticsCentral::RemoveNetStatisticsEngine (
  689. const GUID* pguidId)
  690. {
  691. TraceFileFunc(ttidStatMon);
  692. HRESULT hr = S_OK;
  693. BOOL fFound = FALSE;
  694. CExceptionSafeComObjectLock EsLock(this);
  695. GUID guidTemp = { 0};
  696. AssertSz(pguidId, "We should have a pguidId");
  697. // Look for the item in our list
  698. //
  699. list<INetStatisticsEngine *>::iterator iterPnse;
  700. INetStatisticsEngine* pnseTemp;
  701. iterPnse = m_pnselst.begin();
  702. while ((SUCCEEDED(hr)) && (!fFound) && (iterPnse != m_pnselst.end()))
  703. {
  704. pnseTemp = *iterPnse;
  705. hr = pnseTemp->GetGuidId(&guidTemp);
  706. if (SUCCEEDED(hr))
  707. {
  708. if (guidTemp == *pguidId)
  709. {
  710. // We have found a match, so delete it from out list
  711. //
  712. fFound = TRUE;
  713. m_pnselst.erase(iterPnse);
  714. break;
  715. }
  716. }
  717. iterPnse++;
  718. }
  719. if (m_pnselst.empty())
  720. {
  721. // Stop the timer
  722. //
  723. if (m_unTimerId)
  724. {
  725. ::KillTimer(NULL, m_unTimerId);
  726. m_unTimerId = 0;
  727. }
  728. }
  729. #if 0
  730. // $$REVIEW (jeffspr) - I removed this assert, as it was firing when my
  731. // tray item had deleted itself (and in return, the statmon object) on
  732. // disconnect. It's possible that we shouldn't have hit this code on the
  733. // first Release().
  734. AssertSz(fFound, "We didn't find the connection in our list");
  735. #endif
  736. TraceError("CNetStatisticsCentral::RemoveNetStatisticsEngine", hr);
  737. return hr;
  738. }
  739. //+---------------------------------------------------------------------------
  740. //
  741. // Member: CNetStatisticsCentral::FEngineInList
  742. //
  743. // Purpose: Checks to see if an engine is already in the list
  744. //
  745. // Arguments: pguidId - Guid of the connection trying to be located
  746. // ppnseRet - Return location of a connection if it is already
  747. // in the list. NULL is valid
  748. //
  749. // Returns: TRUE if it is in the list, FALSE if it is not
  750. //
  751. BOOL
  752. CNetStatisticsCentral::FEngineInList (
  753. const GUID* pguidId,
  754. INetStatisticsEngine** ppnseRet)
  755. {
  756. TraceFileFunc(ttidStatMon);
  757. HRESULT hr = S_OK;
  758. BOOL fRet = FALSE;
  759. GUID guidTemp = { 0};
  760. // Init the out param
  761. if (ppnseRet)
  762. {
  763. *ppnseRet = NULL;
  764. }
  765. // Try and find the engine in the list
  766. //
  767. list<INetStatisticsEngine *>::iterator iterPnse;
  768. INetStatisticsEngine* pnseTemp;
  769. iterPnse = m_pnselst.begin();
  770. while ((SUCCEEDED(hr)) && (!fRet) && (iterPnse != m_pnselst.end()))
  771. {
  772. pnseTemp = *iterPnse;
  773. hr = pnseTemp->GetGuidId(&guidTemp);
  774. if (SUCCEEDED(hr))
  775. {
  776. if (guidTemp == *pguidId)
  777. {
  778. // We have found a match
  779. //
  780. fRet = TRUE;
  781. // If we want a result, pass it back
  782. //
  783. if (ppnseRet)
  784. {
  785. ::AddRefObj(*ppnseRet = pnseTemp);
  786. }
  787. break;
  788. }
  789. }
  790. iterPnse++;
  791. }
  792. TraceError("CNetStatisticsCentral::FEngineInList", hr);
  793. return fRet;
  794. }
  795. //+---------------------------------------------------------------------------
  796. //
  797. // Member: CNetStatisticsCentral::HrReadTools
  798. //
  799. // Purpose: Look througth the registry for all tools that should be
  800. // entered in the tool list
  801. //
  802. // Arguments: None.
  803. //
  804. // Returns: Nil
  805. //
  806. HRESULT CNetStatisticsCentral::HrReadTools(VOID)
  807. {
  808. TraceFileFunc(ttidStatMon);
  809. HRESULT hr = S_OK;
  810. // Only read once
  811. //
  812. if (m_lstpsmte.empty())
  813. {
  814. WCHAR szToolEntry[MAX_PATH];
  815. DWORD dwSize = celems(szToolEntry);
  816. DWORD dwRegIndex = 0;
  817. HKEY hkeyToolsRoot = NULL;
  818. FILETIME ftTemp;
  819. // Open the existing key and see what is there
  820. //
  821. // "System\\CurrentControlSet\\Control\\Network\\Connections\\StatMon\\Tools"
  822. hr = ::HrRegOpenKeyEx(
  823. HKEY_LOCAL_MACHINE,
  824. c_szRegKeyToolsRoot,
  825. KEY_READ,
  826. &hkeyToolsRoot);
  827. if (SUCCEEDED(hr))
  828. {
  829. while (SUCCEEDED(hr = ::HrRegEnumKeyEx(
  830. hkeyToolsRoot,
  831. dwRegIndex++,
  832. szToolEntry,
  833. &dwSize,
  834. NULL,
  835. NULL,
  836. &ftTemp)))
  837. {
  838. HKEY hkeyToolEntry = NULL;
  839. // Open the subkey
  840. //
  841. hr = ::HrRegOpenKeyEx(
  842. hkeyToolsRoot,
  843. szToolEntry,
  844. KEY_READ,
  845. &hkeyToolEntry);
  846. if (SUCCEEDED(hr))
  847. {
  848. CStatMonToolEntry* psmteTemp = NULL;
  849. // Read in the tool
  850. //
  851. psmteTemp = new CStatMonToolEntry;
  852. TraceTag(ttidStatMon, "Reading parameters for tool %S", szToolEntry);
  853. hr = HrReadOneTool(hkeyToolEntry, psmteTemp);
  854. if (SUCCEEDED(hr))
  855. {
  856. // Add it to the list sorted
  857. //
  858. InsertNewTool(psmteTemp);
  859. }
  860. else
  861. {
  862. // Something when wrong, delete the entry
  863. //
  864. delete psmteTemp;
  865. }
  866. ::RegSafeCloseKey(hkeyToolEntry);
  867. }
  868. // Make sure the buffer entry is reset to it's original size
  869. //
  870. dwSize = celems(szToolEntry);
  871. }
  872. // Clear up a vaild error case
  873. //
  874. if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
  875. {
  876. hr = S_OK;
  877. }
  878. ::RegSafeCloseKey(hkeyToolsRoot);
  879. }
  880. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  881. {
  882. // It is okay if the key is not there
  883. //
  884. hr = S_OK;
  885. }
  886. }
  887. TraceError("CNetStatisticsCentral::HrReadTools", hr);
  888. return hr;
  889. }
  890. //+---------------------------------------------------------------------------
  891. //
  892. // Member: CNetStatisticsCentral::HrReadOneTool
  893. //
  894. // Purpose: Reads from the registry the tools characteristics
  895. //
  896. // Arguments: hkeyToolEntry - The root of the tool's registry entry
  897. // psmteNew - The entry associated with the tool
  898. //
  899. // Returns: Error code.
  900. //
  901. HRESULT CNetStatisticsCentral::HrReadOneTool( HKEY hkeyToolEntry,
  902. CStatMonToolEntry* psmteNew)
  903. {
  904. TraceFileFunc(ttidStatMon);
  905. HRESULT hr = S_OK;
  906. AssertSz(psmteNew, "We should have an entry");
  907. //
  908. // Read what we can out of the registry.
  909. //
  910. hr = ::HrRegQueryString(hkeyToolEntry,
  911. c_szRegKeyToolsDisplayName,
  912. &(psmteNew->strDisplayName));
  913. TraceError("Statmon Tool registration: failed getting DisplayName", hr);
  914. if (SUCCEEDED(hr))
  915. {
  916. hr = ::HrRegQueryString(hkeyToolEntry,
  917. c_szRegKeyToolsManufacturer,
  918. &(psmteNew->strManufacturer));
  919. TraceError("Stamon Tool registration: failed getting Manufacturer", hr);
  920. }
  921. if (SUCCEEDED(hr))
  922. {
  923. hr = ::HrRegQueryString(hkeyToolEntry,
  924. c_szRegKeyToolsCommandLine,
  925. &(psmteNew->strCommandLine));
  926. TraceError("Stamon Tool registration: failed getting CommandLine", hr);
  927. }
  928. if (SUCCEEDED(hr))
  929. {
  930. hr = ::HrRegQueryString(hkeyToolEntry,
  931. c_szRegKeyToolsDescription,
  932. &(psmteNew->strDescription));
  933. TraceError("Stamon Tool registration: failed getting Description", hr);
  934. }
  935. //
  936. // Read non-critical information
  937. //
  938. if (SUCCEEDED(hr))
  939. {
  940. HKEY hkeyCriteria = NULL;
  941. // Open the "Criteria" subkey
  942. //
  943. hr = ::HrRegOpenKeyEx(
  944. hkeyToolEntry,
  945. c_szRegKeyToolsCriteria,
  946. KEY_READ,
  947. &hkeyCriteria);
  948. if (SUCCEEDED(hr))
  949. {
  950. //1) component list: "ComponentID"
  951. hr = HrRegQueryColString(hkeyCriteria,
  952. c_szRegKeyToolsComponentID,
  953. &psmteNew->lstpstrComponentID);
  954. // 2) connecton type: "ConnectionType"
  955. hr = HrRegQueryColString(hkeyCriteria,
  956. c_szRegKeyToolsConnectionType,
  957. &psmteNew->lstpstrConnectionType);
  958. // 3) Media type: "MediaType"
  959. hr = HrRegQueryColString(hkeyCriteria,
  960. c_szRegKeyToolsMedia,
  961. &psmteNew->lstpstrMediaType);
  962. // Close our handle
  963. //
  964. ::RegSafeCloseKey(hkeyCriteria);
  965. }
  966. // We don't care if we can't open the optional keys
  967. //
  968. hr = S_OK;
  969. }
  970. //
  971. // Read in the command line parameters to be passed to the tool
  972. //
  973. if (SUCCEEDED(hr))
  974. {
  975. hr = HrReadToolFlags(hkeyToolEntry, psmteNew);
  976. }
  977. TraceError("CNetStatisticsCentral::HrReadOneTool", hr);
  978. return hr;
  979. }
  980. //+---------------------------------------------------------------------------
  981. //
  982. // Member: CNetStatisticsCentral::HrReadToolFlags
  983. //
  984. // Purpose: Reads from the registry what flags are wanted when the tool
  985. // is launched
  986. //
  987. // Arguments: hkeyToolEntry - The registry key associated with the tool
  988. // psmteNew - The entry associated with the tool
  989. //
  990. // Returns: Error code.
  991. //
  992. HRESULT CNetStatisticsCentral::HrReadToolFlags(HKEY hkeyToolEntry,
  993. CStatMonToolEntry* psmteNew)
  994. {
  995. TraceFileFunc(ttidStatMon);
  996. HRESULT hr = S_OK;
  997. HKEY hkeyToolFlags = NULL;
  998. // Open the Flags key and see what is there
  999. //
  1000. hr = ::HrRegOpenKeyEx(
  1001. hkeyToolEntry,
  1002. c_szRegKeyToolsFlags,
  1003. KEY_READ,
  1004. &hkeyToolFlags);
  1005. if (SUCCEEDED(hr))
  1006. {
  1007. WCHAR achBuf[MAX_PATH];
  1008. DWORD dwSize = celems(achBuf);
  1009. DWORD dwType = REG_SZ;
  1010. DWORD dwFlagValue = 0;
  1011. DWORD dwIndex = 0;
  1012. DWORD cbData = sizeof(dwFlagValue);
  1013. // Look for all the flags
  1014. //
  1015. while (SUCCEEDED(hr = ::HrRegEnumValue(
  1016. hkeyToolFlags,
  1017. dwIndex,
  1018. achBuf,
  1019. &dwSize,
  1020. &dwType,
  1021. reinterpret_cast<BYTE*>(&dwFlagValue),
  1022. &cbData)))
  1023. {
  1024. INT cTemp = 0;
  1025. // Make sure they are registering DWORDs
  1026. //
  1027. if ((REG_DWORD == dwType) && (0 != dwFlagValue))
  1028. {
  1029. // Do a simple search for the flags. If the list gets long,
  1030. // we should use a better search method.
  1031. //
  1032. for (;c_cAsmtfMap > cTemp; cTemp++)
  1033. {
  1034. // Look for the flag
  1035. //
  1036. if (0 == lstrcmpiW(achBuf, g_asmtfMap[cTemp].pszFlag))
  1037. {
  1038. // If we have a match, add it to the list
  1039. //
  1040. psmteNew->dwFlags |= g_asmtfMap[cTemp].dwValue;
  1041. break;
  1042. }
  1043. }
  1044. }
  1045. else
  1046. {
  1047. AssertSz(FALSE, "Tool writer has registered an invalid flag");
  1048. }
  1049. // Make sure the buffer entry is reset to it's original size
  1050. //
  1051. dwSize = celems(achBuf);
  1052. // Look at the next item
  1053. //
  1054. dwIndex++;
  1055. }
  1056. // Clear up a vaild error case
  1057. //
  1058. if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
  1059. {
  1060. hr = S_OK;
  1061. }
  1062. ::RegSafeCloseKey(hkeyToolFlags);
  1063. }
  1064. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  1065. {
  1066. // It is okay if the key is not there
  1067. //
  1068. hr = S_OK;
  1069. }
  1070. TraceError("CNetStatisticsCentral::HrReadToolFlags", hr);
  1071. return hr;
  1072. }
  1073. //+---------------------------------------------------------------------------
  1074. //
  1075. // Member: CNetStatisticsCentral::InsertNewTool
  1076. //
  1077. // Purpose: Inserts a new tool to m_lstpsmte sorted in display name
  1078. //
  1079. // Arguments: psmteTemp - the new tool to insert
  1080. //
  1081. // Returns: none
  1082. //
  1083. VOID CNetStatisticsCentral::InsertNewTool(CStatMonToolEntry* psmteTemp)
  1084. {
  1085. TraceFileFunc(ttidStatMon);
  1086. Assert(psmteTemp);
  1087. list<CStatMonToolEntry*>::iterator iterSmte;
  1088. iterSmte = m_lstpsmte.begin();
  1089. BOOL fInserted = FALSE;
  1090. tstring strDisplayName = psmteTemp->strDisplayName;
  1091. while (iterSmte != m_lstpsmte.end())
  1092. {
  1093. if (strDisplayName < (*iterSmte)->strDisplayName)
  1094. {
  1095. m_lstpsmte.insert(iterSmte, psmteTemp);
  1096. fInserted = TRUE;
  1097. break;
  1098. }
  1099. else
  1100. {
  1101. // Move on the the next item.
  1102. iterSmte++;
  1103. }
  1104. }
  1105. if (!fInserted)
  1106. m_lstpsmte.push_back(psmteTemp);
  1107. }
  1108. //+---------------------------------------------------------------------------
  1109. //
  1110. // Member: CNetStatisticsCentral::PlstsmteRegEntries
  1111. //
  1112. // Purpose: Hands back a pointer to all the tools found in the registry
  1113. //
  1114. // Arguments: None
  1115. //
  1116. // Returns: The address of the tool list
  1117. //
  1118. list<CStatMonToolEntry*>* CNetStatisticsCentral::PlstsmteRegEntries(VOID)
  1119. {
  1120. return &m_lstpsmte;
  1121. }
  1122. //////////////////////////////////////////////////////////////////////////////
  1123. // //
  1124. // CStatMonToolEntry //
  1125. // //
  1126. //////////////////////////////////////////////////////////////////////////////
  1127. //+---------------------------------------------------------------------------
  1128. //
  1129. // Member: CStatMonToolEntry::CStatMonToolEntry
  1130. //
  1131. // Purpose: Creator
  1132. //
  1133. // Arguments: None
  1134. //
  1135. // Returns: Nil
  1136. //
  1137. CStatMonToolEntry::CStatMonToolEntry(VOID) :
  1138. dwFlags(0)
  1139. {
  1140. return;
  1141. }
  1142. //+---------------------------------------------------------------------------
  1143. //
  1144. // Member: CStatMonToolEntry::~CStatMonToolEntry
  1145. //
  1146. // Purpose: Destructor
  1147. //
  1148. // Arguments: None
  1149. //
  1150. // Returns: Nil
  1151. //
  1152. CStatMonToolEntry::~CStatMonToolEntry(VOID)
  1153. {
  1154. ::FreeCollectionAndItem(lstpstrComponentID);
  1155. ::FreeCollectionAndItem(lstpstrConnectionType);
  1156. ::FreeCollectionAndItem(lstpstrMediaType);
  1157. return;
  1158. }
  1159. //
  1160. // Critical Section class to protect creation of CNetStatisticsCentral.
  1161. //
  1162. CStatCentralCriticalSection::CStatCentralCriticalSection()
  1163. {
  1164. TraceFileFunc(ttidStatMon);
  1165. __try {
  1166. InitializeCriticalSection( &m_csStatCentral );
  1167. bInitialized = TRUE;
  1168. }
  1169. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1170. bInitialized = FALSE;
  1171. }
  1172. }
  1173. CStatCentralCriticalSection::~CStatCentralCriticalSection()
  1174. {
  1175. if ( bInitialized )
  1176. {
  1177. DeleteCriticalSection( &m_csStatCentral );
  1178. }
  1179. }
  1180. HRESULT CStatCentralCriticalSection::Enter()
  1181. {
  1182. TraceFileFunc(ttidStatMon);
  1183. if ( bInitialized )
  1184. {
  1185. EnterCriticalSection( &m_csStatCentral );
  1186. return S_OK;
  1187. }
  1188. return E_OUTOFMEMORY;
  1189. }
  1190. VOID CStatCentralCriticalSection::Leave()
  1191. {
  1192. TraceFileFunc(ttidStatMon);
  1193. if ( bInitialized )
  1194. {
  1195. LeaveCriticalSection( &m_csStatCentral );
  1196. }
  1197. }