Hallo zusammen,
ich bin mir gerade nich sicher wonach ich Suchen soll. Ich wollte mal in Erfahrung bringen ob es möglich ist die Anzahl von Parametern aus einer DLL Methode zu bekommen?
Ich habe folgenden Code
public class MyClass
{
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern IntPtr LoadLibrary(string library);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string methodName);
public void LoadDll()
{
IntPtr module = LoadLibrary("myDll");
// Fehler behandlung wenn DLL nicht gefunden wurde
if (module == IntPtr.Zero)
{
return $"Could not load library: {Marshal.GetLastWin32Error()}";
}
IntPtr dllMethod = GetProcAddress(module, "myFunction");
// Fehler behandlung wenn Methode in der DLL nicht gefunden wurde
if (dllMethod== IntPtr.Zero)
{
return $"Fehler beim Laden der DLL Methode { Marshal.GetLastWin32Error() }";
}
// Hier möchte ich nun abfragen wieviel Parameter in der dll Methode "myFunction" vorhanden sind.
}
}
Freue mich auf eine Antwort 🙂
Das ist technisch nicht möglich. Die Parameter von nativen (z.B. in C oder C++ geschriebenen) Funktionen werden über den Stack (welches einfach nur ein Byte-Array darstellt) übergeben und ausgelesen. Genausowenig ist es daher möglich die genauen Datentypen der Parameter abzufragen, ohne den Code zu kennen. Daher ist es zur Verwendung zwingend nötig, die genaue Signatur der Funktion zu kennen.
Anders sieht es bei .NET aus, da diese mittels Reflection erfragt werden können.
Wenn du wirklich ein Plugin System bastelen möchtest, dann solltest du dir noch mal Gedanken über dein Konzept machen. So wie das aktuell ist, kann es nur nach hinten losgehen.
Dein Plugin sollte eine Schnittstelle haben, die das Programm, welches das Plugin nutzen möchte eindeutig versteht. Das kann man Besten über ein Interface machen, das dein Plugin implementiert und dein Programm laden kann. Dann musst auch nicht mehr die Parameter herausfinden, da alles mit einer eindeutigen Schnittstelle bekannt sein sollte für beide Seiten.
Hier noch etwas ausführlicher:
Erstellen einer .NET Core-Anwendung mit Plug-Ins - .NET
Danke für die Antworten.
@ClaraSoft
Hättest du hier mal ein Beispielprogramm? Kann mir das ehrlich gesagt noch nicht so richtig vorstellen.
Steht alles im Link beschrieben, den ich gepostet habe.
Das funktioniert aber nur für .NET-Assemblies, nicht für native DLLs.
Oder ist "myDll"
gar keine native DLL und du hast nur die falsche Methode zum Laden benutzt?
Mal angemerkt, selbst wenn man rausfinden könnte wie viele Parameter eine Methode/Funktion hat, weiß man ja immer noch nicht welche das sind.
Würde also nicht sehr viel bringen, denn man hat dann immer noch keinen Hinweis darauf was man da nun übergeben soll.
Wenn du wirklich ein Plugin System bastelen möchtest, dann solltest du dir noch mal Gedanken über dein Konzept machen. So wie das aktuell ist, kann es nur nach hinten losgehen.
Dein Plugin sollte eine Schnittstelle haben, die das Programm, welches das Plugin nutzen möchte eindeutig versteht. Das kann man Besten über ein Interface machen, das dein Plugin implementiert und dein Programm laden kann. Dann musst auch nicht mehr die Parameter herausfinden, da alles mit einer eindeutigen Schnittstelle bekannt sein sollte für beide Seiten.
Hier noch etwas ausführlicher:
>
Ich wollte nochmal nachfragen ob du davon ausgegangen bist das "myDll" eine dll von mir ist?
Wenn ja, ist sie nicht. Sorry für das Missverständniss. Hätte es dann anders benennen sollen. Ich muss damit arbeiten und kann auch nichts an der "myDll" ändern.
MyDll ist eine Fremd Dll auf C bzw. C++ Basis soweit ich weiß.
Dann sollte es dafür doch eine zugehörige Headerdatei (.h
oder .hpp
) geben, in der die Funktionen deklariert sind. Die Aufrufe mußt du dann nur per "Marshalling" nach C# übertragen (also so wie du es bisher auch für die Funktionen LoadLibrary
und GetProcAddress
per DllImport
gemacht hast) - du mußt die DLL also nicht dynamisch laden (außer du willst wirklich ein Plugin-System realisieren, d.h. beliebig benannte DLLs mit einheitlicher Schnittstelle aufrufen zu können).
Ich möchte das ganze eher Dynamisch händeln. Der Grund ist das es mehrere Versionen von der aufzurufenden DLL gibt. Hier muss ich bestimmte Unterscheidungen machen was für eine Version genutzt werden soll. Sonst müsste ich ja jede einzelne DLL als DLL Import definieren. Oder sehe ich das falsch?
Bitte keine Full Quotes.
Das geht nicht dynamisch, irgendwo brauchst Du einen gemeinsamen Stand, anhand dessen Du weißt, wie Du XY aufrufen kannst.
Hast Du diesen gemeinsamen Stand nicht, musst Du wohl oder übel alles einzeln machen.
Oder Du rätst, was es für Parameter gibt, wirst dann aber ziemlich sicher irgendwann den Fall haben, dass Du die richtigen Parameter nicht errätst.
Deshalb sollte man das auch umdrehen:
Nicht dein Programm muss die externe DLL und die Parameter der Methoden kennen, sondern die externe DLL kennt dein Programm.
Dein Programm liefert dafür dann eine Schnittstelle, die die externe DLL nutzt - das ist dein gemeinsamer Stand.
Du könntest also ein Interface definieren, wo die Methode, die Du brauchst, definiert ist und als Parameter wird alles übergeben, was Du bieten kannst/darfst.
Die externe DLL muss dann dieses Interface implementieren und kann dann die Daten so weiter reichen, wie es für die jeweilige Version richtig ist.
Diese Implementierung findest Du dann via Reflection oder einer Art Registrierungs-Interface, was aber auch wieder implementiert und irgendwie gefunden werden muss.
Dein Programm bekommt dann die Implementierung und hat ein eindeutiges Interface zum Aufrufen.
Bei externen DLLs geht das natürlich nicht so einfach, da brauchst Du denn einen Vermittler dazwischen - je Version.
Dieser Vermittler implementiert dein Interface und ruft darin die externe Version auf, der muss dann immer angepasst werden, dein Haupt-Programm bleibt dabei aber unberührt.
Der Vermittler kann in C# oder C++/CLI geschrieben werden, je nachdem, was einfacher ist, hauptsache es kommt eine managed DLL bei raus.
Du kannst natürlich auch unmanaged arbeiten, kannst dann aber nicht mit .NET-Interfaces arbeiten und musst irgendwie anders die native Methode definieren, die dein Programm aufruft.
Der Nachteil ist, dass Du je Version eine zusätzliche DLL brauchst, aber je nach Umfang der externen Methoden ist das nur sehr wenig Arbeit.
Außerdem sehe ich das nicht als Nachteil, sondern als Vorteil, denn Du hast einen einzigen Punkt, den Du anpassen musst und gefährdest dein restliches Programm nicht.
Die könnte man z.B. sogar zur Laufzeit austauschen oder als einzige DLL raus geben, ohne das ganze Programm aktualisieren zu müssen.
NuGet Packages im Code auslesen
lock Alternative für async/await
Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.
Verstehe ich das richtig, daß du daher aufgrund deiner Frage zur Parameteranzahl damit herausfinden möchtest, um welche Version es sich handelt?
Das ist, wie schon geschrieben, so nicht möglich.
Und beim Aufrufen der Funktionen per dynamischen Laden müßtest du ja sowieso Marshal.GetDelegateForFunctionPointer (LOL: "marshal" wird als "Mars Hallen" übersetzt) benutzen und dafür dann je nach Funktionsvariante passende Delegates erzeugen.
Du solltest einfach alle Funktionsvarianten (welche du in deinem Programm auch aufrufen möchtest) per DllImport
erzeugen (ich nehme an, die DLL hat immer denselben Namen). Du mußt dann nur in deinem Programm eine passende Logik einbauen, welche die verschiedenen Versionen erkennt (evtl. die Datei-Info auslesen?) und dementsprechend dessen Funktionsvarianten aufruft.
Warum gibt es überhaupt verschiedene Versionen der DLLs, die dein Programm unterstützen soll?
Sonst müsste ich ja jede einzelne DLL als DLL Import definieren. Oder sehe ich das falsch?
Mir ist auch immer noch völlig unklar, was Du tun willst; was Du mit dynamisch meinst.
Soll Deine Anwendung einfach prinzipiell verschiedene Versionen einer Abhängigkeit unterstützen, oder sollen diese auch noch dynamisch während der Laufzeit ausgetauscht werden?
Beides ist prinzipiell (mit unterschiedlichem Aufwand) umsetzbar; aber in allen Fällen würde man das nicht versuchen mit schwarzer Magie sondern mit strukturierten Vorgehen lösen wollen.
Fixe Version während der Runtime: kann man über eine klassische 0815 Pluginstruktur lösen.
Austausch während der Runtime: in .NET Core 3+ / .NET 5 gar nicht so einfach zu lösen, da es keine App Domains mehr gibt; der AssemblyLoadContext bietet aber grundlegende Funktionen dafür an.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code