Ich verwende DllImport
in meiner Lösung.
Mein Problem ist, dass ich zwei Versionen der gleichen DLL für 32 Bit und eine andere für 64 Bit erstellt habe.
Beide haben dieselben Funktionen mit identischen Namen und identischen Signaturen.
Mein Problem ist, dass ich zwei statische Methoden verwenden muss, die diese zur Verfügung stellen und dann zur Laufzeit IntPtr
size verwenden, um den richtigen Aufruf zu bestimmen.
Ich muss dies tun, weil myDllName32
und myDllName64
konstant sein müssen und ich keine Möglichkeit gefunden habe, es zur Laufzeit einzustellen.
Hat jemand eine elegante Lösung dafür, damit ich die Code-Duplizierung und die konstante IntPtr
Größenprüfung loswerden kann.
Wenn ich den Dateinamen festlegen könnte, müsste ich nur einmal überprüfen und ich könnte eine Tonne von wiederholtem Code loswerden.
Das erreichen Sie wahrscheinlich mit dem Schlüsselwort #if
. Wenn Sie ein bedingtes Compilersymbol namens win32
definieren, verwendet der folgende Code den win32-Block. Wenn Sie ihn entfernen, wird der andere Block verwendet:
Dies bedeutet wahrscheinlich, dass Sie das Klassenumbruch entfernen können, das Sie jetzt haben:
%Vor%Aus praktischen Gründen könnten Sie Buildkonfigurationen erstellen, um das Kompilierungssymbol zu steuern.
Ich bevorzuge dies, indem ich den Aufruf LoadLibrary verwende kernel32.dll, um zu erzwingen, dass eine bestimmte DLL von einem bestimmten Pfad geladen wird.
Wenn Sie Ihre 32-Bit- und 64-Bit-DLLs gleich nennen, sie aber in unterschiedlichen Pfaden platzieren, können Sie den folgenden Code verwenden, um die richtige Version auf der Grundlage der von Ihnen ausgeführten Windows-Version zu laden. Sie müssen lediglich ExampleDllLoader.LoadDll () aufrufen, BEVOR Sie auf einen Code verweisen, der auf die ccf -Klasse verweist:
%Vor%Ich weiß, das ist eine wirklich alte Frage (ich bin neu - ist es schlecht, eine alte Frage zu beantworten?), aber ich musste das gleiche Problem lösen. Ich musste dynamisch eine 32-Bit- oder 64-Bit-DLL basierend auf dem Betriebssystem referenzieren, während meine .EXE für jede CPU kompiliert wurde.
Sie können DLLImport verwenden, und Sie müssen LoadLibrary () nicht verwenden.
Ich habe dies mithilfe von SetDLLDirectory . Im Gegensatz zum Namen fügt SetDLLDirectory
dem DLL-Suchpfad hinzu und ersetzt nicht den gesamten Pfad. Dies ermöglichte mir, eine DLL mit dem gleichen Namen ("TestDLL.dll" für diese Diskussion) in Win32 und Win64-Unterverzeichnissen zu haben, und entsprechend aufgerufen.
Eine alternative Option besteht darin, dass sowohl die 32- als auch die 64-Bit-Version der nicht verwalteten DLL denselben Namen haben, sie jedoch in separaten Ordnern in der Build-Ausgabe (z. B. x86 \ und x64 \) enthalten.
Dann wird Ihr Installationsprogramm oder, wie auch immer Sie es verteilen, aktualisiert, damit es die richtige DLL für die Plattform installieren kann, auf der es installiert wird.
Du kannst das nicht so machen, wie du es willst. Sie müssen sich das Attribut DllImport
als Metadaten vorstellen, die zum Zeitpunkt der Kompilierung verwendet werden. Daher können Sie die DLL, die es dynamisch importiert, nicht ändern.
Wenn Sie Ihren verwalteten Code auf "Beliebige CPU" richten möchten, müssen Sie entweder die 32-Bit- und die 64-Bit-Bibliotheken als zwei verschiedene Funktionen importieren, die Sie abhängig von der Laufzeitumgebung aufrufen oder verwenden können zusätzliche Win32-API-Aufrufe, um die korrekte Version der nicht verwalteten Assembly zur Laufzeit zu laden und zusätzliche Win32-Aufrufe, um die erforderlichen Methoden auszuführen. Der Nachteil besteht darin, dass Sie keine Kompilierzeitunterstützung für irgendeine Art von Code für die Typensicherheit usw. haben.
Hmm, ich frage mich, ob Sie eine Schnittstelle und dann eine Klasse mit den Methoden basierend auf den 32-Bit- und 64-Bit-DLLs erstellen könnten.
Ich bin mir nicht sicher, ob es eine explizite Methode gibt, um festzustellen, ob Sie 64 Bit ausführen, aber Folgendes könnte funktionieren: Erlauben unsicheren Code und haben eine unsichere Funktion, die einen Zeiger auf eine Adresse erhält und dann bestimmt, ob der Zeiger ist 4 oder 8 Bytes groß. Basierend auf dem Ergebnis bestimmen, welche Implementierung der Schnittstelle zu erstellen.
Sie können bestimmen, ob Sie 64Bits ausführen oder nicht, indem Sie die Größe des IntPtr-Typs überprüfen (der sowieso als nativer Int-Typ bezeichnet wird). Anschließend können Sie die entsprechende DLL mithilfe eines importierten LoadLibraryW-Aufrufs laden, den Funktionszeiger mithilfe von GetProcAddress abrufen und dann Marshal.GetDelegateForFunctionPointer
Das ist nicht annähernd so kompliziert, wie es aussehen könnte. Sie müssen DllImport sowohl LoadLibraryW und GetProcAddress.