Extended frame painting produces strange colors

I have an extended frame window done like this:

Custom window frame using DWM

But everything drawn in the extended frame has very strange colors (other than white, the only color that remains the same) like this (ignore the messy content in the center and the messy toolbar on the right.

Screenshot

The pink rectangle ( 0xFFC9FF

) should have been 0x8000FF

. If I put DirectX11 content (focal point) in an extended frame the alpha blending for my FPS counter gets messed up. If I do the same in the correct dialog box, then it happens.

So how can I make it right? I've already tried to draw first in DC memory and then use BitBlt

. I am using GDI + (plus CreateCompatibleDC

, CreateCompatibleBitmap

and other functions for handling DC memory).

PS: Because you asked, here is WndProc

:

LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    LRESULT ReturnValue;
    if (DwmDefWindowProc(hWnd, uMsg, wParam, lParam, &ReturnValue)) return ReturnValue;

    switch (uMsg)
    {
    case WM_CREATE:
    {
        // ...

        RECT rcClient;
        GetWindowRect(hWnd, &rcClient);

        SetWindowPos(hWnd,
            NULL,
            rcClient.left, rcClient.top,
            rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
            SWP_FRAMECHANGED);

        return 0;
    }
    case WM_ACTIVATE:
    {
        MARGINS Margins;
        Margins.cxLeftWidth = LEFT_BORDER;
        Margins.cxRightWidth = RIGHT_BORDER;
        Margins.cyTopHeight = TOP_BORDER;
        Margins.cyBottomHeight = BOTTOM_BORDER;
        if (DwmExtendFrameIntoClientArea(hWnd, &Margins) != S_OK)
        {
            MessageBox(hWnd, L"Erro ao configurar janela.", NULL, MB_ICONERROR);
            PostQuitMessage(WM_QUIT);
        }

        if (LOWORD(wParam))
        {
            fActive = true;
        }
        else
        {
            fActive = false;
        }
        InvalidateRect(hWnd, NULL, false);

        return 0;
    }

    case WM_SIZE:
        /* ... */

    case WM_NCCALCSIZE:
        return 0;

    case WM_NCHITTEST:
        /* ... */

    case WM_GETMINMAXINFO:
        ((LPMINMAXINFO)lParam)->ptMinTrackSize = { 640, 400 };
        return 0;

    case WM_PAINT:
    {
        using namespace Gdiplus;

        PAINTSTRUCT ps;
        HDC hDC = BeginPaint(hWnd, &ps);

        RECT rcWindow;
        GetWindowRect(hWnd, &rcWindow);
        POINT ptSize = { rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top };

        HDC hBuffer = CreateCompatibleDC(hDC);
        HBITMAP hBitmap = CreateCompatibleBitmap(hDC, ptSize.x, ptSize.y);
        SelectObject(hBuffer, hBitmap);

        Graphics graphics(hBuffer);
        Pen Outline(Color(128, 128, 128));
        SolidBrush Selected(Color(128, 0, 255));
        Rect Tab1(10, 10, 200, 50);

        graphics.FillRectangle(&Selected, Tab1);
        graphics.DrawRectangle(&Outline, Tab1);

        /* ... */

        BitBlt(hDC, 0, 0, ptSize.x, ptSize.y, hBuffer, 0, 0, SRCCOPY);

        EndPaint(hWnd, &ps);
        return 0;
    }

    /* ... */

    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
}

      

+3


source to share


1 answer


As I said, you were almost there with AlphaBlend. What I didn't remember / understood was that you need to use a 32-bit DibSection that contains a purple rectangle. You also need to make sure you are using 32 bit drawing functions. This means that you either need to write directly to the Dib bits, after getting them with a GetDIBits call (or before creating a DIB from some bits), or you need to use GDI + to draw a purple rectangle. You can see my code with comments in the WM_INITDIALOG handler. This gives the result shown in the second image.

After trying a few tips I gave in the answer that I've since removed, I came across a familiar problem. The color of the purple rectangle changed depending on the color of the window that my window was darkening.

Here is another sample code that has been tested and works under Win7s DWM. I'm not sure if Glass matters here, or if Win 8 will behave in a similar way.

Here's the image: (Color was correct when drawing, making the image 8-bit indexed, changed it a bit)



enter image description hereenter image description here

Note that the text in the edit box is a little flustered, changing it in order not to be good as the background under the window changes from black to white. This is the same effect as the purple rectangle when I used GDI to draw it. When I used GDI + the problem went away. Dragging the window quickly can make the edges of the magenta window look a little odd. I think this is another of the many disadvantages of the Windows7 DWM implementation.

And here is the complete code for that window:

#define _WIN32_IE 0x0501
#define _WIN32_WINNT 0x0501
#define WINVER 0x0510

#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include "resource.h"
#include <dwmapi.h>
#include <gdiplus.h>
#include <wingdi.h>
using namespace Gdiplus;
HINSTANCE hInst;

// BMP, GIF, JPEG, PNG, TIFF, Exif, WMF, and EMF
HBITMAP mLoadImageFile(wchar_t *filename)
{
    HBITMAP result = NULL;
    Bitmap bitmap(filename, false);
    Color colBkg(0,0,0,0);
    bitmap.GetHBITMAP(colBkg, &result);
    return result;
}

HBITMAP zCreateDibSection(HDC hdc, int width, int height, int bitCount)
{
    BITMAPINFO bi;
    ZeroMemory(&bi, sizeof(bi));
    bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
    bi.bmiHeader.biWidth = width;
    bi.bmiHeader.biHeight = height;
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biBitCount = bitCount;
    bi.bmiHeader.biCompression = BI_RGB;
    return CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, 0,0,0);
}

HRESULT ExtendGlassIntoClient(HWND hwnd, int left, int right, int top, int bottom)
{
   MARGINS margins = {left,right,top,bottom};
   HRESULT hr = S_OK;

   hr = DwmExtendFrameIntoClientArea(hwnd,&margins);
   if (SUCCEEDED(hr))
   {
      // ...
   }
   return hr;
}

HBITMAP mImg, mStackOverflowBitmap;
HDC memDC, memDC2;
HBITMAP oldBmp, oldBmp2;
LRESULT CALLBACK DlgMain(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_INITDIALOG:
    {
        ExtendGlassIntoClient(hwndDlg, 0,0,50,0);
        mImg = mLoadImageFile(L"girl.png");
        mStackOverflowBitmap = zCreateDibSection(NULL, 200, 50, 32);

        memDC = CreateCompatibleDC(NULL);
        memDC2 = CreateCompatibleDC(NULL);

        oldBmp = (HBITMAP)SelectObject(memDC, mImg);
        oldBmp2 = (HBITMAP)SelectObject(memDC2, mStackOverflowBitmap);

// ** DOESNT WORK ** - produces a washed-out pink rectangle *****
//        HBRUSH mBrush = CreateSolidBrush( RGB(128,0,255) );
//        RECT mRect = {0,0,200,50};
//        FillRect(memDC2, &mRect, mBrush);
//        DeleteObject(mBrush);

            Color mCol(255,128,0,255);
            SolidBrush mBrush(mCol);
            Graphics graphics(memDC2);
            graphics.FillRectangle(&mBrush, (int)0, (int)0, 200, 50);

    }
    return TRUE;

    case WM_ERASEBKGND:
        {
            HDC hdc;
            RECT mRect, topRect;
            hdc = (HDC)wParam;
            GetClientRect(hwndDlg, &mRect);
            topRect = mRect;
            topRect.bottom = 50;
            FillRect(hdc, &topRect, (HBRUSH)GetStockObject(BLACK_BRUSH));
            mRect.top += 50;
            FillRect(hdc, &mRect, (HBRUSH)GetStockObject(WHITE_BRUSH));

            BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
            AlphaBlend(hdc, 0,0, 55,96, memDC, 0, 0, 55,96, bf);

            AlphaBlend(hdc, 100,32,200,50, memDC2, 0,0,200,50, bf);

            return 1;
        }


    case WM_CLOSE:
    {
        EndDialog(hwndDlg, 0);
    }
    return TRUE;

    case WM_COMMAND:
    {
        switch(LOWORD(wParam))
        {
        }
    }
    return TRUE;
    }
    return FALSE;
}


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR           gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

        hInst=hInstance;
        InitCommonControls();
        int retVal = DialogBox(hInst, MAKEINTRESOURCE(DLG_MAIN), NULL, (DLGPROC)DlgMain);

    GdiplusShutdown(gdiplusToken);
    return retVal;
}

      

+3


source







All Articles