Source code of Windows XP (NT5)
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.

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