Sei sulla pagina 1di 2

winapi - Drawing a window with a standard frame and trans...

1 of 2

http://stackoverow.com/questions/29038024/drawing-a-w...

help

Drawing a window with a standard frame and transparent contents


For xtow, I want to draw a top-level window with the standard non-client area and the client area filled with a bitmap which has an alpha channel.
I now discover the way I have implemented this works on Windows 7, but doesn't render correctly on Windows 8.1, leaving behind images of
the window contents when it is moved or maximized.
To investigate, I made a simple test program alpha-test, which
Uses DwmEnableBlurBehindWindow() to set a non-intersecting blur region, so that alpha values in the window are honoured, without blur.
Uses BitBlt() to copy a bitmap with alpha into it.
//
// g++ alpha-test.cc -o alpha-test -mwindows -lgdiplus -ldwmapi
//
#define

_WIN32_WINNT 0x0600

#include
#include
#include
#include
#include

<assert.h>
<stdio.h>
<windows.h>
<gdiplus.h>
<dwmapi.h>

int width = 360;


int height = 360;
HBITMAP hBitmap;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdcUpdate = BeginPaint(hWnd, &ps);
RECT rc;
GetClientRect(hWnd, &rc);
HBRUSH hbrush = CreateSolidBrush(RGB(0,0,0));
FillRect(hdcUpdate, &rc, hbrush);
DeleteObject(hbrush);
HDC hdcMem = CreateCompatibleDC(hdcUpdate);
HBITMAP hbmpold = (HBITMAP)SelectObject(hdcMem, hBitmap);
if (!BitBlt(hdcUpdate, 0, 0, ps.rcPaint.right, ps.rcPaint.bottom, hdcMem, 0, 0,
SRCCOPY))
{
printf("BitBlt failed: 0x%08x\n", (int)GetLastError());
}
SelectObject(hdcMem, hbmpold);
DeleteDC(hdcMem);
EndPaint(hWnd, &ps);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int
nCmdShow)
{
ULONG_PTR gdiplusToken;
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
LPCTSTR szWindowClass = "TransparentClass";
// Register class
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style
= CS_HREDRAW | CS_VREDRAW; // | CS_OWNDC;
wcex.lpfnWndProc
= WndProc;
wcex.cbClsExtra
= 0;
wcex.cbWndExtra
= 0;
wcex.hInstance
= hInstance;
wcex.hIcon
= NULL;
wcex.hCursor
= LoadCursor(NULL, IDC_ARROW);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm
= NULL;
wcex.hbrBackground = (HBRUSH)CreateSolidBrush(0x00000000);
RegisterClassEx(&wcex);
// Create window
HWND hWnd = CreateWindowEx(WS_EX_APPWINDOW,

lunes, 21/mar/2016 10:07 pm

winapi - Drawing a window with a standard frame and trans...

2 of 2

http://stackoverow.com/questions/29038024/drawing-a-w...

szWindowClass,
"Transparent Window",
WS_OVERLAPPED | WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT, width, height,
NULL, NULL, hInstance, NULL);
Gdiplus::Bitmap *m_pImage = Gdiplus::Bitmap::FromFile(L"sample.png", FALSE);
Gdiplus::Color bg(0,0,0,0);
m_pImage->GetHBITMAP(bg, &hBitmap);
assert(hBitmap);
DWM_BLURBEHIND blurBehind = { 0 };
blurBehind.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
blurBehind.hRgnBlur = CreateRectRgn(0, 0, -1, -1);
blurBehind.fEnable = TRUE;
blurBehind.fTransitionOnMaximized = FALSE;
DwmEnableBlurBehindWindow(hWnd, &blurBehind);
DeleteObject(blurBehind.hRgnBlur);
ShowWindow(hWnd, SW_SHOW);
// Main message loop
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}

Is this really broken? How can I fix my code? Is this a Windows bug/limitation?
Is there another way to achieve my goal of drawing a bitmap with alpha into a window with a border?
Update: I did some tests using Direct2D and Direct3D to fill the client area with the bitmaps, but they mis-rendered in the same way.
windows

winapi
edited Aug 14 '15 at 3:10

asked Mar 13 '15 at 17:03

jturney
1,304

20

1 Answer

The DWM doesn't do blurring any more (this feature was deemed too power hungry and was
removed in Windows 8), so I'd guess that it's not properly compositing the background area of
your window any more - and therefore you aren't getting the "automatic" alpha effect it was
giving you in Windows 7.
This is kind of an unusual way to draw transparent windows to be honest. Using
UpdateLayeredWindow is the "official" way and would have the benefit of working on Windows 8
as well as Windows 7.
answered Mar 13 '15 at 20:24

Jonathan Potter
26.2k

21

44

Maybe I'm missing something, but I think that windows drawn with UpdateLayeredWindow don't get given a
frame, which makes it a bit of a non-starter for my purposes, unless there is some way around that...
jturney Mar 13 '15 at 20:30
@jturney Note that in Windows 8 you can use the WS_EX_LAYERED style on a child window, so you could
probably do this with two code paths, using your existing method for Windows 7 and earlier. Are you sure
though that you can't do it in Windows 7? (I've never actually tried enabling any of the border styles in the
window when I've done that in the past) Jonathan Potter Mar 13 '15 at 20:31

lunes, 21/mar/2016 10:07 pm

Potrebbero piacerti anche