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

标签 c++ winapi dwm

我有一个带有扩展框架的窗口,如下所示:

Custom Window Frame Using DWM

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

Screenshot

粉色矩形 (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。我没有记住/意识到的是,您需要使用一个包含紫色矩形的 32 位 DibSection。您还需要确保使用 32 位感知绘图函数。这意味着您必须直接写入 Dib 的位,在调用 GetDIBits 检索它们之后(或在从某些位创建 DIB 之前)您需要使用 GDI+ 绘制紫色矩形。您可以在 WM_INITDIALOG 处理程序中看到我注释掉的代码。这给出了第二张图片中显示的结果。

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

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

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

enter image description here enter image description here

请注意,编辑框中的文本有点古怪,随着窗口背景从黑色变为白色而从 okay 变为 not okay。这与我使用 GDI 绘制紫色矩形时显示的效果相同。当我改用 GDI+ 时,问题就消失了。快速拖动窗口会使紫色框的边缘显得有些奇怪。我认为这是 Windows7 中 DWM 实现的众多失败之一。

下面是这个窗口的完整代码:

#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;
}

关于c++ - 在扩展框架中绘制会产生奇怪的颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31093494/

相关文章:

C++ 设计多层通信的软件架构

c++ - 如何使用 Doxygen 记录应用程序源文件

c++ - 将转义的 UTF-8 八位字节的字符数组转换为 C++ 中的字符串

c++ - 为什么 SetScrollInfo() 函数会向 WndProc() 发送 WM_SIZE 消息?

c++ - 应用程序无法从 WinSxS 加载 Win32 程序集

windows - 在 Win32 应用程序中模仿 Acrylic

c++ - 为什么类成员函数会影响同名的自由函数?

c++ - 如何检测 win32 NTFS 下的文件移动?

c - 读出 Thunderbird 未读邮件? (Linux、终端)

c# - WINAPI/DWMAPI 不规则形状的模糊窗口