unit WinForm;

//
// Written by Rick Ross (http://rick-ross.com)
//

interface

uses
  System.Drawing, System.Collections, System.ComponentModel,
  System.Windows.Forms, System.Data,
  System.IO,
  System.Reflection,
  Reflect.ReflectNode;

type
  TWinForm = class(System.Windows.Forms.Form)
  {$REGION 'Designer Managed Code'}
  strict private
    /// <summary>
    /// Required designer variable.
    /// </summary>
    Components: System.ComponentModel.Container;
    MainMenu1: System.Windows.Forms.MainMenu;
    mnFile: System.Windows.Forms.MenuItem;
    mnOpenAssembly: System.Windows.Forms.MenuItem;
    mnOpenByName: System.Windows.Forms.MenuItem;
    mnExit: System.Windows.Forms.MenuItem;
    mnHelp: System.Windows.Forms.MenuItem;
    mnAbout: System.Windows.Forms.MenuItem;
    opnDlg: System.Windows.Forms.OpenFileDialog;
    trvwHierarchy: System.Windows.Forms.TreeView;
    Label1: System.Windows.Forms.Label;
    clbxBindingFlags: System.Windows.Forms.CheckedListBox;
    Label2: System.Windows.Forms.Label;
    tbOtherInfo: System.Windows.Forms.TextBox;
    Label3: System.Windows.Forms.Label;
    MenuItem1: System.Windows.Forms.MenuItem;
    mnHideBorlandNamespace: System.Windows.Forms.MenuItem;
    mnClearList: System.Windows.Forms.MenuItem;
    MenuItem2: System.Windows.Forms.MenuItem;
    mnShowLoadedAssemblies: System.Windows.Forms.MenuItem;
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    procedure InitializeComponent;
    procedure mnOpenAssembly_Click(sender: System.Object; e: System.EventArgs);
    procedure mnOpenByName_Click(sender: System.Object; e: System.EventArgs);
    procedure mnExit_Click(sender: System.Object; e: System.EventArgs);
    procedure mnAbout_Click(sender: System.Object; e: System.EventArgs);
    procedure TWinForm_Load(sender: System.Object; e: System.EventArgs);
    procedure trvwHierarchy_AfterSelect(sender: System.Object; e: System.Windows.Forms.TreeViewEventArgs);
    procedure mnHideBorlandNamespace_Click(sender: System.Object; e: System.EventArgs);
    procedure mnClearList_Click(sender: System.Object; e: System.EventArgs);
    procedure mnShowLoadedAssemblies_Click(sender: System.Object; e: System.EventArgs);
  {$ENDREGION}
  strict protected
    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    procedure Dispose(Disposing: Boolean); override;
  strict protected
    FAssemblyName   : string;
    function  GetBindingFlags : BindingFlags;
  public
    constructor Create;
  end;

implementation

uses
  System.Globalization, WinForm1;

{$REGION 'Windows Form Designer generated code'}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
procedure TWinForm.InitializeComponent;
begin
  Self.MainMenu1 := System.Windows.Forms.MainMenu.Create;
  Self.mnFile := System.Windows.Forms.MenuItem.Create;
  Self.mnOpenAssembly := System.Windows.Forms.MenuItem.Create;
  Self.mnOpenByName := System.Windows.Forms.MenuItem.Create;
  Self.mnExit := System.Windows.Forms.MenuItem.Create;
  Self.MenuItem1 := System.Windows.Forms.MenuItem.Create;
  Self.mnHideBorlandNamespace := System.Windows.Forms.MenuItem.Create;
  Self.mnClearList := System.Windows.Forms.MenuItem.Create;
  Self.MenuItem2 := System.Windows.Forms.MenuItem.Create;
  Self.mnShowLoadedAssemblies := System.Windows.Forms.MenuItem.Create;
  Self.mnHelp := System.Windows.Forms.MenuItem.Create;
  Self.mnAbout := System.Windows.Forms.MenuItem.Create;
  Self.opnDlg := System.Windows.Forms.OpenFileDialog.Create;
  Self.trvwHierarchy := System.Windows.Forms.TreeView.Create;
  Self.Label1 := System.Windows.Forms.Label.Create;
  Self.clbxBindingFlags := System.Windows.Forms.CheckedListBox.Create;
  Self.Label2 := System.Windows.Forms.Label.Create;
  Self.tbOtherInfo := System.Windows.Forms.TextBox.Create;
  Self.Label3 := System.Windows.Forms.Label.Create;
  Self.SuspendLayout;
  // 
  // MainMenu1
  // 
  Self.MainMenu1.MenuItems.AddRange([Self.mnFile, Self.MenuItem1, Self.mnHelp]);
  // 
  // mnFile
  // 
  Self.mnFile.Index := 0;
  Self.mnFile.MenuItems.AddRange([Self.mnOpenAssembly, Self.mnOpenByName, Self.mnExit]);
  Self.mnFile.Text := '&File';
  // 
  // mnOpenAssembly
  // 
  Self.mnOpenAssembly.Index := 0;
  Self.mnOpenAssembly.Text := '&Open Assembly';
  Include(Self.mnOpenAssembly.Click, Self.mnOpenAssembly_Click);
  // 
  // mnOpenByName
  // 
  Self.mnOpenByName.Index := 1;
  Self.mnOpenByName.Text := 'Open By &Name';
  Include(Self.mnOpenByName.Click, Self.mnOpenByName_Click);
  // 
  // mnExit
  // 
  Self.mnExit.Index := 2;
  Self.mnExit.Text := 'E&xit';
  Include(Self.mnExit.Click, Self.mnExit_Click);
  // 
  // MenuItem1
  // 
  Self.MenuItem1.Index := 1;
  Self.MenuItem1.MenuItems.AddRange([Self.mnHideBorlandNamespace, Self.mnClearList, Self.MenuItem2, Self.mnShowLoadedAssemblies]);
  Self.MenuItem1.Text := '&Options';
  // 
  // mnHideBorlandNamespace
  // 
  Self.mnHideBorlandNamespace.Checked := True;
  Self.mnHideBorlandNamespace.Index := 0;
  Self.mnHideBorlandNamespace.Text := 'Hide &Borland Namespace';
  Include(Self.mnHideBorlandNamespace.Click, Self.mnHideBorlandNamespace_Click);
  // 
  // mnClearList
  // 
  Self.mnClearList.Index := 1;
  Self.mnClearList.Text := '&Clear List';
  Include(Self.mnClearList.Click, Self.mnClearList_Click);
  // 
  // MenuItem2
  // 
  Self.MenuItem2.Index := 2;
  Self.MenuItem2.Text := '-';
  // 
  // mnShowLoadedAssemblies
  // 
  Self.mnShowLoadedAssemblies.Index := 3;
  Self.mnShowLoadedAssemblies.Text := '&Show Loaded Assemblies';
  Include(Self.mnShowLoadedAssemblies.Click, Self.mnShowLoadedAssemblies_Click);
  // 
  // mnHelp
  // 
  Self.mnHelp.Index := 2;
  Self.mnHelp.MenuItems.AddRange([Self.mnAbout]);
  Self.mnHelp.Text := '&Help';
  // 
  // mnAbout
  // 
  Self.mnAbout.Index := 0;
  Self.mnAbout.Text := '&About';
  Include(Self.mnAbout.Click, Self.mnAbout_Click);
  // 
  // trvwHierarchy
  // 
  Self.trvwHierarchy.ImageIndex := -1;
  Self.trvwHierarchy.Location := System.Drawing.Point.Create(8, 28);
  Self.trvwHierarchy.Name := 'trvwHierarchy';
  Self.trvwHierarchy.SelectedImageIndex := -1;
  Self.trvwHierarchy.Size := System.Drawing.Size.Create(520, 276);
  Self.trvwHierarchy.TabIndex := 0;
  Include(Self.trvwHierarchy.AfterSelect, Self.trvwHierarchy_AfterSelect);
  // 
  // Label1
  // 
  Self.Label1.Font := System.Drawing.Font.Create('Microsoft Sans Serif', 8.25, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, (System.Byte(0)));
  Self.Label1.Location := System.Drawing.Point.Create(544, 8);
  Self.Label1.Name := 'Label1';
  Self.Label1.Size := System.Drawing.Size.Create(100, 16);
  Self.Label1.TabIndex := 2;
  Self.Label1.Text := 'B inding Flags';
  // 
  // clbxBindingFlags
  // 
  Self.clbxBindingFlags.Items.AddRange(['DeclaredOnly', 'FlattenHierarchy', 'Instance', 'NonPublic', 'Public', 'Static']);
  Self.clbxBindingFlags.Location := System.Drawing.Point.Create(544, 24);
  Self.clbxBindingFlags.Name := 'clbxBindingFlags';
  Self.clbxBindingFlags.Size := System.Drawing.Size.Create(120, 94);
  Self.clbxBindingFlags.TabIndex := 3;
  // 
  // Label2
  // 
  Self.Label2.Font := System.Drawing.Font.Create('Microsoft Sans Serif', 8.25, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, (System.Byte(0)));
  Self.Label2.Location := System.Drawing.Point.Create(8, 8);
  Self.Label2.Name := 'Label2';
  Self.Label2.Size := System.Drawing.Size.Create(72, 16);
  Self.Label2.TabIndex := 4;
  Self.Label2.Text := 'Contents';
  // 
  // tbOtherInfo
  // 
  Self.tbOtherInfo.Location := System.Drawing.Point.Create(8, 336);
  Self.tbOtherInfo.Multiline := True;
  Self.tbOtherInfo.Name := 'tbOtherInfo';
  Self.tbOtherInfo.ScrollBars := System.Windows.Forms.ScrollBars.Both;
  Self.tbOtherInfo.Size := System.Drawing.Size.Create(648, 96);
  Self.tbOtherInfo.TabIndex := 5;
  Self.tbOtherInfo.Text := '';
  // 
  // Label3
  // 
  Self.Label3.Font := System.Drawing.Font.Create('Microsoft Sans Serif', 8.25, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, (System.Byte(0)));
  Self.Label3.Location := System.Drawing.Point.Create(8, 312);
  Self.Label3.Name := 'Label3';
  Self.Label3.Size := System.Drawing.Size.Create(200, 16);
  Self.Label3.TabIndex := 6;
  Self.Label3.Text := 'Attributes / Additional Information';
  // 
  // TWinForm
  // 
  Self.AutoScaleBaseSize := System.Drawing.Size.Create(5, 13);
  Self.ClientSize := System.Drawing.Size.Create(672, 442);
  Self.Controls.Add(Self.Label3);
  Self.Controls.Add(Self.tbOtherInfo);
  Self.Controls.Add(Self.Label2);
  Self.Controls.Add(Self.clbxBindingFlags);
  Self.Controls.Add(Self.Label1);
  Self.Controls.Add(Self.trvwHierarchy);
  Self.Menu := Self.MainMenu1;
  Self.Name := 'TWinForm';
  Self.StartPosition := System.Windows.Forms.FormStartPosition.CenterScreen;
  Self.Text := 'Reflect';
  Include(Self.Load, Self.TWinForm_Load);
  Self.ResumeLayout(False);
end;
{$ENDREGION}

procedure TWinForm.Dispose(Disposing: Boolean);
begin
  if Disposing then
  begin
    if Components <> nil then
      Components.Dispose();
  end;
  inherited Dispose(Disposing);
end;

constructor TWinForm.Create;
begin
  inherited Create;
  //
  // Required for Windows Form Designer support
  //
  InitializeComponent;
  //
  // TODO: Add any constructor code after InitializeComponent call
  //
end;

procedure TWinForm.mnClearList_Click(sender: System.Object; e: System.EventArgs);
begin
  trvwHierarchy.Nodes.Clear();
end;

procedure TWinForm.mnHideBorlandNamespace_Click(sender: System.Object; e: System.EventArgs);
begin
  mnHideBorlandNamespace.Checked := not mnHideBorlandNamespace.Checked;
end;

//
// AfterSelect updates the Attributes/ Additional information textbox with
// attributes and other information pertinent to the current node.
//
procedure TWinForm.trvwHierarchy_AfterSelect(sender: System.Object; e: System.Windows.Forms.TreeViewEventArgs);
var
  rtn : ReflectTreeNode;

begin
  tbOtherInfo.Clear();
  if ((e.Node <> nil) and (e.Node is ReflectTreeNode)) then
  begin
    rtn := ReflectTreeNode(e.Node);
    if (rtn.Attributes <> '') then
      tbOtherInfo.Text := rtn.Attributes;
    if (rtn.OtherInfo <> '') then
      tbOtherInfo.Text := tbOtherInfo.Text + Environment.NewLine + rtn.OtherInfo;
  end;
end;

//
// The _Load method is needed to set the items within the checked List box to
// match the default Binding Flags in the ReflectTreeNode class
//

procedure TWinForm.TWinForm_Load(sender: System.Object; e: System.EventArgs);
var
  i : integer;
  bf : BindingFlags;
begin
  // stuff the appropriate default binding flags
  for i:=0 to clbxBindingFlags.Items.Count-1 do
  begin
    // bf := BindingFlags(BindingFlags.Parse( typeof(BindingFlags), clbxBindingFlags.Items[i].ToString() ));
    bf := BindingFlags( System.Enum.Parse( typeof(BindingFlags), clbxBindingFlags.Items[i].ToString() ));

    if ((ReflectTreeNode.defaultBindingFlags and bf) = bf) then
      clbxBindingFlags.SetItemChecked(i, true);
  end;
end;

procedure TWinForm.mnAbout_Click(sender: System.Object; e: System.EventArgs);
begin
  MessageBox.Show('Reflect was written by Rick Ross (http://www.rick-ross.com)','About Reflect',MessageBoxButtons.OK);
end;

procedure TWinForm.mnExit_Click(sender: System.Object; e: System.EventArgs);
begin
  Close;
end;

//
// ShowLoadedAssemblies_Click starts the search for every assembly currently
// loaded in the current AppDomain.
//

procedure TWinForm.mnShowLoadedAssemblies_Click(sender: System.Object; e: System.EventArgs);
var
  oldCursor : System.Windows.Forms.Cursor;
begin
  if MessageBox.Show('Showing loaded assemblies can take some time.' +
                     ' Are you sure you want to continue?',
                     'Confirm load all assemblies', MessageBoxButtons.OKCANCEL ) =
                     System.Windows.Forms.DialogResult.OK then
  begin
    oldCursor := Cursor.Current;
    Cursor.Current := Cursors.WaitCursor;
    try
      trvwHierarchy.BeginUpdate;
      try
        trvwHierarchy.Nodes.Clear();

        ReflectTreeNode.HideBorlandNamespace := mnHideBorlandNamespace.Checked;
        ReflectTreeNode.TheBindingFlags := GetBindingFlags();
        trvwHierarchy.Nodes.Add( ReflectTreeNode.Create( AppDomain.CurrentDomain ) );
      finally
        trvwHierarchy.EndUpdate;
      end;
    finally
      Cursor.Current := oldCursor;
    end;
  end;
end;

//
// OpenByName_Click prompts for a type name and adds it to the tree view
//

procedure TWinForm.mnOpenByName_Click(sender: System.Object; e: System.EventArgs);
var
  frm : TWinForm1;
  oldCursor : System.Windows.Forms.Cursor;
begin
  frm := TWinForm1.Create;
  try
    if (frm.ShowDialog <> System.Windows.Forms.DialogResult.OK) then
      Exit;
    oldCursor := Cursor.Current;
    Cursor.Current := Cursors.WaitCursor;
    try
      trvwHierarchy.BeginUpdate();
      try
        ReflectTreeNode.HideBorlandNamespace := mnHideBorlandNamespace.Checked;
        ReflectTreeNode.TheBindingFlags := GetBindingFlags();
        trvwHierarchy.Nodes.Add( ReflectTreeNode.Create( System.Type.GetType( frm.TypeName )) );
      finally
        trvwHierarchy.EndUpdate();
      end;
    finally
      Cursor.Current := oldCursor;
    end;
  finally
    frm.Free;
  end;

end;

//
// GetBindingFlags returns the BindingFlags representation of the items
// currently selected in the checked list box.
//

function TWinForm.GetBindingFlags : BindingFlags;
var
  ret : BindingFlags;
  bf  : BindingFlags;
  i   : integer;
begin
  ret := ReflectTreeNode.defaultBindingFlags;
  for i:=0 to clbxBindingFlags.Items.Count-1 do
  begin
    // bf := BindingFlags(BindingFlags.Parse( typeof(BindingFlags), clbxBindingFlags.Items[i].ToString() ));
    bf := BindingFlags(System.Enum.Parse( typeof(BindingFlags), clbxBindingFlags.Items[i].ToString() ));
    if (clbxBindingFlags.GetItemCheckState(i) = CheckState.Checked) then
      ret := ret or bf
    else
      ret := ret xor bf;
  end;

  Result := ret;
end;

//
// OpenAssembly_Click prompts the user for the assembly to explore and adds it
// to the treeview control.
//

procedure TWinForm.mnOpenAssembly_Click(sender: System.Object; e: System.EventArgs);
var
  currentAssembly : Assembly;
  oldCursor : System.Windows.Forms.Cursor;

begin
  // open assembly
  opnDlg.Filter      := 'Executables (*.exe)|*.exe|Assemblies (*.dll)|*.dll|All Files|*.*';
  opnDlg.FilterIndex := 1;
  if (opnDlg.ShowDialog() <> System.Windows.Forms.DialogResult.OK) then
    Exit;

  FAssemblyName := opnDlg.FileName;

  // does the file exist?
  if not (System.IO.File.Exists( FAssemblyName ) ) then
  begin
    MessageBox.Show( FAssemblyName + ' does not exist!' );
    Exit;
  end;

  currentAssembly := Assembly.LoadFrom( FAssemblyName );

  oldCursor := Cursor.Current;
  Cursor.Current := Cursors.WaitCursor;
  try
    // Suppress repainting the TreeView until all the objects have been created.
    trvwHierarchy.BeginUpdate();
    try
      ReflectTreeNode.HideBorlandNamespace := mnHideBorlandNamespace.Checked;
      ReflectTreeNode.TheBindingFlags := GetBindingFlags();

      trvwHierarchy.Nodes.Add( ReflectTreeNode.Create(currentAssembly) );
    finally
      trvwHierarchy.EndUpdate();
    end;
  finally
    Cursor.Current := oldCursor;
  end;
end;

end.
