Step-by-Step into the cloud

a blog of Dirk Eisenberg (>)
posts - 81, comments - 15, trackbacks - 17

My Links

News

Article Categories

Archives

Post Categories

Image Galleries

Blogs

Projects

Der managed P/Invoke Mediator

Nach dem letzten Blog meines gleichgesinnten Kollegens hat mich das Thema P/Invoke nicht mehr los gelassen. Ich ging nur mit einer etwas anderen Einstellung in das Thema. Mein Programmche soll nicht die File Redirection von %systemroot%\system32 nutzen. Nein ich will keine Forwarder-Library in das System32-Directory kopieren. Zustimmung erhält aber trotzdem das Mediator.Prinzip. Dieser Mediator bestimmt welche native DLL geladen wird. Im Fall von 64Bit Windows wäre das die 64Bit-Dll, im Fall von 32Bit Windows die 32Bit-Dll und im Falle von Windows CE und dem Compact Framework eine andere.

Mein Ziel ist aber die gesamte Distribution meiner Software in %ProgramFiles%\MySoftware zu handeln und eine foo.dll für 32Bit Windows, eine foo64.dll für 64Bit Windows und eine fooCe.dll für Windows CE zu halten.

Versuch Nummer 1:

Bendenkt man das Attribute in .NET nur Klasse abgeleitet von System.Attribute sind, liegt die Idee nah das DllImportAttribute erneut abzuleiten und im Property-Handling für den DllName die Logik für die Namens-Nomenklatur zu Implementieren. Leider macht das kleine aber wichtige Schlüsselwort sealed einen Strich duch die Rechnung. Damit sorgt das .NET Framework das keine weitere Ableitung von dieser Klasse möglich ist. Der nächste Versuch war irgendeine Art Logik hinter den DllName zu hängen. Leider unterstützt auch hier das .NET Framework nur konstante Parameter-Werte in Attributen. Also auf zu neuen Ufern.

Versuch Nummer 2:

Verfolgt man das Mediator-Konzept weiter, will aber keine eigene Forwarder-Dll schreiben, ist vielleicht folgendes Konzept hilfreich. Für jede unterstützte Plattform wird eine DllImportHelper-Klasse implementiert. Diese kapselt lediglich das Marshaling und die DllImport-Anweisung. Um den Zugriff auf die richtige Helper-Klasse zu realisierien wird eine Schnittstelle zur Verfügung gestellt. DieseDllImport-Klasse orchestriert den Zugriff auf die korrekte Helper-Klasse. Je nach aktueller Plattform wird die entsprechende Methode aus der korrekter DllImport-Helper-Klasse aufgerufen.

Vorteile:

  • Das Mediator-Konzept wurde beibehalten und das Assembly kann einfach um weitere Plattformen erweitert werden. Baut man das Konzept aus, so ist eine Erweiterung für neue Platformen in reinem Managed-Code ohne Veränderung des aufrufenden Codes möglich.
  • Die Verwaltung einer extra Forwarder-Dll entfällt.
  • Die Applikation muss keine Libraries in %systemroot%\system32 ablegen.

Nachteil:

  • Die Bestimmung der aktuellen Platform kostet extra Zeit und verlangsamt den Sprung in den native Code nochmals.
  • Es muss für jede Platform eine extra Klasse im Assembly gehalten werden aber kein zweites Assembly.

Ein einfaches Beispiel ist hier hinterlegt. Dieses Beispiel soll nur illustrieren wie das prinzipielle Vorgehen ist und wurde nicht für den produktiven Einsatz vorgesehen.

64Bit Runtime Check:

Wie findet der geneigte Entwickler in C# heraus ob sich der Prozess gerade als 64Bit bzw. 32Bit-Prozess läuft. Leider ist festzustellen das Microsoft in seinem Environment-Objekt keine passable Lösung für das Problem vorrätig hat. Folgende Lösung stammt aus diesem Blog und hier findet man wie es nicht gemacht werden sollte. Unter C# ist ein int-Datentyp immer 32Bit lang, egal ob 64Bit-Prozess der 32Bit-Prozess aber der IntPtr ist je nach Prozess-Art 32Bit oder 64Bit lang.

bool bIs64Bit = (sizeof(IntPtr) == 8 )

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

Print | posted on Sunday, March 05, 2006 7:06 PM | Filed Under [ .NET Coding Coding ]

Feedback

Gravatar

# re: Der managed P/Invoke Mediator

Dieser Mist nimmt keine Kommentare mehr an dabei habe ich extra mühsam einen etwas längeren verfasst ;-(
3/9/2006 8:53 PM | Stefan
Gravatar

# re: Der managed P/Invoke Mediator

OK, verteile ich's eben auf kleinere Häppchen:

So, ich habe mir das jetzt mal angeschaut. Und ich halte den P/Invoke-Mediator

fuer eine denkbar schlechte Lösung, aus folgenden Gründen:

1. Er versucht ein sehr spezifisches Problem (das einzigartige Zwitterverhalten

von .NET-Assemblies auf x64 Windows) auf allgemeine Art zu lösen. Sowas macht man

aber auch nur bei allgemeinen Problemen, die auch immer wieder auftauchen. Das

angeführte Beispiel mit Erweiterung für Windows CE ist völlig irrelevant, weil es

unter CE dieses Problem, genauso wie unter x86-Windows gar nicht gibt. x64 und

sein sonderbares Verhalten ist schließlich der *Ausnahmefall*, nicht die Regel,

lassen wir doch da mal die Kirche im Dorf. Unter CE würde ich beispielsweise die

Sourcen von foo nehmen und den Linker anweisen, daraus für die jeweilige

Target-CPU immer eine foofwd.dll zu erzeugen und fertig.

3/9/2006 8:59 PM | Stefan
Gravatar

# re: Der managed P/Invoke Mediator

4. Das alles ist mit sehr viel mehr Aufwand verbunden bei der Erweiterung wie bei einer native Forwarder DLL, wo einfach eine Zeile im def file ergänzt wird und gut ist's. Hier muss ich bei einem neuen Export der native DLL (n+1) neue Methoden dem Assembly hinzufügen, wobei n=Anzahl der Plattformen. Hier ist auch Punkt 2 oben von Relevanz. Und jetzt stell Dir mal vor, man hat auf diese Art und Weise schon tonnenweise Code erzeugt und es geht irgendwann um die Frage: "Was müssen wir tun, damit wir die neue Plattform <Windows für Klobürste 2013> unterstützen. Die Antwort der Entwickler wird unisono lauten: "Wir müssen circa 63 Assemblies um P/Invoke-Code ergänzen für unsere native <Windows für Klobürste 2013>-DLLs und überall deren P/Invoke-Mediator ergänzen und alles durchtesten!"

Und das alles, bloss weil es damals im Jahr 2005 so ein OS gab, auf dem sich die damalige .NET-runtime so merkwuerdig verhielt... Stimmt denn bei dem Aufwand ein Projektverantwortlicher noch der Unterstützung von <Windows für Klobürste 2013> zu? Du siehst, das ist auch ein psychologisches Problem das man sich mit der fehlenden Skalierung dieses Ansatzes schafft.
3/9/2006 9:01 PM | Stefan
Gravatar

# re: Der managed P/Invoke Mediator

Ich halte die Lösung mit der forwarder DLL für diesen einmaligen Spezialfall x64 für wesentlich besser, weil damit die jeweilige Umgebung besser und eleganter verstanden ist und das Ganze auch performanter ist. Anstatt dann aber die x64-forwarder DLL nach %systemroot%\system32 zu kopieren, könnte man sie auch in ein Unterverzeichnis unter dem Installationsverzeichnis kopieren und beim Start des .NET-Prozesses unter x64 dessen Kopie der Umgebungsvariable %PATH% um dieses Verzeichnis ergänzen. Wäre halt damit eine Lösung für einen Spezialfall. Keine Ahnung ob das geht, aber das würde den Schrecken (duh!) vom Kopieren nach %systemroot%\system32 nehmen.

Trotzdem ist der .NET P/Invoke Mediator ein akademisch interessantes Thema und es ist gut, so ein Thema von allen Seiten zu beleuchten, bevor man im grossen Stil eventuell in eine Sackgasse rennt.

Aber hey, who am I to judge, bin ich etwa Softwarearchitekt ;-)

3/9/2006 9:02 PM | Stefan
Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification:
 
 

Powered by: