Donnerstag, 4. April 2013

"Dem Inhalt können keine Nichtleerzeichen hinzugefügt werden"

Beim Programmieren geht mit Sicherheit immer etwas irgendwas in die Hose. Wenn man mit XML arbeitet, passiert das auch schon gerne mal bevor man richtig mit dem Programmieren begonnen hat.

Der Konstruktor von XDocument ist dabei besonders tückisch. Er ist folgendermaßen deklariert:

public XDocument(
 params Object[] content
)

Das bedeutet, dass er alles akzeptiert, was man ihm gibt. Das meiste, was man ihm geben kann, ist leider falsch. Man erhält vor allem beim Aufruf von new XDocument("...") die kryptische Fehlermeldung (Exception): "Dem Inhalt können keine Nichtleerzeichen hinzugefügt werden".

Der Fehler kann folgende Ursachen haben:
  1. Der Konstruktor von XDocument wurde mit Datei-Pfad als Argument aufgerufen. Der Konstruktor von XDocument, noch der von XmlDocument ist dafür gedacht, Dateien zu verarbeiten. Man verwendet stattdessen die Methode XDocument.Load (statisch) oder eine passende Load-Methode von XMLDocument.
  2. Der Konstruktor von XDocument wurde mit XML-Code als Argument aufgerufen. Auch keine gute Idee. Wenn das XML bereits als String vorliegt, verwendet man entweder XDocument.Parse (statisch) oder XMLDocument.LoadXML.
Ich hoffe, ich verwirre mit dieser Antwort niemanden. Am besten schaut man sich noch folgendes Code-Beispiel an:
// Laden aus String mit XDocument
System.Xml.Linq.XDocument myXDoc = System.Xml.Linq.XDocument.Parse(p);
 Oder für .NET 2.0 und älter:
// Laden aus String mit XmlDocument
System.Xml.XmlDocument myXmlDoc = new System.Xml.XmlDocument();
myXmlDoc.LoadXml(p); // einfache Variante
   
System.Xml.XmlTextReader reader = new System.Xml.XmlTextReader(new StringReader(p)); // komplizierte Variante (Schritt 1)
myXmlDoc.Load(reader); // komplizierte Variante (Schritt 2)
Wie man das nun mit MSXML.XMLDocument erreicht überlasse ich dem Leser zur Übung.

Montag, 1. April 2013

Wie man eine Instanz von einer Interop-Klasse erstellt

Ich programmiere am liebsten mit C#, aber manchmal bringt es mich dann doch um den Verstand. Jeder der schon einmal versucht hat, mit Visual Studio eine COM-Bibliothek zu referenzieren, wird auf dieses Problem gestoßen sein: Man kann mit dem new-Operator keine Klassen erzeugen. Aber fangen wir mit dem Anfang an.

Wo finde ich Shdocvw.dll?

Ich versuche gerade, eine alte Browser-Bibliothek von Microsoft zu verwenden und habe sie nach einigem Suchen in den Referenzen gefunden. "Shdocvw.dll" ist der Name der Bibliothek, allerdings wird sie nicht so bezeichnet. Die Bezeichnung in den COM-Referenzen ist "Microsoft Internet Controls". Nach dem Hinzufügen taucht diese Bibliothek dann als "Shdocvw" im Projekt auf.

Wie erzeuge ich ein Objekt?

Nun befinden sich dort mehrere interessante Klassen und Interfaces. Mein erster Reflex war, ein Objekt zu erzeugen und dann zu schauen, was es tut:
SHDocVw.WebBrowserClass myBrowser = new SHDocVw.WebBrowserClass();
Das geht so nicht. Der Compiler-Fehler, der bei dieser Gelegenheit auftritt lautet: "Interop type SHDocVw.WebBrowserClass cannot be embedded. Use the applicable interface instead." oder so ähnlich.

In der Fehlermeldung steht es eigentlich bereits: Benutze das Interface! Aber was bedeutet "benutzen"? In jedem besserem C#-Kurs lernt man Factory-Methoden zu verwenden. Also begab ich mich auf die Suche nach einer Factory, jedoch ohne Erfolg. Der Trick ist das Unmögliche:
SHDocVw.WebBrowser myBrowser = new SHDocVw.WebBrowser();
Das Element SHDocVw.WebBrowser ist keine Klasse. Es ist ein Interface. 
Und jeder weiß doch, dass man von Interfaces mit new eigentlich keine Instanzen erzeugen kann.
Nun, man kann. Und ohne dieses Excel-Blog wäre ich wohl nie darauf gekommen.