【发布时间】:2016-02-26 08:49:13
【问题描述】:
我有一个方法,可以动态生成 P/Invoke 函数:
member private this.MakePInvokeMethod(dllName:string, entryName:string, callingConvention:CallingConventions,
returnType:Type, parameterTypes:Type[],
nativeCallConv:CallingConvention, nativeCharSet:CharSet) =
let typeBuilder = moduleBuilder.DefineType("__Internal.DynamicInterop." + entryName)
let methodBuilder = typeBuilder.DefinePInvokeMethod("Invoke", dllName, entryName, MethodAttributes.Static ||| MethodAttributes.PinvokeImpl,
callingConvention, returnType, parameterTypes, nativeCallConv, nativeCharSet)
methodBuilder.SetImplementationFlags(methodBuilder.GetMethodImplementationFlags() ||| MethodImplAttributes.PreserveSig)
typeBuilder.CreateType().GetMethod("Invoke", BindingFlags.Static ||| BindingFlags.NonPublic)
原因是,我可以更轻松地控制 dll 路径。
但是现在我遇到了一个C函数,它使用了函数指针:
CUresult cuOccupancyMaxPotentialBlockSize ( int* minGridSize, int* blockSize, CUfunction func, CUoccupancyB2DSize blockSizeToDynamicSMemSize, size_t dynamicSMemSize, int blockSizeLimit )
其中CUoccupancyB2DSize类型是一个函数指针:
size_t(CUDA_CB* CUoccupancyB2DSize )( int blockSize )
因此,如果我将该类型转换为 Func<int, IntPtr>,则会在生成 P/Invoke 方法时遇到异常:
System.Runtime.InteropServices.MarshalDirectiveException : Cannot marshal 'parameter #4': Generic types cannot be marshaled.
有什么解决方法吗?在普通的 P/Invoke 中,您可以添加 [MarshalAs(UnmanagedType.FunctionPtr)] 将委托转换为函数指针,但是如何通过动态 P/Invoke 方法生成来做到这一点?
【问题讨论】:
-
通过与方法一起创建一个新的委托类型。遗憾的是,您不能使用
Action<>或Func<>。 -
另一种方法是简单地将函数指针视为
IntPtr,但您只是将问题转移到与Action<>/Func<>具有相同限制的Marshal.GetFunctionPointerForDelegate上/跨度> -
有更简单的方法来控制 DLL 路径
-
例如stackoverflow.com/a/8836934/613130
LoadLibrary在使用任何 pinvoke 之前的 DLL。 -
@xanatos 我知道这个
LoadLibrary解决方案,它在Windows 上运行良好,但不适用于Linux/Mono,其中dlopen不会缓存dll。