2009-10-15 8 views
10

Gibt es eine Möglichkeit, die bestimmte DLL, auf die eine P/Invoke (DllImport) -Signatur verweist, von der CPU-Architektur abhängig zu machen?CPU-Architektur unabhängig P/Invoke: Kann der DllName oder der Pfad "dynamisch" sein?

Ich arbeite an einer Anwendung, die eine große Anzahl von Methodensignaturen von einer nativen DLL von einem Drittanbieter lädt, in diesem Fall die User-Space-Schnittstelle DLL zu einem Stück Hardware. Dieser Anbieter hat nun angefangen, sowohl x86- als auch x64-Versionen der DLL zu liefern, und ich denke, dass meine App davon profitieren würde, als 64-Bit-Prozess ausgeführt zu werden. Abgesehen von dieser einen DLL ist alles .NET-Code, also würde das Bauen als "Any CPU" funktionieren.

Alle Methodensignaturen in der systemeigenen DLL sind auf 64 Bit identisch, der Name der DLL ist jedoch unterschiedlich (Foo.dll vs. Foo_x64.dll). Gibt es einen Weg durch die P/Invoke-Signaturen oder app.config-Einträge Ich kann es erhalten, welche DLL basierend auf der laufenden CPU-Architektur zu laden?

Wenn es anstelle von verschiedenen DLL-Namen in verschiedenen Ordnern denselben Namen hatte, öffnet das andere Optionen?

Hinweis: Da die Version dieser User-Space-DLL unbedingt mit dem installierten Kerneltreiber für die Hardware übereinstimmen muss, ist die DLL nicht mit unserer App gebündelt, sondern hängt vom Installationsprogramm des Herstellers ab Verzeichnis in% PATH%.

+0

Mögliche Duplikat von http: // stackoverflow.com/questions/23215518/Ziel-32-Bit-oder-64-Bit-native-dll-abhängig von der Umgebung –

+3

Ich denke, die Vervielfältigung ist anders herum, da diese Frage vier Jahre älter ist als die :) – Cheetah

Antwort

4

Es gibt keine Möglichkeit, eine einzelne PInvoke-Signatur zu erstellen und das gewünschte Verhalten zu erzielen. Das Attribut wird in Metadaten gebrannt und muss konstante Werte haben. Ein Hack, den Sie tun könnten, ist mehrere Methoden zu haben.

public static class NativeMethods32 { 
    [DllImport("Foo.dll")] 
    public static extern int SomeMethod(); 
} 

public static class NativeMethods64 { 
    [DllImport("Foo_x864.dll")] 
    public static extern int SomeMethod(); 
} 

public static class NativeMethods { 
    public static bool Is32Bit { return 4 == IntPtr.Size; } 
    public static SomeMethod() { 
    return Is32Bit ? 
     NativeMethods32.SomeMethod(); 
     NativeMethods64.SomeMethod(); 
    } 
} 

Dies ist jedoch nicht der bevorzugte Ansatz. Ein einfacherer Ansatz wäre, die DLL auf mehreren Plattformen mit demselben Namen zu versehen und eine plattformunabhängige PInvoke-Signatur zu erstellen. Dies ist der Ansatz, den fast alle Windows-Bibliotheken verwenden.

+0

Das gleiche Ding funktioniert nicht für meinen Fall, weil 1) Dies ist ein Drittanbieter DLL 2) Die DLL (s) werden in einem Ordner im System PATH installiert, so dass Apps sie automatisch finden können (zum Glück der Hersteller installiert nicht mehr auf% SystemRoot% \ system32) 3) Auf einem 64-Bit-Betriebssystem müssen sowohl die 32-Bit- als auch 64-Bit-DLLs verfügbar sein # 1 bedeutet, ich kann nicht geigen und # 2 Konflikte mit # 3 . Ich endete mit einer Lösung ähnlich wie Sie vorgeschlagen haben. Ich definierte eine Schnittstelle mit allen Methoden und verwendete LinFu, um zur Laufzeit ein Proxy-Objekt zu erstellen, das an die korrekten statischen Methoden weiterleitet. – Cheetah

11

"Wenn es anstelle verschiedener DLL-Namen in verschiedenen Ordnern denselben Namen hat, öffnet das andere Optionen?"

Vielleicht wäre dies für Sie arbeitet:

public static class NativeMethods 
{ 
    // here we just use "Foo" and at runtime we load "Foo.dll" dynamically 
    // from any path on disk depending on the logic you want to implement 
    [DllImport("Foo", EntryPoint = "bar")] 
    private void bar(); 

    [DllImport("kernel32")] 
    private unsafe static extern void* LoadLibrary(string dllname); 

    [DllImport("kernel32")] 
    private unsafe static extern void FreeLibrary(void* handle); 

    private sealed unsafe class LibraryUnloader 
    { 
    internal LibraryUnloader(void* handle) 
    { 
     this.handle = handle; 
    } 

    ~LibraryUnloader() 
    { 
     if (handle != null) 
     FreeLibrary(handle); 
    } 

    private void* handle; 

    } // LibraryUnloader 

    private static readonly LibraryUnloader unloader; 

    static NativeMethods() 
    { 
    string path; 

    if (IntPtr.Size == 4) 
     path = "path/to/the/32/bit/Foo.dll"; 
    else 
     path = "path/to/the/64/bit/Foo.dll"; 

    unsafe 
    { 
     void* handle = LoadLibrary(path); 

     if (handle == null) 
     throw new DllNotFoundException("unable to find the native Foo library: " + path); 

     unloader = new LibraryUnloader(handle); 
    } 
    } 
} 

Es besteht in der explizit die native Bibliothek mit dem vollständigen Pfad vor P Laden/Invoke selbst versucht, es zu laden.

Was denkst du?

+0

Es wäre Arbeit mit Windows/MS.NET aber was ist mit Mono? – AndreyAkinshin

+0

keine Ahnung von Mono, bitte sagen Sie uns, was Sie herausfinden –

+0

nichts für jetzt = ( – AndreyAkinshin

1

Ich entwickelte eine spezielle Bibliothek für das Ziel: InteropDotNet. Es führt das neue Attribut RuntimeDllImport mit dynamischem Bibliothekspfad-Resolving (on the fly) ein. Standardmäßig können Sie schreiben

[RuntimeDllImport("NativeLib", 
    CallingConvention = CallingConvention.Cdecl, EntryPoint = "sum")] 
int Sum(int a, int b); 

Und die Bibliothek wird je nach Umgebung gelöst werden. Zum Beispiel Pfade für Win/Linux, x86/x64:

x86/NativeLib.dll 
x86/libNativeLib.so 
x64/NativeLib.dll 
x64/libNativeLib.so 
Verwandte Themen