1431 lines
39 KiB
C++
1431 lines
39 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1998.
|
|
//
|
|
// File: S M C E N T . C P P
|
|
//
|
|
// Contents: The central object that controls statistic engines.
|
|
//
|
|
// Notes:
|
|
//
|
|
// Author: CWill 2 Dec 1997
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
#include "sminc.h"
|
|
#include "ncreg.h"
|
|
#include "ncnetcon.h"
|
|
|
|
//
|
|
// External data
|
|
//
|
|
|
|
extern const WCHAR c_szDevice[];
|
|
|
|
extern SM_TOOL_FLAGS g_asmtfMap[];
|
|
extern INT c_cAsmtfMap;
|
|
|
|
//
|
|
// Global Data
|
|
//
|
|
|
|
const UINT c_uiStatCentralRefreshID = 7718;
|
|
const UINT c_uiStatCentralRefreshRate = 1000; // Refresh rate in milliseconds
|
|
|
|
CRITICAL_SECTION g_csStatmonData;
|
|
|
|
CStatCentralCriticalSection CNetStatisticsCentral::g_csStatCentral;
|
|
|
|
//
|
|
// Tool Registry Keys
|
|
//
|
|
|
|
// Required fields
|
|
//
|
|
static const WCHAR c_szRegKeyToolsRoot[] = L"System\\CurrentControlSet\\Control\\Network\\Connections\\StatMon\\Tools";
|
|
static const WCHAR c_szRegKeyToolsDisplayName[] = L"DisplayName";
|
|
static const WCHAR c_szRegKeyToolsManufacturer[] = L"Manufacturer";
|
|
static const WCHAR c_szRegKeyToolsCommandLine[] = L"CommandLine";
|
|
static const WCHAR c_szRegKeyToolsDescription[] = L"Description";
|
|
|
|
// Optional fields
|
|
//
|
|
static const WCHAR c_szRegKeyToolsCriteria[] = L"Criteria";
|
|
static const WCHAR c_szRegKeyToolsComponentID[] = L"ComponentID";
|
|
static const WCHAR c_szRegKeyToolsConnectionType[] = L"ConnectionType";
|
|
static const WCHAR c_szRegKeyToolsMedia[] = L"MediaType";
|
|
static const WCHAR c_szRegKeyToolsFlags[] = L"Flags";
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// CNetStatisticsCentral //
|
|
// //
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
//
|
|
// Make the global instance
|
|
//
|
|
|
|
CNetStatisticsCentral * g_pnscCentral = NULL;
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::CNetStatisticsCentral
|
|
//
|
|
// Purpose: Creator
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Nil
|
|
//
|
|
CNetStatisticsCentral::CNetStatisticsCentral(VOID) :
|
|
m_cRef(0),
|
|
m_fProcessingTimerEvent(FALSE),
|
|
m_unTimerId(0)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
InitializeCriticalSection(&g_csStatmonData);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::~CNetStatisticsCentral
|
|
//
|
|
// Purpose: Destructor
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Nil
|
|
//
|
|
CNetStatisticsCentral::~CNetStatisticsCentral(VOID)
|
|
{
|
|
Assert(0 == m_cRef);
|
|
AssertSz(m_pnselst.empty(), "Someone leaked a INetStatisticsEngine");
|
|
AssertSz(0 == m_unTimerId, "Someone forgot to stop the timer");
|
|
|
|
// Get rid of the global pointer
|
|
//
|
|
g_pnscCentral = NULL;
|
|
|
|
EnterCriticalSection(&g_csStatmonData);
|
|
__try
|
|
{
|
|
// Release the list of engines
|
|
::FreeCollectionAndItem(m_lstpsmte);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
|
|
AssertSz(FALSE, "An exception occurred while freeing the connection list");
|
|
}
|
|
LeaveCriticalSection(&g_csStatmonData);
|
|
|
|
// delete the critical section
|
|
DeleteCriticalSection(&g_csStatmonData);
|
|
}
|
|
|
|
//
|
|
// Function: CNetStatisticsCentral::AddRef
|
|
//
|
|
// Purpose: Increment the reference count on this object
|
|
//
|
|
// Parameters: none
|
|
//
|
|
// Returns: ULONG
|
|
//
|
|
STDMETHODIMP_(ULONG) CNetStatisticsCentral::AddRef()
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
return ++m_cRef;
|
|
}
|
|
|
|
//
|
|
// Function: CNetStatisticsCentral::Release
|
|
//
|
|
// Purpose: Decrement the reference count on this object
|
|
//
|
|
// Parameters: none
|
|
//
|
|
// Returns: ULONG
|
|
//
|
|
STDMETHODIMP_(ULONG) CNetStatisticsCentral::Release()
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
ULONG cRef = --m_cRef;
|
|
|
|
if (cRef == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
return cRef;
|
|
}
|
|
|
|
//
|
|
// Function: CNetStatisticsCentral::QueryInterface
|
|
//
|
|
// Purpose: Allows for the querying of alternate interfaces
|
|
//
|
|
// Parameters: riid [IN] - Interface to retrieve
|
|
// ppvObj [OUT] - Retrieved interface if function succeeds
|
|
//
|
|
// Returns: HRESULT, S_OK on success E_NOINTERFACE on failure
|
|
//
|
|
STDMETHODIMP CNetStatisticsCentral::QueryInterface(REFIID riid, LPVOID FAR *ppvObj)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
*ppvObj = NULL;
|
|
|
|
if (riid == IID_IUnknown)
|
|
{
|
|
*ppvObj = (LPVOID)this;
|
|
AddRef();
|
|
}
|
|
else
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::HrGetNetStatisticsCentral
|
|
//
|
|
// Purpose: This procedure gets and returns a pointer to the one
|
|
// CNetStatisticsCentral object. Creating it if both necessary
|
|
// and required.
|
|
//
|
|
// Arguments: ppnsc [OUT] - Pointer to the CNetStatisticsCentral object
|
|
// fCreate [IN] - If TRUE, and the object does not already
|
|
// exist, then create it.
|
|
//
|
|
// Returns: S_OK - if the object is returned.
|
|
// E_OUTOFMEMORY - if fCreate==TRUE and creation failed
|
|
// E_NOINTERFACE - if fCreate==FALSE and the object doesn't exist
|
|
//
|
|
HRESULT
|
|
CNetStatisticsCentral::HrGetNetStatisticsCentral(
|
|
CNetStatisticsCentral ** ppnsc,
|
|
BOOL fCreate)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
HRESULT hr = E_NOINTERFACE;
|
|
|
|
// Note: scottbri - need critical section to protect creation
|
|
|
|
#if DBG
|
|
Assert( g_csStatCentral.Enter() == S_OK );
|
|
#else
|
|
g_csStatCentral.Enter();
|
|
#endif
|
|
|
|
if ((NULL == g_pnscCentral) && fCreate)
|
|
{
|
|
g_pnscCentral = new CNetStatisticsCentral;
|
|
#if DBG
|
|
// This test is only needed during DBG. The assert will catch
|
|
// the problem, bringing it to out attention, and the test and
|
|
// return will allow the user to press ignore and not crash
|
|
Assert(g_pnscCentral);
|
|
if (NULL == g_pnscCentral)
|
|
{
|
|
g_csStatCentral.Leave();
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
g_csStatCentral.Leave();
|
|
|
|
AddRefObj(g_pnscCentral);
|
|
*ppnsc = g_pnscCentral;
|
|
|
|
return((*ppnsc) ? S_OK : hr);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::TimerCallback
|
|
//
|
|
// Purpose: This is the procedure that gets called by the timer when it is
|
|
// time to update the statistics
|
|
//
|
|
// Arguments: Standard timer procedure
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
VOID
|
|
CALLBACK
|
|
CNetStatisticsCentral::TimerCallback(
|
|
HWND hwnd,
|
|
UINT uMsg,
|
|
UINT_PTR unEvent,
|
|
DWORD dwTime)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
CNetStatisticsCentral* pnsc;
|
|
|
|
if (SUCCEEDED(HrGetNetStatisticsCentral(&pnsc, FALSE)))
|
|
{
|
|
// Prevent same-thread re-entrancy. Any Win32 call made while
|
|
// processing RefreshStatistics that returns control to the message
|
|
// loop may cause this timer callback to be invoked again.
|
|
//
|
|
if ((!pnsc->m_fProcessingTimerEvent) && pnsc->m_unTimerId)
|
|
{
|
|
Assert(pnsc->m_unTimerId == unEvent);
|
|
|
|
pnsc->m_fProcessingTimerEvent = TRUE;
|
|
|
|
pnsc->RefreshStatistics(dwTime);
|
|
|
|
pnsc->m_fProcessingTimerEvent = FALSE;
|
|
}
|
|
else
|
|
{
|
|
TraceTag (ttidStatMon, "CNetStatisticsCentral::TimerCallback "
|
|
"re-entered on same thread. Ignoring.");
|
|
}
|
|
|
|
ReleaseObj(pnsc);
|
|
}
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::RefreshStatistics
|
|
//
|
|
// Purpose: To get all the statistics engines held by central to update
|
|
// their statistics
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
VOID CNetStatisticsCentral::RefreshStatistics(DWORD dwTime)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
static BOOL fInRefreshStatistics = FALSE;
|
|
|
|
if (fInRefreshStatistics)
|
|
return;
|
|
|
|
fInRefreshStatistics = TRUE;
|
|
|
|
CExceptionSafeComObjectLock EsLock(this);
|
|
|
|
HRESULT hr = S_OK;
|
|
list<INetStatisticsEngine *>::iterator iterPnse;
|
|
|
|
// Get the statistics to refresh themselves
|
|
//
|
|
INetStatisticsEngine * pnse = NULL;
|
|
|
|
iterPnse = m_pnselst.begin();
|
|
|
|
while (iterPnse != m_pnselst.end())
|
|
{
|
|
AssertSz (*iterPnse, "Shouldn't we always have non-NULL "
|
|
"entries in our statistics engine list?");
|
|
|
|
pnse = *iterPnse;
|
|
|
|
if (pnse)
|
|
{
|
|
BOOL fNoLongerConnected;
|
|
hr = pnse->UpdateStatistics(&fNoLongerConnected);
|
|
|
|
if (SUCCEEDED(hr) && fNoLongerConnected)
|
|
{
|
|
TraceTag (ttidStatMon, "CNetStatisticsCentral::RefreshStatistics - "
|
|
"UpdateStatistics reports that the connection is no longer connected.");
|
|
}
|
|
}
|
|
|
|
iterPnse++;
|
|
}
|
|
|
|
// Since we possibly removed one or more engines from the list, stop
|
|
// the timer if there are no more engines present.
|
|
//
|
|
if (m_pnselst.empty())
|
|
{
|
|
// Stop the timer
|
|
//
|
|
if (m_unTimerId)
|
|
{
|
|
::KillTimer(NULL, m_unTimerId);
|
|
m_unTimerId = 0;
|
|
}
|
|
}
|
|
|
|
fInRefreshStatistics = FALSE;
|
|
|
|
TraceError("CNetStatisticsCentral::RefreshStatistics", hr);
|
|
return;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::UpdateTitle
|
|
//
|
|
// Purpose: To update the title of a renamed connection if the statmon UI
|
|
// is up.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
|
|
VOID CNetStatisticsCentral::UpdateTitle(const GUID * pguidId,
|
|
PCWSTR pszNewName)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
CExceptionSafeComObjectLock EsLock(this);
|
|
|
|
INetStatisticsEngine * pnse;
|
|
if (FEngineInList(pguidId, &pnse))
|
|
{
|
|
pnse->UpdateTitle(pszNewName);
|
|
ReleaseObj(pnse);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::CloseStatusMonitor
|
|
//
|
|
// Purpose: To close the status monitor UI if the connection is disconnected
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
|
|
VOID CNetStatisticsCentral::CloseStatusMonitor(const GUID * pguidId)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
CExceptionSafeComObjectLock EsLock(this);
|
|
|
|
INetStatisticsEngine * pnse;
|
|
if (FEngineInList(pguidId, &pnse))
|
|
{
|
|
pnse->CloseStatusMonitor();
|
|
ReleaseObj(pnse);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::UpdateRasLinkList
|
|
//
|
|
// Purpose: To update the RAS connections's multi-link list
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
|
|
VOID CNetStatisticsCentral::UpdateRasLinkList(const GUID * pguidId)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
CExceptionSafeComObjectLock EsLock(this);
|
|
|
|
INetStatisticsEngine * pnse;
|
|
if (FEngineInList(pguidId, &pnse))
|
|
{
|
|
pnse->UpdateRasLinkList();
|
|
ReleaseObj(pnse);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::HrCreateNewEngineType
|
|
//
|
|
// Purpose: Creates the implementation of each type of statistics engine
|
|
//
|
|
// Arguments: nctNew - Type of engine to create
|
|
// ncMediaNew - The media type of the connection
|
|
// dwCharacterNew - The character of the connection
|
|
// ppStatEngine - Where to return the newly created stat engine
|
|
//
|
|
// Returns: Error code
|
|
//
|
|
HRESULT
|
|
CNetStatisticsCentral::HrCreateNewEngineType (
|
|
const CONFOLDENTRY& ccfe,
|
|
CNetStatisticsEngine** ppStatEngine)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
// Create the engine of the right type
|
|
//
|
|
|
|
if (ccfe.GetNetConMediaType() == NCM_LAN || ccfe.GetNetConMediaType() == NCM_BRIDGE)
|
|
{
|
|
// LAN connection
|
|
Assert(!(ccfe.GetCharacteristics() & NCCF_INCOMING_ONLY));
|
|
Assert(!(ccfe.GetCharacteristics() & NCCF_OUTGOING_ONLY));
|
|
|
|
CLanStatEngine* pLanObj = NULL;
|
|
INetLanConnection* pnlcNew = NULL;
|
|
tstring strDeviceName;
|
|
|
|
pLanObj = new CComObject <CLanStatEngine>;
|
|
*ppStatEngine = pLanObj;
|
|
|
|
if (!pLanObj)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
pLanObj->put_MediaType(ccfe.GetNetConMediaType(), ccfe.GetNetConSubMediaType());
|
|
// Get some LAN specific info
|
|
//
|
|
hr = ccfe.HrGetNetCon(IID_INetLanConnection,
|
|
reinterpret_cast<VOID**>(&pnlcNew));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
GUID guidDevice;
|
|
|
|
// Find the interface
|
|
//
|
|
hr = pnlcNew->GetDeviceGuid(&guidDevice);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WCHAR achGuid[c_cchGuidWithTerm];
|
|
|
|
// Make the device name
|
|
//
|
|
StringFromGUID2( guidDevice, achGuid,
|
|
c_cchGuidWithTerm);
|
|
|
|
strDeviceName = c_szDevice;
|
|
strDeviceName.append(achGuid);
|
|
|
|
hr = pLanObj->put_Device(&strDeviceName);
|
|
}
|
|
|
|
ReleaseObj(pnlcNew);
|
|
}
|
|
}
|
|
}
|
|
else if (ccfe.GetNetConMediaType() == NCM_SHAREDACCESSHOST_LAN || ccfe.GetNetConMediaType() == NCM_SHAREDACCESSHOST_RAS)
|
|
{
|
|
CComObject<CSharedAccessStatEngine>* pEngine;
|
|
hr = CComObject<CSharedAccessStatEngine>::CreateInstance(&pEngine);
|
|
if(pEngine)
|
|
{
|
|
INetSharedAccessConnection* pNetSharedAccessConnection;
|
|
|
|
hr = ccfe.HrGetNetCon(IID_INetSharedAccessConnection, reinterpret_cast<void**>(&pNetSharedAccessConnection));
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = pEngine->Initialize(ccfe.GetNetConMediaType(), pNetSharedAccessConnection);
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
*ppStatEngine = pEngine;
|
|
}
|
|
ReleaseObj(pNetSharedAccessConnection);
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
delete pEngine;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// RAS connections ..
|
|
|
|
CRasStatEngine* pRasObj = NULL;
|
|
|
|
pRasObj = new CComObject <CRasStatEngine>;
|
|
*ppStatEngine = pRasObj;
|
|
|
|
if (!pRasObj)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
// Pass in the specific type
|
|
pRasObj->put_MediaType(ccfe.GetNetConMediaType(), ccfe.GetNetConSubMediaType());
|
|
pRasObj->put_Character(ccfe.GetCharacteristics());
|
|
|
|
// Get RAS specific data
|
|
//
|
|
if (ccfe.GetCharacteristics() & NCCF_INCOMING_ONLY)
|
|
{
|
|
// RAS incoming connection
|
|
Assert(ccfe.GetNetConMediaType() != NCM_LAN);
|
|
Assert(!(ccfe.GetCharacteristics() & NCCF_OUTGOING_ONLY));
|
|
|
|
INetInboundConnection* pnicNew;
|
|
hr = ccfe.HrGetNetCon(IID_INetInboundConnection,
|
|
reinterpret_cast<VOID**>(&pnicNew));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HRASCONN hRasConn;
|
|
hr = pnicNew->GetServerConnectionHandle(
|
|
reinterpret_cast<ULONG_PTR*>(&hRasConn));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pRasObj->put_RasConn(hRasConn);
|
|
}
|
|
|
|
ReleaseObj(pnicNew);
|
|
}
|
|
}
|
|
else if (ccfe.GetCharacteristics() & NCCF_OUTGOING_ONLY)
|
|
{
|
|
// RAS outgoing connection
|
|
Assert(ccfe.GetNetConMediaType() != NCM_LAN);
|
|
Assert(!(ccfe.GetCharacteristics() & NCCF_INCOMING_ONLY));
|
|
|
|
INetRasConnection* pnrcNew;
|
|
hr = ccfe.HrGetNetCon(IID_INetRasConnection,
|
|
reinterpret_cast<VOID**>(&pnrcNew));
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HRASCONN hRasConn;
|
|
hr = pnrcNew->GetRasConnectionHandle(
|
|
reinterpret_cast<ULONG_PTR*>(&hRasConn));
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
pRasObj->put_RasConn(hRasConn);
|
|
}
|
|
else if (S_FALSE == hr)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_CONNECTION_UNAVAIL);
|
|
}
|
|
|
|
ReleaseObj(pnrcNew);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AssertSz(FALSE, "Unknown connection type...");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
TraceError("CNetStatisticsCentral::HrCreateNewEngineType", hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::HrCreateStatisticsEngineForEntry
|
|
//
|
|
// Purpose: Creates a new statistics engine for the connection
|
|
// represented by the folder entry.
|
|
//
|
|
// Arguments:
|
|
// ccfe [in] Folder entry to create statistics engine for.
|
|
// ppnseNew [out] Returned interface.
|
|
//
|
|
// Returns: S_OK or an error code.
|
|
//
|
|
// Author: shaunco 5 Nov 1998
|
|
//
|
|
// Notes: This MUST be called with this object's lock held.
|
|
//
|
|
HRESULT
|
|
CNetStatisticsCentral::HrCreateStatisticsEngineForEntry(
|
|
const CONFOLDENTRY& ccfe,
|
|
INetStatisticsEngine** ppnseNew)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
Assert (!ccfe.empty());
|
|
Assert (ppnseNew);
|
|
|
|
HRESULT hr;
|
|
|
|
// Initialize the out parameter
|
|
//
|
|
*ppnseNew = NULL;
|
|
|
|
// Create the base engine after initializing the different types
|
|
//
|
|
CNetStatisticsEngine* pStatEngine;
|
|
hr = HrCreateNewEngineType(ccfe, &pStatEngine);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Do the standard initialize
|
|
//
|
|
hr = pStatEngine->HrInitStatEngine(ccfe);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Standard CComCreator::CreateInstance stuff
|
|
//
|
|
pStatEngine->SetVoid(NULL);
|
|
pStatEngine->InternalFinalConstructAddRef();
|
|
hr = pStatEngine->FinalConstruct();
|
|
pStatEngine->InternalFinalConstructRelease();
|
|
|
|
// If all went well, add it to our list
|
|
//
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
INetStatisticsEngine* pnseInter;
|
|
|
|
hr = pStatEngine->GetUnknown()->QueryInterface(
|
|
IID_INetStatisticsEngine,
|
|
reinterpret_cast<VOID**>(&pnseInter));
|
|
|
|
// All has gone well, add it to the list
|
|
//
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Add the new entry to our list
|
|
//
|
|
m_pnselst.push_back(pnseInter);
|
|
|
|
// Now that the central object owns this
|
|
// engine, have the engine AddRef the
|
|
// net statistics central object
|
|
//
|
|
pStatEngine->SetParent(this);
|
|
AddRefObj(*ppnseNew = pStatEngine);
|
|
}
|
|
ReleaseObj(pnseInter);
|
|
}
|
|
}
|
|
// Clean up the object on failure
|
|
//
|
|
if (FAILED(hr))
|
|
{
|
|
delete pStatEngine;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
g_csStatCentral.Enter();
|
|
|
|
// Do the one time initializations
|
|
//
|
|
if (!m_unTimerId)
|
|
{
|
|
// Make sure to start the timer
|
|
//
|
|
m_unTimerId = ::SetTimer(NULL,
|
|
c_uiStatCentralRefreshID,
|
|
c_uiStatCentralRefreshRate,
|
|
TimerCallback);
|
|
|
|
TraceTag(ttidStatMon, "Created Statistics Central Timer with ID of 0x%08x", m_unTimerId);
|
|
}
|
|
|
|
g_csStatCentral.Leave();
|
|
}
|
|
|
|
TraceError("CNetStatisticsCentral::CreateNetStatisticsEngine", hr);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
HrGetStatisticsEngineForEntry (
|
|
const CONFOLDENTRY& ccfe,
|
|
INetStatisticsEngine** ppnse,
|
|
BOOL fCreate)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
HRESULT hr;
|
|
CNetStatisticsCentral* pnsc;
|
|
|
|
// Get the central object. Create if needed.
|
|
//
|
|
hr = CNetStatisticsCentral::HrGetNetStatisticsCentral(&pnsc, fCreate);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pnsc->Lock();
|
|
|
|
// If the engine is already in the list, FEngineInList will
|
|
// AddRef it for return. If not, we'll create it.
|
|
//
|
|
if (!pnsc->FEngineInList(&(ccfe.GetGuidID()), ppnse))
|
|
{
|
|
if (fCreate)
|
|
{
|
|
hr = pnsc->HrCreateStatisticsEngineForEntry(ccfe, ppnse);
|
|
}
|
|
else
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
pnsc->Unlock();
|
|
|
|
ReleaseObj(pnsc);
|
|
}
|
|
|
|
TraceError("HrGetStatisticsEngineForEntry", hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::RemoveNetStatisticsEngine
|
|
//
|
|
// Purpose: Removes a statistics engine from the list
|
|
//
|
|
// Arguments: pguidId - Identifies the engine to remove
|
|
//
|
|
// Returns: Error code
|
|
//
|
|
HRESULT
|
|
CNetStatisticsCentral::RemoveNetStatisticsEngine (
|
|
const GUID* pguidId)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
HRESULT hr = S_OK;
|
|
BOOL fFound = FALSE;
|
|
CExceptionSafeComObjectLock EsLock(this);
|
|
GUID guidTemp = { 0};
|
|
|
|
AssertSz(pguidId, "We should have a pguidId");
|
|
|
|
// Look for the item in our list
|
|
//
|
|
list<INetStatisticsEngine *>::iterator iterPnse;
|
|
INetStatisticsEngine* pnseTemp;
|
|
|
|
iterPnse = m_pnselst.begin();
|
|
while ((SUCCEEDED(hr)) && (!fFound) && (iterPnse != m_pnselst.end()))
|
|
{
|
|
pnseTemp = *iterPnse;
|
|
|
|
hr = pnseTemp->GetGuidId(&guidTemp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (guidTemp == *pguidId)
|
|
{
|
|
// We have found a match, so delete it from out list
|
|
//
|
|
fFound = TRUE;
|
|
|
|
m_pnselst.erase(iterPnse);
|
|
break;
|
|
}
|
|
}
|
|
|
|
iterPnse++;
|
|
}
|
|
|
|
if (m_pnselst.empty())
|
|
{
|
|
// Stop the timer
|
|
//
|
|
if (m_unTimerId)
|
|
{
|
|
::KillTimer(NULL, m_unTimerId);
|
|
m_unTimerId = 0;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
// $$REVIEW (jeffspr) - I removed this assert, as it was firing when my
|
|
// tray item had deleted itself (and in return, the statmon object) on
|
|
// disconnect. It's possible that we shouldn't have hit this code on the
|
|
// first Release().
|
|
AssertSz(fFound, "We didn't find the connection in our list");
|
|
#endif
|
|
|
|
TraceError("CNetStatisticsCentral::RemoveNetStatisticsEngine", hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::FEngineInList
|
|
//
|
|
// Purpose: Checks to see if an engine is already in the list
|
|
//
|
|
// Arguments: pguidId - Guid of the connection trying to be located
|
|
// ppnseRet - Return location of a connection if it is already
|
|
// in the list. NULL is valid
|
|
//
|
|
// Returns: TRUE if it is in the list, FALSE if it is not
|
|
//
|
|
BOOL
|
|
CNetStatisticsCentral::FEngineInList (
|
|
const GUID* pguidId,
|
|
INetStatisticsEngine** ppnseRet)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
HRESULT hr = S_OK;
|
|
BOOL fRet = FALSE;
|
|
GUID guidTemp = { 0};
|
|
|
|
// Init the out param
|
|
if (ppnseRet)
|
|
{
|
|
*ppnseRet = NULL;
|
|
}
|
|
|
|
// Try and find the engine in the list
|
|
//
|
|
list<INetStatisticsEngine *>::iterator iterPnse;
|
|
INetStatisticsEngine* pnseTemp;
|
|
|
|
iterPnse = m_pnselst.begin();
|
|
while ((SUCCEEDED(hr)) && (!fRet) && (iterPnse != m_pnselst.end()))
|
|
{
|
|
pnseTemp = *iterPnse;
|
|
hr = pnseTemp->GetGuidId(&guidTemp);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (guidTemp == *pguidId)
|
|
{
|
|
// We have found a match
|
|
//
|
|
fRet = TRUE;
|
|
|
|
// If we want a result, pass it back
|
|
//
|
|
if (ppnseRet)
|
|
{
|
|
::AddRefObj(*ppnseRet = pnseTemp);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
iterPnse++;
|
|
}
|
|
|
|
TraceError("CNetStatisticsCentral::FEngineInList", hr);
|
|
return fRet;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::HrReadTools
|
|
//
|
|
// Purpose: Look througth the registry for all tools that should be
|
|
// entered in the tool list
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: Nil
|
|
//
|
|
HRESULT CNetStatisticsCentral::HrReadTools(VOID)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
// Only read once
|
|
//
|
|
if (m_lstpsmte.empty())
|
|
{
|
|
WCHAR szToolEntry[MAX_PATH];
|
|
DWORD dwSize = celems(szToolEntry);
|
|
DWORD dwRegIndex = 0;
|
|
HKEY hkeyToolsRoot = NULL;
|
|
FILETIME ftTemp;
|
|
|
|
// Open the existing key and see what is there
|
|
//
|
|
// "System\\CurrentControlSet\\Control\\Network\\Connections\\StatMon\\Tools"
|
|
hr = ::HrRegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
c_szRegKeyToolsRoot,
|
|
KEY_READ,
|
|
&hkeyToolsRoot);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
while (SUCCEEDED(hr = ::HrRegEnumKeyEx(
|
|
hkeyToolsRoot,
|
|
dwRegIndex++,
|
|
szToolEntry,
|
|
&dwSize,
|
|
NULL,
|
|
NULL,
|
|
&ftTemp)))
|
|
{
|
|
HKEY hkeyToolEntry = NULL;
|
|
|
|
// Open the subkey
|
|
//
|
|
hr = ::HrRegOpenKeyEx(
|
|
hkeyToolsRoot,
|
|
szToolEntry,
|
|
KEY_READ,
|
|
&hkeyToolEntry);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
CStatMonToolEntry* psmteTemp = NULL;
|
|
|
|
// Read in the tool
|
|
//
|
|
psmteTemp = new CStatMonToolEntry;
|
|
|
|
TraceTag(ttidStatMon, "Reading parameters for tool %S", szToolEntry);
|
|
hr = HrReadOneTool(hkeyToolEntry, psmteTemp);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Add it to the list sorted
|
|
//
|
|
InsertNewTool(psmteTemp);
|
|
}
|
|
else
|
|
{
|
|
// Something when wrong, delete the entry
|
|
//
|
|
delete psmteTemp;
|
|
}
|
|
|
|
::RegSafeCloseKey(hkeyToolEntry);
|
|
}
|
|
|
|
// Make sure the buffer entry is reset to it's original size
|
|
//
|
|
dwSize = celems(szToolEntry);
|
|
}
|
|
|
|
// Clear up a vaild error case
|
|
//
|
|
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
::RegSafeCloseKey(hkeyToolsRoot);
|
|
}
|
|
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
|
|
{
|
|
// It is okay if the key is not there
|
|
//
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
TraceError("CNetStatisticsCentral::HrReadTools", hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::HrReadOneTool
|
|
//
|
|
// Purpose: Reads from the registry the tools characteristics
|
|
//
|
|
// Arguments: hkeyToolEntry - The root of the tool's registry entry
|
|
// psmteNew - The entry associated with the tool
|
|
//
|
|
// Returns: Error code.
|
|
//
|
|
HRESULT CNetStatisticsCentral::HrReadOneTool( HKEY hkeyToolEntry,
|
|
CStatMonToolEntry* psmteNew)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
AssertSz(psmteNew, "We should have an entry");
|
|
|
|
//
|
|
// Read what we can out of the registry.
|
|
//
|
|
|
|
hr = ::HrRegQueryString(hkeyToolEntry,
|
|
c_szRegKeyToolsDisplayName,
|
|
&(psmteNew->strDisplayName));
|
|
TraceError("Statmon Tool registration: failed getting DisplayName", hr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = ::HrRegQueryString(hkeyToolEntry,
|
|
c_szRegKeyToolsManufacturer,
|
|
&(psmteNew->strManufacturer));
|
|
TraceError("Stamon Tool registration: failed getting Manufacturer", hr);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = ::HrRegQueryString(hkeyToolEntry,
|
|
c_szRegKeyToolsCommandLine,
|
|
&(psmteNew->strCommandLine));
|
|
TraceError("Stamon Tool registration: failed getting CommandLine", hr);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = ::HrRegQueryString(hkeyToolEntry,
|
|
c_szRegKeyToolsDescription,
|
|
&(psmteNew->strDescription));
|
|
TraceError("Stamon Tool registration: failed getting Description", hr);
|
|
}
|
|
|
|
//
|
|
// Read non-critical information
|
|
//
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HKEY hkeyCriteria = NULL;
|
|
|
|
// Open the "Criteria" subkey
|
|
//
|
|
hr = ::HrRegOpenKeyEx(
|
|
hkeyToolEntry,
|
|
c_szRegKeyToolsCriteria,
|
|
KEY_READ,
|
|
&hkeyCriteria);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//1) component list: "ComponentID"
|
|
hr = HrRegQueryColString(hkeyCriteria,
|
|
c_szRegKeyToolsComponentID,
|
|
&psmteNew->lstpstrComponentID);
|
|
|
|
// 2) connecton type: "ConnectionType"
|
|
hr = HrRegQueryColString(hkeyCriteria,
|
|
c_szRegKeyToolsConnectionType,
|
|
&psmteNew->lstpstrConnectionType);
|
|
|
|
// 3) Media type: "MediaType"
|
|
hr = HrRegQueryColString(hkeyCriteria,
|
|
c_szRegKeyToolsMedia,
|
|
&psmteNew->lstpstrMediaType);
|
|
|
|
// Close our handle
|
|
//
|
|
::RegSafeCloseKey(hkeyCriteria);
|
|
}
|
|
|
|
// We don't care if we can't open the optional keys
|
|
//
|
|
hr = S_OK;
|
|
}
|
|
|
|
//
|
|
// Read in the command line parameters to be passed to the tool
|
|
//
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = HrReadToolFlags(hkeyToolEntry, psmteNew);
|
|
}
|
|
|
|
TraceError("CNetStatisticsCentral::HrReadOneTool", hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::HrReadToolFlags
|
|
//
|
|
// Purpose: Reads from the registry what flags are wanted when the tool
|
|
// is launched
|
|
//
|
|
// Arguments: hkeyToolEntry - The registry key associated with the tool
|
|
// psmteNew - The entry associated with the tool
|
|
//
|
|
// Returns: Error code.
|
|
//
|
|
HRESULT CNetStatisticsCentral::HrReadToolFlags(HKEY hkeyToolEntry,
|
|
CStatMonToolEntry* psmteNew)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
HRESULT hr = S_OK;
|
|
HKEY hkeyToolFlags = NULL;
|
|
|
|
// Open the Flags key and see what is there
|
|
//
|
|
hr = ::HrRegOpenKeyEx(
|
|
hkeyToolEntry,
|
|
c_szRegKeyToolsFlags,
|
|
KEY_READ,
|
|
&hkeyToolFlags);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WCHAR achBuf[MAX_PATH];
|
|
DWORD dwSize = celems(achBuf);
|
|
DWORD dwType = REG_SZ;
|
|
DWORD dwFlagValue = 0;
|
|
DWORD dwIndex = 0;
|
|
DWORD cbData = sizeof(dwFlagValue);
|
|
|
|
// Look for all the flags
|
|
//
|
|
while (SUCCEEDED(hr = ::HrRegEnumValue(
|
|
hkeyToolFlags,
|
|
dwIndex,
|
|
achBuf,
|
|
&dwSize,
|
|
&dwType,
|
|
reinterpret_cast<BYTE*>(&dwFlagValue),
|
|
&cbData)))
|
|
{
|
|
INT cTemp = 0;
|
|
|
|
// Make sure they are registering DWORDs
|
|
//
|
|
if ((REG_DWORD == dwType) && (0 != dwFlagValue))
|
|
{
|
|
// Do a simple search for the flags. If the list gets long,
|
|
// we should use a better search method.
|
|
//
|
|
for (;c_cAsmtfMap > cTemp; cTemp++)
|
|
{
|
|
// Look for the flag
|
|
//
|
|
if (0 == lstrcmpiW(achBuf, g_asmtfMap[cTemp].pszFlag))
|
|
{
|
|
// If we have a match, add it to the list
|
|
//
|
|
psmteNew->dwFlags |= g_asmtfMap[cTemp].dwValue;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AssertSz(FALSE, "Tool writer has registered an invalid flag");
|
|
}
|
|
|
|
// Make sure the buffer entry is reset to it's original size
|
|
//
|
|
dwSize = celems(achBuf);
|
|
|
|
// Look at the next item
|
|
//
|
|
dwIndex++;
|
|
}
|
|
|
|
// Clear up a vaild error case
|
|
//
|
|
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
::RegSafeCloseKey(hkeyToolFlags);
|
|
}
|
|
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
|
|
{
|
|
// It is okay if the key is not there
|
|
//
|
|
hr = S_OK;
|
|
}
|
|
|
|
TraceError("CNetStatisticsCentral::HrReadToolFlags", hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::InsertNewTool
|
|
//
|
|
// Purpose: Inserts a new tool to m_lstpsmte sorted in display name
|
|
//
|
|
// Arguments: psmteTemp - the new tool to insert
|
|
//
|
|
// Returns: none
|
|
//
|
|
VOID CNetStatisticsCentral::InsertNewTool(CStatMonToolEntry* psmteTemp)
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
Assert(psmteTemp);
|
|
|
|
list<CStatMonToolEntry*>::iterator iterSmte;
|
|
iterSmte = m_lstpsmte.begin();
|
|
|
|
BOOL fInserted = FALSE;
|
|
tstring strDisplayName = psmteTemp->strDisplayName;
|
|
|
|
while (iterSmte != m_lstpsmte.end())
|
|
{
|
|
if (strDisplayName < (*iterSmte)->strDisplayName)
|
|
{
|
|
m_lstpsmte.insert(iterSmte, psmteTemp);
|
|
fInserted = TRUE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Move on the the next item.
|
|
iterSmte++;
|
|
}
|
|
}
|
|
|
|
if (!fInserted)
|
|
m_lstpsmte.push_back(psmteTemp);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNetStatisticsCentral::PlstsmteRegEntries
|
|
//
|
|
// Purpose: Hands back a pointer to all the tools found in the registry
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: The address of the tool list
|
|
//
|
|
list<CStatMonToolEntry*>* CNetStatisticsCentral::PlstsmteRegEntries(VOID)
|
|
{
|
|
return &m_lstpsmte;
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// CStatMonToolEntry //
|
|
// //
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStatMonToolEntry::CStatMonToolEntry
|
|
//
|
|
// Purpose: Creator
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Nil
|
|
//
|
|
CStatMonToolEntry::CStatMonToolEntry(VOID) :
|
|
dwFlags(0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CStatMonToolEntry::~CStatMonToolEntry
|
|
//
|
|
// Purpose: Destructor
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: Nil
|
|
//
|
|
CStatMonToolEntry::~CStatMonToolEntry(VOID)
|
|
{
|
|
::FreeCollectionAndItem(lstpstrComponentID);
|
|
::FreeCollectionAndItem(lstpstrConnectionType);
|
|
::FreeCollectionAndItem(lstpstrMediaType);
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Critical Section class to protect creation of CNetStatisticsCentral.
|
|
//
|
|
|
|
CStatCentralCriticalSection::CStatCentralCriticalSection()
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
__try {
|
|
InitializeCriticalSection( &m_csStatCentral );
|
|
|
|
bInitialized = TRUE;
|
|
}
|
|
|
|
__except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
|
|
bInitialized = FALSE;
|
|
}
|
|
}
|
|
|
|
CStatCentralCriticalSection::~CStatCentralCriticalSection()
|
|
{
|
|
if ( bInitialized )
|
|
{
|
|
DeleteCriticalSection( &m_csStatCentral );
|
|
}
|
|
}
|
|
|
|
HRESULT CStatCentralCriticalSection::Enter()
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
if ( bInitialized )
|
|
{
|
|
EnterCriticalSection( &m_csStatCentral );
|
|
return S_OK;
|
|
}
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
VOID CStatCentralCriticalSection::Leave()
|
|
{
|
|
TraceFileFunc(ttidStatMon);
|
|
|
|
if ( bInitialized )
|
|
{
|
|
LeaveCriticalSection( &m_csStatCentral );
|
|
}
|
|
}
|