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.

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