|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1998.
//
// File: S M E N G . C P P
//
// Contents: The engine that provides statistics to the status monitor
//
// Notes:
//
// Author: CWill 7 Oct 1997
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "sminc.h"
#include "ncnetcon.h"
#include "ncui.h"
#include "smpsh.h"
#include "smutil.h"
#include "smhelp.h"
extern const WCHAR c_szNetShellDll[];
//+---------------------------------------------------------------------------
//
// Member: CNetStatisticsEngine::CNetStatisticsEngine
//
// Purpose: Initialization
//
// Arguments: None
//
// Returns: Nothing
//
CNetStatisticsEngine::CNetStatisticsEngine(VOID) : m_pnsc(NULL), m_psmEngineData(NULL), m_ppsmg(NULL), m_ppsmt(NULL), m_ppsmr(NULL), m_ppsms(NULL), m_hwndPsh(NULL), m_cStatRef(0), m_fRefreshIcon(FALSE), m_dwChangeFlags(SMDCF_NULL), m_fCreatingDialog(FALSE) { TraceFileFunc(ttidStatMon);
::ZeroMemory(&m_PersistConn, sizeof(m_PersistConn)); ::ZeroMemory(&m_guidId, sizeof(m_guidId)); }
//+---------------------------------------------------------------------------
//
// Member: CNetStatisticsEngine::~CNetStatisticsEngine
//
// Purpose: Cleans up all data before destroying the object
//
// Arguments: None
//
// Returns: Nothing
//
CNetStatisticsEngine::~CNetStatisticsEngine(VOID) { // Make sure we don't try to update our stats while destroying
//
m_cStatRef = 0;
// Make sure we are no longer in the global list if we are valid
//
if ((GUID_NULL != m_guidId) && (NULL != m_pnsc)) { (VOID) m_pnsc->RemoveNetStatisticsEngine(&m_guidId); }
//
// Clear the data
//
if (m_psmEngineData) { delete(m_psmEngineData); m_psmEngineData = NULL; }
// Release the object because we AddRefed it
//
::ReleaseObj(m_ppsmg);
delete m_ppsmt; m_ppsmt = NULL;
delete m_ppsmr; m_ppsmr = NULL;
delete m_ppsms; m_ppsms = NULL;
AssertSz(FImplies(m_PersistConn.pbBuf, m_PersistConn.ulSize), "Buffer with no size.");
MemFree(m_PersistConn.pbBuf);
::ReleaseObj(m_pnsc); }
//+---------------------------------------------------------------------------
//
// Member: CNetStatisticsEngine::HrInitStatEngine
//
// Purpose: Initilaizes the statistics engine
//
// Arguments: ccfe - The connection folder entry associated with this
// statistics engine
//
// Returns: Error code
//
HRESULT CNetStatisticsEngine::HrInitStatEngine(const CONFOLDENTRY& ccfe) { TraceFileFunc(ttidStatMon);
HRESULT hr;
Assert(!ccfe.empty());
ULONG cb = ccfe.GetPersistSize(); hr = HrMalloc(cb, (PVOID*)&m_PersistConn.pbBuf); if (SUCCEEDED(hr)) { CopyMemory(m_PersistConn.pbBuf, ccfe.GetPersistData(), cb); m_PersistConn.ulSize = cb; m_PersistConn.clsid = ccfe.GetCLSID(); m_guidId = ccfe.GetGuidID(); }
TraceError("CNetStatisticsEngine::HrInitStatEngine", hr); return hr; }
//+---------------------------------------------------------------------------
//
// Member: CNetStatisticsEngine::StartStatistics
//
// Purpose: Start retrieving statistics off of the engine
//
// Arguments: None
//
// Returns: Error code
//
HRESULT CNetStatisticsEngine::StartStatistics(VOID) { TraceFileFunc(ttidStatMon);
HRESULT hr = S_OK;
::InterlockedIncrement(&m_cStatRef); m_fRefreshIcon = TRUE;
TraceError("CNetStatisticsEngine::StartStatistics", hr); return hr; }
//+---------------------------------------------------------------------------
//
// Member: CNetStatisticsEngine::StopStatistics
//
// Purpose: Tell the engine that that statistics are no longer needed
//
// Arguments: None
//
// Returns: Error code
//
HRESULT CNetStatisticsEngine::StopStatistics(VOID) { TraceFileFunc(ttidStatMon);
HRESULT hr = S_OK;
if (0 == ::InterlockedDecrement(&m_cStatRef)) { //$ REVIEW (cwill) 5 Feb 1998: We can stop doing statistics now.
}
TraceError("CNetStatisticsEngine::StopStatistics", hr); return hr; }
DWORD CNetStatisticsEngine::MonitorThread(CNetStatisticsEngine * pnse) { // Create a new scope since FreeLibraryAndExitThread will not call destructors on global scope
{ TraceFileFunc(ttidStatMon);
HRESULT hr; BOOL fUninitCom = TRUE; CWaitCursor WaitCursor; BOOL fHasSupportPage = FALSE; int iIndexSupportPage = 0; // Initialize COM on this thread
//
hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED); if (RPC_E_CHANGED_MODE == hr) { hr = S_OK; fUninitCom = FALSE; } if (SUCCEEDED(hr)) { INetConnection* pncStatEng; // Get INetConnection and initialize the pages
//
hr = pnse->HrGetConnectionFromBlob(&pncStatEng); if (SUCCEEDED(hr)) { // Initialize the general page
//
hr = pnse->m_ppsmg->HrInitGenPage(pnse, pncStatEng, g_aHelpIDs_IDD_STATMON_GENERAL); if (SUCCEEDED(hr)) { // Initialize the tool page
//
hr = pnse->m_ppsmt->HrInitToolPage(pncStatEng, g_aHelpIDs_IDD_STATMON_TOOLS); if (SUCCEEDED(hr)) { if (pnse->m_ppsmr) { // Initialize the RAS page
//
hr = pnse->m_ppsmr->HrInitRasPage(pncStatEng, pnse->m_ppsmg, g_aHelpIDs_IDD_STATMON_RAS); }
if (SUCCEEDED(hr)) { PROPSHEETHEADER pshTemp = { 0 }; INT nPages = 1; // Start with only the general page
HPROPSHEETPAGE ahpspTemp[4];
// Put together the required property pages
// If we have a RAS page
//
if (pnse->m_ppsmr) { ahpspTemp[0] = pnse->m_ppsmg->CreatePage(IDD_STATMON_GENERAL_RAS, PSP_DEFAULT);
// Create the RAS page
//
ahpspTemp[nPages] = pnse->m_ppsmr->CreatePage(IDD_STATMON_RAS, PSP_DEFAULT);
nPages++; } else if(NCM_LAN == pnse->m_ncmType || NCM_BRIDGE == pnse->m_ncmType) { ahpspTemp[0] = pnse->m_ppsmg->CreatePage(IDD_STATMON_GENERAL_LAN, PSP_DEFAULT); } else if(NCM_SHAREDACCESSHOST_LAN == pnse->m_ncmType || NCM_SHAREDACCESSHOST_RAS == pnse->m_ncmType) { ahpspTemp[0] = pnse->m_ppsmg->CreatePage(IDD_STATMON_GENERAL_SHAREDACCESS, PSP_DEFAULT); } else { AssertSz(FALSE, "Unknown media type"); }
HICON hIcon = NULL; hr = HrGetIconFromMediaType(GetSystemMetrics(SM_CXSMICON), pnse->m_ncmType, pnse->m_ncsmType, 7, 0, &hIcon);
if (NCM_LAN == pnse->m_ncmType || NCM_BRIDGE == pnse->m_ncmType) { hr = pnse->m_ppsms->HrInitPage(pncStatEng, g_aHelpIDs_IDD_PROPPAGE_IPCFG);
if (SUCCEEDED(hr)) { ahpspTemp[nPages] = pnse->m_ppsms->CreatePage(IDD_PROPPAGE_IPCFG, PSP_DEFAULT); fHasSupportPage = TRUE; iIndexSupportPage = nPages; nPages++; } } // If we have any tools to display
//
if (!pnse->m_ppsmt->FToolListEmpty()) { ahpspTemp[nPages] = pnse->m_ppsmt->CreatePage(IDD_STATMON_TOOLS, PSP_DEFAULT); nPages++; }
// Fill in the property sheet header
//
pshTemp.dwSize = sizeof(PROPSHEETHEADER); pshTemp.dwFlags = PSH_NOAPPLYNOW | PSH_USECALLBACK; pshTemp.hwndParent = NULL; pshTemp.hInstance = _Module.GetResourceInstance(); pshTemp.hIcon = NULL; pshTemp.nPages = nPages;
if (hIcon) { pshTemp.dwFlags |= PSH_USEHICON; pshTemp.hIcon = hIcon; }
pshTemp.phpage = ahpspTemp; pshTemp.pfnCallback = static_cast<PFNPROPSHEETCALLBACK>( CNetStatisticsEngine::PshCallback);
pshTemp.hbmWatermark = NULL; pshTemp.hplWatermark = NULL; pshTemp.hbmHeader = NULL;
// Set propertysheet title
PWSTR pszCaption = NULL;
NETCON_PROPERTIES* pProps; if (SUCCEEDED(pncStatEng->GetProperties(&pProps))) { // Get the title each time in case it has
// changed
//
AssertSz(pProps->pszwName, "We should have a pProps->pszwName");
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, SzLoadIds(IDS_SM_CAPTION), 0, 0, (PWSTR)&pszCaption, 0, (va_list *)&pProps->pszwName);
pshTemp.pszCaption = pszCaption;
// Get the connection status. If the status is NCS_INVALID_ADDRESS,
// then put the "Support" tab as the start page
if (fHasSupportPage && NCS_INVALID_ADDRESS == pProps->Status) { pshTemp.nStartPage = iIndexSupportPage; Assert(pnse->m_ppsms);
//set the support tab as the first page and m_ppsms is responsible
//for initialize the propsheet
pnse->m_ppsms->SetAsFirstPage(TRUE); } else { pshTemp.nStartPage = 0; Assert(pnse->m_ppsmg);
//set the support tab as the first page and m_ppsmg is responsible
//for initialize the propsheet
pnse->m_ppsmg->SetAsFirstPage(TRUE); }
FreeNetconProperties(pProps); } else { //$ REVIEW : CWill : 02/17/98 : Better default?
pshTemp.pszCaption = SzLoadIds(IDS_SM_ERROR_CAPTION); }
// Launch the page
//
INT iRet = (INT)::PropertySheet(&pshTemp); if (NULL == iRet) { hr = ::HrFromLastWin32Error(); }
if (hIcon) { DestroyIcon(hIcon); }
if (NULL != pszCaption) { LocalFree(pszCaption); } } } }
// Make sure the general page clean up correctly.
// Since the "General" page may not be the first page (support page will be the
// first one when the address is invalid, the OnDestroy method (which calls HrCleanupGenPage)
// of the general page may not called in such case. So we always do a cleanup here. It's
// OK to call HrCleanupGenPage mutliple times.
// general page
AssertSz(pnse->m_ppsmg, "We should have a m_ppsmg"); (VOID) pnse->m_ppsmg->HrCleanupGenPage();
//also cleanup the Support page if it exists. It's safe to call this routine mutliple times.
if (fHasSupportPage) { pnse->m_ppsms->CleanupPage(); }
// leaving creating mode
pnse->m_fCreatingDialog = FALSE;
ReleaseObj(pncStatEng); }
if (fUninitCom) { CoUninitialize(); } } // Initialize com succeeded
// Release the 'pnse' object because it was addref'd before
// the thread was created.
//
ReleaseObj(static_cast<INetStatisticsEngine *>(pnse)); }
// release the dll
//
FreeLibraryAndExitThread(GetModuleHandle(c_szNetShellDll), 1);
return 1; }
//+---------------------------------------------------------------------------
//
// Member: CNetStatisticsEngine::ShowStatusMonitor
//
// Purpose: Create an launch the UI for the status monitor
//
// Arguments: None
//
// Returns: Error code
//
HRESULT CNetStatisticsEngine::ShowStatusMonitor(VOID) { TraceFileFunc(ttidStatMon);
HRESULT hr = S_OK; CExceptionSafeComObjectLock EsLock(m_pnsc);
// Create the property sheet pages if they don't already exist
//
if (!m_ppsmg) { CPspStatusMonitorGen* pObj = NULL;
// Make sure we have read in the tools
//
(VOID) m_pnsc->HrReadTools();
if (m_ncmType == NCM_LAN || m_ncmType == NCM_BRIDGE) { CPspLanGen* pLanObj = NULL;
// Make the Tool property page
m_ppsmt = new CPspLanTool;
// Create the object
pLanObj = new CComObject <CPspLanGen>;
if (pLanObj) { pLanObj->put_MediaType(m_ncmType, m_ncsmType); }
// Give it back to the page
pObj = pLanObj;
m_ppsms = new CPspStatusMonitorIpcfg;
} else if(m_ncmType == NCM_SHAREDACCESSHOST_LAN || m_ncmType == NCM_SHAREDACCESSHOST_RAS) { m_ppsmt = new CPspSharedAccessTool;
CPspSharedAccessGen* pSharedAccessGen = new CComObject<CPspSharedAccessGen>; pSharedAccessGen->put_MediaType(m_ncmType, m_ncsmType); pObj = pSharedAccessGen; } else if ((m_dwCharacter & NCCF_INCOMING_ONLY) || (m_dwCharacter & NCCF_OUTGOING_ONLY)) { // RAS connections
CPspRasGen* pRasObj = NULL;
// Make the Tool property page
//
m_ppsmt = new CPspRasTool;
// Make the RAS property page and let it be known there are
// now three pages
//
m_ppsmr = new CPspStatusMonitorRas;
// Create the object
//
pRasObj = new CComObject <CPspRasGen>;
if (pRasObj) { pRasObj->put_MediaType(m_ncmType, m_ncsmType); pRasObj->put_Character(m_dwCharacter); }
// Give it back to the page
//
pObj = pRasObj; } else { AssertSz(FALSE, "Unknown connection type."); }
if (NULL != pObj) { // Do the standard CComCreator::CreateInstance stuff.
//
pObj->SetVoid(NULL); pObj->InternalFinalConstructAddRef(); hr = pObj->FinalConstruct(); pObj->InternalFinalConstructRelease();
if (SUCCEEDED(hr)) { m_ppsmg = static_cast<CPspStatusMonitorGen*>(pObj);
// Hold on to the interface
::AddRefObj(m_ppsmg); }
// Make sure we clean up nicely
//
if (FAILED(hr)) { delete pObj; } }
// Clean up the other pages on failure
//
if (FAILED(hr)) { if (m_ppsmt) { delete m_ppsmt; m_ppsmt = NULL; }
if (m_ppsmr) { delete m_ppsmr; m_ppsmr = NULL; } } }
//
// Show the property sheets
//
if (SUCCEEDED(hr)) { // NOTE: The variable m_fCreatingDialog is reset to FALSE in the following
// 3 places, which should cover all senarios:
//
// 1) In CPspStatusMonitorGen::OnInitDialog, after m_hWnd is assigned.
// 2) In CNetStatisticsEngine::ShowStatusMonitor, in case CreateThread failed.
// 3) In CNetStatisticsEngine::MonitorThread, just before exiting
// (in case of failing to create UI).
//
if (m_hwndPsh) { // Bring the existing property sheet page to the foreground
//
::SetForegroundWindow(m_hwndPsh); } else if (!m_fCreatingDialog) { // Addref 'this' object
//
AddRefObj(static_cast<INetStatisticsEngine *>(this));
// entering creating mode
m_fCreatingDialog = TRUE;
// Create the property sheet on a different thread
//
// Make sure the dll don't get unloaded while the thread is active
HINSTANCE hInst = LoadLibrary(c_szNetShellDll); HANDLE hthrd = NULL;
if (hInst) { DWORD dwThreadId; hthrd = CreateThread(NULL, STACK_SIZE_TINY, (LPTHREAD_START_ROUTINE)CNetStatisticsEngine::MonitorThread, (LPVOID)this, 0, &dwThreadId); if (NULL != hthrd) { CloseHandle(hthrd); } } // clean up on failure
if (!hthrd) { // Release 'this' object on failure
//
ReleaseObj(static_cast<INetStatisticsEngine *>(this));
// Release the dll
//
if (hInst) FreeLibrary(hInst);
// leaving creating mode
m_fCreatingDialog = FALSE;
hr = HrFromLastWin32Error(); } } }
TraceError("CNetStatisticsEngine::ShowStatusMonitor", hr); return hr; }
//+---------------------------------------------------------------------------
//
// Member: CNetStatisticsEngine::GetStatistics
//
// Purpose:
//
// Arguments:
//
// Returns:
//
HRESULT CNetStatisticsEngine::GetStatistics( STATMON_ENGINEDATA** ppseAllData) { TraceFileFunc(ttidStatMon);
HRESULT hr = S_OK;
// Make sure we have a valid pointer
if (ppseAllData) { STATMON_ENGINEDATA * pEngineData = NULL;
// Allocate space and copy the data ..
EnterCriticalSection(&g_csStatmonData);
if (!m_psmEngineData) { DWORD dwChangeFlags; BOOL fNoLongerConnected;
hr = HrUpdateData(&dwChangeFlags, &fNoLongerConnected); }
if (m_psmEngineData) { DWORD dwBytes = sizeof(STATMON_ENGINEDATA); PVOID pbBuf; hr = HrCoTaskMemAlloc(dwBytes, &pbBuf); if (SUCCEEDED(hr)) { pEngineData = reinterpret_cast<STATMON_ENGINEDATA *>(pbBuf);
// fill in the data
*pEngineData = *m_psmEngineData; } }
LeaveCriticalSection(&g_csStatmonData);
*ppseAllData = pEngineData; } else { // We should have good data
hr = E_INVALIDARG; }
TraceError("CNetStatisticsEngine::GetStatistics", hr); return hr; }
//+---------------------------------------------------------------------------
//
// Member: CNetStatisticsEngine::UpdateStatistics
//
// Purpose: Get the new statistics from the devices and notify all the
// advises that the data has changed
//
// Arguments: None
//
// Returns: Error code
//
HRESULT CNetStatisticsEngine::UpdateStatistics ( BOOL* pfNoLongerConnected) { TraceFileFunc(ttidStatMon);
HRESULT hr = S_OK;
Assert (pfNoLongerConnected);
// Initialize the output parameter.
//
*pfNoLongerConnected = FALSE;
// Don't bother doing anything if we don't have any ref count
//
if (m_cStatRef) { // Get the new data
//
DWORD dwChangeFlags;
hr = HrUpdateData(&dwChangeFlags, pfNoLongerConnected);
// If it represents a change, notify our connection points.
//
if (SUCCEEDED(hr) && (m_fRefreshIcon || // Bug#319276, force a refresh if new client is added
(dwChangeFlags != m_dwChangeFlags) || (*pfNoLongerConnected))) { m_fRefreshIcon = FALSE;
ULONG cpUnk; IUnknown** apUnk;
hr = HrCopyIUnknownArrayWhileLocked ( this, &m_vec, &cpUnk, &apUnk); if (SUCCEEDED(hr) && cpUnk && apUnk) { // Notify everyone that we have changed
//
for (ULONG i = 0; i < cpUnk; i++) { INetConnectionStatisticsNotifySink* pSink = static_cast<INetConnectionStatisticsNotifySink*>(apUnk[i]);
hr = pSink->OnStatisticsChanged(dwChangeFlags);
ReleaseObj(pSink); }
MemFree(apUnk); }
// Remember the change flags for comparison next time.
//
m_dwChangeFlags = dwChangeFlags; } }
TraceError("CNetStatisticsEngine::UpdateStatistics", hr); return hr; }
//+---------------------------------------------------------------------------
//
// Member: CNetStatisticsEngine::UpdateTitle
//
// Purpose: If the status monitor UI is up, change the title
//
// Arguments: pszwNewName
//
// Returns: None
//
HRESULT CNetStatisticsEngine::UpdateTitle (PCWSTR pszwNewName) { TraceFileFunc(ttidStatMon);
if (m_hwndPsh) { // Set propertysheet title
PWSTR pszCaption = NULL;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, SzLoadIds(IDS_SM_CAPTION), 0, 0, (PWSTR)&pszCaption, 0, (va_list *)&pszwNewName);
PropSheet_SetTitle(m_hwndPsh,0,pszCaption); }
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CNetStatisticsEngine::CloseStatusMonitor
//
// Purpose: If the status monitor UI is up, close it
//
// Arguments: None
//
// Returns: None
//
HRESULT CNetStatisticsEngine::CloseStatusMonitor() { TraceFileFunc(ttidStatMon);
if (m_hwndPsh) { PropSheet_PressButton(m_hwndPsh, PSBTN_CANCEL); }
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CNetStatisticsEngine::UpdateRasLinkList
//
// Purpose: If the status monitor UI is up and on the RAS page, update
// the multi-link combo-box and button state
//
// Arguments: None
//
// Returns: Error code
//
HRESULT CNetStatisticsEngine::UpdateRasLinkList() { TraceFileFunc(ttidStatMon);
HRESULT hr = S_OK;
if (m_hwndPsh) { HWND hwndDlg = PropSheet_GetCurrentPageHwnd(m_hwndPsh);
if (hwndDlg) { if (GetDlgItem(hwndDlg, IDC_TXT_SM_NUM_DEVICES_VAL)) { // we are on the RAS page, update the combo box, active link count etc.
::PostMessage(hwndDlg, PWM_UPDATE_RAS_LINK_LIST, 0, 0); } } }
TraceError("CNetStatisticsEngine::UpdateRasLinkList", hr); return hr; }
//+---------------------------------------------------------------------------
//
// Member: CNetStatisticsEngine::GetGuidId
//
// Purpose: Gets the Connection GUID of the engine into a pre-allocated
// buffer
//
// Arguments: pguidId - Location of buffer to hold the GUID
//
// Returns: Error code
//
HRESULT CNetStatisticsEngine::GetGuidId(GUID* pguidId) { TraceFileFunc(ttidStatMon);
HRESULT hr = S_OK;
// Pass back the GUID
//
if (pguidId) { *pguidId = m_guidId; } else { hr = E_POINTER; }
TraceError("CNetStatisticsEngine::GetGuidId", hr); return hr; }
//+------------------------------------------------------------------
//
// CNetStatisticsEngine::PshCallback
//
// Purpose:
//
//
// Parameters:
// hwndDlg [in]
// uMsg [in]
// lParam [in]
//
// Returns:
// a
//
// Side Effects:
//
INT CALLBACK CNetStatisticsEngine::PshCallback(HWND hwndDlg, UINT uMsg, LPARAM lParam) { TraceFileFunc(ttidStatMon);
switch (uMsg) { // called before the dialog is created, hwndPropSheet = NULL,
// lParam points to dialog resource
// This would hide the context help "?" on toolbar
#if 0
case PSCB_PRECREATE: { LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE)lParam;
lpTemplate->style &= ~DS_CONTEXTHELP; } break; #endif
case PSCB_INITIALIZED: { HWND hwndTemp = NULL;
// Cancel button becomes close
//
hwndTemp = ::GetDlgItem(hwndDlg, IDCANCEL); if (NULL != hwndTemp) { ::SetWindowText(hwndTemp, ::SzLoadIds(IDS_SM_PSH_CLOSE)); }
HICON hIcon; hIcon = (HICON)SendMessage(hwndDlg, WM_GETICON, ICON_SMALL, 0); // Assert(hIcon);
if (hIcon) { SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon); } } break; }
return 0; }
|