Layered Windows Tutorial
by ultraschall

Windows 2000 users will probably have noticed the support of a cool transparency effect. It is, of course, possible to use this effect in your programs and the goal of this tutorial is to demonstrate the reader how to achieve this. Microsoft calls all this stuff "layering", so that's why i have chosen that title. This is rather a short tutorial because it's really very very easy to make your windows transparent ;)

Well, the first step to make a window transparent is to create it with the WS_EX_LAYERED extended window style. It is also possible to apply this style to the window after it has been created. To apply the style use the SetWindowLong function. Please note that you cannot use this style for child windows. That means that you cannot make a single button/edit/static/etc. in a window transparent, but the whole window. All child controls will also become transparent automatically.

Windows 2000 offers two different effects:

1. It is possible to make the entire window transparent
2. It is possible to make a specific color transparent

And it is also possible to combine both of these effects!

Creating a window with the WS_EX_LAYERED style, however, is not enough. All windows with this style will remain invisible until you set the level of transparency with the SetLayeredWindowAttributes function:

BOOL SetLayeredWindowAttributes(
..HWND hwnd, ...... // handle to the layered window
..COLORREF crKey, . // specifies the color key
..BYTE bAlpha, .... // value for the blend function
..DWORD dwFlags ... // action
);

Well, the first parameter is obvious. You have to pass the handle of the window that has the WS_EX_LAYERED style to the function.

The second parameter tells Windows which color you want to make transparent. If you look up COLORREF you'll find out that this parameter is a dword value with the following form: 0x00bbggrr. I guess no further explanation is needed :)
If you don't want to make a specific color transparent you must set the appropiate flag in the dwFlags parameter.

The third parameter specifies the transparency level of the entire window. Set this parameter to 0 to make a window completely transparent or 255 to make it opaque.
If you don't want to make the entire window transparent you can set bAlpha to 255, but it is better (and more efficient) to turn off the transparency by setting the appropiate flag in the dwFlags parameter.

The dwFlags parameter specifies the action(s) to take. This parameter can be either LWA_COLORKEY or LWA_ALPHA or both. If you just want to make a single color in a window transparent specify LWA_COLORKEY. If you want to make an entire window transparent set dwFlags to LWA_ALPHA. To use both effects set it to LWA_COLORKEY + LWA_ALPHA.


Now let's have a look on an example:

I've created a dialog box which contains several controls including a checkbox. The windows becomes transparent if you select it and opaque if you deselect it. Here's the .rc file: (if you don't know what this is go and read Iczelion's great tutorials)

#define DS_MODALFRAME 0x80L
#define WS_POPUP 0x80000000L
#define WS_CAPTION 0x00C00000L
#define WS_SYSMENU 0x00080000L
#define ES_AUTOHSCROLL 0x0080L
#define WS_TABSTOP 0x00010000L
#define SS_BLACKRECT 0x00000004L
#define BS_AUTOCHECKBOX 0x00000003L


1000 DIALOG DISCARDABLE 0, 0, 186, 66
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Layered Windows"
FONT 8, "Tahoma"
BEGIN
  LTEXT "This text is transparent",1001,7,7,76,8
  EDITTEXT 1002,7,19,172,14,ES_AUTOHSCROLL
  PUSHBUTTON "OK",1003,7,38,50,14
  CONTROL "Check me",1004,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,63,40,47,10
  CONTROL "",1005,"Static",SS_BLACKRECT,118,39,61,20
END

Use rc.exe to compile it to a .res file.

And now the .asm source:

.586
.MODEL FLAT,STDCALL
INCLUDELIB kernel32.lib
INCLUDELIB user32.lib
OPTION SCOPED

GetModuleHandleA PROTO :DWORD
DialogBoxParamA PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
EndDialog PROTO :DWORD,:DWORD
GetWindowLongA PROTO :DWORD,:DWORD
SetWindowLongA PROTO :DWORD,:DWORD,:DWORD
GetModuleHandleA PROTO :DWORD
GetProcAddress PROTO :DWORD,:DWORD

WM_INITDIALOG equ 110h
WM_CLOSE      equ 10h
WM_COMMAND    equ 111h
BN_CLICKED    equ 0
GWL_EXSTYLE   equ -20

WS_EX_LAYERED equ 80000h ; I guess you won't find these equates in your includes
LMA_COLORKEY  equ 1
LMA_ALPHA     equ 2

.DATA

User32        db 'User32.dll',0
SLWA          db 'SetLayeredWindowAttributes',0
Trans         dd 0 ; Just a flag (0 = opaque, -1 = transparent)

.DATA?

pSLWA         dd ? ; Offset of SetLayeredWindowAttributes will be saved here

.CODE

DlgProc PROC hWnd: DWORD,uMsg: DWORD,wParam: DWORD,lParam: DWORD
  pushad
  .IF uMsg == WM_INITDIALOG

    ; Get current EX style of window and add WS_EX_LAYERED

    invoke GetWindowLongA,hWnd,GWL_EXSTYLE
    or eax,WS_EX_LAYERED
    invoke SetWindowLongA,hWnd,GWL_EXSTYLE,eax

    ; Get offset of SetLayeredWindowAttributes

    invoke GetModuleHandleA,addr User32
    invoke GetProcAddress,eax,addr SLWA
    mov pSLWA,eax


    ; Set transparency level to "opaque"

    push LMA_ALPHA ; only set alpha value
    push 255       ; alpha value
    push 0
    push hWnd
    call pSLWA

  .ELSEIF uMsg == WM_CLOSE

    invoke EndDialog,hWnd,0

  .ELSEIF (uMsg == WM_COMMAND) && (lParam != 0)

    mov edx,wParam
    shr edx,16
    cmp dx,BN_CLICKED ; button clicked?
    jnz @F
    cmp wParam,1004   ; is it the checkbox?
    jnz @F
    not Trans         ; switch flag
    cmp Trans,0
    jz TurnOff


    ; Make window and color black transparent

    push LMA_COLORKEY + LMA_ALPHA
    push 200          ; alpha value
    push 0            ; = black
    push hWnd
    call pSLWA

    jmp @F

    TurnOff:

    ; Set transparency level to "opaque"

    push LMA_ALPHA
    push 255
    push 0
    push hWnd
    call pSLWA


    @@:

  .ELSE

    popad
    sub eax,eax
    ret

  .ENDIF

  popad
  mov eax,1
  ret
DlgProc ENDP

Start:
  invoke GetModuleHandleA,0
  invoke DialogBoxParamA,eax,1000,0,addr DlgProc,0
  ret

END Start

ENDS

Assemble and link with:

ml /c /coff /Cp filename.asm
Link /SUBSYSTEM:WINDOWS /LIBPATH:C:\Coding\Masm\Lib filename.obj dialogresource.res


That was easy, huh?
Please give me some feedback: ultraschall@elitereversers.de

Now time for some greets:
defiler, sn00pee, keyboard junky, mendo, viny, the egoiste, basic, ratso, haldir, mvd, iczelion, n4y, masta, telcofix, xor, flwright, blind angel and lorian