动态导入C/C++ DLL

3 pinvoke f# interop

根据我的学习,在F#中使用P/Invoke,必须首先使用DllImport声明函数签名,如下所示:

[<DllImport("kernel32.dll", EntryPoint="CopyFile")>]
extern bool copyfile(char[] lpExistingFile, char[] lpNewFile, bool bFailIfExists);
Run Code Online (Sandbox Code Playgroud)

在编译时知道DLL名称时,这一切都很好.如果我只能在运行时发现名称,如何与非托管C/C++ DLL接口?

Jb *_*ain 5

或者,您可以提出一种动态生成PInvoke方法的解决方案.

open System
open System.Reflection
open System.Reflection.Emit
open System.Runtime.InteropServices

let assembly = AppDomain.CurrentDomain.DefineDynamicAssembly (new AssemblyName ("PInvokeLibrary"), AssemblyBuilderAccess.Run)
let module_builder = assembly.DefineDynamicModule ("PInvokeLibrary")

let define_dynamic_pinvoke<'d when 'd :> Delegate> (name, library) =
  let invoke = typeof<'d>.GetMethod ("Invoke") (* signature of delegate 'd *)
  let parameters =
    invoke.GetParameters ()
    |> Array.map (fun p -> p.ParameterType)
  let type_builder = module_builder.DefineType (name, TypeAttributes.Public)
  let method_builder =
    type_builder.DefinePInvokeMethod (
      name,
      library,
      MethodAttributes.Public ||| MethodAttributes.Static ||| MethodAttributes.PinvokeImpl,
      CallingConventions.Standard,
      invoke.ReturnType,
      parameters,
      CallingConvention.Winapi,
      CharSet.Ansi)
  method_builder.SetImplementationFlags (method_builder.GetMethodImplementationFlags () ||| MethodImplAttributes.PreserveSig)
  let result_type = type_builder.CreateType ()
  let pinvoke = result_type.GetMethod (name)
  Delegate.CreateDelegate (typeof<'d>, pinvoke) :?> 'd

let beep = define_dynamic_pinvoke<Func<int, int, bool>> ("Beep", "kernel32.dll")

beep.Invoke (800, 100)
Run Code Online (Sandbox Code Playgroud)