Click here to Skip to main content
11,432,241 members (60,900 online)
Click here to Skip to main content

Runtime Object Editor

, 30 May 2006
Rate this:
Please Sign up or sign in to vote.
A powerful window/object editor to be used at runtime that allows viewing/changing of properties and fields, method invocations, and object hierarchy navigation.

RuntimeObjectEditor.jpg

Introduction

Debugging a managed Windows application is, most of the time, not an easy task, thus any tool that can help will make your life easier. Here, I'm trying to present a small tool that can help you in developing Windows applications, especially working with forms and their controls.

The main idea behind this tool is to provide an easy way to modify properties of objects at runtime without having to restart the application. The Runtime Object Editor tool provides you this and a few more:

  1. A properties editor like the VS editor that can be used to change the properties of any object or control at runtime.
  2. Shows you all the properties that are defined on an object (even if they are not normally visible in the designer) e.g.: "Controls".
  3. Shows you all the fields of an object organized by the class in the hierarchy that owns that property.
  4. Shows all the methods of an object organized by the class and visibility of the method.
  5. Provides a simple way to invoke methods on objects and pass arguments on any method (public, private ...).
  6. Shows you all the events defined on an object and all the event listeners registered to listen to a specific event (e.g.: Form_Load).
  7. Shows process information including static information about Application, CurrentContext, CurrentThread, CurrentPrincipal, CurrentProcess, and garbage collection.
  8. A simple way to find a window/control in your application.
  9. And an (almost) non intrusive way to integrate it into your application.
  10. Can be injected in any .NET process allowing you to easily hook and modify other processes. You can even hook into Visual Studio and modify some of its (.NET) properties (E.g.: the Properties Editor from VS).
  11. Supports back/forward navigation between the last edited objects, and supports navigation to child items in collections, enumerations or arrays (E.g.: the Controls collection of a Control).

Background

Reflection

Reflection is the main way to interact with objects that you know nothing about, thus this tool makes use of reflection for all the information that it can display on its tabs. For a short description of how Reflection can be used, see [1].

PInvoke

PInvoke calls are used to detect the window from the point where the mouse is located. A good article about how to detect a window from a point (mouse location) can be found here: [2].

Modules

The Runtime Object Editor has three major components:

  1. WindowFinder - Provides a drag and drop pointer that you can use to select your window. The implementation is quite similar with [2], with the major difference that it's a C# implementation and that I can also correctly detect the hidden/disabled windows when trying to select a control.
  2. XPropertyGrid and its tabs - A PropertyGrid derived class where you can see and edit the properties of your object.
  3. Descriptors/Designers and TypeConverters - These classes will describe the "properties" of a method like: parameters, type converters, return type, and will do the real invoke of the method.
  4. The assembly injector helper DLL and classes that allow the editor to attach to any running .NET process and modify its properties.

WindowFinder

A drag and drop component is provided for selecting the target window that you want to see in the object editor.

Its behavior is quite simple: click the finder icon, capture the mouse, whenever the mouse is moved, detect the window under the mouse pointer, and fire an event notifying that a new window was found. The only noticeable code in the window finder is the WindowFinder_MouseMove method that detects the window from the mouse location.

private void WindowFinder_MouseMove(object sender, MouseEventArgs e)
{
    if ( !searching )
        EndSearch();

    // Grab the window from the screen location of the mouse.
    POINT windowPoint = POINT.FromPoint( this.PointToScreen(new Point(e.X,e.Y) ));
    IntPtr found = WindowFromPoint ( windowPoint );
    
    // we have a valid window handle
    if ( found != IntPtr.Zero )
    {    
        // give it another try, it might be a child
        // window (disabled, hidden .. something else)
        // offset the point to be a client point of the active window
        if( ScreenToClient ( found, ref windowPoint ) )
        {
            // check if there is some hidden/disabled
            // child window at this point
            IntPtr childWindow = ChildWindowFromPoint(found, windowPoint);
            if ( childWindow != IntPtr.Zero )
            {    // great, we have the inner child
                found = childWindow;
            }
        }
    }

    // Is this the same window as the last detected one?
    if( found != window.DetectedWindow )
    {
        window.SetWindowHandle ( found );
        Trace.WriteLine ( "FoundWindow:" + window.Name + ":" + 
                          window.Text + " Managed:" + window.IsManaged );
        InvokeActiveWindowChanged ();
    }
}

