1 / 38

Migration und Nutzung von vorhandenem Code Interoperability

Migration und Nutzung von vorhandenem Code Interoperability. Migration und Nutzung von vorhandenem Code Interoperability. Bernd Marquardt Software & Consulting berndm@go-sky.de. Agenda. Das Problem des „alten“ Codes Einführung Interop-Möglichkeiten DLL‘s COM ActiveX Wrapper-Klassen

glenys
Download Presentation

Migration und Nutzung von vorhandenem Code Interoperability

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Migration und Nutzung von vorhandenem CodeInteroperability

  2. Migration und Nutzung von vorhandenem CodeInteroperability Bernd Marquardt Software & Consulting berndm@go-sky.de

  3. Agenda • Das Problem des „alten“ Codes • Einführung • Interop-Möglichkeiten • DLL‘s • COM • ActiveX • Wrapper-Klassen • Unmanaged Code ruft managed Code auf • Migration • Zusammenfassung

  4. Einführung • Grundsätzlich gibt es im Moment in der Windows-Welt zwei Arten von Code: • Unmanaged Code (Die „alte“ Welt) • „Alter“ x86-Maschinencode • Wird sofort ausgeführt • Managed Code (Die .NET-Welt) • „Neuer“, maschinenunabhängiger IL-Code • Wird zur Laufzeit in Maschinencode übersetzt und ausgeführt

  5. Einführung • In beiden Welten gibt es unterschiedliche „Codesorten“: • Unmanaged: Clients (EXE), DLL‘s mit API‘s, COM-Komponenten (als DLL und als EXE), ActiveX-Komponenten, „normale“ Klassenbibliotheken • Managed: Clients (EXE), .NET-Komponenten

  6. Einführung • In den Code der „alten“ Welt wurde sehr viel Geld investiert • Es ist unmöglich, in kurzen Zeit alles wieder neu für .NET zu programmieren • Welche Möglichkeiten gibt es in .NET, mit „altem“ Code weiterzuarbeiten?

  7. Einführung • Was macht die gemeinsame Nutzung von .NET und unman. Code schwer? • Monolithischer Code („eine EXE“) • Was macht die gemeinsame Nutzung von .NET und unman. Code leicht? • Aufteilung des gesamten Projektes in kleine Einheiten (Client, DLL‘s, COM- und ActiveX-Komponenten)

  8. DLL (API) aus man. Code • Unmanaged DLL‘s mit Attribut „DllImport“ [DllImport („Kernel32.Dll“)] public extern static void Sleep(uint uiMSec); [DllImport („Kernel32.Dll“, EntryPoint = „Sleep“)] public extern static void Schlaf(uint uiMSec); [DllImport („User32.Dll“, CharSet = CharSet::Ansi)] public extern static void MessageBox(int hWnd, string strMsg, string strTitel, uint uiFlags);

  9. Beispiel für Standard-Marshaller • Methode in einer Standard-DLL • Einfache Deklaration erfordert u.U. spezielle Dekodierung • “Maßgeschneiderte” Versionen möglich int SomeFunc(int sel, void* buf, int size); [DllImport("some.dll")]static extern int SomeFunc(int sel, [MarshalAs(UnmanagedType.LPArray)] byte[] buf, int size); [DllImport("some.dll", EntryPoint="SomeFunc")]static extern int SomeFunc_String(int sel, StringBuilder sb, int size); [DllImport("some.dll", EntryPoint="SomeFunc")]static extern int SomeFunc_Int(int sel, ref int i, int size);

  10. Array als Referenzparameter // Originaldeklaration der Library-Funktion// int f(int** ppArray, int* pSize);[DllImport("PInvokeLib.dll")]public static extern int f(ref IntPtr array, ref int size);// Unmanaged Speicherbereich anlegenIntPtr buffer = Marshal.AllocCoTaskMem( Marshal.SizeOf(size) * array2.Length);// Daten in Speicherbereich kopierenMarshal.Copy(array2, 0, buffer, array2.Length); int res = f(ref buffer, ref size); int[] arrayRes = new int[size]; // Daten zurückkopierenMarshal.Copy(buffer, arrayRes, 0, size);// Unmanaged Speicherbereich freigebenMarshal.FreeCoTaskMem(buffer);

  11. DLL (API) aus man. Code • System-DLL‘s und eigene DLL‘s können aufgerufen werden • Typ-Konvertierungen der Standardtypen werden automatisch gemacht • Aufruf ist etwas langsamer, als aus unmanaged Code • Interfaces als Parameter werden unterstützt • Können nicht als Ausgabeparameter dienen • Arrays von Basistypen können benutzt werden • Attribute steuern Konvertierung

  12. DllImport – wann nicht? • Beispiel: char* DoSomething(...) [DllImport („TheSuperLib“)] extern „C“ String* DoSomething(...); • Problem hier: • Der Speicher, auf den der Zeiger zeigt, kann nicht freigegeben werden

  13. DLL (API) aus man. Code • Zweite Methode: IJW = „It just works“ • Geht nur mit managed C++ Extensions • Benötigte C/C++-Header-Datei muss eingefügt werden • Z.B.: #include <stdio.h> • Aufruf der API-Funktionen ist jetzt möglich

  14. DLL (API) aus man. Code • Vorteile von „IJW“: • Kein „DllImport“ erforderlich • Geringfügig schneller • Bei Aufruf mehrerer unmanaged API‘s: Die Daten müssen nur einmal „gemarshalled“ werden

  15. COM aus man. Code • Erzeugung eines Runtime-Callable-Wrappers (RCW) durch .NET Unmanaged Code Managed Code Runtime Callable Wrapper COM-Objekt Managed Client

  16. COM aus man. Code • Wrapper von Hand erzeugen mit: • TblImp.EXE • Wrapper automatisch erzeugen mit: • Visual Studio .NET • Befehl „Add Reference“ • Ist in vielen Fällen ausreichend • Datenkonvertierung findet statt • Z.B.: String nach BSTR • Geht nicht bei Custom Marshaling

  17. COM aus man. Code • Problem bei der Benutzung der COM-Komponenten: • Durch den Garbage Collector von .NET wird die COM-Komponente nicht „sofort“ freigegeben • Das kann zu unerwartetem Verhalten führen • Lösungen: • Aufruf von System.GC.Collect (nicht gut!) • Aufruf von System.Runtime.InteropServices.Marshal. ReleaseComObject

  18. Rückgabewerte und Exceptions • COM meldet Fehler via Result-Code zurück • .NET-Methoden werfen Exceptions • Runtime setzt Konzepte ineinander um • HRESULT gibt Fehlerklasse an • Zusätzliche Informationen werden via IErrorInfo erhalten • Ein COM-Objekt sollte dieses Interface implementieren

  19. Early und Late Binding • Early Binding: Objekterzeugung mit „new“ • Late Binding: (IDispatch) • Benutzung von Type.GetTypeFromProgID, Activator.CreateInstance und Type.InvokeMember • Parameterübergabe in einem Array

  20. Aufruf eines COM-Servers (late) namespace LateBoundClient { using System.Reflection;...Type typ;Object obj;Object[] prms = new Object[2];int r; typ = Type.GetTypeFromProgID(„MyLib.MyServer"); obj = Activator.CreateInstance(typ);prms[0] = 10; prms[1] = 150; r = (int)typ.InvokeMember(„aMethod", BindingFlags.InvokeMethod, null, obj, prms); ... }

  21. Wrapper-Klassen • Managed Wrapper-Klassen umhüllen eine normale unmanaged C++-Klasse • Die Hüllklasse funktioniert wie ein Proxy • Die Hüllklasse hat die gleiche Funktionalität wie die C++-Klasse • Es wird immer ein „Klassenpaar“ erzeugt, bzw. zerstört

  22. Wrapper-Klassen __gc class ManClass { public: // Konstruktor ManClass() { m_pC = new CppClass(); } // Freigabe ~ManClass() { delete m_pC; } // Methoden void managed_f() { m_pC->native_f(); } private: CppClass * m_pC; }; class CppClass { public: // Konstruktor CppClass() { …} // Destruktor ~CppClass() { …} // Methoden void native_f() { …} };

  23. Wrapper-Klassen • Erzeugung von Wrapper-Klassen • Erzeugung einer man. C++-Klasse • Data member: Zeiger vom Typ der C++-Klasse • In der managed Klasse müssen die Konstruktoren nachgebildet werden • In der Dispose-Methode der managed Klasse die Instanz der unmanaged Klasse zerstören • Alle Methoden in der managed Klasse implementieren

  24. Wrapper-Klassen • Destruktoren • Sowohl den Destruktor als auch die Dispose-Methode implementieren • Wrapper-Klasse von IDisposable ableiten • „Selbst-gesteuertes“ Zerstören des Objektes durch Dispose-Aufruf • Dispose vergessen: Garbage Collector schlägt mit dem Destruktor zu • System.GC.SupressFinalize in der Dispose-Methode nicht vergessen

  25. Probleme mit Wrappern • Variable Parameteranzahl • Daten-Marshaling • Default Argumente • Destruktoren (Garbage Collector) • Properties • Vergleichsoperatoren mit Overloading

  26. .NET-Code aus unman. Code • Man kann .NET-Komponenten aus altem Code aufrufen • CCW = COM Callable Wrapper • using System.Runtime.InteropServices; • Attribut [ClassInterface(ClassInterfaceType.AutoDual)] vor der Klasse definieren • Assembly in das Verzeichnis des Clients kopieren • TypeLib mit TLBEXP erzeugen • Registrieren mit REGASM

  27. Migration: Grundsätzliche Überlegungen • Es gibt verschiedene Arten von Code • Algorithmen • API-intensiver Code • MFC-intensiver Code (UI-Code) • ATL-intensiver Code (COM/DCOM) • Alle Codearten erfordern einen anderen Migrationsaufwand

  28. Grundsätzliche Überlegungen • Was erschwert eine Migration? • Monolithischer Code • Die Verwendung von Klassen-Bibliotheken • Besonders dann, wenn die Klassen als Code in das Projekt aufgenommen wurden  Später: Wrapper-Klassen • Viel UI-Code • Templates (Generische Datentypen) • Multiple Inheritance

  29. Grundsätzliche Überlegungen • Was erschwert eine Migration? • Klassen, welche im Destruktor die Resourcenverwaltung implementiert haben (Thema: Garbage Colletion) • Code, der intensiv mit Zeigern arbeitet • Code mit vielen API-Aufrufen

  30. Grundsätzliche Überlegungen • Was erleichtert die Migration? • Komponenten-orientierter Code • Mehrschichtiges Applikations-Design • Wichtig ist eine gute Trennung von UI und Business-Logik • Code in COM-Komponenten ist nützlich • Code in DLL‘s ist nützlich

  31. Grundsätzliche Überlegungen • Eine Migration sollte nach Möglichkeit in mehreren kleinen Schritten durchgeführt werden • Was kann zunächst ohne Migration wiederverwendet werden? • COM-Komponenten • Windows-DLL‘s • Der erste Schritt soll kurz sein! • COM-Komponenten und DLL‘s sind aber auch am leichtesten zu portieren

  32. Grundsätzliche Überlegungen • Komplexe Codeteile zunächst einmal als unmanaged Code übernehmen • „Unsaubere“ Codeteile in managed Code portieren • Resourcen-intensive in managed Code portieren (Ausnutzung des Garbage Collectors)

  33. Grundsätzliche Überlegungen • Vor der Migration: • Test- Szenarien mit der „alten“ Applikation generieren • Während der Migration kann immer wieder vergleichend getestet werden • Migrieren Sie keine Projekte, die im Moment in der Entwicklungsphase sind

  34. Zusammenfassung • Microsoft hat viel für die Interoperabilität von “altem” und .NET-Code getan • Die Investitionen werden weitgehend geschützt • Eine Applikation kann Schritt für Schritt migriert werden • Wichtig: Komponenten müssen vorhanden sein

  35. Questions and Answers

  36. Further Information • Microsoft Visual C++ .NET Compiler Migration Guidehttp://www.gotdotnet.com/team/cplusplus/articles/compmig.doc • Managed Extensions for C++ Migration Guidehttp://www.gotdotnet.com/team/cplusplus/articles/mcmigrate.doc

  37. Glossary • Managed Code: Code, der unter der Kontrolle der .NET-Common Language Runtime läuft. • Unmanaged Code: Prozessor-abhängiger Maschinencode. • CLR: Common Language Runtime; gemeinsame Runtime für alle .NET-Sprachen. • GC: Garbage Collector; verwaltet den Speicher bei .NET-Anwendungen; zerstört bei Bedarf die nicht mehr referenzierten Objekte im Speicher. • (MS-) IL-Code: Microsoft Intermediate Language; Platform-unabhängiger Zwischencode, der von den .NET-Sprach-Compilern erzeugt wird; wird vom JIT-Compiler zur Laufzeit in nativen Maschinencode übersetzt. • JIT-Compiler: Just In Time-Compiler; übersetzt zur Laufzeit den MS-IL-Code in native Maschinensprache. • ILDASM: Tool zum Anschauen des MS-IL-Codes in einer .NET-EXE-Datei. • RCW: Runtime Callable Wrapper; Wrapper-Klasse, die den Aufruf von „unmanaged“ COM-Komponenten aus „managed“ Code ermöglicht

  38. Ihr Potenzial. Unser Antrieb.

More Related