Samstag, 30. Oktober 2010

Allgemeiner Fehler in GDI+

Die Fehlermeldung "Allgemeiner Fehler in GDI+." ist ganz schön fies in C# - sie tritt sporadisch auf und die Ursache ist oft auf den ersten Blick nicht ersichtlich. Deswegen werde ich diesen Post der Fehlermeldung und ihren Ursachen widmen und die meiner Meinung nach 2 häufigsten Quellen des Grafikfehlers beschreiben.
Der oben genannte Fehler kann auftreten wenn ein Bild (Image) über die Methode Save() in einen nicht existierenden Pfad gespeichert werden soll.
Folgender Code versucht, den Inhalt der pictureBox als Bild zu speichern und wirft dabei die Fehlermeldung, sofern der angegebene Pfad nicht vorhanden ist:

pictureBox1.Image.Save("C:\\NichtExistierenderPfad\\test.jpg");

Beim Laden eines Bildes führt ein falscher Pfad dagegen zu einer FileNotFoundException.
Eine weitere sehr häufige Ursache des leidigen Fehlers "Allgemeiner Fehler in GDI+." ist die Nichtfreigebung eines Bildobjekts.
Lädt man ein Bild z.B. über die Methode Image.FromFile(), bleibt dieses solange im Speicher geöffet, bis es nicht freigegeben wird. Insbesondere ist vor dem Freigeben kein Speichern über Save() möglich.
Das folgende Codebeispiel lädt ein Bild in die pictureBox und versucht dann, dieses zu speichern - doch es tritt der "Allgemeiner Fehler in GDI+." Fehler auf, da das Bild nicht freigegeben wurde.

pictureBox1.Image = Image.FromFile("C:\\test\\test1.jpg");
pictureBox1.Image.Save("C:\\test\\test2.jpg");

Das Bild muss zur korrekten Funktionsweise des Codes intern "umkopiert" werden:

pictureBox1.Image = Image.FromFile("C:\\test\\test1.jpg");
Image Copy = pictureBox1.Image;
Copy.Save("C:\\test\\test2.jpg");

Ich hoffe, der Post hat die grundlegende Problematik dieses Fehlers deutlich gemacht, über weitere Ursachen, Besonderheiten etc. bin ich jederzeit dankbar!

Donnerstag, 28. Oktober 2010

Bild in byte - Array speichern

Um mit C# ein Bild (Image) in ein byte - Array zu konvertieren, speichern wir das Bild zuerst in einen Stream und kopieren den Inhalt dieses Streams dann in ein byte - Array.
Prinzipiell kann jeder Streamtyp dazu verwendet werden, am einfachsten ist jedoch die Verwendung eines MemoryStreams, welcher lediglich temporär Daten in den Arbeitsspeicher schreibt bzw. daraus liest.
Ein Bild vom Typ Image kann über die Methode Save() in den als 1. Parameter spezifizierten Stream geschrieben werden, als 2. Parameter kann das Format angegeben werden, in welchem das Bild gespeichert werden soll (also z.B. Gif oder Bmp).
Der folgende Beispielcode speichert den Inhalt der pictureBox auf dem Formular in einem byte - Array:

            MemoryStream TempStream = new MemoryStream();
            byte[] ImageInBytes;

            pictureBox1.Image.Save(TempStream, System.Drawing.Imaging.ImageFormat.Gif);
            ImageInBytes = TempStream.ToArray();

Dienstag, 26. Oktober 2010

Code mit #region gliedern

Bei größeren Codeprojekten kann die Codeansicht schnell unübersichtlich werden, sind alle Methoden etc. erweitert ist ganz schön Scrollarbeit nötig, um von oben im Quellcode bis nach unten zu kommen.
Doch Codeblöcke lassen sich mit C# auch ganz einfach gliedern, und zwar mit dem Schlüsselwort #region.
Dieses Schlüsselwort beginnt einen Block welcher durch #endregion beendet werden muss.
Die definierten Regionen können dann z.B. wie Methoden ein- oder ausgeklappt werden, die folgenden 2 Bilder zeigen dies:

"Normal" (ausgeklappt):










Eingeklappt:

Mittwoch, 20. Oktober 2010

Komprimierung mit C#, Teil 3 - Archive erstellen und wieder entpacken

Im 3. und (vorerst) letzten Teil zur Reihe "Komprimierung in C#" möchte ich euch eine Möglichkeit zeigen, mehrere Dateien auf einmal in einem Archiv zu komprimieren und dieses wieder zu entpacken.
Um diesen Post hier zu verstehen, ist ein Verständnis der Techniken aus Teil 1 und 2 hilfreich.
Mehrere Dateien in ein Archiv zu verpacken, geht in C# nur über einen kleinen Umweg, denn das verwendete gzip - Format unterstützt standardmäßig nur die Komprimierung von einzelnen Dateien.
Sammlungen von mehreren Dateien werden so meistens zuerst mit tar und dann mit gzip komprimiert, sie erhalten dann die Endung .tar.gz.
Obwohl uns das tar - Format in .Net nicht zur Verfügung steht, lässt sich eine Komprimierung von mehreren Dateien doch umsetzen: Wir fassen die einzelnen Dateien einfach zu einer großen Datei zusammen, in welcher die Dateien durch besondere Zeichen voneinander getrennt sind. Diese große Datei wird dann komprimiert und beim Dekomprimieren wieder anhand der Sonderzeichen in die einzelnen Dateien aufgeteilt.

Die Technik:
Als Kennzeichnung zwischen den Dateien schrieb ich folgenden Header vor jede Datei in den Stream:
|*START*OF*HEADER*|*||GRÖSSE_DER_DATEI||NAME_DER_DATEI*|*END*OF*HEADER*|
Probleme könnte es also in dem unwahrscheinlichen Fall geben, wenn der Inhalt einer Datei der Struktur gleichen würde.

Die Komprimierung / Erstellung eines Archivs:
Der Methode zur Komprimierung werden die zu komprimierenden Dateien als String - Array übergeben sowie der Name und Pfad des Archivs.
Die Dateien werden nun durchlaufen und der jeweilige Header sowie anschließend der Inhalt der Datei wird zuerst in einen MemoryStream geschrieben.
Die Daten aus diesem werden anschließend in ein byte - Array kopiert und dieses wird dann mit einem GZipStream in die Archivdatei geschrieben.
Dadurch, dass die Dateien erst zusammengefasst und dann mit dem GZipStream geschrieben werden und nicht jede Datei nacheinander in das Archiv geschrieben wird, kann das Archiv viel stärker komprimiert werden, da auch Redundanzen zwischen den einzelnen Dateien ausgenutzt werden können.
Der Code:

        private void CreateArchive(string[] files, string archiv)
        {
            GZipStream CompressStream = new GZipStream(new FileStream(archiv, FileMode.Create), CompressionMode.Compress);
            FileStream NormalFileStream;
            byte[] Content;

            ASCIIEncoding encoder = new ASCIIEncoding();
            byte[] HeaderStart = encoder.GetBytes("|*START*OF*HEADER*|*");
            byte[] HeaderEnd = encoder.GetBytes("*|*END*OF*HEADER*|");
            byte[] FileSize; // Größe der aktuellen Datei
            byte[] Separator = encoder.GetBytes("||");
            byte[] FileName; // Name der aktuellen Datei

            MemoryStream TempStream = new MemoryStream();

            foreach (string file in files)
            {
                NormalFileStream = new FileStream(file, FileMode.Open);
                FileSize = encoder.GetBytes(NormalFileStream.Length.ToString());
                FileName = encoder.GetBytes(file.Substring(file.LastIndexOf('\\') + 1));

                TempStream.Write(HeaderStart, 0, HeaderStart.Length);
                TempStream.Write(Separator, 0, Separator.Length);
                TempStream.Write(FileSize, 0, FileSize.Length);
                TempStream.Write(Separator, 0, Separator.Length);
                TempStream.Write(FileName, 0, FileName.Length);
                TempStream.Write(HeaderEnd, 0, HeaderEnd.Length);

                Content = new byte[NormalFileStream.Length];
                NormalFileStream.Read(Content, 0, Content.Length);
                NormalFileStream.Close();
                TempStream.Write(Content, 0, Content.Length);
            }

            byte[] BigFileContent = new byte[TempStream.Length];
            TempStream.Position = 0;
            TempStream.Read(BigFileContent, 0, BigFileContent.Length);
            CompressStream.Write(BigFileContent, 0, BigFileContent.Length);
            CompressStream.Close();
        }


Die Dekomprimierung / Entpackung eines Archivs:
Die Komprimierung war der einfache Part, die Dekomprimierung gestaltet sich etwas schwieriger.
Die Methode zur Dekomprimierung erhält den Pfad und Namen des Archivs sowie den Pfad, in den die Dateien anhand ihrer ursprünglichen Namen entpackt werden sollen.
Zuerst müssen die Daten aus der Archivdatei dekomprimiert werden, hierzu wird diese mit einem GZipStream ausgelesen.
Der Inhalt dieses wird anschließend in einen MemoryStream kopiert und dieser schreibt seinen Inhalt in ein byte - Array (ist leichter über einen MemoryStream, deswegen der Umweg).
Das byte - Array wird mit einer Instanz der Klasse ASCIIEncoder in einen String umgewandelt.
Das Auswerten des Inhalts erfolgt in einer Endlosschleife, in jedem Durchlauf wird eine Datei behandelt.
Es gibt 2 Zeiger, die auf eine Position im String zeigen.
Der erste speichert die aktuelle Position, der zweite die aktuelle Suchposition.
Der erste steht immer auf der Position, an der der Header der aktuellen Datei anfängt, der zweite auf eine um 22 höhere Position (da wo die Dateigröße anfängt).
Da die Struktur des Headers bekannt ist (z.B. die Größe der ersten Datei beginnt ab Position 22 und geht bis zum ersten Vorkommen von "||" - deshalb steht die Suchposition auf einer um 22 höheren Position als die aktuelle Position, nach der Suchposition markiert das erste Vorkommen von "||" das Ende der Dateigröße, davor taucht noch ein "||" vor der Dateigröße aus.), können Dateigröße und Name ausgelesen werden.
Die aktuelle Position wird nun um die Länge des Headers inkrementiert.
Mit einem FileStream wird nun das byte - Array, welches den Inhalt der großen Datei speichert, von der aktuellen Position bis zur Position aktuelle Position zuzüglich aktueller Dateilänge, in eine neue Datei geschrieben, diese wird im übergebenen Verzeichnis angelegt und trägt den Namen der ursprünglichen Datei.
Die Positionszeiger werden anschließend um die Größe der aktuellen Datei erhöht.
Der Code:
        private void OpenArchive(string archiv, string decompressPath)
        {
            GZipStream DecompressStream = new GZipStream(new FileStream(archiv, FileMode.Open), CompressionMode.Decompress);
            FileStream NormalFileStream;
            MemoryStream TempStream = new MemoryStream();

            ASCIIEncoding decoder = new ASCIIEncoding();
            ASCIIEncoding Encoder = new ASCIIEncoding();

            string StringFromBytes; // String - Darstellung der eingelesenen Bytes
            int EndSize; // Position im Header, an welcher die Bezeichnung der Dateigröße zu Ende ist
            long FileLength; // Größe der aktuellen Datei
            int StartFileName; // Position im Header, an welcher die Bezeichnung des Dateinamens anfängt
            int EndFileName; // Position im Header, an welcher die Bezeichnung des Dateinamens aufhört
            string FileName; // Name der aktuellen Datei
            string EmptyHeader = "|*START*OF*HEADER*|*||||*|*END*OF*HEADER*|"; // "Prototyp" des Headers
            byte[] EmptyHeaderBytes = Encoder.GetBytes(EmptyHeader); // Prototyp als Bytes

            long CurrentPosition = 0; // aktuelle Position im Inhalt der Datei
            long CurrentSearchPosition = 22; // aktuelle Suchposition im Inhalt der Datei

            DecompressStream.CopyTo(TempStream);
            byte[] BigFileContent = new byte[TempStream.Length];
            TempStream.Position = 0;
            TempStream.Read(BigFileContent, 0, BigFileContent.Length);
        
            StringFromBytes = decoder.GetString(BigFileContent);

            while (true)
            {
                EndSize = StringFromBytes.IndexOf("||", (int)CurrentSearchPosition);
                FileLength = long.Parse(StringFromBytes.Substring((int)CurrentSearchPosition, EndSize - (int)CurrentSearchPosition)); // die Bezeichnung der Dateigröße geht von Position 22 im Header bis Position EndSize

                StartFileName = EndSize + 2;
                EndFileName = StringFromBytes.IndexOf("*|*", StartFileName);
                FileName = StringFromBytes.Substring(StartFileName, EndFileName - StartFileName); // Dateinamen auslesen
              
                CurrentPosition += EmptyHeaderBytes.Length + Encoder.GetBytes(FileLength.ToString()).Length + Encoder.GetBytes(FileName).Length;
                
                NormalFileStream = new FileStream(decompressPath + "\\" + FileName, FileMode.Create);
                NormalFileStream.Write(BigFileContent, (int)CurrentPosition, (int)FileLength);

                CurrentPosition += FileLength;
                CurrentSearchPosition = CurrentPosition + 22;
                NormalFileStream.Close();

                if (CurrentSearchPosition > BigFileContent.Length)
                    break;
            }

            DecompressStream.Close();
        }

Montag, 18. Oktober 2010

Komprimierung mit C#, Teil 2 - Dateien komprimieren

Heute setzte ich das Tutorial zu Komprimierungsmethoden in C# aus dem vorigen Post fort.
Während es im selbigen um das Grundprinzip und die Komprimierung / Dekomprimierung von einfachen Zeichenketten ging, zeige ich jetzt eine etwas fortgeschrittenere Anwendung dieser Prinzipien zum Komprimieren / Dekomprimieren von ganzen Dateien.

Die Kompression:
Wie bei der Komprimierung von Zeichenketten legen wir eine neue Instanz der Klasse GZipStream an und übergeben dieser im Konstruktor einen FileStream, der auf die Zieldatei zeigt.
Wir legen weiterhin einen anderen FileStream an, der auf die Quelldatei zeigt.
Mit diesem lesen wir nun den Inhalt der alten Datei in ein byte - Array.
Schreiben wir dieses nun mit der Methode Write() des GZipStreams, schreibt dieser den komprimierten Inhalt der Quelldatei in die Zieldatei - wir haben eine Datei komprimiert, fast so, als hätten wir sie per WinZip oder einem ähnlichen Programm zu einem Archiv hinzugefügt.
Öffnet man die komprimierte Datei mit einem Entpackungsprorgamm (z.B. WinZip), kann man das ursprüngliche Bild extrahieren und öffnen.
Der entsprechende Code dazu:

        private void CompressFile(string normalFile, string compressedFile)
        {
            GZipStream CompressStream = new GZipStream(new FileStream(compressedFile, FileMode.Create), CompressionMode.Compress);
            
            FileStream NormalFileStream = new FileStream(normalFile, FileMode.Open);
            byte[] Content = new byte[NormalFileStream.Length];
            NormalFileStream.Read(Content, 0, Content.Length);
            NormalFileStream.Close();

            CompressStream.Write(Content, 0, Content.Length);
            CompressStream.Close();
        }

