diff --git a/BizHawk.Emulation.Common/BizInvoke/BizInvoker.cs b/BizHawk.Emulation.Common/BizInvoke/BizInvoker.cs
index cb3b3b36b1..475b5c40fb 100644
--- a/BizHawk.Emulation.Common/BizInvoke/BizInvoker.cs
+++ b/BizHawk.Emulation.Common/BizInvoke/BizInvoker.cs
@@ -10,10 +10,65 @@ namespace BizHawk.Emulation.Common.BizInvoke
{
public static class BizInvoker
{
+ ///
+ /// holds information about a proxy implementation, including type and setup hooks
+ ///
+ private class InvokerImpl
+ {
+ public Type ImplType;
+ public List> Hooks;
+
+ public object Create(IImportResolver dll)
+ {
+ var ret = Activator.CreateInstance(ImplType);
+ foreach (var f in Hooks)
+ f(ret, dll);
+ return ret;
+ }
+ }
+
+ ///
+ /// dictionary of all generated proxy implementations and their basetypes
+ ///
+ private static IDictionary Impls = new Dictionary();
+
+ ///
+ /// the assembly that all proxies are placed in
+ ///
+ private static readonly AssemblyBuilder ImplAssemblyBuilder;
+ ///
+ /// the module that all proxies are placed in
+ ///
+ private static readonly ModuleBuilder ImplModuleBilder;
+
+ static BizInvoker()
+ {
+ var aname = new AssemblyName("BizInvokeProxyAssembly");
+ ImplAssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(aname, AssemblyBuilderAccess.Run);
+ ImplModuleBilder = ImplAssemblyBuilder.DefineDynamicModule("BizInvokerModule");
+ }
+
+ ///
+ /// get an implementation proxy for an interop class
+ ///
public static T GetInvoker(IImportResolver dll)
where T : class
{
- var baseType = typeof(T);
+ InvokerImpl impl;
+ lock (Impls)
+ {
+ var baseType = typeof(T);
+ if (!Impls.TryGetValue(baseType, out impl))
+ {
+ impl = CreateProxy(baseType);
+ Impls.Add(baseType, impl);
+ }
+ }
+ return (T)impl.Create(dll);
+ }
+
+ private static InvokerImpl CreateProxy(Type baseType)
+ {
if (baseType.IsSealed)
throw new InvalidOperationException("Can't proxy a sealed type");
if (!baseType.IsPublic)
@@ -49,38 +104,32 @@ namespace BizHawk.Emulation.Common.BizInvoke
}
// hooks that will be run on the created proxy object
- var postCreateHooks = new List>();
+ var postCreateHooks = new List>();
- var aname = new AssemblyName(baseType.Name + Guid.NewGuid().ToString("N"));
- var assy = AppDomain.CurrentDomain.DefineDynamicAssembly(aname, AssemblyBuilderAccess.Run);
- var module = assy.DefineDynamicModule("BizInvoker");
- var type = module.DefineType("Bizhawk.BizInvokeProxy", TypeAttributes.Class | TypeAttributes.Public, baseType);
+ var type = ImplModuleBilder.DefineType("Bizhawk.BizInvokeProxy", TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed, baseType);
foreach (var mi in baseMethods)
{
var entryPointName = mi.Attr.EntryPoint ?? mi.Info.Name;
- var entryPtr = dll.Resolve(entryPointName);
- if (entryPtr == IntPtr.Zero)
- throw new InvalidOperationException("Resolver returned NULL for entry point " + entryPointName);
- if (false)
- {
- ImplementMethodCalli(type, mi.Info, entryPtr, mi.Attr.CallingConvention);
- }
- else
- {
- var hook = ImplementMethodDelegate(type, mi.Info, entryPtr, mi.Attr.CallingConvention);
- postCreateHooks.Add(hook);
- }
+ var hook = mi.Attr.Compatibility
+ ? ImplementMethodDelegate(type, mi.Info, mi.Attr.CallingConvention, entryPointName)
+ : ImplementMethodCalli(type, mi.Info, mi.Attr.CallingConvention, entryPointName);
+
+ postCreateHooks.Add(hook);
}
- var ret = Activator.CreateInstance(type.CreateType());
- foreach (var hook in postCreateHooks)
- hook(ret);
- return (T)ret;
+ return new InvokerImpl
+ {
+ Hooks = postCreateHooks,
+ ImplType = type.CreateType()
+ };
}
- private static Action