Introduction

Some of you may have been www.codeproject.com members for quite some time, and may recall about
4 years ago, I published an article which drew a class diagram from a DLL/Exe called "AutoDiagrammer".
I was quite lucky with that article, as it turned out to be very popular, and got loads of votes and a ton of views. Basically people seemed to love it, which is ace... I was very
happy with that. Every author here wants people to like the stuff they publish (myself included, it's the whole vanity thing I suppose).

Thing is, I wrote that original article a long time ago, when I was just getting into WPF, and although I was pretty happy with it, I always thought it
could be so much better. It was also WinForms, so fast forward a couple of years, I now know enough WPF to really do justice to the original article and get it to how I always
envisaged it could be.

The things that I felt were wrong with the first "AutoDiagrammer" article were as follows:

The drawing of class associations was based on a grid layout.

The user could not move the classes around on the design surface; once they were laid out, that was it.

The Association lines were not that clear to see.

The user could not scale the produced diagram that well (it was possible, but was not that great).

The loading of the DLL/Exe to be drawn as a class diagram was done in the same AppDomain as the AutoDiagrammer.exe app, so when
reflecting, it would be forced into loading all the additionally reflected types from the DLL/Exe into the AutoDiagrammer.exe app's AppDomain. Ouch...not cool.

People found it slightly cumbersome figuring out how to get a diagram actually produced.

That said, there were things I feel I definitely got right such as:

The overall idea (people seemed to generally like it, and find it a very useful tool).

The reflecting of information was correct.

The ability to fine tune what was show on the diagram.

With all these good and bad points in mind. coupled with the fact that I now know enough WPF to do the original code justice and do it how I always wanted
to do it, I thought.. yes, the time is right, do a complete re-write of the original article.

So that is what this article is, it is a complete re-write of the original "AutoDiagrammer" article; the feature
list of this new articles code is:

Detection of valid .NET assembly (yes, same as the first article, this tool only works with .NET Assemblies).

The ability to move the classes in the design surface within the diagram.

The ability to not show classes that did not have any associations on the diagram, but still allow the user the ability to view these from a drop
down list. This aids in keeping the diagram clutter-free, only show what is absolutely needed.

Persisted settings, so that the next time the application is run, your personal settings will be as you left them.

Proper scaling of objects as vectors, so whatever scale the diagram is viewed at, the objects are as clear as they could be.

Saving of the diagram to an PNG file which can easily be viewed using the standard Window Image Viewer.

Printing to a printer.

Loading the DLL/Exe into a separate AppDomain that does not polute the AutoDiagrammer.exeAppDomain with the loaded DLL/Exe types.

Integrated help.

The classes show a full Association popup with all Associations shown as a list of strings.

The Association lines show in a different color when the user hovers over them with the mouse.

As you can see, I have kept what was good with the old article/codebase and have added more features to it. I am really happy with how it turned out and I hope you will be too.

What Does it Look Like

I think the best way to show you how this all looks is with a couple of screenshots, so let's look at a few. Then we will look at how to use this new
version of AutoDiagrammer, which I have cunningly called AutoDiagrammer II. Nice, huh?

When the app starts, it looks like this, where it is waiting for you to pick a DLL/Exe to draw the class diagram of.

And after you click the "Open Dll/Exe" button and navigate to a valid .NET DLL/Exe, this is what it might look like (Note: I have created a dummy test DLL
to test it with, so that is what is shown above):

This is now waiting for you to pick the items that you wish to appear on the drawn diagram. This is much easier than the first AutoDiagrammer article, as all
you do now is select using the check boxes beside each TreeViewItem and then click the "Draw Icon" above the TreeView.

The next step would be to click the "Draw Icon", but before we do that, let's consider my small test case DLL, which is shown in its entirety below:

Not all the classes are shown on the diagram, the "Doer" class is not shown! Why is that? Well, it has no associations so is not on the diagram,
but is instead in the list of "Non Associated Items" in the top right, from where you can view the class.

The association from Class1 to ConcreteRenderer was found, this is thanks to the parsing of the method body IL within the Class1.DoIt() method.

Association lines are colored differently when you hover over a class.

We can make the diagram take up all the width of the page, and hide the left hand pane altogether.

Now let's see some other features such as viewing the Associations, which is possible by clicking on the Show Associations icon in the top right hand side of a class.

And how about being able to view the IL for a method? That's possible, right? Yes, just click the magnifying glass next to a method (as long as it is enabled)
and you will be shown an IL window with the method body IL in it. If I had an infinite amount of time, I could probably get this into C#, but I just don't
right now, so IL it is. Heck there may even be some of you that can read IL as well as read C#, who knows.

How to Use the New AutoDiagrammer

The following sections will give you an overview of how to use the new version of AutoDiagrammer. Note, I have covered some of this ground whilst showing the screenshots above,
so please forgive me for that.

Installing AutoDiagrammer

When you download and build the attached code, you will see the following in the bin/XXXX folder:

All you need to do is copy the entire bin/XXXX folder to a new folder where you wish to run AutoDiagrammer.exe from. That is all you need to do.
Then to run AutoDiagrammer.exe, just double click on it wherever you copied the files and it should work just fine.

Load a DLL/Exe

This is the easy bit, all you need to do is pick the "Open" button and then choose whether it is a DLL or Exe you wish to open, and then browse to the location
of the file you wish to open.

Picking the Classes to Draw

Once you have picked which DLL/Exe to load, you will get a populated TreeView which is organized into namespaces that the classes reside in.
This process may take a while as this is where the bulk of the work is done reflecting out the information from the requested DLL/Exe, and
there is also a timeout on this process, which can be adjusted from the Settings window.

Whilst the treeview is being generated, you will see this loading banner:

Assuming you have a loaded TreeView, all you need to do now is pick which classes you would like to appear on the diagram. This is done by
simply using the CheckBoxes beside the names of the classes, or beside the entire namespace, or even the whole TreeView. Then click on the Draw
button (yes, the one shown with the pencil).

After you have clicked which classes to draw and clicked the Draw button, you will see a second loading screen (that will be of the form shown below) whilst the diagram is created.

After the diagram has been created (or a timeout occurs, which again can be adjusted via the Settings window):

A new diagram will be shown (or in the case of a timeout, the last diagram which was successfully loaded (if there was one)):

Note: All the classes may not appear on the diagram, as only those classes which have associations are shown on the
actual diagram. This is to de-clutter the diagram of information that is not really that valid. Not associated classes may still be viewed, which is explained below.

Working With the Drawn Class Diagram

Classes

Each class has several possible parts (again, the diagram will not include these parts if there is nothing to show or if the user has
requested these parts not be shown). The possible parts that may show up on a given class are as follows:

Interfaces

Constructors

Fields

Events

Properties

Methods

Here is what a typical example of a class may look like:

Viewing Method Body IL

One thing that is also quite useful is that you can view the method body IL using the small magnifying glass icon shown:

Important note: Each of these sections is within an expandable region. There is also a setting that you can use to
determine if the class diagram is redrawn when these sections are expanded. The default is that the diagram will not be drawn again on
expand/collapse; if this does not suit you, feel free to use the system setting to alter this behaviour.

Viewing Associations

It is also possible to view all the associations for a given class by hovering over the class, which will show a popup of the associations:

Not Associated Classes

As stated earlier, the diagram is kept free of clutter by not placing any classes that do not have Associations actually on
the diagram. These classes are still available, but they are just not on the main diagram, and must be accessed using the Not Associated Items dropdown,
which will only be shown if there are classes with no Associations that the user selected to draw.

Picking one of these will simply show a popup window with the details about the selected class using the same sections as if it was part of the main diagram.

Saving

The diagram can be saved to an PNG, using the Save button provided.

Which can then be viewed in the standard Image Viewer

Printing

The diagram may be printed using the Print button provided.

Customising What is Shown on a Diagram

The Settings window allows the diagram to be tailored to your specific requirements. These settings will be saved to disk whenever you close AutoDiagrammer.exe,
and are reloaded when you next run AutoDigrammer.exe.

There are many settings here to control not only what is shown on the diagram but also what graph layout algorithm the diagram should use.
The default graph layout algorithm is "Efficient Sugiyama", but you may find that another graph layout may be better for your diagram needs.
This will largely be down to experimenting with what your diagram shows and what works best for you.

Graph Layout Algorithm

The Settings windows allow the user to pick between different graph layout algorithms that may be used when creating the diagram.
As previously mentioned, the default graph layout algorithm is "Efficient Sugiyama", but there are several other layout algorithms, as shown in the list below:

Bounded FR

Efficient Sugiyama

FR

ISOM

KK

Tree

These layout algorithms may or may not suit your specific diagramming needs. This will largely be down to trial and error.
However, all settings are persisted, so when you exit AutoDiagrammer and come back to it, rest assured it will be how you left it.

What is common for all the different layout algorithms is that they have many different parameters that you can play with. For example, here
is a different set of settings that are available for the "Efficient Sugiyama" layout algorithm:

And here are the settings for the "Tree" layout algorithm:

I would suggest that once you have an active diagram with classes and Associations, you open the Settings window and experiment with the
different layout algorithms and then hit the "Re-Layout Graph" button at the top right hand corner (shown highlighted in figures above) to find what works best for you.

Picking What to Show

AutoDiagrammer also has many, many settings which control how the diagram will be drawn. These settings are shown below:

A lot of these are kind of pro-active settings in the sense that you will not need to Re-Layout the diagram again. This is down to the fact
that the diagram binds directly to the settings ViewModel which is a singleton instance. Obviously, the timeouts will only take effect the next time a new diagram is created.

How it Works

The following subsections will hopefully give you an understanding of how the new AutoDiagrammer code hangs together. One thing I should just mention now is that it is based on WPF and MVVM.
Now, some of you may know that I authored my own MVVM framework called Cinch which I pretty much use for any MVVM development I do when I write something
in WPF. And this article is no different; as such, you will find that I do indeed use Cinch and MVVM. If you are not familiar
with Cinch or MVVM, you may want to read about those first. If you are happy with these two things, no problem, let's continue.

The Basic Idea

Before we get into the nitty gritty, let's just go through the basic idea in dead simple numbered steps of what we are trying to achieve:

Allow the user to open a DLL/Exe, which is then examined to see if it is a valid .NET assembly. If it not, quit after telling
the user why. If it is valid, go to step 2.

Load the valid .NET assembly in a new AppDomain and extract the treeview information and all the class information like interfaces/methods (including the method
body IL)/properties/events etc.

Use the data from step 2 to draw a treeview of the namespaces and types found.

Allow the user to select what types they wish to draw.

For all the user selected types within the treeview which was created in step 4, create the actual graph objects which will represent the selected type.

For all those graph objects from step 5 that have Associations, add these objects to a Graphsharp graph.

For all those graph objects from step 5 that do not have Associations, add these objects to a combobox such that the user can view these but they
are not part of the main diagram.

In a nutshell, this is how the diagram is created. There are obviously other areas that are not directly related to the creation of the diagram such
as settings/help etc., but we will cover those too, do not worry.

There are however a few supporting classes that I will not be going into, as I just don't think it is all that necessary, but obviously, the code is attached
to this article, and if you are curious about one of the classes I do not cover, add a query to this article forum and I will answer it.

Detecting if a DLL/Exe is .NET

AutoDiagrammer.exe only supports the rendering of types that are found inside a valid .NET DLL/Exe. This is easily achieved using the following helper class:

///<summary>/// A simple helper class, that one has one method, that
/// is used to determine if an input file is an actual
/// CLR type file.
///</summary>publicclass DotNetObject
{
#region Public Methods
///<summary>/// Return true if the file specified is a real CLR type, otherwise false is returned.
/// False is also returned in the case of an exception being caught
///</summary>///<paramname="file">A string representing the file to check for CLR validity</param>///<returns>True if the file specified is a real CLR type, otherwise false is returned.
/// False is also returned in the case of an exception being caught</returns>publicstaticbool IsValidDotNetAssembly(String file)
{
uint peHeader;
uint peHeaderSignature;
ushort machine;
ushort sections;
uint timestamp;
uint pSymbolTable;
uint noOfSymbol;
ushort optionalHeaderSize;
ushort characteristics;
ushort dataDictionaryStart;
uint[] dataDictionaryRVA = newuint[16];
uint[] dataDictionarySize = newuint[16];
//get the input stream
Stream fs = new FileStream(@file, FileMode.Open, FileAccess.Read);
try
{
BinaryReader reader = new BinaryReader(fs);
//PE Header starts @ 0x3C (60). Its a 4 byte header.
fs.Position = 0x3C;
peHeader = reader.ReadUInt32();
//Moving to PE Header start location...
fs.Position = peHeader;
peHeaderSignature = reader.ReadUInt32();
//We can also show all these value, but we will be
//limiting to the CLI header test.
machine = reader.ReadUInt16();
sections = reader.ReadUInt16();
timestamp = reader.ReadUInt32();
pSymbolTable = reader.ReadUInt32();
noOfSymbol = reader.ReadUInt32();
optionalHeaderSize = reader.ReadUInt16();
characteristics = reader.ReadUInt16();
/*
Now we are at the end of the PE Header and from here, the
PE Optional Headers starts...
To go directly to the datadictionary, we'll increase the
stream’s current position to with 96 (0x60). 96 because,
28 for Standard fields
68 for NT-specific fields
From here DataDictionary starts...and its of total 128 bytes.
DataDictionay has 16 directories in total,
doing simple maths 128/16 = 8.
So each directory is of 8 bytes.
In this 8 bytes, 4 bytes is of RVA and 4 bytes of Size.
btw, the 15th directory consist of CLR header! if its 0, its not a CLR file :)
*/
dataDictionaryStart = Convert.ToUInt16(Convert.ToUInt16(fs.Position) + 0x60);
fs.Position = dataDictionaryStart;
for (int i = 0; i < 15; i++)
{
dataDictionaryRVA[i] = reader.ReadUInt32();
dataDictionarySize[i] = reader.ReadUInt32();
}
if (dataDictionaryRVA[14] == 0)
{
fs.Close();
returnfalse;
}
else
{
fs.Close();
returntrue;
}
}
catch (Exception)
{
returnfalse;
}
finally
{
fs.Close();
}
}
///<summary>/// Return true if t is wanted for diagram, at present the only thing
/// not allowed are System namespaced Dlls
///</summary>publicstaticbool IsWantedForDiagramType(Type t)
{
//check to see if the class lives in a namespace
if (!string.IsNullOrEmpty(t.Namespace))
{
//dont really want user to trawl the standard System namespaces
if (t.Namespace.StartsWith("System"))
returnfalse;
}
returntrue;
}
#endregion
}

Examining the Types in a Separate AppDomain

One of the main things that AutoDiagrammer will be doing is examining DLL/Exe files and reflecting out information from those loaded files. Which sounds easy
enough, but if you are not careful, this reflected information will be loaded into your current AppDomain. Yes, all the reflected types will be
loaded into the current AppDomain. The old AutoDiagrammer did not make any provision for this obvious oversight.

However, the new AutoDiagrammer presented in this article does fix all this by making sure that the loaded DLL/Exe is examined using Reflection in its own
AppDomain which is unloaded when the Reflection process is finished. This ensures that none of the type information in the reflected DLL/Exe
is serialized into the current AppDomain.

This is a fairly complex bit of code, and would take many, many code listings to fully explain, so I will keep things brief. The general rule of thumb though
when working with another AppDomain where your code relies on data structures of some sort being returned from the code in the new AppDomain,
is the data structures themselves must be Serializable to allow them to be serialized back into the primary AppDomain. The other trick is that
your secondary AppDomain loader should inherit from MarshallByRefObject, which allows it to be unwrapped in the primary AppDomain.

It it also advisable to apply the same Evidence to the new AppDomain as the primary AppDomain.

As I say, there is way too much code to go through this in fine detail; instead, I will show you the core pieces, and that should allow you to understand
where to look in the attached code, if that is of interest to you.

which is the only method that is exposed on the TreeCreator service, returns a List<AssemblyTreeViewModel> where AssemblyTreeViewModel
is serializable (as it is returned from the new AppDomain to the primary AppDomain).

These represent the TreeView items, and also hold an internal reference to a SerializableVertex which represents the class
information found. So how is it that one of these AssemblyTreeViewModel objects is constructed with a fully populated SerializableVertex?

Well, if you look closely at the end of the TreeCreator code above (look at the AddTypes(IGrouping<String, Type> types,
AssemblyTreeViewModel parent) method), you will see lines like these:

It can be seen that we make use of a little helper class called TypeReflector which does all the work for us. We will look at that
next. From this code, you can see, by the time we return a List<AssemblyTreeViewModel> from the TreeCreator
service, we have already reflected out all the information we need from the loaded DLL/Exe.

Reflecting Out Class Data

As stated above, the TreeCreator service is the code that is responsible for loading and reflecting the DLL/Exe
data in a separate AppDomain, where the result is a List<AssemblyTreeViewModel> where each AssemblyTreeViewModel is constructed
with a fully populated SerializableVertex which is later used to draw the Graphsharp graph (the diagram essentially).

So let's see how one of these SerializableVertex objects is created.

Recall, I stated that we use a helper class called TypeReflector which looks like this:

Note: I have only shown the code above for reflecting out methods, but the other reflective methods are pretty similar to the one for the methods, I think you get the idea though.

How Associations are Found

One of the things that I am most happy with in this new version of AutoDiagrammer is how the Associations between classes are found. Here are the general rules
of how Associations from one type to another type are found:

If there is a property to a different type

For each backing field to a different type

For each constructor parameter to a different type

For each method argument to a different type

For each NEWOBJ IL instruction found when parsing a method body to a different type

Most of this is dead simple/standard Reflection code, apart from point 5, which is what I want to spend a little bit of time on.

So what is done to achieve that? Well, what we do is that for each method we see, we load up the IL instructions for that method, and look for any new
objects being instantiated, and we look at the type of the new object and work out whether to add the new object instance as an Association to the type currently being reflected.

Creating the Diagram

The diagram is obviously based on a graph of some sort. I am lucky enough to have messed around with a rather cool graph for WPF in a previous article,
so the choice was very easy, just use what I had used before, which is Graphsharp, which is a very easy to use WPF graphing library.

Once all the classes (Vertex in Graphsharp language) have been reflected, the creating of the diagram is actually pretty simple;
all that has to be done is as follows:

The hard work that aids the method above has already been done by the previously explained reflection stages of the overall process; all that is
really happening is that whatever classes were selected by the users are then turned into UI ready Graphsharp
based Vertex/Edge objects. This is achieved by the use of the UI service AssemblyManipulationService which deals with all the Assembly
reflection/AssemblyTreeViewModel objects, and has this method whose sole job it is to take the currently selected AssemblyTreeViewModel
and return a GraphResults object which represents UI ready Graphsharp based Vertex/Edge objects. We will talk more about
the GraphResults object in a minute.

Settings

As already mentioned throughout the article, there is a singleton SettingsViewModel which is used to control the settings associated with the
diagram. There are numerous settings, and by and large, all that happens is that a property value is changed. However, there is one point of interest in that the
SettingsViewModel persists/hydrates its settings to disk whenever AutoDiagrammer closes/opens.

That may be of interest. This is actually achieved through the use of XLINQ; here is the most relevant code for the SettingsViewModel:

Where for simple single valued properties, we just use a new XLINQ XElement. However, some of the Graphsharp
settings are complex types with many properties. To handle these, we just extend the original Graphsharp settings classes and allow
the creation/retrieval of an XML fragment, as shown below.

All the other Graphsharp settings that AutoDiagrammer uses work in the same manner.

Saving to PNG

I wanted to be able to save to a format that I know has native support on Windows, and that has a native viewer available. To this end, I chose to use PNG
(Potrable Network Graphic) as the format. Here is how I save the diagram to an PNG file.

And here is how it is used within the rest of the code, where it can be seen that we simply pass along the name of the file to save and a UIElement
to print to PNG, which in this case is the actual diagram UIElement.

There is some added complexity above in that the actual diagram is inside a ZoomControl (which is part of the WPFExtensions
CodePlex project), so you have to take into account the current zoom, then set the diagram to Zoom = 1.0, and then save the PNG, and then reset the zoom to its previous value.

Print

AutoDiagrammer.exe allows it to be printed. This is achieved using the print button within the AutoDiagrammer.exe, which when clicked will show a print dialog.

Here is the UI Service code that achieves the printing of an PNG file:

That's It

That brings us to the end of this new version of AutoDiagrammer. I hope you can see that this new article and its associated code is actually a lot better than the old
AutoDiagrammer code. If you think this new code may be of use to you, could you spare the time to add a vote/comment?
It would be most appreciated, thanks.

History

06/06/2011: Initial issue.

08/06/2011:

Fixed the Culture parsing of the settings.

Added new settings to control the number of items on the diagram.

Also added the ability to opt in/out of parsing method body IL.

Also added right click context menu to allow all parts of classes on diagram to be toggled as one.

13/06/2011:

Added MouseWheel zooming.

Added ability to drag on single DLL/Exe as well as traditional OpenFileDialog support.

27/09/2011

Added extra settings to control how constructors/fields/properties/methods add to drawn association lines.