![]() |
Languages »
C# »
Utilities
Intermediate
Runtime Object EditorBy Corneliu TusneaA powerful window/object editor to be used at runtime that allows viewing/changing of properties and fields, method invocations, and object hierarchy navigation. |
C#.NET1.1, .NET2.0, WinXP, Win2003VS.NET2003, VS2005, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

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:
Controls".
public, private ...).
Form_Load).
Application, CurrentContext, CurrentThread, CurrentPrincipal, CurrentProcess, and garbage collection.
Controls collection of a Control). 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 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].
The Runtime Object Editor has three major components:
PropertyGrid derived class where you can see and edit the properties of your object.
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 inherits from the PropertyGrid in order to be able to add our own tabs to the PropertyGrid.

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:

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.

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).

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.

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

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).
MessageBox or a web browser window hosted in another process).
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).
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.
General
News
Question
Answer
Joke
Rant
Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 30 May 2006 Editor: Smitha Vijayan |
Copyright 2006 by Corneliu Tusnea Everything else Copyright © CodeProject, 1999-2010 Web20 | Advertise on the Code Project |