Nun die Dekompression:
Hierfür wird im Konstruktor des GZipStreams ein FileStream, der auf die auszulesende, komprimierte Datei zeigt, übergeben.
Außerdem wird ein neuer FileStream angelegt, welcher auf die zu schreibende, dekomprimierte Datei zeigt.
Wie im vorigen Post auch zur Dekomprimierung benutzt, wird nun eine Endlosschleife eingesetzt, um die komprimierte Datei auszulesen.
Hierfür wird die Methode Read() des GZipStreams verwendet, welche die übergebene Anzahl an Bytes einliest und dabei dekomprimiert. Das Ergebnis wird in einem Buffer gespeichert, welcher dann über den FileStream in die neue Datei geschrieben wird.
Wurde das Ende der Datei erreicht, liest die Methode Read() weniger Bytes als in den Buffer passen würden, woran das Programm das Ende erkennt.
Die komprimierte Datei wurde nun entpackt und wieder als lesbare Datei angelegt.
Der Code dazu lautet:

        private void DecompressFile(string compressedFile, string normalFile)
        {
            GZipStream DecompressStream = new GZipStream(new FileStream(compressedFile, FileMode.Open), CompressionMode.Decompress);

            FileStream NormalFileStream = new FileStream(normalFile, FileMode.Create);

            int BytesReadCount = 0;
            byte[] Buffer = new byte[4096];

            while (true)
            {
                BytesReadCount = DecompressStream.Read(Buffer, 0, Buffer.Length);
                if (BytesReadCount != 0)
                {
                    NormalFileStream.Write(Buffer, 0, BytesReadCount);
                }
                if (BytesReadCount < Buffer.Length)
                    break;
            }

            NormalFileStream.Close();
            DecompressStream.Close();

        }

Sonntag, 17. Oktober 2010

Webcam Chat

Auf Anfrage eines Lesers habe ich mich kürzlich der Realisierung eines etwas aufwendigeren Projekts gewidmet, der Entwicklung eines in C# implementierten Webcam Chats.
Diesen möchte ich in diesem Post vorstellen, zum Verständnis sind einige Vorkenntnisse hilfreich:
- Den Code zur Einbindung einer Webcam habe ich mit Erlaubnis vom net-blog übernommen.
- Die Verbindung der Partner wird über TCP / IP hergestellt, hierzu gibt es eine Einführung auf diesem Blog (hier).
- Viele möchten sich sicherlich über das Internet mit Freunden vernetzen, wie die Verbindung darüber läuft und insbesondere welche IPs zu verwenden sind, findet ihr hier (und auch noch allgemeine Infos zur Vernetzung im LAN).
- Wie in Bild "gestreamt" werden kann wird in diesem Post erklärt.
- Und schließlich gibt's hier allgemeine Infos zum Fehler "Allgemeiner Fehler in GDI+", welcher sporadisch bei Grafikanwendungen auftritt.

Hier die Oberfläche des Programms:

Freitag, 15. Oktober 2010

Komprimierung mit C#, Teil 1 - einfache Strings

Das .Net Studio bringt standardmäßig eine Klasse zur Komprimierung und Dekomprimierung von Daten im gzip Format mit sich, System.IO.Compression.GZipStream.
gzip ist ein gutes, offen verfügbares Format, welches, für technisch Interessierte, zur Komprimierung, ähnlich wie das ZIP - Format, den Deflate Algorithmus verwendet.
Die Klasse GZipStream ist ein Stream, wie herkömmliche Streams können mit ihr Daten geschrieben und gelesen werden, nur werden diese dabei direkt komprimiert bzw. dekomprimiert.
Als erstes Anwendungsbeispiel werde ich eine einfache Möglichkeit zur (De-)Komprimierung von Zeichenketten in (bzw. aus) einer Datei zeigen.
Für alle folgenden Codebeispiele werden die Anweisungen
using System.IO.Compression;
using System.IO;

benötigt.

Zuerst zur Komprimierung: Die Klasse GZipStream erwartet einen Stream im Konstruktor, in den die Daten hinein komprimiert werden sollen sowie den Komprimiermodus (hier CompressionMode.Compress).
Als Stream geben wir einen FileStream an, der auf die Datei zeigt, in welche der komprimierte String geschrieben werden soll.
Die Klasse GZipStream kann nur Bytes lesen und schreiben, daher muss der zu komprimierende String in ein byte - Array umgewandelt werden, was die Klasse ASCIIEncoding erledigt.
Das erhaltene Array wird dann mittels Write() geschrieben, der GZipStream komprimiert die Byte - Folge und schreibt sie über den FileStream in eine Datei.
Und so sieht der dazu passende Code aus:

private void CompressString(string uncompressedString)
{
    GZipStream CompressStream = new GZipStream(new FileStream(Application.StartupPath + "\\CompressedString.gz", FileMode.Create), CompressionMode.Compress);
    ASCIIEncoding Encoder = new ASCIIEncoding();
    byte[] UncompressedStringInBytes = Encoder.GetBytes(uncompressedString);
    CompressStream.Write(UncompressedStringInBytes, 0, UncompressedStringInBytes.Length);
    CompressStream.Close();
}

Der der Methode CompressString übergebene String wird in die Datei "CompressedString.gz" im Anwendungsverzeichnis geschrieben, .gz ist die Dateiendung für gzip - Dateien.
Die Datei kann mit herkömmlichen Entpackungsprogrammen (z.B. WinZip) entpackt werden, öffnet man die entpackte Datei mit einem Texteditor findet man den ursprünglichen String wieder.

Nun zum umgekehrten Fall, der Dekomprimierung des Strings aus der Datei:
Die Klasse GZipStream erwartet im Konstruktor wieder einen Stream, dieses Mal den Stream, aus welchem die komprimierten Daten gelesen werden sollen, und den Komprimiermodus (hier CompressionMode.Decompress).
Wir übergeben als Stream wieder einen FileStream.
Das Auslesen der Datei erfolgt nun durch eine Endlosschleife, in dieser wird jedes Mal über die Methode Read() des GZipStreams ein byte - Array in einen Buffer gelesen.
Die gelesenen Bytes werden über die Klasse ASCIIEncoding in einen String umgewandelt, wurden in einem Durchlauf weniger Bytes gelesen als der Buffer groß ist, ist die Datei offensichtlich zu Ende und die Schleife wird beendet.
Der Code:

        private string DecompressString(string compressedFile)
        {
            GZipStream DecompressStream = new GZipStream(new FileStream(Application.StartupPath + "\\CompressedString.gz", FileMode.Open), CompressionMode.Decompress);
            byte[] Buffer = new byte[4096];
            ASCIIEncoding Decoder = new ASCIIEncoding();
            int BytesReadCount = 0;
            string DecompressedString = "";

            while (true)
            {
                BytesReadCount = DecompressStream.Read(Buffer, 0, Buffer.Length);
                if (BytesReadCount != 0)
                {
                    DecompressedString += Decoder.GetString(Buffer, 0, BytesReadCount);
                }
                if (BytesReadCount < Buffer.Length)
                    break;
            }

            DecompressStream.Close();
            return (DecompressedString);
        }

Der Aufruf der beiden Methoden könnte zum Beispiel so aussehen:

CompressString("Dies ist ein Test 123456.");
string DecompressedString = DecompressString(Application.StartupPath + "\\CompressedString.gz");

Mittwoch, 13. Oktober 2010

Startseite des Internet Explorers auslesen / ändern

Die Startseite des Internet Explorers wird in der Registry gespeichert, und zwar im Schlüssel HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\Start Page.
Diese Information kann nun einfach mit C# ausgelesen und beliebig verändert werden.
Ein kleines Tutorial zur Benutzung der Registry mit C# gab es hier.
Da so die benutzten Methoden bekannt sein sollten, poste ich hier nur kurz den Programmcode.
Zuerst eine Methode, die die Startseite des Internet Explorers ausliest und als String zurückgibt:

private string GetIEStartPage()
{
    RegistryKey StartPageKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Internet Explorer\Main"); // entsprechenden Pfad in der Registry öffnen
    return StartPageKey.GetValue("Start Page").ToString(); // den Wert aus dem Schlüssel "Start Page" auslesen und zurückgeben
}

