Figure 3
Figure 3 MetaViewer.cs//==========================================
// Matt Pietrek
// MSDN Magazine, March 2001
// FILE: MetaViewer.cs
//==========================================
namespace MetaViewerFormNamespace
{
using System;
using System.Drawing;
using System.ComponentModel;
using System.WinForms;
using System.Reflection;
using System.Text.RegularExpressions;
// An enum for associating treeview nodes with the appropriate
// icons
enum TreeViewBitmapEnum
{
Unknown = 0,
Type = 1,
Interface = 2,
ValueClass = 3,
Method = 4,
Field = 5,
Property = 6,
Event = 7
}
public class MetaViewerForm : System.WinForms.Form
{
private string m_strFileName;
private Assembly m_assembly = null;
private System.ComponentModel.Container components;
public System.WinForms.ImageList imageList1;
private System.WinForms.TextBox text_details;
private System.WinForms.TreeView treeView1;
private System.WinForms.TextBox text_search;
private System.WinForms.Button button_search;
private System.WinForms.Button button_assembly;
public MetaViewerForm( string strFileName )
{
m_strFileName = strFileName;
// Required for Win Form Designer support
InitializeComponent();
DisplayMetaData( );
}
public override void Dispose()
{
base.Dispose();
components.Dispose();
}
public static void Main(string[] args)
{
if (args.Length < 1 )
{
MessageBox.Show( "Syntax: MetaViewer <filename>" );
return;
}
try
{
Application.Run(new MetaViewerForm(args[0]));
}
catch( Exception e )
{
e.ToString(); // Kill compiler warning about "unused e"
// :-)
}
}
private void InitializeComponent()
{
System.Resources.ResourceManager resources = new
System.Resources.ResourceManager(typeof(MetaViewerForm));
this.components = new System.ComponentModel.Container();
this.imageList1 = new System.WinForms.ImageList();
this.text_details = new System.WinForms.TextBox();
this.text_search = new System.WinForms.TextBox();
this.treeView1 = new System.WinForms.TreeView();
this.button_search = new System.WinForms.Button();
this.button_assembly = new System.WinForms.Button();
imageList1.ImageSize = new System.Drawing.Size(16, 16);
imageList1.ImageStream = (System.WinForms.ImageListStreamer)
resources.GetObject("imageList1.ImageStream");
imageList1.ColorDepth = System.WinForms.ColorDepth.Depth8Bit;
imageList1.TransparentColor = System.Drawing.Color.Transparent;
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.Text = "MetaViewer";
this.ClientSize = new System.Drawing.Size(728, 412);
text_details.Location = new System.Drawing.Point(504, 8);
text_details.Text = "";
text_details.Multiline = true;
text_details.TabIndex = 0;
text_details.ReadOnly = true;
text_details.TabStop = false;
text_details.Size = new System.Drawing.Size(216, 392);
treeView1.Location = new System.Drawing.Point(8, 8);
treeView1.Text = "treeView1";
treeView1.Size = new System.Drawing.Size(480, 352);
treeView1.TabIndex = 0;
treeView1.AfterSelect += new
System.WinForms.TreeViewEventHandler(treeView1_AfterSelect);
treeView1.ImageList = imageList1;
treeView1.HideSelection = false;
text_search.Location = new System.Drawing.Point(232, 376);
text_search.TabIndex = 3;
text_search.Size = new System.Drawing.Size(224, 20);
button_search.Location = new System.Drawing.Point(128, 368);
button_search.Size = new System.Drawing.Size(96, 40);
button_search.TabIndex = 2;
button_search.Text = "Search";
button_search.Click+=new
System.EventHandler(button_search_Click);
button_assembly.Location = new System.Drawing.Point(16, 368);
button_assembly.Size = new System.Drawing.Size(96, 40);
button_assembly.TabIndex = 1;
button_assembly.Text = "Assembly Info...";
button_assembly.Click +=
new System.EventHandler(button_assembly_Click);
this.Controls.Add(text_details);
this.Controls.Add(treeView1);
this.Controls.Add(text_search);
this.Controls.Add(button_search);
this.Controls.Add(button_assembly);
}
//===========================================================
// Search for a Type that contains the string in the text control
//===========================================================
protected void button_search_Click(object sender,
System.EventArgs e)
{
int currentIndex = treeView1.SelectedNode.Index;
int maxIndex = treeView1.GetNodeCount(false);
// 2nd param "i" to Regex means case insensitive search
Regex regex = new Regex( text_search.Text, "i" );
TreeNode node = treeView1.Nodes[currentIndex];
if ( regex.IsMatch(node.Text) )
currentIndex++;
int i;
for ( i = currentIndex; i < maxIndex; i++ )
{
node = treeView1.Nodes[i];
// if ( node.Text == text_search.Text )
if ( regex.IsMatch(node.Text) )
{
treeView1.SelectedNode = node;
ActiveControl = treeView1;
break;
}
}
if ( i == maxIndex )
MessageBox.Show( "No matches found" );
}
//===========================================================
// When the "Assembly Info..." button is pressed, show the window
//===========================================================
protected void button_assembly_Click( object sender,
System.EventArgs e)
{
AssemblyInfoForm assemblyInfoForm =
new AssemblyInfoForm( m_assembly );
assemblyInfoForm.Show();
}
//===========================================================
// When a treeview node is selected, update the details pane
//===========================================================
protected
void treeView1_AfterSelect( object sender,
System.WinForms.TreeViewEventArgs e)
{
text_details.Clear();
if ( e.node is TypeNode )
{
ShowTypeDetails( ((TypeNode)e.node).m_type );
}
else if ( e.node is MemberInfoNode )
{
ShowMemberInfoDetails(((MemberInfoNode)e.node).m_memberInfo);
}
}
//===========================================================
// Top level routine called to display metadata for an assembly
//===========================================================
private void DisplayMetaData()
{
try
{
m_assembly = Assembly.Load( m_strFileName );
}
catch( Exception e )
{
MessageBox.Show( e.Message );
throw e; // Application.Exit doesn't seem to work here...
}
// Iterate through each of the modules in the assembly
foreach ( Module module in m_assembly.GetModules() )
{
// Add the module's types to the TreeView
PopulateTypes( module.GetTypes() );
// Add module level methods and properties
PopulateMembers( module.GetMethods(), treeView1.Nodes );
PopulateMembers( module.GetFields(), treeView1.Nodes );
}
this.Text = "MetaViewer: " + m_strFileName;
}
//===========================================================
// Fill in the main treeview with the types in a module
//===========================================================
protected void PopulateTypes( Type[] arTypes )
{
foreach ( Type t in arTypes )
{
TypeNode typeNode = new TypeNode( t );
TreeViewBitmapEnum treeViewBitmapEnum;
if ( t.IsClass )
treeViewBitmapEnum = TreeViewBitmapEnum.Type;
else if ( t.IsInterface )
treeViewBitmapEnum = TreeViewBitmapEnum.Interface;
else if ( t.IsValueType )
treeViewBitmapEnum = TreeViewBitmapEnum.ValueClass;
// For now, treat unmanaged and managed value classes the
// same
else if ( t.IsUnmanagedValueType )
treeViewBitmapEnum = TreeViewBitmapEnum.ValueClass;
else
treeViewBitmapEnum = TreeViewBitmapEnum.Unknown;
typeNode.ImageIndex = typeNode.SelectedImageIndex =
(int)treeViewBitmapEnum;
treeView1.Nodes.Add( typeNode );
MemberInfo[] arMemberInfo = t.GetMembers(
BindingFlags.LookupAll |
BindingFlags.DeclaredOnly
);
PopulateMembers( arMemberInfo, typeNode.Nodes );
}
}
//===========================================================
// Add the members of a type to the appropriate node in the
// treeview
//===========================================================
protected void PopulateMembers( MemberInfo[] arMemberInfo,
TreeNodeCollection treeNodeCollection)
{
foreach( MemberInfo member in arMemberInfo )
{
MemberInfoNode memberInfoNode = new MemberInfoNode(member);
TreeViewBitmapEnum treeViewBitmapEnum2;
if ( member is MethodInfo || member is ConstructorInfo )
treeViewBitmapEnum2 = TreeViewBitmapEnum.Method;
else if ( member is FieldInfo )
treeViewBitmapEnum2 = TreeViewBitmapEnum.Field;
else if ( member is PropertyInfo )
treeViewBitmapEnum2 = TreeViewBitmapEnum.Property;
else if ( member is EventInfo )
treeViewBitmapEnum2 = TreeViewBitmapEnum.Event;
else
treeViewBitmapEnum2 = TreeViewBitmapEnum.Unknown;
memberInfoNode.ImageIndex =
memberInfoNode.SelectedImageIndex
= (int)treeViewBitmapEnum2;
treeNodeCollection.Add( memberInfoNode );
}
}
//===========================================================
// Updates the details pane with info about the selected Type
//===========================================================
protected void ShowTypeDetails( Type t )
{
text_details.AppendText(
String.Format("Namespace: {0}\r\n", t.Namespace) );
// Show derivation hierarchy, back to System.Object
text_details.AppendText( "Derives from:\r\n" );
while ( true )
{
Type baseType = t.BaseType;
if ( baseType == null )
break;
text_details.AppendText( "\t" + baseType.Name + "\r\n" );
t = t.BaseType;
}
}
//===========================================================
// Updates the details pane with info about the selected member
//===========================================================
protected void ShowMemberInfoDetails( MemberInfo memberInfo )
{
if ( memberInfo is MethodBase )
{
MethodBase methodBase = (MethodBase)memberInfo;
if ( methodBase.IsVirtual )
text_details.AppendText( "Virtual\r\n" );
if ( methodBase.IsStatic )
text_details.AppendText( "Static\r\n" );
if ( methodBase.IsPublic )
text_details.AppendText( "Public\r\n" );
if ( methodBase.IsPrivate )
text_details.AppendText( "Private\r\n" );
if ( (methodBase.Attributes &
(MethodAttributes)MethodAttributes.PinvokeImpl) != 0 )
{
text_details.AppendText( "PInvoke\r\n" );
}
if ( memberInfo is MethodInfo )
{
text_details.AppendText(
String.Format("returns {0}\r\n",
((MethodInfo)memberInfo).ReturnType.Name) );
}
ParameterInfo [] arParamInfo = methodBase.GetParameters();
if ( arParamInfo.Length > 0 )
text_details.AppendText( "Parameters:\r\n" );
foreach ( ParameterInfo paramInfo in arParamInfo )
{
text_details.AppendText( String.Format("\t{0} {1}\r\n",
paramInfo.ParameterType.Name, paramInfo.Name));
}
}
else if ( memberInfo is FieldInfo )
{
FieldInfo fieldInfo = (FieldInfo)memberInfo;
if ( fieldInfo.IsStatic )
text_details.AppendText( "Static\r\n" );
if ( fieldInfo.IsPublic )
text_details.AppendText( "Public\r\n" );
if ( fieldInfo.IsPrivate )
text_details.AppendText( "Private\r\n" );
text_details.AppendText( memberInfo.GetType().Name );
}
else if ( memberInfo is PropertyInfo )
{
PropertyInfo propertyInfo = (PropertyInfo)memberInfo;
if ( propertyInfo.CanRead )
text_details.AppendText( "Readable\r\n" );
if ( propertyInfo.CanWrite )
text_details.AppendText( "Writeable\r\n" );
text_details.AppendText( memberInfo.GetType().Name );
}
}
} // End class class MetaViewerForm
} // End namespace
Figure 5 AssemblyInfoForm.cs //==========================================
// Matt Pietrek
// MSDN Magazine, March 2001
// FILE: AssemblyInfoForm.cs
//==========================================
namespace MetaViewerFormNamespace
{
using System;
using System.WinForms;
using System.Reflection;
public class AssemblyInfoForm : System.WinForms.Form
{
private System.ComponentModel.Container components;
private System.WinForms.Button button_ok;
private System.WinForms.TextBox text_assemblyInfo;
private Assembly m_assembly;
public AssemblyInfoForm(Assembly assembly)
{
m_assembly = assembly;
// Required for Win Form Designer support
InitializeComponent();
DisplayAssemblyInfo();
}
public override void Dispose() {
base.Dispose();
components.Dispose();
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.button_ok = new System.WinForms.Button();
this.text_assemblyInfo = new System.WinForms.TextBox();
button_ok.Location = new System.Drawing.Point(256, 320);
button_ok.Size = new System.Drawing.Size(64, 32);
button_ok.TabIndex = 0;
button_ok.Text = "OK";
button_ok.Click += new System.EventHandler(button_ok_Click);
text_assemblyInfo.Location = new System.Drawing.Point(8, 8);
text_assemblyInfo.ReadOnly = true;
text_assemblyInfo.Multiline = true;
text_assemblyInfo.TabIndex = 0;
text_assemblyInfo.TabStop = false;
text_assemblyInfo.Size = new System.Drawing.Size(560, 296);
text_assemblyInfo.ScrollBars = ScrollBars.Both;
this.Text = "Assembly Info";
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(576, 356);
this.Controls.Add(button_ok);
this.Controls.Add(text_assemblyInfo);
}
protected void button_ok_Click(object sender, System.EventArgs e)
{
this.Close();
}
//===========================================================
protected void DisplayAssemblyInfo()
{
// Dislay list of modules in the assembly
foreach ( Module module in m_assembly.GetModules() )
{
text_assemblyInfo.AppendText(
String.Format("Module: {0}\r\n", module.Name) );
}
//==================================================
// Display the list of assemblies referenced by this assembly
text_assemblyInfo.AppendText( "\r\n" );
text_assemblyInfo.AppendText( "Referenced Assemblies:\r\n" );
foreach( AssemblyName assemblyName in
m_assembly.GetReferencedAssemblies() )
{
text_assemblyInfo.AppendText( String.Format("\t{0}\r\n",
assemblyName.Name) );
}
//==================================================
// Display the files in this asssembly
text_assemblyInfo.AppendText( "\r\n" );
text_assemblyInfo.AppendText( "Files:\r\n" );
foreach ( String strResourceName in
m_assembly.GetManifestResourceNames() )
{
text_assemblyInfo.AppendText( String.Format("\t{0}\r\n",
strResourceName) );
}
}
}
}
Figure 6 MemberNode.cs //==========================================
// Matt Pietrek
// MSDN Magazine, March 2001
// FILE: MemberNode.cs
//==========================================
namespace MetaViewerFormNamespace
{
using System.WinForms;
using System.Reflection;
public class MemberInfoNode : TreeNode
{
// The System.Reflection.MemberInfo associated with this node
public MemberInfo m_memberInfo;
public MemberInfoNode(MemberInfo memberInfo)
{
m_memberInfo = memberInfo;
Text = m_memberInfo.Name;
}
}
}
Show: