/*++ Copyright (c) 1995 Microsoft Corporation Module Name: perfhist.c Abstract: This Module contains the code for the histogram monitoring utility Author: Stephane Plante (t-stephp) (28-Feb-1995) Revision History: --*/ #include "perfhist.h" #include TEXTFORMAT labels[] = { { { 15,379, 55,396 }, TEXT("Drive:"), ( 6), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_LEFT }, { { 15,396, 55,413 }, TEXT("Type:"), ( 5), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_LEFT }, { { 195,379,275,396 }, TEXT("Average:"), ( 8), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_LEFT }, { { 195,396,275,413 }, TEXT("Avg. Read:"), (10), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_LEFT }, { { 195,413,275,430 }, TEXT("Avg. Write:"), (11), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_LEFT }, { { 405,379,525,396 }, TEXT("Total Average:"), (14), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_LEFT }, { { 405,396,525,413 }, TEXT("Total Avg. Read:"), (16), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_LEFT }, { { 405,413,525,430 }, TEXT("Total Avg. Write:"), (17), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_LEFT }, { { 15,413, 75,430 }, TEXT("Buckets:"), ( 8), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_LEFT }, { { 1, 1,640, 17 }, TEXT("DISK HOTSPOTS"), (13), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_CENTER }, { { 1, 45,640, 62 }, TEXT("Interval Disk Access"), (20), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_CENTER }, { { 5, 45, 34, 62 }, TEXT("Hits"), ( 4), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_LEFT }, { { 5,355,115,372 }, TEXT("Disk Location"), (13), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_LEFT }, { { 280,355,320,372 }, TEXT("Key:"), ( 4), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_LEFT }, { { 350,355,380,372 }, TEXT("20%"), ( 3), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 410,355,440,372 }, TEXT("40%"), ( 3), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 470,355,500,372 }, TEXT("60%"), ( 3), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 530,355,560,372 }, TEXT("80%"), ( 3), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 590,355,630,372 }, TEXT("100%"), ( 3), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, }; TEXTFORMAT variables[] = { { { 65,379,175,396 }, TEXT(""), ( 0), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 65,396,175,413 }, TEXT(""), ( 0), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 285,379,385,396 }, TEXT("0"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 285,396,385,413 }, TEXT("0"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 285,413,385,430 }, TEXT("0"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 530,379,625,396 }, TEXT("0"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 530,396,625,413 }, TEXT("0"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 530,413,625,430 }, TEXT("0"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 85,413,175,430 }, TEXT("0"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, }; TEXTFORMAT xaxis[] = { { { 0,338, 30,355 }, TEXT("0"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 40,338, 97,355 }, TEXT("10"), ( 2), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 107,338,164,355 }, TEXT("20"), ( 2), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 172,338,228,355 }, TEXT("30"), ( 2), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 240,338,297,355 }, TEXT("40"), ( 2), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 307,338,364,355 }, TEXT("50"), ( 2), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 374,338,430,355 }, TEXT("60"), ( 2), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 440,338,497,355 }, TEXT("70"), ( 2), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 507,338,564,355 }, TEXT("80"), ( 2), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 574,338,630,355 }, TEXT("90"), ( 2), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT } }; TEXTFORMAT yaxis[] = { { { 5,318, 28,335 }, TEXT("0"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 5,286, 28,303 }, TEXT("1"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 5,254, 28,271 }, TEXT("2"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 5,222, 28,239 }, TEXT("3"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 5,190, 28,207 }, TEXT("4"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 5,158, 28,175 }, TEXT("5"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 5,126, 28,143 }, TEXT("6"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 5, 94, 28,111 }, TEXT("7"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT }, { { 5, 62, 28, 79 }, TEXT("8"), ( 1), { 0 }, DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_RIGHT } }; COLOREDBOX boxes[] = { {330,355, 17, 17, RGB(0,0,255) }, {390,355, 17, 17, RGB(255,255,0) }, {450,355, 17, 17, RGB(255,0,255) }, {510,355, 17, 17, RGB(0,255,0) }, {570,355, 17, 17, RGB(255,0,0) } }; IOCTL_MAPPING type[] = { { TEXT("Location"), IOCTL_DISK_HISTOGRAM, PROCESS_READ | PROCESS_WRITE }, { TEXT("Read Location"), IOCTL_DISK_HISTOGRAM, PROCESS_READ }, { TEXT("Read Req. Size"), IOCTL_DISK_REQUEST, PROCESS_READ }, { TEXT("Req. Size"), IOCTL_DISK_REQUEST, PROCESS_READ | PROCESS_WRITE }, { TEXT("Write Location"), IOCTL_DISK_HISTOGRAM, PROCESS_WRITE }, { TEXT("Write Req. Size"), IOCTL_DISK_REQUEST, PROCESS_WRITE }, }; HINSTANCE hInst; HWND hMainWnd; HFONT hMainFont; HMENU hMenuHandle; HBRUSH hBrush; HBRUSH hBrush1; HBRUSH hBrush2; HBRUSH hBrush3; HBRUSH hBrush4; HBRUSH hBrush5; CHAR szAppName[] = "perfhist"; CHAR szTitle[] = "Disk Histogram Monitor"; BOOLEAN timerOn = FALSE; ULONG cMax = 9; UINT activeDrives = 0; INFORMATION current; INFORMATION total; PULONG pHist = NULL; PULONG pCurr = NULL; LARGE_INTEGER CurrentWrite; LARGE_INTEGER CurrentRead; LARGE_INTEGER CurrentAvg; LARGE_INTEGER TotalWrite; LARGE_INTEGER TotalRead; LARGE_INTEGER TotalAvg; RECT rCoordRect; PERFHISTSTRUCT PerfHist = { IDW_FULL, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL, NULL, NULL }; int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdList, int CmdShow) /*++ Routine Description: This routine initializes the appropriate windows classes and then serves as a message pump for the system. Arguments: hInstance: Handle to this instance hPrevInstance: Handle to the Previous Instance lpCmdList: What the user typed on the command line CmdShow: Wether the user wants us visible or invisible at the start Return Value: What the result of the program is. TRUE for successful run and normal termination. FALSE otherwise. --*/ { MSG msg; HANDLE hAccelTable; if (!hPrevInstance) { if (!InitApplication(hInstance)) { return FALSE; } } if (!InitInstance(hInstance,CmdShow)) { return FALSE; } hAccelTable = LoadAccelerators(hInstance,szAppName); while (GetMessage(&msg,NULL,0,0) ) { if (!TranslateAccelerator(msg.hwnd,hAccelTable,&msg) ) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; } // End of WinMain BOOL InitApplication( HINSTANCE hInstance) /*++ Routine Description: This Routine actually initializes the main application class and registers it. Arguments: hInstance Handle to this instance Return Value: Wether the registration was successful. --*/ { WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = (HICON)NULL; wc.hCursor = LoadCursor(NULL,IDC_ARROW); wc.hbrBackground = CreateSolidBrush(RGB(64,64,64)); wc.lpszMenuName = MAKEINTRESOURCE(PERF_MENU); wc.lpszClassName = szAppName; if (!RegisterClass(&wc)) { return FALSE; } return TRUE; } // End InitApplications; BOOL InitInstance( HINSTANCE hInstance, int CmdShow) /*++ Routine Description: This build the screen and determines the number of physical drivers currently on the system. Arguments: hInstance Handle to this instance CmdShow Wether the user wants us to come out visible Return Value: Wether the creation succeeded --*/ { HWND hWnd; HANDLE handle; HMENU hMenu; HFONT temp = NULL; DISK_HISTOGRAM histgram; DWORD numBytes; TCHAR szTopMost[] = TEXT("Always on &Top"); hInst = hInstance; hWnd = CreateWindowEx( 0, szAppName, szTitle, WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 0, 0, 640, 480, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } // // Add the Always on Top string to the System menu // hMenu = GetSystemMenu(hWnd,FALSE); AppendMenu(hMenu,MF_SEPARATOR,0,NULL); AppendMenu(hMenu,MF_ENABLED | MF_UNCHECKED | MF_STRING, IDM_TOPMOST, szTopMost); // // Setup all the entries in the Main Data Structure // PerfHist.hdcMain = GetDC(hWnd); PerfHist.hdcMem = CreateCompatibleDC(PerfHist.hdcMain); PerfHist.hBitMap = CreateCompatibleBitmap(PerfHist.hdcMain,640,480); PerfHist.bCantHide = FALSE; PerfHist.bTmpHide = FALSE; PerfHist.fDisplay = FALSE; PerfHist.wFormat = IDW_FULL; PerfHist.bIconic = FALSE; PerfHist.bNoTitle = FALSE; PerfHist.bTopMost = FALSE; // // Initialize the Main DC (Memory DC) // hMainFont = SelectObject(PerfHist.hdcMain,temp); SelectObject(PerfHist.hdcMain,hMainFont); SelectObject(PerfHist.hdcMem, hMainFont); SelectObject(PerfHist.hdcMem,hBrush); SelectObject(PerfHist.hdcMem,PerfHist.hBitMap); SetStretchBltMode(PerfHist.hdcMem,BLACKONWHITE); SetBkColor(PerfHist.hdcMem,RGB(64,64,64)); SetBkMode(PerfHist.hdcMem,TRANSPARENT); SetTextColor(PerfHist.hdcMem,RGB(255,255,255)); PatBlt(PerfHist.hdcMem,0,0,640,480, PATCOPY); handle = CreateFile(TEXT("\\\\.\\PhysicalDrive0"), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (handle == INVALID_HANDLE_VALUE) { MessageBox(NULL, TEXT("Could not open a drive."), TEXT("Error"), MB_ICONEXCLAMATION | MB_OK); return FALSE; } if (!DeviceIoControl (handle, IOCTL_DISK_REQUEST, NULL, 0, &histgram, sizeof(DISK_HISTOGRAM), &numBytes, NULL)) { if (GetLastError() == ERROR_INVALID_FUNCTION) { MessageBox(NULL, TEXT("Histgram.sys is not started on your system.\n" "Start the driver and reboot."), TEXT("Error"), MB_ICONEXCLAMATION | MB_OK); CloseHandle(handle); return FALSE; } } CloseHandle(handle); ShowWindow(hWnd,CmdShow); UpdateWindow(hWnd); hMainWnd = hWnd; return TRUE; } TCHAR **GetAttachedDrives( PINT NumberDrives) /*++ Routine Description: This routine builds an array of string which contains the name of each physicaldrive present on the system. Arguments: NumberDrives Pointer to where to return the number of drives Returns: An array of strings Credit: Chuck Park, that GOD of a Programmer, wrote this and was kind enough to let me use it! --*/ { BOOL ValidDrive; TCHAR (*drivestrings)[16]; TCHAR buffer[21]; HANDLE handle; INT i = 0; *NumberDrives = 0; do { ValidDrive = FALSE; _stprintf(buffer,TEXT("\\\\.\\PhysicalDrive%d"),i); handle = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (handle != INVALID_HANDLE_VALUE) { ValidDrive = TRUE; ++(*NumberDrives); ++i; CloseHandle(handle); } } while (ValidDrive); drivestrings = malloc ((16 * *NumberDrives * sizeof(TCHAR))); if (!drivestrings) { return NULL; } for (i = 0; i < *NumberDrives; i++) { _stprintf(drivestrings[i],"PhysicalDrive%d",i); } return (TCHAR **)drivestrings; } void SetMenuBar( HWND hwnd) /*++ Routine Description: This function adds or removes the window title and the Menu bar based on the current flags. Arguments: hwnd Which window we wand to update returns: nada --*/ { static DWORD wID; DWORD dwStyle; int cy; int cx; dwStyle = GetWindowLong(hwnd,GWL_STYLE); if (PerfHist.bNoTitle) { // // Remove the caption && menu bar, etc // dwStyle &= ~ (WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); wID = SetWindowLong(hwnd, GWL_ID,0); // // Uncheck the NO_TITLE option in the file menu // CheckMenuItem(hMenuHandle, IDM_FILE_NO_TITLEBAR, MF_BYCOMMAND | MF_CHECKED); // // Change the height to better reflect the space we are using // if (PerfHist.wFormat == IDW_FULL) { cy = 440; cx = 640; } else { cx = 600; cy = 45; } } else { dwStyle |= (WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX); // // Let's only reset the ID if the current wID is NULL // if (!GetWindowLong(hwnd,GWL_ID)) { SetWindowLong(hwnd,GWL_ID,wID); SetWindowRgn(hwnd,NULL,TRUE); } // // Check the NO_TITLE option in the file menu // CheckMenuItem(hMenuHandle, IDM_FILE_NO_TITLEBAR, MF_BYCOMMAND | MF_UNCHECKED); // // Change the height to better reflect the space we are using // if (PerfHist.wFormat == IDW_FULL) { cx = 640; cy = 480; } else { cx = 600; cy = 95; } } if (PerfHist.wFormat == IDW_FULL) { // // UnCheck the SMALL_DISPLAY menu setting // CheckMenuItem(hMenuHandle, IDM_FILE_SMALL_DISPLAY, MF_BYCOMMAND | MF_UNCHECKED); } else { // // Check the SMALL_DISPLAY menu setting // CheckMenuItem(hMenuHandle, IDM_FILE_SMALL_DISPLAY, MF_BYCOMMAND | MF_CHECKED); } // // Set the new style to the window // SetWindowLong(hwnd,GWL_STYLE,dwStyle); // // Set the new size of the window. // Make sure that we don't make it noticable to the user // SetWindowPos(hwnd,NULL,0,0,cx,cy,SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); // // Force a Repaint // InvalidateRgn(hwnd,NULL,TRUE); // // Show the window // ShowWindow(hwnd,SW_SHOW); } void DrawColoredBox( int iWhich) /*++ Routine Description: This function displays one of the coloured boxes which servers as a key for the histogram Arguments: iWhich which coloured box to draw on the screen Return Value: Nothing --*/ { HDC hdcMem; HBITMAP hBitMap; HBRUSH hBrush; if (iWhich < 0 || iWhich >= boxesSize) return; hdcMem = CreateCompatibleDC(PerfHist.hdcMain); hBitMap = CreateCompatibleBitmap(PerfHist.hdcMain,boxes[iWhich].width ,boxes[iWhich].height); SelectObject(hdcMem,hBitMap); hBrush = CreateSolidBrush(boxes[iWhich].colour); SelectObject(hdcMem,hBrush); PatBlt(hdcMem, 0, 0, boxes[iWhich].width, boxes[iWhich].height, PATCOPY); BitBlt(PerfHist.hdcMem, boxes[iWhich].x, boxes[iWhich].y, boxes[iWhich].width, boxes[iWhich].height, hdcMem, 0, 0, SRCCOPY); DeleteObject(hBitMap); DeleteObject(hBrush); DeleteDC(hdcMem); } void DrawString( TEXTFORMAT *string) /*++ Routine Description: This functions displays the contents of the TEXTFORMAT record to the screen Arguments: The address of the record to print to the screen Returns: Nothing --*/ { FillRect(PerfHist.hdcMem,&string->rect,hBrush); DrawText(PerfHist.hdcMem,string->text,string->length,&string->rect,string->style); // InvalidateRect(hMainWnd,string->rect,TRUE); } void DrawXaxis( ULONG uMax) /*++ Routine Description: This function displays the number and draws the line for the xaxis portion of the histogram Arguments: uMax The largest number to display Return Value: Nothing --*/ { ULONG i,j; ULONGLONG size; ULONG index; for (i = 0; i < xaxisSize; i++) { index = uMax * i / ( xaxisSize - 1); if (xaxis[i].value.QuadPart != (LONGLONG) index) { xaxis[i].value.QuadPart = (LONGLONG) index; if (current.ioctl == IOCTL_DISK_REQUEST) { for (j = 0, size = 1;j < index; j++) size *= 2; } else { size = current.histogram->Granularity * index; } // // Lets try to figure out what kind of units we should tack // onto the end of each numbers. The best way to do that // is to work our way up the scale... // if (size < 1024) { // // It's less then 1K, so don't use anything // _stprintf(xaxis[i].text,"%ld",size); } else if (size < (1024 * 1024)) { // // It's in the 1kb-999kB range, so call it that // _stprintf(xaxis[i].text,"%ldKb",(size / 1024) ); } else if (size < (1024 * 1024 * 1024)) { // // It's in the 1Mb-999Mb Range, so call it that // _stprintf(xaxis[i].text,"%ldMb",(size / (1024 * 1024) ) ); } else { // // Its in the 1Gb+ range // _stprintf(xaxis[i].text,"%ldGb",(size / (1024 * 1024 * 1024) ) ); } xaxis[i].length = _tcslen(xaxis[i].text); DrawString(&xaxis[i]); } } // // We had better choose our title according to what we are displaying! // if (current.ioctl == IOCTL_DISK_REQUEST) { _stprintf(labels[12].text,"IO Request Size"); } else { _stprintf(labels[12].text,"Disk Location"); } labels[12].length = _tcslen(labels[12].text); DrawString(&labels[12]); } void DrawYaxis( ULONG uMax) /*++ Routine Description: This function displays the number and draws the line for the yaxis portion of the histogram Arguments: uMax The largest number to display Return Value: Nothing --*/ { ULONG i; ULONG index; if (uMax == 0) return; for (i = 0; i < yaxisSize; i++) { index = i * uMax / (yaxisSize - 1); if (yaxis[i].value.QuadPart != (LONGLONG) index) { yaxis[i].value.QuadPart = (LONGLONG) index; _stprintf(yaxis[i].text,"%ld",yaxis[i].value.QuadPart); yaxis[i].length = _tcslen(yaxis[i].text); DrawString(&yaxis[i]); } } } void DrawFont() /*++ Routine Description: This function selects the proper font into the current DC Arguments: Nothing Returns: Nothing --*/ { CHOOSEFONT cf; LOGFONT lf; HFONT hFont = NULL; HDC hDC; cf.lStructSize = sizeof(CHOOSEFONT); cf.hwndOwner = (HWND) NULL; cf.hDC = (HDC) NULL; cf.lpLogFont = &lf; cf.iPointSize = 0; cf.Flags = CF_SCREENFONTS; cf.rgbColors = RGB(0,0,0); cf.lCustData = 0L; cf.lpfnHook = (LPCFHOOKPROC) NULL; cf.lpTemplateName = (LPSTR) NULL; cf.hInstance = (HINSTANCE) NULL; cf.lpszStyle = (LPSTR) NULL; cf.nFontType = SCREEN_FONTTYPE; cf.nSizeMin = 0; cf.nSizeMax = 0; ChooseFont(&cf); hFont = CreateFontIndirect(cf.lpLogFont); if (hFont) { hMainFont = hFont; hFont = SelectObject(PerfHist.hdcMain,hMainFont); if (hFont) { DeleteObject(hFont); } hFont = SelectObject(PerfHist.hdcMem,hMainFont); if (hFont) { DeleteObject(hFont); } } else { hDC = GetDC(hMainWnd); // // Do a quick double select to remember what the main font is! // hMainFont = SelectObject(hDC,hFont); SelectObject(hDC,hMainFont); ReleaseDC(hMainWnd,hDC); } } void DrawHistogram() /*++ Routine Description: This function draws both bitmaps to the screen Arguments: none Return Value: Nothing --*/ { HDC hdcMem; HBITMAP hBitMap; ULONG i; ULONG tMax; BOOL status = FALSE; ULONGLONG lCurRead = 0; ULONGLONG lCurWrite = 0; ULONGLONG lTotRead = 0; ULONGLONG lTotWrite = 0; ULONG write; ULONG read; // // Calculate the highest area of activity // memset(pHist,0, (total.histogram->Size * sizeof(ULONG) ) ); memset(pCurr,0, (total.histogram->Size * sizeof(ULONG) ) ); total.histogram->ReadCount += current.histogram->ReadCount; total.histogram->WriteCount += current.histogram->WriteCount; for (i = tMax = 0; i < total.histogram->Size; i++) { write = current.histogram->Histogram[i].Writes; total.histogram->Histogram[i].Writes += write; lCurWrite += (write * (i+1)); lTotWrite += (total.histogram->Histogram[i].Writes * (i+1)); if (total.flags & PROCESS_WRITE) { pHist[i] += total.histogram->Histogram[i].Writes; pCurr[i] += write; } read = current.histogram->Histogram[i].Reads; total.histogram->Histogram[i].Reads += read; lCurRead += (read * (i+1)); lTotRead += (total.histogram->Histogram[i].Reads * (i+1)); if (total.flags & PROCESS_READ) { pHist[i] += total.histogram->Histogram[i].Reads; pCurr[i] += read; } if (pHist[i] > tMax) { tMax = pHist[i]; } if (pCurr[i] > cMax) { status = TRUE; cMax = pCurr[i]; } } // // Create a compatible DC // hdcMem = CreateCompatibleDC(PerfHist.hdcMain); // // Create a bitmap compatible with the current dc // hBitMap = CreateCompatibleBitmap(PerfHist.hdcMain, total.histogram->Size, cMax); // // Load the Bitmap into the temp memory we have allocated // SelectObject(hdcMem,hBitMap); // // Color the background grey in the bitmap // SelectObject(hdcMem, GetStockObject(LTGRAY_BRUSH)); // // Reset the background grey in the bitmap // status = PatBlt(hdcMem,0,0,total.histogram->Size,cMax,PATCOPY); // // Draw the Histogram, using different colored brushes where // possible // for (i = 0; i < current.histogram->Size; i++) { if (pCurr[i] <= 0) continue; else if (pCurr[i] < (cMax * 1 / 5)) SelectObject(hdcMem,hBrush1); else if (pCurr[i] < (cMax * 2 / 5)) SelectObject(hdcMem,hBrush2); else if (pCurr[i] < (cMax * 3 / 5)) SelectObject(hdcMem,hBrush3); else if (pCurr[i] < (cMax * 4 / 5)) SelectObject(hdcMem,hBrush4); else SelectObject(hdcMem,hBrush5); // // Draw the line, of the appropriate height, // remember that the bottom of the BM is the // x-axis! // PatBlt(hdcMem, i, (cMax - pCurr[i]), 1, pCurr[i], PATCOPY); } // // Perform the stretch that will dispay the bitmap insides // its proper window // status = StretchBlt(PerfHist.hdcMem, 30, 62, 600, 273, hdcMem, 0, 0, total.histogram->Size, cMax, SRCCOPY); // // Test to see if the window is currently minized // If it is, then we had better do something about it. // if (PerfHist.bIconic) { DeleteDC(hdcMem); DeleteObject(hBitMap); // // We don't need to do any more work, so stop here! // return; } // // Recalculate the various averages // read = current.histogram->Granularity; // using read as a scratch var if (current.histogram->ReadCount) { CurrentRead.QuadPart = (lCurRead * read / current.histogram->ReadCount); TotalRead.QuadPart = (lTotRead * read / total.histogram->ReadCount); } else { CurrentRead.QuadPart = 0; } if (current.histogram->WriteCount) { CurrentWrite.QuadPart = (lCurWrite * read / current.histogram->WriteCount); TotalWrite.QuadPart = (lTotWrite * read / total.histogram->WriteCount); } else { CurrentWrite.QuadPart = 0; } if (current.histogram->WriteCount || current.histogram->ReadCount) { CurrentAvg.QuadPart = (lCurRead + lCurWrite) * read / (current.histogram->ReadCount + current.histogram->WriteCount); TotalAvg.QuadPart = (lTotRead + lTotWrite) * read / (total.histogram->ReadCount + total.histogram->WriteCount); } else { CurrentAvg.QuadPart = 0; } // // Oops, we changed the size of the Yaxis. Better redraw it // if (status) DrawYaxis(cMax); SelectObject(hdcMem, GetStockObject(LTGRAY_BRUSH)); PatBlt(hdcMem,0,0,total.histogram->Size,1,PATCOPY); for (i = 0; i < total.histogram->Size; i++) { if (pHist[i] <= 0) continue; else if (pHist[i] < (tMax * 1 / 5)) SetPixelV(hdcMem,i,0,RGB(0,0,255)); else if (pHist[i] < (tMax * 2 / 5)) SetPixelV(hdcMem,i,0,RGB(0,255,0)); else if (pHist[i] < (tMax * 3 / 5)) SetPixelV(hdcMem,i,0,RGB(255,255,0)); else if (pHist[i] < (tMax * 4 / 5)) SetPixelV(hdcMem,i,0,RGB(255,0,255)); else SetPixelV(hdcMem,i,0,RGB(255,0,0)); } // // Display the bitmap in the disk usage window // making sure to only strech the appropriate space // StretchBlt(PerfHist.hdcMem, 30, 20, 600, 20, hdcMem, 0, 0, total.histogram->Size, 1, SRCCOPY); // // Release all used resources // DeleteDC(hdcMem); DeleteObject(hBitMap); } BOOL ProcessCreate( HWND hWnd, LPCREATESTRUCT lpCreateStruct) /*++ Routine Description: This routine process the WM_CREATE message send to the WndProc function. It is responsible for creating all the initial objects on the screen. Arguments: hwnd The window which is affected by the message lpCreateStruct (lParam) Returns: TRUE or FALSE --*/ { int i; hBrush = CreateSolidBrush(RGB(64,64,64)); hBrush1 = CreateSolidBrush(RGB(0,0,255)); hBrush2 = CreateSolidBrush(RGB(255,255,0)); hBrush3 = CreateSolidBrush(RGB(255,0,255)); hBrush4 = CreateSolidBrush(RGB(0,255,0)); hBrush5 = CreateSolidBrush(RGB(255,0,0)); hMenuHandle = GetMenu(hWnd); // // Create static text controls // for (i = 0; i < labelsSize; i++) { labels[i].length = _tcslen(labels[i].text); } for (i = 0; i < variablesSize; i++) { variables[i].length = _tcslen(variables[i].text); } for (i = 0; i < xaxisSize; i++) { xaxis[i].length = _tcslen(xaxis[i].text); xaxis[i].value.QuadPart = -1; } for (i = 0; i < yaxisSize; i++) { yaxis[i].length = _tcslen(yaxis[i].text); yaxis[i].value.QuadPart = -1; } // // These menu items should not be allowed right now // EnableMenuItem (hMenuHandle,IDM_OPTIONS_START,MF_GRAYED); EnableMenuItem (hMenuHandle,IDM_OPTIONS_STOP, MF_GRAYED); return TRUE; } void ProcessPaint( HWND hWnd) /*++ Routine Description: This routine handles all window paint messages. Arguments: hWnd window to redraw Returns: void --*/ { PAINTSTRUCT ps; TEXTFORMAT *tf; RECT *rc; ULONG num; ULONG i,j; BeginPaint(hMainWnd,&ps); // // Are we an icon? Gee, if so, then many we should just dump // the HISTOGRAM to the top-left corner of the screen? That // would be very smart! // if (PerfHist.bIconic) { // // We need to do a very nasty stretch-move-blit here, but hey? what // the heck? we are gods anyways! // StretchBlt(PerfHist.hdcMain, 0, 0, 36, 36, PerfHist.hdcMem, 30, 62, 600, 273, SRCCOPY); // // If we don't do an EndPaint, we will continually get WM_PAINT // messages, which is really bad, so might as well do one. // EndPaint(hMainWnd,&ps); return; } if (PerfHist.wFormat != IDW_FULL) { // // Here we are simply gonna display the main total bar in the // window, then we are gonna exit // BitBlt(PerfHist.hdcMain, 0, 0, 600, 20, PerfHist.hdcMem, 30, 20, SRCCOPY); // // Let's also display the current bar in the window, to give the user // a better idea of what is going on. // StretchBlt(PerfHist.hdcMain, 0, 25, 600, 20, PerfHist.hdcMem, 30, 334, 600, 1, SRCCOPY); EndPaint(hMainWnd,&ps); return; } // // The easiest way to do this is to check to see which regions have // changed and to update them. // // If I really analyze this code, I might discover that alot of it // is very redundant because the data is painted on the memory map // so we don't need to redraw it!!! // // However, removing this requires that other portions of the program // be updated to display the screen properly // for (i = 0; i < 4; i++) { if (i == 0) { tf = &labels[0]; num = labelsSize; } else if (i == 1) { tf = &variables[0]; num = variablesSize; } else if (i == 2) { tf = &xaxis[0]; num = xaxisSize; } else { tf = &yaxis[0]; num = yaxisSize; } for (j = 0; j < num ; j++) { rc = &tf->rect; if ( ( (rc->top > ps.rcPaint.top && rc->top < ps.rcPaint.bottom) || ( (rc->bottom) > ps.rcPaint.top && (rc->bottom) < ps.rcPaint.bottom) ) && ( (rc->left > ps.rcPaint.left && rc->left < ps.rcPaint.right) || ( (rc->right) > ps.rcPaint.left && (rc->right) < ps.rcPaint.right) ) ) { DrawString(tf); } tf++; } } for (i = 0; i < boxesSize; i++) { if ( ( (boxes[i].y > ps.rcPaint.top && boxes[i].y < ps.rcPaint.bottom) || ( (boxes[i].y + boxes[i].height) > ps.rcPaint.top && (boxes[i].y + boxes[i].height) < ps.rcPaint.bottom) ) && ( (boxes[i].x > ps.rcPaint.left && boxes[i].x < ps.rcPaint.right) || ( (boxes[i].x + boxes[i].width) > ps.rcPaint.left && (boxes[i].x + boxes[i].width) < ps.rcPaint.right) ) ) { DrawColoredBox(i); } } BitBlt(PerfHist.hdcMain, 0, 0, 640, 480, PerfHist.hdcMem, 0, 0, SRCCOPY); EndPaint(hMainWnd,&ps); } void ProcessCommand( HWND hWnd, int id, HWND hWndCtl, UINT codeNotify) /*++ Routine Description: This rouinte handles all window commands Arugments: hWnd window that sent command id command sent hWndCtl not used codeNotify not used Returns: void --*/ { DISK_HISTOGRAM tempHist; DWORD numBytes; switch(id) { case IDM_FILE_EXIT: DestroyWindow(hWnd); break; case IDM_FILE_NO_TITLEBAR: PerfHist.fDisplay = FALSE; PerfHist.bNoTitle = (PerfHist.bNoTitle ? FALSE : TRUE); SetMenuBar(hWnd); // This is the function that does the work break; case IDM_FILE_SMALL_DISPLAY: PerfHist.fDisplay = FALSE; PerfHist.wFormat = (PerfHist.wFormat == IDW_FULL ? IDW_TOTAL : IDW_FULL); SetMenuBar(hWnd); // This is the function that does the work InvalidateRgn(hMainWnd,NULL,TRUE); break; case IDM_OPTIONS_CONFIGURATION: DialogBox(hInst, MAKEINTRESOURCE(IDD_PERF_CONFIGURATION), hWnd, (DLGPROC)ConfigProc); break; case IDM_OPTIONS_CHANGEFONT: DrawFont(); InvalidateRgn(hMainWnd,NULL,TRUE); break; case IDM_OPTIONS_START: EnableMenuItem(hMenuHandle,IDM_OPTIONS_STOP, MF_ENABLED); EnableMenuItem(hMenuHandle,IDM_OPTIONS_START,MF_GRAYED); DrawMenuBar(hWnd); // // Flush the Current Values // DeviceIoControl(current.handle, current.ioctl, NULL, 0, &tempHist, DISK_HISTOGRAM_SIZE, &numBytes, NULL); SetTimer(hWnd,ID_TIMER,1000,(TIMERPROC)NULL); break; case IDM_OPTIONS_STOP: KillTimer(hWnd,ID_TIMER); EnableMenuItem(hMenuHandle,IDM_OPTIONS_STOP, MF_GRAYED); EnableMenuItem(hMenuHandle,IDM_OPTIONS_START,MF_ENABLED); DrawMenuBar(hWnd); break; default: FORWARD_WM_COMMAND(hWnd,id,hWndCtl,codeNotify,DefWindowProc); } } void ProcessDestroy( HWND hWnd) /*++ Routine Description: This is the routine that process the destroy window message Arugments: hWnd The window that is to be destroyed Returns: Nothing --*/ { DeleteObject(hMainFont); DeleteObject(hBrush); DeleteObject(hBrush1); DeleteObject(hBrush2); DeleteObject(hBrush3); DeleteObject(hBrush4); DeleteObject(hBrush5); PostQuitMessage(0); } VOID ProcessTimer( HWND hWnd, UINT id) /*++ Routine Description: This is the routine that process each timer tick. It calls a DeviceIoControl to get the latest and greatest information Arguments: hWnd The current window id not used Returns Void --*/ { DWORD numBytes; if (!DeviceIoControl(current.handle, current.ioctl, NULL, 0, current.histogram, (DISK_HISTOGRAM_SIZE + (current.histogram->Size * HISTOGRAM_BUCKET_SIZE )), &numBytes, NULL) && GetLastError() == ERROR_INVALID_FUNCTION) { KillTimer(hWnd,ID_TIMER); MessageBox(NULL, TEXT("Error obtaining histogram data."), TEXT("Error"), MB_ICONEXCLAMATION | MB_OK); return; } // // Reset the pointer to the histogram to the 'correct location' // current.histogram->Histogram = (HISTOGRAM_BUCKET *) ( (char *) current.histogram + DISK_HISTOGRAM_SIZE ); // // Draw the Histogram // DrawHistogram(); numBytes = (numBytes - DISK_HISTOGRAM_SIZE) / HISTOGRAM_BUCKET_SIZE; if (variables[8].value.QuadPart != (LONGLONG) numBytes) { variables[8].value.QuadPart = (LONGLONG) numBytes; _stprintf(variables[8].text,"%ld", variables[8].value.QuadPart); variables[8].length = _tcslen(variables[8].text); DrawString(&variables[8]); } // // Update the 'current' selections // if (variables[2].value.QuadPart != CurrentAvg.QuadPart) { variables[2].value.QuadPart = CurrentAvg.QuadPart; _stprintf(variables[2].text,"%ld",variables[2].value.QuadPart); variables[2].length = _tcslen(variables[2].text); DrawString(&variables[2]); } if (variables[3].value.QuadPart != CurrentRead.QuadPart) { variables[3].value.QuadPart = CurrentRead.QuadPart; _stprintf(variables[3].text,"%ld",variables[3].value.QuadPart); variables[3].length = _tcslen(variables[3].text); DrawString(&variables[3]); } if (variables[4].value.QuadPart != CurrentWrite.QuadPart) { variables[4].value.QuadPart = CurrentWrite.QuadPart; _stprintf(variables[4].text,"%ld",variables[4].value.QuadPart); variables[4].length = _tcslen(variables[4].text); DrawString(&variables[4]); } // // Update the 'total' selections // if (variables[5].value.QuadPart != TotalAvg.QuadPart) { variables[5].value.QuadPart = TotalAvg.QuadPart; _stprintf(variables[5].text,"%ld",variables[5].value.QuadPart); variables[5].length = _tcslen(variables[5].text); DrawString(&variables[5]); } if (variables[6].value.QuadPart != TotalRead.QuadPart) { variables[6].value.QuadPart = TotalRead.QuadPart; _stprintf(variables[6].text,"%ld",variables[6].value.QuadPart); variables[6].length = _tcslen(variables[6].text); DrawString(&variables[6]); } if (variables[7].value.QuadPart != TotalWrite.QuadPart) { variables[7].value.QuadPart = TotalWrite.QuadPart; _stprintf(variables[7].text,"%ld",variables[7].value.QuadPart); variables[7].length = _tcslen(variables[7].text); DrawString(&variables[7]); } ProcessPaint(hMainWnd); return; } BOOL APIENTRY ConfigProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) /*++ Routine Description: This is the callback routine for the configuration dialog box. Arugments: hDlg The Dialog Box uMsg The message which has been sent to the window wParam lParam Returns 0 --*/ { BOOL processed = TRUE; static int NumberOfCurrentDrives = 0; DISK_HISTOGRAM tempHist; INT noActive; INT errNum; INT i; TCHAR (*drvs)[16]; TCHAR buffer[16]; TCHAR fileName[20]; TCHAR errorBuf[64]; HDC hdc; switch(uMsg) { case WM_INITDIALOG: (char **)drvs = GetAttachedDrives(&NumberOfCurrentDrives); if (!drvs) { break; } for (i = 0; i < NumberOfCurrentDrives; i++) { SendDlgItemMessage(hDlg, IDC_PHYSICAL_DRIVE, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR)drvs[i]); } free (drvs); for (i = 0; i < typeSize; i++) { SendDlgItemMessage(hDlg, IDC_SOURCE_DATA, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR)type[i].name); } // // Diasable the OK button for now // EnableWindow(GetDlgItem(hDlg,IDOK),FALSE); processed = FALSE; break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_SOURCE_DATA: case IDC_PHYSICAL_DRIVE: if (HIWORD(wParam) == LBN_DBLCLK || HIWORD(wParam) == LBN_SELCHANGE) { if (SendDlgItemMessage(hDlg,IDC_PHYSICAL_DRIVE,LB_GETCURSEL,0,0) != LB_ERR && SendDlgItemMessage(hDlg,IDC_SOURCE_DATA, LB_GETCURSEL,0,0) != LB_ERR) { if (!IsWindowEnabled(GetDlgItem(hDlg,IDOK))) { EnableWindow(GetDlgItem(hDlg,IDOK),TRUE); } } else { if (IsWindowEnabled(GetDlgItem(hDlg,IDOK))) { EnableWindow(GetDlgItem(hDlg,IDOK),FALSE); } } } break; case IDOK: if (timerOn) { KillTimer(hMainWnd,ID_TIMER); } EnableMenuItem (hMenuHandle,IDM_OPTIONS_START,MF_ENABLED); EnableMenuItem (hMenuHandle,IDM_OPTIONS_STOP, MF_GRAYED); DrawMenuBar(hMainWnd); if (current.handle != INVALID_HANDLE_VALUE) { CloseHandle(current.handle); current.handle = INVALID_HANDLE_VALUE; } if (current.histogram != NULL) { free (current.histogram); current.histogram = NULL; } if (total.histogram != NULL) { free(total.histogram); total.histogram = NULL; } if (pHist != NULL) { free(pHist); pHist = NULL; } if (pCurr != NULL) { free(pCurr); pCurr = NULL; } noActive = SendDlgItemMessage(hDlg, IDC_PHYSICAL_DRIVE, LB_GETCURSEL, 0, 0); errNum = SendDlgItemMessage(hDlg, IDC_PHYSICAL_DRIVE, LB_GETTEXT, (WPARAM)noActive, (LPARAM)(LPCTSTR)buffer); if (errNum == LB_ERR) { _tcscpy(variables[0].text,TEXT("")); _tcscpy(variables[1].text,TEXT("")); variables[0].length = _tcslen(variables[0].text); variables[1].length = _tcslen(variables[1].text); DrawString(&variables[0]); DrawString(&variables[1]); MessageBox(NULL, TEXT("Could not retrieve text selection from dialog"), TEXT("Error"), MB_ICONEXCLAMATION | MB_OK); processed = TRUE; break; } _stprintf(fileName,TEXT("\\\\.\\")); _tcscat(fileName,buffer); current.handle = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (current.handle == INVALID_HANDLE_VALUE) { _stprintf(errorBuf, TEXT("Could not open drive: %s\n"), fileName); _tcscpy(variables[0].text,TEXT("")); _tcscpy(variables[1].text,TEXT("")); variables[0].length = _tcslen(variables[0].text); variables[1].length = _tcslen(variables[1].text); DrawString(&variables[0]); DrawString(&variables[1]); MessageBox(NULL, errorBuf, TEXT("Error"), MB_ICONEXCLAMATION | MB_OK); processed = TRUE; break; } // // Updates the displayed current drive // _tcscpy(variables[0].text,&buffer[8]); variables[0].length = _tcslen(&buffer[8]); DrawString(&variables[0]); noActive = SendDlgItemMessage(hDlg, IDC_SOURCE_DATA, LB_GETCURSEL, 0, 0); errNum = SendDlgItemMessage(hDlg, IDC_SOURCE_DATA, LB_GETTEXT, noActive, (LPARAM) (LPCTSTR) buffer); if (errNum == LB_ERR) { _tcscpy(variables[0].text,TEXT("")); _tcscpy(variables[1].text,TEXT("")); variables[0].length = _tcslen(variables[0].text); variables[1].length = _tcslen(variables[1].text); DrawString(&variables[0]); DrawString(&variables[1]); MessageBox(NULL, TEXT("Could not retrieve text selection from dialog"), TEXT("Error"), MB_ICONEXCLAMATION | MB_OK); processed = TRUE; break; } current.flags = type[noActive].flags; current.ioctl = type[noActive].ioctl; total.flags = type[noActive].flags; total.ioctl = type[noActive].ioctl; if (!DeviceIoControl(current.handle, current.ioctl, NULL, 0, &tempHist, sizeof(DISK_HISTOGRAM), &noActive, NULL)) { if (GetLastError() == ERROR_INVALID_FUNCTION) { MessageBox(NULL, TEXT("DeviceIoControl Request Failed"), TEXT("Error"), MB_ICONEXCLAMATION | MB_OK); _tcscpy(variables[0].text,TEXT("")); _tcscpy(variables[1].text,TEXT("")); variables[0].length = _tcslen(variables[0].text); variables[1].length = _tcslen(variables[1].text); DrawString(&variables[0]); DrawString(&variables[1]); CloseHandle(current.handle); EnableMenuItem (hMenuHandle,IDM_OPTIONS_START,MF_GRAYED); DrawMenuBar(hMainWnd); processed = TRUE; break; } } current.histogram = malloc( tempHist.Size * HISTOGRAM_BUCKET_SIZE + DISK_HISTOGRAM_SIZE); total.histogram = malloc( tempHist.Size * HISTOGRAM_BUCKET_SIZE + DISK_HISTOGRAM_SIZE); pHist = malloc( tempHist.Size * sizeof(ULONG) ); pCurr = malloc( tempHist.Size * sizeof(ULONG) ); if (current.histogram == NULL || total.histogram == NULL || pHist == NULL || pCurr == NULL) { MessageBox(NULL, TEXT("Could not allocate memory"), TEXT("Error"), MB_ICONEXCLAMATION | MB_OK); _tcscpy(variables[0].text,TEXT("")); _tcscpy(variables[1].text,TEXT("")); variables[0].length = _tcslen(variables[0].text); variables[1].length = _tcslen(variables[1].text); DrawString(&variables[0]); DrawString(&variables[1]); CloseHandle(current.handle); if (current.histogram) { free(current.histogram); } if (total.histogram) { free(total.histogram); } if (pHist) { free(pHist); } EnableMenuItem (hMenuHandle,IDM_OPTIONS_START,MF_GRAYED); DrawMenuBar(hMainWnd); processed = TRUE; break; } memset(current.histogram,0, ( (tempHist.Size * HISTOGRAM_BUCKET_SIZE) + DISK_HISTOGRAM_SIZE) ); memset(total.histogram, 0, ( (tempHist.Size * HISTOGRAM_BUCKET_SIZE) + DISK_HISTOGRAM_SIZE) ); current.histogram->Histogram = (PHISTOGRAM_BUCKET) ( ( char *) current.histogram + DISK_HISTOGRAM_SIZE); total.histogram->Histogram = (PHISTOGRAM_BUCKET) ( ( char *) total.histogram + DISK_HISTOGRAM_SIZE ); total.histogram->Size = tempHist.Size; current.histogram->Size = tempHist.Size; total.histogram->Granularity = tempHist.Granularity; current.histogram->Granularity = tempHist.Granularity; total.histogram->DiskSize = tempHist.DiskSize; TotalWrite.QuadPart = TotalRead.QuadPart = TotalAvg.QuadPart = 0; CurrentWrite.QuadPart = CurrentRead.QuadPart = CurrentAvg.QuadPart = 0; // // Reset the Max value in the histogram // cMax = yaxisSize; // // Display the new Xaxis // DrawXaxis(total.histogram->Size); // // Sets the Drive type text in the type window // _tcscpy(variables[1].text,buffer); variables[1].length = _tcslen(buffer); DrawString(&variables[1]); // // Reset all the other text windows // for (i = 2; i < variablesSize; i++) { _tcscpy(variables[i].text,TEXT("0")); variables[i].length = _tcslen(variables[i].text); DrawString(&variables[i]); } // // Deliberate Fall-Through -- We want to get rid of the // dialog box // case IDCANCEL: EndDialog(hDlg,TRUE); break; default: processed = FALSE; break; } default: processed = FALSE; break; } UpdateWindow(hMainWnd); return (processed); } LRESULT WINAPI WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) /*++ Routine Description: This is the main callback routine for the application. All API messages are processed by this routine. Arguments: hWnd The window which is affected by the message uMsg The message which has been sent to the window wParam Not Used lParam Not Used Returns 0 --*/ { switch(uMsg) { HANDLE_MSG(hwnd,WM_COMMAND, ProcessCommand); HANDLE_MSG(hwnd,WM_CREATE, ProcessCreate); HANDLE_MSG(hwnd,WM_PAINT, ProcessPaint); HANDLE_MSG(hwnd,WM_TIMER, ProcessTimer); HANDLE_MSG(hwnd,WM_DESTROY, ProcessDestroy); case WM_MOUSEACTIVATE: // // The right button temp. hides the window if topmost is // enabled. The window re-appears when right button is // released. When this happens, we don't want to activate // the window just before hiding it because it looks really // bad, so we intercept, the activate message. // if (GetAsyncKeyState(VK_RBUTTON) & 0x8000) { return (MA_NOACTIVATE); } else { goto DEFPROC; } break; case WM_INITMENU: PerfHist.bCantHide = TRUE; goto DEFPROC; case WM_MENUSELECT: if (LOWORD(lParam) == -1 && HIWORD(lParam) == 0) { PerfHist.bCantHide = FALSE; } goto DEFPROC; case WM_RBUTTONDOWN: case WM_NCRBUTTONDOWN: // // The right button temporarily hides the window, if the // window is topmost, and if no menu is currently 'active'. // if (!PerfHist.bTmpHide && PerfHist.bTopMost && !PerfHist.bCantHide) { ShowWindow(hwnd,SW_HIDE); SetCapture(hwnd); PerfHist.bTmpHide = TRUE; } break; case WM_RBUTTONUP: case WM_NCRBUTTONUP: // // If the window is currently hidden, right button up brings it // back. We must make sure we show it in its previous state, ie: // minized, or normal. // if (PerfHist.bTmpHide) { ReleaseCapture(); if (PerfHist.bIconic) { ShowWindow(hwnd,SW_SHOWMINNOACTIVE); } else { ShowWindow(hwnd,SW_SHOWNOACTIVATE); } PerfHist.bTmpHide = FALSE; } break; case WM_SIZE: // // If we are minimizing the window, then we should remember that. // Also, if we resize the window, we should remember that we are // no longer minized. // if (wParam == SIZE_MINIMIZED) { PerfHist.bIconic = TRUE; UpdateWindow(hwnd); } else if (PerfHist.bIconic) { InvalidateRect(hMainWnd,NULL,TRUE); PerfHist.bIconic = FALSE; UpdateWindow(hwnd); } break; case WM_KEYDOWN: // // ESC key toggles the menu/title bar (just like a double click // on the cline area of the window // if ( (wParam = VK_ESCAPE) && !(HIWORD(lParam) & 0x4000)) { goto TOGGLE_TITLE; } break; case WM_NCLBUTTONDBLCLK: if (!PerfHist.bNoTitle) { // // If we have title bars, etc, etc, let the normal stuff // take place. // goto DEFPROC; } // // Else: we don't have any title bars, etc, then this is // actually a request to bring the title bars back... // /* Fall Through */ case WM_LBUTTONDBLCLK: TOGGLE_TITLE: PerfHist.fDisplay = FALSE; PerfHist.bNoTitle = (PerfHist.bNoTitle ? FALSE : TRUE); SetMenuBar(hwnd); // This is the function that does the work break; case WM_NCHITTEST: // // If we have no title/menu bar, clicking and dragging the // client ara move sthe window. To do this, return HTCAPTION. // Note: dragging is not allowed if window maximized, or if // the caption bar is present. wParam = DefWindowProc(hwnd,uMsg,wParam,lParam); if (PerfHist.bNoTitle && (wParam == HTCLIENT) && !IsZoomed(hwnd)) { return HTCAPTION; } return wParam; case WM_SYSCOMMAND: switch (wParam) { case SC_MINIMIZE: if (!IsZoomed(hwnd)) { GetWindowRect(hwnd,&rCoordRect); } if (PerfHist.bTopMost) { PerfHist.bTopMost = FALSE; PostMessage(hwnd,WM_SYSCOMMAND, IDM_TOPMOST, 0L); } break; case SC_MAXIMIZE: if (!IsIconic(hwnd)) { GetWindowRect(hwnd,&rCoordRect); } break; case IDM_TOPMOST: { HMENU hMenu; hMenu = GetSystemMenu(hwnd,FALSE); if (PerfHist.bTopMost) { CheckMenuItem(hMenu,IDM_TOPMOST,MF_BYCOMMAND | MF_UNCHECKED); SetWindowPos(hwnd,HWND_NOTOPMOST,0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); PerfHist.bTopMost = FALSE; } else { CheckMenuItem(hMenu,IDM_TOPMOST,MF_BYCOMMAND | MF_CHECKED); SetWindowPos(hwnd,HWND_TOPMOST,0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); PerfHist.bTopMost = TRUE; } break; } default: goto DEFPROC; } goto DEFPROC; default: DEFPROC: return (DefWindowProc(hwnd,uMsg,wParam,lParam)); } return 0; }