Click here to Skip to main content
15,880,503 members
Articles / Programming Languages / Objective C

A Simple Windows Forms Properties Spy

Rate me:
Please Sign up or sign in to vote.
4.98/5 (50 votes)
19 Aug 2003CPOL4 min read 333K   11.8K   168   49
A utility that can be used to spy the properties of any Windows forms control in the system

Image 1

Image 2

Introduction

wfspy is a tool that helps you to view properties of any Windows 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.

C#
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.

C#
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)


Written By
Architect
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionMy Updates Now On GitHub Pin
cplotts15-May-12 8:06
cplotts15-May-12 8:06 
AnswerRe: My Updates Now On GitHub Pin
cartspan15-Aug-12 11:17
cartspan15-Aug-12 11:17 
GeneralRe: My Updates Now On GitHub Pin
cplotts15-Aug-12 12:27
cplotts15-Aug-12 12:27 
GeneralRe: My Updates Now On GitHub Pin
SFWheeler15-Aug-12 13:30
SFWheeler15-Aug-12 13:30 
GeneralRe: My Updates Now On GitHub Pin
cplotts16-Aug-12 0:41
cplotts16-Aug-12 0:41 
QuestionHow to get Window calc properties using reflection method. (Like button size, color, label color, font, font size). Pin
GaurangPatel27-Jan-11 17:47
GaurangPatel27-Jan-11 17:47 
QuestionHelp needed! Pin
mohandasgandhiG22-Jul-09 19:46
mohandasgandhiG22-Jul-09 19:46 
GeneralCreating problem in Dual Core and Multithreaded application Pin
mohandasgandhiG21-Jul-09 1:24
mohandasgandhiG21-Jul-09 1:24 
GeneralCool! Pin
Miguel Barros6-Mar-09 5:57
Miguel Barros6-Mar-09 5:57 
Generaldll are still in use after closing the application Pin
lsdisciples8-Jun-08 18:36
lsdisciples8-Jun-08 18:36 
QuestionCan use on WindowsMobile devices? Pin
Peter Rilling7-Feb-08 13:49
Peter Rilling7-Feb-08 13:49 
GeneralArticle on injecting assembly Pin
S. Senthil Kumar11-Oct-06 6:58
S. Senthil Kumar11-Oct-06 6:58 
GeneralRe: Article on injecting assembly Pin
Rama Krishna Vavilala11-Oct-06 8:18
Rama Krishna Vavilala11-Oct-06 8:18 
GeneralRe: Article on injecting assembly Pin
tech.U29-May-07 16:10
tech.U29-May-07 16:10 
QuestionAccessing the properties programatically? Pin
VanSkalen15-Sep-06 7:19
VanSkalen15-Sep-06 7:19 
AnswerRe: Accessing the properties programatically? Pin
RCuber12-Mar-07 0:29
RCuber12-Mar-07 0:29 
GeneralVery nice!!!! Pin
Mike DiRenzo18-Aug-06 5:13
Mike DiRenzo18-Aug-06 5:13 
QuestionUpdates Pin
cplotts20-Jun-06 7:46
cplotts20-Jun-06 7:46 
AnswerRe: Updates Pin
Rama Krishna Vavilala20-Jun-06 7:59
Rama Krishna Vavilala20-Jun-06 7:59 
GeneralRe: Updates Pin
cplotts20-Jun-06 8:22
cplotts20-Jun-06 8:22 
GeneralRe: Updates Pin
lsdisciples28-Oct-07 10:38
lsdisciples28-Oct-07 10:38 
GeneralRe: Updates Pin
cplotts19-Apr-10 4:22
cplotts19-Apr-10 4:22 
GeneralRe: Updates Pin
cplotts28-Oct-09 11:22
cplotts28-Oct-09 11:22 
GeneralRe: Updates Pin
mohandasgandhiG2-Aug-06 19:20
mohandasgandhiG2-Aug-06 19:20 
GeneralVS 2005 Pin
BuddyWork19-May-06 7:49
BuddyWork19-May-06 7:49 

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

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