myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Rund um die Programmierung » 32bit/64bit unmanaged DLL "importen" - wie?
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

32bit/64bit unmanaged DLL "importen" - wie?

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
myCSharp.de
Moderationshinweis von herbivore (11.06.2012 10:32):

Dies ist ein Thread, auf den aus der FAQ verwiesen wird. Bitte keine weitere Diskussion, sondern nur wichtige Ergänzungen und diese bitte knapp und präzise. Vielen Dank!
 
CaptainIglo
myCSharp.de-Mitglied

Dabei seit: 09.02.2005
Beiträge: 366
Entwicklungsumgebung: VS 2005 Pro / TS + VS 2008
Herkunft: Feldkirch - Österreich


CaptainIglo ist offline MSN-Passport-Profil von CaptainIglo anzeigen

32bit/64bit unmanaged DLL "importen" - wie?

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo,

habe hier ein Project in welchem ich eine externe C++-dll verwende, welche in der 32bit und 64bit Variante vorliegt (32bit geht unter 64bit nicht) und per DllImport verwednet wird.

Kann ich meiner Anwendung irgendwie sagen, dass sie anstatt "xyz.dll", je nach System "x32\xyz.dll" bzw. "x64\xyz.dll" lädt?

mfg
Capt.Iglo
28.03.2009 14:07 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Timur Zanagar Timur Zanagar ist männlich
myCSharp.de-Mitglied

avatar-3412.jpg


Dabei seit: 10.11.2004
Beiträge: 1.457


Timur Zanagar ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo CaptainIglo,

Wenn dein Projekt via AnyCPU kompiliert wird, dann IMHO garnicht. Du müsstest zwei Konfigurationen anlegen und via DllImport je nach Konfiguration die eine oder andere DLL miteinbinden.
28.03.2009 15:06 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegen mehr als 3 Jahre.
gfoidl gfoidl ist männlich
myCSharp.de-Team

avatar-2894.jpg


Dabei seit: 07.06.2009
Beiträge: 6.659
Entwicklungsumgebung: VS 2019
Herkunft: Waidring


gfoidl ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo zusammen,

nachfolgender Vorschlag bezieht sich auf unmanaged (od. native) DLLs.

Zitat:
Kann ich meiner Anwendung irgendwie sagen, dass sie anstatt "xyz.dll", je nach System "x32\xyz.dll" bzw. "x64\xyz.dll" lädt?

Statt x32 wird üblicherweise x86 verwendet, aber das ändert nichts an der Lösung.

Die Suchreihenfolge für native DLLs ist:

Zitat von Dynamic-Link Library Search Order (Windows):
  1. The directory from which the application loaded.
  2. The system directory.
  3. The Windows directory.
  4. The current directory.
  5. The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.

Davon können wir Punkt 4 und 5 beeinflussen. Punkt 4 ist aber nicht sicher, da nicht garantiert ist, dass dieses Verzeichnis während der Lebensdauer des Prozesses nicht geändert wird. D.h. wir müssen den Weg über die Umgebungsvariable PATH gehen.

Beispielsweise so:

C#-Code:
string path = Environment.GetEnvironmentVariable("PATH") ?? string.Empty;
string dllDir = System.IO.Path.GetDirectoryName(typeof(NativeMethods).Assembly.Location);

if (Environment.Is64BitProcess)
    dllDir = System.IO.Path.Combine(dllDir, "x64");
else
    dllDir = System.IO.Path.Combine(dllDir, "x86");

path += ";" + dllDir;

Environment.SetEnvironmentVariable("PATH", path);

Da in Environment.SetEnvironmentVariable kein EnvironmentVariableTarget angegeben wurde, gilt diese Umgebungsvariable nur für den aktuellen Prozess.

Dieser Code sollte ausgeführt werden, bevor erstmals auf eine mit DllImport versehenen Methode zugegriffen wird. Z.B. in im Einstiegspunkt des Prozesses (Main) od. im statischen Konstruktor der (wie im Beispiel) NativeMethods-Klasse.

Das .net-Projekt ist mit der Konfiguration "Any CPU" zu erstellen.

Wenn das Ganze auch für NuGet verwendet werden soll, so ist es praktisch sich Microsoft.SqlServer.Compact als Vorlage zu nehmen. Die Script-Files im tools-Ordner sind entsprechend anzupassen.


Managed DLLs (also .net-DLLs) sollten idealerweise mit der Konfiguration "Any CPU" erstellt werden, da für die CLR nur die Bittigkeit der EXE von Bedeutung ist. D.h. wenn die EXE 32bit ist, so wird von der CLR die DLL auch als 32bit behandelt. Für 64bit analog. Für fremde DLLs muss die Bittigkeit der EXE zu jener der DLLs passen, andernfalls erhält man zur Laufzeit eine  BadImageFormatException. Siehe hierzu auch  BadImageFormatException bei Verwendung einer Assembly.
Bei managed DLLs macht es keinen Sinn eine 32bit- und eine 64bit-Version anzubieten und diese zur Laufzeit entsprechend einzubinden, da bei managed DLLs Any CPU die bessere Wahl ist.

mfG Gü

Speedski, nativ, native, DLL, unmanaged, DllImport, 32bit, 64bit, 32/64, 32/64bit
08.06.2012 13:53 Beiträge des Benutzers | zu Buddylist hinzufügen
Mr. Bart Simpson Mr. Bart Simpson ist männlich
myCSharp.de-Mitglied

avatar-3273.gif


Dabei seit: 13.03.2004
Beiträge: 501
Herkunft: Mittelfranken


Mr. Bart Simpson ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Nur als Ergänzung: Das Laden von nativen DLLs lässt sich auch mit einem anderen Ansatz lösen - ohne setzen von Path-Variablen etc.
Folgende Vorgehensweise ist dafür nötig:

a) Native Windows Calls einbinden

C#-Code:
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadLibraryEx(string dllFilePath, IntPtr hReservedNull, LoadLibraryFlags dwFlags);

[DllImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FreeLibrary(IntPtr hModule);

[DllImport("Kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

b) den Pfad zur richtigen Dll bestimmen (ggf. abhängig von Environment.Is64BitProcess)
c) die DLL laden und den Zeiger darauf merken

C#-Code:
LoadLibraryEx("FullPathToLibrary.dll", IntPtr.Zero, LoadLibraryFlags.LOAD_WITH_ALTERED_SEARCH_PATH)

d) Für jede benötigte Funktion jeweils den Einsprungpunkt holen und einen entsprechenden Delegate darauf erezugen lassen

C#-Code:
private static TDelegate GetFunctionDelegate<TDelegate>(IntPtr dllHandle, string functionName)
           where TDelegate : class
        {
            IntPtr function = NativeCalls.GetProcAddress(dllHandle, functionName);
            var funcPointer = Marshal.GetDelegateForFunctionPointer(function, typeof(TDelegate));
            return funcPointer as TDelegate;
        }

TDelegate muss dafür definiert sein als Delegate mit der Signatur der zu importierenden Funktion.
Am Ende kann die DLL dann auch noch mit FreeLibrary wieder freigegeben werden.

Vorteile hiervon:
  • Es wird alles dynamisch geladen
  • Der Pfad zur DLL kann frei angegeben werden (ohne PATH-Variable und andere Unwägbarkeiten)
  • Der Zeitpunkt des Ladens (und Entladens) der DLL kann exakt bestimmt werden
  • Es ist (wenn nötig) möglich die aufzurufenden Methoden dynamisch zu bestimmen (Zugriff via String, der den Namen enthält)
  • Verschiedene Funktionen mit gleicher Signatur können über den selben Delegate-Typ importiert werden (keine mehrfachen Importe via DllImport-Attribut nötig)
Nachteil: Mann muss einiges "von Hand lösen" - z.B. via Marshal.GetLastWin32Error() immer die nativen Calls überprüfen und das Ergebnis ggf. in eine ".net-konforme" Exception packen, was beim "normalen" DllImport schon automatisch mit dabei ist.

Bart Simpson
11.06.2012 10:02 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 11 Jahre.
Der letzte Beitrag ist älter als 8 Jahre.
Antwort erstellen


© Copyright 2003-2020 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 14.08.2020 18:10