In the last few newsletters, I have described how windows created by the Windows
Forms library are usually created from a single windows class. This windows
class is used to create all forms that have the same style and are created in
the same application domain. Windows Forms does not provide a mechanism to access
other windows on the Windows desktop, which is a good thing from a security
point of view, but it is irritating from the developers point of view.
To get around this issue, a developer can resort to Win32 and use FindWindowEx()
to get the handle of a window that fits the criteria passed to the function.
FindWindowEx()
takes the title of a window or the name of the class of
the window. Since most forms will have the same window class, it means that
the developer can only search for a window by its title. This can be quite restrictive.
In this newsletter, I will describe how to use a Win32 feature called Windows
Properties to allow you to search for a particular window type.
A Win32 window can have properties. A property can be any data that you choose,
so it could be a string, an integer, or some complex data type. You provide
each property with a name when you add the property to the window. Win32 gives
you functions to enumerate the properties associated with a window and to get
the data associated with the property. Note that these Win32 properties are
not accessible through the Form
class, so instead you have to import
the Win32 functions through platform invoke.
The public methods are shown here:
public class WindowsProperties : IDisposable { public WindowsProperties(IntPtr hWnd); public void Dispose(); public void AddProperty(string propName, string propValue); public string GetProperty(string propName); public static string GetProperty(IntPtr h, string propName); }
The idea is that you can create an instance of this class and initialize it
with the handle of an existing window (for example from Form.Handle
,
or returned from FindWindowEx
). Next, you can add a string property with
a specific name using AddProperty()
; if the window already has a property
with the same name, then this method replaces its value with the value you supply.
You can use the GetProperty()
method to get the value of a property with
a specific name. If the property does not exist, null is returned. I have to
reiterate here that this class only affects Win32 window properties and has
nothing to do with Windows Forms properties.
So, how can I use this? Well, the download also includes a class called ClassName
,
which adds a window property called _className
to a window. You can create
an instance of this class in your form and it will add the name of the forms
.NET class as the _className
property. Code that enumerates windows can
use the static WindowsProperties.GetProperty()
method to obtain the value
of the _className
property to see if the window was created from a form
that used ClassName
. The sample code uses this facility to ensure that
only one instance of the form will ever exist, and that this instance is always
the last one that is created. The class does this by repeatedly calling FindWindowEx()
to get the windows that have the same windows class as the current window, which
will return all the forms with the same style as the current form. It then uses
ClassName
to get the value of the _className windows property and compares
this with the name of the class of the current form. If this comparison succeeds,
it means that the form was created from the same .NET class, and so the code
sends the WM_CLOSE
message to the window to close it.
Richard Grimes speaks at conferences and writes extensively on .NET, COM, and COM+. He is the author of Developing Applications with Visual Studio .NET (Addison-Wesley, 2002). If you have comments about this topic, Richard can be reached at [email protected].