#include <tchar.h>
#include <STDIO.H>
#include <locale.h>
#include <WINDOWS.H>
#include <atlconv.h>
#include <atlstr.h>
#include <vector>
#include <list>
#include <map>
#include <strsafe.h>
#include <boost\format.hpp>
#include <boost\io\ios_state.hpp>
#include <boost\algorithm\string.hpp>
#include <boost\xpressive\xpressive_dynamic.hpp>
#define PERF_SUBKEY_GLOBAL _T("Global")
#define REG_SUBKEY_COUNTER _T("Counter")
#define REG_SUBKEY_HELP _T("Help")
#define FIRST_PERF_OBJECT_TYPE( PerfData ) ((PPERF_OBJECT_TYPE)((PBYTE)PerfData + PerfData->HeaderLength))
#define NEXT_PERF_OBJECT_TYPE( PerfObj ) ((PPERF_OBJECT_TYPE)((PBYTE)PerfObj + PerfObj->TotalByteLength))
#define FIRST_PERF_COUNTER_DEFINITION( PerfObj ) ((PPERF_COUNTER_DEFINITION)((PBYTE)PerfObj + PerfObj->HeaderLength))
#define NEXT_PERF_COUNTER_DEFINITION( PerfCounterDef ) ((PPERF_COUNTER_DEFINITION)((PBYTE)PerfCounterDef + PerfCounterDef->ByteLength))
#define FIRST_PERF_INSTANCE_DEFINITION( PerfObj ) ((PPERF_INSTANCE_DEFINITION)((PBYTE)PerfObj + PerfObj->DefinitionLength))
#define PERF_COUNTER_BLOCK_FROM_INSTANCE( PerfInst ) ((PPERF_COUNTER_BLOCK)((PBYTE)PerfInst + PerfInst->ByteLength))
#define PERF_COUNTER_BLOCK_FROM_OBJECT( PerfObj ) ((PPERF_COUNTER_BLOCK)((PBYTE)PerfObj + PerfObj->DefinitionLength))
#define NEXT_PERF_INSTANCE_DEFINITION( PerfInst ) ((PPERF_INSTANCE_DEFINITION)((PBYTE)PerfInst + PerfInst->ByteLength + PERF_COUNTER_BLOCK_FROM_INSTANCE(PerfInst)->ByteLength ))
#define GET_COUNTER_VALUE_DWORD( PerfCounter, PerfCounterDef ) (*(LPDWORD)((LPBYTE)PerfCounter + PerfCounterDef->CounterOffset ))
#define GET_COUNTER_VALUE_OF_TYPE( PerfCounter, PerfCounterDef, Type ) (*(Type*)((LPBYTE)PerfCounter + PerfCounterDef->CounterOffset ))
namespace std
{
typedef basic_string<TCHAR, char_traits<TCHAR>, allocator<TCHAR> > tstring;
}
std::map<DWORD, CString> g_mapCounters;
std::map<DWORD, CString> g_mapHelps;
std::map<std::tstring, BOOL> g_mapPhys;
typedef struct _PerfInstance_t
{
PPERF_INSTANCE_DEFINITION pInstance;
CString strInstanceName;
CString strParentInstanceName;
PPERF_COUNTER_BLOCK pPerfCounters;
}PerfInstance_t, *pPerfInstance_t;
typedef struct _PerfObject_t
{
PPERF_OBJECT_TYPE pPerfObject;
std::vector<PPERF_COUNTER_DEFINITION>
vecPerfCounterDefs;
PPERF_COUNTER_BLOCK pPerfCounters;
std::vector<PerfInstance_t> vecPerfInstances;
}PerfObject_t, *pPerfObject_t;
typedef struct _PerfData_t
{
std::vector<PerfObject_t> vecPerfObjects;
}PerfData_t, *pPerfData_t;
// 获得性能数据块
std::vector<BYTE> GetRegValueData(
LPCTSTR lpSubKey,
HKEY hParentKey = HKEY_PERFORMANCE_DATA,
LPCTSTR lpMachineName = NULL,
DWORD dwPerSize = 0x400 )
{
DWORD dwType;
CONST DWORD dwDefaultBufferSize = dwPerSize;
DWORD dwBufferSize = dwDefaultBufferSize;
// 性能数据缓冲
std::vector<BYTE> vecBuffer;
HKEY hKey = hParentKey;
if( lpMachineName && lpMachineName[0] != _T('\0') )
{
if( RegConnectRegistry(
lpMachineName,
hKey,
&hKey ) != ERROR_SUCCESS )
return vecBuffer;
}
LSTATUS lStatus;
vecBuffer.resize(dwBufferSize);
while( ( lStatus = RegQueryValueEx(
hKey,
lpSubKey,
NULL,
&dwType,
vecBuffer.data(),
&dwBufferSize ) ) != ERROR_SUCCESS )
{
if( lStatus == ERROR_MORE_DATA )
{
// 缓冲尺寸太小,增加内存分配
dwBufferSize += dwDefaultBufferSize;
vecBuffer.resize( dwBufferSize );
}
else
{
vecBuffer.clear();
return vecBuffer;
}
}
vecBuffer.resize( dwBufferSize );
return vecBuffer;
}
std::vector<BYTE> GetRegValueData(
DWORD dwSubKey,
HKEY hParentKey = HKEY_PERFORMANCE_DATA,
LPCTSTR lpMachineName = NULL,
DWORD dwPerSize = 0x400 )
{
TCHAR szSubKey[0x10];
_ltot_s( dwSubKey, szSubKey, 0x10, 10 );
return GetRegValueData( szSubKey, hParentKey, lpMachineName, dwPerSize );
}
// 枚举性能对象
BOOL EnumPerfObject(
IN PERF_DATA_BLOCK * pPerfData,
OUT std::list<PERF_OBJECT_TYPE> & vecRefObjType )
{
vecRefObjType.clear();
PERF_OBJECT_TYPE * pObjType = FIRST_PERF_OBJECT_TYPE( pPerfData );
for( DWORD i(0); i < pPerfData->NumObjectTypes; ++i )
{
vecRefObjType.push_back( *pObjType );
pObjType = NEXT_PERF_OBJECT_TYPE( pObjType );
}
return TRUE;
}
// 获取性能计数器名字
BOOL GetCounters( std::map<DWORD, CString> & mapCounters )
{
mapCounters.clear();
std::vector<BYTE> vecBuffer = GetRegValueData( REG_SUBKEY_COUNTER, HKEY_PERFORMANCE_NLSTEXT );
if( vecBuffer.empty() ) return FALSE;
LPTSTR lpStr = (LPTSTR)vecBuffer.data();
while( *lpStr )
{
DWORD dwCounter = _ttol(lpStr);
lpStr += lstrlen(lpStr) + 1;
mapCounters[dwCounter] = lpStr;
lpStr += lstrlen(lpStr) + 1;
}
return TRUE;
}
// 获取性能计数器的帮助
BOOL GetHelps( std::map<DWORD, CString> & mapHelps )
{
mapHelps.clear();
std::vector<BYTE> vecBuffer = GetRegValueData( REG_SUBKEY_HELP, HKEY_PERFORMANCE_NLSTEXT );
if( vecBuffer.empty() ) return FALSE;
LPTSTR lpStr = (LPTSTR)vecBuffer.data();
while( *lpStr )
{
DWORD dwCounter = _ttol(lpStr);
lpStr += lstrlen(lpStr) + 1;
mapHelps[dwCounter] = lpStr;
lpStr += lstrlen(lpStr) + 1;
}
return TRUE;
}
PPERF_OBJECT_TYPE GetObjectType(
PPERF_DATA_BLOCK pPerfDataBlock,
DWORD dwObjectNameTitleIndex )
{
PPERF_OBJECT_TYPE pPerfObjectType = FIRST_PERF_OBJECT_TYPE( pPerfDataBlock );
for( DWORD i(0); i < pPerfDataBlock->NumObjectTypes; ++i )
{
if( pPerfObjectType->ObjectNameTitleIndex == dwObjectNameTitleIndex )
{
return pPerfObjectType;
}
pPerfObjectType = NEXT_PERF_OBJECT_TYPE( pPerfObjectType );
}
return NULL;
}
PPERF_INSTANCE_DEFINITION GetParentInstance(
PPERF_OBJECT_TYPE const pPerfObjectType,
DWORD dwInstanceIndex )
{
PPERF_INSTANCE_DEFINITION pPerfInstanceDefinition = FIRST_PERF_INSTANCE_DEFINITION( pPerfObjectType );
PPERF_COUNTER_BLOCK pPerfCounterBlock = NULL;
for( DWORD i(0); i < dwInstanceIndex; ++i )
{
pPerfCounterBlock = PERF_COUNTER_BLOCK_FROM_INSTANCE( pPerfInstanceDefinition );
pPerfInstanceDefinition = NEXT_PERF_INSTANCE_DEFINITION( pPerfInstanceDefinition );
}
return pPerfInstanceDefinition;
}
CString GetInstanceName(
PPERF_INSTANCE_DEFINITION pPerfInstanceDefinition,
UINT CodePage )
{
CStringW strInstanceNameW;
const DWORD dwMaxInstNameLen = 0xFF;
if( pPerfInstanceDefinition->NameLength > dwMaxInstNameLen ) return CString();
LPBYTE lpInstanceName = (LPBYTE)pPerfInstanceDefinition + pPerfInstanceDefinition->NameOffset;
if( CodePage == 0 ) // Unicode
{
DWORD cch = pPerfInstanceDefinition->NameLength / 2;
StringCchCopyNW(
strInstanceNameW.GetBuffer( cch + 1 ),
cch + 1,
(LPCWSTR)lpInstanceName,
cch );
strInstanceNameW.ReleaseBuffer();
}
else if( CodePage != UINT_MAX ) // 异常值
{
CStringA strInstanceNameA;
StringCbCopyNA(
strInstanceNameA.GetBuffer( pPerfInstanceDefinition->NameLength + 1 ),
pPerfInstanceDefinition->NameLength + 1,
(LPCSTR)lpInstanceName,
pPerfInstanceDefinition->NameLength );
strInstanceNameA.ReleaseBuffer();
strInstanceNameW = CA2W( strInstanceNameA, CodePage );
}
return CString( strInstanceNameW );
}
void GetFullInstanceName(
PPERF_DATA_BLOCK const pPerfDataBlock,
PPERF_INSTANCE_DEFINITION pInstance,
UINT CodePage,
CString & strName,
CString & strParentName )
{
strName = GetInstanceName( pInstance, CodePage );
if( pInstance->ParentObjectTitleIndex )
{
PPERF_OBJECT_TYPE pParentObject = GetObjectType(
pPerfDataBlock,
pInstance->ParentObjectTitleIndex );
if( pParentObject )
{
PPERF_INSTANCE_DEFINITION pParentInstance = GetParentInstance(
pParentObject,
pInstance->ParentObjectInstance );
if( pParentInstance )
{
strParentName = GetInstanceName( pParentInstance, CodePage );
}
}
}
}
DWORD LoadCounterDefs(
PPERF_OBJECT_TYPE const pPerfObject,
std::vector<PPERF_COUNTER_DEFINITION> & vecPerfCounterDefs )
{
vecPerfCounterDefs.clear();
DWORD dwSkippedBaseRecords = 0;
PPERF_COUNTER_DEFINITION pPerfCounterDef = FIRST_PERF_COUNTER_DEFINITION( pPerfObject );
for( DWORD i(0); i < pPerfObject->NumCounters; ++i )
{
vecPerfCounterDefs.push_back( pPerfCounterDef );
pPerfCounterDef = NEXT_PERF_COUNTER_DEFINITION( pPerfCounterDef );
}
return pPerfObject->NumCounters - dwSkippedBaseRecords;
}
void LoadInstances(
PPERF_DATA_BLOCK const pPerfData,
PPERF_OBJECT_TYPE const pPerfObject,
std::vector<PerfInstance_t> & vecPerfInstances )
{
vecPerfInstances.clear();
PPERF_INSTANCE_DEFINITION pInstance = FIRST_PERF_INSTANCE_DEFINITION( pPerfObject );
for( LONG i(0); i < pPerfObject->NumInstances; ++i )
{
PerfInstance_t perfInst;
perfInst.pPerfCounters = PERF_COUNTER_BLOCK_FROM_INSTANCE( pInstance );
perfInst.pInstance = pInstance;
GetFullInstanceName(
pPerfData,
pInstance,
pPerfObject->CodePage,
perfInst.strInstanceName,
perfInst.strParentInstanceName );
vecPerfInstances.push_back( perfInst );
pInstance = NEXT_PERF_INSTANCE_DEFINITION( pInstance );
}
}
BOOL LoadObjects(
PPERF_DATA_BLOCK const pPerfDataBlock,
std::vector<PerfObject_t> & vecPerfObjects )
{
vecPerfObjects.clear();
PPERF_OBJECT_TYPE pPerfObject = FIRST_PERF_OBJECT_TYPE( pPerfDataBlock );
for( DWORD i(0); i < pPerfDataBlock->NumObjectTypes; ++i )
{
PerfObject_t perfObj;
perfObj.pPerfObject = pPerfObject;
LoadCounterDefs( pPerfObject, perfObj.vecPerfCounterDefs );
if( pPerfObject->NumInstances == 0 ||
pPerfObject->NumInstances == PERF_NO_INSTANCES )
{
// 没有实例对象
perfObj.pPerfCounters = PERF_COUNTER_BLOCK_FROM_OBJECT( pPerfObject );
}
else
{
LoadInstances( pPerfDataBlock, pPerfObject, perfObj.vecPerfInstances );
}
vecPerfObjects.push_back( perfObj );
pPerfObject = NEXT_PERF_OBJECT_TYPE( pPerfObject );
if( (LPBYTE)pPerfObject >= (LPBYTE)pPerfDataBlock + pPerfDataBlock->TotalByteLength ) break;
}
return TRUE;
}
BOOL LoadObjectData(
PPERF_DATA_BLOCK const pPerfDataBlock,
PerfData_t & perfData )
{
if( pPerfDataBlock == NULL ) return FALSE;
TCHAR szSubKey[0x400] = {0};
if( !(pPerfDataBlock->Signature[0] == L'P' &&
pPerfDataBlock->Signature[1] == L'E' &&
pPerfDataBlock->Signature[2] == L'R' &&
pPerfDataBlock->Signature[3] == L'F' ) )
{
return FALSE;
}
return LoadObjects( pPerfDataBlock, perfData.vecPerfObjects );
}
DWORD GetNumberOfTextEntries(LPCTSTR lpszSource)
{
DWORD dwEntries = 0;
DWORD dwSize = sizeof(DWORD);
HKEY hKey = NULL;
do
{
LRESULT lResult = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
_T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib"),
0,
KEY_READ,
&hKey );
if( lResult != ERROR_SUCCESS ) break;
lResult = RegQueryValueEx(
hKey,
lpszSource,
NULL,
0,
(LPBYTE)&dwEntries,
&dwSize );
if( lResult != ERROR_SUCCESS ) break;
}while(false);
if( hKey ) RegCloseKey( hKey );
return dwEntries;
}
enum ETrafficType // (查 mapCounters 表可得知)
{
EAllTraffic = 388, // 总的流量
EIncomingTraffic = 264, // 输入流量
EOutGoingTraffic = 506 // 输出流量
};
LSTATUS GetRegDWORDValue( HKEY hRootKey, CString strPath, CString strValueName, DWORD & dwValue )
{
HKEY hKey;
LSTATUS lStatus;
do
{
lStatus = RegOpenKey(
hRootKey,
strPath,
&hKey );
if( lStatus != ERROR_SUCCESS ) break;
DWORD dwLen = sizeof(DWORD);
lStatus = RegQueryValueEx(
hKey,
strValueName,
NULL,
NULL,
reinterpret_cast<LPBYTE>(&dwValue),
&dwLen );
} while (false);
if( hKey != NULL ) RegCloseKey( hKey );
return lStatus;
}
LSTATUS GetRegStringValue( HKEY hRootKey, CString strPath, CString strValueName, CString & strValue )
{
HKEY hKey;
LSTATUS lStatus;
do
{
lStatus = RegOpenKey(
hRootKey,
strPath,
&hKey );
if( lStatus != ERROR_SUCCESS ) break;
DWORD dwMaxValueLen;
lStatus = RegQueryInfoKey(
hKey,
NULL,
NULL,
0,
NULL,
NULL,
NULL,
NULL,
NULL,
&dwMaxValueLen,
NULL,
NULL );
if( lStatus != ERROR_SUCCESS ) break;
lStatus = RegQueryValueEx(
hKey,
strValueName,
NULL,
NULL,
reinterpret_cast<LPBYTE>(strValue.GetBuffer( dwMaxValueLen / sizeof(TCHAR) )),
&dwMaxValueLen );
strValue.ReleaseBuffer();
} while (false);
if( hKey != NULL ) RegCloseKey( hKey );
return lStatus;
}
void FixInstanceName( std::tstring & name )
{
name = boost::xpressive::regex_replace(
name,
boost::xpressive::basic_regex<std::tstring::const_iterator>::compile( _T("\\W") ),
_T("") );
boost::erase_all( name, _T("_") );
}
LSTATUS GetApaptersIsHardwareList( std::map<std::tstring, BOOL> & map )
{
map.clear();
LSTATUS lStatus = 0;
HKEY hKey = NULL;
do
{
CString strRootPath = _T("SYSTEM\\ControlSet001\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}");
// 打开适配器的注册表路径
lStatus = RegOpenKey(
HKEY_LOCAL_MACHINE,
strRootPath,
&hKey );
if( lStatus != ERROR_SUCCESS ) break;
// 获得子键数目和子值最大字节数
DWORD dwSubKeys;
DWORD dwMaxKeyNameLen;
lStatus = RegQueryInfoKey(
hKey,
NULL,
NULL,
0,
&dwSubKeys,
&dwMaxKeyNameLen,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL );
if( lStatus != ERROR_SUCCESS ) break;
for( DWORD i(0); i < dwSubKeys; ++i )
{
CString strSubKeyName;
lStatus = RegEnumKey(
hKey,
i,
strSubKeyName.GetBuffer( dwMaxKeyNameLen ),
dwMaxKeyNameLen );
strSubKeyName.ReleaseBuffer();
if( lStatus != ERROR_SUCCESS ) break;
CString strAdapterPath = (strRootPath + CString(_T("\\")) + strSubKeyName);
/*
// 方法一: 获得 DeviceInstanceId
CString strDeviceInstanceId;
lStatus = GetRegStringValue( HKEY_LOCAL_MACHINE, strAdapterPath, _T("DeviceInstanceID"), strDeviceInstanceId );
if( lStatus != ERROR_SUCCESS ) break;
*/
// 方法一: 获得 Characteristics
DWORD dwCharacteristics;
lStatus = GetRegDWORDValue( HKEY_LOCAL_MACHINE, strAdapterPath, _T("Characteristics"), dwCharacteristics );
if( lStatus != ERROR_SUCCESS ) break;
// 获得驱动描述
CString strDriverDesc;
lStatus = GetRegStringValue( HKEY_LOCAL_MACHINE, strAdapterPath, _T("DriverDesc"), strDriverDesc );
if( lStatus == ERROR_SUCCESS )
{
std::tstring tsDriverDesc = strDriverDesc;
FixInstanceName( tsDriverDesc );
/*
// 方法一: 如果 DeviceInstanceId 是以 USB\\ 或 PCI\\ 开头的, 则认为其为物理适配器
map[tsDriverDesc] =
( strDeviceInstanceId.Left( 4 ).CompareNoCase(_T("USB\\")) == 0 ||
strDeviceInstanceId.Left( 4 ).CompareNoCase(_T("PCI\\")) == 0 );
*/
// 方法二: 判断 Characteristics(特征) 中是否含有 NCF_PHYSICAL 标志
map[tsDriverDesc] = ( dwCharacteristics & 0x4 ); // NCF_PHYSICAL
}
}
}while(false);
return lStatus;
}
void PrintObjectNames(
std::basic_ostream<TCHAR, std::char_traits<TCHAR> > & os,
const PerfData_t & perfData,
const std::map<DWORD, CString> & mapCounters,
const std::map<DWORD, CString> & mapHelps )
{
typedef boost::basic_format<TCHAR> format_t;
typedef std::map< DWORD, DWORD > map_traffics_t;
typedef std::map<std::tstring, map_traffics_t > map_inst_traffics_t;
static map_inst_traffics_t map_inst_traffics; // 用于保存上一次的流量数据
for( size_t i = 0; i < perfData.vecPerfObjects.size(); ++i )
{
const PerfObject_t & perfObject = perfData.vecPerfObjects[i];
DWORD dwIndex = perfObject.pPerfObject->ObjectNameTitleIndex;
DWORD dwTotalIn = 0, dwTotalOut = 0;
if( perfObject.vecPerfInstances.size() == 0 )
{
// 如果不是网络适配器(不同的协议种类),那么就不统计
continue;
}
else
{
for( size_t j = 0; j < perfObject.vecPerfInstances.size(); ++j )
{
std::tstring strInstanceName = perfObject.vecPerfInstances[j].strInstanceName;
FixInstanceName( strInstanceName );
// 修正名字(耗资源)
os << format_t( _T("%1%(%2%)\n") )
% perfObject.vecPerfInstances[j].strParentInstanceName.GetString()
% perfObject.vecPerfInstances[j].strInstanceName.GetString();
BOOL bIsPhysicalAdapter = FALSE;
auto iterPhy = g_mapPhys.find( strInstanceName );
if( iterPhy != g_mapPhys.end() )
{
bIsPhysicalAdapter = iterPhy->second;
}
PPERF_COUNTER_BLOCK pPerfCounter = perfObject.vecPerfInstances[j].pPerfCounters;
DWORD dwAllTraffic = 0, dwIncomingTraffic = 0, dwOutGoingTraffic = 0;
for( size_t k = 0; k < perfObject.vecPerfCounterDefs.size(); ++k )
{
DWORD dwCounterVal = GET_COUNTER_VALUE_DWORD( pPerfCounter, perfObject.vecPerfCounterDefs[k] );
dwIndex = perfObject.vecPerfCounterDefs[k]->CounterNameTitleIndex;
switch( dwIndex )
{
case EAllTraffic: dwAllTraffic = dwCounterVal; break;
case EIncomingTraffic: dwIncomingTraffic = dwCounterVal; break;
case EOutGoingTraffic: dwOutGoingTraffic = dwCounterVal; break;
}
}
if( map_inst_traffics.count(strInstanceName ) )
{
if( map_inst_traffics[strInstanceName].size() != 0 )
{
DWORD dwIn = dwIncomingTraffic - map_inst_traffics[strInstanceName].at(EIncomingTraffic);
DWORD dwOut = dwOutGoingTraffic - map_inst_traffics[strInstanceName].at(EOutGoingTraffic);
if( bIsPhysicalAdapter )
{
dwTotalIn += dwIn;
dwTotalOut += dwOut;
}
format_t fmt( _T(" | %s:%|.2f| KB/S - %s:%|.2f| KB/S\n") );
fmt % mapCounters.at(EIncomingTraffic).GetString()
% ( dwIn / 1024.0f )
% mapCounters.at(EOutGoingTraffic).GetString()
% ( dwOut / 1024.0f );
os << fmt.str();
}
}
map_traffics_t map_traffics;
map_traffics[EAllTraffic] = dwAllTraffic;
map_traffics[EIncomingTraffic] = dwIncomingTraffic;
map_traffics[EOutGoingTraffic] = dwOutGoingTraffic;
map_inst_traffics[strInstanceName] = map_traffics;
}
}
// 总流量*
os << _T(" ==== Total ==== ") << std::endl;
format_t fmt( _T(" | %s:%|.2f| KB/S - %s:%|.2f| KB/S\n") );
fmt % mapCounters.at(EIncomingTraffic).GetString()
% ( dwTotalIn / 1024.0f )
% mapCounters.at(EOutGoingTraffic).GetString()
% ( dwTotalOut / 1024.0f );
os << fmt.str();
}
}
int _tmain()
{
setlocale(LC_ALL,"");
// 获得计数器名字和帮助
GetCounters( g_mapCounters );
GetHelps( g_mapHelps );
GetApaptersIsHardwareList( g_mapPhys );
while( true )
{
std::vector<BYTE> vecPerfDataBlock = GetRegValueData(510);
PPERF_DATA_BLOCK pPerfDataBlock = (PPERF_DATA_BLOCK)vecPerfDataBlock.data();
std::list<PERF_OBJECT_TYPE> vecRefObjType;
EnumPerfObject( (PPERF_DATA_BLOCK)vecPerfDataBlock.data(), vecRefObjType );
PerfData_t perfData;
LoadObjectData( pPerfDataBlock, perfData );
PrintObjectNames(
#ifdef UNICODE
std::wcout
#else
std::cout
#endif
, perfData, g_mapCounters, g_mapHelps );
Sleep(1000);
system("cls");
}
getchar();
return 0;
}
WINDOWS网络流量监控(区分物理网卡)(Win32)
最新推荐文章于 2024-07-26 10:43:05 发布