An Ode to wfSpy

As I’ve mentioned before, I love user interface spying utilities and often find myself championing their use.

Today, I got a message from someone requesting the modifications we made to wfSpy. I’ve always wanted to publish them back to the community and tried to do so by contacting the original author. However, I never got any response.

wfSpy stands for Windows Forms Spy and so it is a spying utility for Windows Forms applications (and specifically for .NET 2.0 and forward). It is similar to Hawkeye, but is easier to use … and doesn’t have quite as much functionality.

We made several modifications to it but the notable two are as follows.

First off, a colleague (Don Kackman) of mine added the crosshairs ability. Take a look at the main window that comes up when you launch it.

image

If you click on the magnifying glass, drag it on top of a Windows Forms control, and release … the wfSpy properties window will then come up.

image

The wfSpy properties window shows all the properties on the control that you just selected … and not only can you view them … but you can also modify them (at runtime) as well!

The second notable change that we added was synchronizing the tree view (on the wfSpy’s main window) such that the control you selected … is the active ‘window’ selected.

This is extremely useful in the case where you have controls that are hiding other controls … and there is no way to select those hidden (or covered) controls with the crosshairs. In this case, you use the crosshairs to select the control you can select, and then you close the properties window and use the tree view to select the control you want. I would often turn the Visible property of a control on and off … to help me navigate through the tree of controls.

When utilizing the tree view synchronization feature … make sure you have a refreshed version of the current controls in the tree view … by clicking the ‘Refresh’ button on wfSpy’s main window. Otherwise, the synchronization logic might not be able to find the control (in the tree view) you selected.

So, without further adieu … here is the source code.

Hope it helps!

p.s.

Leave a comment if it does help you … I always enjoy hearing that my efforts have actually paid dividends. 🙂

p.s.s.

I have just (May 15th, 2012) pushed the sourced code to GitHub after receiving yet another request for the .NET 4.0 version.

It is at the following location: https://github.com/cplotts/wfSpy

Share

WPF & Memory Leaks

The Red Herring:

Recently, I had to track down why all of our new WPF screens were leaking memory like a sieve. A coworker of mine ran into a discussion on the WPF forum and my jaw dropped. I rapidly dove into this issue and soon discovered that this issue was not really the one causing us problems (that I could tell). It seems as if this issue only raises its ugly head in certain situations (see the post for more detail).

The Awesome Tool:

memprofiler.png

At this point, we ran into a tool that, in my opinion, is a must have if you are trying to find memory leaks in a .NET application. It is called (aptly enough), .NET Memory Profiler and it is made by a company called SciTech software. Previously, we had been using AQtime and I still would recommend that tool for performance profiling but when it comes to memory allocation profiling (i.e. memory leaks), it is quite slow. The .NET Memory Profiler doesn’t do performance profiling and focuses exclusively on memory allocation profiling. I think this has made it the best tool out there. I have tried Jet Brains dotTRACE as well, which is also very fast, but the .NET Memory Profiler beats that one hands down in how it presents the information to the user and how it allows you to navigate through all the objects that have been created or are still living on the heap. They do offer a free 14-day trial and I would recommend that you try their 3.5 version which you can preview now. This version has a very nice feature that they call Automatic Memory Analysis, which is basically tips and warnings regarding common memory usage issues.

The Real Issue:

Using this tool and some grit, the previously mentioned coworker and I finally ran into the issue that was causing us problems. It is a known issue. Personally, I love what it says at the knowledge base article just referenced:

When you use data binding in Microsoft Windows Presentation Foundation (WPF), a memory leak may occur.

Ha! Are you kidding me?!

You can check out the knowledge base article for more info, but basically, if you are binding to something that isn’t a DependencyProperty or doesn’t implement INotifyPropertyChanged, WPF tries to use the ValueChanged event. In doing so, it calls PropertyDescriptor.AddValueChanged which creates a strong reference from the property descriptor to the object being bound to.

Something as simple as the following xaml causes a leak:

<Label Name="MyLabel">
    <Stack Panel Name="MyStackPanel">
        <TextBlock Text="{Binding ElementName=MyStackPanel, Path=Children.Count}" />
    </StackPanel>
</Label>

One way that you can verify that this issue is causing you problems is to see PropertyDescriptor in the root path. Check out this screen capture:

rootpath.png

The Solution:

So, how did we rid ourselves of this problem? Well, we basically went in and modified the objects that were causing us leaks to inherit from INotifyPropertyChangedeven if we didn’t really want to notify anyone of changes. In the those cases, we would #pragma the CS00067 warning away that came from not using the PropertyChanged event:

public class SomeClassBeingDataBoundTo : INotifyPropertyChanged
{
    // class implementation

#pragma warning disable 0067
    // If you data-bind to a regular .NET property on a regular .NET object, that object will never get garbage-collected.
    //    •    Dependency properties are not affected.
    //    •    Objects implementing the INotifyPropertyChanged interface are not affected.
    public event PropertyChangedEventHandler PropertyChanged;
#pragma warning restore 0067
}

How the heck did I miss this?

So, after all the excitement subsided, I did a Google search to see if I could find any other blogs that talks about this problem.  Heh heh. The link at the top of search results … was about our issue. Argh! I don’t know how I missed it before when I was doing my original research.

Even better, the search results brought up Jossef Goldberg’s priceless post on finding memory leaks in WPF applications (that I’ve run into before). That post is a must read if you are trying to find leaks in your WPF applications. And, yes, it too, talks about our issue.

Someone, please take my software engineering card away.

I hope my pain is someone else’s gain.

Share

Snoop Now Works in WPF Interop Scenarios, Part II

First off, in my previous post, I made the mistake of assuming (given the new look and new functionality) that Pete Blois had bumped the version of Snoop up to 2.0. This does not seem to be the case. So, oops! My apologies!

Now, onto the meat of post: I have found a couple more places where you need to insulate yourself from not having a current Application … and I was able to fix the keyboard issue!

Let’s tackle the keyboard issue first as that is the big one. In the Inspect method of the SnoopUI class, you need to call the static method ElementHost.EnableModelessKeyboardInterop and you need to do that when in an interop scenario, that is, when the current Application is null.

The MSDN documentation for this method states that this method allows a System.Windows.Window to receive keyboard messages correctly when opened modelessly from Windows Forms (our interop scenario). Hmm. Sounds exactly like what I was looking for!

public void Inspect(object target)
{
    this.rootObject = target;
    this.Load(target);
    this.CurrentSelection = this.root;

    this.OnPropertyChanged("Root");

    if (Application.Current != null)
    {
        this.Owner = Application.Current.MainWindow;
    }
    else
    {
        ElementHost.EnableModelessKeyboardInterop(this);
    }
    this.Show();
}


This also requires you to add a reference to WindowsFormsIntegration.dll and to add a using statement:

using System.Windows.Forms.Integration;

With the above changes, you should be able to use the keyboard once again to change property values in the property grid that comes up when you Snoop something. Whew! That copy/paste trick was getting old, really fast.

Now, onto the additional places where you need to protect yourself from not having an Application instance. First, the Previewer was broken … and you need to modify the HandleMagnify method of the Previewer class:

private void HandleMagnify(object sender, ExecutedRoutedEventArgs e)
{
    Zoomer zoomer = new Zoomer();
    zoomer.Target = this.Target;
    if (Application.Current != null)
        zoomer.Owner = Application.Current.MainWindow;
    zoomer.Show();
    e.Handled = true;
}


Second, you need to modify the ProcessFilter method of the SnoopUI class so that it uses the Dispatcher for the current thread versus grabbing it off the non-existent Application instance:

private void ProcessFilter()
{
    this.filtered.Clear();

    // Blech.
    if (this.filter == "Clear Filter")
    {
        Dispatcher dispatcher = null;
        if (Application.Current == null)
            dispatcher = Dispatcher.CurrentDispatcher;
        else
            dispatcher = Application.Current.Dispatcher;

        dispatcher.BeginInvoke
        (
            DispatcherPriority.Loaded,
            new DispatcherOperationCallback
            (
                delegate(object arg)
                {
                    this.Filter = string.Empty;
                    return null;
                }
            ),
            null
        );
        return;
    }
    if (this.filter == "Visuals with binding errors")
        this.FilterBindings(this.root);
    else if (this.filter.Length == 0)
        this.filtered.Add(this.root);
    else
        this.FilterTree(this.root, this.filter.ToLower());
}

By the way, I would love to hear (by leaving a comment on the blog here), if this helps you at all. I was truly missing the ability to Snoop our WPF interop application myself.

Enjoy!

p.s.

I would love to make my source code modifications to Snoop readily available to the general public, but I have been unable to contact Pete Blois and obtain his permission to do so. Sorry!

(The source code and binaries for Snoop are now (see posts: 1, 2) up on CodePlex. Please go download it from there as that code will contain the latest and greatest bits.)

Share

Snoop Now Works in WPF Interop Scenarios, Part I

Background:

Coming from the land of Windows Forms, I have grown addicted to having tools like wfSpy and Hawkeye. A software engineer at the presentation layer needs to have tools like these in order to inspect the objects in a running application and change properties on the fly.

Very soon after jumping in head first into WPF, I discovered Pete Blois’ utility: Snoop. It was definitely what I was looking for. Unfortunately, after playing with it for a while, I learned that it didn’t support our WPF interop scenario. In particular, our application is a Windows Forms application that is hosting WPF content through ElementHost. When you use ElementHost, you don’t have an Application object and Snoop coughs up a hairball because of that.

After that, Josh Smith created Woodstock and Mole soon followed. These are both debugger visualizers, and in particular, Mole is extremely nice and powerful. The Achilles tendon of debugger visualizers, however, is that you have to be running in the Visual Studio debugger. There are many cases where you can’t or don’t want to do this.

Josh Smith realized this and has created Crack.NET. This is a heap walker in the vein of Snoop and Mole … but it can be run outside of the debugger. It is a useful tool in its own right, and of particular note, you can modify the object you’ve ‘cracked’ using IronPython in the tool’s Scriptorium area.

However, even given the above, I was still missing the functionality of good, old wfSpy. Snoop was very close to what I wanted, it just didn’t handle the WPF interop story.

So, after reading this post in the WPF forums, I finally broke down, dove into the source code and figured out why. It was rather easy to fix, actually, and here is what I had to do.

 

The Fix:

In the Enqueue method of the DelayedCall class, you need to get hold of the Dispatcher from something other than the Application.Current object. Here is the whole Enqueue method:

public void Enqueue()
{
    if (!this.queued)
    {
        this.queued = true;

        Dispatcher dispatcher = null;
        if (Application.Current == null)
            dispatcher = Dispatcher.CurrentDispatcher;
        else
            dispatcher = Application.Current.Dispatcher;

        dispatcher.BeginInvoke
        (
            this.priority,
            new DispatcherOperationCallback(this.Process),
            null
        );
    }
}


In the Inspect method of the SnoopUI class, you once again need to protect yourself from not having an Application object:

public void Inspect(object target)
{
    this.rootObject = target;
    this.Load(target);
    this.CurrentSelection = this.root;

    this.OnPropertyChanged("Root");

    if (Application.Current != null)
        this.Owner = Application.Current.MainWindow;
    this.Show();
}

After those two changes, you can Snoop WPF content hosted in a Windows Forms application through ElementHost. Do I hear a ‘hallelujah’?

On a related note:

One thing I should mention is that property editing is broken in Snoop 2.0. In the WPF forum post mentioned above, Mark points out how to fix this. You just need to add the following line in the correct place in the PropertyInformation constructor:

binding.Mode =
	property.IsReadOnly ?
	BindingMode.OneWay :
	BindingMode.TwoWay;

However, this doesn’t seem to fix it completely when you are running in a WPF interop scenario … because there is still an issue to find and fix. Namely, you can’t use the keyboard to modify the property values. However, I have discovered that you can paste a value in using the clipboard. If you find out how to fix this, please let me know.

Finally:

Mark also has fixes for a couple other items. One takes care of an issue when the nesting gets too deep and another is a fix for popping the context after you ‘delve’ in on something.

I hope this helps someone. I personally am happy to the point of tears that I will now be able to Snoop our application!

Update:

I have found the keyboard issue and have fixed it. I have also uncovered a couple other changes that you need to make. For example, the Previewer wasn’t working. See my next blog post for details.

Update:

(The source code and binaries for Snoop are now (see posts: 1, 2) up on CodePlex. Please go download it from there as that code will contain the latest and greatest bits.)

Share

Kaxaml: Don’t Leave Home Without It

KaxamlLogo

Ok, I just have to give a shout out to one of the best tools out there for authoring loose xaml. And, if the logo didn’t give it away … it’s Robby Ingebretsen’s Kaxaml tool. It is available here for download … free of charge!

It’s been out for quite some time … so the purpose of this blog post is really to just publicly thank him for making such an awesome tool … one, in fact, that I don’t leave home without.

Recently, I have been composing Haikus … just because a tool like this … deserves poetry … and poetry better than mine!

But, in case you haven’t heard about it or haven’t played with it much … here is some quick info. I believe you pronounce it <ka-zam-al> … and I like to think like Shazam! Pow! (I have not confirmed this was the intent of its author … it might just be the meanderings of this crazy mind of mine.)

It has a pretty sweet list of features:

  • A snippet library with the ability to insert snippets via shortcut
  • IntelliSense
  • A folding editor
  • An integrated color picker
  • A xaml scrubber (or pretty printer or formatter or whatever you want to call it)
  • The ability to zoom in and out on your rendered xaml
  • The ability to make your xaml larger (use ctrl-wheel)
  • Handles both WPF and Silverlight
  • And more!
    Bonus: Robby recently recorded several videos that will bring you up to Kaxaml power user status in a matter of minutes. Check them out.
Share