Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3825 lines
98 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // TaskMan - NT TaskManager
  4. // Copyright (C) Microsoft
  5. //
  6. // File: netpage.cpp
  7. //
  8. // History: Oct-18-2000 Olaf Miller Created
  9. //
  10. //--------------------------------------------------------------------------
  11. #include "precomp.h"
  12. #define MIN_GRAPH_HEIGHT 120
  13. #define SCROLLBAR_WIDTH 17
  14. #define INVALID_VALUE 0xFFFFFFFF
  15. #define PERCENT_SHIFT 10000000
  16. #define PERCENT_DECIMAL_POINT 7
  17. //
  18. // Determines how the graphs are drawen (zoomed level)
  19. //
  20. static int g_NetScrollamount = 0;
  21. extern WCHAR g_szG[];
  22. extern WCHAR g_szM[];
  23. extern WCHAR g_szK[];
  24. extern WCHAR g_szZero[];
  25. extern WCHAR g_szPackets[];
  26. extern WCHAR g_szBitsPerSec[];
  27. extern WCHAR g_szScaleFont[SHORTSTRLEN];
  28. extern WCHAR g_szPercent[];
  29. extern WCHAR g_szNonOperational[];
  30. extern WCHAR g_szUnreachable[];
  31. extern WCHAR g_szDisconnected[];
  32. extern WCHAR g_szConnecting[];
  33. extern WCHAR g_szConnected[];
  34. extern WCHAR g_szOperational[];
  35. extern WCHAR g_szUnknownStatus[];
  36. extern WCHAR g_szGroupThousSep[];
  37. extern WCHAR g_szDecimal[];
  38. extern ULONG g_ulGroupSep;
  39. //
  40. // Window Proc the Network Tab
  41. //
  42. INT_PTR CALLBACK NetPageProc(
  43. HWND hwnd, // handle to dialog box
  44. UINT uMsg, // message
  45. WPARAM wParam, // first message parameter
  46. LPARAM lParam // second message parameter
  47. );
  48. //
  49. // Colors of the pens
  50. //
  51. static const COLORREF aNetColors[] =
  52. {
  53. RGB(255, 000, 0),
  54. RGB(255, 255, 0),
  55. RGB(000, 255, 0),
  56. };
  57. //
  58. // Default values for the Networking Page's statistics columns
  59. //
  60. struct
  61. {
  62. SHORT Format;
  63. SHORT Width;
  64. } NetColumnDefaults[NUM_NETCOLUMN] =
  65. {
  66. { LVCFMT_LEFT, 96 }, // COL_ADAPTERNAME
  67. { LVCFMT_LEFT, 96 }, // COL_ADAPTERDESC
  68. { LVCFMT_RIGHT, 96 }, // COL_NETWORKUTIL
  69. { LVCFMT_RIGHT, 60 }, // COL_LINKSPEED
  70. { LVCFMT_RIGHT, 96 }, // COL_STATE
  71. { LVCFMT_RIGHT, 70 }, // COL_BYTESSENTTHRU
  72. { LVCFMT_RIGHT, 70 }, // COL_BYTESRECTHRU
  73. { LVCFMT_RIGHT, 75 }, // COL_BYTESTOTALTHRU
  74. { LVCFMT_RIGHT, 70 }, // COL_BYTESSENT
  75. { LVCFMT_RIGHT, 70 }, // COL_BYTESREC
  76. { LVCFMT_RIGHT, 50 }, // COL_BYTESTOTAL
  77. { LVCFMT_RIGHT, 70 }, // COL_BYTESSENTPERINTER
  78. { LVCFMT_RIGHT, 70 }, // COL_BYTESRECPERINTER
  79. { LVCFMT_RIGHT, 70 }, // COL_BYTESTOTALPERINTER
  80. { LVCFMT_RIGHT, 70 }, // COL_UNICASTSSSENT
  81. { LVCFMT_RIGHT, 70 }, // COL_UNICASTSREC
  82. { LVCFMT_RIGHT, 50 }, // COL_UNICASTSTOTAL
  83. { LVCFMT_RIGHT, 70 }, // COL_UNICASTSSENTPERINTER
  84. { LVCFMT_RIGHT, 70 }, // COL_UNICASTSRECPERINTER
  85. { LVCFMT_RIGHT, 70 }, // COL_UNICASTSTOTALPERINTER
  86. { LVCFMT_RIGHT, 70 }, // COL_NONUNICASTSSSENT
  87. { LVCFMT_RIGHT, 70 }, // COL_NONUNICASTSREC
  88. { LVCFMT_RIGHT, 50 }, // COL_NONUNICASTSTOTAL
  89. { LVCFMT_RIGHT, 70 }, // COL_NONUNICASTSSENTPERINTER
  90. { LVCFMT_RIGHT, 70 }, // COL_NONUNICASTSRECPERINTER
  91. { LVCFMT_RIGHT, 70 }, // COL_NONUNICASTSTOTALPERINTER
  92. };
  93. //
  94. // List of the name of the columns. These strings appear in the column header
  95. //
  96. static const _aIDNetColNames[NUM_NETCOLUMN] =
  97. {
  98. IDS_COL_ADAPTERNAME,
  99. IDS_COL_ADAPTERDESC,
  100. IDS_COL_NETWORKUTIL,
  101. IDS_COL_LINKSPEED,
  102. IDS_COL_STATE,
  103. IDS_COL_BYTESSENTTHRU,
  104. IDS_COL_BYTESRECTHRU,
  105. IDS_COL_BYTESTOTALTHRU,
  106. IDS_COL_BYTESSENT,
  107. IDS_COL_BYTESREC,
  108. IDS_COL_BYTESTOTAL,
  109. IDS_COL_BYTESSENTPERINTER,
  110. IDS_COL_BYTESRECPERINTER,
  111. IDS_COL_BYTESTOTALPERINTER,
  112. IDS_COL_UNICASTSSSENT,
  113. IDS_COL_UNICASTSREC,
  114. IDS_COL_UNICASTSTOTAL,
  115. IDS_COL_UNICASTSSENTPERINTER,
  116. IDS_COL_UNICASTSRECPERINTER,
  117. IDS_COL_UNICASTSTOTALPERINTER,
  118. IDS_COL_NONUNICASTSSSENT,
  119. IDS_COL_NONUNICASTSREC,
  120. IDS_COL_NONUNICASTSTOTAL,
  121. IDS_COL_NONUNICASTSSENTPERINTER,
  122. IDS_COL_NONUNICASTSRECPERINTER,
  123. IDS_COL_NONUNICASTSTOTALPERINTER,
  124. };
  125. //
  126. // List of window checkbox IDs. These check boxes appear in the Select a column diaglog box.
  127. //
  128. const int g_aNetDlgColIDs[] =
  129. {
  130. IDC_ADAPTERNAME,
  131. IDC_ADAPTERDESC,
  132. IDC_NETWORKUTIL,
  133. IDC_LINKSPEED,
  134. IDC_STATE,
  135. IDC_BYTESSENTTHRU,
  136. IDC_BYTESRECTHRU,
  137. IDC_BYTESTOTALTHRU,
  138. IDC_BYTESSENT,
  139. IDC_BYTESREC,
  140. IDC_BYTESTOTAL,
  141. IDC_BYTESSENTPERINTER,
  142. IDC_BYTESRECPERINTER,
  143. IDC_BYTESTOTALPERINTER,
  144. IDC_UNICASTSSSENT,
  145. IDC_UNICASTSREC,
  146. IDC_UNICASTSTOTAL,
  147. IDC_UNICASTSSENTPERINTER,
  148. IDC_UNICASTSRECPERINTER,
  149. IDC_UNICASTSTOTALPERINTER,
  150. IDC_NONUNICASTSSSENT,
  151. IDC_NONUNICASTSREC,
  152. IDC_NONUNICASTSTOTAL,
  153. IDC_NONUNICASTSSENTPERINTER,
  154. IDC_NONUNICASTSRECPERINTER,
  155. IDC_NONUNICASTSTOTALPERINTER,
  156. };
  157. /*++
  158. Routine Description:
  159. Changes the size of an array. Allocates new memory for the array and
  160. copies the data in the old array to the new array. If the new array is
  161. larger then the old array the extra memory is zeroed out.
  162. Arguments:
  163. ppSrc -- Pointer to the source array.
  164. dwNewSize -- The size (in bytes) of the new array.
  165. Return Value:
  166. HRESULT
  167. Revision History:
  168. 1-6-2000 Created by omiller
  169. --*/
  170. HRESULT ChangeArraySize(LPVOID *ppSrc, DWORD dwNewSize)
  171. {
  172. if( ppSrc == NULL )
  173. {
  174. return E_INVALIDARG;
  175. }
  176. if( NULL == *ppSrc )
  177. {
  178. //
  179. // The array is empty. Allocate new space for it,
  180. //
  181. *ppSrc = (LPVOID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwNewSize);
  182. if( NULL == *ppSrc )
  183. {
  184. return E_OUTOFMEMORY;
  185. }
  186. }
  187. else
  188. {
  189. LPVOID pTmp;
  190. //
  191. // The array contains data. Allocate new memory for it and copy over the data in the array.
  192. // If the new array is larger then the old array the extra memory is zeroed out.
  193. //
  194. pTmp = (LPVOID)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *ppSrc, dwNewSize);
  195. if( pTmp )
  196. {
  197. *ppSrc = pTmp;
  198. }
  199. else
  200. {
  201. return E_OUTOFMEMORY;
  202. }
  203. }
  204. return S_OK;
  205. }
  206. /*++
  207. Routine Description:
  208. Initialize all of the CAdapter class members. The CAdapter class
  209. use the Ip Helper api's to collect information about the Network
  210. adapters on the local system.
  211. Arguments:
  212. NONE
  213. Return Value:
  214. VOID
  215. Revision History:
  216. 1-6-2000 Created by omiller
  217. --*/
  218. CAdapter::CAdapter()
  219. {
  220. m_dwAdapterCount = 0;
  221. m_ppaiAdapterStats = NULL;
  222. m_pifTable = NULL;
  223. m_bToggle = 0;
  224. m_dwLastReportedNumberOfAdapters = 0;
  225. }
  226. /*++
  227. Routine Description:
  228. Adds any new adapters reported by the IPHLPAPI and removes any old adapters
  229. that are no longer reported by the IPHLPAPI
  230. Arguments:
  231. void
  232. Return Value:
  233. HRESULT
  234. Revision History:
  235. 1-6-2000 Created by omiller
  236. --*/
  237. HRESULT CAdapter::RefreshAdapterTable()
  238. {
  239. DWORD dwSize;
  240. DWORD dwRetVal;
  241. BOOLEAN bFound;
  242. HRESULT hr;
  243. LONG i, j;
  244. //
  245. // Get the list of active adapters
  246. //
  247. do
  248. {
  249. //
  250. // Determine the size of the adapter array
  251. //
  252. if ( NULL != m_pifTable )
  253. {
  254. dwSize = (DWORD) HeapSize( GetProcessHeap(), 0, m_pifTable );
  255. }
  256. else
  257. {
  258. dwSize = 0;
  259. }
  260. //
  261. // Collect all of the adapter information for all adapters (WAN and LAN)
  262. //
  263. dwRetVal = GetInterfaceInfo(m_pifTable, &dwSize);
  264. switch(dwRetVal)
  265. {
  266. case ERROR_INSUFFICIENT_BUFFER:
  267. //
  268. // The array is to small. Need to make it bigger and try again.
  269. //
  270. hr = ChangeArraySize( (LPVOID *) &m_pifTable, dwSize );
  271. if( FAILED(hr) )
  272. {
  273. // Unable to expand the size of the array
  274. //
  275. return hr;
  276. }
  277. break;
  278. case NO_ERROR:
  279. //
  280. // Everything is happy
  281. //
  282. break;
  283. case ERROR_MORE_DATA: // Error code 234
  284. // For some reason this error message means that there are no adapters. BUG?
  285. //
  286. m_dwAdapterCount = 0;
  287. return S_FALSE;
  288. default:
  289. // Something went wrong fail.
  290. //
  291. m_dwAdapterCount = 0;
  292. return E_FAIL;
  293. }
  294. }
  295. while(dwRetVal);
  296. //
  297. // Fixed Bug: 669937 Av in taskmgr !CAdapter::RefreshAdapterTable
  298. // Determine which adapters are common in both lists.
  299. //
  300. for(i=0; i<(LONG)m_dwAdapterCount; i++)
  301. {
  302. for(j=0, bFound = FALSE; bFound == FALSE && j<m_pifTable->NumAdapters; j++)
  303. {
  304. if( m_ppaiAdapterStats[i]->ifRowStartStats.dwIndex == m_pifTable->Adapter[j].Index )
  305. {
  306. m_pifTable->Adapter[j].Index = INVALID_VALUE;
  307. bFound = TRUE;
  308. }
  309. }
  310. if( !bFound )
  311. {
  312. if( m_dwAdapterCount > (DWORD)(i+1))
  313. {
  314. memmove(&m_ppaiAdapterStats[i],&m_ppaiAdapterStats[i+1],(m_dwAdapterCount - (i+1)) * sizeof(ADAPTER_INFOEX));
  315. }
  316. m_dwAdapterCount--;
  317. i--;
  318. }
  319. }
  320. //
  321. // Add any new adapters
  322. //
  323. hr = ChangeArraySize( (LPVOID *) &m_ppaiAdapterStats, sizeof(ADAPTER_INFOEX) * min(m_pifTable->NumAdapters,MAX_ADAPTERS));
  324. for(i=0; SUCCEEDED(hr) && i<m_pifTable->NumAdapters; i++)
  325. {
  326. if( m_pifTable->Adapter[i].Index != INVALID_VALUE )
  327. {
  328. hr = InitializeAdapter( &m_ppaiAdapterStats[ m_dwAdapterCount++ ], &m_pifTable->Adapter[ i ] );
  329. }
  330. }
  331. if( FAILED(hr) )
  332. {
  333. m_dwAdapterCount = 0;
  334. }
  335. return hr;
  336. }
  337. /*++
  338. Routine Description:
  339. Update the connection names of the network adapter. This function is only called when the
  340. user selects the refresh menu item. The connection rarely change, so it would be a waste of
  341. time to update the connection name every time the get the adapter statistics.
  342. Arguments:
  343. void
  344. Return Value:
  345. HRESULT
  346. Revision History:
  347. 1-6-2000 Created by omiller
  348. --*/
  349. void CAdapter::RefreshConnectionNames()
  350. {
  351. //
  352. // Update the connection name for each adapter in out list
  353. //
  354. for(DWORD dwAdapter=0; dwAdapter < m_dwAdapterCount; dwAdapter++)
  355. {
  356. GetConnectionName( m_ppaiAdapterStats[dwAdapter]->wszGuid
  357. , m_ppaiAdapterStats[dwAdapter]->wszConnectionName
  358. , ARRAYSIZE(m_ppaiAdapterStats[dwAdapter]->wszConnectionName)
  359. );
  360. }
  361. }
  362. /*++
  363. Routine Description:
  364. Get the connection name of an adapter.
  365. Arguments:
  366. pwszAdapterGuid -- The guid of the adapter
  367. pwszConnectionName -- returns the connection name of the adapter
  368. Return Value:
  369. HRESULT
  370. Revision History:
  371. 1-6-2000 Created by omiller
  372. --*/
  373. HRESULT CAdapter::GetConnectionName(LPWSTR pwszAdapterGuid, LPWSTR pwszConnectionName, DWORD cchConnectionName)
  374. {
  375. GUID IfGuid;
  376. WCHAR wszConnName[MAXLEN_IFDESCR+1];
  377. DWORD Size;
  378. DWORD dwRetVal;
  379. HRESULT hr;
  380. //
  381. // Make sure the string is NULL terminated
  382. //
  383. Size = sizeof(wszConnName) - sizeof(WCHAR);
  384. wszConnName[MAXLEN_IFDESCR] = L'\0';
  385. //
  386. // Convert the GUID into a string
  387. //
  388. hr = CLSIDFromString( pwszAdapterGuid, &IfGuid );
  389. if( SUCCEEDED(hr) )
  390. {
  391. //
  392. // Use the private IPHLPAPI to get the connection name of the device. Size is the size fo the buffer,
  393. // not the number of chars
  394. //
  395. dwRetVal = NhGetInterfaceNameFromDeviceGuid(&IfGuid, wszConnName, &Size, FALSE, TRUE);
  396. if( NO_ERROR == dwRetVal )
  397. {
  398. StringCchCopy(pwszConnectionName, cchConnectionName, wszConnName);
  399. return S_OK;
  400. }
  401. }
  402. return E_FAIL;
  403. }
  404. /*++
  405. Routine Description:
  406. Initialize the adapter information. i.e. get the adapter name, guid, adapter description and the initial
  407. adapter statistics (bytes sent, bytes recieved etc)
  408. Arguments:
  409. ppaiAdapterStats -- Adapter to initialize
  410. pAdapterDescription -- Information about the adapter (Index and Adapter GUID)
  411. Return Value:
  412. HRESULT
  413. Revision History:
  414. 1-6-2000 Created by omiller
  415. --*/
  416. HRESULT CAdapter::InitializeAdapter(PPADAPTER_INFOEX ppaiAdapterStats, PIP_ADAPTER_INDEX_MAP pAdapterDescription)
  417. {
  418. DWORD dwRetVal;
  419. HRESULT hr;
  420. INT iAdapterNameLength;
  421. if( !ppaiAdapterStats || !pAdapterDescription)
  422. {
  423. return E_INVALIDARG;
  424. }
  425. if( NULL == *ppaiAdapterStats )
  426. {
  427. //
  428. // This slot was never used before, we need to allocate memory for it
  429. //
  430. *ppaiAdapterStats = (PADAPTER_INFOEX) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(**ppaiAdapterStats) );
  431. }
  432. if( *ppaiAdapterStats )
  433. {
  434. //
  435. // Initialize the adapter by filling in all the adapter values.
  436. //
  437. (*ppaiAdapterStats)->ifRowStartStats.dwIndex = (DWORD)pAdapterDescription->Index;
  438. // Get the initial statistics for this adapter
  439. //
  440. dwRetVal = GetIfEntry( &(*ppaiAdapterStats)->ifRowStartStats );
  441. if( NO_ERROR == dwRetVal )
  442. {
  443. if( (*ppaiAdapterStats)->ifRowStartStats.dwType == MIB_IF_TYPE_PPP ||
  444. (*ppaiAdapterStats)->ifRowStartStats.dwType == MIB_IF_TYPE_SLIP)
  445. {
  446. // We only need to adjust the link speed of modems since they compress data causing
  447. // network utilization to exceed 100%. The link speed of modems also changes during a
  448. // connection but the IPHLPAPIs do not report this change.
  449. //
  450. (*ppaiAdapterStats)->bAdjustLinkSpeed = TRUE;
  451. }
  452. else
  453. {
  454. (*ppaiAdapterStats)->bAdjustLinkSpeed = FALSE;
  455. }
  456. //
  457. // Initialize the adapter values. The start current and last stats are all the same at the start
  458. //
  459. memcpy( &(*ppaiAdapterStats)->ifRowStats[0], &(*ppaiAdapterStats)->ifRowStartStats, sizeof((*ppaiAdapterStats)->ifRowStats[0]) );
  460. memcpy( &(*ppaiAdapterStats)->ifRowStats[1], &(*ppaiAdapterStats)->ifRowStartStats, sizeof((*ppaiAdapterStats)->ifRowStats[1]) );
  461. memset( &(*ppaiAdapterStats)->ulHistory[0], INVALID_VALUE, sizeof((*ppaiAdapterStats)->ulHistory[0]) );
  462. memset( &(*ppaiAdapterStats)->ulHistory[1], INVALID_VALUE, sizeof((*ppaiAdapterStats)->ulHistory[1]) );
  463. mbstowcs( (*ppaiAdapterStats)->wszDesc, (LPCSTR)(*ppaiAdapterStats)->ifRowStartStats.bDescr, ARRAYSIZE((*ppaiAdapterStats)->wszDesc) );
  464. //
  465. // Extract the Device guid of the adapter
  466. //
  467. hr = E_FAIL;
  468. iAdapterNameLength = lstrlen(pAdapterDescription->Name);
  469. if( iAdapterNameLength >= GUID_STR_LENGTH )
  470. {
  471. // The Guid is the last GUID_STR_LENGTH chars in the name. Get the guid and from the guid get the connection name
  472. //
  473. StringCchCopy( (*ppaiAdapterStats)->wszGuid
  474. , ARRAYSIZE((*ppaiAdapterStats)->wszGuid)
  475. , &pAdapterDescription->Name[iAdapterNameLength - GUID_STR_LENGTH]
  476. );
  477. hr = GetConnectionName( (*ppaiAdapterStats)->wszGuid
  478. , (*ppaiAdapterStats)->wszConnectionName
  479. , ARRAYSIZE((*ppaiAdapterStats)->wszConnectionName)
  480. );
  481. }
  482. if( FAILED(hr) )
  483. {
  484. //
  485. // We were unable to get the connection name, use the adapter description as the connection name
  486. //
  487. StringCchCopy( (*ppaiAdapterStats)->wszConnectionName
  488. , ARRAYSIZE((*ppaiAdapterStats)->wszConnectionName)
  489. , (*ppaiAdapterStats)->wszDesc
  490. );
  491. }
  492. return S_OK;
  493. }
  494. }
  495. return E_OUTOFMEMORY;
  496. }
  497. /*++
  498. Routine Description:
  499. Adjusts the link speed of an adapter. Modems change link speed during a connection and the also
  500. compress data. This often causes taskmgr to report network utilization greater than 100%. To avoid
  501. confusing the user modems use the max link speed that taskmgr sees. If the link speed changes
  502. the adapters graph is adjusted to reflect the change in link speed.
  503. Arguments:
  504. pAdapterInfo -- Adapter whos link speed needs to be adjusted.
  505. Return Value:
  506. void
  507. Revision History:
  508. 1-6-2000 Created by omiller
  509. --*/
  510. void CAdapter::AdjustLinkSpeed(PADAPTER_INFOEX pAdapterInfo)
  511. {
  512. if( pAdapterInfo && pAdapterInfo->ullTickCountDiff)
  513. {
  514. ULONGLONG ullBitsPerSecond;
  515. ULONGLONG ullBytesMoved;
  516. // Compute the total number of bits moved in this interval
  517. //
  518. ullBytesMoved = (pAdapterInfo->ifRowStats[m_bToggle].dwInOctets + pAdapterInfo->ifRowStats[m_bToggle].dwOutOctets) -
  519. (pAdapterInfo->ifRowStats[!m_bToggle].dwInOctets + pAdapterInfo->ifRowStats[!m_bToggle].dwOutOctets);
  520. // Compute the real link speed. Modems lie about there link speed based on the number of bytes moved in this interval
  521. //
  522. ullBitsPerSecond = ullBytesMoved * 8 * 1000 / pAdapterInfo->ullTickCountDiff;
  523. // Memorize and use the highest link speed
  524. //
  525. pAdapterInfo->ifRowStats[m_bToggle].dwSpeed = (DWORD) max( max( ullBitsPerSecond, pAdapterInfo->ullLinkspeed )
  526. , pAdapterInfo->ifRowStats[m_bToggle].dwSpeed
  527. );
  528. if( pAdapterInfo->ullLinkspeed == 0 )
  529. {
  530. // First time run, no need to adjust the graphs
  531. //
  532. pAdapterInfo->ullLinkspeed = (DWORD) pAdapterInfo->ifRowStats[m_bToggle].dwSpeed;
  533. }
  534. else if( pAdapterInfo->ullLinkspeed != pAdapterInfo->ifRowStats[m_bToggle].dwSpeed )
  535. {
  536. // Adjust the points on the adapters graphs to reflect the new link speed.
  537. //
  538. for(DWORD dwPoint=0; dwPoint<HIST_SIZE; dwPoint++)
  539. {
  540. if( pAdapterInfo->ulHistory[BYTES_RECEIVED_UTIL][dwPoint] != INVALID_VALUE )
  541. {
  542. pAdapterInfo->ulHistory[BYTES_RECEIVED_UTIL][dwPoint] = (ULONG)(pAdapterInfo->ulHistory[BYTES_RECEIVED_UTIL][dwPoint] * pAdapterInfo->ullLinkspeed / pAdapterInfo->ifRowStats[m_bToggle].dwSpeed);
  543. pAdapterInfo->ulHistory[BYTES_SENT_UTIL][dwPoint] = (ULONG)(pAdapterInfo->ulHistory[BYTES_SENT_UTIL][dwPoint] * pAdapterInfo->ullLinkspeed / pAdapterInfo->ifRowStats[m_bToggle].dwSpeed);
  544. }
  545. }
  546. // Remember the new linkspeed
  547. //
  548. pAdapterInfo->ullLinkspeed = (DWORD) pAdapterInfo->ifRowStats[m_bToggle].dwSpeed;
  549. }
  550. }
  551. }
  552. /*++
  553. Routine Description:
  554. Every few seconds this function is called to collect data about each of active network adapter
  555. (Adapter name, bytes sent, bytes received, unicasts packets sent, unicast packets received etc).
  556. The CAdapter class memorizes the first and last set of data that it collected. It does this so the
  557. user can determine i.e. the number of bytes sent between now and when taskmgr started and the number
  558. of bytes sent between now and the last interval. Furthermore it memorizes the length of the interval
  559. (in milliseconds)
  560. Arguments:
  561. bAdapterListChange -- Indicates if the adapters have been added or removed.
  562. Return Value:
  563. HRESULT
  564. Note:
  565. The current and last data is stored in a two dimentional array. When the data is collected the next
  566. time (i.e. when this function is called again), the Current data becomes the last data. Inorder to save time
  567. Current and last data are stored in a two dimensional array and m_bToggle is used to indicate which dimenstion
  568. is current (m_bToggle) and which is the last set of data (!m_bToggle).
  569. Revision History:
  570. 1-6-2000 Created by omiller
  571. --*/
  572. HRESULT CAdapter::Update(BOOLEAN & bAdapterListChange)
  573. {
  574. DWORD dwRetVal;
  575. DWORD dwNumberOfAdaptersReported = 0;
  576. HRESULT hr = S_OK;
  577. bAdapterListChange = FALSE;
  578. if( m_dwAdapterCount < MAX_ADAPTERS )
  579. {
  580. //
  581. // Check if there are any new adapters. If we already have 32 adapters don't bother, our list is full
  582. // If an Adapter is removed we will catch that later.
  583. //
  584. dwRetVal = GetNumberOfInterfaces( &dwNumberOfAdaptersReported );
  585. if( NO_ERROR == dwRetVal )
  586. {
  587. //
  588. // Make sure the number of interfaces is still the same. If not we need to update our interface table.
  589. //
  590. if( m_dwLastReportedNumberOfAdapters != dwNumberOfAdaptersReported )
  591. {
  592. //
  593. // The number of adapters changed, refresh our list
  594. //
  595. hr = RefreshAdapterTable();
  596. bAdapterListChange = TRUE;
  597. m_dwLastReportedNumberOfAdapters = dwNumberOfAdaptersReported;
  598. }
  599. }
  600. else
  601. {
  602. //
  603. // Unknow error, abort
  604. //
  605. hr = E_FAIL;
  606. }
  607. }
  608. if( SUCCEEDED(hr) )
  609. {
  610. m_bToggle = !m_bToggle;
  611. // Get the statistics for each adapter
  612. //
  613. for(DWORD dwAdapter=0; dwAdapter < m_dwAdapterCount; dwAdapter++)
  614. {
  615. dwRetVal = GetIfEntry(&m_ppaiAdapterStats[dwAdapter]->ifRowStats[m_bToggle]);
  616. if( NO_ERROR == dwRetVal )
  617. {
  618. // Compute the sampling interval for this adapter. If it the first run make sure delta time is 0
  619. // Advance the adapter's throughput history
  620. //
  621. ULONGLONG ullTickCount = GetTickCount();
  622. m_ppaiAdapterStats[dwAdapter]->ullTickCountDiff
  623. = ullTickCount - (m_ppaiAdapterStats[dwAdapter]->ullLastTickCount ? m_ppaiAdapterStats[dwAdapter]->ullLastTickCount : ullTickCount);
  624. m_ppaiAdapterStats[dwAdapter]->ullLastTickCount = ullTickCount;
  625. m_ppaiAdapterStats[dwAdapter]->ifRowStartStats.dwSpeed = m_ppaiAdapterStats[dwAdapter]->ifRowStats[m_bToggle].dwSpeed;
  626. if( m_ppaiAdapterStats[dwAdapter]->bAdjustLinkSpeed )
  627. {
  628. AdjustLinkSpeed(m_ppaiAdapterStats[dwAdapter]);
  629. }
  630. AdvanceAdapterHistory(dwAdapter);
  631. }
  632. else if( ERROR_INVALID_DATA == dwRetVal )
  633. {
  634. // The adapter is no longer active. When the list is refreshed the adapter will be removed.
  635. //
  636. bAdapterListChange = TRUE;
  637. }
  638. else
  639. {
  640. // Something went wrong abort
  641. //
  642. hr = E_FAIL;
  643. break;
  644. }
  645. }
  646. }
  647. if( bAdapterListChange )
  648. {
  649. // Our adapter list is not uptodate, adapters that were active are no longer active. Remove them from our list
  650. //
  651. hr = RefreshAdapterTable();
  652. }
  653. return hr;
  654. }
  655. /*++
  656. Routine Description:
  657. Adds commas into a number string to make it more readable
  658. Arguments:
  659. ullValue - Number to simplify
  660. pwsz - Buffer to store resulting string
  661. cchNumber -- size of the buffer pwsz.
  662. Return Value:
  663. String containing the simplified number
  664. Revision History:
  665. 1-6-2000 Created by omiller
  666. --*/
  667. WCHAR * CNetPage::CommaNumber(ULONGLONG ullValue, WCHAR *pwsz, int cchNumber)
  668. {
  669. WCHAR wsz[100];
  670. NUMBERFMT nfmt;
  671. nfmt.NumDigits = 0;
  672. nfmt.LeadingZero = 0;
  673. nfmt.Grouping = UINT(g_ulGroupSep);
  674. nfmt.lpDecimalSep = g_szDecimal;
  675. nfmt.lpThousandSep = g_szGroupThousSep;
  676. nfmt.NegativeOrder = 0;
  677. _ui64tow(ullValue,wsz,10);
  678. GetNumberFormat(LOCALE_USER_DEFAULT,
  679. 0,
  680. wsz,
  681. &nfmt,
  682. pwsz,
  683. cchNumber);
  684. return pwsz;
  685. }
  686. /*++
  687. Routine Description:
  688. Simplifies a number by converting the number into Giga, Mega or Kilo
  689. Arguments:
  690. ullValue - Number to simplify
  691. psz - Buffer to store resulting string
  692. bBytes - Indicates if the number is in bytes
  693. Return Value:
  694. String containing the simplified number
  695. Revision History:
  696. 1-6-2000 Created by omiller
  697. --*/
  698. WCHAR * CNetPage::SimplifyNumber(ULONGLONG ullValue, WCHAR *psz, DWORD cch)
  699. {
  700. ULONG ulDivValue=1;
  701. LPWSTR pwszUnit=L"";
  702. WCHAR wsz[100];
  703. // ullValue is not number of bytes so div by 10^X
  704. //
  705. if( ullValue >= 1000000000 )
  706. {
  707. ulDivValue = 1000000000;
  708. pwszUnit = g_szG;
  709. }
  710. else if( ullValue >= 1000000 )
  711. {
  712. ulDivValue = 1000000;
  713. pwszUnit = g_szM;
  714. }
  715. else if( ullValue >= 1000 )
  716. {
  717. ulDivValue = 1000;
  718. pwszUnit = g_szK;
  719. }
  720. //
  721. // Shown in the UI - don't care if these get chopped.
  722. //
  723. StringCchCopy( psz, cch, CommaNumber( ullValue / ulDivValue, wsz, ARRAYSIZE(wsz) ) );
  724. StringCchCat( psz, cch, L" " );
  725. StringCchCat( psz, cch, pwszUnit );
  726. return psz;
  727. }
  728. /*++
  729. Routine Description:
  730. Converts a floating point value (Stored as an integer shifted by PERCENT_SHIFT) into a string
  731. Arguments:
  732. ulValue - floating point value to convert
  733. psz - Buffer to store resulting string
  734. bDisplayDecimal - Indicates if the decimal value should be displayed.
  735. Return Value:
  736. String containg the Floating point string
  737. Revision History:
  738. 1-6-2000 Created by omiller
  739. --*/
  740. WCHAR * CNetPage::FloatToString(ULONGLONG ullValue, WCHAR *psz, DWORD cch, BOOLEAN bDisplayDecimal)
  741. {
  742. ULONGLONG ulDecimal = 0;
  743. ULONGLONG ulNumber = 0;
  744. WCHAR wsz[100];
  745. // Get the integer value of the number
  746. //
  747. ulNumber = ullValue / PERCENT_SHIFT;
  748. if( _ui64tow(ulNumber,wsz,10) )
  749. {
  750. StringCchCopy( psz, cch, wsz ); // Shown in UI - don't care if it gets chopped.
  751. if( ulNumber )
  752. {
  753. ullValue = ullValue - ulNumber * PERCENT_SHIFT;
  754. }
  755. if( !ulNumber || bDisplayDecimal)
  756. {
  757. ulDecimal = ullValue * 100 / PERCENT_SHIFT;
  758. if( ulDecimal && _ui64tow(ulDecimal,wsz,10) )
  759. {
  760. StringCchCat( psz, cch, g_szDecimal ); // Shown in UI - don't care if it gets chopped.
  761. if( ulDecimal < 10 )
  762. {
  763. StringCchCat( psz, cch, g_szZero ); // Shown in UI - don't care if it gets chopped.
  764. }
  765. if( wsz[1] == L'0' )
  766. {
  767. wsz[1] = L'\0';
  768. }
  769. StringCchCat( psz, cch, wsz ); // Shown in UI - don't care if it gets chopped.
  770. }
  771. }
  772. }
  773. return psz;
  774. }
  775. /*++
  776. Routine Description:
  777. Initialize the networking tab. This function always returns 1. The networking tab
  778. displays all active connections (LAN and WAN). If no connections are present when
  779. taskmgr is started, the Network tab should still be displayed (thus return 1) incase
  780. a connection is established after taskmgr has started. The network tab will detect any
  781. newly established connections.
  782. Arguments:
  783. None
  784. Return Value:
  785. 1
  786. Revision History:
  787. 1-6-2000 Created by omiller
  788. --*/
  789. BYTE InitNetInfo()
  790. {
  791. // The network page should always appear even if there are no Network Adapters currently present.
  792. //
  793. return 1;
  794. }
  795. /*++
  796. Routine Description:
  797. Uninitialize all CAdapter class members. Frees all memory that
  798. was allocated by the class.
  799. Arguments:
  800. NONE
  801. Return Value:
  802. VOID
  803. Revision History:
  804. 1-6-2000 Created by omiller
  805. --*/
  806. CAdapter::~CAdapter()
  807. {
  808. if( NULL != m_pifTable )
  809. {
  810. HeapFree( GetProcessHeap(), 0, m_pifTable );
  811. }
  812. if( 0 != m_dwAdapterCount )
  813. {
  814. DWORD dwSize;
  815. DWORD dwTotalAdapterCount;
  816. // Get the total size of the array and compute the number of entries in the array.
  817. // m_dwAdapterCount only indicates the adapters are active. The array could have been bigger
  818. // at one point. Free the memory for all the entries.
  819. //
  820. dwSize = (DWORD)(m_ppaiAdapterStats == NULL ? 0 : HeapSize(GetProcessHeap(),0,m_ppaiAdapterStats));
  821. dwTotalAdapterCount = dwSize / sizeof(PADAPTER_INFOEX);
  822. for(DWORD dwAdapter=0; dwAdapter < dwTotalAdapterCount; dwAdapter++)
  823. {
  824. if( m_ppaiAdapterStats[dwAdapter] )
  825. {
  826. HeapFree( GetProcessHeap(), 0, m_ppaiAdapterStats[ dwAdapter ]);
  827. }
  828. }
  829. HeapFree( GetProcessHeap(), 0, m_ppaiAdapterStats );
  830. }
  831. }
  832. /*++
  833. Routine Description:
  834. Returns the number active adapters. The IP helper functions
  835. provide information about physical and non-physical adapters
  836. (such as the Microsoft TCP loop back adapter).
  837. Arguments:
  838. NONE
  839. Return Value:
  840. Number of active adapters
  841. Revision History:
  842. 1-6-2000 Created by omiller
  843. --*/
  844. DWORD CAdapter::GetNumberOfAdapters()
  845. {
  846. return m_dwAdapterCount;
  847. }
  848. /*++
  849. Routine Description:
  850. Resets the initial data for all Network adapters. The CAdapter class collects
  851. information for all active network adapters (Bytes sent, bytes received, unicasts
  852. packets sent, unicast packets received etc). The class memorizes the first set of data
  853. for each adapter. This is done so that the user can determine the number of i.e. bytes
  854. sent from when taskmgr was first started. (i.e. the number of bytes seen now minuse the
  855. number of bytes seen when taskmgr was started). When the user selects the Reset option,
  856. this functions overwrites the initial data, collected when taskmgr started, with the
  857. current data.
  858. Arguments:
  859. NONE
  860. Return Value:
  861. S_OK
  862. Revision History:
  863. 1-6-2000 Created by omiller
  864. --*/
  865. HRESULT CAdapter::Reset()
  866. {
  867. for(DWORD dwAdapter=0; dwAdapter < m_dwAdapterCount; dwAdapter++)
  868. {
  869. // Overwrite the Start and Last stats with the Current stats
  870. //
  871. memcpy( &m_ppaiAdapterStats[dwAdapter]->ifRowStartStats
  872. , &m_ppaiAdapterStats[dwAdapter]->ifRowStats[m_bToggle]
  873. , sizeof(m_ppaiAdapterStats[dwAdapter]->ifRowStartStats)
  874. );
  875. memcpy( &m_ppaiAdapterStats[dwAdapter]->ifRowStats[!m_bToggle]
  876. , &m_ppaiAdapterStats[dwAdapter]->ifRowStats[m_bToggle]
  877. , sizeof(m_ppaiAdapterStats[dwAdapter]->ifRowStats[!m_bToggle])
  878. );
  879. }
  880. return S_OK;
  881. }
  882. /*++
  883. Routine Description:
  884. Extracts the text fields (i.e. connection name and description) from a specified adapter
  885. Arguments:
  886. deAdapter -- Adapter who text the caller wants
  887. nStatValue -- Specifies which field the caller wants i.e. (Name or description)
  888. Return Value:
  889. NULL -- if the adapter index is invalid or nStatValue is invalid
  890. Revision History:
  891. 1-6-2000 Created by omiller
  892. --*/
  893. LPWSTR CAdapter::GetAdapterText(DWORD dwAdapter, NETCOLUMNID nStatValue)
  894. {
  895. if( dwAdapter < m_dwAdapterCount )
  896. {
  897. switch(nStatValue)
  898. {
  899. case COL_ADAPTERNAME:
  900. // Get adapter name
  901. //
  902. return m_ppaiAdapterStats[dwAdapter]->wszConnectionName;
  903. case COL_ADAPTERDESC:
  904. // Get adapter description
  905. //
  906. return m_ppaiAdapterStats[dwAdapter]->wszDesc;
  907. case COL_STATE:
  908. switch(m_ppaiAdapterStats[dwAdapter]->ifRowStats[m_bToggle].dwOperStatus)
  909. {
  910. case IF_OPER_STATUS_NON_OPERATIONAL:
  911. return g_szNonOperational;
  912. case IF_OPER_STATUS_UNREACHABLE:
  913. return g_szUnreachable;
  914. case IF_OPER_STATUS_DISCONNECTED:
  915. return g_szDisconnected;
  916. case IF_OPER_STATUS_CONNECTING:
  917. return g_szConnecting;
  918. case IF_OPER_STATUS_CONNECTED:
  919. return g_szConnected;
  920. case IF_OPER_STATUS_OPERATIONAL:
  921. return g_szOperational;
  922. }
  923. return g_szUnknownStatus;
  924. }
  925. }
  926. return NULL;
  927. }
  928. /*++
  929. Routine Description:
  930. Get the Send/Receive Network utilization history for a specified adapter
  931. Arguments:
  932. deAdapter -- Adapter who text the caller wants
  933. nHistoryType -- BYTES_SENT_UTIL for send history
  934. BYTES_RECEIVED_UTIL for receive history
  935. Return Value:
  936. NULL -- if the adapter index is invalid or nStatValue is invalid
  937. Revision History:
  938. 1-6-2000 Created by omiller
  939. --*/
  940. ULONG * CAdapter::GetAdapterHistory(DWORD dwAdapter, ADAPTER_HISTORY nHistoryType)
  941. {
  942. if( dwAdapter < m_dwAdapterCount )
  943. {
  944. // Return the history
  945. //
  946. return m_ppaiAdapterStats[ dwAdapter ]->ulHistory[ nHistoryType ];
  947. }
  948. return NULL;
  949. }
  950. /*++
  951. Routine Description:
  952. Updates the Send/Received Network Utilization adapter history
  953. Arguments:
  954. dwAdapter -- Adapter Index
  955. Return Value:
  956. NONE
  957. Revision History:
  958. 1-6-2000 Created by omiller
  959. --*/
  960. BOOLEAN CAdapter::AdvanceAdapterHistory(DWORD dwAdapter)
  961. {
  962. ULONG *pulHistory;
  963. if( dwAdapter < m_dwAdapterCount )
  964. {
  965. // Shift the receive adapter history by one and add the new point
  966. //
  967. pulHistory = m_ppaiAdapterStats[ dwAdapter ]->ulHistory[ BYTES_RECEIVED_UTIL ];
  968. MoveMemory((LPVOID) (pulHistory + 1), (LPVOID) (pulHistory), sizeof(ULONG) * (HIST_SIZE - 1) );
  969. // Get and add the receive network utiliation
  970. //
  971. pulHistory[0] = (ULONG) GetAdapterStat(dwAdapter, COL_BYTESRECTHRU);
  972. // Shift the send adapter history by one and add the new point
  973. //
  974. pulHistory = m_ppaiAdapterStats[ dwAdapter ]->ulHistory[ BYTES_SENT_UTIL ];
  975. MoveMemory((LPVOID) (pulHistory + 1), (LPVOID) (pulHistory), sizeof(ULONG) * (HIST_SIZE - 1) );
  976. // Get and add the send network utilization
  977. //
  978. pulHistory[0] = (ULONG) GetAdapterStat(dwAdapter, COL_BYTESSENTTHRU);
  979. return TRUE;
  980. }
  981. return FALSE;
  982. }
  983. /*++
  984. Routine Description:
  985. Get the scale. The scale specifies the maximum value that is in the Adapters history.
  986. This value determines how the data is graphed.
  987. Arguments:
  988. dwAdapter -- Adapter Index
  989. Return Value:
  990. Maximum value in history
  991. Revision History:
  992. 1-6-2000 Created by omiller
  993. --*/
  994. DWORD CAdapter::GetScale(DWORD dwAdapter)
  995. {
  996. if( dwAdapter < m_dwAdapterCount )
  997. {
  998. return m_ppaiAdapterStats[ dwAdapter ]->dwScale;
  999. }
  1000. return 0;
  1001. }
  1002. /*++
  1003. Routine Description:
  1004. Set the scale. The scale specifies the maximum value that is in the Adapters history.
  1005. This value determines how the data is graphed.
  1006. Arguments:
  1007. dwAdapter -- Adapter Index
  1008. Return Value:
  1009. NONE
  1010. Revision History:
  1011. 1-6-2000 Created by omiller
  1012. --*/
  1013. void CAdapter::SetScale(DWORD dwAdapter, DWORD dwScale)
  1014. {
  1015. if( dwAdapter < m_dwAdapterCount )
  1016. {
  1017. m_ppaiAdapterStats[dwAdapter]->dwScale = dwScale;
  1018. }
  1019. }
  1020. /*++
  1021. Routine Description:
  1022. Computes and returns the requested statistiocs value for the specified adapter
  1023. Arguments:
  1024. dwAdapter -- Adapter Index
  1025. nStatValue -- The stat value requested
  1026. bAccumulative -- If true the current value is returned
  1027. if fale the current - start value is returned.
  1028. Return Value:
  1029. The requested Statistic value
  1030. Revision History:
  1031. 1-6-2000 Created by omiller
  1032. --*/
  1033. ULONGLONG CAdapter::GetAdapterStat(DWORD dwAdapter, NETCOLUMNID nStatValue, BOOL bAccumulative)
  1034. {
  1035. if( dwAdapter < m_dwAdapterCount )
  1036. {
  1037. // Create pointers to the arrays so I do not have to write so much
  1038. //
  1039. PMIB_IFROW pifrStart = &m_ppaiAdapterStats[dwAdapter]->ifRowStartStats;
  1040. PMIB_IFROW pifrLast = &m_ppaiAdapterStats[dwAdapter]->ifRowStats[!m_bToggle];
  1041. PMIB_IFROW pifrCurrent = &m_ppaiAdapterStats[dwAdapter]->ifRowStats[m_bToggle];
  1042. ULONGLONG ullTickCountDiff = m_ppaiAdapterStats[dwAdapter]->ullTickCountDiff;
  1043. // Get the stats value, do the calculation and return the value
  1044. //
  1045. switch(nStatValue)
  1046. {
  1047. case COL_NETWORKUTIL:
  1048. case COL_BYTESSENTTHRU:
  1049. case COL_BYTESRECTHRU:
  1050. case COL_BYTESTOTALTHRU:
  1051. {
  1052. // Contains the maximum number of bytes that could have been transimited in the time intrval
  1053. // between Last and Current)
  1054. //
  1055. ULONGLONG ullMaxBytesTransmittedInInterval;
  1056. ULONGLONG ull;
  1057. ullMaxBytesTransmittedInInterval = (pifrCurrent->dwSpeed * ullTickCountDiff)/(8 * 1000);
  1058. if( ullMaxBytesTransmittedInInterval == 0 )
  1059. {
  1060. return 0;
  1061. }
  1062. switch(nStatValue)
  1063. {
  1064. case COL_BYTESTOTALTHRU:
  1065. case COL_NETWORKUTIL:
  1066. ull = (pifrCurrent->dwInOctets - pifrLast->dwInOctets) + (pifrCurrent->dwOutOctets - pifrLast->dwOutOctets);
  1067. break;
  1068. case COL_BYTESSENTTHRU:
  1069. ull = (pifrCurrent->dwOutOctets - pifrLast->dwOutOctets);
  1070. break;
  1071. case COL_BYTESRECTHRU:
  1072. ull = (pifrCurrent->dwInOctets - pifrLast->dwInOctets);
  1073. break;
  1074. default:
  1075. ull = 0;
  1076. break;
  1077. }
  1078. ull *= 100 * PERCENT_SHIFT;
  1079. ull /= ullMaxBytesTransmittedInInterval;
  1080. // Make usre we do not exceed 100%, just confuses the user. Davepl inside joke!
  1081. //
  1082. return ull > 100 * PERCENT_SHIFT ? 99 * PERCENT_SHIFT : ull;
  1083. }
  1084. case COL_LINKSPEED:
  1085. return pifrStart->dwSpeed;
  1086. case COL_BYTESSENT:
  1087. return (ULONGLONG)(pifrCurrent->dwOutOctets - (bAccumulative ? pifrStart->dwOutOctets : 0));
  1088. case COL_BYTESREC:
  1089. return (ULONGLONG)(pifrCurrent->dwInOctets - (bAccumulative ? pifrStart->dwInOctets : 0));
  1090. case COL_BYTESTOTAL:
  1091. return (ULONGLONG)((pifrCurrent->dwInOctets + pifrCurrent->dwOutOctets) - (bAccumulative ? (pifrStart->dwInOctets + pifrStart->dwOutOctets) : 0));
  1092. case COL_BYTESSENTPERINTER:
  1093. return (ULONGLONG)(pifrCurrent->dwOutOctets - pifrLast->dwOutOctets);
  1094. case COL_BYTESRECPERINTER:
  1095. return (ULONGLONG)(pifrCurrent->dwInOctets - pifrLast->dwInOctets);
  1096. case COL_BYTESTOTALPERINTER:
  1097. return (ULONGLONG)((pifrCurrent->dwOutOctets + pifrCurrent->dwInOctets) - (pifrLast->dwOutOctets + pifrLast->dwInOctets));
  1098. case COL_UNICASTSSSENT:
  1099. return (ULONGLONG)(pifrCurrent->dwInUcastPkts - (bAccumulative ? pifrStart->dwInUcastPkts : 0));
  1100. case COL_UNICASTSREC:
  1101. return (ULONGLONG)(pifrCurrent->dwOutUcastPkts - (bAccumulative ? pifrStart->dwOutUcastPkts : 0));
  1102. case COL_UNICASTSTOTAL:
  1103. return (ULONGLONG)((pifrCurrent->dwInUcastPkts + pifrCurrent->dwOutUcastPkts) - (bAccumulative ? (pifrStart->dwInUcastPkts + pifrStart->dwOutUcastPkts) : 0));
  1104. case COL_UNICASTSSENTPERINTER:
  1105. return (ULONGLONG)(pifrCurrent->dwOutUcastPkts - pifrLast->dwOutUcastPkts);
  1106. case COL_UNICASTSRECPERINTER:
  1107. return (ULONGLONG)(pifrCurrent->dwInUcastPkts - pifrLast->dwInUcastPkts);
  1108. case COL_UNICASTSTOTALPERINTER:
  1109. return (ULONGLONG)((pifrCurrent->dwOutUcastPkts + pifrCurrent->dwInUcastPkts) - (pifrLast->dwOutUcastPkts + pifrLast->dwInUcastPkts));
  1110. case COL_NONUNICASTSSSENT:
  1111. return (ULONGLONG)(pifrCurrent->dwInNUcastPkts - (bAccumulative ? pifrStart->dwInNUcastPkts : 0));
  1112. case COL_NONUNICASTSREC:
  1113. return (ULONGLONG)(pifrCurrent->dwOutNUcastPkts - (bAccumulative ? pifrStart->dwOutNUcastPkts : 0));
  1114. case COL_NONUNICASTSTOTAL:
  1115. return (ULONGLONG)((pifrCurrent->dwInNUcastPkts + pifrCurrent->dwOutNUcastPkts) - (bAccumulative ? (pifrStart->dwInNUcastPkts + pifrStart->dwOutNUcastPkts) : 0));
  1116. case COL_NONUNICASTSSENTPERINTER:
  1117. return (ULONGLONG)(pifrCurrent->dwOutNUcastPkts - pifrLast->dwOutNUcastPkts);
  1118. case COL_NONUNICASTSRECPERINTER:
  1119. return (ULONGLONG)(pifrCurrent->dwInNUcastPkts - pifrLast->dwInNUcastPkts);
  1120. case COL_NONUNICASTSTOTALPERINTER:
  1121. return (ULONGLONG)((pifrCurrent->dwOutNUcastPkts + pifrCurrent->dwInNUcastPkts) - (pifrLast->dwOutNUcastPkts + pifrLast->dwInNUcastPkts));
  1122. }
  1123. }
  1124. return 0;
  1125. }
  1126. /*++
  1127. Routine Description:
  1128. Initilize all member variables. The CNetPage class displays the information collected
  1129. by the CAdpter class
  1130. Arguments:
  1131. NONE
  1132. Return Value:
  1133. NONE
  1134. Revision History:
  1135. 1-6-2000 Created by omiller
  1136. --*/
  1137. CNetPage::CNetPage()
  1138. {
  1139. ZeroMemory((LPVOID) m_hPens, sizeof(m_hPens));
  1140. m_bReset = TRUE;
  1141. m_hPage = NULL; // Handle to this page's dlg
  1142. m_hwndTabs = NULL; // Parent window
  1143. m_hdcGraph = NULL; // Inmemory dc for cpu hist
  1144. m_hbmpGraph = NULL; // Inmemory bmp for adapter hist
  1145. m_bPageActive = FALSE;
  1146. m_hScaleFont = NULL;
  1147. m_lScaleWidth = 0;
  1148. m_lScaleFontHeight = 0;
  1149. m_pGraph = NULL;
  1150. m_dwGraphCount = 0;
  1151. m_dwFirstVisibleAdapter = 0;
  1152. m_dwGraphsPerPage = 0;
  1153. }
  1154. /*++
  1155. Routine Description:
  1156. Clean up
  1157. Arguments:
  1158. NONE
  1159. Return Value:
  1160. NONE
  1161. Revision History:
  1162. 1-6-2000 Created by omiller
  1163. --*/
  1164. CNetPage::~CNetPage()
  1165. {
  1166. DestroyGraphs();
  1167. ReleasePens();
  1168. ReleaseScaleFont();
  1169. };
  1170. /*++
  1171. Routine Description:
  1172. Reset the start Adapter set
  1173. Arguments:
  1174. NONE
  1175. Return Value:
  1176. NONE
  1177. Revision History:
  1178. 1-6-2000 Created by omiller
  1179. --*/
  1180. void CNetPage::Reset()
  1181. {
  1182. m_bReset = TRUE;
  1183. }
  1184. /*++
  1185. Routine Description:
  1186. Creates the number of required graphs
  1187. Arguments:
  1188. dwGraphsRequired -- Graphs required
  1189. Return Value:
  1190. NONE
  1191. Revision History:
  1192. 1-6-2000 Created by omiller
  1193. --*/
  1194. HRESULT CNetPage::CreateGraphs(DWORD dwGraphsRequired)
  1195. {
  1196. DWORD dwSize;
  1197. LRESULT lFont;
  1198. HRESULT hr = S_OK;
  1199. // Create moore graphs if required
  1200. //
  1201. if( dwGraphsRequired > m_dwGraphCount )
  1202. {
  1203. // Expand the size of the array so it can hold more graphs
  1204. //
  1205. dwSize = dwGraphsRequired * sizeof(GRAPH);
  1206. hr = ChangeArraySize((LPVOID *)&m_pGraph,dwSize);
  1207. if( SUCCEEDED(hr) )
  1208. {
  1209. // Get the font of the parent window
  1210. //
  1211. lFont = SendMessage(m_hPage,WM_GETFONT,NULL,NULL);
  1212. for(; m_dwGraphCount < dwGraphsRequired; m_dwGraphCount++)
  1213. {
  1214. // Create the graph window. The graph is drawn in the window
  1215. //
  1216. m_pGraph[m_dwGraphCount].hwndGraph = CreateWindowEx(WS_EX_CLIENTEDGE,
  1217. L"BUTTON",
  1218. L"",
  1219. WS_CHILDWINDOW | BS_OWNERDRAW | WS_DISABLED,
  1220. 0,0,0,0,
  1221. m_hPage,
  1222. (HMENU)ULongToPtr(IDC_NICGRAPH + m_dwGraphCount),
  1223. NULL,NULL);
  1224. if( m_pGraph[m_dwGraphCount].hwndGraph )
  1225. {
  1226. if( m_dwGraphCount == 0 )
  1227. {
  1228. HDC hdc = GetDC(m_pGraph[m_dwGraphCount].hwndGraph);
  1229. if(hdc )
  1230. {
  1231. CreateScaleFont(hdc);
  1232. ReleaseDC(m_pGraph[m_dwGraphCount].hwndGraph,hdc);
  1233. }
  1234. }
  1235. // Create the frame window. The window draws a pretty border around the graph
  1236. //
  1237. m_pGraph[m_dwGraphCount].hwndFrame = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
  1238. L"DavesFrameClass",
  1239. L"",
  1240. 0x7 | WS_CHILDWINDOW,
  1241. 0,0,0,0,
  1242. m_hPage,
  1243. NULL,NULL,NULL);
  1244. if( m_pGraph[m_dwGraphCount].hwndFrame )
  1245. {
  1246. // Create the graph window. The graph is drawn in the window
  1247. //
  1248. SendMessage(m_pGraph[m_dwGraphCount].hwndFrame,WM_SETFONT,lFont,FALSE);
  1249. }
  1250. else
  1251. {
  1252. // Destroy the graph window and abort
  1253. // TODO hr = error and break;
  1254. DestroyWindow(m_pGraph[m_dwGraphCount].hwndGraph);
  1255. return E_OUTOFMEMORY;
  1256. }
  1257. }
  1258. else
  1259. {
  1260. // Unable to create the window, abort
  1261. //
  1262. return E_OUTOFMEMORY;
  1263. }
  1264. }
  1265. }
  1266. }
  1267. return hr;
  1268. }
  1269. /*++
  1270. Routine Description:
  1271. Destroies the History graph windows
  1272. Arguments:
  1273. NONE
  1274. Return Value:
  1275. NONE
  1276. Revision History:
  1277. 1-6-2000 Created by omiller
  1278. --*/
  1279. void CNetPage::DestroyGraphs()
  1280. {
  1281. for(DWORD dwGraph=0; dwGraph < m_dwGraphCount; dwGraph++)
  1282. {
  1283. DestroyWindow( m_pGraph[dwGraph].hwndGraph );
  1284. DestroyWindow( m_pGraph[dwGraph].hwndFrame );
  1285. }
  1286. if( NULL != m_pGraph )
  1287. {
  1288. HeapFree( GetProcessHeap(), 0, m_pGraph );
  1289. m_pGraph = NULL;
  1290. }
  1291. m_dwGraphCount = 0;
  1292. }
  1293. /*++
  1294. Routine Description:
  1295. Restores the order of the Network tab's list view columns. The order is
  1296. stored in g_Options. When taskmgr is closed, the order is stored in the registry
  1297. Arguments:
  1298. hwndList -- Handle to the list view
  1299. Return Value:
  1300. NONE
  1301. Revision History:
  1302. 1-6-2000 Borrowed by omiller
  1303. --*/
  1304. void CNetPage::RestoreColumnOrder(HWND hwndList)
  1305. {
  1306. INT rgOrder[ARRAYSIZE(g_aNetDlgColIDs)];
  1307. INT cOrder = 0;
  1308. INT iOrder = 0;
  1309. //
  1310. // Get the order of the columns
  1311. //
  1312. for (int i = 0; i < ARRAYSIZE(g_aNetDlgColIDs); i++)
  1313. {
  1314. iOrder = g_Options.m_NetColumnPositions[i];
  1315. if (-1 == iOrder)
  1316. break;
  1317. rgOrder[cOrder++] = iOrder;
  1318. }
  1319. if (0 < cOrder)
  1320. {
  1321. //
  1322. // Set the order of the columns
  1323. //
  1324. const HWND hwndHeader = ListView_GetHeader(hwndList);
  1325. Header_SetOrderArray(hwndHeader, Header_GetItemCount(hwndHeader), rgOrder);
  1326. }
  1327. }
  1328. /*++
  1329. Routine Description:
  1330. Remember the order of the Network tab's list view columns. The order is
  1331. stored in g_Options. When taskmgr is closed, the order is stored in the registry
  1332. Arguments:
  1333. hwndList -- Handle to the list view
  1334. Return Value:
  1335. NONE
  1336. Revision History:
  1337. 1-6-2000 Borrowed by omiller
  1338. --*/
  1339. void CNetPage::RememberColumnOrder(HWND hwndList)
  1340. {
  1341. const HWND hwndHeader = ListView_GetHeader(hwndList);
  1342. int x;
  1343. x = Header_GetItemCount(hwndHeader);
  1344. ASSERT(Header_GetItemCount(hwndHeader) <= ARRAYSIZE(g_Options.m_NetColumnPositions));
  1345. //
  1346. // Clear the array
  1347. //
  1348. FillMemory(&g_Options.m_NetColumnPositions, sizeof(g_Options.m_NetColumnPositions), 0xFF);
  1349. //
  1350. // Get the order of the columns and store it in the array
  1351. //
  1352. Header_GetOrderArray(hwndHeader,
  1353. Header_GetItemCount(hwndHeader),
  1354. g_Options.m_NetColumnPositions);
  1355. }
  1356. /*++
  1357. Routine Description:
  1358. The Window Proc for the select a column Dialog box. Allows the user to select the collumns.
  1359. Arguments:
  1360. hwndDlg -- Handle to the dialog box
  1361. uMsg -- Window message
  1362. wParam -- Window message
  1363. lParam -- WIndows Message
  1364. Return Value:
  1365. Something
  1366. Revision History:
  1367. 1-6-2000 Borrowed by omiller
  1368. --*/
  1369. INT_PTR CALLBACK NetColSelectDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1370. {
  1371. static CNetPage * pPage = NULL;
  1372. switch(uMsg)
  1373. {
  1374. case WM_INITDIALOG:
  1375. pPage = (CNetPage *) lParam;
  1376. //
  1377. // Start with none of the boxes checked
  1378. //
  1379. for (int i = 0; i < ARRAYSIZE(g_aNetDlgColIDs); i++)
  1380. {
  1381. CheckDlgButton(hwndDlg, g_aNetDlgColIDs[i], BST_UNCHECKED);
  1382. }
  1383. //
  1384. // Then turn on the ones for the columns we have active
  1385. //
  1386. for (i = 0; i < ARRAYSIZE(g_aNetDlgColIDs); i++)
  1387. {
  1388. if (g_Options.m_ActiveNetCol[i] == -1)
  1389. {
  1390. break;
  1391. }
  1392. CheckDlgButton(hwndDlg, g_aNetDlgColIDs[ g_Options.m_ActiveNetCol[ i ] ], BST_CHECKED);
  1393. }
  1394. return TRUE;
  1395. case WM_COMMAND:
  1396. //
  1397. // If user clicked OK, add the columns to the array and reset the listview
  1398. //
  1399. if (LOWORD(wParam) == IDOK)
  1400. {
  1401. //
  1402. // First, make sure the column width array is up to date
  1403. //
  1404. pPage->SaveColumnWidths();
  1405. INT iCol = 0;
  1406. for (int i = 0; i < NUM_NETCOLUMN && g_aNetDlgColIDs[i] >= 0; i++)
  1407. {
  1408. if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, g_aNetDlgColIDs[i]))
  1409. {
  1410. //
  1411. // It is checked
  1412. //
  1413. if (g_Options.m_ActiveNetCol[iCol] != (NETCOLUMNID) i)
  1414. {
  1415. //
  1416. // If the column wasn't already there, insert its column
  1417. // width into the column width array
  1418. //
  1419. ShiftArray(g_Options.m_NetColumnWidths, iCol, SHIFT_UP);
  1420. ShiftArray(g_Options.m_ActiveNetCol, iCol, SHIFT_UP);
  1421. g_Options.m_NetColumnWidths[iCol] = NetColumnDefaults[ i ].Width;
  1422. g_Options.m_ActiveNetCol[iCol] = (NETCOLUMNID) i;
  1423. }
  1424. iCol++;
  1425. }
  1426. else
  1427. {
  1428. //
  1429. // Not checked, column not active. If it used to be active,
  1430. // remove its column width from the column width array
  1431. //
  1432. if (g_Options.m_ActiveNetCol[iCol] == (NETCOLUMNID) i)
  1433. {
  1434. ShiftArray(g_Options.m_NetColumnWidths, iCol, SHIFT_DOWN);
  1435. ShiftArray(g_Options.m_ActiveNetCol, iCol, SHIFT_DOWN);
  1436. }
  1437. }
  1438. }
  1439. //
  1440. // Terminate the column list
  1441. //
  1442. g_Options.m_ActiveNetCol[iCol] = (NETCOLUMNID) -1;
  1443. pPage->SetupColumns();
  1444. EndDialog(hwndDlg, IDOK);
  1445. }
  1446. else if (LOWORD(wParam) == IDCANCEL)
  1447. {
  1448. EndDialog(hwndDlg, IDCANCEL);
  1449. }
  1450. break;
  1451. }
  1452. return FALSE;
  1453. }
  1454. /*++
  1455. Routine Description:
  1456. Handle the slect a column dialog box
  1457. Arguments:
  1458. NONE
  1459. Return Value:
  1460. NONE
  1461. Revision History:
  1462. 1-6-2000 Created by omiller
  1463. --*/
  1464. void CNetPage::PickColumns()
  1465. {
  1466. DialogBoxParam( g_hInstance
  1467. , MAKEINTRESOURCE(IDD_SELECTNETCOLS)
  1468. , g_hMainWnd
  1469. , NetColSelectDlgProc
  1470. , (LPARAM) this
  1471. );
  1472. }
  1473. /*++
  1474. Routine Description:
  1475. Creates the necessary pens
  1476. Arguments:
  1477. NONE
  1478. Return Value:
  1479. NONE
  1480. Revision History:
  1481. 1-6-2000 Created by omiller
  1482. --*/
  1483. void CNetPage::CreatePens()
  1484. {
  1485. for (int i = 0; i < ARRAYSIZE(aNetColors); i++)
  1486. {
  1487. //
  1488. // Create the pens. If a failure occurs, just substitute
  1489. // the white pen
  1490. //
  1491. m_hPens[i] = CreatePen(PS_SOLID, 1, aNetColors[i]);
  1492. if (NULL == m_hPens[i])
  1493. {
  1494. m_hPens[i] = (HPEN) GetStockObject(WHITE_PEN);
  1495. }
  1496. }
  1497. }
  1498. /*++
  1499. Routine Description:
  1500. Destroys the pens
  1501. Arguments:
  1502. NONE
  1503. Return Value:
  1504. NONE
  1505. Revision History:
  1506. 1-6-2000 Created by omiller
  1507. --*/
  1508. void CNetPage::ReleasePens()
  1509. {
  1510. for (int i = 0; i < NUM_PENS; i++)
  1511. {
  1512. if ( NULL != m_hPens[ i ] )
  1513. {
  1514. DeleteObject( m_hPens[ i ] );
  1515. }
  1516. }
  1517. }
  1518. /*++
  1519. Routine Description:
  1520. Compute the width (in px) of a string
  1521. Arguments:
  1522. hdc - DC handle
  1523. pszwText - String to determine the width of.
  1524. Return Value:
  1525. The width of the string
  1526. Revision History:
  1527. 1-6-2000 Created by omiller
  1528. --*/
  1529. int GetStrWidth(HDC hdc, WCHAR *pszwText)
  1530. {
  1531. int iWidth;
  1532. int iTotalWidth = 0;
  1533. if( pszwText )
  1534. {
  1535. // Sum the width of the chars in the string
  1536. //
  1537. for(int i=0; pszwText[i]!=L'\0'; i++)
  1538. {
  1539. if( GetCharWidth32( hdc, pszwText[i], pszwText[i], &iWidth ) )
  1540. {
  1541. iTotalWidth += iWidth;
  1542. }
  1543. else
  1544. {
  1545. // GetCharWidth32 failed, return -1 as an error code
  1546. return -1;
  1547. }
  1548. }
  1549. }
  1550. // Return the total width of the string
  1551. //
  1552. return iTotalWidth;
  1553. }
  1554. /*++
  1555. Routine Description:
  1556. Creates the font for the scale. The font is created when the first graph is created.
  1557. The hdc of the raph is used to determine the height of the font and the total with of
  1558. the scale.
  1559. Arguments:
  1560. NONE
  1561. Return Value:
  1562. NONE
  1563. Revision History:
  1564. 1-6-2000 Created by omiller
  1565. --*/
  1566. void CNetPage::CreateScaleFont(HDC hdc)
  1567. {
  1568. if( NULL == m_hScaleFont && NULL != hdc)
  1569. {
  1570. //
  1571. // The font has not yet been created.
  1572. //
  1573. INT FontSize;
  1574. NONCLIENTMETRICS ncm = {0};
  1575. LOGFONT lf;
  1576. HFONT hOldFont = NULL;
  1577. ncm.cbSize = sizeof(ncm);
  1578. if ( SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0) )
  1579. {
  1580. lf = ncm.lfMessageFont;
  1581. lf.lfWeight = FW_THIN;
  1582. //
  1583. // Make sure the font name will not be clipped.
  1584. //
  1585. Assert( ARRAYSIZE(lf.lfFaceName) >= ARRAYSIZE(g_szScaleFont) );
  1586. StringCchCopy( lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), g_szScaleFont );
  1587. FontSize = 8;
  1588. lf.lfHeight = 0 - GetDeviceCaps(hdc, LOGPIXELSY) * FontSize / 72;
  1589. m_hScaleFont = CreateFontIndirect(&lf);
  1590. if ( NULL != m_hScaleFont )
  1591. {
  1592. hOldFont = (HFONT) SelectObject( hdc, (HGDIOBJ) m_hScaleFont );
  1593. }
  1594. m_lScaleFontHeight = lf.lfHeight - 2;
  1595. m_lScaleWidth = GetStrWidth(hdc,L" 22.5 %");
  1596. if( NULL != hOldFont )
  1597. {
  1598. SelectObject( hdc, (HGDIOBJ) hOldFont );
  1599. }
  1600. }
  1601. }
  1602. }
  1603. /*++
  1604. Routine Description:
  1605. Releases the fonts
  1606. Arguments:
  1607. NONE
  1608. Return Value:
  1609. NONE
  1610. Revision History:
  1611. 1-6-2000 Created by omiller
  1612. --*/
  1613. void CNetPage::ReleaseScaleFont()
  1614. {
  1615. if( m_hScaleFont )
  1616. {
  1617. DeleteObject(m_hScaleFont);
  1618. m_hScaleFont = NULL;
  1619. }
  1620. }
  1621. /*++
  1622. Routine Description:
  1623. Draws the scale for the graph
  1624. Arguments:
  1625. hdcGraph - hdc of the graph
  1626. prcGraph - Graph region
  1627. dwMaxScaleValue - The highest scale value
  1628. Return Value:
  1629. NONE
  1630. Revision History:
  1631. 1-6-2000 Created by omiller
  1632. --*/
  1633. INT CNetPage::DrawScale(HDC hdcGraph, RECT *prcGraph, DWORD dwMaxScaleValue)
  1634. {
  1635. HPEN hOldPen = NULL;
  1636. HFONT hOldFont = NULL;
  1637. INT Leftside = prcGraph->left;
  1638. WCHAR sz[100];
  1639. RECT rc;
  1640. if( g_Options.m_bShowScale )
  1641. {
  1642. if( NULL != m_hScaleFont )
  1643. {
  1644. // Set the scale font
  1645. hOldFont = (HFONT) SelectObject(hdcGraph,(HGDIOBJ)m_hScaleFont);
  1646. }
  1647. // Set the text attributes
  1648. //
  1649. SetBkMode(hdcGraph,TRANSPARENT);
  1650. SetTextColor(hdcGraph,RGB(255, 255, 0));
  1651. // Make room for the scale
  1652. //
  1653. Leftside += m_lScaleWidth;
  1654. rc.left = prcGraph->left;
  1655. rc.right = Leftside - 3;
  1656. // Draw the upper scale value
  1657. //
  1658. rc.top = prcGraph->top;
  1659. rc.bottom = rc.top - m_lScaleFontHeight;
  1660. FloatToString( dwMaxScaleValue * PERCENT_SHIFT, sz, ARRAYSIZE(sz), TRUE );
  1661. StringCchCat( sz, ARRAYSIZE(sz), L" " );
  1662. StringCchCat( sz, ARRAYSIZE(sz), g_szPercent );
  1663. DrawText(hdcGraph,sz,lstrlen(sz),&rc,DT_RIGHT);
  1664. // Draw the middle scale value. multi by PERCENT_SHIFT because FloatToString takes a number shifted by PERCENT_SHIFT
  1665. //
  1666. rc.top = prcGraph->top + (prcGraph->bottom - prcGraph->top)/2 + m_lScaleFontHeight/2;
  1667. rc.bottom = rc.top - m_lScaleFontHeight;
  1668. FloatToString( ( dwMaxScaleValue * PERCENT_SHIFT ) / 2, sz, ARRAYSIZE(sz), TRUE );
  1669. StringCchCat( sz, ARRAYSIZE(sz), L" " );
  1670. StringCchCat( sz, ARRAYSIZE(sz), g_szPercent );
  1671. DrawText(hdcGraph,sz,lstrlen(sz),&rc,DT_RIGHT);
  1672. // Draw the botton scale value
  1673. //
  1674. rc.top = prcGraph->bottom + m_lScaleFontHeight;
  1675. rc.bottom = rc.top - m_lScaleFontHeight;
  1676. StringCchCopy( sz, ARRAYSIZE(sz), g_szZero );
  1677. StringCchCat( sz, ARRAYSIZE(sz), L" " );
  1678. StringCchCat( sz, ARRAYSIZE(sz), g_szPercent );
  1679. DrawText(hdcGraph,sz,lstrlen(sz),&rc,DT_RIGHT);
  1680. if( hOldFont )
  1681. {
  1682. SelectObject(hdcGraph,hOldFont);
  1683. }
  1684. // Draw the scale line. Divides the scale from the graph
  1685. //
  1686. hOldPen = (HPEN) SelectObject( hdcGraph, m_hPens[1] );
  1687. MoveToEx(hdcGraph,
  1688. Leftside,
  1689. prcGraph->top,
  1690. (LPPOINT) NULL);
  1691. LineTo(hdcGraph,
  1692. Leftside,
  1693. prcGraph->bottom);
  1694. if( NULL != hOldPen)
  1695. {
  1696. SelectObject( hdcGraph, hOldPen );
  1697. }
  1698. }
  1699. return Leftside;
  1700. }
  1701. /*++
  1702. Routine Description:
  1703. Draw the graph paper. The size of the squares depends of the zoom level.
  1704. Arguments:
  1705. NONE
  1706. Return Value:
  1707. NONE
  1708. Revision History:
  1709. 1-6-2000 Created by omiller
  1710. --*/
  1711. ULONG CNetPage::DrawAdapterGraphPaper(HDC hdcGraph, RECT * prcGraph, DWORD dwZoom)
  1712. {
  1713. #define GRAPHPAPERSIZE 12
  1714. HPEN hPen;
  1715. int Leftside = prcGraph->left;
  1716. ULONG ulSquareSize = GRAPHPAPERSIZE + (20 * (100 - 100/dwZoom)) / 100; //28
  1717. int nLineCount = 0;
  1718. Leftside = DrawScale(hdcGraph,prcGraph,100/dwZoom);
  1719. hPen = CreatePen(PS_SOLID, 1, RGB(0, 128, 64));
  1720. HGDIOBJ hOldObj = SelectObject(hdcGraph, hPen);
  1721. // Draw the vertical lines
  1722. //
  1723. for (int i = (ulSquareSize) + 1; i < prcGraph->bottom - prcGraph->top; i+= ulSquareSize)
  1724. {
  1725. MoveToEx(hdcGraph,
  1726. Leftside,
  1727. prcGraph->bottom - i,
  1728. (LPPOINT) NULL);
  1729. LineTo(hdcGraph,
  1730. prcGraph->right,
  1731. prcGraph->bottom - i);
  1732. nLineCount++;
  1733. }
  1734. // Draw the horizontal lines
  1735. //
  1736. for (i = prcGraph->right - g_NetScrollamount; i > Leftside; i -= GRAPHPAPERSIZE)
  1737. {
  1738. MoveToEx(hdcGraph,
  1739. i,
  1740. prcGraph->top,
  1741. (LPPOINT) NULL);
  1742. LineTo(hdcGraph,
  1743. i,
  1744. prcGraph->bottom);
  1745. }
  1746. if (hOldObj)
  1747. {
  1748. SelectObject(hdcGraph, hOldObj);
  1749. }
  1750. if( hPen )
  1751. {
  1752. DeleteObject(hPen);
  1753. }
  1754. return Leftside - prcGraph->left - 3;
  1755. }
  1756. /*++
  1757. Routine Description:
  1758. Add the column headers to the Network tab's List view
  1759. Arguments:
  1760. NONE
  1761. Return Value:
  1762. HRESULT
  1763. Revision History:
  1764. 1-6-2000 Created by omiller
  1765. --*/
  1766. HRESULT CNetPage::SetupColumns()
  1767. {
  1768. //
  1769. // Delete all the items in the list view
  1770. //
  1771. ListView_DeleteAllItems(m_hListView);
  1772. //
  1773. // Remove all existing columns
  1774. //
  1775. LV_COLUMN lvcolumn;
  1776. while(ListView_DeleteColumn(m_hListView, 0))
  1777. {
  1778. NULL;
  1779. }
  1780. //
  1781. // Add all of the new columns
  1782. //
  1783. INT iColumn = 0;
  1784. while (g_Options.m_ActiveNetCol[iColumn] >= 0)
  1785. {
  1786. INT idColumn = g_Options.m_ActiveNetCol[iColumn];
  1787. WCHAR szTitle[MAX_PATH];
  1788. LoadString(g_hInstance, _aIDNetColNames[idColumn], szTitle, ARRAYSIZE(szTitle));
  1789. lvcolumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_TEXT | LVCF_WIDTH;
  1790. lvcolumn.fmt = NetColumnDefaults[ idColumn ].Format | (idColumn > 1 ? LVCFMT_RIGHT : 0);
  1791. // If no width preference has been recorded for this column, use the
  1792. // default
  1793. if (-1 == g_Options.m_NetColumnWidths[iColumn])
  1794. {
  1795. lvcolumn.cx = NetColumnDefaults[ idColumn ].Width;
  1796. }
  1797. else
  1798. {
  1799. lvcolumn.cx = g_Options.m_NetColumnWidths[iColumn];
  1800. }
  1801. lvcolumn.pszText = szTitle;
  1802. lvcolumn.iSubItem = iColumn;
  1803. if (-1 == ListView_InsertColumn(m_hListView, iColumn, &lvcolumn))
  1804. {
  1805. return E_FAIL;
  1806. }
  1807. iColumn++;
  1808. }
  1809. ListView_SetExtendedListViewStyleEx(m_hListView,LVS_EX_HEADERDRAGDROP | LVS_EX_FULLROWSELECT , LVS_EX_HEADERDRAGDROP | LVS_EX_FULLROWSELECT);
  1810. return S_OK;
  1811. }
  1812. /*++
  1813. Routine Description:
  1814. Save the width of the columns
  1815. Arguments:
  1816. NONE
  1817. Return Value:
  1818. HRESULT
  1819. Revision History:
  1820. 1-6-2000 Created by omiller
  1821. --*/
  1822. void CNetPage::SaveColumnWidths()
  1823. {
  1824. UINT i = 0;
  1825. LV_COLUMN col = { 0 };
  1826. while (g_Options.m_ActiveNetCol[i] != (NETCOLUMNID) -1)
  1827. {
  1828. col.mask = LVCF_WIDTH;
  1829. if (ListView_GetColumn(m_hListView, i, &col) )
  1830. {
  1831. g_Options.m_NetColumnWidths[i] = (SHORT)col.cx;
  1832. }
  1833. else
  1834. {
  1835. ASSERT(0 && "Couldn't get the column width");
  1836. }
  1837. i++;
  1838. }
  1839. }
  1840. /*++
  1841. Routine Description:
  1842. Initialize the Network tab
  1843. Arguments:
  1844. NONE
  1845. Return Value:
  1846. HRESULT
  1847. Revision History:
  1848. 1-6-2000 Created by omiller
  1849. --*/
  1850. HRESULT CNetPage::Initialize(HWND hwndParent)
  1851. {
  1852. CreatePens();
  1853. // Our pseudo-parent is the tab contrl, and is what we base our
  1854. // sizing on. However, in order to keep tab order right among
  1855. // the controls, we actually create ourselves with the main
  1856. // window as the parent
  1857. m_hwndTabs = hwndParent;
  1858. //
  1859. // Create the dialog which represents the body of this page
  1860. //
  1861. m_hPage = CreateDialogParam(
  1862. g_hInstance, // handle to application instance
  1863. MAKEINTRESOURCE(IDD_NETPAGE), // identifies dialog box template name
  1864. g_hMainWnd, // handle to owner window
  1865. NetPageProc, // pointer to dialog box procedure
  1866. (LPARAM) this ); // User data (our this pointer)
  1867. if (NULL == m_hPage)
  1868. {
  1869. return GetLastHRESULT();
  1870. }
  1871. // no fail if GetDlgItem
  1872. m_hNoAdapterText = GetDlgItem(m_hPage, IDC_NOADAPTERS);
  1873. if( !m_hNoAdapterText )
  1874. {
  1875. return E_FAIL;
  1876. }
  1877. m_hScrollBar = GetDlgItem(m_hPage, IDC_GRAPHSCROLLVERT);
  1878. if( !m_hScrollBar )
  1879. {
  1880. return E_FAIL;
  1881. }
  1882. m_hListView = GetDlgItem(m_hPage, IDC_NICTOTALS);
  1883. if( !m_hListView )
  1884. {
  1885. return E_FAIL;
  1886. }
  1887. // Add the columns to the list view
  1888. //
  1889. SetupColumns();
  1890. // Order the columns for the user
  1891. //
  1892. RestoreColumnOrder(m_hListView);
  1893. return S_OK;
  1894. }
  1895. /*++
  1896. Routine Description:
  1897. Creates the memory bitmaps for the graphs
  1898. Arguments:
  1899. NONE
  1900. Return Value:
  1901. HRESULT
  1902. Revision History:
  1903. 1-6-2000 Created by omiller
  1904. --*/
  1905. HRESULT CNetPage::CreateMemoryBitmaps(int x, int y)
  1906. {
  1907. //
  1908. // Create the inmemory bitmaps and DCs that we will use
  1909. //
  1910. HDC hdcPage = GetDC(m_hPage);
  1911. m_hdcGraph = CreateCompatibleDC(hdcPage);
  1912. if (NULL == m_hdcGraph)
  1913. {
  1914. ReleaseDC(m_hPage, hdcPage);
  1915. return GetLastHRESULT();
  1916. }
  1917. m_rcGraph.left = 0;
  1918. m_rcGraph.top = 0;
  1919. m_rcGraph.right = x;
  1920. m_rcGraph.bottom = y;
  1921. m_hbmpGraph = CreateCompatibleBitmap(hdcPage, x, y);
  1922. ReleaseDC(m_hPage, hdcPage);
  1923. if (NULL == m_hbmpGraph)
  1924. {
  1925. HRESULT hr = GetLastHRESULT();
  1926. DeleteDC(m_hdcGraph);
  1927. m_hdcGraph = NULL;
  1928. return hr;
  1929. }
  1930. //
  1931. // Select the bitmap into the DC
  1932. //
  1933. m_hOldObject = SelectObject(m_hdcGraph, m_hbmpGraph);
  1934. return S_OK;
  1935. }
  1936. /*++
  1937. Routine Description:
  1938. Destroy the bitmaps for the graphs
  1939. Arguments:
  1940. NONE
  1941. Return Value:
  1942. NONE
  1943. Revision History:
  1944. 1-6-2000 Created by omiller
  1945. --*/
  1946. void CNetPage::FreeMemoryBitmaps()
  1947. {
  1948. if ( NULL != m_hdcGraph )
  1949. {
  1950. if ( NULL != m_hOldObject )
  1951. {
  1952. HGDIOBJ hObj = SelectObject( m_hdcGraph, m_hOldObject );
  1953. ASSERT( hObj == (HGDIOBJ) m_hbmpGraph );
  1954. hObj; // unreferenced on FRE builds
  1955. }
  1956. DeleteDC(m_hdcGraph);
  1957. m_hdcGraph = NULL;
  1958. }
  1959. if ( NULL != m_hbmpGraph )
  1960. {
  1961. DeleteObject(m_hbmpGraph);
  1962. m_hbmpGraph = NULL;
  1963. }
  1964. }
  1965. /*++
  1966. Routine Description:
  1967. This function is called when the Network tab is activated.
  1968. Arguments:
  1969. NONE
  1970. Return Value:
  1971. NONE
  1972. Revision History:
  1973. 1-6-2000 Created by omiller
  1974. --*/
  1975. HRESULT CNetPage::Activate()
  1976. {
  1977. // Adjust the size and position of our dialog relative
  1978. // to the tab control which "owns" us
  1979. RECT rcParent;
  1980. GetClientRect(m_hwndTabs, &rcParent);
  1981. MapWindowPoints(m_hwndTabs, g_hMainWnd, (LPPOINT) &rcParent, 2);
  1982. TabCtrl_AdjustRect(m_hwndTabs, FALSE, &rcParent);
  1983. // The user has switched to the tab. The Networking tab is now active
  1984. // The tab will stay active for the whole life time of taskmgr
  1985. //
  1986. m_bPageActive = TRUE;
  1987. SetWindowPos(m_hPage,
  1988. HWND_TOP,
  1989. rcParent.left, rcParent.top,
  1990. rcParent.right - rcParent.left, rcParent.bottom - rcParent.top,
  1991. 0);
  1992. // Make this page visible
  1993. ShowWindow(m_hPage, SW_SHOW);
  1994. // Newly created dialogs seem to steal the focus, so give it back to the
  1995. // tab control (which must have had it if we got here in the first place)
  1996. SetFocus(m_hwndTabs);
  1997. TimerEvent();
  1998. // Change the menu bar to be the menu for this page
  1999. HMENU hMenuOld = GetMenu(g_hMainWnd);
  2000. HMENU hMenuNew = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_MAINMENU_NET));
  2001. AdjustMenuBar(hMenuNew);
  2002. CheckMenuItem(hMenuNew,IDM_BYTESSENT,g_Options.m_bAutoSize ? MF_CHECKED:MF_UNCHECKED);
  2003. CheckMenuItem(hMenuNew,IDM_BYTESSENT,g_Options.m_bGraphBytesSent ? MF_CHECKED:MF_UNCHECKED);
  2004. CheckMenuItem(hMenuNew,IDM_BYTESRECEIVED,g_Options.m_bGraphBytesReceived ? MF_CHECKED:MF_UNCHECKED);
  2005. CheckMenuItem(hMenuNew,IDM_BYTESTOTAL,g_Options.m_bGraphBytesTotal ? MF_CHECKED:MF_UNCHECKED);
  2006. g_hMenu = hMenuNew;
  2007. if (g_Options.m_fNoTitle == FALSE)
  2008. {
  2009. SetMenu(g_hMainWnd, hMenuNew);
  2010. }
  2011. if (hMenuOld)
  2012. {
  2013. DestroyMenu(hMenuOld);
  2014. }
  2015. SizeNetPage();
  2016. return S_OK;
  2017. }
  2018. /*++
  2019. Routine Description:
  2020. This function is called when the Network tab is deactivated.
  2021. Arguments:
  2022. NONE
  2023. Return Value:
  2024. NONE
  2025. Revision History:
  2026. 1-6-2000 Created by omiller
  2027. --*/
  2028. void CNetPage::Deactivate()
  2029. {
  2030. SaveColumnWidths();
  2031. if (m_hPage)
  2032. {
  2033. ShowWindow(m_hPage, SW_HIDE);
  2034. }
  2035. FreeMemoryBitmaps( );
  2036. }
  2037. //
  2038. //
  2039. //
  2040. HRESULT CNetPage::Destroy()
  2041. {
  2042. //
  2043. // When we are being destroyed, kill off our dialog
  2044. //
  2045. if (m_hPage)
  2046. {
  2047. DestroyWindow(m_hPage);
  2048. m_hPage = NULL;
  2049. }
  2050. FreeMemoryBitmaps( );
  2051. return S_OK;
  2052. }
  2053. /*++
  2054. Routine Description:
  2055. Get the title of the networking tab i.e. "Networking"
  2056. Arguments:
  2057. NONE
  2058. Return Value:
  2059. NONE
  2060. Revision History:
  2061. 1-6-2000 Created by omiller
  2062. --*/
  2063. void CNetPage::GetTitle(LPTSTR pszText, size_t bufsize)
  2064. {
  2065. LoadString(g_hInstance, IDS_NETPAGETITLE, pszText, static_cast<int>(bufsize));
  2066. }
  2067. /*++
  2068. Routine Description:
  2069. Size the History graph
  2070. Arguments:
  2071. hdwp -- Defered Window Handle
  2072. pGraph -- History graph to size
  2073. pRect -- The corrdinates of the graph
  2074. pDimRect -- The dimentions of the actual history graph
  2075. Return Value:
  2076. NONE
  2077. Revision History:
  2078. 1-6-2000 Created by omiller
  2079. --*/
  2080. void CNetPage::SizeGraph(HDWP hdwp, GRAPH *pGraph, RECT *pRect, RECT *pDimRect)
  2081. {
  2082. RECT rc;
  2083. DWORD dwGraphWidth = pRect->right - g_DefSpacing * 2;
  2084. DWORD dwGraphHeight = pRect->bottom - g_TopSpacing - g_DefSpacing;
  2085. // Size the frame
  2086. //
  2087. rc.left = pRect->left;
  2088. rc.top = pRect->top;
  2089. rc.right = pRect->left + pRect->right;
  2090. rc.bottom = pRect->top + pRect->bottom;
  2091. DeferWindowPos(hdwp,
  2092. pGraph->hwndFrame,
  2093. NULL,
  2094. rc.left,
  2095. rc.top,
  2096. rc.right - rc.left,
  2097. rc.bottom - rc.top,
  2098. SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
  2099. // Size the History graph
  2100. //
  2101. rc.left = rc.left + g_DefSpacing;
  2102. rc.top = rc.top + g_TopSpacing;
  2103. rc.right = rc.left + dwGraphWidth;
  2104. rc.bottom = rc.top + dwGraphHeight;
  2105. DeferWindowPos(hdwp,
  2106. pGraph->hwndGraph,
  2107. NULL,
  2108. rc.left,
  2109. rc.top,
  2110. rc.right - rc.left,
  2111. rc.bottom - rc.top,
  2112. SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
  2113. if( pDimRect )
  2114. {
  2115. // Return the size of the history graph
  2116. //
  2117. *pDimRect = rc;
  2118. }
  2119. }
  2120. /*++
  2121. Routine Description:
  2122. Hide the history graph
  2123. Arguments:
  2124. hdwp -- Defered Window Handle
  2125. pGraph -- History graph to hide
  2126. Return Value:
  2127. NONE
  2128. Revision History:
  2129. 1-6-2000 Created by omiller
  2130. --*/
  2131. void CNetPage::HideGraph(HDWP hdwp, GRAPH *pGraph)
  2132. {
  2133. // Hide the frame
  2134. //
  2135. DeferWindowPos(hdwp,
  2136. pGraph->hwndFrame,
  2137. NULL,
  2138. 0,0,0,0,
  2139. SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW);
  2140. // Hide the graph
  2141. //
  2142. DeferWindowPos(hdwp,
  2143. pGraph->hwndGraph,
  2144. NULL,
  2145. 0,0,0,0,
  2146. SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW);
  2147. }
  2148. /*++
  2149. Routine Description:
  2150. Compute the number of graphs we can squeeze on a page
  2151. Arguments:
  2152. dwHeight -- Height of the graphing area
  2153. dwAdapterCount -- Total number of adapters
  2154. Return Value:
  2155. Number of adapters that can be squeeze on to the tab
  2156. Revision History:
  2157. 1-6-2000 Created by omiller
  2158. --*/
  2159. DWORD CNetPage::GraphsPerPage(DWORD dwHeight, DWORD dwAdapterCount)
  2160. {
  2161. DWORD dwGraphsPerPage = 0;
  2162. if( dwAdapterCount )
  2163. {
  2164. DWORD dwGraphHeight;
  2165. // Compute the average height of an adapter if all adapters were put on the page
  2166. // If they all fit then squueze all of them on the page, if the height is smaller then the min
  2167. // height compute the number of adapters we can squeeze on the page.
  2168. //
  2169. dwGraphHeight = dwHeight / dwAdapterCount;
  2170. dwGraphHeight = dwGraphHeight < MIN_GRAPH_HEIGHT ? MIN_GRAPH_HEIGHT : dwGraphHeight;
  2171. dwGraphsPerPage = dwHeight > dwGraphHeight ? dwHeight / dwGraphHeight : 1;
  2172. }
  2173. return dwGraphsPerPage;
  2174. }
  2175. /*++
  2176. Routine Description:
  2177. Get the first adapter that the user sees graphed.
  2178. Arguments:
  2179. void
  2180. Return Value:
  2181. The first adapter the user sees graphed
  2182. Revision History:
  2183. 1-6-2000 Created by omiller
  2184. --*/
  2185. DWORD CNetPage::GetFirstVisibleAdapter()
  2186. {
  2187. DWORD dwAdapter = m_dwFirstVisibleAdapter;
  2188. DWORD dwAdapterCount = m_Adapter.GetNumberOfAdapters();
  2189. if( dwAdapter + m_dwGraphsPerPage > dwAdapterCount )
  2190. {
  2191. dwAdapter = dwAdapterCount - m_dwGraphsPerPage;
  2192. }
  2193. if( dwAdapter >= dwAdapterCount )
  2194. {
  2195. dwAdapter = 0;
  2196. }
  2197. return dwAdapter;
  2198. }
  2199. /*++
  2200. Routine Description:
  2201. Assigns a name to each graph.
  2202. Arguments:
  2203. void
  2204. Return Value:
  2205. void
  2206. Revision History:
  2207. 1-6-2000 Created by omiller
  2208. --*/
  2209. void CNetPage::LabelGraphs()
  2210. {
  2211. DWORD dwAdapter;
  2212. dwAdapter = GetFirstVisibleAdapter();
  2213. for(DWORD dwGraph=0; dwGraph < m_dwGraphsPerPage; dwGraph++)
  2214. {
  2215. SetWindowText( m_pGraph[ dwGraph ].hwndFrame, m_Adapter.GetAdapterText( dwAdapter + dwGraph, COL_ADAPTERNAME) );
  2216. }
  2217. UpdateGraphs();
  2218. }
  2219. /*++
  2220. Routine Description:
  2221. Size the history graphs.
  2222. Arguments:
  2223. void
  2224. Return Value:
  2225. void
  2226. Revision History:
  2227. 1-6-2000 Created by omiller
  2228. --*/
  2229. void CNetPage::SizeNetPage()
  2230. {
  2231. HRESULT hr;
  2232. HDWP hdwp;
  2233. RECT rcParent;
  2234. RECT rcGraph = {0};
  2235. RECT rcGraphDim = {0};
  2236. DWORD dwAdapterCount;
  2237. DWORD dwGraphHistoryHeight = 0;
  2238. BOOLEAN bNeedScrollBar = FALSE;
  2239. m_dwGraphsPerPage = 0;
  2240. if (g_Options.m_fNoTitle)
  2241. {
  2242. // Just display the graphs, not the list view or the tabs
  2243. //
  2244. GetClientRect(g_hMainWnd, &rcParent);
  2245. dwGraphHistoryHeight = rcParent.bottom - rcParent.top - g_DefSpacing;
  2246. }
  2247. else
  2248. {
  2249. // Display the graphs, list view and tabs
  2250. //
  2251. GetClientRect(m_hwndTabs, &rcParent);
  2252. MapWindowPoints(m_hwndTabs, m_hPage, (LPPOINT) &rcParent, 2);
  2253. TabCtrl_AdjustRect(m_hwndTabs, FALSE, &rcParent);
  2254. dwGraphHistoryHeight = (rcParent.bottom - rcParent.top - g_DefSpacing) * 3 / 4;
  2255. }
  2256. // Determine the number of adapters so we can compute the number of graphs to display perpage.
  2257. //
  2258. dwAdapterCount = m_Adapter.GetNumberOfAdapters();
  2259. if( dwAdapterCount )
  2260. {
  2261. // Compute the number of graphs we can squeeze onto the page. One graph always fits onto the tab.
  2262. //
  2263. m_dwGraphsPerPage = GraphsPerPage(dwGraphHistoryHeight, dwAdapterCount);
  2264. hr = CreateGraphs(m_dwGraphsPerPage);
  2265. if( FAILED(hr) )
  2266. {
  2267. // Unable to create the graphs, abort
  2268. //
  2269. return;
  2270. }
  2271. // Determine if we need to display the scroll bar
  2272. //
  2273. bNeedScrollBar = (dwAdapterCount > m_dwGraphsPerPage);
  2274. // Determine the rect for the first graph
  2275. //
  2276. rcGraph.left = rcParent.left + g_DefSpacing;
  2277. rcGraph.right = (rcParent.right - rcParent.left) - g_DefSpacing*2 - (bNeedScrollBar ? SCROLLBAR_WIDTH + g_DefSpacing : 0);
  2278. rcGraph.top = rcParent.top + g_DefSpacing;
  2279. rcGraph.bottom = dwGraphHistoryHeight / m_dwGraphsPerPage;
  2280. }
  2281. //
  2282. // SizeGraph() and HideGraph() each have 2 DeferWindowPos calls.
  2283. //
  2284. hdwp = BeginDeferWindowPos(3 + m_dwGraphCount * 2);
  2285. if( hdwp )
  2286. {
  2287. // Position the scroll bar window
  2288. //
  2289. DeferWindowPos(hdwp,
  2290. m_hScrollBar,
  2291. NULL,
  2292. rcParent.right - g_DefSpacing - SCROLLBAR_WIDTH,
  2293. rcParent.top + g_DefSpacing,
  2294. SCROLLBAR_WIDTH,
  2295. rcGraph.bottom * m_dwGraphsPerPage,
  2296. (bNeedScrollBar ? SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW : SWP_HIDEWINDOW));
  2297. // Position the induvidual graphs. We might have created more graphs then we needed, hide the extra graphs
  2298. //
  2299. for(DWORD dwGraph=0; dwGraph < m_dwGraphCount; dwGraph++ )
  2300. {
  2301. if( dwGraph < m_dwGraphsPerPage )
  2302. {
  2303. SizeGraph( hdwp, &m_pGraph[ dwGraph ], &rcGraph, &rcGraphDim );
  2304. rcGraph.top += rcGraph.bottom;
  2305. }
  2306. else
  2307. {
  2308. // Do not display these graphs
  2309. //
  2310. HideGraph( hdwp, &m_pGraph[ dwGraph ] );
  2311. }
  2312. }
  2313. // Postion the list view that displays the stats
  2314. DeferWindowPos(hdwp,
  2315. m_hListView,
  2316. NULL,
  2317. rcGraph.left,
  2318. rcGraph.top + g_DefSpacing,
  2319. rcParent.right - rcParent.left - rcGraph.left - g_DefSpacing,
  2320. rcParent.bottom - rcGraph.top - g_DefSpacing,
  2321. dwAdapterCount ? SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW : SWP_HIDEWINDOW);
  2322. // Position the "No Active Adapters found" text
  2323. //
  2324. DeferWindowPos(hdwp,
  2325. m_hNoAdapterText,
  2326. NULL,
  2327. rcParent.left ,
  2328. rcParent.top + (rcParent.bottom - rcParent.top) / 2 - 40,
  2329. rcParent.right - rcParent.left,
  2330. rcParent.bottom - rcParent.top,
  2331. dwAdapterCount ? SWP_HIDEWINDOW : SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
  2332. EndDeferWindowPos(hdwp);
  2333. FreeMemoryBitmaps(); // Free any old ones
  2334. CreateMemoryBitmaps(rcGraphDim.right - rcGraphDim.left, rcGraphDim.bottom - rcGraphDim.top - 4);
  2335. LabelGraphs();
  2336. if( bNeedScrollBar )
  2337. {
  2338. SCROLLINFO si;
  2339. // Set up the scroll bar
  2340. //
  2341. si.cbSize = sizeof(SCROLLINFO);
  2342. si.fMask = SIF_PAGE | SIF_RANGE;
  2343. si.nPage = 1;
  2344. si.nMin = 0;
  2345. si.nMax = dwAdapterCount - m_dwGraphsPerPage;
  2346. SetScrollInfo(m_hScrollBar,SB_CTL,&si,TRUE);
  2347. }
  2348. }
  2349. }
  2350. /*++
  2351. Routine Description:
  2352. Update all of the Networking graphs. i.e. redraw the graphs
  2353. Arguments:
  2354. NONE
  2355. Return Value:
  2356. NONE
  2357. Revision History:
  2358. 1-6-2000 Created by omiller
  2359. --*/
  2360. void CNetPage::UpdateGraphs()
  2361. {
  2362. for (DWORD dwGraph = 0; dwGraph < m_dwGraphsPerPage; dwGraph++)
  2363. {
  2364. InvalidateRect( m_pGraph[dwGraph].hwndGraph, NULL, FALSE );
  2365. UpdateWindow( m_pGraph[dwGraph].hwndGraph) ;
  2366. }
  2367. }
  2368. /*++
  2369. Routine Description:
  2370. Draw a Networking graph
  2371. Arguments:
  2372. prc -- the coordinates of the graph
  2373. hPen -- The color of the graph line
  2374. dwZoom -- the zoom level of the graph
  2375. pHistory -- The history to plot
  2376. pHistory2 -- The other history to draw in cobonation with the first history i.e. pHistory + pHistory2
  2377. Return Value:
  2378. NONE
  2379. Revision History:
  2380. 1-6-2000 Created by omiller
  2381. --*/
  2382. DWORD CNetPage::DrawGraph(LPRECT prc, HPEN hPen, DWORD dwZoom, ULONG *pHistory, ULONG *pHistory2)
  2383. {
  2384. HGDIOBJ hOldObj;
  2385. ULONGLONG nValue;
  2386. DWORD nMax=0;
  2387. int Width = prc->right - prc->left;
  2388. int Scale = (Width - 1) / HIST_SIZE;
  2389. if (0 == Scale)
  2390. {
  2391. Scale = 2;
  2392. }
  2393. hOldObj = SelectObject(m_hdcGraph, hPen );
  2394. // Compute the height of the graph
  2395. //
  2396. int GraphHeight = m_rcGraph.bottom - m_rcGraph.top;
  2397. // Get the first value to plot
  2398. //
  2399. if( pHistory2 )
  2400. {
  2401. if( pHistory[0] == INVALID_VALUE || pHistory2[0] == INVALID_VALUE )
  2402. {
  2403. return nMax;
  2404. }
  2405. nValue = (DWORD) (pHistory[0]+pHistory2[0]);
  2406. }
  2407. else
  2408. {
  2409. if( pHistory[0] == INVALID_VALUE )
  2410. {
  2411. return nMax;
  2412. }
  2413. nValue = (DWORD) (pHistory[0]);
  2414. }
  2415. // Memorize the max value that is plotted (effects the zoom level)
  2416. //
  2417. nMax = (DWORD)(nValue/PERCENT_SHIFT > nMax ? nValue/PERCENT_SHIFT : nMax);
  2418. nValue = (nValue * GraphHeight * dwZoom/ 100)/PERCENT_SHIFT;
  2419. nValue = nValue == 0 ? 1 : nValue;
  2420. MoveToEx(m_hdcGraph,
  2421. m_rcGraph.right,
  2422. m_rcGraph.bottom - (ULONG)nValue,
  2423. (LPPOINT) NULL);
  2424. // Plot the points
  2425. //
  2426. for (INT nPoint = 1; nPoint < HIST_SIZE && nPoint * Scale < Width; nPoint++)
  2427. {
  2428. if( pHistory2 )
  2429. {
  2430. if( pHistory[nPoint] == INVALID_VALUE || pHistory2[nPoint] == INVALID_VALUE )
  2431. {
  2432. return nMax;
  2433. }
  2434. // Get both points
  2435. //
  2436. nValue = (DWORD) (pHistory[nPoint]+pHistory2[nPoint]);
  2437. }
  2438. else
  2439. {
  2440. if( pHistory[nPoint] == INVALID_VALUE )
  2441. {
  2442. return nMax;
  2443. }
  2444. // Just get the first point
  2445. //
  2446. nValue = (DWORD) (pHistory[nPoint]);
  2447. }
  2448. //nValue /= PERCENT_SHIFT;
  2449. // Memorize the max value that is plotted (effects the zoom level)
  2450. //
  2451. nMax = (DWORD)(nValue/PERCENT_SHIFT > nMax ? nValue/PERCENT_SHIFT : nMax);
  2452. nValue = (nValue * GraphHeight * dwZoom / 100) / PERCENT_SHIFT;
  2453. nValue = nValue == 0 ? 1 : nValue;
  2454. LineTo(m_hdcGraph,
  2455. m_rcGraph.right - (Scale * nPoint),
  2456. m_rcGraph.bottom - (ULONG)nValue);
  2457. }
  2458. if (hOldObj)
  2459. {
  2460. SelectObject(m_hdcGraph, hOldObj);
  2461. }
  2462. // Return the maximum value plotted
  2463. //
  2464. return nMax;
  2465. }
  2466. /*++
  2467. Routine Description:
  2468. Draw a Networking graph
  2469. Arguments:
  2470. lpdi -- the coordinates of the graph
  2471. iPane -- The id of the graph to draw
  2472. Return Value:
  2473. NONE
  2474. Revision History:
  2475. 1-6-2000 Created by omiller
  2476. --*/
  2477. void CNetPage::DrawAdapterGraph(LPDRAWITEMSTRUCT lpdi, UINT iPane)
  2478. {
  2479. DWORD dwZoom = 1;
  2480. DWORD dwScale = 100;
  2481. DWORD dwAdapter;
  2482. if( iPane > m_dwGraphCount )
  2483. {
  2484. return;
  2485. }
  2486. // Get the adapter index.
  2487. //
  2488. dwAdapter = iPane + GetFirstVisibleAdapter();
  2489. if( dwAdapter >= m_Adapter.GetNumberOfAdapters() )
  2490. {
  2491. // Invalid adapter, abort.
  2492. //
  2493. return;
  2494. }
  2495. // Get the scale for the adapter
  2496. //
  2497. dwScale = m_Adapter.GetScale(dwAdapter);
  2498. // Determine the zoom level
  2499. //
  2500. if( g_Options.m_bAutoSize )
  2501. {
  2502. if( dwScale < 1 )
  2503. {
  2504. dwZoom = 100;
  2505. }
  2506. else if( dwScale < 5)
  2507. {
  2508. dwZoom = 20;
  2509. }
  2510. else if( dwScale < 25)
  2511. {
  2512. dwZoom = 4;
  2513. }
  2514. else if( dwScale < 50)
  2515. {
  2516. dwZoom = 2;
  2517. }
  2518. else
  2519. {
  2520. dwZoom = 1;
  2521. }
  2522. }
  2523. if (NULL == m_hdcGraph)
  2524. {
  2525. return;
  2526. }
  2527. // Draw a black background into the graph
  2528. //
  2529. FillRect(m_hdcGraph, &m_rcGraph, (HBRUSH) GetStockObject(BLACK_BRUSH));
  2530. int Width = lpdi->rcItem.right - lpdi->rcItem.left;
  2531. int Scale = (Width - 1) / HIST_SIZE;
  2532. if (0 == Scale)
  2533. {
  2534. Scale = 2;
  2535. }
  2536. // Draw the graph paper. The zoom effects the horzontal lines
  2537. //
  2538. ULONG ulWidth = DrawAdapterGraphPaper(m_hdcGraph, &m_rcGraph, dwZoom);
  2539. DWORD nValue;
  2540. dwScale = 0;
  2541. lpdi->rcItem.left += ulWidth;
  2542. if( g_Options.m_bGraphBytesSent )
  2543. {
  2544. // Draw the bytes sent graph. Check the max value plotted
  2545. //
  2546. nValue = DrawGraph(&lpdi->rcItem, m_hPens[0], dwZoom, m_Adapter.GetAdapterHistory(dwAdapter,BYTES_SENT_UTIL));
  2547. dwScale = nValue > dwScale ? nValue : dwScale;
  2548. }
  2549. if( g_Options.m_bGraphBytesReceived )
  2550. {
  2551. // Draw the bytes received graph. Check the max value plotted
  2552. //
  2553. nValue = DrawGraph(&lpdi->rcItem,m_hPens[1], dwZoom, m_Adapter.GetAdapterHistory(dwAdapter,BYTES_RECEIVED_UTIL));
  2554. dwScale = nValue > dwScale ? nValue : dwScale;
  2555. }
  2556. if( g_Options.m_bGraphBytesTotal)
  2557. {
  2558. // Draw the bytes total graph. Check the max value plotted
  2559. //
  2560. nValue = DrawGraph(&lpdi->rcItem,m_hPens[2],dwZoom, m_Adapter.GetAdapterHistory(dwAdapter,BYTES_SENT_UTIL),m_Adapter.GetAdapterHistory(dwAdapter,BYTES_RECEIVED_UTIL));
  2561. dwScale = nValue > dwScale ? nValue : dwScale;
  2562. }
  2563. lpdi->rcItem.left -= ulWidth;
  2564. // Save the max value plotted
  2565. //
  2566. m_Adapter.SetScale(dwAdapter,dwScale);
  2567. // Shift and display the graph
  2568. //
  2569. INT xDiff = 0; //(m_rcGraph.right - m_rcGraph.left) - (lpdi->rcItem.right - lpdi->rcItem.left);
  2570. BitBlt( lpdi->hDC,
  2571. lpdi->rcItem.left,
  2572. lpdi->rcItem.top,
  2573. lpdi->rcItem.right - lpdi->rcItem.left,
  2574. lpdi->rcItem.bottom - lpdi->rcItem.top,
  2575. m_hdcGraph,
  2576. xDiff,
  2577. 0,
  2578. SRCCOPY);
  2579. }
  2580. /*++
  2581. Routine Description:
  2582. Updates the Network tab's listview
  2583. Arguments:
  2584. NONE
  2585. Return Value:
  2586. HRESULT
  2587. Revision History:
  2588. 1-6-2000 Created by omiller
  2589. --*/
  2590. HRESULT CNetPage::UpdatePage()
  2591. {
  2592. HRESULT hr = S_OK;
  2593. LVITEM lvitem;
  2594. INT iColumn = 0;
  2595. DWORD dwItemCount;
  2596. DWORD dwItem=0;
  2597. ULONGLONG ull;
  2598. DWORD dwAdapterCount = m_Adapter.GetNumberOfAdapters();
  2599. dwItemCount = ListView_GetItemCount(m_hListView);
  2600. // Add or update the list view items
  2601. //
  2602. for(DWORD dwAdapter = 0; dwAdapter < dwAdapterCount; dwAdapter++)
  2603. {
  2604. // Only show the requested stats
  2605. //
  2606. iColumn = 0;
  2607. while (g_Options.m_ActiveNetCol[iColumn] >= 0)
  2608. {
  2609. // This buffer needs to hold a 20 digit number with commas and G, M K and sometime bs so it is big enough
  2610. WCHAR szw[100];
  2611. lvitem.mask = LVIF_TEXT;
  2612. lvitem.iSubItem = iColumn;
  2613. lvitem.iItem = dwItem;
  2614. lvitem.pszText = L"";
  2615. lvitem.lParam = (LPARAM)NULL; //&m_Adapter.m_pAdapterInfo[dwAdapter]; //dwAdapter; //NULL; //(LPARAM)pna;
  2616. // Get the value
  2617. //
  2618. switch(g_Options.m_ActiveNetCol[iColumn])
  2619. {
  2620. case COL_ADAPTERNAME:
  2621. case COL_ADAPTERDESC:
  2622. case COL_STATE:
  2623. lvitem.pszText = m_Adapter.GetAdapterText(dwAdapter,g_Options.m_ActiveNetCol[iColumn]);
  2624. break;
  2625. case COL_NETWORKUTIL:
  2626. case COL_BYTESSENTTHRU:
  2627. case COL_BYTESRECTHRU:
  2628. case COL_BYTESTOTALTHRU:
  2629. // This buffer needs to hold a 20 digit number with commas and G, M K and sometime bs so it is big enough
  2630. ull = m_Adapter.GetAdapterStat(dwAdapter,g_Options.m_ActiveNetCol[iColumn],!g_Options.m_bNetShowAll);
  2631. FloatToString( ull, szw, ARRAYSIZE(szw), FALSE );
  2632. StringCchCat( szw, ARRAYSIZE(szw), L" " );
  2633. StringCchCat( szw, ARRAYSIZE(szw), g_szPercent );
  2634. lvitem.pszText = szw;
  2635. break;
  2636. case COL_LINKSPEED:
  2637. ull = m_Adapter.GetAdapterStat(dwAdapter,g_Options.m_ActiveNetCol[iColumn],!g_Options.m_bNetShowAll);
  2638. SimplifyNumber( ull, szw, ARRAYSIZE(szw) );
  2639. StringCchCat( szw, ARRAYSIZE(szw), g_szBitsPerSec );
  2640. lvitem.pszText = szw;
  2641. break;
  2642. case COL_BYTESSENT:
  2643. case COL_BYTESREC:
  2644. case COL_BYTESTOTAL:
  2645. case COL_BYTESSENTPERINTER:
  2646. case COL_BYTESRECPERINTER:
  2647. case COL_BYTESTOTALPERINTER:
  2648. ull = m_Adapter.GetAdapterStat(dwAdapter,g_Options.m_ActiveNetCol[iColumn],!g_Options.m_bNetShowAll);
  2649. CommaNumber( ull, szw, ARRAYSIZE(szw) );
  2650. lvitem.pszText = szw;
  2651. break;
  2652. case COL_UNICASTSSSENT:
  2653. case COL_UNICASTSREC:
  2654. case COL_UNICASTSTOTAL:
  2655. case COL_UNICASTSSENTPERINTER:
  2656. case COL_UNICASTSRECPERINTER:
  2657. case COL_UNICASTSTOTALPERINTER:
  2658. case COL_NONUNICASTSSSENT:
  2659. case COL_NONUNICASTSREC:
  2660. case COL_NONUNICASTSTOTAL:
  2661. case COL_NONUNICASTSSENTPERINTER:
  2662. case COL_NONUNICASTSRECPERINTER:
  2663. case COL_NONUNICASTSTOTALPERINTER:
  2664. ull = m_Adapter.GetAdapterStat(dwAdapter,g_Options.m_ActiveNetCol[iColumn],!g_Options.m_bNetShowAll);
  2665. CommaNumber( ull, szw, ARRAYSIZE(szw) );
  2666. lvitem.pszText = szw;
  2667. break;
  2668. }
  2669. if( dwItem >= dwItemCount)
  2670. {
  2671. // The adapter is not in the listview, add it
  2672. //
  2673. lvitem.mask |= LVIF_PARAM;
  2674. if( -1 == ListView_InsertItem(m_hListView, &lvitem) )
  2675. {
  2676. return E_FAIL;
  2677. }
  2678. dwItemCount = ListView_GetItemCount(m_hListView);
  2679. }
  2680. else
  2681. {
  2682. // The adapter is already in the list view, update the value
  2683. //
  2684. ListView_SetItem(m_hListView, &lvitem);
  2685. }
  2686. iColumn++;
  2687. }
  2688. dwItem++;
  2689. }
  2690. return hr;
  2691. }
  2692. /*++
  2693. Routine Description:
  2694. Collect the Adapter information and update the tab
  2695. Arguments:
  2696. Return Value:
  2697. HRESULT
  2698. Revision History:
  2699. 1-6-2000 Created by omiller
  2700. --*/
  2701. void CNetPage::CalcNetTime(void)
  2702. {
  2703. BOOLEAN bAdapterListChange = FALSE;
  2704. HRESULT hr;
  2705. // Update our adapter list with the new stats
  2706. //
  2707. hr = m_Adapter.Update(bAdapterListChange);
  2708. if( SUCCEEDED(hr) )
  2709. {
  2710. // Collect the adapter information
  2711. //
  2712. if( m_bReset )
  2713. {
  2714. // Reset the Adapter start values
  2715. //
  2716. m_Adapter.Reset();
  2717. m_bReset = FALSE;
  2718. }
  2719. if( bAdapterListChange )
  2720. {
  2721. // Some adapters changed, update the graphs (create and delete graphs)
  2722. //
  2723. Refresh();
  2724. }
  2725. // Update the listview
  2726. //
  2727. UpdatePage();
  2728. }
  2729. }
  2730. void CNetPage::Refresh()
  2731. {
  2732. m_Adapter.RefreshConnectionNames();
  2733. SizeNetPage();
  2734. ListView_DeleteAllItems(m_hListView);
  2735. }
  2736. /*++
  2737. Routine Description:
  2738. Handle the timer event
  2739. Arguments:
  2740. NONE
  2741. Return Value:
  2742. NONE
  2743. Revision History:
  2744. 1-6-2000 Created by omiller
  2745. --*/
  2746. void CNetPage::TimerEvent()
  2747. {
  2748. // If the Network tab is not selected and the user does not want to waste cpu usage for the networking adapter history
  2749. // do not do any of the Networking calculations.
  2750. //
  2751. if( m_bPageActive || g_Options.m_bTabAlwaysActive)
  2752. {
  2753. // This will make the graph scrolll
  2754. //
  2755. g_NetScrollamount+=2;
  2756. g_NetScrollamount %= GRAPHPAPERSIZE;
  2757. // Collect the Adapter information
  2758. //
  2759. CalcNetTime();
  2760. // Check if window minimized
  2761. //
  2762. if (FALSE == IsIconic(g_hMainWnd))
  2763. {
  2764. UpdateGraphs();
  2765. }
  2766. }
  2767. }
  2768. //
  2769. //
  2770. //
  2771. DWORD CNetPage::GetNumberOfGraphs()
  2772. {
  2773. return m_dwGraphCount;
  2774. }
  2775. //
  2776. //
  2777. //
  2778. void CNetPage::ScrollGraphs(WPARAM wParam)
  2779. {
  2780. SCROLLINFO si;
  2781. si.cbSize = sizeof(SCROLLINFO);
  2782. si.fMask = SIF_ALL;
  2783. if( GetScrollInfo(m_hScrollBar,SB_CTL,&si) )
  2784. {
  2785. switch(LOWORD(wParam))
  2786. {
  2787. case SB_BOTTOM:
  2788. si.nPos = si.nMax;
  2789. break;
  2790. case SB_TOP:
  2791. si.nPos = si.nMin;
  2792. break;
  2793. case SB_LINEDOWN:
  2794. si.nPos++;
  2795. break;
  2796. case SB_LINEUP:
  2797. si.nPos--;
  2798. break;
  2799. case SB_PAGEUP:
  2800. si.nPos -= m_dwGraphsPerPage;
  2801. break;
  2802. case SB_PAGEDOWN:
  2803. si.nPos += m_dwGraphsPerPage;
  2804. break;
  2805. case SB_THUMBTRACK:
  2806. case SB_THUMBPOSITION:
  2807. si.nPos = HIWORD(wParam);
  2808. break;
  2809. }
  2810. if( si.nPos < si.nMin )
  2811. {
  2812. si.nPos = si.nMin;
  2813. }
  2814. else if( si.nPos > si.nMax )
  2815. {
  2816. si.nPos = si.nMax;
  2817. }
  2818. m_dwFirstVisibleAdapter = si.nPos;
  2819. SetScrollPos(m_hScrollBar,SB_CTL,si.nPos,TRUE);
  2820. LabelGraphs();
  2821. }
  2822. }
  2823. /*++
  2824. Routine Description:
  2825. Window Proc for the Networking tab
  2826. Arguments:
  2827. hwnd -- handle to dialog box
  2828. uMsg -- message
  2829. wParam -- first message parameter
  2830. lParam -- second message parameter
  2831. Return Value:
  2832. NO IDEA
  2833. Revision History:
  2834. 1-6-2000 Created by omiller
  2835. --*/
  2836. INT_PTR CALLBACK NetPageProc(
  2837. HWND hwnd, // handle to dialog box
  2838. UINT uMsg, // message
  2839. WPARAM wParam, // first message parameter
  2840. LPARAM lParam // second message parameter
  2841. )
  2842. {
  2843. CNetPage * thispage = (CNetPage *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  2844. // See if the parent wants this message
  2845. //
  2846. if (TRUE == CheckParentDeferrals(uMsg, wParam, lParam))
  2847. {
  2848. return TRUE;
  2849. }
  2850. switch(uMsg)
  2851. {
  2852. case WM_SHOWWINDOW:
  2853. case WM_SIZE:
  2854. //
  2855. // Size our kids
  2856. //
  2857. thispage->SizeNetPage();
  2858. return TRUE;
  2859. case WM_INITDIALOG:
  2860. {
  2861. SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
  2862. DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
  2863. dwStyle |= WS_CLIPCHILDREN;
  2864. SetWindowLong(hwnd, GWL_STYLE, dwStyle);
  2865. }
  2866. return TRUE;
  2867. case WM_LBUTTONUP:
  2868. case WM_LBUTTONDOWN:
  2869. // We need to fake client mouse clicks in this child to appear as nonclient
  2870. // (caption) clicks in the parent so that the user can drag the entire app
  2871. // when the title bar is hidden by dragging the client area of this child
  2872. if (g_Options.m_fNoTitle)
  2873. {
  2874. SendMessage(g_hMainWnd,
  2875. uMsg == WM_LBUTTONUP ? WM_NCLBUTTONUP : WM_NCLBUTTONDOWN,
  2876. HTCAPTION,
  2877. lParam);
  2878. }
  2879. break;
  2880. case WM_COMMAND :
  2881. if( LOWORD(wParam) == IDM_NETRESET)
  2882. {
  2883. thispage->Reset();
  2884. }
  2885. break;
  2886. case WM_DRAWITEM:
  2887. //
  2888. // Draw one of our owner draw controls
  2889. //
  2890. if (wParam >= IDC_NICGRAPH && wParam <= (WPARAM)(IDC_NICGRAPH + thispage->GetNumberOfGraphs()) )
  2891. {
  2892. thispage->DrawAdapterGraph( (LPDRAWITEMSTRUCT) lParam, (UINT)wParam - IDC_NICGRAPH);
  2893. return TRUE;
  2894. }
  2895. break;
  2896. case WM_DESTROY:
  2897. thispage->RememberColumnOrder(GetDlgItem(hwnd, IDC_NICTOTALS));
  2898. break;
  2899. case WM_VSCROLL:
  2900. thispage->ScrollGraphs(wParam);
  2901. break;
  2902. }
  2903. return FALSE;
  2904. }