I have a window created with the WS_EX_LAYERED
window style. I am currently drawing onto a memory bitmap using GDI+, and using UpdateLayeredWindow
to update the graphical content of my layered window.
Here's a snippet of my code:
void Redraw(HWND hWnd, int width, int height) {
static bool floppy = true;
floppy = !floppy;
HDC hScreenDC = GetDC(HWND_DESKTOP);
HDC hMemDC = CreateCompatibleDC(hScreenDC);
HBITMAP hBmp = CreateCompatibleBitmap(hScreenDC, width, height);
HGDIOBJ hObj = SelectObject(hMemDC, hBmp);
Graphics gfx(hMemDC);
SolidBrush b(Color(254, (floppy ? 255 : 0), (floppy ? 0 : 255), 0));
gfx.FillRectangle(&b, Rect(0, 0, width, height));
BLENDFUNCTION blend;
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
POINT src = { 0, 0 };
SIZE size;
size.cx = width;
size.cy = height;
Assert(UpdateLayeredWindow(
hWnd,
hScreenDC,
NULL,
&size,
hMemDC,
&src,
RGB(0, 0, 0),
&blend,
ULW_ALPHA
));
SelectObject(hMemDC, hObj);
DeleteObject(hBmp);
DeleteDC(hMemDC);
ReleaseDC(HWND_DESKTOP, hScreenDC);
}
When creating my SolidBrush
, I specified the value of 254 for the alpha component. This results in a 99.6% opaque fill, which is not what I want.
When I specify 255 as the alpha component, there appears to be no fill; my window becomes completely transparent. This is an issue because I wish to draw shapes that are 100% opaque, but I also wish to draw some that aren't.
There seems to be some qwerks with
FillRectangle
. This becomes apparent when we observe that usingFillEllipse
with aSolidBrush
whose alpha component is 255, results in the shape being rendered perfectly (opaque).Here are two work-arounds that I came up with, which each solve the issue for me:
Call
FillRectangle
twiceSince the same area is being filled twice, they will blend and create RGB(255, 0, 0) regardless of the content behind the window (it's now 100% opaque). I do not prefer this method, as it requires every rectangle to be drawn twice.
Use
FillPolygon
insteadJust as with
FillEllipse
,FillPolygon
doesn't seem to have the colour issue, unless you call it like so:The above code will result in a 100% transparent window. I am guessing that this is either due to some form of optimisation that passes the call to
FillRectangle
instead. Or - most likely - there is some problem withFillPolygon
, which is called byFillRectangle
. However, if you add an extraPoint
to the array, you can get around it:The above code will indeed draw a 100% opaque shape, which fixes my problem.
UpdateLayeredWindow()
requires a bitmap with pre-multiplied alpha:You can use
Bitmap::ConvertFormat()
to convert a bitmap to pre-multiplied (the format isPixelFormat32bppPARGB
).