From comments, a test with SetWindowRgn and a (very) old function to convert a HBITMAP to a Region =>
(remove space from S leep (editor bug...))
Test with the BMP version of this image : Butterfly-Deep-Magenta.png
to use LoadImage (otherwise, GDI+ or WIC to load .PNG)
(RGB(192, 0, 192) for transparent color)
#include <windows.h>
#include <tchar.h>
#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;
#define IDC_BUTTON 11
HBITMAP hBitmap = NULL;
HRGN BitmapToRegion(HBITMAP hBmp, COLORREF cTransparentColor);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
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(0, wcex.lpszClassName, TEXT("Test"), WS_POPUP, nX, nY, nWidth, nHeight, NULL, NULL, hInst, NULL);
//HWND hWnd = CreateWindowEx(0, wcex.lpszClassName, TEXT("Test"), WS_OVERLAPPEDWINDOW, 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;
PAINTSTRUCT ps;
HDC hDC;
switch (message)
{
case WM_CREATE:
{
hWndButton = CreateWindowEx(0, L"Button", L"Click", WS_CHILD | WS_VISIBLE | BS_PUSHLIKE, 50, 60, 60, 32, hWnd, (HMENU)IDC_BUTTON, hInst, NULL);
// https://i.ibb.co/mCf0gTV/Butterfly-Deep-Magenta.png
hBitmap = (HBITMAP)LoadImage(NULL, L"e:\\Butterfly_DeepMagenta.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
// Transparent color = Deep Magenta
HRGN hRegion = BitmapToRegion(hBitmap, RGB(192, 0, 192));
SetWindowRgn(hWnd, hRegion, true);
return 0;
}
break;
case WM_COMMAND:
{
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
case IDC_BUTTON:
{
if (wmEvent == BN_CLICKED)
{
Beep(1000, 10);
}
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_NCHITTEST:
return HTCAPTION;
case WM_NCRBUTTONDOWN:
{
S leep(200);
DestroyWindow(hWnd);
}
break;
case WM_PAINT:
{
hDC = BeginPaint(hWnd, &ps);
if (hBitmap)
{
BITMAP bm;
GetObject(hBitmap, sizeof(bm), &bm);
HDC hDCMem = CreateCompatibleDC(NULL);
HBITMAP hBitmapOld = (HBITMAP)SelectObject(hDCMem, hBitmap);
BitBlt(hDC, 0, 0, bm.bmWidth, bm.bmHeight, hDCMem, 0, 0, SRCCOPY);
SelectObject(hDCMem, hBitmapOld);
DeleteDC(hDCMem);
}
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Old function from the Net...
HRGN BitmapToRegion(HBITMAP hBmp, COLORREF cTransparentColor)
{
HRGN hRgn = NULL;
if (hBmp == NULL)
return NULL;
HDC hMemDC = CreateCompatibleDC(NULL);
if (hMemDC == NULL)
return NULL;
BITMAP bm;
GetObject(hBmp, sizeof(bm), &bm);
BITMAPINFOHEADER RGB32BITSBITMAPINFO =
{
sizeof(BITMAPINFOHEADER), // biSize
bm.bmWidth, // biWidth;
bm.bmHeight, // biHeight;
1, // biPlanes;
32, // biBitCount
BI_RGB, // biCompression;
0, // biSizeImage;
0, // biXPelsPerMeter;
0, // biYPelsPerMeter;
0, // biClrUsed;
0 // biClrImportant;
};
void* pBitmapBits;
HBITMAP hDIBBitmap = CreateDIBSection(hMemDC, (BITMAPINFO*)&RGB32BITSBITMAPINFO, DIB_RGB_COLORS, &pBitmapBits, NULL, 0);
if (hDIBBitmap == NULL)
{
DeleteDC(hMemDC);
return NULL;
}
HBITMAP hBipmapOld = (HBITMAP)SelectObject(hMemDC, hDIBBitmap);
HDC hDC = CreateCompatibleDC(hMemDC);
if (hDC)
{
BITMAP bm32;
GetObject(hDIBBitmap, sizeof(bm32), &bm32);
while (bm32.bmWidthBytes % 4)
{
bm32.bmWidthBytes++;
}
HBITMAP holdBmp = (HBITMAP)SelectObject(hDC, hBmp);
BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY);
DWORD nMaxRects = 100;
HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (sizeof(RECT) * nMaxRects));
RGNDATA* pData = (RGNDATA*)GlobalLock(hData);
pData->rdh.dwSize = sizeof(RGNDATAHEADER);
pData->rdh.iType = RDH_RECTANGLES;
pData->rdh.nCount = pData->rdh.nRgnSize = 0;
SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
// Scan each bitmap row from bottom to top (the bitmap is inverted vertically)
BYTE* p32 = (BYTE*)bm32.bmBits + (bm32.bmHeight - 1) * bm32.bmWidthBytes;
for (int y = 0; y < bm.bmHeight; y++)
{
// Scan each bitmap pixel from left to right
for (int x = 0; x < bm.bmWidth; x++)
{
// Search for a continuous range of "non transparent pixels"
int x0 = x;
LONG* p = (LONG*)p32 + x;
while (x < bm.bmWidth)
{
if (*p == cTransparentColor)
{
// This pixel is "transparent"
break;
}
p++;
x++;
}
if (x > x0)
{
// Add the pixels (x0, y) to (x, y+1) as a new rectangle in the region
if (pData->rdh.nCount >= nMaxRects)
{
GlobalUnlock(hData);
nMaxRects += 100;
hData = GlobalReAlloc(hData, sizeof(RGNDATAHEADER) + (sizeof(RECT) * nMaxRects), GMEM_MOVEABLE);
pData = (RGNDATA*)GlobalLock(hData);
}
RECT* pr = (RECT*)&pData->Buffer;
SetRect(&pr[pData->rdh.nCount], x0, y, x, y + 1);
if (x0 < pData->rdh.rcBound.left)
pData->rdh.rcBound.left = x0;
if (y < pData->rdh.rcBound.top)
pData->rdh.rcBound.top = y;
if (x > pData->rdh.rcBound.right)
pData->rdh.rcBound.right = x;
if (y + 1 > pData->rdh.rcBound.bottom)
pData->rdh.rcBound.bottom = y + 1;
pData->rdh.nCount++;
if (pData->rdh.nCount == 2000)
{
HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * nMaxRects), pData);
if (hRgn)
{
CombineRgn(hRgn, hRgn, h, RGN_OR);
DeleteObject(h);
}
else
hRgn = h;
pData->rdh.nCount = 0;
SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
}
}
}
p32 -= bm32.bmWidthBytes;
}
// Create or extend the region with the remaining rectangles
HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * nMaxRects), pData);
if (hRgn)
{
CombineRgn(hRgn, hRgn, h, RGN_OR);
DeleteObject(h);
}
else
hRgn = h;
SelectObject(hDC, hBipmapOld);
DeleteDC(hDC);
GlobalUnlock(hData);
GlobalFree(hData);
}
DeleteObject(SelectObject(hMemDC, hBipmapOld));
DeleteDC(hMemDC);
return hRgn;
}