-1

I have a method, which generates the P/Invoke function dynamically:

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)

The reason is, I can control the dll path easier.

But now I met a C function, which uses a function pointer:

CUresult cuOccupancyMaxPotentialBlockSize ( int* minGridSize, int* blockSize, CUfunction func, CUoccupancyB2DSize blockSizeToDynamicSMemSize, size_t dynamicSMemSize, int  blockSizeLimit )

Where the type CUoccupancyB2DSize is a function pointer of:

size_t(CUDA_CB* CUoccupancyB2DSize )( int  blockSize )

So if I translate that type to Func<int, IntPtr>, I got exception while generating the P/Invoke method:

System.Runtime.InteropServices.MarshalDirectiveException : Cannot marshal 'parameter #4': Generic types cannot be marshaled.

Is there any workaround? In normal P/Invoke, you can add [MarshalAs(UnmanagedType.FunctionPtr)] to translate a delegate into a function pointer, but how to do that with dynamic P/Invoke method generation?

Xiang Zhang
  • 2,831
  • 20
  • 40
  • By creating a new delegate type together with the medthod. Sadlyt you can't use `Action<>` or `Func<>`. – xanatos Feb 26 '16 at 08:56
  • An alternative is to simply consider the function pointer as a `IntPtr`, but then you are only moving the problem on the `Marshal.GetFunctionPointerForDelegate` that has the same limitation with `Action<>`/`Func<>` – xanatos Feb 26 '16 at 09:02
  • There are far easier ways to control the DLL path – David Heffernan Feb 26 '16 at 09:03
  • Like for example http://stackoverflow.com/a/8836934/613130 `LoadLibrary` the DLL before using any pinvoke. – xanatos Feb 26 '16 at 09:07
  • @xanatos I know this `LoadLibrary` solution, it works fine on Windows, but it doesn't work with Linux/Mono, where the `dlopen` won't cache the dll. – Xiang Zhang Feb 26 '16 at 09:09
  • @xanatos I think I can try this `IntPtr` solution :) – Xiang Zhang Feb 26 '16 at 09:11
  • @XiangZhang Probably not. See here another solution: http://stackoverflow.com/a/16569389/613130 You can use `AppDomain.CurrentDomain.AssemblyResolve` – xanatos Feb 26 '16 at 09:23
  • @xanatos isn't `AssemblyResolve` used for assembly? I want to support multiplatform, on MacOSX, the native is `.dylib`, on Linux, native is `.so`, I know there is some dll name map config file in Mono, but I also want the native dlls(or .so or .dylib) could be stored by relative path, and it might not be in system PATH. – Xiang Zhang Feb 26 '16 at 09:36

1 Answers1

0

As suggest from @xanatos, I found a workaround. The function pointer can be replaced simply with IntPtr, and then you use Marshal.GetFunctionPointerForDelegate. One thing to note, the delegate must NOT be generic, which means you cannot use Func<int, IntPtr>, instead you need to define a non-generic delegate type yourself and use that.

Xiang Zhang
  • 2,831
  • 20
  • 40