Archive for the ‘.NET’ Category

Interfaces in C#

Monday, May 2nd, 2011

Hallo,

kürzlich habe ich zur Auffrischung meines C#-Wissens die neue Auflage von “Effective C#“  bestellt und begonnen, die einzelnen Items durchzuschauen. Das Item 23 “Understand How Interfaces differ from Virtual Methods” hat mich dann doch einigermaßen beeindruckt, gibt es doch einen Eindruck von der Fülle an Konzepten die zum Thema “Interfaces” in C# relevant sind. Beim Versuch eine Webpage oder Blog-posting zu finden, in dem ein mehr oder weniger vollständiger Überblick über dieses Thema gegeben wird, habe ich aber nichts brauchbares gefunden. Die meisten Fundstellen waren Einführungen in das Thema Interfaces im allgemeinen und begnügten sich damit, das Konzept vorzustellen und zu motivieren.

In diesem Posting versuche ich einen eher Referenz-artigen aber hoffentlich vollständigen Überblick über die Eigenheiten und Möglichkeiten von Interfaces in C# zu geben. Das Konzept an sich und die übliche Verwendung werde ich nicht weiter Erläutern.

Methoden in Interfaces sind per default nicht virtuell

Per default sind Methoden in Interfaces nicht virtuell. D.h. wenn eine Objektreferenz den Typ des Interfaces hat, wird immer die Methode der obersten Klasse in der Vererbungshierarchie gerufen, die die Methode implementiert. Die erneute Implementierung einer Interfaces-Methode in einer abgeleiteten Klasse ist überhaupt nur unter Verwendung des Schlüsselwortes new möglich,  was bereits auf das beschriebene Verhalten hinweist.

Interfaces können in verschiedenen Ebenen der Vererbungshierarchie implementiert werden

Wenn man von einer vorhandenen Klasse ableitet und mit deren Implementierung eines Interfaces nicht zufrieden ist, besteht die Möglichkeit, das Interface in der abgeleiteten Klasse erneut zu implementieren. Dazu erklärt man auch in der abgeleiteten Klasse, dass man das Interface definiert. In diesem Fall wird bei Verwendung einer Objektreferenz vom Typ des Interfaces die “tiefstmögliche” (bezogen auf die Vererbungshierarchie) Implementierung gerufen.

Dieses Vorgehen ist aber auch nicht ganz unproblematisch:

  • Die Verwendung des Schlüsselwortes new ist immer noch nötig
  • Es müssen alle Methoden des Interfaces implementiert werden, auch wenn man nur eine Teilmenge ersetzen will
  • Wenn man eine Referenz mit dem Typ einer direkten oder indirekten Superklasse zum Aufruf einer Methode verwendet, die Teil des Interfaces ist, wird die Implementierung des Klasse, die dem Typ der Referenz entspricht, gerufen. Dieses Verhalten ist bei virtuellen Methoden gerade nicht so.

Methoden in Interfaces können abstract definiert werden

Wenn eine Klasse als abstract definiert ist, dürfen auch Methoden aus Interfaces (die in einer Klasse, die ein Interface implementiert, eigentlich auch implementiert sein müssen) als abstract definiert sein. In diesem Fall müssen diese Methoden in der Basisklasse nicht implementiert werden. Die abgeleiteten Klassen müssen die Methode dann implementieren. Damit könnte man z.B. in einer gemeinsamen Basisklasse sinnvolle Default-Implementierungen einer Teilmenge der Interface-Member implementieren während man von den abgeleiteten Klassen erwartet, dass sie die restlichen Member des Interfaces selbst implementieren.

Methoden in Interfaces können virtuell sein

Wie bei normalen Methoden (die kein Bestandteil eines Interfaces sind) kann eine Methode als virtual deklariert werden und verhält sich dann entsprechend. D.h. es wird immer die Implementierung in der tiefsten Ebene der Vererbungshierarchie gerufen, egal welchen Typ die Referenz hat, über die man die Methode aufruft.
Dazu muss die Methode in der Interface-Definition nicht virtual sein.

Es ist möglich, mehrere Interfaces zu implementieren, die die gleichen Member haben

Grundsätzlich kann eine Klasse einen gegebenen Member nur einmal implementieren. Nun ist es nicht unrealistisch, dass man in einer Klasse mehrere Interfaces implementiert und die Gefahr identischer Member in zwei oder mehr Interfaces ist durchaus real. Dieses Problem lässt sich einfach lösen, indem vor jeder Implementierung eines Members der Interfaces-Name vorangestellt wird. Diese explizite Qualifizierung  muss dann auch beim Aufruf der Methode verwendet werden, sofern nicht eine Referenz vom Typ eines der Interfaces verwendet wird (sondern eine Referenz auf die konkrete Klasse).

Viele Grüße,
Andreas

Technorati Tags: ,

Neues Hilfesystem für Visual Studio 2010 mit Service Pack 1

Sunday, February 20th, 2011

Hallo,

in einem früheren Posting habe ich mein Unverständnis ausgedrückt, dass Microsoft die Hilfe-Funktion in Visual Studio 2010 quasi abgeschafft hat. Auch in Zeiten des Internet und der Suchmaschinen ist eine gute Hilfe-Funktion wichtig.

Nachdem diese Klage ja sehr verbreitet  war, scheint Microsoft ein Einsehen zu haben, und bringt mit dem Service Pack (SP) 1 für Visual Studio 2010 wieder eine richtige Hilfe-Funktion.
Ich bin sicher, dass der lokale Help-Viewer eine Verbesserung gegenüber der aktuellen Situation darstellt.

An der fehlenden Intellisense-Funktion für managed C++/CLI (managed C++), die ja auch viele Benutzer vermissen, scheint sich nichts getan zu haben. Microsoft scheint hier auch einen der Nachteile einer ‘buy’-Lösung zu erfahren: die fehlende Möglichkeit der individuellen Anpassung. Vermutlich lässt sich der hinzugekaufte Compiler der Edison Design Group, der ja in Visual Studio 2010 für die Bereitstellung der Intellisense-Fetaures in C++ verwendet wird, nicht ohne weiteres so erweitern, dass er mit den Spracherweiterungen von C++/CLI vernünftig umgeht.

Auf der anderen Seite muss man sagen, dass der Intellisense-Support für Standard C++ in Visual Studio 2010 viel besser ist als in älteren Versionen von Visual Studio und die Produktivität spürbar steigert. Insbesondere, dass Fehler direkt beim Tippen angezeigt werden, ist eine große Hilfe (man könnte auch sagen, dass dieses Feature langsam überfällig war).

Viele Grüße,
Andreas

Technorati Tags:

Einschränkungen beim Debuggen mit mixed moded Anwendungen im 64-Bit Modus

Sunday, June 27th, 2010

Hallo,

kürzlich bekam ich vom Visual Studio 2010 Debugger beim Starten einer Anwendung folgende Fehlermeldung:

—————————
Microsoft Visual Studio
—————————
Fehler beim Ausführen des Projekts: Das Programm “…\unittest\bin\Debug\unittest.exe” kann nicht gestartet werden.

Das Debuggen im gemischten Modus für x64-Prozesse wird nur bei Verwendung von Microsoft .NET Framework vor Version 4 unterstützt.
—————————
OK   Hilfe
————————–

Die Konstellation war dabei folgende:

  • Ein reines C#-Programm referenziert eine Assembly, die mit managed C++ erstellt war. Diese Assembly bindet auch native code ein (mixed mode).
  • Als Compiler wurde der vc90 verwendet.
  • Als Targetversion für das .NET-Framework wurde für alle Komponenten 2.0 verwendet.
  • Alle Anwendungen waren als 32-Bit-Anwendungen in Visual Studio 2008 erstellt und wurden von Visual Studio 2010 zur Version 2010 konvertiert.

Für die in C# erstellte (reine .NET) Anwendung war in den Einstellungen als Zielplattform “Any CPU” eingetragen, wie bereits in der Vorgängerversion:

AnyCPU

Nach der Umstellung auf X86 konnte die Anwendung erfolgreich im Debugger gestartet werden.

X86

Die Fehlermeldung ist grundsätzlich ziemlich irreführend. Alle beteiligten Komponenten waren ja explizit für .NET 2.0 konfiguriert.

Oder ist sie gar falsch?

Auf dieser Seite findet man folgendes Zitat:

Debugging im gemischten Modus (Aufrufe von systemeigenem Code bis zu verwalteten Codes, oder umgekehrt) wird für x64-Prozesse unterstützt, wenn der verwaltete Code Microsoft .NET Framework, Version 4 oder höher, verwendet.

Debugging im gemischten Modus wird nicht für IA64-Prozesse oder x64-Prozesse unterstützt, die frühere .NET Framework-Versionen als 4 verwenden.

was ja ein klarer Gegensatz zur oben zitieren Fehlermeldung ist.

Grundsätzlich ist es schon etwas unschön, wenn man für die reine .NET-Komponent nicht mehr “Any CPU” wählen kann, nur weil sie eine mixed mode Assembly nutzt, die im 32-Bit Modus erstellt wurde.

Eine Rolle könnte auch spielen, dass ich inzwischen Windows 7 x64 benutze, während ich zuvor Windows XP X86 verwendet habe.

Viele Grüße,
Andreas

Technorati Tags: , ,


DoDragDrop und SelectedNode in WinForms TreeViews

Monday, November 30th, 2009

Hallo,

kürzlich fiel mir ein überraschender Effekt im Zusammenhang mit WinForms TreeViews und drag and drop auf. Fall man im MouseDown-Event eine DragDrop-Operation mit der Methode DoDragDrop() startet, wird der selektierte Knoten nicht auf den angeklickten Knoten gesetzt.

In folgendem Beispiel wurde der Knoten “BasicActivities” angeklickt und damit zum selected node. Anschließend wurde der Knoten ActivityFinalNode angeklickt. Der Focus-ähnliche Rahmen um den Knoten “BasicActivities” blieb aber erhalten:

SelektierterKnotenFalsch

Das hat zur Konsequenz, dass der zuvor selektierte Knoten “BasicActivities” nach einer anschließenden Mousebewegung ohne click wieder selektiert wird.

Dieses Verhalten tritt nicht auf, wenn der Aufruf der Methode DoDragDrop() unterbleibt.

Wenn man den Knoten im MouseDown-Event explizit selektiert (wie hier beschrieben), tritt dieser Effekt nicht auf und das TreeView verhält sich wie gewohnt.

theTreeView.SelectedNode = nodeAt;
DoDragDrop(nodeAt.TheClass, DragDropEffects.Copy);

Viele Grüße,
Andreas

Technorati Tags: ,

Wie kann man native Methoden in managed C++ Klassen nutzen?

Sunday, October 4th, 2009

Hallo,

Microsoft hat mit der Einführung des .NET-Frameworks auch C++-Erweiterungen (C++/CLI) definiert, mit denen vorhandener C++ source code für .NET-Anwendungen verfügbar gemacht werden kann.

Die Intention dabei war die Steigerung der Akzeptanz des .NET-Frameworks, da es relativ einfach gemacht wird, bereits vorhandenen C++ code in .NET-Anwendungen zu integrieren. Meiner persönlichen Erfahrung nach geht das sehr gut, d.h. es ist ziemlich einfach vorhanden C++ code mit C++/CLI .NET-tauglich zu machen und die entstandenen Assemblys haben keine nennenswerten Einschränkungen (abgesehen davon, dass sie nur für die Plattform geeignet sind, für die der native code kompiliert wurde).

Der übliche Weg besteht darin eine neue Assembly zu erstellen, die C++/CLI Klassen (und ggf. native Klassen) enthält. Diese Klassen rufen dann den eigentlichen legacy code, typischerweise in bereits vorhandenen Libraries/DLLs.

Folgende Frage stellt sich bei der Erstellung eines Managed C++ Wrappers um vorhanden C++ code schnell:

Wie kann ich innerhalb des .NET-Wrappers native Datenstrukturen zwischen managed Klassen austauschen?

Dies ist grundsätzlich nicht ohne weiteres möglich, da in der öffentlichen Schnittstelle nur CLR-kompatible Datentypen verwendet werden dürfen (ansonsten könnten nicht alle Elemente der Schnittstelle von anderen .NET kompatiblen Komponenten konsumiert werden).

Es ist allerdings möglich, private Methoden zu definieren, die nicht CLR-konforme Datentypen konsumieren oder zurückgeben dürfen. Damit solche Methoden von anderen Klassen in der C++/CLI Wrapper-Assembly gerufen werden dürfen, müsste man alle diese Klassen als friend definieren, was eine etwas unbefriedigende Lösung ist.

Diese Überlegung führt aber zur optimalen Lösung: die Deklaration der entsprechenden Methoden als public private. public private ist in C++/CLI die Entsprechung zu internal in C# und bedeutet “sichtbar innerhalb der Assembly”.
Da die entsprechenden Methoden nur von den C++-Klassen innerhalb der Wrapper-Assembly gerufen werden, gibt es keinen Grund sie zu verbieten (was der Compiler dann auch nicht macht).

Viele Grüße,
Andreas

Technorati Tags: ,

Prüfen auf Schreibrechte für eine Datei in C#

Saturday, February 28th, 2009

Hallo,

manchmal möchte man wissen, ob ein bestimmter Benutzer bestimmte Rechte (z.B. Schreibrechte) für eine bestimmte Datei besitzt. Wie sich herausstellt, ist diese Anforderung alles andere als leicht umzusetzen, weil dabei viele verschiedene Aspekte eine Rolle spielen. Die Vorgehensweise sieht prinzipiell so aus:

  • Abfragen der Access Control Listen für die Datei
  • Itererieren über alle Einträge und prüfen ob man für die Kennung oder die Gruppe des gewünschten Benutzers Einträge findet
  • Dabei die Präzedenz der Einträge beachten (explizite kommen vor vererbten Regeln, “Deny”-Regeln kommen for “Allow”-Regeln)

Den nicht unerheblichen Code hat dankenswerterweise Bruce Hatt in einem Artikel auf CodeProject.com veröffentlicht.

Man sollte bedenken, dass die Möglichkeit in eine Datei zu schreiben zusätzlich durch das “ReadOnly-flag” und die .NET Code Access Security eingeschränkt sein könnte. Beides wird in dieser Klasse nicht berücksichtigt.

Die Prüfung auf das ReadOnly-flag könnte man so schreiben:

FileAttributes attrs = File.GetAttributes(fileName);
 
if ((attrs & FileAttributes.ReadOnly) != 0)
{
    readOnly = true;
}

Und für die Prüfung im Rahmen der CAS könnte man folgenden Code verwenden:

FileIOPermission fp = new FileIOPermission(FileIOPermissionAccess.Write, fileName);
try
{
    fp.Demand();
}
 
catch (SecurityException)
{
    readOnly = true;
}

Wenn es nur um die Prüfung auf Schreibrechte geht, hört man oft den Vorschlag, einfach den Schreibvorgang auszuführen und ggf. die geworfene Exception zu fangen. Dieser Vorschlag ist aber nicht immer geeignet. In meinem Fall war es so, dass ich an einer Anwendung arbeite, in der Dateien editiert werden können. Falls Dateien nicht geschrieben werden können, soll dies visualisiert werden. Man möchte aber vermeiden, dazu bei jedem Start der Anwendung die zu editierenden Texte zu speichern, da damit der Timestamp verändert wäre, obwohl der Benutzer die Datei gar nicht geändert hat und auch nicht speichern wollte.

Viele Grüße,
Andreas

Technorati Tags: ,

.NET Assembly-Ladevorgang loggen

Monday, January 26th, 2009

Hallo,

kürzlich hatte ich folgende Situation:

In einer C#-Solution wurde eine in Managed C++ erstellte .NET Assembly referenziert. Sobald die C#-Anwendung eine Klasse aus der referenzierten Library benutzen wollte, gab es eine Exception der Form:


System.IO.FileNotFoundException: Die Datei oder Assembly "etocl, Version=1.0.3306.20332, Culture=de, PublicKeyToken=null" oder eine Abhängigkeit davon wurde nicht gefunden. Das System kann die angegebene Datei nicht finden.
Dateiname: "etocl, Version=1.0.3306.20332, Culture=de, PublicKeyToken=null"

Die referenzierte Assembly fand sich aber wie es sein sollte im Arbeitsverzeichnis des C#-Programms. Um ein Protokoll des Ladevorgangs zu bekommen kann man nun folgenden Registry-Eintrag anlegen:


[HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) = 1

Danach enthält die Fehlermeldung eine Aufstellung der Pfade, die der Loader durchsucht hat:


LOG: Download von neuem URL file:///K:/Develop/et/etroot/src/apps/etoclide/bin/Debug/de/etocl.DLL.
LOG: Download von neuem URL file:///K:/Develop/et/etroot/src/apps/etoclide/bin/Debug/de/etocl/etocl.DLL.
LOG: Download von neuem URL file:///K:/Develop/et/etroot/src/apps/etoclide/bin/Debug/de/etocl.EXE.
LOG: Download von neuem URL file:///K:/Develop/et/etroot/src/apps/etoclide/bin/Debug/de/etocl/etocl.EXE.

und das Problem wird schnell sichtbar: der loader sucht im Unterverzeichnis “de”. Mit diesem Hinweis ausgerüstet sieht man schnell, dass das AssemblyInfo.cpp-file der referenzierten Library einen expliziten Eintrag für das locale enthielt:


[assembly:AssemblyCultureAttribute("de")]

Nach Entfernung dieses Eintrags und erneuter Erstellung der library  funktionierte dann auch alles wieder.

Fairerweise muss ich sagen, dass bereits die ursprüngliche Meldung einen Hinweis auf das Problem enthielt, allerdings nicht so deutlich:


System.IO.FileNotFoundException: Die Datei oder Assembly "etocl, Version=1.0.3306.20332, Culture=de, PublicKeyToken=null" oder eine Abhängigkeit davon wurde nicht gefunden. Das System kann die angegebene Datei nicht finden.
Dateiname: "etocl, Version=1.0.3306.20332, Culture=de, PublicKeyToken=null"

Microsoft empfiehlt, den Registry-Eintrag wieder zu löschen da er zu einer Performance-Einbusse führen könnte.

Viele Grüße,
Andreas

Technorati Tags: ,

ClickOnce-Installation und der Fehler “Datei…wurde seit ihrer ersten Veröffentlichung geändert” Fehler

Monday, October 20th, 2008

Hallo,

bei einer ClickOnce-Installation einer Microsoft .NET Software kann bei der Erstellung des setup-Programmes in Visual Studio eine Option gewählt werden, die bewirkt dass vorausgesetzte Software (”redistributable prerequisites” – wie etwas das .NET framework selbst) automatisch als Teil der Installation geladen und installiert werden.

Dabei kann angegeben werden, ob die Komponenten von der Website des Hersteller oder von einer anderen Quelle geladen werden sollen.

Erforderliche Komponenten für ClickOnce Installation Dialog in Visual Studio

Im ersteren Fall kann folgendes Fehlerszenario entstehen:

Der Entwickler hat eines der vorausgesetzten Softwarepakete (z.B. das deutsche language pack vstor_lp_de_30.exe für die VSTO 3.0 runtime) lokal installiert. Beim Erstellen des setup-Programmes wird dieses Paket nicht integriert, wohl aber Information über die verwendete Version.

Nun wird die Installation auf einem beliebigen anderen Rechner gestartet. Der installer sieht dass auf der Website des Komponentenherstellers (also Microsoft für obiges Beispiel) eine andere Version der Komponente verfügbar ist. Genau dann wird diese Fehlermeldung generiert:

Error: Die Datei “C:\DOKUME~1\awa\LOKALE~1\Temp\VSD6.tmp\VSTOR30\vstor_lp_de_30.exe” wurde seit ihrer ersten Veröffentlichung geändert.

Die lokal auf dem Entwicklungsrechner mit Visual Studio 2008 SP1 installierte Version war vom 27.12.2007 während die Version auf der Microsoft Website vom 12.08.2008 war.

Dieses Verhalten ist ziemlich problematisch, kann doch ein update auf der Website des Komponentenherstellers grundsätzlich zu einem beliebigen Zeitpunkt erfolgen. Danach müssten alle ClickOnce-setups, die die aktualisierte Komponente benötigen, aktualisiert werden.

Es wäre sinnvoll, zumindest kleinere Abhängigkeiten direkt in das setup zu integrieren. Leider kann das Verhalten nicht für einzelne Abhängigkeiten individuell eingestellt werden, so dass in diesem Fall auch die .NET runtime in das setup integriert werden müsste, was nicht wirklich attraktiv ist.

Falls prerequisites ausgeschlossen werden bricht die Installation ohne konkrete Fehlermeldung ab, wenn die prerquisites nicht vorhanden sind bzw. nicht in der richtigen Version vorhanden sind.

Insgesamt würde ich empfehlen ausser den .NET runtimes alle erforderlichen prerequistes dem setup mit der Option “Erforderliche Komponenten vom demselben Speicherort wie die Anwendung herunterladen” hinzuzufügen. Die Installationsanleitung muss dann einen deutlichen Hinweis auf die erforderliche .NET runtime bzw. weitere nicht eingeschlossene prerequistes beinhalten.

