Profilo di ArildRandom thoughts about An...BlogElenchi Strumenti Guida

Blog


06 settembre

Debugging more events

A couple of months ago, I posted a class that used the new DynamicMethod class in .NET to dynamically hook up events to all events declared on an object and display a string in VS' output pane whenever that event is raised. While quite useful, it has some drawbacks; most importantly, if you are doing this to multiple objects of the same or similar type (think multiple controls, all of which share a large number of events), it's very hard to see which particular object the event is coming from.

In some cases, you might also want to hook up only a particular event or set of events on a class, or exclude certain events. For example, all the Mouse-related events (MouseEnter, MouseMove, MouseLeave) can quickly clog up your output and hide the information you are looking for.

With this in mind, I decided to make a better version of this method. The new version is vastly improved:

  • It now supports a filter string which lets you specify a regex that has to match the name of the event(s) you are after
  • It now supports a custom format string which lets you output a lot of relevant information whenever the event is raised

The filter string can be used like this:

DebugUtils.DebugEvents(someControl, null, ".*Changed"); // only monitor the *Changed events on the control (think databinding events)

That's pretty much all there is to the filter string, if you know your regular expressions. The format string is a little more involved, though. It supports the following special keywords (yeah, I stole some of these from the VS 2005 tracepoint syntax, so sue me...):

  • $EVENT - Replaced with the name of the event raised (you almost always want this one).
  • $TYPE - Replaced with the fully qualified type name of the object raising the event.
  • $TIMESTAMP - Replaced with the current time.
  • $CALLER - Replaced with the fully qualified method name (and possibly line number if symbols are available) of the method that raised the event.
  • $STACKTRACE - Replaced with a full stack trace of the code that eventually raised the event in question.

You probably don't want to use the last one unless you also have some filtering on the events (or very few events on the object to begin with); it generates a lot of output. However, it can often be very useful if you need to see why a particular event is being raised. Line numbers and file names will be included if debug symbols are available.

In addition to the special keywords, it can also evaluate simple property and field expressions on the two arguments passed into the event. These are designated as "sender" and "e", respectively (as is the custom for naming event arguments in .NET). For example:

DebugUtils.DebugEvents(this.reportsListView, "$TIMESTAMP: $EVENT raised, e.InvalidRect is {e.Invalidrect}", "Invalidated");

Which prints the following output to VS' Output Pane:

22:53:32.995125: Invalidated raised, e.InvalidRect is {X=0,Y=0,Width=627,Height=269}
22:53:33.010750: Invalidated raised, e.InvalidRect is {X=0,Y=0,Width=627,Height=269}
22:53:39.932625: Invalidated raised, e.InvalidRect is {X=0,Y=0,Width=627,Height=269}

(etc...)

The source for this file can be found in the SVN repository at http://ankhsvn.com/svn/Utils/trunk/Utils/Debugging/DebugUtils.cs, and unit tests: http://ankhsvn.com/svn/Utils/trunk/UtilsTest/Debugging/DebugUtilsTest.cs. To use it for yourself, either copy the file as is or check out the entire VS 2005 project from http://ankhsvn.com/svn/Utils/trunk/ and build it. The class is made available under a slightly modified MIT license (I removed the clause requiring derivatives to carry the notice).

UPDATE: I've removed the use of the ListUtils class so that people who want to copy the file in itself won't need to also get the ListUtils class. I've also added XML doc comments to the various overloads.

04 luglio

The ”Members” and ”Types” dropdowns in VS.NET

The code editor window in VS.NET has two dropdowns on top, one containing the types present in the current file and the other containing the members present in that file. This is a pretty good idea, and makes it easy to navigate through a code file. However, I found that I never really used it all that much. I’m not all that big on having to use the mouse to navigate in VS.NET in the first place, and it was usually faster to just search through the file either manually with arrow keys and PgUp/PgDwn (using the Eyeball Mk I feature shipped with most Visual Studio users) or with incremental search (Ctrl+I).

It seems that the main trouble with those two dropdowns is that they’re not easily accessible through the keyboard. There is no built-in VS command that drops them down. However, you can set the focus on the navigation bar by pressing Ctrl-F2. That’ll leave the Types dropdown focused, so you can use Down Arrow to navigate it, or press TAB to get to the Members dropdown. This means that if you want to use the Members dropdown to navigate to another member in the current class, you have to do Ctrl-F2 + TAB + Down Arrow before you can start selecting the member you want. For me, this is too much (and Ctrl-F2 is a very awkward key combination as well unless you have very big hands or use both hands to press it).

The lack of a decent key binding for those two dropdowns kept annoying me to the point where I decided to do something about it. So I wrote a small VS addin that adds two new commands to Visual Studio, one to drop down the Types combo and one to drop down the Members combo. It also sets focus on the dropdowns, so you can navigate right away using arrow keys and/or the first letter in the member you’re looking for.

When starting up for the first time, the addin will ask you if it should install key bindings for the two commands, Ctrl-D, Ctrl-P (for tyPes) and Ctrl-D, Ctrl-M (for Members). I considered Ctrl-D, Ctrl-T for the Types one, but it felt a lot more awkward to use, so I settled on the current choice.

