windows-nt/Source/XPSP1/NT/net/config/shell/statmon/smgenpsp.cpp
2020-09-26 16:20:57 +08:00

1667 lines
44 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1998.
//
// File: S M G E N P S P . C P P
//
// Contents: The rendering of the UI for the network status monitor.
//
// Notes:
//
// Author: CWill 6 Oct 1997
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "foldinc.h"
#include "ncatlui.h"
#include "ncnetcon.h"
#include "ncperms.h"
#include "ncui.h"
#include "ncreg.h"
#include "nsres.h"
#include "sminc.h"
#include "smpsh.h"
#include "windutil.h"
#include "conprops.h"
#include "oncommand.h"
#include "pidlutil.h"
#include "openfold.h"
#include "..\folder\confold.h"
#include "cfpidl.h"
DWORD MapRSSIToWirelessSignalStrength(int iRSSI);
PCWSTR PszGetRSSIString(int iRSSI);
//
// Function Prototypes
//
VOID CompressionToSz(UINT uiCompression, WCHAR* pchbuffer);
//
// Common Strings
//
extern const WCHAR c_szNetShellDll[];
//
// Constants
//
const UINT c_unLocalRefreshTimerID = 817;
//
// ShowLanErrors
//
static const WCHAR c_szRegKeyStatmonRoot[] = L"System\\CurrentControlSet\\Control\\Network\\Connections\\StatMon";
static const WCHAR c_szShowLanErrors[] = L"ShowLanErrors";
// forward declaration
DWORD PropertyThread(CNetStatisticsEngine * pnse);
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::CPspStatusMonitorGen
//
// Purpose: Creator
//
// Arguments: None
//
// Returns: Nil
//
CPspStatusMonitorGen::CPspStatusMonitorGen() :
m_psmEngineData(NULL),
m_pnseStat(NULL),
m_dwConPointCookie(0),
m_fStats(FALSE),
m_ncmType(NCM_LAN),
m_ncsmType(NCSM_LAN),
m_dwCharacter(0),
m_dwLastUpdateStatusDisplayTick(0),
m_fProcessingTimerEvent(FALSE),
m_fIsFirstPage(FALSE),
m_iLastSignalStrength(-100)
{
TraceFileFunc(ttidStatMon);
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::FinalRelease
//
// Purpose: Called after last Release.
//
// Arguments: None
//
// Returns: Nil
//
VOID
CPspStatusMonitorGen::FinalRelease(VOID)
{
TraceFileFunc(ttidStatMon);
(VOID) HrCleanupGenPage();
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::HrInitGenPage
//
// Purpose: Before the property page is populated, we have to make sure
// that we have some of the required data. This method
// initializes the page so that it is ready to be shown.
//
// Arguments: pnseNew - The statistics engine associated with this page
// pncNew - The connection the page is being created for
//
// Returns: Error code
//
HRESULT
CPspStatusMonitorGen::HrInitGenPage (
CNetStatisticsEngine* pnseNew,
INetConnection* pncNew,
const DWORD * adwHelpIDs)
{
TraceFileFunc(ttidStatMon);
HRESULT hr = S_OK;
INetStatisticsEngine* pnseInter = pnseNew;
AssertSz(pnseNew, "We don't have a pnseNew");
// Set context help ID
m_adwHelpIDs = adwHelpIDs;
// Initialize the engine data
//
AssertSz(!m_psmEngineData, "We should't have a m_psmEngineData");
DWORD dwBytes = sizeof(STATMON_ENGINEDATA);
PVOID pbBuf;
hr = HrCoTaskMemAlloc(dwBytes, &pbBuf);
if (SUCCEEDED(hr))
{
m_psmEngineData = reinterpret_cast<STATMON_ENGINEDATA *>(pbBuf);
ZeroMemory(m_psmEngineData, sizeof(STATMON_ENGINEDATA));
}
// Advise the interface
//
if (SUCCEEDED(hr))
{
IConnectionPoint* pcpStat = NULL;
hr = ::HrGetPcpFromPnse(pnseInter, &pcpStat);
if (SUCCEEDED(hr))
{
INetConnectionStatisticsNotifySink* pncsThis = this;
hr = pcpStat->Advise(pncsThis, &m_dwConPointCookie);
::ReleaseObj(pcpStat);
}
}
// Keep track of our owner
//
if (SUCCEEDED(hr))
{
AssertSz(!m_pnseStat, "We should't have a m_pnseStat");
m_pnseStat = pnseNew;
::AddRefObj(pnseInter);
}
TraceError("CPspStatusMonitorGen::HrInitGenPage", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::OnInitDialog
//
// Purpose: When the page comes up, initialize the fields
//
// Arguments: Standard command parameters
//
// Returns: Standard return
//
LRESULT
CPspStatusMonitorGen::OnInitDialog (
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled)
{
TraceFileFunc(ttidStatMon);
// initialize data member
m_iStatTrans = Stat_Unknown;
// Initialize the icon in the dialog by forcing it to change
//
UpdatePageIcon(SMDCF_TRANSMITTING | SMDCF_RECEIVING);
UpdatePageIcon(SMDCF_NULL);
UpdateSignalStrengthIcon(0);
// Tell the CNetStatisticsEngine about our parent property sheet
// so if someone attempts to bring up a statistics monitor we
// can utilize the existing one
//
Assert(m_pnseStat);
m_pnseStat->SetPropsheetWindow(GetParent());
// Start our local refresh timer with a 1 second period.
//
SetTimer (c_unLocalRefreshTimerID, 1000, NULL);
// leaving creating mode
m_pnseStat->UnSetCreatingDialog();
BOOL fEnableDisconnect = TRUE; // Should we disable the Disconnect button
BOOL fEnableProperties = TRUE; // Should we disable the Properties button
BOOL fShowErrorCount = TRUE;
switch(m_ncmType)
{
case NCM_LAN:
case NCM_BRIDGE:
fEnableDisconnect = FHasPermission(NCPERM_LanConnect);
fEnableProperties = FHasPermission(NCPERM_LanProperties);
if(!FIsShowLanErrorRegKeySet())
{
fShowErrorCount = FALSE;
}
::ShowWindow(GetDlgItem(IDC_TXT_ERROR), fShowErrorCount);
::ShowWindow(GetDlgItem(IDC_TXT_SM_ERROR_TRANS), fShowErrorCount);
::ShowWindow(GetDlgItem(IDC_TXT_SM_ERROR_RECV), fShowErrorCount);
::ShowWindow(GetDlgItem(IDC_FRM_LONG), fShowErrorCount);
::ShowWindow(GetDlgItem(IDC_FRM_SHORT), !fShowErrorCount); // reversed...
break;
case NCM_SHAREDACCESSHOST_RAS:
::SetWindowText(GetDlgItem(IDC_PSB_DISCONNECT), ::SzLoadIds(IDS_SM_PSH_DISCONNECT)); // If RAS connection, change the "Disable" button to "Disconnect"
//fallthru
case NCM_SHAREDACCESSHOST_LAN:
{
// TODO fEnableDisconnect
// TODO fEnableProperties
HRESULT hr;
fShowErrorCount = FALSE; // no error stuff in spec
}
break;
case NCM_TUNNEL:
::ShowWindow(GetDlgItem(IDC_TXT_SM_SPEED_LABEL), FALSE);
::ShowWindow(GetDlgItem(IDC_TXT_SM_SPEED), FALSE);
//fallthru
case NCM_DIRECT: // REVIEW correct?
case NCM_ISDN:
case NCM_PHONE:
case NCM_PPPOE:
fEnableDisconnect = FHasPermission(NCPERM_RasConnect);
if (
(m_dwCharacter & NCCF_INCOMING_ONLY) ||
((m_dwCharacter & NCCF_ALL_USERS) && !FHasPermission(NCPERM_RasAllUserProperties)) ||
(!(m_dwCharacter & NCCF_ALL_USERS) && !FHasPermission(NCPERM_RasMyProperties))
)
{
fEnableProperties = FALSE;
}
::SetWindowText(GetDlgItem(IDC_PSB_DISCONNECT), ::SzLoadIds(IDS_SM_PSH_DISCONNECT)); // If RAS connection, change the "Disable" button to "Disconnect"
::ShowWindow(GetDlgItem(IDC_TXT_ERROR), fShowErrorCount);
::ShowWindow(GetDlgItem(IDC_TXT_SM_ERROR_TRANS), fShowErrorCount);
::ShowWindow(GetDlgItem(IDC_TXT_SM_ERROR_RECV), fShowErrorCount);
::ShowWindow(GetDlgItem(IDC_FRM_LONG), fShowErrorCount);
::ShowWindow(GetDlgItem(IDC_FRM_SHORT), !fShowErrorCount); // reversed...
break;
default:
AssertSz(FALSE, "Unknown media type");
break;
}
::EnableWindow(::GetDlgItem(m_hWnd, IDC_PSB_DISCONNECT), fEnableDisconnect);
::EnableWindow(::GetDlgItem(m_hWnd, IDC_PSB_PROPERTIES), fEnableProperties);
if (m_fIsFirstPage)
{
// get window handle to propertysheet
HWND hwndParent=GetParent();
Assert(hwndParent);
// center the property sheet on desktop
FCenterWindow (hwndParent, NULL);
// hide the "ok" button
//
::ShowWindow(::GetDlgItem(hwndParent, IDOK), FALSE);
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::OnSetActive
//
// Purpose: Enable statistics when the page has focus
//
// Arguments: Standard notification parameters
//
// Returns: Standard return
//
LRESULT
CPspStatusMonitorGen::OnSetActive (
INT idCtrl,
LPNMHDR pnmh,
BOOL& bHandled)
{
TraceFileFunc(ttidStatMon);
HRESULT hr = S_OK;
// Only turn them on if they are not running
//
if (!m_fStats)
{
hr = m_pnseStat->StartStatistics();
m_fStats = TRUE;
}
// User's intent is to view statistics, so give them an immediate
// refreshed view of them.
//
::PostMessage (m_hWnd, PWM_UPDATE_STATUS_DISPLAY, 0, SMDCF_NULL);
TraceError("CPspStatusMonitorGen::OnSetActive", hr);
return LresFromHr(hr);
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::OnKillActive
//
// Purpose: Disable statistics when the page is changed
//
// Arguments: Standard notification parameters
//
// Returns: Standard return
//
LRESULT
CPspStatusMonitorGen::OnKillActive (
INT idCtrl,
LPNMHDR pnmh,
BOOL& bHandled)
{
TraceFileFunc(ttidStatMon);
HRESULT hr = S_OK;
// Only turn them off if they are running
//
if (m_fStats)
{
hr = m_pnseStat->StopStatistics();
m_fStats = FALSE;
}
TraceError("CPspStatusMonitorGen::OnKillActive", hr);
return LresFromHr(hr);
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::OnClose
//
// Purpose: Cleans up the items in the page when the dialog is being
// closed
//
// Arguments: Standard command parameters
//
// Returns: Standard return
//
LRESULT
CPspStatusMonitorGen::OnClose (
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled)
{
return DestroyWindow();
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::OnDestroy
//
// Purpose: Cleans up the items in the page when the dialog is being
// destroyed
//
// Arguments: Standard command parameters
//
// Returns: Standard return
//
LRESULT
CPspStatusMonitorGen::OnDestroy (
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled)
{
TraceFileFunc(ttidStatMon);
HWND hwndIcon = ::GetDlgItem(m_hWnd, IDI_SM_STATUS_ICON);
HICON hOldIcon = reinterpret_cast<HICON>(::SendMessage(
hwndIcon,
STM_GETICON,
0,
0));
if (hOldIcon)
{
DestroyIcon(hOldIcon);
}
HRESULT hr = S_OK;
AssertSz(m_pnseStat, "We should have a m_pnseStat");
// Make sure we don't get released during our destroy
//
::AddRefObj(this);
// Stop our local refresh timer
//
KillTimer (c_unLocalRefreshTimerID);
// Make sure stats are in a happy state
//
if (m_fStats)
{
(VOID) m_pnseStat->StopStatistics();
m_fStats = FALSE;
}
//
// *** Do this last ***
//
// It is very likely this will result in the this page being destroyed
// if it is the window closing
//
m_pnseStat->SetPropsheetWindow(NULL);
// Clean up all the interfaces
//
hr = HrCleanupGenPage();
::ReleaseObj(this);
TraceError("CPspStatusMonitorGen::OnDestroy", hr);
return 0;
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::HrCleanupGenPage
//
// Purpose: Cleans out all the interfaces that are used by the open page
//
// Arguments: None
//
// Returns: Error code
//
HRESULT
CPspStatusMonitorGen::HrCleanupGenPage (
VOID)
{
TraceFileFunc(ttidStatMon);
HRESULT hr = S_OK;
INetStatisticsEngine* pnseStat = m_pnseStat;
// Only disconnect if we haven't already.
//
if (pnseStat)
{
// Unadvise the interface
//
IConnectionPoint* pcpStat = NULL;
if (m_dwConPointCookie
&& (SUCCEEDED(::HrGetPcpFromPnse(pnseStat, &pcpStat))))
{
(VOID) pcpStat->Unadvise(m_dwConPointCookie);
::ReleaseObj(pcpStat);
// Very important to zero the cookie. This tells
// OnStatisticsChanged that we're no longer interested in updates.
//
m_dwConPointCookie = 0;
}
if (m_psmEngineData)
{
CoTaskMemFree(m_psmEngineData);
m_psmEngineData = NULL;
}
//
// *** Do this last ***
//
// It is very likely this will result in the this page being destroyed
// if it is the window closing
//
m_pnseStat = NULL;
::ReleaseObj(pnseStat);
}
TraceError("CPspStatusMonitorGen::HrCleanupGenPage", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::OnContextMenu
//
// Purpose: When right click a control, bring up help
//
// Arguments: Standard command parameters
//
// Returns: Standard return
//
LRESULT
CPspStatusMonitorGen::OnContextMenu(UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& fHandled)
{
TraceFileFunc(ttidStatMon);
if (m_adwHelpIDs != NULL)
{
::WinHelp(m_hWnd,
c_szNetCfgHelpFile,
HELP_CONTEXTMENU,
(ULONG_PTR)m_adwHelpIDs);
}
return 0;
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::OnHelp
//
// Purpose: When drag context help icon over a control, bring up help
//
// Arguments: Standard command parameters
//
// Returns: Standard return
//
LRESULT
CPspStatusMonitorGen::OnHelp(UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& fHandled)
{
TraceFileFunc(ttidStatMon);
LPHELPINFO lphi = reinterpret_cast<LPHELPINFO>(lParam);
Assert(lphi);
if ((m_adwHelpIDs != NULL) && (HELPINFO_WINDOW == lphi->iContextType))
{
::WinHelp(static_cast<HWND>(lphi->hItemHandle),
c_szNetCfgHelpFile,
HELP_WM_HELP,
(ULONG_PTR)m_adwHelpIDs);
}
return 0;
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::OnDisconnect
//
// Purpose: When the disconnect button is hit, disconnect the connection
// and closes the dialog
//
// Arguments: Standard notification parameters
//
// Returns: Standard return
//
LRESULT CPspStatusMonitorGen::OnDisconnect(WORD wNotifyCode, WORD wID,
HWND hWndCtl, BOOL& fHandled)
{
TraceFileFunc(ttidStatMon);
HRESULT hr = S_OK;
switch (wNotifyCode)
{
case BN_CLICKED:
case BN_DOUBLECLICKED:
{
hr = HrDisconnectConnection();
}
}
TraceError("CPspStatusMonitorGen::OnDisconnect", hr);
return 0;
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::OnRaiseproperties
//
// Purpose: Bring up the property of this connection
//
// Arguments: Standard notification parameters
//
// Returns: Standard return
//
LRESULT CPspStatusMonitorGen::OnRaiseProperties(WORD wNotifyCode, WORD wID,
HWND hWndCtl, BOOL& fHandled)
{
TraceFileFunc(ttidStatMon);
HRESULT hr = S_OK;
switch (wNotifyCode)
{
case BN_CLICKED:
case BN_DOUBLECLICKED:
{
// Addref m_pnseStat object
//
AddRefObj(static_cast<INetStatisticsEngine *>(m_pnseStat));
// Make sure the netshell.dll is not unloaded
//
HINSTANCE hInst = LoadLibrary(c_szNetShellDll);
HANDLE hthrd = NULL;
// Create the property sheet on a different thread
//
if (hInst)
{
DWORD dwThreadId;
hthrd = CreateThread(NULL, STACK_SIZE_TINY,
(LPTHREAD_START_ROUTINE)PropertyThread,
(LPVOID)m_pnseStat, 0, &dwThreadId);
}
if (NULL != hthrd)
{
CloseHandle(hthrd);
}
else
{
/// Release m_pnseStat object on failure
//
ReleaseObj(static_cast<INetStatisticsEngine *>(m_pnseStat));
// release the dll
//
if (hInst)
FreeLibrary(hInst);
hr = HrFromLastWin32Error();
}
}
}
TraceError("CPspStatusMonitorGen::OnRaiseproperties", hr);
return 0;
}
DWORD PropertyThread(CNetStatisticsEngine * pnse)
{
TraceFileFunc(ttidStatMon);
HRESULT hr = S_OK;
BOOL fUninitCom = TRUE;
// 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* pncMonitor = NULL;
// Get the INetConnection
//
Assert (pnse);
hr = pnse->HrGetConnectionFromBlob(&pncMonitor);
if (SUCCEEDED(hr))
{
hr = HrRaiseConnectionProperties(NULL, pncMonitor);
}
ReleaseObj(pncMonitor);
}
if (fUninitCom)
{
CoUninitialize();
}
// release input interface
ReleaseObj(static_cast<INetStatisticsEngine *>(pnse));
// release the library we loaded
FreeLibraryAndExitThread(GetModuleHandle(c_szNetShellDll), hr);
TraceError("PropertyThread", hr);
return 1;
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::HrDisconnectConnection
//
// Purpose: disconnect the connection and closes the dialog if succeeded
//
// Arguments: fConfirmed TRUE if the user has confirmed to disconnect the connection
//
// Returns: Standard return
//
HRESULT CPspStatusMonitorGen::HrDisconnectConnection(BOOL fConfirmed)
{
TraceFileFunc(ttidStatMon);
HRESULT hr;
Assert (m_pnseStat);
// Get the INetConnection
//
INetConnection* pncMonitor;
hr = m_pnseStat->HrGetConnectionFromBlob(&pncMonitor);
if (SUCCEEDED(hr))
{
PCONFOLDPIDL pidlConnection;
hr = HrCreateConFoldPidl(WIZARD_NOT_WIZARD, pncMonitor, pidlConnection);
if (SUCCEEDED(hr))
{
CONFOLDENTRY ccfe;
hr = pidlConnection.ConvertToConFoldEntry(ccfe);
if (SUCCEEDED(hr))
{
// Get the pidl for the Connections Folder
//
PCONFOLDPIDLFOLDER pidlFolder;
hr = HrGetConnectionsFolderPidl(pidlFolder);
if (SUCCEEDED(hr))
{
// Get the Connections Folder object
//
LPSHELLFOLDER psfConnections;
hr = HrGetConnectionsIShellFolder(pidlFolder, &psfConnections);
if (SUCCEEDED(hr))
{
hr = HrOnCommandDisconnectInternal(ccfe,
m_hWnd,
psfConnections);
ReleaseObj(psfConnections);
}
}
}
}
// release INetConnection interface
ReleaseObj(pncMonitor);
}
// If anything above failed.
//
if (SUCCEEDED(hr))
{
if (S_OK == hr)
{
// close the property sheet
HWND hwndPS = ::GetParent(m_hWnd);
// Push the Close ("Cancel") button to close dialog
//
::PostMessage(hwndPS, WM_COMMAND, MAKEWPARAM(IDCANCEL, 0),
(LPARAM)::GetDlgItem(hwndPS, IDCANCEL));
}
else
{
// Disconnect confirmation canceled. Do nothing (don't close
// statmon, anyway).
//
AssertSz(S_FALSE == hr, "Disconnect != S_OK or S_FALSE, but succeeded? What is it then?");
}
}
else
{
TraceError("pncMonitor->Disconnect", hr);
// Warn the user and don't close if we couldn't disconnect
//
::NcMsgBox( m_hWnd,
IDS_SM_ERROR_CAPTION,
IDS_SM_ERROR_CANNOT_DISCONNECT,
MB_ICONWARNING);
}
TraceError("CPspStatusMonitorGen::HrDisconnectConnection", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::OnSetCursor
//
// Purpose: Ensure the mouse cursor over the Property Sheet is an Arrow.
//
// Arguments: Standard command parameters
//
// Returns: Standard return
//
LRESULT
CPspStatusMonitorGen::OnSetCursor (
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled)
{
TraceFileFunc(ttidStatMon);
if (LOWORD(lParam) == HTCLIENT)
{
SetCursor(LoadCursor(NULL, IDC_ARROW));
}
return FALSE;
}
LRESULT
CPspStatusMonitorGen::OnTimer (
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled)
{
TraceFileFunc(ttidStatMon);
// Prevent same-thread re-entrancy. Any Win32 call made while
// processing this event that return control to the message
// loop may cause this timer to fire again.
//
if (!m_fProcessingTimerEvent)
{
m_fProcessingTimerEvent = TRUE;
// If we're within 200 milliseconds of the last time we updated the
// status display, don't bother doing it again. This covers the case
// where our timer coincides with the timer in smcent which would
// would cause us to update the status display twice in rapid
// succession each time the timers fire.
//
DWORD dwTick = GetTickCount ();
if (dwTick > m_dwLastUpdateStatusDisplayTick + 200)
{
OnUpdateStatusDisplay (uMsg, 0, m_dwChangeFlags, bHandled);
}
m_fProcessingTimerEvent = FALSE;
}
return 0;
}
LRESULT
CPspStatusMonitorGen::OnUpdateStatusDisplay(
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled)
{
TraceFileFunc(ttidStatMon);
HRESULT hr = S_OK;
DWORD dwChangeFlags = lParam;
// We may be in the process of disconnecting the statistics page in
// which case m_dwConPointCookie will be zero.
//
if (m_dwConPointCookie)
{
Assert (m_psmEngineData);
STATMON_ENGINEDATA* psmNewData = NULL;
hr = m_pnseStat->GetStatistics(&psmNewData);
if (SUCCEEDED(hr) && psmNewData)
{
if (m_psmEngineData)
{
//
// Display the new stats
//
UpdatePage(m_psmEngineData, psmNewData);
// Update the icon image
//
UpdatePageIcon(dwChangeFlags);
UpdateSignalStrengthIcon(psmNewData->SMED_802_11_SIGNAL_STRENGTH);
// Note the clock tick of when we last updated
// the status display.
//
m_dwLastUpdateStatusDisplayTick = GetTickCount();
// Replace the old data with the new
//
CoTaskMemFree(m_psmEngineData);
}
m_psmEngineData = psmNewData;
}
}
else
{
TraceTag (ttidStatMon,
"CPspStatusMonitorGen::OnStatisticsChanged called but we've "
"been closed. Ignoring.");
}
TraceError("CPspStatusMonitorGen::OnUpdateStatusDisplay", hr);
return 0;
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::OnStatisticsChanged
//
// Purpose: This is the callback that tell the property page that the
// data on the page has changed
//
// Arguments: dwCookie - The cookie of the connection that has changed
// dwChangeFlags - What has changed
//
// Returns: Error code
//
STDMETHODIMP
CPspStatusMonitorGen::OnStatisticsChanged(
DWORD dwChangeFlags)
{
TraceFileFunc(ttidStatMon);
::PostMessage (m_hWnd, PWM_UPDATE_STATUS_DISPLAY, 0, dwChangeFlags);
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::UpdatePage
//
// Purpose: Fill the fields on the page with new data
//
// Arguments: pseOldData - The old stats being displayed on the page
// pseNewData - The new stats being displayed on the page
//
// Returns: Nothing
//
VOID
CPspStatusMonitorGen::UpdatePage (
STATMON_ENGINEDATA* pseOldData,
const STATMON_ENGINEDATA* pseNewData)
{
TraceFileFunc(ttidStatMon);
AssertSz(pseOldData, "We don't have a puiOld");
AssertSz(pseNewData, "We don't have a puiNew");
//
// Update the dialog fields
//
UpdatePageConnectionStatus(pseOldData, pseNewData);
UpdatePageDuration(pseOldData, pseNewData);
UpdatePageSpeed(pseOldData, pseNewData);
// If the StatMon is not getting any bytes (a common problem with net
// cards), display packets instead
//
if (ShouldShowPackets(pseNewData))
{
// Only change the label if we have to
//
if (Stat_Packets != m_iStatTrans)
{
SetDlgItemText(IDC_TXT_SM_BYTES_LABEL, ::SzLoadIds(IDS_SM_PACKETS));
m_iStatTrans = Stat_Packets;
// Force a refresh
//
pseOldData->SMED_PACKETSTRANSMITTING = 0;
pseOldData->SMED_PACKETSRECEIVING = 0;
}
UpdatePageBytesTransmitting(pseOldData, pseNewData, Stat_Packets);
UpdatePageBytesReceiving(pseOldData, pseNewData, Stat_Packets);
}
else
{
// Only change the label if we have to
//
if (Stat_Bytes != m_iStatTrans)
{
SetDlgItemText(IDC_TXT_SM_BYTES_LABEL, ::SzLoadIds(IDS_SM_BYTES));
m_iStatTrans = Stat_Bytes;
// Force a refresh
//
pseOldData->SMED_BYTESTRANSMITTING = 0;
pseOldData->SMED_BYTESRECEIVING = 0;
}
UpdatePageBytesTransmitting(pseOldData, pseNewData, Stat_Bytes);
UpdatePageBytesReceiving(pseOldData, pseNewData, Stat_Bytes);
}
UpdatePageCompTransmitting(pseOldData, pseNewData);
UpdatePageCompReceiving(pseOldData, pseNewData);
UpdatePageErrorsTransmitting(pseOldData, pseNewData);
UpdatePageErrorsReceiving(pseOldData, pseNewData);
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::ShouldShowPackets
//
// Purpose: Decided whether to show bytes or packets
//
// Arguments: pseNewData - The new stats being displayed on the page
//
// Returns: Nothing
//
BOOL CPspStatusMonitorGen::ShouldShowPackets(const STATMON_ENGINEDATA* pseNewData)
{
TraceFileFunc(ttidStatMon);
return (0 == pseNewData->SMED_BYTESTRANSMITTING) && (0 == pseNewData->SMED_BYTESRECEIVING);
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::UpdatePageSpeed
//
// Purpose: Updates the speed display on the general page
//
// Arguments: pseOldData - The old stats being displayed on the page
// pseNewData - The new stats being displayed on the page
//
// Returns: Nothing
//
VOID
CPspStatusMonitorGen::UpdatePageSpeed(
const STATMON_ENGINEDATA* pseOldData,
const STATMON_ENGINEDATA* pseNewData)
{
TraceFileFunc(ttidStatMon);
AssertSz(pseOldData, "We don't have a pseOldData");
AssertSz(pseNewData, "We don't have a pseNewData");
// Get the data and see if either is different
//
if ((pseOldData->SMED_SPEEDTRANSMITTING != pseNewData->SMED_SPEEDTRANSMITTING)
|| (pseOldData->SMED_SPEEDRECEIVING != pseNewData->SMED_SPEEDRECEIVING))
{
WCHAR achBuffer[MAX_PATH];
FormatTransmittingReceivingSpeed (
pseNewData->SMED_SPEEDTRANSMITTING,
pseNewData->SMED_SPEEDRECEIVING,
achBuffer);
// Set the control text.
//
SetDlgItemText(IDC_TXT_SM_SPEED, achBuffer);
}
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::UpdatePageConnectionStatus
//
// Purpose: Update the connections field on the property page
//
// Arguments: puiOldData - The old stats being displayed on the page
// puiNewData - The new stats being displayed on the page
//
// Returns: Nothing
//
VOID
CPspStatusMonitorGen::UpdatePageConnectionStatus(
const STATMON_ENGINEDATA* pseOldData,
const STATMON_ENGINEDATA* pseNewData)
{
TraceFileFunc(ttidStatMon);
AssertSz(pseOldData, "We don't have a pseOldData");
AssertSz(pseNewData, "We don't have a pseNewdata");
// Update the Connection Status
//
if ((pseNewData->SMED_CONNECTIONSTATUS == NCS_DISCONNECTED) ||
(pseOldData->SMED_CONNECTIONSTATUS != pseNewData->SMED_CONNECTIONSTATUS))
{
INT idsConnection = IDS_SM_CS_DISCONNECTED;
// Make sure our strings are still intact
AssertSz((((IDS_SM_CS_DISCONNECTED + 1) == IDS_SM_CS_CONNECTING)
&& ((IDS_SM_CS_DISCONNECTED + 2) == IDS_SM_CS_CONNECTED)
&& ((IDS_SM_CS_DISCONNECTED + 3) == IDS_SM_CS_DISCONNECTING)
&& ((IDS_SM_CS_DISCONNECTED + 4) == IDS_SM_CS_HARDWARE_NOT_PRESENT)
&& ((IDS_SM_CS_DISCONNECTED + 5) == IDS_SM_CS_HARDWARE_DISABLED)
&& ((IDS_SM_CS_DISCONNECTED + 6) == IDS_SM_CS_HARDWARE_MALFUNCTION)),
"Some one has been messing with connection status strings");
idsConnection = (IDS_SM_CS_DISCONNECTED
+ pseNewData->SMED_CONNECTIONSTATUS);
if (idsConnection == IDS_SM_CS_DISCONNECTED)
{
// close the property sheet
HWND hwndPS = ::GetParent(m_hWnd);
TraceTag(ttidStatMon, "Closing Status Monitor page because status was: DISCONNECTED");
// Push the Close ("Cancel") button to close dialog
//
::PostMessage(hwndPS, WM_COMMAND, MAKEWPARAM(IDCANCEL, 0),
(LPARAM)::GetDlgItem(hwndPS, IDCANCEL));
}
else
{
SetDlgItemText(IDC_TXT_SM_STATUS, ::SzLoadIds(idsConnection));
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::UpdatePageIcon
//
// Purpose: Update the icon on the property page
//
// Arguments: dwChangeFlags - The new changed state
//
// Returns: Nothing
//
VOID
CPspStatusMonitorGen::UpdatePageIcon (
DWORD dwChangeFlags)
{
TraceFileFunc(ttidStatMon);
// If either of these have changed, change the icon
// so we'll know to update the icon
//
if (((SMDCF_TRANSMITTING | SMDCF_RECEIVING) & m_dwChangeFlags)
!= ((SMDCF_TRANSMITTING | SMDCF_RECEIVING) & dwChangeFlags))
{
HICON hStatusIcon = 0;
HWND hwndIcon = NULL;
// Get the new icon
//
hStatusIcon = GetCurrentConnectionStatusIconId(m_ncmType, m_ncsmType, m_dwCharacter, dwChangeFlags);
if (hStatusIcon)
{
hwndIcon = ::GetDlgItem(m_hWnd, IDI_SM_STATUS_ICON);
// Set the icon to the new one
//
HICON hOldIcon = reinterpret_cast<HICON>(::SendMessage(
hwndIcon,
STM_SETICON,
(WPARAM)hStatusIcon,
0));
DestroyIcon(hOldIcon);
}
}
// Keep the flags for the next update
//
m_dwChangeFlags = dwChangeFlags;
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::UpdateSignalStrengthIcon
//
// Purpose: Update the icon on the property page
//
// Arguments: iRSSI - The new signal strenghth
//
// Returns: Nothing
//
inline
VOID
CPspStatusMonitorGen::UpdateSignalStrengthIcon (
INT iRSSI)
{
TraceFileFunc(ttidStatMon);
if (0 == iRSSI)
{
if (0 != m_iLastSignalStrength)
{
::ShowWindow(::GetDlgItem(m_hWnd, IDC_TXT_SM_SIGNAL_STRENGTH), SW_HIDE);
::ShowWindow(::GetDlgItem(m_hWnd, IDI_SM_SIGNAL_STRENGTH_ICON), SW_HIDE);
}
m_iLastSignalStrength = iRSSI;
return;
}
else
{
if (0 == m_iLastSignalStrength)
{
::ShowWindow(::GetDlgItem(m_hWnd, IDC_TXT_SM_SIGNAL_STRENGTH), SW_SHOW);
::ShowWindow(::GetDlgItem(m_hWnd, IDI_SM_SIGNAL_STRENGTH_ICON), SW_SHOW);
}
}
INT idStatusIcon = 0;
m_iLastSignalStrength = iRSSI;
// Get the new icon
//
idStatusIcon = IDI_802_11_LEVEL0 + MapRSSIToWirelessSignalStrength(iRSSI);
HWND hwndSignalStrength = ::GetDlgItem(m_hWnd, IDI_SM_SIGNAL_STRENGTH_ICON);
Assert(hwndSignalStrength);
if (hwndSignalStrength)
{
HDC hdcSignalStrength = ::GetDC(hwndSignalStrength);
Assert(hdcSignalStrength);
if (hdcSignalStrength)
{
HICON hIconSignalStrength = LoadIconTile(_Module.GetResourceInstance(), MAKEINTRESOURCE(idStatusIcon));
Assert(hIconSignalStrength);
if (hIconSignalStrength)
{
::DrawIconEx(hdcSignalStrength, 0, 0, hIconSignalStrength, 48, 48, 0, NULL, DI_IMAGE | DI_MASK);
DestroyIcon(hIconSignalStrength);
}
::ReleaseDC(hwndSignalStrength, hdcSignalStrength);
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::UpdateSignalStrengthIcon
//
// Purpose: Update the icon on the property page
//
// Arguments: iRSSI - The new signal strenghth
//
// Returns: Nothing
//
LRESULT CPspStatusMonitorGen::OnPaint (
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled)
{
TraceFileFunc(ttidStatMon);
PAINTSTRUCT ps;
BeginPaint(&ps);
UpdateSignalStrengthIcon(m_iLastSignalStrength);
EndPaint(&ps);
bHandled = TRUE;
return 0;
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::UpdatePageDuration
//
// Purpose: Updates the duration display on the general page
//
// Arguments: pseOldData - The old stats being displayed on the page
// pseNewData - The new stats being displayed on the page
//
// Returns: Nothing
//
VOID
CPspStatusMonitorGen::UpdatePageDuration(
const STATMON_ENGINEDATA* pseOldData,
const STATMON_ENGINEDATA* pseNewData)
{
TraceFileFunc(ttidStatMon);
AssertSz(pseOldData, "We don't have a pseOldData");
AssertSz(pseNewData, "We don't have a pseNewData");
// Get the see if either is different
//
if (pseOldData->SMED_DURATION != pseNewData->SMED_DURATION)
{
tstring strDuration;
// Format the time duration as a string
//
FormatTimeDuration(pseNewData->SMED_DURATION, &strDuration);
// Set the control
//
SetDlgItemText(IDC_TXT_SM_DURATION, strDuration.c_str());
}
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::UpdatePageBytesTransmitting
//
// Purpose: Updates the bytes Transmitting display on the general page
//
// Arguments: pseOldData - The old stats being displayed on the page
// pseNewData - The new stats being displayed on the page
// iStat - The which stats to display
//
// Returns: Nothing
//
VOID
CPspStatusMonitorGen::UpdatePageBytesTransmitting(
const STATMON_ENGINEDATA* pseOldData,
const STATMON_ENGINEDATA* pseNewData,
StatTrans iStat)
{
TraceFileFunc(ttidStatMon);
AssertSz(pseOldData, "We don't have a pseOldData");
AssertSz(pseNewData, "We don't have a pseNewData");
AssertSz(((Stat_Packets == iStat) || (Stat_Bytes == iStat)), "We have an invalid iStat");
UINT64 ui64Old;
UINT64 ui64New;
if (Stat_Bytes == iStat)
{
ui64Old = pseOldData->SMED_BYTESTRANSMITTING;
ui64New = pseNewData->SMED_BYTESTRANSMITTING;
}
else
{
ui64Old = pseOldData->SMED_PACKETSTRANSMITTING;
ui64New = pseNewData->SMED_PACKETSTRANSMITTING;
}
// See if either is different
//
if (ui64Old != ui64New)
{
SetDlgItemFormatted64bitInteger(
m_hWnd,
IDC_TXT_SM_BYTES_TRANS,
ui64New, FALSE);
}
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::UpdatePageBytesReceiving
//
// Purpose: Updates the bytes receiving display on the general page
//
// Arguments: puiOld - The old stats being displayed on the page
// puiNew - The new stats being displayed on the page
// iStat - The which stats to display
//
// Returns: Nothing
//
VOID
CPspStatusMonitorGen::UpdatePageBytesReceiving(
const STATMON_ENGINEDATA* pseOldData,
const STATMON_ENGINEDATA* pseNewData,
StatTrans iStat)
{
TraceFileFunc(ttidStatMon);
AssertSz(pseOldData, "We don't have a puiOld");
AssertSz(pseNewData, "We don't have a puiNew");
AssertSz(((Stat_Packets == iStat) || (Stat_Bytes == iStat)), "We have an invalid iStat");
UINT64 ui64Old;
UINT64 ui64New;
if (Stat_Bytes == iStat)
{
ui64Old = pseOldData->SMED_BYTESRECEIVING;
ui64New = pseNewData->SMED_BYTESRECEIVING;
}
else
{
ui64Old = pseOldData->SMED_PACKETSRECEIVING;
ui64New = pseNewData->SMED_PACKETSRECEIVING;
}
// See if either is different
//
if (ui64Old != ui64New)
{
SetDlgItemFormatted64bitInteger(
m_hWnd,
IDC_TXT_SM_BYTES_RCVD,
ui64New, FALSE);
}
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::UpdatePageCompTransmitting
//
// Purpose: Updates the compression transmitting display on the general
// page
//
// Arguments: pseOldData - The old stats being displayed on the page
// pseNewData - The new stats being displayed on the page
//
// Returns: Nothing
//
VOID
CPspStatusMonitorGen::UpdatePageCompTransmitting(
const STATMON_ENGINEDATA* pseOldData,
const STATMON_ENGINEDATA* pseNewData)
{
TraceFileFunc(ttidStatMon);
AssertSz(pseOldData, "We don't have a pseOldData");
AssertSz(pseNewData, "We don't have a pseNewData");
// See if either is different
//
if (pseOldData->SMED_COMPRESSIONTRANSMITTING
!= pseNewData->SMED_COMPRESSIONTRANSMITTING)
{
WCHAR achBuf[20];
CompressionToSz(pseNewData->SMED_COMPRESSIONTRANSMITTING, achBuf);
SetDlgItemText(IDC_TXT_SM_COMP_TRANS, achBuf);
}
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::UpdatePageCompReceiving
//
// Purpose: Updates the compression receiving display on the general page
//
// Arguments: pseOldData - The old stats being displayed on the page
// pseNewData - The new stats being displayed on the page
//
// Returns: Nothing
//
VOID
CPspStatusMonitorGen::UpdatePageCompReceiving(
const STATMON_ENGINEDATA* pseOldData,
const STATMON_ENGINEDATA* pseNewData)
{
TraceFileFunc(ttidStatMon);
AssertSz(pseOldData, "We don't have a puiOld");
AssertSz(pseNewData, "We don't have a puiNew");
// see if either is different
//
if (pseOldData->SMED_COMPRESSIONRECEIVING != pseNewData->SMED_COMPRESSIONRECEIVING)
{
WCHAR achBuf[20];
CompressionToSz(pseNewData->SMED_COMPRESSIONRECEIVING, achBuf);
SetDlgItemText(IDC_TXT_SM_COMP_RCVD, achBuf);
}
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::UpdatePageErrorsTransmitting
//
// Purpose: Updates the compression transmitting display on the general
// page
//
// Arguments: pseOldData - The old stats being displayed on the page
// pseNewData - The new stats being displayed on the page
//
// Returns: Nothing
//
VOID
CPspStatusMonitorGen::UpdatePageErrorsTransmitting(
const STATMON_ENGINEDATA* pseOldData,
const STATMON_ENGINEDATA* pseNewData)
{
TraceFileFunc(ttidStatMon);
AssertSz(pseOldData, "We don't have a pseOldData");
AssertSz(pseNewData, "We don't have a pseNewData");
// See if either is different
//
if (pseOldData->SMED_ERRORSTRANSMITTING
!= pseNewData->SMED_ERRORSTRANSMITTING)
{
SetDlgItemFormatted32bitInteger (
m_hWnd,
IDC_TXT_SM_ERROR_TRANS,
pseNewData->SMED_ERRORSTRANSMITTING,
FALSE);
}
}
//+---------------------------------------------------------------------------
//
// Member: CPspStatusMonitorGen::UpdatePageErrorsReceiving
//
// Purpose: Updates the compression receiving display on the general page
//
// Arguments: pseOldData - The old stats being displayed on the page
// pseNewData - The new stats being displayed on the page
//
// Returns: Nothing
//
VOID
CPspStatusMonitorGen::UpdatePageErrorsReceiving(
const STATMON_ENGINEDATA* pseOldData,
const STATMON_ENGINEDATA* pseNewData)
{
TraceFileFunc(ttidStatMon);
AssertSz(pseOldData, "We don't have a pseOldData");
AssertSz(pseNewData, "We don't have a pseNewData");
// see if either is different
//
if (pseOldData->SMED_ERRORSRECEIVING != pseNewData->SMED_ERRORSRECEIVING)
{
SetDlgItemFormatted32bitInteger (
m_hWnd,
IDC_TXT_SM_ERROR_RECV,
pseNewData->SMED_ERRORSRECEIVING,
FALSE);
}
}
//+---------------------------------------------------------------------------
//
// Function: CompressionToSz
//
// Purpose: To format nicely BPS into a readable string
//
// Arguments: uiCompression - The amount of compression
// pchBuffer - The Buffer to receive the string
//
// Returns: Nothing
//
VOID
CompressionToSz (
UINT uiCompression,
WCHAR* pchBuffer)
{
TraceFileFunc(ttidStatMon);
AssertSz((((INT)uiCompression >= 0) && ((INT)uiCompression <= 100)),
"Invalid compression");
wsprintfW(pchBuffer, L"%lu %%", uiCompression);
}
//+---------------------------------------------------------------------------
//
// Function: FIsShowLanErrorRegKeySet
//
// Purpose: Check if the registry key is set:
// System\CurrentControlSet\Control\Network\Connections\StatMon\ShowLanErrors
//
// Arguments:
//
// Returns: Nothing
//
BOOL CPspStatusMonitorGen::FIsShowLanErrorRegKeySet()
{
TraceFileFunc(ttidStatMon);
BOOL fRet = FALSE;
HKEY hkeyStatmonRoot = NULL;
HRESULT hr = S_OK;
// "System\\CurrentControlSet\\Control\\Network\\Connections\\StatMon\\ShowLanErrors"
hr = ::HrRegOpenKeyEx(
HKEY_LOCAL_MACHINE,
c_szRegKeyStatmonRoot,
KEY_READ,
&hkeyStatmonRoot);
if (SUCCEEDED(hr))
{
Assert(hkeyStatmonRoot);
DWORD dwValue =0;
hr = HrRegQueryDword(hkeyStatmonRoot, c_szShowLanErrors, &dwValue);
if SUCCEEDED(hr)
{
fRet = !!dwValue;
}
RegCloseKey(hkeyStatmonRoot);
}
return fRet;
}