2009-11-23 6 views
3

D'après ce que j'ai appris à utiliser P/Invoke en F #, la signature de la fonction doit être déclarée en utilisant d'abord DllImport comme ceci:importation Dynamiquement un C/C++ DLL

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

C'est tout bon quand la DLL Le nom est connu au moment de la compilation. Comment puis-je m'interfacer avec une DLL C/C++ non gérée si je ne peux découvrir le nom qu'à l'exécution?

Répondre

1

Ce problème n'est pas spécifique à F #. Vous aurez besoin de construire une DLL proxy en C++/CLI qui sera chargée de charger la DLL nécessaire en utilisant la fonction LoadLibrary de l'API win.

4

Les API natives pour cela sont LoadLibrary() et GetProcAddress(). Je ne sais pas s'il existe des versions gérées de cela, mais une recherche Google a trouvé quelque chose d'intéressant:

Type-safe Managed wrappers for kernel32!GetProcAddress.

ligne d'ouverture de c'est:

Pinvoke est cool en code managé, mais parfois vous avez besoin d'aller droit au kernel32 GetProcAddress!. Par exemple, vous avez peut-être besoin d'un contrôle dynamique sur la DLL non managée que vous souhaitez charger.

Cela ressemble à ce que vous voulez faire, non? Reste de l'article here.

5

Alternativement, vous pouvez trouver une solution qui génère dynamiquement des méthodes 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) 
+0

Je pense que ce serait mieux si vous pouviez passer la signature d'une fonction native F # pour define_dynamic_pinvoke, comme define_dynamic_pinvoke <(int * int -> bool)> ("Beep", "kernel32.dll"), mais j'avoue que je ne sais pas comment y parvenir. –

0

Je pense que ce serait mieux si vous pouviez passer la signature d'une fonction native F # pour define_dynamic_pinvoke, comme define_dynamic_pinvoke < (int * int -> bool)> ("Bip", « kernel32.dll "), mais j'avoue que je ne sais pas comment y parvenir.

Vous pouvez réécrire l'échantillon:

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

+0

Non, ne compile pas. –

Questions connexes