Рисование в расширенной рамке дает странные цвета

У меня есть окно с расширенной рамкой, сделанной так:

Пользовательская оконная рама с использованием DWM

Но все, что нарисовано в расширенной рамке, имеет очень странные цвета (за исключением белого, единственного цвета, который остается неизменным), например, (игнорируйте грязный контент в центре и грязную панель инструментов справа.

Скриншот

Розовый прямоугольник (0xFFC9FF) должен был быть 0x8000FF, Если я помещу содержимое DirectX11 (центральное место) в расширенный кадр, альфа-смешение для моего счетчика FPS испортится. Если я сделаю то же самое с правым диалогом, произойдет то же самое.

Так как я могу сделать это правильно? Я уже пытался нарисовать сначала на DC памяти, а затем использовать BitBlt, Я использую GDI + (плюс CreateCompatibleDC, CreateCompatibleBitmap и другие функции для обработки памяти постоянного тока).

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

3

Решение

Как я уже говорил, вы были почти там с AlphaBlend. Однако я не смог запомнить / осознать, что вам нужно использовать 32-битный DibSection, который содержит фиолетовый прямоугольник. Вам также необходимо убедиться, что вы используете 32-битные функции рисования. Это означает, что вы должны либо записывать непосредственно в биты Dib, после их извлечения с помощью вызова GetDIBits (или до создания DIB из некоторых битов) или же вам нужно использовать GDI +, чтобы нарисовать фиолетовый прямоугольник. Вы можете увидеть мой закомментированный код в обработчике WM_INITDIALOG. Это дает результат, показанный на втором изображении.

Попробовав несколько советов, которые я дал в удаленном ответе, я обнаружил знакомую проблему. Цвет фиолетового прямоугольника менялся в зависимости от цвета окна, в котором было мое окно.

Вот еще один пример кода, который был протестирован и работает в Win7 с реализацией DWM. Я не уверен, что Glass меняет здесь ситуацию, или Win 8 будет вести себя аналогично.

Вот изображение: (При рисовании цвет был правильным, делая изображение 8-битным индексированным, оно немного изменилось)

введите описание изображения здесь введите описание изображения здесь

Обратите внимание, что текст в окне редактирования выглядит немного странно, меняется с «хорошо» на «не хорошо», так как фон под окном меняется с черного на белый. Это тот же эффект, который проявлял фиолетовый прямоугольник, когда я использовал GDI для его рисования. Когда я вместо этого использовал GDI +, проблема исчезла. Быстрое перетаскивание окна может сделать края пурпурной рамки немного странными. Я думаю, что это еще один из многих недостатков реализации DWM в Windows7.

И вот полный код этого окна:

#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

Другие решения