Dieser und noch weitere Artikel wurde von guenni81 erstellt.


Folgende Themen werden von diesem Artikel berührt:


Druckversion des Artikels


Wie kann man mit Nero und C# eine CD/DVD brennen???

Inhaltsverzeichnis

  1. Einleitung
  2. Was benötigen wir dazu?
  3. Wo bekomme ich die benötigten Dateien?
  4. Aufteilung des Tutorials
  5. Erstellen der zu nutzenden DLL für unser C#-Programm
  6. Erstellen eines Programms zum Brennen von Daten auf CD


Einleitung

Hallo zusammen,
in diesem kleinen Tutorial möchte ich euch zeigen, wie man mithilfe der NeroAPI und der Programmiersprache C# eine Anwendung entwickeln kann, mit der sich eigene CDs / DVDs erstellen lassen.

Was benötigen wir dazu?

Als Erstes benötigen wir einen Texteditor, in dem wir später unseren Quellcode schreiben können.
Als Zweites benötigen wir noch eine SDK-Version des Frameworks, mit dem wir später unseren Quellcode zu einer EXE- oder DLL-Datei konvertieren können.
Und zum Schluss benötigen wir noch eine installierte Version von dem Brennprogramm Nero!

Wo bekomme ich die benötigten Dateien?

Eine Demoversion des Brennprogrammes Nero bekommt ihr unter www.nero.com!
Die SDK-Version des .NET Frameworks könnt ihr euch unter www.microsoft.com kostenlos herunterladen!

Aufteilung des Tutorials

Im ersten Teil dieses Tutorials möchte ich euch zeigen, wie wir die benötigte Assemblydatei der NeroCOM erstellen. Diese Assemblydatei benötigen wir ebenfalls im zweiten Teil dieses Tutorials.
Im zweiten Teil möchte ich euch zeigen, wie man mithilfe der NeroCOM-Schnittstelle ein kleines Programm erstellt, das ermöglicht, CDs / DVDs zu brennen.

Erstellen der zu nutzenden DLL für unser C#-Programm

Bevor wir mit dem Programmieren anfangen können, müssen wir uns zuerst einmal die COM von Nero in eine funktionsfähige Assembly konvertieren!


  1. Wir suchen uns in dem Nero-Verzeichnis die Datei NeroCOM.dll heraus und konvertieren diese mithilfe des "Microsoft (R) .NET Framework Type Library to Assembly Converter" (tlbimp.exe) in eine .NET-Assembly.

  2. Dazu geben wir Folgendes in der Eingabeaufforderung ein: "tlbimp.exe NeroCOM.dll".
    Anschließend sollten wir folgende Rückmeldung des Konverters erhalten: "Type library imported to NEROLib.dll".
    Dies bedeutet, dass uns das Konvertierungsprogramm eine Assembly namens NEROlib.dll erstellt hat, die wir nun im .NET Framework nutzen können.

    Hinweis: Es wäre zum jetzigen Zeitpunkt zwar schon möglich, mithilfe dieser Assembly eine CD / DVD zu erzeugen, aber im jetzigen Zustand würde keines der von der COM-Schnittstelle zur Verfügung stehenden Events ausgelöst werden.

  3. Um genau dies zu erreichen, dass auch die zur Verfügung stehenden Events in unserem Programm genutzt werden können, müssen wir die so eben erzeugte Assembly-Datei noch ein wenig bearbeiten.

    Um dies durchzuführen, müssen wir die Datei zuerst mit dem Programm "ildasm.exe" in IL-Assemblercode extrahieren.
    Dazu müssen wir in der Eingabeaufforderung Folgendes eingeben:
    ildasm /source nerolib.dll /output=nerolib.il

    Nach diesem Aufruf bekommen wir zwei Dateien erstellt. Die "nerolib.il" und die "nerolib.res". Für uns ist nur die nerolib.il wichtig.

  4. Als Nächstes öffnen wir die Datei nerolib.il mit einem Texteditor und suchen nach Suchbegriff "_SinkHelper".
    Der erste Punkt, den wir finden, sollte
    .class private auto ansi sealed _INeroEvents_SinkHelper
    extends [mscorlib]System.Object
    implements NEROLib._INeroEvents
    sein.
    Hier ändern wir das „private“ nun zum „public“. Anschließend suchen wir weiter nach Klassen, die die Endung _SinkHelper haben und führen dieselbe Änderung dort ebenfalls durch!

  5. Wenn wir die Änderungen erfolgreich vorgenommen haben, können wir die geänderte Datei wieder zu einer für uns nützlichen Assembly konvertieren.
    Dies ist mit dem Befehl "ilasm.exe" realisierbar! Hierfür geben wir in der Eingabeaufforderung Folgendes ein:
    ilasm /dll nerolib.il /output=nerolib_new.dll


Hinweis:
Die Datei muss beim Einbinden in das Projekt wieder nerolib.dll heißen, da diese ansonsten nicht korrekt funktioniert.

Dies war nun der erste Teil, mit dem wir die für uns benötigte Assemblydatei erstellen!!!

Erstellen eines Programmes zum Brennen von Daten auf CD

Ich möchte euch begrüßen zum zweiten Teil dieses Tutorials. In diesem Teil werden wir eine kleine Applikation erstellen, mit der wir zwei Testdateien auf eine CD Brennen.

Als Erstes erstellen wir uns ein Grundgerüst für dieses kleines Testprogramm.
Mein Quellcode:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
using System;
using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

 
namespace Brennen
{
    /// <summary>

    /// Zusammenfassende Beschreibung für Form1.

    /// </summary>

    public class Form1 : System.Windows.Forms.Form
    {
        private System.Windows.Forms.Button btn_brennen;
        private System.Windows.Forms.ComboBox cmb_brennerauswahl;
        private System.Windows.Forms.ProgressBar prgbar_fortschritt;
        /// <summary>

        /// Erforderliche Designervariable.

        /// </summary>

        private System.ComponentModel.Container components = null;
 
        public Form1()
        {
            //
            // Erforderlich für die Windows Form-Designerunterstützung
            //
            InitializeComponent();
 
            //
            // TODO: Fügen Sie den Konstruktorcode nach dem Aufruf von InitializeComponent hinzu
            //
        }
 
        /// <summary>

        /// Die verwendeten Ressourcen bereinigen.

        /// </summary>

        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }
 
        #region Windows Form Designer generated code

        /// <summary>

        /// Erforderliche Methode für die Designerunterstützung.

        /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.

        /// </summary>

        private void InitializeComponent()
        {
            this.btn_brennen = new System.Windows.Forms.Button();
            this.prgbar_fortschritt = new System.Windows.Forms.ProgressBar();
            this.cmb_brennerauswahl = new System.Windows.Forms.ComboBox();
            this.SuspendLayout();
            //
            // btn_brennen
            //
            this.btn_brennen.Location = new System.Drawing.Point(224, 160);
            this.btn_brennen.Name = "btn_brennen";
            this.btn_brennen.Size = new System.Drawing.Size(176, 23);
            this.btn_brennen.TabIndex = 0;
            this.btn_brennen.Text = "Dateien Brennen";
            //
            // prgbar_fortschritt
            //
            this.prgbar_fortschritt.Location = new System.Drawing.Point(8, 120);
            this.prgbar_fortschritt.Name = "prgbar_fortschritt";
            this.prgbar_fortschritt.Size = new System.Drawing.Size(600, 16);
            this.prgbar_fortschritt.TabIndex = 1;
            //
            // cmb_brennerauswahl
            //
            this.cmb_brennerauswahl.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
            this.cmb_brennerauswahl.Location = new System.Drawing.Point(192, 40);
            this.cmb_brennerauswahl.Name = "cmb_brennerauswahl";
            this.cmb_brennerauswahl.Size = new System.Drawing.Size(272, 21);
            this.cmb_brennerauswahl.TabIndex = 2;
            //
            // Form1
            //
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(616, 198);
            this.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                          this.cmb_brennerauswahl,
                                                                          this.prgbar_fortschritt,
                                                                          this.btn_brennen});
            this.Name = "Form1";
            this.Text = "Tutorial Brennen";
            this.ResumeLayout(false);
 
        }
        #endregion

 
        /// <summary>

        /// Der Haupteinstiegspunkt für die Anwendung.

        /// </summary>

        [STAThread]
        static void Main()
        {
            Application.Run(new Form1());
        }
    }
}


Zuerst erstellen wir eine neue Instanz von der NeroClass.
C#:
private NEROLib.NeroClass neroclass = new NEROLib.NeroClass();


Diese Instanz benötigen wir später, um die Laufwerke zu ermitteln.
Um die Laufwerke in einer Collection aufzunehmen, benötigen wir jetzt eine Instanz von der NeroDrivesClass.
C#:
private NEROLib.NeroDrivesClass ndrives;


Als Nächstes erstellen wir eine Methode, die uns unsere ComboBox mit den vorhandenen Brennern / Laufwerken füllt.
In diesem Tutorial heißt diese Methode GetRecoderList().

Nun müssen wir uns als Erstes eine Liste der vorhandenen Brenner besorgen. Dies machen wir so:

