在扩展框架中绘制会产生奇怪的颜色

Drawing in the extended frame gives strange colors

我有一个 window 的加长框架是这样制作的:

Custom Window Frame Using DWM

但是在扩展框中绘制的任何东西都有非常奇怪的颜色(除了白色,唯一保持不变的颜色),就像这样(忽略中间杂乱的内容和右边杂乱的工具栏。

粉色矩形 (0xFFC9FF) 应该是 0x8000FF。如果我将 DirectX11 内容(中心内容)放在扩展帧中,我的 FPS 计数器的 alpha 混合就会变得混乱。如果我对右侧的对话框执行相同的操作,也会发生同样的情况。

那么我怎样才能正确地做到这一点呢?我已经尝试过先绘制到内存 DC,然后再使用 BitBlt。我正在使用 GDI+(加上 CreateCompatibleDCCreateCompatibleBitmap 和其他函数来处理内存 DC)。

PS:因为你问了,这里是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);
    }
}

正如我所提到的,您几乎已经掌握了 AlphaBlend。我没能做到 remember/realize 的是您需要使用包含紫色矩形的 32 位 DibSection。您还需要确保使用 32 位感知绘图函数。这意味着您要么必须直接写入 Dib 的位,在调用 GetDIBits 检索它们之后(或在从某些位创建 DIB 之前) 您需要使用 GDI+ 来绘制紫色矩形。您可以在 WM_INITDIALOG 处理程序中看到我注释掉的代码。这给出了第二张图片中显示的结果。

在尝试了我在已删除的答案中给出的一些建议后,我发现了一个熟悉的问题。紫色矩形的颜色根据我的 window 遮挡的 window 的颜色而变化。

这是另一个代码示例,已经过测试,可以在 DWM 的 Win7s 实现下运行。我不确定 Glass 是否会有所不同,或者 Win 8 是否会有类似的表现。

这是图片:(绘制时颜色正确,使图片成为 8 位索引的图片略有更改)

请注意,编辑框中的文本有点古怪,随着 window 旁边的背景从黑色变为白色,从正常变为不正常。这与我使用 GDI 绘制紫色矩形时显示的效果相同。当我改用 GDI+ 时,问题就消失了。快速拖动 window 会使紫色框的边缘看起来有点奇怪。我认为这是 Windows7.

中 DWM 实施的众多失败之一

这是 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, mWhosebugBitmap;
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");
        mWhosebugBitmap = zCreateDibSection(NULL, 200, 50, 32);

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

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

// ** 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;
}