/*++

Copyright (c) 1990  Microsoft Corporation

Module Name:

    Draw.c

Abstract:

   Win32 application to display performance statictics. This routine implements
   graphics output for display windows.

Author:

   Mark Enstrom  (marke)

Environment:

   Win32

Revision History:

   10-07-92     Initial version



--*/

//
// set variable to define global variables
//

#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <math.h>
#include <errno.h>
#include "vdmperf.h"

extern DISPLAY_ITEM    PerfDataList[SAVE_SUBJECTS];
extern VDMPERF_INFO    VdmperfInfo;
extern PUCHAR          PerfNames[];



BOOLEAN
FitPerfWindows(
    IN  HWND            hWnd,
    IN  HDC             hDC,
    IN  PDISPLAY_ITEM   DisplayItems,
    IN  ULONG           NumberOfWindows
    )

/*++

Routine Description:

    Calculate all parameters to fit the given number of
    windows into the app window. Fill out the data structure
    for each sub-window

Arguments:

    hDC             -   Screen context
    DisplayItems    -   List of display structures
    NumberOfWindows -   Number of sub-windows

Return Value:

    Status

Revision History:

      02-17-91      Initial code

--*/

{
    RECT    ClientRect;
    int     cx,cy;
    UINT    Index;
    int     ActiveWindows,IndexX,IndexY;
    int     WindowsX,WindowsY,WindowWidth,WindowHeight;
    int     LastRowWidth,LoopWidth;
    double  fWindowsX,fActiveWindows,fcx,fcy;

    //
    //  Find out the client area bounds
    //

    GetClientRect(hWnd,&ClientRect);

    cx = ClientRect.right;
    cy = ClientRect.bottom - 2;   // subtract 2 to give a little more border

    //
    //  Find out how many perf windows are active
    //

    ActiveWindows = 0;

    for (Index=0;Index<NumberOfWindows;Index++) {
        if (DisplayItems[Index].Display == TRUE) {
            ActiveWindows++;
        }
    }

    //
    // Return if there are no active windows to display
    //

    if (ActiveWindows == 0) {
        return(TRUE);
    }


    //
    //  Now convert the window dimensions to floating point and
    //  then take the square root of the window dimension to find
    //  out the number of windows in the x direction
    //

    fActiveWindows = 1.0 * ActiveWindows;

    fcx = 1.0 * cx;
    fcy = 1.0 * cy;

    if (fcy != 0.0) {
        fWindowsX = sqrt((fcx * fActiveWindows) / fcy);
    }   else {

        //
        // If fcy = 0 then return since this is an error condition that
        // would cause a divide by zero.
        //

        return(FALSE);
    }

    //
    // convert back to integer
    //

    WindowsX = (int)fWindowsX;

    if (WindowsX == 0) {
        WindowsX = 1;
    } else if (WindowsX > ActiveWindows) {
        WindowsX = ActiveWindows;
    }

    WindowsY = ActiveWindows / WindowsX;

    //
    //  Add on extra line to Y to take care of the left over windows ie:
    //  if there are 15 active windows and the x number = 7 then y = 2 with 1
    //  left over.
    //

    Index = ActiveWindows - (WindowsX * WindowsY);

    if (Index > 0) {
        WindowsY++;
        LastRowWidth = cx / Index;
    } else {
        LastRowWidth = cx / WindowsX;
    }

    WindowWidth  = cx / WindowsX;
    WindowHeight = cy / WindowsY;

    //
    // Assign positions for each active window
    //

    Index  = 0;

    for (IndexY=0;IndexY<WindowsY;IndexY++) {
        for (IndexX=0;IndexX<WindowsX;IndexX++) {

            //
            // Find the next active display item
            //

            while ((DisplayItems[Index].Display != TRUE) && (Index < NumberOfWindows)) {
                Index++;
            }

            //
            //  Add y fixup for last row
            //

            if (IndexY == WindowsY - 1) {
                LoopWidth = LastRowWidth;
            } else {
                LoopWidth = WindowWidth;
            }


            DisplayItems[Index].PositionX = LoopWidth  * IndexX;
            DisplayItems[Index].PositionY = WindowHeight * IndexY + 1;  // +1 for more top border
            DisplayItems[Index].Width     = LoopWidth - 1;
            DisplayItems[Index].Height    = WindowHeight - 1;

            //
            // Last Column fix-up to use all of window.
            //

            if (IndexX == WindowsX - 1) {
                DisplayItems[Index].Width = cx - DisplayItems[Index].PositionX - 1;
            }

            //
            //
            //

            Index++;

            if (Index >= NumberOfWindows) {
                break;
            }

        }


        if (Index >= NumberOfWindows) {
            break;
        }


    }

    return(TRUE);
}



VOID
CalcDrawFrame(
    PDISPLAY_ITEM   DisplayItem
    )
/*++

Routine Description:

    Calculate all borders for graphics windows

Arguments:

    DisplayItem - Data structure with all perf window info

Return Value:

   status of operation


Revision History:

      03-21-91      Initial code

--*/

{
    LONG    x1,x2,y1,y2;
    LONG    gx1,gx2,gy1,gy2;
    LONG    tx1,tx2,ty1,ty2;
    LONG    GraphHeight,TextHeight;
    BOOLEAN TextWindow;

    double  fx1,fx2,fy1;

    //
    // Draw a 3-d stand out box around item window
    //

    x1 = DisplayItem->PositionX + 2;
    x2 = DisplayItem->PositionX + DisplayItem->Width - 2;
    y1 = DisplayItem->PositionY + 2;
    y2 = DisplayItem->PositionY + DisplayItem->Height - 2;

    //
    // find out in there is enough space for a text window
    //

    if ((y2 - y1 - 12) > 30) {

        TextWindow = TRUE;

        //
        // Calculate dimensions for a text window and a graphics window
        //
        // fx1 = portion of the window - bordres and free space
        //
        // fx2 = fraction of window used for graphics
        //
        // fy1 = fraction of winddow used for text
        //

        fx1 = (y2 - y1 - 10);

        fx2 = fx1 * 0.6666;
        fy1 = fx1 * 0.3333;

        GraphHeight = (LONG)fx2;
        TextHeight  = (LONG)fy1;

        if (TextHeight > 20) {
            GraphHeight += TextHeight-20;
            TextHeight = 20;
        }

        //
        // Calculate window boundaries
        //

        gx1 = x1 + 4;
        gx2 = x2 - 4;
        gy1 = y1 + 4;
        gy2 = y1 + 4 + GraphHeight + 1;

        tx1 = x1 + 4;
        tx2 = x2 - 4;
        ty1 = gy2 + 1 + 2 + 1;  // border,free space,border
        ty2 = gy2 + TextHeight + 1;

    }   else {

        TextWindow = FALSE;
        GraphHeight = y2 - y1 - 10;
        gx1 = x1 + 4;
        gx2 = x2 - 4;
        gy1 = y1 + 4;
        gy2 = y2 - 4;
        tx1 = tx2 = ty1 = ty2 = 0;

    }

    //
    // Fill in structures for drawing text and graphics
    //

    DisplayItem->Border.left        = x1;
    DisplayItem->Border.right       = x2;
    DisplayItem->Border.top         = y1;
    DisplayItem->Border.bottom      = y2;

    DisplayItem->GraphBorder.left   = gx1;
    DisplayItem->GraphBorder.right  = gx2;
    DisplayItem->GraphBorder.top    = gy1;
    DisplayItem->GraphBorder.bottom = gy2;

    DisplayItem->TextBorder.left    = tx1;
    DisplayItem->TextBorder.right   = tx2;
    DisplayItem->TextBorder.top     = ty1;
    DisplayItem->TextBorder.bottom  = ty2;
}




VOID
DrawFrame(
    HDC             hDC,
    PDISPLAY_ITEM   DisplayItem
    )
/*++

Routine Description:

    Draw the window frame for a performance window

Arguments:

    hDC         - Device Context for window
    DisplayItem - Data structure with all perf window info

Return Value:

   status of operation


Revision History:

      03-21-91      Initial code

--*/

