Post subject: Patch: Allow BizHawk to run "External Tool"
Player (105)
Joined: 1/4/2013
Posts: 117
Location: Belgium
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.
Player (105)
Joined: 1/4/2013
Posts: 117
Location: Belgium
As movie says more than writing text: Link to video Ok it's far from amazing (and buggy, I just coded few hours) but you got a small idea of possibilities it can bring. I add a menu, it will be grayed if no plugin detected (same way as before). I guess it's ready for a pull request. PS: Debbuging is possible. Run the compiled BizHawk, in Visual Studio under the Debug menu => Attatch to process... (or Ctrl + Alt + P) and choose EmuHawk.exe. Put a breakpoint whereever you want and finally, load your plugin. EDIT: I moved the video to a more recent and more reveling one
If you want to test it, you can download the patched version of BizHawk here and the plugin here. Place the dll and param.xml files into the GameTools folder. Rename the dll like this: Legend of Zelda, The - Majora's Mask (USA).dll Run BizHawk, start the ROM and then Tools => Custom Tool (below Lua Console); it should normally work.