XPropertyGrid and the tabs

XPropertyGrid inherits from the PropertyGrid in order to be able to add our own tabs to the PropertyGrid.

The Tabs of the Runtime Object Editor

All tabs inherit from System.Windows.Forms.Design.PropertyTab and provide a list of properties in public override PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes). The list of methods are obtained as PropertyDescriptor[] objects. From this point on, you have no more direct control over what we display, and we have to rely completely on overriding the methods from the objects used for describing other objects (PropertyDescriptor, TypeConverter, ComponentDesigner, UITypeEditor).

The custom tabs are:

  1. Properties
  2. AllFields
  3. AllProperties
  4. Events
  5. Methods
  6. Process Information

Properties tab

The Properties tab simply emulates the Properties tab we normally see in Visual Studio. This Properties tab will show the properties of the object based on the attributes they have set. Some properties that are normally visible at design time only, might not be visible here. Also, properties that are marked with DesignerSerializationVisibily(Hidden) or Browsable(false) will not be visible in this tab.

AllFields tab

The AllFields tab will show you all the fields defined in each class from the selected object's hierarchy. The fields can be modified (unless marked as read-only).

AllProperties tab

Contrary to the Properties tab that filters properties based on some of the attributes applied and does not show non-public properties, the AllProperties tab will display all the properties defined on the objects, disregarding the attributes or visibility of the properties. The AllProperites tab also allows hierarchical navigation inside the collections by allowing you to expand them and select items you want to modify.

AllEvents tab

The Events tab will display all the events defined on an object and give you the option to view all the event listeners attached to each event, including the objects that own the event handler and the function name that will handle the event. Because events can be implemented using the public event { add; remove; } pattern, and there are no specific guidelines about how this pattern is to be implemented, it is possible that the Events tab will not be able to correctly read the listeners registered for some of the events.

Methods tab

MethodPropertyDescriptor

Describes how a method is "to be seen" in the grid.

A list of such objects is generated by the MethodsTab.GetProperties and passed on to the grid. The grid will interrogate the descriptor for its value, the editor, and the child objects. We will return as the value of a method, the result from the last invocation. As child objects, we publish the list of parameters the method has, thus we can open the method declaration and fill in the typed parameters.

Whenever we change the value of a parameter, the MethodPropertyDescriptor will invoke the method for us and will give us the return value.

ParameterPropertyDescriptor

When the grid editor requests the list of child properties of the MethodPropertyDescriptor, we return an array containing a ParameterPropertyDescriptor to describe each parameter of the method, and a ReturnParamterDescriptor to describe and show the returned value of the last invoke of the method.

Usage

The RuntimeObjectEditor can be integrated in your application to be used for debugging purposes or can be injected into any running .NET process (including Visual Studio if you want to be convinced that Visual Studio contains .NET code).

Injecting RuntimeObjectEditor into other processes:

  1. Start the RuntimeObjectEditorLoader.exe (the loader that can inject the editor into other processes).
  2. Start any .NET application (.NET 1.1 or .NET 2.0).
  3. Drag and drop the WindowFinder on any window from the newly started .NET process.
    • The title of the editor will change to "target in different process. release selection to hook".
  4. Once you release the mouse after the drag and drop operation, the RuntimeObjectEditor will hook into the selected process and restart inside the new process.
  5. Start playing with the objects from the new process.
Note:
  • Some .NET processes use unmanaged windows that can not be hooked by the RuntimeObjectEditor (e.g.: you can not select a button from a MessageBox or a web browser window hosted in another process).
  • If you open a modal dialog and you can not get access to the RuntimeObjectEditor anymore, just press Control+Shift+R to restart the RuntimeObjectEditor on top of the modal window you have active.
  • Once loaded in a process, the RuntimeObjectEditor can "jump" into another process if you drag the window finder to a window in another process.
  • If you want to hook into Visual Studio, you can start by selecting the Properties window of Visual Studio or any form open in Design mode.
  • Changes done to forms that are visible in Design mode inside Visual Studio do get applied if you switch to a code window or save the form.

Integrating RuntimeObjectEditor into your application

  1. Add a reference to RuntimeObjectEditor.dll.
  2. Write RuntimeObjectEditor.ObjectEditor.Instance.Enable(); in your static void Main just before your Application.Run code. This will enable the ObjectEditor and will register the hotkey. The default hotkey used is "Control+Shift+R". If you want to change the default hotkey, just set RuntimeObjectEditor.ObjectEditor.Instance.HotKey to whatever key combination you want. The property supports combinations like: Control|Alt|Shift|+key (e.g.: Control+Shift+Alt+F1).
  3. When running your application, press the hot key combinations you registered and start playing with the editor.

Future improvements

  • Provide better invoke options (invoke on request).
  • Be able to hook/log any event, and maybe break into debugger.
  • Make a log with all the changes you apply to a window so you can then copy/paste them into code.
  • Integrate with Lutz Roeder's .NET Reflector.

References

History

  • You can always find the latest version at: Runtime Object Editor's Blog.
  • 29 May 2006 v1.1.4 - Second major release:
    • Show/Edit fields.
    • Show/Edit all properties.
    • Navigate collections.
    • Show events and registered event listeners.
    • Show process information.
    • Navigate back/forward between objects.
    • Inject into running .NET processes.
  • 27 Feb 2005 v1.0.1 - First version:
    • Show/Edit public properties normally visible in the Designer.
    • Invoke methods on objects.
    • Code integration in other applications.

Acknowledgements

I have to thank Rama Krishna Vavilala for his article A simple Windows Forms properties spy, from where I got the process injection code and integrated it into the RuntimeObjectEditor.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Corneliu Tusnea
Technical Lead OneSaas - Cloud Integrations Made Easy
Australia Australia

Comments and Discussions

 
GeneralMy vote of 5 Pin
itsho23-Jul-13 3:10
memberitsho23-Jul-13 3:10 
GeneralRe: My vote of 5 Pin
Corneliu Tusnea23-Jul-13 4:35
memberCorneliu Tusnea23-Jul-13 4:35 
QuestionWhat about in win32 process ? Pin
leal854-Nov-10 6:43
memberleal854-Nov-10 6:43 
QuestionRuntimeEditorHook Pin
AdeS8922-Oct-10 0:52
memberAdeS8922-Oct-10 0:52 
GeneralOutOfMemoryException Pin
Member 462140918-Sep-08 2:31
memberMember 462140918-Sep-08 2:31 
Generallive Pin
bullnan6-May-08 17:15
memberbullnan6-May-08 17:15 
QuestionUse for replacement of PropertyGrid, in vb.net Pin
Member 222717110-Apr-08 12:54
memberMember 222717110-Apr-08 12:54 
Generalwww.codeplex.com/hawkeye Pin
Corneliu Tusnea14-Mar-08 20:32
memberCorneliu Tusnea14-Mar-08 20:32 
GeneralGet Object in Internet Explorer Pin
ramip9-Dec-07 4:00
memberramip9-Dec-07 4:00 
Generalget Object in Web Browser Pin
ramip9-Dec-07 3:52
memberramip9-Dec-07 3:52 
GeneralWeb "Dynamic Property" framework. [modified] Pin
codezilla942-Oct-07 14:53
membercodezilla942-Oct-07 14:53 
General5 Of Course. Pin
Hoss Fly25-Sep-07 18:20
memberHoss Fly25-Sep-07 18:20 
What an awsome Project. Thanks!

