BigBasti's Blog About Me & my Digital Lifestyle

16Aug/101

.NET: Mit Extension Methods arbeiten

Aus gegebenen Anlass möchte ich heute einen kleinen Artikel zu dem Thema Extension Methods in .NET schreiben, einfach nur weil es eine sehr simple Möglichkeit bietet sich das Leben zu erleichtern. Falls es euch nichts sagt, mit Extension Methods, die  es seit C# 3.0 gibt ist es möglich bestehende Klassen, sogar interne Core-Klassen wie Integer oder String mit eigenen Methoden zu erweitern.

Wieso das nützlich ist fragst du dich? Na ganz einfach, habt ihr schon mal die Methode String.toInt32() vermisst? Diese ist nur eine (sehr simple) Methode, die man häufiger gebrauchen könnte, die es aber nicht gibt. Diese könnte man sehr einfach mit einer Extension Method erweitern.

Als Beispiel möchte ich hier aber den Artikel von vor ein paar Tagen nehmen, wo wir eine Methode erstellt haben mit der man ein XmlElement in einem XmlDocument umbenennen konnte. Dies mussten wir machen, da die Klasse XmlDocument keine Methode dafür anbietet. Nun wollen wir mal die XmlDocument Klasse um diese Methode erweitern.

Das ganze funktioniert sehr einfach:


    public static class XmlDocumentExtension
    {
        public static bool RenameXmlElement(this XmlDocument doc,
                                            XmlElement oldElement,
                                            string newName) {
            try {
                //Neues XmlElement mit neuem namen anlegen
                XmlElement newElement = oldElement.OwnerDocument.CreateElement(newName);

                //Dem neuen XmlElement alle Attribute des alten Elements übergeben
                foreach (XmlAttribute a in oldElement.Attributes) {
                    newElement.SetAttributeNode((XmlAttribute)a);
                }

                //Dem neuen XmlElement alle Kinder Elemente des alten Elements anhängen
                foreach (XmlNode n in oldElement.ChildNodes) {
                    newElement.AppendChild(n.Clone());
                }

                oldElement.ParentNode.ReplaceChild(newElement, oldElement);
            } catch {
                return false;
            }

        return true;
        }
    }

Wir legen eine ganz normale Klasse an, diese kann heißen wie man will, ich habe sie hier nur zum besseren Verständnis so benannt. In der klasse legen wir nun die Funktion an um die wir unsere Klasse erweitern wollen. Hierbei ist wichtig, dass sowohl die Klasse als auch die Funktion als public und static markiert wird. Des Weiteren sollte man einen Verweis auf System.Code.dll setzen.

Bei der Deklaration der Funktion muss man dann angeben welche Klasse erweitert werden soll. Hier erweitern wir die Klasse XmlDocument weswegen vor diesem Parameter noch ein this steht. Dieser Parameter wird nur dazu benötigt und muss dann später bei dem Aufruf der Funktion nicht gesetzt werden.

Bild 1: Auch IntelliSense erkennt unsere Erweiterung an und bietet diese an

Natürlich bleibt die "original" Klasse XmlDocument unberührt von dieser Aktion und wird nur virtuell erweitert. Diese Erweiterung ist natürlich auch nur für das Aktuelle Projekt nutzbar.

Ich finde dieses Feature wirklich sehr nützlich und kann es euch deswegen auch nur empfehlen.

public static bool RenameXmlElement(this XmlDocument doc,
XmlElement oldElement,
string newName) {
try {
//Neues XmlElement mit neuem namen anlegen
XmlElement newElement = oldElement.OwnerDocument.CreateElement(newName);

//Dem neuen XmlElement alle Attribute des alten Elements übergeben
foreach (XmlAttribute a in oldElement.Attributes) {
newElement.SetAttributeNode((XmlAttribute)a);
}

//Dem neuen XmlElement alle Kinder Elemente des alten Elements anhängen
foreach (XmlNode n in oldElement.ChildNodes) {
newElement.AppendChild(n.Clone());
}

oldElement.ParentNode.ReplaceChild(newElement, oldElement);
} catch {
return false;
}

return true;
}

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
20Jul/101

Windows Aero Glas in eigenen Projekten Nutzen Teil 5 – Der letzte Versuch

In den letzten Tagen habe ich mal wieder ein wenig mit der Windows API herumgespielt, speziell mit der Aero Glas API (DWMAPI). Ich habe euch ja auch noch versprochen einen Beitrag über Steuerelemente in Verbindung mit Glas nachzuliefern. Nunja hier ist er :)

Bild 1: Probleme mit der Transparenz

In Bild 1 sehen wir das Problem, viele der Windows Forms Steuerelemente nutzen GDI zur Darstellung und haben deswegen keinen Alpha-Kanal, der aber für die Darstellung auf Glas benötigt wird. Deswegen nutzen wir die Schwarze Farbe um unsere Fläche in Glas zu verwandeln, leider denkt der DWM dann, dass auch die Texte auf unseren Steuerelementen zu Glas werden sollen.

Ich habe mich nun ein wenig im Internet umgehört und verschiedene Ansätze gefunden und diverse Hacks mit der Windows32API Ausprobiert, die aber alle leider nicht mehr funktionieren. So will ich euch heute zwei Möglichkeiten vorstellen wie man es doch hinkriegen könnte.

1. Owner Drawing

Da die Steuerelemente mit GDI gerendert werden haben wir ein kleines Problem wie man oben sieht. Also müssen wir die Darstellung der Steuerelemente selbst in die Hand nehmen. Dieser Vorgang nennt sich OwnerDrawing und bedeutet soviel wie "SelberZeichnen". Ich will das Ganze mal anhand einer Textbox demonstrieren.

Und genauso ist auch das Vorgehen. Wir erstellen eine neue Klasse und nennen Sie "AeroTextBox". Diese Klasse erbt nun von der Original TextBox. Nun müssen wir ein paar kleine Änderungen an der Klasse vornehmen in Bezug auf die Darstellung, also des WM_PAINT Ereignisses.

Da wir das Zeichnen des Steuerelements selbst in die Hand nehmen wollen müssen wir die WM_PAINT Message abfangen und auf unsere eigene Methode umleiten:

C#


    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        base.WndProc( ref m);

        switch (m.Msg)
        {
            case 0xf: //WM_PAINT
                RedrawControlAsBitmap(this.Handle);
                break;
        }
    }

VB.NET


 Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
	MyBase.WndProc(m)

	Select Case m.Msg
		Case &Hf 'WM_PAINT
			RedrawControlAsBitmap(Me.Handle)
			Exit Select
	End Select
End Sub

Wie man sieht fangen wir hier die Message ab und rufen unsere eigene Methode auf, die das Zeichnen übernehmen wird:

C#


    public void RedrawControlAsBitmap(IntPtr hwnd)
    {
        Control c = Control.FromHandle(hwnd);
        using (Bitmap bm = new Bitmap(c.Width, c.Height))
        {
            c.DrawToBitmap(bm, c.ClientRectangle);
            using (Graphics g = c.CreateGraphics())
            {
                g.DrawImage(bm, new Point(-1, -1));
            }
        }
        c = null;
    }

VB.NET


Public Sub RedrawControlAsBitmap(hwnd As IntPtr)
	Dim c As Control = Control.FromHandle(hwnd)

	Using bm As New Bitmap(c.Width, c.Height)
		c.DrawToBitmap(bm, c.ClientRectangle)

		Using g As Graphics = c.CreateGraphics()
			g.DrawImage(bm, New Point(-1, -1))
		End Using
	End Using
	c = Nothing
End Sub

Was hier passiert ist eigentlich sehr simpel, wir zeichnen das Control neu und legen das gezeichnete Bild nun über das Control drüber. Nur diesmal machen wir das ganze mit einem Alpha Kanal, sodass der DWM uns die Darstellung nicht versaut!

Nun bleibt noch ein kleines Problem, nämlich dass bei manchen Aktionen des Benutzers wie zB. bei MouseOver oder KeyPress Events das Steuerelement neugezeichnet wird und unsere Funktion da oben nicht greift. Hier müssen wir manuell dafür sorgen, dass Windows erneut die WM_PAINT Message versendet. Das erreichen wir indem wir die einzelnen Events überschreiben und die Invalidate()-Methode aufrufen. Diese Methode erklärt die ganze Oberfläche des Steuerelements für ungültig und bewirkt, dass das Steuerelement neu gezeichnet wird.

C#


    protected override void OnMouseClick(System.Windows.Forms.MouseEventArgs e)
    {
        base.OnMouseClick(e);
        Invalidate();
    }

    protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
    {
        base.OnMouseMove(e);
        Invalidate();
    }

    protected override void OnTextChanged(System.EventArgs e)
    {
        base.OnTextChanged(e);
        Invalidate();
    }

    protected override void OnMouseEnter(System.EventArgs e)
    {
        base.OnMouseEnter(e);
        Invalidate();
    }

VB.NET


Protected Overrides Sub OnMouseClick(e As System.Windows.Forms.MouseEventArgs)
	MyBase.OnMouseClick(e)
	Invalidate()
End Sub

Protected Overrides Sub OnMouseMove(e As System.Windows.Forms.MouseEventArgs)
	MyBase.OnMouseMove(e)
	Invalidate()
End Sub

Protected Overrides Sub OnTextChanged(e As System.EventArgs)
	MyBase.OnTextChanged(e)
	Invalidate()
End Sub

Protected Overrides Sub OnMouseEnter(e As System.EventArgs)
	MyBase.OnMouseEnter(e)
	Invalidate()
End Sub

Nun wird das Control richtig dargestellt. Wie ihr vielleicht auch gesehen habt haben wir in unserer Methode, die für das Neuzeichnen verantwortlich ist nicht TextBox sondern die Superklasse Control benutzt. Das bedeutet für uns, dass wir mit diesem Code jedes Steuerelement ableiten und auf diese Weise neuzeichnen können mit mehr oder weniger viel Erfolg. Ich habe mal ein paar Klassen abgeleitet und für euch auf dem Glass-Form platziert:

Bild 2: Die OwnerDrawn Steuerelemente

Wie man sieht ist das schon eine sehr vielversprechende Verbesserung der Darstellung, wenn auch nicht perfekt. Aber natürlich steht es euch noch frei die Darstellung weiter zu verbessern und auf die einzelnen Steuerelemente anzupassen.

Nachdem ihr die selbst erstellten Klassen die von den einzelnen Steuerelementen erben einmal kompiliert habt, wird Visual Studio dies bemerken und euch diese neuen Steuerelemente zusammen mit den anderen in der Toolbox anbieten. Diese können dann wie gewohnt per Drag & Drop auf das Formular gezogen werden.

Bild 3: Bequemer Gehts nicht

Wie ihr euch vorstellen könnt ist es ein ziemlicher Aufwand jedes Steuerelement noch mal neu anzulegen und dessen komplette Darstellung zu übernehmen. Es ist wirklich sehr frickelig! Deswegen wird dieser Ansatz auch eher selten verwendet! Die Demo dazu könnt ihr euch übrigens am Ende des Artikels herunterladen.

Variante 2. "The Microsoft Way"

Natürlich stolpert man irgendwann bei der Recherche über das Windows API SDK in dem es einige Beispiele dazu gibt wie man die neuen Funktionen in Windows benutzt, darunter natürlich auch Glas.

Der Ansatz den Microsoft da aber nach ihrer eigenen Best Practise verwendet ist aber eher ernüchternd. Hier geht es nach dem Motto, platziert einfach keine Steuerelemente auf dem Glas! - Super nicht?

In dem einzigen Beispiel das Microsoft da aufführt wird eine Form gezeigt, dessen Rahmen in das Formular bis zum darauf liegendem Panel erweitert wurde, nicht wirklich spannend. Aber wenn ich so überlege, fällt mit spontan auch kein Windows Programm auf, bei dem irgendwelche Steuerelemente auf dem Glas liegen - kennt ihr welche? In dem meisten Programmen liegen fast nur Grafiken auf dem Glas oder so ähnliche Controls wie die im Windows Explorer.

Also sage ich es mal Microsofts Worten: lasst die Controls vom Glas weg oder benutzt WPF! ;-)

Hier noch die Demo zu der Variante 1: Download [VS 2008 Projekt]

Zur zweiten Variante habe ich keine Demo gemacht, ihr könnt euch ja das Windows API SDK herunterladen und dort im Aero Ordner nachgucken.

<< Teil 4 des Tutorials

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
8Jul/101

Microsoft SQL Server Compact Edition – Eine Einfuehrung

Oft müssen Clientprogramme große Datenmangen speichern, und in den meisten Fällen wird dazu eine Datenbank eingesetzt. Wenn man eine Internetverbindung voraussetzt kann man einen mächtigen Datenbank Server anbinden und die Daten in der Cloud sichern. Doch oft ist eine Offline Lösung viel einfacher und effektiver.

Inzwischen gibt es auch viele verschiedene lokale Datenbanksysteme wie zB. SQLite, DB4O oder auch MS SQL Server Compact Edition. Alle diese Serversysteme haben auch den Vorteil, dass diese auf den mobilen Systemen problemlos eingesetzt werden können, haben aber auch den Nachteil, dass sie meist nicht den Vollen Feature Umfang eines echten SQL Servers bieten können.

Vorbereitung

In diesem Artikel soll es um den SQL Server Compact Edition von Microsoft gehen, diesen wollte ich schon immer mal testen und nun hatte ich mal die Zeit dazu.

Sofern ihr es noch nicht habt könnt ihr den SQL CE Server kostenlos bei Microsoft herunterladen. Nach der Installation arbeiten wir wie gewohnt im Visual Studio.

Implementierung

Die ganze Implementierung der Datenbank, Erzeugung der Tabellen sowie die Anbindung erfolgt aus Visual Studio heraus. Die Funktionen die man dort hat sind aber auch  stark von dem Provider abhängig, so bieten verschiedene Provider mehr oder weniger Funktionalität.

Um eine Datenbank zu einem Projekt hinzuzufügen öffnet einfach den Projektmappen-Explorer (Ansicht->Projektmappen-Explorer) und Klickt mit der rechten Maustaste auf euer Projekt und dann auf "Hinzufügen"->"Komponente..." und wählt eine Lokale Datenbank aus. In dem Datenbank Assistent Fenster klickt nun 2 Mal auf "Zurück" um auf die erste Seite des Assistenten zu gelangen.

Klickt nun auf "Neue Verbindung". In dem folgendem Fenster sollte man darauf achten, dass als Datenquelle "Microsoft SQL Server Compact 3.5" ausgewählt ist.

Bild 1: Datenbank Konfiguration

Klickt nun auf "Erstellen..." nun solltet ihr das Fenster aus Bild 1 sehen. Wählt oben den Speicherort eurer Datenbank und legt wenn nötig ein Passwort fest um die Datenbank zu verschlüsseln. Bestätigt das Ganze noch zwei Mal mit OK. Visual Studio sollte euch dann darauf hinweisen, dass ihr vorhabt eine Lokale Datenbank zu verwenden und schlägt euch vor diese in euer Projekt zu importieren - das nehmen wir gerne an.

Visual Studio fügt die neu erzeugte Datenbank Datei dem Projekt hinzu und setzt auch die nötigen Verweise auf System.Data und auf System.Data.SqlServerCe.

Anlegen der Tabellen

Beim Anlegen der Tabellen in unserer Datenbank ist uns Visual Studio natürlich ebenfalls sehr behilflich. Öffnet einfach den Server-Explorer (Ansicht->Server-Explorer) und erweitert eure frisch angelegte Datenbank. (Eventuell müsst ihr auch ein Passwort angeben wenn ihr die Datenbank verschlüsselt habt)

Klickt nun mit der rechten Maustaste auf Tabellen und wählt "Tabelle erstellen" um den Tabellen Assistenten zu starten.

Bild 2: Tabellen Assistent

Hier könnt ihr eure Tabelle anlegen und konfigurieren. Wenn ihr die nun fertige Tabelle im Server-Explorer rechts anklickt und dann "Tabelleneigenschaften" wählt bekommt ihr noch mehr Konfigurationsmöglichkeiten wie etwa Beziehungen.

Bereits beim Erstellen der Tabellen ist es euch vielleicht schon aufgefallen, dass es nicht so viele Datentypen zur Auswahl gibt wie in einem richtigen SQL Server aber das sind nicht die einzigen Einschränkungen...

Arbeiten mit der Datenbank

Das Arbeiten mit der Datenbank gestaltet sich nicht anders als mit anderen Datenbanken. Die Objekte die man dafür benötigt heißen sogar fast gleich. Alle Klasse die man nutzt haben noch den Zusatz "Ce", also statt "SqlCommand" heißt es nun "SqlCeCommand".

Und auch die Nutzung unterscheidet sich nur geringfügig:

Datenbank Verbindung herstellen:


        private SqlCeConnection con;
        private string dbLocation = Environment.CurrentDirectory + "\\clipboard.sdf";
        private string conString;

        private void connectDB(){
            conString = "Data Source=\"" + dbLocation + "\"; Password=\"bigbasti.com\"; Encrypt=True";
            con = new SqlCeConnection(conString);
            con.Open();
        }

Eine Select Abfrage durchführen:


        ///
        /// Führt einen Select Befehl auf der Datenbank aus und gibt das ergebnis in einer DataTable zurück
        ///
        ///Der auszuführende Befehl
        /// Return: Ein DataTable mit den ausgelesenen Daten
        public DataTable executeSelect(string query) {
            connectDB();
            DataTable dt = new DataTable();
            SqlCeCommand com = new SqlCeCommand(query, con);
            SqlCeDataAdapter sad = new SqlCeDataAdapter(com);

            sad.Fill(dt);
            con.Close();
            return dt;
        }

        public int checkDouble(string link, string date) {
            int retVal;
            using (SqlCeConnection con = new SqlCeConnection(conString)) {
                con.Open();

                //Doppelte Einträge verhindern
                DataTable dt = executeSelect("SELECT * FROM cp_link WHERE link LIKE '" + link + "'");
                if (dt.Rows.Count > 0) {
                    executeNonQuery("DELETE FROM cp_link WHERE link LIKE '" + link + "'");
                }
            }
            return retVal;
        }

UPDATE, DELETE und INSERT:


        ///
        /// Executes an SQL statement against the SqlCeConnection and returns
        /// the number of rows affected.You also can use ExecuteNonQuery to
        /// change the data in a database without using a DataSet by executing
        /// UPDATE, INSERT, or DELETE statements.
        ///
        ///Der Befehl der ausgeführt werden soll
        /// The number of rows affected.
        public int executeNonQuery(string q) {
            int retVal;
            using (SqlCeConnection con = new SqlCeConnection(conString)) {
                con.Open();
                using (SqlCeCommand com = new SqlCeCommand(q, con)) {
                    retVal = com.ExecuteNonQuery();
                }
            }
            return retVal;
        }
        public int doSomeInsert(string link, string date) {
            int retVal;
            using (SqlCeConnection con = new SqlCeConnection(conString)) {
                con.Open();
                using (SqlCeCommand com = new SqlCeCommand("INSERT INTO cp_link  (link, date) VALUES (@link, @date )", con)) {
                    com.Parameters.AddWithValue("@link", link);
                    com.Parameters.AddWithValue("@date", date);
                    retVal = com.ExecuteNonQuery();
                }
            }
            return retVal;
        }

Hier gibts eigentlich nichts besonderes. Leider hat man hier, da es eine Compact Edition ist nicht so viele Befehle zur Verfügung wie im Original. So fehlt zB. auch der TRUNCAT Befehl wie ich erstaunt feststellen musste. Ich habe da nicht noch weiter recherchiert was noch alles fehlt, da ich für das was ich gemacht habe keine besonderen Aktionen benötigte.

Deployment

Wenn ihr das Projekt über ein Setup-Projekt deployen wollt dann sollte da eigentlich nichts schief gehen. Ihr könnt aber natürlich auch ohne ein extra Setup-Projekt deployen, dazu solltet ihr folgende Schritte machen:

  1. Öffnet die Eigenschaften eures Projekts
  2. Öffnet dort den "Veröffentlichen" (Publish) Tab
  3. Klickt auf den Knopf "Erforderliche Komponenten"
  4. Sucht den Eintrag "SQL Server Compact Edition 3.5" und entfernt das Häkchen und schließt die Eigenschaften
  5. Nun benötigen wir die erforderlichen DLL Dateien, diese liegen in "C:\Programe\Microsoft SQL Server Compact Edition\"
  6. Es sind 7 oder auch mehr Dateien, abhängig davon wie viele Sprachen installiert sind (siehe Bild links)
  7. Markiert diese DLLs und zieht diese direkt in den Projektmappen-Explorer, da mit diese DLLs dem Projekt hinzugefügt werden
  8. Markiert die neuen DLLs in dem Projektmappen-Explorer -> klickt mit der rechten Maustaste darauf und wählt "Eigenschaften"
  9. Setzt die Eigenschaft "In Ausgabeverzeichnis kopieren" auf "Kopieren, wenn neuer" damit ihr immer die Aktuelle Version im Build Verzeichnis habt
  10. Klickt im Projektmappen-Explorer mit der rechten Maustaste auf System.Data.SqlServerCe und wählt Eigenschaften
  11. Setzt hier die Eigenschaft "Lokale Kopie" auf True. Dieser Schritt ist nötig damit das Programm lokal nach der DLL sucht und nicht versucht sich diese aus dem GAC (Global Assembly Cache) zu holen.

