PopupMenu - Transparent Menu Demonstration

Demonstrates how to create transparent menus in Windows 2000 or XP using the PopupMenu object.

Transparent Menu Demonstration

Windows 2000 and XP support all sorts of exciting new user interface effects, one of them being the ability to make Windows transparent. For more details, visit MSDN and search for the technical article "Layered Windows: A New Way to Use Translucency and Transparency Effects in Windows Applications." This sample demonstrates how to use the OwnerDraw facility of the vbAccelerator PopupMenu DLL to make your menus transparent too.

About Window Transparency

There are a number of techniques for making Windows transparent, however, the simplest is to change a window's style bits to add the new WS_EX_LAYERED style attribute. Once this has been set, you can use the new layered window API SetLayeredWindowAttributes to modify the alpha of the window (the alpha defines the window's transparency, between 0 for completely transparent and 255 for opaque.)

Here is a quick overview of the code you use to change a Window's transparency:

' Declares:
Private Declare Function GetWindowLong Lib "USER32" Alias "GetWindowLongA" _
    (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "USER32" Alias "SetWindowLongA" _
    (ByVal hWnd As Long, ByVal nIndex As Long, _
    ByVal dwNewLong As Long) As Long
Private Const GWL_STYLE = (-16)
Private Const GWL_EXSTYLE = (-20)
'Requires Windows 2000 or later:
Private Const WS_EX_LAYERED = &H80000

Private Declare Function SetLayeredWindowAttributes Lib "USER32" _
    (ByVal hWnd As Long, ByVal crKey As Long, _
    ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long
Private Const LWA_COLORKEY = &H1
Private Const LWA_ALPHA = &H2

Public Sub MakeWindowTransparent(ByVal hWnd As Long, ByVal alphaAmount As Byte)
Dim lStyle As Long
    lStyle = GetWindowLong(hWnd, GWL_EXSTYLE)
    lStyle = lStyle Or WS_EX_LAYERED
    SetWindowLong hWnd, GWL_EXSTYLE, lStyle
    SetLayeredWindowAttributes hWnd, 0, alphaAmount, LWA_ALPHA
End Sub

Note that this technique only works with top-level windows, so unfortunately you cannot apply it to individual controls.

Creating Transparent Menus

In order to use this technique, you just need to know the hWnd of the Window you want to change. So how do we use this for a menu? The answer to this is surprisingly simple. Menus are actually implemented internally in Windows using a specific class of window, however, unfortunately none of the Menu APIs actually provide you with this window handle. When you set a menu to OwnerDraw style, though, Windows passes you the hDC of the menu to draw onto. This means you can find the Window handle using the API call GetWindowFromDC (note: of course it is possible in future versions of Windows that this implementation could change).

Using the PopupMenu object makes it simple to create a transparent menu since you can set the OwnerDraw attribute for any menu item. This means that the object notifies you through DrawItem event whenever an item needs to be drawn, and one of the parameters you get is the hDC to draw onto. If you don't do anything in these methods, PopupMenu assumes you want the menu to draw in the default style so just gets on with it.

So having set OwnerDraw to true for all menu items, we can find the window handle by calling WindowFromDC during the DrawItem and then setting the window to the layered style if it isn't already. The only slight catch is that in Windows 2000 and XP menus can be animated when they pop open. If this style is enabled, the Window and DC that you get to draw onto whilst the menu is popping open is actually a temporary one which goes away. Therefore to ensure the menu gets to be transparent as soon as it opens, the code stops menu animations for the popup menu it displays using the PopupMenu object NoMenuAnimation setting.