You've probably come across many applications that use non-rectangular windows. Windows Media Player and Winamp instantly come to mind:

It's quite easy to create non-rectangular windows from a bitmap file in your Win32 applications, using functions such as CreateRectRgn and CombineRgn.
With a little help
I've created a helper function to simplify the process. Just include the bitmap you want to use in your resource file:
#define IDB_BMRGN 201
IDB_BMPRGN BITMAP DISCARDABLE "region.bmp"
Then, in the initialization part of your dialog, call my CreateBmpRgn function, specifying the handle of the window, the bitmap, and the color your want to be transparent (in the form 00BBGGRRh):
; load image
INVOKE LoadImage, hInstance, IDB_BMPRGN, IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR
mov hBitmap, eax
; create region using magenta as the transparent color
INVOKE CreateBmpRgn, hWnd, hBitmap, 0FF00FFh
; set region
INVOKE SetWindowRgn, hWnd, eax, TRUE
You can check out the results in this example application written in MASM32: non-rectangular.zip (press Esc to close it).
The real thing
The code for the function is a bit more complex:
CreateBmpRgn PROC hWnd :HWND, hBmRgn :HBITMAP, clrTrans :COLORREF
LOCAL hdcDest :HDC
LOCAL hdcSrc :HDC
LOCAL bmInfo :BITMAP
LOCAL hRgn :HRGN
LOCAL hTmpRgn :HRGN
LOCAL x :DWORD
LOCAL y :DWORD
LOCAL begin :DWORD
; destination device context
INVOKE GetDC, hWnd
mov hdcDest, eax
; source device context
INVOKE CreateCompatibleDC, hdcDest
mov hdcSrc, eax
; get bitmap info
INVOKE GetObject, hBmRgn, SIZEOF BITMAP, ADDR bmInfo
; select bitmap into device context
INVOKE SelectObject, hdcSrc, hBmRgn
; create empty region
INVOKE CreateRectRgn, 0, 0, 0, 0
mov hRgn, eax
mov x, 0
mov y, 0
; pixel rows
.WHILE TRUE
mov eax, y
.BREAK .IF eax == bmInfo.bmHeight
; pixel columns
.WHILE TRUE
mov eax, x
.BREAK .IF eax == bmInfo.bmWidth
; skip first transparent pixels of the row
.WHILE TRUE
mov eax, x
.BREAK .IF eax == bmInfo.bmWidth
INVOKE GetPixel, hdcSrc, x, y
.BREAK .IF eax != clrTrans
inc x
.ENDW
; remember this pixel
push x
pop begin
; find first non-transparent pixel
.WHILE TRUE
mov eax, x
.BREAK .IF eax == bmInfo.bmWidth
INVOKE GetPixel, hdcSrc, x, y
.BREAK .IF eax == clrTrans
inc x
.ENDW
; create temp region
mov eax, y
inc eax
INVOKE CreateRectRgn, begin, y, x, eax
mov hTmpRgn, eax
; combine it with final region
INVOKE CombineRgn, hRgn, hRgn, hTmpRgn, RGN_OR
; delete temp region
INVOKE DeleteObject, hTmpRgn
.ENDW
mov x, 0
inc y
.ENDW
; release and delete device contexts
INVOKE ReleaseDC, hWnd, hdcDest
INVOKE DeleteDC, hdcSrc
mov eax, hRgn
ret
CreateBmpRgn ENDP
What I'm doing is reading the image pixel by pixel, identifying which ones should be transparent, creating temporary rectangular regions, and combining them all to form the final region.
Comments