Und das war es eigentlich schon. Nun könnt ihr das Projekt problemlos deployen.

VN:F [1.9.3_1094]
Rating: 10.0/10 (3 votes cast)
17Jun/101

.NET: Charts und Diagramme mit MSChart erstellen

Vor Kurzem musste ich für einen Kunden eine Datenauswertung in einer .NET Applikation realisieren und wollte dazu ein schönes Diagramm erstellen. Leider musste ich (zu meinem Erstaunen) feststellen, dass das .NET Framework über kein eigenes Control für solche Zwecke verfügt, zumindest nicht im Framework 3.5!

Nach ein wenig googlen bin ich dann auf die Charting Controls von Microsoft gestoßen, diese können hier heruntergeladen werden und für das Framework 3.5 nachinstalliert werden. Das Framework 4.0 bringt es gleich mit.

Nach der Installation steht euch der Namespace "System.Windows.Forms.DataVisualization.Charting" zur Verfügung, der wirklich alles woran man so denken kann mitbringt, und das völlig kostenlos! Dieses Control kann man auch in ASP.NET Projekten benutzen.

Die eigentlich Benutzung ist auch sehr einfach gehalten, so können wir mit diesem Code einen einfachen Graphen erstellen und anzeigen:


using System.Windows.Forms.DataVisualization.Charting;

        private void Form1_Load(object sender, EventArgs e) {
            chart1.Series.Add("Balcken");
            chart1.Series.Add("Area");

            //Ausssehen festlegen
            chart1.Series["Balcken"].ChartType = SeriesChartType.Column;
            chart1.Series["Linien"].ChartType = SeriesChartType.Line;
            chart1.Series["Area"].ChartType = SeriesChartType.Area;

            //Zufällige Werte generieren
            Random random = new Random();

            for (int pointIndex = 0; pointIndex < 10; pointIndex++) {

                chart1.Series["Area"].Points.AddY(random.Next(20, 50));
            }

            for (int pointIndex = 0; pointIndex < 10; pointIndex++) {

                chart1.Series["Balcken"].Points.AddY(random.Next(50, 100));
            }

            for (int pointIndex = 0; pointIndex < 10; pointIndex++) {

                chart1.Series["Linien"].Points.AddY(random.Next(70, 100));
            }
        }

Wie ihr sehen könnt ist es alles sehr sehr simpel aufgebaut und man hat mit nur wenigen Zeilen Code ein schönes Diagramm gemacht:

Bild 1: Schöne Diagramme schnell gemacht

Wie oben bereits erwähnt seid ihr nicht auf diese Diagrammtypen beschränkt, sondern habt eine ziemlich große Auswahl an verschiedenen Diagrammtypen, darunter auch welche mit Farbverläufen und auch in 3D!

Bild 2: Eine breite Auswahl an verschiedenen Visualisierungen

Bei der Auslieferung eurer App solltet ihr darauf achten, dass ihr die System.Windows.Forms.DataVisualization.dll mit ausliefert, da der Benutzer sonst die Anwendung nicht starten kann, da diese DLL nicht Bestandteil von Framework 3.5 ist. Wenn ihr aber mit Sicherheit wisst, dass der Benutzer das Framework in der Version 4.0 installiert hat könnt ihr euch diesen Schritt sparen!

Weitere Informationen findet ihr im MSDN. Ein Demoprojekt gibts hier:

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
10Jun/101

C#: Webservices ueber HTTPS nutzen

Wenn eure Anwendung mit Webservices zusammen arbeitet z.B. über HttpWebRequests und dieser Service eine sichere Verbindung voraussetzt müsst ihr die Zertifikate akzeptieren, die euch der Server sendet, damit eine Kommunikation zu Stande kommen kann.

Im .NET Framework ist das relativ einfach geregelt, man muss lediglich eine delegate Methode registrieren:


            System.Net.ServicePointManager.ServerCertificateValidationCallback +=
                delegate(
                    object sender,
                    System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                    System.Security.Cryptography.X509Certificates.X509Chain chain,
                    System.Net.Security.SslPolicyErrors sslPolicyErrors)
                {
                    return true;
                };

Diese Methode wird nun bei jedem HTTPS Aufruf gestartet. Deren Aufgabe ist es das übergebene Zertifikat zu prüfen und für gut oder schlecht zu befinden. In dem oberen Fall akzeptieren wir alle Zertifikate, egal ob sie sicher sind oder ungültig, dies wird oft zum Testen benutzt.

Natürlich stellen euch die Objekte X509Certificate und X509Chain viele Methoden zur Verfügung mit denen ihr den Hersteller und auch den Aufrufer überprüfen könnt.


           System.Net.ServicePointManager.ServerCertificateValidationCallback +=
                delegate(
                    object sender,
                    System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                    System.Security.Cryptography.X509Certificates.X509Chain chain,
                    System.Net.Security.SslPolicyErrors sslPolicyErrors)
                {
                    //Prüfen, ob das Zertifikat noch nicht abgelaufen ist ( > 0 -> Abgelaufen)
                    if (DateTime.Now.CompareTo(DateTime.Parse(cert.GetExpirationDateString())) < 0)
                    {
                        //Prüfen ob Zertifizierungsstelle bekannt ist (Werte für euch anpassen)
                        if (cert.Issuer.Equals("C=[country ID], S=[state], L=[location], O=[office], OU=[office unit], CN=[host name], E=email id"))
                        {
                            //Alles OK?
                            return true;
                        }
                    }
                    //Ansonsten das Zertifikat ablehnen
                    return false;
                };

So könnte eine einfache Prüfung aussehen, in der geprüft wird, ob das Zertifikat noch gültig ist und ob der Herausgeber bekannt ist. (Hier müsst ihr die Werte natürlich anpassen)

Wenn ihr diesen Aufruf nun einmalig tätigt, bevor ihr den ersten Webzugriff macht sollten keine Probleme bei der Kommunikation mit dem SSL Server auftreten!

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
12Mai/101

C#: Oeffentliche IP Adresse bestimmen

Vor einiger Zeit habe ich einen Artikel darüber geschrieben, wie man die Lokale IP Adresse bestimmen kann. Seit dem kamen immer wieder mal Anfragen nach der öffentlichen IP Adresse, also die Adresse, mit der wir durch das Internet unterwegs sind.

Bild 1: Aufbau eines gewöhnlichen Heimnetzwerks

Leider kann man diese IP Adresse nicht so einfach bestimmen, denn sobald ein Router im Spiel ist (und das ist er heutzutage in 98% der Fälle) ist man vom Internet getrennt.

Aber warum kann ich denn nun die öffentliche IP Adresse nicht auslesen?

Wenn ihr Bild 1 mal anschaut, werdet ihr feststellen, dass dieser Haushalt zwei Computer hat, die beide durch den Router in Internet kommen. (Ohne Router würde immer nur ein Computer gleichzeitig im Internet sein können) Aber wir haben vom Router nur eine Verbindung zum Internet. Das bedeutet, dass beide Rechner über die selbe Verbindung im Internet Surfen und auch beide die selbe IP Adresse in Internet haben.

Dies ist möglich, da der Router sich darum kümmert, dass jeder Rechner das bekommt was er will, dieser trennt das eigene Heimnetzwerk von dem öffentlichen Netzwerk (dem Internet) - somit weiß nur der Router welche IP wir nach außen hin haben, wir als einzelner Rechner kennen nur unsere Heimnetzadressen.

Wie kann ich nun meine öffentliche IP herausfinden?

Um dieses Ziel zu erreichen müssen wir uns leider Hilfsmittel bedienen. Die wohl einfachste Lösung ist es eine Seite im Internet danach zu "fragen" welche IP man hat, denn wenn wir über den Router auf eine Internetseite zugreifen, sieht die Internetseite nur die IP des Routers und das ist auch unsere Öffentliche IP.

Woher bekomme ich dieses Hilfsmittel?

Hier hat man zwei Möglichkeiten, erstens man kennt eine Internetseite die einem die IP Adresse anzeigt, oder man baut sich eine eigene. Denn der Aufwand dafür ist sehr gering, alles was man dafür benötigt ist ein einfaches PHP Skript:


	$ip = getenv("REMOTE_ADDR");
		print $ip;

Dieses Skript macht nichts anderes, als die IP Adresse des Aufrufers anzuzeigen und mehr benötigen wir ja auch nicht!

Dieses Skript speichert ihr nun in einer Datei namens "index.php" und speichert diese auf eurem Webserver. ACHTUNG: wenn ihr einen kostenlosen Webspace benutzt, kann es sein, dass der Anbieter automatisch bei einem Aufruf eigenen Code in eure Dateien schreibt, um zB. Werbung ein zublenden - ich empfehle euch einen eigenen, bezahlten Webspace zu nutzen oder auf fremde Dienste vertrauen.

Da ich diese Funktionalität auch öfters benötige habe ich mir schon ein solches Skript angelegt, dieses findet ihr unter http://myip.bigbasti.com - diese Adresse könnt ihr auch gerne in euren Programmen nutzen um eure IP zu bestimmen.

Nun müssen wir nur noch dieses Skript in unserem Programm abfragen. Und das geschieht sehr einfach mit einem HttpWebRequest - so als würde man eine ganz normale Webseite aufrufen (was wir ja auch tun!)


        /// Diese Methode liefert durch einen Webrequest die Öffentlich IP Adresse dieses Computers
        /// "provider">Die URL an die der Request gesendet werden soll. Bsp: http://myip.bigbasti.com
        /// returns>String mit der Öffentlichen IP Adresse in Punktnotation oder null bei Fehler
        public static String GetMyPublicIP(string provider)
        {
            try
            {
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(provider);
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                StreamReader reader = new StreamReader(response.GetResponseStream());

                return reader.ReadToEnd();
            }
            catch (Exception e)
            {}
            return null;
        }

Hier machen wir nichts anderes, als die Webseite auf zurufen, und das was sie ausgibt herunter zuladen und da das Einzige was sie ausgibt unsere IP ist müssen wir nichts mehr machen!

Die obere Funktion könnt ihr zum Beispiel so benutzen:

String myip = GetMyPublicIP("http://myip.bigbasti.com");

Im Prinzip gar nicht so komplex, die einzige Unbequemlichkeit bleibt aber natürlich der externe Dienst auf den man sich verlassen muss!

VN:F [1.9.3_1094]
Rating: 5.5/10 (2 votes cast)
29Apr/100

VB.NET: Einstellungen in der Windows Registry Speichern

In so gut wie jedem Computerprogramm müssen Informationen wie Einstellungen oder Benutzerdaten gespeichert werden. Um dies zu realisieren gibt es viele Ansätze wie zB: eine Datenbank, eine XML oder INI Datei oder direkt in der Registry. In diesem kleinem Tutorial werde ich auf die letztere Methode eingehen.

Zu nächst sei gesagt, dass ich es euch nicht empfehlen würde eine Einstellungen in der Registry zu sichern. Das hat folgende Gründe:

  • Die Daten sind sehr versteckt und nicht jeder Benutzer weiß, wie man an diese herankommt
  • Man kann diese nur sehr schwer sichern oder auf ein anderen System umziehen
  • Es wird oft vergessen diese Einstellungen aus der Registry zu löschen, sodass diese als "Leichen" im System bleiben
  • Speicherort ist von der Version des Programms abhängig

Auf der anderen Seite gibts aber auch natürlich Vorteile:

  • Einstellungen sind vor ungeübten Nutzern "geschützt"
  • Sehr geringer Programmier-Aufwand
  • Einstellungen können oft auch nach einer Neuinstallation weiter verwendet werden. (Kann auch zum Nachteil werden wenn Einstellungen fehlerhaft sind)

Besonders in früheren Windows Zeiten wurden fast alle Einstellungen in der Registry gesichert. Inzwischen setzt sich die Sicherung der Daten in XML Dateien durch und das .NET Framework bietet seit der 3er Version auch den Namensraum My.Settings mit denen diese XML Dateien automatisch erzeugt werden. Aber heute scheuen wir uns mal den anderen Weg an!

Wie oben bereits erwähnt kann man mit sehr wenig Aufwand seine Einstellungen in der Registry sichern, diese werden dabei hier gesichert:

HKEY_CURRENT_USER\Software\[Unternehmen]\[Programm]\[Version]

Hier werden die Einstellungen gesichert, dabei werden die Variablen in den Klammern automatisch gefüllt.

.Dazu bietet uns der Application-Namesraum alles was wir benötigen. Was wir aber noch machen sollten ist die Überprüfung der Werte und das Exceptionhandling.

Alles was man zum speichern eines Werts angeben muss ist der Name unter dem der Wert gespeichert werden soll und der Wert selbst. Alle Werte werden dann automatisch unter dem oberen Pfad abgelegt.


	'''
	''' Speichert einen Wert unter angegebenem Namen in der Registry
	'''
	Public Sub SaveSetting(ByVal name As String, ByVal value As String)
	    Try
	      	Application.UserAppDataRegistry.SetValue(name, value)
	    Catch ex As Exception
	      	debug.WriteLine("Fehler: " &amp; ex.Message)
	    End Try
  	End Sub

Um die Werte nun wieder auszulesen benötigt man lediglich den Namen, den man zum speichern benutzt hat und man bekommt den Wert aus der Registry geworfen!


	'''
	''' Lädt den String aus der Regitry passend zu dem angegebenem Namen
	'''
	Public Function LoadSetting(ByVal name As String) As String
		Try
			If Not Application.UserAppDataRegistry.GetValue(name) Is Nothing Then
				Return CType(Application.UserAppDataRegistry.GetValue(name), String)
		  	Else
		    	Return String.Empty
		  	End If

		Catch ex As Exception
		  	debug.WriteLine("Fehler: " &amp; ex.Message)
		  	Return String.Empty
		End Try
	End Function

Hier muss man aber beachten, dass das Programm, das die Werte ausließt die selbe Version haben muss wie das was sie in die Registry geschrieben hat, da der Pfad (siehe oben) nicht mehr passt!

Wenn man die oberen Methoden implementeirt hat kann man nun die Einstellungen sehr bequem speichern:


	'Die Einstellung aller Controls auf der Form speichern
	Sub Button1Click(sender As Object, e As EventArgs)
		Dim rs As New RegSaver 'Diese Klasse beinhaltet die oben definierten Funktionen

		'Daten für alle Controls speichern
		For Each c As Control In Me.Controls
			If TypeOf c Is RadioButton Then
				Dim a As RadioButton = CType(c, RadioButton)
				rs.SaveSetting(a.Name,a.Checked)
			End If

			If TypeOf c Is CheckBox Then
				Dim a As CheckBox = CType(c, CheckBox)
				rs.SaveSetting(a.Name,a.Checked)
			End If

			If TypeOf c Is TextBox Then
				Dim a As TextBox = CType(c, TextBox)
				rs.SaveSetting(a.Name,a.text)
			End If
		Next
	End Sub

und auch wieder auslesen:


	'Die werte aller Controls wieder laden
	Sub MainFormLoad(sender As Object, e As EventArgs)
		Dim rs As New RegSaver
				'Daten für alle Controls laden
		For Each c As Control In Me.Controls
			Try	'beim ersten starten gibt es keinen wert der gecastet werden kann!
				If TypeOf c Is RadioButton Then
					Dim a As RadioButton = CType(c, RadioButton)
					a.Checked = cbool(rs.loadsetting(a.Name))
				End If

				If TypeOf c Is CheckBox Then
					Dim a As CheckBox = CType(c, CheckBox)
					a.Checked = cbool(rs.loadSetting(a.Name))
				End If
			Catch ex As Exception
				debug.WriteLine("Fehler: " &amp; ex.Message)
			End Try

			If TypeOf c Is TextBox Then
				Dim a As TextBox = CType(c, TextBox)
				a.Text = rs.loadSetting(a.Name)
			End If
		Next
	End Sub

Wenn die Werte das erste Malgeladen werden, kann es zu fehlern kommen, da man NULL-Strings zurückbekommt, deswegen sollte man hier immer die Exceptions catchen! Falls es in der Registry noch keine passenden Einstellung zu dem Namen gibt, wird diese beim Laden automatisch angelegt!

Bild 1: Demoapplikation mit den geladenen Einstellungen

Wenn der Code durchgelaufen ist wird folgende Struktur in der Registry angelegt:

Bild 2: Die Einstellungen in der Registry

Natürlich bleibt es euch überlassen, wie ihr die Einstellungen benennet, ich habe hier den Namen des Controls verwendet um dessen Status zu speichern, damit ich nicht so viel Code schreiben musste.

Welche Methode ihr nutzt müsst ihr natürlich selber an Hand des Projekts entscheiden, kennen sollte man sie aber alle.

Ein Kleines Demoprojekt gibts hier:

Download: Diesmal ausnahmsweise ein SharpDevelop Projekt

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
23Mrz/100

Asynchrone Programmierung (mit der TPL) Teil 2

Ja, ich weiß, lang ist es her, dass ich den ersten Teil geschrieben habe aber nun (nach nur 5 Monaten) gehts endlich weiter, und diesmal wirds neben der Theorie auch Code geben!

Wie ihr seht habe ich den Titel etwas abgeändert nun tauchen da drei neue Buchstaben auf die ihr (vielleicht) noch nie gehört habt, diese stehen für Task Parallel Library. Wie der Name es schon sagt, ist es eine Library die es uns ermöglicht parallel zu programmieren, aber dazu später mehr!

Machen wir erstmal mit ein wenig Theorie weiter. Im ersten Teil haben wir erfahren, dass es nicht automatisch heißt, dass ein Programm schneller wird, wenn man viele Prozessoren im Rechner verbaut hat, und diesen Gedanken möchte ich in dem zweiten Teil noch etwas fortführen.

Dazu möchte ich ein Beispiel geben. Nehmen wir an wir haben eine Funktion geschrieben, in der eine FOR-Schleife vorkommt die viele Berechnungen anstellt und die Ergebnisse in ein Array Speichert zb so:


        static double [] oldWay = new double[10000000];
        public static void doitOldSchool()
        {
            for (int i = 0; i < oldWay.Length; i++)
            {
                oldWay[i] = (Math.Sin(i) / Math.Cos(i)) * Math.Tan(i) * 12345;
            }
        }

Ich denke so eine Schleife hat schon jeder mal geschrieben, da ist nichts kompliziertes dran, sie funktioniert auch hervorragend und liefert uns ein Ergebnis.

Die obere Schleife ist natürlich sehr simpel und ein Durchgang ist schnell erledigt, aber die Schleife wird hier 10 Millionen mal durchlaufen - und das ist ne Menge! Stellt euch vor irgendwann später wird diese Schleife um weitere Rechnungen oder Aktionen erweitert, dann könnte sie die Anwendung dauerhaft blockieren und einfrieren lassen.

Anmerkung: Dies ist nur ein Beispiel, im wahren Leben ist sowas natürlich blöd, da würde die Schleife viel weniger Durchläufe haben, aber dafür einen größeren Body, was die Sache wieder ausgleicht!

Spätestens wenn die Anwendung merkbar langsamer wird lohnt es sich über Parallelisierung nachzudenken, denn wenn inzwischen eh fast jeder Rechner und Laptop eine Mehrkern CPU hat würde das Programm doch schneller laufen oder?

Hier muss man aufpassen, denn die Parallelisierung bietet viele Fallen, denn wenn man die obige Schleife parallelisiert wird sie in sehr viele einzelne Threads zerteilt und auf alle CPU Kerne verteilt. Man kann es sich ungefähr so vorstellen, dass jeder Schleifendurchgang einen Einzelnen Thread bekommt.

Das hört sich eigentlich ganz toll an, aber hier darf man nicht aus den Augen verlieren, dass es auch seine Zeit dauert einen Thread zu erzeugen und dieser erzeugte Thread muss irgendwann auch vernichtet werden. Das heißt also, dass es Zeit kostet einen Thread anzulegen und zu zerstören, und wenn wir uns unsere Schleife so anschauen werden dort ziemlich viele Threads gebildet und auch vernichtet. So kann es vorkommen, dass ein parallel laufendes Programm langsamer ist als sein sequentielles Ebenbild!

Hier gilt aber ein einfache Regel, es muss sich "lohnen" einen Thread zu erzeugen. Das heißt, dass ein Thread auch was zu tun haben muss, in unserem Beispiel ist die Berechnung so schnell, dass das Erzeugen und Vernichten des Threads länger dauert als die Berechnung!

Aber das hängt auch noch von der verwendeten Hardware ab, so werden zu Beispiel Threads auf einem 64-Bit System ca. 30% schneller erzeugt als auf einem 32-Bit System. Desweiteren wird die Performance von der Anzahl der CPU-Kerne beeinflusst, denn wenn davon genug da sind können viel mehr Aktionen gleichzeitig laufen was natürlich das Programm beschleunigt.

Aber gut, genug der Theorie. Nun wollen wir ein bisschen in die Praxis gehen und gucken wie wir mit der Parallelisierung an der Performance der Anwendung schrauben können! Wenn wir die Obige sequentielle Schleife so ausführen benötigt diese knapp 2 Sekunden um alle 10 Millionen Werte zu berechnen:

Bild 1: Das Ergebnis der Sequentiellen Schleife (Core2Duo @ 2,4 gHz)

Gar nicht mal schlecht was man in 2 Sekunden alles berechnen kann! Aber das Blöde hierbei ist, dass die Anwendung dann natürlich 2 Sekunden Blockiert ist. Versuchen wir nun mal die Arbeit gerecht auf alle Prozessoren (in diesem Falle 2) zu verteilen!

Dazu ist aber etwas Vorbereitung nötig. Die TPL wird von Visual Studio 2010 von Haus aus unterstützt, desweiteren wird auch das .NET Framework in der Version 4.0 benötigt, außerdem macht es auch Sinn einen Rechner mit mehr als einem CPU-Kern zu haben ;-) Es müsste auch mit Visual Studio 2008 gehen wenn man das .NET Framework 4 installiert, aber dafür lege ich nicht meine Hand ins Feuer!

Wenn das erledigt ist könnt ihr ein neues C# Konsolen Projekt anlegen. Alles was wir brauchen befindet sich in dem Namespace System.Threading.Tasks, weswegen wir das importieren sollten!

Nun wollen wir unsere FOR-Schleife in eine parallele FOR-Schleife umwandeln. Zum Glück ist das einfacher als es sich anhört, da und die TPL alles nötige zur Verfügung stellt! Schreiben wir also die Schleife folgendermaßen um:


        static double [] newWay = new double[10000000];
       public static void doitNewSchool()
        {
            Parallel.For(0,                 //From (Startwert)
                        newWay.Length,      //TO   (Endwert)
                        (i) =>              //Initialisierung der Variablen
                        {                   //Code der ausgeführt werden soll
                           newWay[i] = (Math.Sin(i) / Math.Cos(i)) * Math.Tan(i) * 12345;
                        });
        }

Zugegeben, auf den ersten Blick sieht das ganze verwirrend aus, da der Kopf der Schleife sich geändert hat. Aber auf den zweiten Blick erkennt man viel wieder. So beginnt die Schleife ebenfalls mit dem Startwert, gefolgt von der Abbruchbedingung. Nun kommt das neue, denn die TPL verwendet hier die so genannten Lambda Ausdrücke, die mit C# 3.0 Einzug erhielten. So ist es nun möglich ganze Codeblöcke in Parameter Felder zu setzen und vieles mehr.

Aber man langsam, man beginnt hier mit der Initialisierung der benötigten Variablen in diesem Fall nur eine namens "i", die Initialisierung erfolgt Typenlos in runden Klammern mit dem Pfeil dahinter wird der dazugehörige Codeblock initiiert (Anonyme Methoden). (ihr könnt die Variablen auch Typisieren, wenn ihr aber keinen Typ angibt wird er automatisch bestimmt!)

Der Inhalt der Schleife bleibt hierbei aber exakt der gleiche, praktisch oder? Aber was passiert nun genau? Naja einfach ausgedrückt wird der Block in viele einzelne Teile zerbrochen die in eigenen Threads dann über die verfügbaren CPU-Kerne verteilt werden. Schließlich werden die Ergebnisse wieder zusammengetragen!

Bevor wir nun hingehen und die neue Schleife testen will ich euch noch was zeigen. Auf dem Folgenden Screenshot sieht man die CPU-Auslastung während unsere erste sequentielle Schleife läuft:

Bild 2: CPU-Auslastung während sequentieller Berechnung

Wie man ganz klar erkennen kann werden beide Kerne belastet! Wie kann das sein? Das Programm ist doch sequentiell! Die Erklärung ist relativ simpel, denn das System (hier Windows 7) erkennt auch, dass da ein Programm einen Kern überlastet und verteilt die Last automatisch auf andere Kerne. Ok, und warum soll ich mir nun die mühe machen und parallel programmieren wenn das System das doch auch so für mich macht?

Ganz einfach, weil das System es schlecht macht. Hier kann man es nicht erkennen, da der PC nur 2 Kerne hat. Wenn man mehr Kerne hätte würde man erkennen, dass das System, zwar versucht einen Kern zu entlasten und die Arbeit zu verteilen, aber es bezieht nur 1, vielleicht 2 weitere kerne in die Arbeit mit ein, alle anderen dürfen weiter "karten spielen" und auf Arbeit warten. Wenn wir aber unser Programm parallel gestalten, werden alle verfügbaren Kerne ausgenutzt!

Ok, dann wollen wir mal unsere überarbeitete parallel laufende Schleife mal anschmeißen:

Bild 3: Parallel laufende Schleife

Ahja, wie man sieht konnte unsere neue Schleife die Werte in fast der halben Zeit berechnen. Das ist eine enorme Steigerung! Schauen wir uns auch nochmal die CPU-Auslastung an:

Bild 4: Steile Berge

Man erkennt sofort, dass die CPU hier sehr viel effizienter genutzt wird, die Auslastung steigt kurz bis an das Maximum an und geht danach direkt wieder runter! Vergleicht man das Bild mit dem Sequentiellen sieht man auch, dass beide Kerne fast gleichstark und auch durchgängig belastet werden. Die last wird perfekt auf die verschiedenen Kerne verteilt!

Ruft man beide Funktionen hintereinander zur Laufzeit auf, wird der Unterschied noch besser sichtbar:

Bild 5: 100% Schneller

Der Unterschied ist gewaltig, man würde den Unterschied noch mehr spüren, wenn man eine Schleife mit einem Größerem Body testen würde, aber das könnt ihr dann ja mal selber irgendwann üben.

In bild 5 sieht man die Ergebnisse der Berechnung auf einem Windows 7 32 Bit Rechner mit einem Core2Duo mit 2,4 gHz. Schauen wir uns doch mal an, wie die Zahlen abweichen wenn wir ein System haben dass ein paar mehr Kerne hat und im 64 Bit Modus läuft:

Bild 6: Unglaublich oder?

Hier sieht man es nochmal ganz deutlich wie überlegen die parallel programmierte Schleife der sequentiellen ist. So sieht die CPU Verteilung aus auf einem 64 Bit System mit 16 Kernen:

Bild 7: Gegenüberstellung (Zum vergrößern klicken)

Wie man sieht beansprucht die sequentielle Schleife nur 4 der Prozessoren, und das nicht mal ganz. Die parallele Schleife dagegen hat 15 der 16 Kerne belastet und ist dem entsprechend 10 mal schneller fertig geworden!

Zum Schluss will ich noch eine kleine Schwäche der Parallelen Variante (wenn man sie Schwäche nennen mag) zeigen. Ich habe hier ganz bewusst eine Schleife genommen, die 10 Millionen mal ausgeführt wird, denn wenn die Schleife kleiner wird, hat man mit der Parallelen Schleife keinen Vorteil mehr!

Die Erklärung dafür habe ich zu Beginn dieses Artikels gegeben, denn die Thread Erzeugung dauert einfach viel zu lange! So sieht man hier den Ablauf der selben Schleife mit 100.000, 10.000 und 1000 Durchgängen:

Bild 8: Man muss vorher abwägen

Man muss sich unbedingt vorher Gedanken machen, ob es sich lohnt einen Prozess zu parallelisieren.

In dem Nächten Teil, der (ich hoffe) bald kommt werde ich euch dann noch ein paar weitere Gefahren zeigen, und auch Methoden wie man die Parallelisierung noch ein wenig beschleunigen kann, sowie auch weitere Beispiele mit anderen Schleifen und ganzen Codeblöcken!

Ich hoffe der Artikel hat euch gefallen und freue mich auf euer Feedback!

Die Demoanwendung gibts hier:

.

.

VN:F [1.9.3_1094]
Rating: 9.0/10 (1 vote cast)
19Mrz/100

.NET: Taskleiste und Start Button ausblenden

Vor einer Weile habe ich einen Artikel geschrieben, in dem ich zeige wie man die Windows Taskleiste ausblenden kann, sodass nur der Startbutton übrig bleibt. Nun wollen wir auch noch den Startbutton entfernen, sodass von der Taskleiste nichts mehr übrig bleibt!

Das Vorgehen ist hierbei fast das gleiche, der Unterschied besteht nur darin, dass der Prozess, der für die Anzeige des Start-Buttons verwendet wird etwas schwerer zu finden ist! Diesen Prozess werdet ihr vergeblich in der Process.getProcesses() Übersicht des .NET Frameworks suchen.

Hier müssen wir so vorgehen wie in dem Beitrag "Alle Sichtbaren Prozesse auflisten" und benutzen deshalb die Windows Funktion "EnumWindows" die uns alle Fensterprozesse liefert, inklusive dem Start-Button Prozess.

Suchen müssen wir hier den Prozess mit dem Titel "Start" und von der Klasse "Button". Ich habe hier um die Arbeit zu erleichtern 2 kleine Klassen geschrieben. (Ich werde bald eine Library veröffentlichen mit weiteren Funktionen)


            ProcessListDemo.Windows windows = new ProcessListDemo.Windows();

            foreach (ProcessListDemo.Window w in windows.lstWindows)
            {
                if (w.winTitle == "Start" &amp;amp;&amp;amp; w.winClass == "Button" &amp;amp;&amp;amp; w.winVisible == true)
                {
                    sbHandle = w.winHandle;
                    if (sbHandle != IntPtr.Zero)
                    {
                        ShowWindow(sbHandle, 0);
                    }
                    else
                    {
                        //Fehler
                    }
                }
            }

Wenn man nun das Handle des Startbuttons hat kann man mit der Windows Funktion ShowWindow das Fenster bzw. den Button ausblenden.

Bild 1: Demoanwendung kann nun auch den Startbutton verschwinden lassen

Wundert euch nicht, dass der Button nicht verschwindet wenn ihr den Code ausführt, denn erst wenn auch die Taskleiste verschwunden ist ist auch der Button weg. Also kann man nur den Button anzeigen oder Taskleiste und Button. Nur die Taskleiste (also ohne den Start Knopf) Geht leider nicht!

Probiert es einfach mit der Demoanwendung aus:

.

.

VN:F [1.9.3_1094]
Rating: 0.0/10 (0 votes cast)
18Mrz/100

VB.NET: Netzwerkadapter Einstellungen auslesen

Das .NET Framework bietet viele sehr nützliche Schnittstellen, so auch um Netzwerkinformationen auszulesen. Alles was man braucht findet man in dem System.Net Namensraum. In dieser Demo möchte ich euch zeigen, wie man alle verfügbaren Netzwerkadapter auflistet und deren Informationen ausließt.

So lässt sich sehr einfach eine Auflistung aller Netzwerkschnittstellen des Systems zusammenstellen:


    Dim adapter As NetworkInterface     'Eine Netzwerkadapter Instanz
    Dim adapters As NetworkInterface()  'Array mit allen Netzwerkadaptern

    Public Sub DisplayDnsConfiguration()
        adapters = NetworkInterface.GetAllNetworkInterfaces()

        'Alle Adapter in der Liste durchlaufen
        For Each Me.adapter In adapters
            Dim properties As IPInterfaceProperties = adapter.GetIPProperties()

            lstNetworks.Items.Add(adapter.Description)
        Next adapter
    End Sub

Hier wird die lstNetworks mit allen verfügbaren Netzwerkadaptern gefüllt. Da wir nun die Bezeichnungen der Netzwerkadapter haben können wir uns nun daran machen deren Einstellungen auszulesen.

Die Einstellungen sind hierbei genauso schnell ausgelesen, denn wenn man erst die richtige NetworkInterface-Instanz erwischt hat kann man ganz bequem auf die Einstellungen zugreifen:

bild1Bild 1: Ein paar Eigenschaften des Netzwerkadapters

Den dazugehörigen Code spare ich mir mal an dieser Stelle, da es einfach zu viel Text ist. Ihr könnt diesen aber natürlich in dem Demoprojekt nachgucken.

Wie in Bild 1 auch zu erkennen ist hat man auch Zugriff auf die übertragenen Bytes in beide Richtungen. So kann man zB. auch sehr einfach die aktuelle Netzwerkauslastung bestimmen, indem man den alten Wert speichert und mit dem neuen Wert nach einer Sekunde vergleicht. Dadurch bekommt man die übertragenen Bytes pro Sekunde. (Dies könnt ihr auch in dem Demoprojekt nachgucken)

bild2

Bild 2: Das Demoprogramm in Aktion (klicken zum Vergrößern)

In dem Demoprogramm habe ich mal versucht die am häufigsten benötigten Informationen einer Netzwerkschnittstelle zusammenzufassen, aber das meiste ist hier aber auch nur Copy’n’Paste!

Das Demoprogramm zeigt alle verfügbaren netzwerkschnittstellen, deren Eigenschaften sowie die aktuelle Adapterauslastung in KB/s.

vs2008demo

VN:F [1.9.3_1094]
Rating: 9.7/10 (3 votes cast)
Get Adobe Flash playerPlugin by wpburn.com wordpress themes