Click here to Skip to main content
Click here to Skip to main content

A simple Windows forms properties spy

, 19 Aug 2003 CPOL
Rate this:
Please Sign up or sign in to vote.
A utility that can be used to spy the properties of any Windows forms control in the system.

Introduction

wfspy is a tool that helps you to view properties of any window form control in the system. I originally needed a small utility that will give me the managed control type name and the assembly name from a window handle, but gradually the tool became sophisticated enough to show all properties of a managed control (and optionally modify them). The only feature currently missing is the spying of events, which I plan to add later on.

wfspy uses Windows hooks to do its job. There are 3 assemblies in the project:-

  1. wfspy - a C# executable. This is the main application which has the UI code.
  2. wfspylib - a C# class library that contains utility functions and controls. This library gets injected into the process where the window belongs.
  3. wfspyhook - a managed C++ class library (.dll) which has code to inject a managed assembly into a process.

Using wfspy

The tool itself is pretty simple. The main window shows all the managed windows and their hierarchy, with the desktop window as the root. Any unmanaged window which is not parent of a managed window directly or indirectly, is not shown in the tree. The managed windows are shown using a slightly different icon. You can view the properties of the managed window by clicking on the details button in the main form. This brings up the dialog box with the property grid as shown in the second screen shot. The properties can even be modified in the grid. The next few sections discuss some important aspects of the implementation.

Enumerating managed windows

To enumerate managed windows, the standard Win32 API function EnumChildWindows is used. Unmanaged windows are filtered out from the tree if they don't parent any manage windows. In order to find out whether a window is managed or not, its class name is inspected. Any managed window that derives from System.Windows.Forms.Control has class name of the form WindowsForms10.<character sequence>.app<hash code of appdomain>. The character sequence in the middle is the class name of the window that is being superclassed like Button, SysListView32 etc. The following code determines whether a class name is managed or not.

private static Regex classNameRegex = new 
           Regex(@"WindowsForms10\..*\.app[\da-eA-E]*$", 
           RegexOptions.Singleline);
            
public static bool IsDotNetWindow(string className)
{
    Match match = classNameRegex.Match(className);
    return (match.Success);
}

Injecting a .NET assembly into a process

The technique to inject a .NET assembly in another process is slightly tricky as unlike functions in a regular Win32 DLL. .NET functions are compiled into native code during run time so the addresses are not static. This problem can be overcome by using managed C++, which allows managed global functions to be exported from an assembly. The exported function is actually a thunk that at runtime, points to the code generated by the JIT compiler. Thus the exported function can be used as a hook procedure. That function can be used to load another assembly. I will cover this technique in detail in another article.

Viewing properties of a control

Given an HWND the managed Control object can be found from the Control.FromHandle method. The properties of the control object can then be viewed in a property grid. There is a problem here the property grid should be created in the process where control object belongs. Luckily Windows allows a process to create child windows to a parent window belonging to another process. This technique is used to create the property grid from the target process, as a child of a form in the wfspy process. In order to do this the property grid control is placed in a user control. The CreateParams property of the user control is overridden.

protected override CreateParams CreateParams
{
    get
    {
        System.Windows.Forms.CreateParams cp = base.CreateParams;
        cp.Parent = parentWindow;
        RECT rc = new RECT();
        UnmanagedMethods.GetClientRect(parentWindow, ref rc);
        
        cp.X = rc.left;
        cp.Y = rc.top;
        cp.Width = rc.right - rc.left;
        cp.Height = rc.bottom - rc.top;

        return cp;
    }
}

The parentWindow is actually the handle of a form belonging to the wfspy process. This enables editable property view of a control in the wfspy application.

Known bugs/ remarks

The included wfspy works only for .NET windows 1.0.3705. If you want the tool to work with .NET 1.1, please build the code using VS.NET 2003. If you use wfspy to view a window in an application that uses a different .NET version, strange results may occur. Suggestions are welcome on how to fix this bug. I intend to update the article soon with the ability to spy control events.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Rama Krishna Vavilala
Architect
United States United States
No Biography provided

Comments and Discussions

 
QuestionMy Updates Now On GitHub Pinmembercplotts15-May-12 9:06 
AnswerRe: My Updates Now On GitHub Pinmembercartspan15-Aug-12 12:17 
GeneralRe: My Updates Now On GitHub Pinmembercplotts15-Aug-12 13:27 
GeneralRe: My Updates Now On GitHub PinmemberSFWheeler15-Aug-12 14:30 
GeneralRe: My Updates Now On GitHub Pinmembercplotts16-Aug-12 1:41 
QuestionHow to get Window calc properties using reflection method. (Like button size, color, label color, font, font size). PinmemberMember 426710927-Jan-11 18:47 
QuestionHelp needed! PinmembermohandasgandhiG22-Jul-09 20:46 
GeneralCreating problem in Dual Core and Multithreaded application PinmembermohandasgandhiG21-Jul-09 2:24 
GeneralCool! PinmemberMiguel Barros6-Mar-09 6:57 
Generaldll are still in use after closing the application Pinmemberlsdisciples8-Jun-08 19:36 
QuestionCan use on WindowsMobile devices? PinmemberPeter Rilling7-Feb-08 14:49 
GeneralArticle on injecting assembly PinmemberS. Senthil Kumar11-Oct-06 7:58 
GeneralRe: Article on injecting assembly PinmemberRama Krishna Vavilala11-Oct-06 9:18 
GeneralRe: Article on injecting assembly Pinmembertech.U29-May-07 17:10 
QuestionAccessing the properties programatically? PinmemberVanSkalen15-Sep-06 8:19 
AnswerRe: Accessing the properties programatically? PinmemberGopi Charan K12-Mar-07 1:29 
GeneralVery nice!!!! PinmemberMike DiRenzo18-Aug-06 6:13 
QuestionUpdates Pinmembercplotts20-Jun-06 8:46 
AnswerRe: Updates PinmemberRama Krishna Vavilala20-Jun-06 8:59 
GeneralRe: Updates Pinmembercplotts20-Jun-06 9:22 
GeneralRe: Updates Pinmemberlsdisciples28-Oct-07 11:38 
GeneralRe: Updates Pinmembercplotts19-Apr-10 5:22 
GeneralRe: Updates Pinmembercplotts28-Oct-09 12:22 
GeneralRe: Updates PinmembermohandasgandhiG2-Aug-06 20:20 
GeneralVS 2005 PinmemberBuddyWork19-May-06 8:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141216.1 | Last Updated 20 Aug 2003
Article Copyright 2003 by Rama Krishna Vavilala
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid