Click here to Skip to main content
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 Pinmemberitsho23-Jul-13 2:10 
GeneralRe: My vote of 5 PinmemberCorneliu Tusnea23-Jul-13 3:35 
QuestionWhat about in win32 process ? Pinmemberleal854-Nov-10 5:43 
QuestionRuntimeEditorHook PinmemberAdeS8921-Oct-10 23:52 
GeneralOutOfMemoryException PinmemberMember 462140918-Sep-08 1:31 
Generallive Pinmemberbullnan6-May-08 16:15 
QuestionUse for replacement of PropertyGrid, in vb.net PinmemberMember 222717110-Apr-08 11:54 
Generalwww.codeplex.com/hawkeye PinmemberCorneliu Tusnea14-Mar-08 19:32 
GeneralGet Object in Internet Explorer Pinmemberramip9-Dec-07 3:00 
Generalget Object in Web Browser Pinmemberramip9-Dec-07 2:52 
GeneralWeb "Dynamic Property" framework. [modified] Pinmembercodezilla942-Oct-07 13:53 
General5 Of Course. PinmemberHoss Fly25-Sep-07 17:20 
GeneralAccess denied error - with a solution PinmemberKeith Iveson21-Sep-07 2:22 
GeneralGreat Job! And a suggestion ... Pinmembercplotts19-Jun-07 11:14 
GeneralRe: Great Job! And a suggestion ... Pinmembercplotts21-Jun-07 5:55 
QuestionCornelus, where are you? Pinmembercaddzooks10-Jun-07 13:34 
GeneralCompliments again PinmemberMarcus Deecke30-May-07 10:57 
QuestionHow to edit an object which is not a part of a control? PinmemberDiana Fernandez29-Jan-07 22:56 
AnswerRe: How to edit an object which is not a part of a control? Pinmembervtalau31-Oct-07 22:57 
AnswerRe: How to edit an object which is not a part of a control? PinmemberNilzor20-Mar-10 7:27 
GeneralBreeding PinmemberMarcus Deecke15-Nov-06 13:33 
GeneralRe: Breeding PinmemberCorneliu Tusnea3-Dec-06 2:00 
QuestionGreat stuff. How about as a generic control? Pinmembermpwcsfb13-Nov-06 5:47 
AnswerRe: Great stuff. How about as a generic control? PinmemberCorneliu Tusnea13-Nov-06 22:32 
GeneralHawkeye - I can see your SecureStrings! PinmemberCorneliu Tusnea26-Oct-06 3:18 
GeneralReally COOL! Pinmembertopcoder312-Oct-06 17:39 
GeneralProblems with controls on forms Pinmembersolo6-Sep-06 22:08 
QuestionRe: Problems with controls on forms PinmemberCorneliu Tusnea7-Sep-06 14:02 
AnswerRe: Problems with controls on forms PinmemberTrendyTim7-Sep-06 15:43 
AnswerRe: Problems with controls on forms Pinmembersolo8-Sep-06 2:42 
GeneralAwesome PinmemberRama Krishna Vavilala11-Aug-06 16:19 
GeneralRe: Awesome PinmemberCorneliu Tusnea13-Aug-06 3:42 
GeneralDynamic loading in debug builds only... Pinmemberrittjc13-Jul-06 15:20 
GeneralRe: Dynamic loading in debug builds only... PinmemberCorneliu Tusnea15-Jul-06 15:29 
GeneralRe: Dynamic loading in debug builds only... Pinmemberrittjc15-Jul-06 17:46 
QuestionNice job Pinmemberrittjc13-Jul-06 12:56 
AnswerRe: Nice job PinmemberCorneliu Tusnea15-Jul-06 15:25 
QuestionRenaming properties ... PinmemberMatthewDBush19-Jun-06 21:06 
AnswerRe: Renaming properties ... PinmemberCorneliu Tusnea20-Jun-06 13:47 
GeneralImpressive and one request PinmemberPayo15-Jun-06 22:27 
GeneralRe: Impressive and one request PinmemberTutu19-Jun-06 13:52 
GeneralRe: Impressive and one request PinmemberPayo20-Jun-06 1:02 
NewsNew beta For download PinmemberTutu12-Jun-06 3:31 
GeneralWow PinmemberPaul Conrad9-Jun-06 5:45 
GeneralRe: Wow [modified] PinmemberTutu12-Jun-06 2:39 
GeneralI'm stunned Pinmember#endif6-Jun-06 3:18 
GeneralRe: I'm stunned PinmemberTutu6-Jun-06 3:37 
GeneralAmazing, but with some problems. PinmemberNinjaCross30-May-06 23:06 
GeneralRe: Amazing, but with some problems. PinmemberTutu31-May-06 0:52 
GeneralRe: Amazing, but with some problems. PinmemberNinjaCross31-May-06 6: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
Web01 | 2.8.141030.1 | Last Updated 30 May 2006
Article Copyright 2006 by Corneliu Tusnea
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid