3 Stimmen

Dynamisches Importieren einer C/C++ DLL

Von dem, was ich gelernt habe, um P/Invoke in F# zu verwenden, muss die Funktionssignatur zuerst mit DllImport wie folgt deklariert werden:

[]
extern bool copyfile(char[] lpExistingFile, char[] lpNewFile, bool bFailIfExists);

Das ist alles gut, wenn der DLL-Name zur Kompilierzeit bekannt ist. Wie kann ich mit einer nicht verwalteten C/C++ DLL interagieren, wenn ich den Namen nur zur Laufzeit herausfinden kann?

5voto

Jb Evain Punkte 16941

Alternativ können Sie eine Lösung entwickeln, die PInvoke-Methoden dynamisch generiert.

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") (* Signatur des Delegaten '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> ("Beep", "kernel32.dll")

beep.Invoke (800, 100)

0 Stimmen

Ich denke, es wäre besser, wenn Sie die Signatur einer nativen F#-Funktion an define_dynamic_pinvoke übergeben könnten, wie z.B. define_dynamic_pinvoke<(int * int -> bool)> ("Beep", "kernel32.dll"), aber ich gebe zu, dass ich nicht weiß, wie man das erreicht.

4voto

asveikau Punkte 37340

Die nativen APIs dafür sind LoadLibrary() und GetProcAddress(). Bin mir nicht sicher, ob es verwaltete Versionen davon gibt, aber eine Google-Suche hat etwas Interessantes gefunden:

Typsichere verwaltete Wrapper für kernel32!GetProcAddress.

Die erste Zeile davon lautet:

Pinvoke ist cool in verwaltetem Code, aber manchmal müssen Sie direkt auf kernel32!GetProcAddress zugreifen. Zum Beispiel benötigen Sie möglicherweise dynamische Kontrolle darüber, welche nicht verwaltete DLL Sie laden möchten.

Klingt nach dem, was Sie tun möchten, oder? Rest des Artikels hier.

1voto

Dieses Problem ist nicht spezifisch für F#. Sie müssten eine Proxy-DLL in C++/CLI erstellen, die dafür verantwortlich ist, die erforderliche DLL mit der LoadLibrary-Funktion aus der Win-API zu laden.

0voto

js mouret Punkte 1

Ich denke, es wäre besser, wenn Sie die Signatur einer nativen F#-Funktion an define_dynamic_pinvoke übergeben könnten, wie define_dynamic_pinvoke<(int * int -> bool)> ("Beep", "kernel32.dll"), aber ich gebe zu, dass ich nicht weiß, wie man das erreicht.

Sie können das Beispiel wie folgt umschreiben:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X