8 Stimmen

Importieren Sie externe dll basierend auf 64bit oder 32bit OS

Ich habe eine dll, die sowohl in 32bit und 64bit Version kommt. Meine .NET WinForm ist für "Any CPU" konfiguriert und mein Chef erlaubt uns keine getrennten Installationen für die verschiedenen Betriebssystemversionen. Also frage ich mich: Wenn ich beide DLLs in der Installation verpacke, gibt es dann eine Möglichkeit, die WinForm zu bestimmen, ob es 64bit/32bit ist und die richtige DLL zu laden.

Ich fand dieser Artikel zur Bestimmung der Version. Aber ich bin mir nicht sicher, wie ich das richtige DLLImport-Attribut für die Methoden zu definieren, die ich verwenden möchte. Irgendwelche Ideen?

14voto

Hans Passant Punkte 894572

Sie könnten die API-Funktion SetDllDirectory nutzen, die den Suchpfad für nicht verwaltete Assemblies ändert. Speichern Sie Ihre 32-Bit-DLLs im x86-Unterverzeichnis des App-Installationsverzeichnisses, die 64-Bit-DLLs im x64-Unterverzeichnis.

Führen Sie diesen Code beim Start der Anwendung aus, bevor Sie einen P/Invoke ausführen:

using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
...

    public static void SetUnmanagedDllDirectory() {
        string path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
        path = Path.Combine(path, IntPtr.Size == 8 ? "x64 " : "x86");
        if (!SetDllDirectory(path)) throw new System.ComponentModel.Win32Exception();
    }

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool SetDllDirectory(string path);

6voto

Kieron Punkte 25804

Können Sie beide importieren und dann entscheiden, welches Programm Sie stattdessen über .NET aufrufen möchten?

Zum Beispiel:

[DllImport("32bit.dll", CharSet = CharSet.Unicode, EntryPoint="CallMe")]
public static extern int CallMe32 (IntPtr hWnd, String text, String caption, uint type);

[DllImport("64bit.dll", CharSet = CharSet.Unicode, EntryPoint="CallMe")]
public static extern int CallMe64 (IntPtr hWnd, String text, String caption, uint type);

3voto

SLaks Punkte 832502

Sie sollten zwei verschiedene private extern Methoden, und erstellen Sie eine interne Methode, die prüft IntPtr.Size und ruft die richtige Version auf.

3voto

Reed Copsey Punkte 536986

Meine Lösung besteht darin, eine einzige abstrakte Klasse zu erstellen, mit einer konkreten Version, die meine 32-Bit-DLL lädt und umhüllt, und einer separaten Implementierung, die die 64-Bit-DLL lädt und umhüllt. Eine einzige Factory-Methode in der Basisklasse kann verwendet werden, um die entsprechende Implementierung auf der Grundlage der folgenden Parameter zu instanziieren IntPtr.Size .

Das Schöne an diesem Ansatz ist, dass der Rest Ihres Codes vollständig von der Plattform isoliert ist - er konstruiert einfach ein Objekt mit der Factory-Methode Ihrer Basisklasse und arbeitet damit. Es ist auch sehr einfach, mehrere Methoden innerhalb der betreffenden DLLs auf einheitliche Weise aufzurufen, und Ihr gesamter "nativer" Code kann leicht in eine private Implementierung verschoben werden.

2voto

Andras Vass Punkte 11288

...oder Sie können verwenden Marshal.GetDelegateForFunctionPointer() zu tun dynamisches P/Invoke .
...oder rufen Sie an LoadLibrary() mit einem vollständig qualifizierten Pfad bevor die CLR versucht, es für Sie zu laden.

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