さて、私は可能な解決策を見つけました:
将来使用するためにすべてのデリゲートを作成してキャッシュする汎用のInvokeメソッドを作成しました。
public void Select(uint target)
{
fixed (void* pThis = &this)
{
Generic.Invoke<Action<uint, uint>>(this.VTable[0xC0], CallingConvention.ThisCall)
((uint)pThis, target);
}
}
[FieldOffset(0x00)]
public uint* VTable;
キャッシュ:
public static T Invoke<T>(uint addr, CallingConvention conv) where T : class
{
var type = typeof(T);
if (!cache.Contains(type))
cache.Set<T>(type, NativeHelper.GetDelegateForFunctionPointer<T>(addr, conv));
return cache.Get<T>(type);
}
そして、関数を作成する(そしてジェネリックFunc / Actionで機能する)関数
public static T GetDelegateForFunctionPointer<T>(uint ptr, CallingConvention conv)
where T : class
{
var delegateType = typeof(T);
var method = delegateType.GetMethod("Invoke");
var returnType = method.ReturnType;
var paramTypes =
method
.GetParameters()
.Select((x) => x.ParameterType)
.ToArray();
var invoke = new DynamicMethod("Invoke", returnType, paramTypes, typeof(Delegate));
var il = invoke.GetILGenerator();
for (int i = 0; i < paramTypes.Length; i++)
il.Emit(OpCodes.Ldarg, i);
il.Emit(OpCodes.Ldc_I4, ptr);
il.EmitCalli(OpCodes.Calli, conv, returnType, paramTypes);
il.Emit(OpCodes.Ret);
return invoke.CreateDelegate(delegateType) as T;
}