|
Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
Xardas
Anmeldungsdatum: 17.09.2006 Beiträge: 23
|
Verfasst am: 25.04.2014, 20:23 Titel: Statische DLL erzeugen |
|
|
Moin,
ich bin auf der Suche nach einer Möglichkeit in FreeBasic statische DLLs zu erzeugen.Ich habe zwar ein paar Beispiele in C gefunden, steige da aber nicht so ganz durch, weil auch die genannten Compileroptionen sich nur auf Visual C++ beziehen. (http://www.functionx.com/visualc/libraries/staticdll.htm)
Wäre super, wenn mir jemand ein Simples Beispiel erläutern kann über das Erzeugen und spätere einbinden der DLL.
LG Xardas
PS:
Bin mir gerade nicht sicher, ob der Link oben aussagekräftig genug ist.
Ich zitiere mal Wikipedia um genauer darzustellen was ich meine:
Zitat: |
DLLs im Speicher
Es gibt zwei verschiedene Arten, wie DLLs vom Betriebssystem in den Speicher geladen werden. Es gibt statische DLLs, die nur einmal geladen werden. Alle Programme greifen dann auf diese eine Instanz der DLL zu. Diese DLL hat dann nur einen globalen Speicherbereich. Die Windows-Kernel-DLLs sind solche statischen DLLs, was ihnen erlaubt, das gesamte System zu verwalten (z. B. alle offenen Dateien zu überwachen).
Quelle: http://de.wikipedia.org/wiki/Dynamic_Link_Library
|
|
|
Nach oben |
|
|
Jojo alter Rang
Anmeldungsdatum: 12.02.2005 Beiträge: 9736 Wohnort: Neben der Festplatte
|
Verfasst am: 25.04.2014, 21:27 Titel: |
|
|
Bist du dir sicher, dass du so etwas überhaupt brauchst? Typischerweise verwendet man "normale" DLLs oder statische Bibliotheken (Compilerswitch -lib), welche direkt in das Programm eingebettet werden. Möchtest du zwei Programme miteinander kommunizieren lassen, bieten sich dazu typischerweise eher Pipes und Shared Memory an. _________________ » Die Mathematik wurde geschaffen, um Probleme zu lösen, die es nicht gäbe, wenn die Mathematik nicht erschaffen worden wäre.
|
|
Nach oben |
|
|
Xardas
Anmeldungsdatum: 17.09.2006 Beiträge: 23
|
Verfasst am: 25.04.2014, 21:32 Titel: |
|
|
mit "normalen" dlls komme ich nicht weiter. Genau deswegen stelle ich ja hier die Frage
Pipes finde ich persönlich unglaublich langsam.
Ich brauche genau wie in dem Wikipedia Beispiel beschrieben ein DLL - Verhalten ähnlich dem Windows Kernel. Sprich einmal geladen und jede Kommunikation läuft über diese DLL.
Ein weiteres Problem ist, dass bei der normalen Verwendung einer DLL, jede erneute Einbindung wie ein "neustart" des Programms bewirkt hat.
Beispiel: (Struktur)
Code: |
main.dll (Eben diese DLL auf die sich alles fixiert) = verwaltet virtualFS und GUI
virtualFS.dll = Virtuelles Dateisystem
GUI.dll = Simple Grafische Oberfläche
aufruf1.dll = enthält Berechnungsgrundlagen 1
aufruf2.dll = enthält Berechnungsgrundlagen 2
|
Prinzip
Code: |
Programmstart main.dll lädt virtualFS.dll und GUI.dll
aufruf1.dll wird eingebunden führt Berechnungen aus ruft Funktionen zur Darstellung in main.dll auf und speichert darüber die Werte
aufruf2.dll wird eingebunden führt Berechnungen aus ruft Funktionen zur Darstellung in main.dll auf und speichert darüber die Werte
|
Aus Sicherheitsgründen muss main.dll Dateien oder auch Variablen sperren, damit keine Konflikte auftauchen.
Das ist nur das grobe Prinzip. Aber genau in dieser Art und Weise brauche ich den Quellcode/ die mögliche Option[/img]
Ist Free Basic überhaupt in der Lage shared memory zu nutzen?
Wie sieht das mit grafischen Prozessen wie z.B. die der SDL Libary aus?
Ich habe jetzt das Problem, wenn aufruf1.dll oder aufruf2.dll auf die GUI zugreifen immer ein neues Grafikfenster erstellt wird. |
|
Nach oben |
|
|
Jojo alter Rang
Anmeldungsdatum: 12.02.2005 Beiträge: 9736 Wohnort: Neben der Festplatte
|
Verfasst am: 25.04.2014, 23:30 Titel: |
|
|
Zitat: | Aus Sicherheitsgründen muss main.dll Dateien oder auch Variablen sperren, damit keine Konflikte auftauchen. |
Ich würde behaupten, sobald du Locking zur Synchornisation einbaust, ist das genau so langsam wie Pipes auch.
Zitat: | Ist Free Basic überhaupt in der Lage shared memory zu nutzen? |
Da dies Sache der Betriebssystem-API ist: Ja. Unter Windows geht das mit CreateFileMapping/OpenFileMapping/MapViewOfFile. Shared memory hat erst mal keine Geschwindigkeitseinbußen, aber wenn du keinen lock-free Code schreiben kannst (was du auch besser nicht versuchen solltest, wenn du nicht genau weißt, was du tust), musst du dabei genau wie bei allen anderen Mechanismen den Zugriff sperren (z.B. mit SetEvent/WaitForSingleObject). Zumindest die Windows-Pipes (also CreateNamedPipe und co.) sollten da performancemäßig aber auch äquivalent sein, weil die ja intern auch nur dieselben Mechanismen einsetzen.
Ob die FB-eigenen Pipe-Mechanismen vergleichbar sind, kann ich nicht sagen. Ich hab die ganzen oben genannten Techniken nur unter C++ eingesetzt und sie funktionieren alle ziemlich schnell, vor allem wenn man sich Gedanken darüber macht, wie man die Anzahl der Locks auf ein Minimum reduzieren kann.
Letztendlich hilft hier nur ein Benchmark, um zu vergleichen, welche Version den größten Durchsatz hat. _________________ » Die Mathematik wurde geschaffen, um Probleme zu lösen, die es nicht gäbe, wenn die Mathematik nicht erschaffen worden wäre.
|
|
Nach oben |
|
|
Sebastian Administrator
Anmeldungsdatum: 10.09.2004 Beiträge: 5969 Wohnort: Deutschland
|
Verfasst am: 25.04.2014, 23:38 Titel: Multi-Threading innerhalb eines Programms als Alternative? |
|
|
Hallo,
man kann als Faustregel sagen, dass alles, was in einer C-Umgebung benutzt werden kann, auch in FreeBASIC verwendet werden kann. Es kann auch das ganze Win32-API verwendet werden - genauso wie in C. Nur die Syntax ist geringfügig anders (anderes Pointer-Symbol, keine Semikolons, ...).
Der angedachte Aufbau der Anwendung aus etlichen DLLs, die irgendwie miteinander kommunizieren sollen und wobei auch das Hauptprogramm bloß aus einer DLL geladen wird, ist m. M. n. zumindest ungewöhnlich. Wenn du etwas mehr beschreibst, was dahintersteckt, fällt uns vielleicht noch eine andere Lösung ein, die näher am "Normalprogramm" liegt.
Geht es dir z. B. vor allem um die Nebenläufigkeit? Dass irgendwelche Berechnungen unabhängig von der grafischen Darstellung (=> SDL o. ä.) ablaufen? Dafür könntest du innerhalb einer FB-Anwendung einfach mehrere Threads starten (siehe z. B. THREADCALL). Du könntest die komplette Grafikausgabe in einen eigenen Thread auslagern und in anderen Threads parallel etwas anderes tun. Diese Threads können innerhalb desselben Programms über Variablen kommunizieren, sodass man nichts mit Pipes, Sockets, ... bauen muss.
Oder geht das Ganze eher in Richtung eines Plugin-Systems?
Oder hast du vielleicht ein Setting mit einem Background-Prozess (Richtung NT-Dienst) und einem Monitoring-Programm, das über ein Notification-Area-Icon (Systray) den Status des Dienstes signalisiert (wofür es dann eine Kommunikation zwischen beidem braucht)? ...
Viele Grüße & ein schönes Wochenende!
Sebastian _________________
Die gefährlichsten Familienclans | Opas Leistung muss sich wieder lohnen - für 6 bis 10 Generationen! |
|
Nach oben |
|
|
ThePuppetMaster
Anmeldungsdatum: 18.02.2007 Beiträge: 1837 Wohnort: [JN58JR]
|
Verfasst am: 26.04.2014, 11:45 Titel: |
|
|
Unter win98 mit VB6 hab ich sowas ähnliches auch mal gemacht.
In VB6 hab ich dazu dll's geschrieben, welche mit na VB6 exe geladen wird. dabei hat jede exe auf die selbe dll instanz zugegriffen. Der Trick lag dabei in einem etwas komplexerem api aufruf, welcher die dll in die eigene instanz gelinkt hat.
Aber, ka ob das noch unter den aktuellen win versionen funzt.
wenn den source ma haben magst, kann ich dir das uppen.
hier n auszug aus der basisfunktion:
Code: | Private Function GetCoClasses(ByVal strFile As String, udtCoClasses() As CoClass) As Boolean
Dim hRes As HRESULT
Dim udtITypeLib As ITypeLib
Dim udtITypeInfo As ITypeInfo
Dim udtTypeAttr As TYPEATTR
Dim oTypeLib As Long
Dim oTypeInfo As Long
Dim pVTbl As Long
Dim pAttr As Long
Dim lngTypeInfos As Long
Dim lngCoCls As Long
Dim strTypeName As String
Dim i As Long
hRes = LoadTypeLibEx(StrPtr(strFile), REGKIND_NONE, oTypeLib)
If hRes <> S_OK Then Exit Function
CpyMem pVTbl, ByVal oTypeLib, 4
CpyMem udtITypeLib, ByVal pVTbl, Len(udtITypeLib)
lngTypeInfos = CallPointer(udtITypeLib.GetTypeInfoCount, oTypeLib)
For i = 0 To lngTypeInfos - 1
hRes = CallPointer(udtITypeLib.GetTypeInfo, oTypeLib, i, VarPtr(oTypeInfo))
If hRes = S_OK Then
CpyMem pVTbl, ByVal oTypeInfo, 4
CpyMem udtITypeInfo, ByVal pVTbl, Len(udtITypeInfo)
CallPointer udtITypeInfo.GetTypeAttr, oTypeInfo, VarPtr(pAttr)
CpyMem udtTypeAttr, ByVal pAttr, Len(udtTypeAttr)
CallPointer udtITypeInfo.ReleaseTypeAttr, oTypeInfo, pAttr
CallPointer udtITypeLib.GetDocumentation, oTypeLib, i, VarPtr(strTypeName), 0, 0, 0
If udtTypeAttr.TYPEKIND = TKIND_COCLASS Then
ReDim Preserve udtCoClasses(lngCoCls) As CoClass
With udtCoClasses(lngCoCls)
.guid = udtTypeAttr.guid
.Name = strTypeName
End With
lngCoCls = lngCoCls + 1
End If
CallPointer udtITypeInfo.IUnk.Release, oTypeInfo
oTypeInfo = 0
End If
Next
CallPointer udtITypeLib.IUnk.Release, oTypeLib
GetCoClasses = True
End Function
|
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
|
Xardas
Anmeldungsdatum: 17.09.2006 Beiträge: 23
|
Verfasst am: 26.04.2014, 17:23 Titel: |
|
|
Cool, vielen dank
Ja, plugins spielen später auch eine Rolle aber in erster Linie geht es darum möglichst flexibel zu sein und bei einem Update nur einzelne Teile austauschen zu können. Da das Programm auf mehreren Rechnern mit unterschiedlichen Windows Versionen läuft, sind Komplikationen nicht auszuschließen. Für diesen Fall möchte ich nicht das ganze Programm neu compilieren, sondern lediglich die DLL austauschen, wo Probleme auftreten. |
|
Nach oben |
|
|
Sebastian Administrator
Anmeldungsdatum: 10.09.2004 Beiträge: 5969 Wohnort: Deutschland
|
Verfasst am: 26.04.2014, 17:35 Titel: |
|
|
Xardas hat Folgendes geschrieben: | Für diesen Fall möchte ich nicht das ganze Programm neu compilieren, sondern lediglich die DLL austauschen, wo Probleme auftreten. |
Wir wissen hier jetzt natürlich nicht, was für ein Programm das wird, aber der Aufwand zum Neucompilieren und Auswechseln einer DLL-Datei ist doch eigentlich genau der gleiche wie bei einer EXE-Datei. _________________
Die gefährlichsten Familienclans | Opas Leistung muss sich wieder lohnen - für 6 bis 10 Generationen! |
|
Nach oben |
|
|
Xardas
Anmeldungsdatum: 17.09.2006 Beiträge: 23
|
Verfasst am: 26.04.2014, 17:53 Titel: |
|
|
In dem Fall nicht.
Die grafische Ansteuerung läuft über die gui.dll für die Anzeige von statistiken usw. Als Plattform dafür dient widerum SDL.
Da ich aber in naher zukunft auf SDL2 umsteigen möchte, tausche ich als folge nur die gui.dll und sdl aus. Sollten ältere Betriebsystem mit SDL2 Probleme bekommen, so bleibt einfach SDL erhalten.
Sollten sich interne Berechnungen irgendwann ändern, so muss ich mir keine Gedanken machen, welche grafische Plattform ich gewählt habe usw.
Vom Prinzip eigentlich simple (natürlich aufwenig von der Handhabung her). Jedes komplexere Programm arbeitet ähnlich, deshalb bin ich gerade etwas verwundert, warum diese Methode auf solche Verwunderung stößt. |
|
Nach oben |
|
|
Jojo alter Rang
Anmeldungsdatum: 12.02.2005 Beiträge: 9736 Wohnort: Neben der Festplatte
|
Verfasst am: 26.04.2014, 17:59 Titel: |
|
|
Xardas hat Folgendes geschrieben: | Jedes komplexere Programm arbeitet ähnlich, deshalb bin ich gerade etwas verwundert, warum diese Methode auf solche Verwunderung stößt. |
[citation needed]
Dass eine große Zahl an Programmen statische DLLs verwenden, wäre mir neu. Die wenigsten Programme kommunizieren überhaupt zwischen mehreren Programminstanzen, und die meisten tun das vermutlich über Shared Memory / Pipes / Sockets / Mailslots. _________________ » Die Mathematik wurde geschaffen, um Probleme zu lösen, die es nicht gäbe, wenn die Mathematik nicht erschaffen worden wäre.
|
|
Nach oben |
|
|
dreael Administrator
Anmeldungsdatum: 10.09.2004 Beiträge: 2509 Wohnort: Hofen SH (Schweiz)
|
Verfasst am: 26.04.2014, 18:22 Titel: |
|
|
Also .DLLs (Linux: .so) verfolgen einen völlig anderen Zweck: Gemeinsame Codeteile an völlig zueinander unabhängige Programme so bereitstellen, dass sie die .EXE-Datei nicht statisch hineinlinken muss, d.h. das Betriebssystem "linkt" zur Laufzeit alles zusammen und kann so den Speicherverbrauch (Code nur 1x ins RAM laden, aber in mehrere Prozesse hineinfalten) optimieren und gibt dann auch entsprechend kleinere .EXE-Dateien auf der Festplatte des Endbenutzers.
@Xardas: Immer drandenken, dass Software-Architektur ein eigenes Gebiet ist, allerdings ein ziemlich wichtiges, weil damit der grundlegende Aufbau zu Beginn festgelegt wird. Kann im einfachsten Fall (die meisten FB-Projekte hier) eine Standalone-.EXE sein.
Nebenbei: In FbEdit lässt sich .DLL als Projekttyp explizit auswählen (selber bisher noch nie ausprobiert). _________________ Teste die PC-Sicherheit mit www.sec-check.net |
|
Nach oben |
|
|
ThePuppetMaster
Anmeldungsdatum: 18.02.2007 Beiträge: 1837 Wohnort: [JN58JR]
|
Verfasst am: 26.04.2014, 20:58 Titel: |
|
|
@Xardas .. das was du bis jetzt beschreibst, klingt alles andere als wäre es nötig mit irgend welchen komponenten über gemeinsame dll's zu kommunizieren.
was du (meiner ansicht nach) brauchst ist ein simplex Plugin-system.
Die Interne struktur ist hier einfach entscheident. du musst das pluginsystem entsprechend so konstruieren, das du plugins wärend des betriebs tauschen kannst. offline kannst du plugins bzw. dll's immer problemlos wechseln, wenn der interne aufbau, bzw. die linkbaren routinen identisch bleiben.
Ein "Programmneustart", wie du es beschreibst, ist bei dll's auch simpel zu verhindern. auch hier ist es relevant, wie du den internen aufbau händelst.
Pipes, shared-mem, usw. ist NUR DANN sinvoll, wenn du UNTERSCHIEDLICHE Programminstanzen auf den selben Speicherbereich zugreifen sollen, bzw. miteinander kommunizieren sollen.
Sprich ... >2< EXE Datein, welche miteinander quasseln sollen.
du beschreibst jedoch eine exe, welche dll's nutzen soll. Und, diese dll's sollen (vermutlich) miteinander kommunizieren können. DAS ist problemlos mit den in FB zur Verfügung stehenden Funktionen realisierbar.
Fertige doch einmal ein sehr einfaches beispiel an, das dein problem beinhaltet. lade es hoch, und zeig uns das, was du vor hast, und das was nicht geht.
Dann können wir dir auch hinsichtlich optimierungsprozess und "best of" helfen.
MfG
TPM
PS: Mein oben genannter code ist z.B. auch nur für ein app, das mehrfach gestartet, aber auf die selbe dll instanz zugreifen soll. Die exe läd mehrere dll's, aber eine davon soll in jeder applikation die selben speicherbereiche nutzen.
Wenn die exe eh nur einmal läuft, dann ist der "aufwand" absolut unnötig und überzogen! _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
|
Xardas
Anmeldungsdatum: 17.09.2006 Beiträge: 23
|
Verfasst am: 28.04.2014, 17:51 Titel: |
|
|
Erstmal vielen dank für die Hilfe.
Ich werde in den nächsten Tagen (sobald ich dazu komme) einen Dummy schreiben und hochladen. Das "original" Programm bzw. die Unterlagen dazu darf ich leider nicht Online stellen. (Hat rechtliche Gründe )
Kenn jemand ein gutes Freeware Programm um Ablaufdiagramme vernünftig darstellen zu können? Ich benutze zur Zeit Visual Paradigm aber ich bin von dem Programm nicht sehr begeistert. (zu fehleranfällig, komplizierte Menüstruktur etc)
Lg X |
|
Nach oben |
|
|
RockTheSchock
Anmeldungsdatum: 04.04.2007 Beiträge: 138
|
Verfasst am: 29.04.2014, 17:29 Titel: |
|
|
Ich glaube du machst es dir zu schwierig. Um Ein-/Ausgabe von den Berechnungen/der Logik zu trennen, brauchst du keine DLLs oder Shared Memory oder IPC Mechanismus.
Wichtig ist das du den Source Code gut strukturierst. Ob da eine einzelne EXE mit statisch verlinkten libraries oder eine EXE + 1 gui.dll + calc.dll + sdl.dll rauskommt spielt keine Rolle. Sofern du nicht einen Server Dienst betreibst, der permanent durchlaufen muss aber trotdem Teile im Betrieb ausgetauscht werden müssen, reicht eine einzige EXE.
Programm beenden - EXE ersetzen - Programm starten - fertig
Die Struktur des Sourcecodes ist das entscheidende. Dabei hilft gerade für komplexe Programme mit GUI:
Jede Klasse(Type) besteht aus einem Modul(.bas) und einer Header(.bi) Datei.
- Die Implementierung also Funktionen und Subs in das Modul
- Die Types und Declares kommen in den Header.
Alle Daten werden als Parameter Funktionen / Subs übergeben und weiterverarbeitet. d.h. Es sollte möglichst kaum Shared Variablen geben.
Du kannst eine Oberklasse GUI machen von der du SDLGUI und SDL2GUI ableitest und dann dynamisch die sdl bibliothek nutzt die im programm eingestellt ist. Bedeutet die EXE ist größer hat aber beide GUIs drin. Alternativ könntest du auch mit dem preprozessor und #ifdef arbeiten, um mit einem Schalter eine Bibliothek auszuwählen.
Oder du arbeitest tatsächlich mit einer dll bibliothek, die austauschbar ist, wobei du da sehr drauf achten musst, dass da nicht irgendwelche inkompatiblen Versionen einer dll, die nicht mit der EXE harmonieren, rumfliegen. Oder du erzeugst eine statische lib und nutzt die compiler optionen um eine EXE entweder mit der einen statischen lib oder der anderen zu erzeugen. |
|
Nach oben |
|
|
ThePuppetMaster
Anmeldungsdatum: 18.02.2007 Beiträge: 1837 Wohnort: [JN58JR]
|
Verfasst am: 29.04.2014, 17:31 Titel: |
|
|
@RockTheSchock ... das programm muss zwangsweise nichtmal beendet werden. Die DLL's können auch im laufendem Betrieb getauscht werden.
Die DLL-Kompatibilität läst sich auch einfach damit sichern, das ein einheitliches schnitstellenverfahren ausgearbeitet wird. dadurch sidn inkompatibilitäten quasi unmöglich, und können im programm / vom programm aus kontroliert und gemeldet werden.
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
|
RockTheSchock
Anmeldungsdatum: 04.04.2007 Beiträge: 138
|
Verfasst am: 29.04.2014, 17:47 Titel: |
|
|
Ich persönlich finde es schöner, wenn man möglichst nur eine EXE Datei hat und sonst höchstens dll dateien/bibliotheken von extern. Dll sind nur von Vorteil wenn man wirklich ein Hot - Plugin System benötigt. Dafür muss man nämlich Code schreiben der ein möglichst ausgearbeites Interface hat, dass sich nicht mehr ändern soll und wenn es doch noch erweitert werden soll wird es komplexer mit Versionkonmtrolle usw. Aber Grundlage von allem ist weniger was denn nun letztendlich kompiliert rauskommt, sondern eher dass der Sourcecode schön übersichtlich in Modulen und Header getrennt wird und mit Klassen und Objekten gearbeitet wird. Gerade bei GUIs bietet es sich an auch Vererbung und Überladen von Prozeduren zu nutzen.
Zuletzt bearbeitet von RockTheSchock am 29.04.2014, 17:51, insgesamt einmal bearbeitet |
|
Nach oben |
|
|
ThePuppetMaster
Anmeldungsdatum: 18.02.2007 Beiträge: 1837 Wohnort: [JN58JR]
|
Verfasst am: 29.04.2014, 17:51 Titel: |
|
|
Eigentlich nicht ... es gibt da schliesslich viele möglichkeiten der datenkontrolle.
Code: |
function mydllfunc(byval V_function as integer, byval v_data as any ptr, byref r_data as any ptr) as integer
selec case v_function
case 1: r_data = ... : Return 1
case 2
case 3
case else: return -1
end select
end function
|
sehr simpel, und änderungsmöglichkeiten ohne das interface zu verändern sind auch vorhanden , incl. überwachung und "versionskontrolle", wenn man so mag.
MfG
TPM _________________ [ WebFBC ][ OPS ][ ToOFlo ][ Wiemann.TV ] |
|
Nach oben |
|
|
Xardas
Anmeldungsdatum: 17.09.2006 Beiträge: 23
|
Verfasst am: 30.04.2014, 20:05 Titel: |
|
|
Ich kann leute verstehen die gerne nur eine EXE als Produkt haben wollen und repektiere deren Einstellung dazu aber ich persönlich (verzeiht meine Wortwahl) hasse es in dieser Weise zu programmieren, weil ich eine andere Vorstellung von Flexibilität und Erweiterbarkeit habe.
Aber das ist Geschmackssache (und sollte hier auch nicht das Thema sein). |
|
Nach oben |
|
|
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
|