bring back the old non-ContainerLayout ExecutableEditor because the ContainerLayout one disappears the whole app when the 'Managed Assembly' tab is selected (BUG)

This commit is contained in:
Michael Becker 2020-05-18 01:38:27 -04:00
parent 08e51334c3
commit 805c3e221f
No known key found for this signature in database
GPG Key ID: 506F54899E2BFED7
4 changed files with 602 additions and 7 deletions

View File

@ -198,12 +198,7 @@ namespace UniversalEditor.Plugins.Executable.UserInterface.Editors.Executable
txtAssemblyVersion.Text = executable.ManagedAssembly.GetName().Version.ToString();
// pnlManagedAssembly.Assembly = executable.ManagedAssembly;
// UpdateTypeList();
tmManagedDisassemblyTypes.Rows.Add(new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmManagedDisassemblyTypes.Columns[0], "Test")
}));
UpdateTypeList();
}
}

View File

@ -0,0 +1,257 @@
//
// ExecutableEditor.cs - provides an Editor for the ExecutableObjectModel
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2019-2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using UniversalEditor.ObjectModels.Executable;
using UniversalEditor.UserInterface;
using MBS.Framework.UserInterface;
using MBS.Framework.UserInterface.Controls;
using MBS.Framework.UserInterface.Dialogs;
using MBS.Framework.UserInterface.Input.Mouse;
using MBS.Framework.UserInterface.Layouts;
namespace UniversalEditor.Plugins.Executable.UserInterface.Editors.Executable
{
/// <summary>
/// Provides an <see cref="Editor" /> for the <see cref="ExecutableObjectModel" />.
/// </summary>
public class ExecutableEditor : Editor
{
private static EditorReference _er = null;
public override EditorReference MakeReference()
{
if (_er == null)
{
_er = base.MakeReference();
_er.SupportedObjectModels.Add(typeof(ExecutableObjectModel));
}
return _er;
}
protected override EditorSelection CreateSelectionInternal(object content)
{
throw new NotImplementedException();
}
public override void UpdateSelections()
{
throw new NotImplementedException();
}
private ListView tvSections = null;
private DefaultTreeModel tmSections = null;
private TabContainer tbs = null;
private Label lblAssemblyName = null;
private TextBox txtAssemblyName = null;
private Label lblAssemblyVersion = null;
private TextBox txtAssemblyVersion = null;
private DefaultTreeModel tmOtherInformation = null;
private ManagedAssemblyPanel pnlManagedAssembly = null;
public ExecutableEditor()
{
this.Layout = new BoxLayout(Orientation.Vertical);
tmSections = new DefaultTreeModel(new Type[] { typeof(string), typeof(string), typeof(string), typeof(string) });
tvSections = new ListView();
tvSections.Model = tmSections;
tvSections.Columns.Add(new ListViewColumnText(tmSections.Columns[0], "Name"));
tvSections.Columns.Add(new ListViewColumnText(tmSections.Columns[1], "Physical address"));
tvSections.Columns.Add(new ListViewColumnText(tmSections.Columns[2], "Virtual address"));
tvSections.Columns.Add(new ListViewColumnText(tmSections.Columns[3], "Size"));
tvSections.BeforeContextMenu += tvSections_BeforeContextMenu;
tbs = new TabContainer();
TabPage tabSections = new TabPage("Sections (0)");
tabSections.Layout = new BoxLayout(Orientation.Vertical);
tabSections.Controls.Add(tvSections, new BoxLayout.Constraints(true, true));
tbs.TabPages.Add(tabSections);
TabPage tabVersion = new TabPage("Version");
tabVersion.Layout = new GridLayout();
Label lblFileVersion = new Label();
lblFileVersion.Text = "File version:";
lblFileVersion.HorizontalAlignment = HorizontalAlignment.Left;
tabVersion.Controls.Add(lblFileVersion, new GridLayout.Constraints(0, 0));
TextBox txtFileVersion = new TextBox();
tabVersion.Controls.Add(txtFileVersion, new GridLayout.Constraints(0, 1, 1, 1, ExpandMode.Horizontal));
Label lblDescription = new Label();
lblDescription.Text = "Description:";
lblDescription.HorizontalAlignment = HorizontalAlignment.Left;
tabVersion.Controls.Add(lblDescription, new GridLayout.Constraints(1, 0));
TextBox txtDescription = new TextBox();
tabVersion.Controls.Add(txtDescription, new GridLayout.Constraints(1, 1, 1, 1, ExpandMode.Horizontal));
Label lblCopyright = new Label();
lblCopyright.Text = "Copyright:";
lblCopyright.HorizontalAlignment = HorizontalAlignment.Left;
tabVersion.Controls.Add(lblCopyright, new GridLayout.Constraints(2, 0));
TextBox txtCopyright = new TextBox();
tabVersion.Controls.Add(txtCopyright, new GridLayout.Constraints(2, 1, 1, 1, ExpandMode.Horizontal));
Label lblOtherInformationLabel = new Label();
lblOtherInformationLabel.Text = "Other version information:";
lblOtherInformationLabel.HorizontalAlignment = HorizontalAlignment.Left;
tabVersion.Controls.Add(lblOtherInformationLabel, new GridLayout.Constraints(3, 0, 1, 2));
tmOtherInformation = new DefaultTreeModel(new Type[] { typeof(string), typeof(string) });
ListView lvOtherInformation = new ListView();
lvOtherInformation.Model = tmOtherInformation;
lvOtherInformation.Columns.Add(new ListViewColumnText(tmOtherInformation.Columns[0], "Name"));
lvOtherInformation.Columns.Add(new ListViewColumnText(tmOtherInformation.Columns[1], "Value"));
tabVersion.Controls.Add(lvOtherInformation, new GridLayout.Constraints(4, 0, 1, 2, ExpandMode.Both));
tbs.TabPages.Add(tabVersion);
TabPage tabManagedAssembly = new TabPage("Managed Assembly");
tabManagedAssembly.Layout = new BoxLayout(Orientation.Vertical);
lblAssemblyName = new Label("Assembly name: ");
lblAssemblyName.HorizontalAlignment = HorizontalAlignment.Left;
txtAssemblyName = new TextBox();
lblAssemblyVersion = new Label("Assembly version: ");
lblAssemblyVersion.HorizontalAlignment = HorizontalAlignment.Left;
txtAssemblyVersion = new TextBox();
Container pnlMetadata = new Container();
pnlMetadata.Layout = new GridLayout();
pnlMetadata.Controls.Add(lblAssemblyName, new GridLayout.Constraints(0, 0));
pnlMetadata.Controls.Add(txtAssemblyName, new GridLayout.Constraints(0, 1, 1, 1, ExpandMode.Horizontal));
pnlMetadata.Controls.Add(lblAssemblyVersion, new GridLayout.Constraints(1, 0));
pnlMetadata.Controls.Add(txtAssemblyVersion, new GridLayout.Constraints(1, 1, 1, 1, ExpandMode.Horizontal));
tabManagedAssembly.Controls.Add(pnlMetadata, new BoxLayout.Constraints(false, true));
pnlManagedAssembly = new ManagedAssemblyPanel();
tabManagedAssembly.Controls.Add(pnlManagedAssembly, new BoxLayout.Constraints(true, true));
tbs.TabPages.Add(tabManagedAssembly);
Application.AttachCommandEventHandler("ExecutableEditor_ContextMenu_Sections_Selected_CopyTo", ContextMenu_CopyTo_Click);
this.Controls.Add(tbs, new BoxLayout.Constraints(true, true));
}
private void ContextMenu_CopyTo_Click(object sender, EventArgs e)
{
FileDialog fd = new FileDialog();
if (tvSections.SelectedRows.Count == 1)
{
fd.Mode = FileDialogMode.Save;
ExecutableSection section = tvSections.SelectedRows[0].GetExtraData<ExecutableSection>("section");
fd.SelectedFileNames.Add(section.Name);
if (fd.ShowDialog() == DialogResult.OK)
{
System.IO.File.WriteAllBytes(fd.SelectedFileNames[fd.SelectedFileNames.Count - 1], section.Data);
}
}
else if (tvSections.SelectedRows.Count > 1)
{
// select a folder
fd.Mode = FileDialogMode.SelectFolder;
if (fd.ShowDialog() == DialogResult.OK)
{
foreach (TreeModelRow row in tvSections.SelectedRows)
{
ExecutableSection section = tvSections.SelectedRows[0].GetExtraData<ExecutableSection>("section");
System.IO.File.WriteAllBytes(fd.SelectedFileNames[fd.SelectedFileNames.Count - 1] + System.IO.Path.DirectorySeparatorChar.ToString() + section.Name, section.Data);
}
}
}
}
void tvSections_BeforeContextMenu(object sender, EventArgs e)
{
bool selected = tvSections.SelectedRows.Count > 0;
if (e is MouseEventArgs)
{
MouseEventArgs ee = (e as MouseEventArgs);
ListViewHitTestInfo lvih = tvSections.HitTest(ee.X, ee.Y);
if (lvih.Row == null)
selected = false;
}
if (selected)
{
tvSections.ContextMenuCommandID = "ExecutableEditor_ContextMenu_Sections_Selected";
}
else
{
tvSections.ContextMenuCommandID = "ExecutableEditor_ContextMenu_Sections_Unselected";
}
}
protected override void OnObjectModelChanged(EventArgs e)
{
base.OnObjectModelChanged(e);
// tv.Nodes.Clear();
// lvSections.Items.Clear();
tbs.TabPages[0].Text = "Sections (0)";
tbs.TabPages[1].Visible = false;
ExecutableObjectModel executable = (ObjectModel as ExecutableObjectModel);
if (executable == null) return;
tbs.TabPages[0].Text = "Sections (" + executable.Sections.Count.ToString() + ")";
foreach (ExecutableSection section in executable.Sections)
{
tmSections.Rows.Add(new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmSections.Columns[0], section.Name),
new TreeModelRowColumn(tmSections.Columns[1], section.PhysicalAddress.ToString()),
new TreeModelRowColumn(tmSections.Columns[2], section.VirtualAddress.ToString()),
new TreeModelRowColumn(tmSections.Columns[3], section.VirtualSize.ToString())
}));
tmSections.Rows[tmSections.Rows.Count - 1].SetExtraData<ExecutableSection>("section", section);
}
if (executable.ManagedAssembly != null)
{
tbs.TabPages[1].Visible = true;
txtAssemblyName.Text = executable.ManagedAssembly.GetName().Name;
txtAssemblyVersion.Text = executable.ManagedAssembly.GetName().Version.ToString();
pnlManagedAssembly.Assembly = executable.ManagedAssembly;
}
}
}
}

View File

@ -0,0 +1,338 @@
//
// ManagedAssemblyPanel.cs - provides a UWT Container with controls to edit managed assembly information for an ExecutableObjectModel
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2019-2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Reflection;
using System.Text;
using MBS.Framework.UserInterface;
using MBS.Framework.UserInterface.Controls;
using MBS.Framework.UserInterface.Dialogs;
using MBS.Framework.UserInterface.Layouts;
namespace UniversalEditor.Plugins.Executable.UserInterface.Editors.Executable
{
/// <summary>
/// Provides a UWT Container with controls to edit managed assembly information for an <see cref="ObjectModels.Executable.ExecutableObjectModel" />.
/// </summary>
public class ManagedAssemblyPanel : Container
{
private TextBox txtSearch = null;
private ListView tvTypes = null;
private DefaultTreeModel tmTypes = null;
private TextBox txtSource = null;
private ComboBox cboLanguage = null;
private Assembly _Assembly = null;
public Assembly Assembly
{
get { return _Assembly; }
set
{
_Assembly = value;
UpdateTypeList();
}
}
private void UpdateTypeList()
{
tmTypes.Rows.Clear();
Type[] types = null;
try
{
types = _Assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
types = ex.Types;
}
for (int i = 0; i < types.Length; i++)
{
if (types[i] == null)
continue;
string[] nameParts = types[i].FullName.Split(new char[] { '.' });
bool nestedClass = false;
while (nameParts[nameParts.Length - 1].Contains("+"))
{
// handle the case of nested classes
nestedClass = true;
Array.Resize<string>(ref nameParts, nameParts.Length + 1);
string[] p = nameParts[nameParts.Length - 2].Split(new char[] { '+' });
nameParts[nameParts.Length - 2] = p[0];
nameParts[nameParts.Length - 1] = p[1];
}
TreeModelRow row = tmTypes.RecursiveCreateTreeModelRow(tmTypes.Columns[0], nameParts, new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmTypes.Columns[1], "Namespace")
});
if (nestedClass)
row.ParentRow.RowColumns[1].Value = "Class";
row.RowColumns.Add(new TreeModelRowColumn(tmTypes.Columns[1], "Class"));
SetupTypeTreeModelRow(row, types[i]);
}
}
private void SetupTypeTreeModelRow(TreeModelRow row, Type type)
{
row.SetExtraData<Type>("item", type);
BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;
TreeModelRow rowBaseTypes = new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmTypes.Columns[0], "Base Types")
});
if (type.BaseType != null)
{
TreeModelRow rowBaseType = new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmTypes.Columns[0], type.BaseType.FullName)
});
SetupTypeTreeModelRow(rowBaseType, type.BaseType);
rowBaseTypes.Rows.Add(rowBaseType);
}
row.Rows.Add(rowBaseTypes);
TreeModelRow rowDerivedTypes = new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmTypes.Columns[0], "Derived Types")
});
row.Rows.Add(rowDerivedTypes);
FieldInfo[] fields = type.GetFields(bindingFlags);
for (int j = 0; j < fields.Length; j++)
{
TreeModelRow row2 = new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmTypes.Columns[0], fields[j]),
new TreeModelRowColumn(tmTypes.Columns[1], "Field")
});
row2.SetExtraData<FieldInfo>("item", fields[j]);
row.Rows.Add(row2);
}
EventInfo[] events = type.GetEvents(bindingFlags);
for (int j = 0; j < events.Length; j++)
{
TreeModelRow row2 = new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmTypes.Columns[0], events[j]),
new TreeModelRowColumn(tmTypes.Columns[1], "Event")
});
row2.SetExtraData<EventInfo>("item", events[j]);
row.Rows.Add(row2);
}
PropertyInfo[] props = type.GetProperties(bindingFlags);
for (int j = 0; j < props.Length; j++)
{
TreeModelRow row2 = new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmTypes.Columns[0], props[j]),
new TreeModelRowColumn(tmTypes.Columns[1], "Property")
});
row2.SetExtraData<PropertyInfo>("item", props[j]);
row.Rows.Add(row2);
}
MethodInfo[] meths = type.GetMethods(bindingFlags);
for (int j = 0; j < meths.Length; j++)
{
if (meths[j].IsSpecialName && (meths[j].Name.StartsWith("set_", StringComparison.OrdinalIgnoreCase) || meths[j].Name.StartsWith("get_", StringComparison.OrdinalIgnoreCase)))
{
// we can be REASONABLY sure that this is a property setter / getter,
// and as we've already gotten all the properties, ignore it
continue;
}
TreeModelRow row2 = new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmTypes.Columns[0], GetMethodTitle(meths[j])),
new TreeModelRowColumn(tmTypes.Columns[1], "Method")
});
row2.SetExtraData<MethodInfo>("item", meths[j]);
row.Rows.Add(row2);
}
}
private void tsbILSave_Click(object sender, EventArgs e)
{
MemberInfo t = tvTypes.SelectedRows[0].GetExtraData<MemberInfo>("item");
if (t == null)
return;
FileDialog dlg = new FileDialog();
dlg.Text = "Save Code File";
dlg.SelectedFileNames.Clear();
dlg.SelectedFileNames.Add(t.Name + Language.CodeFileExtension);
if (dlg.ShowDialog() == DialogResult.OK)
{
}
}
public ManagedAssemblyPanel()
{
Layout = new BoxLayout(Orientation.Vertical);
Container ctToolbarAndOthers = new Container();
ctToolbarAndOthers.Layout = new BoxLayout(Orientation.Horizontal);
Toolbar tb = new Toolbar();
tb.Items.Add(new ToolbarItemButton("tsbILSave", StockType.Save, tsbILSave_Click));
ctToolbarAndOthers.Controls.Add(tb, new BoxLayout.Constraints(false, true));
cboLanguage = new ComboBox();
cboLanguage.Changed += cboLanguage_Changed;
Type[] codeProviders = MBS.Framework.Reflection.GetAvailableTypes(new Type[] { typeof(CodeProvider) });
DefaultTreeModel tmLanguage = new DefaultTreeModel(new Type[] { typeof(string) });
/*
tmLanguage.Rows.Add(new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmLanguage.Columns[0], "Raw Bytes")
}));
*/
for (int i = 0; i < codeProviders.Length; i++)
{
CodeProvider codeProvider = (codeProviders[i].Assembly.CreateInstance(codeProviders[i].FullName) as CodeProvider);
TreeModelRow row = new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(tmLanguage.Columns[0], codeProvider.Title)
});
row.SetExtraData<CodeProvider>("provider", codeProvider);
tmLanguage.Rows.Add(row);
}
if (tmLanguage.Rows.Count > 0)
{
cboLanguage.SelectedItem = tmLanguage.Rows[0];
}
cboLanguage.ReadOnly = true;
cboLanguage.Model = tmLanguage;
ctToolbarAndOthers.Controls.Add(cboLanguage, new BoxLayout.Constraints(false, false));
Controls.Add(ctToolbarAndOthers, new BoxLayout.Constraints(false, true));
SplitContainer scLeftRight = new SplitContainer(Orientation.Vertical);
scLeftRight.SplitterPosition = 250;
txtSearch = new TextBox();
scLeftRight.Panel1.Layout = new BoxLayout(Orientation.Vertical);
scLeftRight.Panel1.Controls.Add(txtSearch, new BoxLayout.Constraints(false, true));
tvTypes = new ListView();
tvTypes.SelectionChanged += tvTypes_SelectionChanged;
tmTypes = new DefaultTreeModel(new Type[] { typeof(string), typeof(string) });
tvTypes.Model = tmTypes;
tvTypes.Columns.Add(new ListViewColumnText(tmTypes.Columns[0], "Name"));
tvTypes.Columns.Add(new ListViewColumnText(tmTypes.Columns[1], "Type"));
scLeftRight.Panel1.Controls.Add(tvTypes, new BoxLayout.Constraints(true, true));
scLeftRight.Panel2.Layout = new BoxLayout(Orientation.Vertical);
txtSource = new TextBox();
txtSource.Multiline = true;
scLeftRight.Panel2.Controls.Add(txtSource, new BoxLayout.Constraints(true, true));
Controls.Add(scLeftRight, new BoxLayout.Constraints(true, true));
}
void cboLanguage_Changed(object sender, EventArgs e)
{
CodeProvider provider = cboLanguage.SelectedItem.GetExtraData<CodeProvider>("provider");
Language = provider;
}
private CodeProvider _Language = CodeProvider.CSharp;
public CodeProvider Language
{
get { return _Language; }
set
{
_Language = value;
tvTypes_SelectionChanged(this, EventArgs.Empty);
}
}
private string GetAccessModifiersSourceCode(PropertyInfo mi)
{
return Language.GetAccessModifiers(mi);
}
private string GetAccessModifiersSourceCode(MethodInfo mi)
{
return Language.GetAccessModifiers(mi);
}
private string GetAccessModifiersSourceCode(FieldInfo mi)
{
return Language.GetAccessModifiers(mi);
}
private string GetAccessModifiersSourceCode(Type mi)
{
return Language.GetAccessModifiers(mi);
}
private string GetMethodTitle(MethodInfo mi)
{
StringBuilder sb = new StringBuilder();
string typeName = Language.GetTypeName(mi.ReturnType);
sb.Append(mi.Name);
sb.Append('(');
sb.Append(')');
sb.Append(" : ");
sb.Append(typeName);
return sb.ToString();
}
private void tvTypes_SelectionChanged(object sender, EventArgs e)
{
if (tvTypes.SelectedRows.Count == 0)
return;
object item = tvTypes.SelectedRows[0].GetExtraData("item");
if (item is Type)
{
Type typ = (item as Type);
txtSource.Text = Language.GetSourceCode(typ, 0);
}
else if (item is MethodInfo)
{
txtSource.Text = Language.GetSourceCode(item as MethodInfo, 0);
}
}
}
}

View File

@ -31,16 +31,18 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Editors\Executable\ExecutableEditor.cs" />
<Compile Include="Editors\Executable\CodeProvider.cs" />
<Compile Include="Editors\Executable\CodeProviders\CSharpCodeProvider.cs" />
<Compile Include="Editors\Executable\CodeProviders\VisualBasicCodeProvider.cs" />
<Compile Include="Editors\Executable\ILOpcode.cs" />
<Compile Include="Editors\Executable\NonLayout\ExecutableEditor.cs" />
<Compile Include="Editors\Executable\NonLayout\ManagedAssemblyPanel.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Editors\" />
<Folder Include="Editors\Executable\" />
<Folder Include="Editors\Executable\CodeProviders\" />
<Folder Include="Editors\Executable\NonLayout\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\UniversalEditor.Core\UniversalEditor.Core.csproj">
@ -68,5 +70,8 @@
<Name>MBS.Framework.UserInterface</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="Editors\Executable\ExecutableEditor.cs.exclude" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>