You can of course remap the key bindings for the commands yourself using the Keyboard options page under Tools->Options. The commands are named “MemberDropDown.DropDownMembers” and “MemberDropDown.DropDownTypes”.

The addin will presently only work for Visual Studio 2005, however, I might consider making it work for all VSes if there’s interest. You can find an MSI installer here and the source is in a Subversion repository here.

15 giugno

Debugging events and the joys of DynamicMethod

The DynamicMethod class is new to .NET 2.0. It is believed that it was added as a consequence of Jim Hugunin being hired by Microsoft to work on IronPython, a CLR version of the Python language. Dynamic languages like Python, Perl, JavaScript and PHP usually provide a function called eval or something similar, which allows the evaluation of code provided as a string. In other words, you could do something like s = “print(“ + a + “ + “ + b )”; eval( s ) to dynamically print the result of a calculation (ok, the example’s a little silly in that there are easier ways to accomplish this, but anyway…).

In versions of IronPython that ran on .NET 1.x, eval was implemented by evaluating the expression and emitting CIL code using the functionality in the System.Reflection.Emit namespace to generate a method in a new .NET assembly. This assembly would then be loaded into the runtime and the method would be called. Unfortunately, .NET has no way of unloading an assembly from an appdomain once it was loaded, so those versions of Ironpython had an implicit memory leak every time you used eval.

DynamicMethod was introduced as a way to achieve this functionality without having the overhead of creating a new assembly merely to create and execute a dynamically provided method. DynamicMethod is also a part of the System.Reflection.Emit and lets you emit code in the same way you would to an assembly on disk. However, with DynamicMethod there is no need to create a new assembly. Instead, the CIL code is generated directly to memory, and .NET’s inability to unload assemblies from an appdomain are no longer relevant.

I encountered a situation recently where I had the need to see what events a particular Windows Forms component raised and in which order. The documentation was of no real help, so I started looking for other ways to investigate this. Manually hooking up each event to a handler wasn’t very tempting, even with the help of anonymous delegates. I knew I could get a list of the available events through reflection, and even hook up event handlers this way dynamically, but how could I create event handler methods for all of them that would actually give me information on which event was raised?

While attending Oslo University for my masters, I had both taken a class on compiler implementation and design and been a teaching assistant in the same class. During those two semesters, I wrote two compilers that emitted CIL code using the functionality in System.Reflection.Emit, so I had some experience with code generation and CIL. While I’d never actually used it, I had heard of the DynamicMethod class and knew roughly how it worked. It struck me that it would be a good fit for this problem; with DynamicMethod, I could dynamically emit custom event handlers for every event on the object I wanted to monitor.

It turned out that using DynamicMethod was little different from the “traditional” way of using S.R.E to emit CIL code. You obtain an ILGenerator object, which has a bunch of overloaded Emit methods to create the various opcodes. In my case, I decided to emit a call to System.Debug.WriteLine with the full name of the event as a parameter.

The code is as follows:

[Conditional("DEBUG")]

public static void DebugEvents( params object[] objects )

{

    foreach ( object o in objects )

    {

        foreach ( EventInfo info in o.GetType().GetEvents( BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public ) )

        {

            MethodInfo mi = info.EventHandlerType.GetMethod( "Invoke" );

            Type[] parmTypes = ListUtils.ToArray(

                ListUtils.Map<ParameterInfo, Type>( mi.GetParameters(), delegate( ParameterInfo par )

                {

                    return par.ParameterType;

                } )

            );

            DynamicMethod m = new DynamicMethod( info.Name + "Handler", typeof( void ), parmTypes, o.GetType() );

            ILGenerator generator = m.GetILGenerator();

 

            string eventInfoString = String.Format( "Event raised: {0}.{1}", o.GetType().FullName, info.Name );

            generator.Emit( OpCodes.Ldstr, eventInfoString );

            generator.EmitCall( OpCodes.Call, typeof( Debug ).GetMethod( "WriteLine", new Type[] { typeof( string ) } ), null );

            generator.Emit( OpCodes.Ret );

 

            Delegate del = m.CreateDelegate( info.EventHandlerType );

 

            info.AddEventHandler( o, del );

        }

    }

}

As you can see, it uses reflection to obtain EventInfo objects for all events on the passed-in objects. It then gets the parameter list for its Invoke method and creates a DynamicMethod object that has the same signature. Through the ILGenerator object, a call to Debug.WriteLine is emitted with a string containing the name of the event as the sole parameter. A delegate is created from the DynamicMethod which is then added as an event handler for the event.

Anything sent to Debug.WriteLine goes to the Debug window in VS.NET if you run an application under the debugger, so if you call DebugEvents passing in a very plain Windows Forms form as an argument you should see something like this:

 

 

The ListUtils class referenced in the code can be found here.

13 giugno

MSDN Man

Huh, neat:

Msdnman is a command-line documentation tool that exposes the content in the Microsoft/TechNet Publishing System in a manner reminiscent of the *nix "man" command.