A test with a .JPG with UpdateLayeredWindow and white color as transparent color =>
Remove the space at S leep (bug in this editor...)
#include <windows.h>
#include <tchar.h>
#include "gdiplus.h"
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")
#include <Urlmon.h> // URLDownloadToCacheFile
#pragma comment (lib, "Urlmon")
#include <shlwapi.h> // SHCreateStreamOnFile
#pragma comment (lib, "shlwapi")
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int nWidth = 600, nHeight = 400;
BOOL SetPicture(HWND hWnd, HBITMAP hBmp, COLORREF nColor);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
hInst = hInstance;
WNDCLASSEX wcex =
{
sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInst, LoadIcon(NULL, IDI_APPLICATION),
LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1), NULL, TEXT("WindowClass"), NULL,
};
if (!RegisterClassEx(&wcex))
return MessageBox(NULL, TEXT("Cannot register class !"), TEXT("Error"), MB_ICONERROR | MB_OK);
int nX = (GetSystemMetrics(SM_CXSCREEN) - nWidth) / 2, nY = (GetSystemMetrics(SM_CYSCREEN) - nHeight) / 2;
HWND hWnd = CreateWindowEx(WS_EX_NOREDIRECTIONBITMAP | WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_NOACTIVATE, wcex.lpszClassName, TEXT("Test"), WS_POPUP | WS_VISIBLE, nX, nY, nWidth, nHeight, NULL, NULL, hInst, NULL);
if (!hWnd)
return MessageBox(NULL, TEXT("Cannot create window !"), TEXT("Error"), MB_ICONERROR | MB_OK);
ShowWindow(hWnd, SW_SHOWNORMAL);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hWndButton = NULL, hWndStatic = NULL;
int wmId, wmEvent;
switch (message)
{
case WM_CREATE:
{
WCHAR wsURL[MAX_PATH] = TEXT("https://image.ibb.co/buLv2e/Little_Girl3.jpg");
WCHAR wsFilename[MAX_PATH];
HRESULT hr = URLDownloadToCacheFile(NULL, wsURL, wsFilename, ARRAYSIZE(wsFilename), 0x0, NULL);
if (SUCCEEDED(hr))
{
IStream* pStream = NULL;
hr = SHCreateStreamOnFile(wsFilename, STGM_READ | STGM_SHARE_DENY_WRITE, &pStream);
if (SUCCEEDED(hr))
{
HBITMAP hBitmap = NULL;
Gdiplus::Bitmap* pBitmap = new Gdiplus::Bitmap(pStream);
if (pBitmap)
{
pBitmap->GetHBITMAP(Gdiplus::Color(255, 255, 255), &hBitmap);
SetPicture(hWnd, hBitmap, RGB(255, 255, 255));
}
}
}
return 0;
}
break;
case WM_NCHITTEST:
{
return HTCAPTION;
}
break;
case WM_NCRBUTTONDOWN:
{
S leep(200);
DestroyWindow(hWnd);
}
break;
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
BOOL SetPicture(HWND hWnd, HBITMAP hBmp, COLORREF nColor)
{
BITMAP bm;
GetObject(hBmp, sizeof(bm), &bm);
SIZE szBmp = { bm.bmWidth, bm.bmHeight };
HDC hDCScreen = GetDC(NULL);
HDC hDCMem = CreateCompatibleDC(hDCScreen);
HBITMAP hBmpOld = (HBITMAP)SelectObject(hDCMem, hBmp);
BLENDFUNCTION blend = { 0 };
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 255;
//blend.AlphaFormat = AC_SRC_OVER;
blend.AlphaFormat = AC_SRC_ALPHA;
RECT rc;
GetWindowRect(hWnd, &rc);
POINT ptSrc = { 0 };
POINT ptDest = { rc.left, rc.top };
BOOL bRet = UpdateLayeredWindow(
hWnd,
hDCScreen,
&ptDest,
&szBmp,
hDCMem,
&ptSrc,
nColor,
&blend,
//ULW_ALPHA);
ULW_COLORKEY);
SelectObject(hDCMem, hBmpOld);
DeleteDC(hDCMem);
ReleaseDC(NULL, hDCScreen);
return bRet;
}
You must use GetWindowLong with SetWindowLong
like :
(except for WS_EX_TOPMOST as the doc says (SetWindowPos))
Using this code only doesn't change the image. If I add these lines I get a partially transparent window like here.
Someone was having the same problem, found this link or this link but it didn't helped either.
According to the link code, I get the following picture with a little change. Do you need this?
Yes, this is the effect that I try to achieve in Unreal Engine, the difference I think is that in that example there is a 32bit image. I would like to understand the code better and to adjust it for my project. Thankyou!
It works in my test
Instead of using a hBitmap from a JPG, if I generate the bitmap with WM_PRINT in a memory DC (copy of the window image without DWM) (or PrintWindow but borders must be removed),
by posting a WM_USER + x message in WM_CREATE (to let the window draw itself)
and after having added a button for the test, I get :
Hey Castorix31 ,
I am sure this works in visual studio, but I am working with unreal engine and I thing the bitmap from memory DC doesn't include transparency, I am not sure about that. So one solution would be to use TransparentBlt but I haven't managed to include the library so I am looking for an alternative. Other solution might be with DwmEnableBlurBehindWindow like here. I think I grow some gray hair meanwhile and didn't found a solution yet. :)
DwmEnableBlurBehindWindow does not work anymore in Windows 10 (it is in the MSDN doc, in the Note)
Otherwise, SetWindowCompositionAttribute works (not officially documented, but many samples from Google)
And if you use DWM APIs, they use ARGB instead of RGB (with GDI), so the colors must be changed (with GDI+ or DIB Sections))
I didnt't knew that DwmEnableBlurBehindWindow is no longer working.
So, I have the following code, can you please tell me where am I am mistaking ?
HDC hdc1 = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
HBITMAP hBmpOld = (HBITMAP)SelectObject(hdc, hBitmap);
FillRect(hdc,&rect,CreateSolidBrush(RGB(0,0,0)));
SelectObject ( hdc, hBitmap );
TransparentBlt(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, hdc1, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0x00000000);
const MARGINS margins{ -1 };
DwmExtendFrameIntoClientArea(hwnd, &margins);
LONG nExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, nExStyle | WS_EX_LAYERED);
SetLayeredWindowAttributes( hwnd, 0x00000000, FMath::TruncToInt( 0.2 * 255.0f ), LWA_ALPHA );
//SetLayeredWindowAttributes( hwnd, 0x00000000, FMath::TruncToInt( 0.2 * 255.0f ), LWA_COLORKEY );
if (hdc)
{
HGDIOBJ hPrevObj = 0;
POINT ptDest = {rect.left, rect.top};
POINT ptSrc = {0, 0};
SIZE client = {rect.right - rect.left, rect.bottom - rect.top};
BLENDFUNCTION blendFunc = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
UpdateLayeredWindow(hwnd, hdc1, &ptDest, &client, hdc, &ptSrc, RGB(0, 0, 0), &blendFunc, ULW_COLORKEY);
SelectObject(hdc, hBmpOld);
DeleteObject(hBitmap);
DeleteDC(hdc);
ReleaseDC(NULL, hdc1);
}
Thankyou very much. So the problem I was facing had nothing to do with alpha-blending, after so many days I have managed to find the solution. I had to change from directx to ES3.1
Hi I am trying to learn to do the exact thing in Unreal! Would it be possible to post the code of how you synthesized it all together?
Sign in to comment
0 additional answers
Sort by: Most helpful