WPF intim

XAML-Code ausspionieren

Im Gegensatz zu C#- oder Visual-Basic-
Code wird XAML-Code nicht nach MSIL
kompiliert, sondern lediglich in ein effizienteres
binäres Format übersetzt. Dieser Binärdatei
wird dann in der Assembly der
Anwendung als Ressource hinterlegt. Jetzt
könnte man auf die Idee kommen, auch eigene
Ressourcen auf diese Weise zu laden
oder XAML-Ressourcen aus anderen Anwendungen
zu extrahieren. Dazu müsste
lediglich ein Uri-Objekt für die Ressource
der anderen Anwendung erzeugt und darauf
die Methode LoadComponent() angewendet
werden. Listing 5 skizziert diese
Vorgehensweise:

Bei der Angabe der URI muss lediglich noch der Name der Assembly
angegeben werden. Auf diese Weise können
Ressourcen auch aus anderen Dateien
geladen werden. Im Gegensatz zum letzten
Aufruf der Methode LoadComponent()
wird diesmal der Rückgabewert in ein
Window-Objekt umgewandelt, vorausgesetzt,
das Wurzelelement der XAML-Datei
ist tatsächlich von diesem Typ. Danach
wird ein Stream geöffnet (im Speicher
oder in eine Datei) und mittels eines
XamlWriters der Binärcode des XAMLObjekts
(hier vom Typ Window) als Textrepräsentation
in den Stream geschrieben.
Abbildung 1 zeigt den aus einer Assembly
extrahierten XAML-Code innerhalb einer
RichText-Komponente an:

Dieser entspricht
ziemlich genau dem Original, außer
das als Alias für den WPF-Namespace
das Kürzel av verwendet wird.

Dies hat natürlich Auswirkungen, was
die Sicherheit einer Anwendung angeht und
es führt zu neuen Möglichkeiten, XAML-Ressourcen
nachzuladen. XAML-Code
ist demnach standardmäßig nicht mehr
oder weniger geschützt, wie MSIL-Code.
In diesem Fall ist es sogar ein zusätzlicher
Nachteil, dass der XAML-Code nicht nach
MSIL übertragen wird, da sich Assembly-
Ressourcen noch wesentlich einfacher
extrahieren lassen. Eine Lösung zur Verbesserung
der Sicherheit könnte die Verwendung
der Klasse XamlReader sein, die
XAML-Code aus einer Textdatei laden
und in eine Objektrepräsentation übertragen
kann.

XAML lesen und schreiben

Die beiden Klassen XamlReader und Xaml-
Writer
erlauben das Lesen und Schreiben
von XAML aus und in Streams in Markup-
Syntax. Ein XamlReader erzeugt als Ergebnis
ein Objekt vom Typ des Wurzelelements
des XAML-Codes während ein XamlWriter
ein solches Objekt als Argument nimmt
und es als Markup in den Stream schreibt.
Durch die Verschachtelung von Streams ist
es nun möglich, Teile der Anwendung als
verschlüsselte und optional gepackte Ressourcen
abzuspeichern, diese zur Laufzeit
laden, entschlüsseln, über einen XamlReader
einzulesen und das Ergebnis in die Anwendung
zu integrieren.

Umgekehrt bietet der XamlWriter z.B.
die Möglichkeit, einen kompletten Objektbaum
im Code (mit C# oder Visual Basic)
zu erzeugen und diesen dann als Markup
in eine Datei zu schreiben. Damit ließe sich
z.B. eine aufwändige Animation oder eine
3D-Grafik im Code erzeugen, als XAML speichern und diese als „Loose XAML“ im
Internet oder Intranet bereitstellen, sodass
sie über einen Browser geladen werden
kann. Der Fantasie sind wie immer keine
Grenzen gesetzt. Der Code aus Listing 6
könnte sich in einer externen XAML-Datei
befinden. Er soll den vollständigen Inhalt
eines Fensters beinhalten, der hier allerdings
nur aus Layout-Container sowie
zwei Komponenten besteht.

Das Hauptfenster wird in XAML lediglich
aus einem Window-Element erzeugt,
welches keinen weiteren Inhalt besitzt.
Nach dem Laden des Hauptfensters (Ereignis
Loaded) oder einem anderen Zeitpunkt
kann jetzt der Inhalt der XAML-Datei
(oder einer XAML-Ressource in der
Assembly) geladen und in den Elementbaum
integriert werden. Im einfachsten
Fall wird dazu der Inhalt über einen File-
Stream bereitgestellt, welcher der Methode
Load() des XamlReaders als Eingabe
übergeben wird. Die Methode liefert als
Resultat ein Objekt vom Typ des Wurzelelements
zurück, welches allerdings noch
in diesen Typ umgewandelt werden muss,
um es einer entsprechenden Variablen zuzuweisen.
Danach kann der Stream wieder
geschlossen werden. Um Komponenten,
die sich in der XAML-Datei befinden mit
einem Ereignishandler zu versehen, ließe
sich z.B. die Methode FindName() verwenden,
wenn die Komponenten einen Namen
besitzen. Zum Abschluss kann der Inhalt
des Hauptfensters (oder einer anderen
Komponente) mit dem Inhalt der XAML-Datei
versehen werden (this.Content = sp;).
Der Inhalt des Fensters stammt jetzt vollständig
aus dem Markup einer externen
XAML-Datei.

XAML = XML

Dieser Exkurs in die Interna einer WPF-Anwendung sowie dem Laden und Speichern
von XAML zur Laufzeit sollte reichlich
Stoff für Ideen geben. Ein großer Vorteil
von XAML ist bekanntlich, dass es sich um
pures XML handelt. Dementsprechend
einfach ist das automatisierte Generieren
und Verarbeiten von XAML-Code. Dieser
Code kann zum Beispiel mit dem Xaml-
Reader geladen und in eine Anwendung
integriert werden. Wurde innerhalb einer
Anwendung z.B. eine Vektorgrafik erzeugt,
könnte die Grafik als Baum von WPF-Grafikelementen
erzeugt und mit dem Baum
in einer XAML-Datei gespeichert werden.
Damit liegt nicht nur ein gut verarbeitbares
Austauschformat vor, die Grafik lässt sich
auf vielfältige Weise in andere WPF-Anwendungen
integrieren, z.B. als Hintergrundbild.
Soll verhindert werden, dass
der XAML-Code allzu einfach durch andere
gelesen werden kann, kann er z.B. verschlüsselt
abgelegt werden und muss dann
manuell geladen und in den Elementbaum
„eingehängt“ werden. Natürlich könnte
man auch einfach auf die Verwendung von
XAML verzichten und sämtliche Anweisungen
im Code hinterlegen und darauf einen
Obfuscator anwenden. Absolut sicher
werden diese Maßnahmen den Code aber
auch nicht machen können.

Nachdem Dirk Frischalowski sein Buch zur WPF endlich fertig gestellt hat, widmet er sich voller
Elan dem nächsten Projekt: Einem Buch zu Expression
Blend. Das wird allerdings noch etwas
dauern. Bereits begonnen hat er damit, sein lange
angekündigtes WPF-Tutorial unter www.gowinfx
.de wieder aufleben zu lassen.

Links & Literatur

[1] Dirk Frischalowski: Windows Presentation
Foundation. Grafische Oberflächen mit .NET
3.0, Addison-Wesley 2007

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.