Tuldok Lambat's Tech Blog

Thursday, December 15, 2005

Setting An External Application's Opacity

Opacity is nothing new in the .NET world, in fact it's an inherent property of WinForms although in actuality it's really an intrinsic property of Win2k's (and later Windows OS’es) window forms. In my opinion, the opacity property is one of the features of windows form that is not use most often but at the same time also one of the properties occasionally seek in an application i.e wouldn't be nice to have your IM console a bit translucent or your media player set invisibly enough so that everyone won't notice? It’s wickedly evil yet simple to do.

The enabling technology

As far as I know, the .NET framework (v2.0) as it stands today do not have inherent capability to subclass external applications and mess with its window and its style, which I think is just logical lest it affects its portability. Leaving us no better choice than to use good old Windows API. The following table describes the API functions and constants/ flags we’re going to utilize for our demo application.

Free Image Hosting at www.ImageShack.us
Please refer to your MSDN for more info regarding the above functions.

Now that we’ve define the functions to use. It’s time to put them into code. The snippet below is the content of the APIHelper class contained in the sample.

class APIHelper
public static int GWL_EXSTYLE = -20;
public static int WS_EX_LAYERED = 0x80000;
public static int LWA_ALPHA = 0x2;
public static extern int WindowFromPoint(int x, int y);
public static extern int SetLayeredWindowAttributes(int hWnd, byte crey, byte alpha, int dwFlags);
public static extern int SetWindowLong(int hWnd, int nIndex, int dwNewLong);
public static extern int GetWindowLong(int hWnd, int nIndex);
public static extern int GetParent (int hWnd);
public static extern int GetParentOwner(int hWnd);

Practically, the function SetLayeredWindowAttributes is the only function that enables setting the opacity of a window, the functions SetWindowLong and GetWindowLong are just there as auxillary to its working. While the functions GetParent and WindowFromPoint are there because of the demo application’s objective, that is – to enable the user to change the opacity of an external window (obtained by the GetParent) by dragging a pointer to it (WindowFromPoint identifies the window pointed to).

A brief explanation

Before we delve on the technical details of the demo, I’d like you to bear this in mind, “Everything in Windows is a window”. True, Windows wouldn’t be called as such if its not. The textboxes, the labels, the buttons, the forms and all the rest of the controls (except for, I think, the image controls) are all windows, that is, they have what you call a “windows handle” (hWnd or handle by any other name). A window handle uniquely identifies each window (or should I say control in higher level parlance), and this is what we need to peruse the above functions.

In particular, I’d like to discuss the following snippet that made use of the GetParent. This snippet is located under the MouseUp event, the trigger that indicates that we’re through selecting a window.

lastWnd = APIHelper.WindowFromPoint(MousePosition.X, MousePosition.Y);
while (APIHelper.GetParent(lastWnd) > 0)

lastWnd = APIHelper.GetParent(lastWnd);

As you can see, the snippet retrieves the window handle of the “window” pointed to by mouse position. Now this can just be any other controls present on a form window, which we won’t need to deal with since what we’re interested is the form. And for us to get a handle from it is to walk the parent-child hierarchy until we find a window (/control) that don’t have a parent – the topmost window or the form window.

Now that we have grabbed a window handle, it’s time to do our thing. The TrackBar control in our demo app will be use to adjust the window’s opacity thru its scroll event.

int oldWinStyle = APIHelper.GetWindowLong(lastWnd, APIHelper.GWL_EXSTYLE);
APIHelper.SetWindowLong(lastWnd, APIHelper.GWL_EXSTYLE,
trackBar1.Value < 255 ? oldWinStyle APIHelper.WS_EX_LAYERED :
oldWinStyle & ~APIHelper.WS_EX_LAYERED);
APIHelper.SetLayeredWindowAttributes(lastWnd, 0, (byte)trackBar1.Value, APIHelper.LWA_ALPHA);

In pseudo terms, the snippet simply says, get the window’s previous style OR that to WS_EX_LAYERED to enable its opacity (or layering) and when done set its LWA_ALPHA attribute to the value indicated on the TrackBar. Easy is it? Below are the snapshots of the demo app in action.

Free Image Hosting at www.ImageShack.us Free Image Hosting at www.ImageShack.us
Figure 1 & 2: Before and after applying the transparency using the demo application.

Free Image Hosting at www.ImageShack.us
Figure 3: Applying transparency to a set of windows using yet another demo application included in the download.


The opacity feature of Win2K forms really is cool and a bit tweaking of the demo app would surely make it a nice-to-have tool in everyone’s desktop.

How to create layered Windows in Visual Basic
Using Windows


http://www.megaupload.com/?d=P8CO97WY (Framework 2.0)
http://www.megaupload.com/?d=RPSTEM8T (Framework 1.1)
Most Recent Version (Framework 1.1)