C#:
ndrives = (NEROLib.NeroDrivesClass)neroclass.GetDrives(NEROLib.NERO_MEDIA_TYPE.NERO_MEDIA_CD);


Die Variable ndrives enthält nun alle von GetDrives übergebenen Laufwerke.
Anschließend fügen wir mithilfe einer Foreach die Laufwerke der ComboBox hinzu:
C#:
foreach(NEROLib.NeroDrive ndrive in ndrives)
{
    // Laufwerkname in der ComboBox anlegen
cmb_brennerauswahl.Items.Add(ndrive.DeviceName);       
}

Nun müssen wir beim Start nur noch diese Methode aufrufen und erhalten so alle Laufwerke in der ComboBox!



Als Nächstes schreiben wir die Funktion zum Brennen der Dateien. Diese wird für den Button "Dateien Brennen" hinterlegt. Diese Funktion nenne ich in diesem Tutorial btn_brennen_Click, da dies auf ein Event (Click) des Buttons reagiert.

Zu erst müssen wir einen neuen ISO-Track erstellen, in dem wir später die Verzeichnisse und Dateien hinterlegen.
C#:
// Neuen ISO-Track erstellen
NEROLib.NeroISOTrackClass niso = new NEROLib.NeroISOTrackClass();

Als Nächstes vergeben wir einen Namen für den neuen ISO-Track. Dieser Name wird nach dem Brennen auch der Name der CD sein.
Im nächsten Schritt müssen wir ein neues Verzeichnis erstellen, in dem wir die späteren Dateien einfügen. Dies machen wir mit folgender Syntax:
C#:
// Neues Verzeichnis erstellen
NEROLib.NeroFolderClass nfolder = new NEROLib.NeroFolderClass();

Diesem Verzeichnis geben wir keinen Namen, da wir dies als RootFolder für den ISO-Track nutzen wollen. Nun erstellen wir ein zweites Verzeichnis.
C#:
// Zweites Verzeichnis erstellen
NEROLib.NeroFolderClass nsecondfolder = new NEROLib.NeroFolderClass();
 
// Verzeichnis benennen
nsecondfolder.Name = "TestFolder";

Nachdem wir dem zweiten Verzeichnis einen Namen gegeben haben, fügen wir dies dem RootFolder hinzu:
C#:
// Verzeichnis zwei dem Root-Verzeichnis hinzufügen
nfolder.Folders.Add(nsecondfolder);

Jetzt fügen wir dem ISO-Track das Root-Verzeichnis hinzu:
C#:
// Root-Folder dem ISO-Track hinzufügen
niso.RootFolder = nfolder;

Nach all dem fehlen uns jetzt nur noch die Dateien, die wir auf die CD brennen wollen. Diese müssen wir nun den zwei Verzeichnissen hinzufügen.
Dies funktioniert im Prinzip genau so wie mit den Verzeichnissen.
Mit der Namenseigenschaft gibt man den Dateinamen auf der CD an, mit der SourceFilePath-Eigenschaft wird der Pfad und die zu erfassende Datei festgelegt.
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Zwei Dateien erstellen
NEROLib.NeroFileClass nfile1 = new NEROLib.NeroFileClass();;
NEROLib.NeroFileClass nfile2 = new NEROLib.NeroFileClass();;
 
// Eigenschaften der Files festlegen
nfile1.Name = "TestPack1.rar";
nfile1.SourceFilePath = @"C:\testfile1.rar";
 
nfile2.Name = "TestPack2.rar";
nfile2.SourceFilePath = @"C:\testfile2.rar";
 
// Dateien den Verzeichnissen hinzufügen
nfolder.Files.Add(nfile1);
nsecondfolder.Files.Add(nfile2);

Als Nächstes müssen wir noch sagen, mit welchen Optionen wir den ISO-Track brennen wollen. In unserem Beispiel soll ein ISO-FileSystem erzeugt werden.
C#:
// Brennoptionen für den ISO-Track festlegen
niso.BurnOptions = NEROLib.NERO_BURN_OPTIONS.NERO_BURN_OPTION_CREATE_ISO_FS;


Nun legen wir eine neue Globale Variable namens ndrive an.
C#:
private NEROLib.NeroDrive ndrive;


Dieser Variable übergeben wir das von uns ausgewählte Laufwerk
(Diese Variable stellt uns nun die Eigenschaften eines Laufwerkes zur Verfügung)
C#:
// Ausgewähltes Laufwerk an
ndrive = (NEROLib.NeroDrive)ndrives.Item(cmb_brennerauswahl.SelectedIndex);

Um die CD jetzt endgültig zu erstellen, rufen wir die BurnIsoAudioCD-Funktion von der Variable ndrive auf.
C#:
// CD erstellen und Daten auf CD brennen
ndrive.BurnIsoAudioCD("","",false,niso,null,null,NEROLib.NERO_BURN_FLAGS.NERO_BURN_FLAG_WRITE,10,NEROLib.NERO_MEDIA_TYPE.NERO_MEDIA_CDRW);

Mit unserem jetzigen Programm würde es schon funktionieren, eine CD zu erstellen. Die Progressbar würde aber keinen Fortschritt anzeigen. Aus diesem Grund fügen wir nun noch eine Funktion zu dem Event, das uns von der NeroCOM-Schnittstelle zur Verfügung gestellt wird, hinzu. In diesem Programm nenne ich diese Funktion OnProgress().
Das OnProgress-Event erwartet zwei Parameter. Der erste Parameter gibt die Prozentzahl zurück, wie viel Daten auf die CD schon gebrannt wurden. Der zweite Parameter gibt zurück, ob das Brennen beendet wurde.
C#:
private void OnProgress(ref int percent, ref bool fertig)
{
    prgbar_fortschritt.Value = percent;
}


Und hiermit wird nun auch der Fortschritt des Brennens angezeigt.
Jetzt müssen wir noch dem OnProgress-Event einen neuen Eventhandler mit unserer Funktion hinzufügen.
Das Event müssen wir in der Brennfunktion btn_brennen_Click zuordnen, da hier ja erst die Wahl des Brenners aktualisiert wird.
C#:
// OnProgress-Event einen neuen Eventhandler hinzufügen
ndrive.OnProgress += new NEROLib._INeroDriveEvents_OnProgressEventHandler(OnProgress);


Wichtig:
Wird der Zwischenschritt über das ndrive-Element nicht beachtet, so kann es Probleme mit der korrekten Funktion der Progressbar kommen.

Ich hoffe, das euch das Tutorial gefallen hat!!!
Mit freundlichen Grüßen,
euer Günni


Und zum Abschluss noch einmal den komplette Quellcode:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
using System;
using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

 
namespace Brennen
{
    /// <summary>

    /// Zusammenfassende Beschreibung für Form1.

    /// </summary>

    public class Form1 : System.Windows.Forms.Form
    {
        private System.Windows.Forms.Button btn_brennen;
        private System.Windows.Forms.ComboBox cmb_brennerauswahl;
        private System.Windows.Forms.ProgressBar prgbar_fortschritt;
        private NEROLib.NeroClass neroclass = new NEROLib.NeroClass();
        private NEROLib.NeroDrivesClass ndrives;
        private NEROLib.NeroDrive ndrive;
 
        /// <summary>

        /// Erforderliche Designervariable.

        /// </summary>

        private System.ComponentModel.Container components = null;
 
        public Form1()
        {
            //
            // Erforderlich für die Windows Form-Designerunterstützung
            //
            InitializeComponent();
 
            //
            // TODO: Fügen Sie den Konstruktorcode nach dem Aufruf von InitializeComponent hinzu
            //
            GetRecoderList(); // Laufwerke ermitteln
            prgbar_fortschritt.Value = 0;
        }
 
        /// <summary>

        /// Die verwendeten Ressourcen bereinigen.

        /// </summary>

        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }
 
        #region Windows Form Designer generated code

        /// <summary>

        /// Erforderliche Methode für die Designerunterstützung.

        /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.

        /// </summary>

