0
votes

I am trying to display a users monitors inside a window which is all scaled down to the largest possible size. Currently it does not use a buffer and I am unsure how to create one for what I need.

As it dynamically draws the monitors, to stop having to redraw the entire window white, with WM_ERASEBKGND, when it is resized I think, after a lot of reading, that drawing a scale representation of the entire 'Virtual Desktop' as a memory DIB would be the best method: Therefore I can fill in the white space in between the monitors and thus make it not have to redraw them.

Bit of a multiple-part question. Is creating a memory scale virtual desktop as proposed that can be BitBlt to the display? To do this would I be using CreateDIBSection?

Currently my WM_PAINT looks like this:

    hdc = BeginPaint(hwnd, &ps);

    innerBorder = 2;
    additional = 350;
    ratio = (static_cast<double>(sA.getDesktop()->right - sA.getDesktop()->left) / (sA.getDesktop()->bottom - sA.getDesktop()->top));

    cxMax = max((innerBorder * 2), min((cA.right - border), (((cA.bottom - border - additional) * ratio))));
    cyMax = max((innerBorder * 2) , min((cA.bottom - border - additional), (((cA.right - border) / ratio))));

    cxBorder = (cA.right - cxMax) / 2;

    SelectObject(hdc, GetStockObject(DC_PEN));
    SelectObject(hdc, GetStockObject(DC_BRUSH));

    SetDCPenColor(hdc, RGB(255, 255, 255));

    //Draw Borders around virtual desktop
    Rectangle(hdc, cA.left, cA.top, cxBorder, cA.bottom);
    Rectangle(hdc, cA.right - cxBorder, cA.top, cA.right, cA.bottom);

    //Draw Borders around virtual desktop
    Rectangle(hdc, cxBorder, cA.top, cA.right - cxBorder, (border / 2));
    Rectangle(hdc, cxBorder, cyMax + (border / 2), cA.right - cxBorder, cA.bottom);

    for (i = 0; i < sA.getNumberOfMonitors(); i++)
    {
        rT = {
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.left - sA.getDesktop()->left) / (sA.getDesktop()->right - sA.getDesktop()->left)) * cxMax) + cxBorder + innerBorder,
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.top - sA.getDesktop()->top) / (sA.getDesktop()->bottom - sA.getDesktop()->top)) * cyMax) + (border / 2) + innerBorder,
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.right - sA.getDesktop()->left) / (sA.getDesktop()->right - sA.getDesktop()->left)) * cxMax) + cxBorder - innerBorder,
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.bottom - sA.getDesktop()->top) / (sA.getDesktop()->bottom - sA.getDesktop()->top)) * cyMax) + (border / 2) - innerBorder,
        };

        SetDCPenColor(hdc, RGB(255, 255, 255));

        //Draw Borders around Monitor RECT
        Rectangle(hdc, rT.left - innerBorder, rT.top, rT.left, rT.bottom);
        Rectangle(hdc, rT.right, rT.top, rT.right + innerBorder, rT.bottom);
        Rectangle(hdc, rT.left - innerBorder, rT.bottom, rT.right + innerBorder, rT.bottom + innerBorder);
        Rectangle(hdc, rT.left - innerBorder, rT.top - innerBorder, rT.right + innerBorder, rT.top);


        //Draw Monitor RECT
        SetDCPenColor(hdc, RGB(0, 0, 0));

        Rectangle(hdc, rT.left, rT.top, rT.right, rT.bottom);

        DrawText(hdc, sA.getMonitor(i)->szDevice, strlen(sA.getMonitor(i)->szDevice), &rT, DT_CENTER | DT_BOTTOM | DT_NOPREFIX | DT_SINGLELINE);
    }

    EndPaint(hwnd, &ps);

Most of it is just calculating the relative sizes of the monitors to the window and is very little drawing yet. I do want it to load the fill and the borders from images. I think I have pretty much hit a brick wall. I am not sure how to continue to create the memory buffer.

EDIT: One of my many attempts at creating a memory buffer, which results in a monochromatic bitmap.

    hdcDisplay = BeginPaint(hwnd, &ps);
    hdcBuffer = CreateCompatibleDC(hdcDisplay);

    innerBorder = 2;
    additional = 350;
    ratio = (static_cast<double>(sA.getDesktop()->right - sA.getDesktop()->left) / (sA.getDesktop()->bottom - sA.getDesktop()->top));

    cxMax = max((innerBorder * 2), min((cA.right - border), (((cA.bottom - border - additional) * ratio))));
    cyMax = max((innerBorder * 2) , min((cA.bottom - border - additional), (((cA.right - border) / ratio))));

    cxBorder = (cA.right - cxMax) / 2;

    hBitmapDraw = CreateCompatibleBitmap(hdcDisplay, cxMax, cyMax);
    hBitmapPrevious = static_cast<HBITMAP>(SelectObject(hdcBuffer, hBitmapDraw));
    GetObject(hBitmapDraw, sizeof(BITMAP), &bmpDraw);

    BITMAPINFOHEADER bmpInfo;

    bmpInfo.biSize = sizeof(BITMAPINFOHEADER);
    bmpInfo.biWidth = cxMax;
    bmpInfo.biHeight = cyMax;
    bmpInfo.biPlanes = 1;
    bmpInfo.biBitCount = 32;
    bmpInfo.biCompression = BI_RGB;
    bmpInfo.biSizeImage = 0;
    bmpInfo.biXPelsPerMeter = 0;
    bmpInfo.biYPelsPerMeter = 0;
    bmpInfo.biClrUsed = 0;
    bmpInfo.biClrImportant = 0;

    //pBitmapBits = (BYTE*)malloc(sizeof(BYTE)* cxMax * 3 * cyMax);
    //hBitmapDraw = CreateDIBSection(hdcDisplay, (BITMAPINFO *)&bmpInfo, DIB_RGB_COLORS, NULL, NULL, 0);
    SelectObject(hdcBuffer, hBitmapDraw);

    SelectObject(hdcBuffer, GetStockObject(DC_PEN));
    SelectObject(hdcBuffer, GetStockObject(DC_BRUSH));

    SetDCPenColor(hdcBuffer, RGB(255, 255, 255));

    for (i = 0; i < sA.getNumberOfMonitors(); i++)
    {
        rT = {
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.left - sA.getDesktop()->left) / (sA.getDesktop()->right - sA.getDesktop()->left)) * cxMax) + cxBorder + innerBorder,
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.top - sA.getDesktop()->top) / (sA.getDesktop()->bottom - sA.getDesktop()->top)) * cyMax) + (border / 2) + innerBorder,
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.right - sA.getDesktop()->left) / (sA.getDesktop()->right - sA.getDesktop()->left)) * cxMax) + cxBorder - innerBorder,
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.bottom - sA.getDesktop()->top) / (sA.getDesktop()->bottom - sA.getDesktop()->top)) * cyMax) + (border / 2) - innerBorder,
        };

        SetDCPenColor(hdcBuffer, RGB(255, 255, 255));

        //Draw Borders
        Rectangle(hdcBuffer, rT.left - innerBorder, rT.top, rT.left, rT.bottom);
        Rectangle(hdcBuffer, rT.right, rT.top, rT.right + innerBorder, rT.bottom);
        Rectangle(hdcBuffer, rT.left - innerBorder, rT.bottom, rT.right + innerBorder, rT.bottom + innerBorder);
        Rectangle(hdcBuffer, rT.left - innerBorder, rT.top - innerBorder, rT.right + innerBorder, rT.top);


        SetDCPenColor(hdcBuffer, RGB(0, 0, 0));

        Rectangle(hdcBuffer, rT.left, rT.top, rT.right, rT.bottom);

        DrawText(hdcBuffer, sA.getMonitor(i)->szDevice, strlen(sA.getMonitor(i)->szDevice), &rT, DT_CENTER | DT_BOTTOM | DT_NOPREFIX | DT_SINGLELINE);
    }

    BitBlt(hdcDisplay, cxBorder, (border / 2), cxMax - cxBorder, cyMax, hdcBuffer, cxBorder, border/2, SRCCOPY);
    SelectObject(hdcBuffer, hBitmapPrevious);
    DeleteDC(hdcBuffer);
    EndPaint(hwnd, &ps);
1

1 Answers

1
votes

You can draw into a bitmap by doing:

HDC memDC = CreateCompatibleDC(hdc);
HBITMAP memBM = CreateCompatibleBitmap(hdc, nWidth, nHeight);
SelectObject(memDC, memBM);

Just replace the hdc calls in your code with memDC. You can then call StretchBlt with the memDC as the source DC.

When you are finished with the memory DC, use DeleteDC to clean it up.

MSDN has an example of Scaling an image using this technique. You could replace the DrawBitmap code with your drawing logic.