{
    RECT    DrawRect;
    LONG    x1,x2,y1,y2;
    LONG    gx1,gx2,gy1,gy2;
    LONG    tx1,tx2,ty1,ty2;

    //
    // Draw a 3-d stand out box around item window
    //

    x1 = DisplayItem->Border.left;
    x2 = DisplayItem->Border.right;
    y1 = DisplayItem->Border.top;
    y2 = DisplayItem->Border.bottom;

    gx1 = DisplayItem->GraphBorder.left;
    gx2 = DisplayItem->GraphBorder.right;
    gy1 = DisplayItem->GraphBorder.top;
    gy2 = DisplayItem->GraphBorder.bottom;

    tx1 = DisplayItem->TextBorder.left;
    tx2 = DisplayItem->TextBorder.right;
    ty1 = DisplayItem->TextBorder.top;
    ty2 = DisplayItem->TextBorder.bottom;

    //
    // Draw top border in light shade
    //

    DrawRect.left   = x1;
    DrawRect.right  = x2;
    DrawRect.top    = y1;
    DrawRect.bottom = y1 + 2;

    FillRect(hDC,&DrawRect,VdmperfInfo.hLightBrush);

    //
    // Draw Left border in light shade
    //

    DrawRect.left   = x1;
    DrawRect.right  = x1 + 2;
    DrawRect.top    = y1;
    DrawRect.bottom = y2;

    FillRect(hDC,&DrawRect,VdmperfInfo.hLightBrush);

    //
    // Draw right border in dark shade
    //


    DrawRect.left   = x2 - 2;
    DrawRect.right  = x2;
    DrawRect.top    = y1;
    DrawRect.bottom = y2;

    FillRect(hDC,&DrawRect,VdmperfInfo.hDarkBrush);

    //
    // draw bottom in dark shade
    //

    DrawRect.left   = x1;
    DrawRect.right  = x2;
    DrawRect.top    = y2-2;
    DrawRect.bottom = y2;

    FillRect(hDC,&DrawRect,VdmperfInfo.hDarkBrush);

    //
    // Draw graphics area single border
    //

    //
    // Draw top border in dark shade
    //

    DrawRect.left   = gx1;
    DrawRect.right  = gx2;
    DrawRect.top    = gy1;
    DrawRect.bottom = gy1+1;

    FillRect(hDC,&DrawRect,VdmperfInfo.hDarkBrush);

    //
    // Draw Left border in Dark shade
    //

    DrawRect.left   = gx1;
    DrawRect.right  = gx1 + 1;
    DrawRect.top    = gy1;
    DrawRect.bottom = gy2;

    FillRect(hDC,&DrawRect,VdmperfInfo.hDarkBrush);

    //
    // Draw right border in Light shade
    //


    DrawRect.left   = gx2 - 1;
    DrawRect.right  = gx2;
    DrawRect.top    = gy1;
    DrawRect.bottom = gy2;

    FillRect(hDC,&DrawRect,VdmperfInfo.hLightBrush);

    //
    // draw bottom in Light shade
    //

    DrawRect.left   = gx1;
    DrawRect.right  = gx2;
    DrawRect.top    = gy2-1;
    DrawRect.bottom = gy2;

    FillRect(hDC,&DrawRect,VdmperfInfo.hLightBrush);

    if (tx2 > 0) {

        //
        // Draw top border in Dark shade
        //

        DrawRect.left   = tx1;
        DrawRect.right  = tx2;
        DrawRect.top    = ty1;
        DrawRect.bottom = ty1 + 1;

        FillRect(hDC,&DrawRect,VdmperfInfo.hDarkBrush);

        //
        // Draw Left border in Dark shade
        //

        DrawRect.left   = tx1;
        DrawRect.right  = tx1 + 1;
        DrawRect.top    = ty1;
        DrawRect.bottom = ty2;

        FillRect(hDC,&DrawRect,VdmperfInfo.hDarkBrush);

        //
        // Draw right border in Light shade
        //


        DrawRect.left   = tx2 - 1;
        DrawRect.right  = tx2;
        DrawRect.top    = ty1;
        DrawRect.bottom = ty2;

        FillRect(hDC,&DrawRect,VdmperfInfo.hLightBrush);

        //
        // draw bottom in Light shade
        //

        DrawRect.left   = tx1;
        DrawRect.right  = tx2;
        DrawRect.top    = ty2-1;
        DrawRect.bottom = ty2;

        FillRect(hDC,&DrawRect,VdmperfInfo.hLightBrush);

    }
}




VOID
DrawPerfText(
    HDC             hDC,
    PDISPLAY_ITEM   DisplayItem,
    UINT            Item
    )
/*++

Routine Description:

    Draw text into the perf window

Arguments:

    hDC         - Device Context for window
    DisplayItem - Data structure with all perf window info

Return Value:

   status of operation


Revision History:

      03-21-91      Initial code

--*/

{
    RECT    TextRect;
    UCHAR   TextStr[50];
    UINT    FontSize;

    //
    // Check that text display is enabled
    //

    if (DisplayItem->TextBorder.right == 0) {
        return;
    }

    TextRect.left = DisplayItem->TextBorder.left +1;
    TextRect.right = DisplayItem->TextBorder.right -1;
    TextRect.top = DisplayItem->TextBorder.top +1;
    TextRect.bottom = DisplayItem->TextBorder.bottom -1;

    FillRect(hDC,&TextRect,VdmperfInfo.hBackground);

    SetBkColor(hDC,RGB(192,192,192));

    //
    //  Decide which font to draw with
    //

    FontSize =  TextRect.bottom - TextRect.top;

    if (FontSize >= 15) {
        VdmperfInfo.hOldFont = SelectObject(hDC,VdmperfInfo.LargeFont);
    } else if (FontSize > 10) {
        VdmperfInfo.hOldFont = SelectObject(hDC,VdmperfInfo.MediumFont);
    } else {
        VdmperfInfo.hOldFont = SelectObject(hDC,VdmperfInfo.SmallFont);
    }

    DrawText(
                hDC,
                PerfNames[Item],
                strlen(PerfNames[Item]),
                &TextRect,
                DT_LEFT | DT_VCENTER | DT_SINGLELINE
             );


    //
    // Build the numeric value
    //

    wsprintf(TextStr,"   %li",DisplayItem->TotalTime[0]);

    DrawText(
                hDC,
                TextStr,
                strlen(TextStr),
                &TextRect,
                DT_RIGHT | DT_VCENTER | DT_SINGLELINE
             );




    SelectObject(hDC,VdmperfInfo.hOldFont);

}





VOID
DrawPerfGraph(
    HDC             hDC,
    PDISPLAY_ITEM   DisplayItem
    )
/*++

Routine Description:

    Draw graphics into the perf window

Arguments:

    hDC         - Device Context for window
    DisplayItem - Data structure with all perf window info

Return Value:

   status of operation


Revision History:

      03-21-91      Initial code

--*/

{
    RECT    GraphRect,MemGraphRect;
    ULONG   Scale,i,GraphWidth,GraphHeight;



    GraphRect.left   = DisplayItem->GraphBorder.left   + 1;
    GraphRect.right  = DisplayItem->GraphBorder.right  - 1;
    GraphRect.top    = DisplayItem->GraphBorder.top    + 1;
    GraphRect.bottom = DisplayItem->GraphBorder.bottom - 1;

    GraphWidth  = GraphRect.right  - GraphRect.left -1;
    GraphHeight = GraphRect.bottom - GraphRect.top -1;

    //
    // Memory bitmap is zero-offset for all windows, add 1 to make fillrect fill out
    // to right and bottom edge
    //

    MemGraphRect.left   = 0;
    MemGraphRect.right  = GraphWidth +1;
    MemGraphRect.top    = 0;
    MemGraphRect.bottom = GraphHeight +1;

    FillRect(DisplayItem->MemoryDC,&MemGraphRect,VdmperfInfo.hBackground);

    MemGraphRect.right  = GraphWidth;
    MemGraphRect.bottom = GraphHeight;

    if (DisplayItem->Max == 0) {
        DisplayItem->Max = 1;
    }

    //
    // calculate scale from data to perf window
    //

    //
    //  Outline object in green
    //



    SelectObject(DisplayItem->MemoryDC,VdmperfInfo.hRedPen);

    //
    // X scale factor (100 items in x space). Scale can not be less than 1
    //

    Scale = (GraphWidth -1)/ DATA_LIST_LENGTH;
    if (Scale == 0) {
        Scale = 1;
    }


    MoveToEx(DisplayItem->MemoryDC,
             MemGraphRect.right,
             MemGraphRect.bottom - (DisplayItem->TotalTime[0] * GraphHeight)/ DisplayItem->Max,
             (LPPOINT)NULL);




    for (i=1;((i<DATA_LIST_LENGTH) && i*Scale < GraphWidth);i++) {
        LineTo(DisplayItem->MemoryDC,
               MemGraphRect.right - Scale * i,
               MemGraphRect.bottom - (DisplayItem->TotalTime[i] * GraphHeight)/DisplayItem->Max);

    }

    //
    //  Draw UserTime if needed
    //

    if (DisplayItem->NumberOfElements>1) {

        //
        // Select kernel pen
        //

        SelectObject(DisplayItem->MemoryDC,VdmperfInfo.hRedPen);

        MoveToEx(DisplayItem->MemoryDC,
             MemGraphRect.right,
             MemGraphRect.bottom - (DisplayItem->KernelTime[0] * GraphHeight)/ DisplayItem->Max,
             (LPPOINT)NULL);




        for (i=1;((i<DATA_LIST_LENGTH) && i*Scale < GraphWidth);i++) {
            LineTo(DisplayItem->MemoryDC,
                    MemGraphRect.right - Scale * i,
                    MemGraphRect.bottom - (DisplayItem->KernelTime[i] * GraphHeight)/DisplayItem->Max
               );

        }

        //
        // Select User Pen
        //

        SelectObject(DisplayItem->MemoryDC,VdmperfInfo.hGreenPen);

        MoveToEx(DisplayItem->MemoryDC,
             MemGraphRect.right,
             MemGraphRect.bottom - (DisplayItem->UserTime[0] * GraphHeight)/ DisplayItem->Max,
             (LPPOINT)NULL);

        for (i=1;((i<DATA_LIST_LENGTH) && i * Scale < GraphWidth);i++) {
            LineTo(DisplayItem->MemoryDC,
               MemGraphRect.right - Scale * i,
               MemGraphRect.bottom - (DisplayItem->UserTime[i] * GraphHeight)/DisplayItem->Max);

        }
    }


    BitBlt(
            hDC,
            GraphRect.left,
            GraphRect.top,
            GraphWidth+1,
            GraphHeight+1,
            DisplayItem->MemoryDC,
            0,
            0,
            SRCCOPY);


}

VOID
ShiftPerfGraph(
    HDC             hDC,
    PDISPLAY_ITEM   DisplayItem
    )
/*++

Routine Description:

    Shift memory bitmap 1 location left then draw the 1 new data point.
    BitBlt this to the screen.


Arguments:

    hDC         - Device Context for window
    DisplayItem - Data structure with all perf window info

Return Value:

   status of operation


Revision History:

      03-21-91      Initial code

--*/

{
    RECT    GraphRect,MemGraphRect,FillArea;
    ULONG   Scale,GraphWidth,GraphHeight;



    GraphRect.left   = DisplayItem->GraphBorder.left   + 1;
    GraphRect.right  = DisplayItem->GraphBorder.right  - 1;
    GraphRect.top    = DisplayItem->GraphBorder.top    + 1;
    GraphRect.bottom = DisplayItem->GraphBorder.bottom - 1;

    GraphWidth  = GraphRect.right  - GraphRect.left -1;
    GraphHeight = GraphRect.bottom - GraphRect.top -1;

    //
    // Memory bitmap is zero-offset for all windows, add 1 to make fillrect fill out
    // to right and bottom edge
    //

    MemGraphRect.left   = 0;
    MemGraphRect.right  = GraphWidth;
    MemGraphRect.top    = 0;
    MemGraphRect.bottom = GraphHeight;

    if (DisplayItem->Max == 0) {
        DisplayItem->Max = 1;
    }

    //
    // calculate scale from data to perf window
    //
    // X scale factor (100 items in x space). Scale can not be less than 1
    //

    Scale = (GraphWidth -1)/ DATA_LIST_LENGTH;
    if (Scale == 0) {
        Scale = 1;
    }

    //
    // Shift memory image left by scale
    //


    BitBlt( DisplayItem->MemoryDC,
            0,
            0,
            GraphWidth+1 - Scale,
            GraphHeight+1,
            DisplayItem->MemoryDC,
            Scale,
            0,
            SRCCOPY);


    //
    // Fill The new area on the right of the screen
    //

    FillArea.left   = GraphWidth +1 - Scale;
    FillArea.right  = GraphWidth +1;
    FillArea.top    = 0;
    FillArea.bottom = GraphHeight +1;

    FillRect(DisplayItem->MemoryDC,&FillArea,VdmperfInfo.hBackground);


    //
    // Draw the 1 new data point
    //

    SelectObject(DisplayItem->MemoryDC,VdmperfInfo.hRedPen);

    MoveToEx(DisplayItem->MemoryDC,
             MemGraphRect.right,
             MemGraphRect.bottom - (DisplayItem->TotalTime[0] * GraphHeight)/ DisplayItem->Max,
             (LPPOINT)NULL);




    LineTo(DisplayItem->MemoryDC,
            MemGraphRect.right - Scale,
            MemGraphRect.bottom - (DisplayItem->TotalTime[1] * GraphHeight)/DisplayItem->Max);


    //
    //  Draw UserTime if needed
    //

    if (DisplayItem->NumberOfElements>1) {

        //
        // Select kernel pen
        //

        SelectObject(DisplayItem->MemoryDC,VdmperfInfo.hRedPen);

        MoveToEx(DisplayItem->MemoryDC,
             MemGraphRect.right,
             MemGraphRect.bottom - (DisplayItem->KernelTime[0] * GraphHeight)/ DisplayItem->Max,
             (LPPOINT)NULL);




        LineTo(
                DisplayItem->MemoryDC,
                MemGraphRect.right - Scale,
                MemGraphRect.bottom - (DisplayItem->KernelTime[1] * GraphHeight)/DisplayItem->Max
              );

        //
        // Select User Pen
        //

        SelectObject(DisplayItem->MemoryDC,VdmperfInfo.hGreenPen);

        MoveToEx(
                    DisplayItem->MemoryDC,
                    MemGraphRect.right,
                    MemGraphRect.bottom - (DisplayItem->UserTime[0] * GraphHeight)/ DisplayItem->Max,
                    (LPPOINT)NULL
                 );

        LineTo(
                DisplayItem->MemoryDC,
                MemGraphRect.right - Scale,
                MemGraphRect.bottom - (DisplayItem->UserTime[1] * GraphHeight)/DisplayItem->Max
              );

    }


    BitBlt(
            hDC,
            GraphRect.left,
            GraphRect.top,
            GraphWidth+1,
            GraphHeight+1,
            DisplayItem->MemoryDC,
            0,
            0,
            SRCCOPY);


}



BOOLEAN
CreateMemoryContext(
    HDC             hDC,
    PDISPLAY_ITEM   DisplayItem
    )
/*++

Routine Description:

    Create a memory context and a memory bitmap for each perf window



Arguments:

    hDC         - Device Context for window
    DisplayItem - Data structure with all perf window info

Return Value:

   status of operation


Revision History:

      03-21-91      Initial code

--*/

{

    int     Width;
    int     Height;

    if (DisplayItem->Display == TRUE) {

        //
        //  Calculate width of memory bitmap needed
        //

        Width  = DisplayItem->GraphBorder.right - DisplayItem->GraphBorder.left;
        Height = DisplayItem->GraphBorder.bottom - DisplayItem->GraphBorder.top;

        if ((Width<=0) || (Height <= 0)) {

            //
            // Disable this window that is to small to be seen
            //

            DisplayItem->Display = FALSE;

            return(TRUE);
        }

        //
        //  Create DC and Bitmap
        //

        DisplayItem->MemoryDC     = CreateCompatibleDC(hDC);

        if (DisplayItem->MemoryDC == NULL) {
            return(FALSE);
        }

        //DbgPrint("Createcompatiblebitmap %i %i\n",Width,Height);

        DisplayItem->MemoryBitmap = CreateCompatibleBitmap(hDC,Width,Height);

        if (DisplayItem->MemoryBitmap == 0) {
            return(FALSE);
        }

        SelectObject(DisplayItem->MemoryDC,DisplayItem->MemoryBitmap);

    }

    return(TRUE);
}



VOID
DeleteMemoryContext(
    PDISPLAY_ITEM   DisplayItem
    )
/*++

Routine Description:

    Delete memory bitmap and context

Arguments:

    hDC         - Device Context for window
    DisplayItem - Data structure with all perf window info

Return Value:

   status of operation


Revision History:

      03-21-91      Initial code

--*/

{

    if (DisplayItem->MemoryDC != NULL) {
        DeleteDC(DisplayItem->MemoryDC);
    }

    if (DisplayItem->MemoryBitmap != NULL) {
        DeleteObject(DisplayItem->MemoryBitmap);
    }

}