        private void InitializeComponent()
        {
            this.btn_brennen = new System.Windows.Forms.Button();
            this.prgbar_fortschritt = new System.Windows.Forms.ProgressBar();
            this.cmb_brennerauswahl = new System.Windows.Forms.ComboBox();
            this.SuspendLayout();
            //
            // btn_brennen
            //
            this.btn_brennen.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.btn_brennen.Location = new System.Drawing.Point(224, 160);
            this.btn_brennen.Name = "btn_brennen";
            this.btn_brennen.Size = new System.Drawing.Size(176, 23);
            this.btn_brennen.TabIndex = 0;
            this.btn_brennen.Text = "Dateien Brennen";
            this.btn_brennen.Click += new System.EventHandler(this.btn_brennen_Click);
            //
            // prgbar_fortschritt
            //
            this.prgbar_fortschritt.Location = new System.Drawing.Point(8, 120);
            this.prgbar_fortschritt.Name = "prgbar_fortschritt";
            this.prgbar_fortschritt.Size = new System.Drawing.Size(600, 16);
            this.prgbar_fortschritt.Step = 1;
            this.prgbar_fortschritt.TabIndex = 1;
            //
            // cmb_brennerauswahl
            //
            this.cmb_brennerauswahl.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
            this.cmb_brennerauswahl.Location = new System.Drawing.Point(192, 40);
            this.cmb_brennerauswahl.Name = "cmb_brennerauswahl";
            this.cmb_brennerauswahl.Size = new System.Drawing.Size(272, 21);
            this.cmb_brennerauswahl.TabIndex = 2;
            //
            // Form1
            //
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(616, 198);
            this.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                          this.cmb_brennerauswahl,
                                                                          this.prgbar_fortschritt,
                                                                          this.btn_brennen});
            this.Name = "Form1";
            this.Text = "Tutorial Brennen";
            this.ResumeLayout(false);
 
        }
        #endregion

 
        /// <summary>

        /// Der Haupteinstiegspunkt für die Anwendung.

        /// </summary>

        [STAThread]
        static void Main()
        {
            Application.Run(new Form1());
        }
 
        # region Eigendefiniert Methoden/Funktionen

        private void GetRecoderList()
        {
            // Ermittle alle Laufwerke mit der Eigenschaft (siehe Media_type)
            ndrives = (NEROLib.NeroDrivesClass)neroclass.GetDrives(NEROLib.NERO_MEDIA_TYPE.NERO_MEDIA_CD);
           
            // Alle ermittelten Laufwerke in der ComboBox anlegen
            foreach(NEROLib.NeroDrive ndrive in ndrives)
            {
                // Laufwerkname in der ComboBox anlegen
                cmb_brennerauswahl.Items.Add(ndrive.DeviceName);
               
            }
        }
        #endregion

 
        // Funktion, die zwei Dateien auf eine CD brennt
        private void btn_brennen_Click(object sender, System.EventArgs e)
        {
            // Neuen ISO-Track erstellen
            NEROLib.NeroISOTrackClass niso = new NEROLib.NeroISOTrackClass();
 
            // ISO-Track benennen
            niso.Name = "TEST-CD";
 
            // Neues Verzeichnis erstellen
            NEROLib.NeroFolderClass nfolder = new NEROLib.NeroFolderClass();
           
            // Zweites Verzeichnis erstellen
            NEROLib.NeroFolderClass nsecondfolder = new NEROLib.NeroFolderClass();
           
            // Verzeichnis benennen
            nsecondfolder.Name = "TestFolder";
 
            // Verzeichnis zwei dem Root-Verzeichnis hinzufügen
            nfolder.Folders.Add(nsecondfolder);
 
            // Root Folder dem ISO-Track hinzufügen
            niso.RootFolder = nfolder;
           
            // Zwei Dateien erstellen
            NEROLib.NeroFileClass nfile1 = new NEROLib.NeroFileClass();
            NEROLib.NeroFileClass nfile2 = new NEROLib.NeroFileClass();
 
            // Eigenschaften der Files festlegen
            nfile1.Name = "TestPack1.rar";
            nfile1.SourceFilePath = @"C:\testfile1.rar";
 
            nfile2.Name = "TestPack2.rar";
            nfile2.SourceFilePath = @"C:\testfile2.rar";
 
            // Dateien den Verzeichnissen hinzufügen
            nfolder.Files.Add(nfile1);
            nsecondfolder.Files.Add(nfile2);
 
            // Brennoptionen für den ISO Track festlegen
            niso.BurnOptions = NEROLib.NERO_BURN_OPTIONS.NERO_BURN_OPTION_CREATE_ISO_FS;
           
            // Ausgewähltes Laufwerk übergeben
            ndrive = (NEROLib.NeroDrive)ndrives.Item(cmb_brennerauswahl.SelectedIndex);
           
            // Hinzufügen des OnProgress-Events zum ausgewählten Laufwerk
            ndrive.OnProgress += new NEROLib._INeroDriveEvents_OnProgressEventHandler(OnProgress);
 
            // CD erstellen und Daten auf CD brennen
            ndrive.BurnIsoAudioCD("","",false,niso,null,null,NEROLib.NERO_BURN_FLAGS.NERO_BURN_FLAG_WRITE,10,NEROLib.NERO_MEDIA_TYPE.NERO_MEDIA_CDRW);
        }
 
        private void OnProgress(ref int percent, ref bool abort)
        {
            prgbar_fortschritt.Value = percent;
        }
    }
}

Sie können Kommentare zu diesem Artikel im Forum schreiben. (Eine Registrierung ist nicht notwendig.)

Logo-Design: MastaMind Webdesign