Vielen Dank an Joe Wirtley für den Hinweis auf die root cause.

Viele Grüße,
Andreas

Technorati Tags: ,

Erstellung eines AddIns für Word 2007 – Teil 5 (Finden der OCL-Fragmente)

Saturday, September 27th, 2008

Hallo,

wie erwartet war dieser Teil einfach zu lösen, da es im Internet genügend Beispiele gibt, wie man mit dem Word-Objektmodell arbeitet. Die OCL-Fragmente werden anhand ihrer Vorlage identifiziert. Die Vorlage muss “OCL” heißen, kann ansonsten aber beliebig gestaltet werden. Die Verwendung eines fonst mit fester Zeichenbreite (”fixed width”) empfiehlt sich.

Ein wenig mehr Zeit als nötig habe ich benötigt, weil mir anfangs nicht klar war, dass der englische Begriff für “Formatvorlage” “Style” ist und nicht “Format”.

Bei der Umsetzung merkt man, dass die Kompatibilität zu Visual Basic for Applications (VBA) kein Designziel für C# war. Ein komfortabler Umgang mit den Office-Objektmodellen setzt einige features voraus, die Visual Basic.NET hat, C# aber nicht (z.B. default parameter). Deshalb sollte man grössere Anbindungen von Office-Objektmodellen in eigenen Visual Basic.NET assemblies erstellen. Für unser kleines Word-AddIn spielt das aber keine Rolle, da wir nur minimal auf die Word-Objekte zugreifen.

Um die OCL-Fragement zu finden, wird das Word “Find”-Objekt benutzt:

IList<TextFragment> FindFragmentsByStyle(Word.Document doc, Object styleName)
{
            List<TextFragment> result = new List<TextFragment>();
 
            Object start = 0;
            Object end = doc.Characters.Count;
            Word.Range range = doc.Range(ref start, ref end);
            Word.Find find = range.Find;
 
            Object style = null;
 
            try
            {
                style = doc.Styles.get_Item(ref styleName);
            }
 
            catch (Exception)
            {
                /*
                 * Style not found.
                 */
                return (result);
            }
 
            find.set_Style(ref style);
            ExecuteFind(find);
            while (find.Found)
            {
                string text = range.Text;
                int linenum = GetRelativeLineNum(doc, range);
                int pagenum =     (int)range.get_Information(Microsoft.Office.Interop.Word.WdInformation.wdActiveEndPageNumber);
 
                result.Add(new TextFragment(text, linenum, pagenum));
                ExecuteFind(find);
            }
 
            return (result);
}

Die Methode ExecuteFind() enthält einige low level Details beim Suchen nach dem nächsten Treffer:

private bool ExecuteFind(Word.Find find, Object wrapFind, Object forwardFind)
{
            // Simple wrapper around Find.Execute:
            Object forward = forwardFind;
            Object wrap = wrapFind;
 
            return find.Execute(ref missing, ref missing, ref missing,
              ref missing, ref missing, ref missing,
              ref forward, ref wrap, ref missing, ref missing, ref missing,
              ref missing, ref missing, ref missing,
              ref missing);
}

Als Ergebnis gibt die Methode FindFragmentsByStyle() eine Liste von Objekten der (selbst erstellen) Klasse TextFragment zurück. Diese Klasse speichert den eigentlichen Text und Informationen zur Position des Textes im Dokument (Seiten- und Zeilennummer).

Viele Grüße,
Andreas

Technorati Tags: , ,

Nette Silverlight Demo

Thursday, September 4th, 2008

Hallo,

Microsofts Silverlight stellt eine Plattform dar, mit der man “Rich Internet Applications” (RIAs) mit Schwerpunkt auf grafische Darstellung erstellen kann.

Wer sich für Silverlight interessiert findet unter http://foidoschess.tv/ eine nette Demonstration der Möglichkeiten von Silverlight. Dummerweise ist eine Registrierung erforderlich, ich habe hierfür eine Email-Adresse @mailinator.com verwendet.

Ausserdem muss man noch die Silverlight Runtime installieren, was aber schnell und unkompliziert geht.

Da ich öfter das Internet nutze um Schachpartien live zu verfolgen (z.B. soweit möglich bei dem im Oktober anstehenden Weltmeisterschaftskampf) kann ich den Mehrwert der Foidos-Plattform durchaus erkennen.

Viele Grüße,
Andreas

Technorati Tags: ,