Dynamic import of C / C ++ DLL

From what I learned to use P / Invoke in F #, a function signature must be declared first using DllImport as follows:

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

This is good when the DLL name is known at compile time. How can I interact with an unmanaged C / C ++ DLL if I can only find out the name at runtime?

+3
source share
4 answers

Alternatively, you can find a solution that dynamically generates PInvoke methods.

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)
+5
source

The native APIs for this are LoadLibrary () and GetProcAddress (). Not sure if there are manageable versions of this, but a Google search found something interesting:

kernel32! GetProcAddress.

:

Pinvoke - , kernel32! GetProcAddress. , , dll, .

, , ? .

+4

F #. - DLL ++/CLI, DLL LoadLibrary win API.

+1

I think it would be better if you could pass the signature of your own F # function to define_dynamic_pinvoke, for example define_dynamic_pinvoke <(int * int → bool)> ("Beep", "kernel32.dll"), but I admit I don’t know how to achieve it.

You can rewrite the sample as:

let beep = define_dynamic_pinvoke<delegate of (int * int) -> bool> ("Beep", "kernel32.dll")

0
source

Source: https://habr.com/ru/post/1723658/


All Articles