Nun noch die Methode zum Ändern der Startseite, diese erwartet die neue Startseite als String - Parameter:

private void SetIEStartPage(string newStartPage)
{
    RegistryKey StartPageKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Internet Explorer\Main", true); // entsprechenden Pfad in der Registry mit Schreibrechten öffnen
    StartPageKey.SetValue("Start Page", newStartPage); // den neuen Wert in den Schlüssel "Start Page" schreiben
}

Montag, 11. Oktober 2010

Computername herausfinden

Um mit C# den Namen des eigenen Computers herauszufinden, gibt es 2 einfache Möglichkeiten:
Über die Klasse Dns (using System.Net wird benötigt):

string ComputerName = Dns.GetHostName();

Und über die Klasse SystenInformation:

string ComputerName = System.Windows.Forms.SystemInformation.ComputerName.ToString();

Freitag, 8. Oktober 2010

HTML - Seiten mit dem Webbrowser Steuerlement aufrufen

In C# gibt es ein fertiges Steuerelement, mit dem sich Internetseiten wie im Browser aufrufen lassen.
Das Steuerelement heißt WebBrowser und befindet sich standardmäßig schon in der Toolbox.
Zieht man es auf ein Formular, erstreckt es sich wahrscheinlich standardmäßig über dessen ganze Breite, ist dieses nicht gewünscht, kann man die Eigenschaft Dock ändern.
So sieht ein Teil dieses Blogs im WebBrowser aus:



Nun möchte ich ein paar Methoden dieses Steuerlements beschreiben:

Navigate(): Dieses ist wohl die wichtigste Methode, mit ihr kann man Seiten im WebBrowser Steuerelement aufrufen. Sie erwartet in einer Überladung einen String als Parameter, welcher dann als Zieladresse interpretiert wird.

GoHome(): Navigiert zur Startseite des aktuellen Benutzers.

GoSearch(): Navigiert zur Seite der Standardsuchmaschine des aktuellen Benutzers.

Print(): Druckt die aktuelle Seite des Browsersteuerelements mit den aktuellen Druckeinstellungen des Systems.

ShowPrintDialog(): Ruft den "Drucken" Dialog des Internet Explorers auf, um die aktuelle Seite zu drucken.

ShowSaveAsDialog(): Öffnet den Dialog "Seite speichern", um die aktuelle Seite als HTML - Dokument zu speichern.

Zum Schluss noch ein Link zu einer meiner Meinung nach sehr informativen Seite zum Thema Webbrowser, auf der auch ein kostenlos E-Book zu diesem Thema verfügbar ist:
readup.de

Dienstag, 5. Oktober 2010

Video zum Post "VLC Player einbinden" online

Auf mein Youtube Konto habe ich ein neues Video hochgeladen, es zeigt die Einbindung des VLC Players wie in diesem Post beschrieben.
Das Video findet ihr unter der Adresse http://www.youtube.com/watch?v=Bh4qsHrk910 .

Montag, 4. Oktober 2010

IP Adresse anhand des Hostnamens herausfinden

Internetseiten kann man durch Eingabe von einprägsamen Adressen im Browser aufrufen. Dass wir uns hierbei keine kryptischen IP - Adressen der Server, auf denen die Seiten gehostet werden, merken müssen, verdanken wir dem DNS (Domain Name System) Dienst.
Dieser löst bei Anfragen die übergebene URL in eine IP - Adresse auf, welche dann in Wirklichkeit aufgerufen wird.
Um mit C# abzufragen, welche IP - Adressen denn nun hinter den Hostnamen stehen, können wir die Klasse Dns aus System.Net verwenden.
Die Methode GetHostByName() gibt ein Array von IP - Adressen zurück, welche für den übergebenen Host hinterlegt sind.
Der folgende Code gibt die IP - Adresse des Servers, auf dem dieser Blog läuft, in einer Konsole aus (using System.Net wird vorrausgesetzt):

foreach (IPAddress IP in Dns.GetHostByName("csharp-tricks.blogspot.com").AddressList)
{
    Console.WriteLine(IP.ToString());
}

Samstag, 2. Oktober 2010

Wahl der IP - Adressen zur Kommunikation über TCP / IP

Im vorigen Post habe ich beschrieben, wie man mit C# Daten über das TCP / IP Protokoll austauschen kann.
Die beschriebene Methode funktioniert sowohl über das Internet als auch über das Netzwerk.
In diesem Post noch kurz zur Wahl der IP - Adressen.
Befinden sich Server und Client im selben lokalen Netzwerk, kann der Client beim Verbinden auf den Server einfach dessen Netzwerk IP eingeben.
In einem lokalen Netzwerk hat jeder Computer eine eindeutige IP, diese haben meistens die Form 192.168.xxx.xxx.
Soll die Verbindung über das Internet erfolgen, muss die sogenannte WAN IP verwendet werden. Diese kann zum Beispiel über die Seite http://www.wieistmeineip.de/ abgefragt werden (um diese mit C# auszulesen siehe dieser Post).
Das Problem ist allerdings, dass diese Adresse nur pro "Zugangspunkt" zum Internet und nicht pro Rechner vergeben wird. Heutzutage haben die meisten Haushalte eine Internet Verbindung über einen Router, an dem mehrere PCs hängen.
Folglich kriegt nur der Router eine WAN IP, alle angeschlossenen PCs erhalten dieselbe.
Wenn die Verbindung also über das Internet nicht klappt, kann das daran liegen, dass der Router zwar die Verbindungsanfrage vom Client an seine IP erhält, aber nicht weiß, an welchen PC im lokalen Netzwerk er diese Anfrage weiterleiten soll.
Dann muss im Router eine neue Regel zum Port Forwarding angelegt werden.
Port Forwarding bedeutet Port Weiterleitung und sagt dem Router folglichermaßen, welche Anfragen auf welchen Ports er an welchen PC weiterleiten soll.
Legt man nun eine neue Regel an für den Port, auf dem der Server "lauscht" und leitet diesen Port an die IP Adresse des eigenen PCs im lokalen Netzwerk weiter, klappt auch die TCP / IP Verbindung über das Internet.

Freitag, 1. Oktober 2010

Datenaustausch im Internet und Netzwerk über TCP / IP

Um 2 PCs mit C# entweder über das Internet oder das lokale Netzwerk zu verbinden, gibt es unzählige Möglichkeiten.
Die meisten Möglichkeiten werden jedoch über die Verwendung von Sockets und über das TCP - Protokoll führen. Heute möchte ich euch eine davon zeigen.
Es gibt im Netz sicherlich sehr viele gute Tutorials, die das gleiche Thema behandeln wie dieser Post und sehr detailliert auf die damit verbundene Technik eingehen.
Im generellen Stil dieses Blogs werde ich daher nur relativ knapp auf den Code eingehen und die Theorie anderen überlassen.
Einleitend aber doch ein paar Satz dazu: Zur Kommunikation über ein Netzwerk (das Internet einbezogen) brauchen die beteiligten Computer ein gemeinsames Protokoll zur Datenübertragung, dass alle verstehen. Ein solches Protokoll ist zum Beispiel das hier verwendete TCP/IP Protokoll. Diese Abkürzung bedeutet Transmission Control Protocol / Internet Protocoll und ist eigentlich eine Sammlung von Protokollen zur Kommunikation über das Internet.
Das TCP/IP Protokoll nutzt zur Kommunikation Sockets. Diese sind Endpunkte, zwischen denen die Datenübertragung abläuft, man kann sie als äußere Schnittstellen zwischen den Kommunikationspartnern ansehen. Die Kommunikation läuft weiterhin über einen festgelegten Port. Ports sind eine Methode, die eingehenden Daten auf einem Rechner zu sortieren. Jede Anwendung, die Daten über das Internet / lokale Netzwerk sendet und empfängt, tut dies über einen bestimmten Port. So weiß der Computer, wohin er welche Daten leiten soll.

So, nun aber wie versprochen zur Praxis: