My system is Windows 7 and i want to use Direct2D for a toolkit project.
I want to create a window which is per-pixel transparent/translucent (we can see windows transparently or translucently which are below my window) in some parts of the window.
I've looked at https://learn.microsoft.com/en-us/archive/msdn-magazine/2014/june/windows-with-c-high-performance-window-layering-using-the-windows-composition-engine (see the image at the very bottom of this web page) and it seems that it is possible, but only with the extended window style WS_EX_NOREDIRECTIONBITMAP, which is not available on Win7 (only since win8).
I've tried to use a render target which is bgra with premultiplied alpha and an extended window style WS_EX_COMPOSITED | WS_EX_TRANSPARENT without luck
here is my code (the relevant code, that is creation of render target and layout, is in the render() function):
#include <iostream>
#ifdef _WIN32_WINNT
# undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x602
#include <d2d1.h>
static HINSTANCE instance = NULL;
static HWND win = NULL;
static ID2D1Factory *factory = NULL;
static ID2D1HwndRenderTarget *rt = NULL;
LRESULT CALLBACK _window_procedure(HWND window,
UINT message,
WPARAM window_param,
LPARAM data_param);
static void
render()
{
RECT r;
HRESULT res;
/* render target */
GetClientRect(win, &r);
D2D1_SIZE_U size = D2D1::SizeU(r.right, r.bottom);
FLOAT dpix;
FLOAT dpiy;
factory->GetDesktopDpi(&dpix, &dpiy);
D2D1_RENDER_TARGET_PROPERTIES rtp;
rtp.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
rtp.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
rtp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
rtp.dpiX = dpix;
rtp.dpiY = dpiy;
rtp.usage = D2D1_RENDER_TARGET_USAGE_NONE;
rtp.minLevel = D2D1_FEATURE_LEVEL_10;
D2D1_HWND_RENDER_TARGET_PROPERTIES wrtp;
wrtp.hwnd = win;
wrtp.pixelSize = size;
wrtp.presentOptions = D2D1_PRESENT_OPTIONS_IMMEDIATELY;
res =factory->CreateHwndRenderTarget(rtp, wrtp, &rt);
if (FAILED(res))
{
std::cout << "CreateHwndRenderTarget failed" << std::endl;
return;
}
/* brush */
ID2D1SolidColorBrush *brush;
/* rgba */
const D2D1_COLOR_F color = D2D1::ColorF(0.5, 0.5, 0, 0.5);
res = rt->CreateSolidColorBrush(color, &brush);
if (FAILED(res))
{
std::cout << "CreateSolidColorBrush failed" << std::endl;
return;
}
/* ellipse */
D2D1_ELLIPSE ellipse;
D2D1_SIZE_F sz = rt->GetSize();
const float x = sz.width / 2;
const float y = sz.height / 2;
const float radius = std::min(x, y);
ellipse = D2D1::Ellipse(D2D1::Point2F(x, y), radius, radius);
rt->BeginDraw();
rt->Clear( D2D1::ColorF(D2D1::ColorF::SkyBlue, 0.5f) );
rt->FillEllipse(ellipse, brush);
rt->EndDraw();
}
LRESULT CALLBACK
_window_procedure(HWND window,
UINT message,
WPARAM window_param,
LPARAM data_param)
{
switch (message)
{
case WM_CLOSE:
PostQuitMessage(0);
return 0;
case WM_KEYUP:
if (window_param == 'Q')
{
PostQuitMessage(0);
}
return 0;
/* GDI notifications */
case WM_PAINT:
{
RECT rect;
std::cout << "paint" << std::endl;
if (GetUpdateRect(window, &rect, FALSE))
{
PAINTSTRUCT ps;
BeginPaint(window, &ps);
render();
EndPaint(window, &ps);
}
return 0;
}
default:
return DefWindowProc(window, message, window_param, data_param);
}
}
int main()
{
/* class */
WNDCLASS wc;
instance = GetModuleHandle(NULL);
if (!instance)
return 1;
memset (&wc, 0, sizeof (WNDCLASS));
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = _window_procedure;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = instance;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(1 + COLOR_BTNFACE);
wc.lpszMenuName = NULL;
wc.lpszClassName = "D2D";
if(!RegisterClass(&wc))
goto free_library;
/* Window */
int w;
int h;
RECT r;
DWORD style;
DWORD exstyle;
w = 640;
h = 480;
style = WS_OVERLAPPEDWINDOW | WS_SIZEBOX;
exstyle = 0;
exstyle |= WS_EX_COMPOSITED | WS_EX_TRANSPARENT;
//exstyle |= WS_EX_NOREDIRECTIONBITMAP;
r.left = 0;
r.top = 0;
r.right = w;
r.bottom = h;
if (!AdjustWindowRectEx(&r, style, FALSE, exstyle))
goto unregister_class;
win = CreateWindowEx(exstyle,
"D2D", "Test",
style,
100, 100,
r.right - r.left,
r.bottom - r.top,
NULL,
NULL, instance, NULL);
if (!win)
goto unregister_class;
ShowWindow(win, SW_SHOWNORMAL);
/* factory */
if (FAILED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
&factory)))
goto destroy_win;
/* msg loop */
while(1)
{
MSG msg;
BOOL ret;
ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
if (ret)
{
do
{
if (msg.message == WM_QUIT)
goto beach;
TranslateMessage(&msg);
DispatchMessageW(&msg);
} while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE));
}
}
beach:
factory->Release();
DestroyWindow(win);
UnregisterClass("D2D", instance);
FreeLibrary(instance);
return 0;
destroy_win:
DestroyWindow(win);
unregister_class:
UnregisterClass("D2D", instance);
free_library:
FreeLibrary(instance);
return 1;
}
I also does not want to use layered windows.
does someone know if it is possible to achieve what I want on Windows 7 ?
thank you
It is possible to have a transparent window on Win7 without
WS_EX_LAYERED
style, but it have some disadvantages:window must have
WS_POPUP
style, othervise if Windows style have glass, background for window will be blured.DWM (Desktop Window Manager) on windows must be turned on, otherwise windows will be not transparent
while window is transparent visualy, mouse click are not going throught 100% transparent area. Maybe there is solution for this, but I don't know any.
if your window is not transparent, you have probably turned off DWM or Windows doesn't have areo style set.
https://weblogs.asp.net/kennykerr/direct2d-and-the-desktop-window-manager