如何通过可在本机代码上调用的"MethodName"获取 .NET 托管方法指针



前提条件

我将获得其指针的.net方法是:

  • 公共静态方法
  • 没有过载
  • 参数和返回值仅为ValueType(不安全指针、基元类型、非托管结构(

原因

获取方法指针,以便我可以在C++程序中调用。

这对我有效,但我需要为每个方法声明委托。

我想摆脱一遍又一遍的做事。

网侧:

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void UpdateDelegate(float delta);
public static void* GetUpdatePointer()
{
var delegateInstance = = new UpdateDelegate(Update);
var pfnUpdate = Marshal.GetFunctionPointerForDelegate(delegateInstance);
return (void*)pfnUpdate;
}
public static Update(float delta)=>{...}

在C++端:

typedef void (_stdcall *  FuncPtr)(float);
void foo()
{
//just pseudo-code showing where is the pfnUpdate from.
FuncPtr pfnUpdate = (FuncPtr)GetUpdatePointer();
pfnUpdate(0.01f);
}

我想要什么

在c#中,我为我的本机代码导出GetMethodPointer。它将返回一个指向指定方法的函数指针,本机程序可以通过stdcall调用约定调用该指针。

//avoid gc collect this object
static List<Delegate> KeepReference = new List<Delegate>();
public unsafe static void* GetMethodPointer(string name)
{
System.Reflection.MethodInfo methodInfo = typeof(PhysicsMain).GetMethod(name);
// also mark this delegate with [UnmanagedFunctionPointer(CallingConvention.StdCall)] attribute
Type delegateType = ConstructDelegateTypeWithMethodInfo(methodInfo);
var delegateInstance = Delegate.CreateDelegate(delegateType, methodInfo);
KeepReference.Add(delegateInstance);
return (void*)Marshal.GetFunctionPointerForDelegate(delegateInstance);
}

我需要ConstructDelegateTypeWithMethodInfo来创建一个与指定方法具有相同签名的委托。并为其标记[UnmanagedFunctionPointer(CallingConvention.StdCall(]属性,以便将其封送为函数指针。

我认为它可能会使用IL、Reflection,甚至Asm来做到这一点。或者使用IL来编写整个GetMethodPointer方法。

这些天我终于找到了一个解决方案。首先,我看到了这篇文章给出的Expression.GetDelegateType。但它对我不起作用,因为Marshal.GetFunctionPointerForDelegate不支持Expression.GetDelegateType生成的泛型委托类型。我认为Expression.GetDelegateType的实现可能有一条线索。因此,我浏览了referencesource,得到了一个名为MakeNewCustomDelegate的内部方法。此链接提供了有关如何调用内部方法的代码。事情很容易解决!

编辑:我忘了说,委托的默认非托管调用调用是stdcall,所以我们不需要显式地用[UnmanagedFunctionPointer(CallingConvention.stdcall(]标记委托。

在您的示例中,您假设方法的类是know函数(PhysicsMain(。

如果UpdateDelegate也是已知的,你可以很容易地使用它:

Type delegateType = typeof(UpdateDelegate);
var delegateInstance = Delegate.CreateDelegate(delegateType, methodInfo);

但你也可以通过名称获得这种类型:

Type delegateType = Type.GetType("Namespace.ClassName+UpdateDelegate");
var delegateInstance = Delegate.CreateDelegate(delegateType, methodInfo);

您可以查看delegateType.CustomAttributes并验证该类型是否具有UnmanagedFunctionPointer属性。

最新更新