据我所知,要在 F# 中使用 P/Invoke,必须首先使用 DllImport 声明函数签名,如下所示:
[<DllImport("kernel32.dll", EntryPoint="CopyFile")>]
extern bool copyfile(char[] lpExistingFile, char[] lpNewFile, bool bFailIfExists);
如果 DLL 名称在编译时已知,那就太好了。如果我只能在运行时发现名称,如何与非托管 C/C++ DLL 交互?
最佳答案
或者,您可以提出一个动态生成 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)
关于interop - 动态导入 C/C++ DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1782610/