HossFly
GeneralAccess denied error - with a solution Pin
Keith Iveson21-Sep-07 3:22
memberKeith Iveson21-Sep-07 3:22 
GeneralGreat Job! And a suggestion ... Pin
cplotts19-Jun-07 12:14
membercplotts19-Jun-07 12:14 
GeneralRe: Great Job! And a suggestion ... Pin
cplotts21-Jun-07 6:55
membercplotts21-Jun-07 6:55 
QuestionCornelus, where are you? Pin
caddzooks10-Jun-07 14:34
membercaddzooks10-Jun-07 14:34 
GeneralCompliments again Pin
Marcus Deecke30-May-07 11:57
memberMarcus Deecke30-May-07 11:57 
QuestionHow to edit an object which is not a part of a control? Pin
Diana Fernandez29-Jan-07 23:56
memberDiana Fernandez29-Jan-07 23:56 
AnswerRe: How to edit an object which is not a part of a control? Pin
vtalau31-Oct-07 23:57
membervtalau31-Oct-07 23:57 
AnswerRe: How to edit an object which is not a part of a control? Pin
Nilzor20-Mar-10 8:27
memberNilzor20-Mar-10 8:27 
GeneralBreeding Pin
Marcus Deecke15-Nov-06 14:33
memberMarcus Deecke15-Nov-06 14:33 
GeneralRe: Breeding Pin
Corneliu Tusnea3-Dec-06 3:00
memberCorneliu Tusnea3-Dec-06 3:00 
QuestionGreat stuff. How about as a generic control? Pin
mpwcsfb13-Nov-06 6:47
membermpwcsfb13-Nov-06 6:47 
AnswerRe: Great stuff. How about as a generic control? Pin
Corneliu Tusnea13-Nov-06 23:32
memberCorneliu Tusnea13-Nov-06 23:32 
GeneralHawkeye - I can see your SecureStrings! Pin
Corneliu Tusnea26-Oct-06 4:18
memberCorneliu Tusnea26-Oct-06 4:18 
GeneralReally COOL! Pin
topcoder312-Oct-06 18:39
membertopcoder312-Oct-06 18:39 
GeneralProblems with controls on forms Pin
solo6-Sep-06 23:08
membersolo6-Sep-06 23:08 
QuestionRe: Problems with controls on forms Pin
Corneliu Tusnea7-Sep-06 15:02
memberCorneliu Tusnea7-Sep-06 15:02 
AnswerRe: Problems with controls on forms Pin
TrendyTim7-Sep-06 16:43
memberTrendyTim7-Sep-06 16:43 
AnswerRe: Problems with controls on forms Pin
solo8-Sep-06 3:42
membersolo8-Sep-06 3:42 
GeneralAwesome Pin
Rama Krishna Vavilala11-Aug-06 17:19
memberRama Krishna Vavilala11-Aug-06 17:19 
GeneralRe: Awesome Pin
Corneliu Tusnea13-Aug-06 4:42
memberCorneliu Tusnea13-Aug-06 4:42 
GeneralDynamic loading in debug builds only... Pin
rittjc13-Jul-06 16:20
memberrittjc13-Jul-06 16:20 
GeneralRe: Dynamic loading in debug builds only... Pin
Corneliu Tusnea15-Jul-06 16:29
memberCorneliu Tusnea15-Jul-06 16:29 
GeneralRe: Dynamic loading in debug builds only... Pin
rittjc15-Jul-06 18:46
memberrittjc15-Jul-06 18:46 
QuestionNice job Pin
rittjc13-Jul-06 13:56
memberrittjc13-Jul-06 13:56 
AnswerRe: Nice job Pin
Corneliu Tusnea15-Jul-06 16:25
memberCorneliu Tusnea15-Jul-06 16:25 
QuestionRenaming properties ... Pin
MatthewDBush19-Jun-06 22:06
memberMatthewDBush19-Jun-06 22:06 
AnswerRe: Renaming properties ... Pin
Corneliu Tusnea20-Jun-06 14:47
memberCorneliu Tusnea20-Jun-06 14:47 
GeneralImpressive and one request Pin
Payo15-Jun-06 23:27
memberPayo15-Jun-06 23:27 
GeneralRe: Impressive and one request Pin
Tutu19-Jun-06 14:52
memberTutu19-Jun-06 14:52 
GeneralRe: Impressive and one request Pin
Payo20-Jun-06 2:02
memberPayo20-Jun-06 2:02 
NewsNew beta For download Pin
Tutu12-Jun-06 4:31
memberTutu12-Jun-06 4:31 
GeneralWow Pin
Paul Conrad9-Jun-06 6:45
memberPaul Conrad9-Jun-06 6:45 
GeneralRe: Wow [modified] Pin
Tutu12-Jun-06 3:39
memberTutu12-Jun-06 3:39 
GeneralI'm stunned Pin
#endif6-Jun-06 4:18
member#endif6-Jun-06 4:18 
GeneralRe: I'm stunned Pin
Tutu6-Jun-06 4:37
memberTutu6-Jun-06 4:37 
GeneralAmazing, but with some problems. Pin
NinjaCross31-May-06 0:06
memberNinjaCross31-May-06 0:06 
GeneralRe: Amazing, but with some problems. Pin
Tutu31-May-06 1:52
memberTutu31-May-06 1:52 
GeneralRe: Amazing, but with some problems. Pin
NinjaCross31-May-06 7:47
memberNinjaCross31-May-06 7:47 

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
Web02 | 2.8.150428.2 | Last Updated 30 May 2006
Article Copyright 2006 by Corneliu Tusnea
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid