So, as suggested by zeromus here's a dedicated topic about the feature I developped.
I create a new interface named ICustomGameTool who inherits from IToolForm. It doesn't do anything else (at least, for the moment), it's just a way to distinguish an "external tool" from something coded inside the BizHawk project.
I added a pathentry in BizHawk.Client.Common/config/PathEntry.cs as following:
Language: C
/*...*/
new PathEntry { System = "Global_NULL", SystemDisplayName="Global", Type = "Multi-Disk Bundles", Path = Path.Combine(".", "Tools"), Ordinal = 12 },
new PathEntry { System = "Global_NULL", SystemDisplayName="Global", Type = "GameTools", Path = Path.Combine(".", "GameTools"), Ordinal = 13 },
/*...*/
Then in ToolManager.cs:
In order to handle an incorrectly load tool, I added a null return at bout line 70.
Language: C
/*...*/
var newTool = CreateInstance(toolType);
if (newTool == null)
{
return null;
}
/*...*/
Now the biggest part is in the function CreateInstance that I reviewed like this:
Language: C
private IToolForm CreateInstance(Type toolType)
{
IToolForm tool;
//Specific case for custom tools
if (toolType == typeof(ICustomGameTool))
{
string path = Path.Combine(Global.Config.PathEntries["Global", "GameTools"].Path, string.Format("{0}.dll", Global.Game.Name));
if (File.Exists(path)
&& MessageBox.Show("A custom plugin has been found for the ROM you're loading. Do you want to load it?\r\nAccept ONLY if you trust the source and if you know what you're doing. In any other case, choose no."
, "Answer to life, universe and everything else?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
try
{
// As the object is "remote"(external to the project), the CreateInstanceFrom returns a handle.We need to Unwrap in order to make the casting
tool = System.Activator.CreateInstanceFrom(path, "BizHawk.Client.EmuHawk.CustomMainForm").Unwrap() as IToolForm;
if (tool == null)
{
MessageBox.Show("It seems that the object CustomMainForm does not implement IToolForm. Please review the code.", "Boom!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return null;
}
}
catch (MissingMethodException)
{
MessageBox.Show("It seems that the object CustomMainForm does not have a public default constructor. Please review the code.", "Boom!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return null;
}
catch (TypeLoadException)
{
MessageBox.Show("It seems that the object CustomMainForm does not exists. Please review the code.", "Boom!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return null;
}
}
else
{
return null;
}
}
else
{
tool = (IToolForm)Activator.CreateInstance(toolType);
}
// Add to our list of tools
_tools.Add(tool);
return tool;
}
Finally, I added this line ine the LoadRom function (in MainForm.cs):
Language: C
GlobalWin.Tools.Load<ICustomGameTool>();
The code of the external tool should reference the Exe and looks like this:
Language: C
/*...*/
namespace BizHawk.Client.EmuHawk
{
public partial class CustomMainForm : Form, ICustomGameTool
{
public CustomMainForm()
{
InitializeComponent();
}
/*...*/
When compiled, renamed like the targeted ROM (c.f. in gamedb) and placed into the GameTools folders, the form will be automatically shown (exactly the same way as the RAM Watch for example) when the ROM will be loaded.
Same questions: What do you think about this? Could it be interesting?
EDIT:
GitHub link. I applied my changes from the current Release branch of the official project.