Veröffentlicht: 28. Feb 2003 | Aktualisiert: 23. Jun 2004
Von Alexander Wechsler
Mit der neuen Version Visual Studio 2003 erschließ;en sich Entwicklern neue Möglichkeiten, bereits existierende ActiveX Controls auf einfache Weise für .NET-basierte Anwendungen wieder zu verwenden.
Auf dieser Seite
Los geht's - wie kommt das ActiveX Control auf das Formular?
Was passiert im Hintergrund?
Auswirkungen von ActiveX Controls auf die .NET Anwendung
Verwendung des ActiveX Controls im Formularcode
Arbeiten mit Ereignissen aus dem ActiveX Control
Transparente ActiveX Controls
Zusammenfassung
Grafische Komponenten haben seit geraumer Zeit die Erstellung von Benutzerinterfaces in Anwendungsentwicklung revolutioniert. Mit ihrer Hilfe war es möglich die Programmierung von Oberflächen für Rich-Client Systeme schnell und effizient wie aus einem Baukastensystem durchzuführen. Nicht zuletzt der Erfolg von RAD-Entwicklungstools wie Visual Basic und Borland Delphi beruht auf diesem Ansatz. Zudem entstand ein einträglicher Markt für Hersteller solcher Bausteine, die über Jahre hinweg immer neue, verbesserte Versionen ihrer Grids, Gauge-Controls und Bildbearbeitungskomponenten zur Verfügung stellen konnten.
"Build or buy" ist eines der daraus entstandenen Schlagworte unserer Branche. Begonnen hat dies unter Windows mit den 16 Bit VBX-Controls, die dann die Wandlung hin zu den 32-bit OCX- und ActiveX-Controls erfahren haben. An der Spitze dieser Evolution stehen im Bereich der Microsoft Technologien derzeit die Windows.Forms Controls als Teilmenge des allumfassenden .NET Frameworks.
Mit Visual Studio .NET 2002 war es natürlich möglich auch ActiveX Controls im eigenen Code über die COM-Interop Mechanismen zu verwenden. Man hatte jedoch nur Zugriff auf deren Methoden und Eigenschaften, nicht auf die grafische Darstellung. Die Platzierung eines ActiveX Controls auf einem .NET Windows.Forms Formular war leider bisher nicht möglich!
An dieser Stelle schafft Visual Studio .NET 2003 Abhilfe. Mittels geeigneter Wrapper-Klassen sorgt es dafür, dass auch ActiveX-Controls nahtlos im Formular gehostet werden können.
Die dadurch entstehenden Vorteile und der Funktionalitätsgewinn sind enorm. Gerade bei der Migration älterer Anwendungen in die .NET-Infrastruktur müssen nicht mehr schon funktionierende als ActiveX-Control vorliegende Module neu programmiert werden, sondern können - so wie sie sind - wieder verwendet werden. Dies schützt bereits getätigte Investitionen und minimiert den Migrationsaufwand, da gerade die Erstellung anspruchsvoller und hochfunktionaler Benutzeroberflächen nach wie vor einen groß;en Anteil am Projekt-Gesamtaufwand beansprucht.
Ein rundes Bild ergibt sich auch, wenn man für die Migration der Anwendung eine Art evolutionären Ansatz wählt. Das heiß;t, die alten Teile der Applikation bleiben wenn möglich unverändert, nur Neuerungen oder grundlegende Änderungen werden in neuer .NET Technologie umgesetzt. Hier schließ;t die Wiederverwendung der grafischen Controls für die Präsentationsschicht eine Lücke zwischen den beiden Welten. Man kann sich auf diese Weise für die Weiterentwicklung der Anwendung die Rosinen aus beiden Bereichen herauspicken und kommt so schneller und budgetfreundlicher zum Ziel.
Los geht's - wie kommt das ActiveX Control auf das Formular?
Die ActiveX_on_WindowsForms C#-Beispielanwendung (Download: http://www.msdnonline.de/download/Code_ActiveX_on_WindowsForms.zip) zeigt die neue Funktionalität anhand eines sehr prominenten ActiveX-Controls der SHDocvw.dll, auch besser bekannt als Internet Explorer. Die Anwendung wurde mit der aktuellen Beta Version von Visual Studio .NET 2003 erstellt.
Mittels einfacher Grundfunktionalität wie dem Navigieren zu einer Webpage und der Interaktion mit Methoden-Aufrufen und Events demonstriert das Beispiel die Integration des Controls in die .NET Welt. Wie weit dies geht zeigt auch die Verwendung von Eigenschaften wie Alpha-Blending (Transparenz) die normalerweise nur unter Windows.Forms zur Verfügung stehen. Mit ihr testet die Beispielanwendung ob die Integration der beiden Welten auch durchgehend eingehalten wurde.
Bild1: Formular der Beispielanwendung
Ein kurzer Blick auf das Formular zeigt, dass sich neben dem IE-Control noch eine Textbox, mehrere Labels, ein Button und ein Slider-Element befinden.
Die Textbox nimmt die URL auf, zu der navigiert wird, sobald der Button gedrückt wird. Neben dem Label "Page Status" befindet sich ein weiteres Label als Ausgabe-Element für Information die aus dem ActiveX-Control via Event-Mechanismen an das Formular weitergegeben werden. Dazu folgen im Codewalk noch detailliertere Informationen. Mit dem Slider-Control kann die Transparenz des Gesamtformulars eingestellt werden, um das Verhalten des .NET Formulars im Zusammenspiel mit dem ActiveX Control zu testen.
Zur Erstellung des Formulars legt man in Visual Studio .NET 2003 ein neues Projekt für eine C# Windows Applikation an.
Die Toolbar in Visual Studio .NET bietet eigentlich schon alle der angesprochenen Elemente bis auf das Web Browser Control. Altgediente Visual Basic Profis werden sich gleich zu Hause fühlen, denn für Sie ändert sich an der Vorgehensweise rein gar nichts. Man klickt mit der rechten Maustaste auf die Toolbox, wählt "Add/Remove Item" aus den Kontextmenü und bekommt den "Customize Toolbox" Dialog angezeigt.
Bild2: Hinzufügen von ActiveX Controls in die Toolbar
Auf zwei Reitern stehen dann .NET Framework Komponenten und ActiveX (=COM) Komponenten zur Verfügung. Man wählt den Microsoft Web Browser aus der Liste aus und er erscheint als Bestandteil der Toolbox.
Bild 3: Toolbar mit Web Browser Control
Der Browser kann jetzt wie jedes andere Control mittels "Drag and Drop" auf das Formular gezogen werden. Seine Eigenschaften lassen sich im Properties Dialog einstellen und er kann so nach belieben konfiguriert werden.
Visual Studio.NET generiert dabei die notwendigen Wrapper-Klassen in managed Code sowie den notwendigen Infrastrukturcode für das Formular. Bei einigen anderen ActiveX Controls wie zum Beispiel dem Windows Media Player erscheinen die Control-Eigenschaften in einem eigenen Dialogfenster, was aber für deren Benutzung keine weiteren Auswirkungen hat.
Was passiert im Hintergrund?
Im ..|bin|debug Verzeichnis des Projektes legt Visual Studio .NET 2003 die Wrapper-Klassen mit den Dateinamen AXInterop.SHDocVw.dll und Interop.SHDocVw.dll ab. Dabei enthält die DLL mit der Präfix AX das eigentliche Wrapper-Control für das Formular. Es leitet sich mittels Vererbung vom ActiveX Standard Container System.Windows.Form.AXHost ab. Die zweite Wrapper-Klasse dient als COM-Interop-Proxy zwischen dem ActiveX Control und der Common Language Runtime und kümmert sich um das Handling der Datentypen zwischen beiden.
Bei der Erstellung der Wrapper-Klassen werden Mitgliedern von COM-Klassen die in .NET eine Entsprechung haben, z.B. der Eigenschaft "Width", die Vorsilbe "Ctl" vorangestellt um Kollisionen im Namensraum zu vermeiden. Aus "Width" wird somit "CtlWidth".
Dieser in Visual Studio .NET 2003 automatisch ablaufende Vorgang der Erstellung von Wrapper-Klassen lässt sich auch manuell mittels des Werkzeuges aximp.exe nachvollziehen. Der Befehl aximp c:\windows\system32\shdocvw.dll erzeugt identische DLL's, jedoch mit etwas abweichenden Namen, da im Gegensatz zu Visual Studio nicht der Vorsilbenteil "Interop", sondern nur der Filename zur Namensgebung verwendet wird.
Dies hat leider in Bezug auf den IE einen unangenehmen Nebeneffekt. Wird aximp.exe im "Documents and Settings" Ordner ausgeführt, so erzeugt sie eine Datei mit Namen SHDocVw.dll, den COM-Interop-Wrapper. Da dieser synonym mit dem IE COM-Control ist und der "Documents and Settings" Ordner zuerst durchsucht wird, treten nach einem Computerneustart mit Internet Explorer und Windows-Explorer Probleme auf, da beide versuchen die Wrapper-Klasse anstatt des COM-Controls zu laden.
Deswegen ist es zu empfehlen aximp.exe nur in Verzeichnissen zu verwenden, die nicht im Systempfad liegen!
Aximp.exe bietet darüber hinaus noch einige interessante Möglichkeiten die bei der automatischen Generierung in Visual Studio nicht angeboten werden.
Als Beispiel sei hier die Option erwähnt, sich den Sourcecode des Formular-Wrappers ausgeben zu lassen. Wenn man möchte, kann man hier tief in die inneren Zusammenhänge zwischen Control und Formular eintauchen. Ein guter Überblick auf alle zur Verfügung stehenden Optionen findet sich in der Visual Studio Hilfe.
Auswirkungen von ActiveX Controls auf die .NET Anwendung
Auch wenn die Vorteile der Verwendung von ActiveX Controls sehr überzeugend sind, so muss man doch auch einige wichtige Aspekte berücksichtigen, die diese Vorgehensweise mit sich bringt:
-
COM-Interop
Natürlich erfordern ActiveX Controls als COM-Komponenten auf Windows.Forms eine Inter-Plattform Kommunikation zwischen Control (COM) und Formular (.NET Framework), welche aufgrund des notwendigen Aufwandes durch Marshalling die Anwendungsperformance beeinträchtigt.
-
Sicherheit
Bei reinen .NET Anwendungen garantiert die .NET Sicherheitsinfrastruktur mittels Code Access Security die volle Kontrolle über den ausgeführten Code. Durch Verwendung von unmanaged Code- den ActiveX Controls - greift dieses Sicherheitssystem zumindest in Teilbereichen nicht mehr.
-
Installation und Wartung
Mit den ActiveX Controls werden auch die für COM Komponenten notwendigen Registrierungsmechanismen erforderlich. Das erzeugt einigen Aufwand bei Verteilung (Setup-Programme) und Wartung (Versionierung).
Während die Performance-Nachteile auf Clientsystemen bei den derzeit zur Verfügung stehenden Prozessorleistungen und maß;vollem Einsatz von ActiveX Controls keine drastischen Auswirkungen haben sollten, so sind der Mehraufwand für Installations- und Wartungsaufgaben (Achtung: Mit ActiveX-Steuerelementen öffnen Sie den Gefahren der DLL-Hölle auch wieder das Tor!) sowie die Sicherheitsaspekte gewichtige Punkte, die unbedingt für das jeweilige Projekt berücksichtigt und bewertet werden müssen.
Verwendung des ActiveX Controls im Formularcode
Für die Beispielanwendung wird das Web Browser Control zur Darstellung von HTML-Seiten genutzt. Dazu übergibt das Formular nach einem Mausklick auf den Go-Button die eingegebene URL an das Control.
//Event Handler für "Go" Button private void
bttn_URL_navigate_Click(object sender, System.EventArgs e) { //Anlegen eines
Objektes für optionale Parameter object dobj=Type.Missing; //Mit dem Webbrowser
eine Page ansteuern try { //Ziel-URL aus Eingabefeld string URL =
this.txtBox_URL.Text; axWebBrowser1.Navigate(URL,ref dobj, ref dobj, ref
dobj,ref dobj); } catch (Exception ex) { //Ausgabe der Fehlermeldung string s
=ex.Message; MessageBox.Show(s); } }
Der Vorgang ist ziemlich geradlinig mit Ausnahme der Paramerterübergabe. COM bzw. ActiveX-Controls kennen optionale Parameter, C# hingegen jedoch nicht. Aus diesem Grunde legt man ein Dummy-Objekt mit dem Datentyp Type.Missing an, welches anstelle der optionalen Parameter in der Methodensignatiur übergeben wird. Das Browser Control stellt anschließ;end die gewünschte Seite auf dem Formular dar.
Damit ist der erste Schritt getan, wir können jetzt HTML-Seiten auf einem .NET Formular hosten. Moderne Anwendungen erfordern jedoch einen höheren Grad von Interaktion als die bloß;e Darstellung. So tritt zwangsläufig die Frage auf, wie man Ereignisse aus dem Browser und am besten auch aus der dargestellten HTML-Seite für das Formular nutzbar machen kann.
Arbeiten mit Ereignissen aus dem ActiveX Control
Das Visual Studio Team hat die in den ActiveX Controls erzeugten Ereignisse nahtlos in die Eventinfrastruktur des .NET Frameworks integriert. Die von Visual Studio oder von aximp.exe erzeugten Wrapper-Klassen enthalten Delegates für alle im Control vorkommenden Events. Im Formular ist es deshalb nur noch notwendig, die passende Ereignis-Senke für das Ereignis zu schaffen. Dies geschieht indem man eine passende Eventhandler-Methode implementiert und diese dann für das Ereignis aus dem Control registriert.
Einen Überblick über die zur Verfügung stehenden Event Delegates des ActiveX Controls verschafft man sich am besten mittels des Object Browser in Visual Sudio .NET oder dem Werkzeug ILDasm.exe. ILDasm gibt als Metadatenbrowser sehr detailliert über die zur Verfügung stehenden Delegates Auskunft.
So wird aus dem mit Hilfe von ILDasm angezeigten Intermediate-Language-Code für das DownloadComplete Ereignis aus der AXInterop.SHDocVw.dll ersichtlich, dass sich das Event vom Standard System.EventHandler Delegate ableitet.
.event [mscorlib]System.EventHandler DownloadComplete {
.removeon instance void AxSHDocVw.AxWebBrowser::remove_DownloadComplete(class
[mscorlib]System.EventHandler) .addon instance void
AxSHDocVw.AxWebBrowser::add_DownloadComplete(class
[mscorlib]System.EventHandler) } // end of event
AxWebBrowser::DownloadComplete
Das DownloadComplete Ereignis feuert immer, wenn eine HTML-Seite im Browser erfolgreich geladen werden konnte. Es eignet sich deshalb gut um festzustellen, ob der Browser das Interpretieren der Seite abgeschlossen hat und man mit der Seite arbeiten kann. Wie oben bereits erwähnt, muss man als Entwickler zwei Dinge tun, um dieses Ereignis zu verwenden: Erstens ist eine Methode nötig, um das Ereignis zu behandeln.
//Event Handler-Methode für Browser Download Complete
private void axWebBrowser1_DownloadComplete(object sender, EventArgs e) {
//Anzeigen des Browser Events this.lbl_PageStatus_value.Text="HTML-Dokument
geladen";
. }
Und zweitens müssen Sie die Methode mittels des Standard System.EventHandler Delegates registrieren:
//Verdrahten des Browser Container Events
axWebBrowser1.DownloadComplete += new
EventHandler(axWebBrowser1_DownloadComplete);
Da nun bei Auftreten des Ereignisses der Eventhandler Delegate in der Lage ist, die mit ihm verknüpfte Methode aufzurufen, erscheint in unserem Fall die Meldung "HTML-Dolument geladen" im dafür vorgesehenen Label.
Das alles ist standard .NET Eventhandling. Interessanter wird die Angelegenheit, wenn man versucht, innerhalb des Browser Controls-Formulars auf Ereignisse zu reagieren, welche in der HTML-Page bzw. deren Tags ausgelöst werden. Auf den ersten Blick bietet unsere Browser- Wrapper-Klasse keinerlei Möglichkeiten sich mit tiefer liegenden Objekten in der aus managed und unmanaged Code bestehenden Hierarchie zu beschäftigen.
Aus diesem Grund empfiehlt es sich den Objektbaum im Locals Fenster während des Debuggens etwas genauer zu betrachten.
Bild 4: Objektbaum für das Browser Control
Unter dem WebBrowser (axWebBrowser1) findet sich ein Document Objekt, welches auf einen nicht in den Wrapper-Klassen des Browsers vorkommenden Datentyp verweist: [mshtml.HTMLDocumentClass]. Mit Hilfe dieses Hinweises können wir daran gehen, die Anwendung um den fehlenden Namespace zu erweitern.
Bild 5: Hinzufügen des Microsoft.mshtml NamespacesDamit die erforderlichen Objekte für unsere Beispielanwendung zugänglich werden, muss der Namensraum Microsoft.mshtml dem Projekt als Referenz hinzugefügt und durch das using statement im Code verfügbar gemacht werden.
Der Namensraum Microsoft.mshtml bietet Zugriff auf das komplette Document Object Model (DOM) des Browsers. Mit seiner Hilfe können wir auch auf Ereignisse innerhalb der Page und den HTML-Tags reagieren. Für diesen Zugriff definieren wir ein mshtml.DocumentClass Objekt auf Formularebene, welches im DownloadComplete Eventhandler das aktuell geladenene HTML-Dokument zugewiesen bekommt.
//Definition HTMLDocumentClass
- dieses Objekt ermöglicht später //den Zugriff auf die geladene Webseite
private mshtml.HTMLDocumentClass hdoc;
Dazu wird der DownloadComplete Eventhandler um einige Zeilen Code erweitert.
//Verknüpfen der Page im Browser mit der HTMLDocument
Klasse hdoc = (mshtml.HTMLDocumentClass) axWebBrowser1.Document; //Verdrahten
des Click Events der HTMLPage hdoc.HTMLDocumentEvents2_Event_onclick +=new
HTMLDocumentEvents2_onclickEventHandler(hdoc_HTMLDocumentEvents2_Event_onclick);
Zusätzlich wird das von uns vorgesehene Click-Event dem entsprechenden Eventhandler mittels des geeigneten Delegates aus dem mshtml Namespace zugewiesen. Das Vorgehen ist hierbei im Wesentlichen identisch zum DownloadComplete Event.
Klickt man jetzt mit der Maus auf das geladene HTML-Dokument, so wird ein Klick-Ereignis ausgelöst, welches durch das DOM, den Browser Container und die Wrapper-Klassen hoch in das Formular wandert (Event-Bubbling), wo es in der Methode hdoc_HTMLDocumentEvents2_Event_onclick behandelt wird.
//Event Handler für HTMLPage Click Event private bool
hdoc_HTMLDocumentEvents2_Event_onclick(mshtml.IHTMLEventObj he) { //Ausgabe des
Tag-Namens von dem Element, dass auf der HTML- //Seite angeklickt wurde
this.lbl_PageStatus_value.Text = "Click auf Element: " +
he.srcElement.tagName.ToString(); //Rückgabewert true stoppt das Event Bubbling
für dieses Event. //Bei false wandert es weiter nach oben. return true;
}
Über die srcElement-Eigenschaft des mshtml Ereignisobjektes ist es möglich zum auslösenden Objekt zurückzugreifen und wie in diesem Fall den Namen des Tags auf dem dafür vorgesehenen Label darzustellen.
Als Ergebnis der Methode wird True zurückgegeben. False würde bedeuten, dass das Ereignis in der Objekthierarchie weiter nach oben wandert und nochmals behandelt werden kann.
Somit schließ;t sich der Kreis. Im ActiveX Control auftretende Ereignisse können im .NET Formular behandelt werden und es ist möglich, feingranular die Objekthierarchie des COM Objektes auch in tieferen Ebenen des Objektbaumes wie dem DOM der HTML-Seite zu manipulieren.
Doch die Integration von ActiveX Controls in .NET Windows.Forms geht noch weiter, wie sich am nächsten Beispiel zeigen lässt.
Transparente ActiveX Controls
Eine der Neuerungen bei den .NET Windows.Forms Formularen ist, dass ihre Transparenz durch die Eigenschaft Opacity eingestellt werden kann. Diese Eigenschaft steht für klassische ActiveX Controls nicht zur Verfügung. Interessant ist es deshalb, wie sich die COM-Controls in Kombination mit dem .NET Formular verhalten. Bleibt das Control wie bisher sichtbar oder hat es neue Funktionalität hinzugewonnen?
Um dies zu testen fügen wir unserer Beispielanwendung ein Slider- Control hinzu, das als Stellschieber für die Sichtbarkeit des Formulars dienen soll. Dabei sollte der Minimalwert begrenzt werden, da ganz durchsichtige Formulare schwer auf dem Bildschirm wieder zu finden sind und meist nicht mehr sichtbar gemacht werden können.
private void trackBar_Opacity_Scroll(object sender,
System.EventArgs e) { //Zuweisung der Transparenzeinstellungen - Berechnung
erfolgt //mit Double Werten da Form.Opacity vom Typ Double ist this.Opacity =
((double)1/100)*(double)trackBar_Opacity.Value; //Formular mit aktuellem Wert
neu zeichnen this.Refresh(); }
Wir reagieren auf das Scroll Ereignis des Slider-Controls und berechnen den von der Stellung des Schiebers abhängigen Wert der Transparenz. Dabei ist zu beachten, dass die Eigenschaft Opacity einen Double Wert zwischen 0 und 1 darstellt. Das Slider Control liefert standardmäß;ig Integer Werte. Diese müssen, damit die Berechnung zum richtigen Ergebnis kommt, in Double Werte gecastet werden. Danach wird das Formular neu gezeichnet um die Änderungen sichtbar zu machen.
Bild 6: ActiveX-Controls auf transparenten .NET Formularen
Was wird nun aus den ActiveX Controls? Sie werden in der Tat zusammen mit dem Formular transparent.
Schön, wird mancher denken, aber wie ist diese Funktion eigentlich sinnvoll zu verwenden? Dafür gibt es eine einfache Antwort. Mit der Transparenzeigenschaft lassen sich nicht nur anspruchsvolle grafische Effekte über das Ein- und Ausblenden von Formularen verwirklichen. Es ist zudem möglich, Funktionsflächen über Inhalte zulegen, die diese Funktionalität sonst nicht bieten wie z.B. Bilder, Grafiken, Videos und Landkarten (ähnlich einer HTML-Imagemap). Gerade für die Erstellung interaktiver CD's, DVD's bieten sich hiermit interessante neue Möglichkeiten.
Zusammenfassung
Die Verwendung von ActiveX Controls auf Windows.Forms mit der nächsten Version des .NET Framework erschließ;t für den Entwickler grafischer Benutzer-Interfaces vielfältige Möglichkeiten, die vor allem bei der Migration und Weiterentwicklung bereits bestehender COM Anwendungen zum Tragen kommen.
Da wichtige Bestandteile des Windows Betriebssystems als COM/ActiveX Komponenten vorliegen, der Internet Explorer und der Windows Media Player sind zwei der bekanntesten Beispiele, wird es mit Visual Studio .NET 2003 erheblich einfacher, das volle Potential der Windows Infrastruktur auch unter .NET auszunutzen.
Natürlich kommt dieser enorme Funktionalitätsgewinn nicht ohne einen Kompromiss zwischen der .NET- und der COM-Welt zustande. ActiveX Controls bringen nach wie vor die Nachteile der COM-Technologie in den Bereichen Deployment und Wartung mit sich. Zudem fügen sie sich leider in keiner Weise in die .NET Sicherheitskonzepte ein.
So sollte man in der Designphase der Anwendung abwägen, wie sich die Vor- und Nachteile von ActiveX Controls auf die Gesamtlösung während Erstellung und Betrieb auswirken werden.
Die Integration der grafischen ActiveX-Controls in die .NET Welt ist Microsoft sehr gut gelungen. Wie das Code-Beispiel zeigt, fügen sich die Bestandteile nahtlos und ohne Mehraufwand für den Entwickler zusammen. Die Programmiermodelle für .NET und die Wrapper-Klassen der gehosteten ActiveX-Komponenten sind identisch und harmonieren auch im Detail.